From 731946f4b90eb1173452dd30f1296dd825155d82 Mon Sep 17 00:00:00 2001 From: jbj Date: Wed, 21 Mar 2001 18:33:35 +0000 Subject: Initial revision CVS patchset: 4644 CVS date: 2001/03/21 18:33:35 --- db/LICENSE | 102 + db/README | 5 + db/btree/bt_compare.c | 211 + db/btree/bt_conv.c | 98 + db/btree/bt_curadj.c | 573 + db/btree/bt_cursor.c | 2131 ++++ db/btree/bt_delete.c | 530 + db/btree/bt_method.c | 387 + db/btree/bt_open.c | 468 + db/btree/bt_put.c | 859 ++ db/btree/bt_rec.c | 1219 ++ db/btree/bt_reclaim.c | 53 + db/btree/bt_recno.c | 1369 ++ db/btree/bt_rsearch.c | 429 + db/btree/bt_search.c | 471 + db/btree/bt_split.c | 1126 ++ db/btree/bt_stat.c | 480 + db/btree/bt_upgrade.c | 164 + db/btree/bt_verify.c | 2237 ++++ db/btree/btree.src | 296 + db/btree/btree_auto.c | 2284 ++++ db/build_unix/.IGNORE_ME | 3 + db/build_vxworks/BerkeleyDB.wpj | 6066 +++++++++ db/build_vxworks/BerkeleyDB.wsp | 24 + db/build_vxworks/db.h | 1369 ++ db/build_vxworks/db_config.h | 264 + db/build_vxworks/db_int.h | 398 + db/build_vxworks/ex_access/ex_access.wpj | 244 + db/build_vxworks/ex_btrec/ex_btrec.wpj | 250 + db/build_vxworks/ex_dbclient/ex_dbclient.wpj | 266 + db/build_vxworks/ex_env/ex_env.wpj | 248 + db/build_vxworks/ex_mpool/ex_mpool.wpj | 248 + db/build_vxworks/ex_tpcb/ex_tpcb.wpj | 261 + db/build_win32/Berkeley_DB.dsw | 569 + db/build_win32/app_dsp.src | 148 + db/build_win32/db.h | 1378 +++ db/build_win32/db_archive.dsp | 151 + db/build_win32/db_buildall.dsp | 128 + db/build_win32/db_checkpoint.dsp | 151 + db/build_win32/db_config.h | 275 + db/build_win32/db_deadlock.dsp | 151 + db/build_win32/db_dll.dsp | 753 ++ db/build_win32/db_dump.dsp | 151 + db/build_win32/db_int.h | 398 + db/build_win32/db_java.dsp | 174 + db/build_win32/db_load.dsp | 151 + db/build_win32/db_printlog.dsp | 151 + db/build_win32/db_recover.dsp | 151 + db/build_win32/db_stat.dsp | 151 + db/build_win32/db_static.dsp | 714 ++ db/build_win32/db_tcl.dsp | 135 + db/build_win32/db_test.dsp | 99 + db/build_win32/db_upgrade.dsp | 151 + db/build_win32/db_verify.dsp | 151 + db/build_win32/dbkill.cpp | 131 + db/build_win32/dllmain.c | 97 + db/build_win32/dynamic_dsp.src | 154 + db/build_win32/ex_access.dsp | 151 + db/build_win32/ex_btrec.dsp | 151 + db/build_win32/ex_env.dsp | 151 + db/build_win32/ex_lock.dsp | 151 + db/build_win32/ex_mpool.dsp | 151 + db/build_win32/ex_tpcb.dsp | 151 + db/build_win32/excxx_access.dsp | 151 + db/build_win32/excxx_btrec.dsp | 151 + db/build_win32/excxx_env.dsp | 151 + db/build_win32/excxx_lock.dsp | 151 + db/build_win32/excxx_mpool.dsp | 151 + db/build_win32/excxx_tpcb.dsp | 151 + db/build_win32/include.tcl | 16 + db/build_win32/java_dsp.src | 135 + db/build_win32/libdb.def | 151 + db/build_win32/libdb.rc | 33 + db/build_win32/libdb_tcl.def | 35 + db/build_win32/libdbrc.src | 33 + db/build_win32/srcfile_dsp.src | 4 + db/build_win32/static_dsp.src | 127 + db/build_win32/tcl_dsp.src | 92 + db/clib/getcwd.c | 272 + db/clib/getopt.c | 139 + db/clib/memcmp.c | 67 + db/clib/memmove.c | 155 + db/clib/raise.c | 32 + db/clib/snprintf.c | 61 + db/clib/strcasecmp.c | 102 + db/clib/strerror.c | 77 + db/clib/vsnprintf.c | 47 + db/common/db_byteorder.c | 62 + db/common/db_err.c | 544 + db/common/db_getlong.c | 159 + db/common/db_log2.c | 65 + db/common/util_log.c | 63 + db/common/util_sig.c | 87 + db/cxx/cxx_app.cpp | 671 + db/cxx/cxx_except.cpp | 132 + db/cxx/cxx_lock.cpp | 125 + db/cxx/cxx_log.cpp | 125 + db/cxx/cxx_mpool.cpp | 180 + db/cxx/cxx_table.cpp | 808 ++ db/cxx/cxx_txn.cpp | 136 + db/cxx/namemap.txt | 21 + db/db/Design.fileop | 452 + db/db/crdel.src | 103 + db/db/crdel_auto.c | 900 ++ db/db/crdel_rec.c | 646 + db/db/db.c | 2325 ++++ db/db/db.src | 178 + db/db/db_am.c | 511 + db/db/db_auto.c | 1270 ++ db/db/db_cam.c | 974 ++ db/db/db_conv.c | 348 + db/db/db_dispatch.c | 983 ++ db/db/db_dup.c | 275 + db/db/db_iface.c | 687 ++ db/db/db_join.c | 730 ++ db/db/db_meta.c | 309 + db/db/db_method.c | 629 + db/db/db_overflow.c | 681 + db/db/db_pr.c | 1284 ++ db/db/db_rec.c | 529 + db/db/db_reclaim.c | 134 + db/db/db_ret.c | 160 + db/db/db_upg.c | 338 + db/db/db_upg_opd.c | 353 + db/db/db_vrfy.c | 2340 ++++ db/db/db_vrfyutil.c | 830 ++ db/db185/db185.c | 593 + db/db185/db185_int.h | 129 + db/db_archive/db_archive.c | 164 + db/db_checkpoint/db_checkpoint.c | 237 + db/db_deadlock/db_deadlock.c | 222 + db/db_dump/db_dump.c | 517 + db/db_dump185/db_dump185.c | 353 + db/db_load/db_load.c | 998 ++ db/db_printlog/README | 25 + db/db_printlog/commit.awk | 7 + db/db_printlog/count.awk | 9 + db/db_printlog/db_printlog.c | 200 + db/db_printlog/dbname.awk | 79 + db/db_printlog/fileid.awk | 37 + db/db_printlog/pgno.awk | 47 + db/db_printlog/range.awk | 27 + db/db_printlog/rectype.awk | 27 + db/db_printlog/status.awk | 26 + db/db_printlog/txn.awk | 34 + db/db_recover/db_recover.c | 288 + db/db_stat/db_stat.c | 989 ++ db/db_upgrade/db_upgrade.c | 173 + db/db_verify/db_verify.c | 182 + db/dbm/dbm.c | 489 + db/dist/Makefile.in | 999 ++ db/dist/RELEASE | 8 + db/dist/acconfig.h | 108 + db/dist/aclocal/mutex.m4 | 395 + db/dist/aclocal/options.m4 | 121 + db/dist/aclocal/programs.m4 | 48 + db/dist/aclocal/tcl.m4 | 126 + db/dist/aclocal/types.m4 | 139 + db/dist/build/chk.def | 50 + db/dist/build/chk.define | 55 + db/dist/build/chk.offt | 19 + db/dist/build/chk.srcfiles | 29 + db/dist/build/chk.tags | 39 + db/dist/build/script | 94 + db/dist/config.guess | 1289 ++ db/dist/config.hin | 231 + db/dist/config.sub | 1328 ++ db/dist/configure | 5811 +++++++++ db/dist/configure.in | 501 + db/dist/gen_rec.awk | 475 + db/dist/gen_rpc.awk | 1482 +++ db/dist/install-sh | 251 + db/dist/ltconfig | 3136 +++++ db/dist/ltmain.sh | 4029 ++++++ db/dist/rec_ctemp | 62 + db/dist/s_all | 16 + db/dist/s_config | 37 + db/dist/s_include | 33 + db/dist/s_java | 31 + db/dist/s_perm | 37 + db/dist/s_readme | 18 + db/dist/s_recover | 56 + db/dist/s_rpc | 70 + db/dist/s_symlink | 91 + db/dist/s_tags | 47 + db/dist/s_tcl | 53 + db/dist/s_vxworks | 48 + db/dist/s_win32 | 67 + db/dist/s_win32_dsp | 98 + db/dist/srcfiles.in | 269 + db/dist/template/db_server_proc | 1057 ++ db/dist/template/gen_client_ret | 522 + db/dist/template/rec_btree | 943 ++ db/dist/template/rec_crdel | 385 + db/dist/template/rec_db | 509 + db/dist/template/rec_hash | 881 ++ db/dist/template/rec_log | 137 + db/dist/template/rec_qam | 509 + db/dist/template/rec_txn | 509 + db/docs/api_c/c_index.html | 172 + db/docs/api_c/c_pindex.html | 530 + db/docs/api_c/db_close.html | 119 + db/docs/api_c/db_create.html | 107 + db/docs/api_c/db_cursor.html | 103 + db/docs/api_c/db_del.html | 101 + db/docs/api_c/db_err.html | 93 + db/docs/api_c/db_fd.html | 92 + db/docs/api_c/db_get.html | 156 + db/docs/api_c/db_get_byteswapped.html | 84 + db/docs/api_c/db_get_type.html | 81 + db/docs/api_c/db_join.html | 151 + db/docs/api_c/db_key_range.html | 106 + db/docs/api_c/db_lsn.html | 36 + db/docs/api_c/db_open.html | 182 + db/docs/api_c/db_put.html | 136 + db/docs/api_c/db_remove.html | 108 + db/docs/api_c/db_rename.html | 109 + db/docs/api_c/db_set_append_recno.html | 66 + db/docs/api_c/db_set_bt_compare.html | 105 + db/docs/api_c/db_set_bt_minkey.html | 92 + db/docs/api_c/db_set_bt_prefix.html | 106 + db/docs/api_c/db_set_cachesize.html | 107 + db/docs/api_c/db_set_dup_compare.html | 102 + db/docs/api_c/db_set_errcall.html | 76 + db/docs/api_c/db_set_errfile.html | 73 + db/docs/api_c/db_set_errpfx.html | 62 + db/docs/api_c/db_set_feedback.html | 95 + db/docs/api_c/db_set_flags.html | 181 + db/docs/api_c/db_set_h_ffactor.html | 93 + db/docs/api_c/db_set_h_hash.html | 97 + db/docs/api_c/db_set_h_nelem.html | 88 + db/docs/api_c/db_set_lorder.html | 94 + db/docs/api_c/db_set_malloc.html | 98 + db/docs/api_c/db_set_pagesize.html | 90 + db/docs/api_c/db_set_paniccall.html | 70 + db/docs/api_c/db_set_q_extentsize.html | 90 + db/docs/api_c/db_set_re_delim.html | 90 + db/docs/api_c/db_set_re_len.html | 94 + db/docs/api_c/db_set_re_pad.html | 88 + db/docs/api_c/db_set_re_source.html | 130 + db/docs/api_c/db_set_realloc.html | 99 + db/docs/api_c/db_stat.html | 195 + db/docs/api_c/db_sync.html | 98 + db/docs/api_c/db_upgrade.html | 135 + db/docs/api_c/db_verify.html | 150 + db/docs/api_c/dbc_close.html | 64 + db/docs/api_c/dbc_count.html | 55 + db/docs/api_c/dbc_del.html | 68 + db/docs/api_c/dbc_dup.html | 72 + db/docs/api_c/dbc_get.html | 167 + db/docs/api_c/dbc_put.html | 154 + db/docs/api_c/dbm.html | 220 + db/docs/api_c/dbt.html | 158 + db/docs/api_c/env_close.html | 84 + db/docs/api_c/env_create.html | 74 + db/docs/api_c/env_open.html | 205 + db/docs/api_c/env_remove.html | 125 + db/docs/api_c/env_set_cachesize.html | 87 + db/docs/api_c/env_set_data_dir.html | 77 + db/docs/api_c/env_set_errcall.html | 73 + db/docs/api_c/env_set_errfile.html | 70 + db/docs/api_c/env_set_errpfx.html | 59 + db/docs/api_c/env_set_feedback.html | 69 + db/docs/api_c/env_set_flags.html | 84 + db/docs/api_c/env_set_lg_bsize.html | 68 + db/docs/api_c/env_set_lg_dir.html | 73 + db/docs/api_c/env_set_lg_max.html | 68 + db/docs/api_c/env_set_lk_conflicts.html | 69 + db/docs/api_c/env_set_lk_detect.html | 72 + db/docs/api_c/env_set_lk_max.html | 72 + db/docs/api_c/env_set_lk_max_lockers.html | 68 + db/docs/api_c/env_set_lk_max_locks.html | 67 + db/docs/api_c/env_set_lk_max_objects.html | 68 + db/docs/api_c/env_set_mp_mmapsize.html | 71 + db/docs/api_c/env_set_mutexlocks.html | 59 + db/docs/api_c/env_set_pageyield.html | 68 + db/docs/api_c/env_set_paniccall.html | 67 + db/docs/api_c/env_set_panicstate.html | 64 + db/docs/api_c/env_set_rec_init.html | 71 + db/docs/api_c/env_set_region_init.html | 77 + db/docs/api_c/env_set_server.html | 77 + db/docs/api_c/env_set_shm_key.html | 87 + db/docs/api_c/env_set_tas_spins.html | 70 + db/docs/api_c/env_set_tmp_dir.html | 89 + db/docs/api_c/env_set_tx_max.html | 67 + db/docs/api_c/env_set_tx_recover.html | 75 + db/docs/api_c/env_set_tx_timestamp.html | 63 + db/docs/api_c/env_set_verbose.html | 78 + db/docs/api_c/env_strerror.html | 60 + db/docs/api_c/env_version.html | 57 + db/docs/api_c/hsearch.html | 107 + db/docs/api_c/lock_detect.html | 73 + db/docs/api_c/lock_get.html | 91 + db/docs/api_c/lock_id.html | 57 + db/docs/api_c/lock_put.html | 59 + db/docs/api_c/lock_stat.html | 92 + db/docs/api_c/lock_vec.html | 123 + db/docs/api_c/log_archive.html | 102 + db/docs/api_c/log_compare.html | 51 + db/docs/api_c/log_file.html | 76 + db/docs/api_c/log_flush.html | 62 + db/docs/api_c/log_get.html | 114 + db/docs/api_c/log_put.html | 81 + db/docs/api_c/log_register.html | 64 + db/docs/api_c/log_stat.html | 90 + db/docs/api_c/log_unregister.html | 59 + db/docs/api_c/memp_fclose.html | 61 + db/docs/api_c/memp_fget.html | 98 + db/docs/api_c/memp_fopen.html | 157 + db/docs/api_c/memp_fput.html | 79 + db/docs/api_c/memp_fset.html | 72 + db/docs/api_c/memp_fsync.html | 59 + db/docs/api_c/memp_register.html | 93 + db/docs/api_c/memp_stat.html | 118 + db/docs/api_c/memp_sync.html | 83 + db/docs/api_c/memp_trickle.html | 66 + db/docs/api_c/pindex.src | 301 + db/docs/api_c/set_func_close.html | 66 + db/docs/api_c/set_func_dirfree.html | 75 + db/docs/api_c/set_func_dirlist.html | 78 + db/docs/api_c/set_func_exists.html | 75 + db/docs/api_c/set_func_free.html | 67 + db/docs/api_c/set_func_fsync.html | 66 + db/docs/api_c/set_func_ioinfo.html | 83 + db/docs/api_c/set_func_malloc.html | 67 + db/docs/api_c/set_func_map.html | 86 + db/docs/api_c/set_func_open.html | 66 + db/docs/api_c/set_func_read.html | 66 + db/docs/api_c/set_func_realloc.html | 67 + db/docs/api_c/set_func_rename.html | 66 + db/docs/api_c/set_func_seek.html | 81 + db/docs/api_c/set_func_sleep.html | 76 + db/docs/api_c/set_func_unlink.html | 66 + db/docs/api_c/set_func_unmap.html | 75 + db/docs/api_c/set_func_write.html | 67 + db/docs/api_c/set_func_yield.html | 84 + db/docs/api_c/txn_abort.html | 63 + db/docs/api_c/txn_begin.html | 93 + db/docs/api_c/txn_checkpoint.html | 75 + db/docs/api_c/txn_commit.html | 83 + db/docs/api_c/txn_id.html | 50 + db/docs/api_c/txn_prepare.html | 63 + db/docs/api_c/txn_stat.html | 94 + db/docs/api_cxx/cxx_index.html | 148 + db/docs/api_cxx/cxx_pindex.html | 516 + db/docs/api_cxx/db_class.html | 109 + db/docs/api_cxx/db_close.html | 123 + db/docs/api_cxx/db_cursor.html | 105 + db/docs/api_cxx/db_del.html | 104 + db/docs/api_cxx/db_err.html | 94 + db/docs/api_cxx/db_fd.html | 95 + db/docs/api_cxx/db_get.html | 158 + db/docs/api_cxx/db_get_byteswapped.html | 85 + db/docs/api_cxx/db_get_type.html | 82 + db/docs/api_cxx/db_join.html | 153 + db/docs/api_cxx/db_key_range.html | 109 + db/docs/api_cxx/db_open.html | 185 + db/docs/api_cxx/db_put.html | 138 + db/docs/api_cxx/db_remove.html | 110 + db/docs/api_cxx/db_rename.html | 112 + db/docs/api_cxx/db_set_append_recno.html | 69 + db/docs/api_cxx/db_set_bt_compare.html | 109 + db/docs/api_cxx/db_set_bt_minkey.html | 94 + db/docs/api_cxx/db_set_bt_prefix.html | 110 + db/docs/api_cxx/db_set_cachesize.html | 108 + db/docs/api_cxx/db_set_dup_compare.html | 106 + db/docs/api_cxx/db_set_errcall.html | 79 + db/docs/api_cxx/db_set_errfile.html | 80 + db/docs/api_cxx/db_set_errpfx.html | 63 + db/docs/api_cxx/db_set_feedback.html | 97 + db/docs/api_cxx/db_set_flags.html | 183 + db/docs/api_cxx/db_set_h_ffactor.html | 95 + db/docs/api_cxx/db_set_h_hash.html | 102 + db/docs/api_cxx/db_set_h_nelem.html | 90 + db/docs/api_cxx/db_set_lorder.html | 96 + db/docs/api_cxx/db_set_malloc.html | 103 + db/docs/api_cxx/db_set_pagesize.html | 92 + db/docs/api_cxx/db_set_paniccall.html | 76 + db/docs/api_cxx/db_set_q_extentsize.html | 92 + db/docs/api_cxx/db_set_re_delim.html | 92 + db/docs/api_cxx/db_set_re_len.html | 96 + db/docs/api_cxx/db_set_re_pad.html | 90 + db/docs/api_cxx/db_set_re_source.html | 132 + db/docs/api_cxx/db_set_realloc.html | 103 + db/docs/api_cxx/db_stat.html | 201 + db/docs/api_cxx/db_sync.html | 101 + db/docs/api_cxx/db_upgrade.html | 135 + db/docs/api_cxx/db_verify.html | 150 + db/docs/api_cxx/dbc_class.html | 49 + db/docs/api_cxx/dbc_close.html | 68 + db/docs/api_cxx/dbc_count.html | 59 + db/docs/api_cxx/dbc_del.html | 72 + db/docs/api_cxx/dbc_dup.html | 76 + db/docs/api_cxx/dbc_get.html | 170 + db/docs/api_cxx/dbc_put.html | 158 + db/docs/api_cxx/dbenv_class.html | 76 + db/docs/api_cxx/dbt_class.html | 230 + db/docs/api_cxx/env_close.html | 87 + db/docs/api_cxx/env_open.html | 209 + db/docs/api_cxx/env_remove.html | 129 + db/docs/api_cxx/env_set_cachesize.html | 89 + db/docs/api_cxx/env_set_data_dir.html | 80 + db/docs/api_cxx/env_set_errcall.html | 76 + db/docs/api_cxx/env_set_errfile.html | 77 + db/docs/api_cxx/env_set_error_stream.html | 74 + db/docs/api_cxx/env_set_errpfx.html | 60 + db/docs/api_cxx/env_set_feedback.html | 72 + db/docs/api_cxx/env_set_flags.html | 87 + db/docs/api_cxx/env_set_lg_bsize.html | 71 + db/docs/api_cxx/env_set_lg_dir.html | 76 + db/docs/api_cxx/env_set_lg_max.html | 71 + db/docs/api_cxx/env_set_lk_conflicts.html | 71 + db/docs/api_cxx/env_set_lk_detect.html | 75 + db/docs/api_cxx/env_set_lk_max.html | 75 + db/docs/api_cxx/env_set_lk_max_lockers.html | 71 + db/docs/api_cxx/env_set_lk_max_locks.html | 70 + db/docs/api_cxx/env_set_lk_max_objects.html | 71 + db/docs/api_cxx/env_set_mp_mmapsize.html | 74 + db/docs/api_cxx/env_set_mutexlocks.html | 62 + db/docs/api_cxx/env_set_pageyield.html | 71 + db/docs/api_cxx/env_set_paniccall.html | 72 + db/docs/api_cxx/env_set_panicstate.html | 67 + db/docs/api_cxx/env_set_rec_init.html | 73 + db/docs/api_cxx/env_set_region_init.html | 80 + db/docs/api_cxx/env_set_server.html | 80 + db/docs/api_cxx/env_set_shm_key.html | 90 + db/docs/api_cxx/env_set_tas_spins.html | 73 + db/docs/api_cxx/env_set_tmp_dir.html | 92 + db/docs/api_cxx/env_set_tx_max.html | 70 + db/docs/api_cxx/env_set_tx_recover.html | 77 + db/docs/api_cxx/env_set_tx_timestamp.html | 66 + db/docs/api_cxx/env_set_verbose.html | 81 + db/docs/api_cxx/env_strerror.html | 62 + db/docs/api_cxx/env_version.html | 59 + db/docs/api_cxx/except_class.html | 64 + db/docs/api_cxx/get_errno.html | 43 + db/docs/api_cxx/lock_class.html | 61 + db/docs/api_cxx/lock_detect.html | 73 + db/docs/api_cxx/lock_get.html | 94 + db/docs/api_cxx/lock_id.html | 61 + db/docs/api_cxx/lock_put.html | 63 + db/docs/api_cxx/lock_stat.html | 98 + db/docs/api_cxx/lock_vec.html | 127 + db/docs/api_cxx/log_archive.html | 106 + db/docs/api_cxx/log_compare.html | 53 + db/docs/api_cxx/log_file.html | 79 + db/docs/api_cxx/log_flush.html | 66 + db/docs/api_cxx/log_get.html | 118 + db/docs/api_cxx/log_put.html | 84 + db/docs/api_cxx/log_register.html | 68 + db/docs/api_cxx/log_stat.html | 96 + db/docs/api_cxx/log_unregister.html | 63 + db/docs/api_cxx/lsn_class.html | 38 + db/docs/api_cxx/memp_fclose.html | 65 + db/docs/api_cxx/memp_fget.html | 101 + db/docs/api_cxx/memp_fopen.html | 160 + db/docs/api_cxx/memp_fput.html | 83 + db/docs/api_cxx/memp_fset.html | 76 + db/docs/api_cxx/memp_fsync.html | 63 + db/docs/api_cxx/memp_register.html | 102 + db/docs/api_cxx/memp_stat.html | 125 + db/docs/api_cxx/memp_sync.html | 87 + db/docs/api_cxx/memp_trickle.html | 70 + db/docs/api_cxx/mempfile_class.html | 62 + db/docs/api_cxx/pindex.src | 287 + db/docs/api_cxx/txn_abort.html | 67 + db/docs/api_cxx/txn_begin.html | 96 + db/docs/api_cxx/txn_checkpoint.html | 75 + db/docs/api_cxx/txn_class.html | 59 + db/docs/api_cxx/txn_commit.html | 87 + db/docs/api_cxx/txn_id.html | 52 + db/docs/api_cxx/txn_prepare.html | 67 + db/docs/api_cxx/txn_stat.html | 100 + db/docs/api_cxx/what.html | 43 + db/docs/api_java/db_class.html | 92 + db/docs/api_java/db_close.html | 113 + db/docs/api_java/db_cursor.html | 94 + db/docs/api_java/db_del.html | 94 + db/docs/api_java/db_fd.html | 79 + db/docs/api_java/db_get.html | 149 + db/docs/api_java/db_get_byteswapped.html | 75 + db/docs/api_java/db_get_type.html | 72 + db/docs/api_java/db_join.html | 142 + db/docs/api_java/db_key_range.html | 99 + db/docs/api_java/db_open.html | 179 + db/docs/api_java/db_put.html | 128 + db/docs/api_java/db_remove.html | 104 + db/docs/api_java/db_rename.html | 105 + db/docs/api_java/db_set_append_recno.html | 75 + db/docs/api_java/db_set_bt_compare.html | 105 + db/docs/api_java/db_set_bt_minkey.html | 85 + db/docs/api_java/db_set_bt_prefix.html | 106 + db/docs/api_java/db_set_cachesize.html | 99 + db/docs/api_java/db_set_dup_compare.html | 102 + db/docs/api_java/db_set_errcall.html | 81 + db/docs/api_java/db_set_errpfx.html | 55 + db/docs/api_java/db_set_feedback.html | 95 + db/docs/api_java/db_set_flags.html | 170 + db/docs/api_java/db_set_h_ffactor.html | 86 + db/docs/api_java/db_set_h_hash.html | 97 + db/docs/api_java/db_set_h_nelem.html | 81 + db/docs/api_java/db_set_lorder.html | 87 + db/docs/api_java/db_set_pagesize.html | 83 + db/docs/api_java/db_set_q_extentsize.html | 83 + db/docs/api_java/db_set_re_delim.html | 83 + db/docs/api_java/db_set_re_len.html | 87 + db/docs/api_java/db_set_re_pad.html | 81 + db/docs/api_java/db_set_re_source.html | 123 + db/docs/api_java/db_stat.html | 185 + db/docs/api_java/db_sync.html | 91 + db/docs/api_java/db_upgrade.html | 125 + db/docs/api_java/db_verify.html | 140 + db/docs/api_java/dbc_class.html | 49 + db/docs/api_java/dbc_close.html | 67 + db/docs/api_java/dbc_count.html | 58 + db/docs/api_java/dbc_del.html | 71 + db/docs/api_java/dbc_dup.html | 75 + db/docs/api_java/dbc_get.html | 168 + db/docs/api_java/dbc_put.html | 157 + db/docs/api_java/dbenv_class.html | 65 + db/docs/api_java/dbt_class.html | 227 + db/docs/api_java/deadlock_class.html | 47 + db/docs/api_java/env_close.html | 82 + db/docs/api_java/env_open.html | 212 + db/docs/api_java/env_remove.html | 129 + db/docs/api_java/env_set_cachesize.html | 86 + db/docs/api_java/env_set_data_dir.html | 77 + db/docs/api_java/env_set_errcall.html | 78 + db/docs/api_java/env_set_error_stream.html | 69 + db/docs/api_java/env_set_errpfx.html | 52 + db/docs/api_java/env_set_feedback.html | 76 + db/docs/api_java/env_set_flags.html | 84 + db/docs/api_java/env_set_lg_bsize.html | 71 + db/docs/api_java/env_set_lg_dir.html | 73 + db/docs/api_java/env_set_lg_max.html | 71 + db/docs/api_java/env_set_lk_conflicts.html | 68 + db/docs/api_java/env_set_lk_detect.html | 74 + db/docs/api_java/env_set_lk_max.html | 74 + db/docs/api_java/env_set_lk_max_lockers.html | 70 + db/docs/api_java/env_set_lk_max_locks.html | 69 + db/docs/api_java/env_set_lk_max_objects.html | 70 + db/docs/api_java/env_set_mp_mmapsize.html | 66 + db/docs/api_java/env_set_mutexlocks.html | 59 + db/docs/api_java/env_set_pageyield.html | 69 + db/docs/api_java/env_set_panicstate.html | 65 + db/docs/api_java/env_set_rec_init.html | 78 + db/docs/api_java/env_set_region_init.html | 78 + db/docs/api_java/env_set_server.html | 77 + db/docs/api_java/env_set_shm_key.html | 87 + db/docs/api_java/env_set_tas_spins.html | 71 + db/docs/api_java/env_set_tmp_dir.html | 89 + db/docs/api_java/env_set_tx_max.html | 69 + db/docs/api_java/env_set_tx_recover.html | 84 + db/docs/api_java/env_set_tx_timestamp.html | 64 + db/docs/api_java/env_set_verbose.html | 77 + db/docs/api_java/env_strerror.html | 58 + db/docs/api_java/env_version.html | 58 + db/docs/api_java/except_class.html | 52 + db/docs/api_java/get_errno.html | 46 + db/docs/api_java/java_index.html | 131 + db/docs/api_java/java_pindex.html | 478 + db/docs/api_java/lock_class.html | 54 + db/docs/api_java/lock_detect.html | 69 + db/docs/api_java/lock_get.html | 92 + db/docs/api_java/lock_id.html | 59 + db/docs/api_java/lock_put.html | 61 + db/docs/api_java/lock_stat.html | 94 + db/docs/api_java/lock_vec.html | 33 + db/docs/api_java/log_archive.html | 92 + db/docs/api_java/log_compare.html | 52 + db/docs/api_java/log_file.html | 77 + db/docs/api_java/log_flush.html | 65 + db/docs/api_java/log_get.html | 117 + db/docs/api_java/log_put.html | 83 + db/docs/api_java/log_register.html | 67 + db/docs/api_java/log_stat.html | 93 + db/docs/api_java/log_unregister.html | 62 + db/docs/api_java/lsn_class.html | 37 + db/docs/api_java/mem_class.html | 48 + db/docs/api_java/memp_fclose.html | 33 + db/docs/api_java/memp_fget.html | 33 + db/docs/api_java/memp_fopen.html | 33 + db/docs/api_java/memp_fput.html | 33 + db/docs/api_java/memp_fset.html | 33 + db/docs/api_java/memp_fsync.html | 33 + db/docs/api_java/memp_register.html | 33 + db/docs/api_java/memp_stat.html | 102 + db/docs/api_java/memp_sync.html | 33 + db/docs/api_java/memp_trickle.html | 60 + db/docs/api_java/pindex.src | 249 + db/docs/api_java/runrec_class.html | 50 + db/docs/api_java/txn_abort.html | 65 + db/docs/api_java/txn_begin.html | 93 + db/docs/api_java/txn_checkpoint.html | 74 + db/docs/api_java/txn_class.html | 58 + db/docs/api_java/txn_commit.html | 85 + db/docs/api_java/txn_id.html | 51 + db/docs/api_java/txn_prepare.html | 65 + db/docs/api_java/txn_stat.html | 95 + db/docs/api_tcl/db_close.html | 59 + db/docs/api_tcl/db_count.html | 38 + db/docs/api_tcl/db_cursor.html | 42 + db/docs/api_tcl/db_del.html | 47 + db/docs/api_tcl/db_get.html | 98 + db/docs/api_tcl/db_get_join.html | 45 + db/docs/api_tcl/db_get_type.html | 34 + db/docs/api_tcl/db_is_byteswapped.html | 37 + db/docs/api_tcl/db_join.html | 48 + db/docs/api_tcl/db_open.html | 300 + db/docs/api_tcl/db_put.html | 74 + db/docs/api_tcl/db_remove.html | 49 + db/docs/api_tcl/db_rename.html | 50 + db/docs/api_tcl/db_stat.html | 41 + db/docs/api_tcl/db_sync.html | 36 + db/docs/api_tcl/dbc_close.html | 36 + db/docs/api_tcl/dbc_del.html | 38 + db/docs/api_tcl/dbc_dup.html | 46 + db/docs/api_tcl/dbc_get.html | 168 + db/docs/api_tcl/dbc_put.html | 133 + db/docs/api_tcl/env_close.html | 42 + db/docs/api_tcl/env_open.html | 168 + db/docs/api_tcl/env_remove.html | 70 + db/docs/api_tcl/pindex.src | 27 + db/docs/api_tcl/tcl_index.html | 49 + db/docs/api_tcl/tcl_pindex.html | 258 + db/docs/api_tcl/txn.html | 62 + db/docs/api_tcl/txn_abort.html | 45 + db/docs/api_tcl/txn_commit.html | 68 + db/docs/api_tcl/version.html | 39 + db/docs/images/api.gif | Bin 0 -> 121 bytes db/docs/images/next.gif | Bin 0 -> 225 bytes db/docs/images/prev.gif | Bin 0 -> 234 bytes db/docs/images/ps.gif | Bin 0 -> 244 bytes db/docs/images/ref.gif | Bin 0 -> 119 bytes db/docs/images/sleepycat.gif | Bin 0 -> 6211 bytes db/docs/index.html | 75 + db/docs/ref/am/close.html | 43 + db/docs/ref/am/count.html | 28 + db/docs/ref/am/curclose.html | 28 + db/docs/ref/am/curdel.html | 26 + db/docs/ref/am/curdup.html | 34 + db/docs/ref/am/curget.html | 74 + db/docs/ref/am/curput.html | 40 + db/docs/ref/am/cursor.html | 41 + db/docs/ref/am/delete.html | 28 + db/docs/ref/am/error.html | 61 + db/docs/ref/am/get.html | 39 + db/docs/ref/am/join.html | 184 + db/docs/ref/am/open.html | 47 + db/docs/ref/am/opensub.html | 64 + db/docs/ref/am/ops.html | 36 + db/docs/ref/am/partial.html | 134 + db/docs/ref/am/put.html | 36 + db/docs/ref/am/stability.html | 49 + db/docs/ref/am/stat.html | 36 + db/docs/ref/am/sync.html | 38 + db/docs/ref/am/upgrade.html | 50 + db/docs/ref/am/verify.html | 50 + db/docs/ref/am_conf/bt_compare.html | 85 + db/docs/ref/am_conf/bt_minkey.html | 53 + db/docs/ref/am_conf/bt_prefix.html | 66 + db/docs/ref/am_conf/bt_recnum.html | 34 + db/docs/ref/am_conf/byteorder.html | 38 + db/docs/ref/am_conf/cachesize.html | 86 + db/docs/ref/am_conf/dup.html | 71 + db/docs/ref/am_conf/extentsize.html | 38 + db/docs/ref/am_conf/h_ffactor.html | 31 + db/docs/ref/am_conf/h_hash.html | 39 + db/docs/ref/am_conf/h_nelem.html | 32 + db/docs/ref/am_conf/intro.html | 45 + db/docs/ref/am_conf/logrec.html | 45 + db/docs/ref/am_conf/malloc.html | 31 + db/docs/ref/am_conf/pagesize.html | 66 + db/docs/ref/am_conf/re_source.html | 62 + db/docs/ref/am_conf/recno.html | 69 + db/docs/ref/am_conf/renumber.html | 80 + db/docs/ref/am_conf/select.html | 116 + db/docs/ref/arch/apis.html | 74 + db/docs/ref/arch/bigpic.gif | Bin 0 -> 2589 bytes db/docs/ref/arch/bigpic.html | 114 + db/docs/ref/arch/progmodel.html | 41 + db/docs/ref/arch/script.html | 29 + db/docs/ref/arch/smallpic.gif | Bin 0 -> 1613 bytes db/docs/ref/arch/utilities.html | 62 + db/docs/ref/build_unix/aix.html | 60 + db/docs/ref/build_unix/conf.html | 143 + db/docs/ref/build_unix/flags.html | 60 + db/docs/ref/build_unix/freebsd.html | 57 + db/docs/ref/build_unix/hpux.html | 89 + db/docs/ref/build_unix/install.html | 60 + db/docs/ref/build_unix/intro.html | 60 + db/docs/ref/build_unix/irix.html | 30 + db/docs/ref/build_unix/linux.html | 30 + db/docs/ref/build_unix/notes.html | 138 + db/docs/ref/build_unix/osf1.html | 30 + db/docs/ref/build_unix/qnx.html | 58 + db/docs/ref/build_unix/sco.html | 29 + db/docs/ref/build_unix/shlib.html | 94 + db/docs/ref/build_unix/solaris.html | 90 + db/docs/ref/build_unix/sunos.html | 30 + db/docs/ref/build_unix/test.html | 49 + db/docs/ref/build_unix/ultrix.html | 27 + db/docs/ref/build_vxworks/faq.html | 85 + db/docs/ref/build_vxworks/intro.html | 86 + db/docs/ref/build_vxworks/notes.html | 56 + db/docs/ref/build_win/faq.html | 49 + db/docs/ref/build_win/intro.html | 143 + db/docs/ref/build_win/notes.html | 56 + db/docs/ref/build_win/test.html | 77 + db/docs/ref/cam/intro.html | 72 + db/docs/ref/debug/common.html | 109 + db/docs/ref/debug/compile.html | 43 + db/docs/ref/debug/intro.html | 58 + db/docs/ref/debug/printlog.html | 160 + db/docs/ref/debug/runtime.html | 47 + db/docs/ref/distrib/layout.html | 74 + db/docs/ref/dumpload/format.html | 69 + db/docs/ref/dumpload/text.html | 32 + db/docs/ref/dumpload/utility.html | 45 + db/docs/ref/env/create.html | 73 + db/docs/ref/env/error.html | 57 + db/docs/ref/env/intro.html | 56 + db/docs/ref/env/naming.html | 145 + db/docs/ref/env/open.html | 30 + db/docs/ref/env/region.html | 66 + db/docs/ref/env/remote.html | 48 + db/docs/ref/env/security.html | 54 + db/docs/ref/install/file.html | 37 + db/docs/ref/install/magic.s5.be.txt | 87 + db/docs/ref/install/magic.s5.le.txt | 87 + db/docs/ref/install/magic.txt | 56 + db/docs/ref/intro/data.html | 54 + db/docs/ref/intro/dbis.html | 159 + db/docs/ref/intro/dbisnot.html | 146 + db/docs/ref/intro/distrib.html | 28 + db/docs/ref/intro/need.html | 60 + db/docs/ref/intro/products.html | 69 + db/docs/ref/intro/terrain.html | 248 + db/docs/ref/intro/what.html | 53 + db/docs/ref/intro/where.html | 39 + db/docs/ref/java/compat.html | 34 + db/docs/ref/java/conf.html | 82 + db/docs/ref/java/faq.html | 31 + db/docs/ref/java/program.html | 72 + db/docs/ref/lock/am_conv.html | 129 + db/docs/ref/lock/cam_conv.html | 53 + db/docs/ref/lock/config.html | 46 + db/docs/ref/lock/dead.html | 93 + db/docs/ref/lock/intro.html | 89 + db/docs/ref/lock/max.html | 88 + db/docs/ref/lock/nondb.html | 50 + db/docs/ref/lock/notxn.html | 46 + db/docs/ref/lock/page.html | 62 + db/docs/ref/lock/stdmode.html | 61 + db/docs/ref/lock/twopl.html | 50 + db/docs/ref/log/config.html | 40 + db/docs/ref/log/intro.html | 58 + db/docs/ref/log/limits.html | 47 + db/docs/ref/mp/config.html | 55 + db/docs/ref/mp/intro.html | 59 + db/docs/ref/perl/intro.html | 42 + db/docs/ref/pindex.src | 212 + db/docs/ref/program/appsignals.html | 35 + db/docs/ref/program/byteorder.html | 31 + db/docs/ref/program/compatible.html | 32 + db/docs/ref/program/copy.html | 63 + db/docs/ref/program/dbsizes.html | 45 + db/docs/ref/program/diskspace.html | 145 + db/docs/ref/program/environ.html | 33 + db/docs/ref/program/errorret.html | 108 + db/docs/ref/program/extending.html | 242 + db/docs/ref/program/mt.html | 95 + db/docs/ref/program/namespace.html | 44 + db/docs/ref/program/recimp.html | 49 + db/docs/ref/program/runtime.html | 57 + db/docs/ref/program/scope.html | 71 + db/docs/ref/program/solaris.txt | 213 + db/docs/ref/program/version.html | 45 + db/docs/ref/refs/bdb_usenix.html | 1120 ++ db/docs/ref/refs/bdb_usenix.ps | 1441 +++ db/docs/ref/refs/embedded.html | 672 + db/docs/ref/refs/hash_usenix.ps | 12209 ++++++++++++++++++ db/docs/ref/refs/libtp_usenix.ps | 12340 +++++++++++++++++++ db/docs/ref/refs/refs.html | 75 + db/docs/ref/refs/witold.html | 16 + db/docs/ref/rpc/client.html | 75 + db/docs/ref/rpc/intro.html | 62 + db/docs/ref/rpc/server.html | 54 + db/docs/ref/sendmail/intro.html | 51 + db/docs/ref/simple_tut/close.html | 102 + db/docs/ref/simple_tut/del.html | 93 + db/docs/ref/simple_tut/errors.html | 46 + db/docs/ref/simple_tut/example.txt | 73 + db/docs/ref/simple_tut/get.html | 97 + db/docs/ref/simple_tut/handles.html | 29 + db/docs/ref/simple_tut/intro.html | 40 + db/docs/ref/simple_tut/keydata.html | 48 + db/docs/ref/simple_tut/open.html | 90 + db/docs/ref/simple_tut/put.html | 127 + db/docs/ref/tcl/error.html | 69 + db/docs/ref/tcl/faq.html | 60 + db/docs/ref/tcl/intro.html | 70 + db/docs/ref/tcl/program.html | 33 + db/docs/ref/tcl/using.html | 53 + db/docs/ref/test/faq.html | 32 + db/docs/ref/test/run.html | 78 + db/docs/ref/toc.html | 310 + db/docs/ref/transapp/admin.html | 47 + db/docs/ref/transapp/app.html | 117 + db/docs/ref/transapp/archival.html | 149 + db/docs/ref/transapp/checkpoint.html | 127 + db/docs/ref/transapp/cursor.html | 169 + db/docs/ref/transapp/data_open.html | 119 + db/docs/ref/transapp/deadlock.html | 92 + db/docs/ref/transapp/env_open.html | 174 + db/docs/ref/transapp/filesys.html | 62 + db/docs/ref/transapp/inc.html | 201 + db/docs/ref/transapp/intro.html | 42 + db/docs/ref/transapp/logfile.html | 104 + db/docs/ref/transapp/put.html | 151 + db/docs/ref/transapp/read.html | 40 + db/docs/ref/transapp/reclimit.html | 106 + db/docs/ref/transapp/recovery.html | 91 + db/docs/ref/transapp/term.html | 60 + db/docs/ref/transapp/throughput.html | 117 + db/docs/ref/transapp/transapp.txt | 492 + db/docs/ref/transapp/why.html | 49 + db/docs/ref/transapp/writetest.txt | 100 + db/docs/ref/txn/config.html | 37 + db/docs/ref/txn/intro.html | 86 + db/docs/ref/txn/limits.html | 66 + db/docs/ref/txn/nested.html | 66 + db/docs/ref/txn/other.html | 67 + db/docs/ref/upgrade.2.0/convert.html | 74 + db/docs/ref/upgrade.2.0/disk.html | 27 + db/docs/ref/upgrade.2.0/intro.html | 32 + db/docs/ref/upgrade.2.0/system.html | 84 + db/docs/ref/upgrade.2.0/toc.html | 20 + db/docs/ref/upgrade.3.0/close.html | 34 + db/docs/ref/upgrade.3.0/cxx.html | 31 + db/docs/ref/upgrade.3.0/db.html | 48 + db/docs/ref/upgrade.3.0/db_cxx.html | 47 + db/docs/ref/upgrade.3.0/dbenv.html | 68 + db/docs/ref/upgrade.3.0/dbenv_cxx.html | 72 + db/docs/ref/upgrade.3.0/dbinfo.html | 72 + db/docs/ref/upgrade.3.0/disk.html | 30 + db/docs/ref/upgrade.3.0/eacces.html | 28 + db/docs/ref/upgrade.3.0/eagain.html | 34 + db/docs/ref/upgrade.3.0/envopen.html | 156 + db/docs/ref/upgrade.3.0/func.html | 69 + db/docs/ref/upgrade.3.0/intro.html | 26 + db/docs/ref/upgrade.3.0/java.html | 34 + db/docs/ref/upgrade.3.0/join.html | 28 + db/docs/ref/upgrade.3.0/jump_set.html | 48 + db/docs/ref/upgrade.3.0/lock_detect.html | 24 + db/docs/ref/upgrade.3.0/lock_notheld.html | 27 + db/docs/ref/upgrade.3.0/lock_put.html | 25 + db/docs/ref/upgrade.3.0/lock_stat.html | 24 + db/docs/ref/upgrade.3.0/log_register.html | 25 + db/docs/ref/upgrade.3.0/log_stat.html | 23 + db/docs/ref/upgrade.3.0/memp_stat.html | 26 + db/docs/ref/upgrade.3.0/open.html | 65 + db/docs/ref/upgrade.3.0/rmw.html | 31 + db/docs/ref/upgrade.3.0/stat.html | 24 + db/docs/ref/upgrade.3.0/toc.html | 47 + db/docs/ref/upgrade.3.0/txn_begin.html | 25 + db/docs/ref/upgrade.3.0/txn_commit.html | 25 + db/docs/ref/upgrade.3.0/txn_stat.html | 23 + db/docs/ref/upgrade.3.0/value_set.html | 41 + db/docs/ref/upgrade.3.0/xa.html | 33 + db/docs/ref/upgrade.3.1/btstat.html | 50 + db/docs/ref/upgrade.3.1/config.html | 35 + db/docs/ref/upgrade.3.1/disk.html | 34 + db/docs/ref/upgrade.3.1/dup.html | 31 + db/docs/ref/upgrade.3.1/env.html | 53 + db/docs/ref/upgrade.3.1/intro.html | 26 + db/docs/ref/upgrade.3.1/log_register.html | 28 + db/docs/ref/upgrade.3.1/logalloc.html | 27 + db/docs/ref/upgrade.3.1/memp_register.html | 30 + db/docs/ref/upgrade.3.1/put.html | 63 + db/docs/ref/upgrade.3.1/set_feedback.html | 27 + db/docs/ref/upgrade.3.1/set_paniccall.html | 27 + db/docs/ref/upgrade.3.1/set_tx_recover.html | 36 + db/docs/ref/upgrade.3.1/sysmem.html | 25 + db/docs/ref/upgrade.3.1/tcl.html | 30 + db/docs/ref/upgrade.3.1/tmp.html | 34 + db/docs/ref/upgrade.3.1/toc.html | 33 + db/docs/ref/upgrade.3.1/txn_check.html | 26 + db/docs/ref/upgrade.3.2/callback.html | 39 + db/docs/ref/upgrade.3.2/db_dump.html | 29 + db/docs/ref/upgrade.3.2/disk.html | 28 + db/docs/ref/upgrade.3.2/handle.html | 27 + db/docs/ref/upgrade.3.2/incomplete.html | 39 + db/docs/ref/upgrade.3.2/intro.html | 26 + db/docs/ref/upgrade.3.2/mutexlock.html | 28 + db/docs/ref/upgrade.3.2/notfound.html | 25 + db/docs/ref/upgrade.3.2/renumber.html | 39 + db/docs/ref/upgrade.3.2/set_flags.html | 35 + db/docs/ref/upgrade.3.2/toc.html | 27 + db/docs/ref/upgrade.3.2/tx_recover.html | 32 + db/docs/ref/upgrade/process.html | 108 + db/docs/ref/xa/config.html | 79 + db/docs/ref/xa/faq.html | 55 + db/docs/ref/xa/intro.html | 61 + db/docs/sleepycat/contact.html | 107 + db/docs/sleepycat/legal.html | 56 + db/docs/sleepycat/license.html | 109 + db/docs/utility/berkeley_db_svc.html | 88 + db/docs/utility/db_archive.html | 85 + db/docs/utility/db_checkpoint.html | 82 + db/docs/utility/db_deadlock.html | 85 + db/docs/utility/db_dump.html | 128 + db/docs/utility/db_load.html | 151 + db/docs/utility/db_printlog.html | 69 + db/docs/utility/db_recover.html | 97 + db/docs/utility/db_stat.html | 104 + db/docs/utility/db_upgrade.html | 93 + db/docs/utility/db_verify.html | 73 + db/docs/utility/index.html | 28 + db/env/db_salloc.c | 360 + db/env/db_shash.c | 124 + db/env/env_method.c | 461 + db/env/env_open.c | 1064 ++ db/env/env_recover.c | 449 + db/env/env_region.c | 1205 ++ db/examples_c/README | 23 + db/examples_c/ex_access.c | 171 + db/examples_c/ex_btrec.c | 241 + db/examples_c/ex_dbclient.c | 248 + db/examples_c/ex_env.c | 170 + db/examples_c/ex_lock.c | 235 + db/examples_c/ex_mpool.c | 280 + db/examples_c/ex_thread.c | 604 + db/examples_c/ex_tpcb.c | 811 ++ db/examples_c/ex_tpcb.h | 39 + db/examples_cxx/AccessExample.cpp | 151 + db/examples_cxx/BtRecExample.cpp | 247 + db/examples_cxx/EnvExample.cpp | 122 + db/examples_cxx/LockExample.cpp | 236 + db/examples_cxx/MpoolExample.cpp | 210 + db/examples_cxx/TpcbExample.cpp | 666 + db/hash/hash.c | 2096 ++++ db/hash/hash.src | 361 + db/hash/hash_auto.c | 2023 +++ db/hash/hash_conv.c | 112 + db/hash/hash_dup.c | 805 ++ db/hash/hash_func.c | 242 + db/hash/hash_meta.c | 121 + db/hash/hash_method.c | 126 + db/hash/hash_page.c | 1655 +++ db/hash/hash_rec.c | 1078 ++ db/hash/hash_reclaim.c | 68 + db/hash/hash_stat.c | 329 + db/hash/hash_upgrade.c | 271 + db/hash/hash_verify.c | 1051 ++ db/hsearch/hsearch.c | 148 + db/include/btree.h | 317 + db/include/btree_auto.h | 267 + db/include/btree_ext.h | 122 + db/include/clib_ext.h | 38 + db/include/common_ext.h | 44 + db/include/crdel_auto.h | 88 + db/include/cxx_int.h | 96 + db/include/db.src | 1375 +++ db/include/db_185.h | 175 + db/include/db_am.h | 131 + db/include/db_auto.h | 140 + db/include/db_cxx.h | 652 + db/include/db_dispatch.h | 95 + db/include/db_ext.h | 208 + db/include/db_int.src | 397 + db/include/db_join.h | 30 + db/include/db_page.h | 576 + db/include/db_server.h | 762 ++ db/include/db_server_int.h | 85 + db/include/db_shash.h | 77 + db/include/db_swap.h | 115 + db/include/db_upgrade.h | 174 + db/include/db_verify.h | 191 + db/include/debug.h | 104 + db/include/env_ext.h | 35 + db/include/gen_client_ext.h | 121 + db/include/gen_server_ext.h | 106 + db/include/hash.h | 140 + db/include/hash_auto.h | 248 + db/include/hash_ext.h | 106 + db/include/lock.h | 190 + db/include/lock_ext.h | 39 + db/include/log.h | 208 + db/include/log_auto.h | 39 + db/include/log_ext.h | 33 + db/include/mp.h | 244 + db/include/mp_ext.h | 33 + db/include/mutex.h | 744 ++ db/include/mutex_ext.h | 31 + db/include/os.h | 46 + db/include/os_ext.h | 62 + db/include/os_jump.h | 34 + db/include/qam.h | 150 + db/include/qam_auto.h | 129 + db/include/qam_ext.h | 56 + db/include/queue.h | 319 + db/include/region.h | 292 + db/include/rpc_client_ext.h | 19 + db/include/rpc_server_ext.h | 21 + db/include/shqueue.h | 337 + db/include/tcl_db.h | 219 + db/include/tcl_ext.h | 89 + db/include/txn.h | 150 + db/include/txn_auto.h | 114 + db/include/txn_ext.h | 24 + db/include/xa.h | 179 + db/include/xa_ext.h | 17 + db/java/src/com/sleepycat/db/Db.java | 710 ++ db/java/src/com/sleepycat/db/DbAppendRecno.java | 22 + db/java/src/com/sleepycat/db/DbBtreeCompare.java | 21 + db/java/src/com/sleepycat/db/DbBtreePrefix.java | 21 + db/java/src/com/sleepycat/db/DbBtreeStat.java | 40 + db/java/src/com/sleepycat/db/DbConstants.java | 217 + .../src/com/sleepycat/db/DbDeadlockException.java | 28 + db/java/src/com/sleepycat/db/DbDupCompare.java | 21 + db/java/src/com/sleepycat/db/DbEnv.java | 392 + db/java/src/com/sleepycat/db/DbEnvFeedback.java | 19 + db/java/src/com/sleepycat/db/DbErrcall.java | 23 + db/java/src/com/sleepycat/db/DbException.java | 56 + db/java/src/com/sleepycat/db/DbFeedback.java | 23 + db/java/src/com/sleepycat/db/DbHash.java | 21 + db/java/src/com/sleepycat/db/DbHashStat.java | 37 + db/java/src/com/sleepycat/db/DbKeyRange.java | 23 + db/java/src/com/sleepycat/db/DbLock.java | 38 + db/java/src/com/sleepycat/db/DbLockStat.java | 30 + db/java/src/com/sleepycat/db/DbLogStat.java | 35 + db/java/src/com/sleepycat/db/DbLsn.java | 42 + .../src/com/sleepycat/db/DbMemoryException.java | 28 + db/java/src/com/sleepycat/db/DbMpoolFStat.java | 28 + db/java/src/com/sleepycat/db/DbMpoolStat.java | 42 + .../com/sleepycat/db/DbOutputStreamErrcall.java | 58 + db/java/src/com/sleepycat/db/DbQueueStat.java | 32 + db/java/src/com/sleepycat/db/DbRecoveryInit.java | 23 + .../com/sleepycat/db/DbRunRecoveryException.java | 32 + db/java/src/com/sleepycat/db/DbTxn.java | 47 + db/java/src/com/sleepycat/db/DbTxnRecover.java | 22 + db/java/src/com/sleepycat/db/DbTxnStat.java | 40 + db/java/src/com/sleepycat/db/Dbc.java | 56 + db/java/src/com/sleepycat/db/Dbt.java | 110 + .../src/com/sleepycat/examples/AccessExample.java | 186 + .../src/com/sleepycat/examples/BtRecExample.java | 348 + db/java/src/com/sleepycat/examples/EnvExample.java | 128 + .../src/com/sleepycat/examples/LockExample.java | 235 + .../src/com/sleepycat/examples/TpcbExample.java | 831 ++ db/libdb_java/checkapi.prl | 132 + db/libdb_java/com_sleepycat_db_Db.h | 349 + db/libdb_java/com_sleepycat_db_DbEnv.h | 509 + db/libdb_java/com_sleepycat_db_DbLock.h | 29 + db/libdb_java/com_sleepycat_db_DbLsn.h | 29 + db/libdb_java/com_sleepycat_db_DbTxn.h | 53 + db/libdb_java/com_sleepycat_db_Dbc.h | 69 + db/libdb_java/com_sleepycat_db_Dbt.h | 157 + db/libdb_java/java_Db.c | 964 ++ db/libdb_java/java_DbEnv.c | 1300 ++ db/libdb_java/java_DbLock.c | 55 + db/libdb_java/java_DbLsn.c | 43 + db/libdb_java/java_DbTxn.c | 82 + db/libdb_java/java_Dbc.c | 196 + db/libdb_java/java_Dbt.c | 176 + db/libdb_java/java_info.c | 1001 ++ db/libdb_java/java_info.h | 200 + db/libdb_java/java_locked.c | 294 + db/libdb_java/java_locked.h | 98 + db/libdb_java/java_util.c | 556 + db/libdb_java/java_util.h | 359 + db/lock/Design | 293 + db/lock/lock.c | 1439 +++ db/lock/lock_conflict.c | 34 + db/lock/lock_deadlock.c | 637 + db/lock/lock_method.c | 148 + db/lock/lock_region.c | 430 + db/lock/lock_stat.c | 308 + db/lock/lock_util.c | 138 + db/log/log.c | 653 + db/log/log.src | 46 + db/log/log_archive.c | 447 + db/log/log_auto.c | 326 + db/log/log_compare.c | 34 + db/log/log_findckp.c | 135 + db/log/log_get.c | 465 + db/log/log_method.c | 121 + db/log/log_put.c | 701 ++ db/log/log_rec.c | 621 + db/log/log_register.c | 433 + db/mp/Design | 52 + db/mp/mp_alloc.c | 152 + db/mp/mp_bh.c | 662 + db/mp/mp_fget.c | 417 + db/mp/mp_fopen.c | 756 ++ db/mp/mp_fput.c | 186 + db/mp/mp_fset.c | 98 + db/mp/mp_method.c | 115 + db/mp/mp_region.c | 357 + db/mp/mp_register.c | 85 + db/mp/mp_stat.c | 388 + db/mp/mp_sync.c | 658 + db/mp/mp_trickle.c | 149 + db/mutex/README | 108 + db/mutex/mut_fcntl.c | 174 + db/mutex/mut_pthread.c | 328 + db/mutex/mut_tas.c | 200 + db/mutex/mutex.c | 253 + db/mutex/uts4_cc.s | 21 + db/os/os_abs.c | 31 + db/os/os_alloc.c | 342 + db/os/os_dir.c | 108 + db/os/os_errno.c | 44 + db/os/os_fid.c | 140 + db/os/os_finit.c | 111 + db/os/os_fsync.c | 90 + db/os/os_handle.c | 165 + db/os/os_map.c | 436 + db/os/os_method.c | 206 + db/os/os_oflags.c | 106 + db/os/os_open.c | 226 + db/os/os_region.c | 116 + db/os/os_rename.c | 46 + db/os/os_root.c | 36 + db/os/os_rpath.c | 69 + db/os/os_rw.c | 147 + db/os/os_seek.c | 76 + db/os/os_sleep.c | 77 + db/os/os_spin.c | 109 + db/os/os_stat.c | 108 + db/os/os_tmpdir.c | 119 + db/os/os_unlink.c | 106 + db/os_vxworks/os_abs.c | 45 + db/os_vxworks/os_finit.c | 57 + db/os_vxworks/os_map.c | 440 + db/os_win32/os_abs.c | 33 + db/os_win32/os_dir.c | 82 + db/os_win32/os_errno.c | 146 + db/os_win32/os_fid.c | 145 + db/os_win32/os_finit.c | 60 + db/os_win32/os_map.c | 310 + db/os_win32/os_open.c | 201 + db/os_win32/os_rename.c | 57 + db/os_win32/os_seek.c | 65 + db/os_win32/os_sleep.c | 41 + db/os_win32/os_spin.c | 59 + db/os_win32/os_type.c | 35 + db/perl.BerkeleyDB/BerkeleyDB.pm | 1227 ++ db/perl.BerkeleyDB/BerkeleyDB.pod | 1751 +++ db/perl.BerkeleyDB/BerkeleyDB.pod.P | 1518 +++ db/perl.BerkeleyDB/BerkeleyDB.xs | 3927 ++++++ db/perl.BerkeleyDB/BerkeleyDB/Btree.pm | 8 + db/perl.BerkeleyDB/BerkeleyDB/Hash.pm | 8 + db/perl.BerkeleyDB/Changes | 112 + db/perl.BerkeleyDB/MANIFEST | 49 + db/perl.BerkeleyDB/Makefile.PL | 112 + db/perl.BerkeleyDB/README | 464 + db/perl.BerkeleyDB/Todo | 57 + db/perl.BerkeleyDB/config.in | 51 + db/perl.BerkeleyDB/dbinfo | 109 + db/perl.BerkeleyDB/hints/irix_6_5.pl | 1 + db/perl.BerkeleyDB/hints/solaris.pl | 1 + db/perl.BerkeleyDB/mkconsts | 211 + db/perl.BerkeleyDB/mkpod | 146 + db/perl.BerkeleyDB/patches/5.004 | 44 + db/perl.BerkeleyDB/patches/5.004_01 | 217 + db/perl.BerkeleyDB/patches/5.004_02 | 217 + db/perl.BerkeleyDB/patches/5.004_03 | 223 + db/perl.BerkeleyDB/patches/5.004_04 | 209 + db/perl.BerkeleyDB/patches/5.004_05 | 209 + db/perl.BerkeleyDB/patches/5.005 | 209 + db/perl.BerkeleyDB/patches/5.005_01 | 209 + db/perl.BerkeleyDB/patches/5.005_02 | 264 + db/perl.BerkeleyDB/patches/5.005_03 | 250 + db/perl.BerkeleyDB/patches/5.6.0 | 294 + db/perl.BerkeleyDB/t/btree.t | 976 ++ db/perl.BerkeleyDB/t/db-3.0.t | 128 + db/perl.BerkeleyDB/t/db-3.1.t | 172 + db/perl.BerkeleyDB/t/db-3.2.t | 90 + db/perl.BerkeleyDB/t/destroy.t | 141 + db/perl.BerkeleyDB/t/env.t | 279 + db/perl.BerkeleyDB/t/examples.t | 482 + db/perl.BerkeleyDB/t/examples.t.T | 496 + db/perl.BerkeleyDB/t/examples3.t | 213 + db/perl.BerkeleyDB/t/examples3.t.T | 217 + db/perl.BerkeleyDB/t/filter.t | 244 + db/perl.BerkeleyDB/t/hash.t | 777 ++ db/perl.BerkeleyDB/t/join.t | 270 + db/perl.BerkeleyDB/t/mldbm.t | 166 + db/perl.BerkeleyDB/t/queue.t | 837 ++ db/perl.BerkeleyDB/t/recno.t | 967 ++ db/perl.BerkeleyDB/t/strict.t | 220 + db/perl.BerkeleyDB/t/subdb.t | 296 + db/perl.BerkeleyDB/t/txn.t | 354 + db/perl.BerkeleyDB/t/unknown.t | 212 + db/perl.BerkeleyDB/typemap | 275 + db/perl.DB_File/Changes | 343 + db/perl.DB_File/DB_File.pm | 2072 ++++ db/perl.DB_File/DB_File.xs | 2072 ++++ db/perl.DB_File/DB_File_BS | 6 + db/perl.DB_File/MANIFEST | 27 + db/perl.DB_File/Makefile.PL | 187 + db/perl.DB_File/README | 396 + db/perl.DB_File/config.in | 99 + db/perl.DB_File/dbinfo | 109 + db/perl.DB_File/hints/dynixptx.pl | 3 + db/perl.DB_File/hints/sco.pl | 2 + db/perl.DB_File/patches/5.004 | 44 + db/perl.DB_File/patches/5.004_01 | 217 + db/perl.DB_File/patches/5.004_02 | 217 + db/perl.DB_File/patches/5.004_03 | 223 + db/perl.DB_File/patches/5.004_04 | 209 + db/perl.DB_File/patches/5.004_05 | 209 + db/perl.DB_File/patches/5.005 | 209 + db/perl.DB_File/patches/5.005_01 | 209 + db/perl.DB_File/patches/5.005_02 | 264 + db/perl.DB_File/patches/5.005_03 | 250 + db/perl.DB_File/patches/5.6.0 | 294 + db/perl.DB_File/t/db-btree.t | 1306 ++ db/perl.DB_File/t/db-hash.t | 753 ++ db/perl.DB_File/t/db-recno.t | 899 ++ db/perl.DB_File/typemap | 44 + db/perl.DB_File/version.c | 81 + db/qam/qam.c | 1357 ++ db/qam/qam.src | 124 + db/qam/qam_auto.c | 1282 ++ db/qam/qam_conv.c | 83 + db/qam/qam_files.c | 503 + db/qam/qam_method.c | 472 + db/qam/qam_open.c | 268 + db/qam/qam_rec.c | 732 ++ db/qam/qam_stat.c | 201 + db/qam/qam_upgrade.c | 111 + db/qam/qam_verify.c | 194 + db/rpc_client/client.c | 371 + db/rpc_client/db_server_clnt.c | 692 ++ db/rpc_client/gen_client.c | 2494 ++++ db/rpc_client/gen_client_ret.c | 542 + db/rpc_server/clsrv.html | 453 + db/rpc_server/db_server.sed | 5 + db/rpc_server/db_server.x | 492 + db/rpc_server/db_server_proc.c | 1546 +++ db/rpc_server/db_server_proc.sed | 418 + db/rpc_server/db_server_svc.c | 359 + db/rpc_server/db_server_svc.sed | 5 + db/rpc_server/db_server_util.c | 612 + db/rpc_server/db_server_xdr.c | 1149 ++ db/rpc_server/gen_db_server.c | 703 ++ db/rpc_server/rpc.src | 599 + db/tcl/docs/db.html | 266 + db/tcl/docs/env.html | 303 + db/tcl/docs/historic.html | 168 + db/tcl/docs/index.html | 47 + db/tcl/docs/library.html | 26 + db/tcl/docs/lock.html | 187 + db/tcl/docs/log.html | 142 + db/tcl/docs/mpool.html | 189 + db/tcl/docs/test.html | 149 + db/tcl/docs/txn.html | 56 + db/tcl/tcl_compat.c | 1055 ++ db/tcl/tcl_db.c | 1771 +++ db/tcl/tcl_db_pkg.c | 2246 ++++ db/tcl/tcl_dbcursor.c | 744 ++ db/tcl/tcl_env.c | 678 + db/tcl/tcl_internal.c | 440 + db/tcl/tcl_lock.c | 655 + db/tcl/tcl_log.c | 581 + db/tcl/tcl_mp.c | 822 ++ db/tcl/tcl_txn.c | 473 + db/test/TESTS | 448 + db/test/archive.tcl | 232 + db/test/byteorder.tcl | 23 + db/test/conscript.tcl | 123 + db/test/dbm.tcl | 128 + db/test/dbscript.tcl | 357 + db/test/ddscript.tcl | 43 + db/test/dead001.tcl | 76 + db/test/dead002.tcl | 68 + db/test/dead003.tcl | 92 + db/test/env001.tcl | 147 + db/test/env002.tcl | 156 + db/test/env003.tcl | 177 + db/test/env004.tcl | 103 + db/test/env005.tcl | 53 + db/test/env006.tcl | 42 + db/test/env007.tcl | 100 + db/test/env008.tcl | 73 + db/test/hsearch.tcl | 51 + db/test/include.tcl | 19 + db/test/join.tcl | 451 + db/test/lock001.tcl | 170 + db/test/lock002.tcl | 151 + db/test/lock003.tcl | 48 + db/test/lockscript.tcl | 88 + db/test/log.tcl | 337 + db/test/logtrack.list | 68 + db/test/logtrack.tcl | 130 + db/test/mdbscript.tcl | 381 + db/test/mpool.tcl | 420 + db/test/mpoolscript.tcl | 170 + db/test/mutex.tcl | 225 + db/test/mutexscript.tcl | 91 + db/test/ndbm.tcl | 141 + db/test/recd001.tcl | 180 + db/test/recd002.tcl | 96 + db/test/recd003.tcl | 111 + db/test/recd004.tcl | 90 + db/test/recd005.tcl | 231 + db/test/recd006.tcl | 262 + db/test/recd007.tcl | 723 ++ db/test/recd008.tcl | 227 + db/test/recd009.tcl | 181 + db/test/recd010.tcl | 235 + db/test/recd011.tcl | 115 + db/test/recd012.tcl | 423 + db/test/recd013.tcl | 244 + db/test/recd014.tcl | 467 + db/test/rpc001.tcl | 444 + db/test/rpc002.tcl | 144 + db/test/rsrc001.tcl | 223 + db/test/rsrc002.tcl | 65 + db/test/rsrc003.tcl | 174 + db/test/sdb001.tcl | 123 + db/test/sdb002.tcl | 167 + db/test/sdb003.tcl | 137 + db/test/sdb004.tcl | 179 + db/test/sdb005.tcl | 109 + db/test/sdb006.tcl | 130 + db/test/sdb007.tcl | 123 + db/test/sdb008.tcl | 151 + db/test/sdb009.tcl | 77 + db/test/sdb010.tcl | 46 + db/test/sdbscript.tcl | 47 + db/test/sdbtest001.tcl | 133 + db/test/sdbtest002.tcl | 163 + db/test/sdbutils.tcl | 171 + db/test/sysscript.tcl | 283 + db/test/test.tcl | 1297 ++ db/test/test001.tcl | 157 + db/test/test002.tcl | 128 + db/test/test003.tcl | 177 + db/test/test004.tcl | 134 + db/test/test005.tcl | 14 + db/test/test006.tcl | 118 + db/test/test007.tcl | 13 + db/test/test008.tcl | 138 + db/test/test009.tcl | 15 + db/test/test010.tcl | 126 + db/test/test011.tcl | 349 + db/test/test012.tcl | 113 + db/test/test013.tcl | 193 + db/test/test014.tcl | 204 + db/test/test015.tcl | 235 + db/test/test016.tcl | 170 + db/test/test017.tcl | 237 + db/test/test018.tcl | 13 + db/test/test019.tcl | 107 + db/test/test020.tcl | 108 + db/test/test021.tcl | 130 + db/test/test022.tcl | 55 + db/test/test023.tcl | 204 + db/test/test024.tcl | 206 + db/test/test025.tcl | 105 + db/test/test026.tcl | 112 + db/test/test027.tcl | 13 + db/test/test028.tcl | 208 + db/test/test029.tcl | 192 + db/test/test030.tcl | 191 + db/test/test031.tcl | 196 + db/test/test032.tcl | 195 + db/test/test033.tcl | 103 + db/test/test034.tcl | 16 + db/test/test035.tcl | 16 + db/test/test036.tcl | 135 + db/test/test037.tcl | 191 + db/test/test038.tcl | 174 + db/test/test039.tcl | 177 + db/test/test040.tcl | 16 + db/test/test041.tcl | 16 + db/test/test042.tcl | 149 + db/test/test043.tcl | 162 + db/test/test044.tcl | 243 + db/test/test045.tcl | 117 + db/test/test046.tcl | 717 ++ db/test/test047.tcl | 192 + db/test/test048.tcl | 139 + db/test/test049.tcl | 160 + db/test/test050.tcl | 191 + db/test/test051.tcl | 191 + db/test/test052.tcl | 254 + db/test/test053.tcl | 194 + db/test/test054.tcl | 369 + db/test/test055.tcl | 118 + db/test/test056.tcl | 145 + db/test/test057.tcl | 225 + db/test/test058.tcl | 99 + db/test/test059.tcl | 128 + db/test/test060.tcl | 53 + db/test/test061.tcl | 215 + db/test/test062.tcl | 125 + db/test/test063.tcl | 141 + db/test/test064.tcl | 62 + db/test/test065.tcl | 146 + db/test/test066.tcl | 73 + db/test/test067.tcl | 114 + db/test/test068.tcl | 181 + db/test/test069.tcl | 14 + db/test/test070.tcl | 120 + db/test/test071.tcl | 15 + db/test/test072.tcl | 225 + db/test/test073.tcl | 265 + db/test/test074.tcl | 221 + db/test/test075.tcl | 195 + db/test/test076.tcl | 59 + db/test/test077.tcl | 68 + db/test/test078.tcl | 90 + db/test/test079.tcl | 18 + db/test/test080.tcl | 41 + db/test/test081.tcl | 16 + db/test/test082.tcl | 15 + db/test/test083.tcl | 136 + db/test/test084.tcl | 48 + db/test/test085.tcl | 274 + db/test/test086.tcl | 162 + db/test/test087.tcl | 278 + db/test/test088.tcl | 142 + db/test/test090.tcl | 20 + db/test/test091.tcl | 21 + db/test/testparams.tcl | 115 + db/test/testutils.tcl | 2380 ++++ db/test/txn.tcl | 181 + db/test/update.tcl | 92 + db/test/upgrade.tcl | 279 + db/test/upgrade/README | 85 + db/test/upgrade/generate-2.X/pack-2.6.6.pl | 114 + db/test/upgrade/generate-2.X/test-2.6.patch | 379 + db/test/wordlist | 10001 +++++++++++++++ db/test/wrap.tcl | 58 + db/txn/txn.c | 869 ++ db/txn/txn.src | 114 + db/txn/txn_auto.c | 893 ++ db/txn/txn_rec.c | 339 + db/txn/txn_region.c | 393 + db/xa/xa.c | 661 + db/xa/xa_db.c | 182 + db/xa/xa_map.c | 189 + 1446 files changed, 333303 insertions(+) create mode 100644 db/LICENSE create mode 100644 db/README create mode 100644 db/btree/bt_compare.c create mode 100644 db/btree/bt_conv.c create mode 100644 db/btree/bt_curadj.c create mode 100644 db/btree/bt_cursor.c create mode 100644 db/btree/bt_delete.c create mode 100644 db/btree/bt_method.c create mode 100644 db/btree/bt_open.c create mode 100644 db/btree/bt_put.c create mode 100644 db/btree/bt_rec.c create mode 100644 db/btree/bt_reclaim.c create mode 100644 db/btree/bt_recno.c create mode 100644 db/btree/bt_rsearch.c create mode 100644 db/btree/bt_search.c create mode 100644 db/btree/bt_split.c create mode 100644 db/btree/bt_stat.c create mode 100644 db/btree/bt_upgrade.c create mode 100644 db/btree/bt_verify.c create mode 100644 db/btree/btree.src create mode 100644 db/btree/btree_auto.c create mode 100644 db/build_unix/.IGNORE_ME create mode 100644 db/build_vxworks/BerkeleyDB.wpj create mode 100644 db/build_vxworks/BerkeleyDB.wsp create mode 100644 db/build_vxworks/db.h create mode 100644 db/build_vxworks/db_config.h create mode 100644 db/build_vxworks/db_int.h create mode 100644 db/build_vxworks/ex_access/ex_access.wpj create mode 100644 db/build_vxworks/ex_btrec/ex_btrec.wpj create mode 100644 db/build_vxworks/ex_dbclient/ex_dbclient.wpj create mode 100644 db/build_vxworks/ex_env/ex_env.wpj create mode 100644 db/build_vxworks/ex_mpool/ex_mpool.wpj create mode 100644 db/build_vxworks/ex_tpcb/ex_tpcb.wpj create mode 100644 db/build_win32/Berkeley_DB.dsw create mode 100644 db/build_win32/app_dsp.src create mode 100644 db/build_win32/db.h create mode 100644 db/build_win32/db_archive.dsp create mode 100644 db/build_win32/db_buildall.dsp create mode 100644 db/build_win32/db_checkpoint.dsp create mode 100644 db/build_win32/db_config.h create mode 100644 db/build_win32/db_deadlock.dsp create mode 100644 db/build_win32/db_dll.dsp create mode 100644 db/build_win32/db_dump.dsp create mode 100644 db/build_win32/db_int.h create mode 100644 db/build_win32/db_java.dsp create mode 100644 db/build_win32/db_load.dsp create mode 100644 db/build_win32/db_printlog.dsp create mode 100644 db/build_win32/db_recover.dsp create mode 100644 db/build_win32/db_stat.dsp create mode 100644 db/build_win32/db_static.dsp create mode 100644 db/build_win32/db_tcl.dsp create mode 100644 db/build_win32/db_test.dsp create mode 100644 db/build_win32/db_upgrade.dsp create mode 100644 db/build_win32/db_verify.dsp create mode 100644 db/build_win32/dbkill.cpp create mode 100644 db/build_win32/dllmain.c create mode 100644 db/build_win32/dynamic_dsp.src create mode 100644 db/build_win32/ex_access.dsp create mode 100644 db/build_win32/ex_btrec.dsp create mode 100644 db/build_win32/ex_env.dsp create mode 100644 db/build_win32/ex_lock.dsp create mode 100644 db/build_win32/ex_mpool.dsp create mode 100644 db/build_win32/ex_tpcb.dsp create mode 100644 db/build_win32/excxx_access.dsp create mode 100644 db/build_win32/excxx_btrec.dsp create mode 100644 db/build_win32/excxx_env.dsp create mode 100644 db/build_win32/excxx_lock.dsp create mode 100644 db/build_win32/excxx_mpool.dsp create mode 100644 db/build_win32/excxx_tpcb.dsp create mode 100644 db/build_win32/include.tcl create mode 100644 db/build_win32/java_dsp.src create mode 100644 db/build_win32/libdb.def create mode 100644 db/build_win32/libdb.rc create mode 100644 db/build_win32/libdb_tcl.def create mode 100644 db/build_win32/libdbrc.src create mode 100644 db/build_win32/srcfile_dsp.src create mode 100644 db/build_win32/static_dsp.src create mode 100644 db/build_win32/tcl_dsp.src create mode 100644 db/clib/getcwd.c create mode 100644 db/clib/getopt.c create mode 100644 db/clib/memcmp.c create mode 100644 db/clib/memmove.c create mode 100644 db/clib/raise.c create mode 100644 db/clib/snprintf.c create mode 100644 db/clib/strcasecmp.c create mode 100644 db/clib/strerror.c create mode 100644 db/clib/vsnprintf.c create mode 100644 db/common/db_byteorder.c create mode 100644 db/common/db_err.c create mode 100644 db/common/db_getlong.c create mode 100644 db/common/db_log2.c create mode 100644 db/common/util_log.c create mode 100644 db/common/util_sig.c create mode 100644 db/cxx/cxx_app.cpp create mode 100644 db/cxx/cxx_except.cpp create mode 100644 db/cxx/cxx_lock.cpp create mode 100644 db/cxx/cxx_log.cpp create mode 100644 db/cxx/cxx_mpool.cpp create mode 100644 db/cxx/cxx_table.cpp create mode 100644 db/cxx/cxx_txn.cpp create mode 100644 db/cxx/namemap.txt create mode 100644 db/db/Design.fileop create mode 100644 db/db/crdel.src create mode 100644 db/db/crdel_auto.c create mode 100644 db/db/crdel_rec.c create mode 100644 db/db/db.c create mode 100644 db/db/db.src create mode 100644 db/db/db_am.c create mode 100644 db/db/db_auto.c create mode 100644 db/db/db_cam.c create mode 100644 db/db/db_conv.c create mode 100644 db/db/db_dispatch.c create mode 100644 db/db/db_dup.c create mode 100644 db/db/db_iface.c create mode 100644 db/db/db_join.c create mode 100644 db/db/db_meta.c create mode 100644 db/db/db_method.c create mode 100644 db/db/db_overflow.c create mode 100644 db/db/db_pr.c create mode 100644 db/db/db_rec.c create mode 100644 db/db/db_reclaim.c create mode 100644 db/db/db_ret.c create mode 100644 db/db/db_upg.c create mode 100644 db/db/db_upg_opd.c create mode 100644 db/db/db_vrfy.c create mode 100644 db/db/db_vrfyutil.c create mode 100644 db/db185/db185.c create mode 100644 db/db185/db185_int.h create mode 100644 db/db_archive/db_archive.c create mode 100644 db/db_checkpoint/db_checkpoint.c create mode 100644 db/db_deadlock/db_deadlock.c create mode 100644 db/db_dump/db_dump.c create mode 100644 db/db_dump185/db_dump185.c create mode 100644 db/db_load/db_load.c create mode 100644 db/db_printlog/README create mode 100644 db/db_printlog/commit.awk create mode 100644 db/db_printlog/count.awk create mode 100644 db/db_printlog/db_printlog.c create mode 100644 db/db_printlog/dbname.awk create mode 100644 db/db_printlog/fileid.awk create mode 100644 db/db_printlog/pgno.awk create mode 100644 db/db_printlog/range.awk create mode 100644 db/db_printlog/rectype.awk create mode 100644 db/db_printlog/status.awk create mode 100644 db/db_printlog/txn.awk create mode 100644 db/db_recover/db_recover.c create mode 100644 db/db_stat/db_stat.c create mode 100644 db/db_upgrade/db_upgrade.c create mode 100644 db/db_verify/db_verify.c create mode 100644 db/dbm/dbm.c create mode 100644 db/dist/Makefile.in create mode 100644 db/dist/RELEASE create mode 100644 db/dist/acconfig.h create mode 100644 db/dist/aclocal/mutex.m4 create mode 100644 db/dist/aclocal/options.m4 create mode 100644 db/dist/aclocal/programs.m4 create mode 100644 db/dist/aclocal/tcl.m4 create mode 100644 db/dist/aclocal/types.m4 create mode 100755 db/dist/build/chk.def create mode 100755 db/dist/build/chk.define create mode 100755 db/dist/build/chk.offt create mode 100755 db/dist/build/chk.srcfiles create mode 100755 db/dist/build/chk.tags create mode 100644 db/dist/build/script create mode 100755 db/dist/config.guess create mode 100644 db/dist/config.hin create mode 100755 db/dist/config.sub create mode 100755 db/dist/configure create mode 100644 db/dist/configure.in create mode 100644 db/dist/gen_rec.awk create mode 100644 db/dist/gen_rpc.awk create mode 100755 db/dist/install-sh create mode 100644 db/dist/ltconfig create mode 100644 db/dist/ltmain.sh create mode 100644 db/dist/rec_ctemp create mode 100644 db/dist/s_all create mode 100755 db/dist/s_config create mode 100755 db/dist/s_include create mode 100755 db/dist/s_java create mode 100755 db/dist/s_perm create mode 100755 db/dist/s_readme create mode 100755 db/dist/s_recover create mode 100644 db/dist/s_rpc create mode 100755 db/dist/s_symlink create mode 100755 db/dist/s_tags create mode 100755 db/dist/s_tcl create mode 100644 db/dist/s_vxworks create mode 100755 db/dist/s_win32 create mode 100644 db/dist/s_win32_dsp create mode 100644 db/dist/srcfiles.in create mode 100644 db/dist/template/db_server_proc create mode 100644 db/dist/template/gen_client_ret create mode 100644 db/dist/template/rec_btree create mode 100644 db/dist/template/rec_crdel create mode 100644 db/dist/template/rec_db create mode 100644 db/dist/template/rec_hash create mode 100644 db/dist/template/rec_log create mode 100644 db/dist/template/rec_qam create mode 100644 db/dist/template/rec_txn create mode 100644 db/docs/api_c/c_index.html create mode 100644 db/docs/api_c/c_pindex.html create mode 100644 db/docs/api_c/db_close.html create mode 100644 db/docs/api_c/db_create.html create mode 100644 db/docs/api_c/db_cursor.html create mode 100644 db/docs/api_c/db_del.html create mode 100644 db/docs/api_c/db_err.html create mode 100644 db/docs/api_c/db_fd.html create mode 100644 db/docs/api_c/db_get.html create mode 100644 db/docs/api_c/db_get_byteswapped.html create mode 100644 db/docs/api_c/db_get_type.html create mode 100644 db/docs/api_c/db_join.html create mode 100644 db/docs/api_c/db_key_range.html create mode 100644 db/docs/api_c/db_lsn.html create mode 100644 db/docs/api_c/db_open.html create mode 100644 db/docs/api_c/db_put.html create mode 100644 db/docs/api_c/db_remove.html create mode 100644 db/docs/api_c/db_rename.html create mode 100644 db/docs/api_c/db_set_append_recno.html create mode 100644 db/docs/api_c/db_set_bt_compare.html create mode 100644 db/docs/api_c/db_set_bt_minkey.html create mode 100644 db/docs/api_c/db_set_bt_prefix.html create mode 100644 db/docs/api_c/db_set_cachesize.html create mode 100644 db/docs/api_c/db_set_dup_compare.html create mode 100644 db/docs/api_c/db_set_errcall.html create mode 100644 db/docs/api_c/db_set_errfile.html create mode 100644 db/docs/api_c/db_set_errpfx.html create mode 100644 db/docs/api_c/db_set_feedback.html create mode 100644 db/docs/api_c/db_set_flags.html create mode 100644 db/docs/api_c/db_set_h_ffactor.html create mode 100644 db/docs/api_c/db_set_h_hash.html create mode 100644 db/docs/api_c/db_set_h_nelem.html create mode 100644 db/docs/api_c/db_set_lorder.html create mode 100644 db/docs/api_c/db_set_malloc.html create mode 100644 db/docs/api_c/db_set_pagesize.html create mode 100644 db/docs/api_c/db_set_paniccall.html create mode 100644 db/docs/api_c/db_set_q_extentsize.html create mode 100644 db/docs/api_c/db_set_re_delim.html create mode 100644 db/docs/api_c/db_set_re_len.html create mode 100644 db/docs/api_c/db_set_re_pad.html create mode 100644 db/docs/api_c/db_set_re_source.html create mode 100644 db/docs/api_c/db_set_realloc.html create mode 100644 db/docs/api_c/db_stat.html create mode 100644 db/docs/api_c/db_sync.html create mode 100644 db/docs/api_c/db_upgrade.html create mode 100644 db/docs/api_c/db_verify.html create mode 100644 db/docs/api_c/dbc_close.html create mode 100644 db/docs/api_c/dbc_count.html create mode 100644 db/docs/api_c/dbc_del.html create mode 100644 db/docs/api_c/dbc_dup.html create mode 100644 db/docs/api_c/dbc_get.html create mode 100644 db/docs/api_c/dbc_put.html create mode 100644 db/docs/api_c/dbm.html create mode 100644 db/docs/api_c/dbt.html create mode 100644 db/docs/api_c/env_close.html create mode 100644 db/docs/api_c/env_create.html create mode 100644 db/docs/api_c/env_open.html create mode 100644 db/docs/api_c/env_remove.html create mode 100644 db/docs/api_c/env_set_cachesize.html create mode 100644 db/docs/api_c/env_set_data_dir.html create mode 100644 db/docs/api_c/env_set_errcall.html create mode 100644 db/docs/api_c/env_set_errfile.html create mode 100644 db/docs/api_c/env_set_errpfx.html create mode 100644 db/docs/api_c/env_set_feedback.html create mode 100644 db/docs/api_c/env_set_flags.html create mode 100644 db/docs/api_c/env_set_lg_bsize.html create mode 100644 db/docs/api_c/env_set_lg_dir.html create mode 100644 db/docs/api_c/env_set_lg_max.html create mode 100644 db/docs/api_c/env_set_lk_conflicts.html create mode 100644 db/docs/api_c/env_set_lk_detect.html create mode 100644 db/docs/api_c/env_set_lk_max.html create mode 100644 db/docs/api_c/env_set_lk_max_lockers.html create mode 100644 db/docs/api_c/env_set_lk_max_locks.html create mode 100644 db/docs/api_c/env_set_lk_max_objects.html create mode 100644 db/docs/api_c/env_set_mp_mmapsize.html create mode 100644 db/docs/api_c/env_set_mutexlocks.html create mode 100644 db/docs/api_c/env_set_pageyield.html create mode 100644 db/docs/api_c/env_set_paniccall.html create mode 100644 db/docs/api_c/env_set_panicstate.html create mode 100644 db/docs/api_c/env_set_rec_init.html create mode 100644 db/docs/api_c/env_set_region_init.html create mode 100644 db/docs/api_c/env_set_server.html create mode 100644 db/docs/api_c/env_set_shm_key.html create mode 100644 db/docs/api_c/env_set_tas_spins.html create mode 100644 db/docs/api_c/env_set_tmp_dir.html create mode 100644 db/docs/api_c/env_set_tx_max.html create mode 100644 db/docs/api_c/env_set_tx_recover.html create mode 100644 db/docs/api_c/env_set_tx_timestamp.html create mode 100644 db/docs/api_c/env_set_verbose.html create mode 100644 db/docs/api_c/env_strerror.html create mode 100644 db/docs/api_c/env_version.html create mode 100644 db/docs/api_c/hsearch.html create mode 100644 db/docs/api_c/lock_detect.html create mode 100644 db/docs/api_c/lock_get.html create mode 100644 db/docs/api_c/lock_id.html create mode 100644 db/docs/api_c/lock_put.html create mode 100644 db/docs/api_c/lock_stat.html create mode 100644 db/docs/api_c/lock_vec.html create mode 100644 db/docs/api_c/log_archive.html create mode 100644 db/docs/api_c/log_compare.html create mode 100644 db/docs/api_c/log_file.html create mode 100644 db/docs/api_c/log_flush.html create mode 100644 db/docs/api_c/log_get.html create mode 100644 db/docs/api_c/log_put.html create mode 100644 db/docs/api_c/log_register.html create mode 100644 db/docs/api_c/log_stat.html create mode 100644 db/docs/api_c/log_unregister.html create mode 100644 db/docs/api_c/memp_fclose.html create mode 100644 db/docs/api_c/memp_fget.html create mode 100644 db/docs/api_c/memp_fopen.html create mode 100644 db/docs/api_c/memp_fput.html create mode 100644 db/docs/api_c/memp_fset.html create mode 100644 db/docs/api_c/memp_fsync.html create mode 100644 db/docs/api_c/memp_register.html create mode 100644 db/docs/api_c/memp_stat.html create mode 100644 db/docs/api_c/memp_sync.html create mode 100644 db/docs/api_c/memp_trickle.html create mode 100644 db/docs/api_c/pindex.src create mode 100644 db/docs/api_c/set_func_close.html create mode 100644 db/docs/api_c/set_func_dirfree.html create mode 100644 db/docs/api_c/set_func_dirlist.html create mode 100644 db/docs/api_c/set_func_exists.html create mode 100644 db/docs/api_c/set_func_free.html create mode 100644 db/docs/api_c/set_func_fsync.html create mode 100644 db/docs/api_c/set_func_ioinfo.html create mode 100644 db/docs/api_c/set_func_malloc.html create mode 100644 db/docs/api_c/set_func_map.html create mode 100644 db/docs/api_c/set_func_open.html create mode 100644 db/docs/api_c/set_func_read.html create mode 100644 db/docs/api_c/set_func_realloc.html create mode 100644 db/docs/api_c/set_func_rename.html create mode 100644 db/docs/api_c/set_func_seek.html create mode 100644 db/docs/api_c/set_func_sleep.html create mode 100644 db/docs/api_c/set_func_unlink.html create mode 100644 db/docs/api_c/set_func_unmap.html create mode 100644 db/docs/api_c/set_func_write.html create mode 100644 db/docs/api_c/set_func_yield.html create mode 100644 db/docs/api_c/txn_abort.html create mode 100644 db/docs/api_c/txn_begin.html create mode 100644 db/docs/api_c/txn_checkpoint.html create mode 100644 db/docs/api_c/txn_commit.html create mode 100644 db/docs/api_c/txn_id.html create mode 100644 db/docs/api_c/txn_prepare.html create mode 100644 db/docs/api_c/txn_stat.html create mode 100644 db/docs/api_cxx/cxx_index.html create mode 100644 db/docs/api_cxx/cxx_pindex.html create mode 100644 db/docs/api_cxx/db_class.html create mode 100644 db/docs/api_cxx/db_close.html create mode 100644 db/docs/api_cxx/db_cursor.html create mode 100644 db/docs/api_cxx/db_del.html create mode 100644 db/docs/api_cxx/db_err.html create mode 100644 db/docs/api_cxx/db_fd.html create mode 100644 db/docs/api_cxx/db_get.html create mode 100644 db/docs/api_cxx/db_get_byteswapped.html create mode 100644 db/docs/api_cxx/db_get_type.html create mode 100644 db/docs/api_cxx/db_join.html create mode 100644 db/docs/api_cxx/db_key_range.html create mode 100644 db/docs/api_cxx/db_open.html create mode 100644 db/docs/api_cxx/db_put.html create mode 100644 db/docs/api_cxx/db_remove.html create mode 100644 db/docs/api_cxx/db_rename.html create mode 100644 db/docs/api_cxx/db_set_append_recno.html create mode 100644 db/docs/api_cxx/db_set_bt_compare.html create mode 100644 db/docs/api_cxx/db_set_bt_minkey.html create mode 100644 db/docs/api_cxx/db_set_bt_prefix.html create mode 100644 db/docs/api_cxx/db_set_cachesize.html create mode 100644 db/docs/api_cxx/db_set_dup_compare.html create mode 100644 db/docs/api_cxx/db_set_errcall.html create mode 100644 db/docs/api_cxx/db_set_errfile.html create mode 100644 db/docs/api_cxx/db_set_errpfx.html create mode 100644 db/docs/api_cxx/db_set_feedback.html create mode 100644 db/docs/api_cxx/db_set_flags.html create mode 100644 db/docs/api_cxx/db_set_h_ffactor.html create mode 100644 db/docs/api_cxx/db_set_h_hash.html create mode 100644 db/docs/api_cxx/db_set_h_nelem.html create mode 100644 db/docs/api_cxx/db_set_lorder.html create mode 100644 db/docs/api_cxx/db_set_malloc.html create mode 100644 db/docs/api_cxx/db_set_pagesize.html create mode 100644 db/docs/api_cxx/db_set_paniccall.html create mode 100644 db/docs/api_cxx/db_set_q_extentsize.html create mode 100644 db/docs/api_cxx/db_set_re_delim.html create mode 100644 db/docs/api_cxx/db_set_re_len.html create mode 100644 db/docs/api_cxx/db_set_re_pad.html create mode 100644 db/docs/api_cxx/db_set_re_source.html create mode 100644 db/docs/api_cxx/db_set_realloc.html create mode 100644 db/docs/api_cxx/db_stat.html create mode 100644 db/docs/api_cxx/db_sync.html create mode 100644 db/docs/api_cxx/db_upgrade.html create mode 100644 db/docs/api_cxx/db_verify.html create mode 100644 db/docs/api_cxx/dbc_class.html create mode 100644 db/docs/api_cxx/dbc_close.html create mode 100644 db/docs/api_cxx/dbc_count.html create mode 100644 db/docs/api_cxx/dbc_del.html create mode 100644 db/docs/api_cxx/dbc_dup.html create mode 100644 db/docs/api_cxx/dbc_get.html create mode 100644 db/docs/api_cxx/dbc_put.html create mode 100644 db/docs/api_cxx/dbenv_class.html create mode 100644 db/docs/api_cxx/dbt_class.html create mode 100644 db/docs/api_cxx/env_close.html create mode 100644 db/docs/api_cxx/env_open.html create mode 100644 db/docs/api_cxx/env_remove.html create mode 100644 db/docs/api_cxx/env_set_cachesize.html create mode 100644 db/docs/api_cxx/env_set_data_dir.html create mode 100644 db/docs/api_cxx/env_set_errcall.html create mode 100644 db/docs/api_cxx/env_set_errfile.html create mode 100644 db/docs/api_cxx/env_set_error_stream.html create mode 100644 db/docs/api_cxx/env_set_errpfx.html create mode 100644 db/docs/api_cxx/env_set_feedback.html create mode 100644 db/docs/api_cxx/env_set_flags.html create mode 100644 db/docs/api_cxx/env_set_lg_bsize.html create mode 100644 db/docs/api_cxx/env_set_lg_dir.html create mode 100644 db/docs/api_cxx/env_set_lg_max.html create mode 100644 db/docs/api_cxx/env_set_lk_conflicts.html create mode 100644 db/docs/api_cxx/env_set_lk_detect.html create mode 100644 db/docs/api_cxx/env_set_lk_max.html create mode 100644 db/docs/api_cxx/env_set_lk_max_lockers.html create mode 100644 db/docs/api_cxx/env_set_lk_max_locks.html create mode 100644 db/docs/api_cxx/env_set_lk_max_objects.html create mode 100644 db/docs/api_cxx/env_set_mp_mmapsize.html create mode 100644 db/docs/api_cxx/env_set_mutexlocks.html create mode 100644 db/docs/api_cxx/env_set_pageyield.html create mode 100644 db/docs/api_cxx/env_set_paniccall.html create mode 100644 db/docs/api_cxx/env_set_panicstate.html create mode 100644 db/docs/api_cxx/env_set_rec_init.html create mode 100644 db/docs/api_cxx/env_set_region_init.html create mode 100644 db/docs/api_cxx/env_set_server.html create mode 100644 db/docs/api_cxx/env_set_shm_key.html create mode 100644 db/docs/api_cxx/env_set_tas_spins.html create mode 100644 db/docs/api_cxx/env_set_tmp_dir.html create mode 100644 db/docs/api_cxx/env_set_tx_max.html create mode 100644 db/docs/api_cxx/env_set_tx_recover.html create mode 100644 db/docs/api_cxx/env_set_tx_timestamp.html create mode 100644 db/docs/api_cxx/env_set_verbose.html create mode 100644 db/docs/api_cxx/env_strerror.html create mode 100644 db/docs/api_cxx/env_version.html create mode 100644 db/docs/api_cxx/except_class.html create mode 100644 db/docs/api_cxx/get_errno.html create mode 100644 db/docs/api_cxx/lock_class.html create mode 100644 db/docs/api_cxx/lock_detect.html create mode 100644 db/docs/api_cxx/lock_get.html create mode 100644 db/docs/api_cxx/lock_id.html create mode 100644 db/docs/api_cxx/lock_put.html create mode 100644 db/docs/api_cxx/lock_stat.html create mode 100644 db/docs/api_cxx/lock_vec.html create mode 100644 db/docs/api_cxx/log_archive.html create mode 100644 db/docs/api_cxx/log_compare.html create mode 100644 db/docs/api_cxx/log_file.html create mode 100644 db/docs/api_cxx/log_flush.html create mode 100644 db/docs/api_cxx/log_get.html create mode 100644 db/docs/api_cxx/log_put.html create mode 100644 db/docs/api_cxx/log_register.html create mode 100644 db/docs/api_cxx/log_stat.html create mode 100644 db/docs/api_cxx/log_unregister.html create mode 100644 db/docs/api_cxx/lsn_class.html create mode 100644 db/docs/api_cxx/memp_fclose.html create mode 100644 db/docs/api_cxx/memp_fget.html create mode 100644 db/docs/api_cxx/memp_fopen.html create mode 100644 db/docs/api_cxx/memp_fput.html create mode 100644 db/docs/api_cxx/memp_fset.html create mode 100644 db/docs/api_cxx/memp_fsync.html create mode 100644 db/docs/api_cxx/memp_register.html create mode 100644 db/docs/api_cxx/memp_stat.html create mode 100644 db/docs/api_cxx/memp_sync.html create mode 100644 db/docs/api_cxx/memp_trickle.html create mode 100644 db/docs/api_cxx/mempfile_class.html create mode 100644 db/docs/api_cxx/pindex.src create mode 100644 db/docs/api_cxx/txn_abort.html create mode 100644 db/docs/api_cxx/txn_begin.html create mode 100644 db/docs/api_cxx/txn_checkpoint.html create mode 100644 db/docs/api_cxx/txn_class.html create mode 100644 db/docs/api_cxx/txn_commit.html create mode 100644 db/docs/api_cxx/txn_id.html create mode 100644 db/docs/api_cxx/txn_prepare.html create mode 100644 db/docs/api_cxx/txn_stat.html create mode 100644 db/docs/api_cxx/what.html create mode 100644 db/docs/api_java/db_class.html create mode 100644 db/docs/api_java/db_close.html create mode 100644 db/docs/api_java/db_cursor.html create mode 100644 db/docs/api_java/db_del.html create mode 100644 db/docs/api_java/db_fd.html create mode 100644 db/docs/api_java/db_get.html create mode 100644 db/docs/api_java/db_get_byteswapped.html create mode 100644 db/docs/api_java/db_get_type.html create mode 100644 db/docs/api_java/db_join.html create mode 100644 db/docs/api_java/db_key_range.html create mode 100644 db/docs/api_java/db_open.html create mode 100644 db/docs/api_java/db_put.html create mode 100644 db/docs/api_java/db_remove.html create mode 100644 db/docs/api_java/db_rename.html create mode 100644 db/docs/api_java/db_set_append_recno.html create mode 100644 db/docs/api_java/db_set_bt_compare.html create mode 100644 db/docs/api_java/db_set_bt_minkey.html create mode 100644 db/docs/api_java/db_set_bt_prefix.html create mode 100644 db/docs/api_java/db_set_cachesize.html create mode 100644 db/docs/api_java/db_set_dup_compare.html create mode 100644 db/docs/api_java/db_set_errcall.html create mode 100644 db/docs/api_java/db_set_errpfx.html create mode 100644 db/docs/api_java/db_set_feedback.html create mode 100644 db/docs/api_java/db_set_flags.html create mode 100644 db/docs/api_java/db_set_h_ffactor.html create mode 100644 db/docs/api_java/db_set_h_hash.html create mode 100644 db/docs/api_java/db_set_h_nelem.html create mode 100644 db/docs/api_java/db_set_lorder.html create mode 100644 db/docs/api_java/db_set_pagesize.html create mode 100644 db/docs/api_java/db_set_q_extentsize.html create mode 100644 db/docs/api_java/db_set_re_delim.html create mode 100644 db/docs/api_java/db_set_re_len.html create mode 100644 db/docs/api_java/db_set_re_pad.html create mode 100644 db/docs/api_java/db_set_re_source.html create mode 100644 db/docs/api_java/db_stat.html create mode 100644 db/docs/api_java/db_sync.html create mode 100644 db/docs/api_java/db_upgrade.html create mode 100644 db/docs/api_java/db_verify.html create mode 100644 db/docs/api_java/dbc_class.html create mode 100644 db/docs/api_java/dbc_close.html create mode 100644 db/docs/api_java/dbc_count.html create mode 100644 db/docs/api_java/dbc_del.html create mode 100644 db/docs/api_java/dbc_dup.html create mode 100644 db/docs/api_java/dbc_get.html create mode 100644 db/docs/api_java/dbc_put.html create mode 100644 db/docs/api_java/dbenv_class.html create mode 100644 db/docs/api_java/dbt_class.html create mode 100644 db/docs/api_java/deadlock_class.html create mode 100644 db/docs/api_java/env_close.html create mode 100644 db/docs/api_java/env_open.html create mode 100644 db/docs/api_java/env_remove.html create mode 100644 db/docs/api_java/env_set_cachesize.html create mode 100644 db/docs/api_java/env_set_data_dir.html create mode 100644 db/docs/api_java/env_set_errcall.html create mode 100644 db/docs/api_java/env_set_error_stream.html create mode 100644 db/docs/api_java/env_set_errpfx.html create mode 100644 db/docs/api_java/env_set_feedback.html create mode 100644 db/docs/api_java/env_set_flags.html create mode 100644 db/docs/api_java/env_set_lg_bsize.html create mode 100644 db/docs/api_java/env_set_lg_dir.html create mode 100644 db/docs/api_java/env_set_lg_max.html create mode 100644 db/docs/api_java/env_set_lk_conflicts.html create mode 100644 db/docs/api_java/env_set_lk_detect.html create mode 100644 db/docs/api_java/env_set_lk_max.html create mode 100644 db/docs/api_java/env_set_lk_max_lockers.html create mode 100644 db/docs/api_java/env_set_lk_max_locks.html create mode 100644 db/docs/api_java/env_set_lk_max_objects.html create mode 100644 db/docs/api_java/env_set_mp_mmapsize.html create mode 100644 db/docs/api_java/env_set_mutexlocks.html create mode 100644 db/docs/api_java/env_set_pageyield.html create mode 100644 db/docs/api_java/env_set_panicstate.html create mode 100644 db/docs/api_java/env_set_rec_init.html create mode 100644 db/docs/api_java/env_set_region_init.html create mode 100644 db/docs/api_java/env_set_server.html create mode 100644 db/docs/api_java/env_set_shm_key.html create mode 100644 db/docs/api_java/env_set_tas_spins.html create mode 100644 db/docs/api_java/env_set_tmp_dir.html create mode 100644 db/docs/api_java/env_set_tx_max.html create mode 100644 db/docs/api_java/env_set_tx_recover.html create mode 100644 db/docs/api_java/env_set_tx_timestamp.html create mode 100644 db/docs/api_java/env_set_verbose.html create mode 100644 db/docs/api_java/env_strerror.html create mode 100644 db/docs/api_java/env_version.html create mode 100644 db/docs/api_java/except_class.html create mode 100644 db/docs/api_java/get_errno.html create mode 100644 db/docs/api_java/java_index.html create mode 100644 db/docs/api_java/java_pindex.html create mode 100644 db/docs/api_java/lock_class.html create mode 100644 db/docs/api_java/lock_detect.html create mode 100644 db/docs/api_java/lock_get.html create mode 100644 db/docs/api_java/lock_id.html create mode 100644 db/docs/api_java/lock_put.html create mode 100644 db/docs/api_java/lock_stat.html create mode 100644 db/docs/api_java/lock_vec.html create mode 100644 db/docs/api_java/log_archive.html create mode 100644 db/docs/api_java/log_compare.html create mode 100644 db/docs/api_java/log_file.html create mode 100644 db/docs/api_java/log_flush.html create mode 100644 db/docs/api_java/log_get.html create mode 100644 db/docs/api_java/log_put.html create mode 100644 db/docs/api_java/log_register.html create mode 100644 db/docs/api_java/log_stat.html create mode 100644 db/docs/api_java/log_unregister.html create mode 100644 db/docs/api_java/lsn_class.html create mode 100644 db/docs/api_java/mem_class.html create mode 100644 db/docs/api_java/memp_fclose.html create mode 100644 db/docs/api_java/memp_fget.html create mode 100644 db/docs/api_java/memp_fopen.html create mode 100644 db/docs/api_java/memp_fput.html create mode 100644 db/docs/api_java/memp_fset.html create mode 100644 db/docs/api_java/memp_fsync.html create mode 100644 db/docs/api_java/memp_register.html create mode 100644 db/docs/api_java/memp_stat.html create mode 100644 db/docs/api_java/memp_sync.html create mode 100644 db/docs/api_java/memp_trickle.html create mode 100644 db/docs/api_java/pindex.src create mode 100644 db/docs/api_java/runrec_class.html create mode 100644 db/docs/api_java/txn_abort.html create mode 100644 db/docs/api_java/txn_begin.html create mode 100644 db/docs/api_java/txn_checkpoint.html create mode 100644 db/docs/api_java/txn_class.html create mode 100644 db/docs/api_java/txn_commit.html create mode 100644 db/docs/api_java/txn_id.html create mode 100644 db/docs/api_java/txn_prepare.html create mode 100644 db/docs/api_java/txn_stat.html create mode 100644 db/docs/api_tcl/db_close.html create mode 100644 db/docs/api_tcl/db_count.html create mode 100644 db/docs/api_tcl/db_cursor.html create mode 100644 db/docs/api_tcl/db_del.html create mode 100644 db/docs/api_tcl/db_get.html create mode 100644 db/docs/api_tcl/db_get_join.html create mode 100644 db/docs/api_tcl/db_get_type.html create mode 100644 db/docs/api_tcl/db_is_byteswapped.html create mode 100644 db/docs/api_tcl/db_join.html create mode 100644 db/docs/api_tcl/db_open.html create mode 100644 db/docs/api_tcl/db_put.html create mode 100644 db/docs/api_tcl/db_remove.html create mode 100644 db/docs/api_tcl/db_rename.html create mode 100644 db/docs/api_tcl/db_stat.html create mode 100644 db/docs/api_tcl/db_sync.html create mode 100644 db/docs/api_tcl/dbc_close.html create mode 100644 db/docs/api_tcl/dbc_del.html create mode 100644 db/docs/api_tcl/dbc_dup.html create mode 100644 db/docs/api_tcl/dbc_get.html create mode 100644 db/docs/api_tcl/dbc_put.html create mode 100644 db/docs/api_tcl/env_close.html create mode 100644 db/docs/api_tcl/env_open.html create mode 100644 db/docs/api_tcl/env_remove.html create mode 100644 db/docs/api_tcl/pindex.src create mode 100644 db/docs/api_tcl/tcl_index.html create mode 100644 db/docs/api_tcl/tcl_pindex.html create mode 100644 db/docs/api_tcl/txn.html create mode 100644 db/docs/api_tcl/txn_abort.html create mode 100644 db/docs/api_tcl/txn_commit.html create mode 100644 db/docs/api_tcl/version.html create mode 100644 db/docs/images/api.gif create mode 100644 db/docs/images/next.gif create mode 100644 db/docs/images/prev.gif create mode 100644 db/docs/images/ps.gif create mode 100644 db/docs/images/ref.gif create mode 100644 db/docs/images/sleepycat.gif create mode 100644 db/docs/index.html create mode 100644 db/docs/ref/am/close.html create mode 100644 db/docs/ref/am/count.html create mode 100644 db/docs/ref/am/curclose.html create mode 100644 db/docs/ref/am/curdel.html create mode 100644 db/docs/ref/am/curdup.html create mode 100644 db/docs/ref/am/curget.html create mode 100644 db/docs/ref/am/curput.html create mode 100644 db/docs/ref/am/cursor.html create mode 100644 db/docs/ref/am/delete.html create mode 100644 db/docs/ref/am/error.html create mode 100644 db/docs/ref/am/get.html create mode 100644 db/docs/ref/am/join.html create mode 100644 db/docs/ref/am/open.html create mode 100644 db/docs/ref/am/opensub.html create mode 100644 db/docs/ref/am/ops.html create mode 100644 db/docs/ref/am/partial.html create mode 100644 db/docs/ref/am/put.html create mode 100644 db/docs/ref/am/stability.html create mode 100644 db/docs/ref/am/stat.html create mode 100644 db/docs/ref/am/sync.html create mode 100644 db/docs/ref/am/upgrade.html create mode 100644 db/docs/ref/am/verify.html create mode 100644 db/docs/ref/am_conf/bt_compare.html create mode 100644 db/docs/ref/am_conf/bt_minkey.html create mode 100644 db/docs/ref/am_conf/bt_prefix.html create mode 100644 db/docs/ref/am_conf/bt_recnum.html create mode 100644 db/docs/ref/am_conf/byteorder.html create mode 100644 db/docs/ref/am_conf/cachesize.html create mode 100644 db/docs/ref/am_conf/dup.html create mode 100644 db/docs/ref/am_conf/extentsize.html create mode 100644 db/docs/ref/am_conf/h_ffactor.html create mode 100644 db/docs/ref/am_conf/h_hash.html create mode 100644 db/docs/ref/am_conf/h_nelem.html create mode 100644 db/docs/ref/am_conf/intro.html create mode 100644 db/docs/ref/am_conf/logrec.html create mode 100644 db/docs/ref/am_conf/malloc.html create mode 100644 db/docs/ref/am_conf/pagesize.html create mode 100644 db/docs/ref/am_conf/re_source.html create mode 100644 db/docs/ref/am_conf/recno.html create mode 100644 db/docs/ref/am_conf/renumber.html create mode 100644 db/docs/ref/am_conf/select.html create mode 100644 db/docs/ref/arch/apis.html create mode 100644 db/docs/ref/arch/bigpic.gif create mode 100644 db/docs/ref/arch/bigpic.html create mode 100644 db/docs/ref/arch/progmodel.html create mode 100644 db/docs/ref/arch/script.html create mode 100644 db/docs/ref/arch/smallpic.gif create mode 100644 db/docs/ref/arch/utilities.html create mode 100644 db/docs/ref/build_unix/aix.html create mode 100644 db/docs/ref/build_unix/conf.html create mode 100644 db/docs/ref/build_unix/flags.html create mode 100644 db/docs/ref/build_unix/freebsd.html create mode 100644 db/docs/ref/build_unix/hpux.html create mode 100644 db/docs/ref/build_unix/install.html create mode 100644 db/docs/ref/build_unix/intro.html create mode 100644 db/docs/ref/build_unix/irix.html create mode 100644 db/docs/ref/build_unix/linux.html create mode 100644 db/docs/ref/build_unix/notes.html create mode 100644 db/docs/ref/build_unix/osf1.html create mode 100644 db/docs/ref/build_unix/qnx.html create mode 100644 db/docs/ref/build_unix/sco.html create mode 100644 db/docs/ref/build_unix/shlib.html create mode 100644 db/docs/ref/build_unix/solaris.html create mode 100644 db/docs/ref/build_unix/sunos.html create mode 100644 db/docs/ref/build_unix/test.html create mode 100644 db/docs/ref/build_unix/ultrix.html create mode 100644 db/docs/ref/build_vxworks/faq.html create mode 100644 db/docs/ref/build_vxworks/intro.html create mode 100644 db/docs/ref/build_vxworks/notes.html create mode 100644 db/docs/ref/build_win/faq.html create mode 100644 db/docs/ref/build_win/intro.html create mode 100644 db/docs/ref/build_win/notes.html create mode 100644 db/docs/ref/build_win/test.html create mode 100644 db/docs/ref/cam/intro.html create mode 100644 db/docs/ref/debug/common.html create mode 100644 db/docs/ref/debug/compile.html create mode 100644 db/docs/ref/debug/intro.html create mode 100644 db/docs/ref/debug/printlog.html create mode 100644 db/docs/ref/debug/runtime.html create mode 100644 db/docs/ref/distrib/layout.html create mode 100644 db/docs/ref/dumpload/format.html create mode 100644 db/docs/ref/dumpload/text.html create mode 100644 db/docs/ref/dumpload/utility.html create mode 100644 db/docs/ref/env/create.html create mode 100644 db/docs/ref/env/error.html create mode 100644 db/docs/ref/env/intro.html create mode 100644 db/docs/ref/env/naming.html create mode 100644 db/docs/ref/env/open.html create mode 100644 db/docs/ref/env/region.html create mode 100644 db/docs/ref/env/remote.html create mode 100644 db/docs/ref/env/security.html create mode 100644 db/docs/ref/install/file.html create mode 100644 db/docs/ref/install/magic.s5.be.txt create mode 100644 db/docs/ref/install/magic.s5.le.txt create mode 100644 db/docs/ref/install/magic.txt create mode 100644 db/docs/ref/intro/data.html create mode 100644 db/docs/ref/intro/dbis.html create mode 100644 db/docs/ref/intro/dbisnot.html create mode 100644 db/docs/ref/intro/distrib.html create mode 100644 db/docs/ref/intro/need.html create mode 100644 db/docs/ref/intro/products.html create mode 100644 db/docs/ref/intro/terrain.html create mode 100644 db/docs/ref/intro/what.html create mode 100644 db/docs/ref/intro/where.html create mode 100644 db/docs/ref/java/compat.html create mode 100644 db/docs/ref/java/conf.html create mode 100644 db/docs/ref/java/faq.html create mode 100644 db/docs/ref/java/program.html create mode 100644 db/docs/ref/lock/am_conv.html create mode 100644 db/docs/ref/lock/cam_conv.html create mode 100644 db/docs/ref/lock/config.html create mode 100644 db/docs/ref/lock/dead.html create mode 100644 db/docs/ref/lock/intro.html create mode 100644 db/docs/ref/lock/max.html create mode 100644 db/docs/ref/lock/nondb.html create mode 100644 db/docs/ref/lock/notxn.html create mode 100644 db/docs/ref/lock/page.html create mode 100644 db/docs/ref/lock/stdmode.html create mode 100644 db/docs/ref/lock/twopl.html create mode 100644 db/docs/ref/log/config.html create mode 100644 db/docs/ref/log/intro.html create mode 100644 db/docs/ref/log/limits.html create mode 100644 db/docs/ref/mp/config.html create mode 100644 db/docs/ref/mp/intro.html create mode 100644 db/docs/ref/perl/intro.html create mode 100644 db/docs/ref/pindex.src create mode 100644 db/docs/ref/program/appsignals.html create mode 100644 db/docs/ref/program/byteorder.html create mode 100644 db/docs/ref/program/compatible.html create mode 100644 db/docs/ref/program/copy.html create mode 100644 db/docs/ref/program/dbsizes.html create mode 100644 db/docs/ref/program/diskspace.html create mode 100644 db/docs/ref/program/environ.html create mode 100644 db/docs/ref/program/errorret.html create mode 100644 db/docs/ref/program/extending.html create mode 100644 db/docs/ref/program/mt.html create mode 100644 db/docs/ref/program/namespace.html create mode 100644 db/docs/ref/program/recimp.html create mode 100644 db/docs/ref/program/runtime.html create mode 100644 db/docs/ref/program/scope.html create mode 100644 db/docs/ref/program/solaris.txt create mode 100644 db/docs/ref/program/version.html create mode 100644 db/docs/ref/refs/bdb_usenix.html create mode 100644 db/docs/ref/refs/bdb_usenix.ps create mode 100644 db/docs/ref/refs/embedded.html create mode 100644 db/docs/ref/refs/hash_usenix.ps create mode 100644 db/docs/ref/refs/libtp_usenix.ps create mode 100644 db/docs/ref/refs/refs.html create mode 100644 db/docs/ref/refs/witold.html create mode 100644 db/docs/ref/rpc/client.html create mode 100644 db/docs/ref/rpc/intro.html create mode 100644 db/docs/ref/rpc/server.html create mode 100644 db/docs/ref/sendmail/intro.html create mode 100644 db/docs/ref/simple_tut/close.html create mode 100644 db/docs/ref/simple_tut/del.html create mode 100644 db/docs/ref/simple_tut/errors.html create mode 100644 db/docs/ref/simple_tut/example.txt create mode 100644 db/docs/ref/simple_tut/get.html create mode 100644 db/docs/ref/simple_tut/handles.html create mode 100644 db/docs/ref/simple_tut/intro.html create mode 100644 db/docs/ref/simple_tut/keydata.html create mode 100644 db/docs/ref/simple_tut/open.html create mode 100644 db/docs/ref/simple_tut/put.html create mode 100644 db/docs/ref/tcl/error.html create mode 100644 db/docs/ref/tcl/faq.html create mode 100644 db/docs/ref/tcl/intro.html create mode 100644 db/docs/ref/tcl/program.html create mode 100644 db/docs/ref/tcl/using.html create mode 100644 db/docs/ref/test/faq.html create mode 100644 db/docs/ref/test/run.html create mode 100644 db/docs/ref/toc.html create mode 100644 db/docs/ref/transapp/admin.html create mode 100644 db/docs/ref/transapp/app.html create mode 100644 db/docs/ref/transapp/archival.html create mode 100644 db/docs/ref/transapp/checkpoint.html create mode 100644 db/docs/ref/transapp/cursor.html create mode 100644 db/docs/ref/transapp/data_open.html create mode 100644 db/docs/ref/transapp/deadlock.html create mode 100644 db/docs/ref/transapp/env_open.html create mode 100644 db/docs/ref/transapp/filesys.html create mode 100644 db/docs/ref/transapp/inc.html create mode 100644 db/docs/ref/transapp/intro.html create mode 100644 db/docs/ref/transapp/logfile.html create mode 100644 db/docs/ref/transapp/put.html create mode 100644 db/docs/ref/transapp/read.html create mode 100644 db/docs/ref/transapp/reclimit.html create mode 100644 db/docs/ref/transapp/recovery.html create mode 100644 db/docs/ref/transapp/term.html create mode 100644 db/docs/ref/transapp/throughput.html create mode 100644 db/docs/ref/transapp/transapp.txt create mode 100644 db/docs/ref/transapp/why.html create mode 100644 db/docs/ref/transapp/writetest.txt create mode 100644 db/docs/ref/txn/config.html create mode 100644 db/docs/ref/txn/intro.html create mode 100644 db/docs/ref/txn/limits.html create mode 100644 db/docs/ref/txn/nested.html create mode 100644 db/docs/ref/txn/other.html create mode 100644 db/docs/ref/upgrade.2.0/convert.html create mode 100644 db/docs/ref/upgrade.2.0/disk.html create mode 100644 db/docs/ref/upgrade.2.0/intro.html create mode 100644 db/docs/ref/upgrade.2.0/system.html create mode 100644 db/docs/ref/upgrade.2.0/toc.html create mode 100644 db/docs/ref/upgrade.3.0/close.html create mode 100644 db/docs/ref/upgrade.3.0/cxx.html create mode 100644 db/docs/ref/upgrade.3.0/db.html create mode 100644 db/docs/ref/upgrade.3.0/db_cxx.html create mode 100644 db/docs/ref/upgrade.3.0/dbenv.html create mode 100644 db/docs/ref/upgrade.3.0/dbenv_cxx.html create mode 100644 db/docs/ref/upgrade.3.0/dbinfo.html create mode 100644 db/docs/ref/upgrade.3.0/disk.html create mode 100644 db/docs/ref/upgrade.3.0/eacces.html create mode 100644 db/docs/ref/upgrade.3.0/eagain.html create mode 100644 db/docs/ref/upgrade.3.0/envopen.html create mode 100644 db/docs/ref/upgrade.3.0/func.html create mode 100644 db/docs/ref/upgrade.3.0/intro.html create mode 100644 db/docs/ref/upgrade.3.0/java.html create mode 100644 db/docs/ref/upgrade.3.0/join.html create mode 100644 db/docs/ref/upgrade.3.0/jump_set.html create mode 100644 db/docs/ref/upgrade.3.0/lock_detect.html create mode 100644 db/docs/ref/upgrade.3.0/lock_notheld.html create mode 100644 db/docs/ref/upgrade.3.0/lock_put.html create mode 100644 db/docs/ref/upgrade.3.0/lock_stat.html create mode 100644 db/docs/ref/upgrade.3.0/log_register.html create mode 100644 db/docs/ref/upgrade.3.0/log_stat.html create mode 100644 db/docs/ref/upgrade.3.0/memp_stat.html create mode 100644 db/docs/ref/upgrade.3.0/open.html create mode 100644 db/docs/ref/upgrade.3.0/rmw.html create mode 100644 db/docs/ref/upgrade.3.0/stat.html create mode 100644 db/docs/ref/upgrade.3.0/toc.html create mode 100644 db/docs/ref/upgrade.3.0/txn_begin.html create mode 100644 db/docs/ref/upgrade.3.0/txn_commit.html create mode 100644 db/docs/ref/upgrade.3.0/txn_stat.html create mode 100644 db/docs/ref/upgrade.3.0/value_set.html create mode 100644 db/docs/ref/upgrade.3.0/xa.html create mode 100644 db/docs/ref/upgrade.3.1/btstat.html create mode 100644 db/docs/ref/upgrade.3.1/config.html create mode 100644 db/docs/ref/upgrade.3.1/disk.html create mode 100644 db/docs/ref/upgrade.3.1/dup.html create mode 100644 db/docs/ref/upgrade.3.1/env.html create mode 100644 db/docs/ref/upgrade.3.1/intro.html create mode 100644 db/docs/ref/upgrade.3.1/log_register.html create mode 100644 db/docs/ref/upgrade.3.1/logalloc.html create mode 100644 db/docs/ref/upgrade.3.1/memp_register.html create mode 100644 db/docs/ref/upgrade.3.1/put.html create mode 100644 db/docs/ref/upgrade.3.1/set_feedback.html create mode 100644 db/docs/ref/upgrade.3.1/set_paniccall.html create mode 100644 db/docs/ref/upgrade.3.1/set_tx_recover.html create mode 100644 db/docs/ref/upgrade.3.1/sysmem.html create mode 100644 db/docs/ref/upgrade.3.1/tcl.html create mode 100644 db/docs/ref/upgrade.3.1/tmp.html create mode 100644 db/docs/ref/upgrade.3.1/toc.html create mode 100644 db/docs/ref/upgrade.3.1/txn_check.html create mode 100644 db/docs/ref/upgrade.3.2/callback.html create mode 100644 db/docs/ref/upgrade.3.2/db_dump.html create mode 100644 db/docs/ref/upgrade.3.2/disk.html create mode 100644 db/docs/ref/upgrade.3.2/handle.html create mode 100644 db/docs/ref/upgrade.3.2/incomplete.html create mode 100644 db/docs/ref/upgrade.3.2/intro.html create mode 100644 db/docs/ref/upgrade.3.2/mutexlock.html create mode 100644 db/docs/ref/upgrade.3.2/notfound.html create mode 100644 db/docs/ref/upgrade.3.2/renumber.html create mode 100644 db/docs/ref/upgrade.3.2/set_flags.html create mode 100644 db/docs/ref/upgrade.3.2/toc.html create mode 100644 db/docs/ref/upgrade.3.2/tx_recover.html create mode 100644 db/docs/ref/upgrade/process.html create mode 100644 db/docs/ref/xa/config.html create mode 100644 db/docs/ref/xa/faq.html create mode 100644 db/docs/ref/xa/intro.html create mode 100644 db/docs/sleepycat/contact.html create mode 100644 db/docs/sleepycat/legal.html create mode 100644 db/docs/sleepycat/license.html create mode 100644 db/docs/utility/berkeley_db_svc.html create mode 100644 db/docs/utility/db_archive.html create mode 100644 db/docs/utility/db_checkpoint.html create mode 100644 db/docs/utility/db_deadlock.html create mode 100644 db/docs/utility/db_dump.html create mode 100644 db/docs/utility/db_load.html create mode 100644 db/docs/utility/db_printlog.html create mode 100644 db/docs/utility/db_recover.html create mode 100644 db/docs/utility/db_stat.html create mode 100644 db/docs/utility/db_upgrade.html create mode 100644 db/docs/utility/db_verify.html create mode 100644 db/docs/utility/index.html create mode 100644 db/env/db_salloc.c create mode 100644 db/env/db_shash.c create mode 100644 db/env/env_method.c create mode 100644 db/env/env_open.c create mode 100644 db/env/env_recover.c create mode 100644 db/env/env_region.c create mode 100644 db/examples_c/README create mode 100644 db/examples_c/ex_access.c create mode 100644 db/examples_c/ex_btrec.c create mode 100644 db/examples_c/ex_dbclient.c create mode 100644 db/examples_c/ex_env.c create mode 100644 db/examples_c/ex_lock.c create mode 100644 db/examples_c/ex_mpool.c create mode 100644 db/examples_c/ex_thread.c create mode 100644 db/examples_c/ex_tpcb.c create mode 100644 db/examples_c/ex_tpcb.h create mode 100644 db/examples_cxx/AccessExample.cpp create mode 100644 db/examples_cxx/BtRecExample.cpp create mode 100644 db/examples_cxx/EnvExample.cpp create mode 100644 db/examples_cxx/LockExample.cpp create mode 100644 db/examples_cxx/MpoolExample.cpp create mode 100644 db/examples_cxx/TpcbExample.cpp create mode 100644 db/hash/hash.c create mode 100644 db/hash/hash.src create mode 100644 db/hash/hash_auto.c create mode 100644 db/hash/hash_conv.c create mode 100644 db/hash/hash_dup.c create mode 100644 db/hash/hash_func.c create mode 100644 db/hash/hash_meta.c create mode 100644 db/hash/hash_method.c create mode 100644 db/hash/hash_page.c create mode 100644 db/hash/hash_rec.c create mode 100644 db/hash/hash_reclaim.c create mode 100644 db/hash/hash_stat.c create mode 100644 db/hash/hash_upgrade.c create mode 100644 db/hash/hash_verify.c create mode 100644 db/hsearch/hsearch.c create mode 100644 db/include/btree.h create mode 100644 db/include/btree_auto.h create mode 100644 db/include/btree_ext.h create mode 100644 db/include/clib_ext.h create mode 100644 db/include/common_ext.h create mode 100644 db/include/crdel_auto.h create mode 100644 db/include/cxx_int.h create mode 100644 db/include/db.src create mode 100644 db/include/db_185.h create mode 100644 db/include/db_am.h create mode 100644 db/include/db_auto.h create mode 100644 db/include/db_cxx.h create mode 100644 db/include/db_dispatch.h create mode 100644 db/include/db_ext.h create mode 100644 db/include/db_int.src create mode 100644 db/include/db_join.h create mode 100644 db/include/db_page.h create mode 100644 db/include/db_server.h create mode 100644 db/include/db_server_int.h create mode 100644 db/include/db_shash.h create mode 100644 db/include/db_swap.h create mode 100644 db/include/db_upgrade.h create mode 100644 db/include/db_verify.h create mode 100644 db/include/debug.h create mode 100644 db/include/env_ext.h create mode 100644 db/include/gen_client_ext.h create mode 100644 db/include/gen_server_ext.h create mode 100644 db/include/hash.h create mode 100644 db/include/hash_auto.h create mode 100644 db/include/hash_ext.h create mode 100644 db/include/lock.h create mode 100644 db/include/lock_ext.h create mode 100644 db/include/log.h create mode 100644 db/include/log_auto.h create mode 100644 db/include/log_ext.h create mode 100644 db/include/mp.h create mode 100644 db/include/mp_ext.h create mode 100644 db/include/mutex.h create mode 100644 db/include/mutex_ext.h create mode 100644 db/include/os.h create mode 100644 db/include/os_ext.h create mode 100644 db/include/os_jump.h create mode 100644 db/include/qam.h create mode 100644 db/include/qam_auto.h create mode 100644 db/include/qam_ext.h create mode 100644 db/include/queue.h create mode 100644 db/include/region.h create mode 100644 db/include/rpc_client_ext.h create mode 100644 db/include/rpc_server_ext.h create mode 100644 db/include/shqueue.h create mode 100644 db/include/tcl_db.h create mode 100644 db/include/tcl_ext.h create mode 100644 db/include/txn.h create mode 100644 db/include/txn_auto.h create mode 100644 db/include/txn_ext.h create mode 100644 db/include/xa.h create mode 100644 db/include/xa_ext.h create mode 100644 db/java/src/com/sleepycat/db/Db.java create mode 100644 db/java/src/com/sleepycat/db/DbAppendRecno.java create mode 100644 db/java/src/com/sleepycat/db/DbBtreeCompare.java create mode 100644 db/java/src/com/sleepycat/db/DbBtreePrefix.java create mode 100644 db/java/src/com/sleepycat/db/DbBtreeStat.java create mode 100644 db/java/src/com/sleepycat/db/DbConstants.java create mode 100644 db/java/src/com/sleepycat/db/DbDeadlockException.java create mode 100644 db/java/src/com/sleepycat/db/DbDupCompare.java create mode 100644 db/java/src/com/sleepycat/db/DbEnv.java create mode 100644 db/java/src/com/sleepycat/db/DbEnvFeedback.java create mode 100644 db/java/src/com/sleepycat/db/DbErrcall.java create mode 100644 db/java/src/com/sleepycat/db/DbException.java create mode 100644 db/java/src/com/sleepycat/db/DbFeedback.java create mode 100644 db/java/src/com/sleepycat/db/DbHash.java create mode 100644 db/java/src/com/sleepycat/db/DbHashStat.java create mode 100644 db/java/src/com/sleepycat/db/DbKeyRange.java create mode 100644 db/java/src/com/sleepycat/db/DbLock.java create mode 100644 db/java/src/com/sleepycat/db/DbLockStat.java create mode 100644 db/java/src/com/sleepycat/db/DbLogStat.java create mode 100644 db/java/src/com/sleepycat/db/DbLsn.java create mode 100644 db/java/src/com/sleepycat/db/DbMemoryException.java create mode 100644 db/java/src/com/sleepycat/db/DbMpoolFStat.java create mode 100644 db/java/src/com/sleepycat/db/DbMpoolStat.java create mode 100644 db/java/src/com/sleepycat/db/DbOutputStreamErrcall.java create mode 100644 db/java/src/com/sleepycat/db/DbQueueStat.java create mode 100644 db/java/src/com/sleepycat/db/DbRecoveryInit.java create mode 100644 db/java/src/com/sleepycat/db/DbRunRecoveryException.java create mode 100644 db/java/src/com/sleepycat/db/DbTxn.java create mode 100644 db/java/src/com/sleepycat/db/DbTxnRecover.java create mode 100644 db/java/src/com/sleepycat/db/DbTxnStat.java create mode 100644 db/java/src/com/sleepycat/db/Dbc.java create mode 100644 db/java/src/com/sleepycat/db/Dbt.java create mode 100644 db/java/src/com/sleepycat/examples/AccessExample.java create mode 100644 db/java/src/com/sleepycat/examples/BtRecExample.java create mode 100644 db/java/src/com/sleepycat/examples/EnvExample.java create mode 100644 db/java/src/com/sleepycat/examples/LockExample.java create mode 100644 db/java/src/com/sleepycat/examples/TpcbExample.java create mode 100644 db/libdb_java/checkapi.prl create mode 100644 db/libdb_java/com_sleepycat_db_Db.h create mode 100644 db/libdb_java/com_sleepycat_db_DbEnv.h create mode 100644 db/libdb_java/com_sleepycat_db_DbLock.h create mode 100644 db/libdb_java/com_sleepycat_db_DbLsn.h create mode 100644 db/libdb_java/com_sleepycat_db_DbTxn.h create mode 100644 db/libdb_java/com_sleepycat_db_Dbc.h create mode 100644 db/libdb_java/com_sleepycat_db_Dbt.h create mode 100644 db/libdb_java/java_Db.c create mode 100644 db/libdb_java/java_DbEnv.c create mode 100644 db/libdb_java/java_DbLock.c create mode 100644 db/libdb_java/java_DbLsn.c create mode 100644 db/libdb_java/java_DbTxn.c create mode 100644 db/libdb_java/java_Dbc.c create mode 100644 db/libdb_java/java_Dbt.c create mode 100644 db/libdb_java/java_info.c create mode 100644 db/libdb_java/java_info.h create mode 100644 db/libdb_java/java_locked.c create mode 100644 db/libdb_java/java_locked.h create mode 100644 db/libdb_java/java_util.c create mode 100644 db/libdb_java/java_util.h create mode 100644 db/lock/Design create mode 100644 db/lock/lock.c create mode 100644 db/lock/lock_conflict.c create mode 100644 db/lock/lock_deadlock.c create mode 100644 db/lock/lock_method.c create mode 100644 db/lock/lock_region.c create mode 100644 db/lock/lock_stat.c create mode 100644 db/lock/lock_util.c create mode 100644 db/log/log.c create mode 100644 db/log/log.src create mode 100644 db/log/log_archive.c create mode 100644 db/log/log_auto.c create mode 100644 db/log/log_compare.c create mode 100644 db/log/log_findckp.c create mode 100644 db/log/log_get.c create mode 100644 db/log/log_method.c create mode 100644 db/log/log_put.c create mode 100644 db/log/log_rec.c create mode 100644 db/log/log_register.c create mode 100644 db/mp/Design create mode 100644 db/mp/mp_alloc.c create mode 100644 db/mp/mp_bh.c create mode 100644 db/mp/mp_fget.c create mode 100644 db/mp/mp_fopen.c create mode 100644 db/mp/mp_fput.c create mode 100644 db/mp/mp_fset.c create mode 100644 db/mp/mp_method.c create mode 100644 db/mp/mp_region.c create mode 100644 db/mp/mp_register.c create mode 100644 db/mp/mp_stat.c create mode 100644 db/mp/mp_sync.c create mode 100644 db/mp/mp_trickle.c create mode 100644 db/mutex/README create mode 100644 db/mutex/mut_fcntl.c create mode 100644 db/mutex/mut_pthread.c create mode 100644 db/mutex/mut_tas.c create mode 100644 db/mutex/mutex.c create mode 100644 db/mutex/uts4_cc.s create mode 100644 db/os/os_abs.c create mode 100644 db/os/os_alloc.c create mode 100644 db/os/os_dir.c create mode 100644 db/os/os_errno.c create mode 100644 db/os/os_fid.c create mode 100644 db/os/os_finit.c create mode 100644 db/os/os_fsync.c create mode 100644 db/os/os_handle.c create mode 100644 db/os/os_map.c create mode 100644 db/os/os_method.c create mode 100644 db/os/os_oflags.c create mode 100644 db/os/os_open.c create mode 100644 db/os/os_region.c create mode 100644 db/os/os_rename.c create mode 100644 db/os/os_root.c create mode 100644 db/os/os_rpath.c create mode 100644 db/os/os_rw.c create mode 100644 db/os/os_seek.c create mode 100644 db/os/os_sleep.c create mode 100644 db/os/os_spin.c create mode 100644 db/os/os_stat.c create mode 100644 db/os/os_tmpdir.c create mode 100644 db/os/os_unlink.c create mode 100644 db/os_vxworks/os_abs.c create mode 100644 db/os_vxworks/os_finit.c create mode 100644 db/os_vxworks/os_map.c create mode 100644 db/os_win32/os_abs.c create mode 100644 db/os_win32/os_dir.c create mode 100644 db/os_win32/os_errno.c create mode 100644 db/os_win32/os_fid.c create mode 100644 db/os_win32/os_finit.c create mode 100644 db/os_win32/os_map.c create mode 100644 db/os_win32/os_open.c create mode 100644 db/os_win32/os_rename.c create mode 100644 db/os_win32/os_seek.c create mode 100644 db/os_win32/os_sleep.c create mode 100644 db/os_win32/os_spin.c create mode 100644 db/os_win32/os_type.c create mode 100644 db/perl.BerkeleyDB/BerkeleyDB.pm create mode 100644 db/perl.BerkeleyDB/BerkeleyDB.pod create mode 100644 db/perl.BerkeleyDB/BerkeleyDB.pod.P create mode 100644 db/perl.BerkeleyDB/BerkeleyDB.xs create mode 100644 db/perl.BerkeleyDB/BerkeleyDB/Btree.pm create mode 100644 db/perl.BerkeleyDB/BerkeleyDB/Hash.pm create mode 100644 db/perl.BerkeleyDB/Changes create mode 100644 db/perl.BerkeleyDB/MANIFEST create mode 100644 db/perl.BerkeleyDB/Makefile.PL create mode 100644 db/perl.BerkeleyDB/README create mode 100644 db/perl.BerkeleyDB/Todo create mode 100644 db/perl.BerkeleyDB/config.in create mode 100755 db/perl.BerkeleyDB/dbinfo create mode 100644 db/perl.BerkeleyDB/hints/irix_6_5.pl create mode 100644 db/perl.BerkeleyDB/hints/solaris.pl create mode 100644 db/perl.BerkeleyDB/mkconsts create mode 100755 db/perl.BerkeleyDB/mkpod create mode 100644 db/perl.BerkeleyDB/patches/5.004 create mode 100644 db/perl.BerkeleyDB/patches/5.004_01 create mode 100644 db/perl.BerkeleyDB/patches/5.004_02 create mode 100644 db/perl.BerkeleyDB/patches/5.004_03 create mode 100644 db/perl.BerkeleyDB/patches/5.004_04 create mode 100644 db/perl.BerkeleyDB/patches/5.004_05 create mode 100644 db/perl.BerkeleyDB/patches/5.005 create mode 100644 db/perl.BerkeleyDB/patches/5.005_01 create mode 100644 db/perl.BerkeleyDB/patches/5.005_02 create mode 100644 db/perl.BerkeleyDB/patches/5.005_03 create mode 100644 db/perl.BerkeleyDB/patches/5.6.0 create mode 100644 db/perl.BerkeleyDB/t/btree.t create mode 100644 db/perl.BerkeleyDB/t/db-3.0.t create mode 100644 db/perl.BerkeleyDB/t/db-3.1.t create mode 100644 db/perl.BerkeleyDB/t/db-3.2.t create mode 100644 db/perl.BerkeleyDB/t/destroy.t create mode 100644 db/perl.BerkeleyDB/t/env.t create mode 100644 db/perl.BerkeleyDB/t/examples.t create mode 100644 db/perl.BerkeleyDB/t/examples.t.T create mode 100644 db/perl.BerkeleyDB/t/examples3.t create mode 100644 db/perl.BerkeleyDB/t/examples3.t.T create mode 100644 db/perl.BerkeleyDB/t/filter.t create mode 100644 db/perl.BerkeleyDB/t/hash.t create mode 100644 db/perl.BerkeleyDB/t/join.t create mode 100644 db/perl.BerkeleyDB/t/mldbm.t create mode 100644 db/perl.BerkeleyDB/t/queue.t create mode 100644 db/perl.BerkeleyDB/t/recno.t create mode 100644 db/perl.BerkeleyDB/t/strict.t create mode 100644 db/perl.BerkeleyDB/t/subdb.t create mode 100644 db/perl.BerkeleyDB/t/txn.t create mode 100644 db/perl.BerkeleyDB/t/unknown.t create mode 100644 db/perl.BerkeleyDB/typemap create mode 100644 db/perl.DB_File/Changes create mode 100644 db/perl.DB_File/DB_File.pm create mode 100644 db/perl.DB_File/DB_File.xs create mode 100644 db/perl.DB_File/DB_File_BS create mode 100644 db/perl.DB_File/MANIFEST create mode 100644 db/perl.DB_File/Makefile.PL create mode 100644 db/perl.DB_File/README create mode 100644 db/perl.DB_File/config.in create mode 100644 db/perl.DB_File/dbinfo create mode 100644 db/perl.DB_File/hints/dynixptx.pl create mode 100644 db/perl.DB_File/hints/sco.pl create mode 100644 db/perl.DB_File/patches/5.004 create mode 100644 db/perl.DB_File/patches/5.004_01 create mode 100644 db/perl.DB_File/patches/5.004_02 create mode 100644 db/perl.DB_File/patches/5.004_03 create mode 100644 db/perl.DB_File/patches/5.004_04 create mode 100644 db/perl.DB_File/patches/5.004_05 create mode 100644 db/perl.DB_File/patches/5.005 create mode 100644 db/perl.DB_File/patches/5.005_01 create mode 100644 db/perl.DB_File/patches/5.005_02 create mode 100644 db/perl.DB_File/patches/5.005_03 create mode 100644 db/perl.DB_File/patches/5.6.0 create mode 100644 db/perl.DB_File/t/db-btree.t create mode 100644 db/perl.DB_File/t/db-hash.t create mode 100644 db/perl.DB_File/t/db-recno.t create mode 100644 db/perl.DB_File/typemap create mode 100644 db/perl.DB_File/version.c create mode 100644 db/qam/qam.c create mode 100644 db/qam/qam.src create mode 100644 db/qam/qam_auto.c create mode 100644 db/qam/qam_conv.c create mode 100644 db/qam/qam_files.c create mode 100644 db/qam/qam_method.c create mode 100644 db/qam/qam_open.c create mode 100644 db/qam/qam_rec.c create mode 100644 db/qam/qam_stat.c create mode 100644 db/qam/qam_upgrade.c create mode 100644 db/qam/qam_verify.c create mode 100644 db/rpc_client/client.c create mode 100644 db/rpc_client/db_server_clnt.c create mode 100644 db/rpc_client/gen_client.c create mode 100644 db/rpc_client/gen_client_ret.c create mode 100644 db/rpc_server/clsrv.html create mode 100644 db/rpc_server/db_server.sed create mode 100644 db/rpc_server/db_server.x create mode 100644 db/rpc_server/db_server_proc.c create mode 100644 db/rpc_server/db_server_proc.sed create mode 100644 db/rpc_server/db_server_svc.c create mode 100644 db/rpc_server/db_server_svc.sed create mode 100644 db/rpc_server/db_server_util.c create mode 100644 db/rpc_server/db_server_xdr.c create mode 100644 db/rpc_server/gen_db_server.c create mode 100644 db/rpc_server/rpc.src create mode 100644 db/tcl/docs/db.html create mode 100644 db/tcl/docs/env.html create mode 100644 db/tcl/docs/historic.html create mode 100644 db/tcl/docs/index.html create mode 100644 db/tcl/docs/library.html create mode 100644 db/tcl/docs/lock.html create mode 100644 db/tcl/docs/log.html create mode 100644 db/tcl/docs/mpool.html create mode 100644 db/tcl/docs/test.html create mode 100644 db/tcl/docs/txn.html create mode 100644 db/tcl/tcl_compat.c create mode 100644 db/tcl/tcl_db.c create mode 100644 db/tcl/tcl_db_pkg.c create mode 100644 db/tcl/tcl_dbcursor.c create mode 100644 db/tcl/tcl_env.c create mode 100644 db/tcl/tcl_internal.c create mode 100644 db/tcl/tcl_lock.c create mode 100644 db/tcl/tcl_log.c create mode 100644 db/tcl/tcl_mp.c create mode 100644 db/tcl/tcl_txn.c create mode 100644 db/test/TESTS create mode 100644 db/test/archive.tcl create mode 100644 db/test/byteorder.tcl create mode 100644 db/test/conscript.tcl create mode 100644 db/test/dbm.tcl create mode 100644 db/test/dbscript.tcl create mode 100644 db/test/ddscript.tcl create mode 100644 db/test/dead001.tcl create mode 100644 db/test/dead002.tcl create mode 100644 db/test/dead003.tcl create mode 100644 db/test/env001.tcl create mode 100644 db/test/env002.tcl create mode 100644 db/test/env003.tcl create mode 100644 db/test/env004.tcl create mode 100644 db/test/env005.tcl create mode 100644 db/test/env006.tcl create mode 100644 db/test/env007.tcl create mode 100644 db/test/env008.tcl create mode 100644 db/test/hsearch.tcl create mode 100644 db/test/include.tcl create mode 100644 db/test/join.tcl create mode 100644 db/test/lock001.tcl create mode 100644 db/test/lock002.tcl create mode 100644 db/test/lock003.tcl create mode 100644 db/test/lockscript.tcl create mode 100644 db/test/log.tcl create mode 100644 db/test/logtrack.list create mode 100644 db/test/logtrack.tcl create mode 100644 db/test/mdbscript.tcl create mode 100644 db/test/mpool.tcl create mode 100644 db/test/mpoolscript.tcl create mode 100644 db/test/mutex.tcl create mode 100644 db/test/mutexscript.tcl create mode 100644 db/test/ndbm.tcl create mode 100644 db/test/recd001.tcl create mode 100644 db/test/recd002.tcl create mode 100644 db/test/recd003.tcl create mode 100644 db/test/recd004.tcl create mode 100644 db/test/recd005.tcl create mode 100644 db/test/recd006.tcl create mode 100644 db/test/recd007.tcl create mode 100644 db/test/recd008.tcl create mode 100644 db/test/recd009.tcl create mode 100644 db/test/recd010.tcl create mode 100644 db/test/recd011.tcl create mode 100644 db/test/recd012.tcl create mode 100644 db/test/recd013.tcl create mode 100644 db/test/recd014.tcl create mode 100644 db/test/rpc001.tcl create mode 100644 db/test/rpc002.tcl create mode 100644 db/test/rsrc001.tcl create mode 100644 db/test/rsrc002.tcl create mode 100644 db/test/rsrc003.tcl create mode 100644 db/test/sdb001.tcl create mode 100644 db/test/sdb002.tcl create mode 100644 db/test/sdb003.tcl create mode 100644 db/test/sdb004.tcl create mode 100644 db/test/sdb005.tcl create mode 100644 db/test/sdb006.tcl create mode 100644 db/test/sdb007.tcl create mode 100644 db/test/sdb008.tcl create mode 100644 db/test/sdb009.tcl create mode 100644 db/test/sdb010.tcl create mode 100644 db/test/sdbscript.tcl create mode 100644 db/test/sdbtest001.tcl create mode 100644 db/test/sdbtest002.tcl create mode 100644 db/test/sdbutils.tcl create mode 100644 db/test/sysscript.tcl create mode 100644 db/test/test.tcl create mode 100644 db/test/test001.tcl create mode 100644 db/test/test002.tcl create mode 100644 db/test/test003.tcl create mode 100644 db/test/test004.tcl create mode 100644 db/test/test005.tcl create mode 100644 db/test/test006.tcl create mode 100644 db/test/test007.tcl create mode 100644 db/test/test008.tcl create mode 100644 db/test/test009.tcl create mode 100644 db/test/test010.tcl create mode 100644 db/test/test011.tcl create mode 100644 db/test/test012.tcl create mode 100644 db/test/test013.tcl create mode 100644 db/test/test014.tcl create mode 100644 db/test/test015.tcl create mode 100644 db/test/test016.tcl create mode 100644 db/test/test017.tcl create mode 100644 db/test/test018.tcl create mode 100644 db/test/test019.tcl create mode 100644 db/test/test020.tcl create mode 100644 db/test/test021.tcl create mode 100644 db/test/test022.tcl create mode 100644 db/test/test023.tcl create mode 100644 db/test/test024.tcl create mode 100644 db/test/test025.tcl create mode 100644 db/test/test026.tcl create mode 100644 db/test/test027.tcl create mode 100644 db/test/test028.tcl create mode 100644 db/test/test029.tcl create mode 100644 db/test/test030.tcl create mode 100644 db/test/test031.tcl create mode 100644 db/test/test032.tcl create mode 100644 db/test/test033.tcl create mode 100644 db/test/test034.tcl create mode 100644 db/test/test035.tcl create mode 100644 db/test/test036.tcl create mode 100644 db/test/test037.tcl create mode 100644 db/test/test038.tcl create mode 100644 db/test/test039.tcl create mode 100644 db/test/test040.tcl create mode 100644 db/test/test041.tcl create mode 100644 db/test/test042.tcl create mode 100644 db/test/test043.tcl create mode 100644 db/test/test044.tcl create mode 100644 db/test/test045.tcl create mode 100644 db/test/test046.tcl create mode 100644 db/test/test047.tcl create mode 100644 db/test/test048.tcl create mode 100644 db/test/test049.tcl create mode 100644 db/test/test050.tcl create mode 100644 db/test/test051.tcl create mode 100644 db/test/test052.tcl create mode 100644 db/test/test053.tcl create mode 100644 db/test/test054.tcl create mode 100644 db/test/test055.tcl create mode 100644 db/test/test056.tcl create mode 100644 db/test/test057.tcl create mode 100644 db/test/test058.tcl create mode 100644 db/test/test059.tcl create mode 100644 db/test/test060.tcl create mode 100644 db/test/test061.tcl create mode 100644 db/test/test062.tcl create mode 100644 db/test/test063.tcl create mode 100644 db/test/test064.tcl create mode 100644 db/test/test065.tcl create mode 100644 db/test/test066.tcl create mode 100644 db/test/test067.tcl create mode 100644 db/test/test068.tcl create mode 100644 db/test/test069.tcl create mode 100644 db/test/test070.tcl create mode 100644 db/test/test071.tcl create mode 100644 db/test/test072.tcl create mode 100644 db/test/test073.tcl create mode 100644 db/test/test074.tcl create mode 100644 db/test/test075.tcl create mode 100644 db/test/test076.tcl create mode 100644 db/test/test077.tcl create mode 100644 db/test/test078.tcl create mode 100644 db/test/test079.tcl create mode 100644 db/test/test080.tcl create mode 100644 db/test/test081.tcl create mode 100644 db/test/test082.tcl create mode 100644 db/test/test083.tcl create mode 100644 db/test/test084.tcl create mode 100644 db/test/test085.tcl create mode 100644 db/test/test086.tcl create mode 100644 db/test/test087.tcl create mode 100644 db/test/test088.tcl create mode 100644 db/test/test090.tcl create mode 100644 db/test/test091.tcl create mode 100644 db/test/testparams.tcl create mode 100644 db/test/testutils.tcl create mode 100644 db/test/txn.tcl create mode 100644 db/test/update.tcl create mode 100644 db/test/upgrade.tcl create mode 100644 db/test/upgrade/README create mode 100644 db/test/upgrade/generate-2.X/pack-2.6.6.pl create mode 100644 db/test/upgrade/generate-2.X/test-2.6.patch create mode 100644 db/test/wordlist create mode 100644 db/test/wrap.tcl create mode 100644 db/txn/txn.c create mode 100644 db/txn/txn.src create mode 100644 db/txn/txn_auto.c create mode 100644 db/txn/txn_rec.c create mode 100644 db/txn/txn_region.c create mode 100644 db/xa/xa.c create mode 100644 db/xa/xa_db.c create mode 100644 db/xa/xa_map.c (limited to 'db') diff --git a/db/LICENSE b/db/LICENSE new file mode 100644 index 000000000..32cc483d6 --- /dev/null +++ b/db/LICENSE @@ -0,0 +1,102 @@ +/*- + * $Id: LICENSE,v 11.7 2000/11/01 20:35:49 bostic Exp $ + */ + +The following is the license that applies to this copy of the Berkeley DB +software. For a license to use the Berkeley DB software under conditions +other than those described here, or to purchase support for this software, +please contact Sleepycat Software by email at db@sleepycat.com, or on the +Web at http://www.sleepycat.com. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +/* + * Copyright (c) 1990-2000 + * Sleepycat Software. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Redistributions in any form must be accompanied by information on + * how to obtain complete source code for the DB software and any + * accompanying software that uses the DB software. The source code + * must either be included in the distribution or be available for no + * more than the cost of distribution plus a nominal fee, and must be + * freely redistributable under reasonable conditions. For an + * executable file, complete source code means the source code for all + * modules it contains. It does not include source code for modules or + * files that typically accompany the major components of the operating + * system on which the executable file runs. + * + * THIS SOFTWARE IS PROVIDED BY SLEEPYCAT SOFTWARE ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL SLEEPYCAT SOFTWARE + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1990, 1993, 1994, 1995 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * Copyright (c) 1995, 1996 + * The President and Fellows of Harvard University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY HARVARD AND ITS CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL HARVARD OR ITS CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ diff --git a/db/README b/db/README new file mode 100644 index 000000000..f9892d5cb --- /dev/null +++ b/db/README @@ -0,0 +1,5 @@ +Sleepycat Software: Berkeley DB 3.2.9: (January 24, 2001) + +This is version 3.2.9 of Berkeley DB from Sleepycat Software. To view +the release and installation documentation, load the distribution file +docs/index.html into your web browser. diff --git a/db/btree/bt_compare.c b/db/btree/bt_compare.c new file mode 100644 index 000000000..91481c313 --- /dev/null +++ b/db/btree/bt_compare.c @@ -0,0 +1,211 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994, 1995 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Mike Olson. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: bt_compare.c,v 11.12 2000/10/26 19:00:28 krinsky Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "btree.h" + +/* + * __bam_cmp -- + * Compare a key to a given record. + * + * PUBLIC: int __bam_cmp __P((DB *, const DBT *, PAGE *, + * PUBLIC: u_int32_t, int (*)(DB *, const DBT *, const DBT *), int *)); + */ +int +__bam_cmp(dbp, dbt, h, indx, func, cmpp) + DB *dbp; + const DBT *dbt; + PAGE *h; + u_int32_t indx; + int (*func)__P((DB *, const DBT *, const DBT *)); + int *cmpp; +{ + BINTERNAL *bi; + BKEYDATA *bk; + BOVERFLOW *bo; + DBT pg_dbt; + + /* + * Returns: + * < 0 if dbt is < page record + * = 0 if dbt is = page record + * > 0 if dbt is > page record + * + * !!! + * We do not clear the pg_dbt DBT even though it's likely to contain + * random bits. That should be okay, because the app's comparison + * routine had better not be looking at fields other than data/size. + * We don't clear it because we go through this path a lot and it's + * expensive. + */ + switch (TYPE(h)) { + case P_LBTREE: + case P_LDUP: + case P_LRECNO: + bk = GET_BKEYDATA(h, indx); + if (B_TYPE(bk->type) == B_OVERFLOW) + bo = (BOVERFLOW *)bk; + else { + pg_dbt.data = bk->data; + pg_dbt.size = bk->len; + *cmpp = func(dbp, dbt, &pg_dbt); + return (0); + } + break; + case P_IBTREE: + /* + * The following code guarantees that the left-most key on an + * internal page at any place in the tree sorts less than any + * user-specified key. The reason is that if we have reached + * this internal page, we know the user key must sort greater + * than the key we're storing for this page in any internal + * pages at levels above us in the tree. It then follows that + * any user-specified key cannot sort less than the first page + * which we reference, and so there's no reason to call the + * comparison routine. While this may save us a comparison + * routine call or two, the real reason for this is because + * we don't maintain a copy of the smallest key in the tree, + * so that we don't have to update all the levels of the tree + * should the application store a new smallest key. And, so, + * we may not have a key to compare, which makes doing the + * comparison difficult and error prone. + */ + if (indx == 0) { + *cmpp = 1; + return (0); + } + + bi = GET_BINTERNAL(h, indx); + if (B_TYPE(bi->type) == B_OVERFLOW) + bo = (BOVERFLOW *)(bi->data); + else { + pg_dbt.data = bi->data; + pg_dbt.size = bi->len; + *cmpp = func(dbp, dbt, &pg_dbt); + return (0); + } + break; + default: + return (__db_pgfmt(dbp, PGNO(h))); + } + + /* + * Overflow. + */ + return (__db_moff(dbp, dbt, + bo->pgno, bo->tlen, func == __bam_defcmp ? NULL : func, cmpp)); +} + +/* + * __bam_defcmp -- + * Default comparison routine. + * + * PUBLIC: int __bam_defcmp __P((DB *, const DBT *, const DBT *)); + */ +int +__bam_defcmp(dbp, a, b) + DB *dbp; + const DBT *a, *b; +{ + size_t len; + u_int8_t *p1, *p2; + + COMPQUIET(dbp, NULL); + + /* + * Returns: + * < 0 if a is < b + * = 0 if a is = b + * > 0 if a is > b + * + * XXX + * If a size_t doesn't fit into a long, or if the difference between + * any two characters doesn't fit into an int, this routine can lose. + * What we need is a signed integral type that's guaranteed to be at + * least as large as a size_t, and there is no such thing. + */ + len = a->size > b->size ? b->size : a->size; + for (p1 = a->data, p2 = b->data; len--; ++p1, ++p2) + if (*p1 != *p2) + return ((long)*p1 - (long)*p2); + return ((long)a->size - (long)b->size); +} + +/* + * __bam_defpfx -- + * Default prefix routine. + * + * PUBLIC: size_t __bam_defpfx __P((DB *, const DBT *, const DBT *)); + */ +size_t +__bam_defpfx(dbp, a, b) + DB *dbp; + const DBT *a, *b; +{ + size_t cnt, len; + u_int8_t *p1, *p2; + + COMPQUIET(dbp, NULL); + + cnt = 1; + len = a->size > b->size ? b->size : a->size; + for (p1 = a->data, p2 = b->data; len--; ++p1, ++p2, ++cnt) + if (*p1 != *p2) + return (cnt); + + /* + * We know that a->size must be <= b->size, or they wouldn't be + * in this order. + */ + return (a->size < b->size ? a->size + 1 : a->size); +} diff --git a/db/btree/bt_conv.c b/db/btree/bt_conv.c new file mode 100644 index 000000000..fd30f375f --- /dev/null +++ b/db/btree/bt_conv.c @@ -0,0 +1,98 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: bt_conv.c,v 11.6 2000/03/31 00:30:26 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_swap.h" +#include "btree.h" + +/* + * __bam_pgin -- + * Convert host-specific page layout from the host-independent format + * stored on disk. + * + * PUBLIC: int __bam_pgin __P((DB_ENV *, db_pgno_t, void *, DBT *)); + */ +int +__bam_pgin(dbenv, pg, pp, cookie) + DB_ENV *dbenv; + db_pgno_t pg; + void *pp; + DBT *cookie; +{ + DB_PGINFO *pginfo; + PAGE *h; + + pginfo = (DB_PGINFO *)cookie->data; + if (!pginfo->needswap) + return (0); + + h = pp; + return (TYPE(h) == P_BTREEMETA ? __bam_mswap(pp) : + __db_byteswap(dbenv, pg, pp, pginfo->db_pagesize, 1)); +} + +/* + * __bam_pgout -- + * Convert host-specific page layout to the host-independent format + * stored on disk. + * + * PUBLIC: int __bam_pgout __P((DB_ENV *, db_pgno_t, void *, DBT *)); + */ +int +__bam_pgout(dbenv, pg, pp, cookie) + DB_ENV *dbenv; + db_pgno_t pg; + void *pp; + DBT *cookie; +{ + DB_PGINFO *pginfo; + PAGE *h; + + pginfo = (DB_PGINFO *)cookie->data; + if (!pginfo->needswap) + return (0); + + h = pp; + return (TYPE(h) == P_BTREEMETA ? __bam_mswap(pp) : + __db_byteswap(dbenv, pg, pp, pginfo->db_pagesize, 0)); +} + +/* + * __bam_mswap -- + * Swap the bytes on the btree metadata page. + * + * PUBLIC: int __bam_mswap __P((PAGE *)); + */ +int +__bam_mswap(pg) + PAGE *pg; +{ + u_int8_t *p; + + __db_metaswap(pg); + + p = (u_int8_t *)pg + sizeof(DBMETA); + + SWAP32(p); /* maxkey */ + SWAP32(p); /* minkey */ + SWAP32(p); /* re_len */ + SWAP32(p); /* re_pad */ + SWAP32(p); /* root */ + + return (0); +} diff --git a/db/btree/bt_curadj.c b/db/btree/bt_curadj.c new file mode 100644 index 000000000..011acd2f4 --- /dev/null +++ b/db/btree/bt_curadj.c @@ -0,0 +1,573 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: bt_curadj.c,v 11.20 2001/01/17 16:15:49 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "btree.h" +#include "txn.h" + +static int __bam_opd_cursor __P((DB *, DBC *, db_pgno_t, u_int32_t, u_int32_t)); + +#ifdef DEBUG +/* + * __bam_cprint -- + * Display the current internal cursor. + * + * PUBLIC: void __bam_cprint __P((DBC *)); + */ +void +__bam_cprint(dbc) + DBC *dbc; +{ + BTREE_CURSOR *cp; + + cp = (BTREE_CURSOR *)dbc->internal; + + fprintf(stderr, "\tinternal: ovflsize: %lu", (u_long)cp->ovflsize); + if (dbc->dbtype == DB_RECNO) + fprintf(stderr, " recno: %lu", (u_long)cp->recno); + if (F_ISSET(cp, C_DELETED)) + fprintf(stderr, " (deleted)"); + fprintf(stderr, "\n"); +} +#endif + +/* + * Cursor adjustments are logged if they are for subtransactions. This is + * because it's possible for a subtransaction to adjust cursors which will + * still be active after the subtransaction aborts, and so which must be + * restored to their previous locations. Cursors that can be both affected + * by our cursor adjustments and active after our transaction aborts can + * only be found in our parent transaction -- cursors in other transactions, + * including other child transactions of our parent, must have conflicting + * locker IDs, and so cannot be affected by adjustments in this transaction. + */ + +/* + * __bam_ca_delete -- + * Update the cursors when items are deleted and when already deleted + * items are overwritten. Return the number of relevant cursors found. + * + * PUBLIC: int __bam_ca_delete __P((DB *, db_pgno_t, u_int32_t, int)); + */ +int +__bam_ca_delete(dbp, pgno, indx, delete) + DB *dbp; + db_pgno_t pgno; + u_int32_t indx; + int delete; +{ + BTREE_CURSOR *cp; + DB *ldbp; + DB_ENV *dbenv; + DBC *dbc; + int count; /* !!!: Has to contain max number of cursors. */ + + dbenv = dbp->dbenv; + + /* + * Adjust the cursors. We have the page write locked, so the + * only other cursors that can be pointing at a page are + * those in the same thread of control. Unfortunately, we don't + * know that they're using the same DB handle, so traverse + * all matching DB handles in the same DB_ENV, then all cursors + * on each matching DB handle. + * + * Each cursor is single-threaded, so we only need to lock the + * list of DBs and then the list of cursors in each DB. + */ + MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp); + for (count = 0, ldbp = __dblist_get(dbenv, dbp->adj_fileid); + ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid; + ldbp = LIST_NEXT(ldbp, dblistlinks)) { + MUTEX_THREAD_LOCK(dbenv, dbp->mutexp); + for (dbc = TAILQ_FIRST(&ldbp->active_queue); + dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) { + cp = (BTREE_CURSOR *)dbc->internal; + if (cp->pgno == pgno && cp->indx == indx) { + if (delete) + F_SET(cp, C_DELETED); + else + F_CLR(cp, C_DELETED); + ++count; + } + } + MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp); + } + MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp); + + return (count); +} + +/* + * __ram_ca_delete -- + * Return the number of relevant cursors. + * + * PUBLIC: int __ram_ca_delete __P((DB *, db_pgno_t)); + */ +int +__ram_ca_delete(dbp, root_pgno) + DB *dbp; + db_pgno_t root_pgno; +{ + DB *ldbp; + DBC *dbc; + DB_ENV *dbenv; + int found; + + found = 0; + dbenv = dbp->dbenv; + + /* + * Review the cursors. See the comment in __bam_ca_delete(). + */ + MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp); + for (ldbp = __dblist_get(dbenv, dbp->adj_fileid); + found == 0 && ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid; + ldbp = LIST_NEXT(ldbp, dblistlinks)) { + MUTEX_THREAD_LOCK(dbenv, dbp->mutexp); + for (dbc = TAILQ_FIRST(&ldbp->active_queue); + found == 0 && dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) + if (dbc->internal->root == root_pgno) + found = 1; + MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp); + } + MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp); + return (found); +} + +/* + * __bam_ca_di -- + * Adjust the cursors during a delete or insert. + * + * PUBLIC: int __bam_ca_di __P((DBC *, db_pgno_t, u_int32_t, int)); + */ +int +__bam_ca_di(my_dbc, pgno, indx, adjust) + DBC *my_dbc; + db_pgno_t pgno; + u_int32_t indx; + int adjust; +{ + DB *dbp, *ldbp; + DB_ENV *dbenv; + DB_LSN lsn; + DB_TXN *my_txn; + DBC *dbc; + DBC_INTERNAL *cp; + int found, ret; + + dbp = my_dbc->dbp; + dbenv = dbp->dbenv; + + my_txn = IS_SUBTRANSACTION(my_dbc->txn) ? my_dbc->txn : NULL; + + /* + * Adjust the cursors. See the comment in __bam_ca_delete(). + */ + found = 0; + MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp); + for (ldbp = __dblist_get(dbenv, dbp->adj_fileid); + ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid; + ldbp = LIST_NEXT(ldbp, dblistlinks)) { + MUTEX_THREAD_LOCK(dbenv, dbp->mutexp); + for (dbc = TAILQ_FIRST(&ldbp->active_queue); + dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) { + if (dbc->dbtype == DB_RECNO) + continue; + cp = dbc->internal; + if (cp->pgno == pgno && cp->indx >= indx) { + /* Cursor indices should never be negative. */ + DB_ASSERT(cp->indx != 0 || adjust > 0); + + cp->indx += adjust; + if (my_txn != NULL && dbc->txn != my_txn) + found = 1; + } + } + MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp); + } + MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp); + + if (found != 0 && DB_LOGGING(my_dbc)) { + if ((ret = __bam_curadj_log(dbenv, + my_dbc->txn, &lsn, 0, dbp->log_fileid, + DB_CA_DI, pgno, 0, 0, adjust, indx, 0)) != 0) + return (ret); + } + + return (0); +} + +/* + * __bam_opd_cursor -- create a new opd cursor. + */ +static int +__bam_opd_cursor(dbp, dbc, first, tpgno, ti) + DB *dbp; + DBC *dbc; + db_pgno_t tpgno; + u_int32_t first, ti; +{ + BTREE_CURSOR *cp, *orig_cp; + DBC *dbc_nopd; + int ret; + + orig_cp = (BTREE_CURSOR *)dbc->internal; + dbc_nopd = NULL; + + /* + * Allocate a new cursor and create the stack. If duplicates + * are sorted, we've just created an off-page duplicate Btree. + * If duplicates aren't sorted, we've just created a Recno tree. + */ + if ((ret = __db_c_newopd(dbc, tpgno, &dbc_nopd)) != 0) + return (ret); + + cp = (BTREE_CURSOR *)dbc_nopd->internal; + cp->pgno = tpgno; + cp->indx = ti; + + if (dbp->dup_compare == NULL) { + /* + * Converting to off-page Recno trees is tricky. The + * record number for the cursor is the index + 1 (to + * convert to 1-based record numbers). + */ + cp->recno = ti + 1; + } + + /* + * Transfer the deleted flag from the top-level cursor to the + * created one. + */ + if (F_ISSET(orig_cp, C_DELETED)) { + F_SET(cp, C_DELETED); + F_CLR(orig_cp, C_DELETED); + } + + /* Stack the cursors and reset the initial cursor's index. */ + orig_cp->opd = dbc_nopd; + orig_cp->indx = first; + return (0); +} + +/* + * __bam_ca_dup -- + * Adjust the cursors when moving items from a leaf page to a duplicates + * page. + * + * PUBLIC: int __bam_ca_dup __P((DBC *, + * PUBLIC: u_int32_t, db_pgno_t, u_int32_t, db_pgno_t, u_int32_t)); + */ +int +__bam_ca_dup(my_dbc, first, fpgno, fi, tpgno, ti) + DBC *my_dbc; + db_pgno_t fpgno, tpgno; + u_int32_t first, fi, ti; +{ + BTREE_CURSOR *orig_cp; + DB *dbp, *ldbp; + DBC *dbc; + DB_ENV *dbenv; + DB_LSN lsn; + DB_TXN *my_txn; + int found, ret; + + dbp = my_dbc->dbp; + dbenv = dbp->dbenv; + my_txn = IS_SUBTRANSACTION(my_dbc->txn) ? my_dbc->txn : NULL; + + /* + * Adjust the cursors. See the comment in __bam_ca_delete(). + */ + found = 0; + MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp); + for (ldbp = __dblist_get(dbenv, dbp->adj_fileid); + ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid; + ldbp = LIST_NEXT(ldbp, dblistlinks)) { +loop: MUTEX_THREAD_LOCK(dbenv, dbp->mutexp); + for (dbc = TAILQ_FIRST(&ldbp->active_queue); + dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) { + /* Find cursors pointing to this record. */ + orig_cp = (BTREE_CURSOR *)dbc->internal; + if (orig_cp->pgno != fpgno || orig_cp->indx != fi) + continue; + + /* + * Since we rescan the list see if this is already + * converted. + */ + if (orig_cp->opd != NULL) + continue; + + MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp); + if ((ret = __bam_opd_cursor(dbp, + dbc, first, tpgno, ti)) !=0) + return (ret); + if (my_txn != NULL && dbc->txn != my_txn) + found = 1; + /* We released the MUTEX to get a cursor, start over. */ + goto loop; + } + MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp); + } + MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp); + + if (found != 0 && DB_LOGGING(my_dbc)) { + if ((ret = __bam_curadj_log(dbenv, + my_dbc->txn, &lsn, 0, dbp->log_fileid, + DB_CA_DUP, fpgno, tpgno, 0, first, fi, ti)) != 0) + return (ret); + } + return (0); +} + +/* + * __bam_ca_undodup -- + * Adjust the cursors when returning items to a leaf page + * from a duplicate page. + * Called only during undo processing. + * + * PUBLIC: int __bam_ca_undodup __P((DB *, + * PUBLIC: u_int32_t, db_pgno_t, u_int32_t, u_int32_t)); + */ +int +__bam_ca_undodup(dbp, first, fpgno, fi, ti) + DB *dbp; + db_pgno_t fpgno; + u_int32_t first, fi, ti; +{ + BTREE_CURSOR *orig_cp; + DB *ldbp; + DBC *dbc; + DB_ENV *dbenv; + int ret; + + dbenv = dbp->dbenv; + + /* + * Adjust the cursors. See the comment in __bam_ca_delete(). + */ + MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp); + for (ldbp = __dblist_get(dbenv, dbp->adj_fileid); + ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid; + ldbp = LIST_NEXT(ldbp, dblistlinks)) { +loop: MUTEX_THREAD_LOCK(dbenv, dbp->mutexp); + for (dbc = TAILQ_FIRST(&ldbp->active_queue); + dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) { + orig_cp = (BTREE_CURSOR *)dbc->internal; + + if (orig_cp->pgno != fpgno || + orig_cp->indx != first || + ((BTREE_CURSOR *)orig_cp->opd->internal)->indx + != ti) + continue; + MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp); + if ((ret = orig_cp->opd->c_close(orig_cp->opd)) != 0) + return (ret); + orig_cp->opd = NULL; + orig_cp->indx = fi; + /* + * We released the MUTEX to free a cursor, + * start over. + */ + goto loop; + } + MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp); + } + MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp); + + return (0); +} + +/* + * __bam_ca_rsplit -- + * Adjust the cursors when doing reverse splits. + * + * PUBLIC: int __bam_ca_rsplit __P((DBC *, db_pgno_t, db_pgno_t)); + */ +int +__bam_ca_rsplit(my_dbc, fpgno, tpgno) + DBC* my_dbc; + db_pgno_t fpgno, tpgno; +{ + DB *dbp, *ldbp; + DBC *dbc; + DB_ENV *dbenv; + DB_LSN lsn; + DB_TXN *my_txn; + int found, ret; + + dbp = my_dbc->dbp; + dbenv = dbp->dbenv; + my_txn = IS_SUBTRANSACTION(my_dbc->txn) ? my_dbc->txn : NULL; + + /* + * Adjust the cursors. See the comment in __bam_ca_delete(). + */ + found = 0; + MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp); + for (ldbp = __dblist_get(dbenv, dbp->adj_fileid); + ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid; + ldbp = LIST_NEXT(ldbp, dblistlinks)) { + MUTEX_THREAD_LOCK(dbenv, dbp->mutexp); + for (dbc = TAILQ_FIRST(&ldbp->active_queue); + dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) { + if (dbc->dbtype == DB_RECNO) + continue; + if (dbc->internal->pgno == fpgno) { + dbc->internal->pgno = tpgno; + if (my_txn != NULL && dbc->txn != my_txn) + found = 1; + } + } + MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp); + } + MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp); + + if (found != 0 && DB_LOGGING(my_dbc)) { + if ((ret = __bam_curadj_log(dbenv, + my_dbc->txn, &lsn, 0, dbp->log_fileid, + DB_CA_RSPLIT, fpgno, tpgno, 0, 0, 0, 0)) != 0) + return (ret); + } + return (0); +} + +/* + * __bam_ca_split -- + * Adjust the cursors when splitting a page. + * + * PUBLIC: int __bam_ca_split __P((DBC *, + * PUBLIC: db_pgno_t, db_pgno_t, db_pgno_t, u_int32_t, int)); + */ +int +__bam_ca_split(my_dbc, ppgno, lpgno, rpgno, split_indx, cleft) + DBC *my_dbc; + db_pgno_t ppgno, lpgno, rpgno; + u_int32_t split_indx; + int cleft; +{ + DB *dbp, *ldbp; + DBC *dbc; + DBC_INTERNAL *cp; + DB_ENV *dbenv; + DB_LSN lsn; + DB_TXN *my_txn; + int found, ret; + + dbp = my_dbc->dbp; + dbenv = dbp->dbenv; + my_txn = IS_SUBTRANSACTION(my_dbc->txn) ? my_dbc->txn : NULL; + + /* + * Adjust the cursors. See the comment in __bam_ca_delete(). + * + * If splitting the page that a cursor was on, the cursor has to be + * adjusted to point to the same record as before the split. Most + * of the time we don't adjust pointers to the left page, because + * we're going to copy its contents back over the original page. If + * the cursor is on the right page, it is decremented by the number of + * records split to the left page. + */ + found = 0; + MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp); + for (ldbp = __dblist_get(dbenv, dbp->adj_fileid); + ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid; + ldbp = LIST_NEXT(ldbp, dblistlinks)) { + MUTEX_THREAD_LOCK(dbenv, dbp->mutexp); + for (dbc = TAILQ_FIRST(&ldbp->active_queue); + dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) { + if (dbc->dbtype == DB_RECNO) + continue; + cp = dbc->internal; + if (cp->pgno == ppgno) { + if (my_txn != NULL && dbc->txn != my_txn) + found = 1; + if (cp->indx < split_indx) { + if (cleft) + cp->pgno = lpgno; + } else { + cp->pgno = rpgno; + cp->indx -= split_indx; + } + } + } + MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp); + } + MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp); + + if (found != 0 && DB_LOGGING(my_dbc)) { + if ((ret = __bam_curadj_log(dbenv, my_dbc->txn, + &lsn, 0, dbp->log_fileid, DB_CA_SPLIT, ppgno, rpgno, + cleft ? lpgno : PGNO_INVALID, 0, split_indx, 0)) != 0) + return (ret); + } + + return (0); +} + +/* + * __bam_ca_undosplit -- + * Adjust the cursors when undoing a split of a page. + * If we grew a level we will execute this for both the + * left and the right pages. + * Called only during undo processing. + * + * PUBLIC: void __bam_ca_undosplit __P((DB *, + * PUBLIC: db_pgno_t, db_pgno_t, db_pgno_t, u_int32_t)); + */ +void +__bam_ca_undosplit(dbp, frompgno, topgno, lpgno, split_indx) + DB *dbp; + db_pgno_t frompgno, topgno, lpgno; + u_int32_t split_indx; +{ + DB *ldbp; + DBC *dbc; + DB_ENV *dbenv; + DBC_INTERNAL *cp; + + dbenv = dbp->dbenv; + + /* + * Adjust the cursors. See the comment in __bam_ca_delete(). + * + * When backing out a split, we move the cursor back + * to the original offset and bump it by the split_indx. + */ + MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp); + for (ldbp = __dblist_get(dbenv, dbp->adj_fileid); + ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid; + ldbp = LIST_NEXT(ldbp, dblistlinks)) { + MUTEX_THREAD_LOCK(dbenv, dbp->mutexp); + for (dbc = TAILQ_FIRST(&ldbp->active_queue); + dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) { + if (dbc->dbtype == DB_RECNO) + continue; + cp = dbc->internal; + if (cp->pgno == topgno) { + cp->pgno = frompgno; + cp->indx += split_indx; + } else if (cp->pgno == lpgno) + cp->pgno = frompgno; + } + MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp); + } + MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp); +} diff --git a/db/btree/bt_cursor.c b/db/btree/bt_cursor.c new file mode 100644 index 000000000..84ab7c807 --- /dev/null +++ b/db/btree/bt_cursor.c @@ -0,0 +1,2131 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: bt_cursor.c,v 11.88 2001/01/11 18:19:49 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_shash.h" +#include "btree.h" +#include "lock.h" +#include "qam.h" +#include "common_ext.h" + +static int __bam_c_close __P((DBC *, db_pgno_t, int *)); +static int __bam_c_del __P((DBC *)); +static int __bam_c_destroy __P((DBC *)); +static int __bam_c_first __P((DBC *)); +static int __bam_c_get __P((DBC *, DBT *, DBT *, u_int32_t, db_pgno_t *)); +static int __bam_c_getstack __P((DBC *)); +static int __bam_c_last __P((DBC *)); +static int __bam_c_next __P((DBC *, int)); +static int __bam_c_physdel __P((DBC *)); +static int __bam_c_prev __P((DBC *)); +static int __bam_c_put __P((DBC *, DBT *, DBT *, u_int32_t, db_pgno_t *)); +static void __bam_c_reset __P((BTREE_CURSOR *)); +static int __bam_c_search __P((DBC *, const DBT *, u_int32_t, int *)); +static int __bam_c_writelock __P((DBC *)); +static int __bam_getboth_finddatum __P((DBC *, DBT *)); +static int __bam_getbothc __P((DBC *, DBT *)); +static int __bam_isopd __P((DBC *, db_pgno_t *)); + +/* + * Acquire a new page/lock. If we hold a page/lock, discard the page, and + * lock-couple the lock. + * + * !!! + * We have to handle both where we have a lock to lock-couple and where we + * don't -- we don't duplicate locks when we duplicate cursors if we are + * running in a transaction environment as there's no point if locks are + * never discarded. This means that the cursor may or may not hold a lock. + */ +#undef ACQUIRE +#define ACQUIRE(dbc, mode, lpgno, lock, fpgno, pagep, ret) {\ + if ((pagep) != NULL) { \ + ret = memp_fput((dbc)->dbp->mpf, pagep, 0); \ + pagep = NULL; \ + } else \ + ret = 0; \ + if ((ret) == 0 && STD_LOCKING(dbc)) \ + ret = __db_lget(dbc, \ + (lock).off == LOCK_INVALID ? 0 : LCK_COUPLE, \ + lpgno, mode, 0, &lock); \ + else \ + (lock).off = LOCK_INVALID; \ + if ((ret) == 0) \ + ret = memp_fget((dbc)->dbp->mpf, &(fpgno), 0, &(pagep));\ +} + +/* Acquire a new page/lock for a cursor. */ +#undef ACQUIRE_CUR +#define ACQUIRE_CUR(dbc, mode, ret) { \ + BTREE_CURSOR *__cp = (BTREE_CURSOR *)(dbc)->internal; \ + ACQUIRE(dbc, mode, \ + __cp->pgno, __cp->lock, __cp->pgno, __cp->page, ret); \ + if ((ret) == 0) \ + __cp->lock_mode = (mode); \ +} + +/* + * Acquire a new page/lock for a cursor, and move the cursor on success. + * The reason that this is a separate macro is because we don't want to + * set the pgno/indx fields in the cursor until we actually have the lock, + * otherwise the cursor adjust routines will adjust the cursor even though + * we're not really on the page. + */ +#undef ACQUIRE_CUR_SET +#define ACQUIRE_CUR_SET(dbc, mode, p, ret) { \ + BTREE_CURSOR *__cp = (BTREE_CURSOR *)(dbc)->internal; \ + ACQUIRE(dbc, mode, p, __cp->lock, p, __cp->page, ret); \ + if ((ret) == 0) { \ + __cp->pgno = p; \ + __cp->indx = 0; \ + __cp->lock_mode = (mode); \ + } \ +} + +/* + * Acquire a write lock if we don't already have one. + * + * !!! + * See ACQUIRE macro on why we handle cursors that don't have locks. + */ +#undef ACQUIRE_WRITE_LOCK +#define ACQUIRE_WRITE_LOCK(dbc, ret) { \ + BTREE_CURSOR *__cp = (BTREE_CURSOR *)(dbc)->internal; \ + ret = 0; \ + if (STD_LOCKING(dbc) && \ + __cp->lock_mode != DB_LOCK_WRITE && \ + ((ret) = __db_lget(dbc, \ + __cp->lock.off == LOCK_INVALID ? 0 : LCK_COUPLE, \ + __cp->pgno, DB_LOCK_WRITE, 0, &__cp->lock)) == 0) \ + __cp->lock_mode = DB_LOCK_WRITE; \ +} + +/* Discard the current page/lock. */ +#undef DISCARD +#define DISCARD(dbc, ldiscard, lock, pagep, ret) { \ + int __t_ret; \ + if ((pagep) != NULL) { \ + ret = memp_fput((dbc)->dbp->mpf, pagep, 0); \ + pagep = NULL; \ + } else \ + ret = 0; \ + if ((lock).off != LOCK_INVALID) { \ + __t_ret = ldiscard ? \ + __LPUT((dbc), lock): __TLPUT((dbc), lock); \ + if (__t_ret != 0 && (ret) == 0) \ + ret = __t_ret; \ + (lock).off = LOCK_INVALID; \ + } \ +} + +/* Discard the current page/lock for a cursor. */ +#undef DISCARD_CUR +#define DISCARD_CUR(dbc, ret) { \ + BTREE_CURSOR *__cp = (BTREE_CURSOR *)(dbc)->internal; \ + DISCARD(dbc, 0, __cp->lock, __cp->page, ret); \ + if ((ret) == 0) \ + __cp->lock_mode = DB_LOCK_NG; \ +} + +/* If on-page item is a deleted record. */ +#undef IS_DELETED +#define IS_DELETED(page, indx) \ + B_DISSET(GET_BKEYDATA(page, \ + (indx) + (TYPE(page) == P_LBTREE ? O_INDX : 0))->type) +#undef IS_CUR_DELETED +#define IS_CUR_DELETED(dbc) \ + IS_DELETED((dbc)->internal->page, (dbc)->internal->indx) + +/* + * Test to see if two cursors could point to duplicates of the same key. + * In the case of off-page duplicates they are they same, as the cursors + * will be in the same off-page duplicate tree. In the case of on-page + * duplicates, the key index offsets must be the same. For the last test, + * as the original cursor may not have a valid page pointer, we use the + * current cursor's. + */ +#undef IS_DUPLICATE +#define IS_DUPLICATE(dbc, i1, i2) \ + (((PAGE *)(dbc)->internal->page)->inp[i1] == \ + ((PAGE *)(dbc)->internal->page)->inp[i2]) +#undef IS_CUR_DUPLICATE +#define IS_CUR_DUPLICATE(dbc, orig_pgno, orig_indx) \ + (F_ISSET(dbc, DBC_OPD) || \ + (orig_pgno == (dbc)->internal->pgno && \ + IS_DUPLICATE(dbc, (dbc)->internal->indx, orig_indx))) + +/* + * __bam_c_reset -- + * Initialize internal cursor structure. + */ +static void +__bam_c_reset(cp) + BTREE_CURSOR *cp; +{ + cp->csp = cp->sp; + cp->lock.off = LOCK_INVALID; + cp->lock_mode = DB_LOCK_NG; + cp->recno = RECNO_OOB; + cp->order = INVALID_ORDER; + cp->flags = 0; +} + +/* + * __bam_c_init -- + * Initialize the access private portion of a cursor + * + * PUBLIC: int __bam_c_init __P((DBC *, DBTYPE)); + */ +int +__bam_c_init(dbc, dbtype) + DBC *dbc; + DBTYPE dbtype; +{ + BTREE *t; + BTREE_CURSOR *cp; + DB *dbp; + int ret; + u_int32_t minkey; + + dbp = dbc->dbp; + + /* Allocate/initialize the internal structure. */ + if (dbc->internal == NULL) { + if ((ret = __os_malloc(dbp->dbenv, + sizeof(BTREE_CURSOR), NULL, &cp)) != 0) + return (ret); + dbc->internal = (DBC_INTERNAL *)cp; + + cp->sp = cp->csp = cp->stack; + cp->esp = cp->stack + sizeof(cp->stack) / sizeof(cp->stack[0]); + } else + cp = (BTREE_CURSOR *)dbc->internal; + __bam_c_reset(cp); + + /* Initialize methods. */ + dbc->c_close = __db_c_close; + dbc->c_count = __db_c_count; + dbc->c_del = __db_c_del; + dbc->c_dup = __db_c_dup; + dbc->c_get = __db_c_get; + dbc->c_put = __db_c_put; + if (dbtype == DB_BTREE) { + dbc->c_am_close = __bam_c_close; + dbc->c_am_del = __bam_c_del; + dbc->c_am_destroy = __bam_c_destroy; + dbc->c_am_get = __bam_c_get; + dbc->c_am_put = __bam_c_put; + dbc->c_am_writelock = __bam_c_writelock; + } else { + dbc->c_am_close = __bam_c_close; + dbc->c_am_del = __ram_c_del; + dbc->c_am_destroy = __bam_c_destroy; + dbc->c_am_get = __ram_c_get; + dbc->c_am_put = __ram_c_put; + dbc->c_am_writelock = __bam_c_writelock; + } + + /* + * The btree leaf page data structures require that two key/data pairs + * (or four items) fit on a page, but other than that there's no fixed + * requirement. The btree off-page duplicates only require two items, + * to be exact, but requiring four for them as well seems reasonable. + * + * Recno uses the btree bt_ovflsize value -- it's close enough. + */ + t = dbp->bt_internal; + minkey = F_ISSET(dbc, DBC_OPD) ? 2 : t->bt_minkey; + cp->ovflsize = B_MINKEY_TO_OVFLSIZE(minkey, dbp->pgsize); + + return (0); +} + +/* + * __bam_c_refresh + * Set things up properly for cursor re-use. + * + * PUBLIC: int __bam_c_refresh __P((DBC *)); + */ +int +__bam_c_refresh(dbc) + DBC *dbc; +{ + BTREE_CURSOR *cp; + DB *dbp; + + dbp = dbc->dbp; + cp = (BTREE_CURSOR *)dbc->internal; + __bam_c_reset(cp); + + /* + * If our caller set the root page number, it's because the root was + * known. This is always the case for off page dup cursors. Else, + * pull it out of our internal information. + */ + if (cp->root == PGNO_INVALID) + cp->root = ((BTREE *)dbp->bt_internal)->bt_root; + + /* Initialize for record numbers. */ + if (F_ISSET(dbc, DBC_OPD) || + dbc->dbtype == DB_RECNO || F_ISSET(dbp, DB_BT_RECNUM)) { + F_SET(cp, C_RECNUM); + + /* + * All btrees that support record numbers, optionally standard + * recno trees, and all off-page duplicate recno trees have + * mutable record numbers. + */ + if ((F_ISSET(dbc, DBC_OPD) && dbc->dbtype == DB_RECNO) || + F_ISSET(dbp, DB_BT_RECNUM | DB_RE_RENUMBER)) + F_SET(cp, C_RENUMBER); + } + + return (0); +} + +/* + * __bam_c_close -- + * Close down the cursor. + */ +static int +__bam_c_close(dbc, root_pgno, rmroot) + DBC *dbc; + db_pgno_t root_pgno; + int *rmroot; +{ + BTREE_CURSOR *cp, *cp_opd, *cp_c; + DB *dbp; + DBC *dbc_opd, *dbc_c; + PAGE *h; + u_int32_t num; + int cdb_lock, ret, t_ret; + + dbp = dbc->dbp; + cp = (BTREE_CURSOR *)dbc->internal; + cp_opd = (dbc_opd = cp->opd) == NULL ? + NULL : (BTREE_CURSOR *)dbc_opd->internal; + cdb_lock = ret = 0; + + /* + * There are 3 ways this function is called: + * + * 1. Closing a primary cursor: we get called with a pointer to a + * primary cursor that has a NULL opd field. This happens when + * closing a btree/recno database cursor without an associated + * off-page duplicate tree. + * + * 2. Closing a primary and an off-page duplicate cursor stack: we + * get called with a pointer to the primary cursor which has a + * non-NULL opd field. This happens when closing a btree cursor + * into database with an associated off-page btree/recno duplicate + * tree. (It can't be a primary recno database, recno databases + * don't support duplicates.) + * + * 3. Closing an off-page duplicate cursor stack: we get called with + * a pointer to the off-page duplicate cursor. This happens when + * closing a non-btree database that has an associated off-page + * btree/recno duplicate tree or for a btree database when the + * opd tree is not empty (root_pgno == PGNO_INVALID). + * + * If either the primary or off-page duplicate cursor deleted a btree + * key/data pair, check to see if the item is still referenced by a + * different cursor. If it is, confirm that cursor's delete flag is + * set and leave it to that cursor to do the delete. + * + * NB: The test for == 0 below is correct. Our caller already removed + * our cursor argument from the active queue, we won't find it when we + * search the queue in __bam_ca_delete(). + * NB: It can't be true that both the primary and off-page duplicate + * cursors have deleted a btree key/data pair. Either the primary + * cursor may have deleted an item and there's no off-page duplicate + * cursor, or there's an off-page duplicate cursor and it may have + * deleted an item. + * + * Primary recno databases aren't an issue here. Recno keys are either + * deleted immediately or never deleted, and do not have to be handled + * here. + * + * Off-page duplicate recno databases are an issue here, cases #2 and + * #3 above can both be off-page recno databases. The problem is the + * same as the final problem for off-page duplicate btree databases. + * If we no longer need the off-page duplicate tree, we want to remove + * it. For off-page duplicate btrees, we are done with the tree when + * we delete the last item it contains, i.e., there can be no further + * references to it when it's empty. For off-page duplicate recnos, + * we remove items from the tree as the application calls the remove + * function, so we are done with the tree when we close the last cursor + * that references it. + * + * We optionally take the root page number from our caller. If the + * primary database is a btree, we can get it ourselves because dbc + * is the primary cursor. If the primary database is not a btree, + * the problem is that we may be dealing with a stack of pages. The + * cursor we're using to do the delete points at the bottom of that + * stack and we need the top of the stack. + */ + if (F_ISSET(cp, C_DELETED)) { + dbc_c = dbc; + switch (dbc->dbtype) { + case DB_BTREE: /* Case #1, #3. */ + if (__bam_ca_delete(dbp, cp->pgno, cp->indx, 1) == 0) + goto lock; + goto done; + case DB_RECNO: + if (!F_ISSET(dbc, DBC_OPD)) /* Case #1. */ + goto done; + /* Case #3. */ + if (__ram_ca_delete(dbp, cp->root) == 0) + goto lock; + goto done; + default: + return (__db_unknown_type(dbp->dbenv, + "__bam_c_close", dbc->dbtype)); + } + } + + if (dbc_opd == NULL) + goto done; + + if (F_ISSET(cp_opd, C_DELETED)) { /* Case #2. */ + /* + * We will not have been provided a root page number. Acquire + * one from the primary database. + */ + if ((ret = memp_fget(dbp->mpf, &cp->pgno, 0, &h)) != 0) + goto err; + root_pgno = GET_BOVERFLOW(h, cp->indx + O_INDX)->pgno; + if ((ret = memp_fput(dbp->mpf, h, 0)) != 0) + goto err; + + dbc_c = dbc_opd; + switch (dbc_opd->dbtype) { + case DB_BTREE: + if (__bam_ca_delete( + dbp, cp_opd->pgno, cp_opd->indx, 1) == 0) + goto lock; + goto done; + case DB_RECNO: + if (__ram_ca_delete(dbp, cp_opd->root) == 0) + goto lock; + goto done; + default: + return (__db_unknown_type(dbp->dbenv, + "__bam_c_close", dbc->dbtype)); + } + } + goto done; + +lock: cp_c = (BTREE_CURSOR *)dbc_c->internal; + + /* + * If this is CDB, upgrade the lock if necessary. While we acquired + * the write lock to logically delete the record, we released it when + * we returned from that call, and so may not be holding a write lock + * at the moment. NB: to get here in CDB we must either be holding a + * write lock or be the only cursor that is permitted to acquire write + * locks. The reason is that there can never be more than a single CDB + * write cursor (that cursor cannot be dup'd), and so that cursor must + * be closed and the item therefore deleted before any other cursor + * could acquire a reference to this item. + * + * Note that dbc may be an off-page dup cursor; this is the sole + * instance in which an OPD cursor does any locking, but it's necessary + * because we may be closed by ourselves without a parent cursor + * handy, and we have to do a lock upgrade on behalf of somebody. + * If this is the case, the OPD has been given the parent's locking + * info in __db_c_get--the OPD is also a WRITEDUP. + */ + if (CDB_LOCKING(dbp->dbenv)) { + DB_ASSERT(!F_ISSET(dbc, DBC_OPD) || F_ISSET(dbc, DBC_WRITEDUP)); + if (!F_ISSET(dbc, DBC_WRITER)) { + if ((ret = + lock_get(dbp->dbenv, dbc->locker, DB_LOCK_UPGRADE, + &dbc->lock_dbt, DB_LOCK_WRITE, &dbc->mylock)) != 0) + goto err; + cdb_lock = 1; + } + + cp_c->lock.off = LOCK_INVALID; + if ((ret = + memp_fget(dbp->mpf, &cp_c->pgno, 0, &cp_c->page)) != 0) + goto err; + + goto delete; + } + + /* + * The variable dbc_c has been initialized to reference the cursor in + * which we're going to do the delete. Initialize the cursor's page + * and lock structures as necessary. + * + * First, we may not need to acquire any locks. If we're in case #3, + * that is, the primary database isn't a btree database, our caller + * is responsible for acquiring any necessary locks before calling us. + */ + if (F_ISSET(dbc, DBC_OPD)) { + cp_c->lock.off = LOCK_INVALID; + if ((ret = + memp_fget(dbp->mpf, &cp_c->pgno, 0, &cp_c->page)) != 0) + goto err; + goto delete; + } + + /* + * Otherwise, acquire a write lock. If the cursor that did the initial + * logical deletion (and which had a write lock) is not the same as the + * cursor doing the physical deletion (which may have only ever had a + * read lock on the item), we need to upgrade. The confusion comes as + * follows: + * + * C1 created, acquires item read lock + * C2 dup C1, create C2, also has item read lock. + * C1 acquire write lock, delete item + * C1 close + * C2 close, needs a write lock to physically delete item. + * + * If we're in a TXN, we know that C2 will be able to acquire the write + * lock, because no locker other than the one shared by C1 and C2 can + * acquire a write lock -- the original write lock C1 acquire was never + * discarded. + * + * If we're not in a TXN, it's nastier. Other cursors might acquire + * read locks on the item after C1 closed, discarding its write lock, + * and such locks would prevent C2 from acquiring a read lock. That's + * OK, though, we'll simply wait until we can acquire a read lock, or + * we'll deadlock. (Which better not happen, since we're not in a TXN.) + * + * Lock the primary database page, regardless of whether we're deleting + * an item on a primary database page or an off-page duplicates page. + */ + ACQUIRE(dbc, DB_LOCK_WRITE, + cp->pgno, cp_c->lock, cp_c->pgno, cp_c->page, ret); + if (ret != 0) + goto err; + +delete: /* + * If the delete occurred in a btree, delete the on-page physical item + * referenced by the cursor. + */ + if (dbc_c->dbtype == DB_BTREE && (ret = __bam_c_physdel(dbc_c)) != 0) + goto err; + + /* + * If we're not working in an off-page duplicate tree, then we're + * done. + */ + if (!F_ISSET(dbc_c, DBC_OPD) || root_pgno == PGNO_INVALID) + goto done; + + /* + * We may have just deleted the last element in the off-page duplicate + * tree, and closed the last cursor in the tree. For an off-page btree + * there are no other cursors in the tree by definition, if the tree is + * empty. For an off-page recno we know we have closed the last cursor + * in the tree because the __ram_ca_delete call above returned 0 only + * in that case. So, if the off-page duplicate tree is empty at this + * point, we want to remove it. + */ + if ((ret = memp_fget(dbp->mpf, &root_pgno, 0, &h)) != 0) + goto err; + if ((num = NUM_ENT(h)) == 0) { + if ((ret = __db_free(dbc, h)) != 0) + goto err; + } else { + if ((ret = memp_fput(dbp->mpf, h, 0)) != 0) + goto err; + goto done; + } + + /* + * When removing the tree, we have to do one of two things. If this is + * case #2, that is, the primary tree is a btree, delete the key that's + * associated with the tree from the btree leaf page. We know we are + * the only reference to it and we already have the correct lock. We + * detect this case because the cursor that was passed to us references + * an off-page duplicate cursor. + * + * If this is case #3, that is, the primary tree isn't a btree, pass + * the information back to our caller, it's their job to do cleanup on + * the primary page. + */ + if (dbc_opd != NULL) { + cp->lock.off = LOCK_INVALID; + if ((ret = memp_fget(dbp->mpf, &cp->pgno, 0, &cp->page)) != 0) + goto err; + if ((ret = __bam_c_physdel(dbc)) != 0) + goto err; + } else + *rmroot = 1; +err: +done: /* + * Discard the page references and locks, and confirm that the stack + * has been emptied. + */ + if (dbc_opd != NULL) { + DISCARD_CUR(dbc_opd, t_ret); + if (t_ret != 0 && ret == 0) + ret = t_ret; + } + DISCARD_CUR(dbc, t_ret); + if (t_ret != 0 && ret == 0) + ret = t_ret; + + /* Downgrade any CDB lock we acquired. */ + if (cdb_lock) + (void)__lock_downgrade( + dbp->dbenv, &dbc->mylock, DB_LOCK_IWRITE, 0); + + return (ret); +} + +/* + * __bam_c_destroy -- + * Close a single cursor -- internal version. + */ +static int +__bam_c_destroy(dbc) + DBC *dbc; +{ + /* Discard the structures. */ + __os_free(dbc->internal, sizeof(BTREE_CURSOR)); + + return (0); +} + +/* + * __bam_c_count -- + * Return a count of on and off-page duplicates. + * + * PUBLIC: int __bam_c_count __P((DBC *, db_recno_t *)); + */ +int +__bam_c_count(dbc, recnop) + DBC *dbc; + db_recno_t *recnop; +{ + BTREE_CURSOR *cp; + DB *dbp; + db_indx_t indx, top; + db_recno_t recno; + int ret; + + dbp = dbc->dbp; + cp = (BTREE_CURSOR *)dbc->internal; + + /* + * Called with the top-level cursor that may reference an off-page + * duplicates page. If it's a set of on-page duplicates, get the + * page and count. Otherwise, get the root page of the off-page + * duplicate tree, and use the count. We don't have to acquire any + * new locks, we have to have a read lock to even get here. + */ + if (cp->opd == NULL) { + if ((ret = memp_fget(dbp->mpf, &cp->pgno, 0, &cp->page)) != 0) + return (ret); + + /* + * Move back to the beginning of the set of duplicates and + * then count forward. + */ + for (indx = cp->indx;; indx -= P_INDX) + if (indx == 0 || + !IS_DUPLICATE(dbc, indx, indx - P_INDX)) + break; + for (recno = 1, top = NUM_ENT(cp->page) - P_INDX; + indx < top; ++recno, indx += P_INDX) + if (!IS_DUPLICATE(dbc, indx, indx + P_INDX)) + break; + *recnop = recno; + } else { + if ((ret = memp_fget(dbp->mpf, + &cp->opd->internal->root, 0, &cp->page)) != 0) + return (ret); + + *recnop = RE_NREC(cp->page); + } + + ret = memp_fput(dbp->mpf, cp->page, 0); + cp->page = NULL; + + return (ret); +} + +/* + * __bam_c_del -- + * Delete using a cursor. + */ +static int +__bam_c_del(dbc) + DBC *dbc; +{ + BTREE_CURSOR *cp; + DB *dbp; + int ret, t_ret; + + dbp = dbc->dbp; + cp = (BTREE_CURSOR *)dbc->internal; + ret = 0; + + /* If the item was already deleted, return failure. */ + if (F_ISSET(cp, C_DELETED)) + return (DB_KEYEMPTY); + + /* + * This code is always called with a page lock but no page. + */ + DB_ASSERT(cp->page == NULL); + + /* + * We don't physically delete the record until the cursor moves, so + * we have to have a long-lived write lock on the page instead of a + * a long-lived read lock. Note, we have to have a read lock to even + * get here. + * + * If we're maintaining record numbers, we lock the entire tree, else + * we lock the single page. + */ + if (F_ISSET(cp, C_RECNUM)) { + if ((ret = __bam_c_getstack(dbc)) != 0) + goto err; + cp->page = cp->csp->page; + } else { + ACQUIRE_CUR(dbc, DB_LOCK_WRITE, ret); + if (ret != 0) + goto err; + } + + /* Log the change. */ + if (DB_LOGGING(dbc) && + (ret = __bam_cdel_log(dbp->dbenv, dbc->txn, &LSN(cp->page), 0, + dbp->log_fileid, PGNO(cp->page), &LSN(cp->page), cp->indx)) != 0) + goto err; + + /* Set the intent-to-delete flag on the page. */ + if (TYPE(cp->page) == P_LBTREE) + B_DSET(GET_BKEYDATA(cp->page, cp->indx + O_INDX)->type); + else + B_DSET(GET_BKEYDATA(cp->page, cp->indx)->type); + + /* Mark the page dirty. */ + ret = memp_fset(dbp->mpf, cp->page, DB_MPOOL_DIRTY); + +err: /* + * If we've been successful so far and the tree has record numbers, + * adjust the record counts. Either way, release acquired page(s). + */ + if (F_ISSET(cp, C_RECNUM)) { + if (ret == 0) + ret = __bam_adjust(dbc, -1); + (void)__bam_stkrel(dbc, 0); + } else + if (cp->page != NULL && + (t_ret = memp_fput(dbp->mpf, cp->page, 0)) != 0 && ret == 0) + ret = t_ret; + + cp->page = NULL; + + /* Update the cursors last, after all chance of failure is past. */ + if (ret == 0) + (void)__bam_ca_delete(dbp, cp->pgno, cp->indx, 1); + + return (ret); +} + +/* + * __bam_c_dup -- + * Duplicate a btree cursor, such that the new one holds appropriate + * locks for the position of the original. + * + * PUBLIC: int __bam_c_dup __P((DBC *, DBC *)); + */ +int +__bam_c_dup(orig_dbc, new_dbc) + DBC *orig_dbc, *new_dbc; +{ + BTREE_CURSOR *orig, *new; + int ret; + + orig = (BTREE_CURSOR *)orig_dbc->internal; + new = (BTREE_CURSOR *)new_dbc->internal; + + /* + * If we're holding a lock we need to acquire a copy of it, unless + * we're in a transaction. We don't need to copy any lock we're + * holding inside a transaction because all the locks are retained + * until the transaction commits or aborts. + */ + if (orig->lock.off != LOCK_INVALID && orig_dbc->txn == NULL) { + if ((ret = __db_lget(new_dbc, + 0, new->pgno, new->lock_mode, 0, &new->lock)) != 0) + return (ret); + } + new->ovflsize = orig->ovflsize; + new->recno = orig->recno; + new->flags = orig->flags; + + return (0); +} + +/* + * __bam_c_get -- + * Get using a cursor (btree). + */ +static int +__bam_c_get(dbc, key, data, flags, pgnop) + DBC *dbc; + DBT *key, *data; + u_int32_t flags; + db_pgno_t *pgnop; +{ + BTREE_CURSOR *cp; + DB *dbp; + db_pgno_t orig_pgno; + db_indx_t orig_indx; + int exact, newopd, ret; + + dbp = dbc->dbp; + cp = (BTREE_CURSOR *)dbc->internal; + orig_pgno = cp->pgno; + orig_indx = cp->indx; + + newopd = 0; + switch (flags) { + case DB_CURRENT: + /* It's not possible to return a deleted record. */ + if (F_ISSET(cp, C_DELETED)) { + ret = DB_KEYEMPTY; + goto err; + } + + /* + * Acquire the current page. We have at least a read-lock + * already. The caller may have set DB_RMW asking for a + * write lock, but upgrading to a write lock has no better + * chance of succeeding now instead of later, so don't try. + */ + if ((ret = memp_fget(dbp->mpf, &cp->pgno, 0, &cp->page)) != 0) + goto err; + break; + case DB_FIRST: + newopd = 1; + if ((ret = __bam_c_first(dbc)) != 0) + goto err; + break; + case DB_GET_BOTH: + /* + * There are two ways to get here based on DBcursor->c_get + * with the DB_GET_BOTH flag set: + * + * 1. Searching a sorted off-page duplicate tree: do a tree + * search. + * + * 2. Searching btree: do a tree search. If it returns a + * reference to off-page duplicate tree, return immediately + * and let our caller deal with it. If the search doesn't + * return a reference to off-page duplicate tree, start an + * on-page search. + */ + if (F_ISSET(dbc, DBC_OPD)) { + if ((ret = __bam_c_search( + dbc, data, DB_GET_BOTH, &exact)) != 0) + goto err; + if (!exact) { + ret = DB_NOTFOUND; + goto err; + } + } else { + if ((ret = __bam_c_search( + dbc, key, DB_GET_BOTH, &exact)) != 0) + return (ret); + if (!exact) { + ret = DB_NOTFOUND; + goto err; + } + + if (pgnop != NULL && __bam_isopd(dbc, pgnop)) { + newopd = 1; + break; + } + if ((ret = __bam_getboth_finddatum(dbc, data)) != 0) + goto err; + } + break; + case DB_GET_BOTHC: + if ((ret = __bam_getbothc(dbc, data)) != 0) + goto err; + break; + case DB_LAST: + newopd = 1; + if ((ret = __bam_c_last(dbc)) != 0) + goto err; + break; + case DB_NEXT: + newopd = 1; + if (cp->pgno == PGNO_INVALID) { + if ((ret = __bam_c_first(dbc)) != 0) + goto err; + } else + if ((ret = __bam_c_next(dbc, 1)) != 0) + goto err; + break; + case DB_NEXT_DUP: + if ((ret = __bam_c_next(dbc, 1)) != 0) + goto err; + if (!IS_CUR_DUPLICATE(dbc, orig_pgno, orig_indx)) { + ret = DB_NOTFOUND; + goto err; + } + break; + case DB_NEXT_NODUP: + newopd = 1; + if (cp->pgno == PGNO_INVALID) { + if ((ret = __bam_c_first(dbc)) != 0) + goto err; + } else + do { + if ((ret = __bam_c_next(dbc, 1)) != 0) + goto err; + } while (IS_CUR_DUPLICATE(dbc, orig_pgno, orig_indx)); + break; + case DB_PREV: + newopd = 1; + if (cp->pgno == PGNO_INVALID) { + if ((ret = __bam_c_last(dbc)) != 0) + goto err; + } else + if ((ret = __bam_c_prev(dbc)) != 0) + goto err; + break; + case DB_PREV_NODUP: + newopd = 1; + if (cp->pgno == PGNO_INVALID) { + if ((ret = __bam_c_last(dbc)) != 0) + goto err; + } else + do { + if ((ret = __bam_c_prev(dbc)) != 0) + goto err; + } while (IS_CUR_DUPLICATE(dbc, orig_pgno, orig_indx)); + break; + case DB_SET: + case DB_SET_RECNO: + newopd = 1; + if ((ret = __bam_c_search(dbc, key, flags, &exact)) != 0) + goto err; + break; + case DB_SET_RANGE: + newopd = 1; + if ((ret = __bam_c_search(dbc, key, flags, &exact)) != 0) + goto err; + + /* + * As we didn't require an exact match, the search function + * may have returned an entry past the end of the page. Or, + * we may be referencing a deleted record. If so, move to + * the next entry. + */ + if (cp->indx == NUM_ENT(cp->page) || IS_CUR_DELETED(dbc)) + if ((ret = __bam_c_next(dbc, 0)) != 0) + goto err; + break; + default: + ret = __db_unknown_flag(dbp->dbenv, "__bam_c_get", flags); + goto err; + } + + /* + * We may have moved to an off-page duplicate tree. Return that + * information to our caller. + */ + if (newopd && pgnop != NULL) + (void)__bam_isopd(dbc, pgnop); + + /* Don't return the key, it was passed to us */ + if (flags == DB_SET) + F_SET(key, DB_DBT_ISSET); + +err: /* + * Regardless of whether we were successful or not, if the cursor + * moved, clear the delete flag, DBcursor->c_get never references + * a deleted key, if it moved at all. + */ + if (F_ISSET(cp, C_DELETED) + && (cp->pgno != orig_pgno || cp->indx != orig_indx)) + F_CLR(cp, C_DELETED); + + return (ret); +} + +/* + * __bam_getbothc -- + * Search for a matching data item on a join. + */ +static int +__bam_getbothc(dbc, data) + DBC *dbc; + DBT *data; +{ + BTREE_CURSOR *cp; + DB *dbp; + int cmp, exact, ret; + + dbp = dbc->dbp; + cp = (BTREE_CURSOR *)dbc->internal; + + /* + * Acquire the current page. We have at least a read-lock + * already. The caller may have set DB_RMW asking for a + * write lock, but upgrading to a write lock has no better + * chance of succeeding now instead of later, so don't try. + */ + if ((ret = memp_fget(dbp->mpf, &cp->pgno, 0, &cp->page)) != 0) + return (ret); + + /* + * An off-page duplicate cursor. Search the remaining duplicates + * for one which matches (do a normal btree search, then verify + * that the retrieved record is greater than the original one). + */ + if (F_ISSET(dbc, DBC_OPD)) { + /* + * Check to make sure the desired item comes strictly after + * the current position; if it doesn't, return DB_NOTFOUND. + */ + if ((ret = __bam_cmp(dbp, data, cp->page, cp->indx, + dbp->dup_compare == NULL ? __bam_defcmp : dbp->dup_compare, + &cmp)) != 0) + return (ret); + + if (cmp <= 0) + return (DB_NOTFOUND); + + /* Discard the current page, we're going to do a full search. */ + if ((ret = memp_fput(dbp->mpf, cp->page, 0)) != 0) + return (ret); + cp->page = NULL; + + return (__bam_c_search(dbc, data, DB_GET_BOTH, &exact)); + } + + /* + * We're doing a DBC->c_get(DB_GET_BOTHC) and we're already searching + * a set of on-page duplicates (either sorted or unsorted). Continue + * a linear search from after the current position. + * + * (Note that we could have just finished a "set" of one duplicate, + * i.e. not a duplicate at all, but the following check will always + * return DB_NOTFOUND in this case, which is the desired behavior.) + */ + if (cp->indx + P_INDX >= NUM_ENT(cp->page) || + !IS_DUPLICATE(dbc, cp->indx, cp->indx + P_INDX)) + return (DB_NOTFOUND); + cp->indx += P_INDX; + + return (__bam_getboth_finddatum(dbc, data)); +} + +/* + * __bam_getboth_finddatum -- + * Find a matching on-page data item. + */ +static int +__bam_getboth_finddatum(dbc, data) + DBC *dbc; + DBT *data; +{ + BTREE_CURSOR *cp; + DB *dbp; + db_indx_t base, lim, top; + int cmp, ret; + + dbp = dbc->dbp; + cp = (BTREE_CURSOR *)dbc->internal; + + /* + * Called (sometimes indirectly) from DBC->get to search on-page data + * item(s) for a matching value. If the original flag was DB_GET_BOTH, + * the cursor argument is set to the first data item for the key. If + * the original flag was DB_GET_BOTHC, the cursor argument is set to + * the first data item that we can potentially return. In both cases, + * there may or may not be additional duplicate data items to search. + * + * If the duplicates are not sorted, do a linear search. + * + * If the duplicates are sorted, do a binary search. The reason for + * this is that large pages and small key/data pairs result in large + * numbers of on-page duplicates before they get pushed off-page. + */ + if (dbp->dup_compare == NULL) { + for (;; cp->indx += P_INDX) { + if (!IS_CUR_DELETED(dbc) && + (ret = __bam_cmp(dbp, data, cp->page, + cp->indx + O_INDX, __bam_defcmp, &cmp)) != 0) + return (ret); + if (cmp == 0) + return (0); + + if (cp->indx + P_INDX >= NUM_ENT(cp->page) || + !IS_DUPLICATE(dbc, cp->indx, cp->indx + P_INDX)) + break; + } + } else { + /* + * Find the top and bottom of the duplicate set. Binary search + * requires at least two items, don't loop if there's only one. + */ + for (base = top = cp->indx; + top < NUM_ENT(cp->page); top += P_INDX) + if (!IS_DUPLICATE(dbc, cp->indx, top)) + break; + if (base == (top - P_INDX)) { + if ((ret = __bam_cmp(dbp, data, + cp->page, cp->indx + O_INDX, + dbp->dup_compare, &cmp)) != 0) + return (ret); + return (cmp == 0 ? 0 : DB_NOTFOUND); + } + + for (lim = + (top - base) / (db_indx_t)P_INDX; lim != 0; lim >>= 1) { + cp->indx = base + ((lim >> 1) * P_INDX); + if ((ret = __bam_cmp(dbp, data, cp->page, + cp->indx + O_INDX, dbp->dup_compare, &cmp)) != 0) + return (ret); + if (cmp == 0) { + if (!IS_CUR_DELETED(dbc)) + return (0); + break; + } + if (cmp > 0) { + base = cp->indx + P_INDX; + --lim; + } + } + } + return (DB_NOTFOUND); +} + +/* + * __bam_c_put -- + * Put using a cursor. + */ +static int +__bam_c_put(dbc, key, data, flags, pgnop) + DBC *dbc; + DBT *key, *data; + u_int32_t flags; + db_pgno_t *pgnop; +{ + BTREE_CURSOR *cp; + DB *dbp; + DBT dbt; + u_int32_t iiop; + int cmp, exact, needkey, ret, stack; + void *arg; + + dbp = dbc->dbp; + cp = (BTREE_CURSOR *)dbc->internal; + +split: needkey = ret = stack = 0; + switch (flags) { + case DB_AFTER: + case DB_BEFORE: + case DB_CURRENT: + needkey = 1; + iiop = flags; + + /* + * If the Btree has record numbers (and we're not replacing an + * existing record), we need a complete stack so that we can + * adjust the record counts. The check for flags == DB_CURRENT + * is superfluous but left in for clarity. (If C_RECNUM is set + * we know that flags must be DB_CURRENT, as DB_AFTER/DB_BEFORE + * are illegal in a Btree unless it's configured for duplicates + * and you cannot configure a Btree for both record renumbering + * and duplicates.) + */ + if (flags == DB_CURRENT && + F_ISSET(cp, C_RECNUM) && F_ISSET(cp, C_DELETED)) { + if ((ret = __bam_c_getstack(dbc)) != 0) + goto err; + /* + * Initialize the cursor from the stack. Don't take + * the page number or page index, they should already + * be set. + */ + cp->page = cp->csp->page; + cp->lock = cp->csp->lock; + cp->lock_mode = cp->csp->lock_mode; + + stack = 1; + break; + } + + /* Acquire the current page with a write lock. */ + ACQUIRE_WRITE_LOCK(dbc, ret); + if (ret != 0) + goto err; + if ((ret = memp_fget(dbp->mpf, &cp->pgno, 0, &cp->page)) != 0) + goto err; + break; + case DB_KEYFIRST: + case DB_KEYLAST: + case DB_NODUPDATA: + /* + * Searching off-page, sorted duplicate tree: do a tree search + * for the correct item; __bam_c_search returns the smallest + * slot greater than the key, use it. + */ + if (F_ISSET(dbc, DBC_OPD)) { + if ((ret = + __bam_c_search(dbc, data, flags, &exact)) != 0) + goto err; + stack = 1; + + /* Disallow "sorted" duplicate duplicates. */ + if (exact) { + ret = __db_duperr(dbp, flags); + goto err; + } + iiop = DB_BEFORE; + break; + } + + /* Searching a btree. */ + if ((ret = __bam_c_search(dbc, key, + flags == DB_KEYFIRST || dbp->dup_compare != NULL ? + DB_KEYFIRST : DB_KEYLAST, &exact)) != 0) + goto err; + stack = 1; + + /* + * If we don't have an exact match, __bam_c_search returned + * the smallest slot greater than the key, use it. + */ + if (!exact) { + iiop = DB_KEYFIRST; + break; + } + + /* + * If duplicates aren't supported, replace the current item. + * (If implementing the DB->put function, our caller already + * checked the DB_NOOVERWRITE flag.) + */ + if (!F_ISSET(dbp, DB_AM_DUP)) { + iiop = DB_CURRENT; + break; + } + + /* + * If we find a matching entry, it may be an off-page duplicate + * tree. Return the page number to our caller, we need a new + * cursor. + */ + if (pgnop != NULL && __bam_isopd(dbc, pgnop)) + goto done; + + /* If the duplicates aren't sorted, move to the right slot. */ + if (dbp->dup_compare == NULL) { + if (flags == DB_KEYFIRST) + iiop = DB_BEFORE; + else + for (;; cp->indx += P_INDX) + if (cp->indx + P_INDX >= + NUM_ENT(cp->page) || + !IS_DUPLICATE(dbc, cp->indx, + cp->indx + P_INDX)) { + iiop = DB_AFTER; + break; + } + break; + } + + /* + * We know that we're looking at the first of a set of sorted + * on-page duplicates. Walk the list to find the right slot. + */ + for (;; cp->indx += P_INDX) { + if ((ret = __bam_cmp(dbp, data, cp->page, + cp->indx + O_INDX, dbp->dup_compare, &cmp)) !=0) + return (ret); + if (cmp < 0) { + iiop = DB_BEFORE; + break; + } + + /* Disallow "sorted" duplicate duplicates. */ + if (cmp == 0) { + if (IS_DELETED(cp->page, cp->indx)) { + iiop = DB_CURRENT; + break; + } + ret = __db_duperr(dbp, flags); + goto err; + } + + if (cp->indx + P_INDX >= NUM_ENT(cp->page) || + ((PAGE *)cp->page)->inp[cp->indx] != + ((PAGE *)cp->page)->inp[cp->indx + P_INDX]) { + iiop = DB_AFTER; + break; + } + } + break; + default: + ret = __db_unknown_flag(dbp->dbenv, "__bam_c_put", flags); + goto err; + } + + switch (ret = __bam_iitem(dbc, key, data, iiop, 0)) { + case 0: + break; + case DB_NEEDSPLIT: + /* + * To split, we need a key for the page. Either use the key + * argument or get a copy of the key from the page. + */ + if (flags == DB_AFTER || + flags == DB_BEFORE || flags == DB_CURRENT) { + memset(&dbt, 0, sizeof(DBT)); + if ((ret = __db_ret(dbp, cp->page, 0, &dbt, + &dbc->rkey.data, &dbc->rkey.ulen)) != 0) + goto err; + arg = &dbt; + } else + arg = F_ISSET(dbc, DBC_OPD) ? data : key; + + /* + * Discard any locks and pinned pages (the locks are discarded + * even if we're running with transactions, as they lock pages + * that we're sorry we ever acquired). If stack is set and the + * cursor entries are valid, they point to the same entries as + * the stack, don't free them twice. + */ + if (stack) + ret = __bam_stkrel(dbc, STK_CLRDBC | STK_NOLOCK); + else + DISCARD_CUR(dbc, ret); + if (ret != 0) + goto err; + + /* Split the tree. */ + if ((ret = __bam_split(dbc, arg)) != 0) + return (ret); + + goto split; + default: + goto err; + } + +err: +done: /* + * Discard any pages pinned in the tree and their locks, except for + * the leaf page. Note, the leaf page participated in any stack we + * acquired, and so we have to adjust the stack as necessary. If + * there was only a single page on the stack, we don't have to free + * further stack pages. + */ + if (stack && BT_STK_POP(cp) != NULL) + (void)__bam_stkrel(dbc, 0); + + /* + * Regardless of whether we were successful or not, clear the delete + * flag. If we're successful, we either moved the cursor or the item + * is no longer deleted. If we're not successful, then we're just a + * copy, no need to have the flag set. + */ + F_CLR(cp, C_DELETED); + + return (ret); +} + +/* + * __bam_c_rget -- + * Return the record number for a cursor. + * + * PUBLIC: int __bam_c_rget __P((DBC *, DBT *, u_int32_t)); + */ +int +__bam_c_rget(dbc, data, flags) + DBC *dbc; + DBT *data; + u_int32_t flags; +{ + BTREE_CURSOR *cp; + DB *dbp; + DBT dbt; + db_recno_t recno; + int exact, ret; + + COMPQUIET(flags, 0); + dbp = dbc->dbp; + cp = (BTREE_CURSOR *)dbc->internal; + + /* + * Get the page with the current item on it. + * Get a copy of the key. + * Release the page, making sure we don't release it twice. + */ + if ((ret = memp_fget(dbp->mpf, &cp->pgno, 0, &cp->page)) != 0) + return (ret); + memset(&dbt, 0, sizeof(DBT)); + if ((ret = __db_ret(dbp, cp->page, + cp->indx, &dbt, &dbc->rkey.data, &dbc->rkey.ulen)) != 0) + goto err; + ret = memp_fput(dbp->mpf, cp->page, 0); + cp->page = NULL; + if (ret != 0) + return (ret); + + if ((ret = __bam_search(dbc, &dbt, + F_ISSET(dbc, DBC_RMW) ? S_FIND_WR : S_FIND, + 1, &recno, &exact)) != 0) + goto err; + + ret = __db_retcopy(dbp, data, + &recno, sizeof(recno), &dbc->rdata.data, &dbc->rdata.ulen); + + /* Release the stack. */ +err: __bam_stkrel(dbc, 0); + + return (ret); +} + +/* + * __bam_c_writelock -- + * Upgrade the cursor to a write lock. + */ +static int +__bam_c_writelock(dbc) + DBC *dbc; +{ + BTREE_CURSOR *cp; + int ret; + + cp = (BTREE_CURSOR *)dbc->internal; + + if (cp->lock_mode == DB_LOCK_WRITE) + return (0); + + /* + * When writing to an off-page duplicate tree, we need to have the + * appropriate page in the primary tree locked. The general DBC + * code calls us first with the primary cursor so we can acquire the + * appropriate lock. + */ + ACQUIRE_WRITE_LOCK(dbc, ret); + return (ret); +} + +/* + * __bam_c_first -- + * Return the first record. + */ +static int +__bam_c_first(dbc) + DBC *dbc; +{ + BTREE_CURSOR *cp; + DB *dbp; + db_pgno_t pgno; + int ret; + + dbp = dbc->dbp; + cp = (BTREE_CURSOR *)dbc->internal; + ret = 0; + + /* Walk down the left-hand side of the tree. */ + for (pgno = cp->root;;) { + ACQUIRE_CUR_SET(dbc, DB_LOCK_READ, pgno, ret); + if (ret != 0) + return (ret); + + /* If we find a leaf page, we're done. */ + if (ISLEAF(cp->page)) + break; + + pgno = GET_BINTERNAL(cp->page, 0)->pgno; + } + + /* If we want a write lock instead of a read lock, get it now. */ + if (F_ISSET(dbc, DBC_RMW)) { + ACQUIRE_WRITE_LOCK(dbc, ret); + if (ret != 0) + return (ret); + } + + /* If on an empty page or a deleted record, move to the next one. */ + if (NUM_ENT(cp->page) == 0 || IS_CUR_DELETED(dbc)) + if ((ret = __bam_c_next(dbc, 0)) != 0) + return (ret); + + return (0); +} + +/* + * __bam_c_last -- + * Return the last record. + */ +static int +__bam_c_last(dbc) + DBC *dbc; +{ + BTREE_CURSOR *cp; + DB *dbp; + db_pgno_t pgno; + int ret; + + dbp = dbc->dbp; + cp = (BTREE_CURSOR *)dbc->internal; + ret = 0; + + /* Walk down the right-hand side of the tree. */ + for (pgno = cp->root;;) { + ACQUIRE_CUR_SET(dbc, DB_LOCK_READ, pgno, ret); + if (ret != 0) + return (ret); + + /* If we find a leaf page, we're done. */ + if (ISLEAF(cp->page)) + break; + + pgno = + GET_BINTERNAL(cp->page, NUM_ENT(cp->page) - O_INDX)->pgno; + } + + /* If we want a write lock instead of a read lock, get it now. */ + if (F_ISSET(dbc, DBC_RMW)) { + ACQUIRE_WRITE_LOCK(dbc, ret); + if (ret != 0) + return (ret); + } + + cp->indx = NUM_ENT(cp->page) == 0 ? 0 : + NUM_ENT(cp->page) - + (TYPE(cp->page) == P_LBTREE ? P_INDX : O_INDX); + + /* If on an empty page or a deleted record, move to the previous one. */ + if (NUM_ENT(cp->page) == 0 || IS_CUR_DELETED(dbc)) + if ((ret = __bam_c_prev(dbc)) != 0) + return (ret); + + return (0); +} + +/* + * __bam_c_next -- + * Move to the next record. + */ +static int +__bam_c_next(dbc, initial_move) + DBC *dbc; + int initial_move; +{ + BTREE_CURSOR *cp; + DB *dbp; + db_indx_t adjust; + db_lockmode_t lock_mode; + db_pgno_t pgno; + int ret; + + dbp = dbc->dbp; + cp = (BTREE_CURSOR *)dbc->internal; + ret = 0; + + /* + * We're either moving through a page of duplicates or a btree leaf + * page. + * + * !!! + * This code handles empty pages and pages with only deleted entries. + */ + if (F_ISSET(dbc, DBC_OPD)) { + adjust = O_INDX; + lock_mode = DB_LOCK_NG; + } else { + adjust = dbc->dbtype == DB_BTREE ? P_INDX : O_INDX; + lock_mode = + F_ISSET(dbc, DBC_RMW) ? DB_LOCK_WRITE : DB_LOCK_READ; + } + if (cp->page == NULL) { + ACQUIRE_CUR(dbc, lock_mode, ret); + if (ret != 0) + return (ret); + } + + if (initial_move) + cp->indx += adjust; + + for (;;) { + /* + * If at the end of the page, move to a subsequent page. + * + * !!! + * Check for >= NUM_ENT. If the original search landed us on + * NUM_ENT, we may have incremented indx before the test. + */ + if (cp->indx >= NUM_ENT(cp->page)) { + if ((pgno + = NEXT_PGNO(cp->page)) == PGNO_INVALID) + return (DB_NOTFOUND); + + ACQUIRE_CUR_SET(dbc, lock_mode, pgno, ret); + if (ret != 0) + return (ret); + continue; + } + if (IS_CUR_DELETED(dbc)) { + cp->indx += adjust; + continue; + } + break; + } + return (0); +} + +/* + * __bam_c_prev -- + * Move to the previous record. + */ +static int +__bam_c_prev(dbc) + DBC *dbc; +{ + BTREE_CURSOR *cp; + DB *dbp; + db_indx_t adjust; + db_lockmode_t lock_mode; + db_pgno_t pgno; + int ret; + + dbp = dbc->dbp; + cp = (BTREE_CURSOR *)dbc->internal; + ret = 0; + + /* + * We're either moving through a page of duplicates or a btree leaf + * page. + * + * !!! + * This code handles empty pages and pages with only deleted entries. + */ + if (F_ISSET(dbc, DBC_OPD)) { + adjust = O_INDX; + lock_mode = DB_LOCK_NG; + } else { + adjust = dbc->dbtype == DB_BTREE ? P_INDX : O_INDX; + lock_mode = + F_ISSET(dbc, DBC_RMW) ? DB_LOCK_WRITE : DB_LOCK_READ; + } + if (cp->page == NULL) { + ACQUIRE_CUR(dbc, lock_mode, ret); + if (ret != 0) + return (ret); + } + + for (;;) { + /* If at the beginning of the page, move to a previous one. */ + if (cp->indx == 0) { + if ((pgno = + PREV_PGNO(cp->page)) == PGNO_INVALID) + return (DB_NOTFOUND); + + ACQUIRE_CUR_SET(dbc, lock_mode, pgno, ret); + if (ret != 0) + return (ret); + + if ((cp->indx = NUM_ENT(cp->page)) == 0) + continue; + } + + /* Ignore deleted records. */ + cp->indx -= adjust; + if (IS_CUR_DELETED(dbc)) + continue; + + break; + } + return (0); +} + +/* + * __bam_c_search -- + * Move to a specified record. + */ +static int +__bam_c_search(dbc, key, flags, exactp) + DBC *dbc; + const DBT *key; + u_int32_t flags; + int *exactp; +{ + BTREE *t; + BTREE_CURSOR *cp; + DB *dbp; + PAGE *h; + db_indx_t indx; + db_pgno_t bt_lpgno; + db_recno_t recno; + u_int32_t sflags; + int cmp, ret; + + dbp = dbc->dbp; + cp = (BTREE_CURSOR *)dbc->internal; + t = dbp->bt_internal; + ret = 0; + + /* + * Find an entry in the database. Discard any lock we currently hold, + * we're going to search the tree. + */ + DISCARD_CUR(dbc, ret); + if (ret != 0) + return (ret); + + switch (flags) { + case DB_SET_RECNO: + if ((ret = __ram_getno(dbc, key, &recno, 0)) != 0) + return (ret); + sflags = (F_ISSET(dbc, DBC_RMW) ? S_FIND_WR : S_FIND) | S_EXACT; + if ((ret = __bam_rsearch(dbc, &recno, sflags, 1, exactp)) != 0) + return (ret); + break; + case DB_SET: + case DB_GET_BOTH: + sflags = (F_ISSET(dbc, DBC_RMW) ? S_FIND_WR : S_FIND) | S_EXACT; + goto search; + case DB_SET_RANGE: + sflags = + (F_ISSET(dbc, DBC_RMW) ? S_WRITE : S_READ) | S_DUPFIRST; + goto search; + case DB_KEYFIRST: + sflags = S_KEYFIRST; + goto fast_search; + case DB_KEYLAST: + case DB_NODUPDATA: + sflags = S_KEYLAST; +fast_search: /* + * If the application has a history of inserting into the first + * or last pages of the database, we check those pages first to + * avoid doing a full search. + * + * If the tree has record numbers, we need a complete stack so + * that we can adjust the record counts, so fast_search isn't + * possible. + */ + if (F_ISSET(cp, C_RECNUM)) + goto search; + + /* + * !!! + * We do not mutex protect the t->bt_lpgno field, which means + * that it can only be used in an advisory manner. If we find + * page we can use, great. If we don't, we don't care, we do + * it the slow way instead. Regardless, copy it into a local + * variable, otherwise we might acquire a lock for a page and + * then read a different page because it changed underfoot. + */ + bt_lpgno = t->bt_lpgno; + + /* + * If the tree has no history of insertion, do it the slow way. + */ + if (bt_lpgno == PGNO_INVALID) + goto search; + + /* Lock and retrieve the page on which we last inserted. */ + h = NULL; + ACQUIRE(dbc, + DB_LOCK_WRITE, bt_lpgno, cp->lock, bt_lpgno, h, ret); + if (ret != 0) + goto fast_miss; + + /* + * It's okay if the page type isn't right or it's empty, it + * just means that the world changed. + */ + if (TYPE(h) != P_LBTREE || NUM_ENT(h) == 0) + goto fast_miss; + + /* + * What we do here is test to see if we're at the beginning or + * end of the tree and if the new item sorts before/after the + * first/last page entry. We don't try and catch inserts into + * the middle of the tree (although we could, as long as there + * were two keys on the page and we saved both the index and + * the page number of the last insert). + */ + if (h->next_pgno == PGNO_INVALID) { + indx = NUM_ENT(h) - P_INDX; + if ((ret = __bam_cmp(dbp, + key, h, indx, t->bt_compare, &cmp)) != 0) + return (ret); + + if (cmp < 0) + goto try_begin; + if (cmp > 0) { + indx += P_INDX; + goto fast_hit; + } + + /* + * Found a duplicate. If doing DB_KEYLAST, we're at + * the correct position, otherwise, move to the first + * of the duplicates. If we're looking at off-page + * duplicates, duplicate duplicates aren't permitted, + * so we're done. + */ + if (flags == DB_KEYLAST) + goto fast_hit; + for (; + indx > 0 && h->inp[indx - P_INDX] == h->inp[indx]; + indx -= P_INDX) + ; + goto fast_hit; + } +try_begin: if (h->prev_pgno == PGNO_INVALID) { + indx = 0; + if ((ret = __bam_cmp(dbp, + key, h, indx, t->bt_compare, &cmp)) != 0) + return (ret); + + if (cmp > 0) + goto fast_miss; + if (cmp < 0) + goto fast_hit; + + /* + * Found a duplicate. If doing DB_KEYFIRST, we're at + * the correct position, otherwise, move to the last + * of the duplicates. If we're looking at off-page + * duplicates, duplicate duplicates aren't permitted, + * so we're done. + */ + if (flags == DB_KEYFIRST) + goto fast_hit; + for (; + indx < (db_indx_t)(NUM_ENT(h) - P_INDX) && + h->inp[indx] == h->inp[indx + P_INDX]; + indx += P_INDX) + ; + goto fast_hit; + } + goto fast_miss; + +fast_hit: /* Set the exact match flag, we may have found a duplicate. */ + *exactp = cmp == 0; + + /* + * Insert the entry in the stack. (Our caller is likely to + * call __bam_stkrel() after our return.) + */ + BT_STK_CLR(cp); + BT_STK_ENTER(dbp->dbenv, + cp, h, indx, cp->lock, cp->lock_mode, ret); + if (ret != 0) + return (ret); + break; + +fast_miss: /* + * This was not the right page, so we do not need to retain + * the lock even in the presence of transactions. + */ + DISCARD(dbc, 1, cp->lock, h, ret); + if (ret != 0) + return (ret); + +search: if ((ret = + __bam_search(dbc, key, sflags, 1, NULL, exactp)) != 0) + return (ret); + break; + default: + return (__db_unknown_flag(dbp->dbenv, "__bam_c_search", flags)); + } + + /* Initialize the cursor from the stack. */ + cp->page = cp->csp->page; + cp->pgno = cp->csp->page->pgno; + cp->indx = cp->csp->indx; + cp->lock = cp->csp->lock; + cp->lock_mode = cp->csp->lock_mode; + + /* + * If we inserted a key into the first or last slot of the tree, + * remember where it was so we can do it more quickly next time. + */ + if (TYPE(cp->page) == P_LBTREE && + (flags == DB_KEYFIRST || flags == DB_KEYLAST)) + t->bt_lpgno = + (NEXT_PGNO(cp->page) == PGNO_INVALID && + cp->indx >= NUM_ENT(cp->page)) || + (PREV_PGNO(cp->page) == PGNO_INVALID && + cp->indx == 0) ? cp->pgno : PGNO_INVALID; + return (0); +} + +/* + * __bam_c_physdel -- + * Physically remove an item from the page. + */ +static int +__bam_c_physdel(dbc) + DBC *dbc; +{ + BTREE_CURSOR *cp; + DB *dbp; + DBT key; + DB_LOCK lock; + PAGE *h; + db_pgno_t pgno; + int delete_page, empty_page, exact, level, ret; + + dbp = dbc->dbp; + cp = (BTREE_CURSOR *)dbc->internal; + delete_page = empty_page = ret = 0; + + /* If the page is going to be emptied, consider deleting it. */ + delete_page = empty_page = + NUM_ENT(cp->page) == (TYPE(cp->page) == P_LBTREE ? 2 : 1); + + /* + * Check if the application turned off reverse splits. Applications + * can't turn off reverse splits in off-page duplicate trees, that + * space will never be reused unless the exact same key is specified. + */ + if (delete_page && + !F_ISSET(dbc, DBC_OPD) && F_ISSET(dbp, DB_BT_REVSPLIT)) + delete_page = 0; + + /* + * We never delete the last leaf page. (Not really true -- we delete + * the last leaf page of off-page duplicate trees, but that's handled + * by our caller, not down here.) + */ + if (delete_page && cp->pgno == cp->root) + delete_page = 0; + + /* + * To delete a leaf page other than an empty root page, we need a + * copy of a key from the page. Use the 0th page index since it's + * the last key the page held. + */ + if (delete_page) { + memset(&key, 0, sizeof(DBT)); + if ((ret = __db_ret(dbp, cp->page, + 0, &key, &dbc->rkey.data, &dbc->rkey.ulen)) != 0) + return (ret); + } + + /* + * Delete the items. If page isn't empty, we adjust the cursors. + * + * !!! + * The following operations to delete a page may deadlock. The easy + * scenario is if we're deleting an item because we're closing cursors + * because we've already deadlocked and want to call txn_abort(). If + * we fail due to deadlock, we'll leave a locked, possibly empty page + * in the tree, which won't be empty long because we'll undo the delete + * when we undo the transaction's modifications. + * + * !!! + * Delete the key item first, otherwise the on-page duplicate checks + * in __bam_ditem() won't work! + */ + if (TYPE(cp->page) == P_LBTREE) { + if ((ret = __bam_ditem(dbc, cp->page, cp->indx)) != 0) + return (ret); + if (!empty_page) + if ((ret = __bam_ca_di(dbc, + PGNO(cp->page), cp->indx, -1)) != 0) + return (ret); + } + if ((ret = __bam_ditem(dbc, cp->page, cp->indx)) != 0) + return (ret); + if (!empty_page) + if ((ret = __bam_ca_di(dbc, PGNO(cp->page), cp->indx, -1)) != 0) + return (ret); + + /* If we're not going to try and delete the page, we're done. */ + if (!delete_page) + return (0); + + /* + * Call __bam_search to reacquire the empty leaf page, but this time + * get both the leaf page and it's parent, locked. Jump back up the + * tree, until we have the top pair of pages that we want to delete. + * Once we have the top page that we want to delete locked, lock the + * underlying pages and check to make sure they're still empty. If + * they are, delete them. + */ + for (level = LEAFLEVEL;; ++level) { + /* Acquire a page and its parent, locked. */ + if ((ret = __bam_search( + dbc, &key, S_WRPAIR, level, NULL, &exact)) != 0) + return (ret); + + /* + * If we reach the root or the parent page isn't going to be + * empty when we delete one record, stop. + */ + h = cp->csp[-1].page; + if (h->pgno == cp->root || NUM_ENT(h) != 1) + break; + + /* Discard the stack, retaining no locks. */ + (void)__bam_stkrel(dbc, STK_NOLOCK); + } + + /* + * Move the stack pointer one after the last entry, we may be about + * to push more items onto the page stack. + */ + ++cp->csp; + + /* + * cp->csp[-2].page is now the parent page, which we may or may not be + * going to delete, and cp->csp[-1].page is the first page we know we + * are going to delete. Walk down the chain of pages, acquiring pages + * until we've acquired a leaf page. Generally, this shouldn't happen; + * we should only see a single internal page with one item and a single + * leaf page with no items. The scenario where we could see something + * else is if reverse splits were turned off for awhile and then turned + * back on. That could result in all sorts of strangeness, e.g., empty + * pages in the tree, trees that looked like linked lists, and so on. + * + * !!! + * Sheer paranoia: if we find any pages that aren't going to be emptied + * by the delete, someone else added an item while we were walking the + * tree, and we discontinue the delete. Shouldn't be possible, but we + * check regardless. + */ + for (h = cp->csp[-1].page;;) { + if (ISLEAF(h)) { + if (NUM_ENT(h) != 0) + break; + break; + } else + if (NUM_ENT(h) != 1) + break; + + /* + * Get the next page, write lock it and push it onto the stack. + * We know it's index 0, because it can only have one element. + */ + switch (TYPE(h)) { + case P_IBTREE: + pgno = GET_BINTERNAL(h, 0)->pgno; + break; + case P_IRECNO: + pgno = GET_RINTERNAL(h, 0)->pgno; + break; + default: + return (__db_pgfmt(dbp, PGNO(h))); + } + + if ((ret = + __db_lget(dbc, 0, pgno, DB_LOCK_WRITE, 0, &lock)) != 0) + break; + if ((ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) + break; + BT_STK_PUSH(dbp->dbenv, cp, h, 0, lock, DB_LOCK_WRITE, ret); + if (ret != 0) + break; + } + + /* Adjust the cursor stack to reference the last page on the stack. */ + BT_STK_POP(cp); + + /* + * If everything worked, delete the stack, otherwise, release the + * stack and page locks without further damage. + */ + if (ret == 0) + ret = __bam_dpages(dbc, cp->sp); + else + (void)__bam_stkrel(dbc, 0); + + return (ret); +} + +/* + * __bam_c_getstack -- + * Acquire a full stack for a cursor. + */ +static int +__bam_c_getstack(dbc) + DBC *dbc; +{ + BTREE_CURSOR *cp; + DB *dbp; + DBT dbt; + PAGE *h; + int exact, ret, t_ret; + + dbp = dbc->dbp; + cp = (BTREE_CURSOR *)dbc->internal; + + /* + * Get the page with the current item on it. The caller of this + * routine has to already hold a read lock on the page, so there + * is no additional lock to acquire. + */ + if ((ret = memp_fget(dbp->mpf, &cp->pgno, 0, &h)) != 0) + return (ret); + + /* Get a copy of a key from the page. */ + memset(&dbt, 0, sizeof(DBT)); + if ((ret = __db_ret(dbp, + h, 0, &dbt, &dbc->rkey.data, &dbc->rkey.ulen)) != 0) + goto err; + + /* Get a write-locked stack for the page. */ + exact = 0; + ret = __bam_search(dbc, &dbt, S_KEYFIRST, 1, NULL, &exact); + +err: /* Discard the key and the page. */ + if ((t_ret = memp_fput(dbp->mpf, h, 0)) != 0 && ret == 0) + ret = t_ret; + + return (ret); +} + +/* + * __bam_isopd -- + * Return if the cursor references an off-page duplicate tree via its + * page number. + */ +static int +__bam_isopd(dbc, pgnop) + DBC *dbc; + db_pgno_t *pgnop; +{ + BOVERFLOW *bo; + + if (TYPE(dbc->internal->page) != P_LBTREE) + return (0); + + bo = GET_BOVERFLOW(dbc->internal->page, dbc->internal->indx + O_INDX); + if (B_TYPE(bo->type) == B_DUPLICATE) { + *pgnop = bo->pgno; + return (1); + } + return (0); +} diff --git a/db/btree/bt_delete.c b/db/btree/bt_delete.c new file mode 100644 index 000000000..972588788 --- /dev/null +++ b/db/btree/bt_delete.c @@ -0,0 +1,530 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994, 1995 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Mike Olson. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: bt_delete.c,v 11.31 2001/01/17 18:48:46 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_shash.h" +#include "btree.h" +#include "lock.h" + +/* + * __bam_delete -- + * Delete the items referenced by a key. + * + * PUBLIC: int __bam_delete __P((DB *, DB_TXN *, DBT *, u_int32_t)); + */ +int +__bam_delete(dbp, txn, key, flags) + DB *dbp; + DB_TXN *txn; + DBT *key; + u_int32_t flags; +{ + DBC *dbc; + DBT lkey; + DBT data; + u_int32_t f_init, f_next; + int ret, t_ret; + + PANIC_CHECK(dbp->dbenv); + DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->del"); + DB_CHECK_TXN(dbp, txn); + + /* Check for invalid flags. */ + if ((ret = + __db_delchk(dbp, key, flags, F_ISSET(dbp, DB_AM_RDONLY))) != 0) + return (ret); + + /* Allocate a cursor. */ + if ((ret = dbp->cursor(dbp, txn, &dbc, DB_WRITELOCK)) != 0) + return (ret); + + DEBUG_LWRITE(dbc, txn, "bam_delete", key, NULL, flags); + + /* + * Walk a cursor through the key/data pairs, deleting as we go. Set + * the DB_DBT_USERMEM flag, as this might be a threaded application + * and the flags checking will catch us. We don't actually want the + * keys or data, so request a partial of length 0. + */ + memset(&lkey, 0, sizeof(lkey)); + F_SET(&lkey, DB_DBT_USERMEM | DB_DBT_PARTIAL); + memset(&data, 0, sizeof(data)); + F_SET(&data, DB_DBT_USERMEM | DB_DBT_PARTIAL); + + /* + * If locking (and we haven't already acquired CDB locks), set the + * read-modify-write flag. + */ + f_init = DB_SET; + f_next = DB_NEXT_DUP; + if (STD_LOCKING(dbc)) { + f_init |= DB_RMW; + f_next |= DB_RMW; + } + + /* Walk through the set of key/data pairs, deleting as we go. */ + if ((ret = dbc->c_get(dbc, key, &data, f_init)) != 0) + goto err; + for (;;) { + if ((ret = dbc->c_del(dbc, 0)) != 0) + goto err; + if ((ret = dbc->c_get(dbc, &lkey, &data, f_next)) != 0) { + if (ret == DB_NOTFOUND) { + ret = 0; + break; + } + goto err; + } + } + +err: /* Discard the cursor. */ + if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0) + ret = t_ret; + + return (ret); +} + +/* + * __bam_ditem -- + * Delete one or more entries from a page. + * + * PUBLIC: int __bam_ditem __P((DBC *, PAGE *, u_int32_t)); + */ +int +__bam_ditem(dbc, h, indx) + DBC *dbc; + PAGE *h; + u_int32_t indx; +{ + BINTERNAL *bi; + BKEYDATA *bk; + DB *dbp; + u_int32_t nbytes; + int ret; + + dbp = dbc->dbp; + + switch (TYPE(h)) { + case P_IBTREE: + bi = GET_BINTERNAL(h, indx); + switch (B_TYPE(bi->type)) { + case B_DUPLICATE: + case B_KEYDATA: + nbytes = BINTERNAL_SIZE(bi->len); + break; + case B_OVERFLOW: + nbytes = BINTERNAL_SIZE(bi->len); + if ((ret = + __db_doff(dbc, ((BOVERFLOW *)bi->data)->pgno)) != 0) + return (ret); + break; + default: + return (__db_pgfmt(dbp, PGNO(h))); + } + break; + case P_IRECNO: + nbytes = RINTERNAL_SIZE; + break; + case P_LBTREE: + /* + * If it's a duplicate key, discard the index and don't touch + * the actual page item. + * + * !!! + * This works because no data item can have an index matching + * any other index so even if the data item is in a key "slot", + * it won't match any other index. + */ + if ((indx % 2) == 0) { + /* + * Check for a duplicate after us on the page. NOTE: + * we have to delete the key item before deleting the + * data item, otherwise the "indx + P_INDX" calculation + * won't work! + */ + if (indx + P_INDX < (u_int32_t)NUM_ENT(h) && + h->inp[indx] == h->inp[indx + P_INDX]) + return (__bam_adjindx(dbc, + h, indx, indx + O_INDX, 0)); + /* + * Check for a duplicate before us on the page. It + * doesn't matter if we delete the key item before or + * after the data item for the purposes of this one. + */ + if (indx > 0 && h->inp[indx] == h->inp[indx - P_INDX]) + return (__bam_adjindx(dbc, + h, indx, indx - P_INDX, 0)); + } + /* FALLTHROUGH */ + case P_LDUP: + case P_LRECNO: + bk = GET_BKEYDATA(h, indx); + switch (B_TYPE(bk->type)) { + case B_DUPLICATE: + nbytes = BOVERFLOW_SIZE; + break; + case B_OVERFLOW: + nbytes = BOVERFLOW_SIZE; + if ((ret = __db_doff( + dbc, (GET_BOVERFLOW(h, indx))->pgno)) != 0) + return (ret); + break; + case B_KEYDATA: + nbytes = BKEYDATA_SIZE(bk->len); + break; + default: + return (__db_pgfmt(dbp, PGNO(h))); + } + break; + default: + return (__db_pgfmt(dbp, PGNO(h))); + } + + /* Delete the item and mark the page dirty. */ + if ((ret = __db_ditem(dbc, h, indx, nbytes)) != 0) + return (ret); + if ((ret = memp_fset(dbp->mpf, h, DB_MPOOL_DIRTY)) != 0) + return (ret); + + return (0); +} + +/* + * __bam_adjindx -- + * Adjust an index on the page. + * + * PUBLIC: int __bam_adjindx __P((DBC *, PAGE *, u_int32_t, u_int32_t, int)); + */ +int +__bam_adjindx(dbc, h, indx, indx_copy, is_insert) + DBC *dbc; + PAGE *h; + u_int32_t indx, indx_copy; + int is_insert; +{ + DB *dbp; + db_indx_t copy; + int ret; + + dbp = dbc->dbp; + + /* Log the change. */ + if (DB_LOGGING(dbc) && + (ret = __bam_adj_log(dbp->dbenv, dbc->txn, &LSN(h), + 0, dbp->log_fileid, PGNO(h), &LSN(h), indx, indx_copy, + (u_int32_t)is_insert)) != 0) + return (ret); + + /* Shuffle the indices and mark the page dirty. */ + if (is_insert) { + copy = h->inp[indx_copy]; + if (indx != NUM_ENT(h)) + memmove(&h->inp[indx + O_INDX], &h->inp[indx], + sizeof(db_indx_t) * (NUM_ENT(h) - indx)); + h->inp[indx] = copy; + ++NUM_ENT(h); + } else { + --NUM_ENT(h); + if (indx != NUM_ENT(h)) + memmove(&h->inp[indx], &h->inp[indx + O_INDX], + sizeof(db_indx_t) * (NUM_ENT(h) - indx)); + } + if ((ret = memp_fset(dbp->mpf, h, DB_MPOOL_DIRTY)) != 0) + return (ret); + + return (0); +} + +/* + * __bam_dpages -- + * Delete a set of locked pages. + * + * PUBLIC: int __bam_dpages __P((DBC *, EPG *)); + */ +int +__bam_dpages(dbc, stack_epg) + DBC *dbc; + EPG *stack_epg; +{ + BTREE_CURSOR *cp; + BINTERNAL *bi; + DB *dbp; + DBT a, b; + DB_LOCK c_lock, p_lock; + EPG *epg; + PAGE *child, *parent; + db_indx_t nitems; + db_pgno_t pgno, root_pgno; + db_recno_t rcnt; + int done, ret, t_ret; + + dbp = dbc->dbp; + cp = (BTREE_CURSOR *)dbc->internal; + + /* + * We have the entire stack of deletable pages locked. + * + * Btree calls us with a pointer to the beginning of a stack, where + * the first page in the stack is to have a single item deleted, and + * the rest of the pages are to be removed. + * + * Recno calls us with a pointer into the middle of the stack, where + * the referenced page is to have a single item deleted, and pages + * after the stack reference are to be removed. + * + * First, discard any pages that we don't care about. + */ + ret = 0; + for (epg = cp->sp; epg < stack_epg; ++epg) { + if ((t_ret = + memp_fput(dbp->mpf, epg->page, 0)) != 0 && ret == 0) + ret = t_ret; + (void)__TLPUT(dbc, epg->lock); + } + if (ret != 0) + goto err; + + /* + * !!! + * There is an interesting deadlock situation here. We have to relink + * the leaf page chain around the leaf page being deleted. Consider + * a cursor walking through the leaf pages, that has the previous page + * read-locked and is waiting on a lock for the page we're deleting. + * It will deadlock here. Before we unlink the subtree, we relink the + * leaf page chain. + */ + if ((ret = __db_relink(dbc, DB_REM_PAGE, cp->csp->page, NULL, 1)) != 0) + goto err; + + /* + * Delete the last item that references the underlying pages that are + * to be deleted, and adjust cursors that reference that page. Then, + * save that page's page number and item count and release it. If + * the application isn't retaining locks because it's running without + * transactions, this lets the rest of the tree get back to business + * immediately. + */ + if ((ret = __bam_ditem(dbc, epg->page, epg->indx)) != 0) + goto err; + if ((ret = __bam_ca_di(dbc, PGNO(epg->page), epg->indx, -1)) != 0) + goto err; + + pgno = PGNO(epg->page); + nitems = NUM_ENT(epg->page); + + if ((ret = memp_fput(dbp->mpf, epg->page, 0)) != 0) + goto err_inc; + (void)__TLPUT(dbc, epg->lock); + + /* Free the rest of the pages in the stack. */ + while (++epg <= cp->csp) { + /* + * Delete page entries so they will be restored as part of + * recovery. We don't need to do cursor adjustment here as + * the pages are being emptied by definition and so cannot + * be referenced by a cursor. + */ + if (NUM_ENT(epg->page) != 0) { + DB_ASSERT(NUM_ENT(epg->page) == 1); + + if ((ret = __bam_ditem(dbc, epg->page, epg->indx)) != 0) + goto err; + } + + if ((ret = __db_free(dbc, epg->page)) != 0) { + epg->page = NULL; + goto err_inc; + } + (void)__TLPUT(dbc, epg->lock); + } + + if (0) { +err_inc: ++epg; +err: for (; epg <= cp->csp; ++epg) { + if (epg->page != NULL) + (void)memp_fput(dbp->mpf, epg->page, 0); + (void)__TLPUT(dbc, epg->lock); + } + BT_STK_CLR(cp); + return (ret); + } + BT_STK_CLR(cp); + + /* + * If we just deleted the next-to-last item from the root page, the + * tree can collapse one or more levels. While there remains only a + * single item on the root page, write lock the last page referenced + * by the root page and copy it over the root page. + */ + root_pgno = cp->root; + if (pgno != root_pgno || nitems != 1) + return (0); + + for (done = 0; !done;) { + /* Initialize. */ + parent = child = NULL; + p_lock.off = c_lock.off = LOCK_INVALID; + + /* Lock the root. */ + pgno = root_pgno; + if ((ret = + __db_lget(dbc, 0, pgno, DB_LOCK_WRITE, 0, &p_lock)) != 0) + goto stop; + if ((ret = memp_fget(dbp->mpf, &pgno, 0, &parent)) != 0) + goto stop; + + if (NUM_ENT(parent) != 1) + goto stop; + + switch (TYPE(parent)) { + case P_IBTREE: + /* + * If this is overflow, then try to delete it. + * The child may or may not still point at it. + */ + bi = GET_BINTERNAL(parent, 0); + if (B_TYPE(bi->type) == B_OVERFLOW) + if ((ret = __db_doff(dbc, + ((BOVERFLOW *)bi->data)->pgno)) != 0) + goto stop; + pgno = bi->pgno; + break; + case P_IRECNO: + pgno = GET_RINTERNAL(parent, 0)->pgno; + break; + default: + goto stop; + } + + /* Lock the child page. */ + if ((ret = + __db_lget(dbc, 0, pgno, DB_LOCK_WRITE, 0, &c_lock)) != 0) + goto stop; + if ((ret = memp_fget(dbp->mpf, &pgno, 0, &child)) != 0) + goto stop; + + /* Log the change. */ + if (DB_LOGGING(dbc)) { + memset(&a, 0, sizeof(a)); + a.data = child; + a.size = dbp->pgsize; + memset(&b, 0, sizeof(b)); + b.data = P_ENTRY(parent, 0); + b.size = TYPE(parent) == P_IRECNO ? RINTERNAL_SIZE : + BINTERNAL_SIZE(((BINTERNAL *)b.data)->len); + if ((ret = + __bam_rsplit_log(dbp->dbenv, dbc->txn, &child->lsn, + 0, dbp->log_fileid, PGNO(child), &a, PGNO(parent), + RE_NREC(parent), &b, &parent->lsn)) != 0) + goto stop; + } + + /* + * Make the switch. + * + * One fixup -- internal pages below the top level do not store + * a record count, so we have to preserve it if we're not + * converting to a leaf page. Note also that we are about to + * overwrite the parent page, including its LSN. This is OK + * because the log message we wrote describing this update + * stores its LSN on the child page. When the child is copied + * onto the parent, the correct LSN is copied into place. + */ + COMPQUIET(rcnt, 0); + if (F_ISSET(cp, C_RECNUM) && LEVEL(child) > LEAFLEVEL) + rcnt = RE_NREC(parent); + memcpy(parent, child, dbp->pgsize); + PGNO(parent) = root_pgno; + if (F_ISSET(cp, C_RECNUM) && LEVEL(child) > LEAFLEVEL) + RE_NREC_SET(parent, rcnt); + + /* Mark the pages dirty. */ + if ((ret = memp_fset(dbp->mpf, parent, DB_MPOOL_DIRTY)) != 0) + goto stop; + if ((ret = memp_fset(dbp->mpf, child, DB_MPOOL_DIRTY)) != 0) + goto stop; + + /* Adjust the cursors. */ + if ((ret = __bam_ca_rsplit(dbc, PGNO(child), root_pgno)) != 0) + goto stop; + + /* + * Free the page copied onto the root page and discard its + * lock. (The call to __db_free() discards our reference + * to the page.) + */ + if ((ret = __db_free(dbc, child)) != 0) { + child = NULL; + goto stop; + } + child = NULL; + + if (0) { +stop: done = 1; + } + if (p_lock.off != LOCK_INVALID) + (void)__TLPUT(dbc, p_lock); + if (parent != NULL && + (t_ret = memp_fput(dbp->mpf, parent, 0)) != 0 && ret == 0) + ret = t_ret; + if (c_lock.off != LOCK_INVALID) + (void)__TLPUT(dbc, c_lock); + if (child != NULL && + (t_ret = memp_fput(dbp->mpf, child, 0)) != 0 && ret == 0) + ret = t_ret; + } + + return (ret); +} diff --git a/db/btree/bt_method.c b/db/btree/bt_method.c new file mode 100644 index 000000000..5e3af27d0 --- /dev/null +++ b/db/btree/bt_method.c @@ -0,0 +1,387 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: bt_method.c,v 11.20 2000/11/30 00:58:28 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "btree.h" +#include "qam.h" + +static int __bam_set_bt_compare + __P((DB *, int (*)(DB *, const DBT *, const DBT *))); +static int __bam_set_bt_maxkey __P((DB *, u_int32_t)); +static int __bam_set_bt_minkey __P((DB *, u_int32_t)); +static int __bam_set_bt_prefix + __P((DB *, size_t(*)(DB *, const DBT *, const DBT *))); +static int __ram_set_re_delim __P((DB *, int)); +static int __ram_set_re_len __P((DB *, u_int32_t)); +static int __ram_set_re_pad __P((DB *, int)); +static int __ram_set_re_source __P((DB *, const char *)); + +/* + * __bam_db_create -- + * Btree specific initialization of the DB structure. + * + * PUBLIC: int __bam_db_create __P((DB *)); + */ +int +__bam_db_create(dbp) + DB *dbp; +{ + BTREE *t; + int ret; + + /* Allocate and initialize the private btree structure. */ + if ((ret = __os_calloc(dbp->dbenv, 1, sizeof(BTREE), &t)) != 0) + return (ret); + dbp->bt_internal = t; + + t->bt_minkey = DEFMINKEYPAGE; /* Btree */ + t->bt_compare = __bam_defcmp; + t->bt_prefix = __bam_defpfx; + + dbp->set_bt_compare = __bam_set_bt_compare; + dbp->set_bt_maxkey = __bam_set_bt_maxkey; + dbp->set_bt_minkey = __bam_set_bt_minkey; + dbp->set_bt_prefix = __bam_set_bt_prefix; + + t->re_pad = ' '; /* Recno */ + t->re_delim = '\n'; + t->re_eof = 1; + + dbp->set_re_delim = __ram_set_re_delim; + dbp->set_re_len = __ram_set_re_len; + dbp->set_re_pad = __ram_set_re_pad; + dbp->set_re_source = __ram_set_re_source; + + return (0); +} + +/* + * __bam_db_close -- + * Btree specific discard of the DB structure. + * + * PUBLIC: int __bam_db_close __P((DB *)); + */ +int +__bam_db_close(dbp) + DB *dbp; +{ + BTREE *t; + + t = dbp->bt_internal; + /* Recno */ + /* Close any backing source file descriptor. */ + if (t->re_fp != NULL) + (void)fclose(t->re_fp); + + /* Free any backing source file name. */ + if (t->re_source != NULL) + __os_freestr(t->re_source); + + __os_free(t, sizeof(BTREE)); + dbp->bt_internal = NULL; + + return (0); +} + +/* + * __bam_set_flags -- + * Set Btree specific flags. + * + * PUBLIC: int __bam_set_flags __P((DB *, u_int32_t *flagsp)); + */ +int +__bam_set_flags(dbp, flagsp) + DB *dbp; + u_int32_t *flagsp; +{ + u_int32_t flags; + + flags = *flagsp; + if (LF_ISSET(DB_DUP | DB_DUPSORT | DB_RECNUM | DB_REVSPLITOFF)) { + DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_flags"); + + /* + * The DB_DUP and DB_DUPSORT flags are shared by the Hash + * and Btree access methods. + */ + if (LF_ISSET(DB_DUP | DB_DUPSORT)) + DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE | DB_OK_HASH); + + if (LF_ISSET(DB_RECNUM | DB_REVSPLITOFF)) + DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE); + + if (LF_ISSET(DB_DUP | DB_DUPSORT)) { + /* DB_DUP/DB_DUPSORT is incompatible with DB_RECNUM. */ + if (F_ISSET(dbp, DB_BT_RECNUM)) + goto incompat; + + if (LF_ISSET(DB_DUPSORT)) { + if (dbp->dup_compare == NULL) + dbp->dup_compare = __bam_defcmp; + F_SET(dbp, DB_AM_DUPSORT); + } + + F_SET(dbp, DB_AM_DUP); + LF_CLR(DB_DUP | DB_DUPSORT); + } + + if (LF_ISSET(DB_RECNUM)) { + /* DB_RECNUM is incompatible with DB_DUP/DB_DUPSORT. */ + if (F_ISSET(dbp, DB_AM_DUP)) + goto incompat; + + F_SET(dbp, DB_BT_RECNUM); + LF_CLR(DB_RECNUM); + } + + if (LF_ISSET(DB_REVSPLITOFF)) { + F_SET(dbp, DB_BT_REVSPLIT); + LF_CLR(DB_REVSPLITOFF); + } + + *flagsp = flags; + } + return (0); + +incompat: + return (__db_ferr(dbp->dbenv, "DB->set_flags", 1)); +} + +/* + * __bam_set_bt_compare -- + * Set the comparison function. + */ +static int +__bam_set_bt_compare(dbp, func) + DB *dbp; + int (*func) __P((DB *, const DBT *, const DBT *)); +{ + BTREE *t; + + DB_ILLEGAL_AFTER_OPEN(dbp, "set_bt_compare"); + DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE); + + t = dbp->bt_internal; + + /* + * Can't default the prefix routine if the user supplies a comparison + * routine; shortening the keys can break their comparison algorithm. + */ + t->bt_compare = func; + if (t->bt_prefix == __bam_defpfx) + t->bt_prefix = NULL; + + return (0); +} + +/* + * __bam_set_bt_maxkey -- + * Set the maximum keys per page. + */ +static int +__bam_set_bt_maxkey(dbp, bt_maxkey) + DB *dbp; + u_int32_t bt_maxkey; +{ + BTREE *t; + + DB_ILLEGAL_AFTER_OPEN(dbp, "set_bt_maxkey"); + DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE); + + t = dbp->bt_internal; + + if (bt_maxkey < 1) { + __db_err(dbp->dbenv, "minimum bt_maxkey value is 1"); + return (EINVAL); + } + + t->bt_maxkey = bt_maxkey; + return (0); +} + +/* + * __bam_set_bt_minkey -- + * Set the minimum keys per page. + */ +static int +__bam_set_bt_minkey(dbp, bt_minkey) + DB *dbp; + u_int32_t bt_minkey; +{ + BTREE *t; + + DB_ILLEGAL_AFTER_OPEN(dbp, "set_bt_minkey"); + DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE); + + t = dbp->bt_internal; + + if (bt_minkey < 2) { + __db_err(dbp->dbenv, "minimum bt_minkey value is 2"); + return (EINVAL); + } + + t->bt_minkey = bt_minkey; + return (0); +} + +/* + * __bam_set_bt_prefix -- + * Set the prefix function. + */ +static int +__bam_set_bt_prefix(dbp, func) + DB *dbp; + size_t (*func) __P((DB *, const DBT *, const DBT *)); +{ + BTREE *t; + + DB_ILLEGAL_AFTER_OPEN(dbp, "set_bt_prefix"); + DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE); + + t = dbp->bt_internal; + + t->bt_prefix = func; + return (0); +} + +/* + * __ram_set_flags -- + * Set Recno specific flags. + * + * PUBLIC: int __ram_set_flags __P((DB *, u_int32_t *flagsp)); + */ +int +__ram_set_flags(dbp, flagsp) + DB *dbp; + u_int32_t *flagsp; +{ + u_int32_t flags; + + flags = *flagsp; + if (LF_ISSET(DB_RENUMBER | DB_SNAPSHOT)) { + DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_flags"); + + DB_ILLEGAL_METHOD(dbp, DB_OK_RECNO); + + if (LF_ISSET(DB_RENUMBER)) { + F_SET(dbp, DB_RE_RENUMBER); + LF_CLR(DB_RENUMBER); + } + + if (LF_ISSET(DB_SNAPSHOT)) { + F_SET(dbp, DB_RE_SNAPSHOT); + LF_CLR(DB_SNAPSHOT); + } + + *flagsp = flags; + } + return (0); +} + +/* + * __ram_set_re_delim -- + * Set the variable-length input record delimiter. + */ +static int +__ram_set_re_delim(dbp, re_delim) + DB *dbp; + int re_delim; +{ + BTREE *t; + + DB_ILLEGAL_AFTER_OPEN(dbp, "set_re_delim"); + DB_ILLEGAL_METHOD(dbp, DB_OK_RECNO); + + t = dbp->bt_internal; + + t->re_delim = re_delim; + F_SET(dbp, DB_RE_DELIMITER); + + return (0); +} + +/* + * __ram_set_re_len -- + * Set the variable-length input record length. + */ +static int +__ram_set_re_len(dbp, re_len) + DB *dbp; + u_int32_t re_len; +{ + BTREE *t; + QUEUE *q; + + DB_ILLEGAL_AFTER_OPEN(dbp, "set_re_len"); + DB_ILLEGAL_METHOD(dbp, DB_OK_QUEUE | DB_OK_RECNO); + + t = dbp->bt_internal; + t->re_len = re_len; + + q = dbp->q_internal; + q->re_len = re_len; + + F_SET(dbp, DB_RE_FIXEDLEN); + + return (0); +} + +/* + * __ram_set_re_pad -- + * Set the fixed-length record pad character. + */ +static int +__ram_set_re_pad(dbp, re_pad) + DB *dbp; + int re_pad; +{ + BTREE *t; + QUEUE *q; + + DB_ILLEGAL_AFTER_OPEN(dbp, "set_re_pad"); + DB_ILLEGAL_METHOD(dbp, DB_OK_QUEUE | DB_OK_RECNO); + + t = dbp->bt_internal; + t->re_pad = re_pad; + + q = dbp->q_internal; + q->re_pad = re_pad; + + F_SET(dbp, DB_RE_PAD); + + return (0); +} + +/* + * __ram_set_re_source -- + * Set the backing source file name. + */ +static int +__ram_set_re_source(dbp, re_source) + DB *dbp; + const char *re_source; +{ + BTREE *t; + + DB_ILLEGAL_AFTER_OPEN(dbp, "set_re_source"); + DB_ILLEGAL_METHOD(dbp, DB_OK_RECNO); + + t = dbp->bt_internal; + + return (__os_strdup(dbp->dbenv, re_source, &t->re_source)); +} diff --git a/db/btree/bt_open.c b/db/btree/bt_open.c new file mode 100644 index 000000000..405c1880f --- /dev/null +++ b/db/btree/bt_open.c @@ -0,0 +1,468 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994, 1995 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Mike Olson. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: bt_open.c,v 11.42 2000/11/30 00:58:28 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_swap.h" +#include "btree.h" +#include "db_shash.h" +#include "lock.h" +#include "log.h" +#include "mp.h" + +/* + * __bam_open -- + * Open a btree. + * + * PUBLIC: int __bam_open __P((DB *, const char *, db_pgno_t, u_int32_t)); + */ +int +__bam_open(dbp, name, base_pgno, flags) + DB *dbp; + const char *name; + db_pgno_t base_pgno; + u_int32_t flags; +{ + BTREE *t; + + t = dbp->bt_internal; + + /* Initialize the remaining fields/methods of the DB. */ + dbp->del = __bam_delete; + dbp->key_range = __bam_key_range; + dbp->stat = __bam_stat; + + /* + * We don't permit the user to specify a prefix routine if they didn't + * also specify a comparison routine, they can't know enough about our + * comparison routine to get it right. + */ + if (t->bt_compare == __bam_defcmp && t->bt_prefix != __bam_defpfx) { + __db_err(dbp->dbenv, +"prefix comparison may not be specified for default comparison routine"); + return (EINVAL); + } + + /* + * Verify that the bt_minkey value specified won't cause the + * calculation of ovflsize to underflow [#2406] for this pagesize. + */ + if (B_MINKEY_TO_OVFLSIZE(t->bt_minkey, dbp->pgsize) > + B_MINKEY_TO_OVFLSIZE(DEFMINKEYPAGE, dbp->pgsize)) { + __db_err(dbp->dbenv, + "bt_minkey value of %lu too high for page size of %lu", + (u_long)t->bt_minkey, (u_long)dbp->pgsize); + return (EINVAL); + } + + /* Start up the tree. */ + return (__bam_read_root(dbp, name, base_pgno, flags)); +} + +/* + * __bam_metachk -- + * + * PUBLIC: int __bam_metachk __P((DB *, const char *, BTMETA *)); + */ +int +__bam_metachk(dbp, name, btm) + DB *dbp; + const char *name; + BTMETA *btm; +{ + DB_ENV *dbenv; + u_int32_t vers; + int ret; + + dbenv = dbp->dbenv; + + /* + * At this point, all we know is that the magic number is for a Btree. + * Check the version, the database may be out of date. + */ + vers = btm->dbmeta.version; + if (F_ISSET(dbp, DB_AM_SWAP)) + M_32_SWAP(vers); + switch (vers) { + case 6: + case 7: + __db_err(dbenv, + "%s: btree version %lu requires a version upgrade", + name, (u_long)vers); + return (DB_OLD_VERSION); + case 8: + break; + default: + __db_err(dbenv, + "%s: unsupported btree version: %lu", name, (u_long)vers); + return (EINVAL); + } + + /* Swap the page if we need to. */ + if (F_ISSET(dbp, DB_AM_SWAP) && (ret = __bam_mswap((PAGE *)btm)) != 0) + return (ret); + + /* + * Check application info against metadata info, and set info, flags, + * and type based on metadata info. + */ + if ((ret = + __db_fchk(dbenv, "DB->open", btm->dbmeta.flags, BTM_MASK)) != 0) + return (ret); + + if (F_ISSET(&btm->dbmeta, BTM_RECNO)) { + if (dbp->type == DB_BTREE) + goto wrong_type; + dbp->type = DB_RECNO; + DB_ILLEGAL_METHOD(dbp, DB_OK_RECNO); + } else { + if (dbp->type == DB_RECNO) + goto wrong_type; + dbp->type = DB_BTREE; + DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE); + } + + if (F_ISSET(&btm->dbmeta, BTM_DUP)) + F_SET(dbp, DB_AM_DUP); + else + if (F_ISSET(dbp, DB_AM_DUP)) { + __db_err(dbenv, + "%s: DB_DUP specified to open method but not set in database", + name); + return (EINVAL); + } + + if (F_ISSET(&btm->dbmeta, BTM_RECNUM)) { + if (dbp->type != DB_BTREE) + goto wrong_type; + F_SET(dbp, DB_BT_RECNUM); + + if ((ret = __db_fcchk(dbenv, + "DB->open", dbp->flags, DB_AM_DUP, DB_BT_RECNUM)) != 0) + return (ret); + } else + if (F_ISSET(dbp, DB_BT_RECNUM)) { + __db_err(dbenv, + "%s: DB_RECNUM specified to open method but not set in database", + name); + return (EINVAL); + } + + if (F_ISSET(&btm->dbmeta, BTM_FIXEDLEN)) { + if (dbp->type != DB_RECNO) + goto wrong_type; + F_SET(dbp, DB_RE_FIXEDLEN); + } else + if (F_ISSET(dbp, DB_RE_FIXEDLEN)) { + __db_err(dbenv, + "%s: DB_FIXEDLEN specified to open method but not set in database", + name); + return (EINVAL); + } + + if (F_ISSET(&btm->dbmeta, BTM_RENUMBER)) { + if (dbp->type != DB_RECNO) + goto wrong_type; + F_SET(dbp, DB_RE_RENUMBER); + } else + if (F_ISSET(dbp, DB_RE_RENUMBER)) { + __db_err(dbenv, + "%s: DB_RENUMBER specified to open method but not set in database", + name); + return (EINVAL); + } + + if (F_ISSET(&btm->dbmeta, BTM_SUBDB)) + F_SET(dbp, DB_AM_SUBDB); + else + if (F_ISSET(dbp, DB_AM_SUBDB)) { + __db_err(dbenv, + "%s: multiple databases specified but not supported by file", + name); + return (EINVAL); + } + + if (F_ISSET(&btm->dbmeta, BTM_DUPSORT)) { + if (dbp->dup_compare == NULL) + dbp->dup_compare = __bam_defcmp; + F_SET(dbp, DB_AM_DUPSORT); + } else + if (dbp->dup_compare != NULL) { + __db_err(dbenv, + "%s: duplicate sort specified but not supported in database", + name); + return (EINVAL); + } + + /* Set the page size. */ + dbp->pgsize = btm->dbmeta.pagesize; + + /* Copy the file's ID. */ + memcpy(dbp->fileid, btm->dbmeta.uid, DB_FILE_ID_LEN); + + return (0); + +wrong_type: + if (dbp->type == DB_BTREE) + __db_err(dbenv, + "open method type is Btree, database type is Recno"); + else + __db_err(dbenv, + "open method type is Recno, database type is Btree"); + return (EINVAL); +} + +/* + * __bam_read_root -- + * Check (and optionally create) a tree. + * + * PUBLIC: int __bam_read_root __P((DB *, const char *, db_pgno_t, u_int32_t)); + */ +int +__bam_read_root(dbp, name, base_pgno, flags) + DB *dbp; + const char *name; + db_pgno_t base_pgno; + u_int32_t flags; +{ + BTMETA *meta; + BTREE *t; + DBC *dbc; + DB_LSN orig_lsn; + DB_LOCK metalock; + PAGE *root; + int locked, ret, t_ret; + + ret = 0; + t = dbp->bt_internal; + meta = NULL; + root = NULL; + locked = 0; + + /* + * Get a cursor. If DB_CREATE is specified, we may be creating + * the root page, and to do that safely in CDB we need a write + * cursor. In STD_LOCKING mode, we'll synchronize using the + * meta page lock instead. + */ + if ((ret = dbp->cursor(dbp, dbp->open_txn, + &dbc, LF_ISSET(DB_CREATE) && CDB_LOCKING(dbp->dbenv) ? + DB_WRITECURSOR : 0)) != 0) + return (ret); + + /* Get, and optionally create the metadata page. */ + if ((ret = + __db_lget(dbc, 0, base_pgno, DB_LOCK_READ, 0, &metalock)) != 0) + goto err; + if ((ret = memp_fget( + dbp->mpf, &base_pgno, DB_MPOOL_CREATE, (PAGE **)&meta)) != 0) + goto err; + + /* + * If the magic number is correct, we're not creating the tree. + * Correct any fields that may not be right. Note, all of the + * local flags were set by DB->open. + */ +again: if (meta->dbmeta.magic != 0) { + t->bt_maxkey = meta->maxkey; + t->bt_minkey = meta->minkey; + t->re_pad = meta->re_pad; + t->re_len = meta->re_len; + + t->bt_meta = base_pgno; + t->bt_root = meta->root; + + (void)memp_fput(dbp->mpf, meta, 0); + meta = NULL; + goto done; + } + + /* In recovery if it's not there it will be created elsewhere.*/ + if (IS_RECOVERING(dbp->dbenv)) + goto done; + + /* If we're doing CDB; we now have to get the write lock. */ + if (CDB_LOCKING(dbp->dbenv)) { + /* + * We'd better have DB_CREATE set if we're actually doing + * the create. + */ + DB_ASSERT(LF_ISSET(DB_CREATE)); + if ((ret = lock_get(dbp->dbenv, dbc->locker, DB_LOCK_UPGRADE, + &dbc->lock_dbt, DB_LOCK_WRITE, &dbc->mylock)) != 0) + goto err; + } + + /* + * If we are doing locking, relase the read lock and get a write lock. + * We want to avoid deadlock. + */ + if (locked == 0 && STD_LOCKING(dbc)) { + if ((ret = __LPUT(dbc, metalock)) != 0) + goto err; + if ((ret = __db_lget(dbc, + 0, base_pgno, DB_LOCK_WRITE, 0, &metalock)) != 0) + goto err; + locked = 1; + goto again; + } + + /* Initialize the tree structure metadata information. */ + orig_lsn = meta->dbmeta.lsn; + memset(meta, 0, sizeof(BTMETA)); + meta->dbmeta.lsn = orig_lsn; + meta->dbmeta.pgno = base_pgno; + meta->dbmeta.magic = DB_BTREEMAGIC; + meta->dbmeta.version = DB_BTREEVERSION; + meta->dbmeta.pagesize = dbp->pgsize; + meta->dbmeta.type = P_BTREEMETA; + meta->dbmeta.free = PGNO_INVALID; + if (F_ISSET(dbp, DB_AM_DUP)) + F_SET(&meta->dbmeta, BTM_DUP); + if (F_ISSET(dbp, DB_RE_FIXEDLEN)) + F_SET(&meta->dbmeta, BTM_FIXEDLEN); + if (F_ISSET(dbp, DB_BT_RECNUM)) + F_SET(&meta->dbmeta, BTM_RECNUM); + if (F_ISSET(dbp, DB_RE_RENUMBER)) + F_SET(&meta->dbmeta, BTM_RENUMBER); + if (F_ISSET(dbp, DB_AM_SUBDB)) + F_SET(&meta->dbmeta, BTM_SUBDB); + if (dbp->dup_compare != NULL) + F_SET(&meta->dbmeta, BTM_DUPSORT); + if (dbp->type == DB_RECNO) + F_SET(&meta->dbmeta, BTM_RECNO); + memcpy(meta->dbmeta.uid, dbp->fileid, DB_FILE_ID_LEN); + + meta->maxkey = t->bt_maxkey; + meta->minkey = t->bt_minkey; + meta->re_len = t->re_len; + meta->re_pad = t->re_pad; + + /* If necessary, log the meta-data and root page creates. */ + if ((ret = __db_log_page(dbp, + name, &orig_lsn, base_pgno, (PAGE *)meta)) != 0) + goto err; + + /* Create and initialize a root page. */ + if ((ret = __db_new(dbc, + dbp->type == DB_RECNO ? P_LRECNO : P_LBTREE, &root)) != 0) + goto err; + root->level = LEAFLEVEL; + + if (dbp->open_txn != NULL && (ret = __bam_root_log(dbp->dbenv, + dbp->open_txn, &meta->dbmeta.lsn, 0, dbp->log_fileid, + meta->dbmeta.pgno, root->pgno, &meta->dbmeta.lsn)) != 0) + goto err; + + meta->root = root->pgno; + + DB_TEST_RECOVERY(dbp, DB_TEST_POSTLOGMETA, ret, name); + if ((ret = __db_log_page(dbp, + name, &root->lsn, root->pgno, root)) != 0) + goto err; + DB_TEST_RECOVERY(dbp, DB_TEST_POSTLOG, ret, name); + + t->bt_meta = base_pgno; + t->bt_root = root->pgno; + + /* Release the metadata and root pages. */ + if ((ret = memp_fput(dbp->mpf, meta, DB_MPOOL_DIRTY)) != 0) + goto err; + meta = NULL; + if ((ret = memp_fput(dbp->mpf, root, DB_MPOOL_DIRTY)) != 0) + goto err; + root = NULL; + + /* + * Flush the metadata and root pages to disk. + * + * !!! + * It's not useful to return not-yet-flushed here -- convert it to + * an error. + */ + if ((ret = memp_fsync(dbp->mpf)) == DB_INCOMPLETE) { + __db_err(dbp->dbenv, "Metapage flush failed"); + ret = EINVAL; + } + DB_TEST_RECOVERY(dbp, DB_TEST_POSTSYNC, ret, name); + +done: /* + * !!! + * We already did an insert and so the last-page-inserted has been + * set. I'm not sure where the *right* place to clear this value + * is, it's not intuitively obvious that it belongs here. + */ + t->bt_lpgno = PGNO_INVALID; + +err: +DB_TEST_RECOVERY_LABEL + /* Put any remaining pages back. */ + if (meta != NULL) + if ((t_ret = memp_fput(dbp->mpf, meta, 0)) != 0 && + ret == 0) + ret = t_ret; + if (root != NULL) + if ((t_ret = memp_fput(dbp->mpf, root, 0)) != 0 && + ret == 0) + ret = t_ret; + + /* We can release the metapage lock when we are done. */ + if ((t_ret = __LPUT(dbc, metalock)) != 0 && ret == 0) + ret = t_ret; + + if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0) + ret = t_ret; + return (ret); +} diff --git a/db/btree/bt_put.c b/db/btree/bt_put.c new file mode 100644 index 000000000..19a04526d --- /dev/null +++ b/db/btree/bt_put.c @@ -0,0 +1,859 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994, 1995 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Mike Olson. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: bt_put.c,v 11.46 2001/01/17 18:48:46 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "btree.h" + +static int __bam_dup_convert __P((DBC *, PAGE *, u_int32_t)); +static int __bam_ovput + __P((DBC *, u_int32_t, db_pgno_t, PAGE *, u_int32_t, DBT *)); + +/* + * __bam_iitem -- + * Insert an item into the tree. + * + * PUBLIC: int __bam_iitem __P((DBC *, DBT *, DBT *, u_int32_t, u_int32_t)); + */ +int +__bam_iitem(dbc, key, data, op, flags) + DBC *dbc; + DBT *key, *data; + u_int32_t op, flags; +{ + BKEYDATA *bk, bk_tmp; + BTREE *t; + BTREE_CURSOR *cp; + DB *dbp; + DBT bk_hdr, tdbt; + PAGE *h; + db_indx_t indx; + u_int32_t data_size, have_bytes, need_bytes, needed; + int cmp, bigkey, bigdata, dupadjust, padrec, replace, ret, was_deleted; + + COMPQUIET(bk, NULL); + + dbp = dbc->dbp; + cp = (BTREE_CURSOR *)dbc->internal; + t = dbp->bt_internal; + h = cp->page; + indx = cp->indx; + dupadjust = replace = was_deleted = 0; + + /* + * Fixed-length records with partial puts: it's an error to specify + * anything other simple overwrite. + */ + if (F_ISSET(dbp, DB_RE_FIXEDLEN) && + F_ISSET(data, DB_DBT_PARTIAL) && data->dlen != data->size) { + data_size = data->size; + goto len_err; + } + + /* + * Figure out how much space the data will take, including if it's a + * partial record. + * + * Fixed-length records: it's an error to specify a record that's + * longer than the fixed-length, and we never require less than + * the fixed-length record size. + */ + data_size = F_ISSET(data, DB_DBT_PARTIAL) ? + __bam_partsize(op, data, h, indx) : data->size; + padrec = 0; + if (F_ISSET(dbp, DB_RE_FIXEDLEN)) { + if (data_size > t->re_len) { +len_err: __db_err(dbp->dbenv, + "Length improper for fixed length record %lu", + (u_long)data_size); + return (EINVAL); + } + if (data_size < t->re_len) { + padrec = 1; + data_size = t->re_len; + } + } + + /* + * Handle partial puts or short fixed-length records: build the + * real record. + */ + if (padrec || F_ISSET(data, DB_DBT_PARTIAL)) { + tdbt = *data; + if ((ret = + __bam_build(dbc, op, &tdbt, h, indx, data_size)) != 0) + return (ret); + data = &tdbt; + } + + /* + * If the user has specified a duplicate comparison function, return + * an error if DB_CURRENT was specified and the replacement data + * doesn't compare equal to the current data. This stops apps from + * screwing up the duplicate sort order. We have to do this after + * we build the real record so that we're comparing the real items. + */ + if (op == DB_CURRENT && dbp->dup_compare != NULL) { + if ((ret = __bam_cmp(dbp, data, h, + indx + (TYPE(h) == P_LBTREE ? O_INDX : 0), + dbp->dup_compare, &cmp)) != 0) + return (ret); + if (cmp != 0) { + __db_err(dbp->dbenv, + "Current data differs from put data"); + return (EINVAL); + } + } + + /* + * If the key or data item won't fit on a page, we'll have to store + * them on overflow pages. + */ + needed = 0; + bigdata = data_size > cp->ovflsize; + switch (op) { + case DB_KEYFIRST: + /* We're adding a new key and data pair. */ + bigkey = key->size > cp->ovflsize; + if (bigkey) + needed += BOVERFLOW_PSIZE; + else + needed += BKEYDATA_PSIZE(key->size); + if (bigdata) + needed += BOVERFLOW_PSIZE; + else + needed += BKEYDATA_PSIZE(data_size); + break; + case DB_AFTER: + case DB_BEFORE: + case DB_CURRENT: + /* + * We're either overwriting the data item of a key/data pair + * or we're creating a new on-page duplicate and only adding + * a data item. + * + * !!! + * We're not currently correcting for space reclaimed from + * already deleted items, but I don't think it's worth the + * complexity. + */ + bigkey = 0; + if (op == DB_CURRENT) { + bk = GET_BKEYDATA(h, + indx + (TYPE(h) == P_LBTREE ? O_INDX : 0)); + if (B_TYPE(bk->type) == B_KEYDATA) + have_bytes = BKEYDATA_PSIZE(bk->len); + else + have_bytes = BOVERFLOW_PSIZE; + need_bytes = 0; + } else { + have_bytes = 0; + need_bytes = sizeof(db_indx_t); + } + if (bigdata) + need_bytes += BOVERFLOW_PSIZE; + else + need_bytes += BKEYDATA_PSIZE(data_size); + + if (have_bytes < need_bytes) + needed += need_bytes - have_bytes; + break; + default: + return (__db_unknown_flag(dbp->dbenv, "__bam_iitem", op)); + } + + /* + * If there's not enough room, or the user has put a ceiling on the + * number of keys permitted in the page, split the page. + * + * XXX + * The t->bt_maxkey test here may be insufficient -- do we have to + * check in the btree split code, so we don't undo it there!?!? + */ + if (P_FREESPACE(h) < needed || + (t->bt_maxkey != 0 && NUM_ENT(h) > t->bt_maxkey)) + return (DB_NEEDSPLIT); + + /* + * The code breaks it up into five cases: + * + * 1. Insert a new key/data pair. + * 2. Append a new data item (a new duplicate). + * 3. Insert a new data item (a new duplicate). + * 4. Delete and re-add the data item (overflow item). + * 5. Overwrite the data item. + */ + switch (op) { + case DB_KEYFIRST: /* 1. Insert a new key/data pair. */ + if (bigkey) { + if ((ret = __bam_ovput(dbc, + B_OVERFLOW, PGNO_INVALID, h, indx, key)) != 0) + return (ret); + } else + if ((ret = __db_pitem(dbc, h, indx, + BKEYDATA_SIZE(key->size), NULL, key)) != 0) + return (ret); + + if ((ret = __bam_ca_di(dbc, PGNO(h), indx, 1)) != 0) + return (ret); + ++indx; + break; + case DB_AFTER: /* 2. Append a new data item. */ + if (TYPE(h) == P_LBTREE) { + /* Copy the key for the duplicate and adjust cursors. */ + if ((ret = + __bam_adjindx(dbc, h, indx + P_INDX, indx, 1)) != 0) + return (ret); + if ((ret = + __bam_ca_di(dbc, PGNO(h), indx + P_INDX, 1)) != 0) + return (ret); + + indx += 3; + dupadjust = 1; + + cp->indx += 2; + } else { + ++indx; + cp->indx += 1; + } + break; + case DB_BEFORE: /* 3. Insert a new data item. */ + if (TYPE(h) == P_LBTREE) { + /* Copy the key for the duplicate and adjust cursors. */ + if ((ret = __bam_adjindx(dbc, h, indx, indx, 1)) != 0) + return (ret); + if ((ret = __bam_ca_di(dbc, PGNO(h), indx, 1)) != 0) + return (ret); + + ++indx; + dupadjust = 1; + } + break; + case DB_CURRENT: + /* + * Clear the cursor's deleted flag. The problem is that if + * we deadlock or fail while deleting the overflow item or + * replacing the non-overflow item, a subsequent cursor close + * will try and remove the item because the cursor's delete + * flag is set + */ + (void)__bam_ca_delete(dbp, PGNO(h), indx, 0); + + if (TYPE(h) == P_LBTREE) { + ++indx; + dupadjust = 1; + + /* + * In a Btree deleted records aren't counted (deleted + * records are counted in a Recno because all accesses + * are based on record number). If it's a Btree and + * it's a DB_CURRENT operation overwriting a previously + * deleted record, increment the record count. + */ + was_deleted = B_DISSET(bk->type); + } + + /* + * 4. Delete and re-add the data item. + * + * If we're changing the type of the on-page structure, or we + * are referencing offpage items, we have to delete and then + * re-add the item. We do not do any cursor adjustments here + * because we're going to immediately re-add the item into the + * same slot. + */ + if (bigdata || B_TYPE(bk->type) != B_KEYDATA) { + if ((ret = __bam_ditem(dbc, h, indx)) != 0) + return (ret); + break; + } + + /* 5. Overwrite the data item. */ + replace = 1; + break; + default: + return (__db_unknown_flag(dbp->dbenv, "__bam_iitem", op)); + } + + /* Add the data. */ + if (bigdata) { + if ((ret = __bam_ovput(dbc, + B_OVERFLOW, PGNO_INVALID, h, indx, data)) != 0) + return (ret); + } else { + if (LF_ISSET(BI_DELETED)) { + B_TSET(bk_tmp.type, B_KEYDATA, 1); + bk_tmp.len = data->size; + bk_hdr.data = &bk_tmp; + bk_hdr.size = SSZA(BKEYDATA, data); + ret = __db_pitem(dbc, h, indx, + BKEYDATA_SIZE(data->size), &bk_hdr, data); + } else if (replace) + ret = __bam_ritem(dbc, h, indx, data); + else + ret = __db_pitem(dbc, h, indx, + BKEYDATA_SIZE(data->size), NULL, data); + if (ret != 0) + return (ret); + } + if ((ret = memp_fset(dbp->mpf, h, DB_MPOOL_DIRTY)) != 0) + return (ret); + + /* + * Re-position the cursors if necessary and reset the current cursor + * to point to the new item. + */ + if (op != DB_CURRENT) { + if ((ret = __bam_ca_di(dbc, PGNO(h), indx, 1)) != 0) + return (ret); + cp->indx = TYPE(h) == P_LBTREE ? indx - O_INDX : indx; + } + + /* + * If we've changed the record count, update the tree. There's no + * need to adjust the count if the operation not performed on the + * current record or when the current record was previously deleted. + */ + if (F_ISSET(cp, C_RECNUM) && (op != DB_CURRENT || was_deleted)) + if ((ret = __bam_adjust(dbc, 1)) != 0) + return (ret); + + /* + * If a Btree leaf page is at least 50% full and we may have added or + * modified a duplicate data item, see if the set of duplicates takes + * up at least 25% of the space on the page. If it does, move it onto + * its own page. + */ + if (dupadjust && P_FREESPACE(h) <= dbp->pgsize / 2) { + if ((ret = __bam_dup_convert(dbc, h, indx - O_INDX)) != 0) + return (ret); + } + + /* If we've modified a recno file, set the flag. */ + if (dbc->dbtype == DB_RECNO) + t->re_modified = 1; + + return (ret); +} + +/* + * __bam_partsize -- + * Figure out how much space a partial data item is in total. + * + * PUBLIC: u_int32_t __bam_partsize __P((u_int32_t, DBT *, PAGE *, u_int32_t)); + */ +u_int32_t +__bam_partsize(op, data, h, indx) + u_int32_t op, indx; + DBT *data; + PAGE *h; +{ + BKEYDATA *bk; + u_int32_t nbytes; + + /* + * If the record doesn't already exist, it's simply the data we're + * provided. + */ + if (op != DB_CURRENT) + return (data->doff + data->size); + + /* + * Otherwise, it's the data provided plus any already existing data + * that we're not replacing. + */ + bk = GET_BKEYDATA(h, indx + (TYPE(h) == P_LBTREE ? O_INDX : 0)); + nbytes = + B_TYPE(bk->type) == B_OVERFLOW ? ((BOVERFLOW *)bk)->tlen : bk->len; + + /* + * There are really two cases here: + * + * Case 1: We are replacing some bytes that do not exist (i.e., they + * are past the end of the record). In this case the number of bytes + * we are replacing is irrelevant and all we care about is how many + * bytes we are going to add from offset. So, the new record length + * is going to be the size of the new bytes (size) plus wherever those + * new bytes begin (doff). + * + * Case 2: All the bytes we are replacing exist. Therefore, the new + * size is the oldsize (nbytes) minus the bytes we are replacing (dlen) + * plus the bytes we are adding (size). + */ + if (nbytes < data->doff + data->dlen) /* Case 1 */ + return (data->doff + data->size); + + return (nbytes + data->size - data->dlen); /* Case 2 */ +} + +/* + * __bam_build -- + * Build the real record for a partial put, or short fixed-length record. + * + * PUBLIC: int __bam_build __P((DBC *, u_int32_t, + * PUBLIC: DBT *, PAGE *, u_int32_t, u_int32_t)); + */ +int +__bam_build(dbc, op, dbt, h, indx, nbytes) + DBC *dbc; + u_int32_t op, indx, nbytes; + DBT *dbt; + PAGE *h; +{ + BKEYDATA *bk, tbk; + BOVERFLOW *bo; + BTREE *t; + BTREE_CURSOR *cp; + DB *dbp; + DBT copy; + u_int32_t len, tlen; + u_int8_t *p; + int ret; + + COMPQUIET(bo, NULL); + + dbp = dbc->dbp; + cp = (BTREE_CURSOR *) dbc->internal; + t = dbp->bt_internal; + + /* We use the record data return memory, it's only a short-term use. */ + if (dbc->rdata.ulen < nbytes) { + if ((ret = __os_realloc(dbp->dbenv, + nbytes, NULL, &dbc->rdata.data)) != 0) { + dbc->rdata.ulen = 0; + dbc->rdata.data = NULL; + return (ret); + } + dbc->rdata.ulen = nbytes; + } + + /* + * We use nul or pad bytes for any part of the record that isn't + * specified; get it over with. + */ + memset(dbc->rdata.data, + F_ISSET(dbp, DB_RE_FIXEDLEN) ? t->re_pad : 0, nbytes); + + /* + * In the next clauses, we need to do three things: a) set p to point + * to the place at which to copy the user's data, b) set tlen to the + * total length of the record, not including the bytes contributed by + * the user, and c) copy any valid data from an existing record. If + * it's not a partial put (this code is called for both partial puts + * and fixed-length record padding) or it's a new key, we can cut to + * the chase. + */ + if (!F_ISSET(dbt, DB_DBT_PARTIAL) || op != DB_CURRENT) { + p = (u_int8_t *)dbc->rdata.data + dbt->doff; + tlen = dbt->doff; + goto user_copy; + } + + /* Find the current record. */ + if (indx < NUM_ENT(h)) { + bk = GET_BKEYDATA(h, indx + (TYPE(h) == P_LBTREE ? O_INDX : 0)); + bo = (BOVERFLOW *)bk; + } else { + bk = &tbk; + B_TSET(bk->type, B_KEYDATA, 0); + bk->len = 0; + } + if (B_TYPE(bk->type) == B_OVERFLOW) { + /* + * In the case of an overflow record, we shift things around + * in the current record rather than allocate a separate copy. + */ + memset(©, 0, sizeof(copy)); + if ((ret = __db_goff(dbp, ©, bo->tlen, + bo->pgno, &dbc->rdata.data, &dbc->rdata.ulen)) != 0) + return (ret); + + /* Skip any leading data from the original record. */ + tlen = dbt->doff; + p = (u_int8_t *)dbc->rdata.data + dbt->doff; + + /* + * Copy in any trailing data from the original record. + * + * If the original record was larger than the original offset + * plus the bytes being deleted, there is trailing data in the + * original record we need to preserve. If we aren't deleting + * the same number of bytes as we're inserting, copy it up or + * down, into place. + * + * Use memmove(), the regions may overlap. + */ + if (bo->tlen > dbt->doff + dbt->dlen) { + len = bo->tlen - (dbt->doff + dbt->dlen); + if (dbt->dlen != dbt->size) + memmove(p + dbt->size, p + dbt->dlen, len); + tlen += len; + } + } else { + /* Copy in any leading data from the original record. */ + memcpy(dbc->rdata.data, + bk->data, dbt->doff > bk->len ? bk->len : dbt->doff); + tlen = dbt->doff; + p = (u_int8_t *)dbc->rdata.data + dbt->doff; + + /* Copy in any trailing data from the original record. */ + len = dbt->doff + dbt->dlen; + if (bk->len > len) { + memcpy(p + dbt->size, bk->data + len, bk->len - len); + tlen += bk->len - len; + } + } + +user_copy: + /* + * Copy in the application provided data -- p and tlen must have been + * initialized above. + */ + memcpy(p, dbt->data, dbt->size); + tlen += dbt->size; + + /* Set the DBT to reference our new record. */ + dbc->rdata.size = F_ISSET(dbp, DB_RE_FIXEDLEN) ? t->re_len : tlen; + dbc->rdata.dlen = 0; + dbc->rdata.doff = 0; + dbc->rdata.flags = 0; + *dbt = dbc->rdata; + return (0); +} + +/* + * __bam_ritem -- + * Replace an item on a page. + * + * PUBLIC: int __bam_ritem __P((DBC *, PAGE *, u_int32_t, DBT *)); + */ +int +__bam_ritem(dbc, h, indx, data) + DBC *dbc; + PAGE *h; + u_int32_t indx; + DBT *data; +{ + BKEYDATA *bk; + DB *dbp; + DBT orig, repl; + db_indx_t cnt, lo, ln, min, off, prefix, suffix; + int32_t nbytes; + int ret; + u_int8_t *p, *t; + + dbp = dbc->dbp; + + /* + * Replace a single item onto a page. The logic figuring out where + * to insert and whether it fits is handled in the caller. All we do + * here is manage the page shuffling. + */ + bk = GET_BKEYDATA(h, indx); + + /* Log the change. */ + if (DB_LOGGING(dbc)) { + /* + * We might as well check to see if the two data items share + * a common prefix and suffix -- it can save us a lot of log + * message if they're large. + */ + min = data->size < bk->len ? data->size : bk->len; + for (prefix = 0, + p = bk->data, t = data->data; + prefix < min && *p == *t; ++prefix, ++p, ++t) + ; + + min -= prefix; + for (suffix = 0, + p = (u_int8_t *)bk->data + bk->len - 1, + t = (u_int8_t *)data->data + data->size - 1; + suffix < min && *p == *t; ++suffix, --p, --t) + ; + + /* We only log the parts of the keys that have changed. */ + orig.data = (u_int8_t *)bk->data + prefix; + orig.size = bk->len - (prefix + suffix); + repl.data = (u_int8_t *)data->data + prefix; + repl.size = data->size - (prefix + suffix); + if ((ret = __bam_repl_log(dbp->dbenv, dbc->txn, + &LSN(h), 0, dbp->log_fileid, PGNO(h), &LSN(h), + (u_int32_t)indx, (u_int32_t)B_DISSET(bk->type), + &orig, &repl, (u_int32_t)prefix, (u_int32_t)suffix)) != 0) + return (ret); + } + + /* + * Set references to the first in-use byte on the page and the + * first byte of the item being replaced. + */ + p = (u_int8_t *)h + HOFFSET(h); + t = (u_int8_t *)bk; + + /* + * If the entry is growing in size, shift the beginning of the data + * part of the page down. If the entry is shrinking in size, shift + * the beginning of the data part of the page up. Use memmove(3), + * the regions overlap. + */ + lo = BKEYDATA_SIZE(bk->len); + ln = BKEYDATA_SIZE(data->size); + if (lo != ln) { + nbytes = lo - ln; /* Signed difference. */ + if (p == t) /* First index is fast. */ + h->inp[indx] += nbytes; + else { /* Else, shift the page. */ + memmove(p + nbytes, p, t - p); + + /* Adjust the indices' offsets. */ + off = h->inp[indx]; + for (cnt = 0; cnt < NUM_ENT(h); ++cnt) + if (h->inp[cnt] <= off) + h->inp[cnt] += nbytes; + } + + /* Clean up the page and adjust the item's reference. */ + HOFFSET(h) += nbytes; + t += nbytes; + } + + /* Copy the new item onto the page. */ + bk = (BKEYDATA *)t; + B_TSET(bk->type, B_KEYDATA, 0); + bk->len = data->size; + memcpy(bk->data, data->data, data->size); + + return (0); +} + +/* + * __bam_dup_convert -- + * Check to see if the duplicate set at indx should have its own page. + * If it should, create it. + */ +static int +__bam_dup_convert(dbc, h, indx) + DBC *dbc; + PAGE *h; + u_int32_t indx; +{ + BTREE_CURSOR *cp; + BKEYDATA *bk; + DB *dbp; + DBT hdr; + PAGE *dp; + db_indx_t cnt, cpindx, dindx, first, sz; + int ret; + + dbp = dbc->dbp; + cp = (BTREE_CURSOR *)dbc->internal; + + /* + * Count the duplicate records and calculate how much room they're + * using on the page. + */ + while (indx > 0 && h->inp[indx] == h->inp[indx - P_INDX]) + indx -= P_INDX; + for (cnt = 0, sz = 0, first = indx;; ++cnt, indx += P_INDX) { + if (indx >= NUM_ENT(h) || h->inp[first] != h->inp[indx]) + break; + bk = GET_BKEYDATA(h, indx); + sz += B_TYPE(bk->type) == B_KEYDATA ? + BKEYDATA_PSIZE(bk->len) : BOVERFLOW_PSIZE; + bk = GET_BKEYDATA(h, indx + O_INDX); + sz += B_TYPE(bk->type) == B_KEYDATA ? + BKEYDATA_PSIZE(bk->len) : BOVERFLOW_PSIZE; + } + + /* + * We have to do these checks when the user is replacing the cursor's + * data item -- if the application replaces a duplicate item with a + * larger data item, it can increase the amount of space used by the + * duplicates, requiring this check. But that means we may have done + * this check when it wasn't a duplicate item after all. + */ + if (cnt == 1) + return (0); + + /* + * If this set of duplicates is using more than 25% of the page, move + * them off. The choice of 25% is a WAG, but the value must be small + * enough that we can always split a page without putting duplicates + * on two different pages. + */ + if (sz < dbp->pgsize / 4) + return (0); + + /* Get a new page. */ + if ((ret = __db_new(dbc, + dbp->dup_compare == NULL ? P_LRECNO : P_LDUP, &dp)) != 0) + return (ret); + P_INIT(dp, dbp->pgsize, dp->pgno, + PGNO_INVALID, PGNO_INVALID, LEAFLEVEL, TYPE(dp)); + + /* + * Move this set of duplicates off the page. First points to the first + * key of the first duplicate key/data pair, cnt is the number of pairs + * we're dealing with. + */ + memset(&hdr, 0, sizeof(hdr)); + dindx = first; + indx = first; + cpindx = 0; + do { + /* Move cursors referencing the old entry to the new entry. */ + if ((ret = __bam_ca_dup(dbc, first, + PGNO(h), indx, PGNO(dp), cpindx)) != 0) + goto err; + + /* + * Copy the entry to the new page. If the off-duplicate page + * If the off-duplicate page is a Btree page (i.e. dup_compare + * will be non-NULL, we use Btree pages for sorted dups, + * and Recno pages for unsorted dups), move all entries + * normally, even deleted ones. If it's a Recno page, + * deleted entries are discarded (if the deleted entry is + * overflow, then free up those pages). + */ + bk = GET_BKEYDATA(h, dindx + 1); + hdr.data = bk; + hdr.size = B_TYPE(bk->type) == B_KEYDATA ? + BKEYDATA_SIZE(bk->len) : BOVERFLOW_SIZE; + if (dbp->dup_compare == NULL && B_DISSET(bk->type)) { + /* + * Unsorted dups, i.e. recno page, and we have + * a deleted entry, don't move it, but if it was + * an overflow entry, we need to free those pages. + */ + if (B_TYPE(bk->type) == B_OVERFLOW && + (ret = __db_doff(dbc, + (GET_BOVERFLOW(h, dindx + 1))->pgno)) != 0) + goto err; + } else { + if ((ret = __db_pitem( + dbc, dp, cpindx, hdr.size, &hdr, NULL)) != 0) + goto err; + ++cpindx; + } + /* Delete all but the last reference to the key. */ + if (cnt != 1) { + if ((ret = __bam_adjindx(dbc, + h, dindx, first + 1, 0)) != 0) + goto err; + } else + dindx++; + + /* Delete the data item. */ + if ((ret = __db_ditem(dbc, h, dindx, hdr.size)) != 0) + goto err; + indx += P_INDX; + } while (--cnt); + + /* Put in a new data item that points to the duplicates page. */ + if ((ret = __bam_ovput(dbc, + B_DUPLICATE, dp->pgno, h, first + 1, NULL)) != 0) + goto err; + + /* Adjust cursors for all the above movments. */ + if ((ret = __bam_ca_di(dbc, + PGNO(h), first + P_INDX, first + P_INDX - indx)) != 0) + goto err; + + return (memp_fput(dbp->mpf, dp, DB_MPOOL_DIRTY)); + +err: (void)__db_free(dbc, dp); + return (ret); +} + +/* + * __bam_ovput -- + * Build an item for an off-page duplicates page or overflow page and + * insert it on the page. + */ +static int +__bam_ovput(dbc, type, pgno, h, indx, item) + DBC *dbc; + u_int32_t type, indx; + db_pgno_t pgno; + PAGE *h; + DBT *item; +{ + BOVERFLOW bo; + DBT hdr; + int ret; + + UMRW_SET(bo.unused1); + B_TSET(bo.type, type, 0); + UMRW_SET(bo.unused2); + + /* + * If we're creating an overflow item, do so and acquire the page + * number for it. If we're creating an off-page duplicates tree, + * we are giving the page number as an argument. + */ + if (type == B_OVERFLOW) { + if ((ret = __db_poff(dbc, item, &bo.pgno)) != 0) + return (ret); + bo.tlen = item->size; + } else { + bo.pgno = pgno; + bo.tlen = 0; + } + + /* Store the new record on the page. */ + memset(&hdr, 0, sizeof(hdr)); + hdr.data = &bo; + hdr.size = BOVERFLOW_SIZE; + return (__db_pitem(dbc, h, indx, BOVERFLOW_SIZE, &hdr, NULL)); +} diff --git a/db/btree/bt_rec.c b/db/btree/bt_rec.c new file mode 100644 index 000000000..24dc9bc6a --- /dev/null +++ b/db/btree/bt_rec.c @@ -0,0 +1,1219 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: bt_rec.c,v 11.35 2001/01/10 16:24:47 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "hash.h" +#include "btree.h" +#include "log.h" + +#define IS_BTREE_PAGE(pagep) \ + (TYPE(pagep) == P_IBTREE || \ + TYPE(pagep) == P_LBTREE || TYPE(pagep) == P_LDUP) + +/* + * __bam_pg_alloc_recover -- + * Recovery function for pg_alloc. + * + * PUBLIC: int __bam_pg_alloc_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__bam_pg_alloc_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __bam_pg_alloc_args *argp; + DB *file_dbp; + DBC *dbc; + DBMETA *meta; + DB_MPOOLFILE *mpf; + PAGE *pagep; + db_pgno_t pgno; + int cmp_n, cmp_p, level, modified, ret; + + REC_PRINT(__bam_pg_alloc_print); + REC_INTRO(__bam_pg_alloc_read, 0); + + /* + * Fix up the allocated page. If we're redoing the operation, we have + * to get the page (creating it if it doesn't exist), and update its + * LSN. If we're undoing the operation, we have to reset the page's + * LSN and put it on the free list. + * + * Fix up the metadata page. If we're redoing the operation, we have + * to get the metadata page and update its LSN and its free pointer. + * If we're undoing the operation and the page was ever created, we put + * it on the freelist. + */ + pgno = PGNO_BASE_MD; + meta = NULL; + if ((ret = memp_fget(mpf, &pgno, 0, &meta)) != 0) { + /* The metadata page must always exist on redo. */ + if (DB_REDO(op)) { + (void)__db_pgerr(file_dbp, pgno); + goto out; + } else + goto done; + } + if ((ret = memp_fget(mpf, &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) { + /* + * We specify creation and check for it later, because this + * operation was supposed to create the page, and even in + * the undo case it's going to get linked onto the freelist + * which we're also fixing up. + */ + (void)__db_pgerr(file_dbp, argp->pgno); + goto err; + } + + /* Fix up the allocated page. */ + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + cmp_p = log_compare(&LSN(pagep), &argp->page_lsn); + + /* + * If an inital allocation is aborted and then reallocated + * during an archival restore the log record will have + * an LSN for the page but the page will be empty. + */ + if (IS_ZERO_LSN(LSN(pagep))) + cmp_p = 0; + CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->page_lsn); + /* + * If we we rolled back this allocation previously during an + * archive restore, the page may have the LSN of the meta page + * at the point of the roll back. This will be no more + * than the LSN of the metadata page at the time of this allocation. + */ + if (DB_REDO(op) && + (cmp_p == 0 || + (IS_ZERO_LSN(argp->page_lsn) && + log_compare(&LSN(pagep), &argp->meta_lsn) <= 0))) { + /* Need to redo update described. */ + switch (argp->ptype) { + case P_LBTREE: + case P_LRECNO: + case P_LDUP: + level = LEAFLEVEL; + break; + default: + level = 0; + break; + } + P_INIT(pagep, file_dbp->pgsize, + argp->pgno, PGNO_INVALID, PGNO_INVALID, level, argp->ptype); + + pagep->lsn = *lsnp; + modified = 1; + } else if (cmp_n == 0 && DB_UNDO(op)) { + /* + * Undo the allocation, reinitialize the page and + * link its next pointer to the free list. + */ + P_INIT(pagep, file_dbp->pgsize, + argp->pgno, PGNO_INVALID, argp->next, 0, P_INVALID); + + pagep->lsn = argp->page_lsn; + modified = 1; + } + + if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) { + goto err; + } + + /* + * If the page was newly created, put it on the limbo list. + */ + if (IS_ZERO_LSN(LSN(pagep)) && + IS_ZERO_LSN(argp->page_lsn) && DB_UNDO(op)) { + /* Put the page in limbo.*/ + if ((ret = __db_add_limbo(dbenv, + info, argp->fileid, argp->pgno, 1)) != 0) + goto err; + } + + /* Fix up the metadata page. */ + modified = 0; + cmp_n = log_compare(lsnp, &LSN(meta)); + cmp_p = log_compare(&LSN(meta), &argp->meta_lsn); + CHECK_LSN(op, cmp_p, &LSN(meta), &argp->meta_lsn); + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + LSN(meta) = *lsnp; + meta->free = argp->next; + modified = 1; + } else if (cmp_n == 0 && DB_UNDO(op)) { + /* Need to undo update described. */ + LSN(meta) = argp->meta_lsn; + + /* + * If the page has a zero LSN then its newly created + * and will go into limbo rather than directly on the + * free list. + */ + if (!IS_ZERO_LSN(argp->page_lsn)) + meta->free = argp->pgno; + modified = 1; + } + if ((ret = memp_fput(mpf, meta, modified ? DB_MPOOL_DIRTY : 0)) != 0) + goto out; + /* + * This could be the metapage from a subdb which is read from disk + * to recover its creation. + */ + if (F_ISSET(file_dbp, DB_AM_SUBDB)) + switch (argp->type) { + case P_BTREEMETA: + case P_HASHMETA: + case P_QAMMETA: + file_dbp->sync(file_dbp, 0); + break; + } + +done: *lsnp = argp->prev_lsn; + ret = 0; + + if (0) { +err: + if (meta != NULL) + (void)memp_fput(mpf, meta, 0); + } +out: REC_CLOSE; +} + +/* + * __bam_pg_free_recover -- + * Recovery function for pg_free. + * + * PUBLIC: int __bam_pg_free_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__bam_pg_free_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __bam_pg_free_args *argp; + DB *file_dbp; + DBC *dbc; + DBMETA *meta; + DB_LSN copy_lsn; + DB_MPOOLFILE *mpf; + PAGE *pagep; + db_pgno_t pgno; + int cmp_n, cmp_p, modified, ret; + + COMPQUIET(info, NULL); + REC_PRINT(__bam_pg_free_print); + REC_INTRO(__bam_pg_free_read, 1); + + /* + * Fix up the freed page. If we're redoing the operation we get the + * page and explicitly discard its contents, then update its LSN. If + * we're undoing the operation, we get the page and restore its header. + * Create the page if necessary, we may be freeing an aborted + * create. + */ + if ((ret = memp_fget(mpf, &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + modified = 0; + __ua_memcpy(©_lsn, &LSN(argp->header.data), sizeof(DB_LSN)); + cmp_n = log_compare(lsnp, &LSN(pagep)); + cmp_p = log_compare(&LSN(pagep), ©_lsn); + CHECK_LSN(op, cmp_p, &LSN(pagep), ©_lsn); + if (DB_REDO(op) && + (cmp_p == 0 || + (IS_ZERO_LSN(copy_lsn) && + log_compare(&LSN(pagep), &argp->meta_lsn) <= 0))) { + /* Need to redo update described. */ + P_INIT(pagep, file_dbp->pgsize, + argp->pgno, PGNO_INVALID, argp->next, 0, P_INVALID); + pagep->lsn = *lsnp; + + modified = 1; + } else if (cmp_n == 0 && DB_UNDO(op)) { + /* Need to undo update described. */ + memcpy(pagep, argp->header.data, argp->header.size); + + modified = 1; + } + if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) + goto out; + + /* + * Fix up the metadata page. If we're redoing or undoing the operation + * we get the page and update its LSN and free pointer. + */ + pgno = PGNO_BASE_MD; + if ((ret = memp_fget(mpf, &pgno, 0, &meta)) != 0) { + /* The metadata page must always exist. */ + (void)__db_pgerr(file_dbp, pgno); + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(meta)); + cmp_p = log_compare(&LSN(meta), &argp->meta_lsn); + CHECK_LSN(op, cmp_p, &LSN(meta), &argp->meta_lsn); + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo the deallocation. */ + meta->free = argp->pgno; + LSN(meta) = *lsnp; + modified = 1; + } else if (cmp_n == 0 && DB_UNDO(op)) { + /* Need to undo the deallocation. */ + meta->free = argp->next; + LSN(meta) = argp->meta_lsn; + modified = 1; + } + if ((ret = memp_fput(mpf, meta, modified ? DB_MPOOL_DIRTY : 0)) != 0) + goto out; + +done: *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __bam_split_recover -- + * Recovery function for split. + * + * PUBLIC: int __bam_split_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__bam_split_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __bam_split_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *_lp, *lp, *np, *pp, *_rp, *rp, *sp; + db_pgno_t pgno, root_pgno; + u_int32_t ptype; + int cmp, l_update, p_update, r_update, rc, ret, rootsplit, t_ret; + + COMPQUIET(info, NULL); + REC_PRINT(__bam_split_print); + + mpf = NULL; + _lp = lp = np = pp = _rp = rp = NULL; + sp = NULL; + + REC_INTRO(__bam_split_read, 1); + + /* + * There are two kinds of splits that we have to recover from. The + * first is a root-page split, where the root page is split from a + * leaf page into an internal page and two new leaf pages are created. + * The second is where a page is split into two pages, and a new key + * is inserted into the parent page. + * + * DBTs are not aligned in log records, so we need to copy the page + * so that we can access fields within it throughout this routine. + * Although we could hardcode the unaligned copies in this routine, + * we will be calling into regular btree functions with this page, + * so it's got to be aligned. Copying it into allocated memory is + * the only way to guarantee this. + */ + if ((ret = __os_malloc(dbenv, argp->pg.size, NULL, &sp)) != 0) + goto out; + memcpy(sp, argp->pg.data, argp->pg.size); + + pgno = PGNO(sp); + root_pgno = argp->root_pgno; + rootsplit = pgno == root_pgno; + if (memp_fget(mpf, &argp->left, 0, &lp) != 0) + lp = NULL; + if (memp_fget(mpf, &argp->right, 0, &rp) != 0) + rp = NULL; + + if (DB_REDO(op)) { + l_update = r_update = p_update = 0; + /* + * Decide if we need to resplit the page. + * + * If this is a root split, then the root has to exist, it's + * the page we're splitting and it gets modified. If this is + * not a root split, then the left page has to exist, for the + * same reason. + */ + if (rootsplit) { + if ((ret = memp_fget(mpf, &pgno, 0, &pp)) != 0) { + (void)__db_pgerr(file_dbp, pgno); + pp = NULL; + goto out; + } + cmp = log_compare(&LSN(pp), &LSN(argp->pg.data)); + CHECK_LSN(op, cmp, &LSN(pp), &LSN(argp->pg.data)); + p_update = cmp == 0; + } else if (lp == NULL) { + (void)__db_pgerr(file_dbp, argp->left); + goto out; + } + + if (lp != NULL) { + cmp = log_compare(&LSN(lp), &argp->llsn); + CHECK_LSN(op, cmp, &LSN(lp), &argp->llsn); + if (cmp == 0) + l_update = 1; + } else + l_update = 1; + + if (rp != NULL) { + cmp = log_compare(&LSN(rp), &argp->rlsn); + CHECK_LSN(op, cmp, &LSN(rp), &argp->rlsn); + if (cmp == 0) + r_update = 1; + } else + r_update = 1; + if (!p_update && !l_update && !r_update) + goto check_next; + + /* Allocate and initialize new left/right child pages. */ + if ((ret = + __os_malloc(dbenv, file_dbp->pgsize, NULL, &_lp)) != 0 + || (ret = + __os_malloc(dbenv, file_dbp->pgsize, NULL, &_rp)) != 0) + goto out; + if (rootsplit) { + P_INIT(_lp, file_dbp->pgsize, argp->left, + PGNO_INVALID, + ISINTERNAL(sp) ? PGNO_INVALID : argp->right, + LEVEL(sp), TYPE(sp)); + P_INIT(_rp, file_dbp->pgsize, argp->right, + ISINTERNAL(sp) ? PGNO_INVALID : argp->left, + PGNO_INVALID, LEVEL(sp), TYPE(sp)); + } else { + P_INIT(_lp, file_dbp->pgsize, PGNO(sp), + ISINTERNAL(sp) ? PGNO_INVALID : PREV_PGNO(sp), + ISINTERNAL(sp) ? PGNO_INVALID : argp->right, + LEVEL(sp), TYPE(sp)); + P_INIT(_rp, file_dbp->pgsize, argp->right, + ISINTERNAL(sp) ? PGNO_INVALID : sp->pgno, + ISINTERNAL(sp) ? PGNO_INVALID : NEXT_PGNO(sp), + LEVEL(sp), TYPE(sp)); + } + + /* Split the page. */ + if ((ret = __bam_copy(file_dbp, sp, _lp, 0, argp->indx)) != 0 || + (ret = __bam_copy(file_dbp, sp, _rp, argp->indx, + NUM_ENT(sp))) != 0) + goto out; + + /* If the left child is wrong, update it. */ + if (lp == NULL && (ret = + memp_fget(mpf, &argp->left, DB_MPOOL_CREATE, &lp)) != 0) { + (void)__db_pgerr(file_dbp, argp->left); + lp = NULL; + goto out; + } + if (l_update) { + memcpy(lp, _lp, file_dbp->pgsize); + lp->lsn = *lsnp; + if ((ret = memp_fput(mpf, lp, DB_MPOOL_DIRTY)) != 0) + goto out; + lp = NULL; + } + + /* If the right child is wrong, update it. */ + if (rp == NULL && (ret = memp_fget(mpf, + &argp->right, DB_MPOOL_CREATE, &rp)) != 0) { + (void)__db_pgerr(file_dbp, argp->right); + rp = NULL; + goto out; + } + if (r_update) { + memcpy(rp, _rp, file_dbp->pgsize); + rp->lsn = *lsnp; + if ((ret = memp_fput(mpf, rp, DB_MPOOL_DIRTY)) != 0) + goto out; + rp = NULL; + } + + /* + * If the parent page is wrong, update it. This is of interest + * only if it was a root split, since root splits create parent + * pages. All other splits modify a parent page, but those are + * separately logged and recovered. + */ + if (rootsplit && p_update) { + if (IS_BTREE_PAGE(sp)) { + ptype = P_IBTREE; + rc = argp->opflags & SPL_NRECS ? 1 : 0; + } else { + ptype = P_IRECNO; + rc = 1; + } + + P_INIT(pp, file_dbp->pgsize, root_pgno, + PGNO_INVALID, PGNO_INVALID, _lp->level + 1, ptype); + RE_NREC_SET(pp, + rc ? __bam_total(_lp) + __bam_total(_rp) : 0); + + pp->lsn = *lsnp; + if ((ret = memp_fput(mpf, pp, DB_MPOOL_DIRTY)) != 0) + goto out; + pp = NULL; + } + +check_next: /* + * Finally, redo the next-page link if necessary. This is of + * interest only if it wasn't a root split -- inserting a new + * page in the tree requires that any following page have its + * previous-page pointer updated to our new page. The next + * page must exist because we're redoing the operation. + */ + if (!rootsplit && !IS_ZERO_LSN(argp->nlsn)) { + if ((ret = memp_fget(mpf, &argp->npgno, 0, &np)) != 0) { + (void)__db_pgerr(file_dbp, argp->npgno); + np = NULL; + goto out; + } + cmp = log_compare(&LSN(np), &argp->nlsn); + CHECK_LSN(op, cmp, &LSN(np), &argp->nlsn); + if (cmp == 0) { + PREV_PGNO(np) = argp->right; + np->lsn = *lsnp; + if ((ret = + memp_fput(mpf, np, DB_MPOOL_DIRTY)) != 0) + goto out; + np = NULL; + } + } + } else { + /* + * If the split page is wrong, replace its contents with the + * logged page contents. If the page doesn't exist, it means + * that the create of the page never happened, nor did any of + * the adds onto the page that caused the split, and there's + * really no undo-ing to be done. + */ + if ((ret = memp_fget(mpf, &pgno, 0, &pp)) != 0) { + pp = NULL; + goto lrundo; + } + if (log_compare(lsnp, &LSN(pp)) == 0) { + memcpy(pp, argp->pg.data, argp->pg.size); + if ((ret = memp_fput(mpf, pp, DB_MPOOL_DIRTY)) != 0) + goto out; + pp = NULL; + } + + /* + * If it's a root split and the left child ever existed, update + * its LSN. (If it's not a root split, we've updated the left + * page already -- it's the same as the split page.) If the + * right child ever existed, root split or not, update its LSN. + * The undo of the page allocation(s) will restore them to the + * free list. + */ +lrundo: if ((rootsplit && lp != NULL) || rp != NULL) { + if (rootsplit && lp != NULL && + log_compare(lsnp, &LSN(lp)) == 0) { + lp->lsn = argp->llsn; + if ((ret = + memp_fput(mpf, lp, DB_MPOOL_DIRTY)) != 0) + goto out; + lp = NULL; + } + if (rp != NULL && + log_compare(lsnp, &LSN(rp)) == 0) { + rp->lsn = argp->rlsn; + if ((ret = + memp_fput(mpf, rp, DB_MPOOL_DIRTY)) != 0) + goto out; + rp = NULL; + } + } + + /* + * Finally, undo the next-page link if necessary. This is of + * interest only if it wasn't a root split -- inserting a new + * page in the tree requires that any following page have its + * previous-page pointer updated to our new page. Since it's + * possible that the next-page never existed, we ignore it as + * if there's nothing to undo. + */ + if (!rootsplit && !IS_ZERO_LSN(argp->nlsn)) { + if ((ret = memp_fget(mpf, &argp->npgno, 0, &np)) != 0) { + np = NULL; + goto done; + } + if (log_compare(lsnp, &LSN(np)) == 0) { + PREV_PGNO(np) = argp->left; + np->lsn = argp->nlsn; + if (memp_fput(mpf, np, DB_MPOOL_DIRTY)) + goto out; + np = NULL; + } + } + } + +done: *lsnp = argp->prev_lsn; + ret = 0; + +out: /* Free any pages that weren't dirtied. */ + if (pp != NULL && (t_ret = memp_fput(mpf, pp, 0)) != 0 && ret == 0) + ret = t_ret; + if (lp != NULL && (t_ret = memp_fput(mpf, lp, 0)) != 0 && ret == 0) + ret = t_ret; + if (np != NULL && (t_ret = memp_fput(mpf, np, 0)) != 0 && ret == 0) + ret = t_ret; + if (rp != NULL && (t_ret = memp_fput(mpf, rp, 0)) != 0 && ret == 0) + ret = t_ret; + + /* Free any allocated space. */ + if (_lp != NULL) + __os_free(_lp, file_dbp->pgsize); + if (_rp != NULL) + __os_free(_rp, file_dbp->pgsize); + if (sp != NULL) + __os_free(sp, argp->pg.size); + + REC_CLOSE; +} + +/* + * __bam_rsplit_recover -- + * Recovery function for a reverse split. + * + * PUBLIC: int __bam_rsplit_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__bam_rsplit_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __bam_rsplit_args *argp; + DB *file_dbp; + DBC *dbc; + DB_LSN copy_lsn; + DB_MPOOLFILE *mpf; + PAGE *pagep; + db_pgno_t pgno, root_pgno; + int cmp_n, cmp_p, modified, ret; + + COMPQUIET(info, NULL); + REC_PRINT(__bam_rsplit_print); + REC_INTRO(__bam_rsplit_read, 1); + + /* Fix the root page. */ + pgno = root_pgno = argp->root_pgno; + if ((ret = memp_fget(mpf, &pgno, 0, &pagep)) != 0) { + /* The root page must always exist if we are going forward. */ + if (DB_REDO(op)) { + __db_pgerr(file_dbp, pgno); + goto out; + } + /* This must be the root of an OPD tree. */ + DB_ASSERT(root_pgno != + ((BTREE *)file_dbp->bt_internal)->bt_root); + ret = 0; + goto done; + } + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + cmp_p = log_compare(&LSN(pagep), &argp->rootlsn); + CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->rootlsn); + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + memcpy(pagep, argp->pgdbt.data, argp->pgdbt.size); + pagep->pgno = root_pgno; + pagep->lsn = *lsnp; + modified = 1; + } else if (cmp_n == 0 && DB_UNDO(op)) { + /* Need to undo update described. */ + P_INIT(pagep, file_dbp->pgsize, root_pgno, + argp->nrec, PGNO_INVALID, pagep->level + 1, + IS_BTREE_PAGE(pagep) ? P_IBTREE : P_IRECNO); + if ((ret = __db_pitem(dbc, pagep, 0, + argp->rootent.size, &argp->rootent, NULL)) != 0) + goto out; + pagep->lsn = argp->rootlsn; + modified = 1; + } + if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) + goto out; + + /* + * Fix the page copied over the root page. It's possible that the + * page never made it to disk, so if we're undo-ing and the page + * doesn't exist, it's okay and there's nothing further to do. + */ + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) { + if (DB_UNDO(op)) + goto done; + (void)__db_pgerr(file_dbp, argp->pgno); + goto out; + } + modified = 0; + __ua_memcpy(©_lsn, &LSN(argp->pgdbt.data), sizeof(DB_LSN)); + cmp_n = log_compare(lsnp, &LSN(pagep)); + cmp_p = log_compare(&LSN(pagep), ©_lsn); + CHECK_LSN(op, cmp_p, &LSN(pagep), ©_lsn); + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + pagep->lsn = *lsnp; + modified = 1; + } else if (cmp_n == 0 && DB_UNDO(op)) { + /* Need to undo update described. */ + memcpy(pagep, argp->pgdbt.data, argp->pgdbt.size); + modified = 1; + } + if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) + goto out; + +done: *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __bam_adj_recover -- + * Recovery function for adj. + * + * PUBLIC: int __bam_adj_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__bam_adj_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __bam_adj_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + COMPQUIET(info, NULL); + REC_PRINT(__bam_adj_print); + REC_INTRO(__bam_adj_read, 1); + + /* Get the page; if it never existed and we're undoing, we're done. */ + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) { + if (DB_UNDO(op)) + goto done; + (void)__db_pgerr(file_dbp, argp->pgno); + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + cmp_p = log_compare(&LSN(pagep), &argp->lsn); + CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->lsn); + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + if ((ret = __bam_adjindx(dbc, + pagep, argp->indx, argp->indx_copy, argp->is_insert)) != 0) + goto err; + + LSN(pagep) = *lsnp; + modified = 1; + } else if (cmp_n == 0 && DB_UNDO(op)) { + /* Need to undo update described. */ + if ((ret = __bam_adjindx(dbc, + pagep, argp->indx, argp->indx_copy, !argp->is_insert)) != 0) + goto err; + + LSN(pagep) = argp->lsn; + modified = 1; + } + if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) + goto out; + +done: *lsnp = argp->prev_lsn; + ret = 0; + + if (0) { +err: (void)memp_fput(mpf, pagep, 0); + } +out: REC_CLOSE; +} + +/* + * __bam_cadjust_recover -- + * Recovery function for the adjust of a count change in an internal + * page. + * + * PUBLIC: int __bam_cadjust_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__bam_cadjust_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __bam_cadjust_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + COMPQUIET(info, NULL); + REC_PRINT(__bam_cadjust_print); + REC_INTRO(__bam_cadjust_read, 1); + + /* Get the page; if it never existed and we're undoing, we're done. */ + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) { + if (DB_UNDO(op)) + goto done; + (void)__db_pgerr(file_dbp, argp->pgno); + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + cmp_p = log_compare(&LSN(pagep), &argp->lsn); + CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->lsn); + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + if (IS_BTREE_PAGE(pagep)) { + GET_BINTERNAL(pagep, argp->indx)->nrecs += argp->adjust; + if (argp->opflags & CAD_UPDATEROOT) + RE_NREC_ADJ(pagep, argp->adjust); + } else { + GET_RINTERNAL(pagep, argp->indx)->nrecs += argp->adjust; + if (argp->opflags & CAD_UPDATEROOT) + RE_NREC_ADJ(pagep, argp->adjust); + } + + LSN(pagep) = *lsnp; + modified = 1; + } else if (cmp_n == 0 && DB_UNDO(op)) { + /* Need to undo update described. */ + if (IS_BTREE_PAGE(pagep)) { + GET_BINTERNAL(pagep, argp->indx)->nrecs -= argp->adjust; + if (argp->opflags & CAD_UPDATEROOT) + RE_NREC_ADJ(pagep, -(argp->adjust)); + } else { + GET_RINTERNAL(pagep, argp->indx)->nrecs -= argp->adjust; + if (argp->opflags & CAD_UPDATEROOT) + RE_NREC_ADJ(pagep, -(argp->adjust)); + } + LSN(pagep) = argp->lsn; + modified = 1; + } + if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) + goto out; + +done: *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __bam_cdel_recover -- + * Recovery function for the intent-to-delete of a cursor record. + * + * PUBLIC: int __bam_cdel_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__bam_cdel_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __bam_cdel_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + u_int32_t indx; + int cmp_n, cmp_p, modified, ret; + + COMPQUIET(info, NULL); + REC_PRINT(__bam_cdel_print); + REC_INTRO(__bam_cdel_read, 1); + + /* Get the page; if it never existed and we're undoing, we're done. */ + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) { + if (DB_UNDO(op)) + goto done; + (void)__db_pgerr(file_dbp, argp->pgno); + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + cmp_p = log_compare(&LSN(pagep), &argp->lsn); + CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->lsn); + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + indx = argp->indx + (TYPE(pagep) == P_LBTREE ? O_INDX : 0); + B_DSET(GET_BKEYDATA(pagep, indx)->type); + + LSN(pagep) = *lsnp; + modified = 1; + } else if (cmp_n == 0 && DB_UNDO(op)) { + /* Need to undo update described. */ + indx = argp->indx + (TYPE(pagep) == P_LBTREE ? O_INDX : 0); + B_DCLR(GET_BKEYDATA(pagep, indx)->type); + + (void)__bam_ca_delete(file_dbp, argp->pgno, argp->indx, 0); + + LSN(pagep) = argp->lsn; + modified = 1; + } + if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) + goto out; + +done: *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __bam_repl_recover -- + * Recovery function for page item replacement. + * + * PUBLIC: int __bam_repl_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__bam_repl_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __bam_repl_args *argp; + BKEYDATA *bk; + DB *file_dbp; + DBC *dbc; + DBT dbt; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + u_int8_t *p; + + COMPQUIET(info, NULL); + REC_PRINT(__bam_repl_print); + REC_INTRO(__bam_repl_read, 1); + + /* Get the page; if it never existed and we're undoing, we're done. */ + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) { + if (DB_UNDO(op)) + goto done; + (void)__db_pgerr(file_dbp, argp->pgno); + goto out; + } + bk = GET_BKEYDATA(pagep, argp->indx); + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + cmp_p = log_compare(&LSN(pagep), &argp->lsn); + CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->lsn); + if (cmp_p == 0 && DB_REDO(op)) { + /* + * Need to redo update described. + * + * Re-build the replacement item. + */ + memset(&dbt, 0, sizeof(dbt)); + dbt.size = argp->prefix + argp->suffix + argp->repl.size; + if ((ret = __os_malloc(dbenv, dbt.size, NULL, &dbt.data)) != 0) + goto err; + p = dbt.data; + memcpy(p, bk->data, argp->prefix); + p += argp->prefix; + memcpy(p, argp->repl.data, argp->repl.size); + p += argp->repl.size; + memcpy(p, bk->data + (bk->len - argp->suffix), argp->suffix); + + ret = __bam_ritem(dbc, pagep, argp->indx, &dbt); + __os_free(dbt.data, dbt.size); + if (ret != 0) + goto err; + + LSN(pagep) = *lsnp; + modified = 1; + } else if (cmp_n == 0 && DB_UNDO(op)) { + /* + * Need to undo update described. + * + * Re-build the original item. + */ + memset(&dbt, 0, sizeof(dbt)); + dbt.size = argp->prefix + argp->suffix + argp->orig.size; + if ((ret = __os_malloc(dbenv, dbt.size, NULL, &dbt.data)) != 0) + goto err; + p = dbt.data; + memcpy(p, bk->data, argp->prefix); + p += argp->prefix; + memcpy(p, argp->orig.data, argp->orig.size); + p += argp->orig.size; + memcpy(p, bk->data + (bk->len - argp->suffix), argp->suffix); + + ret = __bam_ritem(dbc, pagep, argp->indx, &dbt); + __os_free(dbt.data, dbt.size); + if (ret != 0) + goto err; + + /* Reset the deleted flag, if necessary. */ + if (argp->isdeleted) + B_DSET(GET_BKEYDATA(pagep, argp->indx)->type); + + LSN(pagep) = argp->lsn; + modified = 1; + } + if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) + goto out; + +done: *lsnp = argp->prev_lsn; + ret = 0; + + if (0) { +err: (void)memp_fput(mpf, pagep, 0); + } +out: REC_CLOSE; +} + +/* + * __bam_root_recover -- + * Recovery function for setting the root page on the meta-data page. + * + * PUBLIC: int __bam_root_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__bam_root_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __bam_root_args *argp; + BTMETA *meta; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + int cmp_n, cmp_p, modified, ret; + + COMPQUIET(info, NULL); + REC_PRINT(__bam_root_print); + REC_INTRO(__bam_root_read, 0); + + if ((ret = memp_fget(mpf, &argp->meta_pgno, 0, &meta)) != 0) { + /* The metadata page must always exist on redo. */ + if (DB_REDO(op)) { + (void)__db_pgerr(file_dbp, argp->meta_pgno); + goto out; + } else + goto done; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(meta)); + cmp_p = log_compare(&LSN(meta), &argp->meta_lsn); + CHECK_LSN(op, cmp_p, &LSN(meta), &argp->meta_lsn); + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + meta->root = argp->root_pgno; + meta->dbmeta.lsn = *lsnp; + ((BTREE *)file_dbp->bt_internal)->bt_root = meta->root; + modified = 1; + } else if (cmp_n == 0 && DB_UNDO(op)) { + /* Nothing to undo except lsn. */ + meta->dbmeta.lsn = argp->meta_lsn; + modified = 1; + } + if ((ret = memp_fput(mpf, meta, modified ? DB_MPOOL_DIRTY : 0)) != 0) + goto out; + +done: *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __bam_curadj_recover -- + * Transaction abort function to undo cursor adjustments. + * This should only be triggered by subtransaction aborts. + * + * PUBLIC: int __bam_curadj_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__bam_curadj_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __bam_curadj_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + int ret; + + COMPQUIET(info, NULL); + + REC_PRINT(__bam_curadj_print); + REC_INTRO(__bam_curadj_read, 0); + + ret = 0; + if (op != DB_TXN_ABORT) + goto done; + + switch(argp->mode) { + case DB_CA_DI: + if ((ret = __bam_ca_di(dbc, argp->from_pgno, + argp->from_indx, -(int)argp->first_indx)) != 0) + goto out; + break; + case DB_CA_DUP: + if ((ret = __bam_ca_undodup(file_dbp, argp->first_indx, + argp->from_pgno, argp->from_indx, argp->to_indx)) != 0) + goto out; + break; + + case DB_CA_RSPLIT: + if ((ret = + __bam_ca_rsplit(dbc, argp->to_pgno, argp->from_pgno)) != 0) + goto out; + break; + + case DB_CA_SPLIT: + __bam_ca_undosplit(file_dbp, argp->from_pgno, + argp->to_pgno, argp->left_pgno, argp->from_indx); + break; + } + +done: *lsnp = argp->prev_lsn; +out: REC_CLOSE; +} + +/* + * __bam_rcuradj_recover -- + * Transaction abort function to undo cursor adjustments in rrecno. + * This should only be triggered by subtransaction aborts. + * + * PUBLIC: int __bam_rcuradj_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__bam_rcuradj_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __bam_rcuradj_args *argp; + BTREE_CURSOR *cp; + DB *file_dbp; + DBC *dbc, *rdbc; + DB_MPOOLFILE *mpf; + int ret, t_ret; + + COMPQUIET(info, NULL); + rdbc = NULL; + + REC_PRINT(__bam_rcuradj_print); + REC_INTRO(__bam_rcuradj_read, 0); + + ret = t_ret = 0; + + if (op != DB_TXN_ABORT) + goto done; + + /* + * We don't know whether we're in an offpage dup set, and + * thus don't know whether the dbc REC_INTRO has handed us is + * of a reasonable type. It's certainly unset, so if this is + * an offpage dup set, we don't have an OPD cursor. The + * simplest solution is just to allocate a whole new cursor + * for our use; we're only really using it to hold pass some + * state into __ram_ca, and this way we don't need to make + * this function know anything about how offpage dups work. + */ + if ((ret = + __db_icursor(file_dbp, NULL, DB_RECNO, argp->root, 0, &rdbc)) != 0) + goto out; + + cp = (BTREE_CURSOR *)rdbc->internal; + F_SET(cp, C_RENUMBER); + cp->recno = argp->recno; + + switch(argp->mode) { + case CA_DELETE: + /* + * The way to undo a delete is with an insert. Since + * we're undoing it, the delete flag must be set. + */ + F_SET(cp, C_DELETED); + F_SET(cp, C_RENUMBER); /* Just in case. */ + cp->order = argp->order; + __ram_ca(rdbc, CA_ICURRENT); + break; + case CA_IAFTER: + case CA_IBEFORE: + case CA_ICURRENT: + /* + * The way to undo an insert is with a delete. The delete + * flag is unset to start with. + */ + F_CLR(cp, C_DELETED); + cp->order = INVALID_ORDER; + __ram_ca(rdbc, CA_DELETE); + break; + } + +done: *lsnp = argp->prev_lsn; +out: if (rdbc != NULL && (t_ret = rdbc->c_close(rdbc)) != 0 && ret == 0) + ret = t_ret; + REC_CLOSE; +} diff --git a/db/btree/bt_reclaim.c b/db/btree/bt_reclaim.c new file mode 100644 index 000000000..538d837c2 --- /dev/null +++ b/db/btree/bt_reclaim.c @@ -0,0 +1,53 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: bt_reclaim.c,v 11.5 2000/03/22 04:21:01 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_shash.h" +#include "lock.h" +#include "btree.h" + +/* + * __bam_reclaim -- + * Free a database. + * + * PUBLIC: int __bam_reclaim __P((DB *, DB_TXN *)); + */ +int +__bam_reclaim(dbp, txn) + DB *dbp; + DB_TXN *txn; +{ + DBC *dbc; + int ret, t_ret; + + /* Acquire a cursor. */ + if ((ret = dbp->cursor(dbp, txn, &dbc, 0)) != 0) + return (ret); + + /* Walk the tree, freeing pages. */ + ret = __bam_traverse(dbc, + DB_LOCK_WRITE, dbc->internal->root, __db_reclaim_callback, dbc); + + /* Discard the cursor. */ + if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0) + ret = t_ret; + + return (ret); +} diff --git a/db/btree/bt_recno.c b/db/btree/bt_recno.c new file mode 100644 index 000000000..6ac0cac35 --- /dev/null +++ b/db/btree/bt_recno.c @@ -0,0 +1,1369 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: bt_recno.c,v 11.65 2001/01/18 14:33:22 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "btree.h" +#include "db_ext.h" +#include "db_shash.h" +#include "lock.h" +#include "lock_ext.h" +#include "qam.h" +#include "txn.h" + +static int __ram_add __P((DBC *, db_recno_t *, DBT *, u_int32_t, u_int32_t)); +static int __ram_delete __P((DB *, DB_TXN *, DBT *, u_int32_t)); +static int __ram_put __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t)); +static int __ram_source __P((DB *)); +static int __ram_sread __P((DBC *, db_recno_t)); +static int __ram_update __P((DBC *, db_recno_t, int)); + +/* + * In recno, there are two meanings to the on-page "deleted" flag. If we're + * re-numbering records, it means the record was implicitly created. We skip + * over implicitly created records if doing a cursor "next" or "prev", and + * return DB_KEYEMPTY if they're explicitly requested.. If not re-numbering + * records, it means that the record was implicitly created, or was deleted. + * We skip over implicitly created or deleted records if doing a cursor "next" + * or "prev", and return DB_KEYEMPTY if they're explicitly requested. + * + * If we're re-numbering records, then we have to detect in the cursor that + * a record was deleted, and adjust the cursor as necessary on the next get. + * If we're not re-numbering records, then we can detect that a record has + * been deleted by looking at the actual on-page record, so we completely + * ignore the cursor's delete flag. This is different from the B+tree code. + * It also maintains whether the cursor references a deleted record in the + * cursor, and it doesn't always check the on-page value. + */ +#define CD_SET(cp) { \ + if (F_ISSET(cp, C_RENUMBER)) \ + F_SET(cp, C_DELETED); \ +} +#define CD_CLR(cp) { \ + if (F_ISSET(cp, C_RENUMBER)) { \ + F_CLR(cp, C_DELETED); \ + cp->order = INVALID_ORDER; \ + } \ +} +#define CD_ISSET(cp) \ + (F_ISSET(cp, C_RENUMBER) && F_ISSET(cp, C_DELETED)) + +/* + * Macros for comparing the ordering of two cursors. + * cp1 comes before cp2 iff one of the following holds: + * cp1's recno is less than cp2's recno + * recnos are equal, both deleted, and cp1's order is less than cp2's + * recnos are equal, cp1 deleted, and cp2 not deleted + */ +#define C_LESSTHAN(cp1, cp2) \ + (((cp1)->recno < (cp2)->recno) || \ + (((cp1)->recno == (cp2)->recno) && \ + ((CD_ISSET((cp1)) && CD_ISSET((cp2)) && (cp1)->order < (cp2)->order) || \ + (CD_ISSET((cp1)) && !CD_ISSET((cp2)))))) + +/* + * cp1 is equal to cp2 iff their recnos and delete flags are identical, + * and if the delete flag is set their orders are also identical. + */ +#define C_EQUAL(cp1, cp2) \ + ((cp1)->recno == (cp2)->recno && CD_ISSET((cp1)) == CD_ISSET((cp2)) && \ + (!CD_ISSET((cp1)) || (cp1)->order == (cp2)->order)) + +/* + * Do we need to log the current cursor adjustment? + */ +#define CURADJ_LOG(dbc) \ + (DB_LOGGING((dbc)) && (dbc)->txn != NULL && (dbc)->txn->parent != NULL) + +/* + * __ram_open -- + * Recno open function. + * + * PUBLIC: int __ram_open __P((DB *, const char *, db_pgno_t, u_int32_t)); + */ +int +__ram_open(dbp, name, base_pgno, flags) + DB *dbp; + const char *name; + db_pgno_t base_pgno; + u_int32_t flags; +{ + BTREE *t; + DBC *dbc; + int ret, t_ret; + + t = dbp->bt_internal; + + /* Initialize the remaining fields/methods of the DB. */ + dbp->del = __ram_delete; + dbp->put = __ram_put; + dbp->stat = __bam_stat; + + /* Start up the tree. */ + if ((ret = __bam_read_root(dbp, name, base_pgno, flags)) != 0) + return (ret); + + /* + * If the user specified a source tree, open it and map it in. + * + * !!! + * We don't complain if the user specified transactions or threads. + * It's possible to make it work, but you'd better know what you're + * doing! + */ + if (t->re_source != NULL && (ret = __ram_source(dbp)) != 0) + return (ret); + + /* If we're snapshotting an underlying source file, do it now. */ + if (F_ISSET(dbp, DB_RE_SNAPSHOT)) { + /* Allocate a cursor. */ + if ((ret = dbp->cursor(dbp, NULL, &dbc, 0)) != 0) + return (ret); + + /* Do the snapshot. */ + if ((ret = __ram_update(dbc, + DB_MAX_RECORDS, 0)) != 0 && ret == DB_NOTFOUND) + ret = 0; + + /* Discard the cursor. */ + if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0) + ret = t_ret; + } + + return (0); +} + +/* + * __ram_delete -- + * Recno db->del function. + */ +static int +__ram_delete(dbp, txn, key, flags) + DB *dbp; + DB_TXN *txn; + DBT *key; + u_int32_t flags; +{ + BTREE_CURSOR *cp; + DBC *dbc; + db_recno_t recno; + int ret, t_ret; + + PANIC_CHECK(dbp->dbenv); + + /* Check for invalid flags. */ + if ((ret = __db_delchk(dbp, + key, flags, F_ISSET(dbp, DB_AM_RDONLY))) != 0) + return (ret); + + /* Acquire a cursor. */ + if ((ret = dbp->cursor(dbp, txn, &dbc, DB_WRITELOCK)) != 0) + return (ret); + + DEBUG_LWRITE(dbc, txn, "ram_delete", key, NULL, flags); + + /* Check the user's record number and fill in as necessary. */ + if ((ret = __ram_getno(dbc, key, &recno, 0)) != 0) + goto err; + + /* Do the delete. */ + cp = (BTREE_CURSOR *)dbc->internal; + cp->recno = recno; + + ret = __ram_c_del(dbc); + + /* Release the cursor. */ +err: if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0) + ret = t_ret; + + return (ret); +} + +/* + * __ram_put -- + * Recno db->put function. + */ +static int +__ram_put(dbp, txn, key, data, flags) + DB *dbp; + DB_TXN *txn; + DBT *key, *data; + u_int32_t flags; +{ + DBC *dbc; + db_recno_t recno; + int ret, t_ret; + + PANIC_CHECK(dbp->dbenv); + + /* Check for invalid flags. */ + if ((ret = __db_putchk(dbp, + key, data, flags, F_ISSET(dbp, DB_AM_RDONLY), 0)) != 0) + return (ret); + + /* Allocate a cursor. */ + if ((ret = dbp->cursor(dbp, txn, &dbc, DB_WRITELOCK)) != 0) + return (ret); + + DEBUG_LWRITE(dbc, txn, "ram_put", key, data, flags); + + /* + * If we're appending to the tree, make sure we've read in all of + * the backing source file. Otherwise, check the user's record + * number and fill in as necessary. If we found the record or it + * simply didn't exist, add the user's record. + */ + if (flags == DB_APPEND) + ret = __ram_update(dbc, DB_MAX_RECORDS, 0); + else + ret = __ram_getno(dbc, key, &recno, 1); + if (ret == 0 || ret == DB_NOTFOUND) + ret = __ram_add(dbc, &recno, data, flags, 0); + + /* Discard the cursor. */ + if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0) + ret = t_ret; + + /* Return the record number if we're appending to the tree. */ + if (ret == 0 && flags == DB_APPEND) + ret = __db_retcopy(dbp, key, &recno, sizeof(recno), + &dbc->rkey.data, &dbc->rkey.ulen); + + return (ret); +} + +/* + * __ram_c_del -- + * Recno cursor->c_del function. + * + * PUBLIC: int __ram_c_del __P((DBC *)); + */ +int +__ram_c_del(dbc) + DBC *dbc; +{ + BKEYDATA bk; + BTREE *t; + BTREE_CURSOR *cp; + DB *dbp; + DB_LSN lsn; + DBT hdr, data; + EPG *epg; + int exact, ret, stack; + + dbp = dbc->dbp; + cp = (BTREE_CURSOR *)dbc->internal; + t = dbp->bt_internal; + stack = 0; + + /* + * The semantics of cursors during delete are as follows: in + * non-renumbering recnos, records are replaced with a marker + * containing a delete flag. If the record referenced by this cursor + * has already been deleted, we will detect that as part of the delete + * operation, and fail. + * + * In renumbering recnos, cursors which represent deleted items + * are flagged with the C_DELETED flag, and it is an error to + * call c_del a second time without an intervening cursor motion. + */ + if (CD_ISSET(cp)) + return (DB_KEYEMPTY); + + /* Search the tree for the key; delete only deletes exact matches. */ + if ((ret = __bam_rsearch(dbc, &cp->recno, S_DELETE, 1, &exact)) != 0) + goto err; + if (!exact) { + ret = DB_NOTFOUND; + goto err; + } + stack = 1; + cp->page = cp->csp->page; + cp->pgno = cp->csp->page->pgno; + cp->indx = cp->csp->indx; + + /* + * If re-numbering records, the on-page deleted flag can only mean + * that this record was implicitly created. Applications aren't + * permitted to delete records they never created, return an error. + * + * If not re-numbering records, the on-page deleted flag means that + * this record was implicitly created, or, was deleted at some time. + * The former is an error because applications aren't permitted to + * delete records they never created, the latter is an error because + * if the record was "deleted", we could never have found it. + */ + if (B_DISSET(GET_BKEYDATA(cp->page, cp->indx)->type)) { + ret = DB_KEYEMPTY; + goto err; + } + + if (F_ISSET(cp, C_RENUMBER)) { + /* Delete the item, adjust the counts, adjust the cursors. */ + if ((ret = __bam_ditem(dbc, cp->page, cp->indx)) != 0) + goto err; + __bam_adjust(dbc, -1); + if (__ram_ca(dbc, CA_DELETE) > 0 && + CURADJ_LOG(dbc) && (ret = __bam_rcuradj_log(dbp->dbenv, + dbc->txn, &lsn, 0, dbp->log_fileid, CA_DELETE, + cp->root, cp->recno, cp->order)) != 0) + goto err; + + /* + * If the page is empty, delete it. + * + * We never delete a root page. First, root pages of primary + * databases never go away, recno or otherwise. However, if + * it's the root page of an off-page duplicates database, then + * it can be deleted. We don't delete it here because we have + * no way of telling the primary database page holder (e.g., + * the hash access method) that its page element should cleaned + * up because the underlying tree is gone. So, we keep the page + * around until the last cursor referencing the empty tree is + * are closed, and then clean it up. + */ + if (NUM_ENT(cp->page) == 0 && PGNO(cp->page) != cp->root) { + /* + * We already have a locked stack of pages. However, + * there are likely entries in the stack that aren't + * going to be emptied by removing the single reference + * to the emptied page (or one of its parents). + */ + for (epg = cp->sp; epg <= cp->csp; ++epg) + if (NUM_ENT(epg->page) <= 1) + break; + + /* + * We want to delete a single item out of the last page + * that we're not deleting, back up to that page. + */ + ret = __bam_dpages(dbc, --epg); + + /* + * Regardless of the return from __bam_dpages, it will + * discard our stack and pinned page. + */ + stack = 0; + cp->page = NULL; + } + } else { + /* Use a delete/put pair to replace the record with a marker. */ + if ((ret = __bam_ditem(dbc, cp->page, cp->indx)) != 0) + goto err; + + B_TSET(bk.type, B_KEYDATA, 1); + bk.len = 0; + memset(&hdr, 0, sizeof(hdr)); + hdr.data = &bk; + hdr.size = SSZA(BKEYDATA, data); + memset(&data, 0, sizeof(data)); + data.data = (void *)""; + data.size = 0; + if ((ret = __db_pitem(dbc, + cp->page, cp->indx, BKEYDATA_SIZE(0), &hdr, &data)) != 0) + goto err; + } + + t->re_modified = 1; + +err: if (stack) + __bam_stkrel(dbc, STK_CLRDBC); + + return (ret); +} + +/* + * __ram_c_get -- + * Recno cursor->c_get function. + * + * PUBLIC: int __ram_c_get + * PUBLIC: __P((DBC *, DBT *, DBT *, u_int32_t, db_pgno_t *)); + */ +int +__ram_c_get(dbc, key, data, flags, pgnop) + DBC *dbc; + DBT *key, *data; + u_int32_t flags; + db_pgno_t *pgnop; +{ + BTREE_CURSOR *cp; + DB *dbp; + int cmp, exact, ret; + + COMPQUIET(pgnop, NULL); + + dbp = dbc->dbp; + cp = (BTREE_CURSOR *)dbc->internal; + +retry: switch (flags) { + case DB_CURRENT: + /* + * If we're using mutable records and the deleted flag is + * set, the cursor is pointing at a nonexistent record; + * return an error. + */ + if (CD_ISSET(cp)) + return (DB_KEYEMPTY); + break; + case DB_NEXT_DUP: + /* + * If we're not in an off-page dup set, we know there's no + * next duplicate since recnos don't have them. If we + * are in an off-page dup set, the next item assuredly is + * a dup, so we set flags to DB_NEXT and keep going. + */ + if (!F_ISSET(dbc, DBC_OPD)) + return (DB_NOTFOUND); + /* FALLTHROUGH */ + case DB_NEXT_NODUP: + /* + * Recno databases don't have duplicates, set flags to DB_NEXT + * and keep going. + */ + /* FALLTHROUGH */ + case DB_NEXT: + flags = DB_NEXT; + /* + * If record numbers are mutable: if we just deleted a record, + * we have to avoid incrementing the record number so that we + * return the right record by virtue of renumbering the tree. + */ + if (CD_ISSET(cp)) + break; + + if (cp->recno != RECNO_OOB) { + ++cp->recno; + break; + } + /* FALLTHROUGH */ + case DB_FIRST: + flags = DB_NEXT; + cp->recno = 1; + break; + case DB_PREV_NODUP: + /* + * Recno databases don't have duplicates, set flags to DB_PREV + * and keep going. + */ + /* FALLTHROUGH */ + case DB_PREV: + flags = DB_PREV; + if (cp->recno != RECNO_OOB) { + if (cp->recno == 1) { + ret = DB_NOTFOUND; + goto err; + } + --cp->recno; + break; + } + /* FALLTHROUGH */ + case DB_LAST: + flags = DB_PREV; + if (((ret = __ram_update(dbc, + DB_MAX_RECORDS, 0)) != 0) && ret != DB_NOTFOUND) + goto err; + if ((ret = __bam_nrecs(dbc, &cp->recno)) != 0) + goto err; + if (cp->recno == 0) { + ret = DB_NOTFOUND; + goto err; + } + break; + case DB_GET_BOTHC: + /* + * If we're doing a join and these are offpage dups, + * we want to keep searching forward from after the + * current cursor position. Increment the recno by 1, + * then proceed as for a DB_SET. + * + * Otherwise, we know there are no additional matching + * data, as recnos don't have dups. return DB_NOTFOUND. + */ + if (F_ISSET(dbc, DBC_OPD)) { + cp->recno++; + break; + } + ret = DB_NOTFOUND; + goto err; + /* NOTREACHED */ + case DB_GET_BOTH: + /* + * If we're searching a set of off-page dups, we start + * a new linear search from the first record. Otherwise, + * we compare the single data item associated with the + * requested record for a match. + */ + if (F_ISSET(dbc, DBC_OPD)) { + cp->recno = 1; + break; + } + /* FALLTHROUGH */ + case DB_SET: + case DB_SET_RANGE: + if ((ret = __ram_getno(dbc, key, &cp->recno, 0)) != 0) + goto err; + break; + default: + ret = __db_unknown_flag(dbp->dbenv, "__ram_c_get", flags); + goto err; + } + + /* + * For DB_PREV, DB_LAST, DB_SET and DB_SET_RANGE, we have already + * called __ram_update() to make sure sufficient records have been + * read from the backing source file. Do it now for DB_CURRENT (if + * the current record was deleted we may need more records from the + * backing file for a DB_CURRENT operation), DB_FIRST and DB_NEXT. + */ + if ((flags == DB_NEXT || flags == DB_CURRENT) && ((ret = + __ram_update(dbc, cp->recno, 0)) != 0) && ret != DB_NOTFOUND) + goto err; + + for (;; ++cp->recno) { + /* Search the tree for the record. */ + if ((ret = __bam_rsearch(dbc, &cp->recno, + F_ISSET(dbc, DBC_RMW) ? S_FIND_WR : S_FIND, + 1, &exact)) != 0) + goto err; + if (!exact) { + ret = DB_NOTFOUND; + goto err; + } + + /* + * Copy the page into the cursor, discarding any lock we + * are currently holding. + */ + cp->page = cp->csp->page; + cp->pgno = cp->csp->page->pgno; + cp->indx = cp->csp->indx; + (void)__TLPUT(dbc, cp->lock); + cp->lock = cp->csp->lock; + cp->lock_mode = cp->csp->lock_mode; + + /* + * If re-numbering records, the on-page deleted flag means this + * record was implicitly created. If not re-numbering records, + * the on-page deleted flag means this record was implicitly + * created, or, it was deleted at some time. Regardless, we + * skip such records if doing cursor next/prev operations or + * walking through off-page duplicates, and fail if they were + * requested explicitly by the application. + */ + if (B_DISSET(GET_BKEYDATA(cp->page, cp->indx)->type)) + switch (flags) { + case DB_NEXT: + case DB_PREV: + (void)__bam_stkrel(dbc, STK_CLRDBC); + goto retry; + case DB_GET_BOTH: + (void)__bam_stkrel(dbc, STK_CLRDBC); + continue; + default: + ret = DB_KEYEMPTY; + goto err; + } + + if (flags == DB_GET_BOTH || flags == DB_GET_BOTHC) { + if ((ret = __bam_cmp(dbp, data, + cp->page, cp->indx, __bam_defcmp, &cmp)) != 0) + return (ret); + if (cmp == 0) + break; + if (!F_ISSET(dbc, DBC_OPD)) { + ret = DB_NOTFOUND; + goto err; + } + (void)__bam_stkrel(dbc, STK_CLRDBC); + } else + break; + } + + /* Return the key if the user didn't give us one. */ + if (!F_ISSET(dbc, DBC_OPD)) { + if (flags != DB_SET && flags != DB_SET_RANGE) + ret = __db_retcopy(dbp, + key, &cp->recno, sizeof(cp->recno), + &dbc->rkey.data, &dbc->rkey.ulen); + F_SET(key, DB_DBT_ISSET); + } + + /* The cursor was reset, no further delete adjustment is necessary. */ +err: CD_CLR(cp); + + return (ret); +} + +/* + * __ram_c_put -- + * Recno cursor->c_put function. + * + * PUBLIC: int __ram_c_put __P((DBC *, DBT *, DBT *, u_int32_t, db_pgno_t *)); + */ +int +__ram_c_put(dbc, key, data, flags, pgnop) + DBC *dbc; + DBT *key, *data; + u_int32_t flags; + db_pgno_t *pgnop; +{ + BTREE_CURSOR *cp; + DB *dbp; + DB_LSN lsn; + int exact, nc, ret, t_ret; + u_int32_t iiflags; + void *arg; + + COMPQUIET(pgnop, NULL); + + dbp = dbc->dbp; + cp = (BTREE_CURSOR *)dbc->internal; + + /* + * DB_KEYFIRST and DB_KEYLAST will only be set if we're dealing with + * an off-page duplicate tree, they can't be specified at user level. + * Translate them into something else. + */ + switch (flags) { + case DB_KEYFIRST: + cp->recno = 1; + flags = DB_BEFORE; + break; + case DB_KEYLAST: + if ((ret = __ram_add(dbc, &cp->recno, data, DB_APPEND, 0)) != 0) + return (ret); + if (CURADJ_LOG(dbc) && (ret = __bam_rcuradj_log(dbp->dbenv, + dbc->txn, &lsn, 0, dbp->log_fileid, CA_ICURRENT, + cp->root, cp->recno, cp->order))) + return (ret); + return (0); + } + + /* + * If we're putting with a cursor that's marked C_DELETED, we need to + * take special care; the cursor doesn't "really" reference the item + * corresponding to its current recno, but instead is "between" that + * record and the current one. Translate the actual insert into + * DB_BEFORE, and let the __ram_ca work out the gory details of what + * should wind up pointing where. + */ + if (CD_ISSET(cp)) + iiflags = DB_BEFORE; + else + iiflags = flags; + +split: if ((ret = __bam_rsearch(dbc, &cp->recno, S_INSERT, 1, &exact)) != 0) + goto err; + /* + * An inexact match is okay; it just means we're one record past the + * end, which is reasonable if we're marked deleted. + */ + DB_ASSERT(exact || CD_ISSET(cp)); + + cp->page = cp->csp->page; + cp->pgno = cp->csp->page->pgno; + cp->indx = cp->csp->indx; + + ret = __bam_iitem(dbc, key, data, iiflags, 0); + t_ret = __bam_stkrel(dbc, STK_CLRDBC); + + if (t_ret != 0 && (ret == 0 || ret == DB_NEEDSPLIT)) + ret = t_ret; + else if (ret == DB_NEEDSPLIT) { + arg = &cp->recno; + if ((ret = __bam_split(dbc, arg)) != 0) + goto err; + goto split; + } + if (ret != 0) + goto err; + + switch (flags) { /* Adjust the cursors. */ + case DB_AFTER: + nc = __ram_ca(dbc, CA_IAFTER); + + /* + * We only need to adjust this cursor forward if we truly added + * the item after the current recno, rather than remapping it + * to DB_BEFORE. + */ + if (iiflags == DB_AFTER) + ++cp->recno; + + /* Only log if __ram_ca found any relevant cursors. */ + if (nc > 0 && CURADJ_LOG(dbc) && + (ret = __bam_rcuradj_log(dbp->dbenv, + dbc->txn, &lsn, 0, dbp->log_fileid, CA_IAFTER, + cp->root, cp->recno, cp->order)) != 0) + goto err; + break; + case DB_BEFORE: + nc = __ram_ca(dbc, CA_IBEFORE); + --cp->recno; + + /* Only log if __ram_ca found any relevant cursors. */ + if (nc > 0 && CURADJ_LOG(dbc) && + (ret = __bam_rcuradj_log(dbp->dbenv, + dbc->txn, &lsn, 0, dbp->log_fileid, CA_IBEFORE, + cp->root, cp->recno, cp->order)) != 0) + goto err; + break; + case DB_CURRENT: + /* + * We only need to do an adjustment if we actually + * added an item, which we only would have done if the + * cursor was marked deleted. + * + * Only log if __ram_ca found any relevant cursors. + */ + if (CD_ISSET(cp) && __ram_ca(dbc, CA_ICURRENT) > 0 && + CURADJ_LOG(dbc) && (ret = __bam_rcuradj_log( + dbp->dbenv, dbc->txn, &lsn, 0, dbp->log_fileid, + CA_ICURRENT, cp->root, cp->recno, cp->order)) != 0) + goto err; + break; + } + + /* Return the key if we've created a new record. */ + if (!F_ISSET(dbc, DBC_OPD) && (flags == DB_AFTER || flags == DB_BEFORE)) + ret = __db_retcopy(dbp, key, &cp->recno, + sizeof(cp->recno), &dbc->rkey.data, &dbc->rkey.ulen); + + /* The cursor was reset, no further delete adjustment is necessary. */ +err: CD_CLR(cp); + + return (ret); +} + +/* + * __ram_ca -- + * Adjust cursors. Returns the number of relevant cursors. + * + * PUBLIC: int __ram_ca __P((DBC *, ca_recno_arg)); + */ +int +__ram_ca(dbc_arg, op) + DBC *dbc_arg; + ca_recno_arg op; +{ + BTREE_CURSOR *cp, *cp_arg; + DB *dbp, *ldbp; + DB_ENV *dbenv; + DBC *dbc; + db_recno_t recno; + int adjusted, found; + u_int32_t order; + + dbp = dbc_arg->dbp; + dbenv = dbp->dbenv; + cp_arg = (BTREE_CURSOR *)dbc_arg->internal; + recno = cp_arg->recno; + + found = 0; + + /* + * It only makes sense to adjust cursors if we're a renumbering + * recno; we should only be called if this is one. + */ + DB_ASSERT(F_ISSET(cp_arg, C_RENUMBER)); + + MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp); + /* + * Adjust the cursors. See the comment in __bam_ca_delete(). + */ + /* + * If we're doing a delete, we need to find the highest + * order of any cursor currently pointing at this item, + * so we can assign a higher order to the newly deleted + * cursor. Unfortunately, this requires a second pass through + * the cursor list. + */ + if (op == CA_DELETE) { + order = 1; + for (ldbp = __dblist_get(dbenv, dbp->adj_fileid); + ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid; + ldbp = LIST_NEXT(ldbp, dblistlinks)) { + MUTEX_THREAD_LOCK(dbenv, dbp->mutexp); + for (dbc = TAILQ_FIRST(&ldbp->active_queue); + dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) { + cp = (BTREE_CURSOR *)dbc->internal; + if (cp_arg->root == cp->root && + recno == cp->recno && CD_ISSET(cp) && + order <= cp->order) + order = cp->order + 1; + } + MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp); + } + } else + order = INVALID_ORDER; + + /* Now go through and do the actual adjustments. */ + for (ldbp = __dblist_get(dbenv, dbp->adj_fileid); + ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid; + ldbp = LIST_NEXT(ldbp, dblistlinks)) { + MUTEX_THREAD_LOCK(dbenv, dbp->mutexp); + for (dbc = TAILQ_FIRST(&ldbp->active_queue); + dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) { + cp = (BTREE_CURSOR *)dbc->internal; + if (cp_arg->root != cp->root) + continue; + ++found; + adjusted = 0; + switch (op) { + case CA_DELETE: + if (recno < cp->recno) { + --cp->recno; + /* + * If the adjustment made them equal, + * we have to merge the orders. + */ + if (recno == cp->recno && CD_ISSET(cp)) + cp->order += order; + } else if (recno == cp->recno && + !CD_ISSET(cp)) { + CD_SET(cp); + cp->order = order; + } + break; + case CA_IBEFORE: + /* + * IBEFORE is just like IAFTER, except that we + * adjust cursors on the current record too. + */ + if (C_EQUAL(cp_arg, cp)) { + ++cp->recno; + adjusted = 1; + } + goto iafter; + case CA_ICURRENT: + + /* + * If the original cursor wasn't deleted, we + * just did a replacement and so there's no + * need to adjust anything--we shouldn't have + * gotten this far. Otherwise, we behave + * much like an IAFTER, except that all + * cursors pointing to the current item get + * marked undeleted and point to the new + * item. + */ + DB_ASSERT(CD_ISSET(cp_arg)); + if (C_EQUAL(cp_arg, cp)) { + CD_CLR(cp); + break; + } + /* FALLTHROUGH */ + case CA_IAFTER: +iafter: if (!adjusted && C_LESSTHAN(cp_arg, cp)) { + ++cp->recno; + adjusted = 1; + } + if (recno == cp->recno && adjusted) + /* + * If we've moved this cursor's recno, + * split its order number--i.e., + * decrement it by enough so that + * the lowest cursor moved has order 1. + * cp_arg->order is the split point, + * so decrement by one less than that. + */ + cp->order -= (cp_arg->order - 1); + break; + } + } + MUTEX_THREAD_UNLOCK(dbp->dbenv, dbp->mutexp); + } + MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp); + + return (found); +} + +/* + * __ram_getno -- + * Check the user's record number, and make sure we've seen it. + * + * PUBLIC: int __ram_getno __P((DBC *, const DBT *, db_recno_t *, int)); + */ +int +__ram_getno(dbc, key, rep, can_create) + DBC *dbc; + const DBT *key; + db_recno_t *rep; + int can_create; +{ + DB *dbp; + db_recno_t recno; + + dbp = dbc->dbp; + + /* Check the user's record number. */ + if ((recno = *(db_recno_t *)key->data) == 0) { + __db_err(dbp->dbenv, "illegal record number of 0"); + return (EINVAL); + } + if (rep != NULL) + *rep = recno; + + /* + * Btree can neither create records nor read them in. Recno can + * do both, see if we can find the record. + */ + return (dbc->dbtype == DB_RECNO ? + __ram_update(dbc, recno, can_create) : 0); +} + +/* + * __ram_update -- + * Ensure the tree has records up to and including the specified one. + */ +static int +__ram_update(dbc, recno, can_create) + DBC *dbc; + db_recno_t recno; + int can_create; +{ + BTREE *t; + BTREE_CURSOR *cp; + DB *dbp; + db_recno_t nrecs; + int ret; + + dbp = dbc->dbp; + cp = (BTREE_CURSOR *)dbc->internal; + t = dbp->bt_internal; + + /* + * If we can't create records and we've read the entire backing input + * file, we're done. + */ + if (!can_create && t->re_eof) + return (0); + + /* + * If we haven't seen this record yet, try to get it from the original + * file. + */ + if ((ret = __bam_nrecs(dbc, &nrecs)) != 0) + return (ret); + if (!t->re_eof && recno > nrecs) { + if ((ret = __ram_sread(dbc, recno)) != 0 && ret != DB_NOTFOUND) + return (ret); + if ((ret = __bam_nrecs(dbc, &nrecs)) != 0) + return (ret); + } + + /* + * If we can create records, create empty ones up to the requested + * record. + */ + if (!can_create || recno <= nrecs + 1) + return (0); + + dbc->rdata.dlen = 0; + dbc->rdata.doff = 0; + dbc->rdata.flags = 0; + if (F_ISSET(dbp, DB_RE_FIXEDLEN)) { + if (dbc->rdata.ulen < t->re_len) { + if ((ret = __os_realloc(dbp->dbenv, + t->re_len, NULL, &dbc->rdata.data)) != 0) { + dbc->rdata.ulen = 0; + dbc->rdata.data = NULL; + return (ret); + } + dbc->rdata.ulen = t->re_len; + } + dbc->rdata.size = t->re_len; + memset(dbc->rdata.data, t->re_pad, t->re_len); + } else + dbc->rdata.size = 0; + + while (recno > ++nrecs) + if ((ret = __ram_add(dbc, + &nrecs, &dbc->rdata, 0, BI_DELETED)) != 0) + return (ret); + return (0); +} + +/* + * __ram_source -- + * Load information about the backing file. + */ +static int +__ram_source(dbp) + DB *dbp; +{ + BTREE *t; + char *source; + int ret; + + t = dbp->bt_internal; + + /* Find the real name, and swap out the one we had before. */ + if ((ret = __db_appname(dbp->dbenv, + DB_APP_DATA, NULL, t->re_source, 0, NULL, &source)) != 0) + return (ret); + __os_freestr(t->re_source); + t->re_source = source; + + /* + * !!! + * It's possible that the backing source file is read-only. We don't + * much care other than we'll complain if there are any modifications + * when it comes time to write the database back to the source. + */ + if ((t->re_fp = fopen(t->re_source, "r")) == NULL) { + ret = errno; + __db_err(dbp->dbenv, "%s: %s", t->re_source, db_strerror(ret)); + return (ret); + } + + t->re_eof = 0; + return (0); +} + +/* + * __ram_writeback -- + * Rewrite the backing file. + * + * PUBLIC: int __ram_writeback __P((DB *)); + */ +int +__ram_writeback(dbp) + DB *dbp; +{ + BTREE *t; + DB_ENV *dbenv; + DBC *dbc; + DBT key, data; + FILE *fp; + db_recno_t keyno; + int ret, t_ret; + u_int8_t delim, *pad; + + t = dbp->bt_internal; + dbenv = dbp->dbenv; + fp = NULL; + + /* If the file wasn't modified, we're done. */ + if (!t->re_modified) + return (0); + + /* If there's no backing source file, we're done. */ + if (t->re_source == NULL) { + t->re_modified = 0; + return (0); + } + + /* Allocate a cursor. */ + if ((ret = dbp->cursor(dbp, NULL, &dbc, 0)) != 0) + return (ret); + + /* + * Read any remaining records into the tree. + * + * !!! + * This is why we can't support transactions when applications specify + * backing (re_source) files. At this point we have to read in the + * rest of the records from the file so that we can write all of the + * records back out again, which could modify a page for which we'd + * have to log changes and which we don't have locked. This could be + * partially fixed by taking a snapshot of the entire file during the + * DB->open as DB->open is transaction protected. But, if a checkpoint + * occurs then, the part of the log holding the copy of the file could + * be discarded, and that would make it impossible to recover in the + * face of disaster. This could all probably be fixed, but it would + * require transaction protecting the backing source file. + * + * XXX + * This could be made to work now that we have transactions protecting + * file operations. Margo has specifically asked for the privilege of + * doing this work. + */ + if ((ret = + __ram_update(dbc, DB_MAX_RECORDS, 0)) != 0 && ret != DB_NOTFOUND) + return (ret); + + /* + * Close any existing file handle and re-open the file, truncating it. + */ + if (t->re_fp != NULL) { + if (fclose(t->re_fp) != 0) { + ret = errno; + goto err; + } + t->re_fp = NULL; + } + if ((fp = fopen(t->re_source, "w")) == NULL) { + ret = errno; + __db_err(dbenv, "%s: %s", t->re_source, db_strerror(ret)); + goto err; + } + + /* + * We step through the records, writing each one out. Use the record + * number and the dbp->get() function, instead of a cursor, so we find + * and write out "deleted" or non-existent records. + */ + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.size = sizeof(db_recno_t); + key.data = &keyno; + + /* + * We'll need the delimiter if we're doing variable-length records, + * and the pad character if we're doing fixed-length records. + */ + delim = t->re_delim; + if (F_ISSET(dbp, DB_RE_FIXEDLEN)) { + if ((ret = __os_malloc(dbenv, t->re_len, NULL, &pad)) != 0) + goto err; + memset(pad, t->re_pad, t->re_len); + } else + COMPQUIET(pad, NULL); + for (keyno = 1;; ++keyno) { + switch (ret = dbp->get(dbp, NULL, &key, &data, 0)) { + case 0: + if (fwrite(data.data, 1, data.size, fp) != data.size) + goto write_err; + break; + case DB_KEYEMPTY: + if (F_ISSET(dbp, DB_RE_FIXEDLEN) && + fwrite(pad, 1, t->re_len, fp) != t->re_len) + goto write_err; + break; + case DB_NOTFOUND: + ret = 0; + goto done; + } + if (!F_ISSET(dbp, DB_RE_FIXEDLEN) && + fwrite(&delim, 1, 1, fp) != 1) { +write_err: ret = errno; + __db_err(dbp->dbenv, + "%s: write failed to backing file: %s", + t->re_source, strerror(ret)); + goto err; + } + } + +err: +done: /* Close the file descriptor. */ + if (fp != NULL && fclose(fp) != 0) { + if (ret == 0) + ret = errno; + __db_err(dbenv, "%s: %s", t->re_source, db_strerror(errno)); + } + + /* Discard the cursor. */ + if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0) + ret = t_ret; + + if (ret == 0) + t->re_modified = 0; + + return (ret); +} + +/* + * __ram_sread -- + * Read records from a source file. + */ +static int +__ram_sread(dbc, top) + DBC *dbc; + db_recno_t top; +{ + BTREE *t; + DB *dbp; + DBT data; + db_recno_t recno; + size_t len; + int ch, ret, was_modified; + + t = dbc->dbp->bt_internal; + dbp = dbc->dbp; + was_modified = t->re_modified; + + if ((ret = __bam_nrecs(dbc, &recno)) != 0) + return (ret); + + /* Use the record data return memory, it's only a short-term use. */ + len = F_ISSET(dbp, DB_RE_FIXEDLEN) ? t->re_len : 256; + if (dbc->rdata.ulen < len) { + if ((ret = __os_realloc( + dbp->dbenv, len, NULL, &dbc->rdata.data)) != 0) { + dbc->rdata.ulen = 0; + dbc->rdata.data = NULL; + return (ret); + } + dbc->rdata.ulen = len; + } + + memset(&data, 0, sizeof(data)); + while (recno < top) { + data.data = dbc->rdata.data; + data.size = 0; + if (F_ISSET(dbp, DB_RE_FIXEDLEN)) + for (len = t->re_len; len > 0; --len) { + if ((ch = getc(t->re_fp)) == EOF) + goto eof; + ((u_int8_t *)data.data)[data.size++] = ch; + } + else + for (;;) { + if ((ch = getc(t->re_fp)) == EOF) + goto eof; + if (ch == t->re_delim) + break; + + ((u_int8_t *)data.data)[data.size++] = ch; + if (data.size == dbc->rdata.ulen) { + if ((ret = __os_realloc(dbp->dbenv, + dbc->rdata.ulen *= 2, + NULL, &dbc->rdata.data)) != 0) { + dbc->rdata.ulen = 0; + dbc->rdata.data = NULL; + return (ret); + } else + data.data = dbc->rdata.data; + } + } + + /* + * Another process may have read this record from the input + * file and stored it into the database already, in which + * case we don't need to repeat that operation. We detect + * this by checking if the last record we've read is greater + * or equal to the number of records in the database. + */ + if (t->re_last >= recno) { + ++recno; + if ((ret = __ram_add(dbc, &recno, &data, 0, 0)) != 0) + goto err; + } + ++t->re_last; + } + + if (0) { +eof: t->re_eof = 1; + ret = DB_NOTFOUND; + } +err: if (!was_modified) + t->re_modified = 0; + + return (ret); +} + +/* + * __ram_add -- + * Add records into the tree. + */ +static int +__ram_add(dbc, recnop, data, flags, bi_flags) + DBC *dbc; + db_recno_t *recnop; + DBT *data; + u_int32_t flags, bi_flags; +{ + BKEYDATA *bk; + BTREE_CURSOR *cp; + int exact, ret, stack; + + cp = (BTREE_CURSOR *)dbc->internal; + +retry: /* Find the slot for insertion. */ + if ((ret = __bam_rsearch(dbc, recnop, + S_INSERT | (flags == DB_APPEND ? S_APPEND : 0), 1, &exact)) != 0) + return (ret); + stack = 1; + cp->page = cp->csp->page; + cp->pgno = cp->csp->page->pgno; + cp->indx = cp->csp->indx; + + /* + * The application may modify the data based on the selected record + * number. + */ + if (flags == DB_APPEND && dbc->dbp->db_append_recno != NULL && + (ret = dbc->dbp->db_append_recno(dbc->dbp, data, *recnop)) != 0) + goto err; + + /* + * If re-numbering records, the on-page deleted flag means this record + * was implicitly created. If not re-numbering records, the on-page + * deleted flag means this record was implicitly created, or, it was + * deleted at some time. + * + * If DB_NOOVERWRITE is set and the item already exists in the tree, + * return an error unless the item was either marked for deletion or + * only implicitly created. + */ + if (exact) { + bk = GET_BKEYDATA(cp->page, cp->indx); + if (!B_DISSET(bk->type) && flags == DB_NOOVERWRITE) { + ret = DB_KEYEXIST; + goto err; + } + } + + /* + * Select the arguments for __bam_iitem() and do the insert. If the + * key is an exact match, or we're replacing the data item with a + * new data item, replace the current item. If the key isn't an exact + * match, we're inserting a new key/data pair, before the search + * location. + */ + switch (ret = __bam_iitem(dbc, + NULL, data, exact ? DB_CURRENT : DB_BEFORE, bi_flags)) { + case 0: + /* + * Don't adjust anything. + * + * If we inserted a record, no cursors need adjusting because + * the only new record it's possible to insert is at the very + * end of the tree. The necessary adjustments to the internal + * page counts were made by __bam_iitem(). + * + * If we overwrote a record, no cursors need adjusting because + * future DBcursor->get calls will simply return the underlying + * record (there's no adjustment made for the DB_CURRENT flag + * when a cursor get operation immediately follows a cursor + * delete operation, and the normal adjustment for the DB_NEXT + * flag is still correct). + */ + break; + case DB_NEEDSPLIT: + /* Discard the stack of pages and split the page. */ + (void)__bam_stkrel(dbc, STK_CLRDBC); + stack = 0; + + if ((ret = __bam_split(dbc, recnop)) != 0) + goto err; + + goto retry; + /* NOTREACHED */ + default: + goto err; + } + +err: if (stack) + __bam_stkrel(dbc, STK_CLRDBC); + + return (ret); +} diff --git a/db/btree/bt_rsearch.c b/db/btree/bt_rsearch.c new file mode 100644 index 000000000..7102cd715 --- /dev/null +++ b/db/btree/bt_rsearch.c @@ -0,0 +1,429 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: bt_rsearch.c,v 11.21 2000/03/28 21:50:04 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "btree.h" +#include "db_shash.h" +#include "lock.h" + +/* + * __bam_rsearch -- + * Search a btree for a record number. + * + * PUBLIC: int __bam_rsearch __P((DBC *, db_recno_t *, u_int32_t, int, int *)); + */ +int +__bam_rsearch(dbc, recnop, flags, stop, exactp) + DBC *dbc; + db_recno_t *recnop; + u_int32_t flags; + int stop, *exactp; +{ + BINTERNAL *bi; + BTREE_CURSOR *cp; + DB *dbp; + DB_LOCK lock; + PAGE *h; + RINTERNAL *ri; + db_indx_t adjust, deloffset, indx, top; + db_lockmode_t lock_mode; + db_pgno_t pg; + db_recno_t recno, t_recno, total; + int ret, stack; + + dbp = dbc->dbp; + cp = (BTREE_CURSOR *)dbc->internal; + + BT_STK_CLR(cp); + + /* + * There are several ways we search a btree tree. The flags argument + * specifies if we're acquiring read or write locks and if we are + * locking pairs of pages. In addition, if we're adding or deleting + * an item, we have to lock the entire tree, regardless. See btree.h + * for more details. + * + * If write-locking pages, we need to know whether or not to acquire a + * write lock on a page before getting it. This depends on how deep it + * is in tree, which we don't know until we acquire the root page. So, + * if we need to lock the root page we may have to upgrade it later, + * because we won't get the correct lock initially. + * + * Retrieve the root page. + */ + pg = cp->root; + stack = LF_ISSET(S_STACK); + lock_mode = stack ? DB_LOCK_WRITE : DB_LOCK_READ; + if ((ret = __db_lget(dbc, 0, pg, lock_mode, 0, &lock)) != 0) + return (ret); + if ((ret = memp_fget(dbp->mpf, &pg, 0, &h)) != 0) { + /* Did not read it, so we can release the lock */ + (void)__LPUT(dbc, lock); + return (ret); + } + + /* + * Decide if we need to save this page; if we do, write lock it. + * We deliberately don't lock-couple on this call. If the tree + * is tiny, i.e., one page, and two threads are busily updating + * the root page, we're almost guaranteed deadlocks galore, as + * each one gets a read lock and then blocks the other's attempt + * for a write lock. + */ + if (!stack && + ((LF_ISSET(S_PARENT) && (u_int8_t)(stop + 1) >= h->level) || + (LF_ISSET(S_WRITE) && h->level == LEAFLEVEL))) { + (void)memp_fput(dbp->mpf, h, 0); + (void)__LPUT(dbc, lock); + lock_mode = DB_LOCK_WRITE; + if ((ret = __db_lget(dbc, 0, pg, lock_mode, 0, &lock)) != 0) + return (ret); + if ((ret = memp_fget(dbp->mpf, &pg, 0, &h)) != 0) { + /* Did not read it, so we can release the lock */ + (void)__LPUT(dbc, lock); + return (ret); + } + stack = 1; + } + + /* + * If appending to the tree, set the record number now -- we have the + * root page locked. + * + * Delete only deletes exact matches, read only returns exact matches. + * Note, this is different from __bam_search(), which returns non-exact + * matches for read. + * + * The record may not exist. We can only return the correct location + * for the record immediately after the last record in the tree, so do + * a fast check now. + */ + total = RE_NREC(h); + if (LF_ISSET(S_APPEND)) { + *exactp = 0; + *recnop = recno = total + 1; + } else { + recno = *recnop; + if (recno <= total) + *exactp = 1; + else { + *exactp = 0; + if (!LF_ISSET(S_PAST_EOF) || recno > total + 1) { + /* + * Keep the page locked for serializability. + * + * XXX + * This leaves the root page locked, which will + * eliminate any concurrency. A possible fix + * would be to lock the last leaf page instead. + */ + (void)memp_fput(dbp->mpf, h, 0); + (void)__TLPUT(dbc, lock); + return (DB_NOTFOUND); + } + } + } + + /* + * !!! + * Record numbers in the tree are 0-based, but the recno is + * 1-based. All of the calculations below have to take this + * into account. + */ + for (total = 0;;) { + switch (TYPE(h)) { + case P_LBTREE: + case P_LDUP: + recno -= total; + /* + * There may be logically deleted records on the page. + * If there are enough, the record may not exist. + */ + if (TYPE(h) == P_LBTREE) { + adjust = P_INDX; + deloffset = O_INDX; + } else { + adjust = O_INDX; + deloffset = 0; + } + for (t_recno = 0, indx = 0;; indx += adjust) { + if (indx >= NUM_ENT(h)) { + *exactp = 0; + if (!LF_ISSET(S_PAST_EOF) || + recno > t_recno + 1) { + ret = DB_NOTFOUND; + goto err; + } + } + if (!B_DISSET( + GET_BKEYDATA(h, indx + deloffset)->type) && + ++t_recno == recno) + break; + } + + /* Correct from 1-based to 0-based for a page offset. */ + BT_STK_ENTER(dbp->dbenv, + cp, h, indx, lock, lock_mode, ret); + if (ret != 0) + goto err; + return (0); + case P_IBTREE: + for (indx = 0, top = NUM_ENT(h);;) { + bi = GET_BINTERNAL(h, indx); + if (++indx == top || total + bi->nrecs >= recno) + break; + total += bi->nrecs; + } + pg = bi->pgno; + break; + case P_LRECNO: + recno -= total; + + /* Correct from 1-based to 0-based for a page offset. */ + --recno; + BT_STK_ENTER(dbp->dbenv, + cp, h, recno, lock, lock_mode, ret); + if (ret != 0) + goto err; + return (0); + case P_IRECNO: + for (indx = 0, top = NUM_ENT(h);;) { + ri = GET_RINTERNAL(h, indx); + if (++indx == top || total + ri->nrecs >= recno) + break; + total += ri->nrecs; + } + pg = ri->pgno; + break; + default: + return (__db_pgfmt(dbp, h->pgno)); + } + --indx; + + if (stack) { + /* Return if this is the lowest page wanted. */ + if (LF_ISSET(S_PARENT) && stop == h->level) { + BT_STK_ENTER(dbp->dbenv, + cp, h, indx, lock, lock_mode, ret); + if (ret != 0) + goto err; + return (0); + } + BT_STK_PUSH(dbp->dbenv, + cp, h, indx, lock, lock_mode, ret); + if (ret != 0) + goto err; + + lock_mode = DB_LOCK_WRITE; + if ((ret = + __db_lget(dbc, 0, pg, lock_mode, 0, &lock)) != 0) + goto err; + } else { + /* + * Decide if we want to return a pointer to the next + * page in the stack. If we do, write lock it and + * never unlock it. + */ + if ((LF_ISSET(S_PARENT) && + (u_int8_t)(stop + 1) >= (u_int8_t)(h->level - 1)) || + (h->level - 1) == LEAFLEVEL) + stack = 1; + + (void)memp_fput(dbp->mpf, h, 0); + + lock_mode = stack && + LF_ISSET(S_WRITE) ? DB_LOCK_WRITE : DB_LOCK_READ; + if ((ret = __db_lget(dbc, + LCK_COUPLE, pg, lock_mode, 0, &lock)) != 0) { + /* + * If we fail, discard the lock we held. This + * is OK because this only happens when we are + * descending the tree holding read-locks. + */ + __LPUT(dbc, lock); + goto err; + } + } + + if ((ret = memp_fget(dbp->mpf, &pg, 0, &h)) != 0) + goto err; + } + /* NOTREACHED */ + +err: BT_STK_POP(cp); + __bam_stkrel(dbc, 0); + return (ret); +} + +/* + * __bam_adjust -- + * Adjust the tree after adding or deleting a record. + * + * PUBLIC: int __bam_adjust __P((DBC *, int32_t)); + */ +int +__bam_adjust(dbc, adjust) + DBC *dbc; + int32_t adjust; +{ + BTREE_CURSOR *cp; + DB *dbp; + EPG *epg; + PAGE *h; + db_pgno_t root_pgno; + int ret; + + dbp = dbc->dbp; + cp = (BTREE_CURSOR *)dbc->internal; + root_pgno = cp->root; + + /* Update the record counts for the tree. */ + for (epg = cp->sp; epg <= cp->csp; ++epg) { + h = epg->page; + if (TYPE(h) == P_IBTREE || TYPE(h) == P_IRECNO) { + if (DB_LOGGING(dbc) && + (ret = __bam_cadjust_log(dbp->dbenv, + dbc->txn, &LSN(h), 0, dbp->log_fileid, + PGNO(h), &LSN(h), (u_int32_t)epg->indx, adjust, + PGNO(h) == root_pgno ? CAD_UPDATEROOT : 0)) != 0) + return (ret); + + if (TYPE(h) == P_IBTREE) + GET_BINTERNAL(h, epg->indx)->nrecs += adjust; + else + GET_RINTERNAL(h, epg->indx)->nrecs += adjust; + + if (PGNO(h) == root_pgno) + RE_NREC_ADJ(h, adjust); + + if ((ret = memp_fset(dbp->mpf, h, DB_MPOOL_DIRTY)) != 0) + return (ret); + } + } + return (0); +} + +/* + * __bam_nrecs -- + * Return the number of records in the tree. + * + * PUBLIC: int __bam_nrecs __P((DBC *, db_recno_t *)); + */ +int +__bam_nrecs(dbc, rep) + DBC *dbc; + db_recno_t *rep; +{ + DB *dbp; + DB_LOCK lock; + PAGE *h; + db_pgno_t pgno; + int ret; + + dbp = dbc->dbp; + + pgno = dbc->internal->root; + if ((ret = __db_lget(dbc, 0, pgno, DB_LOCK_READ, 0, &lock)) != 0) + return (ret); + if ((ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) + return (ret); + + *rep = RE_NREC(h); + + (void)memp_fput(dbp->mpf, h, 0); + (void)__TLPUT(dbc, lock); + + return (0); +} + +/* + * __bam_total -- + * Return the number of records below a page. + * + * PUBLIC: db_recno_t __bam_total __P((PAGE *)); + */ +db_recno_t +__bam_total(h) + PAGE *h; +{ + db_recno_t nrecs; + db_indx_t indx, top; + + nrecs = 0; + top = NUM_ENT(h); + + switch (TYPE(h)) { + case P_LBTREE: + /* Check for logically deleted records. */ + for (indx = 0; indx < top; indx += P_INDX) + if (!B_DISSET(GET_BKEYDATA(h, indx + O_INDX)->type)) + ++nrecs; + break; + case P_LDUP: + /* Check for logically deleted records. */ + for (indx = 0; indx < top; indx += O_INDX) + if (!B_DISSET(GET_BKEYDATA(h, indx)->type)) + ++nrecs; + break; + case P_IBTREE: + for (indx = 0; indx < top; indx += O_INDX) + nrecs += GET_BINTERNAL(h, indx)->nrecs; + break; + case P_LRECNO: + nrecs = NUM_ENT(h); + break; + case P_IRECNO: + for (indx = 0; indx < top; indx += O_INDX) + nrecs += GET_RINTERNAL(h, indx)->nrecs; + break; + } + + return (nrecs); +} diff --git a/db/btree/bt_search.c b/db/btree/bt_search.c new file mode 100644 index 000000000..d822198f2 --- /dev/null +++ b/db/btree/bt_search.c @@ -0,0 +1,471 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994, 1995 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Mike Olson. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: bt_search.c,v 11.32 2001/01/17 20:19:46 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_shash.h" +#include "btree.h" +#include "lock.h" + +/* + * __bam_search -- + * Search a btree for a key. + * + * PUBLIC: int __bam_search __P((DBC *, + * PUBLIC: const DBT *, u_int32_t, int, db_recno_t *, int *)); + */ +int +__bam_search(dbc, key, flags, stop, recnop, exactp) + DBC *dbc; + const DBT *key; + u_int32_t flags; + int stop, *exactp; + db_recno_t *recnop; +{ + BTREE *t; + BTREE_CURSOR *cp; + DB *dbp; + DB_LOCK lock; + PAGE *h; + db_indx_t base, i, indx, lim; + db_lockmode_t lock_mode; + db_pgno_t pg; + db_recno_t recno; + int adjust, cmp, deloffset, ret, stack; + int (*func) __P((DB *, const DBT *, const DBT *)); + + dbp = dbc->dbp; + cp = (BTREE_CURSOR *)dbc->internal; + t = dbp->bt_internal; + recno = 0; + + BT_STK_CLR(cp); + + /* + * There are several ways we search a btree tree. The flags argument + * specifies if we're acquiring read or write locks, if we position + * to the first or last item in a set of duplicates, if we return + * deleted items, and if we are locking pairs of pages. In addition, + * if we're modifying record numbers, we have to lock the entire tree + * regardless. See btree.h for more details. + * + * If write-locking pages, we need to know whether or not to acquire a + * write lock on a page before getting it. This depends on how deep it + * is in tree, which we don't know until we acquire the root page. So, + * if we need to lock the root page we may have to upgrade it later, + * because we won't get the correct lock initially. + * + * Retrieve the root page. + */ +try_again: + pg = cp->root; + stack = LF_ISSET(S_STACK) && F_ISSET(cp, C_RECNUM); + lock_mode = stack ? DB_LOCK_WRITE : DB_LOCK_READ; + if ((ret = __db_lget(dbc, 0, pg, lock_mode, 0, &lock)) != 0) + return (ret); + if ((ret = memp_fget(dbp->mpf, &pg, 0, &h)) != 0) { + /* Did not read it, so we can release the lock */ + (void)__LPUT(dbc, lock); + return (ret); + } + + /* + * Decide if we need to save this page; if we do, write lock it. + * We deliberately don't lock-couple on this call. If the tree + * is tiny, i.e., one page, and two threads are busily updating + * the root page, we're almost guaranteed deadlocks galore, as + * each one gets a read lock and then blocks the other's attempt + * for a write lock. + */ + if (!stack && + ((LF_ISSET(S_PARENT) && (u_int8_t)(stop + 1) >= h->level) || + (LF_ISSET(S_WRITE) && h->level == LEAFLEVEL))) { + (void)memp_fput(dbp->mpf, h, 0); + (void)__LPUT(dbc, lock); + lock_mode = DB_LOCK_WRITE; + if ((ret = __db_lget(dbc, 0, pg, lock_mode, 0, &lock)) != 0) + return (ret); + if ((ret = memp_fget(dbp->mpf, &pg, 0, &h)) != 0) { + /* Did not read it, so we can release the lock */ + (void)__LPUT(dbc, lock); + return (ret); + } + if (!((LF_ISSET(S_PARENT) + && (u_int8_t)(stop + 1) >= h->level) || + (LF_ISSET(S_WRITE) && h->level == LEAFLEVEL))) { + /* Someone else split the root, start over. */ + (void)memp_fput(dbp->mpf, h, 0); + (void)__LPUT(dbc, lock); + goto try_again; + } + stack = 1; + } + + /* Choose a comparison function. */ + func = F_ISSET(dbc, DBC_OPD) ? + (dbp->dup_compare == NULL ? __bam_defcmp : dbp->dup_compare) : + t->bt_compare; + + for (;;) { + /* + * Do a binary search on the current page. If we're searching + * a Btree leaf page, we have to walk the indices in groups of + * two. If we're searching an internal page or a off-page dup + * page, they're an index per page item. If we find an exact + * match on a leaf page, we're done. + */ + adjust = TYPE(h) == P_LBTREE ? P_INDX : O_INDX; + for (base = 0, + lim = NUM_ENT(h) / (db_indx_t)adjust; lim != 0; lim >>= 1) { + indx = base + ((lim >> 1) * adjust); + if ((ret = + __bam_cmp(dbp, key, h, indx, func, &cmp)) != 0) + goto err; + if (cmp == 0) { + if (TYPE(h) == P_LBTREE || TYPE(h) == P_LDUP) + goto found; + goto next; + } + if (cmp > 0) { + base = indx + adjust; + --lim; + } + } + + /* + * No match found. Base is the smallest index greater than + * key and may be zero or a last + O_INDX index. + * + * If it's a leaf page, return base as the "found" value. + * Delete only deletes exact matches. + */ + if (TYPE(h) == P_LBTREE || TYPE(h) == P_LDUP) { + *exactp = 0; + + if (LF_ISSET(S_EXACT)) + goto notfound; + + if (LF_ISSET(S_STK_ONLY)) { + BT_STK_NUM(dbp->dbenv, cp, h, base, ret); + __LPUT(dbc, lock); + (void)memp_fput(dbp->mpf, h, 0); + return (ret); + } + + /* + * !!! + * Possibly returning a deleted record -- DB_SET_RANGE, + * DB_KEYFIRST and DB_KEYLAST don't require an exact + * match, and we don't want to walk multiple pages here + * to find an undeleted record. This is handled by the + * calling routine. + */ + BT_STK_ENTER(dbp->dbenv, + cp, h, base, lock, lock_mode, ret); + if (ret != 0) + goto err; + return (0); + } + + /* + * If it's not a leaf page, record the internal page (which is + * a parent page for the key). Decrement the base by 1 if it's + * non-zero so that if a split later occurs, the inserted page + * will be to the right of the saved page. + */ + indx = base > 0 ? base - O_INDX : base; + + /* + * If we're trying to calculate the record number, sum up + * all the record numbers on this page up to the indx point. + */ +next: if (recnop != NULL) + for (i = 0; i < indx; ++i) + recno += GET_BINTERNAL(h, i)->nrecs; + + pg = GET_BINTERNAL(h, indx)->pgno; + + if (LF_ISSET(S_STK_ONLY)) { + if (stop == h->level) { + BT_STK_NUM(dbp->dbenv, cp, h, indx, ret); + __LPUT(dbc, lock); + (void)memp_fput(dbp->mpf, h, 0); + return (ret); + } + BT_STK_NUMPUSH(dbp->dbenv, cp, h, indx, ret); + (void)memp_fput(dbp->mpf, h, 0); + if ((ret = __db_lget(dbc, + LCK_COUPLE, pg, lock_mode, 0, &lock)) != 0) { + /* + * Discard our lock and return on failure. This + * is OK because it only happens when descending + * the tree holding read-locks. + */ + __LPUT(dbc, lock); + return (ret); + } + } else if (stack) { + /* Return if this is the lowest page wanted. */ + if (LF_ISSET(S_PARENT) && stop == h->level) { + BT_STK_ENTER(dbp->dbenv, + cp, h, indx, lock, lock_mode, ret); + if (ret != 0) + goto err; + return (0); + } + BT_STK_PUSH(dbp->dbenv, + cp, h, indx, lock, lock_mode, ret); + if (ret != 0) + goto err; + + lock_mode = DB_LOCK_WRITE; + if ((ret = + __db_lget(dbc, 0, pg, lock_mode, 0, &lock)) != 0) + goto err; + } else { + /* + * Decide if we want to return a reference to the next + * page in the return stack. If so, lock it and never + * unlock it. + */ + if ((LF_ISSET(S_PARENT) && + (u_int8_t)(stop + 1) >= (u_int8_t)(h->level - 1)) || + (h->level - 1) == LEAFLEVEL) + stack = 1; + + (void)memp_fput(dbp->mpf, h, 0); + + lock_mode = stack && + LF_ISSET(S_WRITE) ? DB_LOCK_WRITE : DB_LOCK_READ; + if ((ret = __db_lget(dbc, + LCK_COUPLE, pg, lock_mode, 0, &lock)) != 0) { + /* + * If we fail, discard the lock we held. This + * is OK because this only happens when we are + * descending the tree holding read-locks. + */ + __LPUT(dbc, lock); + goto err; + } + } + if ((ret = memp_fget(dbp->mpf, &pg, 0, &h)) != 0) + goto err; + } + /* NOTREACHED */ + +found: *exactp = 1; + + /* + * If we're trying to calculate the record number, add in the + * offset on this page and correct for the fact that records + * in the tree are 0-based. + */ + if (recnop != NULL) + *recnop = recno + (indx / P_INDX) + 1; + + /* + * If we got here, we know that we have a Btree leaf or off-page + * duplicates page. If it's a Btree leaf page, we have to handle + * on-page duplicates. + * + * If there are duplicates, go to the first/last one. This is + * safe because we know that we're not going to leave the page, + * all duplicate sets that are not on overflow pages exist on a + * single leaf page. + */ + if (TYPE(h) == P_LBTREE) { + if (LF_ISSET(S_DUPLAST)) + while (indx < (db_indx_t)(NUM_ENT(h) - P_INDX) && + h->inp[indx] == h->inp[indx + P_INDX]) + indx += P_INDX; + else + while (indx > 0 && + h->inp[indx] == h->inp[indx - P_INDX]) + indx -= P_INDX; + } + + /* + * Now check if we are allowed to return deleted items; if not, then + * find the next (or previous) non-deleted duplicate entry. (We do + * not move from the original found key on the basis of the S_DELNO + * flag.) + */ + if (LF_ISSET(S_DELNO)) { + deloffset = TYPE(h) == P_LBTREE ? O_INDX : 0; + if (LF_ISSET(S_DUPLAST)) + while (B_DISSET(GET_BKEYDATA( + h, indx + deloffset)->type) && indx > 0 && + h->inp[indx] == h->inp[indx - adjust]) + indx -= adjust; + else + while (B_DISSET(GET_BKEYDATA( + h, indx + deloffset)->type) && + indx < (db_indx_t)(NUM_ENT(h) - adjust) && + h->inp[indx] == h->inp[indx + adjust]) + indx += adjust; + + /* + * If we weren't able to find a non-deleted duplicate, return + * DB_NOTFOUND. + */ + if (B_DISSET(GET_BKEYDATA(h, indx + deloffset)->type)) + goto notfound; + } + + if (LF_ISSET(S_STK_ONLY)) { + BT_STK_NUM(dbp->dbenv, cp, h, indx, ret); + __LPUT(dbc, lock); + (void)memp_fput(dbp->mpf, h, 0); + } else { + BT_STK_ENTER(dbp->dbenv, cp, h, indx, lock, lock_mode, ret); + if (ret != 0) + goto err; + } + return (0); + +notfound: + /* Keep the page locked for serializability. */ + (void)memp_fput(dbp->mpf, h, 0); + (void)__TLPUT(dbc, lock); + ret = DB_NOTFOUND; + +err: BT_STK_POP(cp); + __bam_stkrel(dbc, 0); + return (ret); +} + +/* + * __bam_stkrel -- + * Release all pages currently held in the stack. + * + * PUBLIC: int __bam_stkrel __P((DBC *, u_int32_t)); + */ +int +__bam_stkrel(dbc, flags) + DBC *dbc; + u_int32_t flags; +{ + BTREE_CURSOR *cp; + DB *dbp; + EPG *epg; + int ret, t_ret; + + dbp = dbc->dbp; + cp = (BTREE_CURSOR *)dbc->internal; + + /* + * Release inner pages first. + * + * The caller must be sure that setting STK_NOLOCK will not effect + * either serializability or recoverability. + */ + for (ret = 0, epg = cp->sp; epg <= cp->csp; ++epg) { + if (epg->page != NULL) { + if (LF_ISSET(STK_CLRDBC) && cp->page == epg->page) { + cp->page = NULL; + cp->lock.off = LOCK_INVALID; + } + if ((t_ret = memp_fput( + dbp->mpf, epg->page, 0)) != 0 && ret == 0) + ret = t_ret; + /* + * XXX + * Temporary fix for #3243 -- under certain deadlock + * conditions we call here again and re-free the page. + * The correct fix is to never release a stack that + * doesn't hold items. + */ + epg->page = NULL; + } + if (epg->lock.off != LOCK_INVALID) { + if (LF_ISSET(STK_NOLOCK)) + (void)__LPUT(dbc, epg->lock); + else + (void)__TLPUT(dbc, epg->lock); + } + } + + /* Clear the stack, all pages have been released. */ + BT_STK_CLR(cp); + + return (ret); +} + +/* + * __bam_stkgrow -- + * Grow the stack. + * + * PUBLIC: int __bam_stkgrow __P((DB_ENV *, BTREE_CURSOR *)); + */ +int +__bam_stkgrow(dbenv, cp) + DB_ENV *dbenv; + BTREE_CURSOR *cp; +{ + EPG *p; + size_t entries; + int ret; + + entries = cp->esp - cp->sp; + + if ((ret = __os_calloc(dbenv, entries * 2, sizeof(EPG), &p)) != 0) + return (ret); + memcpy(p, cp->sp, entries * sizeof(EPG)); + if (cp->sp != cp->stack) + __os_free(cp->sp, entries * sizeof(EPG)); + cp->sp = p; + cp->csp = p + entries; + cp->esp = p + entries * 2; + return (0); +} diff --git a/db/btree/bt_split.c b/db/btree/bt_split.c new file mode 100644 index 000000000..f76337b19 --- /dev/null +++ b/db/btree/bt_split.c @@ -0,0 +1,1126 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994, 1995 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: bt_split.c,v 11.31 2000/12/22 19:08:27 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_shash.h" +#include "lock.h" +#include "btree.h" + +static int __bam_broot __P((DBC *, PAGE *, PAGE *, PAGE *)); +static int __bam_page __P((DBC *, EPG *, EPG *)); +static int __bam_pinsert __P((DBC *, EPG *, PAGE *, PAGE *, int)); +static int __bam_psplit __P((DBC *, EPG *, PAGE *, PAGE *, db_indx_t *)); +static int __bam_root __P((DBC *, EPG *)); +static int __ram_root __P((DBC *, PAGE *, PAGE *, PAGE *)); + +/* + * __bam_split -- + * Split a page. + * + * PUBLIC: int __bam_split __P((DBC *, void *)); + */ +int +__bam_split(dbc, arg) + DBC *dbc; + void *arg; +{ + BTREE *t; + BTREE_CURSOR *cp; + DB *dbp; + enum { UP, DOWN } dir; + db_pgno_t root_pgno; + int exact, level, ret; + + dbp = dbc->dbp; + cp = (BTREE_CURSOR *)dbc->internal; + root_pgno = cp->root; + + /* + * The locking protocol we use to avoid deadlock to acquire locks by + * walking down the tree, but we do it as lazily as possible, locking + * the root only as a last resort. We expect all stack pages to have + * been discarded before we're called; we discard all short-term locks. + * + * When __bam_split is first called, we know that a leaf page was too + * full for an insert. We don't know what leaf page it was, but we + * have the key/recno that caused the problem. We call XX_search to + * reacquire the leaf page, but this time get both the leaf page and + * its parent, locked. We then split the leaf page and see if the new + * internal key will fit into the parent page. If it will, we're done. + * + * If it won't, we discard our current locks and repeat the process, + * only this time acquiring the parent page and its parent, locked. + * This process repeats until we succeed in the split, splitting the + * root page as the final resort. The entire process then repeats, + * as necessary, until we split a leaf page. + * + * XXX + * A traditional method of speeding this up is to maintain a stack of + * the pages traversed in the original search. You can detect if the + * stack is correct by storing the page's LSN when it was searched and + * comparing that LSN with the current one when it's locked during the + * split. This would be an easy change for this code, but I have no + * numbers that indicate it's worthwhile. + */ + t = dbp->bt_internal; + for (dir = UP, level = LEAFLEVEL;; dir == UP ? ++level : --level) { + /* + * Acquire a page and its parent, locked. + */ + if ((ret = (dbc->dbtype == DB_BTREE ? + __bam_search(dbc, arg, S_WRPAIR, level, NULL, &exact) : + __bam_rsearch(dbc, + (db_recno_t *)arg, S_WRPAIR, level, &exact))) != 0) + return (ret); + + /* + * Split the page if it still needs it (it's possible another + * thread of control has already split the page). If we are + * guaranteed that two items will fit on the page, the split + * is no longer necessary. + */ + if (2 * B_MAXSIZEONPAGE(cp->ovflsize) + <= (db_indx_t)P_FREESPACE(cp->csp[0].page)) { + __bam_stkrel(dbc, STK_NOLOCK); + return (0); + } + ret = cp->csp[0].page->pgno == root_pgno ? + __bam_root(dbc, &cp->csp[0]) : + __bam_page(dbc, &cp->csp[-1], &cp->csp[0]); + BT_STK_CLR(cp); + + switch (ret) { + case 0: + /* Once we've split the leaf page, we're done. */ + if (level == LEAFLEVEL) + return (0); + + /* Switch directions. */ + if (dir == UP) + dir = DOWN; + break; + case DB_NEEDSPLIT: + /* + * It's possible to fail to split repeatedly, as other + * threads may be modifying the tree, or the page usage + * is sufficiently bad that we don't get enough space + * the first time. + */ + if (dir == DOWN) + dir = UP; + break; + default: + return (ret); + } + } + /* NOTREACHED */ +} + +/* + * __bam_root -- + * Split the root page of a btree. + */ +static int +__bam_root(dbc, cp) + DBC *dbc; + EPG *cp; +{ + DB *dbp; + DBT log_dbt; + DB_LSN log_lsn; + PAGE *lp, *rp; + db_indx_t split; + u_int32_t opflags; + int ret; + + dbp = dbc->dbp; + + /* Yeah, right. */ + if (cp->page->level >= MAXBTREELEVEL) { + __db_err(dbp->dbenv, + "Too many btree levels: %d", cp->page->level); + ret = ENOSPC; + goto err; + } + + /* Create new left and right pages for the split. */ + lp = rp = NULL; + if ((ret = __db_new(dbc, TYPE(cp->page), &lp)) != 0 || + (ret = __db_new(dbc, TYPE(cp->page), &rp)) != 0) + goto err; + P_INIT(lp, dbp->pgsize, lp->pgno, + PGNO_INVALID, ISINTERNAL(cp->page) ? PGNO_INVALID : rp->pgno, + cp->page->level, TYPE(cp->page)); + P_INIT(rp, dbp->pgsize, rp->pgno, + ISINTERNAL(cp->page) ? PGNO_INVALID : lp->pgno, PGNO_INVALID, + cp->page->level, TYPE(cp->page)); + + /* Split the page. */ + if ((ret = __bam_psplit(dbc, cp, lp, rp, &split)) != 0) + goto err; + + /* Log the change. */ + if (DB_LOGGING(dbc)) { + memset(&log_dbt, 0, sizeof(log_dbt)); + log_dbt.data = cp->page; + log_dbt.size = dbp->pgsize; + ZERO_LSN(log_lsn); + opflags = F_ISSET( + (BTREE_CURSOR *)dbc->internal, C_RECNUM) ? SPL_NRECS : 0; + if ((ret = __bam_split_log(dbp->dbenv, dbc->txn, + &LSN(cp->page), 0, dbp->log_fileid, PGNO(lp), &LSN(lp), + PGNO(rp), &LSN(rp), (u_int32_t)NUM_ENT(lp), 0, &log_lsn, + dbc->internal->root, &log_dbt, opflags)) != 0) + goto err; + LSN(lp) = LSN(cp->page); + LSN(rp) = LSN(cp->page); + } + + /* Clean up the new root page. */ + if ((ret = (dbc->dbtype == DB_RECNO ? + __ram_root(dbc, cp->page, lp, rp) : + __bam_broot(dbc, cp->page, lp, rp))) != 0) + goto err; + + /* Adjust any cursors. */ + if ((ret = __bam_ca_split(dbc, + cp->page->pgno, lp->pgno, rp->pgno, split, 1)) != 0) + goto err; + + /* Success -- write the real pages back to the store. */ + (void)memp_fput(dbp->mpf, cp->page, DB_MPOOL_DIRTY); + (void)__TLPUT(dbc, cp->lock); + (void)memp_fput(dbp->mpf, lp, DB_MPOOL_DIRTY); + (void)memp_fput(dbp->mpf, rp, DB_MPOOL_DIRTY); + + return (0); + +err: if (lp != NULL) + (void)__db_free(dbc, lp); + if (rp != NULL) + (void)__db_free(dbc, rp); + (void)memp_fput(dbp->mpf, cp->page, 0); + (void)__TLPUT(dbc, cp->lock); + return (ret); +} + +/* + * __bam_page -- + * Split the non-root page of a btree. + */ +static int +__bam_page(dbc, pp, cp) + DBC *dbc; + EPG *pp, *cp; +{ + BTREE_CURSOR *bc; + DBT log_dbt; + DB_LSN log_lsn; + DB *dbp; + DB_LOCK tplock; + DB_LSN save_lsn; + PAGE *lp, *rp, *alloc_rp, *tp; + db_indx_t split; + u_int32_t opflags; + int ret, t_ret; + + dbp = dbc->dbp; + alloc_rp = lp = rp = tp = NULL; + tplock.off = LOCK_INVALID; + ret = -1; + + /* + * Create a new right page for the split, and fill in everything + * except its LSN and page number. + * + * We malloc space for both the left and right pages, so we don't get + * a new page from the underlying buffer pool until we know the split + * is going to succeed. The reason is that we can't release locks + * acquired during the get-a-new-page process because metadata page + * locks can't be discarded on failure since we may have modified the + * free list. So, if you assume that we're holding a write lock on the + * leaf page which ran out of space and started this split (e.g., we + * have already written records to the page, or we retrieved a record + * from it with the DB_RMW flag set), failing in a split with both a + * leaf page locked and the metadata page locked can potentially lock + * up the tree badly, because we've violated the rule of always locking + * down the tree, and never up. + */ + if ((ret = __os_malloc(dbp->dbenv, dbp->pgsize, NULL, &rp)) != 0) + goto err; + P_INIT(rp, dbp->pgsize, 0, + ISINTERNAL(cp->page) ? PGNO_INVALID : PGNO(cp->page), + ISINTERNAL(cp->page) ? PGNO_INVALID : NEXT_PGNO(cp->page), + cp->page->level, TYPE(cp->page)); + + /* + * Create new left page for the split, and fill in everything + * except its LSN and next-page page number. + */ + if ((ret = __os_malloc(dbp->dbenv, dbp->pgsize, NULL, &lp)) != 0) + goto err; + P_INIT(lp, dbp->pgsize, PGNO(cp->page), + ISINTERNAL(cp->page) ? PGNO_INVALID : PREV_PGNO(cp->page), + ISINTERNAL(cp->page) ? PGNO_INVALID : 0, + cp->page->level, TYPE(cp->page)); + + /* + * Split right. + * + * Only the indices are sorted on the page, i.e., the key/data pairs + * aren't, so it's simpler to copy the data from the split page onto + * two new pages instead of copying half the data to a new right page + * and compacting the left page in place. Since the left page can't + * change, we swap the original and the allocated left page after the + * split. + */ + if ((ret = __bam_psplit(dbc, cp, lp, rp, &split)) != 0) + goto err; + + /* + * Test to see if we are going to be able to insert the new pages into + * the parent page. The interesting failure here is that the parent + * page can't hold the new keys, and has to be split in turn, in which + * case we want to release all the locks we can. + */ + if ((ret = __bam_pinsert(dbc, pp, lp, rp, 1)) != 0) + goto err; + + /* + * Fix up the previous pointer of any leaf page following the split + * page. + * + * There's interesting deadlock situations here as we try to write-lock + * a page that's not in our direct ancestry. Consider a cursor walking + * backward through the leaf pages, that has our following page locked, + * and is waiting on a lock for the page we're splitting. In that case + * we're going to deadlock here . It's probably OK, stepping backward + * through the tree isn't a common operation. + */ + if (ISLEAF(cp->page) && NEXT_PGNO(cp->page) != PGNO_INVALID) { + if ((ret = __db_lget(dbc, + 0, NEXT_PGNO(cp->page), DB_LOCK_WRITE, 0, &tplock)) != 0) + goto err; + if ((ret = + memp_fget(dbp->mpf, &NEXT_PGNO(cp->page), 0, &tp)) != 0) + goto err; + } + + /* + * We've got everything locked down we need, and we know the split + * is going to succeed. Go and get the additional page we'll need. + */ + if ((ret = __db_new(dbc, TYPE(cp->page), &alloc_rp)) != 0) + goto err; + + /* + * Fix up the page numbers we didn't have before. We have to do this + * before calling __bam_pinsert because it may copy a page number onto + * the parent page and it takes the page number from its page argument. + */ + PGNO(rp) = NEXT_PGNO(lp) = PGNO(alloc_rp); + + /* Actually update the parent page. */ + if ((ret = __bam_pinsert(dbc, pp, lp, rp, 0)) != 0) + goto err; + + bc = (BTREE_CURSOR *)dbc->internal; + /* Log the change. */ + if (DB_LOGGING(dbc)) { + memset(&log_dbt, 0, sizeof(log_dbt)); + log_dbt.data = cp->page; + log_dbt.size = dbp->pgsize; + if (tp == NULL) + ZERO_LSN(log_lsn); + opflags = F_ISSET(bc, C_RECNUM) ? SPL_NRECS : 0; + if ((ret = __bam_split_log(dbp->dbenv, dbc->txn, + &LSN(cp->page), 0, dbp->log_fileid, PGNO(cp->page), + &LSN(cp->page), PGNO(alloc_rp), &LSN(alloc_rp), + (u_int32_t)NUM_ENT(lp), + tp == NULL ? 0 : PGNO(tp), + tp == NULL ? &log_lsn : &LSN(tp), + bc->root, &log_dbt, opflags)) != 0) + goto err; + + /* Update the LSNs for all involved pages. */ + LSN(alloc_rp) = LSN(cp->page); + LSN(lp) = LSN(cp->page); + LSN(rp) = LSN(cp->page); + if (tp != NULL) + LSN(tp) = LSN(cp->page); + } + + /* + * Copy the left and right pages into place. There are two paths + * through here. Either we are logging and we set the LSNs in the + * logging path. However, if we are not logging, then we do not + * have valid LSNs on lp or rp. The correct LSNs to use are the + * ones on the page we got from __db_new or the one that was + * originally on cp->page. In both cases, we save the LSN from the + * real database page (not a malloc'd one) and reapply it after we + * do the copy. + */ + save_lsn = alloc_rp->lsn; + memcpy(alloc_rp, rp, LOFFSET(rp)); + memcpy((u_int8_t *)alloc_rp + HOFFSET(rp), + (u_int8_t *)rp + HOFFSET(rp), dbp->pgsize - HOFFSET(rp)); + alloc_rp->lsn = save_lsn; + + save_lsn = cp->page->lsn; + memcpy(cp->page, lp, LOFFSET(lp)); + memcpy((u_int8_t *)cp->page + HOFFSET(lp), + (u_int8_t *)lp + HOFFSET(lp), dbp->pgsize - HOFFSET(lp)); + cp->page->lsn = save_lsn; + + /* Fix up the next-page link. */ + if (tp != NULL) + PREV_PGNO(tp) = PGNO(rp); + + /* Adjust any cursors. */ + if ((ret = __bam_ca_split(dbc, + PGNO(cp->page), PGNO(cp->page), PGNO(rp), split, 0)) != 0) + goto err; + + __os_free(lp, dbp->pgsize); + __os_free(rp, dbp->pgsize); + + /* + * Success -- write the real pages back to the store. As we never + * acquired any sort of lock on the new page, we release it before + * releasing locks on the pages that reference it. We're finished + * modifying the page so it's not really necessary, but it's neater. + */ + if ((t_ret = + memp_fput(dbp->mpf, alloc_rp, DB_MPOOL_DIRTY)) != 0 && ret == 0) + ret = t_ret; + if ((t_ret = + memp_fput(dbp->mpf, pp->page, DB_MPOOL_DIRTY)) != 0 && ret == 0) + ret = t_ret; + (void)__TLPUT(dbc, pp->lock); + if ((t_ret = + memp_fput(dbp->mpf, cp->page, DB_MPOOL_DIRTY)) != 0 && ret == 0) + ret = t_ret; + (void)__TLPUT(dbc, cp->lock); + if (tp != NULL) { + if ((t_ret = + memp_fput(dbp->mpf, tp, DB_MPOOL_DIRTY)) != 0 && ret == 0) + ret = t_ret; + (void)__TLPUT(dbc, tplock); + } + return (ret); + +err: if (lp != NULL) + __os_free(lp, dbp->pgsize); + if (rp != NULL) + __os_free(rp, dbp->pgsize); + if (alloc_rp != NULL) + (void)__db_free(dbc, alloc_rp); + + if (tp != NULL) + (void)memp_fput(dbp->mpf, tp, 0); + if (tplock.off != LOCK_INVALID) + /* We never updated the next page, we can release it. */ + (void)__LPUT(dbc, tplock); + + (void)memp_fput(dbp->mpf, pp->page, 0); + if (ret == DB_NEEDSPLIT) + (void)__LPUT(dbc, pp->lock); + else + (void)__TLPUT(dbc, pp->lock); + + (void)memp_fput(dbp->mpf, cp->page, 0); + if (ret == DB_NEEDSPLIT) + (void)__LPUT(dbc, cp->lock); + else + (void)__TLPUT(dbc, cp->lock); + + return (ret); +} + +/* + * __bam_broot -- + * Fix up the btree root page after it has been split. + */ +static int +__bam_broot(dbc, rootp, lp, rp) + DBC *dbc; + PAGE *rootp, *lp, *rp; +{ + BINTERNAL bi, *child_bi; + BKEYDATA *child_bk; + BTREE_CURSOR *cp; + DB *dbp; + DBT hdr, data; + db_pgno_t root_pgno; + int ret; + + dbp = dbc->dbp; + cp = (BTREE_CURSOR *)dbc->internal; + + /* + * If the root page was a leaf page, change it into an internal page. + * We copy the key we split on (but not the key's data, in the case of + * a leaf page) to the new root page. + */ + root_pgno = cp->root; + P_INIT(rootp, dbp->pgsize, + root_pgno, PGNO_INVALID, PGNO_INVALID, lp->level + 1, P_IBTREE); + + memset(&data, 0, sizeof(data)); + memset(&hdr, 0, sizeof(hdr)); + + /* + * The btree comparison code guarantees that the left-most key on any + * internal btree page is never used, so it doesn't need to be filled + * in. Set the record count if necessary. + */ + memset(&bi, 0, sizeof(bi)); + bi.len = 0; + B_TSET(bi.type, B_KEYDATA, 0); + bi.pgno = lp->pgno; + if (F_ISSET(cp, C_RECNUM)) { + bi.nrecs = __bam_total(lp); + RE_NREC_SET(rootp, bi.nrecs); + } + hdr.data = &bi; + hdr.size = SSZA(BINTERNAL, data); + if ((ret = + __db_pitem(dbc, rootp, 0, BINTERNAL_SIZE(0), &hdr, NULL)) != 0) + return (ret); + + switch (TYPE(rp)) { + case P_IBTREE: + /* Copy the first key of the child page onto the root page. */ + child_bi = GET_BINTERNAL(rp, 0); + + bi.len = child_bi->len; + B_TSET(bi.type, child_bi->type, 0); + bi.pgno = rp->pgno; + if (F_ISSET(cp, C_RECNUM)) { + bi.nrecs = __bam_total(rp); + RE_NREC_ADJ(rootp, bi.nrecs); + } + hdr.data = &bi; + hdr.size = SSZA(BINTERNAL, data); + data.data = child_bi->data; + data.size = child_bi->len; + if ((ret = __db_pitem(dbc, rootp, 1, + BINTERNAL_SIZE(child_bi->len), &hdr, &data)) != 0) + return (ret); + + /* Increment the overflow ref count. */ + if (B_TYPE(child_bi->type) == B_OVERFLOW) + if ((ret = __db_ovref(dbc, + ((BOVERFLOW *)(child_bi->data))->pgno, 1)) != 0) + return (ret); + break; + case P_LDUP: + case P_LBTREE: + /* Copy the first key of the child page onto the root page. */ + child_bk = GET_BKEYDATA(rp, 0); + switch (B_TYPE(child_bk->type)) { + case B_KEYDATA: + bi.len = child_bk->len; + B_TSET(bi.type, child_bk->type, 0); + bi.pgno = rp->pgno; + if (F_ISSET(cp, C_RECNUM)) { + bi.nrecs = __bam_total(rp); + RE_NREC_ADJ(rootp, bi.nrecs); + } + hdr.data = &bi; + hdr.size = SSZA(BINTERNAL, data); + data.data = child_bk->data; + data.size = child_bk->len; + if ((ret = __db_pitem(dbc, rootp, 1, + BINTERNAL_SIZE(child_bk->len), &hdr, &data)) != 0) + return (ret); + break; + case B_DUPLICATE: + case B_OVERFLOW: + bi.len = BOVERFLOW_SIZE; + B_TSET(bi.type, child_bk->type, 0); + bi.pgno = rp->pgno; + if (F_ISSET(cp, C_RECNUM)) { + bi.nrecs = __bam_total(rp); + RE_NREC_ADJ(rootp, bi.nrecs); + } + hdr.data = &bi; + hdr.size = SSZA(BINTERNAL, data); + data.data = child_bk; + data.size = BOVERFLOW_SIZE; + if ((ret = __db_pitem(dbc, rootp, 1, + BINTERNAL_SIZE(BOVERFLOW_SIZE), &hdr, &data)) != 0) + return (ret); + + /* Increment the overflow ref count. */ + if (B_TYPE(child_bk->type) == B_OVERFLOW) + if ((ret = __db_ovref(dbc, + ((BOVERFLOW *)child_bk)->pgno, 1)) != 0) + return (ret); + break; + default: + return (__db_pgfmt(dbp, rp->pgno)); + } + break; + default: + return (__db_pgfmt(dbp, rp->pgno)); + } + return (0); +} + +/* + * __ram_root -- + * Fix up the recno root page after it has been split. + */ +static int +__ram_root(dbc, rootp, lp, rp) + DBC *dbc; + PAGE *rootp, *lp, *rp; +{ + DB *dbp; + DBT hdr; + RINTERNAL ri; + db_pgno_t root_pgno; + int ret; + + dbp = dbc->dbp; + root_pgno = dbc->internal->root; + + /* Initialize the page. */ + P_INIT(rootp, dbp->pgsize, + root_pgno, PGNO_INVALID, PGNO_INVALID, lp->level + 1, P_IRECNO); + + /* Initialize the header. */ + memset(&hdr, 0, sizeof(hdr)); + hdr.data = &ri; + hdr.size = RINTERNAL_SIZE; + + /* Insert the left and right keys, set the header information. */ + ri.pgno = lp->pgno; + ri.nrecs = __bam_total(lp); + if ((ret = __db_pitem(dbc, rootp, 0, RINTERNAL_SIZE, &hdr, NULL)) != 0) + return (ret); + RE_NREC_SET(rootp, ri.nrecs); + ri.pgno = rp->pgno; + ri.nrecs = __bam_total(rp); + if ((ret = __db_pitem(dbc, rootp, 1, RINTERNAL_SIZE, &hdr, NULL)) != 0) + return (ret); + RE_NREC_ADJ(rootp, ri.nrecs); + return (0); +} + +/* + * __bam_pinsert -- + * Insert a new key into a parent page, completing the split. + */ +static int +__bam_pinsert(dbc, parent, lchild, rchild, space_check) + DBC *dbc; + EPG *parent; + PAGE *lchild, *rchild; + int space_check; +{ + BINTERNAL bi, *child_bi; + BKEYDATA *child_bk, *tmp_bk; + BTREE *t; + BTREE_CURSOR *cp; + DB *dbp; + DBT a, b, hdr, data; + PAGE *ppage; + RINTERNAL ri; + db_indx_t off; + db_recno_t nrecs; + size_t (*func) __P((DB *, const DBT *, const DBT *)); + u_int32_t n, nbytes, nksize; + int ret; + + dbp = dbc->dbp; + cp = (BTREE_CURSOR *)dbc->internal; + t = dbp->bt_internal; + ppage = parent->page; + + /* If handling record numbers, count records split to the right page. */ + nrecs = F_ISSET(cp, C_RECNUM) && !space_check ? __bam_total(rchild) : 0; + + /* + * Now we insert the new page's first key into the parent page, which + * completes the split. The parent points to a PAGE and a page index + * offset, where the new key goes ONE AFTER the index, because we split + * to the right. + * + * XXX + * Some btree algorithms replace the key for the old page as well as + * the new page. We don't, as there's no reason to believe that the + * first key on the old page is any better than the key we have, and, + * in the case of a key being placed at index 0 causing the split, the + * key is unavailable. + */ + off = parent->indx + O_INDX; + + /* + * Calculate the space needed on the parent page. + * + * Prefix trees: space hack used when inserting into BINTERNAL pages. + * Retain only what's needed to distinguish between the new entry and + * the LAST entry on the page to its left. If the keys compare equal, + * retain the entire key. We ignore overflow keys, and the entire key + * must be retained for the next-to-leftmost key on the leftmost page + * of each level, or the search will fail. Applicable ONLY to internal + * pages that have leaf pages as children. Further reduction of the + * key between pairs of internal pages loses too much information. + */ + switch (TYPE(rchild)) { + case P_IBTREE: + child_bi = GET_BINTERNAL(rchild, 0); + nbytes = BINTERNAL_PSIZE(child_bi->len); + + if (P_FREESPACE(ppage) < nbytes) + return (DB_NEEDSPLIT); + if (space_check) + return (0); + + /* Add a new record for the right page. */ + memset(&bi, 0, sizeof(bi)); + bi.len = child_bi->len; + B_TSET(bi.type, child_bi->type, 0); + bi.pgno = rchild->pgno; + bi.nrecs = nrecs; + memset(&hdr, 0, sizeof(hdr)); + hdr.data = &bi; + hdr.size = SSZA(BINTERNAL, data); + memset(&data, 0, sizeof(data)); + data.data = child_bi->data; + data.size = child_bi->len; + if ((ret = __db_pitem(dbc, ppage, off, + BINTERNAL_SIZE(child_bi->len), &hdr, &data)) != 0) + return (ret); + + /* Increment the overflow ref count. */ + if (B_TYPE(child_bi->type) == B_OVERFLOW) + if ((ret = __db_ovref(dbc, + ((BOVERFLOW *)(child_bi->data))->pgno, 1)) != 0) + return (ret); + break; + case P_LDUP: + case P_LBTREE: + child_bk = GET_BKEYDATA(rchild, 0); + switch (B_TYPE(child_bk->type)) { + case B_KEYDATA: + /* + * We set t->bt_prefix to NULL if we have a comparison + * callback but no prefix compression callback. But, + * if we're splitting in an off-page duplicates tree, + * we still have to do some checking. If using the + * default off-page duplicates comparison routine we + * can use the default prefix compression callback. If + * not using the default off-page duplicates comparison + * routine, we can't do any kind of prefix compression + * as there's no way for an application to specify a + * prefix compression callback that corresponds to its + * comparison callback. + */ + if (F_ISSET(dbc, DBC_OPD)) { + if (dbp->dup_compare == __bam_defcmp) + func = __bam_defpfx; + else + func = NULL; + } else + func = t->bt_prefix; + + nbytes = BINTERNAL_PSIZE(child_bk->len); + nksize = child_bk->len; + if (func == NULL) + goto noprefix; + if (ppage->prev_pgno == PGNO_INVALID && off <= 1) + goto noprefix; + tmp_bk = GET_BKEYDATA(lchild, NUM_ENT(lchild) - + (TYPE(lchild) == P_LDUP ? O_INDX : P_INDX)); + if (B_TYPE(tmp_bk->type) != B_KEYDATA) + goto noprefix; + memset(&a, 0, sizeof(a)); + a.size = tmp_bk->len; + a.data = tmp_bk->data; + memset(&b, 0, sizeof(b)); + b.size = child_bk->len; + b.data = child_bk->data; + nksize = func(dbp, &a, &b); + if ((n = BINTERNAL_PSIZE(nksize)) < nbytes) + nbytes = n; + else +noprefix: nksize = child_bk->len; + + if (P_FREESPACE(ppage) < nbytes) + return (DB_NEEDSPLIT); + if (space_check) + return (0); + + memset(&bi, 0, sizeof(bi)); + bi.len = nksize; + B_TSET(bi.type, child_bk->type, 0); + bi.pgno = rchild->pgno; + bi.nrecs = nrecs; + memset(&hdr, 0, sizeof(hdr)); + hdr.data = &bi; + hdr.size = SSZA(BINTERNAL, data); + memset(&data, 0, sizeof(data)); + data.data = child_bk->data; + data.size = nksize; + if ((ret = __db_pitem(dbc, ppage, off, + BINTERNAL_SIZE(nksize), &hdr, &data)) != 0) + return (ret); + break; + case B_DUPLICATE: + case B_OVERFLOW: + nbytes = BINTERNAL_PSIZE(BOVERFLOW_SIZE); + + if (P_FREESPACE(ppage) < nbytes) + return (DB_NEEDSPLIT); + if (space_check) + return (0); + + memset(&bi, 0, sizeof(bi)); + bi.len = BOVERFLOW_SIZE; + B_TSET(bi.type, child_bk->type, 0); + bi.pgno = rchild->pgno; + bi.nrecs = nrecs; + memset(&hdr, 0, sizeof(hdr)); + hdr.data = &bi; + hdr.size = SSZA(BINTERNAL, data); + memset(&data, 0, sizeof(data)); + data.data = child_bk; + data.size = BOVERFLOW_SIZE; + if ((ret = __db_pitem(dbc, ppage, off, + BINTERNAL_SIZE(BOVERFLOW_SIZE), &hdr, &data)) != 0) + return (ret); + + /* Increment the overflow ref count. */ + if (B_TYPE(child_bk->type) == B_OVERFLOW) + if ((ret = __db_ovref(dbc, + ((BOVERFLOW *)child_bk)->pgno, 1)) != 0) + return (ret); + break; + default: + return (__db_pgfmt(dbp, rchild->pgno)); + } + break; + case P_IRECNO: + case P_LRECNO: + nbytes = RINTERNAL_PSIZE; + + if (P_FREESPACE(ppage) < nbytes) + return (DB_NEEDSPLIT); + if (space_check) + return (0); + + /* Add a new record for the right page. */ + memset(&hdr, 0, sizeof(hdr)); + hdr.data = &ri; + hdr.size = RINTERNAL_SIZE; + ri.pgno = rchild->pgno; + ri.nrecs = nrecs; + if ((ret = __db_pitem(dbc, + ppage, off, RINTERNAL_SIZE, &hdr, NULL)) != 0) + return (ret); + break; + default: + return (__db_pgfmt(dbp, rchild->pgno)); + } + + /* + * If a Recno or Btree with record numbers AM page, or an off-page + * duplicates tree, adjust the parent page's left page record count. + */ + if (F_ISSET(cp, C_RECNUM)) { + /* Log the change. */ + if (DB_LOGGING(dbc) && + (ret = __bam_cadjust_log(dbp->dbenv, dbc->txn, + &LSN(ppage), 0, dbp->log_fileid, PGNO(ppage), + &LSN(ppage), parent->indx, -(int32_t)nrecs, 0)) != 0) + return (ret); + + /* Update the left page count. */ + if (dbc->dbtype == DB_RECNO) + GET_RINTERNAL(ppage, parent->indx)->nrecs -= nrecs; + else + GET_BINTERNAL(ppage, parent->indx)->nrecs -= nrecs; + } + + return (0); +} + +/* + * __bam_psplit -- + * Do the real work of splitting the page. + */ +static int +__bam_psplit(dbc, cp, lp, rp, splitret) + DBC *dbc; + EPG *cp; + PAGE *lp, *rp; + db_indx_t *splitret; +{ + DB *dbp; + PAGE *pp; + db_indx_t half, nbytes, off, splitp, top; + int adjust, cnt, iflag, isbigkey, ret; + + dbp = dbc->dbp; + pp = cp->page; + adjust = TYPE(pp) == P_LBTREE ? P_INDX : O_INDX; + + /* + * If we're splitting the first (last) page on a level because we're + * inserting (appending) a key to it, it's likely that the data is + * sorted. Moving a single item to the new page is less work and can + * push the fill factor higher than normal. If we're wrong it's not + * a big deal, we'll just do the split the right way next time. + */ + off = 0; + if (NEXT_PGNO(pp) == PGNO_INVALID && + ((ISINTERNAL(pp) && cp->indx == NUM_ENT(cp->page) - 1) || + (!ISINTERNAL(pp) && cp->indx == NUM_ENT(cp->page)))) + off = NUM_ENT(cp->page) - adjust; + else if (PREV_PGNO(pp) == PGNO_INVALID && cp->indx == 0) + off = adjust; + + if (off != 0) + goto sort; + + /* + * Split the data to the left and right pages. Try not to split on + * an overflow key. (Overflow keys on internal pages will slow down + * searches.) Refuse to split in the middle of a set of duplicates. + * + * First, find the optimum place to split. + * + * It's possible to try and split past the last record on the page if + * there's a very large record at the end of the page. Make sure this + * doesn't happen by bounding the check at the next-to-last entry on + * the page. + * + * Note, we try and split half the data present on the page. This is + * because another process may have already split the page and left + * it half empty. We don't try and skip the split -- we don't know + * how much space we're going to need on the page, and we may need up + * to half the page for a big item, so there's no easy test to decide + * if we need to split or not. Besides, if two threads are inserting + * data into the same place in the database, we're probably going to + * need more space soon anyway. + */ + top = NUM_ENT(pp) - adjust; + half = (dbp->pgsize - HOFFSET(pp)) / 2; + for (nbytes = 0, off = 0; off < top && nbytes < half; ++off) + switch (TYPE(pp)) { + case P_IBTREE: + if (B_TYPE(GET_BINTERNAL(pp, off)->type) == B_KEYDATA) + nbytes += + BINTERNAL_SIZE(GET_BINTERNAL(pp, off)->len); + else + nbytes += BINTERNAL_SIZE(BOVERFLOW_SIZE); + break; + case P_LBTREE: + if (B_TYPE(GET_BKEYDATA(pp, off)->type) == B_KEYDATA) + nbytes += + BKEYDATA_SIZE(GET_BKEYDATA(pp, off)->len); + else + nbytes += BOVERFLOW_SIZE; + + ++off; + /* FALLTHROUGH */ + case P_LDUP: + case P_LRECNO: + if (B_TYPE(GET_BKEYDATA(pp, off)->type) == B_KEYDATA) + nbytes += + BKEYDATA_SIZE(GET_BKEYDATA(pp, off)->len); + else + nbytes += BOVERFLOW_SIZE; + break; + case P_IRECNO: + nbytes += RINTERNAL_SIZE; + break; + default: + return (__db_pgfmt(dbp, pp->pgno)); + } +sort: splitp = off; + + /* + * Splitp is either at or just past the optimum split point. If the + * tree type is such that we're going to promote a key to an internal + * page, and our current choice is an overflow key, look for something + * close by that's smaller. + */ + switch (TYPE(pp)) { + case P_IBTREE: + iflag = 1; + isbigkey = B_TYPE(GET_BINTERNAL(pp, off)->type) != B_KEYDATA; + break; + case P_LBTREE: + case P_LDUP: + iflag = 0; + isbigkey = B_TYPE(GET_BKEYDATA(pp, off)->type) != B_KEYDATA; + break; + default: + iflag = isbigkey = 0; + } + if (isbigkey) + for (cnt = 1; cnt <= 3; ++cnt) { + off = splitp + cnt * adjust; + if (off < (db_indx_t)NUM_ENT(pp) && + ((iflag && + B_TYPE(GET_BINTERNAL(pp,off)->type) == B_KEYDATA) || + B_TYPE(GET_BKEYDATA(pp, off)->type) == B_KEYDATA)) { + splitp = off; + break; + } + if (splitp <= (db_indx_t)(cnt * adjust)) + continue; + off = splitp - cnt * adjust; + if (iflag ? + B_TYPE(GET_BINTERNAL(pp, off)->type) == B_KEYDATA : + B_TYPE(GET_BKEYDATA(pp, off)->type) == B_KEYDATA) { + splitp = off; + break; + } + } + + /* + * We can't split in the middle a set of duplicates. We know that + * no duplicate set can take up more than about 25% of the page, + * because that's the point where we push it off onto a duplicate + * page set. So, this loop can't be unbounded. + */ + if (TYPE(pp) == P_LBTREE && + pp->inp[splitp] == pp->inp[splitp - adjust]) + for (cnt = 1;; ++cnt) { + off = splitp + cnt * adjust; + if (off < NUM_ENT(pp) && + pp->inp[splitp] != pp->inp[off]) { + splitp = off; + break; + } + if (splitp <= (db_indx_t)(cnt * adjust)) + continue; + off = splitp - cnt * adjust; + if (pp->inp[splitp] != pp->inp[off]) { + splitp = off + adjust; + break; + } + } + + /* We're going to split at splitp. */ + if ((ret = __bam_copy(dbp, pp, lp, 0, splitp)) != 0) + return (ret); + if ((ret = __bam_copy(dbp, pp, rp, splitp, NUM_ENT(pp))) != 0) + return (ret); + + *splitret = splitp; + return (0); +} + +/* + * __bam_copy -- + * Copy a set of records from one page to another. + * + * PUBLIC: int __bam_copy __P((DB *, PAGE *, PAGE *, u_int32_t, u_int32_t)); + */ +int +__bam_copy(dbp, pp, cp, nxt, stop) + DB *dbp; + PAGE *pp, *cp; + u_int32_t nxt, stop; +{ + db_indx_t nbytes, off; + + /* + * Copy the rest of the data to the right page. Nxt is the next + * offset placed on the target page. + */ + for (off = 0; nxt < stop; ++nxt, ++NUM_ENT(cp), ++off) { + switch (TYPE(pp)) { + case P_IBTREE: + if (B_TYPE(GET_BINTERNAL(pp, nxt)->type) == B_KEYDATA) + nbytes = + BINTERNAL_SIZE(GET_BINTERNAL(pp, nxt)->len); + else + nbytes = BINTERNAL_SIZE(BOVERFLOW_SIZE); + break; + case P_LBTREE: + /* + * If we're on a key and it's a duplicate, just copy + * the offset. + */ + if (off != 0 && (nxt % P_INDX) == 0 && + pp->inp[nxt] == pp->inp[nxt - P_INDX]) { + cp->inp[off] = cp->inp[off - P_INDX]; + continue; + } + /* FALLTHROUGH */ + case P_LDUP: + case P_LRECNO: + if (B_TYPE(GET_BKEYDATA(pp, nxt)->type) == B_KEYDATA) + nbytes = + BKEYDATA_SIZE(GET_BKEYDATA(pp, nxt)->len); + else + nbytes = BOVERFLOW_SIZE; + break; + case P_IRECNO: + nbytes = RINTERNAL_SIZE; + break; + default: + return (__db_pgfmt(dbp, pp->pgno)); + } + cp->inp[off] = HOFFSET(cp) -= nbytes; + memcpy(P_ENTRY(cp, off), P_ENTRY(pp, nxt), nbytes); + } + return (0); +} diff --git a/db/btree/bt_stat.c b/db/btree/bt_stat.c new file mode 100644 index 000000000..349bb40cf --- /dev/null +++ b/db/btree/bt_stat.c @@ -0,0 +1,480 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: bt_stat.c,v 11.29 2000/11/28 21:42:27 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_shash.h" +#include "lock.h" +#include "btree.h" + +/* + * __bam_stat -- + * Gather/print the btree statistics + * + * PUBLIC: int __bam_stat __P((DB *, void *, void *(*)(size_t), u_int32_t)); + */ +int +__bam_stat(dbp, spp, db_malloc, flags) + DB *dbp; + void *spp; + void *(*db_malloc) __P((size_t)); + u_int32_t flags; +{ + BTMETA *meta; + BTREE *t; + BTREE_CURSOR *cp; + DBC *dbc; + DB_BTREE_STAT *sp; + DB_LOCK lock, metalock; + PAGE *h; + db_pgno_t pgno; + int ret, t_ret; + + PANIC_CHECK(dbp->dbenv); + DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->stat"); + + meta = NULL; + t = dbp->bt_internal; + sp = NULL; + metalock.off = lock.off = LOCK_INVALID; + h = NULL; + ret = 0; + + /* Check for invalid flags. */ + if ((ret = __db_statchk(dbp, flags)) != 0) + return (ret); + + /* Acquire a cursor. */ + if ((ret = dbp->cursor(dbp, NULL, &dbc, 0)) != 0) + return (ret); + cp = (BTREE_CURSOR *)dbc->internal; + + DEBUG_LWRITE(dbc, NULL, "bam_stat", NULL, NULL, flags); + + /* Allocate and clear the structure. */ + if ((ret = __os_malloc(dbp->dbenv, sizeof(*sp), db_malloc, &sp)) != 0) + goto err; + memset(sp, 0, sizeof(*sp)); + + /* If the app just wants the record count, make it fast. */ + if (flags == DB_RECORDCOUNT) { + if ((ret = __db_lget(dbc, 0, + cp->root, DB_LOCK_READ, 0, &lock)) != 0) + goto err; + if ((ret = memp_fget(dbp->mpf, + &cp->root, 0, (PAGE **)&h)) != 0) + goto err; + + sp->bt_nkeys = RE_NREC(h); + + goto done; + } + if (flags == DB_CACHED_COUNTS) { + if ((ret = __db_lget(dbc, + 0, t->bt_meta, DB_LOCK_READ, 0, &lock)) != 0) + goto err; + if ((ret = + memp_fget(dbp->mpf, &t->bt_meta, 0, (PAGE **)&meta)) != 0) + goto err; + sp->bt_nkeys = meta->dbmeta.key_count; + sp->bt_ndata = meta->dbmeta.record_count; + + goto done; + } + + /* Get the metadata page for the entire database. */ + pgno = PGNO_BASE_MD; + if ((ret = __db_lget(dbc, 0, pgno, DB_LOCK_READ, 0, &metalock)) != 0) + goto err; + if ((ret = memp_fget(dbp->mpf, &pgno, 0, (PAGE **)&meta)) != 0) + goto err; + + /* Walk the metadata free list, counting pages. */ + for (sp->bt_free = 0, pgno = meta->dbmeta.free; pgno != PGNO_INVALID;) { + ++sp->bt_free; + + if ((ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) + goto err; + + pgno = h->next_pgno; + if ((ret = memp_fput(dbp->mpf, h, 0)) != 0) + goto err; + h = NULL; + } + + /* Get the root page. */ + pgno = cp->root; + if ((ret = __db_lget(dbc, 0, pgno, DB_LOCK_READ, 0, &lock)) != 0) + goto err; + if ((ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) + goto err; + + /* Get the levels from the root page. */ + sp->bt_levels = h->level; + + /* Discard the root page. */ + if ((ret = memp_fput(dbp->mpf, h, 0)) != 0) + goto err; + h = NULL; + __LPUT(dbc, lock); + + /* Walk the tree. */ + if ((ret = __bam_traverse(dbc, + DB_LOCK_READ, cp->root, __bam_stat_callback, sp)) != 0) + goto err; + + /* + * Get the subdatabase metadata page if it's not the same as the + * one we already have. + */ + if (t->bt_meta != PGNO_BASE_MD || !F_ISSET(dbp, DB_AM_RDONLY)) { + if ((ret = memp_fput(dbp->mpf, meta, 0)) != 0) + goto err; + meta = NULL; + __LPUT(dbc, metalock); + + if ((ret = __db_lget(dbc, + 0, t->bt_meta, F_ISSET(dbp, DB_AM_RDONLY) ? + DB_LOCK_READ : DB_LOCK_WRITE, 0, &metalock)) != 0) + goto err; + if ((ret = + memp_fget(dbp->mpf, &t->bt_meta, 0, (PAGE **)&meta)) != 0) + goto err; + } + + /* Get metadata page statistics. */ + sp->bt_metaflags = meta->dbmeta.flags; + sp->bt_maxkey = meta->maxkey; + sp->bt_minkey = meta->minkey; + sp->bt_re_len = meta->re_len; + sp->bt_re_pad = meta->re_pad; + sp->bt_pagesize = meta->dbmeta.pagesize; + sp->bt_magic = meta->dbmeta.magic; + sp->bt_version = meta->dbmeta.version; + if (!F_ISSET(dbp, DB_AM_RDONLY)) { + meta->dbmeta.key_count = sp->bt_nkeys; + meta->dbmeta.record_count = sp->bt_ndata; + } + + /* Discard the metadata page. */ + if ((ret = memp_fput(dbp->mpf, + meta, F_ISSET(dbp, DB_AM_RDONLY) ? 0 : DB_MPOOL_DIRTY)) != 0) + goto err; + meta = NULL; + __LPUT(dbc, metalock); + +done: *(DB_BTREE_STAT **)spp = sp; + + if (0) { +err: if (sp != NULL) + __os_free(sp, sizeof(*sp)); + } + + if (h != NULL && + (t_ret = memp_fput(dbp->mpf, h, 0)) != 0 && ret == 0) + ret = t_ret; + + if (meta != NULL && + (t_ret = memp_fput(dbp->mpf, meta, 0)) != 0 && ret == 0) + ret = t_ret; + + if (lock.off != LOCK_INVALID) + __LPUT(dbc, lock); + + if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0) + ret = t_ret; + + return (ret); +} + +/* + * __bam_traverse -- + * Walk a Btree database. + * + * PUBLIC: int __bam_traverse __P((DBC *, db_lockmode_t, + * PUBLIC: db_pgno_t, int (*)(DB *, PAGE *, void *, int *), void *)); + */ +int +__bam_traverse(dbc, mode, root_pgno, callback, cookie) + DBC *dbc; + db_lockmode_t mode; + db_pgno_t root_pgno; + int (*callback)__P((DB *, PAGE *, void *, int *)); + void *cookie; +{ + BINTERNAL *bi; + BKEYDATA *bk; + DB *dbp; + DB_LOCK lock; + PAGE *h; + RINTERNAL *ri; + db_indx_t indx; + int already_put, ret, t_ret; + + dbp = dbc->dbp; + + if ((ret = __db_lget(dbc, 0, root_pgno, mode, 0, &lock)) != 0) + return (ret); + if ((ret = memp_fget(dbp->mpf, &root_pgno, 0, &h)) != 0) + goto err; + + switch (TYPE(h)) { + case P_IBTREE: + for (indx = 0; indx < NUM_ENT(h); indx += O_INDX) { + bi = GET_BINTERNAL(h, indx); + if (B_TYPE(bi->type) == B_OVERFLOW && + (ret = __db_traverse_big(dbp, + ((BOVERFLOW *)bi->data)->pgno, + callback, cookie)) != 0) + goto err; + if ((ret = __bam_traverse( + dbc, mode, bi->pgno, callback, cookie)) != 0) + break; + } + break; + case P_IRECNO: + for (indx = 0; indx < NUM_ENT(h); indx += O_INDX) { + ri = GET_RINTERNAL(h, indx); + if ((ret = __bam_traverse( + dbc, mode, ri->pgno, callback, cookie)) != 0) + break; + } + break; + case P_LBTREE: + for (indx = 0; indx < NUM_ENT(h); indx += P_INDX) { + bk = GET_BKEYDATA(h, indx); + if (B_TYPE(bk->type) == B_OVERFLOW && + (ret = __db_traverse_big(dbp, + GET_BOVERFLOW(h, indx)->pgno, + callback, cookie)) != 0) + goto err; + bk = GET_BKEYDATA(h, indx + O_INDX); + if (B_TYPE(bk->type) == B_DUPLICATE && + (ret = __bam_traverse(dbc, mode, + GET_BOVERFLOW(h, indx + O_INDX)->pgno, + callback, cookie)) != 0) + goto err; + if (B_TYPE(bk->type) == B_OVERFLOW && + (ret = __db_traverse_big(dbp, + GET_BOVERFLOW(h, indx + O_INDX)->pgno, + callback, cookie)) != 0) + goto err; + } + break; + case P_LDUP: + case P_LRECNO: + for (indx = 0; indx < NUM_ENT(h); indx += O_INDX) { + bk = GET_BKEYDATA(h, indx); + if (B_TYPE(bk->type) == B_OVERFLOW && + (ret = __db_traverse_big(dbp, + GET_BOVERFLOW(h, indx)->pgno, + callback, cookie)) != 0) + goto err; + } + break; + } + + already_put = 0; + if ((ret = callback(dbp, h, cookie, &already_put)) != 0) + goto err; + +err: if (!already_put && + (t_ret = memp_fput(dbp->mpf, h, 0)) != 0 && ret != 0) + ret = t_ret; + __LPUT(dbc, lock); + + return (ret); +} + +/* + * __bam_stat_callback -- + * Statistics callback. + * + * PUBLIC: int __bam_stat_callback __P((DB *, PAGE *, void *, int *)); + */ +int +__bam_stat_callback(dbp, h, cookie, putp) + DB *dbp; + PAGE *h; + void *cookie; + int *putp; +{ + DB_BTREE_STAT *sp; + db_indx_t indx, top; + u_int8_t type; + + sp = cookie; + *putp = 0; + top = NUM_ENT(h); + + switch (TYPE(h)) { + case P_IBTREE: + case P_IRECNO: + ++sp->bt_int_pg; + sp->bt_int_pgfree += P_FREESPACE(h); + break; + case P_LBTREE: + /* Correct for on-page duplicates and deleted items. */ + for (indx = 0; indx < top; indx += P_INDX) { + if (indx + P_INDX >= top || + h->inp[indx] != h->inp[indx + P_INDX]) + ++sp->bt_nkeys; + + type = GET_BKEYDATA(h, indx + O_INDX)->type; + if (!B_DISSET(type) && B_TYPE(type) != B_DUPLICATE) + ++sp->bt_ndata; + } + + ++sp->bt_leaf_pg; + sp->bt_leaf_pgfree += P_FREESPACE(h); + break; + case P_LRECNO: + /* + * If walking a recno tree, then each of these items is a key. + * Otherwise, we're walking an off-page duplicate set. + */ + if (dbp->type == DB_RECNO) { + sp->bt_nkeys += top; + + /* + * Correct for deleted items in non-renumbering + * Recno databases. + */ + if (F_ISSET(dbp, DB_RE_RENUMBER)) + sp->bt_ndata += top; + else + for (indx = 0; indx < top; indx += O_INDX) { + type = GET_BKEYDATA(h, indx)->type; + if (!B_DISSET(type)) + ++sp->bt_ndata; + } + + ++sp->bt_leaf_pg; + sp->bt_leaf_pgfree += P_FREESPACE(h); + } else { + sp->bt_ndata += top; + + ++sp->bt_dup_pg; + sp->bt_dup_pgfree += P_FREESPACE(h); + } + break; + case P_LDUP: + /* Correct for deleted items. */ + for (indx = 0; indx < top; indx += O_INDX) + if (!B_DISSET(GET_BKEYDATA(h, indx)->type)) + ++sp->bt_ndata; + + ++sp->bt_dup_pg; + sp->bt_dup_pgfree += P_FREESPACE(h); + break; + case P_OVERFLOW: + ++sp->bt_over_pg; + sp->bt_over_pgfree += P_OVFLSPACE(dbp->pgsize, h); + break; + default: + return (__db_pgfmt(dbp, h->pgno)); + } + return (0); +} + +/* + * __bam_key_range -- + * Return proportion of keys relative to given key. The numbers are + * slightly skewed due to on page duplicates. + * + * PUBLIC: int __bam_key_range __P((DB *, + * PUBLIC: DB_TXN *, DBT *, DB_KEY_RANGE *, u_int32_t)); + */ +int +__bam_key_range(dbp, txn, dbt, kp, flags) + DB *dbp; + DB_TXN *txn; + DBT *dbt; + DB_KEY_RANGE *kp; + u_int32_t flags; +{ + BTREE_CURSOR *cp; + DBC *dbc; + EPG *sp; + double factor; + int exact, ret, t_ret; + + PANIC_CHECK(dbp->dbenv); + DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->key_range"); + + if (flags != 0) + return (__db_ferr(dbp->dbenv, "DB->key_range", 0)); + + /* Acquire a cursor. */ + if ((ret = dbp->cursor(dbp, txn, &dbc, 0)) != 0) + return (ret); + + DEBUG_LWRITE(dbc, NULL, "bam_key_range", NULL, NULL, 0); + + if ((ret = __bam_search(dbc, dbt, S_STK_ONLY, 1, NULL, &exact)) != 0) + goto err; + + cp = (BTREE_CURSOR *)dbc->internal; + kp->less = kp->greater = 0.0; + + factor = 1.0; + /* Correct the leaf page. */ + cp->csp->entries /= 2; + cp->csp->indx /= 2; + for (sp = cp->sp; sp <= cp->csp; ++sp) { + /* + * At each level we know that pages greater than indx contain + * keys greater than what we are looking for and those less + * than indx are less than. The one pointed to by indx may + * have some less, some greater or even equal. If indx is + * equal to the number of entries, then the key is out of range + * and everything is less. + */ + if (sp->indx == 0) + kp->greater += factor * (sp->entries - 1)/sp->entries; + else if (sp->indx == sp->entries) + kp->less += factor; + else { + kp->less += factor * sp->indx / sp->entries; + kp->greater += factor * + (sp->entries - sp->indx - 1) / sp->entries; + } + factor *= 1.0/sp->entries; + } + + /* + * If there was an exact match then assign 1 n'th to the key itself. + * Otherwise that factor belongs to those greater than the key, unless + * the key was out of range. + */ + if (exact) + kp->equal = factor; + else { + if (kp->less != 1) + kp->greater += factor; + kp->equal = 0; + } + + BT_STK_CLR(cp); + +err: if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0) + ret = t_ret; + + return (ret); +} diff --git a/db/btree/bt_upgrade.c b/db/btree/bt_upgrade.c new file mode 100644 index 000000000..4032dba3b --- /dev/null +++ b/db/btree/bt_upgrade.c @@ -0,0 +1,164 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: bt_upgrade.c,v 11.19 2000/11/30 00:58:29 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_swap.h" +#include "btree.h" +#include "db_am.h" +#include "db_upgrade.h" + +/* + * __bam_30_btreemeta -- + * Upgrade the metadata pages from version 6 to version 7. + * + * PUBLIC: int __bam_30_btreemeta __P((DB *, char *, u_int8_t *)); + */ +int +__bam_30_btreemeta(dbp, real_name, buf) + DB *dbp; + char *real_name; + u_int8_t *buf; +{ + BTMETA30 *newmeta; + BTMETA2X *oldmeta; + DB_ENV *dbenv; + int ret; + + dbenv = dbp->dbenv; + + newmeta = (BTMETA30 *)buf; + oldmeta = (BTMETA2X *)buf; + + /* + * Move things from the end up, so we do not overwrite things. + * We are going to create a new uid, so we can move the stuff + * at the end of the structure first, overwriting the uid. + */ + + newmeta->re_pad = oldmeta->re_pad; + newmeta->re_len = oldmeta->re_len; + newmeta->minkey = oldmeta->minkey; + newmeta->maxkey = oldmeta->maxkey; + newmeta->dbmeta.free = oldmeta->free; + newmeta->dbmeta.flags = oldmeta->flags; + newmeta->dbmeta.type = P_BTREEMETA; + + newmeta->dbmeta.version = 7; + /* Replace the unique ID. */ + if ((ret = __os_fileid(dbenv, real_name, 1, buf + 36)) != 0) + return (ret); + + newmeta->root = 1; + + return (0); +} + +/* + * __bam_31_btreemeta -- + * Upgrade the database from version 7 to version 8. + * + * PUBLIC: int __bam_31_btreemeta + * PUBLIC: __P((DB *, char *, u_int32_t, DB_FH *, PAGE *, int *)); + */ +int +__bam_31_btreemeta(dbp, real_name, flags, fhp, h, dirtyp) + DB *dbp; + char *real_name; + u_int32_t flags; + DB_FH *fhp; + PAGE *h; + int *dirtyp; +{ + BTMETA31 *newmeta; + BTMETA30 *oldmeta; + + COMPQUIET(dbp, NULL); + COMPQUIET(real_name, NULL); + COMPQUIET(fhp, NULL); + + newmeta = (BTMETA31 *)h; + oldmeta = (BTMETA30 *)h; + + /* + * Copy the effected fields down the page. + * The fields may overlap each other so we + * start at the bottom and use memmove. + */ + newmeta->root = oldmeta->root; + newmeta->re_pad = oldmeta->re_pad; + newmeta->re_len = oldmeta->re_len; + newmeta->minkey = oldmeta->minkey; + newmeta->maxkey = oldmeta->maxkey; + memmove(newmeta->dbmeta.uid, + oldmeta->dbmeta.uid, sizeof(oldmeta->dbmeta.uid)); + newmeta->dbmeta.flags = oldmeta->dbmeta.flags; + newmeta->dbmeta.record_count = 0; + newmeta->dbmeta.key_count = 0; + ZERO_LSN(newmeta->dbmeta.unused3); + + /* Set the version number. */ + newmeta->dbmeta.version = 8; + + /* Upgrade the flags. */ + if (LF_ISSET(DB_DUPSORT)) + F_SET(&newmeta->dbmeta, BTM_DUPSORT); + + *dirtyp = 1; + return (0); +} + +/* + * __bam_31_lbtree -- + * Upgrade the database btree leaf pages. + * + * PUBLIC: int __bam_31_lbtree + * PUBLIC: __P((DB *, char *, u_int32_t, DB_FH *, PAGE *, int *)); + */ +int +__bam_31_lbtree(dbp, real_name, flags, fhp, h, dirtyp) + DB *dbp; + char *real_name; + u_int32_t flags; + DB_FH *fhp; + PAGE *h; + int *dirtyp; +{ + BKEYDATA *bk; + db_pgno_t pgno; + db_indx_t indx; + int ret; + + ret = 0; + for (indx = O_INDX; indx < NUM_ENT(h); indx += P_INDX) { + bk = GET_BKEYDATA(h, indx); + if (B_TYPE(bk->type) == B_DUPLICATE) { + pgno = GET_BOVERFLOW(h, indx)->pgno; + if ((ret = __db_31_offdup(dbp, real_name, fhp, + LF_ISSET(DB_DUPSORT) ? 1 : 0, &pgno)) != 0) + break; + if (pgno != GET_BOVERFLOW(h, indx)->pgno) { + *dirtyp = 1; + GET_BOVERFLOW(h, indx)->pgno = pgno; + } + } + } + + return (ret); +} diff --git a/db/btree/bt_verify.c b/db/btree/bt_verify.c new file mode 100644 index 000000000..9f8647e7e --- /dev/null +++ b/db/btree/bt_verify.c @@ -0,0 +1,2237 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: bt_verify.c,v 1.44 2000/12/06 19:55:44 ubell Exp $ + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: bt_verify.c,v 1.44 2000/12/06 19:55:44 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_verify.h" +#include "btree.h" + +static int __bam_safe_getdata __P((DB *, PAGE *, u_int32_t, int, DBT *, int *)); +static int __bam_vrfy_inp __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, + db_indx_t *, u_int32_t)); +static int __bam_vrfy_treeorder __P((DB *, db_pgno_t, PAGE *, BINTERNAL *, + BINTERNAL *, int (*)(DB *, const DBT *, const DBT *), u_int32_t)); +static int __ram_vrfy_inp __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, + db_indx_t *, u_int32_t)); + +#define OKFLAGS (DB_AGGRESSIVE | DB_NOORDERCHK | DB_SALVAGE) + +/* + * __bam_vrfy_meta -- + * Verify the btree-specific part of a metadata page. + * + * PUBLIC: int __bam_vrfy_meta __P((DB *, VRFY_DBINFO *, BTMETA *, + * PUBLIC: db_pgno_t, u_int32_t)); + */ +int +__bam_vrfy_meta(dbp, vdp, meta, pgno, flags) + DB *dbp; + VRFY_DBINFO *vdp; + BTMETA *meta; + db_pgno_t pgno; + u_int32_t flags; +{ + VRFY_PAGEINFO *pip; + int isbad, t_ret, ret; + db_indx_t ovflsize; + + if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) + return (ret); + + isbad = 0; + + /* + * If VRFY_INCOMPLETE is not set, then we didn't come through + * __db_vrfy_pagezero and didn't incompletely + * check this page--we haven't checked it at all. + * Thus we need to call __db_vrfy_meta and check the common fields. + * + * If VRFY_INCOMPLETE is set, we've already done all the same work + * in __db_vrfy_pagezero, so skip the check. + */ + if (!F_ISSET(pip, VRFY_INCOMPLETE) && + (ret = __db_vrfy_meta(dbp, vdp, &meta->dbmeta, pgno, flags)) != 0) { + if (ret == DB_VERIFY_BAD) + isbad = 1; + else + goto err; + } + + /* bt_minkey: must be >= 2; must produce sensible ovflsize */ + + /* avoid division by zero */ + ovflsize = meta->minkey > 0 ? + B_MINKEY_TO_OVFLSIZE(meta->minkey, dbp->pgsize) : 0; + + if (meta->minkey < 2 || + ovflsize > B_MINKEY_TO_OVFLSIZE(DEFMINKEYPAGE, dbp->pgsize)) { + pip->bt_minkey = 0; + isbad = 1; + EPRINT((dbp->dbenv, + "Nonsensical bt_minkey value %lu on metadata page %lu", + (u_long)meta->minkey, (u_long)pgno)); + } else + pip->bt_minkey = meta->minkey; + + /* bt_maxkey: no constraints (XXX: right?) */ + pip->bt_maxkey = meta->maxkey; + + /* re_len: no constraints on this (may be zero or huge--we make rope) */ + pip->re_len = meta->re_len; + + /* + * The root must not be current page or 0 and it must be within + * database. If this metadata page is the master meta data page + * of the file, then the root page had better be page 1. + */ + pip->root = 0; + if (meta->root == PGNO_INVALID + || meta->root == pgno || !IS_VALID_PGNO(meta->root) || + (pgno == PGNO_BASE_MD && meta->root != 1)) { + isbad = 1; + EPRINT((dbp->dbenv, + "Nonsensical root page %lu on metadata page %lu", + (u_long)meta->root, (u_long)vdp->last_pgno)); + } else + pip->root = meta->root; + + /* Flags. */ + if (F_ISSET(&meta->dbmeta, BTM_RENUMBER)) + F_SET(pip, VRFY_IS_RRECNO); + + if (F_ISSET(&meta->dbmeta, BTM_SUBDB)) { + /* + * If this is a master db meta page, it had better not have + * duplicates. + */ + if (F_ISSET(&meta->dbmeta, BTM_DUP) && pgno == PGNO_BASE_MD) { + isbad = 1; + EPRINT((dbp->dbenv, + "Btree metadata page %lu has both duplicates and multiple databases", + (u_long)pgno)); + } + F_SET(pip, VRFY_HAS_SUBDBS); + } + + if (F_ISSET(&meta->dbmeta, BTM_DUP)) + F_SET(pip, VRFY_HAS_DUPS); + if (F_ISSET(&meta->dbmeta, BTM_DUPSORT)) + F_SET(pip, VRFY_HAS_DUPSORT); + if (F_ISSET(&meta->dbmeta, BTM_RECNUM)) + F_SET(pip, VRFY_HAS_RECNUMS); + if (F_ISSET(pip, VRFY_HAS_RECNUMS) && F_ISSET(pip, VRFY_HAS_DUPS)) { + EPRINT((dbp->dbenv, + "Btree metadata page %lu illegally has both recnums and dups", + (u_long)pgno)); + isbad = 1; + } + + if (F_ISSET(&meta->dbmeta, BTM_RECNO)) { + F_SET(pip, VRFY_IS_RECNO); + dbp->type = DB_RECNO; + } else if (F_ISSET(pip, VRFY_IS_RRECNO)) { + isbad = 1; + EPRINT((dbp->dbenv, + "Metadata page %lu has renumber flag set but is not recno", + (u_long)pgno)); + } + + if (F_ISSET(pip, VRFY_IS_RECNO) && F_ISSET(pip, VRFY_HAS_DUPS)) { + EPRINT((dbp->dbenv, + "Recno metadata page %lu specifies duplicates", + (u_long)pgno)); + isbad = 1; + } + + if (F_ISSET(&meta->dbmeta, BTM_FIXEDLEN)) + F_SET(pip, VRFY_IS_FIXEDLEN); + else if (pip->re_len > 0) { + /* + * It's wrong to have an re_len if it's not a fixed-length + * database + */ + isbad = 1; + EPRINT((dbp->dbenv, + "re_len of %lu in non-fixed-length database", + (u_long)pip->re_len)); + } + + /* + * We do not check that the rest of the page is 0, because it may + * not be and may still be correct. + */ + +err: if ((t_ret = __db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0) + ret = t_ret; + return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret); +} + +/* + * __ram_vrfy_leaf -- + * Verify a recno leaf page. + * + * PUBLIC: int __ram_vrfy_leaf __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, + * PUBLIC: u_int32_t)); + */ +int +__ram_vrfy_leaf(dbp, vdp, h, pgno, flags) + DB *dbp; + VRFY_DBINFO *vdp; + PAGE *h; + db_pgno_t pgno; + u_int32_t flags; +{ + BKEYDATA *bk; + VRFY_PAGEINFO *pip; + db_indx_t i; + int ret, t_ret, isbad; + u_int32_t re_len_guess, len; + + isbad = 0; + if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) + return (ret); + + if ((ret = __db_fchk(dbp->dbenv, + "__ram_vrfy_leaf", flags, OKFLAGS)) != 0) + goto err; + + if (TYPE(h) != P_LRECNO) { + /* We should not have been called. */ + TYPE_ERR_PRINT(dbp->dbenv, "__ram_vrfy_leaf", pgno, TYPE(h)); + DB_ASSERT(0); + ret = EINVAL; + goto err; + } + + /* + * Verify (and, if relevant, save off) page fields common to + * all PAGEs. + */ + if ((ret = __db_vrfy_datapage(dbp, vdp, h, pgno, flags)) != 0) { + if (ret == DB_VERIFY_BAD) + isbad = 1; + else + goto err; + } + + /* + * Verify inp[]. Return immediately if it returns DB_VERIFY_BAD; + * further checks are dangerous. + */ + if ((ret = __bam_vrfy_inp(dbp, + vdp, h, pgno, &pip->entries, flags)) != 0) + goto err; + + if (F_ISSET(pip, VRFY_HAS_DUPS)) { + EPRINT((dbp->dbenv, + "Recno database has dups on page %lu", (u_long)pgno)); + ret = DB_VERIFY_BAD; + goto err; + } + + /* + * Walk through inp and see if the lengths of all the records are the + * same--if so, this may be a fixed-length database, and we want to + * save off this value. We know inp to be safe if we've gotten this + * far. + */ + re_len_guess = 0; + for (i = 0; i < NUM_ENT(h); i++) { + bk = GET_BKEYDATA(h, i); + /* KEYEMPTY. Go on. */ + if (B_DISSET(bk->type)) + continue; + if (bk->type == B_OVERFLOW) + len = ((BOVERFLOW *)bk)->tlen; + else if (bk->type == B_KEYDATA) + len = bk->len; + else { + isbad = 1; + EPRINT((dbp->dbenv, + "Nonsensical type for item %lu, page %lu", + (u_long)i, (u_long)pgno)); + continue; + } + if (re_len_guess == 0) + re_len_guess = len; + + /* + * Is this item's len the same as the last one's? If not, + * reset to 0 and break--we don't have a single re_len. + * Otherwise, go on to the next item. + */ + if (re_len_guess != len) { + re_len_guess = 0; + break; + } + } + pip->re_len = re_len_guess; + + /* Save off record count. */ + pip->rec_cnt = NUM_ENT(h); + +err: if ((t_ret = __db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0) + ret = t_ret; + return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : 0); +} + +/* + * __bam_vrfy -- + * Verify a btree leaf or internal page. + * + * PUBLIC: int __bam_vrfy __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, + * PUBLIC: u_int32_t)); + */ +int +__bam_vrfy(dbp, vdp, h, pgno, flags) + DB *dbp; + VRFY_DBINFO *vdp; + PAGE *h; + db_pgno_t pgno; + u_int32_t flags; +{ + VRFY_PAGEINFO *pip; + int ret, t_ret, isbad; + + isbad = 0; + if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) + return (ret); + + switch (TYPE(h)) { + case P_IBTREE: + case P_IRECNO: + case P_LBTREE: + case P_LDUP: + break; + default: + TYPE_ERR_PRINT(dbp->dbenv, "__bam_vrfy", pgno, TYPE(h)); + DB_ASSERT(0); + ret = EINVAL; + goto err; + } + + /* + * Verify (and, if relevant, save off) page fields common to + * all PAGEs. + */ + if ((ret = __db_vrfy_datapage(dbp, vdp, h, pgno, flags)) != 0) { + if (ret == DB_VERIFY_BAD) + isbad = 1; + else + goto err; + } + + /* + * The record count is, on internal pages, stored in an overloaded + * next_pgno field. Save it off; we'll verify it when we check + * overall database structure. We could overload the field + * in VRFY_PAGEINFO, too, but this seems gross, and space + * is not at such a premium. + */ + pip->rec_cnt = RE_NREC(h); + + /* + * Verify inp[]. + */ + if (TYPE(h) == P_IRECNO) { + if ((ret = __ram_vrfy_inp(dbp, + vdp, h, pgno, &pip->entries, flags)) != 0) + goto err; + } else if ((ret = __bam_vrfy_inp(dbp, + vdp, h, pgno, &pip->entries, flags)) != 0) { + if (ret == DB_VERIFY_BAD) + isbad = 1; + else + goto err; + EPRINT((dbp->dbenv, + "item order check on page %lu unsafe: skipping", + (u_long)pgno)); + } else if (!LF_ISSET(DB_NOORDERCHK) && (ret = + __bam_vrfy_itemorder(dbp, vdp, h, pgno, 0, 0, 0, flags)) != 0) { + /* + * We know that the elements of inp are reasonable. + * + * Check that elements fall in the proper order. + */ + if (ret == DB_VERIFY_BAD) + isbad = 1; + else + goto err; + } + +err: if ((t_ret = __db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0) + ret = t_ret; + return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : 0); +} + +/* + * __ram_vrfy_inp -- + * Verify that all entries in a P_IRECNO inp[] array are reasonable, + * and count them. Note that P_LRECNO uses __bam_vrfy_inp; + * P_IRECNOs are a special, and simpler, case, since they have + * RINTERNALs rather than BKEYDATA/BINTERNALs. + */ +static int +__ram_vrfy_inp(dbp, vdp, h, pgno, nentriesp, flags) + DB *dbp; + VRFY_DBINFO *vdp; + PAGE *h; + db_pgno_t pgno; + db_indx_t *nentriesp; + u_int32_t flags; +{ + RINTERNAL *ri; + VRFY_CHILDINFO child; + VRFY_PAGEINFO *pip; + int ret, t_ret, isbad; + u_int32_t himark, i, offset, nentries; + u_int8_t *pagelayout, *p; + + isbad = 0; + memset(&child, 0, sizeof(VRFY_CHILDINFO)); + nentries = 0; + pagelayout = NULL; + + if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) + return (ret); + + if (TYPE(h) != P_IRECNO) { + TYPE_ERR_PRINT(dbp->dbenv, "__ram_vrfy_inp", pgno, TYPE(h)); + DB_ASSERT(0); + ret = EINVAL; + goto err; + } + + himark = dbp->pgsize; + if ((ret = + __os_malloc(dbp->dbenv, dbp->pgsize, NULL, &pagelayout)) != 0) + goto err; + memset(pagelayout, 0, dbp->pgsize); + for (i = 0; i < NUM_ENT(h); i++) { + if ((u_int8_t *)h->inp + i >= (u_int8_t *)h + himark) { + EPRINT((dbp->dbenv, + "Page %lu entries listing %lu overlaps data", + (u_long)pgno, (u_long)i)); + ret = DB_VERIFY_BAD; + goto err; + } + offset = h->inp[i]; + /* + * Check that the item offset is reasonable: it points + * somewhere after the inp array and before the end of the + * page. + */ + if (offset <= (u_int32_t)((u_int8_t *)h->inp + i - + (u_int8_t *)h) || + offset > (u_int32_t)(dbp->pgsize - RINTERNAL_SIZE)) { + isbad = 1; + EPRINT((dbp->dbenv, + "Bad offset %lu at page %lu index %lu", + (u_long)offset, (u_long)pgno, (u_long)i)); + continue; + } + + /* Update the high-water mark (what HOFFSET should be) */ + if (offset < himark) + himark = offset; + + nentries++; + + /* Make sure this RINTERNAL is not multiply referenced. */ + ri = GET_RINTERNAL(h, i); + if (pagelayout[offset] == 0) { + pagelayout[offset] = 1; + child.pgno = ri->pgno; + child.type = V_RECNO; + child.nrecs = ri->nrecs; + if ((ret = __db_vrfy_childput(vdp, pgno, &child)) != 0) + goto err; + } else { + EPRINT((dbp->dbenv, + "RINTERNAL structure at offset %lu, page %lu referenced twice", + (u_long)offset, (u_long)pgno)); + isbad = 1; + } + } + + for (p = pagelayout + himark; + p < pagelayout + dbp->pgsize; + p += RINTERNAL_SIZE) + if (*p != 1) { + EPRINT((dbp->dbenv, + "Gap between items at offset %lu, page %lu", + (u_long)(p - pagelayout), (u_long)pgno)); + isbad = 1; + } + + if ((db_indx_t)himark != HOFFSET(h)) { + EPRINT((dbp->dbenv, "Bad HOFFSET %lu, appears to be %lu", + (u_long)(HOFFSET(h)), (u_long)himark)); + isbad = 1; + } + + *nentriesp = nentries; + +err: if ((t_ret = __db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0) + ret = t_ret; + if (pagelayout != NULL) + __os_free(pagelayout, dbp->pgsize); + return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret); +} + +/* + * __bam_vrfy_inp -- + * Verify that all entries in inp[] array are reasonable; + * count them. + */ +static int +__bam_vrfy_inp(dbp, vdp, h, pgno, nentriesp, flags) + DB *dbp; + VRFY_DBINFO *vdp; + PAGE *h; + db_pgno_t pgno; + db_indx_t *nentriesp; + u_int32_t flags; +{ + BKEYDATA *bk; + BOVERFLOW *bo; + VRFY_CHILDINFO child; + VRFY_PAGEINFO *pip; + int isbad, initem, isdupitem, ret, t_ret; + u_int32_t himark, offset; /* These would be db_indx_ts but for algnmt.*/ + u_int32_t i, endoff, nentries; + u_int8_t *pagelayout; + + isbad = isdupitem = 0; + nentries = 0; + memset(&child, 0, sizeof(VRFY_CHILDINFO)); + if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) + return (ret); + + switch (TYPE(h)) { + case P_IBTREE: + case P_LBTREE: + case P_LDUP: + case P_LRECNO: + break; + default: + /* + * In the salvager, we might call this from a page which + * we merely suspect is a btree page. Otherwise, it + * shouldn't get called--if it is, that's a verifier bug. + */ + if (LF_ISSET(DB_SALVAGE)) + break; + TYPE_ERR_PRINT(dbp->dbenv, "__bam_vrfy_inp", pgno, TYPE(h)); + DB_ASSERT(0); + ret = EINVAL; + goto err; + } + + /* + * Loop through inp[], the array of items, until we either + * run out of entries or collide with the data. Keep track + * of h_offset in himark. + * + * For each element in inp[i], make sure it references a region + * that starts after the end of the inp array (as defined by + * NUM_ENT(h)), ends before the beginning of the page, doesn't + * overlap any other regions, and doesn't have a gap between + * it and the region immediately after it. + */ + himark = dbp->pgsize; + if ((ret = __os_malloc(dbp->dbenv, + dbp->pgsize, NULL, &pagelayout)) != 0) + goto err; + memset(pagelayout, 0, dbp->pgsize); + for (i = 0; i < NUM_ENT(h); i++) { + + ret = __db_vrfy_inpitem(dbp, + h, pgno, i, 1, flags, &himark, &offset); + if (ret == DB_VERIFY_BAD) { + isbad = 1; + continue; + } else if (ret == DB_VERIFY_FATAL) { + isbad = 1; + goto err; + } else if (ret != 0) + DB_ASSERT(0); + + /* + * We now have a plausible beginning for the item, and we know + * its length is safe. + * + * Mark the beginning and end in pagelayout so we can make sure + * items have no overlaps or gaps. + */ + bk = GET_BKEYDATA(h, i); +#define ITEM_BEGIN 1 +#define ITEM_END 2 + if (pagelayout[offset] == 0) + pagelayout[offset] = ITEM_BEGIN; + else if (pagelayout[offset] == ITEM_BEGIN) { + /* + * Having two inp entries that point at the same patch + * of page is legal if and only if the page is + * a btree leaf and they're onpage duplicate keys-- + * that is, if (i % P_INDX) == 0. + */ + if ((i % P_INDX == 0) && (TYPE(h) == P_LBTREE)) { + /* Flag for later. */ + F_SET(pip, VRFY_HAS_DUPS); + + /* Bump up nentries so we don't undercount. */ + nentries++; + + /* + * We'll check to make sure the end is + * equal, too. + */ + isdupitem = 1; + } else { + isbad = 1; + EPRINT((dbp->dbenv, + "Duplicated item %lu on page %lu", + (u_long)i, (u_long)pgno)); + } + } + + /* + * Mark the end. Its location varies with the page type + * and the item type. + * + * If the end already has a sign other than 0, do nothing-- + * it's an overlap that we'll catch later. + */ + switch(B_TYPE(bk->type)) { + case B_KEYDATA: + if (TYPE(h) == P_IBTREE) + /* It's a BINTERNAL. */ + endoff = offset + BINTERNAL_SIZE(bk->len) - 1; + else + endoff = offset + BKEYDATA_SIZE(bk->len) - 1; + break; + case B_DUPLICATE: + /* + * Flag that we have dups; we'll check whether + * that's okay during the structure check. + */ + F_SET(pip, VRFY_HAS_DUPS); + /* FALLTHROUGH */ + case B_OVERFLOW: + /* + * Overflow entries on internal pages are stored + * as the _data_ of a BINTERNAL; overflow entries + * on leaf pages are stored as the entire entry. + */ + endoff = offset + + ((TYPE(h) == P_IBTREE) ? + BINTERNAL_SIZE(BOVERFLOW_SIZE) : + BOVERFLOW_SIZE) - 1; + break; + default: + /* + * We'll complain later; for now, just mark + * a minimum. + */ + endoff = offset + BKEYDATA_SIZE(0) - 1; + break; + } + + /* + * If this is an onpage duplicate key we've seen before, + * the end had better coincide too. + */ + if (isdupitem && pagelayout[endoff] != ITEM_END) { + EPRINT((dbp->dbenv, + "Duplicated item %lu on page %lu", + (u_long)i, (u_long)pgno)); + isbad = 1; + } else if (pagelayout[endoff] == 0) + pagelayout[endoff] = ITEM_END; + isdupitem = 0; + + /* + * There should be no deleted items in a quiescent tree, + * except in recno. + */ + if (B_DISSET(bk->type) && TYPE(h) != P_LRECNO) { + isbad = 1; + EPRINT((dbp->dbenv, + "Item %lu on page %lu marked deleted", + (u_long)i, (u_long)pgno)); + } + + /* + * Check the type and such of bk--make sure it's reasonable + * for the pagetype. + */ + switch (B_TYPE(bk->type)) { + case B_KEYDATA: + /* + * This is a normal, non-overflow BKEYDATA or BINTERNAL. + * The only thing to check is the len, and that's + * already been done. + */ + break; + case B_DUPLICATE: + if (TYPE(h) == P_IBTREE) { + isbad = 1; + EPRINT((dbp->dbenv, + "Duplicate page referenced by internal btree page %lu at item %lu", + (u_long)pgno, (u_long)i)); + break; + } else if (TYPE(h) == P_LRECNO) { + isbad = 1; + EPRINT((dbp->dbenv, + "Duplicate page referenced by recno page %lu at item %lu", + (u_long)pgno, (u_long)i)); + break; + } + /* FALLTHROUGH */ + case B_OVERFLOW: + bo = (TYPE(h) == P_IBTREE) ? + (BOVERFLOW *)(((BINTERNAL *)bk)->data) : + (BOVERFLOW *)bk; + + if (B_TYPE(bk->type) == B_OVERFLOW) + /* Make sure tlen is reasonable. */ + if (bo->tlen > dbp->pgsize * vdp->last_pgno) { + isbad = 1; + EPRINT((dbp->dbenv, + "Impossible tlen %lu, item %lu, page %lu", + (u_long)bo->tlen, (u_long)i, + (u_long)pgno)); + /* Don't save as a child. */ + break; + } + + if (!IS_VALID_PGNO(bo->pgno) || bo->pgno == pgno || + bo->pgno == PGNO_INVALID) { + isbad = 1; + EPRINT((dbp->dbenv, + "Offpage item %lu, page %lu has bad pgno", + (u_long)i, (u_long)pgno)); + /* Don't save as a child. */ + break; + } + + child.pgno = bo->pgno; + child.type = (B_TYPE(bk->type) == B_OVERFLOW ? + V_OVERFLOW : V_DUPLICATE); + child.tlen = bo->tlen; + if ((ret = __db_vrfy_childput(vdp, pgno, &child)) != 0) + goto err; + break; + default: + isbad = 1; + EPRINT((dbp->dbenv, + "Item %lu on page %lu of invalid type %lu", + (u_long)i, (u_long)pgno)); + break; + } + } + + /* + * Now, loop through and make sure the items are contiguous and + * non-overlapping. + */ + initem = 0; + for (i = himark; i < dbp->pgsize; i++) + if (initem == 0) + switch (pagelayout[i]) { + case 0: + /* May be just for alignment. */ + if (i != ALIGN(i, sizeof(u_int32_t))) + continue; + + isbad = 1; + EPRINT((dbp->dbenv, + "Gap between items, page %lu offset %lu", + (u_long)pgno, (u_long)i)); + /* Find the end of the gap */ + for ( ; pagelayout[i + 1] == 0 && + (size_t)(i + 1) < dbp->pgsize; i++) + ; + break; + case ITEM_BEGIN: + /* We've found an item. Check its alignment. */ + if (i != ALIGN(i, sizeof(u_int32_t))) { + isbad = 1; + EPRINT((dbp->dbenv, + "Offset %lu page %lu unaligned", + (u_long)i, (u_long)pgno)); + } + initem = 1; + nentries++; + break; + case ITEM_END: + /* + * We've hit the end of an item even though + * we don't think we're in one; must + * be an overlap. + */ + isbad = 1; + EPRINT((dbp->dbenv, + "Overlapping items, page %lu offset %lu", + (u_long)pgno, (u_long)i)); + break; + default: + /* Should be impossible. */ + DB_ASSERT(0); + ret = EINVAL; + goto err; + } + else + switch (pagelayout[i]) { + case 0: + /* In the middle of an item somewhere. Okay. */ + break; + case ITEM_END: + /* End of an item; switch to out-of-item mode.*/ + initem = 0; + break; + case ITEM_BEGIN: + /* + * Hit a second item beginning without an + * end. Overlap. + */ + isbad = 1; + EPRINT((dbp->dbenv, + "Overlapping items, page %lu offset %lu", + (u_long)pgno, (u_long)i)); + break; + } + + (void)__os_free(pagelayout, dbp->pgsize); + + /* Verify HOFFSET. */ + if ((db_indx_t)himark != HOFFSET(h)) { + EPRINT((dbp->dbenv, "Bad HOFFSET %lu, appears to be %lu", + (u_long)HOFFSET(h), (u_long)himark)); + isbad = 1; + } + +err: if (nentriesp != NULL) + *nentriesp = nentries; + + if ((t_ret = __db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0) + ret = t_ret; + + return ((isbad == 1 && ret == 0) ? DB_VERIFY_BAD : ret); +} + +/* + * __bam_vrfy_itemorder -- + * Make sure the items on a page sort correctly. + * + * Assumes that NUM_ENT(h) and inp[0]..inp[NUM_ENT(h) - 1] are + * reasonable; be sure that __bam_vrfy_inp has been called first. + * + * If ovflok is set, it also assumes that overflow page chains + * hanging off the current page have been sanity-checked, and so we + * can use __bam_cmp to verify their ordering. If it is not set, + * and we run into an overflow page, carp and return DB_VERIFY_BAD; + * we shouldn't be called if any exist. + * + * PUBLIC: int __bam_vrfy_itemorder __P((DB *, VRFY_DBINFO *, PAGE *, + * PUBLIC: db_pgno_t, u_int32_t, int, int, u_int32_t)); + */ +int +__bam_vrfy_itemorder(dbp, vdp, h, pgno, nentries, ovflok, hasdups, flags) + DB *dbp; + VRFY_DBINFO *vdp; + PAGE *h; + db_pgno_t pgno; + u_int32_t nentries; + int ovflok, hasdups; + u_int32_t flags; +{ + DBT dbta, dbtb, dup1, dup2, *p1, *p2, *tmp; + BTREE *bt; + BINTERNAL *bi; + BKEYDATA *bk; + BOVERFLOW *bo; + VRFY_PAGEINFO *pip; + db_indx_t i; + int cmp, freedup1, freedup2, isbad, ret, t_ret; + int (*dupfunc) __P((DB *, const DBT *, const DBT *)); + int (*func) __P((DB *, const DBT *, const DBT *)); + void *buf1, *buf2, *tmpbuf; + + /* + * We need to work in the ORDERCHKONLY environment where we might + * not have a pip, but we also may need to work in contexts where + * NUM_ENT isn't safe. + */ + if (vdp != NULL) { + if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) + return (ret); + nentries = pip->entries; + } else + pip = NULL; + + ret = isbad = 0; + bo = NULL; /* Shut up compiler. */ + + memset(&dbta, 0, sizeof(DBT)); + F_SET(&dbta, DB_DBT_REALLOC); + + memset(&dbtb, 0, sizeof(DBT)); + F_SET(&dbtb, DB_DBT_REALLOC); + + buf1 = buf2 = NULL; + + DB_ASSERT(!LF_ISSET(DB_NOORDERCHK)); + + dupfunc = (dbp->dup_compare == NULL) ? __bam_defcmp : dbp->dup_compare; + if (TYPE(h) == P_LDUP) + func = dupfunc; + else { + func = __bam_defcmp; + if (dbp->bt_internal != NULL) { + bt = (BTREE *)dbp->bt_internal; + if (bt->bt_compare != NULL) + func = bt->bt_compare; + } + } + + /* + * We alternate our use of dbta and dbtb so that we can walk + * through the page key-by-key without copying a dbt twice. + * p1 is always the dbt for index i - 1, and p2 for index i. + */ + p1 = &dbta; + p2 = &dbtb; + + /* + * Loop through the entries. nentries ought to contain the + * actual count, and so is a safe way to terminate the loop; whether + * we inc. by one or two depends on whether we're a leaf page-- + * on a leaf page, we care only about keys. On internal pages + * and LDUP pages, we want to check the order of all entries. + * + * Note that on IBTREE pages, we start with item 1, since item + * 0 doesn't get looked at by __bam_cmp. + */ + for (i = (TYPE(h) == P_IBTREE) ? 1 : 0; i < nentries; + i += (TYPE(h) == P_LBTREE) ? P_INDX : O_INDX) { + /* + * Put key i-1, now in p2, into p1, by swapping DBTs and bufs. + */ + tmp = p1; + p1 = p2; + p2 = tmp; + tmpbuf = buf1; + buf1 = buf2; + buf2 = tmpbuf; + + /* + * Get key i into p2. + */ + switch (TYPE(h)) { + case P_IBTREE: + bi = GET_BINTERNAL(h, i); + if (B_TYPE(bi->type) == B_OVERFLOW) { + bo = (BOVERFLOW *)(bi->data); + goto overflow; + } else { + p2->data = bi->data; + p2->size = bi->len; + } + + /* + * The leftmost key on an internal page must be + * len 0, since it's just a placeholder and + * automatically sorts less than all keys. + * + * XXX + * This criterion does not currently hold! + * See todo list item #1686. Meanwhile, it's harmless + * to just not check for it. + */ +#if 0 + if (i == 0 && bi->len != 0) { + isbad = 1; + EPRINT((dbp->dbenv, + "Lowest key on internal page %lu of nonzero length", + (u_long)pgno)); + } +#endif + break; + case P_LBTREE: + case P_LDUP: + bk = GET_BKEYDATA(h, i); + if (B_TYPE(bk->type) == B_OVERFLOW) { + bo = (BOVERFLOW *)bk; + goto overflow; + } else { + p2->data = bk->data; + p2->size = bk->len; + } + break; + default: + /* + * This means our caller screwed up and sent us + * an inappropriate page. + */ + TYPE_ERR_PRINT(dbp->dbenv, + "__bam_vrfy_itemorder", pgno, TYPE(h)) + DB_ASSERT(0); + ret = EINVAL; + goto err; + } + + if (0) { + /* + * If ovflok != 1, we can't safely go chasing + * overflow pages with the normal routines now; + * they might be unsafe or nonexistent. Mark this + * page as incomplete and return. + * + * Note that we don't need to worry about freeing + * buffers, since they can't have been allocated + * if overflow items are unsafe. + */ +overflow: if (!ovflok) { + F_SET(pip, VRFY_INCOMPLETE); + goto err; + } + + /* + * Overflow items are safe to chase. Do so. + * Fetch the overflow item into p2->data, + * NULLing it or reallocing it as appropriate. + * + * (We set p2->data to buf2 before the call + * so we're sure to realloc if we can and if p2 + * was just pointing at a non-overflow item.) + */ + p2->data = buf2; + if ((ret = __db_goff(dbp, + p2, bo->tlen, bo->pgno, NULL, NULL)) != 0) { + isbad = 1; + EPRINT((dbp->dbenv, + "Error %lu in fetching overflow item %lu, page %lu", + (u_long)ret, (u_long)i, (u_long)pgno)); + } + /* In case it got realloc'ed and thus changed. */ + buf2 = p2->data; + } + + /* Compare with the last key. */ + if (p1->data != NULL && p2->data != NULL) { + cmp = func(dbp, p1, p2); + + /* comparison succeeded */ + if (cmp > 0) { + isbad = 1; + EPRINT((dbp->dbenv, + "Out-of-order key, page %lu item %lu", + (u_long)pgno, (u_long)i)); + /* proceed */ + } else if (cmp == 0) { + /* + * If they compared equally, this + * had better be a (sub)database with dups. + * Mark it so we can check during the + * structure check. + */ + if (pip != NULL) + F_SET(pip, VRFY_HAS_DUPS); + else if (hasdups == 0) { + isbad = 1; + EPRINT((dbp->dbenv, + "Database with no duplicates has duplicated keys on page %lu", + (u_long)pgno)); + } + + /* + * If we're a btree leaf, check to see + * if the data items of these on-page dups are + * in sorted order. If not, flag this, so + * that we can make sure during the + * structure checks that the DUPSORT flag + * is unset. + * + * At this point i points to a duplicate key. + * Compare the datum before it (same key) + * to the datum after it, i.e. i-1 to i+1. + */ + if (TYPE(h) == P_LBTREE) { + /* + * Unsafe; continue and we'll pick + * up the bogus nentries later. + */ + if (i + 1 >= (db_indx_t)nentries) + continue; + + /* + * We don't bother with clever memory + * management with on-page dups, + * as it's only really a big win + * in the overflow case, and overflow + * dups are probably (?) rare. + */ + if (((ret = __bam_safe_getdata(dbp, + h, i - 1, ovflok, &dup1, + &freedup1)) != 0) || + ((ret = __bam_safe_getdata(dbp, + h, i + 1, ovflok, &dup2, + &freedup2)) != 0)) + goto err; + + /* + * If either of the data are NULL, + * it's because they're overflows and + * it's not safe to chase them now. + * Mark an incomplete and return. + */ + if (dup1.data == NULL || + dup2.data == NULL) { + DB_ASSERT(!ovflok); + F_SET(pip, VRFY_INCOMPLETE); + goto err; + } + + /* + * If the dups are out of order, + * flag this. It's not an error + * until we do the structure check + * and see whether DUPSORT is set. + */ + if (dupfunc(dbp, &dup1, &dup2) > 0) + F_SET(pip, VRFY_DUPS_UNSORTED); + + if (freedup1) + __os_free(dup1.data, 0); + if (freedup2) + __os_free(dup2.data, 0); + } + } + } + } + +err: if (pip != NULL && + ((t_ret = __db_vrfy_putpageinfo(vdp, pip)) != 0) && ret == 0) + ret = t_ret; + + if (buf1 != NULL) + __os_free(buf1, 0); + if (buf2 != NULL) + __os_free(buf2, 0); + + return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret); +} + +/* + * __bam_vrfy_structure -- + * Verify the tree structure of a btree database (including the master + * database containing subdbs). + * + * PUBLIC: int __bam_vrfy_structure __P((DB *, VRFY_DBINFO *, db_pgno_t, + * PUBLIC: u_int32_t)); + */ +int +__bam_vrfy_structure(dbp, vdp, meta_pgno, flags) + DB *dbp; + VRFY_DBINFO *vdp; + db_pgno_t meta_pgno; + u_int32_t flags; +{ + DB *pgset; + VRFY_PAGEINFO *mip, *rip; + db_pgno_t root, p; + int t_ret, ret; + u_int32_t nrecs, level, relen, stflags; + + mip = rip = 0; + pgset = vdp->pgset; + + if ((ret = __db_vrfy_getpageinfo(vdp, meta_pgno, &mip)) != 0) + return (ret); + + if ((ret = __db_vrfy_pgset_get(pgset, meta_pgno, (int *)&p)) != 0) + goto err; + if (p != 0) { + EPRINT((dbp->dbenv, + "Btree metadata page number %lu observed twice", + (u_long)meta_pgno)); + ret = DB_VERIFY_BAD; + goto err; + } + if ((ret = __db_vrfy_pgset_inc(pgset, meta_pgno)) != 0) + goto err; + + root = mip->root; + + if (root == 0) { + EPRINT((dbp->dbenv, + "Btree metadata page %lu has no root", (u_long)meta_pgno)); + ret = DB_VERIFY_BAD; + goto err; + } + + if ((ret = __db_vrfy_getpageinfo(vdp, root, &rip)) != 0) + goto err; + + switch (rip->type) { + case P_IBTREE: + case P_LBTREE: + stflags = flags | ST_TOPLEVEL; + if (F_ISSET(mip, VRFY_HAS_DUPS)) + stflags |= ST_DUPOK; + if (F_ISSET(mip, VRFY_HAS_DUPSORT)) + stflags |= ST_DUPSORT; + if (F_ISSET(mip, VRFY_HAS_RECNUMS)) + stflags |= ST_RECNUM; + ret = __bam_vrfy_subtree(dbp, + vdp, root, NULL, NULL, stflags, NULL, NULL, NULL); + break; + case P_IRECNO: + case P_LRECNO: + stflags = flags | ST_RECNUM | ST_IS_RECNO | ST_TOPLEVEL; + if (mip->re_len > 0) + stflags |= ST_RELEN; + if ((ret = __bam_vrfy_subtree(dbp, vdp, + root, NULL, NULL, stflags, &level, &nrecs, &relen)) != 0) + goto err; + /* + * Even if mip->re_len > 0, re_len may come back zero if the + * tree is empty. It should be okay to just skip the check in + * this case, as if there are any non-deleted keys at all, + * that should never happen. + */ + if (mip->re_len > 0 && relen > 0 && mip->re_len != relen) { + EPRINT((dbp->dbenv, + "Recno database with meta page %lu has bad re_len %lu", + (u_long)meta_pgno, (u_long)relen)); + ret = DB_VERIFY_BAD; + goto err; + } + ret = 0; + break; + case P_LDUP: + EPRINT((dbp->dbenv, + "Duplicate tree referenced from metadata page %lu", + (u_long)meta_pgno)); + ret = DB_VERIFY_BAD; + break; + default: + EPRINT((dbp->dbenv, + "Btree root of incorrect type %lu on meta page %lu", + (u_long)rip->type, (u_long)meta_pgno)); + ret = DB_VERIFY_BAD; + break; + } + +err: if (mip != NULL && + ((t_ret = __db_vrfy_putpageinfo(vdp, mip)) != 0) && ret == 0) + t_ret = ret; + if (rip != NULL && + ((t_ret = __db_vrfy_putpageinfo(vdp, rip)) != 0) && ret == 0) + t_ret = ret; + return (ret); +} + +/* + * __bam_vrfy_subtree-- + * Verify a subtree (or entire) btree with specified root. + * + * Note that this is public because it must be called to verify + * offpage dup trees, including from hash. + * + * PUBLIC: int __bam_vrfy_subtree __P((DB *, VRFY_DBINFO *, db_pgno_t, void *, + * PUBLIC: void *, u_int32_t, u_int32_t *, u_int32_t *, u_int32_t *)); + */ +int +__bam_vrfy_subtree(dbp, + vdp, pgno, l, r, flags, levelp, nrecsp, relenp) + DB *dbp; + VRFY_DBINFO *vdp; + db_pgno_t pgno; + void *l, *r; + u_int32_t flags, *levelp, *nrecsp, *relenp; +{ + BINTERNAL *li, *ri, *lp, *rp; + DB *pgset; + DBC *cc; + PAGE *h; + VRFY_CHILDINFO *child; + VRFY_PAGEINFO *pip; + db_recno_t nrecs, child_nrecs; + db_indx_t i; + int ret, t_ret, isbad, toplevel, p; + int (*func) __P((DB *, const DBT *, const DBT *)); + u_int32_t level, child_level, stflags, child_relen, relen; + + ret = isbad = 0; + nrecs = 0; + h = NULL; + relen = 0; + rp = (BINTERNAL *)r; + lp = (BINTERNAL *)l; + + /* Provide feedback on our progress to the application. */ + if (!LF_ISSET(DB_SALVAGE)) + __db_vrfy_struct_feedback(dbp, vdp); + + if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) + return (ret); + + cc = NULL; + level = pip->bt_level; + + toplevel = LF_ISSET(ST_TOPLEVEL); + LF_CLR(ST_TOPLEVEL); + + /* + * We are recursively descending a btree, starting from the root + * and working our way out to the leaves. + * + * There are four cases we need to deal with: + * 1. pgno is a recno leaf page. Any children are overflows. + * 2. pgno is a duplicate leaf page. Any children + * are overflow pages; traverse them, and then return + * level and nrecs. + * 3. pgno is an ordinary leaf page. Check whether dups are + * allowed, and if so, traverse any off-page dups or + * overflows. Then return nrecs and level. + * 4. pgno is a recno internal page. Recursively check any + * child pages, making sure their levels are one lower + * and their nrecs sum to ours. + * 5. pgno is a btree internal page. Same as #4, plus we + * must verify that for each pair of BINTERNAL entries + * N and N+1, the leftmost item on N's child sorts + * greater than N, and the rightmost item on N's child + * sorts less than N+1. + * + * Furthermore, in any sorted page type (P_LDUP, P_LBTREE, P_IBTREE), + * we need to verify the internal sort order is correct if, + * due to overflow items, we were not able to do so earlier. + */ + switch (pip->type) { + case P_LRECNO: + case P_LDUP: + case P_LBTREE: + /* + * Cases 1, 2 and 3 (overflow pages are common to all three); + * traverse child list, looking for overflows. + */ + if ((ret = __db_vrfy_childcursor(vdp, &cc)) != 0) + goto err; + for (ret = __db_vrfy_ccset(cc, pgno, &child); ret == 0; + ret = __db_vrfy_ccnext(cc, &child)) + if (child->type == V_OVERFLOW && + (ret = __db_vrfy_ovfl_structure(dbp, vdp, + child->pgno, child->tlen, + flags | ST_OVFL_LEAF)) != 0) { + if (ret == DB_VERIFY_BAD) + isbad = 1; + else + goto done; + } + + if ((ret = __db_vrfy_ccclose(cc)) != 0) + goto err; + cc = NULL; + + /* Case 1 */ + if (pip->type == P_LRECNO) { + if (!LF_ISSET(ST_IS_RECNO) && + !(LF_ISSET(ST_DUPOK) && !LF_ISSET(ST_DUPSORT))) { + isbad = 1; + EPRINT((dbp->dbenv, + "Recno leaf page %lu in non-recno tree", + (u_long)pgno)); + goto done; + } + goto leaf; + } else if (LF_ISSET(ST_IS_RECNO)) { + /* + * It's a non-recno leaf. Had better not be a recno + * subtree. + */ + isbad = 1; + EPRINT((dbp->dbenv, + "Non-recno leaf page %lu in recno tree", + (u_long)pgno)); + goto done; + } + + /* Case 2--no more work. */ + if (pip->type == P_LDUP) + goto leaf; + + /* Case 3 */ + + /* Check if we have any dups. */ + if (F_ISSET(pip, VRFY_HAS_DUPS)) { + /* If dups aren't allowed in this btree, trouble. */ + if (!LF_ISSET(ST_DUPOK)) { + isbad = 1; + EPRINT((dbp->dbenv, + "Duplicates on page %lu in non-dup btree", + (u_long)pgno)); + } else { + /* + * We correctly have dups. If any are off-page, + * traverse those btrees recursively. + */ + if ((ret = + __db_vrfy_childcursor(vdp, &cc)) != 0) + goto err; + for (ret = __db_vrfy_ccset(cc, pgno, &child); + ret == 0; + ret = __db_vrfy_ccnext(cc, &child)) { + stflags = flags | ST_RECNUM | ST_DUPSET; + /* Skip any overflow entries. */ + if (child->type == V_DUPLICATE) { + if ((ret = __db_vrfy_duptype( + dbp, vdp, child->pgno, + stflags)) != 0) { + isbad = 1; + /* Next child. */ + continue; + } + if ((ret = __bam_vrfy_subtree( + dbp, vdp, child->pgno, NULL, + NULL, stflags, NULL, NULL, + NULL)) != 0) { + if (ret != + DB_VERIFY_BAD) + goto err; + else + isbad = 1; + } + } + } + + if ((ret = __db_vrfy_ccclose(cc)) != 0) + goto err; + cc = NULL; + + /* + * If VRFY_DUPS_UNSORTED is set, + * ST_DUPSORT had better not be. + */ + if (F_ISSET(pip, VRFY_DUPS_UNSORTED) && + LF_ISSET(ST_DUPSORT)) { + EPRINT((dbp->dbenv, + "Unsorted duplicate set at page %lu in sorted-dup database", + (u_long)pgno)); + isbad = 1; + } + } + } + goto leaf; + break; + case P_IBTREE: + case P_IRECNO: + /* We handle these below. */ + break; + default: + /* + * If a P_IBTREE or P_IRECNO contains a reference to an + * invalid page, we'll wind up here; handle it gracefully. + * Note that the code at the "done" label assumes that the + * current page is a btree/recno one of some sort; this + * is not the case here, so we goto err. + */ + EPRINT((dbp->dbenv, + "Page %lu is of inappropriate type %lu", + (u_long)pgno, (u_long)pip->type)); + ret = DB_VERIFY_BAD; + goto err; + } + + /* + * Cases 4 & 5: This is a btree or recno internal page. For each child, + * recurse, keeping a running count of nrecs and making sure the level + * is always reasonable. + */ + if ((ret = __db_vrfy_childcursor(vdp, &cc)) != 0) + goto err; + for (ret = __db_vrfy_ccset(cc, pgno, &child); ret == 0; + ret = __db_vrfy_ccnext(cc, &child)) + if (child->type == V_RECNO) { + if (pip->type != P_IRECNO) { + TYPE_ERR_PRINT(dbp->dbenv, "__bam_vrfy_subtree", + pgno, pip->type); + DB_ASSERT(0); + ret = EINVAL; + goto err; + } + if ((ret = __bam_vrfy_subtree(dbp, vdp, child->pgno, + NULL, NULL, flags, &child_level, &child_nrecs, + &child_relen)) != 0) { + if (ret != DB_VERIFY_BAD) + goto done; + else + isbad = 1; + } + + if (LF_ISSET(ST_RELEN)) { + if (relen == 0) + relen = child_relen; + /* + * child_relen may be zero if the child subtree + * is empty. + */ + else if (child_relen > 0 && + relen != child_relen) { + isbad = 1; + EPRINT((dbp->dbenv, + "Recno page %lu returned bad re_len", + (u_long)child->pgno)); + } + if (relenp) + *relenp = relen; + } + if (LF_ISSET(ST_RECNUM)) + nrecs += child_nrecs; + if (level != child_level + 1) { + isbad = 1; + EPRINT((dbp->dbenv, "%s%lu%s%lu%s%lu", + "Recno level incorrect on page ", + (u_long)child->pgno, ": got ", + (u_long)child_level, ", expected ", + (u_long)(level - 1))); + } + } else if (child->type == V_OVERFLOW && + (ret = __db_vrfy_ovfl_structure(dbp, vdp, + child->pgno, child->tlen, flags)) != 0) { + if (ret == DB_VERIFY_BAD) + isbad = 1; + else + goto done; + } + + if ((ret = __db_vrfy_ccclose(cc)) != 0) + goto err; + cc = NULL; + + /* We're done with case 4. */ + if (pip->type == P_IRECNO) + goto done; + + /* + * Case 5. Btree internal pages. + * As described above, we need to iterate through all the + * items on the page and make sure that our children sort appropriately + * with respect to them. + * + * For each entry, li will be the "left-hand" key for the entry + * itself, which must sort lower than all entries on its child; + * ri will be the key to its right, which must sort greater. + */ + if (h == NULL && (ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) + goto err; + for (i = 0; i < pip->entries; i += O_INDX) { + li = GET_BINTERNAL(h, i); + ri = (i + O_INDX < pip->entries) ? + GET_BINTERNAL(h, i + O_INDX) : NULL; + + /* + * The leftmost key is forcibly sorted less than all entries, + * so don't bother passing it. + */ + if ((ret = __bam_vrfy_subtree(dbp, vdp, li->pgno, + i == 0 ? NULL : li, ri, flags, &child_level, + &child_nrecs, NULL)) != 0) { + if (ret != DB_VERIFY_BAD) + goto done; + else + isbad = 1; + } + + if (LF_ISSET(ST_RECNUM)) { + /* + * Keep a running tally on the actual record count so + * we can return it to our parent (if we have one) or + * compare it to the NRECS field if we're a root page. + */ + nrecs += child_nrecs; + + /* + * Make sure the actual record count of the child + * is equal to the value in the BINTERNAL structure. + */ + if (li->nrecs != child_nrecs) { + isbad = 1; + EPRINT((dbp->dbenv, + "Item %lu page %lu has incorrect record count of %lu, should be %lu", + (u_long)i, (u_long)pgno, (u_long)li->nrecs, + (u_long)child_nrecs)); + } + } + + if (level != child_level + 1) { + isbad = 1; + EPRINT((dbp->dbenv, "%s%lu%s%lu%s%lu", + "Btree level incorrect on page ", (u_long)li->pgno, + ": got ", (u_long)child_level, ", expected ", + (u_long)(level - 1))); + } + } + + if (0) { +leaf: level = LEAFLEVEL; + if (LF_ISSET(ST_RECNUM)) + nrecs = pip->rec_cnt; + + /* XXX + * We should verify that the record count on a leaf page + * is the sum of the number of keys and the number of + * records in its off-page dups. This requires looking + * at the page again, however, and it may all be changing + * soon, so for now we don't bother. + */ + + if (LF_ISSET(ST_RELEN) && relenp) + *relenp = pip->re_len; + } +done: if (F_ISSET(pip, VRFY_INCOMPLETE) && isbad == 0 && ret == 0) { + /* + * During the page-by-page pass, item order verification was + * not finished due to the presence of overflow items. If + * isbad == 0, though, it's now safe to do so, as we've + * traversed any child overflow pages. Do it. + */ + if (h == NULL && (ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) + goto err; + if ((ret = __bam_vrfy_itemorder(dbp, + vdp, h, pgno, 0, 1, 0, flags)) != 0) + goto err; + F_CLR(pip, VRFY_INCOMPLETE); + } + + /* + * Our parent has sent us BINTERNAL pointers to parent records + * so that we can verify our place with respect to them. If it's + * appropriate--we have a default sort function--verify this. + */ + if (isbad == 0 && ret == 0 && !LF_ISSET(DB_NOORDERCHK) && lp != NULL) { + if (h == NULL && (ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) + goto err; + + /* + * __bam_vrfy_treeorder needs to know what comparison function + * to use. If ST_DUPSET is set, we're in a duplicate tree + * and we use the duplicate comparison function; otherwise, + * use the btree one. If unset, use the default, of course. + */ + func = LF_ISSET(ST_DUPSET) ? dbp->dup_compare : + ((BTREE *)dbp->bt_internal)->bt_compare; + if (func == NULL) + func = __bam_defcmp; + + if ((ret = __bam_vrfy_treeorder( + dbp, pgno, h, lp, rp, func, flags)) != 0) { + if (ret == DB_VERIFY_BAD) + isbad = 1; + else + goto err; + } + } + + /* + * This is guaranteed to succeed for leaf pages, but no harm done. + * + * Internal pages below the top level do not store their own + * record numbers, so we skip them. + */ + if (LF_ISSET(ST_RECNUM) && nrecs != pip->rec_cnt && toplevel) { + isbad = 1; + EPRINT((dbp->dbenv, + "Bad record count on page %lu: got %lu, expected %lu", + (u_long)pgno, (u_long)nrecs, (u_long)pip->rec_cnt)); + } + + if (levelp) + *levelp = level; + if (nrecsp) + *nrecsp = nrecs; + + pgset = vdp->pgset; + if ((ret = __db_vrfy_pgset_get(pgset, pgno, &p)) != 0) + goto err; + if (p != 0) { + isbad = 1; + EPRINT((dbp->dbenv, "Page %lu linked twice", (u_long)pgno)); + } else if ((ret = __db_vrfy_pgset_inc(pgset, pgno)) != 0) + goto err; + +err: if (h != NULL && (t_ret = memp_fput(dbp->mpf, h, 0)) != 0 && ret == 0) + ret = t_ret; + if ((t_ret = __db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0) + ret = t_ret; + if (cc != NULL && ((t_ret = __db_vrfy_ccclose(cc)) != 0) && ret == 0) + ret = t_ret; + return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret); +} + +/* + * __bam_vrfy_treeorder -- + * Verify that the lowest key on a page sorts greater than the + * BINTERNAL which points to it (lp), and the highest key + * sorts less than the BINTERNAL above that (rp). + * + * If lp is NULL, this means that it was the leftmost key on the + * parent, which (regardless of sort function) sorts less than + * all keys. No need to check it. + * + * If rp is NULL, lp was the highest key on the parent, so there's + * no higher key we must sort less than. + */ +static int +__bam_vrfy_treeorder(dbp, pgno, h, lp, rp, func, flags) + DB *dbp; + db_pgno_t pgno; + PAGE *h; + BINTERNAL *lp, *rp; + int (*func) __P((DB *, const DBT *, const DBT *)); + u_int32_t flags; +{ + BOVERFLOW *bo; + DBT dbt; + db_indx_t last; + int ret, cmp; + + memset(&dbt, 0, sizeof(DBT)); + F_SET(&dbt, DB_DBT_MALLOC); + ret = 0; + + switch (TYPE(h)) { + case P_IBTREE: + case P_LDUP: + last = NUM_ENT(h) - O_INDX; + break; + case P_LBTREE: + last = NUM_ENT(h) - P_INDX; + break; + default: + TYPE_ERR_PRINT(dbp->dbenv, + "__bam_vrfy_treeorder", pgno, TYPE(h)); + DB_ASSERT(0); + return (EINVAL); + } + + /* + * The key on page h, the child page, is more likely to be + * an overflow page, so we pass its offset, rather than lp/rp's, + * into __bam_cmp. This will take advantage of __db_moff. + */ + + /* + * Skip first-item check if we're an internal page--the first + * entry on an internal page is treated specially by __bam_cmp, + * so what's on the page shouldn't matter. (Plus, since we're passing + * our page and item 0 as to __bam_cmp, we'll sort before our + * parent and falsely report a failure.) + */ + if (lp != NULL && TYPE(h) != P_IBTREE) { + if (lp->type == B_KEYDATA) { + dbt.data = lp->data; + dbt.size = lp->len; + } else if (lp->type == B_OVERFLOW) { + bo = (BOVERFLOW *)lp->data; + if ((ret = __db_goff(dbp, &dbt, bo->tlen, bo->pgno, + NULL, NULL)) != 0) + return (ret); + } else { + DB_ASSERT(0); + EPRINT((dbp->dbenv, + "Unknown type for internal record")); + return (EINVAL); + } + + /* On error, fall through, free if neeeded, and return. */ + if ((ret = __bam_cmp(dbp, &dbt, h, 0, func, &cmp)) == 0) { + if (cmp > 0) { + EPRINT((dbp->dbenv, + "First item on page %lu sorted greater than parent entry", + (u_long)PGNO(h))); + ret = DB_VERIFY_BAD; + } + } else + EPRINT((dbp->dbenv, + "First item on page %lu had comparison error", + (u_long)PGNO(h))); + + if (dbt.data != lp->data) + __os_free(dbt.data, 0); + if (ret != 0) + return (ret); + } + + if (rp != NULL) { + if (rp->type == B_KEYDATA) { + dbt.data = rp->data; + dbt.size = rp->len; + } else if (rp->type == B_OVERFLOW) { + bo = (BOVERFLOW *)rp->data; + if ((ret = __db_goff(dbp, &dbt, bo->tlen, bo->pgno, + NULL, NULL)) != 0) + return (ret); + } else { + DB_ASSERT(0); + EPRINT((dbp->dbenv, + "Unknown type for internal record")); + return (EINVAL); + } + + /* On error, fall through, free if neeeded, and return. */ + if ((ret = __bam_cmp(dbp, &dbt, h, last, func, &cmp)) == 0) { + if (cmp < 0) { + EPRINT((dbp->dbenv, + "Last item on page %lu sorted greater than parent entry", + (u_long)PGNO(h))); + ret = DB_VERIFY_BAD; + } + } else + EPRINT((dbp->dbenv, + "Last item on page %lu had comparison error", + (u_long)PGNO(h))); + + if (dbt.data != rp->data) + __os_free(dbt.data, 0); + } + + return (ret); +} + +/* + * __bam_salvage -- + * Safely dump out anything that looks like a key on an alleged + * btree leaf page. + * + * PUBLIC: int __bam_salvage __P((DB *, VRFY_DBINFO *, db_pgno_t, u_int32_t, + * PUBLIC: PAGE *, void *, int (*)(void *, const void *), DBT *, + * PUBLIC: u_int32_t)); + */ +int +__bam_salvage(dbp, vdp, pgno, pgtype, h, handle, callback, key, flags) + DB *dbp; + VRFY_DBINFO *vdp; + db_pgno_t pgno; + u_int32_t pgtype; + PAGE *h; + void *handle; + int (*callback) __P((void *, const void *)); + DBT *key; + u_int32_t flags; +{ + DBT dbt, unkdbt; + BKEYDATA *bk; + BOVERFLOW *bo; + db_indx_t i, beg, end; + u_int32_t himark; + u_int8_t *pgmap; + void *ovflbuf; + int t_ret, ret, err_ret; + + /* Shut up lint. */ + COMPQUIET(end, 0); + + ovflbuf = pgmap = NULL; + err_ret = ret = 0; + + memset(&dbt, 0, sizeof(DBT)); + dbt.flags = DB_DBT_REALLOC; + + memset(&unkdbt, 0, sizeof(DBT)); + unkdbt.size = strlen("UNKNOWN") + 1; + unkdbt.data = "UNKNOWN"; + + /* + * Allocate a buffer for overflow items. Start at one page; + * __db_safe_goff will realloc as needed. + */ + if ((ret = __os_malloc(dbp->dbenv, dbp->pgsize, NULL, &ovflbuf)) != 0) + return (ret); + + if (LF_ISSET(DB_AGGRESSIVE)) { + if ((ret = + __os_malloc(dbp->dbenv, dbp->pgsize, NULL, &pgmap)) != 0) + goto err; + memset(pgmap, 0, dbp->pgsize); + } + + /* + * Loop through the inp array, spitting out key/data pairs. + * + * If we're salvaging normally, loop from 0 through NUM_ENT(h). + * If we're being aggressive, loop until we hit the end of the page-- + * NUM_ENT() may be bogus. + */ + himark = dbp->pgsize; + for (i = 0;; i += O_INDX) { + /* If we're not aggressive, break when we hit NUM_ENT(h). */ + if (!LF_ISSET(DB_AGGRESSIVE) && i >= NUM_ENT(h)) + break; + + /* Verify the current item. */ + ret = __db_vrfy_inpitem(dbp, + h, pgno, i, 1, flags, &himark, NULL); + /* If this returned a fatality, it's time to break. */ + if (ret == DB_VERIFY_FATAL) { + /* + * Don't return DB_VERIFY_FATAL; it's private + * and means only that we can't go on with this + * page, not with the whole database. It's + * not even an error if we've run into it + * after NUM_ENT(h). + */ + ret = (i < NUM_ENT(h)) ? DB_VERIFY_BAD : 0; + break; + } + + /* + * If this returned 0, it's safe to print or (carefully) + * try to fetch. + */ + if (ret == 0) { + /* + * We only want to print deleted items if + * DB_AGGRESSIVE is set. + */ + bk = GET_BKEYDATA(h, i); + if (!LF_ISSET(DB_AGGRESSIVE) && B_DISSET(bk->type)) + continue; + + /* + * We're going to go try to print the next item. If + * key is non-NULL, we're a dup page, so we've got to + * print the key first, unless SA_SKIPFIRSTKEY is set + * and we're on the first entry. + */ + if (key != NULL && + (i != 0 || !LF_ISSET(SA_SKIPFIRSTKEY))) + if ((ret = __db_prdbt(key, + 0, " ", handle, callback, 0, NULL)) != 0) + err_ret = ret; + + beg = h->inp[i]; + switch (B_TYPE(bk->type)) { + case B_DUPLICATE: + end = beg + BOVERFLOW_SIZE - 1; + /* + * If we're not on a normal btree leaf page, + * there shouldn't be off-page + * dup sets. Something's confused; just + * drop it, and the code to pick up unlinked + * offpage dup sets will print it out + * with key "UNKNOWN" later. + */ + if (pgtype != P_LBTREE) + break; + + bo = (BOVERFLOW *)bk; + + /* + * If the page number is unreasonable, or + * if this is supposed to be a key item, + * just spit out "UNKNOWN"--the best we + * can do is run into the data items in the + * unlinked offpage dup pass. + */ + if (!IS_VALID_PGNO(bo->pgno) || + (i % P_INDX == 0)) { + /* Not much to do on failure. */ + if ((ret = __db_prdbt(&unkdbt, 0, " ", + handle, callback, 0, NULL)) != 0) + err_ret = ret; + break; + } + + if ((ret = __db_salvage_duptree(dbp, + vdp, bo->pgno, &dbt, handle, callback, + flags | SA_SKIPFIRSTKEY)) != 0) + err_ret = ret; + + break; + case B_KEYDATA: + end = ALIGN(beg + bk->len, sizeof(u_int32_t)) - 1; + dbt.data = bk->data; + dbt.size = bk->len; + if ((ret = __db_prdbt(&dbt, + 0, " ", handle, callback, 0, NULL)) != 0) + err_ret = ret; + break; + case B_OVERFLOW: + end = beg + BOVERFLOW_SIZE - 1; + bo = (BOVERFLOW *)bk; + if ((ret = __db_safe_goff(dbp, vdp, + bo->pgno, &dbt, &ovflbuf, flags)) != 0) { + err_ret = ret; + /* We care about err_ret more. */ + (void)__db_prdbt(&unkdbt, 0, " ", + handle, callback, 0, NULL); + break; + } + if ((ret = __db_prdbt(&dbt, + 0, " ", handle, callback, 0, NULL)) != 0) + err_ret = ret; + break; + default: + /* + * We should never get here; __db_vrfy_inpitem + * should not be returning 0 if bk->type + * is unrecognizable. + */ + DB_ASSERT(0); + return (EINVAL); + } + + /* + * If we're being aggressive, mark the beginning + * and end of the item; we'll come back and print + * whatever "junk" is in the gaps in case we had + * any bogus inp elements and thereby missed stuff. + */ + if (LF_ISSET(DB_AGGRESSIVE)) { + pgmap[beg] = ITEM_BEGIN; + pgmap[end] = ITEM_END; + } + } + } + + /* + * If i is odd and this is a btree leaf, we've printed out a key but not + * a datum; fix this imbalance by printing an "UNKNOWN". + */ + if (pgtype == P_LBTREE && (i % P_INDX == 1) && ((ret = + __db_prdbt(&unkdbt, 0, " ", handle, callback, 0, NULL)) != 0)) + err_ret = ret; + +err: if (pgmap != NULL) + __os_free(pgmap, 0); + __os_free(ovflbuf, 0); + + /* Mark this page as done. */ + if ((t_ret = __db_salvage_markdone(vdp, pgno)) != 0) + return (t_ret); + + return ((err_ret != 0) ? err_ret : ret); +} + +/* + * __bam_salvage_walkdupint -- + * Walk a known-good btree or recno internal page which is part of + * a dup tree, calling __db_salvage_duptree on each child page. + * + * PUBLIC: int __bam_salvage_walkdupint __P((DB *, VRFY_DBINFO *, PAGE *, + * PUBLIC: DBT *, void *, int (*)(void *, const void *), u_int32_t)); + */ +int +__bam_salvage_walkdupint(dbp, vdp, h, key, handle, callback, flags) + DB *dbp; + VRFY_DBINFO *vdp; + PAGE *h; + DBT *key; + void *handle; + int (*callback) __P((void *, const void *)); + u_int32_t flags; +{ + RINTERNAL *ri; + BINTERNAL *bi; + int ret, t_ret; + db_indx_t i; + + ret = 0; + for (i = 0; i < NUM_ENT(h); i++) { + switch (TYPE(h)) { + case P_IBTREE: + bi = GET_BINTERNAL(h, i); + if ((t_ret = __db_salvage_duptree(dbp, + vdp, bi->pgno, key, handle, callback, flags)) != 0) + ret = t_ret; + case P_IRECNO: + ri = GET_RINTERNAL(h, i); + if ((t_ret = __db_salvage_duptree(dbp, + vdp, ri->pgno, key, handle, callback, flags)) != 0) + ret = t_ret; + break; + default: + __db_err(dbp->dbenv, + "__bam_salvage_walkdupint called on non-int. page"); + DB_ASSERT(0); + return (EINVAL); + } + /* Pass SA_SKIPFIRSTKEY, if set, on to the 0th child only. */ + flags &= ~LF_ISSET(SA_SKIPFIRSTKEY); + } + + return (ret); +} + +/* + * __bam_meta2pgset -- + * Given a known-good meta page, return in pgsetp a 0-terminated list of + * db_pgno_t's corresponding to the pages in the btree. + * + * We do this by a somewhat sleazy method, to avoid having to traverse the + * btree structure neatly: we walk down the left side to the very + * first leaf page, then we mark all the pages in the chain of + * NEXT_PGNOs (being wary of cycles and invalid ones), then we + * consolidate our scratch array into a nice list, and return. This + * avoids the memory management hassles of recursion and the + * trouble of walking internal pages--they just don't matter, except + * for the left branch. + * + * PUBLIC: int __bam_meta2pgset __P((DB *, VRFY_DBINFO *, BTMETA *, + * PUBLIC: u_int32_t, DB *)); + */ +int +__bam_meta2pgset(dbp, vdp, btmeta, flags, pgset) + DB *dbp; + VRFY_DBINFO *vdp; + BTMETA *btmeta; + u_int32_t flags; + DB *pgset; +{ + BINTERNAL *bi; + PAGE *h; + RINTERNAL *ri; + db_pgno_t current, p; + int err_ret, ret; + + h = NULL; + ret = err_ret = 0; + DB_ASSERT(pgset != NULL); + for (current = btmeta->root;;) { + if (!IS_VALID_PGNO(current) || current == PGNO(btmeta)) { + err_ret = DB_VERIFY_BAD; + goto err; + } + if ((ret = memp_fget(dbp->mpf, ¤t, 0, &h)) != 0) { + err_ret = ret; + goto err; + } + + switch (TYPE(h)) { + case P_IBTREE: + case P_IRECNO: + if ((ret = __bam_vrfy(dbp, + vdp, h, current, flags | DB_NOORDERCHK)) != 0) { + err_ret = ret; + goto err; + } + if (TYPE(h) == P_IBTREE) { + bi = GET_BINTERNAL(h, 0); + current = bi->pgno; + } else { /* P_IRECNO */ + ri = GET_RINTERNAL(h, 0); + current = ri->pgno; + } + break; + case P_LBTREE: + case P_LRECNO: + goto traverse; + default: + err_ret = DB_VERIFY_BAD; + goto err; + } + + if ((ret = memp_fput(dbp->mpf, h, 0)) != 0) + err_ret = ret; + h = NULL; + } + + /* + * At this point, current is the pgno of leaf page h, the 0th in the + * tree we're concerned with. + */ +traverse: + while (IS_VALID_PGNO(current) && current != PGNO_INVALID) { + if (h == NULL && + (ret = memp_fget(dbp->mpf, ¤t, 0, &h) != 0)) { + err_ret = ret; + break; + } + + if ((ret = __db_vrfy_pgset_get(pgset, current, (int *)&p)) != 0) + goto err; + + if (p != 0) { + /* + * We've found a cycle. Return success anyway-- + * our caller may as well use however much of + * the pgset we've come up with. + */ + break; + } + if ((ret = __db_vrfy_pgset_inc(pgset, current)) != 0) + goto err; + + current = NEXT_PGNO(h); + if ((ret = memp_fput(dbp->mpf, h, 0)) != 0) + err_ret = ret; + h = NULL; + } + +err: if (h != NULL) + (void)memp_fput(dbp->mpf, h, 0); + + return (ret == 0 ? err_ret : ret); +} + +/* + * __bam_safe_getdata -- + * + * Utility function for __bam_vrfy_itemorder. Safely gets the datum at + * index i, page h, and sticks it in DBT dbt. If ovflok is 1 and i's an + * overflow item, we do a safe_goff to get the item and signal that we need + * to free dbt->data; if ovflok is 0, we leaves the DBT zeroed. + */ +static int +__bam_safe_getdata(dbp, h, i, ovflok, dbt, freedbtp) + DB *dbp; + PAGE *h; + u_int32_t i; + int ovflok; + DBT *dbt; + int *freedbtp; +{ + BKEYDATA *bk; + BOVERFLOW *bo; + + memset(dbt, 0, sizeof(DBT)); + *freedbtp = 0; + + bk = GET_BKEYDATA(h, i); + if (B_TYPE(bk->type) == B_OVERFLOW) { + if (!ovflok) + return (0); + + bo = (BOVERFLOW *)bk; + F_SET(dbt, DB_DBT_MALLOC); + + *freedbtp = 1; + return (__db_goff(dbp, dbt, bo->tlen, bo->pgno, NULL, NULL)); + } else { + dbt->data = bk->data; + dbt->size = bk->len; + } + + return (0); +} diff --git a/db/btree/btree.src b/db/btree/btree.src new file mode 100644 index 000000000..a1eba7d7f --- /dev/null +++ b/db/btree/btree.src @@ -0,0 +1,296 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: btree.src,v 10.26 2000/12/12 17:40:23 bostic Exp $ + */ + +PREFIX bam + +INCLUDE #include "db_config.h" +INCLUDE +INCLUDE #ifndef NO_SYSTEM_INCLUDES +INCLUDE #include +INCLUDE +INCLUDE #include +INCLUDE #include +INCLUDE #include +INCLUDE #endif +INCLUDE +INCLUDE #include "db_int.h" +INCLUDE #include "db_page.h" +INCLUDE #include "db_dispatch.h" +INCLUDE #include "db_am.h" +INCLUDE #include "btree.h" +INCLUDE #include "txn.h" +INCLUDE + +/* + * BTREE-pg_alloc: used to record allocating a new page. + * + * meta_lsn: the meta-data page's original lsn. + * page_lsn: the allocated page's original lsn. + * pgno: the page allocated. + * next: the next page on the free list. + */ +BEGIN pg_alloc 51 +ARG fileid int32_t ld +POINTER meta_lsn DB_LSN * lu +POINTER page_lsn DB_LSN * lu +ARG pgno db_pgno_t lu +ARG ptype u_int32_t lu +ARG next db_pgno_t lu +END + +DEPRECATED pg_alloc1 60 +ARG fileid int32_t ld +POINTER meta_lsn DB_LSN * lu +POINTER alloc_lsn DB_LSN * lu +POINTER page_lsn DB_LSN * lu +ARG pgno db_pgno_t lu +ARG ptype u_int32_t lu +ARG next db_pgno_t lu +END + +/* + * BTREE-pg_free: used to record freeing a page. + * + * pgno: the page being freed. + * meta_lsn: the meta-data page's original lsn. + * header: the header from the free'd page. + * next: the previous next pointer on the metadata page. + */ +BEGIN pg_free 52 +ARG fileid int32_t ld +ARG pgno db_pgno_t lu +POINTER meta_lsn DB_LSN * lu +DBT header DBT s +ARG next db_pgno_t lu +END + +DEPRECATED pg_free1 61 +ARG fileid int32_t ld +ARG pgno db_pgno_t lu +POINTER meta_lsn DB_LSN * lu +POINTER alloc_lsn DB_LSN * lu +DBT header DBT s +ARG next db_pgno_t lu +END + +/* + * BTREE-split: used to log a page split. + * + * left: the page number for the low-order contents. + * llsn: the left page's original LSN. + * right: the page number for the high-order contents. + * rlsn: the right page's original LSN. + * indx: the number of entries that went to the left page. + * npgno: the next page number + * nlsn: the next page's original LSN (or 0 if no next page). + * pg: the split page's contents before the split. + */ +DEPRECATED split1 53 +ARG fileid int32_t ld +ARG left db_pgno_t lu +POINTER llsn DB_LSN * lu +ARG right db_pgno_t lu +POINTER rlsn DB_LSN * lu +ARG indx u_int32_t lu +ARG npgno db_pgno_t lu +POINTER nlsn DB_LSN * lu +DBT pg DBT s +END + +/* + * BTREE-split: used to log a page split. + * + * left: the page number for the low-order contents. + * llsn: the left page's original LSN. + * right: the page number for the high-order contents. + * rlsn: the right page's original LSN. + * indx: the number of entries that went to the left page. + * npgno: the next page number + * npgno: the next page number + * nlsn: the next page's original LSN (or 0 if no next page). + * root_pgno: the root page number + * pg: the split page's contents before the split. + * opflags: SPL_NRECS: if splitting a tree that maintains a record count. + */ +BEGIN split 62 +ARG fileid int32_t ld +ARG left db_pgno_t lu +POINTER llsn DB_LSN * lu +ARG right db_pgno_t lu +POINTER rlsn DB_LSN * lu +ARG indx u_int32_t lu +ARG npgno db_pgno_t lu +POINTER nlsn DB_LSN * lu +ARG root_pgno db_pgno_t lu +DBT pg DBT s +ARG opflags u_int32_t lu +END + +/* + * BTREE-rsplit: used to log a reverse-split + * + * pgno: the page number of the page copied over the root. + * pgdbt: the page being copied on the root page. + * nrec: the tree's record count. + * rootent: last entry on the root page. + * rootlsn: the root page's original lsn. + */ +DEPRECATED rsplit1 54 +ARG fileid int32_t ld +ARG pgno db_pgno_t lu +DBT pgdbt DBT s +ARG nrec db_pgno_t lu +DBT rootent DBT s +POINTER rootlsn DB_LSN * lu +END + +/* + * BTREE-rsplit: used to log a reverse-split + * + * pgno: the page number of the page copied over the root. + * pgdbt: the page being copied on the root page. + * root_pgno: the root page number. + * nrec: the tree's record count. + * rootent: last entry on the root page. + * rootlsn: the root page's original lsn. + */ +BEGIN rsplit 63 +ARG fileid int32_t ld +ARG pgno db_pgno_t lu +DBT pgdbt DBT s +ARG root_pgno db_pgno_t lu +ARG nrec db_pgno_t lu +DBT rootent DBT s +POINTER rootlsn DB_LSN * lu +END + +/* + * BTREE-adj: used to log the adjustment of an index. + * + * pgno: the page modified. + * lsn: the page's original lsn. + * indx: the index adjusted. + * indx_copy: the index to copy if inserting. + * is_insert: 0 if a delete, 1 if an insert. + */ +BEGIN adj 55 +ARG fileid int32_t ld +ARG pgno db_pgno_t lu +POINTER lsn DB_LSN * lu +ARG indx u_int32_t lu +ARG indx_copy u_int32_t lu +ARG is_insert u_int32_t lu +END + +/* + * BTREE-cadjust: used to adjust the count change in an internal page. + * + * pgno: the page modified. + * lsn: the page's original lsn. + * indx: the index to be adjusted. + * adjust: the signed adjustment. + * opflags: CAD_UPDATEROOT: if root page count was adjusted. + */ +BEGIN cadjust 56 +ARG fileid int32_t ld +ARG pgno db_pgno_t lu +POINTER lsn DB_LSN * lu +ARG indx u_int32_t lu +ARG adjust int32_t ld +ARG opflags u_int32_t lu +END + +/* + * BTREE-cdel: used to log the intent-to-delete of a cursor record. + * + * pgno: the page modified. + * lsn: the page's original lsn. + * indx: the index to be deleted. + */ +BEGIN cdel 57 +ARG fileid int32_t ld +ARG pgno db_pgno_t lu +POINTER lsn DB_LSN * lu +ARG indx u_int32_t lu +END + +/* + * BTREE-repl: used to log the replacement of an item. + * + * pgno: the page modified. + * lsn: the page's original lsn. + * orig: the original data. + * new: the replacement data. + * duplicate: the prefix of the replacement that matches the original. + */ +BEGIN repl 58 +ARG fileid int32_t ld +ARG pgno db_pgno_t lu +POINTER lsn DB_LSN * lu +ARG indx u_int32_t lu +ARG isdeleted u_int32_t lu +DBT orig DBT s +DBT repl DBT s +ARG prefix u_int32_t lu +ARG suffix u_int32_t lu +END + +/* + * BTREE-root: log the assignment of a root btree page. + */ +BEGIN root 59 +ARG fileid int32_t ld +ARG meta_pgno db_pgno_t lu +ARG root_pgno db_pgno_t lu +POINTER meta_lsn DB_LSN * lu +END + +/* + * BTREE-curadj: undo cursor adjustments on txn abort. + * Should only be processed during DB_TXN_ABORT. + * NOTE: the first_indx field gets used to hold + * signed index adjustment in one case. + * care should be taken if its size is changed. + */ +BEGIN curadj 64 +/* Fileid of db affected. */ +ARG fileid int32_t ld +/* Which adjustment. */ +ARG mode db_ca_mode ld +/* Page entry is from. */ +ARG from_pgno db_pgno_t lu +/* Page entry went to. */ +ARG to_pgno db_pgno_t lu +/* Left page of root split. */ +ARG left_pgno db_pgno_t lu +/* First index of dup set. Also used as adjustment. */ +ARG first_indx u_int32_t lu +/* Index entry is from. */ +ARG from_indx u_int32_t lu +/* Index where entry went. */ +ARG to_indx u_int32_t lu +END + +/* + * BTREE-rcuradj: undo cursor adjustments on txn abort in + * renumbering recno trees. + * Should only be processed during DB_TXN_ABORT. + */ +BEGIN rcuradj 65 +/* Fileid of db affected. */ +ARG fileid int32_t ld +/* Which adjustment. */ +ARG mode ca_recno_arg ld +/* Root page number. */ +ARG root db_pgno_t ld +/* Recno of the adjustment. */ +ARG recno db_recno_t ld +/* Order number of the adjustment. */ +ARG order u_int32_t ld +END diff --git a/db/btree/btree_auto.c b/db/btree/btree_auto.c new file mode 100644 index 000000000..fdb27b7d2 --- /dev/null +++ b/db/btree/btree_auto.c @@ -0,0 +1,2284 @@ +/* Do not edit: automatically built by gen_rec.awk. */ +#include "db_config.h" + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_dispatch.h" +#include "db_am.h" +#include "btree.h" +#include "txn.h" + +int +__bam_pg_alloc_log(dbenv, txnid, ret_lsnp, flags, + fileid, meta_lsn, page_lsn, pgno, ptype, next) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + int32_t fileid; + DB_LSN * meta_lsn; + DB_LSN * page_lsn; + db_pgno_t pgno; + u_int32_t ptype; + db_pgno_t next; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_bam_pg_alloc; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(fileid) + + sizeof(*meta_lsn) + + sizeof(*page_lsn) + + sizeof(pgno) + + sizeof(ptype) + + sizeof(next); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &fileid, sizeof(fileid)); + bp += sizeof(fileid); + if (meta_lsn != NULL) + memcpy(bp, meta_lsn, sizeof(*meta_lsn)); + else + memset(bp, 0, sizeof(*meta_lsn)); + bp += sizeof(*meta_lsn); + if (page_lsn != NULL) + memcpy(bp, page_lsn, sizeof(*page_lsn)); + else + memset(bp, 0, sizeof(*page_lsn)); + bp += sizeof(*page_lsn); + memcpy(bp, &pgno, sizeof(pgno)); + bp += sizeof(pgno); + memcpy(bp, &ptype, sizeof(ptype)); + bp += sizeof(ptype); + memcpy(bp, &next, sizeof(next)); + bp += sizeof(next); + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__bam_pg_alloc_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __bam_pg_alloc_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __bam_pg_alloc_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]bam_pg_alloc: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tmeta_lsn: [%lu][%lu]\n", + (u_long)argp->meta_lsn.file, (u_long)argp->meta_lsn.offset); + printf("\tpage_lsn: [%lu][%lu]\n", + (u_long)argp->page_lsn.file, (u_long)argp->page_lsn.offset); + printf("\tpgno: %lu\n", (u_long)argp->pgno); + printf("\tptype: %lu\n", (u_long)argp->ptype); + printf("\tnext: %lu\n", (u_long)argp->next); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__bam_pg_alloc_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __bam_pg_alloc_args **argpp; +{ + __bam_pg_alloc_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__bam_pg_alloc_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->meta_lsn, bp, sizeof(argp->meta_lsn)); + bp += sizeof(argp->meta_lsn); + memcpy(&argp->page_lsn, bp, sizeof(argp->page_lsn)); + bp += sizeof(argp->page_lsn); + memcpy(&argp->pgno, bp, sizeof(argp->pgno)); + bp += sizeof(argp->pgno); + memcpy(&argp->ptype, bp, sizeof(argp->ptype)); + bp += sizeof(argp->ptype); + memcpy(&argp->next, bp, sizeof(argp->next)); + bp += sizeof(argp->next); + *argpp = argp; + return (0); +} + +int +__bam_pg_alloc1_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __bam_pg_alloc1_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __bam_pg_alloc1_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]bam_pg_alloc1: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tmeta_lsn: [%lu][%lu]\n", + (u_long)argp->meta_lsn.file, (u_long)argp->meta_lsn.offset); + printf("\talloc_lsn: [%lu][%lu]\n", + (u_long)argp->alloc_lsn.file, (u_long)argp->alloc_lsn.offset); + printf("\tpage_lsn: [%lu][%lu]\n", + (u_long)argp->page_lsn.file, (u_long)argp->page_lsn.offset); + printf("\tpgno: %lu\n", (u_long)argp->pgno); + printf("\tptype: %lu\n", (u_long)argp->ptype); + printf("\tnext: %lu\n", (u_long)argp->next); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__bam_pg_alloc1_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __bam_pg_alloc1_args **argpp; +{ + __bam_pg_alloc1_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__bam_pg_alloc1_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->meta_lsn, bp, sizeof(argp->meta_lsn)); + bp += sizeof(argp->meta_lsn); + memcpy(&argp->alloc_lsn, bp, sizeof(argp->alloc_lsn)); + bp += sizeof(argp->alloc_lsn); + memcpy(&argp->page_lsn, bp, sizeof(argp->page_lsn)); + bp += sizeof(argp->page_lsn); + memcpy(&argp->pgno, bp, sizeof(argp->pgno)); + bp += sizeof(argp->pgno); + memcpy(&argp->ptype, bp, sizeof(argp->ptype)); + bp += sizeof(argp->ptype); + memcpy(&argp->next, bp, sizeof(argp->next)); + bp += sizeof(argp->next); + *argpp = argp; + return (0); +} + +int +__bam_pg_free_log(dbenv, txnid, ret_lsnp, flags, + fileid, pgno, meta_lsn, header, next) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + int32_t fileid; + db_pgno_t pgno; + DB_LSN * meta_lsn; + const DBT *header; + db_pgno_t next; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t zero; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_bam_pg_free; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(fileid) + + sizeof(pgno) + + sizeof(*meta_lsn) + + sizeof(u_int32_t) + (header == NULL ? 0 : header->size) + + sizeof(next); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &fileid, sizeof(fileid)); + bp += sizeof(fileid); + memcpy(bp, &pgno, sizeof(pgno)); + bp += sizeof(pgno); + if (meta_lsn != NULL) + memcpy(bp, meta_lsn, sizeof(*meta_lsn)); + else + memset(bp, 0, sizeof(*meta_lsn)); + bp += sizeof(*meta_lsn); + if (header == NULL) { + zero = 0; + memcpy(bp, &zero, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + } else { + memcpy(bp, &header->size, sizeof(header->size)); + bp += sizeof(header->size); + memcpy(bp, header->data, header->size); + bp += header->size; + } + memcpy(bp, &next, sizeof(next)); + bp += sizeof(next); + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__bam_pg_free_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __bam_pg_free_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __bam_pg_free_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]bam_pg_free: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tpgno: %lu\n", (u_long)argp->pgno); + printf("\tmeta_lsn: [%lu][%lu]\n", + (u_long)argp->meta_lsn.file, (u_long)argp->meta_lsn.offset); + printf("\theader: "); + for (i = 0; i < argp->header.size; i++) { + ch = ((u_int8_t *)argp->header.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\tnext: %lu\n", (u_long)argp->next); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__bam_pg_free_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __bam_pg_free_args **argpp; +{ + __bam_pg_free_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__bam_pg_free_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->pgno, bp, sizeof(argp->pgno)); + bp += sizeof(argp->pgno); + memcpy(&argp->meta_lsn, bp, sizeof(argp->meta_lsn)); + bp += sizeof(argp->meta_lsn); + memset(&argp->header, 0, sizeof(argp->header)); + memcpy(&argp->header.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->header.data = bp; + bp += argp->header.size; + memcpy(&argp->next, bp, sizeof(argp->next)); + bp += sizeof(argp->next); + *argpp = argp; + return (0); +} + +int +__bam_pg_free1_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __bam_pg_free1_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __bam_pg_free1_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]bam_pg_free1: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tpgno: %lu\n", (u_long)argp->pgno); + printf("\tmeta_lsn: [%lu][%lu]\n", + (u_long)argp->meta_lsn.file, (u_long)argp->meta_lsn.offset); + printf("\talloc_lsn: [%lu][%lu]\n", + (u_long)argp->alloc_lsn.file, (u_long)argp->alloc_lsn.offset); + printf("\theader: "); + for (i = 0; i < argp->header.size; i++) { + ch = ((u_int8_t *)argp->header.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\tnext: %lu\n", (u_long)argp->next); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__bam_pg_free1_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __bam_pg_free1_args **argpp; +{ + __bam_pg_free1_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__bam_pg_free1_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->pgno, bp, sizeof(argp->pgno)); + bp += sizeof(argp->pgno); + memcpy(&argp->meta_lsn, bp, sizeof(argp->meta_lsn)); + bp += sizeof(argp->meta_lsn); + memcpy(&argp->alloc_lsn, bp, sizeof(argp->alloc_lsn)); + bp += sizeof(argp->alloc_lsn); + memset(&argp->header, 0, sizeof(argp->header)); + memcpy(&argp->header.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->header.data = bp; + bp += argp->header.size; + memcpy(&argp->next, bp, sizeof(argp->next)); + bp += sizeof(argp->next); + *argpp = argp; + return (0); +} + +int +__bam_split1_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __bam_split1_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __bam_split1_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]bam_split1: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tleft: %lu\n", (u_long)argp->left); + printf("\tllsn: [%lu][%lu]\n", + (u_long)argp->llsn.file, (u_long)argp->llsn.offset); + printf("\tright: %lu\n", (u_long)argp->right); + printf("\trlsn: [%lu][%lu]\n", + (u_long)argp->rlsn.file, (u_long)argp->rlsn.offset); + printf("\tindx: %lu\n", (u_long)argp->indx); + printf("\tnpgno: %lu\n", (u_long)argp->npgno); + printf("\tnlsn: [%lu][%lu]\n", + (u_long)argp->nlsn.file, (u_long)argp->nlsn.offset); + printf("\tpg: "); + for (i = 0; i < argp->pg.size; i++) { + ch = ((u_int8_t *)argp->pg.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__bam_split1_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __bam_split1_args **argpp; +{ + __bam_split1_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__bam_split1_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->left, bp, sizeof(argp->left)); + bp += sizeof(argp->left); + memcpy(&argp->llsn, bp, sizeof(argp->llsn)); + bp += sizeof(argp->llsn); + memcpy(&argp->right, bp, sizeof(argp->right)); + bp += sizeof(argp->right); + memcpy(&argp->rlsn, bp, sizeof(argp->rlsn)); + bp += sizeof(argp->rlsn); + memcpy(&argp->indx, bp, sizeof(argp->indx)); + bp += sizeof(argp->indx); + memcpy(&argp->npgno, bp, sizeof(argp->npgno)); + bp += sizeof(argp->npgno); + memcpy(&argp->nlsn, bp, sizeof(argp->nlsn)); + bp += sizeof(argp->nlsn); + memset(&argp->pg, 0, sizeof(argp->pg)); + memcpy(&argp->pg.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->pg.data = bp; + bp += argp->pg.size; + *argpp = argp; + return (0); +} + +int +__bam_split_log(dbenv, txnid, ret_lsnp, flags, + fileid, left, llsn, right, rlsn, indx, + npgno, nlsn, root_pgno, pg, opflags) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + int32_t fileid; + db_pgno_t left; + DB_LSN * llsn; + db_pgno_t right; + DB_LSN * rlsn; + u_int32_t indx; + db_pgno_t npgno; + DB_LSN * nlsn; + db_pgno_t root_pgno; + const DBT *pg; + u_int32_t opflags; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t zero; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_bam_split; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(fileid) + + sizeof(left) + + sizeof(*llsn) + + sizeof(right) + + sizeof(*rlsn) + + sizeof(indx) + + sizeof(npgno) + + sizeof(*nlsn) + + sizeof(root_pgno) + + sizeof(u_int32_t) + (pg == NULL ? 0 : pg->size) + + sizeof(opflags); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &fileid, sizeof(fileid)); + bp += sizeof(fileid); + memcpy(bp, &left, sizeof(left)); + bp += sizeof(left); + if (llsn != NULL) + memcpy(bp, llsn, sizeof(*llsn)); + else + memset(bp, 0, sizeof(*llsn)); + bp += sizeof(*llsn); + memcpy(bp, &right, sizeof(right)); + bp += sizeof(right); + if (rlsn != NULL) + memcpy(bp, rlsn, sizeof(*rlsn)); + else + memset(bp, 0, sizeof(*rlsn)); + bp += sizeof(*rlsn); + memcpy(bp, &indx, sizeof(indx)); + bp += sizeof(indx); + memcpy(bp, &npgno, sizeof(npgno)); + bp += sizeof(npgno); + if (nlsn != NULL) + memcpy(bp, nlsn, sizeof(*nlsn)); + else + memset(bp, 0, sizeof(*nlsn)); + bp += sizeof(*nlsn); + memcpy(bp, &root_pgno, sizeof(root_pgno)); + bp += sizeof(root_pgno); + if (pg == NULL) { + zero = 0; + memcpy(bp, &zero, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + } else { + memcpy(bp, &pg->size, sizeof(pg->size)); + bp += sizeof(pg->size); + memcpy(bp, pg->data, pg->size); + bp += pg->size; + } + memcpy(bp, &opflags, sizeof(opflags)); + bp += sizeof(opflags); + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__bam_split_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __bam_split_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __bam_split_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]bam_split: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tleft: %lu\n", (u_long)argp->left); + printf("\tllsn: [%lu][%lu]\n", + (u_long)argp->llsn.file, (u_long)argp->llsn.offset); + printf("\tright: %lu\n", (u_long)argp->right); + printf("\trlsn: [%lu][%lu]\n", + (u_long)argp->rlsn.file, (u_long)argp->rlsn.offset); + printf("\tindx: %lu\n", (u_long)argp->indx); + printf("\tnpgno: %lu\n", (u_long)argp->npgno); + printf("\tnlsn: [%lu][%lu]\n", + (u_long)argp->nlsn.file, (u_long)argp->nlsn.offset); + printf("\troot_pgno: %lu\n", (u_long)argp->root_pgno); + printf("\tpg: "); + for (i = 0; i < argp->pg.size; i++) { + ch = ((u_int8_t *)argp->pg.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\topflags: %lu\n", (u_long)argp->opflags); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__bam_split_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __bam_split_args **argpp; +{ + __bam_split_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__bam_split_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->left, bp, sizeof(argp->left)); + bp += sizeof(argp->left); + memcpy(&argp->llsn, bp, sizeof(argp->llsn)); + bp += sizeof(argp->llsn); + memcpy(&argp->right, bp, sizeof(argp->right)); + bp += sizeof(argp->right); + memcpy(&argp->rlsn, bp, sizeof(argp->rlsn)); + bp += sizeof(argp->rlsn); + memcpy(&argp->indx, bp, sizeof(argp->indx)); + bp += sizeof(argp->indx); + memcpy(&argp->npgno, bp, sizeof(argp->npgno)); + bp += sizeof(argp->npgno); + memcpy(&argp->nlsn, bp, sizeof(argp->nlsn)); + bp += sizeof(argp->nlsn); + memcpy(&argp->root_pgno, bp, sizeof(argp->root_pgno)); + bp += sizeof(argp->root_pgno); + memset(&argp->pg, 0, sizeof(argp->pg)); + memcpy(&argp->pg.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->pg.data = bp; + bp += argp->pg.size; + memcpy(&argp->opflags, bp, sizeof(argp->opflags)); + bp += sizeof(argp->opflags); + *argpp = argp; + return (0); +} + +int +__bam_rsplit1_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __bam_rsplit1_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __bam_rsplit1_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]bam_rsplit1: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tpgno: %lu\n", (u_long)argp->pgno); + printf("\tpgdbt: "); + for (i = 0; i < argp->pgdbt.size; i++) { + ch = ((u_int8_t *)argp->pgdbt.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\tnrec: %lu\n", (u_long)argp->nrec); + printf("\trootent: "); + for (i = 0; i < argp->rootent.size; i++) { + ch = ((u_int8_t *)argp->rootent.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\trootlsn: [%lu][%lu]\n", + (u_long)argp->rootlsn.file, (u_long)argp->rootlsn.offset); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__bam_rsplit1_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __bam_rsplit1_args **argpp; +{ + __bam_rsplit1_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__bam_rsplit1_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->pgno, bp, sizeof(argp->pgno)); + bp += sizeof(argp->pgno); + memset(&argp->pgdbt, 0, sizeof(argp->pgdbt)); + memcpy(&argp->pgdbt.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->pgdbt.data = bp; + bp += argp->pgdbt.size; + memcpy(&argp->nrec, bp, sizeof(argp->nrec)); + bp += sizeof(argp->nrec); + memset(&argp->rootent, 0, sizeof(argp->rootent)); + memcpy(&argp->rootent.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->rootent.data = bp; + bp += argp->rootent.size; + memcpy(&argp->rootlsn, bp, sizeof(argp->rootlsn)); + bp += sizeof(argp->rootlsn); + *argpp = argp; + return (0); +} + +int +__bam_rsplit_log(dbenv, txnid, ret_lsnp, flags, + fileid, pgno, pgdbt, root_pgno, nrec, rootent, + rootlsn) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + int32_t fileid; + db_pgno_t pgno; + const DBT *pgdbt; + db_pgno_t root_pgno; + db_pgno_t nrec; + const DBT *rootent; + DB_LSN * rootlsn; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t zero; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_bam_rsplit; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(fileid) + + sizeof(pgno) + + sizeof(u_int32_t) + (pgdbt == NULL ? 0 : pgdbt->size) + + sizeof(root_pgno) + + sizeof(nrec) + + sizeof(u_int32_t) + (rootent == NULL ? 0 : rootent->size) + + sizeof(*rootlsn); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &fileid, sizeof(fileid)); + bp += sizeof(fileid); + memcpy(bp, &pgno, sizeof(pgno)); + bp += sizeof(pgno); + if (pgdbt == NULL) { + zero = 0; + memcpy(bp, &zero, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + } else { + memcpy(bp, &pgdbt->size, sizeof(pgdbt->size)); + bp += sizeof(pgdbt->size); + memcpy(bp, pgdbt->data, pgdbt->size); + bp += pgdbt->size; + } + memcpy(bp, &root_pgno, sizeof(root_pgno)); + bp += sizeof(root_pgno); + memcpy(bp, &nrec, sizeof(nrec)); + bp += sizeof(nrec); + if (rootent == NULL) { + zero = 0; + memcpy(bp, &zero, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + } else { + memcpy(bp, &rootent->size, sizeof(rootent->size)); + bp += sizeof(rootent->size); + memcpy(bp, rootent->data, rootent->size); + bp += rootent->size; + } + if (rootlsn != NULL) + memcpy(bp, rootlsn, sizeof(*rootlsn)); + else + memset(bp, 0, sizeof(*rootlsn)); + bp += sizeof(*rootlsn); + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__bam_rsplit_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __bam_rsplit_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __bam_rsplit_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]bam_rsplit: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tpgno: %lu\n", (u_long)argp->pgno); + printf("\tpgdbt: "); + for (i = 0; i < argp->pgdbt.size; i++) { + ch = ((u_int8_t *)argp->pgdbt.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\troot_pgno: %lu\n", (u_long)argp->root_pgno); + printf("\tnrec: %lu\n", (u_long)argp->nrec); + printf("\trootent: "); + for (i = 0; i < argp->rootent.size; i++) { + ch = ((u_int8_t *)argp->rootent.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\trootlsn: [%lu][%lu]\n", + (u_long)argp->rootlsn.file, (u_long)argp->rootlsn.offset); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__bam_rsplit_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __bam_rsplit_args **argpp; +{ + __bam_rsplit_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__bam_rsplit_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->pgno, bp, sizeof(argp->pgno)); + bp += sizeof(argp->pgno); + memset(&argp->pgdbt, 0, sizeof(argp->pgdbt)); + memcpy(&argp->pgdbt.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->pgdbt.data = bp; + bp += argp->pgdbt.size; + memcpy(&argp->root_pgno, bp, sizeof(argp->root_pgno)); + bp += sizeof(argp->root_pgno); + memcpy(&argp->nrec, bp, sizeof(argp->nrec)); + bp += sizeof(argp->nrec); + memset(&argp->rootent, 0, sizeof(argp->rootent)); + memcpy(&argp->rootent.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->rootent.data = bp; + bp += argp->rootent.size; + memcpy(&argp->rootlsn, bp, sizeof(argp->rootlsn)); + bp += sizeof(argp->rootlsn); + *argpp = argp; + return (0); +} + +int +__bam_adj_log(dbenv, txnid, ret_lsnp, flags, + fileid, pgno, lsn, indx, indx_copy, is_insert) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + int32_t fileid; + db_pgno_t pgno; + DB_LSN * lsn; + u_int32_t indx; + u_int32_t indx_copy; + u_int32_t is_insert; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_bam_adj; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(fileid) + + sizeof(pgno) + + sizeof(*lsn) + + sizeof(indx) + + sizeof(indx_copy) + + sizeof(is_insert); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &fileid, sizeof(fileid)); + bp += sizeof(fileid); + memcpy(bp, &pgno, sizeof(pgno)); + bp += sizeof(pgno); + if (lsn != NULL) + memcpy(bp, lsn, sizeof(*lsn)); + else + memset(bp, 0, sizeof(*lsn)); + bp += sizeof(*lsn); + memcpy(bp, &indx, sizeof(indx)); + bp += sizeof(indx); + memcpy(bp, &indx_copy, sizeof(indx_copy)); + bp += sizeof(indx_copy); + memcpy(bp, &is_insert, sizeof(is_insert)); + bp += sizeof(is_insert); + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__bam_adj_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __bam_adj_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __bam_adj_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]bam_adj: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tpgno: %lu\n", (u_long)argp->pgno); + printf("\tlsn: [%lu][%lu]\n", + (u_long)argp->lsn.file, (u_long)argp->lsn.offset); + printf("\tindx: %lu\n", (u_long)argp->indx); + printf("\tindx_copy: %lu\n", (u_long)argp->indx_copy); + printf("\tis_insert: %lu\n", (u_long)argp->is_insert); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__bam_adj_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __bam_adj_args **argpp; +{ + __bam_adj_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__bam_adj_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->pgno, bp, sizeof(argp->pgno)); + bp += sizeof(argp->pgno); + memcpy(&argp->lsn, bp, sizeof(argp->lsn)); + bp += sizeof(argp->lsn); + memcpy(&argp->indx, bp, sizeof(argp->indx)); + bp += sizeof(argp->indx); + memcpy(&argp->indx_copy, bp, sizeof(argp->indx_copy)); + bp += sizeof(argp->indx_copy); + memcpy(&argp->is_insert, bp, sizeof(argp->is_insert)); + bp += sizeof(argp->is_insert); + *argpp = argp; + return (0); +} + +int +__bam_cadjust_log(dbenv, txnid, ret_lsnp, flags, + fileid, pgno, lsn, indx, adjust, opflags) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + int32_t fileid; + db_pgno_t pgno; + DB_LSN * lsn; + u_int32_t indx; + int32_t adjust; + u_int32_t opflags; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_bam_cadjust; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(fileid) + + sizeof(pgno) + + sizeof(*lsn) + + sizeof(indx) + + sizeof(adjust) + + sizeof(opflags); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &fileid, sizeof(fileid)); + bp += sizeof(fileid); + memcpy(bp, &pgno, sizeof(pgno)); + bp += sizeof(pgno); + if (lsn != NULL) + memcpy(bp, lsn, sizeof(*lsn)); + else + memset(bp, 0, sizeof(*lsn)); + bp += sizeof(*lsn); + memcpy(bp, &indx, sizeof(indx)); + bp += sizeof(indx); + memcpy(bp, &adjust, sizeof(adjust)); + bp += sizeof(adjust); + memcpy(bp, &opflags, sizeof(opflags)); + bp += sizeof(opflags); + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__bam_cadjust_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __bam_cadjust_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __bam_cadjust_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]bam_cadjust: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tpgno: %lu\n", (u_long)argp->pgno); + printf("\tlsn: [%lu][%lu]\n", + (u_long)argp->lsn.file, (u_long)argp->lsn.offset); + printf("\tindx: %lu\n", (u_long)argp->indx); + printf("\tadjust: %ld\n", (long)argp->adjust); + printf("\topflags: %lu\n", (u_long)argp->opflags); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__bam_cadjust_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __bam_cadjust_args **argpp; +{ + __bam_cadjust_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__bam_cadjust_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->pgno, bp, sizeof(argp->pgno)); + bp += sizeof(argp->pgno); + memcpy(&argp->lsn, bp, sizeof(argp->lsn)); + bp += sizeof(argp->lsn); + memcpy(&argp->indx, bp, sizeof(argp->indx)); + bp += sizeof(argp->indx); + memcpy(&argp->adjust, bp, sizeof(argp->adjust)); + bp += sizeof(argp->adjust); + memcpy(&argp->opflags, bp, sizeof(argp->opflags)); + bp += sizeof(argp->opflags); + *argpp = argp; + return (0); +} + +int +__bam_cdel_log(dbenv, txnid, ret_lsnp, flags, + fileid, pgno, lsn, indx) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + int32_t fileid; + db_pgno_t pgno; + DB_LSN * lsn; + u_int32_t indx; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_bam_cdel; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(fileid) + + sizeof(pgno) + + sizeof(*lsn) + + sizeof(indx); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &fileid, sizeof(fileid)); + bp += sizeof(fileid); + memcpy(bp, &pgno, sizeof(pgno)); + bp += sizeof(pgno); + if (lsn != NULL) + memcpy(bp, lsn, sizeof(*lsn)); + else + memset(bp, 0, sizeof(*lsn)); + bp += sizeof(*lsn); + memcpy(bp, &indx, sizeof(indx)); + bp += sizeof(indx); + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__bam_cdel_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __bam_cdel_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __bam_cdel_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]bam_cdel: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tpgno: %lu\n", (u_long)argp->pgno); + printf("\tlsn: [%lu][%lu]\n", + (u_long)argp->lsn.file, (u_long)argp->lsn.offset); + printf("\tindx: %lu\n", (u_long)argp->indx); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__bam_cdel_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __bam_cdel_args **argpp; +{ + __bam_cdel_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__bam_cdel_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->pgno, bp, sizeof(argp->pgno)); + bp += sizeof(argp->pgno); + memcpy(&argp->lsn, bp, sizeof(argp->lsn)); + bp += sizeof(argp->lsn); + memcpy(&argp->indx, bp, sizeof(argp->indx)); + bp += sizeof(argp->indx); + *argpp = argp; + return (0); +} + +int +__bam_repl_log(dbenv, txnid, ret_lsnp, flags, + fileid, pgno, lsn, indx, isdeleted, orig, + repl, prefix, suffix) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + int32_t fileid; + db_pgno_t pgno; + DB_LSN * lsn; + u_int32_t indx; + u_int32_t isdeleted; + const DBT *orig; + const DBT *repl; + u_int32_t prefix; + u_int32_t suffix; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t zero; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_bam_repl; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(fileid) + + sizeof(pgno) + + sizeof(*lsn) + + sizeof(indx) + + sizeof(isdeleted) + + sizeof(u_int32_t) + (orig == NULL ? 0 : orig->size) + + sizeof(u_int32_t) + (repl == NULL ? 0 : repl->size) + + sizeof(prefix) + + sizeof(suffix); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &fileid, sizeof(fileid)); + bp += sizeof(fileid); + memcpy(bp, &pgno, sizeof(pgno)); + bp += sizeof(pgno); + if (lsn != NULL) + memcpy(bp, lsn, sizeof(*lsn)); + else + memset(bp, 0, sizeof(*lsn)); + bp += sizeof(*lsn); + memcpy(bp, &indx, sizeof(indx)); + bp += sizeof(indx); + memcpy(bp, &isdeleted, sizeof(isdeleted)); + bp += sizeof(isdeleted); + if (orig == NULL) { + zero = 0; + memcpy(bp, &zero, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + } else { + memcpy(bp, &orig->size, sizeof(orig->size)); + bp += sizeof(orig->size); + memcpy(bp, orig->data, orig->size); + bp += orig->size; + } + if (repl == NULL) { + zero = 0; + memcpy(bp, &zero, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + } else { + memcpy(bp, &repl->size, sizeof(repl->size)); + bp += sizeof(repl->size); + memcpy(bp, repl->data, repl->size); + bp += repl->size; + } + memcpy(bp, &prefix, sizeof(prefix)); + bp += sizeof(prefix); + memcpy(bp, &suffix, sizeof(suffix)); + bp += sizeof(suffix); + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__bam_repl_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __bam_repl_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __bam_repl_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]bam_repl: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tpgno: %lu\n", (u_long)argp->pgno); + printf("\tlsn: [%lu][%lu]\n", + (u_long)argp->lsn.file, (u_long)argp->lsn.offset); + printf("\tindx: %lu\n", (u_long)argp->indx); + printf("\tisdeleted: %lu\n", (u_long)argp->isdeleted); + printf("\torig: "); + for (i = 0; i < argp->orig.size; i++) { + ch = ((u_int8_t *)argp->orig.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\trepl: "); + for (i = 0; i < argp->repl.size; i++) { + ch = ((u_int8_t *)argp->repl.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\tprefix: %lu\n", (u_long)argp->prefix); + printf("\tsuffix: %lu\n", (u_long)argp->suffix); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__bam_repl_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __bam_repl_args **argpp; +{ + __bam_repl_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__bam_repl_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->pgno, bp, sizeof(argp->pgno)); + bp += sizeof(argp->pgno); + memcpy(&argp->lsn, bp, sizeof(argp->lsn)); + bp += sizeof(argp->lsn); + memcpy(&argp->indx, bp, sizeof(argp->indx)); + bp += sizeof(argp->indx); + memcpy(&argp->isdeleted, bp, sizeof(argp->isdeleted)); + bp += sizeof(argp->isdeleted); + memset(&argp->orig, 0, sizeof(argp->orig)); + memcpy(&argp->orig.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->orig.data = bp; + bp += argp->orig.size; + memset(&argp->repl, 0, sizeof(argp->repl)); + memcpy(&argp->repl.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->repl.data = bp; + bp += argp->repl.size; + memcpy(&argp->prefix, bp, sizeof(argp->prefix)); + bp += sizeof(argp->prefix); + memcpy(&argp->suffix, bp, sizeof(argp->suffix)); + bp += sizeof(argp->suffix); + *argpp = argp; + return (0); +} + +int +__bam_root_log(dbenv, txnid, ret_lsnp, flags, + fileid, meta_pgno, root_pgno, meta_lsn) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + int32_t fileid; + db_pgno_t meta_pgno; + db_pgno_t root_pgno; + DB_LSN * meta_lsn; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_bam_root; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(fileid) + + sizeof(meta_pgno) + + sizeof(root_pgno) + + sizeof(*meta_lsn); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &fileid, sizeof(fileid)); + bp += sizeof(fileid); + memcpy(bp, &meta_pgno, sizeof(meta_pgno)); + bp += sizeof(meta_pgno); + memcpy(bp, &root_pgno, sizeof(root_pgno)); + bp += sizeof(root_pgno); + if (meta_lsn != NULL) + memcpy(bp, meta_lsn, sizeof(*meta_lsn)); + else + memset(bp, 0, sizeof(*meta_lsn)); + bp += sizeof(*meta_lsn); + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__bam_root_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __bam_root_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __bam_root_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]bam_root: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tmeta_pgno: %lu\n", (u_long)argp->meta_pgno); + printf("\troot_pgno: %lu\n", (u_long)argp->root_pgno); + printf("\tmeta_lsn: [%lu][%lu]\n", + (u_long)argp->meta_lsn.file, (u_long)argp->meta_lsn.offset); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__bam_root_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __bam_root_args **argpp; +{ + __bam_root_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__bam_root_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->meta_pgno, bp, sizeof(argp->meta_pgno)); + bp += sizeof(argp->meta_pgno); + memcpy(&argp->root_pgno, bp, sizeof(argp->root_pgno)); + bp += sizeof(argp->root_pgno); + memcpy(&argp->meta_lsn, bp, sizeof(argp->meta_lsn)); + bp += sizeof(argp->meta_lsn); + *argpp = argp; + return (0); +} + +int +__bam_curadj_log(dbenv, txnid, ret_lsnp, flags, + fileid, mode, from_pgno, to_pgno, left_pgno, first_indx, + from_indx, to_indx) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + int32_t fileid; + db_ca_mode mode; + db_pgno_t from_pgno; + db_pgno_t to_pgno; + db_pgno_t left_pgno; + u_int32_t first_indx; + u_int32_t from_indx; + u_int32_t to_indx; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_bam_curadj; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(fileid) + + sizeof(mode) + + sizeof(from_pgno) + + sizeof(to_pgno) + + sizeof(left_pgno) + + sizeof(first_indx) + + sizeof(from_indx) + + sizeof(to_indx); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &fileid, sizeof(fileid)); + bp += sizeof(fileid); + memcpy(bp, &mode, sizeof(mode)); + bp += sizeof(mode); + memcpy(bp, &from_pgno, sizeof(from_pgno)); + bp += sizeof(from_pgno); + memcpy(bp, &to_pgno, sizeof(to_pgno)); + bp += sizeof(to_pgno); + memcpy(bp, &left_pgno, sizeof(left_pgno)); + bp += sizeof(left_pgno); + memcpy(bp, &first_indx, sizeof(first_indx)); + bp += sizeof(first_indx); + memcpy(bp, &from_indx, sizeof(from_indx)); + bp += sizeof(from_indx); + memcpy(bp, &to_indx, sizeof(to_indx)); + bp += sizeof(to_indx); + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__bam_curadj_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __bam_curadj_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __bam_curadj_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]bam_curadj: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tmode: %ld\n", (long)argp->mode); + printf("\tfrom_pgno: %lu\n", (u_long)argp->from_pgno); + printf("\tto_pgno: %lu\n", (u_long)argp->to_pgno); + printf("\tleft_pgno: %lu\n", (u_long)argp->left_pgno); + printf("\tfirst_indx: %lu\n", (u_long)argp->first_indx); + printf("\tfrom_indx: %lu\n", (u_long)argp->from_indx); + printf("\tto_indx: %lu\n", (u_long)argp->to_indx); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__bam_curadj_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __bam_curadj_args **argpp; +{ + __bam_curadj_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__bam_curadj_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->mode, bp, sizeof(argp->mode)); + bp += sizeof(argp->mode); + memcpy(&argp->from_pgno, bp, sizeof(argp->from_pgno)); + bp += sizeof(argp->from_pgno); + memcpy(&argp->to_pgno, bp, sizeof(argp->to_pgno)); + bp += sizeof(argp->to_pgno); + memcpy(&argp->left_pgno, bp, sizeof(argp->left_pgno)); + bp += sizeof(argp->left_pgno); + memcpy(&argp->first_indx, bp, sizeof(argp->first_indx)); + bp += sizeof(argp->first_indx); + memcpy(&argp->from_indx, bp, sizeof(argp->from_indx)); + bp += sizeof(argp->from_indx); + memcpy(&argp->to_indx, bp, sizeof(argp->to_indx)); + bp += sizeof(argp->to_indx); + *argpp = argp; + return (0); +} + +int +__bam_rcuradj_log(dbenv, txnid, ret_lsnp, flags, + fileid, mode, root, recno, order) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + int32_t fileid; + ca_recno_arg mode; + db_pgno_t root; + db_recno_t recno; + u_int32_t order; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_bam_rcuradj; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(fileid) + + sizeof(mode) + + sizeof(root) + + sizeof(recno) + + sizeof(order); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &fileid, sizeof(fileid)); + bp += sizeof(fileid); + memcpy(bp, &mode, sizeof(mode)); + bp += sizeof(mode); + memcpy(bp, &root, sizeof(root)); + bp += sizeof(root); + memcpy(bp, &recno, sizeof(recno)); + bp += sizeof(recno); + memcpy(bp, &order, sizeof(order)); + bp += sizeof(order); + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__bam_rcuradj_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __bam_rcuradj_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __bam_rcuradj_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]bam_rcuradj: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tmode: %ld\n", (long)argp->mode); + printf("\troot: %ld\n", (long)argp->root); + printf("\trecno: %ld\n", (long)argp->recno); + printf("\torder: %ld\n", (long)argp->order); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__bam_rcuradj_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __bam_rcuradj_args **argpp; +{ + __bam_rcuradj_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__bam_rcuradj_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->mode, bp, sizeof(argp->mode)); + bp += sizeof(argp->mode); + memcpy(&argp->root, bp, sizeof(argp->root)); + bp += sizeof(argp->root); + memcpy(&argp->recno, bp, sizeof(argp->recno)); + bp += sizeof(argp->recno); + memcpy(&argp->order, bp, sizeof(argp->order)); + bp += sizeof(argp->order); + *argpp = argp; + return (0); +} + +int +__bam_init_print(dbenv) + DB_ENV *dbenv; +{ + int ret; + + if ((ret = __db_add_recovery(dbenv, + __bam_pg_alloc_print, DB_bam_pg_alloc)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __bam_pg_alloc1_print, DB_bam_pg_alloc1)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __bam_pg_free_print, DB_bam_pg_free)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __bam_pg_free1_print, DB_bam_pg_free1)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __bam_split1_print, DB_bam_split1)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __bam_split_print, DB_bam_split)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __bam_rsplit1_print, DB_bam_rsplit1)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __bam_rsplit_print, DB_bam_rsplit)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __bam_adj_print, DB_bam_adj)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __bam_cadjust_print, DB_bam_cadjust)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __bam_cdel_print, DB_bam_cdel)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __bam_repl_print, DB_bam_repl)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __bam_root_print, DB_bam_root)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __bam_curadj_print, DB_bam_curadj)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __bam_rcuradj_print, DB_bam_rcuradj)) != 0) + return (ret); + return (0); +} + +int +__bam_init_recover(dbenv) + DB_ENV *dbenv; +{ + int ret; + + if ((ret = __db_add_recovery(dbenv, + __bam_pg_alloc_recover, DB_bam_pg_alloc)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __deprecated_recover, DB_bam_pg_alloc1)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __bam_pg_free_recover, DB_bam_pg_free)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __deprecated_recover, DB_bam_pg_free1)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __deprecated_recover, DB_bam_split1)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __bam_split_recover, DB_bam_split)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __deprecated_recover, DB_bam_rsplit1)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __bam_rsplit_recover, DB_bam_rsplit)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __bam_adj_recover, DB_bam_adj)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __bam_cadjust_recover, DB_bam_cadjust)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __bam_cdel_recover, DB_bam_cdel)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __bam_repl_recover, DB_bam_repl)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __bam_root_recover, DB_bam_root)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __bam_curadj_recover, DB_bam_curadj)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __bam_rcuradj_recover, DB_bam_rcuradj)) != 0) + return (ret); + return (0); +} + diff --git a/db/build_unix/.IGNORE_ME b/db/build_unix/.IGNORE_ME new file mode 100644 index 000000000..558fd496f --- /dev/null +++ b/db/build_unix/.IGNORE_ME @@ -0,0 +1,3 @@ +Some combinations of the gzip and tar archive exploders found +on Linux systems ignore directories that don't have any files +(other than symbolic links) in them. So, here's a file. diff --git a/db/build_vxworks/BerkeleyDB.wpj b/db/build_vxworks/BerkeleyDB.wpj new file mode 100644 index 000000000..fa8aa61c1 --- /dev/null +++ b/db/build_vxworks/BerkeleyDB.wpj @@ -0,0 +1,6066 @@ +Document file - DO NOT EDIT + + BUILD_PENTIUM_RPCdebug_BUILDRULE +BerkeleyDB.out + + + BUILD_PENTIUM_RPCdebug_MACRO_AR +ar386 + + + BUILD_PENTIUM_RPCdebug_MACRO_ARCHIVE +$(PRJ_DIR)/PENTIUMgnu/BerkeleyDB_sim.a + + + BUILD_PENTIUM_RPCdebug_MACRO_AS +cc386 + + + BUILD_PENTIUM_RPCdebug_MACRO_CC +cc386 + + + BUILD_PENTIUM_RPCdebug_MACRO_CFLAGS +-g \ + -mpentium \ + -ansi \ + -nostdinc \ + -DRW_MULTI_THREAD \ + -D_REENTRANT \ + -fvolatile \ + -nostdlib \ + -fno-builtin \ + -fno-defer-pop \ + -I. \ + -I$(WIND_BASE)/target/h \ + -DCPU=PENTIUM \ + -O0 \ + -I$(PRJ_DIR) \ + -I/export/home/db/include \ + -DDIAGNOSTIC \ + -DDEBUG \ + -DHAVE_RPC + + + BUILD_PENTIUM_RPCdebug_MACRO_CFLAGS_AS +-g \ + -mpentium \ + -ansi \ + -nostdinc \ + -fvolatile \ + -nostdlib \ + -fno-builtin \ + -fno-defer-pop \ + -P \ + -x \ + assembler-with-cpp \ + -I. \ + -I$(WIND_BASE)/target/h \ + -DCPU=PENTIUM + + + BUILD_PENTIUM_RPCdebug_MACRO_CPP +cc386 -E -P -xc + + + BUILD_PENTIUM_RPCdebug_MACRO_LD +ld386 + + + BUILD_PENTIUM_RPCdebug_MACRO_LDFLAGS +-X -N + + + BUILD_PENTIUM_RPCdebug_MACRO_LD_PARTIAL_FLAGS +-X -r + + + BUILD_PENTIUM_RPCdebug_MACRO_NM +nm386 -g + + + BUILD_PENTIUM_RPCdebug_MACRO_OPTION_DEFINE_MACRO +-D + + + BUILD_PENTIUM_RPCdebug_MACRO_OPTION_INCLUDE_DIR +-I + + + BUILD_PENTIUM_RPCdebug_MACRO_POST_BUILD_RULE + + + + BUILD_PENTIUM_RPCdebug_MACRO_PRJ_LIBS + + + + BUILD_PENTIUM_RPCdebug_MACRO_SIZE +size386 + + + BUILD_PENTIUM_RPCdebug_RO_DEPEND_PATH +{$(WIND_BASE)/target/h/} \ + {$(WIND_BASE)/target/src/} \ + {$(WIND_BASE)/target/config/} + + + BUILD_PENTIUM_RPCdebug_TC +::tc_PENTIUMgnu + + + BUILD_PENTIUM_RPCnodebug_BUILDRULE +BerkeleyDB.out + + + BUILD_PENTIUM_RPCnodebug_MACRO_AR +ar386 + + + BUILD_PENTIUM_RPCnodebug_MACRO_ARCHIVE +$(PRJ_DIR)/PENTIUMgnu/BerkeleyDB_sim.a + + + BUILD_PENTIUM_RPCnodebug_MACRO_AS +cc386 + + + BUILD_PENTIUM_RPCnodebug_MACRO_CC +cc386 + + + BUILD_PENTIUM_RPCnodebug_MACRO_CFLAGS +-mpentium \ + -ansi \ + -nostdinc \ + -DRW_MULTI_THREAD \ + -D_REENTRANT \ + -fvolatile \ + -nostdlib \ + -fno-builtin \ + -fno-defer-pop \ + -I. \ + -I$(WIND_BASE)/target/h \ + -DCPU=PENTIUM \ + -O2 \ + -I$(PRJ_DIR) \ + -I/export/home/db/include \ + -DHAVE_RPC + + + BUILD_PENTIUM_RPCnodebug_MACRO_CFLAGS_AS +-g \ + -mpentium \ + -ansi \ + -nostdinc \ + -fvolatile \ + -nostdlib \ + -fno-builtin \ + -fno-defer-pop \ + -P \ + -x \ + assembler-with-cpp \ + -I. \ + -I$(WIND_BASE)/target/h \ + -DCPU=PENTIUM + + + BUILD_PENTIUM_RPCnodebug_MACRO_CPP +cc386 -E -P -xc + + + BUILD_PENTIUM_RPCnodebug_MACRO_LD +ld386 + + + BUILD_PENTIUM_RPCnodebug_MACRO_LDDEPS + + + + BUILD_PENTIUM_RPCnodebug_MACRO_LDFLAGS +-X -N + + + BUILD_PENTIUM_RPCnodebug_MACRO_LD_PARTIAL_FLAGS +-X -r + + + BUILD_PENTIUM_RPCnodebug_MACRO_NM +nm386 -g + + + BUILD_PENTIUM_RPCnodebug_MACRO_OPTION_DEFINE_MACRO +-D + + + BUILD_PENTIUM_RPCnodebug_MACRO_OPTION_INCLUDE_DIR +-I + + + BUILD_PENTIUM_RPCnodebug_MACRO_POST_BUILD_RULE + + + + BUILD_PENTIUM_RPCnodebug_MACRO_PRJ_LIBS + + + + BUILD_PENTIUM_RPCnodebug_MACRO_SIZE +size386 + + + BUILD_PENTIUM_RPCnodebug_RO_DEPEND_PATH +{$(WIND_BASE)/target/h/} \ + {$(WIND_BASE)/target/src/} \ + {$(WIND_BASE)/target/config/} + + + BUILD_PENTIUM_RPCnodebug_TC +::tc_PENTIUMgnu + + + BUILD_PENTIUM_debug_BUILDRULE +BerkeleyDB.out + + + BUILD_PENTIUM_debug_MACRO_AR +ar386 + + + BUILD_PENTIUM_debug_MACRO_ARCHIVE +$(PRJ_DIR)/PENTIUMgnu/BerkeleyDB_sim.a + + + BUILD_PENTIUM_debug_MACRO_AS +cc386 + + + BUILD_PENTIUM_debug_MACRO_CC +cc386 + + + BUILD_PENTIUM_debug_MACRO_CFLAGS +-g \ + -mpentium \ + -ansi \ + -nostdinc \ + -DRW_MULTI_THREAD \ + -D_REENTRANT \ + -fvolatile \ + -nostdlib \ + -fno-builtin \ + -fno-defer-pop \ + -I. \ + -I$(WIND_BASE)/target/h \ + -DCPU=PENTIUM \ + -O0 \ + -I$(PRJ_DIR) \ + -I/export/home/db/include \ + -DDIAGNOSTIC \ + -DDEBUG + + + BUILD_PENTIUM_debug_MACRO_CFLAGS_AS +-g \ + -mpentium \ + -ansi \ + -nostdinc \ + -fvolatile \ + -nostdlib \ + -fno-builtin \ + -fno-defer-pop \ + -P \ + -x \ + assembler-with-cpp \ + -I. \ + -I$(WIND_BASE)/target/h \ + -DCPU=PENTIUM + + + BUILD_PENTIUM_debug_MACRO_CPP +cc386 -E -P -xc + + + BUILD_PENTIUM_debug_MACRO_LD +ld386 + + + BUILD_PENTIUM_debug_MACRO_LDFLAGS +-X -N + + + BUILD_PENTIUM_debug_MACRO_LD_PARTIAL_FLAGS +-X -r + + + BUILD_PENTIUM_debug_MACRO_NM +nm386 -g + + + BUILD_PENTIUM_debug_MACRO_OPTION_DEFINE_MACRO +-D + + + BUILD_PENTIUM_debug_MACRO_OPTION_INCLUDE_DIR +-I + + + BUILD_PENTIUM_debug_MACRO_POST_BUILD_RULE + + + + BUILD_PENTIUM_debug_MACRO_PRJ_LIBS + + + + BUILD_PENTIUM_debug_MACRO_SIZE +size386 + + + BUILD_PENTIUM_debug_RO_DEPEND_PATH +{$(WIND_BASE)/target/h/} \ + {$(WIND_BASE)/target/src/} \ + {$(WIND_BASE)/target/config/} + + + BUILD_PENTIUM_debug_TC +::tc_PENTIUMgnu + + + BUILD_PENTIUM_nodebug_BUILDRULE +BerkeleyDB.out + + + BUILD_PENTIUM_nodebug_MACRO_AR +ar386 + + + BUILD_PENTIUM_nodebug_MACRO_ARCHIVE +$(PRJ_DIR)/PENTIUMgnu/BerkeleyDB_sim.a + + + BUILD_PENTIUM_nodebug_MACRO_AS +cc386 + + + BUILD_PENTIUM_nodebug_MACRO_CC +cc386 + + + BUILD_PENTIUM_nodebug_MACRO_CFLAGS +-mpentium \ + -ansi \ + -nostdinc \ + -DRW_MULTI_THREAD \ + -D_REENTRANT \ + -fvolatile \ + -nostdlib \ + -fno-builtin \ + -fno-defer-pop \ + -I. \ + -I$(WIND_BASE)/target/h \ + -DCPU=PENTIUM \ + -O2 \ + -I$(PRJ_DIR) \ + -I/export/home/db/include + + + BUILD_PENTIUM_nodebug_MACRO_CFLAGS_AS +-g \ + -mpentium \ + -ansi \ + -nostdinc \ + -fvolatile \ + -nostdlib \ + -fno-builtin \ + -fno-defer-pop \ + -P \ + -x \ + assembler-with-cpp \ + -I. \ + -I$(WIND_BASE)/target/h \ + -DCPU=PENTIUM + + + BUILD_PENTIUM_nodebug_MACRO_CPP +cc386 -E -P -xc + + + BUILD_PENTIUM_nodebug_MACRO_LD +ld386 + + + BUILD_PENTIUM_nodebug_MACRO_LDFLAGS +-X -N + + + BUILD_PENTIUM_nodebug_MACRO_LD_PARTIAL_FLAGS +-X -r + + + BUILD_PENTIUM_nodebug_MACRO_NM +nm386 -g + + + BUILD_PENTIUM_nodebug_MACRO_OPTION_DEFINE_MACRO +-D + + + BUILD_PENTIUM_nodebug_MACRO_OPTION_INCLUDE_DIR +-I + + + BUILD_PENTIUM_nodebug_MACRO_POST_BUILD_RULE + + + + BUILD_PENTIUM_nodebug_MACRO_PRJ_LIBS + + + + BUILD_PENTIUM_nodebug_MACRO_SIZE +size386 + + + BUILD_PENTIUM_nodebug_RO_DEPEND_PATH +{$(WIND_BASE)/target/h/} \ + {$(WIND_BASE)/target/src/} \ + {$(WIND_BASE)/target/config/} + + + BUILD_PENTIUM_nodebug_TC +::tc_PENTIUMgnu + + + BUILD_RULE_BerkeleyDB.out + + + + BUILD_RULE_BerkeleyDB_sim.out + + + + BUILD_RULE_archive + + + + BUILD_RULE_objects + + + + BUILD_SIMSPARCSOLARISgnu_MACRO_AR +arsimso + + + BUILD_SIMSPARCSOLARISgnu_MACRO_ARCHIVE +$(PRJ_DIR)/SIMSPARCSOLARISgnu/BerkeleyDB.a + + + BUILD_SIMSPARCSOLARISgnu_MACRO_AS +ccsimso + + + BUILD_SIMSPARCSOLARISgnu_MACRO_CC +ccsimso + + + BUILD_SIMSPARCSOLARISgnu_MACRO_CFLAGS +-g \ + -ansi \ + -nostdinc \ + -DRW_MULTI_THREAD \ + -D_REENTRANT \ + -fvolatile \ + -fno-builtin \ + -I. \ + -I$(WIND_BASE)/target/h \ + -DCPU=SIMSPARCSOLARIS \ + -O2 \ + -I$(PRJ_DIR) \ + -I/export/home/db/include + + + BUILD_SIMSPARCSOLARISgnu_MACRO_CFLAGS_AS +-g \ + -ansi \ + -nostdinc \ + -fvolatile \ + -fno-builtin \ + -P \ + -x \ + assembler-with-cpp \ + -I. \ + -I$(WIND_BASE)/target/h \ + -DCPU=SIMSPARCSOLARIS + + + BUILD_SIMSPARCSOLARISgnu_MACRO_CPP +ccsimso -E -P -xc + + + BUILD_SIMSPARCSOLARISgnu_MACRO_LD +ccsimso + + + BUILD_SIMSPARCSOLARISgnu_MACRO_LDFLAGS +-N + + + BUILD_SIMSPARCSOLARISgnu_MACRO_LD_PARTIAL_FLAGS +-nostdlib -r + + + BUILD_SIMSPARCSOLARISgnu_MACRO_NM +nmsimso + + + BUILD_SIMSPARCSOLARISgnu_MACRO_OPTION_DEFINE_MACRO +-D + + + BUILD_SIMSPARCSOLARISgnu_MACRO_OPTION_INCLUDE_DIR +-I + + + BUILD_SIMSPARCSOLARISgnu_MACRO_SIZE +sizesimso + + + BUILD_SIMSPARCSOLARISgnu_RO_DEPEND_PATH +{$(WIND_BASE)/target/h/} \ + {$(WIND_BASE)/target/src/} \ + {$(WIND_BASE)/target/config/} + + + BUILD_SIMSPARCSOLARISgnu_TC +::tc_SIMSPARCSOLARISgnu + + + BUILD__CURRENT +PENTIUM_RPCdebug + + + BUILD__LIST +PENTIUM_nodebug \ + PENTIUM_RPCdebug \ + PENTIUM_RPCnodebug \ + PENTIUM_debug \ + SIMSPARCSOLARISgnu + + + CORE_INFO_TYPE +::prj_vxApp + + + CORE_INFO_VERSION +2.0 + + + FILE_/export/home/db/btree/bt_compare.c_dependDone +TRUE + + + FILE_/export/home/db/btree/bt_compare.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h + + + FILE_/export/home/db/btree/bt_compare.c_objects +bt_compare.o + + + FILE_/export/home/db/btree/bt_compare.c_tool +C/C++ compiler + + + FILE_/export/home/db/btree/bt_conv.c_dependDone +TRUE + + + FILE_/export/home/db/btree/bt_conv.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_swap.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h + + + FILE_/export/home/db/btree/bt_conv.c_objects +bt_conv.o + + + FILE_/export/home/db/btree/bt_conv.c_tool +C/C++ compiler + + + FILE_/export/home/db/btree/bt_curadj.c_dependDone +TRUE + + + FILE_/export/home/db/btree/bt_curadj.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/txn.h \ + /export/home/db/include/xa.h \ + /export/home/db/include/txn_auto.h \ + /export/home/db/include/txn_ext.h \ + /export/home/db/include/xa_ext.h + + + FILE_/export/home/db/btree/bt_curadj.c_objects +bt_curadj.o + + + FILE_/export/home/db/btree/bt_curadj.c_tool +C/C++ compiler + + + FILE_/export/home/db/btree/bt_cursor.c_dependDone +TRUE + + + FILE_/export/home/db/btree/bt_cursor.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/lock.h \ + /export/home/db/include/lock_ext.h \ + /export/home/db/include/qam.h \ + /export/home/db/include/qam_auto.h \ + /export/home/db/include/qam_ext.h + + + FILE_/export/home/db/btree/bt_cursor.c_objects +bt_cursor.o + + + FILE_/export/home/db/btree/bt_cursor.c_tool +C/C++ compiler + + + FILE_/export/home/db/btree/bt_delete.c_dependDone +TRUE + + + FILE_/export/home/db/btree/bt_delete.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/lock.h \ + /export/home/db/include/lock_ext.h + + + FILE_/export/home/db/btree/bt_delete.c_objects +bt_delete.o + + + FILE_/export/home/db/btree/bt_delete.c_tool +C/C++ compiler + + + FILE_/export/home/db/btree/bt_method.c_dependDone +TRUE + + + FILE_/export/home/db/btree/bt_method.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/qam.h \ + /export/home/db/include/qam_auto.h \ + /export/home/db/include/qam_ext.h + + + FILE_/export/home/db/btree/bt_method.c_objects +bt_method.o + + + FILE_/export/home/db/btree/bt_method.c_tool +C/C++ compiler + + + FILE_/export/home/db/btree/bt_open.c_dependDone +TRUE + + + FILE_/export/home/db/btree/bt_open.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_swap.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/lock.h \ + /export/home/db/include/lock_ext.h \ + /export/home/db/include/log.h \ + /export/home/db/include/log_auto.h \ + /export/home/db/include/log_ext.h \ + /export/home/db/include/mp.h \ + /export/home/db/include/mp_ext.h + + + FILE_/export/home/db/btree/bt_open.c_objects +bt_open.o + + + FILE_/export/home/db/btree/bt_open.c_tool +C/C++ compiler + + + FILE_/export/home/db/btree/bt_put.c_dependDone +TRUE + + + FILE_/export/home/db/btree/bt_put.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h + + + FILE_/export/home/db/btree/bt_put.c_objects +bt_put.o + + + FILE_/export/home/db/btree/bt_put.c_tool +C/C++ compiler + + + FILE_/export/home/db/btree/bt_rec.c_dependDone +TRUE + + + FILE_/export/home/db/btree/bt_rec.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/hash.h \ + /export/home/db/include/hash_auto.h \ + /export/home/db/include/hash_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h \ + /export/home/db/include/log.h \ + /export/home/db/include/log_auto.h \ + /export/home/db/include/log_ext.h + + + FILE_/export/home/db/btree/bt_rec.c_objects +bt_rec.o + + + FILE_/export/home/db/btree/bt_rec.c_tool +C/C++ compiler + + + FILE_/export/home/db/btree/bt_reclaim.c_dependDone +TRUE + + + FILE_/export/home/db/btree/bt_reclaim.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/lock.h \ + /export/home/db/include/lock_ext.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h + + + FILE_/export/home/db/btree/bt_reclaim.c_objects +bt_reclaim.o + + + FILE_/export/home/db/btree/bt_reclaim.c_tool +C/C++ compiler + + + FILE_/export/home/db/btree/bt_recno.c_dependDone +TRUE + + + FILE_/export/home/db/btree/bt_recno.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/lock.h \ + /export/home/db/include/lock_ext.h \ + /export/home/db/include/qam.h \ + /export/home/db/include/qam_auto.h \ + /export/home/db/include/qam_ext.h \ + /export/home/db/include/txn.h \ + /export/home/db/include/xa.h \ + /export/home/db/include/txn_auto.h \ + /export/home/db/include/txn_ext.h \ + /export/home/db/include/xa_ext.h + + + FILE_/export/home/db/btree/bt_recno.c_objects +bt_recno.o + + + FILE_/export/home/db/btree/bt_recno.c_tool +C/C++ compiler + + + FILE_/export/home/db/btree/bt_rsearch.c_dependDone +TRUE + + + FILE_/export/home/db/btree/bt_rsearch.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/lock.h \ + /export/home/db/include/lock_ext.h + + + FILE_/export/home/db/btree/bt_rsearch.c_objects +bt_rsearch.o + + + FILE_/export/home/db/btree/bt_rsearch.c_tool +C/C++ compiler + + + FILE_/export/home/db/btree/bt_search.c_dependDone +TRUE + + + FILE_/export/home/db/btree/bt_search.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/lock.h \ + /export/home/db/include/lock_ext.h + + + FILE_/export/home/db/btree/bt_search.c_objects +bt_search.o + + + FILE_/export/home/db/btree/bt_search.c_tool +C/C++ compiler + + + FILE_/export/home/db/btree/bt_split.c_dependDone +TRUE + + + FILE_/export/home/db/btree/bt_split.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/lock.h \ + /export/home/db/include/lock_ext.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h + + + FILE_/export/home/db/btree/bt_split.c_objects +bt_split.o + + + FILE_/export/home/db/btree/bt_split.c_tool +C/C++ compiler + + + FILE_/export/home/db/btree/bt_stat.c_dependDone +TRUE + + + FILE_/export/home/db/btree/bt_stat.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/lock.h \ + /export/home/db/include/lock_ext.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h + + + FILE_/export/home/db/btree/bt_stat.c_objects +bt_stat.o + + + FILE_/export/home/db/btree/bt_stat.c_tool +C/C++ compiler + + + FILE_/export/home/db/btree/bt_upgrade.c_dependDone +TRUE + + + FILE_/export/home/db/btree/bt_upgrade.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_swap.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/db_upgrade.h + + + FILE_/export/home/db/btree/bt_upgrade.c_objects +bt_upgrade.o + + + FILE_/export/home/db/btree/bt_upgrade.c_tool +C/C++ compiler + + + FILE_/export/home/db/btree/bt_verify.c_dependDone +TRUE + + + FILE_/export/home/db/btree/bt_verify.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_verify.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h + + + FILE_/export/home/db/btree/bt_verify.c_objects +bt_verify.o + + + FILE_/export/home/db/btree/bt_verify.c_tool +C/C++ compiler + + + FILE_/export/home/db/btree/btree_auto.c_dependDone +TRUE + + + FILE_/export/home/db/btree/btree_auto.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h \ + /export/home/db/include/txn.h \ + /export/home/db/include/xa.h \ + /export/home/db/include/txn_auto.h \ + /export/home/db/include/txn_ext.h \ + /export/home/db/include/xa_ext.h + + + FILE_/export/home/db/btree/btree_auto.c_objects +btree_auto.o + + + FILE_/export/home/db/btree/btree_auto.c_tool +C/C++ compiler + + + FILE_/export/home/db/clib/getopt.c_dependDone +TRUE + + + FILE_/export/home/db/clib/getopt.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h + + + FILE_/export/home/db/clib/getopt.c_objects +getopt.o + + + FILE_/export/home/db/clib/getopt.c_tool +C/C++ compiler + + + FILE_/export/home/db/clib/snprintf.c_dependDone +TRUE + + + FILE_/export/home/db/clib/snprintf.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h + + + FILE_/export/home/db/clib/snprintf.c_objects +snprintf.o + + + FILE_/export/home/db/clib/snprintf.c_tool +C/C++ compiler + + + FILE_/export/home/db/clib/strcasecmp.c_dependDone +TRUE + + + FILE_/export/home/db/clib/strcasecmp.c_dependencies +$(PRJ_DIR)/db_config.h + + + FILE_/export/home/db/clib/strcasecmp.c_objects +strcasecmp.o + + + FILE_/export/home/db/clib/strcasecmp.c_tool +C/C++ compiler + + + FILE_/export/home/db/clib/vsnprintf.c_dependDone +TRUE + + + FILE_/export/home/db/clib/vsnprintf.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h + + + FILE_/export/home/db/clib/vsnprintf.c_objects +vsnprintf.o + + + FILE_/export/home/db/clib/vsnprintf.c_tool +C/C++ compiler + + + FILE_/export/home/db/common/db_byteorder.c_dependDone +TRUE + + + FILE_/export/home/db/common/db_byteorder.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h + + + FILE_/export/home/db/common/db_byteorder.c_objects +db_byteorder.o + + + FILE_/export/home/db/common/db_byteorder.c_tool +C/C++ compiler + + + FILE_/export/home/db/common/db_err.c_dependDone +TRUE + + + FILE_/export/home/db/common/db_err.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/lock.h \ + /export/home/db/include/lock_ext.h \ + /export/home/db/include/log.h \ + /export/home/db/include/log_auto.h \ + /export/home/db/include/log_ext.h \ + /export/home/db/include/mp.h \ + /export/home/db/include/mp_ext.h \ + /export/home/db/include/txn.h \ + /export/home/db/include/xa.h \ + /export/home/db/include/txn_auto.h \ + /export/home/db/include/txn_ext.h \ + /export/home/db/include/xa_ext.h \ + /export/home/db/include/clib_ext.h \ + /export/home/db/include/db_auto.h + + + FILE_/export/home/db/common/db_err.c_objects +db_err.o + + + FILE_/export/home/db/common/db_err.c_tool +C/C++ compiler + + + FILE_/export/home/db/common/db_getlong.c_dependDone +TRUE + + + FILE_/export/home/db/common/db_getlong.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/clib_ext.h + + + FILE_/export/home/db/common/db_getlong.c_objects +db_getlong.o + + + FILE_/export/home/db/common/db_getlong.c_tool +C/C++ compiler + + + FILE_/export/home/db/common/db_log2.c_dependDone +TRUE + + + FILE_/export/home/db/common/db_log2.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h + + + FILE_/export/home/db/common/db_log2.c_objects +db_log2.o + + + FILE_/export/home/db/common/db_log2.c_tool +C/C++ compiler + + + FILE_/export/home/db/common/util_log.c_dependDone +TRUE + + + FILE_/export/home/db/common/util_log.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h + + + FILE_/export/home/db/common/util_log.c_objects +util_log.o + + + FILE_/export/home/db/common/util_log.c_tool +C/C++ compiler + + + FILE_/export/home/db/common/util_sig.c_dependDone +TRUE + + + FILE_/export/home/db/common/util_sig.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h + + + FILE_/export/home/db/common/util_sig.c_objects +util_sig.o + + + FILE_/export/home/db/common/util_sig.c_tool +C/C++ compiler + + + FILE_/export/home/db/db/crdel_auto.c_dependDone +TRUE + + + FILE_/export/home/db/db/crdel_auto.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/txn.h \ + /export/home/db/include/xa.h \ + /export/home/db/include/txn_auto.h \ + /export/home/db/include/txn_ext.h \ + /export/home/db/include/xa_ext.h + + + FILE_/export/home/db/db/crdel_auto.c_objects +crdel_auto.o + + + FILE_/export/home/db/db/crdel_auto.c_tool +C/C++ compiler + + + FILE_/export/home/db/db/crdel_rec.c_dependDone +TRUE + + + FILE_/export/home/db/db/crdel_rec.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/log.h \ + /export/home/db/include/log_auto.h \ + /export/home/db/include/log_ext.h \ + /export/home/db/include/hash.h \ + /export/home/db/include/hash_auto.h \ + /export/home/db/include/hash_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/mp.h \ + /export/home/db/include/mp_ext.h + + + FILE_/export/home/db/db/crdel_rec.c_objects +crdel_rec.o + + + FILE_/export/home/db/db/crdel_rec.c_tool +C/C++ compiler + + + FILE_/export/home/db/db/db.c_dependDone +TRUE + + + FILE_/export/home/db/db/db.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/db_swap.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/hash.h \ + /export/home/db/include/hash_auto.h \ + /export/home/db/include/hash_ext.h \ + /export/home/db/include/lock.h \ + /export/home/db/include/lock_ext.h \ + /export/home/db/include/log.h \ + /export/home/db/include/log_auto.h \ + /export/home/db/include/log_ext.h \ + /export/home/db/include/mp.h \ + /export/home/db/include/mp_ext.h \ + /export/home/db/include/qam.h \ + /export/home/db/include/qam_auto.h \ + /export/home/db/include/qam_ext.h + + + FILE_/export/home/db/db/db.c_objects +db.o + + + FILE_/export/home/db/db/db.c_tool +C/C++ compiler + + + FILE_/export/home/db/db/db_am.c_dependDone +TRUE + + + FILE_/export/home/db/db/db_am.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/hash.h \ + /export/home/db/include/hash_auto.h \ + /export/home/db/include/hash_ext.h \ + /export/home/db/include/qam.h \ + /export/home/db/include/qam_auto.h \ + /export/home/db/include/qam_ext.h \ + /export/home/db/include/lock.h \ + /export/home/db/include/lock_ext.h \ + /export/home/db/include/mp.h \ + /export/home/db/include/mp_ext.h \ + /export/home/db/include/txn.h \ + /export/home/db/include/xa.h \ + /export/home/db/include/txn_auto.h \ + /export/home/db/include/txn_ext.h \ + /export/home/db/include/xa_ext.h + + + FILE_/export/home/db/db/db_am.c_objects +db_am.o + + + FILE_/export/home/db/db/db_am.c_tool +C/C++ compiler + + + FILE_/export/home/db/db/db_auto.c_dependDone +TRUE + + + FILE_/export/home/db/db/db_auto.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/txn.h \ + /export/home/db/include/xa.h \ + /export/home/db/include/txn_auto.h \ + /export/home/db/include/txn_ext.h \ + /export/home/db/include/xa_ext.h + + + FILE_/export/home/db/db/db_auto.c_objects +db_auto.o + + + FILE_/export/home/db/db/db_auto.c_tool +C/C++ compiler + + + FILE_/export/home/db/db/db_cam.c_dependDone +TRUE + + + FILE_/export/home/db/db/db_cam.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/lock.h \ + /export/home/db/include/lock_ext.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/hash.h \ + /export/home/db/include/hash_auto.h \ + /export/home/db/include/hash_ext.h \ + /export/home/db/include/qam.h \ + /export/home/db/include/qam_auto.h \ + /export/home/db/include/qam_ext.h \ + /export/home/db/include/txn.h \ + /export/home/db/include/xa.h \ + /export/home/db/include/txn_auto.h \ + /export/home/db/include/txn_ext.h \ + /export/home/db/include/xa_ext.h + + + FILE_/export/home/db/db/db_cam.c_objects +db_cam.o + + + FILE_/export/home/db/db/db_cam.c_tool +C/C++ compiler + + + FILE_/export/home/db/db/db_conv.c_dependDone +TRUE + + + FILE_/export/home/db/db/db_conv.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_swap.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h \ + /export/home/db/include/hash.h \ + /export/home/db/include/hash_auto.h \ + /export/home/db/include/hash_ext.h \ + /export/home/db/include/qam.h \ + /export/home/db/include/qam_auto.h \ + /export/home/db/include/qam_ext.h + + + FILE_/export/home/db/db/db_conv.c_objects +db_conv.o + + + FILE_/export/home/db/db/db_conv.c_tool +C/C++ compiler + + + FILE_/export/home/db/db/db_dispatch.c_dependDone +TRUE + + + FILE_/export/home/db/db/db_dispatch.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/log_auto.h \ + /export/home/db/include/txn.h \ + /export/home/db/include/xa.h \ + /export/home/db/include/txn_auto.h \ + /export/home/db/include/txn_ext.h \ + /export/home/db/include/xa_ext.h \ + /export/home/db/include/log.h \ + /export/home/db/include/log_ext.h + + + FILE_/export/home/db/db/db_dispatch.c_objects +db_dispatch.o + + + FILE_/export/home/db/db/db_dispatch.c_tool +C/C++ compiler + + + FILE_/export/home/db/db/db_dup.c_dependDone +TRUE + + + FILE_/export/home/db/db/db_dup.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/hash.h \ + /export/home/db/include/hash_auto.h \ + /export/home/db/include/hash_ext.h \ + /export/home/db/include/lock.h \ + /export/home/db/include/lock_ext.h + + + FILE_/export/home/db/db/db_dup.c_objects +db_dup.o + + + FILE_/export/home/db/db/db_dup.c_tool +C/C++ compiler + + + FILE_/export/home/db/db/db_iface.c_dependDone +TRUE + + + FILE_/export/home/db/db/db_iface.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h + + + FILE_/export/home/db/db/db_iface.c_objects +db_iface.o + + + FILE_/export/home/db/db/db_iface.c_tool +C/C++ compiler + + + FILE_/export/home/db/db/db_join.c_dependDone +TRUE + + + FILE_/export/home/db/db/db_join.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_join.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h + + + FILE_/export/home/db/db/db_join.c_objects +db_join.o + + + FILE_/export/home/db/db/db_join.c_tool +C/C++ compiler + + + FILE_/export/home/db/db/db_meta.c_dependDone +TRUE + + + FILE_/export/home/db/db/db_meta.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/lock.h \ + /export/home/db/include/lock_ext.h \ + /export/home/db/include/txn.h \ + /export/home/db/include/xa.h \ + /export/home/db/include/txn_auto.h \ + /export/home/db/include/txn_ext.h \ + /export/home/db/include/xa_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h + + + FILE_/export/home/db/db/db_meta.c_objects +db_meta.o + + + FILE_/export/home/db/db/db_meta.c_tool +C/C++ compiler + + + FILE_/export/home/db/db/db_method.c_dependDone +TRUE + + + FILE_/export/home/db/db/db_method.c_dependencies +$(PRJ_DIR)/db_config.h \ + /export/home/db/include/db_server.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h \ + /export/home/db/include/hash.h \ + /export/home/db/include/hash_auto.h \ + /export/home/db/include/hash_ext.h \ + /export/home/db/include/qam.h \ + /export/home/db/include/qam_auto.h \ + /export/home/db/include/qam_ext.h \ + /export/home/db/include/xa.h \ + /export/home/db/include/xa_ext.h \ + /export/home/db/include/gen_client_ext.h \ + /export/home/db/include/rpc_client_ext.h + + + FILE_/export/home/db/db/db_method.c_objects +db_method.o + + + FILE_/export/home/db/db/db_method.c_tool +C/C++ compiler + + + FILE_/export/home/db/db/db_overflow.c_dependDone +TRUE + + + FILE_/export/home/db/db/db_overflow.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/db_verify.h + + + FILE_/export/home/db/db/db_overflow.c_objects +db_overflow.o + + + FILE_/export/home/db/db/db_overflow.c_tool +C/C++ compiler + + + FILE_/export/home/db/db/db_pr.c_dependDone +TRUE + + + FILE_/export/home/db/db/db_pr.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/hash.h \ + /export/home/db/include/hash_auto.h \ + /export/home/db/include/hash_ext.h \ + /export/home/db/include/qam.h \ + /export/home/db/include/qam_auto.h \ + /export/home/db/include/qam_ext.h \ + /export/home/db/include/db_verify.h + + + FILE_/export/home/db/db/db_pr.c_objects +db_pr.o + + + FILE_/export/home/db/db/db_pr.c_tool +C/C++ compiler + + + FILE_/export/home/db/db/db_rec.c_dependDone +TRUE + + + FILE_/export/home/db/db/db_rec.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/log.h \ + /export/home/db/include/log_auto.h \ + /export/home/db/include/log_ext.h \ + /export/home/db/include/hash.h \ + /export/home/db/include/hash_auto.h \ + /export/home/db/include/hash_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h + + + FILE_/export/home/db/db/db_rec.c_objects +db_rec.o + + + FILE_/export/home/db/db/db_rec.c_tool +C/C++ compiler + + + FILE_/export/home/db/db/db_reclaim.c_dependDone +TRUE + + + FILE_/export/home/db/db/db_reclaim.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h + + + FILE_/export/home/db/db/db_reclaim.c_objects +db_reclaim.o + + + FILE_/export/home/db/db/db_reclaim.c_tool +C/C++ compiler + + + FILE_/export/home/db/db/db_ret.c_dependDone +TRUE + + + FILE_/export/home/db/db/db_ret.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h + + + FILE_/export/home/db/db/db_ret.c_objects +db_ret.o + + + FILE_/export/home/db/db/db_ret.c_tool +C/C++ compiler + + + FILE_/export/home/db/db/db_upg.c_dependDone +TRUE + + + FILE_/export/home/db/db/db_upg.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_swap.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/hash.h \ + /export/home/db/include/hash_auto.h \ + /export/home/db/include/hash_ext.h \ + /export/home/db/include/qam.h \ + /export/home/db/include/qam_auto.h \ + /export/home/db/include/qam_ext.h + + + FILE_/export/home/db/db/db_upg.c_objects +db_upg.o + + + FILE_/export/home/db/db/db_upg.c_tool +C/C++ compiler + + + FILE_/export/home/db/db/db_upg_opd.c_dependDone +TRUE + + + FILE_/export/home/db/db/db_upg_opd.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_swap.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/hash.h \ + /export/home/db/include/hash_auto.h \ + /export/home/db/include/hash_ext.h \ + /export/home/db/include/qam.h \ + /export/home/db/include/qam_auto.h \ + /export/home/db/include/qam_ext.h + + + FILE_/export/home/db/db/db_upg_opd.c_objects +db_upg_opd.o + + + FILE_/export/home/db/db/db_upg_opd.c_tool +C/C++ compiler + + + FILE_/export/home/db/db/db_vrfy.c_dependDone +TRUE + + + FILE_/export/home/db/db/db_vrfy.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_swap.h \ + /export/home/db/include/db_verify.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/hash.h \ + /export/home/db/include/hash_auto.h \ + /export/home/db/include/hash_ext.h \ + /export/home/db/include/qam.h \ + /export/home/db/include/qam_auto.h \ + /export/home/db/include/qam_ext.h + + + FILE_/export/home/db/db/db_vrfy.c_objects +db_vrfy.o + + + FILE_/export/home/db/db/db_vrfy.c_tool +C/C++ compiler + + + FILE_/export/home/db/db/db_vrfyutil.c_dependDone +TRUE + + + FILE_/export/home/db/db/db_vrfyutil.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_verify.h \ + /export/home/db/include/db_ext.h + + + FILE_/export/home/db/db/db_vrfyutil.c_objects +db_vrfyutil.o + + + FILE_/export/home/db/db/db_vrfyutil.c_tool +C/C++ compiler + + + FILE_/export/home/db/env/db_salloc.c_dependDone +TRUE + + + FILE_/export/home/db/env/db_salloc.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h + + + FILE_/export/home/db/env/db_salloc.c_objects +db_salloc.o + + + FILE_/export/home/db/env/db_salloc.c_tool +C/C++ compiler + + + FILE_/export/home/db/env/db_shash.c_dependDone +TRUE + + + FILE_/export/home/db/env/db_shash.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h + + + FILE_/export/home/db/env/db_shash.c_objects +db_shash.o + + + FILE_/export/home/db/env/db_shash.c_tool +C/C++ compiler + + + FILE_/export/home/db/env/env_method.c_dependDone +TRUE + + + FILE_/export/home/db/env/env_method.c_dependencies +$(PRJ_DIR)/db_config.h \ + /export/home/db/include/db_server.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/lock.h \ + /export/home/db/include/lock_ext.h \ + /export/home/db/include/log.h \ + /export/home/db/include/log_auto.h \ + /export/home/db/include/log_ext.h \ + /export/home/db/include/mp.h \ + /export/home/db/include/mp_ext.h \ + /export/home/db/include/txn.h \ + /export/home/db/include/xa.h \ + /export/home/db/include/txn_auto.h \ + /export/home/db/include/txn_ext.h \ + /export/home/db/include/xa_ext.h \ + /export/home/db/include/gen_client_ext.h \ + /export/home/db/include/rpc_client_ext.h + + + FILE_/export/home/db/env/env_method.c_objects +env_method.o + + + FILE_/export/home/db/env/env_method.c_tool +C/C++ compiler + + + FILE_/export/home/db/env/env_open.c_dependDone +TRUE + + + FILE_/export/home/db/env/env_open.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/hash.h \ + /export/home/db/include/hash_auto.h \ + /export/home/db/include/hash_ext.h \ + /export/home/db/include/qam.h \ + /export/home/db/include/qam_auto.h \ + /export/home/db/include/qam_ext.h \ + /export/home/db/include/lock.h \ + /export/home/db/include/lock_ext.h \ + /export/home/db/include/log.h \ + /export/home/db/include/log_auto.h \ + /export/home/db/include/log_ext.h \ + /export/home/db/include/mp.h \ + /export/home/db/include/mp_ext.h \ + /export/home/db/include/txn.h \ + /export/home/db/include/xa.h \ + /export/home/db/include/txn_auto.h \ + /export/home/db/include/txn_ext.h \ + /export/home/db/include/xa_ext.h \ + /export/home/db/include/clib_ext.h + + + FILE_/export/home/db/env/env_open.c_objects +env_open.o + + + FILE_/export/home/db/env/env_open.c_tool +C/C++ compiler + + + FILE_/export/home/db/env/env_recover.c_dependDone +TRUE + + + FILE_/export/home/db/env/env_recover.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/log.h \ + /export/home/db/include/log_auto.h \ + /export/home/db/include/log_ext.h \ + /export/home/db/include/txn.h \ + /export/home/db/include/xa.h \ + /export/home/db/include/txn_auto.h \ + /export/home/db/include/txn_ext.h \ + /export/home/db/include/xa_ext.h + + + FILE_/export/home/db/env/env_recover.c_objects +env_recover.o + + + FILE_/export/home/db/env/env_recover.c_tool +C/C++ compiler + + + FILE_/export/home/db/env/env_region.c_dependDone +TRUE + + + FILE_/export/home/db/env/env_region.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/lock.h \ + /export/home/db/include/lock_ext.h \ + /export/home/db/include/log.h \ + /export/home/db/include/log_auto.h \ + /export/home/db/include/log_ext.h \ + /export/home/db/include/mp.h \ + /export/home/db/include/mp_ext.h \ + /export/home/db/include/txn.h \ + /export/home/db/include/xa.h \ + /export/home/db/include/txn_auto.h \ + /export/home/db/include/txn_ext.h \ + /export/home/db/include/xa_ext.h + + + FILE_/export/home/db/env/env_region.c_objects +env_region.o + + + FILE_/export/home/db/env/env_region.c_tool +C/C++ compiler + + + FILE_/export/home/db/hash/hash.c_dependDone +TRUE + + + FILE_/export/home/db/hash/hash.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/db_swap.h \ + /export/home/db/include/hash.h \ + /export/home/db/include/hash_auto.h \ + /export/home/db/include/hash_ext.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h \ + /export/home/db/include/log.h \ + /export/home/db/include/log_auto.h \ + /export/home/db/include/log_ext.h \ + /export/home/db/include/lock.h \ + /export/home/db/include/lock_ext.h \ + /export/home/db/include/txn.h \ + /export/home/db/include/xa.h \ + /export/home/db/include/txn_auto.h \ + /export/home/db/include/txn_ext.h \ + /export/home/db/include/xa_ext.h + + + FILE_/export/home/db/hash/hash.c_objects +hash.o + + + FILE_/export/home/db/hash/hash.c_tool +C/C++ compiler + + + FILE_/export/home/db/hash/hash_auto.c_dependDone +TRUE + + + FILE_/export/home/db/hash/hash_auto.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/hash.h \ + /export/home/db/include/hash_auto.h \ + /export/home/db/include/hash_ext.h \ + /export/home/db/include/txn.h \ + /export/home/db/include/xa.h \ + /export/home/db/include/txn_auto.h \ + /export/home/db/include/txn_ext.h \ + /export/home/db/include/xa_ext.h + + + FILE_/export/home/db/hash/hash_auto.c_objects +hash_auto.o + + + FILE_/export/home/db/hash/hash_auto.c_tool +C/C++ compiler + + + FILE_/export/home/db/hash/hash_conv.c_dependDone +TRUE + + + FILE_/export/home/db/hash/hash_conv.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_swap.h \ + /export/home/db/include/hash.h \ + /export/home/db/include/hash_auto.h \ + /export/home/db/include/hash_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h + + + FILE_/export/home/db/hash/hash_conv.c_objects +hash_conv.o + + + FILE_/export/home/db/hash/hash_conv.c_tool +C/C++ compiler + + + FILE_/export/home/db/hash/hash_dup.c_dependDone +TRUE + + + FILE_/export/home/db/hash/hash_dup.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/hash.h \ + /export/home/db/include/hash_auto.h \ + /export/home/db/include/hash_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h \ + /export/home/db/include/txn.h \ + /export/home/db/include/xa.h \ + /export/home/db/include/txn_auto.h \ + /export/home/db/include/txn_ext.h \ + /export/home/db/include/xa_ext.h + + + FILE_/export/home/db/hash/hash_dup.c_objects +hash_dup.o + + + FILE_/export/home/db/hash/hash_dup.c_tool +C/C++ compiler + + + FILE_/export/home/db/hash/hash_func.c_dependDone +TRUE + + + FILE_/export/home/db/hash/hash_func.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/hash.h \ + /export/home/db/include/hash_auto.h \ + /export/home/db/include/hash_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h + + + FILE_/export/home/db/hash/hash_func.c_objects +hash_func.o + + + FILE_/export/home/db/hash/hash_func.c_tool +C/C++ compiler + + + FILE_/export/home/db/hash/hash_meta.c_dependDone +TRUE + + + FILE_/export/home/db/hash/hash_meta.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/hash.h \ + /export/home/db/include/hash_auto.h \ + /export/home/db/include/hash_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/lock.h \ + /export/home/db/include/lock_ext.h \ + /export/home/db/include/txn.h \ + /export/home/db/include/xa.h \ + /export/home/db/include/txn_auto.h \ + /export/home/db/include/txn_ext.h \ + /export/home/db/include/xa_ext.h + + + FILE_/export/home/db/hash/hash_meta.c_objects +hash_meta.o + + + FILE_/export/home/db/hash/hash_meta.c_tool +C/C++ compiler + + + FILE_/export/home/db/hash/hash_method.c_dependDone +TRUE + + + FILE_/export/home/db/hash/hash_method.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/hash.h \ + /export/home/db/include/hash_auto.h \ + /export/home/db/include/hash_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h + + + FILE_/export/home/db/hash/hash_method.c_objects +hash_method.o + + + FILE_/export/home/db/hash/hash_method.c_tool +C/C++ compiler + + + FILE_/export/home/db/hash/hash_page.c_dependDone +TRUE + + + FILE_/export/home/db/hash/hash_page.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/hash.h \ + /export/home/db/include/hash_auto.h \ + /export/home/db/include/hash_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/lock.h \ + /export/home/db/include/lock_ext.h \ + /export/home/db/include/txn.h \ + /export/home/db/include/xa.h \ + /export/home/db/include/txn_auto.h \ + /export/home/db/include/txn_ext.h \ + /export/home/db/include/xa_ext.h + + + FILE_/export/home/db/hash/hash_page.c_objects +hash_page.o + + + FILE_/export/home/db/hash/hash_page.c_tool +C/C++ compiler + + + FILE_/export/home/db/hash/hash_rec.c_dependDone +TRUE + + + FILE_/export/home/db/hash/hash_rec.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/hash.h \ + /export/home/db/include/hash_auto.h \ + /export/home/db/include/hash_ext.h \ + /export/home/db/include/lock.h \ + /export/home/db/include/lock_ext.h \ + /export/home/db/include/log.h \ + /export/home/db/include/log_auto.h \ + /export/home/db/include/log_ext.h \ + /export/home/db/include/mp.h \ + /export/home/db/include/mp_ext.h + + + FILE_/export/home/db/hash/hash_rec.c_objects +hash_rec.o + + + FILE_/export/home/db/hash/hash_rec.c_tool +C/C++ compiler + + + FILE_/export/home/db/hash/hash_reclaim.c_dependDone +TRUE + + + FILE_/export/home/db/hash/hash_reclaim.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/hash.h \ + /export/home/db/include/hash_auto.h \ + /export/home/db/include/hash_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/lock.h \ + /export/home/db/include/lock_ext.h + + + FILE_/export/home/db/hash/hash_reclaim.c_objects +hash_reclaim.o + + + FILE_/export/home/db/hash/hash_reclaim.c_tool +C/C++ compiler + + + FILE_/export/home/db/hash/hash_stat.c_dependDone +TRUE + + + FILE_/export/home/db/hash/hash_stat.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/hash.h \ + /export/home/db/include/hash_auto.h \ + /export/home/db/include/hash_ext.h \ + /export/home/db/include/lock.h \ + /export/home/db/include/lock_ext.h + + + FILE_/export/home/db/hash/hash_stat.c_objects +hash_stat.o + + + FILE_/export/home/db/hash/hash_stat.c_tool +C/C++ compiler + + + FILE_/export/home/db/hash/hash_upgrade.c_dependDone +TRUE + + + FILE_/export/home/db/hash/hash_upgrade.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_swap.h \ + /export/home/db/include/hash.h \ + /export/home/db/include/hash_auto.h \ + /export/home/db/include/hash_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/db_upgrade.h + + + FILE_/export/home/db/hash/hash_upgrade.c_objects +hash_upgrade.o + + + FILE_/export/home/db/hash/hash_upgrade.c_tool +C/C++ compiler + + + FILE_/export/home/db/hash/hash_verify.c_dependDone +TRUE + + + FILE_/export/home/db/hash/hash_verify.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_verify.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/hash.h \ + /export/home/db/include/hash_auto.h \ + /export/home/db/include/hash_ext.h + + + FILE_/export/home/db/hash/hash_verify.c_objects +hash_verify.o + + + FILE_/export/home/db/hash/hash_verify.c_tool +C/C++ compiler + + + FILE_/export/home/db/hsearch/hsearch.c_dependDone +TRUE + + + FILE_/export/home/db/hsearch/hsearch.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h + + + FILE_/export/home/db/hsearch/hsearch.c_objects +hsearch.o + + + FILE_/export/home/db/hsearch/hsearch.c_tool +C/C++ compiler + + + FILE_/export/home/db/include/tcl_db.h_dependDone +TRUE + + + FILE_/export/home/db/lock/lock.c_dependDone +TRUE + + + FILE_/export/home/db/lock/lock.c_dependencies +$(PRJ_DIR)/db_config.h \ + /export/home/db/include/db_server.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/lock.h \ + /export/home/db/include/lock_ext.h \ + /export/home/db/include/log.h \ + /export/home/db/include/log_auto.h \ + /export/home/db/include/log_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/txn.h \ + /export/home/db/include/xa.h \ + /export/home/db/include/txn_auto.h \ + /export/home/db/include/txn_ext.h \ + /export/home/db/include/xa_ext.h \ + /export/home/db/include/gen_client_ext.h \ + /export/home/db/include/rpc_client_ext.h + + + FILE_/export/home/db/lock/lock.c_objects +lock.o + + + FILE_/export/home/db/lock/lock.c_tool +C/C++ compiler + + + FILE_/export/home/db/lock/lock_conflict.c_dependDone +TRUE + + + FILE_/export/home/db/lock/lock_conflict.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h + + + FILE_/export/home/db/lock/lock_conflict.c_objects +lock_conflict.o + + + FILE_/export/home/db/lock/lock_conflict.c_tool +C/C++ compiler + + + FILE_/export/home/db/lock/lock_deadlock.c_dependDone +TRUE + + + FILE_/export/home/db/lock/lock_deadlock.c_dependencies +$(PRJ_DIR)/db_config.h \ + /export/home/db/include/db_server.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/lock.h \ + /export/home/db/include/lock_ext.h \ + /export/home/db/include/txn.h \ + /export/home/db/include/xa.h \ + /export/home/db/include/txn_auto.h \ + /export/home/db/include/txn_ext.h \ + /export/home/db/include/xa_ext.h \ + /export/home/db/include/gen_client_ext.h \ + /export/home/db/include/rpc_client_ext.h + + + FILE_/export/home/db/lock/lock_deadlock.c_objects +lock_deadlock.o + + + FILE_/export/home/db/lock/lock_deadlock.c_tool +C/C++ compiler + + + FILE_/export/home/db/lock/lock_method.c_dependDone +TRUE + + + FILE_/export/home/db/lock/lock_method.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/lock.h \ + /export/home/db/include/lock_ext.h + + + FILE_/export/home/db/lock/lock_method.c_objects +lock_method.o + + + FILE_/export/home/db/lock/lock_method.c_tool +C/C++ compiler + + + FILE_/export/home/db/lock/lock_region.c_dependDone +TRUE + + + FILE_/export/home/db/lock/lock_region.c_dependencies +$(PRJ_DIR)/db_config.h \ + /export/home/db/include/db_server.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/lock.h \ + /export/home/db/include/lock_ext.h \ + /export/home/db/include/gen_client_ext.h \ + /export/home/db/include/rpc_client_ext.h + + + FILE_/export/home/db/lock/lock_region.c_objects +lock_region.o + + + FILE_/export/home/db/lock/lock_region.c_tool +C/C++ compiler + + + FILE_/export/home/db/lock/lock_stat.c_dependDone +TRUE + + + FILE_/export/home/db/lock/lock_stat.c_dependencies +$(PRJ_DIR)/db_config.h \ + /export/home/db/include/db_server.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/lock.h \ + /export/home/db/include/lock_ext.h \ + /export/home/db/include/gen_client_ext.h \ + /export/home/db/include/rpc_client_ext.h + + + FILE_/export/home/db/lock/lock_stat.c_objects +lock_stat.o + + + FILE_/export/home/db/lock/lock_stat.c_tool +C/C++ compiler + + + FILE_/export/home/db/lock/lock_util.c_dependDone +TRUE + + + FILE_/export/home/db/lock/lock_util.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/hash.h \ + /export/home/db/include/hash_auto.h \ + /export/home/db/include/hash_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/lock.h \ + /export/home/db/include/lock_ext.h + + + FILE_/export/home/db/lock/lock_util.c_objects +lock_util.o + + + FILE_/export/home/db/lock/lock_util.c_tool +C/C++ compiler + + + FILE_/export/home/db/log/log.c_dependDone +TRUE + + + FILE_/export/home/db/log/log.c_dependencies +$(PRJ_DIR)/db_config.h \ + /export/home/db/include/db_server.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/log.h \ + /export/home/db/include/log_auto.h \ + /export/home/db/include/log_ext.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/txn.h \ + /export/home/db/include/xa.h \ + /export/home/db/include/txn_auto.h \ + /export/home/db/include/txn_ext.h \ + /export/home/db/include/xa_ext.h \ + /export/home/db/include/gen_client_ext.h \ + /export/home/db/include/rpc_client_ext.h + + + FILE_/export/home/db/log/log.c_objects +log.o + + + FILE_/export/home/db/log/log.c_tool +C/C++ compiler + + + FILE_/export/home/db/log/log_archive.c_dependDone +TRUE + + + FILE_/export/home/db/log/log_archive.c_dependencies +$(PRJ_DIR)/db_config.h \ + /export/home/db/include/db_server.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/log.h \ + /export/home/db/include/log_auto.h \ + /export/home/db/include/log_ext.h \ + /export/home/db/include/clib_ext.h \ + /export/home/db/include/gen_client_ext.h \ + /export/home/db/include/rpc_client_ext.h + + + FILE_/export/home/db/log/log_archive.c_objects +log_archive.o + + + FILE_/export/home/db/log/log_archive.c_tool +C/C++ compiler + + + FILE_/export/home/db/log/log_auto.c_dependDone +TRUE + + + FILE_/export/home/db/log/log_auto.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/log.h \ + /export/home/db/include/log_auto.h \ + /export/home/db/include/log_ext.h \ + /export/home/db/include/txn.h \ + /export/home/db/include/xa.h \ + /export/home/db/include/txn_auto.h \ + /export/home/db/include/txn_ext.h \ + /export/home/db/include/xa_ext.h + + + FILE_/export/home/db/log/log_auto.c_objects +log_auto.o + + + FILE_/export/home/db/log/log_auto.c_tool +C/C++ compiler + + + FILE_/export/home/db/log/log_compare.c_dependDone +TRUE + + + FILE_/export/home/db/log/log_compare.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h + + + FILE_/export/home/db/log/log_compare.c_objects +log_compare.o + + + FILE_/export/home/db/log/log_compare.c_tool +C/C++ compiler + + + FILE_/export/home/db/log/log_findckp.c_dependDone +TRUE + + + FILE_/export/home/db/log/log_findckp.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/log.h \ + /export/home/db/include/log_auto.h \ + /export/home/db/include/log_ext.h \ + /export/home/db/include/txn.h \ + /export/home/db/include/xa.h \ + /export/home/db/include/txn_auto.h \ + /export/home/db/include/txn_ext.h \ + /export/home/db/include/xa_ext.h + + + FILE_/export/home/db/log/log_findckp.c_objects +log_findckp.o + + + FILE_/export/home/db/log/log_findckp.c_tool +C/C++ compiler + + + FILE_/export/home/db/log/log_get.c_dependDone +TRUE + + + FILE_/export/home/db/log/log_get.c_dependencies +$(PRJ_DIR)/db_config.h \ + /export/home/db/include/db_server.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/log.h \ + /export/home/db/include/log_auto.h \ + /export/home/db/include/log_ext.h \ + /export/home/db/include/hash.h \ + /export/home/db/include/hash_auto.h \ + /export/home/db/include/hash_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/gen_client_ext.h \ + /export/home/db/include/rpc_client_ext.h + + + FILE_/export/home/db/log/log_get.c_objects +log_get.o + + + FILE_/export/home/db/log/log_get.c_tool +C/C++ compiler + + + FILE_/export/home/db/log/log_method.c_dependDone +TRUE + + + FILE_/export/home/db/log/log_method.c_dependencies +$(PRJ_DIR)/db_config.h \ + /export/home/db/include/db_server.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/log.h \ + /export/home/db/include/log_auto.h \ + /export/home/db/include/log_ext.h \ + /export/home/db/include/gen_client_ext.h \ + /export/home/db/include/rpc_client_ext.h + + + FILE_/export/home/db/log/log_method.c_objects +log_method.o + + + FILE_/export/home/db/log/log_method.c_tool +C/C++ compiler + + + FILE_/export/home/db/log/log_put.c_dependDone +TRUE + + + FILE_/export/home/db/log/log_put.c_dependencies +$(PRJ_DIR)/db_config.h \ + /export/home/db/include/db_server.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/log.h \ + /export/home/db/include/log_auto.h \ + /export/home/db/include/log_ext.h \ + /export/home/db/include/hash.h \ + /export/home/db/include/hash_auto.h \ + /export/home/db/include/hash_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/clib_ext.h \ + /export/home/db/include/gen_client_ext.h \ + /export/home/db/include/rpc_client_ext.h + + + FILE_/export/home/db/log/log_put.c_objects +log_put.o + + + FILE_/export/home/db/log/log_put.c_tool +C/C++ compiler + + + FILE_/export/home/db/log/log_rec.c_dependDone +TRUE + + + FILE_/export/home/db/log/log_rec.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/log.h \ + /export/home/db/include/log_auto.h \ + /export/home/db/include/log_ext.h + + + FILE_/export/home/db/log/log_rec.c_objects +log_rec.o + + + FILE_/export/home/db/log/log_rec.c_tool +C/C++ compiler + + + FILE_/export/home/db/log/log_register.c_dependDone +TRUE + + + FILE_/export/home/db/log/log_register.c_dependencies +$(PRJ_DIR)/db_config.h \ + /export/home/db/include/db_server.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/log.h \ + /export/home/db/include/log_auto.h \ + /export/home/db/include/log_ext.h \ + /export/home/db/include/gen_client_ext.h \ + /export/home/db/include/rpc_client_ext.h + + + FILE_/export/home/db/log/log_register.c_objects +log_register.o + + + FILE_/export/home/db/log/log_register.c_tool +C/C++ compiler + + + FILE_/export/home/db/mp/mp_alloc.c_dependDone +TRUE + + + FILE_/export/home/db/mp/mp_alloc.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/mp.h \ + /export/home/db/include/mp_ext.h + + + FILE_/export/home/db/mp/mp_alloc.c_objects +mp_alloc.o + + + FILE_/export/home/db/mp/mp_alloc.c_tool +C/C++ compiler + + + FILE_/export/home/db/mp/mp_bh.c_dependDone +TRUE + + + FILE_/export/home/db/mp/mp_bh.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/mp.h \ + /export/home/db/include/mp_ext.h \ + /export/home/db/include/log.h \ + /export/home/db/include/log_auto.h \ + /export/home/db/include/log_ext.h \ + /export/home/db/include/db_page.h + + + FILE_/export/home/db/mp/mp_bh.c_objects +mp_bh.o + + + FILE_/export/home/db/mp/mp_bh.c_tool +C/C++ compiler + + + FILE_/export/home/db/mp/mp_fget.c_dependDone +TRUE + + + FILE_/export/home/db/mp/mp_fget.c_dependencies +$(PRJ_DIR)/db_config.h \ + /export/home/db/include/db_server.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/mp.h \ + /export/home/db/include/mp_ext.h \ + /export/home/db/include/gen_client_ext.h \ + /export/home/db/include/rpc_client_ext.h + + + FILE_/export/home/db/mp/mp_fget.c_objects +mp_fget.o + + + FILE_/export/home/db/mp/mp_fget.c_tool +C/C++ compiler + + + FILE_/export/home/db/mp/mp_fopen.c_dependDone +TRUE + + + FILE_/export/home/db/mp/mp_fopen.c_dependencies +$(PRJ_DIR)/db_config.h \ + /export/home/db/include/db_server.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/mp.h \ + /export/home/db/include/mp_ext.h \ + /export/home/db/include/gen_client_ext.h \ + /export/home/db/include/rpc_client_ext.h + + + FILE_/export/home/db/mp/mp_fopen.c_objects +mp_fopen.o + + + FILE_/export/home/db/mp/mp_fopen.c_tool +C/C++ compiler + + + FILE_/export/home/db/mp/mp_fput.c_dependDone +TRUE + + + FILE_/export/home/db/mp/mp_fput.c_dependencies +$(PRJ_DIR)/db_config.h \ + /export/home/db/include/db_server.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/mp.h \ + /export/home/db/include/mp_ext.h \ + /export/home/db/include/gen_client_ext.h \ + /export/home/db/include/rpc_client_ext.h + + + FILE_/export/home/db/mp/mp_fput.c_objects +mp_fput.o + + + FILE_/export/home/db/mp/mp_fput.c_tool +C/C++ compiler + + + FILE_/export/home/db/mp/mp_fset.c_dependDone +TRUE + + + FILE_/export/home/db/mp/mp_fset.c_dependencies +$(PRJ_DIR)/db_config.h \ + /export/home/db/include/db_server.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/mp.h \ + /export/home/db/include/mp_ext.h \ + /export/home/db/include/gen_client_ext.h \ + /export/home/db/include/rpc_client_ext.h + + + FILE_/export/home/db/mp/mp_fset.c_objects +mp_fset.o + + + FILE_/export/home/db/mp/mp_fset.c_tool +C/C++ compiler + + + FILE_/export/home/db/mp/mp_method.c_dependDone +TRUE + + + FILE_/export/home/db/mp/mp_method.c_dependencies +$(PRJ_DIR)/db_config.h \ + /export/home/db/include/db_server.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/mp.h \ + /export/home/db/include/mp_ext.h \ + /export/home/db/include/gen_client_ext.h \ + /export/home/db/include/rpc_client_ext.h + + + FILE_/export/home/db/mp/mp_method.c_objects +mp_method.o + + + FILE_/export/home/db/mp/mp_method.c_tool +C/C++ compiler + + + FILE_/export/home/db/mp/mp_region.c_dependDone +TRUE + + + FILE_/export/home/db/mp/mp_region.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/mp.h \ + /export/home/db/include/mp_ext.h + + + FILE_/export/home/db/mp/mp_region.c_objects +mp_region.o + + + FILE_/export/home/db/mp/mp_region.c_tool +C/C++ compiler + + + FILE_/export/home/db/mp/mp_register.c_dependDone +TRUE + + + FILE_/export/home/db/mp/mp_register.c_dependencies +$(PRJ_DIR)/db_config.h \ + /export/home/db/include/db_server.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/mp.h \ + /export/home/db/include/mp_ext.h \ + /export/home/db/include/gen_client_ext.h \ + /export/home/db/include/rpc_client_ext.h + + + FILE_/export/home/db/mp/mp_register.c_objects +mp_register.o + + + FILE_/export/home/db/mp/mp_register.c_tool +C/C++ compiler + + + FILE_/export/home/db/mp/mp_stat.c_dependDone +TRUE + + + FILE_/export/home/db/mp/mp_stat.c_dependencies +$(PRJ_DIR)/db_config.h \ + /export/home/db/include/db_server.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/mp.h \ + /export/home/db/include/mp_ext.h \ + /export/home/db/include/gen_client_ext.h \ + /export/home/db/include/rpc_client_ext.h + + + FILE_/export/home/db/mp/mp_stat.c_objects +mp_stat.o + + + FILE_/export/home/db/mp/mp_stat.c_tool +C/C++ compiler + + + FILE_/export/home/db/mp/mp_sync.c_dependDone +TRUE + + + FILE_/export/home/db/mp/mp_sync.c_dependencies +$(PRJ_DIR)/db_config.h \ + /export/home/db/include/db_server.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/mp.h \ + /export/home/db/include/mp_ext.h \ + /export/home/db/include/gen_client_ext.h \ + /export/home/db/include/rpc_client_ext.h + + + FILE_/export/home/db/mp/mp_sync.c_objects +mp_sync.o + + + FILE_/export/home/db/mp/mp_sync.c_tool +C/C++ compiler + + + FILE_/export/home/db/mp/mp_trickle.c_dependDone +TRUE + + + FILE_/export/home/db/mp/mp_trickle.c_dependencies +$(PRJ_DIR)/db_config.h \ + /export/home/db/include/db_server.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/mp.h \ + /export/home/db/include/mp_ext.h \ + /export/home/db/include/gen_client_ext.h \ + /export/home/db/include/rpc_client_ext.h + + + FILE_/export/home/db/mp/mp_trickle.c_objects +mp_trickle.o + + + FILE_/export/home/db/mp/mp_trickle.c_tool +C/C++ compiler + + + FILE_/export/home/db/mutex/mut_tas.c_dependDone +TRUE + + + FILE_/export/home/db/mutex/mut_tas.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h + + + FILE_/export/home/db/mutex/mut_tas.c_objects +mut_tas.o + + + FILE_/export/home/db/mutex/mut_tas.c_tool +C/C++ compiler + + + FILE_/export/home/db/mutex/mutex.c_dependDone +TRUE + + + FILE_/export/home/db/mutex/mutex.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h + + + FILE_/export/home/db/mutex/mutex.c_objects +mutex.o + + + FILE_/export/home/db/mutex/mutex.c_tool +C/C++ compiler + + + FILE_/export/home/db/os/os_alloc.c_dependDone +TRUE + + + FILE_/export/home/db/os/os_alloc.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/os_jump.h + + + FILE_/export/home/db/os/os_alloc.c_objects +os_alloc.o + + + FILE_/export/home/db/os/os_alloc.c_tool +C/C++ compiler + + + FILE_/export/home/db/os/os_dir.c_dependDone +TRUE + + + FILE_/export/home/db/os/os_dir.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/os_jump.h + + + FILE_/export/home/db/os/os_dir.c_objects +os_dir.o + + + FILE_/export/home/db/os/os_dir.c_tool +C/C++ compiler + + + FILE_/export/home/db/os/os_errno.c_dependDone +TRUE + + + FILE_/export/home/db/os/os_errno.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h + + + FILE_/export/home/db/os/os_errno.c_objects +os_errno.o + + + FILE_/export/home/db/os/os_errno.c_tool +C/C++ compiler + + + FILE_/export/home/db/os/os_fid.c_dependDone +TRUE + + + FILE_/export/home/db/os/os_fid.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h + + + FILE_/export/home/db/os/os_fid.c_objects +os_fid.o + + + FILE_/export/home/db/os/os_fid.c_tool +C/C++ compiler + + + FILE_/export/home/db/os/os_fsync.c_dependDone +TRUE + + + FILE_/export/home/db/os/os_fsync.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/os_jump.h + + + FILE_/export/home/db/os/os_fsync.c_objects +os_fsync.o + + + FILE_/export/home/db/os/os_fsync.c_tool +C/C++ compiler + + + FILE_/export/home/db/os/os_handle.c_dependDone +TRUE + + + FILE_/export/home/db/os/os_handle.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/os_jump.h + + + FILE_/export/home/db/os/os_handle.c_objects +os_handle.o + + + FILE_/export/home/db/os/os_handle.c_tool +C/C++ compiler + + + FILE_/export/home/db/os/os_method.c_dependDone +TRUE + + + FILE_/export/home/db/os/os_method.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/os_jump.h + + + FILE_/export/home/db/os/os_method.c_objects +os_method.o + + + FILE_/export/home/db/os/os_method.c_tool +C/C++ compiler + + + FILE_/export/home/db/os/os_oflags.c_dependDone +TRUE + + + FILE_/export/home/db/os/os_oflags.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h + + + FILE_/export/home/db/os/os_oflags.c_objects +os_oflags.o + + + FILE_/export/home/db/os/os_oflags.c_tool +C/C++ compiler + + + FILE_/export/home/db/os/os_open.c_dependDone +TRUE + + + FILE_/export/home/db/os/os_open.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h + + + FILE_/export/home/db/os/os_open.c_objects +os_open.o + + + FILE_/export/home/db/os/os_open.c_tool +C/C++ compiler + + + FILE_/export/home/db/os/os_region.c_dependDone +TRUE + + + FILE_/export/home/db/os/os_region.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/os_jump.h + + + FILE_/export/home/db/os/os_region.c_objects +os_region.o + + + FILE_/export/home/db/os/os_region.c_tool +C/C++ compiler + + + FILE_/export/home/db/os/os_rename.c_dependDone +TRUE + + + FILE_/export/home/db/os/os_rename.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/os_jump.h + + + FILE_/export/home/db/os/os_rename.c_objects +os_rename.o + + + FILE_/export/home/db/os/os_rename.c_tool +C/C++ compiler + + + FILE_/export/home/db/os/os_root.c_dependDone +TRUE + + + FILE_/export/home/db/os/os_root.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h + + + FILE_/export/home/db/os/os_root.c_objects +os_root.o + + + FILE_/export/home/db/os/os_root.c_tool +C/C++ compiler + + + FILE_/export/home/db/os/os_rpath.c_dependDone +TRUE + + + FILE_/export/home/db/os/os_rpath.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h + + + FILE_/export/home/db/os/os_rpath.c_objects +os_rpath.o + + + FILE_/export/home/db/os/os_rpath.c_tool +C/C++ compiler + + + FILE_/export/home/db/os/os_rw.c_dependDone +TRUE + + + FILE_/export/home/db/os/os_rw.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/os_jump.h + + + FILE_/export/home/db/os/os_rw.c_objects +os_rw.o + + + FILE_/export/home/db/os/os_rw.c_tool +C/C++ compiler + + + FILE_/export/home/db/os/os_seek.c_dependDone +TRUE + + + FILE_/export/home/db/os/os_seek.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/os_jump.h + + + FILE_/export/home/db/os/os_seek.c_objects +os_seek.o + + + FILE_/export/home/db/os/os_seek.c_tool +C/C++ compiler + + + FILE_/export/home/db/os/os_sleep.c_dependDone +TRUE + + + FILE_/export/home/db/os/os_sleep.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/os_jump.h + + + FILE_/export/home/db/os/os_sleep.c_objects +os_sleep.o + + + FILE_/export/home/db/os/os_sleep.c_tool +C/C++ compiler + + + FILE_/export/home/db/os/os_spin.c_dependDone +TRUE + + + FILE_/export/home/db/os/os_spin.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/os_jump.h + + + FILE_/export/home/db/os/os_spin.c_objects +os_spin.o + + + FILE_/export/home/db/os/os_spin.c_tool +C/C++ compiler + + + FILE_/export/home/db/os/os_stat.c_dependDone +TRUE + + + FILE_/export/home/db/os/os_stat.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/os_jump.h + + + FILE_/export/home/db/os/os_stat.c_objects +os_stat.o + + + FILE_/export/home/db/os/os_stat.c_tool +C/C++ compiler + + + FILE_/export/home/db/os/os_tmpdir.c_dependDone +TRUE + + + FILE_/export/home/db/os/os_tmpdir.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h + + + FILE_/export/home/db/os/os_tmpdir.c_objects +os_tmpdir.o + + + FILE_/export/home/db/os/os_tmpdir.c_tool +C/C++ compiler + + + FILE_/export/home/db/os/os_unlink.c_dependDone +TRUE + + + FILE_/export/home/db/os/os_unlink.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/os_jump.h + + + FILE_/export/home/db/os/os_unlink.c_objects +os_unlink.o + + + FILE_/export/home/db/os/os_unlink.c_tool +C/C++ compiler + + + FILE_/export/home/db/os_vxworks/os_abs.c_dependDone +TRUE + + + FILE_/export/home/db/os_vxworks/os_abs.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h + + + FILE_/export/home/db/os_vxworks/os_abs.c_objects +os_abs.o + + + FILE_/export/home/db/os_vxworks/os_abs.c_tool +C/C++ compiler + + + FILE_/export/home/db/os_vxworks/os_finit.c_dependDone +TRUE + + + FILE_/export/home/db/os_vxworks/os_finit.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h + + + FILE_/export/home/db/os_vxworks/os_finit.c_objects +os_finit.o + + + FILE_/export/home/db/os_vxworks/os_finit.c_tool +C/C++ compiler + + + FILE_/export/home/db/os_vxworks/os_map.c_dependDone +TRUE + + + FILE_/export/home/db/os_vxworks/os_map.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h + + + FILE_/export/home/db/os_vxworks/os_map.c_objects +os_map.o + + + FILE_/export/home/db/os_vxworks/os_map.c_tool +C/C++ compiler + + + FILE_/export/home/db/qam/qam.c_dependDone +TRUE + + + FILE_/export/home/db/qam/qam.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/mp.h \ + /export/home/db/include/mp_ext.h \ + /export/home/db/include/lock.h \ + /export/home/db/include/lock_ext.h \ + /export/home/db/include/log.h \ + /export/home/db/include/log_auto.h \ + /export/home/db/include/log_ext.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h \ + /export/home/db/include/qam.h \ + /export/home/db/include/qam_auto.h \ + /export/home/db/include/qam_ext.h + + + FILE_/export/home/db/qam/qam.c_objects +qam.o + + + FILE_/export/home/db/qam/qam.c_tool +C/C++ compiler + + + FILE_/export/home/db/qam/qam_auto.c_dependDone +TRUE + + + FILE_/export/home/db/qam/qam_auto.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/qam.h \ + /export/home/db/include/qam_auto.h \ + /export/home/db/include/qam_ext.h \ + /export/home/db/include/txn.h \ + /export/home/db/include/xa.h \ + /export/home/db/include/txn_auto.h \ + /export/home/db/include/txn_ext.h \ + /export/home/db/include/xa_ext.h + + + FILE_/export/home/db/qam/qam_auto.c_objects +qam_auto.o + + + FILE_/export/home/db/qam/qam_auto.c_tool +C/C++ compiler + + + FILE_/export/home/db/qam/qam_conv.c_dependDone +TRUE + + + FILE_/export/home/db/qam/qam_conv.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/qam.h \ + /export/home/db/include/qam_auto.h \ + /export/home/db/include/qam_ext.h \ + /export/home/db/include/db_swap.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h + + + FILE_/export/home/db/qam/qam_conv.c_objects +qam_conv.o + + + FILE_/export/home/db/qam/qam_conv.c_tool +C/C++ compiler + + + FILE_/export/home/db/qam/qam_files.c_dependDone +TRUE + + + FILE_/export/home/db/qam/qam_files.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/lock.h \ + /export/home/db/include/lock_ext.h \ + /export/home/db/include/btree.h \ + /export/home/db/include/btree_auto.h \ + /export/home/db/include/btree_ext.h \ + /export/home/db/include/qam.h \ + /export/home/db/include/qam_auto.h \ + /export/home/db/include/qam_ext.h \ + /export/home/db/include/mp.h \ + /export/home/db/include/mp_ext.h + + + FILE_/export/home/db/qam/qam_files.c_objects +qam_files.o + + + FILE_/export/home/db/qam/qam_files.c_tool +C/C++ compiler + + + FILE_/export/home/db/qam/qam_method.c_dependDone +TRUE + + + FILE_/export/home/db/qam/qam_method.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/qam.h \ + /export/home/db/include/qam_auto.h \ + /export/home/db/include/qam_ext.h \ + /export/home/db/include/mp.h \ + /export/home/db/include/mp_ext.h \ + /export/home/db/include/lock.h \ + /export/home/db/include/lock_ext.h \ + /export/home/db/include/log.h \ + /export/home/db/include/log_auto.h \ + /export/home/db/include/log_ext.h + + + FILE_/export/home/db/qam/qam_method.c_objects +qam_method.o + + + FILE_/export/home/db/qam/qam_method.c_tool +C/C++ compiler + + + FILE_/export/home/db/qam/qam_open.c_dependDone +TRUE + + + FILE_/export/home/db/qam/qam_open.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/db_swap.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/lock.h \ + /export/home/db/include/lock_ext.h \ + /export/home/db/include/qam.h \ + /export/home/db/include/qam_auto.h \ + /export/home/db/include/qam_ext.h + + + FILE_/export/home/db/qam/qam_open.c_objects +qam_open.o + + + FILE_/export/home/db/qam/qam_open.c_tool +C/C++ compiler + + + FILE_/export/home/db/qam/qam_rec.c_dependDone +TRUE + + + FILE_/export/home/db/qam/qam_rec.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/lock.h \ + /export/home/db/include/lock_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/qam.h \ + /export/home/db/include/qam_auto.h \ + /export/home/db/include/qam_ext.h \ + /export/home/db/include/log.h \ + /export/home/db/include/log_auto.h \ + /export/home/db/include/log_ext.h + + + FILE_/export/home/db/qam/qam_rec.c_objects +qam_rec.o + + + FILE_/export/home/db/qam/qam_rec.c_tool +C/C++ compiler + + + FILE_/export/home/db/qam/qam_stat.c_dependDone +TRUE + + + FILE_/export/home/db/qam/qam_stat.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/lock.h \ + /export/home/db/include/lock_ext.h \ + /export/home/db/include/qam.h \ + /export/home/db/include/qam_auto.h \ + /export/home/db/include/qam_ext.h + + + FILE_/export/home/db/qam/qam_stat.c_objects +qam_stat.o + + + FILE_/export/home/db/qam/qam_stat.c_tool +C/C++ compiler + + + FILE_/export/home/db/qam/qam_upgrade.c_dependDone +TRUE + + + FILE_/export/home/db/qam/qam_upgrade.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_swap.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/db_upgrade.h + + + FILE_/export/home/db/qam/qam_upgrade.c_objects +qam_upgrade.o + + + FILE_/export/home/db/qam/qam_upgrade.c_tool +C/C++ compiler + + + FILE_/export/home/db/qam/qam_verify.c_dependDone +TRUE + + + FILE_/export/home/db/qam/qam_verify.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_verify.h \ + /export/home/db/include/qam.h \ + /export/home/db/include/qam_auto.h \ + /export/home/db/include/qam_ext.h \ + /export/home/db/include/db_ext.h + + + FILE_/export/home/db/qam/qam_verify.c_objects +qam_verify.o + + + FILE_/export/home/db/qam/qam_verify.c_tool +C/C++ compiler + + + FILE_/export/home/db/rpc_client/client.c_dependDone +TRUE + + + FILE_/export/home/db/rpc_client/client.c_dependencies +$(PRJ_DIR)/db_config.h \ + /export/home/db/include/db_server.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/txn.h \ + /export/home/db/include/xa.h \ + /export/home/db/include/txn_auto.h \ + /export/home/db/include/txn_ext.h \ + /export/home/db/include/xa_ext.h \ + /export/home/db/include/gen_client_ext.h \ + /export/home/db/include/rpc_client_ext.h + + + FILE_/export/home/db/rpc_client/client.c_objects +client.o + + + FILE_/export/home/db/rpc_client/client.c_tool +C/C++ compiler + + + FILE_/export/home/db/rpc_client/db_server_clnt.c_dependDone +TRUE + + + FILE_/export/home/db/rpc_client/db_server_clnt.c_dependencies +$(PRJ_DIR)/db_config.h /export/home/db/include/db_server.h + + + FILE_/export/home/db/rpc_client/db_server_clnt.c_objects +db_server_clnt.o + + + FILE_/export/home/db/rpc_client/db_server_clnt.c_tool +C/C++ compiler + + + FILE_/export/home/db/rpc_client/gen_client.c_dependDone +TRUE + + + FILE_/export/home/db/rpc_client/gen_client.c_dependencies +$(PRJ_DIR)/db_config.h \ + /export/home/db/include/db_server.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/mp.h \ + /export/home/db/include/mp_ext.h \ + /export/home/db/include/rpc_client_ext.h \ + /export/home/db/include/txn.h \ + /export/home/db/include/xa.h \ + /export/home/db/include/txn_auto.h \ + /export/home/db/include/txn_ext.h \ + /export/home/db/include/xa_ext.h \ + /export/home/db/include/gen_client_ext.h + + + FILE_/export/home/db/rpc_client/gen_client.c_objects +gen_client.o + + + FILE_/export/home/db/rpc_client/gen_client.c_tool +C/C++ compiler + + + FILE_/export/home/db/rpc_client/gen_client_ret.c_dependDone +TRUE + + + FILE_/export/home/db/rpc_client/gen_client_ret.c_dependencies +$(PRJ_DIR)/db_config.h \ + /export/home/db/include/db_server.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/txn.h \ + /export/home/db/include/xa.h \ + /export/home/db/include/txn_auto.h \ + /export/home/db/include/txn_ext.h \ + /export/home/db/include/xa_ext.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/rpc_client_ext.h + + + FILE_/export/home/db/rpc_client/gen_client_ret.c_objects +gen_client_ret.o + + + FILE_/export/home/db/rpc_client/gen_client_ret.c_tool +C/C++ compiler + + + FILE_/export/home/db/rpc_server/db_server_xdr.c_dependDone +TRUE + + + FILE_/export/home/db/rpc_server/db_server_xdr.c_dependencies +$(PRJ_DIR)/db_config.h /export/home/db/include/db_server.h + + + FILE_/export/home/db/rpc_server/db_server_xdr.c_objects +db_server_xdr.o + + + FILE_/export/home/db/rpc_server/db_server_xdr.c_tool +C/C++ compiler + + + FILE_/export/home/db/txn/txn.c_dependDone +TRUE + + + FILE_/export/home/db/txn/txn.c_dependencies +$(PRJ_DIR)/db_config.h \ + /export/home/db/include/db_server.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_shash.h \ + /export/home/db/include/txn.h \ + /export/home/db/include/xa.h \ + /export/home/db/include/txn_auto.h \ + /export/home/db/include/txn_ext.h \ + /export/home/db/include/xa_ext.h \ + /export/home/db/include/lock.h \ + /export/home/db/include/lock_ext.h \ + /export/home/db/include/log.h \ + /export/home/db/include/log_auto.h \ + /export/home/db/include/log_ext.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/gen_client_ext.h \ + /export/home/db/include/rpc_client_ext.h + + + FILE_/export/home/db/txn/txn.c_objects +txn.o + + + FILE_/export/home/db/txn/txn.c_tool +C/C++ compiler + + + FILE_/export/home/db/txn/txn_auto.c_dependDone +TRUE + + + FILE_/export/home/db/txn/txn_auto.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/txn.h \ + /export/home/db/include/xa.h \ + /export/home/db/include/txn_auto.h \ + /export/home/db/include/txn_ext.h \ + /export/home/db/include/xa_ext.h + + + FILE_/export/home/db/txn/txn_auto.c_objects +txn_auto.o + + + FILE_/export/home/db/txn/txn_auto.c_tool +C/C++ compiler + + + FILE_/export/home/db/txn/txn_rec.c_dependDone +TRUE + + + FILE_/export/home/db/txn/txn_rec.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/txn.h \ + /export/home/db/include/xa.h \ + /export/home/db/include/txn_auto.h \ + /export/home/db/include/txn_ext.h \ + /export/home/db/include/xa_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h + + + FILE_/export/home/db/txn/txn_rec.c_objects +txn_rec.o + + + FILE_/export/home/db/txn/txn_rec.c_tool +C/C++ compiler + + + FILE_/export/home/db/txn/txn_region.c_dependDone +TRUE + + + FILE_/export/home/db/txn/txn_region.c_dependencies +$(PRJ_DIR)/db_config.h \ + /export/home/db/include/db_server.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/txn.h \ + /export/home/db/include/xa.h \ + /export/home/db/include/txn_auto.h \ + /export/home/db/include/txn_ext.h \ + /export/home/db/include/xa_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h \ + /export/home/db/include/gen_client_ext.h \ + /export/home/db/include/rpc_client_ext.h + + + FILE_/export/home/db/txn/txn_region.c_objects +txn_region.o + + + FILE_/export/home/db/txn/txn_region.c_tool +C/C++ compiler + + + FILE_/export/home/db/xa/xa.c_dependDone +TRUE + + + FILE_/export/home/db/xa/xa.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/db_page.h \ + /export/home/db/include/log.h \ + /export/home/db/include/log_auto.h \ + /export/home/db/include/log_ext.h \ + /export/home/db/include/txn.h \ + /export/home/db/include/xa.h \ + /export/home/db/include/txn_auto.h \ + /export/home/db/include/txn_ext.h \ + /export/home/db/include/xa_ext.h \ + /export/home/db/include/db_am.h \ + /export/home/db/include/db_dispatch.h \ + /export/home/db/include/db_auto.h \ + /export/home/db/include/crdel_auto.h \ + /export/home/db/include/db_ext.h + + + FILE_/export/home/db/xa/xa.c_objects +xa.o + + + FILE_/export/home/db/xa/xa.c_tool +C/C++ compiler + + + FILE_/export/home/db/xa/xa_db.c_dependDone +TRUE + + + FILE_/export/home/db/xa/xa_db.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/xa.h \ + /export/home/db/include/xa_ext.h \ + /export/home/db/include/txn.h \ + /export/home/db/include/txn_auto.h \ + /export/home/db/include/txn_ext.h + + + FILE_/export/home/db/xa/xa_db.c_objects +xa_db.o + + + FILE_/export/home/db/xa/xa_db.c_tool +C/C++ compiler + + + FILE_/export/home/db/xa/xa_map.c_dependDone +TRUE + + + FILE_/export/home/db/xa/xa_map.c_dependencies +$(PRJ_DIR)/db_config.h \ + $(PRJ_DIR)/db_int.h \ + $(PRJ_DIR)/db.h \ + /export/home/db/include/queue.h \ + /export/home/db/include/shqueue.h \ + /export/home/db/include/debug.h \ + /export/home/db/include/mutex.h \ + /export/home/db/include/region.h \ + /export/home/db/include/mutex_ext.h \ + /export/home/db/include/env_ext.h \ + /export/home/db/include/os.h \ + /export/home/db/include/os_ext.h \ + /export/home/db/include/common_ext.h \ + /export/home/db/include/txn.h \ + /export/home/db/include/xa.h \ + /export/home/db/include/txn_auto.h \ + /export/home/db/include/txn_ext.h \ + /export/home/db/include/xa_ext.h + + + FILE_/export/home/db/xa/xa_map.c_objects +xa_map.o + + + FILE_/export/home/db/xa/xa_map.c_tool +C/C++ compiler + + + PROJECT_FILES +/export/home/db/hsearch/hsearch.c \ + /export/home/db/mp/mp_trickle.c \ + /export/home/db/mp/mp_bh.c \ + /export/home/db/mp/mp_fget.c \ + /export/home/db/mp/mp_fopen.c \ + /export/home/db/mp/mp_fput.c \ + /export/home/db/mp/mp_fset.c \ + /export/home/db/mp/mp_method.c \ + /export/home/db/mp/mp_region.c \ + /export/home/db/mp/mp_register.c \ + /export/home/db/mp/mp_stat.c \ + /export/home/db/mp/mp_sync.c \ + /export/home/db/mp/mp_alloc.c \ + /export/home/db/db/crdel_rec.c \ + /export/home/db/db/db.c \ + /export/home/db/db/db_am.c \ + /export/home/db/db/db_auto.c \ + /export/home/db/db/db_cam.c \ + /export/home/db/db/db_conv.c \ + /export/home/db/db/db_dispatch.c \ + /export/home/db/db/db_dup.c \ + /export/home/db/db/db_iface.c \ + /export/home/db/db/db_join.c \ + /export/home/db/db/db_meta.c \ + /export/home/db/db/db_method.c \ + /export/home/db/db/db_overflow.c \ + /export/home/db/db/db_pr.c \ + /export/home/db/db/db_rec.c \ + /export/home/db/db/db_reclaim.c \ + /export/home/db/db/db_ret.c \ + /export/home/db/db/crdel_auto.c \ + /export/home/db/clib/getopt.c \ + /export/home/db/clib/snprintf.c \ + /export/home/db/clib/strcasecmp.c \ + /export/home/db/os/os_unlink.c \ + /export/home/db/os/os_alloc.c \ + /export/home/db/os/os_dir.c \ + /export/home/db/os/os_errno.c \ + /export/home/db/os/os_fid.c \ + /export/home/db/os/os_fsync.c \ + /export/home/db/os/os_handle.c \ + /export/home/db/os/os_method.c \ + /export/home/db/os/os_oflags.c \ + /export/home/db/os/os_open.c \ + /export/home/db/os/os_region.c \ + /export/home/db/os/os_rename.c \ + /export/home/db/os/os_root.c \ + /export/home/db/os/os_rpath.c \ + /export/home/db/os/os_rw.c \ + /export/home/db/os/os_seek.c \ + /export/home/db/os/os_spin.c \ + /export/home/db/os/os_stat.c \ + /export/home/db/os/os_tmpdir.c \ + /export/home/db/qam/qam_upgrade.c \ + /export/home/db/qam/qam_auto.c \ + /export/home/db/qam/qam_conv.c \ + /export/home/db/qam/qam_method.c \ + /export/home/db/qam/qam_open.c \ + /export/home/db/qam/qam_rec.c \ + /export/home/db/qam/qam_stat.c \ + /export/home/db/qam/qam.c \ + /export/home/db/hash/hash_upgrade.c \ + /export/home/db/hash/hash_auto.c \ + /export/home/db/hash/hash_conv.c \ + /export/home/db/hash/hash_dup.c \ + /export/home/db/hash/hash_func.c \ + /export/home/db/hash/hash_meta.c \ + /export/home/db/hash/hash_method.c \ + /export/home/db/hash/hash_page.c \ + /export/home/db/hash/hash_rec.c \ + /export/home/db/hash/hash_reclaim.c \ + /export/home/db/hash/hash_stat.c \ + /export/home/db/hash/hash.c \ + /export/home/db/xa/xa_map.c \ + /export/home/db/xa/xa_db.c \ + /export/home/db/xa/xa.c \ + /export/home/db/btree/btree_auto.c \ + /export/home/db/btree/bt_conv.c \ + /export/home/db/btree/bt_curadj.c \ + /export/home/db/btree/bt_cursor.c \ + /export/home/db/btree/bt_delete.c \ + /export/home/db/btree/bt_method.c \ + /export/home/db/btree/bt_open.c \ + /export/home/db/btree/bt_put.c \ + /export/home/db/btree/bt_rec.c \ + /export/home/db/btree/bt_reclaim.c \ + /export/home/db/btree/bt_recno.c \ + /export/home/db/btree/bt_rsearch.c \ + /export/home/db/btree/bt_search.c \ + /export/home/db/btree/bt_split.c \ + /export/home/db/btree/bt_stat.c \ + /export/home/db/btree/bt_upgrade.c \ + /export/home/db/btree/bt_compare.c \ + /export/home/db/common/db_log2.c \ + /export/home/db/common/db_err.c \ + /export/home/db/common/db_getlong.c \ + /export/home/db/common/db_byteorder.c \ + /export/home/db/env/env_region.c \ + /export/home/db/env/db_shash.c \ + /export/home/db/env/env_method.c \ + /export/home/db/env/env_open.c \ + /export/home/db/env/env_recover.c \ + /export/home/db/env/db_salloc.c \ + /export/home/db/lock/lock_util.c \ + /export/home/db/lock/lock_conflict.c \ + /export/home/db/lock/lock_deadlock.c \ + /export/home/db/lock/lock_region.c \ + /export/home/db/lock/lock.c \ + /export/home/db/txn/txn_region.c \ + /export/home/db/txn/txn_auto.c \ + /export/home/db/txn/txn_rec.c \ + /export/home/db/txn/txn.c \ + /export/home/db/log/log_register.c \ + /export/home/db/log/log_archive.c \ + /export/home/db/log/log_auto.c \ + /export/home/db/log/log_compare.c \ + /export/home/db/log/log_findckp.c \ + /export/home/db/log/log_get.c \ + /export/home/db/log/log_method.c \ + /export/home/db/log/log_put.c \ + /export/home/db/log/log_rec.c \ + /export/home/db/log/log.c \ + /export/home/db/mutex/mut_tas.c \ + /export/home/db/mutex/mutex.c \ + /export/home/db/clib/vsnprintf.c \ + /export/home/db/common/util_log.c \ + /export/home/db/common/util_sig.c \ + /export/home/db/os/os_sleep.c \ + /export/home/db/btree/bt_verify.c \ + /export/home/db/hash/hash_verify.c \ + /export/home/db/qam/qam_verify.c \ + /export/home/db/db/db_upg_opd.c \ + /export/home/db/rpc_client/gen_client_ret.c \ + /export/home/db/rpc_client/db_server_clnt.c \ + /export/home/db/rpc_client/gen_client.c \ + /export/home/db/rpc_client/client.c \ + /export/home/db/include/tcl_db.h \ + /export/home/db/rpc_server/db_server_xdr.c \ + /export/home/db/os_vxworks/os_map.c \ + /export/home/db/db/db_vrfy.c \ + /export/home/db/db/db_upg.c \ + /export/home/db/db/db_vrfyutil.c \ + /export/home/db/os_vxworks/os_finit.c \ + /export/home/db/os_vxworks/os_abs.c \ + /export/home/db/lock/lock_method.c \ + /export/home/db/lock/lock_stat.c \ + /export/home/db/qam/qam_files.c + + + userComments +BerkeleyDB + + diff --git a/db/build_vxworks/BerkeleyDB.wsp b/db/build_vxworks/BerkeleyDB.wsp new file mode 100644 index 000000000..cffcf00de --- /dev/null +++ b/db/build_vxworks/BerkeleyDB.wsp @@ -0,0 +1,24 @@ +Document file - DO NOT EDIT + + CORE_INFO_TYPE +Workspace + + + CORE_INFO_VERSION +2.0 + + + projectList +$(PRJ_DIR)/BerkeleyDB.wpj \ + $(PRJ_DIR)/ex_access/ex_access.wpj \ + $(PRJ_DIR)/ex_btrec/ex_btrec.wpj \ + $(PRJ_DIR)/ex_env/ex_env.wpj \ + $(PRJ_DIR)/ex_mpool/ex_mpool.wpj \ + $(PRJ_DIR)/ex_tpcb/ex_tpcb.wpj \ + $(PRJ_DIR)/ex_dbclient/ex_dbclient.wpj + + + userComments + + + diff --git a/db/build_vxworks/db.h b/db/build_vxworks/db.h new file mode 100644 index 000000000..9464b87bc --- /dev/null +++ b/db/build_vxworks/db.h @@ -0,0 +1,1369 @@ +/* DO NOT EDIT: automatically built by dist/s_vxworks. */ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: db.src,v 11.121 2001/01/10 15:43:08 sue Exp $ + */ + +#ifndef _DB_H_ +#define _DB_H_ + +#ifndef __NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +/* + * XXX + * Handle function prototypes and the keyword "const". This steps on name + * space that DB doesn't control, but all of the other solutions are worse. + * + * XXX + * While Microsoft's compiler is ANSI C compliant, it doesn't have _STDC_ + * defined by default, you specify a command line flag or #pragma to turn + * it on. Don't do that, however, because some of Microsoft's own header + * files won't compile. + */ +#undef __P +#if defined(__STDC__) || defined(__cplusplus) || defined(_MSC_VER) +#define __P(protos) protos /* ANSI C prototypes */ +#else +#define const +#define __P(protos) () /* K&R C preprocessor */ +#endif + +/* + * !!! + * DB needs basic information about specifically sized types. If they're + * not provided by the system, typedef them here. + * + * We protect them against multiple inclusion using __BIT_TYPES_DEFINED__, + * as does BIND and Kerberos, since we don't know for sure what #include + * files the user is using. + * + * !!! + * We also provide the standard u_int, u_long etc., if they're not provided + * by the system. + */ +#ifndef __BIT_TYPES_DEFINED__ +#define __BIT_TYPES_DEFINED__ +typedef unsigned char u_int8_t; +typedef unsigned short u_int16_t; +typedef unsigned int u_int32_t; +#endif + + +#define DB_VERSION_MAJOR 3 +#define DB_VERSION_MINOR 2 +#define DB_VERSION_PATCH 9 +#define DB_VERSION_STRING "Sleepycat Software: Berkeley DB 3.2.9: (January 24, 2001)" + +typedef u_int32_t db_pgno_t; /* Page number type. */ +typedef u_int16_t db_indx_t; /* Page offset type. */ +#define DB_MAX_PAGES 0xffffffff /* >= # of pages in a file */ + +typedef u_int32_t db_recno_t; /* Record number type. */ +#define DB_MAX_RECORDS 0xffffffff /* >= # of records in a tree */ + +/* Forward structure declarations, so applications get type checking. */ +struct __db; typedef struct __db DB; +#ifdef DB_DBM_HSEARCH + typedef struct __db DBM; +#endif +struct __db_bt_stat; typedef struct __db_bt_stat DB_BTREE_STAT; +struct __db_dbt; typedef struct __db_dbt DBT; +struct __db_env; typedef struct __db_env DB_ENV; +struct __db_h_stat; typedef struct __db_h_stat DB_HASH_STAT; +struct __db_ilock; typedef struct __db_ilock DB_LOCK_ILOCK; +struct __db_lock_stat; typedef struct __db_lock_stat DB_LOCK_STAT; +struct __db_lock_u; typedef struct __db_lock_u DB_LOCK; +struct __db_lockreq; typedef struct __db_lockreq DB_LOCKREQ; +struct __db_log_stat; typedef struct __db_log_stat DB_LOG_STAT; +struct __db_lsn; typedef struct __db_lsn DB_LSN; +struct __db_mpool_finfo;typedef struct __db_mpool_finfo DB_MPOOL_FINFO; +struct __db_mpool_fstat;typedef struct __db_mpool_fstat DB_MPOOL_FSTAT; +struct __db_mpool_stat; typedef struct __db_mpool_stat DB_MPOOL_STAT; +struct __db_mpoolfile; typedef struct __db_mpoolfile DB_MPOOLFILE; +struct __db_qam_stat; typedef struct __db_qam_stat DB_QUEUE_STAT; +struct __db_txn; typedef struct __db_txn DB_TXN; +struct __db_txn_active; typedef struct __db_txn_active DB_TXN_ACTIVE; +struct __db_txn_stat; typedef struct __db_txn_stat DB_TXN_STAT; +struct __dbc; typedef struct __dbc DBC; +struct __dbc_internal; typedef struct __dbc_internal DBC_INTERNAL; +struct __fh_t; typedef struct __fh_t DB_FH; +struct __key_range; typedef struct __key_range DB_KEY_RANGE; + +/* Key/data structure -- a Data-Base Thang. */ +struct __db_dbt { + /* + * data/size must be fields 1 and 2 for DB 1.85 compatibility. + */ + void *data; /* Key/data */ + u_int32_t size; /* key/data length */ + + u_int32_t ulen; /* RO: length of user buffer. */ + u_int32_t dlen; /* RO: get/put record length. */ + u_int32_t doff; /* RO: get/put record offset. */ + +#define DB_DBT_ISSET 0x001 /* Lower level calls set value. */ +#define DB_DBT_MALLOC 0x002 /* Return in malloc'd memory. */ +#define DB_DBT_PARTIAL 0x004 /* Partial put/get. */ +#define DB_DBT_REALLOC 0x008 /* Return in realloc'd memory. */ +#define DB_DBT_USERMEM 0x010 /* Return in user's memory. */ +#define DB_DBT_DUPOK 0x020 /* Insert if duplicate. */ + u_int32_t flags; +}; + +/* + * Common flags -- + * Interfaces which use any of these common flags should never have + * interface specific flags in this range. + */ +#define DB_CREATE 0x000001 /* Create file as necessary. */ +#define DB_CXX_NO_EXCEPTIONS 0x000002 /* C++: return error values. */ +#define DB_FORCE 0x000004 /* Force (anything). */ +#define DB_NOMMAP 0x000008 /* Don't mmap underlying file. */ +#define DB_RDONLY 0x000010 /* Read-only (O_RDONLY). */ +#define DB_RECOVER 0x000020 /* Run normal recovery. */ +#define DB_THREAD 0x000040 /* Applications are threaded. */ +#define DB_TXN_NOSYNC 0x000080 /* Do not sync log on commit. */ +#define DB_USE_ENVIRON 0x000100 /* Use the environment. */ +#define DB_USE_ENVIRON_ROOT 0x000200 /* Use the environment if root. */ + +/* + * Flags private to db_env_create. + */ +#define DB_CLIENT 0x000400 /* Open for a client environment. */ + +/* + * Flags private to db_create. + */ +#define DB_XA_CREATE 0x000400 /* Open in an XA environment. */ + +/* + * Flags private to DBENV->open. + */ +#define DB_INIT_CDB 0x000400 /* Concurrent Access Methods. */ +#define DB_INIT_LOCK 0x000800 /* Initialize locking. */ +#define DB_INIT_LOG 0x001000 /* Initialize logging. */ +#define DB_INIT_MPOOL 0x002000 /* Initialize mpool. */ +#define DB_INIT_TXN 0x004000 /* Initialize transactions. */ +#define DB_JOINENV 0x008000 /* Initialize all subsystems present. */ +#define DB_LOCKDOWN 0x010000 /* Lock memory into physical core. */ +#define DB_PRIVATE 0x020000 /* DB_ENV is process local. */ +#define DB_RECOVER_FATAL 0x040000 /* Run catastrophic recovery. */ +#define DB_SYSTEM_MEM 0x080000 /* Use system-backed memory. */ + +/* + * Flags private to DB->open. + */ +#define DB_EXCL 0x000400 /* Exclusive open (O_EXCL). */ +#define DB_FCNTL_LOCKING 0x000800 /* UNDOC: fcntl(2) locking. */ +#define DB_ODDFILESIZE 0x001000 /* UNDOC: truncate to N * pgsize. */ +#define DB_RDWRMASTER 0x002000 /* UNDOC: allow subdb master open R/W */ +#define DB_TRUNCATE 0x004000 /* Discard existing DB (O_TRUNC). */ +#define DB_EXTENT 0x008000 /* UNDOC: dealing with an extent. */ + +/* + * Flags private to DBENV->txn_begin. + */ +#define DB_TXN_NOWAIT 0x000400 /* Do not wait for locks in this TXN. */ +#define DB_TXN_SYNC 0x000800 /* Always sync log on commit. */ + +/* + * Flags private to DBENV->set_flags. + */ +#define DB_CDB_ALLDB 0x000400 /* In CDB, lock across environment. */ + +/* + * Flags private to DB->set_feedback's callback. + */ +#define DB_UPGRADE 0x000400 /* Upgrading. */ +#define DB_VERIFY 0x000800 /* Verifying. */ + +/* + * Flags private to DB->set_flags. + * + * DB->set_flags does not share common flags and so values start at 0x01. + */ +#define DB_DUP 0x0001 /* Btree, Hash: duplicate keys. */ +#define DB_DUPSORT 0x0002 /* Btree, Hash: duplicate keys. */ +#define DB_RECNUM 0x0004 /* Btree: record numbers. */ +#define DB_RENUMBER 0x0008 /* Recno: renumber on insert/delete. */ +#define DB_REVSPLITOFF 0x0010 /* Btree: turn off reverse splits. */ +#define DB_SNAPSHOT 0x0020 /* Recno: snapshot the input. */ + +/* + * Flags private to DB->join. + * + * DB->join does not share common flags and so values start at 0x01. + */ +#define DB_JOIN_NOSORT 0x0001 /* Don't try to optimize join. */ + +/* + * Flags private to DB->verify. + * + * DB->verify does not share common flags and so values start at 0x01. + */ +#define DB_AGGRESSIVE 0x0001 /* Salvage anything which might be data.*/ +#define DB_NOORDERCHK 0x0002 /* Skip order check; subdb w/ user func */ +#define DB_ORDERCHKONLY 0x0004 /* Only perform an order check on subdb */ +#define DB_PR_PAGE 0x0008 /* Show page contents (-da). */ +#define DB_PR_HEADERS 0x0010 /* Show only page headers (-dh). */ +#define DB_PR_RECOVERYTEST 0x0020 /* Recovery test (-dr). */ +#define DB_SALVAGE 0x0040 /* Salvage what looks like data. */ +/* + * !!! + * These must not go over 0x8000, or they will collide with the flags + * used by __bam_vrfy_subtree. + */ +#define DB_VRFY_FLAGMASK 0xffff /* For masking above flags. */ + +/* + * Deadlock detector modes; used in the DBENV structure to configure the + * locking subsystem. + */ +#define DB_LOCK_NORUN 0 +#define DB_LOCK_DEFAULT 1 /* Default policy. */ +#define DB_LOCK_OLDEST 2 /* Abort oldest transaction. */ +#define DB_LOCK_RANDOM 3 /* Abort random transaction. */ +#define DB_LOCK_YOUNGEST 4 /* Abort youngest transaction. */ + +/******************************************************* + * Environment. + *******************************************************/ +#define DB_REGION_MAGIC 0x120897 /* Environment magic number. */ + +typedef enum { + DB_TXN_ABORT, + DB_TXN_BACKWARD_ROLL, + DB_TXN_FORWARD_ROLL, + DB_TXN_OPENFILES +} db_recops; + +#define DB_UNDO(op) ((op) == DB_TXN_ABORT || (op) == DB_TXN_BACKWARD_ROLL) +#define DB_REDO(op) ((op) == DB_TXN_FORWARD_ROLL) + +struct __db_env { + /******************************************************* + * Public: owned by the application. + *******************************************************/ + FILE *db_errfile; /* Error message file stream. */ + const char *db_errpfx; /* Error message prefix. */ + /* Callbacks. */ + void (*db_errcall) __P((const char *, char *)); + void (*db_feedback) __P((DB_ENV *, int, int)); + void (*db_paniccall) __P((DB_ENV *, int)); + int (*db_recovery_init) __P((DB_ENV *)); + + /* + * Currently, the verbose list is a bit field with room for 32 + * entries. There's no reason that it needs to be limited, if + * there are ever more than 32 entries, convert to a bit array. + */ +#define DB_VERB_CHKPOINT 0x0001 /* List checkpoints. */ +#define DB_VERB_DEADLOCK 0x0002 /* Deadlock detection information. */ +#define DB_VERB_RECOVERY 0x0004 /* Recovery information. */ +#define DB_VERB_WAITSFOR 0x0008 /* Dump waits-for table. */ + u_int32_t verbose; /* Verbose output. */ + + void *app_private; /* Application-private handle. */ + + /* Locking. */ + u_int8_t *lk_conflicts; /* Two dimensional conflict matrix. */ + u_int32_t lk_modes; /* Number of lock modes in table. */ + u_int32_t lk_max; /* Maximum number of locks. */ + u_int32_t lk_max_lockers;/* Maximum number of lockers. */ + u_int32_t lk_max_objects;/* Maximum number of locked objects. */ + u_int32_t lk_detect; /* Deadlock detect on all conflicts. */ + + /* Logging. */ + u_int32_t lg_bsize; /* Buffer size. */ + u_int32_t lg_max; /* Maximum file size. */ + + /* Memory pool. */ + u_int32_t mp_gbytes; /* Cachesize: GB. */ + u_int32_t mp_bytes; /* Cachesize: Bytes. */ + size_t mp_size; /* DEPRECATED: Cachesize: bytes. */ + int mp_ncache; /* Number of cache regions. */ + size_t mp_mmapsize; /* Maximum file size for mmap. */ + + /* Transactions. */ + u_int32_t tx_max; /* Maximum number of transactions. */ + time_t tx_timestamp; /* Recover to specific timestamp. */ + int (*tx_recover) /* Dispatch function for recovery. */ + __P((DB_ENV *, DBT *, DB_LSN *, db_recops)); + + /******************************************************* + * Private: owned by DB. + *******************************************************/ + int db_panic; /* Panic causing errno. */ + + /* User files, paths. */ + char *db_home; /* Database home. */ + char *db_log_dir; /* Database log file directory. */ + char *db_tmp_dir; /* Database tmp file directory. */ + + char **db_data_dir; /* Database data file directories. */ + int data_cnt; /* Database data file slots. */ + int data_next; /* Next Database data file slot. */ + + int db_mode; /* Default open permissions. */ + + void *reginfo; /* REGINFO structure reference. */ + DB_FH *lockfhp; /* fcntl(2) locking file handle. */ + long shm_key; /* shmget(2) key. */ + + void *lg_handle; /* Log handle. */ + + void *lk_handle; /* Lock handle. */ + + void *mp_handle; /* Mpool handle. */ + + void *tx_handle; /* Txn handle. */ + + int (**dtab) /* Dispatch table */ + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + size_t dtab_size; /* Slots in the dispatch table. */ + + void *cl_handle; /* RPC: remote client handle. */ + long cl_id; /* RPC: Remote client env id. */ + + int dblocal_ref; /* DB_ENV_DBLOCAL: reference count. */ + u_int32_t db_mutexlocks; /* db_set_mutexlocks */ + + /* + * List of open DB handles for this DB_ENV, used for cursor + * adjustment. Must be protected for multi-threaded support. + * + * !!! + * As this structure is allocated in per-process memory, the + * mutex may need to be stored elsewhere on architectures unable + * to support mutexes in heap memory, e.g. HP/UX 9. + */ + void *dblist_mutexp; /* Mutex. */ + /* + * !!! + * Explicit representation of structure in queue.h. + * LIST_HEAD(dblist, __db); + */ + struct { + struct __db *lh_first; + } dblist; + + /* + * XA support. + * + * !!! + * Explicit representations of structures in queue.h. + * + * TAILQ_ENTRY(__db_env); + */ + struct { + struct __db_env *tqe_next; + struct __db_env **tqe_prev; + } links; + int xa_rmid; /* XA Resource Manager ID. */ + DB_TXN *xa_txn; /* XA Current transaction. */ + + void *cj_internal; /* C++/Java private. */ + + /* Methods. */ + int (*close) __P((DB_ENV *, u_int32_t)); + void (*err) __P((const DB_ENV *, int, const char *, ...)); + void (*errx) __P((const DB_ENV *, const char *, ...)); + int (*open) __P((DB_ENV *, const char *, u_int32_t, int)); + int (*remove) __P((DB_ENV *, const char *, u_int32_t)); + int (*set_data_dir) __P((DB_ENV *, const char *)); + void (*set_errcall) __P((DB_ENV *, void (*)(const char *, char *))); + void (*set_errfile) __P((DB_ENV *, FILE *)); + void (*set_errpfx) __P((DB_ENV *, const char *)); + int (*set_feedback) __P((DB_ENV *, void (*)(DB_ENV *, int, int))); + int (*set_flags) __P((DB_ENV *, u_int32_t, int)); + int (*set_mutexlocks) __P((DB_ENV *, int)); + int (*set_paniccall) __P((DB_ENV *, void (*)(DB_ENV *, int))); + int (*set_recovery_init) __P((DB_ENV *, int (*)(DB_ENV *))); + int (*set_server) __P((DB_ENV *, char *, long, long, u_int32_t)); + int (*set_shm_key) __P((DB_ENV *, long)); + int (*set_tmp_dir) __P((DB_ENV *, const char *)); + int (*set_verbose) __P((DB_ENV *, u_int32_t, int)); + + int (*set_lg_bsize) __P((DB_ENV *, u_int32_t)); + int (*set_lg_dir) __P((DB_ENV *, const char *)); + int (*set_lg_max) __P((DB_ENV *, u_int32_t)); + + int (*set_lk_conflicts) __P((DB_ENV *, u_int8_t *, int)); + int (*set_lk_detect) __P((DB_ENV *, u_int32_t)); + int (*set_lk_max) __P((DB_ENV *, u_int32_t)); + int (*set_lk_max_locks) __P((DB_ENV *, u_int32_t)); + int (*set_lk_max_lockers) __P((DB_ENV *, u_int32_t)); + int (*set_lk_max_objects) __P((DB_ENV *, u_int32_t)); + + int (*set_mp_mmapsize) __P((DB_ENV *, size_t)); + int (*set_cachesize) __P((DB_ENV *, u_int32_t, u_int32_t, int)); + + int (*set_tx_max) __P((DB_ENV *, u_int32_t)); + int (*set_tx_recover) __P((DB_ENV *, + int (*)(DB_ENV *, DBT *, DB_LSN *, db_recops))); + int (*set_tx_timestamp) __P((DB_ENV *, time_t *)); + +#ifdef CONFIG_TEST +#define DB_TEST_PREOPEN 1 /* before __os_open */ +#define DB_TEST_POSTOPEN 2 /* after __os_open */ +#define DB_TEST_POSTLOGMETA 3 /* after logging meta in btree */ +#define DB_TEST_POSTLOG 4 /* after logging all pages */ +#define DB_TEST_POSTSYNC 5 /* after syncing the log */ +#define DB_TEST_PRERENAME 6 /* before __os_rename */ +#define DB_TEST_POSTRENAME 7 /* after __os_rename */ + int test_abort; /* Abort value for testing. */ + int test_copy; /* Copy value for testing. */ +#endif + +#define DB_ENV_CDB 0x00001 /* DB_INIT_CDB. */ +#define DB_ENV_CDB_ALLDB 0x00002 /* CDB environment wide locking. */ +#define DB_ENV_CREATE 0x00004 /* DB_CREATE set. */ +#define DB_ENV_DBLOCAL 0x00008 /* DB_ENV allocated for private DB. */ +#define DB_ENV_LOCKDOWN 0x00010 /* DB_LOCKDOWN set. */ +#define DB_ENV_NOMMAP 0x00020 /* DB_NOMMAP set. */ +#define DB_ENV_OPEN_CALLED 0x00040 /* DBENV->open called (paths valid). */ +#define DB_ENV_PRIVATE 0x00080 /* DB_PRIVATE set. */ +#define DB_ENV_RPCCLIENT 0x00100 /* DB_CLIENT set. */ +#define DB_ENV_STANDALONE 0x00200 /* Test: freestanding environment. */ +#define DB_ENV_SYSTEM_MEM 0x00400 /* DB_SYSTEM_MEM set. */ +#define DB_ENV_THREAD 0x00800 /* DB_THREAD set. */ +#define DB_ENV_TXN_NOSYNC 0x01000 /* DB_TXN_NOSYNC set. */ +#define DB_ENV_USER_ALLOC 0x02000 /* User allocated the structure. */ + u_int32_t flags; /* Flags. */ +}; + +/******************************************************* + * Access methods. + *******************************************************/ +/* + * !!! + * Changes here must be reflected in java/src/com/sleepycat/db/Db.java. + */ +typedef enum { + DB_BTREE=1, + DB_HASH, + DB_RECNO, + DB_QUEUE, + DB_UNKNOWN /* Figure it out on open. */ +} DBTYPE; + +#define DB_BTREEVERSION 8 /* Current btree version. */ +#define DB_BTREEOLDVER 6 /* Oldest btree version supported. */ +#define DB_BTREEMAGIC 0x053162 + +#define DB_HASHVERSION 7 /* Current hash version. */ +#define DB_HASHOLDVER 4 /* Oldest hash version supported. */ +#define DB_HASHMAGIC 0x061561 + +#define DB_QAMVERSION 3 /* Current queue version. */ +#define DB_QAMOLDVER 1 /* Oldest queue version supported. */ +#define DB_QAMMAGIC 0x042253 + +#define DB_LOGVERSION 3 /* Current log version. */ +#define DB_LOGOLDVER 3 /* Oldest log version supported. */ +#define DB_LOGMAGIC 0x040988 + +/* + * DB access method and cursor operation values. Each value is an operation + * code to which additional bit flags are added. + */ +#define DB_AFTER 1 /* c_put() */ +#define DB_APPEND 2 /* put() */ +#define DB_BEFORE 3 /* c_put() */ +#define DB_CACHED_COUNTS 4 /* stat() */ +#define DB_CHECKPOINT 5 /* log_put(), log_get() */ +#define DB_CONSUME 6 /* get() */ +#define DB_CONSUME_WAIT 7 /* get() */ +#define DB_CURLSN 8 /* log_put() */ +#define DB_CURRENT 9 /* c_get(), c_put(), log_get() */ +#define DB_FIRST 10 /* c_get(), log_get() */ +#define DB_FLUSH 11 /* log_put() */ +#define DB_GET_BOTH 12 /* get(), c_get() */ +#define DB_GET_BOTHC 13 /* c_get() (internal) */ +#define DB_GET_RECNO 14 /* c_get() */ +#define DB_JOIN_ITEM 15 /* c_get(); do not do primary lookup */ +#define DB_KEYFIRST 16 /* c_put() */ +#define DB_KEYLAST 17 /* c_put() */ +#define DB_LAST 18 /* c_get(), log_get() */ +#define DB_NEXT 19 /* c_get(), log_get() */ +#define DB_NEXT_DUP 20 /* c_get() */ +#define DB_NEXT_NODUP 21 /* c_get() */ +#define DB_NODUPDATA 22 /* put(), c_put() */ +#define DB_NOOVERWRITE 23 /* put() */ +#define DB_NOSYNC 24 /* close() */ +#define DB_POSITION 25 /* c_dup() */ +#define DB_POSITIONI 26 /* c_dup() (internal) */ +#define DB_PREV 27 /* c_get(), log_get() */ +#define DB_PREV_NODUP 28 /* c_get(), log_get() */ +#define DB_RECORDCOUNT 29 /* stat() */ +#define DB_SET 30 /* c_get(), log_get() */ +#define DB_SET_RANGE 31 /* c_get() */ +#define DB_SET_RECNO 32 /* get(), c_get() */ +#define DB_WRITECURSOR 33 /* cursor() */ +#define DB_WRITELOCK 34 /* cursor() (internal) */ + +/* This has to change when the max opcode hits 255. */ +#define DB_OPFLAGS_MASK 0x000000ff /* Mask for operations flags. */ +#define DB_RMW 0x80000000 /* Acquire write flag immediately. */ + +/* + * DB (user visible) error return codes. + * + * !!! + * Changes to any of the user visible error return codes must be reflected + * in java/src/com/sleepycat/db/Db.java. + * + * !!! + * For source compatibility with DB 2.X deadlock return (EAGAIN), use the + * following: + * #include + * #define DB_LOCK_DEADLOCK EAGAIN + * + * !!! + * We don't want our error returns to conflict with other packages where + * possible, so pick a base error value that's hopefully not common. We + * document that we own the error name space from -30,800 to -30,999. + */ +/* Public error return codes. */ +#define DB_INCOMPLETE (-30999)/* Sync didn't finish. */ +#define DB_KEYEMPTY (-30998)/* Key/data deleted or never created. */ +#define DB_KEYEXIST (-30997)/* The key/data pair already exists. */ +#define DB_LOCK_DEADLOCK (-30996)/* Deadlock. */ +#define DB_LOCK_NOTGRANTED (-30995)/* Lock unavailable. */ +#define DB_NOSERVER (-30994)/* Server panic return. */ +#define DB_NOSERVER_HOME (-30993)/* Bad home sent to server. */ +#define DB_NOSERVER_ID (-30992)/* Bad ID sent to server. */ +#define DB_NOTFOUND (-30991)/* Key/data pair not found (EOF). */ +#define DB_OLD_VERSION (-30990)/* Out-of-date version. */ +#define DB_RUNRECOVERY (-30989)/* Panic return. */ +#define DB_VERIFY_BAD (-30988)/* Verify failed; bad format. */ + +/* DB (private) error return codes. */ +#define DB_ALREADY_ABORTED (-30899) +#define DB_DELETED (-30898)/* Recovery file marked deleted. */ +#define DB_JAVA_CALLBACK (-30897)/* Exception during a java callback. */ +#define DB_NEEDSPLIT (-30896)/* Page needs to be split. */ +#define DB_SWAPBYTES (-30895)/* Database needs byte swapping. */ +#define DB_TXN_CKP (-30894)/* Encountered ckp record in log. */ +#define DB_VERIFY_FATAL (-30893)/* Fatal: DB->verify cannot proceed. */ + +#define DB_FILE_ID_LEN 20 /* DB file ID length. */ + +/* DB access method description structure. */ +struct __db { + /******************************************************* + * Public: owned by the application. + *******************************************************/ + u_int32_t pgsize; /* Database logical page size. */ + + /* Callbacks. */ + int (*db_append_recno) __P((DB *, DBT *, db_recno_t)); + void (*db_feedback) __P((DB *, int, int)); + void *(*db_malloc) __P((size_t)); + void *(*db_realloc) __P((void *, size_t)); + int (*dup_compare) __P((DB *, const DBT *, const DBT *)); + + void *app_private; /* Application-private handle. */ + + /******************************************************* + * Private: owned by DB. + *******************************************************/ + DB_ENV *dbenv; /* Backing environment. */ + + DBTYPE type; /* DB access method type. */ + + DB_MPOOLFILE *mpf; /* Backing buffer pool. */ + + void *mutexp; /* Synchronization for free threading */ + + u_int8_t fileid[DB_FILE_ID_LEN];/* File's unique ID for locking. */ + + u_int32_t adj_fileid; /* File's unique ID for curs. adj. */ + +#define DB_LOGFILEID_INVALID -1 + int32_t log_fileid; /* File's unique ID for logging. */ + db_pgno_t meta_pgno; /* Meta page number */ + DB_TXN *open_txn; /* Transaction to protect creates. */ + + long cl_id; /* RPC: remote client id. */ + + /* + * !!! + * Some applications use DB but implement their own locking outside of + * DB. If they're using fcntl(2) locking on the underlying database + * file, and we open and close a file descriptor for that file, we will + * discard their locks. The DB_FCNTL_LOCKING flag to DB->open is an + * undocumented interface to support this usage which leaves any file + * descriptors we open until DB->close. This will only work with the + * DB->open interface and simple caches, e.g., creating a transaction + * thread may open/close file descriptors this flag doesn't protect. + * Locking with fcntl(2) on a file that you don't own is a very, very + * unsafe thing to do. 'Nuff said. + */ + DB_FH *saved_open_fhp; /* Saved file handle. */ + + /* + * Linked list of DBP's, used in the log's dbentry table + * to keep track of all open db handles for a given log id. + * !!! + * Explicit representations of structures in queue.h. + * + * TAILQ_ENTRY(__db) links; + */ + struct { + struct __db *tqe_next; + struct __db **tqe_prev; + } links; + + /* + * Linked list of DBP's, linked from the DB_ENV, used to + * keep track of all open db handles for cursor adjustment. + * + * XXX + * Eventually, this should be merged with "links" above. + * + * !!! + * Explicit representations of structures in queue.h. + * + * LIST_ENTRY(__db) dblistlinks; + */ + struct { + struct __db *le_next; + struct __db **le_prev; + } dblistlinks; + + /* + * Cursor queues. + * + * !!! + * Explicit representations of structures in queue.h. + * + * TAILQ_HEAD(free_queue, __dbc); + * TAILQ_HEAD(active_queue, __dbc); + * TAILQ_HEAD(join_queue, __dbc); + */ + struct { + struct __dbc *tqh_first; + struct __dbc **tqh_last; + } free_queue; + struct { + struct __dbc *tqh_first; + struct __dbc **tqh_last; + } active_queue; + struct { + struct __dbc *tqh_first; + struct __dbc **tqh_last; + } join_queue; + + void *bt_internal; /* Btree/Recno access method private. */ + void *cj_internal; /* C++/Java private. */ + void *h_internal; /* Hash access method private. */ + void *q_internal; /* Queue access method private. */ + void *xa_internal; /* XA private. */ + + /* Methods. */ + int (*close) __P((DB *, u_int32_t)); + int (*cursor) __P((DB *, DB_TXN *, DBC **, u_int32_t)); + int (*del) __P((DB *, DB_TXN *, DBT *, u_int32_t)); + void (*err) __P((DB *, int, const char *, ...)); + void (*errx) __P((DB *, const char *, ...)); + int (*fd) __P((DB *, int *)); + int (*get) __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t)); + int (*get_byteswapped) __P((DB *)); + DBTYPE + (*get_type) __P((DB *)); + int (*join) __P((DB *, DBC **, DBC **, u_int32_t)); + int (*key_range) __P((DB *, + DB_TXN *, DBT *, DB_KEY_RANGE *, u_int32_t)); + int (*open) __P((DB *, + const char *, const char *, DBTYPE, u_int32_t, int)); + int (*put) __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t)); + int (*remove) __P((DB *, const char *, const char *, u_int32_t)); + int (*rename) __P((DB *, + const char *, const char *, const char *, u_int32_t)); + int (*set_append_recno) __P((DB *, int (*)(DB *, DBT *, db_recno_t))); + int (*set_cachesize) __P((DB *, u_int32_t, u_int32_t, int)); + int (*set_dup_compare) __P((DB *, + int (*)(DB *, const DBT *, const DBT *))); + void (*set_errcall) __P((DB *, void (*)(const char *, char *))); + void (*set_errfile) __P((DB *, FILE *)); + void (*set_errpfx) __P((DB *, const char *)); + int (*set_feedback) __P((DB *, void (*)(DB *, int, int))); + int (*set_flags) __P((DB *, u_int32_t)); + int (*set_lorder) __P((DB *, int)); + int (*set_malloc) __P((DB *, void *(*)(size_t))); + int (*set_pagesize) __P((DB *, u_int32_t)); + int (*set_paniccall) __P((DB *, void (*)(DB_ENV *, int))); + int (*set_realloc) __P((DB *, void *(*)(void *, size_t))); + int (*stat) __P((DB *, void *, void *(*)(size_t), u_int32_t)); + int (*sync) __P((DB *, u_int32_t)); + int (*upgrade) __P((DB *, const char *, u_int32_t)); + int (*verify) __P((DB *, + const char *, const char *, FILE *, u_int32_t)); + + int (*set_bt_compare) __P((DB *, + int (*)(DB *, const DBT *, const DBT *))); + int (*set_bt_maxkey) __P((DB *, u_int32_t)); + int (*set_bt_minkey) __P((DB *, u_int32_t)); + int (*set_bt_prefix) __P((DB *, + size_t (*)(DB *, const DBT *, const DBT *))); + + int (*set_h_ffactor) __P((DB *, u_int32_t)); + int (*set_h_hash) __P((DB *, + u_int32_t (*)(DB *, const void *, u_int32_t))); + int (*set_h_nelem) __P((DB *, u_int32_t)); + + int (*set_re_delim) __P((DB *, int)); + int (*set_re_len) __P((DB *, u_int32_t)); + int (*set_re_pad) __P((DB *, int)); + int (*set_re_source) __P((DB *, const char *)); + int (*set_q_extentsize) __P((DB *, u_int32_t)); + + int (*db_am_remove) __P((DB *, const char *, + const char *, DB_LSN *, int (**)(DB *, void*), void **)); + int (*db_am_rename) __P((DB *, + const char *, const char *, const char *)); + +#define DB_OK_BTREE 0x01 +#define DB_OK_HASH 0x02 +#define DB_OK_QUEUE 0x04 +#define DB_OK_RECNO 0x08 + u_int32_t am_ok; /* Legal AM choices. */ + +#define DB_AM_DISCARD 0x00001 /* Discard any cached pages. */ +#define DB_AM_DUP 0x00002 /* DB_DUP. */ +#define DB_AM_DUPSORT 0x00004 /* DB_DUPSORT. */ +#define DB_AM_INMEM 0x00008 /* In-memory; no sync on close. */ +#define DB_AM_PGDEF 0x00010 /* Page size was defaulted. */ +#define DB_AM_RDONLY 0x00020 /* Database is readonly. */ +#define DB_AM_RECOVER 0x00040 /* DBP opened by recovery routine. */ +#define DB_AM_SUBDB 0x00080 /* Subdatabases supported. */ +#define DB_AM_SWAP 0x00100 /* Pages need to be byte-swapped. */ +#define DB_AM_TXN 0x00200 /* DBP was in a transaction. */ +#define DB_AM_VERIFYING 0x00400 /* DB handle is in the verifier. */ +#define DB_BT_RECNUM 0x00800 /* DB_RECNUM. */ +#define DB_BT_REVSPLIT 0x01000 /* DB_REVSPLITOFF. */ +#define DB_DBM_ERROR 0x02000 /* Error in DBM/NDBM database. */ +#define DB_OPEN_CALLED 0x04000 /* DB->open called. */ +#define DB_RE_DELIMITER 0x08000 /* Variablen length delimiter set. */ +#define DB_RE_FIXEDLEN 0x10000 /* Fixed-length records. */ +#define DB_RE_PAD 0x20000 /* Fixed-length record pad. */ +#define DB_RE_RENUMBER 0x40000 /* DB_RENUMBER. */ +#define DB_RE_SNAPSHOT 0x80000 /* DB_SNAPSHOT. */ + u_int32_t flags; +}; + +/* + * DB_LOCK_ILOCK -- + * Internal DB access method lock. + */ +struct __db_ilock { + db_pgno_t pgno; /* Page being locked. */ + u_int8_t fileid[DB_FILE_ID_LEN];/* File id. */ +#define DB_RECORD_LOCK 1 +#define DB_PAGE_LOCK 2 + u_int8_t type; /* Record or Page lock */ +}; + +/* + * DB_LOCK -- + * The structure is allocated by the caller and filled in during a + * lock_get request (or a lock_vec/DB_LOCK_GET). + */ +struct __db_lock_u { + size_t off; /* Offset of the lock in the region */ + u_int32_t ndx; /* Index of the object referenced by + * this lock; used for locking. */ + u_int32_t gen; /* Generation number of this lock. */ +}; + +/* Cursor description structure. */ +struct __dbc { + DB *dbp; /* Related DB access method. */ + DB_TXN *txn; /* Associated transaction. */ + + /* + * !!! + * Explicit representations of structures in queue.h. + * + * TAILQ_ENTRY(__dbc) links; Active/free cursor queues. + */ + struct { + DBC *tqe_next; + DBC **tqe_prev; + } links; + + DBT rkey; /* Returned key. */ + DBT rdata; /* Returned data. */ + + u_int32_t lid; /* Default process' locker id. */ + u_int32_t locker; /* Locker for this operation. */ + DBT lock_dbt; /* DBT referencing lock. */ + DB_LOCK_ILOCK lock; /* Object to be locked. */ + DB_LOCK mylock; /* Lock held on this cursor. */ + + long cl_id; /* Remote client id. */ + + DBTYPE dbtype; /* Cursor type. */ + + DBC_INTERNAL *internal; /* Access method private. */ + + int (*c_close) __P((DBC *)); /* Methods: public. */ + int (*c_count) __P((DBC *, db_recno_t *, u_int32_t)); + int (*c_del) __P((DBC *, u_int32_t)); + int (*c_dup) __P((DBC *, DBC **, u_int32_t)); + int (*c_get) __P((DBC *, DBT *, DBT *, u_int32_t)); + int (*c_put) __P((DBC *, DBT *, DBT *, u_int32_t)); + + /* Methods: private. */ + int (*c_am_close) __P((DBC *, db_pgno_t, int *)); + int (*c_am_del) __P((DBC *)); + int (*c_am_destroy) __P((DBC *)); + int (*c_am_get) __P((DBC *, DBT *, DBT *, u_int32_t, db_pgno_t *)); + int (*c_am_put) __P((DBC *, DBT *, DBT *, u_int32_t, db_pgno_t *)); + int (*c_am_writelock) __P((DBC *)); + +#define DBC_ACTIVE 0x001 /* Cursor is being used. */ +#define DBC_OPD 0x002 /* Cursor references off-page dups. */ +#define DBC_RECOVER 0x004 /* Cursor created by recovery routine + * (do not log or lock). + */ +#define DBC_RMW 0x008 /* Acquire write flag in read op. */ +#define DBC_WRITECURSOR 0x010 /* Cursor may be used to write (CDB). */ +#define DBC_WRITEDUP 0x020 /* idup'ed DBC_WRITECURSOR (CDB). */ +#define DBC_WRITER 0x040 /* Cursor immediately writing (CDB). */ +#define DBC_TRANSIENT 0x080 /* Cursor is transient. */ +#define DBC_COMPENSATE 0x100 /* Cursor is doing compensation + * do not lock. + */ + u_int32_t flags; +}; + +/* Key range statistics structure */ +struct __key_range { + double less; + double equal; + double greater; +}; + +/* Btree/Recno statistics structure. */ +struct __db_bt_stat { + u_int32_t bt_magic; /* Magic number. */ + u_int32_t bt_version; /* Version number. */ + u_int32_t bt_metaflags; /* Metadata flags. */ + u_int32_t bt_nkeys; /* Number of unique keys. */ + u_int32_t bt_ndata; /* Number of data items. */ + u_int32_t bt_pagesize; /* Page size. */ + u_int32_t bt_maxkey; /* Maxkey value. */ + u_int32_t bt_minkey; /* Minkey value. */ + u_int32_t bt_re_len; /* Fixed-length record length. */ + u_int32_t bt_re_pad; /* Fixed-length record pad. */ + u_int32_t bt_levels; /* Tree levels. */ + u_int32_t bt_int_pg; /* Internal pages. */ + u_int32_t bt_leaf_pg; /* Leaf pages. */ + u_int32_t bt_dup_pg; /* Duplicate pages. */ + u_int32_t bt_over_pg; /* Overflow pages. */ + u_int32_t bt_free; /* Pages on the free list. */ + u_int32_t bt_int_pgfree; /* Bytes free in internal pages. */ + u_int32_t bt_leaf_pgfree; /* Bytes free in leaf pages. */ + u_int32_t bt_dup_pgfree; /* Bytes free in duplicate pages. */ + u_int32_t bt_over_pgfree; /* Bytes free in overflow pages. */ +}; + +/* Queue statistics structure. */ +struct __db_qam_stat { + u_int32_t qs_magic; /* Magic number. */ + u_int32_t qs_version; /* Version number. */ + u_int32_t qs_metaflags; /* Metadata flags. */ + u_int32_t qs_nkeys; /* Number of unique keys. */ + u_int32_t qs_ndata; /* Number of data items. */ + u_int32_t qs_pagesize; /* Page size. */ + u_int32_t qs_pages; /* Data pages. */ + u_int32_t qs_re_len; /* Fixed-length record length. */ + u_int32_t qs_re_pad; /* Fixed-length record pad. */ + u_int32_t qs_pgfree; /* Bytes free in data pages. */ + u_int32_t qs_first_recno; /* First not deleted record. */ + u_int32_t qs_cur_recno; /* Last allocated record number. */ +}; + +/* Hash statistics structure. */ +struct __db_h_stat { + u_int32_t hash_magic; /* Magic number. */ + u_int32_t hash_version; /* Version number. */ + u_int32_t hash_metaflags; /* Metadata flags. */ + u_int32_t hash_nkeys; /* Number of unique keys. */ + u_int32_t hash_ndata; /* Number of data items. */ + u_int32_t hash_pagesize; /* Page size. */ + u_int32_t hash_nelem; /* Original nelem specified. */ + u_int32_t hash_ffactor; /* Fill factor specified at create. */ + u_int32_t hash_buckets; /* Number of hash buckets. */ + u_int32_t hash_free; /* Pages on the free list. */ + u_int32_t hash_bfree; /* Bytes free on bucket pages. */ + u_int32_t hash_bigpages; /* Number of big key/data pages. */ + u_int32_t hash_big_bfree; /* Bytes free on big item pages. */ + u_int32_t hash_overflows; /* Number of overflow pages. */ + u_int32_t hash_ovfl_free; /* Bytes free on ovfl pages. */ + u_int32_t hash_dup; /* Number of dup pages. */ + u_int32_t hash_dup_free; /* Bytes free on duplicate pages. */ +}; + +int db_create __P((DB **, DB_ENV *, u_int32_t)); +int db_env_create __P((DB_ENV **, u_int32_t)); +int db_env_set_func_close __P((int (*)(int))); +int db_env_set_func_dirfree __P((void (*)(char **, int))); +int db_env_set_func_dirlist __P((int (*)(const char *, char ***, int *))); +int db_env_set_func_exists __P((int (*)(const char *, int *))); +int db_env_set_func_free __P((void (*)(void *))); +int db_env_set_func_fsync __P((int (*)(int))); +int db_env_set_func_ioinfo __P((int (*)(const char *, + int, u_int32_t *, u_int32_t *, u_int32_t *))); +int db_env_set_func_malloc __P((void *(*)(size_t))); +int db_env_set_func_map __P((int (*)(char *, size_t, int, int, void **))); +int db_env_set_func_open __P((int (*)(const char *, int, ...))); +int db_env_set_func_read __P((ssize_t (*)(int, void *, size_t))); +int db_env_set_func_realloc __P((void *(*)(void *, size_t))); +int db_env_set_func_rename __P((int (*)(const char *, const char *))); +int db_env_set_func_seek + __P((int (*)(int, size_t, db_pgno_t, u_int32_t, int, int))); +int db_env_set_func_sleep __P((int (*)(u_long, u_long))); +int db_env_set_func_unlink __P((int (*)(const char *))); +int db_env_set_func_unmap __P((int (*)(void *, size_t))); +int db_env_set_func_write __P((ssize_t (*)(int, const void *, size_t))); +int db_env_set_func_yield __P((int (*)(void))); +int db_env_set_pageyield __P((int)); +int db_env_set_panicstate __P((int)); +int db_env_set_region_init __P((int)); +int db_env_set_tas_spins __P((u_int32_t)); +char *db_strerror __P((int)); +char *db_version __P((int *, int *, int *)); + +/******************************************************* + * Locking + *******************************************************/ +#define DB_LOCKVERSION 1 + +/* Flag values for lock_vec(), lock_get(). */ +#define DB_LOCK_NOWAIT 0x01 /* Don't wait on unavailable lock. */ +#define DB_LOCK_RECORD 0x02 /* Internal: record lock. */ +#define DB_LOCK_UPGRADE 0x04 /* Internal: upgrade existing lock. */ +#define DB_LOCK_SWITCH 0x08 /* Internal: switch existing lock. */ + +/* Flag values for lock_detect(). */ +#define DB_LOCK_CONFLICT 0x01 /* Run on any conflict. */ + +/* + * Request types. + * + * !!! + * Changes here must be reflected in java/src/com/sleepycat/db/Db.java. + */ +typedef enum { + DB_LOCK_DUMP=0, /* Display held locks. */ + DB_LOCK_GET, /* Get the lock. */ + DB_LOCK_INHERIT, /* Pass locks to parent. */ + DB_LOCK_PUT, /* Release the lock. */ + DB_LOCK_PUT_ALL, /* Release locker's locks. */ + DB_LOCK_PUT_OBJ /* Release locker's locks on obj. */ +} db_lockop_t; + +/* + * Simple R/W lock modes and for multi-granularity intention locking. + * + * !!! + * These values are NOT random, as they are used as an index into the lock + * conflicts arrays, i.e., DB_LOCK_IWRITE must be == 3, and DB_LOCK_IREAD + * must be == 4. + * + * !!! + * Changes here must be reflected in java/src/com/sleepycat/db/Db.java. + */ +typedef enum { + DB_LOCK_NG=0, /* Not granted. */ + DB_LOCK_READ, /* Shared/read. */ + DB_LOCK_WRITE, /* Exclusive/write. */ + DB_LOCK_WAIT, /* Wait for event */ + DB_LOCK_IWRITE, /* Intent exclusive/write. */ + DB_LOCK_IREAD, /* Intent to share/read. */ + DB_LOCK_IWR /* Intent to read and write. */ +} db_lockmode_t; + +/* + * Status of a lock. + */ +typedef enum { + DB_LSTAT_ABORTED, /* Lock belongs to an aborted txn. */ + DB_LSTAT_ERR, /* Lock is bad. */ + DB_LSTAT_FREE, /* Lock is unallocated. */ + DB_LSTAT_HELD, /* Lock is currently held. */ + DB_LSTAT_NOGRANT, /* Lock was not granted. */ + DB_LSTAT_PENDING, /* Lock was waiting and has been + * promoted; waiting for the owner + * to run and upgrade it to held. */ + DB_LSTAT_WAITING /* Lock is on the wait queue. */ +} db_status_t; + +/* Lock request structure. */ +struct __db_lockreq { + db_lockop_t op; /* Operation. */ + db_lockmode_t mode; /* Requested mode. */ + u_int32_t locker; /* Locker identity. */ + DBT *obj; /* Object being locked. */ + DB_LOCK lock; /* Lock returned. */ +}; + +/* + * Commonly used conflict matrices. + * + */ + +/* Multi-granularity locking. */ +#define DB_LOCK_RIW_N 7 +extern const u_int8_t db_riw_conflicts[]; + +struct __db_lock_stat { + u_int32_t st_lastid; /* Last allocated locker ID. */ + u_int32_t st_maxlocks; /* Maximum number of locks in table. */ + u_int32_t st_maxlockers; /* Maximum number of lockers in table. */ + u_int32_t st_maxobjects; /* Maximum number of objects in table. */ + u_int32_t st_nmodes; /* Number of lock modes. */ + u_int32_t st_nlocks; /* Current number of locks. */ + u_int32_t st_maxnlocks; /* Maximum number of locks so far. */ + u_int32_t st_nlockers; /* Current number of lockers. */ + u_int32_t st_maxnlockers; /* Maximum number of lockers so far. */ + u_int32_t st_nobjects; /* Current number of objects. */ + u_int32_t st_maxnobjects; /* Maximum number of objects so far. */ + u_int32_t st_nconflicts; /* Number of lock conflicts. */ + u_int32_t st_nrequests; /* Number of lock gets. */ + u_int32_t st_nreleases; /* Number of lock puts. */ + u_int32_t st_nnowaits; /* Number of requests that would have + waited, but NOWAIT was set. */ + u_int32_t st_ndeadlocks; /* Number of lock deadlocks. */ + u_int32_t st_region_wait; /* Region lock granted after wait. */ + u_int32_t st_region_nowait; /* Region lock granted without wait. */ + u_int32_t st_regsize; /* Region size. */ +}; + +int lock_detect __P((DB_ENV *, u_int32_t, u_int32_t, int *)); +int lock_get __P((DB_ENV *, + u_int32_t, u_int32_t, const DBT *, db_lockmode_t, DB_LOCK *)); +int lock_id __P((DB_ENV *, u_int32_t *)); +int lock_put __P((DB_ENV *, DB_LOCK *)); +int lock_stat __P((DB_ENV *, DB_LOCK_STAT **, void *(*)(size_t))); +int lock_vec __P((DB_ENV *, + u_int32_t, u_int32_t, DB_LOCKREQ *, int, DB_LOCKREQ **)); + +/******************************************************* + * Logging. + *******************************************************/ +/* Flag values for log_archive(). */ +#define DB_ARCH_ABS 0x001 /* Absolute pathnames. */ +#define DB_ARCH_DATA 0x002 /* Data files. */ +#define DB_ARCH_LOG 0x004 /* Log files. */ + +/* + * A DB_LSN has two parts, a fileid which identifies a specific file, and an + * offset within that file. The fileid is an unsigned 4-byte quantity that + * uniquely identifies a file within the log directory -- currently a simple + * counter inside the log. The offset is also an unsigned 4-byte value. The + * log manager guarantees the offset is never more than 4 bytes by switching + * to a new log file before the maximum length imposed by an unsigned 4-byte + * offset is reached. + */ +struct __db_lsn { + u_int32_t file; /* File ID. */ + u_int32_t offset; /* File offset. */ +}; + +/* Log statistics structure. */ +struct __db_log_stat { + u_int32_t st_magic; /* Log file magic number. */ + u_int32_t st_version; /* Log file version number. */ + int st_mode; /* Log file mode. */ + u_int32_t st_lg_bsize; /* Log buffer size. */ + u_int32_t st_lg_max; /* Maximum log file size. */ + u_int32_t st_w_bytes; /* Bytes to log. */ + u_int32_t st_w_mbytes; /* Megabytes to log. */ + u_int32_t st_wc_bytes; /* Bytes to log since checkpoint. */ + u_int32_t st_wc_mbytes; /* Megabytes to log since checkpoint. */ + u_int32_t st_wcount; /* Total writes to the log. */ + u_int32_t st_wcount_fill; /* Overflow writes to the log. */ + u_int32_t st_scount; /* Total syncs to the log. */ + u_int32_t st_region_wait; /* Region lock granted after wait. */ + u_int32_t st_region_nowait; /* Region lock granted without wait. */ + u_int32_t st_cur_file; /* Current log file number. */ + u_int32_t st_cur_offset; /* Current log file offset. */ + u_int32_t st_regsize; /* Region size. */ +}; + +int log_archive __P((DB_ENV *, char **[], u_int32_t, void *(*)(size_t))); +int log_compare __P((const DB_LSN *, const DB_LSN *)); +int log_file __P((DB_ENV *, const DB_LSN *, char *, size_t)); +int log_flush __P((DB_ENV *, const DB_LSN *)); +int log_get __P((DB_ENV *, DB_LSN *, DBT *, u_int32_t)); +int log_put __P((DB_ENV *, DB_LSN *, const DBT *, u_int32_t)); +int log_register __P((DB_ENV *, DB *, const char *)); +int log_stat __P((DB_ENV *, DB_LOG_STAT **, void *(*)(size_t))); +int log_unregister __P((DB_ENV *, DB *)); + +/******************************************************* + * Mpool + *******************************************************/ +/* Flag values for memp_fget(). */ +#define DB_MPOOL_CREATE 0x001 /* Create a page. */ +#define DB_MPOOL_LAST 0x002 /* Return the last page. */ +#define DB_MPOOL_NEW 0x004 /* Create a new page. */ +#define DB_MPOOL_NEW_GROUP 0x008 /* Create a group of pages. */ +#define DB_MPOOL_EXTENT 0x010 /* Get for an extent. */ + +/* Flag values for memp_fput(), memp_fset(). */ +#define DB_MPOOL_CLEAN 0x001 /* Page is not modified. */ +#define DB_MPOOL_DIRTY 0x002 /* Page is modified. */ +#define DB_MPOOL_DISCARD 0x004 /* Don't cache the page. */ + +/* Mpool statistics structure. */ +struct __db_mpool_stat { + u_int32_t st_cache_hit; /* Pages found in the cache. */ + u_int32_t st_cache_miss; /* Pages not found in the cache. */ + u_int32_t st_map; /* Pages from mapped files. */ + u_int32_t st_page_create; /* Pages created in the cache. */ + u_int32_t st_page_in; /* Pages read in. */ + u_int32_t st_page_out; /* Pages written out. */ + u_int32_t st_ro_evict; /* Clean pages forced from the cache. */ + u_int32_t st_rw_evict; /* Dirty pages forced from the cache. */ + u_int32_t st_hash_buckets; /* Number of hash buckets. */ + u_int32_t st_hash_searches; /* Total hash chain searches. */ + u_int32_t st_hash_longest; /* Longest hash chain searched. */ + u_int32_t st_hash_examined; /* Total hash entries searched. */ + u_int32_t st_page_clean; /* Clean pages. */ + u_int32_t st_page_dirty; /* Dirty pages. */ + u_int32_t st_page_trickle; /* Pages written by memp_trickle. */ + u_int32_t st_region_wait; /* Region lock granted after wait. */ + u_int32_t st_region_nowait; /* Region lock granted without wait. */ + u_int32_t st_gbytes; /* Total cache size: GB. */ + u_int32_t st_bytes; /* Total cache size: B. */ + u_int32_t st_ncache; /* Number of caches. */ + u_int32_t st_regsize; /* Cache size. */ +}; + +/* Mpool file open information structure. */ +struct __db_mpool_finfo { + int ftype; /* File type. */ + DBT *pgcookie; /* Byte-string passed to pgin/pgout. */ + u_int8_t *fileid; /* Unique file ID. */ + int32_t lsn_offset; /* LSN offset in page. */ + u_int32_t clear_len; /* Cleared length on created pages. */ +}; + +/* Mpool file statistics structure. */ +struct __db_mpool_fstat { + char *file_name; /* File name. */ + size_t st_pagesize; /* Page size. */ + u_int32_t st_cache_hit; /* Pages found in the cache. */ + u_int32_t st_cache_miss; /* Pages not found in the cache. */ + u_int32_t st_map; /* Pages from mapped files. */ + u_int32_t st_page_create; /* Pages created in the cache. */ + u_int32_t st_page_in; /* Pages read in. */ + u_int32_t st_page_out; /* Pages written out. */ +}; + +int memp_fclose __P((DB_MPOOLFILE *)); +int memp_fget __P((DB_MPOOLFILE *, db_pgno_t *, u_int32_t, void *)); +int memp_fopen __P((DB_ENV *, const char *, + u_int32_t, int, size_t, DB_MPOOL_FINFO *, DB_MPOOLFILE **)); +int memp_fput __P((DB_MPOOLFILE *, void *, u_int32_t)); +int memp_fset __P((DB_MPOOLFILE *, void *, u_int32_t)); +int memp_fsync __P((DB_MPOOLFILE *)); +int memp_register __P((DB_ENV *, int, + int (*)(DB_ENV *, db_pgno_t, void *, DBT *), + int (*)(DB_ENV *, db_pgno_t, void *, DBT *))); +int memp_stat __P((DB_ENV *, + DB_MPOOL_STAT **, DB_MPOOL_FSTAT ***, void *(*)(size_t))); +int memp_sync __P((DB_ENV *, DB_LSN *)); +int memp_trickle __P((DB_ENV *, int, int *)); + +/******************************************************* + * Transactions. + *******************************************************/ +#define DB_TXNVERSION 1 + +/* Operations values to the tx_recover() function. */ +#define DB_TXN_BACKWARD_ROLL 1 /* Read the log backwards. */ +#define DB_TXN_FORWARD_ROLL 2 /* Read the log forwards. */ +#define DB_TXN_OPENFILES 3 /* Read for open files. */ +#define DB_TXN_REDO 4 /* Redo the operation. */ +#define DB_TXN_UNDO 5 /* Undo the operation. */ + +/* Internal transaction status values. */ + +/* Transaction statistics structure. */ +struct __db_txn_active { + u_int32_t txnid; /* Transaction ID */ + u_int32_t parentid; /* Transaction ID of parent */ + DB_LSN lsn; /* Lsn of the begin record */ +}; + +struct __db_txn_stat { + DB_LSN st_last_ckp; /* lsn of the last checkpoint */ + DB_LSN st_pending_ckp; /* last checkpoint did not finish */ + time_t st_time_ckp; /* time of last checkpoint */ + u_int32_t st_last_txnid; /* last transaction id given out */ + u_int32_t st_maxtxns; /* maximum txns possible */ + u_int32_t st_naborts; /* number of aborted transactions */ + u_int32_t st_nbegins; /* number of begun transactions */ + u_int32_t st_ncommits; /* number of committed transactions */ + u_int32_t st_nactive; /* number of active transactions */ + u_int32_t st_maxnactive; /* maximum active transactions */ + DB_TXN_ACTIVE + *st_txnarray; /* array of active transactions */ + u_int32_t st_region_wait; /* Region lock granted after wait. */ + u_int32_t st_region_nowait; /* Region lock granted without wait. */ + u_int32_t st_regsize; /* Region size. */ +}; + +int txn_abort __P((DB_TXN *)); +int txn_begin __P((DB_ENV *, DB_TXN *, DB_TXN **, u_int32_t)); +int txn_checkpoint __P((DB_ENV *, u_int32_t, u_int32_t, u_int32_t)); +int txn_commit __P((DB_TXN *, u_int32_t)); +u_int32_t txn_id __P((DB_TXN *)); +int txn_prepare __P((DB_TXN *)); +int txn_stat __P((DB_ENV *, DB_TXN_STAT **, void *(*)(size_t))); + +#ifndef DB_DBM_HSEARCH +#define DB_DBM_HSEARCH 0 /* No historic interfaces by default. */ +#endif +#if DB_DBM_HSEARCH != 0 +/******************************************************* + * Dbm/Ndbm historic interfaces. + *******************************************************/ +#define DBM_INSERT 0 /* Flags to dbm_store(). */ +#define DBM_REPLACE 1 + +/* + * The DB support for ndbm(3) always appends this suffix to the + * file name to avoid overwriting the user's original database. + */ +#define DBM_SUFFIX ".db" + +#if defined(_XPG4_2) +typedef struct { + char *dptr; + size_t dsize; +} datum; +#else +typedef struct { + char *dptr; + int dsize; +} datum; +#endif + +/* + * Translate DBM calls into DB calls so that DB doesn't step on the + * application's name space. + * + * The global variables dbrdonly, dirf and pagf were not retained when 4BSD + * replaced the dbm interface with ndbm, and are not supported here. + */ +#define dbminit(a) __db_dbm_init(a) +#define dbmclose __db_dbm_close +#if !defined(__cplusplus) +#define delete(a) __db_dbm_delete(a) +#endif +#define fetch(a) __db_dbm_fetch(a) +#define firstkey __db_dbm_firstkey +#define nextkey(a) __db_dbm_nextkey(a) +#define store(a, b) __db_dbm_store(a, b) + +/* Prototype the DB calls. */ +int __db_dbm_close __P((void)); +int __db_dbm_dbrdonly __P((void)); +int __db_dbm_delete __P((datum)); +int __db_dbm_dirf __P((void)); +datum __db_dbm_fetch __P((datum)); +datum __db_dbm_firstkey __P((void)); +int __db_dbm_init __P((char *)); +datum __db_dbm_nextkey __P((datum)); +int __db_dbm_pagf __P((void)); +int __db_dbm_store __P((datum, datum)); + +/* + * Translate NDBM calls into DB calls so that DB doesn't step on the + * application's name space. + */ +#define dbm_clearerr(a) __db_ndbm_clearerr(a) +#define dbm_close(a) __db_ndbm_close(a) +#define dbm_delete(a, b) __db_ndbm_delete(a, b) +#define dbm_dirfno(a) __db_ndbm_dirfno(a) +#define dbm_error(a) __db_ndbm_error(a) +#define dbm_fetch(a, b) __db_ndbm_fetch(a, b) +#define dbm_firstkey(a) __db_ndbm_firstkey(a) +#define dbm_nextkey(a) __db_ndbm_nextkey(a) +#define dbm_open(a, b, c) __db_ndbm_open(a, b, c) +#define dbm_pagfno(a) __db_ndbm_pagfno(a) +#define dbm_rdonly(a) __db_ndbm_rdonly(a) +#define dbm_store(a, b, c, d) __db_ndbm_store(a, b, c, d) + +/* Prototype the DB calls. */ +int __db_ndbm_clearerr __P((DBM *)); +void __db_ndbm_close __P((DBM *)); +int __db_ndbm_delete __P((DBM *, datum)); +int __db_ndbm_dirfno __P((DBM *)); +int __db_ndbm_error __P((DBM *)); +datum __db_ndbm_fetch __P((DBM *, datum)); +datum __db_ndbm_firstkey __P((DBM *)); +datum __db_ndbm_nextkey __P((DBM *)); +DBM *__db_ndbm_open __P((const char *, int, int)); +int __db_ndbm_pagfno __P((DBM *)); +int __db_ndbm_rdonly __P((DBM *)); +int __db_ndbm_store __P((DBM *, datum, datum, int)); + +/******************************************************* + * Hsearch historic interface. + *******************************************************/ +typedef enum { + FIND, ENTER +} ACTION; + +typedef struct entry { + char *key; + char *data; +} ENTRY; + +/* + * Translate HSEARCH calls into DB calls so that DB doesn't step on the + * application's name space. + */ +#define hcreate(a) __db_hcreate(a) +#define hdestroy __db_hdestroy +#define hsearch(a, b) __db_hsearch(a, b) + +/* Prototype the DB calls. */ +int __db_hcreate __P((size_t)); +void __db_hdestroy __P((void)); +ENTRY *__db_hsearch __P((ENTRY, ACTION)); +#endif /* DB_DBM_HSEARCH */ + +/* + * XXX + * MacOS: Reset Metrowerks C enum sizes. + */ +#ifdef __MWERKS__ +#pragma enumsalwaysint reset +#endif + +#if defined(__cplusplus) +} +#endif + +#endif /* !_DB_H_ */ diff --git a/db/build_vxworks/db_config.h b/db/build_vxworks/db_config.h new file mode 100644 index 000000000..cccfc4a7c --- /dev/null +++ b/db/build_vxworks/db_config.h @@ -0,0 +1,264 @@ +/* + * $Id: db_config.h,v 1.4 2000/12/12 18:39:26 bostic Exp $ + */ + +/* Define if building VxWorks */ +#define HAVE_VXWORKS 1 + +/* Define to empty if the keyword does not work. */ +/* #undef const */ + +/* Define if your struct stat has st_blksize. */ +#define HAVE_ST_BLKSIZE 1 + +/* Define to `int' if doesn't define. */ +/* #undef mode_t */ + +/* Define to `long' if doesn't define. */ +/* #undef off_t */ + +/* Define to `int' if doesn't define. */ +/* #undef pid_t */ + +/* Define to `unsigned' if doesn't define. */ +/* #undef size_t */ + +/* Define if the `S_IS*' macros in do not work properly. */ +/* #undef STAT_MACROS_BROKEN */ + +/* Define if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if you can safely include both and . */ +/* #undef TIME_WITH_SYS_TIME */ + +/* !!! + * WORDS_BIGENDIAN is the ONLY option in this file that may be edited + * for VxWorks. + * + * The user must set this according to VxWork's target arch. We use an + * x86 (little-endian) target. + */ +/* Define if your processor stores words with the most significant + byte first (like Motorola and SPARC, unlike Intel and VAX). */ +/* #undef WORDS_BIGENDIAN */ + +/* !!! + * The CONFIG_TEST option may be added using the Tornado project build. + * DO NOT modify it here. + */ +/* Define if you are building a version for running the test suite. */ +/* #undef CONFIG_TEST */ + +/* !!! + * The DEBUG option may be added using the Tornado project build. + * DO NOT modify it here. + */ +/* Define if you want a debugging version. */ +/* #undef DEBUG */ + +/* Define if you want a version that logs read operations. */ +/* #undef DEBUG_ROP */ + +/* Define if you want a version that logs write operations. */ +/* #undef DEBUG_WOP */ + +/* !!! + * The DIAGNOSTIC option may be added using the Tornado project build. + * DO NOT modify it here. + */ +/* Define if you want a version with run-time diagnostic checking. */ +/* #undef DIAGNOSTIC */ + +/* Define if you want to mask harmless unitialized memory read/writes. */ +/* #undef UMRW */ + +/* Define if fcntl/F_SETFD denies child access to file descriptors. */ +/* #undef HAVE_FCNTL_F_SETFD */ + +/* Define if building big-file environment (e.g., AIX, HP/UX, Solaris). */ +/* #undef HAVE_FILE_OFFSET_BITS */ + +/* Mutex possibilities. */ +/* #undef HAVE_MUTEX_68K_GCC_ASSEMBLY */ +/* #undef HAVE_MUTEX_AIX_CHECK_LOCK */ +/* #undef HAVE_MUTEX_ALPHA_GCC_ASSEMBLY */ +/* #undef HAVE_MUTEX_HPPA_GCC_ASSEMBLY */ +/* #undef HAVE_MUTEX_HPPA_MSEM_INIT */ +/* #undef HAVE_MUTEX_IA64_GCC_ASSEMBLY */ +/* #undef HAVE_MUTEX_MACOS */ +/* #undef HAVE_MUTEX_MSEM_INIT */ +/* #undef HAVE_MUTEX_PPC_GCC_ASSEMBLY */ +/* #undef HAVE_MUTEX_PTHREADS */ +/* #undef HAVE_MUTEX_RELIANTUNIX_INITSPIN */ +/* #undef HAVE_MUTEX_SCO_X86_CC_ASSEMBLY */ +/* #undef HAVE_MUTEX_SEMA_INIT */ +/* #undef HAVE_MUTEX_SGI_INIT_LOCK */ +/* #undef HAVE_MUTEX_SOLARIS_LOCK_TRY */ +/* #undef HAVE_MUTEX_SOLARIS_LWP */ +/* #undef HAVE_MUTEX_SPARC_GCC_ASSEMBLY */ +#define HAVE_MUTEX_THREADS 1 +/* #undef HAVE_MUTEX_UI_THREADS */ +/* #undef HAVE_MUTEX_UTS_CC_ASSEMBLY */ +/* #undef HAVE_MUTEX_VMS */ +#define HAVE_MUTEX_VXWORKS 1 +/* #undef HAVE_MUTEX_WIN16 */ +/* #undef HAVE_MUTEX_WIN32 */ +/* #undef HAVE_MUTEX_X86_GCC_ASSEMBLY */ + +/* Define if building on QNX. */ +/* #undef HAVE_QNX */ + +/* !!! + * The HAVE_RPC option may be added using the Tornado project build. + * DO NOT modify it here. + */ +/* Define if building RPC client/server. */ +/* #undef HAVE_RPC */ + +/* Define if your sprintf returns a pointer, not a length. */ +/* #undef SPRINTF_RET_CHARPNT */ + +/* Define if you have the getcwd function. */ +#define HAVE_GETCWD 1 + +/* Define if you have the getopt function. */ +/* #undef HAVE_GETOPT */ + +/* Define if you have the getuid function. */ +/* #undef HAVE_GETUID */ + +/* Define if you have the memcmp function. */ +#define HAVE_MEMCMP 1 + +/* Define if you have the memcpy function. */ +#define HAVE_MEMCPY 1 + +/* Define if you have the memmove function. */ +#define HAVE_MEMMOVE 1 + +/* Define if you have the mlock function. */ +#define HAVE_MLOCK 1 + +/* Define if you have the mmap function. */ +/* #undef HAVE_MMAP */ + +/* Define if you have the munlock function. */ +#define HAVE_MUNLOCK 1 + +/* Define if you have the munmap function. */ +/* #undef HAVE_MUNMAP */ + +/* Define if you have the pread function. */ +/* #undef HAVE_PREAD */ + +/* Define if you have the pstat_getdynamic function. */ +/* #undef HAVE_PSTAT_GETDYNAMIC */ + +/* Define if you have the pwrite function. */ +/* #undef HAVE_PWRITE */ + +/* Define if you have the qsort function. */ +#define HAVE_QSORT 1 + +/* Define if you have the raise function. */ +#define HAVE_RAISE 1 + +/* Define if you have the sched_yield function. */ +#define HAVE_SCHED_YIELD 1 + +/* Define if you have the select function. */ +#define HAVE_SELECT 1 + +/* Define if you have the shmget function. */ +/* #undef HAVE_SHMGET */ + +/* Define if you have the snprintf function. */ +/* #undef HAVE_SNPRINTF */ + +/* Define if you have the strcasecmp function. */ +/* #undef HAVE_STRCASECMP */ + +/* Define if you have the strerror function. */ +#define HAVE_STRERROR 1 + +/* Define if you have the strtoul function. */ +#define HAVE_STRTOUL 1 + +/* Define if you have the sysconf function. */ +/* #undef HAVE_SYSCONF */ + +/* Define if you have the vsnprintf function. */ +/* #undef HAVE_VSNPRINTF */ + +/* Define if you have the yield function. */ +/* #undef HAVE_YIELD */ + +/* Define if you have the header file. */ +#define HAVE_DIRENT_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_NDIR_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_SELECT_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_TIME_H */ + +/* Define if you have the nsl library (-lnsl). */ +/* #undef HAVE_LIBNSL */ + +/* + * !!! + * The following is not part of the automatic configuration setup, but + * provides necessary VxWorks information. + */ +#include "vxWorks.h" + +/* + * VxWorks does not have getpid(). + */ +#define getpid() taskIdSelf() + +/* + * Don't step on the namespace. Other libraries may have their own + * implementations of these functions, we don't want to use their + * implementations or force them to use ours based on the load order. + */ +#ifndef HAVE_GETCWD +#define getcwd __db_Cgetcwd +#endif +#ifndef HAVE_GETOPT +#define getopt __db_Cgetopt +#endif +#ifndef HAVE_MEMCMP +#define memcmp __db_Cmemcmp +#endif +#ifndef HAVE_MEMCPY +#define memcpy __db_Cmemcpy +#endif +#ifndef HAVE_MEMMOVE +#define memmove __db_Cmemmove +#endif +#ifndef HAVE_RAISE +#define raise __db_Craise +#endif +#ifndef HAVE_SNPRINTF +#define snprintf __db_Csnprintf +#endif +#ifndef HAVE_STRCASECMP +#define strcasecmp __db_Cstrcasecmp +#endif +#ifndef HAVE_STRERROR +#define strerror __db_Cstrerror +#endif +#ifndef HAVE_VSNPRINTF +#define vsnprintf __db_Cvsnprintf +#endif diff --git a/db/build_vxworks/db_int.h b/db/build_vxworks/db_int.h new file mode 100644 index 000000000..99dc2932e --- /dev/null +++ b/db/build_vxworks/db_int.h @@ -0,0 +1,398 @@ +/* DO NOT EDIT: automatically built by dist/s_vxworks. */ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: db_int.src,v 11.42 2001/01/11 17:49:17 krinsky Exp $ + */ + +#ifndef _DB_INTERNAL_H_ +#define _DB_INTERNAL_H_ + +/******************************************************* + * General includes. + *******************************************************/ +#include "db.h" + +#ifndef NO_SYSTEM_INCLUDES +#if defined(__STDC__) || defined(__cplusplus) +#include +#else +#include +#endif +#include +#endif + +#include "queue.h" +#include "shqueue.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +/******************************************************* + * General purpose constants and macros. + *******************************************************/ +#define UINT16_T_MAX 0xffff /* Maximum 16 bit unsigned. */ +#define UINT32_T_MAX 0xffffffff /* Maximum 32 bit unsigned. */ + +#define MEGABYTE 1048576 +#define GIGABYTE 1073741824 + +#define MS_PER_SEC 1000 /* Milliseconds in a second. */ +#define USEC_PER_MS 1000 /* Microseconds in a millisecond. */ + +#define DB_MIN_PGSIZE 0x000200 /* Minimum page size (512). */ +#define DB_MAX_PGSIZE 0x010000 /* Maximum page size (65536). */ + +#define RECNO_OOB 0 /* Illegal record number. */ + +/* + * If we are unable to determine the underlying filesystem block size, use + * 8K on the grounds that most OS's use less than 8K for a VM page size. + */ +#define DB_DEF_IOSIZE (8 * 1024) + +/* + * Aligning items to particular sizes or in pages or memory. + * + * db_align_t -- + * Largest integral type, used to align structures in memory. We don't store + * floating point types in structures, so integral types should be sufficient + * (and we don't have to worry about systems that store floats in other than + * power-of-2 numbers of bytes). Additionally this fixes compiler that rewrite + * structure assignments and ANSI C memcpy calls to be in-line instructions + * that happen to require alignment. Note: this alignment isn't sufficient for + * mutexes, which depend on things like cache line alignment. Mutex alignment + * is handled separately, in mutex.h. + * + * db_alignp_t -- + * Integral type that's the same size as a pointer. There are places where + * DB modifies pointers by discarding the bottom bits to guarantee alignment. + * We can't use db_align_t, it may be larger than the pointer, and compilers + * get upset about that. So far we haven't run on any machine where there + * isn't an integral type the same size as a pointer -- here's hoping. + */ +typedef unsigned long db_align_t; +typedef unsigned long db_alignp_t; + +/* Align an integer to a specific boundary. */ +#undef ALIGN +#define ALIGN(value, bound) \ + (((value) + (bound) - 1) & ~(((u_int)bound) - 1)) + +/* Align a pointer to a specific boundary. */ +#undef ALIGNP +#define ALIGNP(value, bound) ALIGN((db_alignp_t)value, bound) + +/* + * There are several on-page structures that are declared to have a number of + * fields followed by a variable length array of items. The structure size + * without including the variable length array or the address of the first of + * those elements can be found using SSZ. + * + * This macro can also be used to find the offset of a structure element in a + * structure. This is used in various places to copy structure elements from + * unaligned memory references, e.g., pointers into a packed page. + * + * There are two versions because compilers object if you take the address of + * an array. + */ +#undef SSZ +#define SSZ(name, field) ((int)&(((name *)0)->field)) + +#undef SSZA +#define SSZA(name, field) ((int)&(((name *)0)->field[0])) + +/* + * Print an address as a u_long (a u_long is the largest type we can print + * portably). Most 64-bit systems have made longs 64-bits, so this should + * work. + */ +#define P_TO_ULONG(p) ((u_long)(db_alignp_t)(p)) + +/* Structure used to print flag values. */ +typedef struct __fn { + u_int32_t mask; /* Flag value. */ + const char *name; /* Flag name. */ +} FN; + +/* Set, clear and test flags. */ +#define FLD_CLR(fld, f) (fld) &= ~(f) +#define FLD_ISSET(fld, f) ((fld) & (f)) +#define FLD_SET(fld, f) (fld) |= (f) +#define F_CLR(p, f) (p)->flags &= ~(f) +#define F_ISSET(p, f) ((p)->flags & (f)) +#define F_SET(p, f) (p)->flags |= (f) +#define LF_CLR(f) (flags &= ~(f)) +#define LF_ISSET(f) (flags & (f)) +#define LF_SET(f) (flags |= (f)) + +/* Display separator string. */ +#undef DB_LINE +#define DB_LINE "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=" + +/* Unused, or not-used-yet variable. "Shut that bloody compiler up!" */ +#define COMPQUIET(n, v) (n) = (v) + +/******************************************************* + * Files. + *******************************************************/ + /* + * We use 1024 as the maximum path length. It's too hard to figure out what + * the real path length is, as it was traditionally stored in , + * and that file isn't always available. + */ +#undef MAXPATHLEN +#define MAXPATHLEN 1024 + +#define PATH_DOT "." /* Current working directory. */ +#define PATH_SEPARATOR "/\\" /* Path separator character. */ + +/* + * Flags understood by __os_open. + */ +#define DB_OSO_CREATE 0x001 /* POSIX: O_CREAT */ +#define DB_OSO_EXCL 0x002 /* POSIX: O_EXCL */ +#define DB_OSO_LOG 0x004 /* Opening a log file. */ +#define DB_OSO_RDONLY 0x008 /* POSIX: O_RDONLY */ +#define DB_OSO_REGION 0x010 /* Opening a region file. */ +#define DB_OSO_SEQ 0x020 /* Expected sequential access. */ +#define DB_OSO_TEMP 0x040 /* Remove after last close. */ +#define DB_OSO_TRUNC 0x080 /* POSIX: O_TRUNC */ + +/* + * Seek options understood by __os_seek. + */ +typedef enum { + DB_OS_SEEK_CUR, /* POSIX: SEEK_CUR */ + DB_OS_SEEK_END, /* POSIX: SEEK_END */ + DB_OS_SEEK_SET /* POSIX: SEEK_SET */ +} DB_OS_SEEK; + +/******************************************************* + * Environment. + *******************************************************/ +/* Type passed to __db_appname(). */ +typedef enum { + DB_APP_NONE=0, /* No type (region). */ + DB_APP_DATA, /* Data file. */ + DB_APP_LOG, /* Log file. */ + DB_APP_TMP /* Temporary file. */ +} APPNAME; + +/* + * CDB_LOCKING CDB product locking. + * LOCKING_ON Locking has been configured. + * LOGGING_ON Logging has been configured. + * MPOOL_ON Memory pool has been configured. + * TXN_ON Transactions have been configured. + */ +#define CDB_LOCKING(dbenv) F_ISSET(dbenv, DB_ENV_CDB) +#define LOCKING_ON(dbenv) ((dbenv)->lk_handle != NULL) +#define LOGGING_ON(dbenv) ((dbenv)->lg_handle != NULL) +#define MPOOL_ON(dbenv) ((dbenv)->mp_handle != NULL) +#define TXN_ON(dbenv) ((dbenv)->tx_handle != NULL) + +/* + * STD_LOCKING Standard locking, that is, locking was configured and CDB + * was not. We do not do locking in off-page duplicate trees, + * so we check for that in the cursor first. + */ +#define STD_LOCKING(dbc) \ + (!F_ISSET(dbc, DBC_OPD) && \ + !CDB_LOCKING((dbc)->dbp->dbenv) && LOCKING_ON((dbc)->dbp->dbenv)) + +/* + * IS_RECOVERING The system is running recovery. + */ +#define IS_RECOVERING(dbenv) \ + (LOGGING_ON(dbenv) && \ + F_ISSET((DB_LOG *)(dbenv)->lg_handle, DBLOG_RECOVER)) + +/* Most initialization methods cannot be called after open is called. */ +#define ENV_ILLEGAL_AFTER_OPEN(dbenv, name) \ + if (F_ISSET((dbenv), DB_ENV_OPEN_CALLED)) \ + return (__db_mi_open(dbenv, name, 1)); + +/* We're not actually user hostile, honest. */ +#define ENV_REQUIRES_CONFIG(dbenv, handle, subsystem) \ + if (handle == NULL) \ + return (__db_env_config(dbenv, subsystem)); + +/******************************************************* + * Database Access Methods. + *******************************************************/ +/* + * DB_IS_THREADED -- + * The database handle is free-threaded (was opened with DB_THREAD). + */ +#define DB_IS_THREADED(dbp) \ + ((dbp)->mutexp != NULL) + +/* Initialization methods are often illegal before/after open is called. */ +#define DB_ILLEGAL_AFTER_OPEN(dbp, name) \ + if (F_ISSET((dbp), DB_OPEN_CALLED)) \ + return (__db_mi_open(dbp->dbenv, name, 1)); +#define DB_ILLEGAL_BEFORE_OPEN(dbp, name) \ + if (!F_ISSET((dbp), DB_OPEN_CALLED)) \ + return (__db_mi_open(dbp->dbenv, name, 0)); +/* Some initialization methods are illegal if environment isn't local. */ +#define DB_ILLEGAL_IN_ENV(dbp, name) \ + if (!F_ISSET(dbp->dbenv, DB_ENV_DBLOCAL)) \ + return (__db_mi_env(dbp->dbenv, name)); +#define DB_ILLEGAL_METHOD(dbp, flags) { \ + int __ret; \ + if ((__ret = __dbh_am_chk(dbp, flags)) != 0) \ + return (__ret); \ +} + +/* + * Common DBC->internal fields. Each access method adds additional fields + * to this list, but the initial fields are common. + */ +#define __DBC_INTERNAL \ + DBC *opd; /* Off-page duplicate cursor. */\ + \ + void *page; /* Referenced page. */ \ + db_pgno_t root; /* Tree root. */ \ + db_pgno_t pgno; /* Referenced page number. */ \ + db_indx_t indx; /* Referenced key item index. */\ + \ + DB_LOCK lock; /* Cursor lock. */ \ + db_lockmode_t lock_mode; /* Lock mode. */ + +struct __dbc_internal { + __DBC_INTERNAL +}; + +/* + * Access-method-common macro for determining whether a cursor + * has been initialized. + */ +#define IS_INITIALIZED(dbc) ((dbc)->internal->pgno != PGNO_INVALID) + +/******************************************************* + * Mpool. + *******************************************************/ +/* + * File types for DB access methods. Negative numbers are reserved to DB. + */ +#define DB_FTYPE_SET -1 /* Call pgin/pgout functions. */ +#define DB_FTYPE_NOTSET 0 /* Don't call... */ + +/* Structure used as the DB pgin/pgout pgcookie. */ +typedef struct __dbpginfo { + size_t db_pagesize; /* Underlying page size. */ + int needswap; /* If swapping required. */ +} DB_PGINFO; + +/******************************************************* + * Log. + *******************************************************/ +/* Initialize an LSN to 'zero'. */ +#define ZERO_LSN(LSN) do { \ + (LSN).file = 0; \ + (LSN).offset = 0; \ +} while (0) + +/* Return 1 if LSN is a 'zero' lsn, otherwise return 0. */ +#define IS_ZERO_LSN(LSN) ((LSN).file == 0) + +/* Test if we need to log a change. */ +#define DB_LOGGING(dbc) \ + (LOGGING_ON((dbc)->dbp->dbenv) && !F_ISSET(dbc, DBC_RECOVER)) + +/* Internal flag for use with internal __log_unregister. */ +#define DB_LOGONLY 0x01 +/******************************************************* + * Txn. + *******************************************************/ +#define DB_NONBLOCK(C) ((C)->txn != NULL && F_ISSET((C)->txn, TXN_NOWAIT)) +#define IS_SUBTRANSACTION(txn) \ + ((txn) != NULL && (txn)->parent != NULL) + +/******************************************************* + * Global variables. + *******************************************************/ +#ifdef HAVE_VXWORKS +#include "semLib.h" +#endif + +/* + * DB global variables. Done in a single structure to minimize the name-space + * pollution. + */ +typedef struct __db_globals { + u_int32_t db_pageyield; /* db_set_pageyield */ + u_int32_t db_panic; /* db_set_panic */ + u_int32_t db_region_init; /* db_set_region_init */ + u_int32_t db_tas_spins; /* db_set_tas_spins */ +#ifdef HAVE_VXWORKS + u_int32_t db_global_init; /* VxWorks: inited */ + SEM_ID db_global_lock; /* VxWorks: global semaphore */ +#endif + /* XA: list of opened environments. */ + TAILQ_HEAD(__db_envq, __db_env) db_envq; +} DB_GLOBALS; + +#ifdef DB_INITIALIZE_DB_GLOBALS +DB_GLOBALS __db_global_values = { + 0, /* db_set_pageyield */ + 1, /* db_set_panic */ + 0, /* db_set_region_init */ + 0, /* db_set_tas_spins */ +#ifdef HAVE_VXWORKS + 0, /* db_global_init */ + NULL, /* db_global_lock */ +#endif + /* XA environment queue */ + {NULL, &__db_global_values.db_envq.tqh_first} +}; +#else +extern DB_GLOBALS __db_global_values; +#endif +#define DB_GLOBAL(v) __db_global_values.v + +/* Forward structure declarations. */ +struct __db_reginfo_t; typedef struct __db_reginfo_t REGINFO; +struct __mutex_t; typedef struct __mutex_t MUTEX; +struct __vrfy_childinfo; typedef struct __vrfy_childinfo VRFY_CHILDINFO; +struct __vrfy_dbinfo; typedef struct __vrfy_dbinfo VRFY_DBINFO; +struct __vrfy_pageinfo; typedef struct __vrfy_pageinfo VRFY_PAGEINFO; +struct __db_txnlist; typedef struct __db_txnlist DB_TXNLIST; +struct __db_txnhead; typedef struct __db_txnhead DB_TXNHEAD; +typedef enum { + TXNLIST_DELETE, + TXNLIST_LSN, + TXNLIST_TXNID, + TXNLIST_PGNO +} db_txnlist_type; + +/* + * Currently, region offsets are limited to 32-bits. I expect that's going + * to have to be fixed in the not-too-distant future, since we won't want to + * split 100Gb memory pools into that many different regions. It's typedef'd + * so it won't be too painful to upgrade. + */ +typedef u_int32_t roff_t; + +#if defined(__cplusplus) +} +#endif + +/******************************************************* + * More general includes. + *******************************************************/ +#include "debug.h" +#include "mutex.h" +#include "region.h" +#include "mutex_ext.h" +#include "env_ext.h" +#include "os.h" +#include "os_ext.h" +#include "common_ext.h" + +#endif /* !_DB_INTERNAL_H_ */ diff --git a/db/build_vxworks/ex_access/ex_access.wpj b/db/build_vxworks/ex_access/ex_access.wpj new file mode 100644 index 000000000..bbbad47a2 --- /dev/null +++ b/db/build_vxworks/ex_access/ex_access.wpj @@ -0,0 +1,244 @@ +Document file - DO NOT EDIT + + BUILD_PENTIUMgnu_MACRO_AR +ar386 + + + BUILD_PENTIUMgnu_MACRO_ARCHIVE +$(PRJ_DIR)/PENTIUMgnu/ex_access.a + + + BUILD_PENTIUMgnu_MACRO_AS +cc386 + + + BUILD_PENTIUMgnu_MACRO_CC +cc386 + + + BUILD_PENTIUMgnu_MACRO_CFLAGS +-g \ + -mpentium \ + -ansi \ + -nostdinc \ + -DRW_MULTI_THREAD \ + -D_REENTRANT \ + -fvolatile \ + -nostdlib \ + -fno-builtin \ + -fno-defer-pop \ + -I. \ + -I$(WIND_BASE)/target/h \ + -DCPU=PENTIUM \ + -I/export/home/db/build_vxworks + + + BUILD_PENTIUMgnu_MACRO_CFLAGS_AS +-g \ + -mpentium \ + -ansi \ + -nostdinc \ + -fvolatile \ + -nostdlib \ + -fno-builtin \ + -fno-defer-pop \ + -P \ + -x \ + assembler-with-cpp \ + -I. \ + -I$(WIND_BASE)/target/h \ + -DCPU=PENTIUM + + + BUILD_PENTIUMgnu_MACRO_CPP +cc386 -E -P -xc + + + BUILD_PENTIUMgnu_MACRO_LD +ld386 + + + BUILD_PENTIUMgnu_MACRO_LDFLAGS +-X -N + + + BUILD_PENTIUMgnu_MACRO_LD_PARTIAL_FLAGS +-X -r + + + BUILD_PENTIUMgnu_MACRO_NM +nm386 -g + + + BUILD_PENTIUMgnu_MACRO_OPTION_DEFINE_MACRO +-D + + + BUILD_PENTIUMgnu_MACRO_OPTION_INCLUDE_DIR +-I + + + BUILD_PENTIUMgnu_MACRO_SIZE +size386 + + + BUILD_PENTIUMgnu_RO_DEPEND_PATH +{$(WIND_BASE)/target/h/} \ + {$(WIND_BASE)/target/src/} \ + {$(WIND_BASE)/target/config/} + + + BUILD_PENTIUMgnu_TC +::tc_PENTIUMgnu + + + BUILD_RULE_archive + + + + BUILD_RULE_ex_access.out + + + + BUILD_RULE_objects + + + + BUILD_SIMSPARCSOLARISgnu_BUILDRULE +ex_access.out + + + BUILD_SIMSPARCSOLARISgnu_MACRO_AR +arsimso + + + BUILD_SIMSPARCSOLARISgnu_MACRO_ARCHIVE +$(PRJ_DIR)/SIMSPARCSOLARISgnu/ex_access.a + + + BUILD_SIMSPARCSOLARISgnu_MACRO_AS +ccsimso + + + BUILD_SIMSPARCSOLARISgnu_MACRO_CC +ccsimso + + + BUILD_SIMSPARCSOLARISgnu_MACRO_CFLAGS +-g \ + -ansi \ + -nostdinc \ + -DRW_MULTI_THREAD \ + -D_REENTRANT \ + -fvolatile \ + -fno-builtin \ + -I/export/home/db/build_vxworks \ + -I. \ + -I$(WIND_BASE)/target/h \ + -DCPU=SIMSPARCSOLARIS + + + BUILD_SIMSPARCSOLARISgnu_MACRO_CFLAGS_AS +-g \ + -ansi \ + -nostdinc \ + -fvolatile \ + -fno-builtin \ + -P \ + -x \ + assembler-with-cpp \ + -I. \ + -I$(WIND_BASE)/target/h \ + -DCPU=SIMSPARCSOLARIS + + + BUILD_SIMSPARCSOLARISgnu_MACRO_CPP +ccsimso -E -P -xc + + + BUILD_SIMSPARCSOLARISgnu_MACRO_LD +ccsimso + + + BUILD_SIMSPARCSOLARISgnu_MACRO_LDFLAGS +-N + + + BUILD_SIMSPARCSOLARISgnu_MACRO_LD_PARTIAL_FLAGS +-nostdlib -r + + + BUILD_SIMSPARCSOLARISgnu_MACRO_NM +nmsimso + + + BUILD_SIMSPARCSOLARISgnu_MACRO_OPTION_DEFINE_MACRO +-D + + + BUILD_SIMSPARCSOLARISgnu_MACRO_OPTION_INCLUDE_DIR +-I + + + BUILD_SIMSPARCSOLARISgnu_MACRO_POST_BUILD_RULE + + + + BUILD_SIMSPARCSOLARISgnu_MACRO_PRJ_LIBS + + + + BUILD_SIMSPARCSOLARISgnu_MACRO_SIZE +sizesimso + + + BUILD_SIMSPARCSOLARISgnu_RO_DEPEND_PATH +{$(WIND_BASE)/target/h/} \ + {$(WIND_BASE)/target/src/} \ + {$(WIND_BASE)/target/config/} + + + BUILD_SIMSPARCSOLARISgnu_TC +::tc_SIMSPARCSOLARISgnu + + + BUILD__CURRENT +PENTIUMgnu + + + BUILD__LIST +SIMSPARCSOLARISgnu PENTIUMgnu + + + CORE_INFO_TYPE +::prj_vxApp + + + CORE_INFO_VERSION +2.0 + + + FILE_/export/home/db/examples_c/ex_access.c_dependDone +TRUE + + + FILE_/export/home/db/examples_c/ex_access.c_dependencies +/export/home/db/build_vxworks/db_config.h /export/home/db/build_vxworks/db.h + + + FILE_/export/home/db/examples_c/ex_access.c_objects +ex_access.o + + + FILE_/export/home/db/examples_c/ex_access.c_tool +C/C++ compiler + + + PROJECT_FILES +/export/home/db/examples_c/ex_access.c + + + userComments +ex_access + + diff --git a/db/build_vxworks/ex_btrec/ex_btrec.wpj b/db/build_vxworks/ex_btrec/ex_btrec.wpj new file mode 100644 index 000000000..801ca6808 --- /dev/null +++ b/db/build_vxworks/ex_btrec/ex_btrec.wpj @@ -0,0 +1,250 @@ +Document file - DO NOT EDIT + + BUILD_PENTIUMgnu_MACRO_AR +ar386 + + + BUILD_PENTIUMgnu_MACRO_ARCHIVE +$(PRJ_DIR)/PENTIUMgnu/ex_btrec.a + + + BUILD_PENTIUMgnu_MACRO_AS +cc386 + + + BUILD_PENTIUMgnu_MACRO_CC +cc386 + + + BUILD_PENTIUMgnu_MACRO_CFLAGS +-g \ + -mpentium \ + -ansi \ + -nostdinc \ + -DRW_MULTI_THREAD \ + -D_REENTRANT \ + -fvolatile \ + -nostdlib \ + -fno-builtin \ + -fno-defer-pop \ + -I. \ + -I$(WIND_BASE)/target/h \ + -DCPU=PENTIUM \ + -I/export/home/db/build_vxworks + + + BUILD_PENTIUMgnu_MACRO_CFLAGS_AS +-g \ + -mpentium \ + -ansi \ + -nostdinc \ + -fvolatile \ + -nostdlib \ + -fno-builtin \ + -fno-defer-pop \ + -P \ + -x \ + assembler-with-cpp \ + -I. \ + -I$(WIND_BASE)/target/h \ + -DCPU=PENTIUM + + + BUILD_PENTIUMgnu_MACRO_CPP +cc386 -E -P -xc + + + BUILD_PENTIUMgnu_MACRO_LD +ld386 + + + BUILD_PENTIUMgnu_MACRO_LDFLAGS +-X -N + + + BUILD_PENTIUMgnu_MACRO_LD_PARTIAL_FLAGS +-X -r + + + BUILD_PENTIUMgnu_MACRO_NM +nm386 -g + + + BUILD_PENTIUMgnu_MACRO_OPTION_DEFINE_MACRO +-D + + + BUILD_PENTIUMgnu_MACRO_OPTION_INCLUDE_DIR +-I + + + BUILD_PENTIUMgnu_MACRO_SIZE +size386 + + + BUILD_PENTIUMgnu_RO_DEPEND_PATH +{$(WIND_BASE)/target/h/} \ + {$(WIND_BASE)/target/src/} \ + {$(WIND_BASE)/target/config/} + + + BUILD_PENTIUMgnu_TC +::tc_PENTIUMgnu + + + BUILD_RULE_archive + + + + BUILD_RULE_ex_btrec.out + + + + BUILD_RULE_objects + + + + BUILD_SIMSPARCSOLARISgnu_BUILDRULE +ex_btrec.out + + + BUILD_SIMSPARCSOLARISgnu_MACRO_AR +arsimso + + + BUILD_SIMSPARCSOLARISgnu_MACRO_ARCHIVE +$(PRJ_DIR)/SIMSPARCSOLARISgnu/ex_btrec.a + + + BUILD_SIMSPARCSOLARISgnu_MACRO_AS +ccsimso + + + BUILD_SIMSPARCSOLARISgnu_MACRO_CC +ccsimso + + + BUILD_SIMSPARCSOLARISgnu_MACRO_CFLAGS +-g \ + -ansi \ + -nostdinc \ + -DRW_MULTI_THREAD \ + -D_REENTRANT \ + -fvolatile \ + -fno-builtin \ + -I/export/home/db/build_vxworks \ + -I/export/home/db/build_vxworks \ + -I/export/home/db/include \ + -I. \ + -I$(WIND_BASE)/target/h \ + -DCPU=SIMSPARCSOLARIS + + + BUILD_SIMSPARCSOLARISgnu_MACRO_CFLAGS_AS +-g \ + -ansi \ + -nostdinc \ + -fvolatile \ + -fno-builtin \ + -P \ + -x \ + assembler-with-cpp \ + -I. \ + -I$(WIND_BASE)/target/h \ + -DCPU=SIMSPARCSOLARIS + + + BUILD_SIMSPARCSOLARISgnu_MACRO_CPP +ccsimso -E -P -xc + + + BUILD_SIMSPARCSOLARISgnu_MACRO_LD +ccsimso + + + BUILD_SIMSPARCSOLARISgnu_MACRO_LDDEPS + + + + BUILD_SIMSPARCSOLARISgnu_MACRO_LDFLAGS +-N + + + BUILD_SIMSPARCSOLARISgnu_MACRO_LD_PARTIAL_FLAGS +-nostdlib -r + + + BUILD_SIMSPARCSOLARISgnu_MACRO_NM +nmsimso + + + BUILD_SIMSPARCSOLARISgnu_MACRO_OPTION_DEFINE_MACRO +-D + + + BUILD_SIMSPARCSOLARISgnu_MACRO_OPTION_INCLUDE_DIR +-I + + + BUILD_SIMSPARCSOLARISgnu_MACRO_POST_BUILD_RULE + + + + BUILD_SIMSPARCSOLARISgnu_MACRO_PRJ_LIBS + + + + BUILD_SIMSPARCSOLARISgnu_MACRO_SIZE +sizesimso + + + BUILD_SIMSPARCSOLARISgnu_RO_DEPEND_PATH +{$(WIND_BASE)/target/h/} \ + {$(WIND_BASE)/target/src/} \ + {$(WIND_BASE)/target/config/} + + + BUILD_SIMSPARCSOLARISgnu_TC +::tc_SIMSPARCSOLARISgnu + + + BUILD__CURRENT +PENTIUMgnu + + + BUILD__LIST +SIMSPARCSOLARISgnu PENTIUMgnu + + + CORE_INFO_TYPE +::prj_vxApp + + + CORE_INFO_VERSION +2.0 + + + FILE_/export/home/db/examples_c/ex_btrec.c_dependDone +TRUE + + + FILE_/export/home/db/examples_c/ex_btrec.c_dependencies +/export/home/db/build_vxworks/db_config.h /export/home/db/build_vxworks/db.h + + + FILE_/export/home/db/examples_c/ex_btrec.c_objects +ex_btrec.o + + + FILE_/export/home/db/examples_c/ex_btrec.c_tool +C/C++ compiler + + + PROJECT_FILES +/export/home/db/examples_c/ex_btrec.c + + + userComments +ex_btrec + + diff --git a/db/build_vxworks/ex_dbclient/ex_dbclient.wpj b/db/build_vxworks/ex_dbclient/ex_dbclient.wpj new file mode 100644 index 000000000..fdb721406 --- /dev/null +++ b/db/build_vxworks/ex_dbclient/ex_dbclient.wpj @@ -0,0 +1,266 @@ +Document file - DO NOT EDIT + + BUILD_PENTIUMgnu_BUILDRULE +ex_dbclient.out + + + BUILD_PENTIUMgnu_MACRO_AR +ar386 + + + BUILD_PENTIUMgnu_MACRO_ARCHIVE +$(PRJ_DIR)/PENTIUMgnu/ex_dbclient.a + + + BUILD_PENTIUMgnu_MACRO_AS +cc386 + + + BUILD_PENTIUMgnu_MACRO_CC +cc386 + + + BUILD_PENTIUMgnu_MACRO_CFLAGS +-g \ + -mpentium \ + -ansi \ + -nostdinc \ + -DRW_MULTI_THREAD \ + -D_REENTRANT \ + -fvolatile \ + -nostdlib \ + -fno-builtin \ + -fno-defer-pop \ + -I/export/home/db/build_vxworks \ + -I/export/home/db/include \ + -I. \ + -I$(WIND_BASE)/target/h \ + -DCPU=PENTIUM + + + BUILD_PENTIUMgnu_MACRO_CFLAGS_AS +-g \ + -mpentium \ + -ansi \ + -nostdinc \ + -fvolatile \ + -nostdlib \ + -fno-builtin \ + -fno-defer-pop \ + -P \ + -x \ + assembler-with-cpp \ + -I. \ + -I$(WIND_BASE)/target/h \ + -DCPU=PENTIUM + + + BUILD_PENTIUMgnu_MACRO_CPP +cc386 -E -P -xc + + + BUILD_PENTIUMgnu_MACRO_LD +ld386 + + + BUILD_PENTIUMgnu_MACRO_LDDEPS + + + + BUILD_PENTIUMgnu_MACRO_LDFLAGS +-X -N + + + BUILD_PENTIUMgnu_MACRO_LD_PARTIAL_FLAGS +-X -r + + + BUILD_PENTIUMgnu_MACRO_NM +nm386 -g + + + BUILD_PENTIUMgnu_MACRO_OPTION_DEFINE_MACRO +-D + + + BUILD_PENTIUMgnu_MACRO_OPTION_INCLUDE_DIR +-I + + + BUILD_PENTIUMgnu_MACRO_POST_BUILD_RULE + + + + BUILD_PENTIUMgnu_MACRO_PRJ_LIBS + + + + BUILD_PENTIUMgnu_MACRO_SIZE +size386 + + + BUILD_PENTIUMgnu_RO_DEPEND_PATH +{$(WIND_BASE)/target/h/} \ + {$(WIND_BASE)/target/src/} \ + {$(WIND_BASE)/target/config/} + + + BUILD_PENTIUMgnu_TC +::tc_PENTIUMgnu + + + BUILD_RULE_archive + + + + BUILD_RULE_ex_dbclient.out + + + + BUILD_RULE_objects + + + + BUILD_SIMSPARCSOLARISgnu_BUILDRULE +ex_dbclient.out + + + BUILD_SIMSPARCSOLARISgnu_MACRO_AR +arsimso + + + BUILD_SIMSPARCSOLARISgnu_MACRO_ARCHIVE +$(PRJ_DIR)/SIMSPARCSOLARISgnu/ex_dbclient.a + + + BUILD_SIMSPARCSOLARISgnu_MACRO_AS +ccsimso + + + BUILD_SIMSPARCSOLARISgnu_MACRO_CC +ccsimso + + + BUILD_SIMSPARCSOLARISgnu_MACRO_CFLAGS +-g \ + -ansi \ + -nostdinc \ + -DRW_MULTI_THREAD \ + -D_REENTRANT \ + -fvolatile \ + -fno-builtin \ + -I/export/home/db/build_vxworks \ + -I/export/home/db/include \ + -I. \ + -I$(WIND_BASE)/target/h \ + -DCPU=SIMSPARCSOLARIS + + + BUILD_SIMSPARCSOLARISgnu_MACRO_CFLAGS_AS +-g \ + -ansi \ + -nostdinc \ + -fvolatile \ + -fno-builtin \ + -P \ + -x \ + assembler-with-cpp \ + -I. \ + -I$(WIND_BASE)/target/h \ + -DCPU=SIMSPARCSOLARIS + + + BUILD_SIMSPARCSOLARISgnu_MACRO_CPP +ccsimso -E -P -xc + + + BUILD_SIMSPARCSOLARISgnu_MACRO_LD +ccsimso + + + BUILD_SIMSPARCSOLARISgnu_MACRO_LDDEPS + + + + BUILD_SIMSPARCSOLARISgnu_MACRO_LDFLAGS +-N + + + BUILD_SIMSPARCSOLARISgnu_MACRO_LD_PARTIAL_FLAGS +-nostdlib -r + + + BUILD_SIMSPARCSOLARISgnu_MACRO_NM +nmsimso + + + BUILD_SIMSPARCSOLARISgnu_MACRO_OPTION_DEFINE_MACRO +-D + + + BUILD_SIMSPARCSOLARISgnu_MACRO_OPTION_INCLUDE_DIR +-I + + + BUILD_SIMSPARCSOLARISgnu_MACRO_POST_BUILD_RULE + + + + BUILD_SIMSPARCSOLARISgnu_MACRO_PRJ_LIBS + + + + BUILD_SIMSPARCSOLARISgnu_MACRO_SIZE +sizesimso + + + BUILD_SIMSPARCSOLARISgnu_RO_DEPEND_PATH +{$(WIND_BASE)/target/h/} \ + {$(WIND_BASE)/target/src/} \ + {$(WIND_BASE)/target/config/} + + + BUILD_SIMSPARCSOLARISgnu_TC +::tc_SIMSPARCSOLARISgnu + + + BUILD__CURRENT +PENTIUMgnu + + + BUILD__LIST +SIMSPARCSOLARISgnu PENTIUMgnu + + + CORE_INFO_TYPE +::prj_vxApp + + + CORE_INFO_VERSION +2.0 + + + FILE_/export/home/db/examples_c/ex_dbclient.c_dependDone +TRUE + + + FILE_/export/home/db/examples_c/ex_dbclient.c_dependencies +/export/home/db/build_vxworks/db_config.h /export/home/db/build_vxworks/db.h + + + FILE_/export/home/db/examples_c/ex_dbclient.c_objects +ex_dbclient.o + + + FILE_/export/home/db/examples_c/ex_dbclient.c_tool +C/C++ compiler + + + PROJECT_FILES +/export/home/db/examples_c/ex_dbclient.c + + + userComments +RPC Client example + + diff --git a/db/build_vxworks/ex_env/ex_env.wpj b/db/build_vxworks/ex_env/ex_env.wpj new file mode 100644 index 000000000..7229ffa13 --- /dev/null +++ b/db/build_vxworks/ex_env/ex_env.wpj @@ -0,0 +1,248 @@ +Document file - DO NOT EDIT + + BUILD_PENTIUMgnu_MACRO_AR +ar386 + + + BUILD_PENTIUMgnu_MACRO_ARCHIVE +$(PRJ_DIR)/PENTIUMgnu/ex_env.a + + + BUILD_PENTIUMgnu_MACRO_AS +cc386 + + + BUILD_PENTIUMgnu_MACRO_CC +cc386 + + + BUILD_PENTIUMgnu_MACRO_CFLAGS +-g \ + -mpentium \ + -ansi \ + -nostdinc \ + -DRW_MULTI_THREAD \ + -D_REENTRANT \ + -fvolatile \ + -nostdlib \ + -fno-builtin \ + -fno-defer-pop \ + -I. \ + -I$(WIND_BASE)/target/h \ + -DCPU=PENTIUM \ + -I/export/home/db/build_vxworks + + + BUILD_PENTIUMgnu_MACRO_CFLAGS_AS +-g \ + -mpentium \ + -ansi \ + -nostdinc \ + -fvolatile \ + -nostdlib \ + -fno-builtin \ + -fno-defer-pop \ + -P \ + -x \ + assembler-with-cpp \ + -I. \ + -I$(WIND_BASE)/target/h \ + -DCPU=PENTIUM + + + BUILD_PENTIUMgnu_MACRO_CPP +cc386 -E -P -xc + + + BUILD_PENTIUMgnu_MACRO_LD +ld386 + + + BUILD_PENTIUMgnu_MACRO_LDFLAGS +-X -N + + + BUILD_PENTIUMgnu_MACRO_LD_PARTIAL_FLAGS +-X -r + + + BUILD_PENTIUMgnu_MACRO_NM +nm386 -g + + + BUILD_PENTIUMgnu_MACRO_OPTION_DEFINE_MACRO +-D + + + BUILD_PENTIUMgnu_MACRO_OPTION_INCLUDE_DIR +-I + + + BUILD_PENTIUMgnu_MACRO_SIZE +size386 + + + BUILD_PENTIUMgnu_RO_DEPEND_PATH +{$(WIND_BASE)/target/h/} \ + {$(WIND_BASE)/target/src/} \ + {$(WIND_BASE)/target/config/} + + + BUILD_PENTIUMgnu_TC +::tc_PENTIUMgnu + + + BUILD_RULE_archive + + + + BUILD_RULE_ex_env.out + + + + BUILD_RULE_objects + + + + BUILD_SIMSPARCSOLARISgnu_BUILDRULE +ex_env.out + + + BUILD_SIMSPARCSOLARISgnu_MACRO_AR +arsimso + + + BUILD_SIMSPARCSOLARISgnu_MACRO_ARCHIVE +$(PRJ_DIR)/SIMSPARCSOLARISgnu/ex_env.a + + + BUILD_SIMSPARCSOLARISgnu_MACRO_AS +ccsimso + + + BUILD_SIMSPARCSOLARISgnu_MACRO_CC +ccsimso + + + BUILD_SIMSPARCSOLARISgnu_MACRO_CFLAGS +-g \ + -ansi \ + -nostdinc \ + -DRW_MULTI_THREAD \ + -D_REENTRANT \ + -fvolatile \ + -fno-builtin \ + -I/export/home/db/build_vxworks \ + -I. \ + -I$(WIND_BASE)/target/h \ + -DCPU=SIMSPARCSOLARIS + + + BUILD_SIMSPARCSOLARISgnu_MACRO_CFLAGS_AS +-g \ + -ansi \ + -nostdinc \ + -fvolatile \ + -fno-builtin \ + -P \ + -x \ + assembler-with-cpp \ + -I. \ + -I$(WIND_BASE)/target/h \ + -DCPU=SIMSPARCSOLARIS + + + BUILD_SIMSPARCSOLARISgnu_MACRO_CPP +ccsimso -E -P -xc + + + BUILD_SIMSPARCSOLARISgnu_MACRO_LD +ccsimso + + + BUILD_SIMSPARCSOLARISgnu_MACRO_LDDEPS + + + + BUILD_SIMSPARCSOLARISgnu_MACRO_LDFLAGS +-N + + + BUILD_SIMSPARCSOLARISgnu_MACRO_LD_PARTIAL_FLAGS +-nostdlib -r + + + BUILD_SIMSPARCSOLARISgnu_MACRO_NM +nmsimso + + + BUILD_SIMSPARCSOLARISgnu_MACRO_OPTION_DEFINE_MACRO +-D + + + BUILD_SIMSPARCSOLARISgnu_MACRO_OPTION_INCLUDE_DIR +-I + + + BUILD_SIMSPARCSOLARISgnu_MACRO_POST_BUILD_RULE + + + + BUILD_SIMSPARCSOLARISgnu_MACRO_PRJ_LIBS + + + + BUILD_SIMSPARCSOLARISgnu_MACRO_SIZE +sizesimso + + + BUILD_SIMSPARCSOLARISgnu_RO_DEPEND_PATH +{$(WIND_BASE)/target/h/} \ + {$(WIND_BASE)/target/src/} \ + {$(WIND_BASE)/target/config/} + + + BUILD_SIMSPARCSOLARISgnu_TC +::tc_SIMSPARCSOLARISgnu + + + BUILD__CURRENT +PENTIUMgnu + + + BUILD__LIST +SIMSPARCSOLARISgnu PENTIUMgnu + + + CORE_INFO_TYPE +::prj_vxApp + + + CORE_INFO_VERSION +2.0 + + + FILE_/export/home/db/examples_c/ex_env.c_dependDone +TRUE + + + FILE_/export/home/db/examples_c/ex_env.c_dependencies +/export/home/db/build_vxworks/db_config.h /export/home/db/build_vxworks/db.h + + + FILE_/export/home/db/examples_c/ex_env.c_objects +ex_env.o + + + FILE_/export/home/db/examples_c/ex_env.c_tool +C/C++ compiler + + + PROJECT_FILES +/export/home/db/examples_c/ex_env.c + + + userComments +ex_env + + diff --git a/db/build_vxworks/ex_mpool/ex_mpool.wpj b/db/build_vxworks/ex_mpool/ex_mpool.wpj new file mode 100644 index 000000000..6dd9ed4db --- /dev/null +++ b/db/build_vxworks/ex_mpool/ex_mpool.wpj @@ -0,0 +1,248 @@ +Document file - DO NOT EDIT + + BUILD_PENTIUMgnu_MACRO_AR +ar386 + + + BUILD_PENTIUMgnu_MACRO_ARCHIVE +$(PRJ_DIR)/PENTIUMgnu/ex_mpool.a + + + BUILD_PENTIUMgnu_MACRO_AS +cc386 + + + BUILD_PENTIUMgnu_MACRO_CC +cc386 + + + BUILD_PENTIUMgnu_MACRO_CFLAGS +-g \ + -mpentium \ + -ansi \ + -nostdinc \ + -DRW_MULTI_THREAD \ + -D_REENTRANT \ + -fvolatile \ + -nostdlib \ + -fno-builtin \ + -fno-defer-pop \ + -I. \ + -I$(WIND_BASE)/target/h \ + -DCPU=PENTIUM \ + -I/export/home/db/build_vxworks + + + BUILD_PENTIUMgnu_MACRO_CFLAGS_AS +-g \ + -mpentium \ + -ansi \ + -nostdinc \ + -fvolatile \ + -nostdlib \ + -fno-builtin \ + -fno-defer-pop \ + -P \ + -x \ + assembler-with-cpp \ + -I. \ + -I$(WIND_BASE)/target/h \ + -DCPU=PENTIUM + + + BUILD_PENTIUMgnu_MACRO_CPP +cc386 -E -P -xc + + + BUILD_PENTIUMgnu_MACRO_LD +ld386 + + + BUILD_PENTIUMgnu_MACRO_LDFLAGS +-X -N + + + BUILD_PENTIUMgnu_MACRO_LD_PARTIAL_FLAGS +-X -r + + + BUILD_PENTIUMgnu_MACRO_NM +nm386 -g + + + BUILD_PENTIUMgnu_MACRO_OPTION_DEFINE_MACRO +-D + + + BUILD_PENTIUMgnu_MACRO_OPTION_INCLUDE_DIR +-I + + + BUILD_PENTIUMgnu_MACRO_SIZE +size386 + + + BUILD_PENTIUMgnu_RO_DEPEND_PATH +{$(WIND_BASE)/target/h/} \ + {$(WIND_BASE)/target/src/} \ + {$(WIND_BASE)/target/config/} + + + BUILD_PENTIUMgnu_TC +::tc_PENTIUMgnu + + + BUILD_RULE_archive + + + + BUILD_RULE_ex_mpool.out + + + + BUILD_RULE_objects + + + + BUILD_SIMSPARCSOLARISgnu_BUILDRULE +ex_mpool.out + + + BUILD_SIMSPARCSOLARISgnu_MACRO_AR +arsimso + + + BUILD_SIMSPARCSOLARISgnu_MACRO_ARCHIVE +$(PRJ_DIR)/SIMSPARCSOLARISgnu/ex_mpool.a + + + BUILD_SIMSPARCSOLARISgnu_MACRO_AS +ccsimso + + + BUILD_SIMSPARCSOLARISgnu_MACRO_CC +ccsimso + + + BUILD_SIMSPARCSOLARISgnu_MACRO_CFLAGS +-g \ + -ansi \ + -nostdinc \ + -DRW_MULTI_THREAD \ + -D_REENTRANT \ + -fvolatile \ + -fno-builtin \ + -I/export/home/db/build_vxworks \ + -I. \ + -I$(WIND_BASE)/target/h \ + -DCPU=SIMSPARCSOLARIS + + + BUILD_SIMSPARCSOLARISgnu_MACRO_CFLAGS_AS +-g \ + -ansi \ + -nostdinc \ + -fvolatile \ + -fno-builtin \ + -P \ + -x \ + assembler-with-cpp \ + -I. \ + -I$(WIND_BASE)/target/h \ + -DCPU=SIMSPARCSOLARIS + + + BUILD_SIMSPARCSOLARISgnu_MACRO_CPP +ccsimso -E -P -xc + + + BUILD_SIMSPARCSOLARISgnu_MACRO_LD +ccsimso + + + BUILD_SIMSPARCSOLARISgnu_MACRO_LDDEPS + + + + BUILD_SIMSPARCSOLARISgnu_MACRO_LDFLAGS +-N + + + BUILD_SIMSPARCSOLARISgnu_MACRO_LD_PARTIAL_FLAGS +-nostdlib -r + + + BUILD_SIMSPARCSOLARISgnu_MACRO_NM +nmsimso + + + BUILD_SIMSPARCSOLARISgnu_MACRO_OPTION_DEFINE_MACRO +-D + + + BUILD_SIMSPARCSOLARISgnu_MACRO_OPTION_INCLUDE_DIR +-I + + + BUILD_SIMSPARCSOLARISgnu_MACRO_POST_BUILD_RULE + + + + BUILD_SIMSPARCSOLARISgnu_MACRO_PRJ_LIBS + + + + BUILD_SIMSPARCSOLARISgnu_MACRO_SIZE +sizesimso + + + BUILD_SIMSPARCSOLARISgnu_RO_DEPEND_PATH +{$(WIND_BASE)/target/h/} \ + {$(WIND_BASE)/target/src/} \ + {$(WIND_BASE)/target/config/} + + + BUILD_SIMSPARCSOLARISgnu_TC +::tc_SIMSPARCSOLARISgnu + + + BUILD__CURRENT +PENTIUMgnu + + + BUILD__LIST +SIMSPARCSOLARISgnu PENTIUMgnu + + + CORE_INFO_TYPE +::prj_vxApp + + + CORE_INFO_VERSION +2.0 + + + FILE_/export/home/db/examples_c/ex_mpool.c_dependDone +TRUE + + + FILE_/export/home/db/examples_c/ex_mpool.c_dependencies +/export/home/db/build_vxworks/db_config.h /export/home/db/build_vxworks/db.h + + + FILE_/export/home/db/examples_c/ex_mpool.c_objects +ex_mpool.o + + + FILE_/export/home/db/examples_c/ex_mpool.c_tool +C/C++ compiler + + + PROJECT_FILES +/export/home/db/examples_c/ex_mpool.c + + + userComments +ex_mpool + + diff --git a/db/build_vxworks/ex_tpcb/ex_tpcb.wpj b/db/build_vxworks/ex_tpcb/ex_tpcb.wpj new file mode 100644 index 000000000..91de499dc --- /dev/null +++ b/db/build_vxworks/ex_tpcb/ex_tpcb.wpj @@ -0,0 +1,261 @@ +Document file - DO NOT EDIT + + BUILD_PENTIUMgnu_BUILDRULE +ex_tpcb.out + + + BUILD_PENTIUMgnu_MACRO_AR +ar386 + + + BUILD_PENTIUMgnu_MACRO_ARCHIVE +$(PRJ_DIR)/PENTIUMgnu/ex_tpcb.a + + + BUILD_PENTIUMgnu_MACRO_AS +cc386 + + + BUILD_PENTIUMgnu_MACRO_CC +cc386 + + + BUILD_PENTIUMgnu_MACRO_CFLAGS +-g \ + -mpentium \ + -ansi \ + -nostdinc \ + -DRW_MULTI_THREAD \ + -D_REENTRANT \ + -fvolatile \ + -nostdlib \ + -fno-builtin \ + -fno-defer-pop \ + -I. \ + -I$(WIND_BASE)/target/h \ + -DCPU=PENTIUM \ + -I/export/home/db/build_vxworks \ + -DVERY_TINY + + + BUILD_PENTIUMgnu_MACRO_CFLAGS_AS +-g \ + -mpentium \ + -ansi \ + -nostdinc \ + -fvolatile \ + -nostdlib \ + -fno-builtin \ + -fno-defer-pop \ + -P \ + -x \ + assembler-with-cpp \ + -I. \ + -I$(WIND_BASE)/target/h \ + -DCPU=PENTIUM + + + BUILD_PENTIUMgnu_MACRO_CPP +cc386 -E -P -xc + + + BUILD_PENTIUMgnu_MACRO_LD +ld386 + + + BUILD_PENTIUMgnu_MACRO_LDFLAGS +-X -N + + + BUILD_PENTIUMgnu_MACRO_LD_PARTIAL_FLAGS +-X -r + + + BUILD_PENTIUMgnu_MACRO_NM +nm386 -g + + + BUILD_PENTIUMgnu_MACRO_OPTION_DEFINE_MACRO +-D + + + BUILD_PENTIUMgnu_MACRO_OPTION_INCLUDE_DIR +-I + + + BUILD_PENTIUMgnu_MACRO_POST_BUILD_RULE + + + + BUILD_PENTIUMgnu_MACRO_PRJ_LIBS + + + + BUILD_PENTIUMgnu_MACRO_SIZE +size386 + + + BUILD_PENTIUMgnu_RO_DEPEND_PATH +{$(WIND_BASE)/target/h/} \ + {$(WIND_BASE)/target/src/} \ + {$(WIND_BASE)/target/config/} + + + BUILD_PENTIUMgnu_TC +::tc_PENTIUMgnu + + + BUILD_RULE_archive + + + + BUILD_RULE_ex_tpcb.out + + + + BUILD_RULE_objects + + + + BUILD_SIMSPARCSOLARISgnu_BUILDRULE +ex_tpcb.out + + + BUILD_SIMSPARCSOLARISgnu_MACRO_AR +arsimso + + + BUILD_SIMSPARCSOLARISgnu_MACRO_ARCHIVE +$(PRJ_DIR)/SIMSPARCSOLARISgnu/ex_tpcb.a + + + BUILD_SIMSPARCSOLARISgnu_MACRO_AS +ccsimso + + + BUILD_SIMSPARCSOLARISgnu_MACRO_CC +ccsimso + + + BUILD_SIMSPARCSOLARISgnu_MACRO_CFLAGS +-g \ + -ansi \ + -nostdinc \ + -DRW_MULTI_THREAD \ + -D_REENTRANT \ + -fvolatile \ + -fno-builtin \ + -I/export/home/db/build_vxworks \ + -I. \ + -I$(WIND_BASE)/target/h \ + -DCPU=SIMSPARCSOLARIS + + + BUILD_SIMSPARCSOLARISgnu_MACRO_CFLAGS_AS +-g \ + -ansi \ + -nostdinc \ + -fvolatile \ + -fno-builtin \ + -P \ + -x \ + assembler-with-cpp \ + -I. \ + -I$(WIND_BASE)/target/h \ + -DCPU=SIMSPARCSOLARIS + + + BUILD_SIMSPARCSOLARISgnu_MACRO_CPP +ccsimso -E -P -xc + + + BUILD_SIMSPARCSOLARISgnu_MACRO_LD +ccsimso + + + BUILD_SIMSPARCSOLARISgnu_MACRO_LDDEPS + + + + BUILD_SIMSPARCSOLARISgnu_MACRO_LDFLAGS +-N + + + BUILD_SIMSPARCSOLARISgnu_MACRO_LD_PARTIAL_FLAGS +-nostdlib -r + + + BUILD_SIMSPARCSOLARISgnu_MACRO_NM +nmsimso + + + BUILD_SIMSPARCSOLARISgnu_MACRO_OPTION_DEFINE_MACRO +-D + + + BUILD_SIMSPARCSOLARISgnu_MACRO_OPTION_INCLUDE_DIR +-I + + + BUILD_SIMSPARCSOLARISgnu_MACRO_POST_BUILD_RULE + + + + BUILD_SIMSPARCSOLARISgnu_MACRO_PRJ_LIBS + + + + BUILD_SIMSPARCSOLARISgnu_MACRO_SIZE +sizesimso + + + BUILD_SIMSPARCSOLARISgnu_RO_DEPEND_PATH +{$(WIND_BASE)/target/h/} \ + {$(WIND_BASE)/target/src/} \ + {$(WIND_BASE)/target/config/} + + + BUILD_SIMSPARCSOLARISgnu_TC +::tc_SIMSPARCSOLARISgnu + + + BUILD__CURRENT +PENTIUMgnu + + + BUILD__LIST +SIMSPARCSOLARISgnu PENTIUMgnu + + + CORE_INFO_TYPE +::prj_vxApp + + + CORE_INFO_VERSION +2.0 + + + FILE_/export/home/db/examples_c/ex_tpcb.c_dependDone +TRUE + + + FILE_/export/home/db/examples_c/ex_tpcb.c_dependencies +/export/home/db/build_vxworks/db_config.h /export/home/db/build_vxworks/db.h + + + FILE_/export/home/db/examples_c/ex_tpcb.c_objects +ex_tpcb.o + + + FILE_/export/home/db/examples_c/ex_tpcb.c_tool +C/C++ compiler + + + PROJECT_FILES +/export/home/db/examples_c/ex_tpcb.c + + + userComments +ex_tpcb + + diff --git a/db/build_win32/Berkeley_DB.dsw b/db/build_win32/Berkeley_DB.dsw new file mode 100644 index 000000000..50ee205bd --- /dev/null +++ b/db/build_win32/Berkeley_DB.dsw @@ -0,0 +1,569 @@ +Microsoft Developer Studio Workspace File, Format Version 5.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "DB_DLL"=.\db_dll.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "DB_Static"=.\db_static.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "db_archive"=.\db_archive.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name DB_DLL + End Project Dependency + Begin Project Dependency + Project_Dep_Name DB_Static + End Project Dependency +}}} + +############################################################################### + +Project: "db_buildall"=.\db_buildall.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name db_archive + End Project Dependency + Begin Project Dependency + Project_Dep_Name db_checkpoint + End Project Dependency + Begin Project Dependency + Project_Dep_Name db_deadlock + End Project Dependency + Begin Project Dependency + Project_Dep_Name DB_DLL + End Project Dependency + Begin Project Dependency + Project_Dep_Name db_dump + End Project Dependency + Begin Project Dependency + Project_Dep_Name db_load + End Project Dependency + Begin Project Dependency + Project_Dep_Name db_printlog + End Project Dependency + Begin Project Dependency + Project_Dep_Name db_recover + End Project Dependency + Begin Project Dependency + Project_Dep_Name db_stat + End Project Dependency + Begin Project Dependency + Project_Dep_Name db_upgrade + End Project Dependency + Begin Project Dependency + Project_Dep_Name db_verify + End Project Dependency + Begin Project Dependency + Project_Dep_Name DB_Static + End Project Dependency + Begin Project Dependency + Project_Dep_Name ex_access + End Project Dependency + Begin Project Dependency + Project_Dep_Name ex_btrec + End Project Dependency + Begin Project Dependency + Project_Dep_Name ex_env + End Project Dependency + Begin Project Dependency + Project_Dep_Name ex_lock + End Project Dependency + Begin Project Dependency + Project_Dep_Name ex_mpool + End Project Dependency + Begin Project Dependency + Project_Dep_Name ex_tpcb + End Project Dependency + Begin Project Dependency + Project_Dep_Name excxx_access + End Project Dependency + Begin Project Dependency + Project_Dep_Name excxx_btrec + End Project Dependency + Begin Project Dependency + Project_Dep_Name excxx_env + End Project Dependency + Begin Project Dependency + Project_Dep_Name excxx_lock + End Project Dependency + Begin Project Dependency + Project_Dep_Name excxx_mpool + End Project Dependency + Begin Project Dependency + Project_Dep_Name excxx_tpcb + End Project Dependency +}}} + +############################################################################### + +Project: "db_checkpoint"=.\db_checkpoint.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name DB_DLL + End Project Dependency + Begin Project Dependency + Project_Dep_Name DB_Static + End Project Dependency +}}} + +############################################################################### + +Project: "db_deadlock"=.\db_deadlock.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name DB_DLL + End Project Dependency + Begin Project Dependency + Project_Dep_Name DB_Static + End Project Dependency +}}} + +############################################################################### + +Project: "db_dump"=.\db_dump.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name DB_DLL + End Project Dependency + Begin Project Dependency + Project_Dep_Name DB_Static + End Project Dependency +}}} + +############################################################################### + +Project: "db_java"=.\db_java.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name DB_DLL + End Project Dependency +}}} + +############################################################################### + +Project: "db_load"=.\db_load.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name DB_DLL + End Project Dependency + Begin Project Dependency + Project_Dep_Name DB_Static + End Project Dependency +}}} + +############################################################################### + +Project: "db_printlog"=.\db_printlog.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name DB_DLL + End Project Dependency + Begin Project Dependency + Project_Dep_Name DB_Static + End Project Dependency +}}} + +############################################################################### + +Project: "db_recover"=.\db_recover.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name DB_DLL + End Project Dependency + Begin Project Dependency + Project_Dep_Name DB_Static + End Project Dependency +}}} + +############################################################################### + +Project: "db_stat"=.\db_stat.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name DB_DLL + End Project Dependency + Begin Project Dependency + Project_Dep_Name DB_Static + End Project Dependency +}}} + +############################################################################### + +Project: "db_tcl"=.\db_tcl.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name DB_DLL + End Project Dependency +}}} + +############################################################################### + +Project: "db_test"=.\db_test.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name db_buildall + End Project Dependency + Begin Project Dependency + Project_Dep_Name db_tcl + End Project Dependency +}}} + +############################################################################### + +Project: "db_upgrade"=.\db_upgrade.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name DB_DLL + End Project Dependency + Begin Project Dependency + Project_Dep_Name DB_Static + End Project Dependency +}}} + +############################################################################### + +Project: "db_verify"=.\db_verify.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name DB_DLL + End Project Dependency + Begin Project Dependency + Project_Dep_Name DB_Static + End Project Dependency +}}} + +############################################################################### + +Project: "ex_access"=.\ex_access.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name DB_DLL + End Project Dependency + Begin Project Dependency + Project_Dep_Name DB_Static + End Project Dependency +}}} + +############################################################################### + +Project: "ex_btrec"=.\ex_btrec.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name DB_Static + End Project Dependency + Begin Project Dependency + Project_Dep_Name DB_DLL + End Project Dependency +}}} + +############################################################################### + +Project: "ex_env"=.\ex_env.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name DB_DLL + End Project Dependency + Begin Project Dependency + Project_Dep_Name DB_Static + End Project Dependency +}}} + +############################################################################### + +Project: "ex_lock"=.\ex_lock.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name DB_DLL + End Project Dependency + Begin Project Dependency + Project_Dep_Name DB_Static + End Project Dependency +}}} + +############################################################################### + +Project: "ex_mpool"=.\ex_mpool.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name DB_DLL + End Project Dependency + Begin Project Dependency + Project_Dep_Name DB_Static + End Project Dependency +}}} + +############################################################################### + +Project: "ex_tpcb"=.\ex_tpcb.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name DB_DLL + End Project Dependency + Begin Project Dependency + Project_Dep_Name DB_Static + End Project Dependency +}}} + +############################################################################### + +Project: "excxx_access"=.\excxx_access.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name DB_DLL + End Project Dependency + Begin Project Dependency + Project_Dep_Name DB_Static + End Project Dependency +}}} + +############################################################################### + +Project: "excxx_btrec"=.\excxx_btrec.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name DB_DLL + End Project Dependency + Begin Project Dependency + Project_Dep_Name DB_Static + End Project Dependency +}}} + +############################################################################### + +Project: "excxx_env"=.\excxx_env.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name DB_DLL + End Project Dependency + Begin Project Dependency + Project_Dep_Name DB_Static + End Project Dependency +}}} + +############################################################################### + +Project: "excxx_lock"=.\excxx_lock.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name DB_DLL + End Project Dependency + Begin Project Dependency + Project_Dep_Name DB_Static + End Project Dependency +}}} + +############################################################################### + +Project: "excxx_mpool"=.\excxx_mpool.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name DB_DLL + End Project Dependency + Begin Project Dependency + Project_Dep_Name DB_Static + End Project Dependency +}}} + +############################################################################### + +Project: "excxx_tpcb"=.\excxx_tpcb.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name DB_DLL + End Project Dependency + Begin Project Dependency + Project_Dep_Name DB_Static + End Project Dependency +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/db/build_win32/app_dsp.src b/db/build_win32/app_dsp.src new file mode 100644 index 000000000..79c4ce785 --- /dev/null +++ b/db/build_win32/app_dsp.src @@ -0,0 +1,148 @@ +# Microsoft Developer Studio Project File - Name="@project_name@" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=@project_name@ - Win32 Debug Static +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "@project_name@.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "@project_name@.mak" CFG="@project_name@ - Win32 Debug Static" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "@project_name@ - Win32 Release" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "@project_name@ - Win32 Debug" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "@project_name@ - Win32 Release Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "@project_name@ - Win32 Debug Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "@project_name@ - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release/libdb@DB_VERSION_MAJOR@@DB_VERSION_MINOR@.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"libcmt" + +!ELSEIF "$(CFG)" == "@project_name@ - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 Debug/libdb@DB_VERSION_MAJOR@@DB_VERSION_MINOR@d.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /nodefaultlib:"libcmtd" /fixed:no + +!ELSEIF "$(CFG)" == "@project_name@ - Win32 Release Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release_static" +# PROP Intermediate_Dir "Release_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Release_static/libdb@DB_VERSION_MAJOR@@DB_VERSION_MINOR@.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release_static/libdb@DB_VERSION_MAJOR@@DB_VERSION_MINOR@s.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "@project_name@ - Win32 Debug Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_static" +# PROP Intermediate_Dir "Debug_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Debug_static/libdb@DB_VERSION_MAJOR@@DB_VERSION_MINOR@d.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no +# ADD LINK32 Debug_static/libdb@DB_VERSION_MAJOR@@DB_VERSION_MINOR@sd.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no + +!ENDIF + +# Begin Target + +# Name "@project_name@ - Win32 Release" +# Name "@project_name@ - Win32 Debug" +# Name "@project_name@ - Win32 Release Static" +# Name "@project_name@ - Win32 Debug Static" +@SOURCE_FILES@ +# Begin Source File + +SOURCE=..\clib\getopt.c +# End Source File +# End Target +# End Project diff --git a/db/build_win32/db.h b/db/build_win32/db.h new file mode 100644 index 000000000..4a7393d4f --- /dev/null +++ b/db/build_win32/db.h @@ -0,0 +1,1378 @@ +/* DO NOT EDIT: automatically built by dist/s_win32. */ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: db.src,v 11.121 2001/01/10 15:43:08 sue Exp $ + */ + +#ifndef _DB_H_ +#define _DB_H_ + +#ifndef __NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +/* + * XXX + * Handle function prototypes and the keyword "const". This steps on name + * space that DB doesn't control, but all of the other solutions are worse. + * + * XXX + * While Microsoft's compiler is ANSI C compliant, it doesn't have _STDC_ + * defined by default, you specify a command line flag or #pragma to turn + * it on. Don't do that, however, because some of Microsoft's own header + * files won't compile. + */ +#undef __P +#if defined(__STDC__) || defined(__cplusplus) || defined(_MSC_VER) +#define __P(protos) protos /* ANSI C prototypes */ +#else +#define const +#define __P(protos) () /* K&R C preprocessor */ +#endif + +/* + * !!! + * DB needs basic information about specifically sized types. If they're + * not provided by the system, typedef them here. + * + * We protect them against multiple inclusion using __BIT_TYPES_DEFINED__, + * as does BIND and Kerberos, since we don't know for sure what #include + * files the user is using. + * + * !!! + * We also provide the standard u_int, u_long etc., if they're not provided + * by the system. + */ +#ifndef __BIT_TYPES_DEFINED__ +#define __BIT_TYPES_DEFINED__ +typedef unsigned char u_int8_t; +typedef short int16_t; +typedef unsigned short u_int16_t; +typedef int int32_t; +typedef unsigned int u_int32_t; +#endif + +#if !defined(_WINSOCKAPI_) +typedef unsigned char u_char; +typedef unsigned short u_short; +typedef unsigned int u_int; +typedef unsigned long u_long; +#endif +typedef int ssize_t; + +#define DB_VERSION_MAJOR 3 +#define DB_VERSION_MINOR 2 +#define DB_VERSION_PATCH 9 +#define DB_VERSION_STRING "Sleepycat Software: Berkeley DB 3.2.9: (January 24, 2001)" + +typedef u_int32_t db_pgno_t; /* Page number type. */ +typedef u_int16_t db_indx_t; /* Page offset type. */ +#define DB_MAX_PAGES 0xffffffff /* >= # of pages in a file */ + +typedef u_int32_t db_recno_t; /* Record number type. */ +#define DB_MAX_RECORDS 0xffffffff /* >= # of records in a tree */ + +/* Forward structure declarations, so applications get type checking. */ +struct __db; typedef struct __db DB; +#ifdef DB_DBM_HSEARCH + typedef struct __db DBM; +#endif +struct __db_bt_stat; typedef struct __db_bt_stat DB_BTREE_STAT; +struct __db_dbt; typedef struct __db_dbt DBT; +struct __db_env; typedef struct __db_env DB_ENV; +struct __db_h_stat; typedef struct __db_h_stat DB_HASH_STAT; +struct __db_ilock; typedef struct __db_ilock DB_LOCK_ILOCK; +struct __db_lock_stat; typedef struct __db_lock_stat DB_LOCK_STAT; +struct __db_lock_u; typedef struct __db_lock_u DB_LOCK; +struct __db_lockreq; typedef struct __db_lockreq DB_LOCKREQ; +struct __db_log_stat; typedef struct __db_log_stat DB_LOG_STAT; +struct __db_lsn; typedef struct __db_lsn DB_LSN; +struct __db_mpool_finfo;typedef struct __db_mpool_finfo DB_MPOOL_FINFO; +struct __db_mpool_fstat;typedef struct __db_mpool_fstat DB_MPOOL_FSTAT; +struct __db_mpool_stat; typedef struct __db_mpool_stat DB_MPOOL_STAT; +struct __db_mpoolfile; typedef struct __db_mpoolfile DB_MPOOLFILE; +struct __db_qam_stat; typedef struct __db_qam_stat DB_QUEUE_STAT; +struct __db_txn; typedef struct __db_txn DB_TXN; +struct __db_txn_active; typedef struct __db_txn_active DB_TXN_ACTIVE; +struct __db_txn_stat; typedef struct __db_txn_stat DB_TXN_STAT; +struct __dbc; typedef struct __dbc DBC; +struct __dbc_internal; typedef struct __dbc_internal DBC_INTERNAL; +struct __fh_t; typedef struct __fh_t DB_FH; +struct __key_range; typedef struct __key_range DB_KEY_RANGE; + +/* Key/data structure -- a Data-Base Thang. */ +struct __db_dbt { + /* + * data/size must be fields 1 and 2 for DB 1.85 compatibility. + */ + void *data; /* Key/data */ + u_int32_t size; /* key/data length */ + + u_int32_t ulen; /* RO: length of user buffer. */ + u_int32_t dlen; /* RO: get/put record length. */ + u_int32_t doff; /* RO: get/put record offset. */ + +#define DB_DBT_ISSET 0x001 /* Lower level calls set value. */ +#define DB_DBT_MALLOC 0x002 /* Return in malloc'd memory. */ +#define DB_DBT_PARTIAL 0x004 /* Partial put/get. */ +#define DB_DBT_REALLOC 0x008 /* Return in realloc'd memory. */ +#define DB_DBT_USERMEM 0x010 /* Return in user's memory. */ +#define DB_DBT_DUPOK 0x020 /* Insert if duplicate. */ + u_int32_t flags; +}; + +/* + * Common flags -- + * Interfaces which use any of these common flags should never have + * interface specific flags in this range. + */ +#define DB_CREATE 0x000001 /* Create file as necessary. */ +#define DB_CXX_NO_EXCEPTIONS 0x000002 /* C++: return error values. */ +#define DB_FORCE 0x000004 /* Force (anything). */ +#define DB_NOMMAP 0x000008 /* Don't mmap underlying file. */ +#define DB_RDONLY 0x000010 /* Read-only (O_RDONLY). */ +#define DB_RECOVER 0x000020 /* Run normal recovery. */ +#define DB_THREAD 0x000040 /* Applications are threaded. */ +#define DB_TXN_NOSYNC 0x000080 /* Do not sync log on commit. */ +#define DB_USE_ENVIRON 0x000100 /* Use the environment. */ +#define DB_USE_ENVIRON_ROOT 0x000200 /* Use the environment if root. */ + +/* + * Flags private to db_env_create. + */ +#define DB_CLIENT 0x000400 /* Open for a client environment. */ + +/* + * Flags private to db_create. + */ +#define DB_XA_CREATE 0x000400 /* Open in an XA environment. */ + +/* + * Flags private to DBENV->open. + */ +#define DB_INIT_CDB 0x000400 /* Concurrent Access Methods. */ +#define DB_INIT_LOCK 0x000800 /* Initialize locking. */ +#define DB_INIT_LOG 0x001000 /* Initialize logging. */ +#define DB_INIT_MPOOL 0x002000 /* Initialize mpool. */ +#define DB_INIT_TXN 0x004000 /* Initialize transactions. */ +#define DB_JOINENV 0x008000 /* Initialize all subsystems present. */ +#define DB_LOCKDOWN 0x010000 /* Lock memory into physical core. */ +#define DB_PRIVATE 0x020000 /* DB_ENV is process local. */ +#define DB_RECOVER_FATAL 0x040000 /* Run catastrophic recovery. */ +#define DB_SYSTEM_MEM 0x080000 /* Use system-backed memory. */ + +/* + * Flags private to DB->open. + */ +#define DB_EXCL 0x000400 /* Exclusive open (O_EXCL). */ +#define DB_FCNTL_LOCKING 0x000800 /* UNDOC: fcntl(2) locking. */ +#define DB_ODDFILESIZE 0x001000 /* UNDOC: truncate to N * pgsize. */ +#define DB_RDWRMASTER 0x002000 /* UNDOC: allow subdb master open R/W */ +#define DB_TRUNCATE 0x004000 /* Discard existing DB (O_TRUNC). */ +#define DB_EXTENT 0x008000 /* UNDOC: dealing with an extent. */ + +/* + * Flags private to DBENV->txn_begin. + */ +#define DB_TXN_NOWAIT 0x000400 /* Do not wait for locks in this TXN. */ +#define DB_TXN_SYNC 0x000800 /* Always sync log on commit. */ + +/* + * Flags private to DBENV->set_flags. + */ +#define DB_CDB_ALLDB 0x000400 /* In CDB, lock across environment. */ + +/* + * Flags private to DB->set_feedback's callback. + */ +#define DB_UPGRADE 0x000400 /* Upgrading. */ +#define DB_VERIFY 0x000800 /* Verifying. */ + +/* + * Flags private to DB->set_flags. + * + * DB->set_flags does not share common flags and so values start at 0x01. + */ +#define DB_DUP 0x0001 /* Btree, Hash: duplicate keys. */ +#define DB_DUPSORT 0x0002 /* Btree, Hash: duplicate keys. */ +#define DB_RECNUM 0x0004 /* Btree: record numbers. */ +#define DB_RENUMBER 0x0008 /* Recno: renumber on insert/delete. */ +#define DB_REVSPLITOFF 0x0010 /* Btree: turn off reverse splits. */ +#define DB_SNAPSHOT 0x0020 /* Recno: snapshot the input. */ + +/* + * Flags private to DB->join. + * + * DB->join does not share common flags and so values start at 0x01. + */ +#define DB_JOIN_NOSORT 0x0001 /* Don't try to optimize join. */ + +/* + * Flags private to DB->verify. + * + * DB->verify does not share common flags and so values start at 0x01. + */ +#define DB_AGGRESSIVE 0x0001 /* Salvage anything which might be data.*/ +#define DB_NOORDERCHK 0x0002 /* Skip order check; subdb w/ user func */ +#define DB_ORDERCHKONLY 0x0004 /* Only perform an order check on subdb */ +#define DB_PR_PAGE 0x0008 /* Show page contents (-da). */ +#define DB_PR_HEADERS 0x0010 /* Show only page headers (-dh). */ +#define DB_PR_RECOVERYTEST 0x0020 /* Recovery test (-dr). */ +#define DB_SALVAGE 0x0040 /* Salvage what looks like data. */ +/* + * !!! + * These must not go over 0x8000, or they will collide with the flags + * used by __bam_vrfy_subtree. + */ +#define DB_VRFY_FLAGMASK 0xffff /* For masking above flags. */ + +/* + * Deadlock detector modes; used in the DBENV structure to configure the + * locking subsystem. + */ +#define DB_LOCK_NORUN 0 +#define DB_LOCK_DEFAULT 1 /* Default policy. */ +#define DB_LOCK_OLDEST 2 /* Abort oldest transaction. */ +#define DB_LOCK_RANDOM 3 /* Abort random transaction. */ +#define DB_LOCK_YOUNGEST 4 /* Abort youngest transaction. */ + +/******************************************************* + * Environment. + *******************************************************/ +#define DB_REGION_MAGIC 0x120897 /* Environment magic number. */ + +typedef enum { + DB_TXN_ABORT, + DB_TXN_BACKWARD_ROLL, + DB_TXN_FORWARD_ROLL, + DB_TXN_OPENFILES +} db_recops; + +#define DB_UNDO(op) ((op) == DB_TXN_ABORT || (op) == DB_TXN_BACKWARD_ROLL) +#define DB_REDO(op) ((op) == DB_TXN_FORWARD_ROLL) + +struct __db_env { + /******************************************************* + * Public: owned by the application. + *******************************************************/ + FILE *db_errfile; /* Error message file stream. */ + const char *db_errpfx; /* Error message prefix. */ + /* Callbacks. */ + void (*db_errcall) __P((const char *, char *)); + void (*db_feedback) __P((DB_ENV *, int, int)); + void (*db_paniccall) __P((DB_ENV *, int)); + int (*db_recovery_init) __P((DB_ENV *)); + + /* + * Currently, the verbose list is a bit field with room for 32 + * entries. There's no reason that it needs to be limited, if + * there are ever more than 32 entries, convert to a bit array. + */ +#define DB_VERB_CHKPOINT 0x0001 /* List checkpoints. */ +#define DB_VERB_DEADLOCK 0x0002 /* Deadlock detection information. */ +#define DB_VERB_RECOVERY 0x0004 /* Recovery information. */ +#define DB_VERB_WAITSFOR 0x0008 /* Dump waits-for table. */ + u_int32_t verbose; /* Verbose output. */ + + void *app_private; /* Application-private handle. */ + + /* Locking. */ + u_int8_t *lk_conflicts; /* Two dimensional conflict matrix. */ + u_int32_t lk_modes; /* Number of lock modes in table. */ + u_int32_t lk_max; /* Maximum number of locks. */ + u_int32_t lk_max_lockers;/* Maximum number of lockers. */ + u_int32_t lk_max_objects;/* Maximum number of locked objects. */ + u_int32_t lk_detect; /* Deadlock detect on all conflicts. */ + + /* Logging. */ + u_int32_t lg_bsize; /* Buffer size. */ + u_int32_t lg_max; /* Maximum file size. */ + + /* Memory pool. */ + u_int32_t mp_gbytes; /* Cachesize: GB. */ + u_int32_t mp_bytes; /* Cachesize: Bytes. */ + size_t mp_size; /* DEPRECATED: Cachesize: bytes. */ + int mp_ncache; /* Number of cache regions. */ + size_t mp_mmapsize; /* Maximum file size for mmap. */ + + /* Transactions. */ + u_int32_t tx_max; /* Maximum number of transactions. */ + time_t tx_timestamp; /* Recover to specific timestamp. */ + int (*tx_recover) /* Dispatch function for recovery. */ + __P((DB_ENV *, DBT *, DB_LSN *, db_recops)); + + /******************************************************* + * Private: owned by DB. + *******************************************************/ + int db_panic; /* Panic causing errno. */ + + /* User files, paths. */ + char *db_home; /* Database home. */ + char *db_log_dir; /* Database log file directory. */ + char *db_tmp_dir; /* Database tmp file directory. */ + + char **db_data_dir; /* Database data file directories. */ + int data_cnt; /* Database data file slots. */ + int data_next; /* Next Database data file slot. */ + + int db_mode; /* Default open permissions. */ + + void *reginfo; /* REGINFO structure reference. */ + DB_FH *lockfhp; /* fcntl(2) locking file handle. */ + long shm_key; /* shmget(2) key. */ + + void *lg_handle; /* Log handle. */ + + void *lk_handle; /* Lock handle. */ + + void *mp_handle; /* Mpool handle. */ + + void *tx_handle; /* Txn handle. */ + + int (**dtab) /* Dispatch table */ + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + size_t dtab_size; /* Slots in the dispatch table. */ + + void *cl_handle; /* RPC: remote client handle. */ + long cl_id; /* RPC: Remote client env id. */ + + int dblocal_ref; /* DB_ENV_DBLOCAL: reference count. */ + u_int32_t db_mutexlocks; /* db_set_mutexlocks */ + + /* + * List of open DB handles for this DB_ENV, used for cursor + * adjustment. Must be protected for multi-threaded support. + * + * !!! + * As this structure is allocated in per-process memory, the + * mutex may need to be stored elsewhere on architectures unable + * to support mutexes in heap memory, e.g. HP/UX 9. + */ + void *dblist_mutexp; /* Mutex. */ + /* + * !!! + * Explicit representation of structure in queue.h. + * LIST_HEAD(dblist, __db); + */ + struct { + struct __db *lh_first; + } dblist; + + /* + * XA support. + * + * !!! + * Explicit representations of structures in queue.h. + * + * TAILQ_ENTRY(__db_env); + */ + struct { + struct __db_env *tqe_next; + struct __db_env **tqe_prev; + } links; + int xa_rmid; /* XA Resource Manager ID. */ + DB_TXN *xa_txn; /* XA Current transaction. */ + + void *cj_internal; /* C++/Java private. */ + + /* Methods. */ + int (*close) __P((DB_ENV *, u_int32_t)); + void (*err) __P((const DB_ENV *, int, const char *, ...)); + void (*errx) __P((const DB_ENV *, const char *, ...)); + int (*open) __P((DB_ENV *, const char *, u_int32_t, int)); + int (*remove) __P((DB_ENV *, const char *, u_int32_t)); + int (*set_data_dir) __P((DB_ENV *, const char *)); + void (*set_errcall) __P((DB_ENV *, void (*)(const char *, char *))); + void (*set_errfile) __P((DB_ENV *, FILE *)); + void (*set_errpfx) __P((DB_ENV *, const char *)); + int (*set_feedback) __P((DB_ENV *, void (*)(DB_ENV *, int, int))); + int (*set_flags) __P((DB_ENV *, u_int32_t, int)); + int (*set_mutexlocks) __P((DB_ENV *, int)); + int (*set_paniccall) __P((DB_ENV *, void (*)(DB_ENV *, int))); + int (*set_recovery_init) __P((DB_ENV *, int (*)(DB_ENV *))); + int (*set_server) __P((DB_ENV *, char *, long, long, u_int32_t)); + int (*set_shm_key) __P((DB_ENV *, long)); + int (*set_tmp_dir) __P((DB_ENV *, const char *)); + int (*set_verbose) __P((DB_ENV *, u_int32_t, int)); + + int (*set_lg_bsize) __P((DB_ENV *, u_int32_t)); + int (*set_lg_dir) __P((DB_ENV *, const char *)); + int (*set_lg_max) __P((DB_ENV *, u_int32_t)); + + int (*set_lk_conflicts) __P((DB_ENV *, u_int8_t *, int)); + int (*set_lk_detect) __P((DB_ENV *, u_int32_t)); + int (*set_lk_max) __P((DB_ENV *, u_int32_t)); + int (*set_lk_max_locks) __P((DB_ENV *, u_int32_t)); + int (*set_lk_max_lockers) __P((DB_ENV *, u_int32_t)); + int (*set_lk_max_objects) __P((DB_ENV *, u_int32_t)); + + int (*set_mp_mmapsize) __P((DB_ENV *, size_t)); + int (*set_cachesize) __P((DB_ENV *, u_int32_t, u_int32_t, int)); + + int (*set_tx_max) __P((DB_ENV *, u_int32_t)); + int (*set_tx_recover) __P((DB_ENV *, + int (*)(DB_ENV *, DBT *, DB_LSN *, db_recops))); + int (*set_tx_timestamp) __P((DB_ENV *, time_t *)); + +#ifdef CONFIG_TEST +#define DB_TEST_PREOPEN 1 /* before __os_open */ +#define DB_TEST_POSTOPEN 2 /* after __os_open */ +#define DB_TEST_POSTLOGMETA 3 /* after logging meta in btree */ +#define DB_TEST_POSTLOG 4 /* after logging all pages */ +#define DB_TEST_POSTSYNC 5 /* after syncing the log */ +#define DB_TEST_PRERENAME 6 /* before __os_rename */ +#define DB_TEST_POSTRENAME 7 /* after __os_rename */ + int test_abort; /* Abort value for testing. */ + int test_copy; /* Copy value for testing. */ +#endif + +#define DB_ENV_CDB 0x00001 /* DB_INIT_CDB. */ +#define DB_ENV_CDB_ALLDB 0x00002 /* CDB environment wide locking. */ +#define DB_ENV_CREATE 0x00004 /* DB_CREATE set. */ +#define DB_ENV_DBLOCAL 0x00008 /* DB_ENV allocated for private DB. */ +#define DB_ENV_LOCKDOWN 0x00010 /* DB_LOCKDOWN set. */ +#define DB_ENV_NOMMAP 0x00020 /* DB_NOMMAP set. */ +#define DB_ENV_OPEN_CALLED 0x00040 /* DBENV->open called (paths valid). */ +#define DB_ENV_PRIVATE 0x00080 /* DB_PRIVATE set. */ +#define DB_ENV_RPCCLIENT 0x00100 /* DB_CLIENT set. */ +#define DB_ENV_STANDALONE 0x00200 /* Test: freestanding environment. */ +#define DB_ENV_SYSTEM_MEM 0x00400 /* DB_SYSTEM_MEM set. */ +#define DB_ENV_THREAD 0x00800 /* DB_THREAD set. */ +#define DB_ENV_TXN_NOSYNC 0x01000 /* DB_TXN_NOSYNC set. */ +#define DB_ENV_USER_ALLOC 0x02000 /* User allocated the structure. */ + u_int32_t flags; /* Flags. */ +}; + +/******************************************************* + * Access methods. + *******************************************************/ +/* + * !!! + * Changes here must be reflected in java/src/com/sleepycat/db/Db.java. + */ +typedef enum { + DB_BTREE=1, + DB_HASH, + DB_RECNO, + DB_QUEUE, + DB_UNKNOWN /* Figure it out on open. */ +} DBTYPE; + +#define DB_BTREEVERSION 8 /* Current btree version. */ +#define DB_BTREEOLDVER 6 /* Oldest btree version supported. */ +#define DB_BTREEMAGIC 0x053162 + +#define DB_HASHVERSION 7 /* Current hash version. */ +#define DB_HASHOLDVER 4 /* Oldest hash version supported. */ +#define DB_HASHMAGIC 0x061561 + +#define DB_QAMVERSION 3 /* Current queue version. */ +#define DB_QAMOLDVER 1 /* Oldest queue version supported. */ +#define DB_QAMMAGIC 0x042253 + +#define DB_LOGVERSION 3 /* Current log version. */ +#define DB_LOGOLDVER 3 /* Oldest log version supported. */ +#define DB_LOGMAGIC 0x040988 + +/* + * DB access method and cursor operation values. Each value is an operation + * code to which additional bit flags are added. + */ +#define DB_AFTER 1 /* c_put() */ +#define DB_APPEND 2 /* put() */ +#define DB_BEFORE 3 /* c_put() */ +#define DB_CACHED_COUNTS 4 /* stat() */ +#define DB_CHECKPOINT 5 /* log_put(), log_get() */ +#define DB_CONSUME 6 /* get() */ +#define DB_CONSUME_WAIT 7 /* get() */ +#define DB_CURLSN 8 /* log_put() */ +#define DB_CURRENT 9 /* c_get(), c_put(), log_get() */ +#define DB_FIRST 10 /* c_get(), log_get() */ +#define DB_FLUSH 11 /* log_put() */ +#define DB_GET_BOTH 12 /* get(), c_get() */ +#define DB_GET_BOTHC 13 /* c_get() (internal) */ +#define DB_GET_RECNO 14 /* c_get() */ +#define DB_JOIN_ITEM 15 /* c_get(); do not do primary lookup */ +#define DB_KEYFIRST 16 /* c_put() */ +#define DB_KEYLAST 17 /* c_put() */ +#define DB_LAST 18 /* c_get(), log_get() */ +#define DB_NEXT 19 /* c_get(), log_get() */ +#define DB_NEXT_DUP 20 /* c_get() */ +#define DB_NEXT_NODUP 21 /* c_get() */ +#define DB_NODUPDATA 22 /* put(), c_put() */ +#define DB_NOOVERWRITE 23 /* put() */ +#define DB_NOSYNC 24 /* close() */ +#define DB_POSITION 25 /* c_dup() */ +#define DB_POSITIONI 26 /* c_dup() (internal) */ +#define DB_PREV 27 /* c_get(), log_get() */ +#define DB_PREV_NODUP 28 /* c_get(), log_get() */ +#define DB_RECORDCOUNT 29 /* stat() */ +#define DB_SET 30 /* c_get(), log_get() */ +#define DB_SET_RANGE 31 /* c_get() */ +#define DB_SET_RECNO 32 /* get(), c_get() */ +#define DB_WRITECURSOR 33 /* cursor() */ +#define DB_WRITELOCK 34 /* cursor() (internal) */ + +/* This has to change when the max opcode hits 255. */ +#define DB_OPFLAGS_MASK 0x000000ff /* Mask for operations flags. */ +#define DB_RMW 0x80000000 /* Acquire write flag immediately. */ + +/* + * DB (user visible) error return codes. + * + * !!! + * Changes to any of the user visible error return codes must be reflected + * in java/src/com/sleepycat/db/Db.java. + * + * !!! + * For source compatibility with DB 2.X deadlock return (EAGAIN), use the + * following: + * #include + * #define DB_LOCK_DEADLOCK EAGAIN + * + * !!! + * We don't want our error returns to conflict with other packages where + * possible, so pick a base error value that's hopefully not common. We + * document that we own the error name space from -30,800 to -30,999. + */ +/* Public error return codes. */ +#define DB_INCOMPLETE (-30999)/* Sync didn't finish. */ +#define DB_KEYEMPTY (-30998)/* Key/data deleted or never created. */ +#define DB_KEYEXIST (-30997)/* The key/data pair already exists. */ +#define DB_LOCK_DEADLOCK (-30996)/* Deadlock. */ +#define DB_LOCK_NOTGRANTED (-30995)/* Lock unavailable. */ +#define DB_NOSERVER (-30994)/* Server panic return. */ +#define DB_NOSERVER_HOME (-30993)/* Bad home sent to server. */ +#define DB_NOSERVER_ID (-30992)/* Bad ID sent to server. */ +#define DB_NOTFOUND (-30991)/* Key/data pair not found (EOF). */ +#define DB_OLD_VERSION (-30990)/* Out-of-date version. */ +#define DB_RUNRECOVERY (-30989)/* Panic return. */ +#define DB_VERIFY_BAD (-30988)/* Verify failed; bad format. */ + +/* DB (private) error return codes. */ +#define DB_ALREADY_ABORTED (-30899) +#define DB_DELETED (-30898)/* Recovery file marked deleted. */ +#define DB_JAVA_CALLBACK (-30897)/* Exception during a java callback. */ +#define DB_NEEDSPLIT (-30896)/* Page needs to be split. */ +#define DB_SWAPBYTES (-30895)/* Database needs byte swapping. */ +#define DB_TXN_CKP (-30894)/* Encountered ckp record in log. */ +#define DB_VERIFY_FATAL (-30893)/* Fatal: DB->verify cannot proceed. */ + +#define DB_FILE_ID_LEN 20 /* DB file ID length. */ + +/* DB access method description structure. */ +struct __db { + /******************************************************* + * Public: owned by the application. + *******************************************************/ + u_int32_t pgsize; /* Database logical page size. */ + + /* Callbacks. */ + int (*db_append_recno) __P((DB *, DBT *, db_recno_t)); + void (*db_feedback) __P((DB *, int, int)); + void *(*db_malloc) __P((size_t)); + void *(*db_realloc) __P((void *, size_t)); + int (*dup_compare) __P((DB *, const DBT *, const DBT *)); + + void *app_private; /* Application-private handle. */ + + /******************************************************* + * Private: owned by DB. + *******************************************************/ + DB_ENV *dbenv; /* Backing environment. */ + + DBTYPE type; /* DB access method type. */ + + DB_MPOOLFILE *mpf; /* Backing buffer pool. */ + + void *mutexp; /* Synchronization for free threading */ + + u_int8_t fileid[DB_FILE_ID_LEN];/* File's unique ID for locking. */ + + u_int32_t adj_fileid; /* File's unique ID for curs. adj. */ + +#define DB_LOGFILEID_INVALID -1 + int32_t log_fileid; /* File's unique ID for logging. */ + db_pgno_t meta_pgno; /* Meta page number */ + DB_TXN *open_txn; /* Transaction to protect creates. */ + + long cl_id; /* RPC: remote client id. */ + + /* + * !!! + * Some applications use DB but implement their own locking outside of + * DB. If they're using fcntl(2) locking on the underlying database + * file, and we open and close a file descriptor for that file, we will + * discard their locks. The DB_FCNTL_LOCKING flag to DB->open is an + * undocumented interface to support this usage which leaves any file + * descriptors we open until DB->close. This will only work with the + * DB->open interface and simple caches, e.g., creating a transaction + * thread may open/close file descriptors this flag doesn't protect. + * Locking with fcntl(2) on a file that you don't own is a very, very + * unsafe thing to do. 'Nuff said. + */ + DB_FH *saved_open_fhp; /* Saved file handle. */ + + /* + * Linked list of DBP's, used in the log's dbentry table + * to keep track of all open db handles for a given log id. + * !!! + * Explicit representations of structures in queue.h. + * + * TAILQ_ENTRY(__db) links; + */ + struct { + struct __db *tqe_next; + struct __db **tqe_prev; + } links; + + /* + * Linked list of DBP's, linked from the DB_ENV, used to + * keep track of all open db handles for cursor adjustment. + * + * XXX + * Eventually, this should be merged with "links" above. + * + * !!! + * Explicit representations of structures in queue.h. + * + * LIST_ENTRY(__db) dblistlinks; + */ + struct { + struct __db *le_next; + struct __db **le_prev; + } dblistlinks; + + /* + * Cursor queues. + * + * !!! + * Explicit representations of structures in queue.h. + * + * TAILQ_HEAD(free_queue, __dbc); + * TAILQ_HEAD(active_queue, __dbc); + * TAILQ_HEAD(join_queue, __dbc); + */ + struct { + struct __dbc *tqh_first; + struct __dbc **tqh_last; + } free_queue; + struct { + struct __dbc *tqh_first; + struct __dbc **tqh_last; + } active_queue; + struct { + struct __dbc *tqh_first; + struct __dbc **tqh_last; + } join_queue; + + void *bt_internal; /* Btree/Recno access method private. */ + void *cj_internal; /* C++/Java private. */ + void *h_internal; /* Hash access method private. */ + void *q_internal; /* Queue access method private. */ + void *xa_internal; /* XA private. */ + + /* Methods. */ + int (*close) __P((DB *, u_int32_t)); + int (*cursor) __P((DB *, DB_TXN *, DBC **, u_int32_t)); + int (*del) __P((DB *, DB_TXN *, DBT *, u_int32_t)); + void (*err) __P((DB *, int, const char *, ...)); + void (*errx) __P((DB *, const char *, ...)); + int (*fd) __P((DB *, int *)); + int (*get) __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t)); + int (*get_byteswapped) __P((DB *)); + DBTYPE + (*get_type) __P((DB *)); + int (*join) __P((DB *, DBC **, DBC **, u_int32_t)); + int (*key_range) __P((DB *, + DB_TXN *, DBT *, DB_KEY_RANGE *, u_int32_t)); + int (*open) __P((DB *, + const char *, const char *, DBTYPE, u_int32_t, int)); + int (*put) __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t)); + int (*remove) __P((DB *, const char *, const char *, u_int32_t)); + int (*rename) __P((DB *, + const char *, const char *, const char *, u_int32_t)); + int (*set_append_recno) __P((DB *, int (*)(DB *, DBT *, db_recno_t))); + int (*set_cachesize) __P((DB *, u_int32_t, u_int32_t, int)); + int (*set_dup_compare) __P((DB *, + int (*)(DB *, const DBT *, const DBT *))); + void (*set_errcall) __P((DB *, void (*)(const char *, char *))); + void (*set_errfile) __P((DB *, FILE *)); + void (*set_errpfx) __P((DB *, const char *)); + int (*set_feedback) __P((DB *, void (*)(DB *, int, int))); + int (*set_flags) __P((DB *, u_int32_t)); + int (*set_lorder) __P((DB *, int)); + int (*set_malloc) __P((DB *, void *(*)(size_t))); + int (*set_pagesize) __P((DB *, u_int32_t)); + int (*set_paniccall) __P((DB *, void (*)(DB_ENV *, int))); + int (*set_realloc) __P((DB *, void *(*)(void *, size_t))); + int (*stat) __P((DB *, void *, void *(*)(size_t), u_int32_t)); + int (*sync) __P((DB *, u_int32_t)); + int (*upgrade) __P((DB *, const char *, u_int32_t)); + int (*verify) __P((DB *, + const char *, const char *, FILE *, u_int32_t)); + + int (*set_bt_compare) __P((DB *, + int (*)(DB *, const DBT *, const DBT *))); + int (*set_bt_maxkey) __P((DB *, u_int32_t)); + int (*set_bt_minkey) __P((DB *, u_int32_t)); + int (*set_bt_prefix) __P((DB *, + size_t (*)(DB *, const DBT *, const DBT *))); + + int (*set_h_ffactor) __P((DB *, u_int32_t)); + int (*set_h_hash) __P((DB *, + u_int32_t (*)(DB *, const void *, u_int32_t))); + int (*set_h_nelem) __P((DB *, u_int32_t)); + + int (*set_re_delim) __P((DB *, int)); + int (*set_re_len) __P((DB *, u_int32_t)); + int (*set_re_pad) __P((DB *, int)); + int (*set_re_source) __P((DB *, const char *)); + int (*set_q_extentsize) __P((DB *, u_int32_t)); + + int (*db_am_remove) __P((DB *, const char *, + const char *, DB_LSN *, int (**)(DB *, void*), void **)); + int (*db_am_rename) __P((DB *, + const char *, const char *, const char *)); + +#define DB_OK_BTREE 0x01 +#define DB_OK_HASH 0x02 +#define DB_OK_QUEUE 0x04 +#define DB_OK_RECNO 0x08 + u_int32_t am_ok; /* Legal AM choices. */ + +#define DB_AM_DISCARD 0x00001 /* Discard any cached pages. */ +#define DB_AM_DUP 0x00002 /* DB_DUP. */ +#define DB_AM_DUPSORT 0x00004 /* DB_DUPSORT. */ +#define DB_AM_INMEM 0x00008 /* In-memory; no sync on close. */ +#define DB_AM_PGDEF 0x00010 /* Page size was defaulted. */ +#define DB_AM_RDONLY 0x00020 /* Database is readonly. */ +#define DB_AM_RECOVER 0x00040 /* DBP opened by recovery routine. */ +#define DB_AM_SUBDB 0x00080 /* Subdatabases supported. */ +#define DB_AM_SWAP 0x00100 /* Pages need to be byte-swapped. */ +#define DB_AM_TXN 0x00200 /* DBP was in a transaction. */ +#define DB_AM_VERIFYING 0x00400 /* DB handle is in the verifier. */ +#define DB_BT_RECNUM 0x00800 /* DB_RECNUM. */ +#define DB_BT_REVSPLIT 0x01000 /* DB_REVSPLITOFF. */ +#define DB_DBM_ERROR 0x02000 /* Error in DBM/NDBM database. */ +#define DB_OPEN_CALLED 0x04000 /* DB->open called. */ +#define DB_RE_DELIMITER 0x08000 /* Variablen length delimiter set. */ +#define DB_RE_FIXEDLEN 0x10000 /* Fixed-length records. */ +#define DB_RE_PAD 0x20000 /* Fixed-length record pad. */ +#define DB_RE_RENUMBER 0x40000 /* DB_RENUMBER. */ +#define DB_RE_SNAPSHOT 0x80000 /* DB_SNAPSHOT. */ + u_int32_t flags; +}; + +/* + * DB_LOCK_ILOCK -- + * Internal DB access method lock. + */ +struct __db_ilock { + db_pgno_t pgno; /* Page being locked. */ + u_int8_t fileid[DB_FILE_ID_LEN];/* File id. */ +#define DB_RECORD_LOCK 1 +#define DB_PAGE_LOCK 2 + u_int8_t type; /* Record or Page lock */ +}; + +/* + * DB_LOCK -- + * The structure is allocated by the caller and filled in during a + * lock_get request (or a lock_vec/DB_LOCK_GET). + */ +struct __db_lock_u { + size_t off; /* Offset of the lock in the region */ + u_int32_t ndx; /* Index of the object referenced by + * this lock; used for locking. */ + u_int32_t gen; /* Generation number of this lock. */ +}; + +/* Cursor description structure. */ +struct __dbc { + DB *dbp; /* Related DB access method. */ + DB_TXN *txn; /* Associated transaction. */ + + /* + * !!! + * Explicit representations of structures in queue.h. + * + * TAILQ_ENTRY(__dbc) links; Active/free cursor queues. + */ + struct { + DBC *tqe_next; + DBC **tqe_prev; + } links; + + DBT rkey; /* Returned key. */ + DBT rdata; /* Returned data. */ + + u_int32_t lid; /* Default process' locker id. */ + u_int32_t locker; /* Locker for this operation. */ + DBT lock_dbt; /* DBT referencing lock. */ + DB_LOCK_ILOCK lock; /* Object to be locked. */ + DB_LOCK mylock; /* Lock held on this cursor. */ + + long cl_id; /* Remote client id. */ + + DBTYPE dbtype; /* Cursor type. */ + + DBC_INTERNAL *internal; /* Access method private. */ + + int (*c_close) __P((DBC *)); /* Methods: public. */ + int (*c_count) __P((DBC *, db_recno_t *, u_int32_t)); + int (*c_del) __P((DBC *, u_int32_t)); + int (*c_dup) __P((DBC *, DBC **, u_int32_t)); + int (*c_get) __P((DBC *, DBT *, DBT *, u_int32_t)); + int (*c_put) __P((DBC *, DBT *, DBT *, u_int32_t)); + + /* Methods: private. */ + int (*c_am_close) __P((DBC *, db_pgno_t, int *)); + int (*c_am_del) __P((DBC *)); + int (*c_am_destroy) __P((DBC *)); + int (*c_am_get) __P((DBC *, DBT *, DBT *, u_int32_t, db_pgno_t *)); + int (*c_am_put) __P((DBC *, DBT *, DBT *, u_int32_t, db_pgno_t *)); + int (*c_am_writelock) __P((DBC *)); + +#define DBC_ACTIVE 0x001 /* Cursor is being used. */ +#define DBC_OPD 0x002 /* Cursor references off-page dups. */ +#define DBC_RECOVER 0x004 /* Cursor created by recovery routine + * (do not log or lock). + */ +#define DBC_RMW 0x008 /* Acquire write flag in read op. */ +#define DBC_WRITECURSOR 0x010 /* Cursor may be used to write (CDB). */ +#define DBC_WRITEDUP 0x020 /* idup'ed DBC_WRITECURSOR (CDB). */ +#define DBC_WRITER 0x040 /* Cursor immediately writing (CDB). */ +#define DBC_TRANSIENT 0x080 /* Cursor is transient. */ +#define DBC_COMPENSATE 0x100 /* Cursor is doing compensation + * do not lock. + */ + u_int32_t flags; +}; + +/* Key range statistics structure */ +struct __key_range { + double less; + double equal; + double greater; +}; + +/* Btree/Recno statistics structure. */ +struct __db_bt_stat { + u_int32_t bt_magic; /* Magic number. */ + u_int32_t bt_version; /* Version number. */ + u_int32_t bt_metaflags; /* Metadata flags. */ + u_int32_t bt_nkeys; /* Number of unique keys. */ + u_int32_t bt_ndata; /* Number of data items. */ + u_int32_t bt_pagesize; /* Page size. */ + u_int32_t bt_maxkey; /* Maxkey value. */ + u_int32_t bt_minkey; /* Minkey value. */ + u_int32_t bt_re_len; /* Fixed-length record length. */ + u_int32_t bt_re_pad; /* Fixed-length record pad. */ + u_int32_t bt_levels; /* Tree levels. */ + u_int32_t bt_int_pg; /* Internal pages. */ + u_int32_t bt_leaf_pg; /* Leaf pages. */ + u_int32_t bt_dup_pg; /* Duplicate pages. */ + u_int32_t bt_over_pg; /* Overflow pages. */ + u_int32_t bt_free; /* Pages on the free list. */ + u_int32_t bt_int_pgfree; /* Bytes free in internal pages. */ + u_int32_t bt_leaf_pgfree; /* Bytes free in leaf pages. */ + u_int32_t bt_dup_pgfree; /* Bytes free in duplicate pages. */ + u_int32_t bt_over_pgfree; /* Bytes free in overflow pages. */ +}; + +/* Queue statistics structure. */ +struct __db_qam_stat { + u_int32_t qs_magic; /* Magic number. */ + u_int32_t qs_version; /* Version number. */ + u_int32_t qs_metaflags; /* Metadata flags. */ + u_int32_t qs_nkeys; /* Number of unique keys. */ + u_int32_t qs_ndata; /* Number of data items. */ + u_int32_t qs_pagesize; /* Page size. */ + u_int32_t qs_pages; /* Data pages. */ + u_int32_t qs_re_len; /* Fixed-length record length. */ + u_int32_t qs_re_pad; /* Fixed-length record pad. */ + u_int32_t qs_pgfree; /* Bytes free in data pages. */ + u_int32_t qs_first_recno; /* First not deleted record. */ + u_int32_t qs_cur_recno; /* Last allocated record number. */ +}; + +/* Hash statistics structure. */ +struct __db_h_stat { + u_int32_t hash_magic; /* Magic number. */ + u_int32_t hash_version; /* Version number. */ + u_int32_t hash_metaflags; /* Metadata flags. */ + u_int32_t hash_nkeys; /* Number of unique keys. */ + u_int32_t hash_ndata; /* Number of data items. */ + u_int32_t hash_pagesize; /* Page size. */ + u_int32_t hash_nelem; /* Original nelem specified. */ + u_int32_t hash_ffactor; /* Fill factor specified at create. */ + u_int32_t hash_buckets; /* Number of hash buckets. */ + u_int32_t hash_free; /* Pages on the free list. */ + u_int32_t hash_bfree; /* Bytes free on bucket pages. */ + u_int32_t hash_bigpages; /* Number of big key/data pages. */ + u_int32_t hash_big_bfree; /* Bytes free on big item pages. */ + u_int32_t hash_overflows; /* Number of overflow pages. */ + u_int32_t hash_ovfl_free; /* Bytes free on ovfl pages. */ + u_int32_t hash_dup; /* Number of dup pages. */ + u_int32_t hash_dup_free; /* Bytes free on duplicate pages. */ +}; + +int db_create __P((DB **, DB_ENV *, u_int32_t)); +int db_env_create __P((DB_ENV **, u_int32_t)); +int db_env_set_func_close __P((int (*)(int))); +int db_env_set_func_dirfree __P((void (*)(char **, int))); +int db_env_set_func_dirlist __P((int (*)(const char *, char ***, int *))); +int db_env_set_func_exists __P((int (*)(const char *, int *))); +int db_env_set_func_free __P((void (*)(void *))); +int db_env_set_func_fsync __P((int (*)(int))); +int db_env_set_func_ioinfo __P((int (*)(const char *, + int, u_int32_t *, u_int32_t *, u_int32_t *))); +int db_env_set_func_malloc __P((void *(*)(size_t))); +int db_env_set_func_map __P((int (*)(char *, size_t, int, int, void **))); +int db_env_set_func_open __P((int (*)(const char *, int, ...))); +int db_env_set_func_read __P((ssize_t (*)(int, void *, size_t))); +int db_env_set_func_realloc __P((void *(*)(void *, size_t))); +int db_env_set_func_rename __P((int (*)(const char *, const char *))); +int db_env_set_func_seek + __P((int (*)(int, size_t, db_pgno_t, u_int32_t, int, int))); +int db_env_set_func_sleep __P((int (*)(u_long, u_long))); +int db_env_set_func_unlink __P((int (*)(const char *))); +int db_env_set_func_unmap __P((int (*)(void *, size_t))); +int db_env_set_func_write __P((ssize_t (*)(int, const void *, size_t))); +int db_env_set_func_yield __P((int (*)(void))); +int db_env_set_pageyield __P((int)); +int db_env_set_panicstate __P((int)); +int db_env_set_region_init __P((int)); +int db_env_set_tas_spins __P((u_int32_t)); +char *db_strerror __P((int)); +char *db_version __P((int *, int *, int *)); + +/******************************************************* + * Locking + *******************************************************/ +#define DB_LOCKVERSION 1 + +/* Flag values for lock_vec(), lock_get(). */ +#define DB_LOCK_NOWAIT 0x01 /* Don't wait on unavailable lock. */ +#define DB_LOCK_RECORD 0x02 /* Internal: record lock. */ +#define DB_LOCK_UPGRADE 0x04 /* Internal: upgrade existing lock. */ +#define DB_LOCK_SWITCH 0x08 /* Internal: switch existing lock. */ + +/* Flag values for lock_detect(). */ +#define DB_LOCK_CONFLICT 0x01 /* Run on any conflict. */ + +/* + * Request types. + * + * !!! + * Changes here must be reflected in java/src/com/sleepycat/db/Db.java. + */ +typedef enum { + DB_LOCK_DUMP=0, /* Display held locks. */ + DB_LOCK_GET, /* Get the lock. */ + DB_LOCK_INHERIT, /* Pass locks to parent. */ + DB_LOCK_PUT, /* Release the lock. */ + DB_LOCK_PUT_ALL, /* Release locker's locks. */ + DB_LOCK_PUT_OBJ /* Release locker's locks on obj. */ +} db_lockop_t; + +/* + * Simple R/W lock modes and for multi-granularity intention locking. + * + * !!! + * These values are NOT random, as they are used as an index into the lock + * conflicts arrays, i.e., DB_LOCK_IWRITE must be == 3, and DB_LOCK_IREAD + * must be == 4. + * + * !!! + * Changes here must be reflected in java/src/com/sleepycat/db/Db.java. + */ +typedef enum { + DB_LOCK_NG=0, /* Not granted. */ + DB_LOCK_READ, /* Shared/read. */ + DB_LOCK_WRITE, /* Exclusive/write. */ + DB_LOCK_WAIT, /* Wait for event */ + DB_LOCK_IWRITE, /* Intent exclusive/write. */ + DB_LOCK_IREAD, /* Intent to share/read. */ + DB_LOCK_IWR /* Intent to read and write. */ +} db_lockmode_t; + +/* + * Status of a lock. + */ +typedef enum { + DB_LSTAT_ABORTED, /* Lock belongs to an aborted txn. */ + DB_LSTAT_ERR, /* Lock is bad. */ + DB_LSTAT_FREE, /* Lock is unallocated. */ + DB_LSTAT_HELD, /* Lock is currently held. */ + DB_LSTAT_NOGRANT, /* Lock was not granted. */ + DB_LSTAT_PENDING, /* Lock was waiting and has been + * promoted; waiting for the owner + * to run and upgrade it to held. */ + DB_LSTAT_WAITING /* Lock is on the wait queue. */ +} db_status_t; + +/* Lock request structure. */ +struct __db_lockreq { + db_lockop_t op; /* Operation. */ + db_lockmode_t mode; /* Requested mode. */ + u_int32_t locker; /* Locker identity. */ + DBT *obj; /* Object being locked. */ + DB_LOCK lock; /* Lock returned. */ +}; + +/* + * Commonly used conflict matrices. + * + */ + +/* Multi-granularity locking. */ +#define DB_LOCK_RIW_N 7 +extern const u_int8_t db_riw_conflicts[]; + +struct __db_lock_stat { + u_int32_t st_lastid; /* Last allocated locker ID. */ + u_int32_t st_maxlocks; /* Maximum number of locks in table. */ + u_int32_t st_maxlockers; /* Maximum number of lockers in table. */ + u_int32_t st_maxobjects; /* Maximum number of objects in table. */ + u_int32_t st_nmodes; /* Number of lock modes. */ + u_int32_t st_nlocks; /* Current number of locks. */ + u_int32_t st_maxnlocks; /* Maximum number of locks so far. */ + u_int32_t st_nlockers; /* Current number of lockers. */ + u_int32_t st_maxnlockers; /* Maximum number of lockers so far. */ + u_int32_t st_nobjects; /* Current number of objects. */ + u_int32_t st_maxnobjects; /* Maximum number of objects so far. */ + u_int32_t st_nconflicts; /* Number of lock conflicts. */ + u_int32_t st_nrequests; /* Number of lock gets. */ + u_int32_t st_nreleases; /* Number of lock puts. */ + u_int32_t st_nnowaits; /* Number of requests that would have + waited, but NOWAIT was set. */ + u_int32_t st_ndeadlocks; /* Number of lock deadlocks. */ + u_int32_t st_region_wait; /* Region lock granted after wait. */ + u_int32_t st_region_nowait; /* Region lock granted without wait. */ + u_int32_t st_regsize; /* Region size. */ +}; + +int lock_detect __P((DB_ENV *, u_int32_t, u_int32_t, int *)); +int lock_get __P((DB_ENV *, + u_int32_t, u_int32_t, const DBT *, db_lockmode_t, DB_LOCK *)); +int lock_id __P((DB_ENV *, u_int32_t *)); +int lock_put __P((DB_ENV *, DB_LOCK *)); +int lock_stat __P((DB_ENV *, DB_LOCK_STAT **, void *(*)(size_t))); +int lock_vec __P((DB_ENV *, + u_int32_t, u_int32_t, DB_LOCKREQ *, int, DB_LOCKREQ **)); + +/******************************************************* + * Logging. + *******************************************************/ +/* Flag values for log_archive(). */ +#define DB_ARCH_ABS 0x001 /* Absolute pathnames. */ +#define DB_ARCH_DATA 0x002 /* Data files. */ +#define DB_ARCH_LOG 0x004 /* Log files. */ + +/* + * A DB_LSN has two parts, a fileid which identifies a specific file, and an + * offset within that file. The fileid is an unsigned 4-byte quantity that + * uniquely identifies a file within the log directory -- currently a simple + * counter inside the log. The offset is also an unsigned 4-byte value. The + * log manager guarantees the offset is never more than 4 bytes by switching + * to a new log file before the maximum length imposed by an unsigned 4-byte + * offset is reached. + */ +struct __db_lsn { + u_int32_t file; /* File ID. */ + u_int32_t offset; /* File offset. */ +}; + +/* Log statistics structure. */ +struct __db_log_stat { + u_int32_t st_magic; /* Log file magic number. */ + u_int32_t st_version; /* Log file version number. */ + int st_mode; /* Log file mode. */ + u_int32_t st_lg_bsize; /* Log buffer size. */ + u_int32_t st_lg_max; /* Maximum log file size. */ + u_int32_t st_w_bytes; /* Bytes to log. */ + u_int32_t st_w_mbytes; /* Megabytes to log. */ + u_int32_t st_wc_bytes; /* Bytes to log since checkpoint. */ + u_int32_t st_wc_mbytes; /* Megabytes to log since checkpoint. */ + u_int32_t st_wcount; /* Total writes to the log. */ + u_int32_t st_wcount_fill; /* Overflow writes to the log. */ + u_int32_t st_scount; /* Total syncs to the log. */ + u_int32_t st_region_wait; /* Region lock granted after wait. */ + u_int32_t st_region_nowait; /* Region lock granted without wait. */ + u_int32_t st_cur_file; /* Current log file number. */ + u_int32_t st_cur_offset; /* Current log file offset. */ + u_int32_t st_regsize; /* Region size. */ +}; + +int log_archive __P((DB_ENV *, char **[], u_int32_t, void *(*)(size_t))); +int log_compare __P((const DB_LSN *, const DB_LSN *)); +int log_file __P((DB_ENV *, const DB_LSN *, char *, size_t)); +int log_flush __P((DB_ENV *, const DB_LSN *)); +int log_get __P((DB_ENV *, DB_LSN *, DBT *, u_int32_t)); +int log_put __P((DB_ENV *, DB_LSN *, const DBT *, u_int32_t)); +int log_register __P((DB_ENV *, DB *, const char *)); +int log_stat __P((DB_ENV *, DB_LOG_STAT **, void *(*)(size_t))); +int log_unregister __P((DB_ENV *, DB *)); + +/******************************************************* + * Mpool + *******************************************************/ +/* Flag values for memp_fget(). */ +#define DB_MPOOL_CREATE 0x001 /* Create a page. */ +#define DB_MPOOL_LAST 0x002 /* Return the last page. */ +#define DB_MPOOL_NEW 0x004 /* Create a new page. */ +#define DB_MPOOL_NEW_GROUP 0x008 /* Create a group of pages. */ +#define DB_MPOOL_EXTENT 0x010 /* Get for an extent. */ + +/* Flag values for memp_fput(), memp_fset(). */ +#define DB_MPOOL_CLEAN 0x001 /* Page is not modified. */ +#define DB_MPOOL_DIRTY 0x002 /* Page is modified. */ +#define DB_MPOOL_DISCARD 0x004 /* Don't cache the page. */ + +/* Mpool statistics structure. */ +struct __db_mpool_stat { + u_int32_t st_cache_hit; /* Pages found in the cache. */ + u_int32_t st_cache_miss; /* Pages not found in the cache. */ + u_int32_t st_map; /* Pages from mapped files. */ + u_int32_t st_page_create; /* Pages created in the cache. */ + u_int32_t st_page_in; /* Pages read in. */ + u_int32_t st_page_out; /* Pages written out. */ + u_int32_t st_ro_evict; /* Clean pages forced from the cache. */ + u_int32_t st_rw_evict; /* Dirty pages forced from the cache. */ + u_int32_t st_hash_buckets; /* Number of hash buckets. */ + u_int32_t st_hash_searches; /* Total hash chain searches. */ + u_int32_t st_hash_longest; /* Longest hash chain searched. */ + u_int32_t st_hash_examined; /* Total hash entries searched. */ + u_int32_t st_page_clean; /* Clean pages. */ + u_int32_t st_page_dirty; /* Dirty pages. */ + u_int32_t st_page_trickle; /* Pages written by memp_trickle. */ + u_int32_t st_region_wait; /* Region lock granted after wait. */ + u_int32_t st_region_nowait; /* Region lock granted without wait. */ + u_int32_t st_gbytes; /* Total cache size: GB. */ + u_int32_t st_bytes; /* Total cache size: B. */ + u_int32_t st_ncache; /* Number of caches. */ + u_int32_t st_regsize; /* Cache size. */ +}; + +/* Mpool file open information structure. */ +struct __db_mpool_finfo { + int ftype; /* File type. */ + DBT *pgcookie; /* Byte-string passed to pgin/pgout. */ + u_int8_t *fileid; /* Unique file ID. */ + int32_t lsn_offset; /* LSN offset in page. */ + u_int32_t clear_len; /* Cleared length on created pages. */ +}; + +/* Mpool file statistics structure. */ +struct __db_mpool_fstat { + char *file_name; /* File name. */ + size_t st_pagesize; /* Page size. */ + u_int32_t st_cache_hit; /* Pages found in the cache. */ + u_int32_t st_cache_miss; /* Pages not found in the cache. */ + u_int32_t st_map; /* Pages from mapped files. */ + u_int32_t st_page_create; /* Pages created in the cache. */ + u_int32_t st_page_in; /* Pages read in. */ + u_int32_t st_page_out; /* Pages written out. */ +}; + +int memp_fclose __P((DB_MPOOLFILE *)); +int memp_fget __P((DB_MPOOLFILE *, db_pgno_t *, u_int32_t, void *)); +int memp_fopen __P((DB_ENV *, const char *, + u_int32_t, int, size_t, DB_MPOOL_FINFO *, DB_MPOOLFILE **)); +int memp_fput __P((DB_MPOOLFILE *, void *, u_int32_t)); +int memp_fset __P((DB_MPOOLFILE *, void *, u_int32_t)); +int memp_fsync __P((DB_MPOOLFILE *)); +int memp_register __P((DB_ENV *, int, + int (*)(DB_ENV *, db_pgno_t, void *, DBT *), + int (*)(DB_ENV *, db_pgno_t, void *, DBT *))); +int memp_stat __P((DB_ENV *, + DB_MPOOL_STAT **, DB_MPOOL_FSTAT ***, void *(*)(size_t))); +int memp_sync __P((DB_ENV *, DB_LSN *)); +int memp_trickle __P((DB_ENV *, int, int *)); + +/******************************************************* + * Transactions. + *******************************************************/ +#define DB_TXNVERSION 1 + +/* Operations values to the tx_recover() function. */ +#define DB_TXN_BACKWARD_ROLL 1 /* Read the log backwards. */ +#define DB_TXN_FORWARD_ROLL 2 /* Read the log forwards. */ +#define DB_TXN_OPENFILES 3 /* Read for open files. */ +#define DB_TXN_REDO 4 /* Redo the operation. */ +#define DB_TXN_UNDO 5 /* Undo the operation. */ + +/* Internal transaction status values. */ + +/* Transaction statistics structure. */ +struct __db_txn_active { + u_int32_t txnid; /* Transaction ID */ + u_int32_t parentid; /* Transaction ID of parent */ + DB_LSN lsn; /* Lsn of the begin record */ +}; + +struct __db_txn_stat { + DB_LSN st_last_ckp; /* lsn of the last checkpoint */ + DB_LSN st_pending_ckp; /* last checkpoint did not finish */ + time_t st_time_ckp; /* time of last checkpoint */ + u_int32_t st_last_txnid; /* last transaction id given out */ + u_int32_t st_maxtxns; /* maximum txns possible */ + u_int32_t st_naborts; /* number of aborted transactions */ + u_int32_t st_nbegins; /* number of begun transactions */ + u_int32_t st_ncommits; /* number of committed transactions */ + u_int32_t st_nactive; /* number of active transactions */ + u_int32_t st_maxnactive; /* maximum active transactions */ + DB_TXN_ACTIVE + *st_txnarray; /* array of active transactions */ + u_int32_t st_region_wait; /* Region lock granted after wait. */ + u_int32_t st_region_nowait; /* Region lock granted without wait. */ + u_int32_t st_regsize; /* Region size. */ +}; + +int txn_abort __P((DB_TXN *)); +int txn_begin __P((DB_ENV *, DB_TXN *, DB_TXN **, u_int32_t)); +int txn_checkpoint __P((DB_ENV *, u_int32_t, u_int32_t, u_int32_t)); +int txn_commit __P((DB_TXN *, u_int32_t)); +u_int32_t txn_id __P((DB_TXN *)); +int txn_prepare __P((DB_TXN *)); +int txn_stat __P((DB_ENV *, DB_TXN_STAT **, void *(*)(size_t))); + +#ifndef DB_DBM_HSEARCH +#define DB_DBM_HSEARCH 0 /* No historic interfaces by default. */ +#endif +#if DB_DBM_HSEARCH != 0 +/******************************************************* + * Dbm/Ndbm historic interfaces. + *******************************************************/ +#define DBM_INSERT 0 /* Flags to dbm_store(). */ +#define DBM_REPLACE 1 + +/* + * The DB support for ndbm(3) always appends this suffix to the + * file name to avoid overwriting the user's original database. + */ +#define DBM_SUFFIX ".db" + +#if defined(_XPG4_2) +typedef struct { + char *dptr; + size_t dsize; +} datum; +#else +typedef struct { + char *dptr; + int dsize; +} datum; +#endif + +/* + * Translate DBM calls into DB calls so that DB doesn't step on the + * application's name space. + * + * The global variables dbrdonly, dirf and pagf were not retained when 4BSD + * replaced the dbm interface with ndbm, and are not supported here. + */ +#define dbminit(a) __db_dbm_init(a) +#define dbmclose __db_dbm_close +#if !defined(__cplusplus) +#define delete(a) __db_dbm_delete(a) +#endif +#define fetch(a) __db_dbm_fetch(a) +#define firstkey __db_dbm_firstkey +#define nextkey(a) __db_dbm_nextkey(a) +#define store(a, b) __db_dbm_store(a, b) + +/* Prototype the DB calls. */ +int __db_dbm_close __P((void)); +int __db_dbm_dbrdonly __P((void)); +int __db_dbm_delete __P((datum)); +int __db_dbm_dirf __P((void)); +datum __db_dbm_fetch __P((datum)); +datum __db_dbm_firstkey __P((void)); +int __db_dbm_init __P((char *)); +datum __db_dbm_nextkey __P((datum)); +int __db_dbm_pagf __P((void)); +int __db_dbm_store __P((datum, datum)); + +/* + * Translate NDBM calls into DB calls so that DB doesn't step on the + * application's name space. + */ +#define dbm_clearerr(a) __db_ndbm_clearerr(a) +#define dbm_close(a) __db_ndbm_close(a) +#define dbm_delete(a, b) __db_ndbm_delete(a, b) +#define dbm_dirfno(a) __db_ndbm_dirfno(a) +#define dbm_error(a) __db_ndbm_error(a) +#define dbm_fetch(a, b) __db_ndbm_fetch(a, b) +#define dbm_firstkey(a) __db_ndbm_firstkey(a) +#define dbm_nextkey(a) __db_ndbm_nextkey(a) +#define dbm_open(a, b, c) __db_ndbm_open(a, b, c) +#define dbm_pagfno(a) __db_ndbm_pagfno(a) +#define dbm_rdonly(a) __db_ndbm_rdonly(a) +#define dbm_store(a, b, c, d) __db_ndbm_store(a, b, c, d) + +/* Prototype the DB calls. */ +int __db_ndbm_clearerr __P((DBM *)); +void __db_ndbm_close __P((DBM *)); +int __db_ndbm_delete __P((DBM *, datum)); +int __db_ndbm_dirfno __P((DBM *)); +int __db_ndbm_error __P((DBM *)); +datum __db_ndbm_fetch __P((DBM *, datum)); +datum __db_ndbm_firstkey __P((DBM *)); +datum __db_ndbm_nextkey __P((DBM *)); +DBM *__db_ndbm_open __P((const char *, int, int)); +int __db_ndbm_pagfno __P((DBM *)); +int __db_ndbm_rdonly __P((DBM *)); +int __db_ndbm_store __P((DBM *, datum, datum, int)); + +/******************************************************* + * Hsearch historic interface. + *******************************************************/ +typedef enum { + FIND, ENTER +} ACTION; + +typedef struct entry { + char *key; + char *data; +} ENTRY; + +/* + * Translate HSEARCH calls into DB calls so that DB doesn't step on the + * application's name space. + */ +#define hcreate(a) __db_hcreate(a) +#define hdestroy __db_hdestroy +#define hsearch(a, b) __db_hsearch(a, b) + +/* Prototype the DB calls. */ +int __db_hcreate __P((size_t)); +void __db_hdestroy __P((void)); +ENTRY *__db_hsearch __P((ENTRY, ACTION)); +#endif /* DB_DBM_HSEARCH */ + +/* + * XXX + * MacOS: Reset Metrowerks C enum sizes. + */ +#ifdef __MWERKS__ +#pragma enumsalwaysint reset +#endif + +#if defined(__cplusplus) +} +#endif + +#endif /* !_DB_H_ */ diff --git a/db/build_win32/db_archive.dsp b/db/build_win32/db_archive.dsp new file mode 100644 index 000000000..e100ec01d --- /dev/null +++ b/db/build_win32/db_archive.dsp @@ -0,0 +1,151 @@ +# Microsoft Developer Studio Project File - Name="db_archive" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=db_archive - Win32 Debug Static +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "db_archive.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "db_archive.mak" CFG="db_archive - Win32 Debug Static" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "db_archive - Win32 Release" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "db_archive - Win32 Debug" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "db_archive - Win32 Release Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "db_archive - Win32 Debug Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "db_archive - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release/libdb32.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"libcmt" + +!ELSEIF "$(CFG)" == "db_archive - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 Debug/libdb32d.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /nodefaultlib:"libcmtd" /fixed:no + +!ELSEIF "$(CFG)" == "db_archive - Win32 Release Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release_static" +# PROP Intermediate_Dir "Release_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Release_static/libdb32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release_static/libdb32s.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "db_archive - Win32 Debug Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_static" +# PROP Intermediate_Dir "Debug_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Debug_static/libdb32d.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no +# ADD LINK32 Debug_static/libdb32sd.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no + +!ENDIF + +# Begin Target + +# Name "db_archive - Win32 Release" +# Name "db_archive - Win32 Debug" +# Name "db_archive - Win32 Release Static" +# Name "db_archive - Win32 Debug Static" +# Begin Source File + +SOURCE=..\db_archive\db_archive.c +# End Source File +# Begin Source File + +SOURCE=..\clib\getopt.c +# End Source File +# End Target +# End Project diff --git a/db/build_win32/db_buildall.dsp b/db/build_win32/db_buildall.dsp new file mode 100644 index 000000000..0f67cd945 --- /dev/null +++ b/db/build_win32/db_buildall.dsp @@ -0,0 +1,128 @@ +# Microsoft Developer Studio Project File - Name="db_buildall" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) External Target" 0x0106 + +CFG=db_buildall - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "db_buildall.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "db_buildall.mak" CFG="db_buildall - Win32 Debug Static" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "db_buildall - Win32 Release" (based on "Win32 (x86) External Target") +!MESSAGE "db_buildall - Win32 Debug" (based on "Win32 (x86) External Target") +!MESSAGE "db_buildall - Win32 Release Static" (based on\ + "Win32 (x86) External Target") +!MESSAGE "db_buildall - Win32 Debug Static" (based on\ + "Win32 (x86) External Target") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" + +!IF "$(CFG)" == "db_buildall - Win32 Release" + +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Cmd_Line "NMAKE /f db_buildall.mak" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "db_buildall.exe" +# PROP BASE Bsc_Name "db_buildall.bsc" +# PROP BASE Target_Dir "" +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Cmd_Line "echo DB release version built." +# PROP Rebuild_Opt "" +# PROP Target_File "db_buildall.exe" +# PROP Bsc_Name "db_buildall.bsc" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "db_buildall - Win32 Debug" + +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Cmd_Line "NMAKE /f db_buildall.mak" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "db_buildall.exe" +# PROP BASE Bsc_Name "db_buildall.bsc" +# PROP BASE Target_Dir "" +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Cmd_Line "echo DB debug version built." +# PROP Rebuild_Opt "" +# PROP Target_File "db_buildall.exe" +# PROP Bsc_Name "db_buildall.bsc" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "db_buildall - Win32 Release Static" + +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release_static" +# PROP BASE Intermediate_Dir "Release_static" +# PROP BASE Cmd_Line "echo DB release version built." +# PROP BASE Rebuild_Opt "" +# PROP BASE Target_File "db_buildall.exe" +# PROP BASE Bsc_Name "db_buildall.bsc" +# PROP BASE Target_Dir "" +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release_static" +# PROP Intermediate_Dir "Release_static" +# PROP Cmd_Line "echo DB release version built." +# PROP Rebuild_Opt "" +# PROP Target_File "db_buildall.exe" +# PROP Bsc_Name "db_buildall.bsc" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "db_buildall - Win32 Debug Static" + +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug_static" +# PROP BASE Intermediate_Dir "Debug_static" +# PROP BASE Cmd_Line "echo DB debug version built." +# PROP BASE Rebuild_Opt "" +# PROP BASE Target_File "db_buildall.exe" +# PROP BASE Bsc_Name "db_buildall.bsc" +# PROP BASE Target_Dir "" +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_static" +# PROP Intermediate_Dir "Debug_static" +# PROP Cmd_Line "echo DB debug version built." +# PROP Rebuild_Opt "" +# PROP Target_File "db_buildall.exe" +# PROP Bsc_Name "db_buildall.bsc" +# PROP Target_Dir "" + +!ENDIF + +# Begin Target + +# Name "db_buildall - Win32 Release" +# Name "db_buildall - Win32 Debug" +# Name "db_buildall - Win32 Release Static" +# Name "db_buildall - Win32 Debug Static" + +!IF "$(CFG)" == "db_buildall - Win32 Release" + +!ELSEIF "$(CFG)" == "db_buildall - Win32 Debug" + +!ELSEIF "$(CFG)" == "db_buildall - Win32 Release Static" + +!ELSEIF "$(CFG)" == "db_buildall - Win32 Debug Static" + +!ENDIF + +# End Target +# End Project diff --git a/db/build_win32/db_checkpoint.dsp b/db/build_win32/db_checkpoint.dsp new file mode 100644 index 000000000..8708a5503 --- /dev/null +++ b/db/build_win32/db_checkpoint.dsp @@ -0,0 +1,151 @@ +# Microsoft Developer Studio Project File - Name="db_checkpoint" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=db_checkpoint - Win32 Debug Static +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "db_checkpoint.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "db_checkpoint.mak" CFG="db_checkpoint - Win32 Debug Static" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "db_checkpoint - Win32 Release" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "db_checkpoint - Win32 Debug" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "db_checkpoint - Win32 Release Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "db_checkpoint - Win32 Debug Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "db_checkpoint - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release/libdb32.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"libcmt" + +!ELSEIF "$(CFG)" == "db_checkpoint - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 Debug/libdb32d.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /nodefaultlib:"libcmtd" /fixed:no + +!ELSEIF "$(CFG)" == "db_checkpoint - Win32 Release Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release_static" +# PROP Intermediate_Dir "Release_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Release_static/libdb32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release_static/libdb32s.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "db_checkpoint - Win32 Debug Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_static" +# PROP Intermediate_Dir "Debug_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Debug_static/libdb32d.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no +# ADD LINK32 Debug_static/libdb32sd.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no + +!ENDIF + +# Begin Target + +# Name "db_checkpoint - Win32 Release" +# Name "db_checkpoint - Win32 Debug" +# Name "db_checkpoint - Win32 Release Static" +# Name "db_checkpoint - Win32 Debug Static" +# Begin Source File + +SOURCE=..\db_checkpoint\db_checkpoint.c +# End Source File +# Begin Source File + +SOURCE=..\clib\getopt.c +# End Source File +# End Target +# End Project diff --git a/db/build_win32/db_config.h b/db/build_win32/db_config.h new file mode 100644 index 000000000..8b12d64c3 --- /dev/null +++ b/db/build_win32/db_config.h @@ -0,0 +1,275 @@ +/* + * $Id: db_config.h,v 11.24 2000/12/12 18:39:26 bostic Exp $ + */ + +/* Define to empty if the keyword does not work. */ +/* #undef const */ + +/* Define if your struct stat has st_blksize. */ +/* #undef HAVE_ST_BLKSIZE */ + +/* Define to `int' if doesn't define. */ +/* #undef mode_t */ + +/* Define to `long' if doesn't define. */ +/* #undef off_t */ + +/* Define to `int' if doesn't define. */ +/* #undef pid_t */ + +/* Define to `unsigned' if doesn't define. */ +/* #undef size_t */ + +/* Define if the `S_IS*' macros in do not work properly. */ +/* #undef STAT_MACROS_BROKEN */ + +/* Define if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if you can safely include both and . */ +/* #undef TIME_WITH_SYS_TIME */ + +/* Define if your processor stores words with the most significant + byte first (like Motorola and SPARC, unlike Intel and VAX). */ +/* #undef WORDS_BIGENDIAN */ + +/* Define if you are building a version for running the test suite. */ +/* #undef CONFIG_TEST */ + +/* Define if you want a debugging version. */ +/* #undef DEBUG */ +#if defined(_DEBUG) +#if !defined(DEBUG) +#define DEBUG 1 +#endif +#endif + +/* Define if you want a version that logs read operations. */ +/* #undef DEBUG_ROP */ + +/* Define if you want a version that logs write operations. */ +/* #undef DEBUG_WOP */ + +/* Define if you want a version with run-time diagnostic checking. */ +/* #undef DIAGNOSTIC */ + +/* Define if you want to mask harmless unitialized memory read/writes. */ +/* #undef UMRW */ + +/* Define if fcntl/F_SETFD denies child access to file descriptors. */ +/* #undef HAVE_FCNTL_F_SETFD */ + +/* Define if building big-file environment (e.g., AIX, HP/UX, Solaris). */ +/* #undef HAVE_FILE_OFFSET_BITS */ + +/* Mutex possibilities. */ +/* #undef HAVE_MUTEX_68K_GCC_ASSEMBLY */ +/* #undef HAVE_MUTEX_AIX_CHECK_LOCK */ +/* #undef HAVE_MUTEX_ALPHA_GCC_ASSEMBLY */ +/* #undef HAVE_MUTEX_HPPA_GCC_ASSEMBLY */ +/* #undef HAVE_MUTEX_HPPA_MSEM_INIT */ +/* #undef HAVE_MUTEX_IA64_GCC_ASSEMBLY */ +/* #undef HAVE_MUTEX_MACOS */ +/* #undef HAVE_MUTEX_MSEM_INIT */ +/* #undef HAVE_MUTEX_PPC_GCC_ASSEMBLY */ +/* #undef HAVE_MUTEX_PTHREADS */ +/* #undef HAVE_MUTEX_RELIANTUNIX_INITSPIN */ +/* #undef HAVE_MUTEX_SCO_X86_CC_ASSEMBLY */ +/* #undef HAVE_MUTEX_SEMA_INIT */ +/* #undef HAVE_MUTEX_SGI_INIT_LOCK */ +/* #undef HAVE_MUTEX_SOLARIS_LOCK_TRY */ +/* #undef HAVE_MUTEX_SOLARIS_LWP */ +/* #undef HAVE_MUTEX_SPARC_GCC_ASSEMBLY */ +#define HAVE_MUTEX_THREADS 1 +/* #undef HAVE_MUTEX_UI_THREADS */ +/* #undef HAVE_MUTEX_UTS_CC_ASSEMBLY */ +/* #undef HAVE_MUTEX_VMS */ +/* #undef HAVE_MUTEX_VXWORKS */ +/* #undef HAVE_MUTEX_WIN16 */ +#define HAVE_MUTEX_WIN32 1 +/* #undef HAVE_MUTEX_X86_GCC_ASSEMBLY */ + +/* Define if building on QNX. */ +/* #undef HAVE_QNX */ + +/* Define if building RPC client/server. */ +/* #undef HAVE_RPC */ + +/* Define if your sprintf returns a pointer, not a length. */ +/* #undef SPRINTF_RET_CHARPNT */ + +/* Define if you have the getcwd function. */ +#define HAVE_GETCWD 1 + +/* Define if you have the getopt function. */ +/* #undef HAVE_GETOPT */ + +/* Define if you have the getuid function. */ +/* #undef HAVE_GETUID */ + +/* Define if you have the memcmp function. */ +#define HAVE_MEMCMP 1 + +/* Define if you have the memcpy function. */ +#define HAVE_MEMCPY 1 + +/* Define if you have the memmove function. */ +#define HAVE_MEMMOVE 1 + +/* Define if you have the mlock function. */ +/* #undef HAVE_MLOCK */ + +/* Define if you have the mmap function. */ +/* #undef HAVE_MMAP */ + +/* Define if you have the munlock function. */ +/* #undef HAVE_MUNLOCK */ + +/* Define if you have the munmap function. */ +/* #undef HAVE_MUNMAP */ + +/* Define if you have the pread function. */ +/* #undef HAVE_PREAD */ + +/* Define if you have the pstat_getdynamic function. */ +/* #undef HAVE_PSTAT_GETDYNAMIC */ + +/* Define if you have the pwrite function. */ +/* #undef HAVE_PWRITE */ + +/* Define if you have the qsort function. */ +#define HAVE_QSORT 1 + +/* Define if you have the raise function. */ +#define HAVE_RAISE 1 + +/* Define if you have the sched_yield function. */ +/* #undef HAVE_SCHED_YIELD */ + +/* Define if you have the select function. */ +/* #undef HAVE_SELECT */ + +/* Define if you have the shmget function. */ +/* #undef HAVE_SHMGET */ + +/* Define if you have the snprintf function. */ +#define HAVE_SNPRINTF 1 + +/* Define if you have the strcasecmp function. */ +/* #undef HAVE_STRCASECMP */ + +/* Define if you have the strerror function. */ +#define HAVE_STRERROR 1 + +/* Define if you have the strtoul function. */ +#define HAVE_STRTOUL 1 + +/* Define if you have the sysconf function. */ +/* #undef HAVE_SYSCONF */ + +/* Define if you have the vsnprintf function. */ +#define HAVE_VSNPRINTF 1 + +/* Define if you have the yield function. */ +/* #undef HAVE_YIELD */ + +/* Define if you have the header file. */ +/* #undef HAVE_DIRENT_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_NDIR_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_SELECT_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_TIME_H */ + +/* Define if you have the nsl library (-lnsl). */ +/* #undef HAVE_LIBNSL */ + +/* + * XXX + * The following is not part of the automatic configuration setup, + * but provides the information necessary to build DB on Windows. + */ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__cplusplus) +#include +#endif + +/* + * To build Tcl interface libraries, the include path must be configured to + * use the directory containing , usually the include directory in + * the Tcl distribution. + */ +#ifdef DB_TCL_SUPPORT +#include +#endif + +#define WIN32_LEAN_AND_MEAN +#include + +/* + * Win32 has fsync, getcwd, snprintf and vsnprintf, but under different names. + */ +#define fsync(fd) _commit(fd) +#define getcwd(buf, size) _getcwd(buf, size) +#define snprintf _snprintf +#define vsnprintf _vsnprintf + +/* + * Win32 does not define getopt and friends in any header file, so we must. + */ +#if defined(__cplusplus) +extern "C" { +#endif +extern int optind; +extern char *optarg; +extern int getopt(int, char * const *, const char *); +#if defined(__cplusplus) +} +#endif + +#define NO_SYSTEM_INCLUDES + +/* + * We use DB_WIN32 much as one would use _WIN32, to determine that we're + * using an operating system environment that supports Win32 calls + * and semantics. We don't use _WIN32 because cygwin/gcc also defines + * that, even though it closely emulates the Unix environment. + */ +#define DB_WIN32 1 + +/* + * This is a grievous hack -- once we've included windows.h, we have no choice + * but to use ANSI-style varargs (because it pulls in stdarg.h for us). DB's + * code decides which type of varargs to use based on the state of __STDC__. + * Sensible. Unfortunately, Microsoft's compiler _doesn't_ define __STDC__ + * unless you invoke it with arguments turning OFF all vendor extensions. Even + * more unfortunately, if we do that, it fails to parse windows.h!!!!! So, we + * define __STDC__ here, after windows.h comes in. Note: the compiler knows + * we've defined it, and starts enforcing strict ANSI compilance from this point + * on. + */ +#define __STDC__ 1 diff --git a/db/build_win32/db_deadlock.dsp b/db/build_win32/db_deadlock.dsp new file mode 100644 index 000000000..c6b42360d --- /dev/null +++ b/db/build_win32/db_deadlock.dsp @@ -0,0 +1,151 @@ +# Microsoft Developer Studio Project File - Name="db_deadlock" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=db_deadlock - Win32 Debug Static +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "db_deadlock.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "db_deadlock.mak" CFG="db_deadlock - Win32 Debug Static" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "db_deadlock - Win32 Release" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "db_deadlock - Win32 Debug" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "db_deadlock - Win32 Release Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "db_deadlock - Win32 Debug Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "db_deadlock - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release/libdb32.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"libcmt" + +!ELSEIF "$(CFG)" == "db_deadlock - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 Debug/libdb32d.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /nodefaultlib:"libcmtd" /fixed:no + +!ELSEIF "$(CFG)" == "db_deadlock - Win32 Release Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release_static" +# PROP Intermediate_Dir "Release_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Release_static/libdb32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release_static/libdb32s.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "db_deadlock - Win32 Debug Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_static" +# PROP Intermediate_Dir "Debug_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Debug_static/libdb32d.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no +# ADD LINK32 Debug_static/libdb32sd.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no + +!ENDIF + +# Begin Target + +# Name "db_deadlock - Win32 Release" +# Name "db_deadlock - Win32 Debug" +# Name "db_deadlock - Win32 Release Static" +# Name "db_deadlock - Win32 Debug Static" +# Begin Source File + +SOURCE=..\db_deadlock\db_deadlock.c +# End Source File +# Begin Source File + +SOURCE=..\clib\getopt.c +# End Source File +# End Target +# End Project diff --git a/db/build_win32/db_dll.dsp b/db/build_win32/db_dll.dsp new file mode 100644 index 000000000..8e3f53ce5 --- /dev/null +++ b/db/build_win32/db_dll.dsp @@ -0,0 +1,753 @@ +# Microsoft Developer Studio Project File - Name="db_dll" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=db_dll - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "db_dll.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "db_dll.mak" CFG="db_dll - Win32 Debug Static" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "db_dll - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "db_dll - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "db_dll - Win32 Release Static" (based on\ + "Win32 (x86) Dynamic-Link Library") +!MESSAGE "db_dll - Win32 Debug Static" (based on\ + "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "db_dll - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /Ob2 /I "." /I "../include" /D "DB_CREATE_DLL" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 /nologo /base:"0x13000000" /subsystem:windows /dll /machine:I386 /out:"Release/libdb32.dll" + +!ELSEIF "$(CFG)" == "db_dll - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 2 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "DB_CREATE_DLL" /D "CONFIG_TEST" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_MBCS" /YX"config.h" /FD /c +# SUBTRACT CPP /Fr +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /base:"0x13000000" /subsystem:windows /dll /pdb:none /debug /machine:I386 /out:"Debug/libdb32d.dll" /fixed:no + +!ELSEIF "$(CFG)" == "db_dll - Win32 Release Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "DB_DLL__" +# PROP BASE Intermediate_Dir "DB_DLL__" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /Ob2 /I "." /I "../include" /D "DB_CREATE_DLL" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /Ob2 /I "." /I "../include" /D "DB_CREATE_DLL" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /base:"0x13000000" /subsystem:windows /dll /machine:I386 /out:"Release/libdb32.dll" +# ADD LINK32 /nologo /base:"0x13000000" /subsystem:windows /dll /machine:I386 /out:"Release/libdb32.dll" + +!ELSEIF "$(CFG)" == "db_dll - Win32 Debug Static" + +# PROP BASE Use_MFC 2 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "DB_DLL_0" +# PROP BASE Intermediate_Dir "DB_DLL_0" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 2 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "DB_CREATE_DLL" /D "CONFIG_TEST" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /YX"config.h" /FD /c +# SUBTRACT BASE CPP /Fr +# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "DB_CREATE_DLL" /D "CONFIG_TEST" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_MBCS" /YX"config.h" /FD /c +# SUBTRACT CPP /Fr +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /base:"0x13000000" /subsystem:windows /dll /pdb:none /debug /machine:I386 /out:"Debug/libdb32d.dll" /fixed:no +# ADD LINK32 /nologo /base:"0x13000000" /subsystem:windows /dll /pdb:none /debug /machine:I386 /out:"Debug/libdb32d.dll" /fixed:no + +!ENDIF + +# Begin Target + +# Name "db_dll - Win32 Release" +# Name "db_dll - Win32 Debug" +# Name "db_dll - Win32 Release Static" +# Name "db_dll - Win32 Debug Static" +# Begin Source File + +SOURCE=..\btree\bt_compare.c +# End Source File +# Begin Source File + +SOURCE=..\btree\bt_conv.c +# End Source File +# Begin Source File + +SOURCE=..\btree\bt_curadj.c +# End Source File +# Begin Source File + +SOURCE=..\btree\bt_cursor.c +# End Source File +# Begin Source File + +SOURCE=..\btree\bt_delete.c +# End Source File +# Begin Source File + +SOURCE=..\btree\bt_method.c +# End Source File +# Begin Source File + +SOURCE=..\btree\bt_open.c +# End Source File +# Begin Source File + +SOURCE=..\btree\bt_put.c +# End Source File +# Begin Source File + +SOURCE=..\btree\bt_rec.c +# End Source File +# Begin Source File + +SOURCE=..\btree\bt_reclaim.c +# End Source File +# Begin Source File + +SOURCE=..\btree\bt_recno.c +# End Source File +# Begin Source File + +SOURCE=..\btree\bt_rsearch.c +# End Source File +# Begin Source File + +SOURCE=..\btree\bt_search.c +# End Source File +# Begin Source File + +SOURCE=..\btree\bt_split.c +# End Source File +# Begin Source File + +SOURCE=..\btree\bt_stat.c +# End Source File +# Begin Source File + +SOURCE=..\btree\bt_upgrade.c +# End Source File +# Begin Source File + +SOURCE=..\btree\bt_verify.c +# End Source File +# Begin Source File + +SOURCE=..\btree\btree_auto.c +# End Source File +# Begin Source File + +SOURCE=.\dllmain.c +# End Source File +# Begin Source File + +SOURCE=.\libdb.def +# End Source File +# Begin Source File + +SOURCE=.\libdb.rc +# End Source File +# Begin Source File + +SOURCE=..\clib\strcasecmp.c +# End Source File +# Begin Source File + +SOURCE=..\common\db_byteorder.c +# End Source File +# Begin Source File + +SOURCE=..\common\db_err.c +# End Source File +# Begin Source File + +SOURCE=..\common\db_getlong.c +# End Source File +# Begin Source File + +SOURCE=..\common\db_log2.c +# End Source File +# Begin Source File + +SOURCE=..\common\util_log.c +# End Source File +# Begin Source File + +SOURCE=..\common\util_sig.c +# End Source File +# Begin Source File + +SOURCE=..\cxx\cxx_app.cpp +# End Source File +# Begin Source File + +SOURCE=..\cxx\cxx_except.cpp +# End Source File +# Begin Source File + +SOURCE=..\cxx\cxx_lock.cpp +# End Source File +# Begin Source File + +SOURCE=..\cxx\cxx_log.cpp +# End Source File +# Begin Source File + +SOURCE=..\cxx\cxx_mpool.cpp +# End Source File +# Begin Source File + +SOURCE=..\cxx\cxx_table.cpp +# End Source File +# Begin Source File + +SOURCE=..\cxx\cxx_txn.cpp +# End Source File +# Begin Source File + +SOURCE=..\db\crdel_auto.c +# End Source File +# Begin Source File + +SOURCE=..\db\crdel_rec.c +# End Source File +# Begin Source File + +SOURCE=..\db\db.c +# End Source File +# Begin Source File + +SOURCE=..\db\db_am.c +# End Source File +# Begin Source File + +SOURCE=..\db\db_auto.c +# End Source File +# Begin Source File + +SOURCE=..\db\db_cam.c +# End Source File +# Begin Source File + +SOURCE=..\db\db_conv.c +# End Source File +# Begin Source File + +SOURCE=..\db\db_dispatch.c +# End Source File +# Begin Source File + +SOURCE=..\db\db_dup.c +# End Source File +# Begin Source File + +SOURCE=..\db\db_iface.c +# End Source File +# Begin Source File + +SOURCE=..\db\db_join.c +# End Source File +# Begin Source File + +SOURCE=..\db\db_meta.c +# End Source File +# Begin Source File + +SOURCE=..\db\db_method.c +# End Source File +# Begin Source File + +SOURCE=..\db\db_overflow.c +# End Source File +# Begin Source File + +SOURCE=..\db\db_pr.c +# End Source File +# Begin Source File + +SOURCE=..\db\db_rec.c +# End Source File +# Begin Source File + +SOURCE=..\db\db_reclaim.c +# End Source File +# Begin Source File + +SOURCE=..\db\db_ret.c +# End Source File +# Begin Source File + +SOURCE=..\db\db_upg.c +# End Source File +# Begin Source File + +SOURCE=..\db\db_upg_opd.c +# End Source File +# Begin Source File + +SOURCE=..\db\db_vrfy.c +# End Source File +# Begin Source File + +SOURCE=..\db\db_vrfyutil.c +# End Source File +# Begin Source File + +SOURCE=..\dbm\dbm.c +# End Source File +# Begin Source File + +SOURCE=..\env\db_salloc.c +# End Source File +# Begin Source File + +SOURCE=..\env\db_shash.c +# End Source File +# Begin Source File + +SOURCE=..\env\env_method.c +# End Source File +# Begin Source File + +SOURCE=..\env\env_open.c +# End Source File +# Begin Source File + +SOURCE=..\env\env_recover.c +# End Source File +# Begin Source File + +SOURCE=..\env\env_region.c +# End Source File +# Begin Source File + +SOURCE=..\hash\hash.c +# End Source File +# Begin Source File + +SOURCE=..\hash\hash_auto.c +# End Source File +# Begin Source File + +SOURCE=..\hash\hash_conv.c +# End Source File +# Begin Source File + +SOURCE=..\hash\hash_dup.c +# End Source File +# Begin Source File + +SOURCE=..\hash\hash_func.c +# End Source File +# Begin Source File + +SOURCE=..\hash\hash_meta.c +# End Source File +# Begin Source File + +SOURCE=..\hash\hash_method.c +# End Source File +# Begin Source File + +SOURCE=..\hash\hash_page.c +# End Source File +# Begin Source File + +SOURCE=..\hash\hash_rec.c +# End Source File +# Begin Source File + +SOURCE=..\hash\hash_reclaim.c +# End Source File +# Begin Source File + +SOURCE=..\hash\hash_stat.c +# End Source File +# Begin Source File + +SOURCE=..\hash\hash_upgrade.c +# End Source File +# Begin Source File + +SOURCE=..\hash\hash_verify.c +# End Source File +# Begin Source File + +SOURCE=..\hsearch\hsearch.c +# End Source File +# Begin Source File + +SOURCE=..\lock\lock.c +# End Source File +# Begin Source File + +SOURCE=..\lock\lock_conflict.c +# End Source File +# Begin Source File + +SOURCE=..\lock\lock_deadlock.c +# End Source File +# Begin Source File + +SOURCE=..\lock\lock_method.c +# End Source File +# Begin Source File + +SOURCE=..\lock\lock_region.c +# End Source File +# Begin Source File + +SOURCE=..\lock\lock_stat.c +# End Source File +# Begin Source File + +SOURCE=..\lock\lock_util.c +# End Source File +# Begin Source File + +SOURCE=..\log\log.c +# End Source File +# Begin Source File + +SOURCE=..\log\log_archive.c +# End Source File +# Begin Source File + +SOURCE=..\log\log_auto.c +# End Source File +# Begin Source File + +SOURCE=..\log\log_compare.c +# End Source File +# Begin Source File + +SOURCE=..\log\log_findckp.c +# End Source File +# Begin Source File + +SOURCE=..\log\log_get.c +# End Source File +# Begin Source File + +SOURCE=..\log\log_method.c +# End Source File +# Begin Source File + +SOURCE=..\log\log_put.c +# End Source File +# Begin Source File + +SOURCE=..\log\log_rec.c +# End Source File +# Begin Source File + +SOURCE=..\log\log_register.c +# End Source File +# Begin Source File + +SOURCE=..\mp\mp_alloc.c +# End Source File +# Begin Source File + +SOURCE=..\mp\mp_bh.c +# End Source File +# Begin Source File + +SOURCE=..\mp\mp_fget.c +# End Source File +# Begin Source File + +SOURCE=..\mp\mp_fopen.c +# End Source File +# Begin Source File + +SOURCE=..\mp\mp_fput.c +# End Source File +# Begin Source File + +SOURCE=..\mp\mp_fset.c +# End Source File +# Begin Source File + +SOURCE=..\mp\mp_method.c +# End Source File +# Begin Source File + +SOURCE=..\mp\mp_region.c +# End Source File +# Begin Source File + +SOURCE=..\mp\mp_register.c +# End Source File +# Begin Source File + +SOURCE=..\mp\mp_stat.c +# End Source File +# Begin Source File + +SOURCE=..\mp\mp_sync.c +# End Source File +# Begin Source File + +SOURCE=..\mp\mp_trickle.c +# End Source File +# Begin Source File + +SOURCE=..\mutex\mut_tas.c +# End Source File +# Begin Source File + +SOURCE=..\mutex\mutex.c +# End Source File +# Begin Source File + +SOURCE=..\os\os_alloc.c +# End Source File +# Begin Source File + +SOURCE=..\os\os_fsync.c +# End Source File +# Begin Source File + +SOURCE=..\os\os_handle.c +# End Source File +# Begin Source File + +SOURCE=..\os\os_method.c +# End Source File +# Begin Source File + +SOURCE=..\os\os_oflags.c +# End Source File +# Begin Source File + +SOURCE=..\os\os_region.c +# End Source File +# Begin Source File + +SOURCE=..\os\os_root.c +# End Source File +# Begin Source File + +SOURCE=..\os\os_rpath.c +# End Source File +# Begin Source File + +SOURCE=..\os\os_rw.c +# End Source File +# Begin Source File + +SOURCE=..\os\os_stat.c +# End Source File +# Begin Source File + +SOURCE=..\os\os_tmpdir.c +# End Source File +# Begin Source File + +SOURCE=..\os\os_unlink.c +# End Source File +# Begin Source File + +SOURCE=..\os_win32\os_abs.c +# End Source File +# Begin Source File + +SOURCE=..\os_win32\os_dir.c +# End Source File +# Begin Source File + +SOURCE=..\os_win32\os_errno.c +# End Source File +# Begin Source File + +SOURCE=..\os_win32\os_fid.c +# End Source File +# Begin Source File + +SOURCE=..\os_win32\os_finit.c +# End Source File +# Begin Source File + +SOURCE=..\os_win32\os_map.c +# End Source File +# Begin Source File + +SOURCE=..\os_win32\os_open.c +# End Source File +# Begin Source File + +SOURCE=..\os_win32\os_rename.c +# End Source File +# Begin Source File + +SOURCE=..\os_win32\os_seek.c +# End Source File +# Begin Source File + +SOURCE=..\os_win32\os_sleep.c +# End Source File +# Begin Source File + +SOURCE=..\os_win32\os_spin.c +# End Source File +# Begin Source File + +SOURCE=..\os_win32\os_type.c +# End Source File +# Begin Source File + +SOURCE=..\qam\qam.c +# End Source File +# Begin Source File + +SOURCE=..\qam\qam_auto.c +# End Source File +# Begin Source File + +SOURCE=..\qam\qam_conv.c +# End Source File +# Begin Source File + +SOURCE=..\qam\qam_files.c +# End Source File +# Begin Source File + +SOURCE=..\qam\qam_method.c +# End Source File +# Begin Source File + +SOURCE=..\qam\qam_open.c +# End Source File +# Begin Source File + +SOURCE=..\qam\qam_rec.c +# End Source File +# Begin Source File + +SOURCE=..\qam\qam_stat.c +# End Source File +# Begin Source File + +SOURCE=..\qam\qam_upgrade.c +# End Source File +# Begin Source File + +SOURCE=..\qam\qam_verify.c +# End Source File +# Begin Source File + +SOURCE=..\txn\txn.c +# End Source File +# Begin Source File + +SOURCE=..\txn\txn_auto.c +# End Source File +# Begin Source File + +SOURCE=..\txn\txn_rec.c +# End Source File +# Begin Source File + +SOURCE=..\txn\txn_region.c +# End Source File +# Begin Source File + +SOURCE=..\xa\xa.c +# End Source File +# Begin Source File + +SOURCE=..\xa\xa_db.c +# End Source File +# Begin Source File + +SOURCE=..\xa\xa_map.c +# End Source File +# End Target +# End Project diff --git a/db/build_win32/db_dump.dsp b/db/build_win32/db_dump.dsp new file mode 100644 index 000000000..977c30f70 --- /dev/null +++ b/db/build_win32/db_dump.dsp @@ -0,0 +1,151 @@ +# Microsoft Developer Studio Project File - Name="db_dump" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=db_dump - Win32 Debug Static +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "db_dump.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "db_dump.mak" CFG="db_dump - Win32 Debug Static" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "db_dump - Win32 Release" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "db_dump - Win32 Debug" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "db_dump - Win32 Release Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "db_dump - Win32 Debug Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "db_dump - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release/libdb32.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"libcmt" + +!ELSEIF "$(CFG)" == "db_dump - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 Debug/libdb32d.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /nodefaultlib:"libcmtd" /fixed:no + +!ELSEIF "$(CFG)" == "db_dump - Win32 Release Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release_static" +# PROP Intermediate_Dir "Release_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Release_static/libdb32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release_static/libdb32s.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "db_dump - Win32 Debug Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_static" +# PROP Intermediate_Dir "Debug_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Debug_static/libdb32d.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no +# ADD LINK32 Debug_static/libdb32sd.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no + +!ENDIF + +# Begin Target + +# Name "db_dump - Win32 Release" +# Name "db_dump - Win32 Debug" +# Name "db_dump - Win32 Release Static" +# Name "db_dump - Win32 Debug Static" +# Begin Source File + +SOURCE=..\db_dump\db_dump.c +# End Source File +# Begin Source File + +SOURCE=..\clib\getopt.c +# End Source File +# End Target +# End Project diff --git a/db/build_win32/db_int.h b/db/build_win32/db_int.h new file mode 100644 index 000000000..0eb4309fc --- /dev/null +++ b/db/build_win32/db_int.h @@ -0,0 +1,398 @@ +/* DO NOT EDIT: automatically built by dist/s_win32. */ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: db_int.src,v 11.42 2001/01/11 17:49:17 krinsky Exp $ + */ + +#ifndef _DB_INTERNAL_H_ +#define _DB_INTERNAL_H_ + +/******************************************************* + * General includes. + *******************************************************/ +#include "db.h" + +#ifndef NO_SYSTEM_INCLUDES +#if defined(__STDC__) || defined(__cplusplus) +#include +#else +#include +#endif +#include +#endif + +#include "queue.h" +#include "shqueue.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +/******************************************************* + * General purpose constants and macros. + *******************************************************/ +#define UINT16_T_MAX 0xffff /* Maximum 16 bit unsigned. */ +#define UINT32_T_MAX 0xffffffff /* Maximum 32 bit unsigned. */ + +#define MEGABYTE 1048576 +#define GIGABYTE 1073741824 + +#define MS_PER_SEC 1000 /* Milliseconds in a second. */ +#define USEC_PER_MS 1000 /* Microseconds in a millisecond. */ + +#define DB_MIN_PGSIZE 0x000200 /* Minimum page size (512). */ +#define DB_MAX_PGSIZE 0x010000 /* Maximum page size (65536). */ + +#define RECNO_OOB 0 /* Illegal record number. */ + +/* + * If we are unable to determine the underlying filesystem block size, use + * 8K on the grounds that most OS's use less than 8K for a VM page size. + */ +#define DB_DEF_IOSIZE (8 * 1024) + +/* + * Aligning items to particular sizes or in pages or memory. + * + * db_align_t -- + * Largest integral type, used to align structures in memory. We don't store + * floating point types in structures, so integral types should be sufficient + * (and we don't have to worry about systems that store floats in other than + * power-of-2 numbers of bytes). Additionally this fixes compiler that rewrite + * structure assignments and ANSI C memcpy calls to be in-line instructions + * that happen to require alignment. Note: this alignment isn't sufficient for + * mutexes, which depend on things like cache line alignment. Mutex alignment + * is handled separately, in mutex.h. + * + * db_alignp_t -- + * Integral type that's the same size as a pointer. There are places where + * DB modifies pointers by discarding the bottom bits to guarantee alignment. + * We can't use db_align_t, it may be larger than the pointer, and compilers + * get upset about that. So far we haven't run on any machine where there + * isn't an integral type the same size as a pointer -- here's hoping. + */ +typedef unsigned long db_align_t; +typedef unsigned long db_alignp_t; + +/* Align an integer to a specific boundary. */ +#undef ALIGN +#define ALIGN(value, bound) \ + (((value) + (bound) - 1) & ~(((u_int)bound) - 1)) + +/* Align a pointer to a specific boundary. */ +#undef ALIGNP +#define ALIGNP(value, bound) ALIGN((db_alignp_t)value, bound) + +/* + * There are several on-page structures that are declared to have a number of + * fields followed by a variable length array of items. The structure size + * without including the variable length array or the address of the first of + * those elements can be found using SSZ. + * + * This macro can also be used to find the offset of a structure element in a + * structure. This is used in various places to copy structure elements from + * unaligned memory references, e.g., pointers into a packed page. + * + * There are two versions because compilers object if you take the address of + * an array. + */ +#undef SSZ +#define SSZ(name, field) ((int)&(((name *)0)->field)) + +#undef SSZA +#define SSZA(name, field) ((int)&(((name *)0)->field[0])) + +/* + * Print an address as a u_long (a u_long is the largest type we can print + * portably). Most 64-bit systems have made longs 64-bits, so this should + * work. + */ +#define P_TO_ULONG(p) ((u_long)(db_alignp_t)(p)) + +/* Structure used to print flag values. */ +typedef struct __fn { + u_int32_t mask; /* Flag value. */ + const char *name; /* Flag name. */ +} FN; + +/* Set, clear and test flags. */ +#define FLD_CLR(fld, f) (fld) &= ~(f) +#define FLD_ISSET(fld, f) ((fld) & (f)) +#define FLD_SET(fld, f) (fld) |= (f) +#define F_CLR(p, f) (p)->flags &= ~(f) +#define F_ISSET(p, f) ((p)->flags & (f)) +#define F_SET(p, f) (p)->flags |= (f) +#define LF_CLR(f) (flags &= ~(f)) +#define LF_ISSET(f) (flags & (f)) +#define LF_SET(f) (flags |= (f)) + +/* Display separator string. */ +#undef DB_LINE +#define DB_LINE "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=" + +/* Unused, or not-used-yet variable. "Shut that bloody compiler up!" */ +#define COMPQUIET(n, v) (n) = (v) + +/******************************************************* + * Files. + *******************************************************/ + /* + * We use 1024 as the maximum path length. It's too hard to figure out what + * the real path length is, as it was traditionally stored in , + * and that file isn't always available. + */ +#undef MAXPATHLEN +#define MAXPATHLEN 1024 + +#define PATH_DOT "." /* Current working directory. */ +#define PATH_SEPARATOR "\\/:" /* Path separator character. */ + +/* + * Flags understood by __os_open. + */ +#define DB_OSO_CREATE 0x001 /* POSIX: O_CREAT */ +#define DB_OSO_EXCL 0x002 /* POSIX: O_EXCL */ +#define DB_OSO_LOG 0x004 /* Opening a log file. */ +#define DB_OSO_RDONLY 0x008 /* POSIX: O_RDONLY */ +#define DB_OSO_REGION 0x010 /* Opening a region file. */ +#define DB_OSO_SEQ 0x020 /* Expected sequential access. */ +#define DB_OSO_TEMP 0x040 /* Remove after last close. */ +#define DB_OSO_TRUNC 0x080 /* POSIX: O_TRUNC */ + +/* + * Seek options understood by __os_seek. + */ +typedef enum { + DB_OS_SEEK_CUR, /* POSIX: SEEK_CUR */ + DB_OS_SEEK_END, /* POSIX: SEEK_END */ + DB_OS_SEEK_SET /* POSIX: SEEK_SET */ +} DB_OS_SEEK; + +/******************************************************* + * Environment. + *******************************************************/ +/* Type passed to __db_appname(). */ +typedef enum { + DB_APP_NONE=0, /* No type (region). */ + DB_APP_DATA, /* Data file. */ + DB_APP_LOG, /* Log file. */ + DB_APP_TMP /* Temporary file. */ +} APPNAME; + +/* + * CDB_LOCKING CDB product locking. + * LOCKING_ON Locking has been configured. + * LOGGING_ON Logging has been configured. + * MPOOL_ON Memory pool has been configured. + * TXN_ON Transactions have been configured. + */ +#define CDB_LOCKING(dbenv) F_ISSET(dbenv, DB_ENV_CDB) +#define LOCKING_ON(dbenv) ((dbenv)->lk_handle != NULL) +#define LOGGING_ON(dbenv) ((dbenv)->lg_handle != NULL) +#define MPOOL_ON(dbenv) ((dbenv)->mp_handle != NULL) +#define TXN_ON(dbenv) ((dbenv)->tx_handle != NULL) + +/* + * STD_LOCKING Standard locking, that is, locking was configured and CDB + * was not. We do not do locking in off-page duplicate trees, + * so we check for that in the cursor first. + */ +#define STD_LOCKING(dbc) \ + (!F_ISSET(dbc, DBC_OPD) && \ + !CDB_LOCKING((dbc)->dbp->dbenv) && LOCKING_ON((dbc)->dbp->dbenv)) + +/* + * IS_RECOVERING The system is running recovery. + */ +#define IS_RECOVERING(dbenv) \ + (LOGGING_ON(dbenv) && \ + F_ISSET((DB_LOG *)(dbenv)->lg_handle, DBLOG_RECOVER)) + +/* Most initialization methods cannot be called after open is called. */ +#define ENV_ILLEGAL_AFTER_OPEN(dbenv, name) \ + if (F_ISSET((dbenv), DB_ENV_OPEN_CALLED)) \ + return (__db_mi_open(dbenv, name, 1)); + +/* We're not actually user hostile, honest. */ +#define ENV_REQUIRES_CONFIG(dbenv, handle, subsystem) \ + if (handle == NULL) \ + return (__db_env_config(dbenv, subsystem)); + +/******************************************************* + * Database Access Methods. + *******************************************************/ +/* + * DB_IS_THREADED -- + * The database handle is free-threaded (was opened with DB_THREAD). + */ +#define DB_IS_THREADED(dbp) \ + ((dbp)->mutexp != NULL) + +/* Initialization methods are often illegal before/after open is called. */ +#define DB_ILLEGAL_AFTER_OPEN(dbp, name) \ + if (F_ISSET((dbp), DB_OPEN_CALLED)) \ + return (__db_mi_open(dbp->dbenv, name, 1)); +#define DB_ILLEGAL_BEFORE_OPEN(dbp, name) \ + if (!F_ISSET((dbp), DB_OPEN_CALLED)) \ + return (__db_mi_open(dbp->dbenv, name, 0)); +/* Some initialization methods are illegal if environment isn't local. */ +#define DB_ILLEGAL_IN_ENV(dbp, name) \ + if (!F_ISSET(dbp->dbenv, DB_ENV_DBLOCAL)) \ + return (__db_mi_env(dbp->dbenv, name)); +#define DB_ILLEGAL_METHOD(dbp, flags) { \ + int __ret; \ + if ((__ret = __dbh_am_chk(dbp, flags)) != 0) \ + return (__ret); \ +} + +/* + * Common DBC->internal fields. Each access method adds additional fields + * to this list, but the initial fields are common. + */ +#define __DBC_INTERNAL \ + DBC *opd; /* Off-page duplicate cursor. */\ + \ + void *page; /* Referenced page. */ \ + db_pgno_t root; /* Tree root. */ \ + db_pgno_t pgno; /* Referenced page number. */ \ + db_indx_t indx; /* Referenced key item index. */\ + \ + DB_LOCK lock; /* Cursor lock. */ \ + db_lockmode_t lock_mode; /* Lock mode. */ + +struct __dbc_internal { + __DBC_INTERNAL +}; + +/* + * Access-method-common macro for determining whether a cursor + * has been initialized. + */ +#define IS_INITIALIZED(dbc) ((dbc)->internal->pgno != PGNO_INVALID) + +/******************************************************* + * Mpool. + *******************************************************/ +/* + * File types for DB access methods. Negative numbers are reserved to DB. + */ +#define DB_FTYPE_SET -1 /* Call pgin/pgout functions. */ +#define DB_FTYPE_NOTSET 0 /* Don't call... */ + +/* Structure used as the DB pgin/pgout pgcookie. */ +typedef struct __dbpginfo { + size_t db_pagesize; /* Underlying page size. */ + int needswap; /* If swapping required. */ +} DB_PGINFO; + +/******************************************************* + * Log. + *******************************************************/ +/* Initialize an LSN to 'zero'. */ +#define ZERO_LSN(LSN) do { \ + (LSN).file = 0; \ + (LSN).offset = 0; \ +} while (0) + +/* Return 1 if LSN is a 'zero' lsn, otherwise return 0. */ +#define IS_ZERO_LSN(LSN) ((LSN).file == 0) + +/* Test if we need to log a change. */ +#define DB_LOGGING(dbc) \ + (LOGGING_ON((dbc)->dbp->dbenv) && !F_ISSET(dbc, DBC_RECOVER)) + +/* Internal flag for use with internal __log_unregister. */ +#define DB_LOGONLY 0x01 +/******************************************************* + * Txn. + *******************************************************/ +#define DB_NONBLOCK(C) ((C)->txn != NULL && F_ISSET((C)->txn, TXN_NOWAIT)) +#define IS_SUBTRANSACTION(txn) \ + ((txn) != NULL && (txn)->parent != NULL) + +/******************************************************* + * Global variables. + *******************************************************/ +#ifdef HAVE_VXWORKS +#include "semLib.h" +#endif + +/* + * DB global variables. Done in a single structure to minimize the name-space + * pollution. + */ +typedef struct __db_globals { + u_int32_t db_pageyield; /* db_set_pageyield */ + u_int32_t db_panic; /* db_set_panic */ + u_int32_t db_region_init; /* db_set_region_init */ + u_int32_t db_tas_spins; /* db_set_tas_spins */ +#ifdef HAVE_VXWORKS + u_int32_t db_global_init; /* VxWorks: inited */ + SEM_ID db_global_lock; /* VxWorks: global semaphore */ +#endif + /* XA: list of opened environments. */ + TAILQ_HEAD(__db_envq, __db_env) db_envq; +} DB_GLOBALS; + +#ifdef DB_INITIALIZE_DB_GLOBALS +DB_GLOBALS __db_global_values = { + 0, /* db_set_pageyield */ + 1, /* db_set_panic */ + 0, /* db_set_region_init */ + 0, /* db_set_tas_spins */ +#ifdef HAVE_VXWORKS + 0, /* db_global_init */ + NULL, /* db_global_lock */ +#endif + /* XA environment queue */ + {NULL, &__db_global_values.db_envq.tqh_first} +}; +#else +extern DB_GLOBALS __db_global_values; +#endif +#define DB_GLOBAL(v) __db_global_values.v + +/* Forward structure declarations. */ +struct __db_reginfo_t; typedef struct __db_reginfo_t REGINFO; +struct __mutex_t; typedef struct __mutex_t MUTEX; +struct __vrfy_childinfo; typedef struct __vrfy_childinfo VRFY_CHILDINFO; +struct __vrfy_dbinfo; typedef struct __vrfy_dbinfo VRFY_DBINFO; +struct __vrfy_pageinfo; typedef struct __vrfy_pageinfo VRFY_PAGEINFO; +struct __db_txnlist; typedef struct __db_txnlist DB_TXNLIST; +struct __db_txnhead; typedef struct __db_txnhead DB_TXNHEAD; +typedef enum { + TXNLIST_DELETE, + TXNLIST_LSN, + TXNLIST_TXNID, + TXNLIST_PGNO +} db_txnlist_type; + +/* + * Currently, region offsets are limited to 32-bits. I expect that's going + * to have to be fixed in the not-too-distant future, since we won't want to + * split 100Gb memory pools into that many different regions. It's typedef'd + * so it won't be too painful to upgrade. + */ +typedef u_int32_t roff_t; + +#if defined(__cplusplus) +} +#endif + +/******************************************************* + * More general includes. + *******************************************************/ +#include "debug.h" +#include "mutex.h" +#include "region.h" +#include "mutex_ext.h" +#include "env_ext.h" +#include "os.h" +#include "os_ext.h" +#include "common_ext.h" + +#endif /* !_DB_INTERNAL_H_ */ diff --git a/db/build_win32/db_java.dsp b/db/build_win32/db_java.dsp new file mode 100644 index 000000000..d1b7e6a91 --- /dev/null +++ b/db/build_win32/db_java.dsp @@ -0,0 +1,174 @@ +# Microsoft Developer Studio Project File - Name="db_java" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=db_java - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "db_java.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "db_java.mak" CFG="db_java - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "db_java - Win32 Release" (based on\ + "Win32 (x86) Dynamic-Link Library") +!MESSAGE "db_java - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "db_java - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /Ob2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "DB_CREATE_DLL" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 Release/libdb32.lib /nologo /base:"0x13000000" /subsystem:windows /dll /machine:I386 /out:"Release/libdb_java32.dll" +# Begin Custom Build - Compiling java files using javac +ProjDir=. +InputPath=.\Release\libdb_java32.dll +SOURCE=$(InputPath) + +"force_compilation.txt" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd $(ProjDir)\..\java\src\com\sleepycat\db + mkdir ..\..\..\..\classes + echo compiling Berkeley DB classes + javac -d ../../../../classes -classpath "$(CLASSPATH);../../../../classes"\ + *.java + echo compiling examples + cd ..\examples + javac -d ../../../../classes -classpath "$(CLASSPATH);../../../../classes"\ + *.java + echo creating jar file + cd ..\..\..\..\classes + jar cf db.jar com\sleepycat\db\*.class + echo Java build finished + +# End Custom Build + +!ELSEIF "$(CFG)" == "db_java - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 2 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "DB_CREATE_DLL" /D "_WINDLL" /D "_AFXDLL" /YX"config.h" /FD /c +# SUBTRACT CPP /Fr +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 Debug/libdb32d.lib /nologo /base:"0x13000000" /subsystem:windows /dll /pdb:none /debug /machine:I386 /out:"Debug/libdb_java32d.dll" /fixed:no +# Begin Custom Build - Compiling java files using javac +ProjDir=. +InputPath=.\Debug\libdb_java32d.dll +SOURCE=$(InputPath) + +"force_compilation.txt" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd $(ProjDir)\..\java\src\com\sleepycat\db + mkdir ..\..\..\..\classes + echo compiling Berkeley DB classes + javac -g -d ../../../../classes -classpath "$(CLASSPATH);../../../../classes"\ + *.java + echo compiling examples + javac -g -d ../../../../classes -classpath "$(CLASSPATH);../../../../classes"\ + *.java + cd ..\examples + echo creating jar file + cd ..\..\..\..\classes + jar cf db.jar com\sleepycat\db\*.class + echo Java build finished + +# End Custom Build + +!ENDIF + +# Begin Target + +# Name "db_java - Win32 Release" +# Name "db_java - Win32 Debug" +# Begin Source File + +SOURCE=..\libdb_java\java_Db.c +# End Source File +# Begin Source File + +SOURCE=..\libdb_java\java_DbEnv.c +# End Source File +# Begin Source File + +SOURCE=..\libdb_java\java_DbLock.c +# End Source File +# Begin Source File + +SOURCE=..\libdb_java\java_DbLsn.c +# End Source File +# Begin Source File + +SOURCE=..\libdb_java\java_DbTxn.c +# End Source File +# Begin Source File + +SOURCE=..\libdb_java\java_Dbc.c +# End Source File +# Begin Source File + +SOURCE=..\libdb_java\java_Dbt.c +# End Source File +# Begin Source File + +SOURCE=..\libdb_java\java_info.c +# End Source File +# Begin Source File + +SOURCE=..\libdb_java\java_locked.c +# End Source File +# Begin Source File + +SOURCE=..\libdb_java\java_util.c +# End Source File +# End Target +# End Project diff --git a/db/build_win32/db_load.dsp b/db/build_win32/db_load.dsp new file mode 100644 index 000000000..5dc199dca --- /dev/null +++ b/db/build_win32/db_load.dsp @@ -0,0 +1,151 @@ +# Microsoft Developer Studio Project File - Name="db_load" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=db_load - Win32 Debug Static +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "db_load.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "db_load.mak" CFG="db_load - Win32 Debug Static" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "db_load - Win32 Release" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "db_load - Win32 Debug" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "db_load - Win32 Release Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "db_load - Win32 Debug Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "db_load - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release/libdb32.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"libcmt" + +!ELSEIF "$(CFG)" == "db_load - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 Debug/libdb32d.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /nodefaultlib:"libcmtd" /fixed:no + +!ELSEIF "$(CFG)" == "db_load - Win32 Release Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release_static" +# PROP Intermediate_Dir "Release_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Release_static/libdb32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release_static/libdb32s.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "db_load - Win32 Debug Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_static" +# PROP Intermediate_Dir "Debug_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Debug_static/libdb32d.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no +# ADD LINK32 Debug_static/libdb32sd.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no + +!ENDIF + +# Begin Target + +# Name "db_load - Win32 Release" +# Name "db_load - Win32 Debug" +# Name "db_load - Win32 Release Static" +# Name "db_load - Win32 Debug Static" +# Begin Source File + +SOURCE=..\db_load\db_load.c +# End Source File +# Begin Source File + +SOURCE=..\clib\getopt.c +# End Source File +# End Target +# End Project diff --git a/db/build_win32/db_printlog.dsp b/db/build_win32/db_printlog.dsp new file mode 100644 index 000000000..b3e69c975 --- /dev/null +++ b/db/build_win32/db_printlog.dsp @@ -0,0 +1,151 @@ +# Microsoft Developer Studio Project File - Name="db_printlog" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=db_printlog - Win32 Debug Static +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "db_printlog.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "db_printlog.mak" CFG="db_printlog - Win32 Debug Static" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "db_printlog - Win32 Release" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "db_printlog - Win32 Debug" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "db_printlog - Win32 Release Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "db_printlog - Win32 Debug Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "db_printlog - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release/libdb32.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"libcmt" + +!ELSEIF "$(CFG)" == "db_printlog - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 Debug/libdb32d.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /nodefaultlib:"libcmtd" /fixed:no + +!ELSEIF "$(CFG)" == "db_printlog - Win32 Release Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release_static" +# PROP Intermediate_Dir "Release_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Release_static/libdb32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release_static/libdb32s.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "db_printlog - Win32 Debug Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_static" +# PROP Intermediate_Dir "Debug_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Debug_static/libdb32d.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no +# ADD LINK32 Debug_static/libdb32sd.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no + +!ENDIF + +# Begin Target + +# Name "db_printlog - Win32 Release" +# Name "db_printlog - Win32 Debug" +# Name "db_printlog - Win32 Release Static" +# Name "db_printlog - Win32 Debug Static" +# Begin Source File + +SOURCE=..\db_printlog\db_printlog.c +# End Source File +# Begin Source File + +SOURCE=..\clib\getopt.c +# End Source File +# End Target +# End Project diff --git a/db/build_win32/db_recover.dsp b/db/build_win32/db_recover.dsp new file mode 100644 index 000000000..4260e8cef --- /dev/null +++ b/db/build_win32/db_recover.dsp @@ -0,0 +1,151 @@ +# Microsoft Developer Studio Project File - Name="db_recover" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=db_recover - Win32 Debug Static +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "db_recover.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "db_recover.mak" CFG="db_recover - Win32 Debug Static" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "db_recover - Win32 Release" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "db_recover - Win32 Debug" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "db_recover - Win32 Release Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "db_recover - Win32 Debug Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "db_recover - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release/libdb32.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"libcmt" + +!ELSEIF "$(CFG)" == "db_recover - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 Debug/libdb32d.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /nodefaultlib:"libcmtd" /fixed:no + +!ELSEIF "$(CFG)" == "db_recover - Win32 Release Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release_static" +# PROP Intermediate_Dir "Release_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Release_static/libdb32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release_static/libdb32s.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "db_recover - Win32 Debug Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_static" +# PROP Intermediate_Dir "Debug_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Debug_static/libdb32d.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no +# ADD LINK32 Debug_static/libdb32sd.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no + +!ENDIF + +# Begin Target + +# Name "db_recover - Win32 Release" +# Name "db_recover - Win32 Debug" +# Name "db_recover - Win32 Release Static" +# Name "db_recover - Win32 Debug Static" +# Begin Source File + +SOURCE=..\db_recover\db_recover.c +# End Source File +# Begin Source File + +SOURCE=..\clib\getopt.c +# End Source File +# End Target +# End Project diff --git a/db/build_win32/db_stat.dsp b/db/build_win32/db_stat.dsp new file mode 100644 index 000000000..630c4a6cf --- /dev/null +++ b/db/build_win32/db_stat.dsp @@ -0,0 +1,151 @@ +# Microsoft Developer Studio Project File - Name="db_stat" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=db_stat - Win32 Debug Static +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "db_stat.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "db_stat.mak" CFG="db_stat - Win32 Debug Static" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "db_stat - Win32 Release" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "db_stat - Win32 Debug" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "db_stat - Win32 Release Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "db_stat - Win32 Debug Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "db_stat - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release/libdb32.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"libcmt" + +!ELSEIF "$(CFG)" == "db_stat - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 Debug/libdb32d.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /nodefaultlib:"libcmtd" /fixed:no + +!ELSEIF "$(CFG)" == "db_stat - Win32 Release Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release_static" +# PROP Intermediate_Dir "Release_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Release_static/libdb32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release_static/libdb32s.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "db_stat - Win32 Debug Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_static" +# PROP Intermediate_Dir "Debug_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Debug_static/libdb32d.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no +# ADD LINK32 Debug_static/libdb32sd.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no + +!ENDIF + +# Begin Target + +# Name "db_stat - Win32 Release" +# Name "db_stat - Win32 Debug" +# Name "db_stat - Win32 Release Static" +# Name "db_stat - Win32 Debug Static" +# Begin Source File + +SOURCE=..\db_stat\db_stat.c +# End Source File +# Begin Source File + +SOURCE=..\clib\getopt.c +# End Source File +# End Target +# End Project diff --git a/db/build_win32/db_static.dsp b/db/build_win32/db_static.dsp new file mode 100644 index 000000000..69c3349c8 --- /dev/null +++ b/db/build_win32/db_static.dsp @@ -0,0 +1,714 @@ +# Microsoft Developer Studio Project File - Name="db_static" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=db_static - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "db_static.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "db_static.mak" CFG="db_static - Win32 Debug Static" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "db_static - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "db_static - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "db_static - Win32 Release Static" (based on\ + "Win32 (x86) Static Library") +!MESSAGE "db_static - Win32 Debug Static" (based on\ + "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe + +!IF "$(CFG)" == "db_static - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "DB_Stati" +# PROP BASE Intermediate_Dir "DB_Stati" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release_static" +# PROP Intermediate_Dir "Release_static" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX"config.h" /FD /c +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"Release_static/libdb32s.lib" + +!ELSEIF "$(CFG)" == "db_static - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "DB_Stat0" +# PROP BASE Intermediate_Dir "DB_Stat0" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_static" +# PROP Intermediate_Dir "Debug_static" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /GX /Z7 /Od /I "." /I "../include" /D "CONFIG_TEST" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX"config.h" /FD /c +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"Debug_static/libdb32sd.lib" + +!ELSEIF "$(CFG)" == "db_static - Win32 Release Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "DB_Stati" +# PROP BASE Intermediate_Dir "DB_Stati" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release_static" +# PROP Intermediate_Dir "Release_static" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX"config.h" /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX"config.h" /FD /c +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"Release/libdb32s.lib" +# ADD LIB32 /nologo /out:"Release_static/libdb32s.lib" + +!ELSEIF "$(CFG)" == "db_static - Win32 Debug Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "DB_Stat0" +# PROP BASE Intermediate_Dir "DB_Stat0" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_static" +# PROP Intermediate_Dir "Debug_static" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /GX /Z7 /Od /I "." /I "../include" /D "CONFIG_TEST" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX"config.h" /FD /c +# ADD CPP /nologo /MTd /W3 /GX /Z7 /Od /I "." /I "../include" /D "CONFIG_TEST" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX"config.h" /FD /c +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"Debug/libdb32sd.lib" +# ADD LIB32 /nologo /out:"Debug_static/libdb32sd.lib" + +!ENDIF + +# Begin Target + +# Name "db_static - Win32 Release" +# Name "db_static - Win32 Debug" +# Name "db_static - Win32 Release Static" +# Name "db_static - Win32 Debug Static" +# Begin Source File + +SOURCE=..\btree\bt_compare.c +# End Source File +# Begin Source File + +SOURCE=..\btree\bt_conv.c +# End Source File +# Begin Source File + +SOURCE=..\btree\bt_curadj.c +# End Source File +# Begin Source File + +SOURCE=..\btree\bt_cursor.c +# End Source File +# Begin Source File + +SOURCE=..\btree\bt_delete.c +# End Source File +# Begin Source File + +SOURCE=..\btree\bt_method.c +# End Source File +# Begin Source File + +SOURCE=..\btree\bt_open.c +# End Source File +# Begin Source File + +SOURCE=..\btree\bt_put.c +# End Source File +# Begin Source File + +SOURCE=..\btree\bt_rec.c +# End Source File +# Begin Source File + +SOURCE=..\btree\bt_reclaim.c +# End Source File +# Begin Source File + +SOURCE=..\btree\bt_recno.c +# End Source File +# Begin Source File + +SOURCE=..\btree\bt_rsearch.c +# End Source File +# Begin Source File + +SOURCE=..\btree\bt_search.c +# End Source File +# Begin Source File + +SOURCE=..\btree\bt_split.c +# End Source File +# Begin Source File + +SOURCE=..\btree\bt_stat.c +# End Source File +# Begin Source File + +SOURCE=..\btree\bt_upgrade.c +# End Source File +# Begin Source File + +SOURCE=..\btree\bt_verify.c +# End Source File +# Begin Source File + +SOURCE=..\btree\btree_auto.c +# End Source File +# Begin Source File + +SOURCE=..\clib\strcasecmp.c +# End Source File +# Begin Source File + +SOURCE=..\common\db_byteorder.c +# End Source File +# Begin Source File + +SOURCE=..\common\db_err.c +# End Source File +# Begin Source File + +SOURCE=..\common\db_getlong.c +# End Source File +# Begin Source File + +SOURCE=..\common\db_log2.c +# End Source File +# Begin Source File + +SOURCE=..\common\util_log.c +# End Source File +# Begin Source File + +SOURCE=..\common\util_sig.c +# End Source File +# Begin Source File + +SOURCE=..\cxx\cxx_app.cpp +# End Source File +# Begin Source File + +SOURCE=..\cxx\cxx_except.cpp +# End Source File +# Begin Source File + +SOURCE=..\cxx\cxx_lock.cpp +# End Source File +# Begin Source File + +SOURCE=..\cxx\cxx_log.cpp +# End Source File +# Begin Source File + +SOURCE=..\cxx\cxx_mpool.cpp +# End Source File +# Begin Source File + +SOURCE=..\cxx\cxx_table.cpp +# End Source File +# Begin Source File + +SOURCE=..\cxx\cxx_txn.cpp +# End Source File +# Begin Source File + +SOURCE=..\db\crdel_auto.c +# End Source File +# Begin Source File + +SOURCE=..\db\crdel_rec.c +# End Source File +# Begin Source File + +SOURCE=..\db\db.c +# End Source File +# Begin Source File + +SOURCE=..\db\db_am.c +# End Source File +# Begin Source File + +SOURCE=..\db\db_auto.c +# End Source File +# Begin Source File + +SOURCE=..\db\db_cam.c +# End Source File +# Begin Source File + +SOURCE=..\db\db_conv.c +# End Source File +# Begin Source File + +SOURCE=..\db\db_dispatch.c +# End Source File +# Begin Source File + +SOURCE=..\db\db_dup.c +# End Source File +# Begin Source File + +SOURCE=..\db\db_iface.c +# End Source File +# Begin Source File + +SOURCE=..\db\db_join.c +# End Source File +# Begin Source File + +SOURCE=..\db\db_meta.c +# End Source File +# Begin Source File + +SOURCE=..\db\db_method.c +# End Source File +# Begin Source File + +SOURCE=..\db\db_overflow.c +# End Source File +# Begin Source File + +SOURCE=..\db\db_pr.c +# End Source File +# Begin Source File + +SOURCE=..\db\db_rec.c +# End Source File +# Begin Source File + +SOURCE=..\db\db_reclaim.c +# End Source File +# Begin Source File + +SOURCE=..\db\db_ret.c +# End Source File +# Begin Source File + +SOURCE=..\db\db_upg.c +# End Source File +# Begin Source File + +SOURCE=..\db\db_upg_opd.c +# End Source File +# Begin Source File + +SOURCE=..\db\db_vrfy.c +# End Source File +# Begin Source File + +SOURCE=..\db\db_vrfyutil.c +# End Source File +# Begin Source File + +SOURCE=..\dbm\dbm.c +# End Source File +# Begin Source File + +SOURCE=..\env\db_salloc.c +# End Source File +# Begin Source File + +SOURCE=..\env\db_shash.c +# End Source File +# Begin Source File + +SOURCE=..\env\env_method.c +# End Source File +# Begin Source File + +SOURCE=..\env\env_open.c +# End Source File +# Begin Source File + +SOURCE=..\env\env_recover.c +# End Source File +# Begin Source File + +SOURCE=..\env\env_region.c +# End Source File +# Begin Source File + +SOURCE=..\hash\hash.c +# End Source File +# Begin Source File + +SOURCE=..\hash\hash_auto.c +# End Source File +# Begin Source File + +SOURCE=..\hash\hash_conv.c +# End Source File +# Begin Source File + +SOURCE=..\hash\hash_dup.c +# End Source File +# Begin Source File + +SOURCE=..\hash\hash_func.c +# End Source File +# Begin Source File + +SOURCE=..\hash\hash_meta.c +# End Source File +# Begin Source File + +SOURCE=..\hash\hash_method.c +# End Source File +# Begin Source File + +SOURCE=..\hash\hash_page.c +# End Source File +# Begin Source File + +SOURCE=..\hash\hash_rec.c +# End Source File +# Begin Source File + +SOURCE=..\hash\hash_reclaim.c +# End Source File +# Begin Source File + +SOURCE=..\hash\hash_stat.c +# End Source File +# Begin Source File + +SOURCE=..\hash\hash_upgrade.c +# End Source File +# Begin Source File + +SOURCE=..\hash\hash_verify.c +# End Source File +# Begin Source File + +SOURCE=..\hsearch\hsearch.c +# End Source File +# Begin Source File + +SOURCE=..\lock\lock.c +# End Source File +# Begin Source File + +SOURCE=..\lock\lock_conflict.c +# End Source File +# Begin Source File + +SOURCE=..\lock\lock_deadlock.c +# End Source File +# Begin Source File + +SOURCE=..\lock\lock_method.c +# End Source File +# Begin Source File + +SOURCE=..\lock\lock_region.c +# End Source File +# Begin Source File + +SOURCE=..\lock\lock_stat.c +# End Source File +# Begin Source File + +SOURCE=..\lock\lock_util.c +# End Source File +# Begin Source File + +SOURCE=..\log\log.c +# End Source File +# Begin Source File + +SOURCE=..\log\log_archive.c +# End Source File +# Begin Source File + +SOURCE=..\log\log_auto.c +# End Source File +# Begin Source File + +SOURCE=..\log\log_compare.c +# End Source File +# Begin Source File + +SOURCE=..\log\log_findckp.c +# End Source File +# Begin Source File + +SOURCE=..\log\log_get.c +# End Source File +# Begin Source File + +SOURCE=..\log\log_method.c +# End Source File +# Begin Source File + +SOURCE=..\log\log_put.c +# End Source File +# Begin Source File + +SOURCE=..\log\log_rec.c +# End Source File +# Begin Source File + +SOURCE=..\log\log_register.c +# End Source File +# Begin Source File + +SOURCE=..\mp\mp_alloc.c +# End Source File +# Begin Source File + +SOURCE=..\mp\mp_bh.c +# End Source File +# Begin Source File + +SOURCE=..\mp\mp_fget.c +# End Source File +# Begin Source File + +SOURCE=..\mp\mp_fopen.c +# End Source File +# Begin Source File + +SOURCE=..\mp\mp_fput.c +# End Source File +# Begin Source File + +SOURCE=..\mp\mp_fset.c +# End Source File +# Begin Source File + +SOURCE=..\mp\mp_method.c +# End Source File +# Begin Source File + +SOURCE=..\mp\mp_region.c +# End Source File +# Begin Source File + +SOURCE=..\mp\mp_register.c +# End Source File +# Begin Source File + +SOURCE=..\mp\mp_stat.c +# End Source File +# Begin Source File + +SOURCE=..\mp\mp_sync.c +# End Source File +# Begin Source File + +SOURCE=..\mp\mp_trickle.c +# End Source File +# Begin Source File + +SOURCE=..\mutex\mut_tas.c +# End Source File +# Begin Source File + +SOURCE=..\mutex\mutex.c +# End Source File +# Begin Source File + +SOURCE=..\os\os_alloc.c +# End Source File +# Begin Source File + +SOURCE=..\os\os_fsync.c +# End Source File +# Begin Source File + +SOURCE=..\os\os_handle.c +# End Source File +# Begin Source File + +SOURCE=..\os\os_method.c +# End Source File +# Begin Source File + +SOURCE=..\os\os_oflags.c +# End Source File +# Begin Source File + +SOURCE=..\os\os_region.c +# End Source File +# Begin Source File + +SOURCE=..\os\os_root.c +# End Source File +# Begin Source File + +SOURCE=..\os\os_rpath.c +# End Source File +# Begin Source File + +SOURCE=..\os\os_rw.c +# End Source File +# Begin Source File + +SOURCE=..\os\os_stat.c +# End Source File +# Begin Source File + +SOURCE=..\os\os_tmpdir.c +# End Source File +# Begin Source File + +SOURCE=..\os\os_unlink.c +# End Source File +# Begin Source File + +SOURCE=..\os_win32\os_abs.c +# End Source File +# Begin Source File + +SOURCE=..\os_win32\os_dir.c +# End Source File +# Begin Source File + +SOURCE=..\os_win32\os_errno.c +# End Source File +# Begin Source File + +SOURCE=..\os_win32\os_fid.c +# End Source File +# Begin Source File + +SOURCE=..\os_win32\os_finit.c +# End Source File +# Begin Source File + +SOURCE=..\os_win32\os_map.c +# End Source File +# Begin Source File + +SOURCE=..\os_win32\os_open.c +# End Source File +# Begin Source File + +SOURCE=..\os_win32\os_rename.c +# End Source File +# Begin Source File + +SOURCE=..\os_win32\os_seek.c +# End Source File +# Begin Source File + +SOURCE=..\os_win32\os_sleep.c +# End Source File +# Begin Source File + +SOURCE=..\os_win32\os_spin.c +# End Source File +# Begin Source File + +SOURCE=..\os_win32\os_type.c +# End Source File +# Begin Source File + +SOURCE=..\qam\qam.c +# End Source File +# Begin Source File + +SOURCE=..\qam\qam_auto.c +# End Source File +# Begin Source File + +SOURCE=..\qam\qam_conv.c +# End Source File +# Begin Source File + +SOURCE=..\qam\qam_files.c +# End Source File +# Begin Source File + +SOURCE=..\qam\qam_method.c +# End Source File +# Begin Source File + +SOURCE=..\qam\qam_open.c +# End Source File +# Begin Source File + +SOURCE=..\qam\qam_rec.c +# End Source File +# Begin Source File + +SOURCE=..\qam\qam_stat.c +# End Source File +# Begin Source File + +SOURCE=..\qam\qam_upgrade.c +# End Source File +# Begin Source File + +SOURCE=..\qam\qam_verify.c +# End Source File +# Begin Source File + +SOURCE=..\txn\txn.c +# End Source File +# Begin Source File + +SOURCE=..\txn\txn_auto.c +# End Source File +# Begin Source File + +SOURCE=..\txn\txn_rec.c +# End Source File +# Begin Source File + +SOURCE=..\txn\txn_region.c +# End Source File +# Begin Source File + +SOURCE=..\xa\xa.c +# End Source File +# Begin Source File + +SOURCE=..\xa\xa_db.c +# End Source File +# Begin Source File + +SOURCE=..\xa\xa_map.c +# End Source File +# End Target +# End Project diff --git a/db/build_win32/db_tcl.dsp b/db/build_win32/db_tcl.dsp new file mode 100644 index 000000000..b6df307d8 --- /dev/null +++ b/db/build_win32/db_tcl.dsp @@ -0,0 +1,135 @@ +# Microsoft Developer Studio Project File - Name="db_tcl" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=db_tcl - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "db_tcl.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "db_tcl.mak" CFG="db_tcl - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "db_tcl - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "db_tcl - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "db_tcl - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /Ob2 /I "." /I "../include" /D "DB_TCL_SUPPORT" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "DB_CREATE_DLL" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 Release/libdb32.lib tcl83.lib /nologo /base:"0x13000000" /subsystem:windows /dll /machine:I386 /out:"Release/libdb_tcl32.dll" + +!ELSEIF "$(CFG)" == "db_tcl - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 2 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "DB_TCL_SUPPORT" /D "CONFIG_TEST" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "DB_CREATE_DLL" /D "_WINDLL" /D "_AFXDLL" /YX"config.h" /FD /c +# SUBTRACT CPP /Fr +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 Debug/libdb32d.lib tcl83d.lib /nologo /base:"0x13000000" /subsystem:windows /dll /pdb:none /debug /machine:I386 /out:"Debug/libdb_tcl32d.dll" /fixed:no + +!ENDIF + +# Begin Target + +# Name "db_tcl - Win32 Release" +# Name "db_tcl - Win32 Debug" +# Begin Source File + +SOURCE=.\libdb_tcl.def +# End Source File +# Begin Source File + +SOURCE=..\tcl\tcl_compat.c +# End Source File +# Begin Source File + +SOURCE=..\tcl\tcl_db.c +# End Source File +# Begin Source File + +SOURCE=..\tcl\tcl_db_pkg.c +# End Source File +# Begin Source File + +SOURCE=..\tcl\tcl_dbcursor.c +# End Source File +# Begin Source File + +SOURCE=..\tcl\tcl_env.c +# End Source File +# Begin Source File + +SOURCE=..\tcl\tcl_internal.c +# End Source File +# Begin Source File + +SOURCE=..\tcl\tcl_lock.c +# End Source File +# Begin Source File + +SOURCE=..\tcl\tcl_log.c +# End Source File +# Begin Source File + +SOURCE=..\tcl\tcl_mp.c +# End Source File +# Begin Source File + +SOURCE=..\tcl\tcl_txn.c +# End Source File +# End Target +# End Project diff --git a/db/build_win32/db_test.dsp b/db/build_win32/db_test.dsp new file mode 100644 index 000000000..25c01c8e3 --- /dev/null +++ b/db/build_win32/db_test.dsp @@ -0,0 +1,99 @@ +# Microsoft Developer Studio Project File - Name="db_test" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=db_test - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "db_test.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "db_test.mak" CFG="db_test - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "db_test - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "db_test - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "db_test - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release/libdb32.lib /nologo /subsystem:console /machine:I386 +# Begin Special Build Tool +SOURCE=$(InputPath) +PostBuild_Desc=Copy built executable files. +PostBuild_Cmds=copy Release\*.exe . +# End Special Build Tool + +!ELSEIF "$(CFG)" == "db_test - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "db_recov" +# PROP BASE Intermediate_Dir "db_recov" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 Debug/libdb32d.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /out:"Debug/dbkill.exe" /fixed:no +# Begin Special Build Tool +SOURCE=$(InputPath) +PostBuild_Desc=Copy built executable files. +PostBuild_Cmds=copy Debug\*.exe . +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "db_test - Win32 Release" +# Name "db_test - Win32 Debug" +# Begin Source File + +SOURCE=.\dbkill.cpp +# End Source File +# End Target +# End Project diff --git a/db/build_win32/db_upgrade.dsp b/db/build_win32/db_upgrade.dsp new file mode 100644 index 000000000..87937e9c0 --- /dev/null +++ b/db/build_win32/db_upgrade.dsp @@ -0,0 +1,151 @@ +# Microsoft Developer Studio Project File - Name="db_upgrade" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=db_upgrade - Win32 Debug Static +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "db_upgrade.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "db_upgrade.mak" CFG="db_upgrade - Win32 Debug Static" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "db_upgrade - Win32 Release" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "db_upgrade - Win32 Debug" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "db_upgrade - Win32 Release Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "db_upgrade - Win32 Debug Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "db_upgrade - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release/libdb32.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"libcmt" + +!ELSEIF "$(CFG)" == "db_upgrade - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 Debug/libdb32d.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /nodefaultlib:"libcmtd" /fixed:no + +!ELSEIF "$(CFG)" == "db_upgrade - Win32 Release Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release_static" +# PROP Intermediate_Dir "Release_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Release_static/libdb32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release_static/libdb32s.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "db_upgrade - Win32 Debug Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_static" +# PROP Intermediate_Dir "Debug_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Debug_static/libdb32d.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no +# ADD LINK32 Debug_static/libdb32sd.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no + +!ENDIF + +# Begin Target + +# Name "db_upgrade - Win32 Release" +# Name "db_upgrade - Win32 Debug" +# Name "db_upgrade - Win32 Release Static" +# Name "db_upgrade - Win32 Debug Static" +# Begin Source File + +SOURCE=..\db_upgrade\db_upgrade.c +# End Source File +# Begin Source File + +SOURCE=..\clib\getopt.c +# End Source File +# End Target +# End Project diff --git a/db/build_win32/db_verify.dsp b/db/build_win32/db_verify.dsp new file mode 100644 index 000000000..70620bfe9 --- /dev/null +++ b/db/build_win32/db_verify.dsp @@ -0,0 +1,151 @@ +# Microsoft Developer Studio Project File - Name="db_verify" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=db_verify - Win32 Debug Static +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "db_verify.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "db_verify.mak" CFG="db_verify - Win32 Debug Static" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "db_verify - Win32 Release" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "db_verify - Win32 Debug" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "db_verify - Win32 Release Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "db_verify - Win32 Debug Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "db_verify - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release/libdb32.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"libcmt" + +!ELSEIF "$(CFG)" == "db_verify - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 Debug/libdb32d.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /nodefaultlib:"libcmtd" /fixed:no + +!ELSEIF "$(CFG)" == "db_verify - Win32 Release Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release_static" +# PROP Intermediate_Dir "Release_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Release_static/libdb32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release_static/libdb32s.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "db_verify - Win32 Debug Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_static" +# PROP Intermediate_Dir "Debug_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Debug_static/libdb32d.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no +# ADD LINK32 Debug_static/libdb32sd.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no + +!ENDIF + +# Begin Target + +# Name "db_verify - Win32 Release" +# Name "db_verify - Win32 Debug" +# Name "db_verify - Win32 Release Static" +# Name "db_verify - Win32 Debug Static" +# Begin Source File + +SOURCE=..\db_verify\db_verify.c +# End Source File +# Begin Source File + +SOURCE=..\clib\getopt.c +# End Source File +# End Target +# End Project diff --git a/db/build_win32/dbkill.cpp b/db/build_win32/dbkill.cpp new file mode 100644 index 000000000..24709f372 --- /dev/null +++ b/db/build_win32/dbkill.cpp @@ -0,0 +1,131 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: dbkill.cpp,v 11.4 2000/05/02 17:08:31 dda Exp $ + */ +/* + * Kill - + * Simulate Unix kill on Windows/NT and Windows/9X. + * This good enough to support the Berkeley DB test suite, + * but may be missing some favorite features. + * + * Would have used MKS kill, but it didn't seem to work well + * on Win/9X. Cygnus kill works within the Gnu/Cygnus environment + * (where processes are given small pids, with presumably a translation + * table between small pids and actual process handles), but our test + * environment, via Tcl, does not use the Cygnus environment. + * + * Compile this and install it as c:/tools/kill.exe (or as indicated + * by build_win32/include.tcl ). + */ + +#include +#include +#include +#include + +/* + * Like atol, with specified base. Would use stdlib, but + * strtol("0xFFFF1234", NULL, 16) returns 0x7FFFFFFF and + * strtol("4294712487", NULL, 16) returns 0x7FFFFFFF w/ VC++ + */ +long +myatol(char *s, int base) +{ + long result = 0; + char ch; + int sign = 1; /* + */ + if (base == 0) + base = 10; + if (base != 10 && base != 16) + return LONG_MAX; + while ((ch = *s++) != '\0') { + if (ch == '-') { + sign = -sign; + } + else if (ch >= '0' && ch <= '9') { + result = result * base + (ch - '0'); + } + else if (ch == 'x' || ch == 'X') { + /* Allow leading 0x..., and switch to base 16 */ + base = 16; + } + else if (base == 16 && ch >= 'a' && ch <= 'f') { + result = result * base + (ch - 'a' + 10); + } + else if (base == 16 && ch >= 'A' && ch <= 'F') { + result = result * base + (ch - 'A' + 10); + } + else { + if (sign > 1) + return LONG_MAX; + else + return LONG_MIN; + } + } + return sign * result; +} + +void +usage_exit() +{ + fprintf(stderr, "Usage: kill [ -sig ] pid\n"); + fprintf(stderr, " for win32, sig must be or 0, 15 (TERM)\n"); + exit(1); +} + +int +main(int argc, char **argv) +{ + HANDLE hProcess ; + DWORD accessflag; + long pid; + int sig = 15; + + if (argc > 2) { + if (argv[1][0] != '-') + usage_exit(); + + if (strcmp(argv[1], "-TERM") == 0) + sig = 15; + else { + /* currently sig is more or less ignored, + * we only care if it is zero or not + */ + sig = atoi(&argv[1][1]); + if (sig < 0) + usage_exit(); + } + argc--; + argv++; + } + if (argc < 2) + usage_exit(); + + pid = myatol(argv[1], 10); + /*printf("pid = %ld (0x%lx) (command line %s)\n", pid, pid, argv[1]);*/ + if (pid == LONG_MAX || pid == LONG_MIN) + usage_exit(); + + if (sig == 0) + accessflag = PROCESS_QUERY_INFORMATION | PROCESS_VM_READ; + else + accessflag = STANDARD_RIGHTS_REQUIRED | PROCESS_TERMINATE; + hProcess = OpenProcess(accessflag, FALSE, pid); + if (hProcess == NULL) { + fprintf(stderr, "dbkill: %s: no such process\n", argv[1]); + exit(1); + } + if (sig == 0) + exit(0); + if (!TerminateProcess(hProcess, 99)) { + DWORD err = GetLastError(); + fprintf(stderr, + "dbkill: cannot kill process: error %d (0x%lx)\n", err, err); + exit(1); + } + return 0; +} diff --git a/db/build_win32/dllmain.c b/db/build_win32/dllmain.c new file mode 100644 index 000000000..70c2e849d --- /dev/null +++ b/db/build_win32/dllmain.c @@ -0,0 +1,97 @@ +/* + * -------------------------------------------------------------------------- + * Copyright (C) 1997 Netscape Communications Corporation + * -------------------------------------------------------------------------- + * + * dllmain.c + * + * $Id: dllmain.c,v 1.3 2000/10/26 21:58:48 bostic Exp $ + */ + +#define WIN32_LEAN_AND_MEAN +#include + +static int ProcessesAttached = 0; +static HINSTANCE Instance; /* Global library instance handle. */ + +/* + * The following declaration is for the VC++ DLL entry point. + */ + +BOOL APIENTRY DllMain (HINSTANCE hInst, + DWORD reason, LPVOID reserved); + +/* + *---------------------------------------------------------------------- + * + * DllEntryPoint -- + * + * This wrapper function is used by Borland to invoke the + * initialization code for Tcl. It simply calls the DllMain + * routine. + * + * Results: + * See DllMain. + * + * Side effects: + * See DllMain. + * + *---------------------------------------------------------------------- + */ + +BOOL APIENTRY +DllEntryPoint(hInst, reason, reserved) + HINSTANCE hInst; /* Library instance handle. */ + DWORD reason; /* Reason this function is being called. */ + LPVOID reserved; /* Not used. */ +{ + return DllMain(hInst, reason, reserved); +} + +/* + *---------------------------------------------------------------------- + * + * DllMain -- + * + * This routine is called by the VC++ C run time library init + * code, or the DllEntryPoint routine. It is responsible for + * initializing various dynamically loaded libraries. + * + * Results: + * TRUE on sucess, FALSE on failure. + * + * Side effects: + * Establishes 32-to-16 bit thunk and initializes sockets library. + * + *---------------------------------------------------------------------- + */ +BOOL APIENTRY +DllMain(hInst, reason, reserved) + HINSTANCE hInst; /* Library instance handle. */ + DWORD reason; /* Reason this function is being called. */ + LPVOID reserved; /* Not used. */ +{ + switch (reason) { + case DLL_PROCESS_ATTACH: + + /* + * Registration of UT need to be done only once for first + * attaching process. At that time set the tclWin32s flag + * to indicate if the DLL is executing under Win32s or not. + */ + + if (ProcessesAttached++) { + return FALSE; /* Not the first initialization. */ + } + + Instance = hInst; + return TRUE; + + case DLL_PROCESS_DETACH: + + ProcessesAttached--; + break; + } + + return TRUE; +} diff --git a/db/build_win32/dynamic_dsp.src b/db/build_win32/dynamic_dsp.src new file mode 100644 index 000000000..3f39047cd --- /dev/null +++ b/db/build_win32/dynamic_dsp.src @@ -0,0 +1,154 @@ +# Microsoft Developer Studio Project File - Name="@project_name@" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=@project_name@ - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "@project_name@.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "@project_name@.mak" CFG="@project_name@ - Win32 Debug Static" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "@project_name@ - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "@project_name@ - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "@project_name@ - Win32 Release Static" (based on\ + "Win32 (x86) Dynamic-Link Library") +!MESSAGE "@project_name@ - Win32 Debug Static" (based on\ + "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "@project_name@ - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /Ob2 /I "." /I "../include" /D "DB_CREATE_DLL" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 /nologo /base:"0x13000000" /subsystem:windows /dll /machine:I386 /out:"Release/libdb@DB_VERSION_MAJOR@@DB_VERSION_MINOR@.dll" + +!ELSEIF "$(CFG)" == "@project_name@ - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 2 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "DB_CREATE_DLL" /D "CONFIG_TEST" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_MBCS" /YX"config.h" /FD /c +# SUBTRACT CPP /Fr +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /base:"0x13000000" /subsystem:windows /dll /pdb:none /debug /machine:I386 /out:"Debug/libdb@DB_VERSION_MAJOR@@DB_VERSION_MINOR@d.dll" /fixed:no + +!ELSEIF "$(CFG)" == "@project_name@ - Win32 Release Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "DB_DLL__" +# PROP BASE Intermediate_Dir "DB_DLL__" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /Ob2 /I "." /I "../include" /D "DB_CREATE_DLL" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /Ob2 /I "." /I "../include" /D "DB_CREATE_DLL" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /base:"0x13000000" /subsystem:windows /dll /machine:I386 /out:"Release/libdb@DB_VERSION_MAJOR@@DB_VERSION_MINOR@.dll" +# ADD LINK32 /nologo /base:"0x13000000" /subsystem:windows /dll /machine:I386 /out:"Release/libdb@DB_VERSION_MAJOR@@DB_VERSION_MINOR@.dll" + +!ELSEIF "$(CFG)" == "@project_name@ - Win32 Debug Static" + +# PROP BASE Use_MFC 2 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "DB_DLL_0" +# PROP BASE Intermediate_Dir "DB_DLL_0" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 2 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "DB_CREATE_DLL" /D "CONFIG_TEST" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /YX"config.h" /FD /c +# SUBTRACT BASE CPP /Fr +# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "DB_CREATE_DLL" /D "CONFIG_TEST" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_MBCS" /YX"config.h" /FD /c +# SUBTRACT CPP /Fr +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /base:"0x13000000" /subsystem:windows /dll /pdb:none /debug /machine:I386 /out:"Debug/libdb@DB_VERSION_MAJOR@@DB_VERSION_MINOR@d.dll" /fixed:no +# ADD LINK32 /nologo /base:"0x13000000" /subsystem:windows /dll /pdb:none /debug /machine:I386 /out:"Debug/libdb@DB_VERSION_MAJOR@@DB_VERSION_MINOR@d.dll" /fixed:no + +!ENDIF + +# Begin Target + +# Name "@project_name@ - Win32 Release" +# Name "@project_name@ - Win32 Debug" +# Name "@project_name@ - Win32 Release Static" +# Name "@project_name@ - Win32 Debug Static" +@SOURCE_FILES@ +# End Target +# End Project diff --git a/db/build_win32/ex_access.dsp b/db/build_win32/ex_access.dsp new file mode 100644 index 000000000..d15253908 --- /dev/null +++ b/db/build_win32/ex_access.dsp @@ -0,0 +1,151 @@ +# Microsoft Developer Studio Project File - Name="ex_access" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=ex_access - Win32 Debug Static +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "ex_access.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "ex_access.mak" CFG="ex_access - Win32 Debug Static" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ex_access - Win32 Release" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "ex_access - Win32 Debug" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "ex_access - Win32 Release Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "ex_access - Win32 Debug Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ex_access - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release/libdb32.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"libcmt" + +!ELSEIF "$(CFG)" == "ex_access - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 Debug/libdb32d.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /nodefaultlib:"libcmtd" /fixed:no + +!ELSEIF "$(CFG)" == "ex_access - Win32 Release Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release_static" +# PROP Intermediate_Dir "Release_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Release_static/libdb32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release_static/libdb32s.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "ex_access - Win32 Debug Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_static" +# PROP Intermediate_Dir "Debug_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Debug_static/libdb32d.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no +# ADD LINK32 Debug_static/libdb32sd.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no + +!ENDIF + +# Begin Target + +# Name "ex_access - Win32 Release" +# Name "ex_access - Win32 Debug" +# Name "ex_access - Win32 Release Static" +# Name "ex_access - Win32 Debug Static" +# Begin Source File + +SOURCE=..\examples_c\ex_access.c +# End Source File +# Begin Source File + +SOURCE=..\clib\getopt.c +# End Source File +# End Target +# End Project diff --git a/db/build_win32/ex_btrec.dsp b/db/build_win32/ex_btrec.dsp new file mode 100644 index 000000000..6ba99a59b --- /dev/null +++ b/db/build_win32/ex_btrec.dsp @@ -0,0 +1,151 @@ +# Microsoft Developer Studio Project File - Name="ex_btrec" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=ex_btrec - Win32 Debug Static +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "ex_btrec.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "ex_btrec.mak" CFG="ex_btrec - Win32 Debug Static" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ex_btrec - Win32 Release" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "ex_btrec - Win32 Debug" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "ex_btrec - Win32 Release Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "ex_btrec - Win32 Debug Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ex_btrec - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release/libdb32.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"libcmt" + +!ELSEIF "$(CFG)" == "ex_btrec - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 Debug/libdb32d.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /nodefaultlib:"libcmtd" /fixed:no + +!ELSEIF "$(CFG)" == "ex_btrec - Win32 Release Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release_static" +# PROP Intermediate_Dir "Release_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Release_static/libdb32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release_static/libdb32s.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "ex_btrec - Win32 Debug Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_static" +# PROP Intermediate_Dir "Debug_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Debug_static/libdb32d.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no +# ADD LINK32 Debug_static/libdb32sd.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no + +!ENDIF + +# Begin Target + +# Name "ex_btrec - Win32 Release" +# Name "ex_btrec - Win32 Debug" +# Name "ex_btrec - Win32 Release Static" +# Name "ex_btrec - Win32 Debug Static" +# Begin Source File + +SOURCE=..\examples_c\ex_btrec.c +# End Source File +# Begin Source File + +SOURCE=..\clib\getopt.c +# End Source File +# End Target +# End Project diff --git a/db/build_win32/ex_env.dsp b/db/build_win32/ex_env.dsp new file mode 100644 index 000000000..a2df7aa4a --- /dev/null +++ b/db/build_win32/ex_env.dsp @@ -0,0 +1,151 @@ +# Microsoft Developer Studio Project File - Name="ex_env" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=ex_env - Win32 Debug Static +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "ex_env.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "ex_env.mak" CFG="ex_env - Win32 Debug Static" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ex_env - Win32 Release" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "ex_env - Win32 Debug" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "ex_env - Win32 Release Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "ex_env - Win32 Debug Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ex_env - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release/libdb32.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"libcmt" + +!ELSEIF "$(CFG)" == "ex_env - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 Debug/libdb32d.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /nodefaultlib:"libcmtd" /fixed:no + +!ELSEIF "$(CFG)" == "ex_env - Win32 Release Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release_static" +# PROP Intermediate_Dir "Release_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Release_static/libdb32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release_static/libdb32s.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "ex_env - Win32 Debug Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_static" +# PROP Intermediate_Dir "Debug_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Debug_static/libdb32d.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no +# ADD LINK32 Debug_static/libdb32sd.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no + +!ENDIF + +# Begin Target + +# Name "ex_env - Win32 Release" +# Name "ex_env - Win32 Debug" +# Name "ex_env - Win32 Release Static" +# Name "ex_env - Win32 Debug Static" +# Begin Source File + +SOURCE=..\examples_c\ex_env.c +# End Source File +# Begin Source File + +SOURCE=..\clib\getopt.c +# End Source File +# End Target +# End Project diff --git a/db/build_win32/ex_lock.dsp b/db/build_win32/ex_lock.dsp new file mode 100644 index 000000000..26485add5 --- /dev/null +++ b/db/build_win32/ex_lock.dsp @@ -0,0 +1,151 @@ +# Microsoft Developer Studio Project File - Name="ex_lock" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=ex_lock - Win32 Debug Static +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "ex_lock.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "ex_lock.mak" CFG="ex_lock - Win32 Debug Static" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ex_lock - Win32 Release" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "ex_lock - Win32 Debug" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "ex_lock - Win32 Release Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "ex_lock - Win32 Debug Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ex_lock - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release/libdb32.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"libcmt" + +!ELSEIF "$(CFG)" == "ex_lock - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 Debug/libdb32d.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /nodefaultlib:"libcmtd" /fixed:no + +!ELSEIF "$(CFG)" == "ex_lock - Win32 Release Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release_static" +# PROP Intermediate_Dir "Release_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Release_static/libdb32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release_static/libdb32s.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "ex_lock - Win32 Debug Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_static" +# PROP Intermediate_Dir "Debug_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Debug_static/libdb32d.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no +# ADD LINK32 Debug_static/libdb32sd.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no + +!ENDIF + +# Begin Target + +# Name "ex_lock - Win32 Release" +# Name "ex_lock - Win32 Debug" +# Name "ex_lock - Win32 Release Static" +# Name "ex_lock - Win32 Debug Static" +# Begin Source File + +SOURCE=..\examples_c\ex_lock.c +# End Source File +# Begin Source File + +SOURCE=..\clib\getopt.c +# End Source File +# End Target +# End Project diff --git a/db/build_win32/ex_mpool.dsp b/db/build_win32/ex_mpool.dsp new file mode 100644 index 000000000..6f8345711 --- /dev/null +++ b/db/build_win32/ex_mpool.dsp @@ -0,0 +1,151 @@ +# Microsoft Developer Studio Project File - Name="ex_mpool" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=ex_mpool - Win32 Debug Static +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "ex_mpool.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "ex_mpool.mak" CFG="ex_mpool - Win32 Debug Static" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ex_mpool - Win32 Release" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "ex_mpool - Win32 Debug" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "ex_mpool - Win32 Release Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "ex_mpool - Win32 Debug Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ex_mpool - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release/libdb32.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"libcmt" + +!ELSEIF "$(CFG)" == "ex_mpool - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 Debug/libdb32d.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /nodefaultlib:"libcmtd" /fixed:no + +!ELSEIF "$(CFG)" == "ex_mpool - Win32 Release Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release_static" +# PROP Intermediate_Dir "Release_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Release_static/libdb32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release_static/libdb32s.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "ex_mpool - Win32 Debug Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_static" +# PROP Intermediate_Dir "Debug_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Debug_static/libdb32d.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no +# ADD LINK32 Debug_static/libdb32sd.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no + +!ENDIF + +# Begin Target + +# Name "ex_mpool - Win32 Release" +# Name "ex_mpool - Win32 Debug" +# Name "ex_mpool - Win32 Release Static" +# Name "ex_mpool - Win32 Debug Static" +# Begin Source File + +SOURCE=..\examples_c\ex_mpool.c +# End Source File +# Begin Source File + +SOURCE=..\clib\getopt.c +# End Source File +# End Target +# End Project diff --git a/db/build_win32/ex_tpcb.dsp b/db/build_win32/ex_tpcb.dsp new file mode 100644 index 000000000..e39c13304 --- /dev/null +++ b/db/build_win32/ex_tpcb.dsp @@ -0,0 +1,151 @@ +# Microsoft Developer Studio Project File - Name="ex_tpcb" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=ex_tpcb - Win32 Debug Static +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "ex_tpcb.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "ex_tpcb.mak" CFG="ex_tpcb - Win32 Debug Static" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ex_tpcb - Win32 Release" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "ex_tpcb - Win32 Debug" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "ex_tpcb - Win32 Release Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "ex_tpcb - Win32 Debug Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ex_tpcb - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release/libdb32.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"libcmt" + +!ELSEIF "$(CFG)" == "ex_tpcb - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 Debug/libdb32d.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /nodefaultlib:"libcmtd" /fixed:no + +!ELSEIF "$(CFG)" == "ex_tpcb - Win32 Release Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release_static" +# PROP Intermediate_Dir "Release_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Release_static/libdb32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release_static/libdb32s.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "ex_tpcb - Win32 Debug Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_static" +# PROP Intermediate_Dir "Debug_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Debug_static/libdb32d.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no +# ADD LINK32 Debug_static/libdb32sd.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no + +!ENDIF + +# Begin Target + +# Name "ex_tpcb - Win32 Release" +# Name "ex_tpcb - Win32 Debug" +# Name "ex_tpcb - Win32 Release Static" +# Name "ex_tpcb - Win32 Debug Static" +# Begin Source File + +SOURCE=..\examples_c\ex_tpcb.c +# End Source File +# Begin Source File + +SOURCE=..\clib\getopt.c +# End Source File +# End Target +# End Project diff --git a/db/build_win32/excxx_access.dsp b/db/build_win32/excxx_access.dsp new file mode 100644 index 000000000..4c09c41c5 --- /dev/null +++ b/db/build_win32/excxx_access.dsp @@ -0,0 +1,151 @@ +# Microsoft Developer Studio Project File - Name="excxx_access" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=excxx_access - Win32 Debug Static +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "excxx_access.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "excxx_access.mak" CFG="excxx_access - Win32 Debug Static" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "excxx_access - Win32 Release" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "excxx_access - Win32 Debug" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "excxx_access - Win32 Release Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "excxx_access - Win32 Debug Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "excxx_access - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release/libdb32.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"libcmt" + +!ELSEIF "$(CFG)" == "excxx_access - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 Debug/libdb32d.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /nodefaultlib:"libcmtd" /fixed:no + +!ELSEIF "$(CFG)" == "excxx_access - Win32 Release Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release_static" +# PROP Intermediate_Dir "Release_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Release_static/libdb32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release_static/libdb32s.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "excxx_access - Win32 Debug Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_static" +# PROP Intermediate_Dir "Debug_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Debug_static/libdb32d.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no +# ADD LINK32 Debug_static/libdb32sd.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no + +!ENDIF + +# Begin Target + +# Name "excxx_access - Win32 Release" +# Name "excxx_access - Win32 Debug" +# Name "excxx_access - Win32 Release Static" +# Name "excxx_access - Win32 Debug Static" +# Begin Source File + +SOURCE=..\examples_cxx\AccessExample.cpp +# End Source File +# Begin Source File + +SOURCE=..\clib\getopt.c +# End Source File +# End Target +# End Project diff --git a/db/build_win32/excxx_btrec.dsp b/db/build_win32/excxx_btrec.dsp new file mode 100644 index 000000000..75809bd3d --- /dev/null +++ b/db/build_win32/excxx_btrec.dsp @@ -0,0 +1,151 @@ +# Microsoft Developer Studio Project File - Name="excxx_btrec" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=excxx_btrec - Win32 Debug Static +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "excxx_btrec.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "excxx_btrec.mak" CFG="excxx_btrec - Win32 Debug Static" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "excxx_btrec - Win32 Release" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "excxx_btrec - Win32 Debug" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "excxx_btrec - Win32 Release Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "excxx_btrec - Win32 Debug Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "excxx_btrec - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release/libdb32.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"libcmt" + +!ELSEIF "$(CFG)" == "excxx_btrec - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 Debug/libdb32d.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /nodefaultlib:"libcmtd" /fixed:no + +!ELSEIF "$(CFG)" == "excxx_btrec - Win32 Release Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release_static" +# PROP Intermediate_Dir "Release_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Release_static/libdb32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release_static/libdb32s.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "excxx_btrec - Win32 Debug Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_static" +# PROP Intermediate_Dir "Debug_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Debug_static/libdb32d.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no +# ADD LINK32 Debug_static/libdb32sd.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no + +!ENDIF + +# Begin Target + +# Name "excxx_btrec - Win32 Release" +# Name "excxx_btrec - Win32 Debug" +# Name "excxx_btrec - Win32 Release Static" +# Name "excxx_btrec - Win32 Debug Static" +# Begin Source File + +SOURCE=..\examples_cxx\BtRecExample.cpp +# End Source File +# Begin Source File + +SOURCE=..\clib\getopt.c +# End Source File +# End Target +# End Project diff --git a/db/build_win32/excxx_env.dsp b/db/build_win32/excxx_env.dsp new file mode 100644 index 000000000..57e3da4d4 --- /dev/null +++ b/db/build_win32/excxx_env.dsp @@ -0,0 +1,151 @@ +# Microsoft Developer Studio Project File - Name="excxx_env" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=excxx_env - Win32 Debug Static +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "excxx_env.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "excxx_env.mak" CFG="excxx_env - Win32 Debug Static" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "excxx_env - Win32 Release" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "excxx_env - Win32 Debug" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "excxx_env - Win32 Release Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "excxx_env - Win32 Debug Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "excxx_env - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release/libdb32.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"libcmt" + +!ELSEIF "$(CFG)" == "excxx_env - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 Debug/libdb32d.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /nodefaultlib:"libcmtd" /fixed:no + +!ELSEIF "$(CFG)" == "excxx_env - Win32 Release Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release_static" +# PROP Intermediate_Dir "Release_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Release_static/libdb32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release_static/libdb32s.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "excxx_env - Win32 Debug Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_static" +# PROP Intermediate_Dir "Debug_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Debug_static/libdb32d.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no +# ADD LINK32 Debug_static/libdb32sd.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no + +!ENDIF + +# Begin Target + +# Name "excxx_env - Win32 Release" +# Name "excxx_env - Win32 Debug" +# Name "excxx_env - Win32 Release Static" +# Name "excxx_env - Win32 Debug Static" +# Begin Source File + +SOURCE=..\examples_cxx\EnvExample.cpp +# End Source File +# Begin Source File + +SOURCE=..\clib\getopt.c +# End Source File +# End Target +# End Project diff --git a/db/build_win32/excxx_lock.dsp b/db/build_win32/excxx_lock.dsp new file mode 100644 index 000000000..95ad8d182 --- /dev/null +++ b/db/build_win32/excxx_lock.dsp @@ -0,0 +1,151 @@ +# Microsoft Developer Studio Project File - Name="excxx_lock" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=excxx_lock - Win32 Debug Static +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "excxx_lock.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "excxx_lock.mak" CFG="excxx_lock - Win32 Debug Static" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "excxx_lock - Win32 Release" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "excxx_lock - Win32 Debug" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "excxx_lock - Win32 Release Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "excxx_lock - Win32 Debug Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "excxx_lock - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release/libdb32.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"libcmt" + +!ELSEIF "$(CFG)" == "excxx_lock - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 Debug/libdb32d.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /nodefaultlib:"libcmtd" /fixed:no + +!ELSEIF "$(CFG)" == "excxx_lock - Win32 Release Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release_static" +# PROP Intermediate_Dir "Release_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Release_static/libdb32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release_static/libdb32s.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "excxx_lock - Win32 Debug Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_static" +# PROP Intermediate_Dir "Debug_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Debug_static/libdb32d.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no +# ADD LINK32 Debug_static/libdb32sd.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no + +!ENDIF + +# Begin Target + +# Name "excxx_lock - Win32 Release" +# Name "excxx_lock - Win32 Debug" +# Name "excxx_lock - Win32 Release Static" +# Name "excxx_lock - Win32 Debug Static" +# Begin Source File + +SOURCE=..\examples_cxx\LockExample.cpp +# End Source File +# Begin Source File + +SOURCE=..\clib\getopt.c +# End Source File +# End Target +# End Project diff --git a/db/build_win32/excxx_mpool.dsp b/db/build_win32/excxx_mpool.dsp new file mode 100644 index 000000000..31b4cba4c --- /dev/null +++ b/db/build_win32/excxx_mpool.dsp @@ -0,0 +1,151 @@ +# Microsoft Developer Studio Project File - Name="excxx_mpool" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=excxx_mpool - Win32 Debug Static +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "excxx_mpool.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "excxx_mpool.mak" CFG="excxx_mpool - Win32 Debug Static" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "excxx_mpool - Win32 Release" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "excxx_mpool - Win32 Debug" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "excxx_mpool - Win32 Release Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "excxx_mpool - Win32 Debug Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "excxx_mpool - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release/libdb32.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"libcmt" + +!ELSEIF "$(CFG)" == "excxx_mpool - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 Debug/libdb32d.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /nodefaultlib:"libcmtd" /fixed:no + +!ELSEIF "$(CFG)" == "excxx_mpool - Win32 Release Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release_static" +# PROP Intermediate_Dir "Release_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Release_static/libdb32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release_static/libdb32s.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "excxx_mpool - Win32 Debug Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_static" +# PROP Intermediate_Dir "Debug_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Debug_static/libdb32d.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no +# ADD LINK32 Debug_static/libdb32sd.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no + +!ENDIF + +# Begin Target + +# Name "excxx_mpool - Win32 Release" +# Name "excxx_mpool - Win32 Debug" +# Name "excxx_mpool - Win32 Release Static" +# Name "excxx_mpool - Win32 Debug Static" +# Begin Source File + +SOURCE=..\examples_cxx\MpoolExample.cpp +# End Source File +# Begin Source File + +SOURCE=..\clib\getopt.c +# End Source File +# End Target +# End Project diff --git a/db/build_win32/excxx_tpcb.dsp b/db/build_win32/excxx_tpcb.dsp new file mode 100644 index 000000000..f9cddf414 --- /dev/null +++ b/db/build_win32/excxx_tpcb.dsp @@ -0,0 +1,151 @@ +# Microsoft Developer Studio Project File - Name="excxx_tpcb" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=excxx_tpcb - Win32 Debug Static +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "excxx_tpcb.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "excxx_tpcb.mak" CFG="excxx_tpcb - Win32 Debug Static" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "excxx_tpcb - Win32 Release" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "excxx_tpcb - Win32 Debug" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "excxx_tpcb - Win32 Release Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "excxx_tpcb - Win32 Debug Static" (based on\ + "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "excxx_tpcb - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release/libdb32.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"libcmt" + +!ELSEIF "$(CFG)" == "excxx_tpcb - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 Debug/libdb32d.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /nodefaultlib:"libcmtd" /fixed:no + +!ELSEIF "$(CFG)" == "excxx_tpcb - Win32 Release Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release_static" +# PROP Intermediate_Dir "Release_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Release_static/libdb32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 Release_static/libdb32s.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "excxx_tpcb - Win32 Debug Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_static" +# PROP Intermediate_Dir "Debug_static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 Debug_static/libdb32d.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no +# ADD LINK32 Debug_static/libdb32sd.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /fixed:no + +!ENDIF + +# Begin Target + +# Name "excxx_tpcb - Win32 Release" +# Name "excxx_tpcb - Win32 Debug" +# Name "excxx_tpcb - Win32 Release Static" +# Name "excxx_tpcb - Win32 Debug Static" +# Begin Source File + +SOURCE=..\examples_cxx\TpcbExample.cpp +# End Source File +# Begin Source File + +SOURCE=..\clib\getopt.c +# End Source File +# End Target +# End Project diff --git a/db/build_win32/include.tcl b/db/build_win32/include.tcl new file mode 100644 index 000000000..4f1234130 --- /dev/null +++ b/db/build_win32/include.tcl @@ -0,0 +1,16 @@ +set tclsh_path SET_YOUR_TCLSH_PATH +set test_path ../test +set tcllib ./Debug/libdb_tcl32d.dll + +set KILL ./dbkill.exe + +# DO NOT EDIT BELOW THIS LINE: automatically built by dist/s_tcl. + +global dict +global testdir +global util_path +set testdir ./TESTDIR + +global is_hp_test +global is_qnx_test +global is_windows_test diff --git a/db/build_win32/java_dsp.src b/db/build_win32/java_dsp.src new file mode 100644 index 000000000..8c4de7602 --- /dev/null +++ b/db/build_win32/java_dsp.src @@ -0,0 +1,135 @@ +# Microsoft Developer Studio Project File - Name="@project_name@" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=@project_name@ - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "@project_name@.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "@project_name@.mak" CFG="@project_name@ - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "@project_name@ - Win32 Release" (based on\ + "Win32 (x86) Dynamic-Link Library") +!MESSAGE "@project_name@ - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "@project_name@ - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /Ob2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "DB_CREATE_DLL" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 Release/libdb32.lib /nologo /base:"0x13000000" /subsystem:windows /dll /machine:I386 /out:"Release/libdb_java@DB_VERSION_MAJOR@@DB_VERSION_MINOR@.dll" +# Begin Custom Build - Compiling java files using javac +ProjDir=. +InputPath=.\Release\libdb_java@DB_VERSION_MAJOR@@DB_VERSION_MINOR@.dll +SOURCE=$(InputPath) + +"force_compilation.txt" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd $(ProjDir)\..\java\src\com\sleepycat\db + mkdir ..\..\..\..\classes + echo compiling Berkeley DB classes + javac -d ../../../../classes -classpath "$(CLASSPATH);../../../../classes"\ + *.java + echo compiling examples + cd ..\examples + javac -d ../../../../classes -classpath "$(CLASSPATH);../../../../classes"\ + *.java + echo creating jar file + cd ..\..\..\..\classes + jar cf db.jar com\sleepycat\db\*.class + echo Java build finished + +# End Custom Build + +!ELSEIF "$(CFG)" == "@project_name@ - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 2 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "DB_CREATE_DLL" /D "_WINDLL" /D "_AFXDLL" /YX"config.h" /FD /c +# SUBTRACT CPP /Fr +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 Debug/libdb32d.lib /nologo /base:"0x13000000" /subsystem:windows /dll /pdb:none /debug /machine:I386 /out:"Debug/libdb_java@DB_VERSION_MAJOR@@DB_VERSION_MINOR@d.dll" /fixed:no +# Begin Custom Build - Compiling java files using javac +ProjDir=. +InputPath=.\Debug\libdb_java@DB_VERSION_MAJOR@@DB_VERSION_MINOR@d.dll +SOURCE=$(InputPath) + +"force_compilation.txt" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cd $(ProjDir)\..\java\src\com\sleepycat\db + mkdir ..\..\..\..\classes + echo compiling Berkeley DB classes + javac -g -d ../../../../classes -classpath "$(CLASSPATH);../../../../classes"\ + *.java + echo compiling examples + javac -g -d ../../../../classes -classpath "$(CLASSPATH);../../../../classes"\ + *.java + cd ..\examples + echo creating jar file + cd ..\..\..\..\classes + jar cf db.jar com\sleepycat\db\*.class + echo Java build finished + +# End Custom Build + +!ENDIF + +# Begin Target + +# Name "@project_name@ - Win32 Release" +# Name "@project_name@ - Win32 Debug" +@SOURCE_FILES@ +# End Target +# End Project diff --git a/db/build_win32/libdb.def b/db/build_win32/libdb.def new file mode 100644 index 000000000..bb23f59fc --- /dev/null +++ b/db/build_win32/libdb.def @@ -0,0 +1,151 @@ +; $Id: libdb.def,v 11.21 2001/01/04 15:07:33 dda Exp $ + +DESCRIPTION 'Berkeley DB 3.2 Library' +EXPORTS + lock_get @1 + lock_id @2 + lock_put @3 + lock_vec @4 + log_compare @5 + log_file @6 + log_flush @7 + log_get @8 + log_put @9 + log_register @10 + log_unregister @11 + memp_fclose @12 + memp_fget @13 + memp_fopen @14 + memp_fput @15 + memp_fset @16 + memp_fsync @17 + memp_register @18 + memp_sync @19 + txn_abort @20 + txn_begin @21 + txn_checkpoint @22 + txn_commit @23 + txn_prepare @24 + db_version @25 + memp_stat @26 + log_archive @27 + lock_detect @28 + txn_id @29 + txn_stat @30 + memp_trickle @31 + log_stat @32 + lock_stat @33 + db_create @34 + db_env_create @35 + db_strerror @36 + db_xa_switch @37 + db_env_set_func_close @38 + db_env_set_func_dirfree @39 + db_env_set_func_dirlist @40 + db_env_set_func_exists @41 + db_env_set_func_free @42 + db_env_set_func_fsync @43 + db_env_set_func_ioinfo @44 + db_env_set_func_malloc @45 + db_env_set_func_map @46 + db_env_set_func_open @47 + db_env_set_func_read @48 + db_env_set_func_realloc @49 + db_env_set_func_rename @50 + db_env_set_func_sleep @51 + db_env_set_func_unlink @52 + db_env_set_func_unmap @53 + db_env_set_func_write @54 + db_env_set_func_yield @55 +; FREE @56 + db_env_set_pageyield @57 + db_env_set_panicstate @58 + db_env_set_region_init @59 + db_env_set_tas_spins @60 +; these are only for testing + __db_loadme @201 + __ham_func2 @202 + __ham_func3 @203 + __ham_func4 @204 + __ham_func5 @205 + __db_hcreate @206 + __db_hsearch @207 + __db_hdestroy @208 + __db_dbm_init @209 + __db_dbm_delete @210 + __db_dbm_fetch @211 + __db_dbm_store @212 + __db_dbm_firstkey @213 + __db_dbm_nextkey @214 + __db_dbm_close @215 + __db_ndbm_open @216 + __db_ndbm_store @217 + __db_ndbm_rdonly @218 + __db_ndbm_pagfno @219 + __db_ndbm_nextkey @220 + __db_ndbm_firstkey @221 + __db_ndbm_fetch @222 + __db_ndbm_error @223 + __db_ndbm_dirfno @224 + __db_ndbm_delete @225 + __db_ndbm_close @226 + __db_ndbm_clearerr @227 + __lock_dump_region @228 + __memp_dump_region @229 + __os_closehandle @230 + __os_openhandle @231 + __os_strdup @232 + __db_r_attach @233 + __db_r_detach @234 + __db_tas_mutex_init @235 + __db_tas_mutex_lock @236 + __db_tas_mutex_unlock @237 + __os_read @238 + __os_write @239 + __os_open @240 + __os_ioinfo @241 + __os_free @242 + __os_malloc @243 + __os_freestr @244 + __os_calloc @245 + __ham_test @246 +; these are needed for linking tools + __db_dump @401 + __db_rpath @402 + __db_dispatch @403 + __db_err @404 + __db_init_print @405 + __txn_init_print @406 + __log_init_print @407 + __ham_init_print @408 + __bam_init_print @409 + __db_jump @410 + __ham_pgin @411 + __ham_pgout @412 + __bam_pgin @413 + __bam_pgout @414 + __db_omode @415 + __db_prdbt @416 + __os_sleep @417 + __db_e_stat @420 + __db_getlong @421 + __os_get_errno @422 + __os_set_errno @423 + __ham_get_meta @424 + __ham_release_meta @425 + __qam_init_print @426 + __crdel_init_print @427 + __qam_pgin_out @428 + __db_pgin @429 + __db_pgout @430 + __db_getulong @431 + __db_util_sigresend @432 + __db_util_siginit @433 + __db_util_interrupted @434 + __db_util_logset @435 + __db_prheader @436 + __db_prfooter @437 + __db_verify_callback @438 + __db_verify_internal @439 + __os_yield @440 + __db_global_values @441 diff --git a/db/build_win32/libdb.rc b/db/build_win32/libdb.rc new file mode 100644 index 000000000..2261d69ce --- /dev/null +++ b/db/build_win32/libdb.rc @@ -0,0 +1,33 @@ +1 VERSIONINFO + FILEVERSION 3,0,2,9 + PRODUCTVERSION 3,0,2,9 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L + +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "Sleepycat Software\0" + VALUE "FileDescription", "Berkeley DB 3.0 DLL\0" + VALUE "FileVersion", "3.2.9\0" + VALUE "InternalName", "libdb.dll\0" + VALUE "LegalCopyright", "Copyright © Sleepycat Software Inc. 1997, 1998, 1999, 2000\0" + VALUE "OriginalFilename", "libdb.dll\0" + VALUE "ProductName", "Sleepycat Software libdb\0" + VALUE "ProductVersion", "3.2.9\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/db/build_win32/libdb_tcl.def b/db/build_win32/libdb_tcl.def new file mode 100644 index 000000000..a18459bea --- /dev/null +++ b/db/build_win32/libdb_tcl.def @@ -0,0 +1,35 @@ +; $Id: libdb_tcl.def,v 11.2 1999/11/21 23:10:00 bostic Exp $ + +DESCRIPTION 'Berkeley DB TCL interface Library' +EXPORTS + Db_tcl_Init + bdb_DbmCommand + bdb_HCommand + bdb_NdbmOpen + bdb_RandCommand + db_Cmd + dbc_Cmd + env_Cmd + ndbm_Cmd + tcl_EnvRemove + tcl_LockDetect + tcl_LockGet + tcl_LockStat + tcl_LockVec + tcl_LogArchive + tcl_LogCompare + tcl_LogFile + tcl_LogFlush + tcl_LogGet + tcl_LogPut + tcl_LogRegister + tcl_LogStat + tcl_LogUnregister + tcl_Mp + tcl_MpStat + tcl_MpSync + tcl_MpTrickle + tcl_Txn + tcl_TxnCheckpoint + tcl_TxnStat + txn_Cmd diff --git a/db/build_win32/libdbrc.src b/db/build_win32/libdbrc.src new file mode 100644 index 000000000..82a93068c --- /dev/null +++ b/db/build_win32/libdbrc.src @@ -0,0 +1,33 @@ +1 VERSIONINFO + FILEVERSION %MAJOR%,0,%MINOR%,%PATCH% + PRODUCTVERSION %MAJOR%,0,%MINOR%,%PATCH% + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L + +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "Sleepycat Software\0" + VALUE "FileDescription", "Berkeley DB 3.0 DLL\0" + VALUE "FileVersion", "%MAJOR%.%MINOR%.%PATCH%\0" + VALUE "InternalName", "libdb.dll\0" + VALUE "LegalCopyright", "Copyright © Sleepycat Software Inc. 1997, 1998, 1999, 2000\0" + VALUE "OriginalFilename", "libdb.dll\0" + VALUE "ProductName", "Sleepycat Software libdb\0" + VALUE "ProductVersion", "%MAJOR%.%MINOR%.%PATCH%\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/db/build_win32/srcfile_dsp.src b/db/build_win32/srcfile_dsp.src new file mode 100644 index 000000000..408a55e2a --- /dev/null +++ b/db/build_win32/srcfile_dsp.src @@ -0,0 +1,4 @@ +# Begin Source File + +SOURCE=@srcdir@\@srcfile@ +# End Source File diff --git a/db/build_win32/static_dsp.src b/db/build_win32/static_dsp.src new file mode 100644 index 000000000..fe0c3a012 --- /dev/null +++ b/db/build_win32/static_dsp.src @@ -0,0 +1,127 @@ +# Microsoft Developer Studio Project File - Name="@project_name@" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=@project_name@ - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "@project_name@.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "@project_name@.mak" CFG="@project_name@ - Win32 Debug Static" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "@project_name@ - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "@project_name@ - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "@project_name@ - Win32 Release Static" (based on\ + "Win32 (x86) Static Library") +!MESSAGE "@project_name@ - Win32 Debug Static" (based on\ + "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe + +!IF "$(CFG)" == "@project_name@ - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "DB_Stati" +# PROP BASE Intermediate_Dir "DB_Stati" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release_static" +# PROP Intermediate_Dir "Release_static" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX"config.h" /FD /c +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"Release_static/libdb@DB_VERSION_MAJOR@@DB_VERSION_MINOR@s.lib" + +!ELSEIF "$(CFG)" == "@project_name@ - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "DB_Stat0" +# PROP BASE Intermediate_Dir "DB_Stat0" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_static" +# PROP Intermediate_Dir "Debug_static" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /GX /Z7 /Od /I "." /I "../include" /D "CONFIG_TEST" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX"config.h" /FD /c +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"Debug_static/libdb@DB_VERSION_MAJOR@@DB_VERSION_MINOR@sd.lib" + +!ELSEIF "$(CFG)" == "@project_name@ - Win32 Release Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "DB_Stati" +# PROP BASE Intermediate_Dir "DB_Stati" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release_static" +# PROP Intermediate_Dir "Release_static" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX"config.h" /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "." /I "../include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX"config.h" /FD /c +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"Release/libdb@DB_VERSION_MAJOR@@DB_VERSION_MINOR@s.lib" +# ADD LIB32 /nologo /out:"Release_static/libdb@DB_VERSION_MAJOR@@DB_VERSION_MINOR@s.lib" + +!ELSEIF "$(CFG)" == "@project_name@ - Win32 Debug Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "DB_Stat0" +# PROP BASE Intermediate_Dir "DB_Stat0" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_static" +# PROP Intermediate_Dir "Debug_static" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /GX /Z7 /Od /I "." /I "../include" /D "CONFIG_TEST" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX"config.h" /FD /c +# ADD CPP /nologo /MTd /W3 /GX /Z7 /Od /I "." /I "../include" /D "CONFIG_TEST" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX"config.h" /FD /c +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"Debug/libdb@DB_VERSION_MAJOR@@DB_VERSION_MINOR@sd.lib" +# ADD LIB32 /nologo /out:"Debug_static/libdb@DB_VERSION_MAJOR@@DB_VERSION_MINOR@sd.lib" + +!ENDIF + +# Begin Target + +# Name "@project_name@ - Win32 Release" +# Name "@project_name@ - Win32 Debug" +# Name "@project_name@ - Win32 Release Static" +# Name "@project_name@ - Win32 Debug Static" +@SOURCE_FILES@ +# End Target +# End Project diff --git a/db/build_win32/tcl_dsp.src b/db/build_win32/tcl_dsp.src new file mode 100644 index 000000000..3b23b8c15 --- /dev/null +++ b/db/build_win32/tcl_dsp.src @@ -0,0 +1,92 @@ +# Microsoft Developer Studio Project File - Name="@project_name@" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=@project_name@ - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "@project_name@.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "@project_name@.mak" CFG="@project_name@ - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "@project_name@ - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "@project_name@ - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "@project_name@ - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /Ob2 /I "." /I "../include" /D "DB_TCL_SUPPORT" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "DB_CREATE_DLL" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 Release/libdb32.lib tcl83.lib /nologo /base:"0x13000000" /subsystem:windows /dll /machine:I386 /out:"Release/libdb_tcl@DB_VERSION_MAJOR@@DB_VERSION_MINOR@.dll" + +!ELSEIF "$(CFG)" == "@project_name@ - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 2 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "." /I "../include" /D "DB_TCL_SUPPORT" /D "CONFIG_TEST" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "DB_CREATE_DLL" /D "_WINDLL" /D "_AFXDLL" /YX"config.h" /FD /c +# SUBTRACT CPP /Fr +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 Debug/libdb32d.lib tcl83d.lib /nologo /base:"0x13000000" /subsystem:windows /dll /pdb:none /debug /machine:I386 /out:"Debug/libdb_tcl@DB_VERSION_MAJOR@@DB_VERSION_MINOR@d.dll" /fixed:no + +!ENDIF + +# Begin Target + +# Name "@project_name@ - Win32 Release" +# Name "@project_name@ - Win32 Debug" +@SOURCE_FILES@ +# End Target +# End Project diff --git a/db/clib/getcwd.c b/db/clib/getcwd.c new file mode 100644 index 000000000..630facb4f --- /dev/null +++ b/db/clib/getcwd.c @@ -0,0 +1,272 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1989, 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: getcwd.c,v 11.7 2000/11/30 00:58:30 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include +#include + +#if HAVE_DIRENT_H +# include +# define NAMLEN(dirent) strlen((dirent)->d_name) +#else +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# if HAVE_SYS_NDIR_H +# include +# endif +# if HAVE_SYS_DIR_H +# include +# endif +# if HAVE_NDIR_H +# include +# endif +#endif + +#include +#include +#include +#include +#endif + +#include "db_int.h" + +#define ISDOT(dp) \ + (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \ + (dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) + +#ifndef dirfd +#define dirfd(dirp) ((dirp)->dd_fd) +#endif + +/* + * getcwd -- + * Get the current working directory. + * + * PUBLIC: #ifndef HAVE_GETCWD + * PUBLIC: char *getcwd __P((char *, size_t)); + * PUBLIC: #endif + */ +char * +getcwd(pt, size) + char *pt; + size_t size; +{ + register struct dirent *dp; + register DIR *dir; + register dev_t dev; + register ino_t ino; + register int first; + register char *bpt, *bup; + struct stat s; + dev_t root_dev; + ino_t root_ino; + size_t ptsize, upsize; + int ret, save_errno; + char *ept, *eup, *up; + + /* + * If no buffer specified by the user, allocate one as necessary. + * If a buffer is specified, the size has to be non-zero. The path + * is built from the end of the buffer backwards. + */ + if (pt) { + ptsize = 0; + if (!size) { + __os_set_errno(EINVAL); + return (NULL); + } + if (size == 1) { + __os_set_errno(ERANGE); + return (NULL); + } + ept = pt + size; + } else { + if ((ret = + __os_malloc(NULL, ptsize = 1024 - 4, NULL, &pt)) != 0) { + __os_set_errno(ret); + return (NULL); + } + ept = pt + ptsize; + } + bpt = ept - 1; + *bpt = '\0'; + + /* + * Allocate bytes (1024 - malloc space) for the string of "../"'s. + * Should always be enough (it's 340 levels). If it's not, allocate + * as necessary. Special case the first stat, it's ".", not "..". + */ + if ((ret = __os_malloc(NULL, upsize = 1024 - 4, NULL, &up)) != 0) + goto err; + eup = up + 1024; + bup = up; + up[0] = '.'; + up[1] = '\0'; + + /* Save root values, so know when to stop. */ + if (stat("/", &s)) + goto err; + root_dev = s.st_dev; + root_ino = s.st_ino; + + __os_set_errno(0); /* XXX readdir has no error return. */ + + for (first = 1;; first = 0) { + /* Stat the current level. */ + if (lstat(up, &s)) + goto err; + + /* Save current node values. */ + ino = s.st_ino; + dev = s.st_dev; + + /* Check for reaching root. */ + if (root_dev == dev && root_ino == ino) { + *--bpt = PATH_SEPARATOR[0]; + /* + * It's unclear that it's a requirement to copy the + * path to the beginning of the buffer, but it's always + * been that way and stuff would probably break. + */ + bcopy(bpt, pt, ept - bpt); + __os_free(up, upsize); + return (pt); + } + + /* + * Build pointer to the parent directory, allocating memory + * as necessary. Max length is 3 for "../", the largest + * possible component name, plus a trailing NULL. + */ + if (bup + 3 + MAXNAMLEN + 1 >= eup) { + if (__os_realloc(NULL, upsize *= 2, NULL, &up) != 0) + goto err; + bup = up; + eup = up + upsize; + } + *bup++ = '.'; + *bup++ = '.'; + *bup = '\0'; + + /* Open and stat parent directory. */ + if (!(dir = opendir(up)) || fstat(dirfd(dir), &s)) + goto err; + + /* Add trailing slash for next directory. */ + *bup++ = PATH_SEPARATOR[0]; + + /* + * If it's a mount point, have to stat each element because + * the inode number in the directory is for the entry in the + * parent directory, not the inode number of the mounted file. + */ + save_errno = 0; + if (s.st_dev == dev) { + for (;;) { + if (!(dp = readdir(dir))) + goto notfound; + if (dp->d_fileno == ino) + break; + } + } else + for (;;) { + if (!(dp = readdir(dir))) + goto notfound; + if (ISDOT(dp)) + continue; + bcopy(dp->d_name, bup, dp->d_namlen + 1); + + /* Save the first error for later. */ + if (lstat(up, &s)) { + if (save_errno == 0) + save_errno = __os_get_errno(); + __os_set_errno(0); + continue; + } + if (s.st_dev == dev && s.st_ino == ino) + break; + } + + /* + * Check for length of the current name, preceding slash, + * leading slash. + */ + if (bpt - pt < dp->d_namlen + (first ? 1 : 2)) { + size_t len, off; + + if (!ptsize) { + __os_set_errno(ERANGE); + goto err; + } + off = bpt - pt; + len = ept - bpt; + if (__os_realloc(NULL, ptsize *= 2, NULL, &pt) != 0) + goto err; + bpt = pt + off; + ept = pt + ptsize; + bcopy(bpt, ept - len, len); + bpt = ept - len; + } + if (!first) + *--bpt = PATH_SEPARATOR[0]; + bpt -= dp->d_namlen; + bcopy(dp->d_name, bpt, dp->d_namlen); + (void)closedir(dir); + + /* Truncate any file name. */ + *bup = '\0'; + } + +notfound: + /* + * If readdir set errno, use it, not any saved error; otherwise, + * didn't find the current directory in its parent directory, set + * errno to ENOENT. + */ + if (__os_get_errno() == 0) + __os_set_errno(save_errno == 0 ? ENOENT : save_errno); + /* FALLTHROUGH */ +err: + if (ptsize) + __os_free(pt, ptsize); + __os_free(up, upsize); + return (NULL); +} diff --git a/db/clib/getopt.c b/db/clib/getopt.c new file mode 100644 index 000000000..667fca1d7 --- /dev/null +++ b/db/clib/getopt.c @@ -0,0 +1,139 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: getopt.c,v 11.4 2000/02/14 02:59:40 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include +#include +#include +#endif + +#include "db_int.h" + +int opterr = 1, /* if error message should be printed */ + optind = 1, /* index into parent argv vector */ + optopt, /* character checked for validity */ + optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ + +#undef BADCH +#define BADCH (int)'?' +#undef BADARG +#define BADARG (int)':' +#undef EMSG +#define EMSG "" + +/* + * getopt -- + * Parse argc/argv argument vector. + * + * PUBLIC: #ifndef HAVE_GETOPT + * PUBLIC: int getopt __P((int, char * const *, const char *)); + * PUBLIC: #endif + */ +int +getopt(nargc, nargv, ostr) + int nargc; + char * const *nargv; + const char *ostr; +{ + static char *progname; + static char *place = EMSG; /* option letter processing */ + char *oli; /* option letter list index */ + + if (!progname) { + if ((progname = __db_rpath(*nargv)) == NULL) + progname = *nargv; + else + ++progname; + } + + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc || *(place = nargv[optind]) != '-') { + place = EMSG; + return (EOF); + } + if (place[1] && *++place == '-') { /* found "--" */ + ++optind; + place = EMSG; + return (EOF); + } + } /* option letter okay? */ + if ((optopt = (int)*place++) == (int)':' || + !(oli = strchr(ostr, optopt))) { + /* + * if the user didn't specify '-' as an option, + * assume it means EOF. + */ + if (optopt == (int)'-') + return (EOF); + if (!*place) + ++optind; + if (opterr && *ostr != ':') + (void)fprintf(stderr, + "%s: illegal option -- %c\n", progname, optopt); + return (BADCH); + } + if (*++oli != ':') { /* don't need argument */ + optarg = NULL; + if (!*place) + ++optind; + } + else { /* need an argument */ + if (*place) /* no white space */ + optarg = place; + else if (nargc <= ++optind) { /* no arg */ + place = EMSG; + if (*ostr == ':') + return (BADARG); + if (opterr) + (void)fprintf(stderr, + "%s: option requires an argument -- %c\n", + progname, optopt); + return (BADCH); + } + else /* white space */ + optarg = nargv[optind]; + place = EMSG; + ++optind; + } + return (optopt); /* dump back option letter */ +} diff --git a/db/clib/memcmp.c b/db/clib/memcmp.c new file mode 100644 index 000000000..2aedc3fa6 --- /dev/null +++ b/db/clib/memcmp.c @@ -0,0 +1,67 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: memcmp.c,v 11.5 2000/02/24 21:58:12 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include +#endif + +/* + * memcmp -- + * + * PUBLIC: #ifndef HAVE_MEMCMP + * PUBLIC: int memcmp __P((const void *, const void *, size_t)); + * PUBLIC: #endif + */ +int +memcmp(s1, s2, n) + char *s1, *s2; + size_t n; +{ + if (n != 0) { + unsigned char *p1 = (unsigned char *)s1, + *p2 = (unsigned char *)s2; + do { + if (*p1++ != *p2++) + return (*--p1 - *--p2); + } while (--n != 0); + } + return (0); +} diff --git a/db/clib/memmove.c b/db/clib/memmove.c new file mode 100644 index 000000000..da6bcfe8b --- /dev/null +++ b/db/clib/memmove.c @@ -0,0 +1,155 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: memmove.c,v 11.4 2000/02/14 02:59:40 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include +#endif + +/* + * sizeof(word) MUST BE A POWER OF TWO + * SO THAT wmask BELOW IS ALL ONES + */ +typedef int word; /* "word" used for optimal copy speed */ + +#undef wsize +#define wsize sizeof(word) +#undef wmask +#define wmask (wsize - 1) + +/* + * Copy a block of memory, handling overlap. + * This is the routine that actually implements + * (the portable versions of) bcopy, memcpy, and memmove. + */ +#ifdef MEMCOPY +/* + * PUBLIC: #ifndef HAVE_MEMCPY + * PUBLIC: void *memcpy __P((void *, const void *, size_t)); + * PUBLIC: #endif + */ +void * +memcpy(dst0, src0, length) +#else +#ifdef MEMMOVE +/* + * PUBLIC: #ifndef HAVE_MEMMOVE + * PUBLIC: void *memmove __P((void *, const void *, size_t)); + * PUBLIC: #endif + */ +void * +memmove(dst0, src0, length) +#else +void +bcopy(src0, dst0, length) +#endif +#endif + void *dst0; + const void *src0; + register size_t length; +{ + register char *dst = dst0; + register const char *src = src0; + register size_t t; + + if (length == 0 || dst == src) /* nothing to do */ + goto done; + + /* + * Macros: loop-t-times; and loop-t-times, t>0 + */ +#undef TLOOP +#define TLOOP(s) if (t) TLOOP1(s) +#undef TLOOP1 +#define TLOOP1(s) do { s; } while (--t) + + if ((unsigned long)dst < (unsigned long)src) { + /* + * Copy forward. + */ + t = (int)src; /* only need low bits */ + if ((t | (int)dst) & wmask) { + /* + * Try to align operands. This cannot be done + * unless the low bits match. + */ + if ((t ^ (int)dst) & wmask || length < wsize) + t = length; + else + t = wsize - (t & wmask); + length -= t; + TLOOP1(*dst++ = *src++); + } + /* + * Copy whole words, then mop up any trailing bytes. + */ + t = length / wsize; + TLOOP(*(word *)dst = *(word *)src; src += wsize; dst += wsize); + t = length & wmask; + TLOOP(*dst++ = *src++); + } else { + /* + * Copy backwards. Otherwise essentially the same. + * Alignment works as before, except that it takes + * (t&wmask) bytes to align, not wsize-(t&wmask). + */ + src += length; + dst += length; + t = (int)src; + if ((t | (int)dst) & wmask) { + if ((t ^ (int)dst) & wmask || length <= wsize) + t = length; + else + t &= wmask; + length -= t; + TLOOP1(*--dst = *--src); + } + t = length / wsize; + TLOOP(src -= wsize; dst -= wsize; *(word *)dst = *(word *)src); + t = length & wmask; + TLOOP(*--dst = *--src); + } +done: +#if defined(MEMCOPY) || defined(MEMMOVE) + return (dst0); +#else + return; +#endif +} diff --git a/db/clib/raise.c b/db/clib/raise.c new file mode 100644 index 000000000..acec86cd6 --- /dev/null +++ b/db/clib/raise.c @@ -0,0 +1,32 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: raise.c,v 11.3 2000/02/14 02:59:41 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include +#include +#endif + +/* + * raise -- + * Send a signal to the current process. + * + * PUBLIC: #ifndef HAVE_RAISE + * PUBLIC: int raise __P((int)); + * PUBLIC: #endif + */ +int +raise(s) + int s; +{ + return (kill(getpid(), s)); +} diff --git a/db/clib/snprintf.c b/db/clib/snprintf.c new file mode 100644 index 000000000..6aa9e3ae6 --- /dev/null +++ b/db/clib/snprintf.c @@ -0,0 +1,61 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: snprintf.c,v 11.5 2000/12/22 19:38:37 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" + +/* + * snprintf -- + * Bounded version of sprintf. + * + * PUBLIC: #ifndef HAVE_SNPRINTF + * PUBLIC: int snprintf __P((char *, size_t, const char *, ...)); + * PUBLIC: #endif + */ +#ifndef HAVE_SNPRINTF +int +#ifdef __STDC__ +snprintf(char *str, size_t n, const char *fmt, ...) +#else +snprintf(str, n, fmt, va_alist) + char *str; + size_t n; + const char *fmt; + va_dcl +#endif +{ + va_list ap; + int rval; + + COMPQUIET(n, 0); +#ifdef __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif +#ifdef SPRINTF_RET_CHARPNT + (void)vsprintf(str, fmt, ap); + va_end(ap); + return (strlen(str)); +#else + rval = vsprintf(str, fmt, ap); + va_end(ap); + return (rval); +#endif +} +#endif diff --git a/db/clib/strcasecmp.c b/db/clib/strcasecmp.c new file mode 100644 index 000000000..6633197bc --- /dev/null +++ b/db/clib/strcasecmp.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 1987, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: strcasecmp.c,v 1.4 2000/03/24 22:31:31 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include +#endif + +/* + * This array is designed for mapping upper and lower case letter + * together for a case independent comparison. The mappings are + * based upon ascii character sequences. + */ +static const unsigned char charmap[] = { + '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007', + '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017', + '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027', + '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037', + '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047', + '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057', + '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067', + '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077', + '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147', + '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', + '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', + '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137', + '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147', + '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', + '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', + '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177', + '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207', + '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217', + '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227', + '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237', + '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247', + '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257', + '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267', + '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277', + '\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307', + '\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317', + '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327', + '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337', + '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347', + '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357', + '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367', + '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377', +}; + +/* + * strcasecmp -- + * Do strcmp(3) in a case-insensitive manner. + * + * PUBLIC: int strcasecmp __P((const char *, const char *)); + */ +int +strcasecmp(s1, s2) + const char *s1, *s2; +{ + register const unsigned char *cm = charmap, + *us1 = (const unsigned char *)s1, + *us2 = (const unsigned char *)s2; + + while (cm[*us1] == cm[*us2++]) + if (*us1++ == '\0') + return (0); + return (cm[*us1] - cm[*--us2]); +} diff --git a/db/clib/strerror.c b/db/clib/strerror.c new file mode 100644 index 000000000..0f7447b04 --- /dev/null +++ b/db/clib/strerror.c @@ -0,0 +1,77 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: strerror.c,v 11.4 2000/02/14 02:59:41 bostic Exp $"; +#endif /* not lint */ + +/* + * strerror -- + * Return the string associated with an errno. + * + * PUBLIC: #ifndef HAVE_STRERROR + * PUBLIC: char *strerror __P((int)); + * PUBLIC: #endif + */ +char * +strerror(num) + int num; +{ + extern int sys_nerr; + extern char *sys_errlist[]; +#undef UPREFIX +#define UPREFIX "Unknown error: " + static char ebuf[40] = UPREFIX; /* 64-bit number + slop */ + int errnum; + char *p, *t, tmp[40]; + + errnum = num; /* convert to unsigned */ + if (errnum < sys_nerr) + return(sys_errlist[errnum]); + + /* Do this by hand, so we don't include stdio(3). */ + t = tmp; + do { + *t++ = "0123456789"[errnum % 10]; + } while (errnum /= 10); + for (p = ebuf + sizeof(UPREFIX) - 1;;) { + *p++ = *--t; + if (t <= tmp) + break; + } + return(ebuf); +} diff --git a/db/clib/vsnprintf.c b/db/clib/vsnprintf.c new file mode 100644 index 000000000..3d27bc0d2 --- /dev/null +++ b/db/clib/vsnprintf.c @@ -0,0 +1,47 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: vsnprintf.c,v 11.4 2000/05/18 19:24:59 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" + +/* + * vsnprintf -- + * Bounded version of vsprintf. + * + * PUBLIC: #ifndef HAVE_VSNPRINTF + * PUBLIC: int vsnprintf(); + * PUBLIC: #endif + */ +#ifndef HAVE_VSNPRINTF +int +vsnprintf(str, n, fmt, ap) + char *str; + size_t n; + const char *fmt; + va_list ap; +{ + COMPQUIET(n, 0); + +#ifdef SPRINTF_RET_CHARPNT + (void)vsprintf(str, fmt, ap); + return (strlen(str)); +#else + return (vsprintf(str, fmt, ap)); +#endif +} +#endif diff --git a/db/common/db_byteorder.c b/db/common/db_byteorder.c new file mode 100644 index 000000000..d089cfe4c --- /dev/null +++ b/db/common/db_byteorder.c @@ -0,0 +1,62 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: db_byteorder.c,v 11.4 2000/11/30 00:58:31 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#ifdef HAVE_ENDIAN_H +#include +#if BYTE_ORDER == BIG_ENDIAN +#define WORDS_BIGENDIAN 1 +#endif +#endif + +#endif + +#include "db_int.h" +#include "common_ext.h" + +/* + * __db_byteorder -- + * Return if we need to do byte swapping, checking for illegal + * values. + * + * PUBLIC: int __db_byteorder __P((DB_ENV *, int)); + */ +int +__db_byteorder(dbenv, lorder) + DB_ENV *dbenv; + int lorder; +{ + switch (lorder) { + case 0: + break; + case 1234: +#if defined(WORDS_BIGENDIAN) + return (DB_SWAPBYTES); +#else + break; +#endif + case 4321: +#if defined(WORDS_BIGENDIAN) + break; +#else + return (DB_SWAPBYTES); +#endif + default: + __db_err(dbenv, + "unsupported byte order, only big and little-endian supported"); + return (EINVAL); + } + return (0); +} diff --git a/db/common/db_err.c b/db/common/db_err.c new file mode 100644 index 000000000..d69bd023d --- /dev/null +++ b/db/common/db_err.c @@ -0,0 +1,544 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: db_err.c,v 11.38 2001/01/22 21:50:25 sue Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#endif + +#include "db_int.h" +#include "db_shash.h" +#include "lock.h" +#include "lock_ext.h" +#include "log.h" +#include "log_ext.h" +#include "mp.h" +#include "mp_ext.h" +#include "txn.h" +#include "txn_ext.h" +#include "clib_ext.h" +#include "common_ext.h" +#include "db_auto.h" + +static void __db_errcall __P((const DB_ENV *, int, int, const char *, va_list)); +static void __db_errfile __P((const DB_ENV *, int, int, const char *, va_list)); + +/* + * __db_fchk -- + * General flags checking routine. + * + * PUBLIC: int __db_fchk __P((DB_ENV *, const char *, u_int32_t, u_int32_t)); + */ +int +__db_fchk(dbenv, name, flags, ok_flags) + DB_ENV *dbenv; + const char *name; + u_int32_t flags, ok_flags; +{ + return (LF_ISSET(~ok_flags) ? __db_ferr(dbenv, name, 0) : 0); +} + +/* + * __db_fcchk -- + * General combination flags checking routine. + * + * PUBLIC: int __db_fcchk + * PUBLIC: __P((DB_ENV *, const char *, u_int32_t, u_int32_t, u_int32_t)); + */ +int +__db_fcchk(dbenv, name, flags, flag1, flag2) + DB_ENV *dbenv; + const char *name; + u_int32_t flags, flag1, flag2; +{ + return (LF_ISSET(flag1) && + LF_ISSET(flag2) ? __db_ferr(dbenv, name, 1) : 0); +} + +/* + * __db_ferr -- + * Common flag errors. + * + * PUBLIC: int __db_ferr __P((const DB_ENV *, const char *, int)); + */ +int +__db_ferr(dbenv, name, iscombo) + const DB_ENV *dbenv; + const char *name; + int iscombo; +{ + __db_err(dbenv, "illegal flag %sspecified to %s", + iscombo ? "combination " : "", name); + return (EINVAL); +} + +/* + * __db_pgerr -- + * Error when unable to retrieve a specified page. + * + * PUBLIC: int __db_pgerr __P((DB *, db_pgno_t)); + */ +int +__db_pgerr(dbp, pgno) + DB *dbp; + db_pgno_t pgno; +{ + /* + * Three things are certain: + * Death, taxes, and lost data. + * Guess which has occurred. + */ + __db_err(dbp->dbenv, + "unable to create/retrieve page %lu", (u_long)pgno); + return (__db_panic(dbp->dbenv, EIO)); +} + +/* + * __db_pgfmt -- + * Error when a page has the wrong format. + * + * PUBLIC: int __db_pgfmt __P((DB *, db_pgno_t)); + */ +int +__db_pgfmt(dbp, pgno) + DB *dbp; + db_pgno_t pgno; +{ + __db_err(dbp->dbenv, + "page %lu: illegal page type or format", (u_long)pgno); + return (__db_panic(dbp->dbenv, EINVAL)); +} + +/* + * __db_eopnotsup -- + * Common operation not supported message. + * + * PUBLIC: int __db_eopnotsup __P((const DB_ENV *)); + */ +int +__db_eopnotsup(dbenv) + const DB_ENV *dbenv; +{ + __db_err(dbenv, "operation not supported"); +#ifdef EOPNOTSUPP + return (EOPNOTSUPP); +#else + return (EINVAL); +#endif +} + +#ifdef DIAGNOSTIC +/* + * __db_assert -- + * Error when an assertion fails. Only checked if #DIAGNOSTIC defined. + * + * PUBLIC: #ifdef DIAGNOSTIC + * PUBLIC: void __db_assert __P((const char *, const char *, int)); + * PUBLIC: #endif + */ +void +__db_assert(failedexpr, file, line) + const char *failedexpr, *file; + int line; +{ + (void)fprintf(stderr, + "__db_assert: \"%s\" failed: file \"%s\", line %d\n", + failedexpr, file, line); + fflush(stderr); + + /* We want a stack trace of how this could possibly happen. */ + abort(); + + /* NOTREACHED */ +} +#endif + +/* + * __db_panic_msg -- + * Just report that someone else paniced. + * + * PUBLIC: int __db_panic_msg __P((DB_ENV *)); + */ +int +__db_panic_msg(dbenv) + DB_ENV *dbenv; +{ + __db_err(dbenv, "region error detected; run recovery."); + return (DB_RUNRECOVERY); +} + +/* + * __db_panic -- + * Lock out the tree due to unrecoverable error. + * + * PUBLIC: int __db_panic __P((DB_ENV *, int)); + */ +int +__db_panic(dbenv, errval) + DB_ENV *dbenv; + int errval; +{ + + if (dbenv != NULL) { + ((REGENV *)((REGINFO *)dbenv->reginfo)->primary)->panic = 1; + + dbenv->db_panic = errval; + + __db_err(dbenv, "PANIC: %s", db_strerror(errval)); + + if (dbenv->db_paniccall != NULL) + dbenv->db_paniccall(dbenv, errval); + } + + /* + * Chaos reigns within. + * Reflect, repent, and reboot. + * Order shall return. + */ + return (DB_RUNRECOVERY); +} + +/* + * db_strerror -- + * ANSI C strerror(3) for DB. + */ +char * +db_strerror(error) + int error; +{ + if (error == 0) + return ("Successful return: 0"); + if (error > 0) + return (strerror(error)); + + /* + * !!! + * The Tcl API requires that some of these return strings be compared + * against strings stored in application scripts. So, any of these + * errors that do not invariably result in a Tcl exception may not be + * altered. + */ + switch (error) { + case DB_INCOMPLETE: + return ("DB_INCOMPLETE: Cache flush was unable to complete"); + case DB_KEYEMPTY: + return ("DB_KEYEMPTY: Non-existent key/data pair"); + case DB_KEYEXIST: + return ("DB_KEYEXIST: Key/data pair already exists"); + case DB_LOCK_DEADLOCK: + return + ("DB_LOCK_DEADLOCK: Locker killed to resolve a deadlock"); + case DB_LOCK_NOTGRANTED: + return ("DB_LOCK_NOTGRANTED: Lock not granted"); + case DB_NOSERVER: + return ("DB_NOSERVER: Fatal error, no server"); + case DB_NOSERVER_HOME: + return ("DB_NOSERVER_HOME: Home unrecognized at server"); + case DB_NOSERVER_ID: + return ("DB_NOSERVER_ID: Identifier unrecognized at server"); + case DB_NOTFOUND: + return ("DB_NOTFOUND: No matching key/data pair found"); + case DB_OLD_VERSION: + return ("DB_OLDVERSION: Database requires a version upgrade"); + case DB_RUNRECOVERY: + return ("DB_RUNRECOVERY: Fatal error, run database recovery"); + case DB_VERIFY_BAD: + return ("DB_VERIFY_BAD: Database verification failed"); + default: { + /* + * !!! + * Room for a 64-bit number + slop. This buffer is only used + * if we're given an unknown error, which should never happen. + * Note, however, we're no longer thread-safe if it does. + */ + static char ebuf[40]; + + (void)snprintf(ebuf, sizeof(ebuf), "Unknown error: %d", error); + return (ebuf); + } + } +} + +/* + * __db_err -- + * Standard DB error routine. The same as db_errx, except that we + * don't write to stderr if no output mechanism was specified. + * + * PUBLIC: void __db_err __P((const DB_ENV *, const char *, ...)); + */ +void +#ifdef __STDC__ +__db_err(const DB_ENV *dbenv, const char *fmt, ...) +#else +__db_err(dbenv, fmt, va_alist) + const DB_ENV *dbenv; + const char *fmt; + va_dcl +#endif +{ + va_list ap; + +/* + XXX + Log the message. + + It would be nice to automatically log the error into the log files + if the application is configured for logging. The problem is that + if we currently hold the log region mutex, we will self-deadlock. + Leave all the structure in place, but turned off. I'd like to fix + this in the future by detecting if we have the log region already + locked (e.g., a flag in the environment handle), or perhaps even + have a finer granularity so that the only calls to __db_err we + can't log are those made while we have the current log buffer + locked, or perhaps have a separate buffer into which we log error + messages. + +#ifdef __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + __db_real_log(dbenv, NULL, "db_err", 0, fmt, ap); + + va_end(ap); +#endif +*/ + + /* Tell the application. */ +#ifdef __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + __db_real_err(dbenv, 0, 0, 0, fmt, ap); + + va_end(ap); +} + +/* + * __db_real_err -- + * All the DB error routines end up here. + * + * PUBLIC: void __db_real_err + * PUBLIC: __P((const DB_ENV *, int, int, int, const char *, va_list)); + */ +void +__db_real_err(dbenv, error, error_set, stderr_default, fmt, ap) + const DB_ENV *dbenv; + int error, error_set, stderr_default; + const char *fmt; + va_list ap; +{ + /* Call the user's callback function, if specified. */ + if (dbenv != NULL && dbenv->db_errcall != NULL) + __db_errcall(dbenv, error, error_set, fmt, ap); + + /* Write to the user's file descriptor, if specified. */ + if (dbenv != NULL && dbenv->db_errfile != NULL) + __db_errfile(dbenv, error, error_set, fmt, ap); + + /* + * If we have a default and we didn't do either of the above, write + * to the default. + */ + if (stderr_default && (dbenv == NULL || + (dbenv->db_errcall == NULL && dbenv->db_errfile == NULL))) + __db_errfile(dbenv, error, error_set, fmt, ap); +} + +/* + * __db_errcall -- + * Do the error message work for callback functions. + */ +static void +__db_errcall(dbenv, error, error_set, fmt, ap) + const DB_ENV *dbenv; + int error, error_set; + const char *fmt; + va_list ap; +{ + char *p; + char __errbuf[2048]; /* !!!: END OF THE STACK DON'T TRUST SPRINTF. */ + + p = __errbuf; + if (fmt != NULL) { + p += vsnprintf(__errbuf, sizeof(__errbuf), fmt, ap); + if (error_set) { + *p++ = ':'; + *p++ = ' '; + } + } + if (error_set) + (void)strcpy(p, db_strerror(error)); + + dbenv->db_errcall(dbenv->db_errpfx, __errbuf); +} + +/* + * __db_errfile -- + * Do the error message work for FILE *s. + */ +static void +__db_errfile(dbenv, error, error_set, fmt, ap) + const DB_ENV *dbenv; + int error, error_set; + const char *fmt; + va_list ap; +{ + FILE *fp; + + fp = dbenv == NULL || + dbenv->db_errfile == NULL ? stderr : dbenv->db_errfile; + + if (dbenv != NULL && dbenv->db_errpfx != NULL) + (void)fprintf(fp, "%s: ", dbenv->db_errpfx); + if (fmt != NULL) { + (void)vfprintf(fp, fmt, ap); + if (error_set) + (void)fprintf(fp, ": "); + } + if (error_set) + (void)fprintf(fp, "%s", db_strerror(error)); + (void)fprintf(fp, "\n"); + (void)fflush(fp); +} + +/* + * __db_logmsg -- + * Write information into the DB log. + * + * PUBLIC: void __db_logmsg __P((const DB_ENV *, + * PUBLIC: DB_TXN *, const char *, u_int32_t, const char *, ...)); + */ +void +#ifdef __STDC__ +__db_logmsg(const DB_ENV *dbenv, + DB_TXN *txnid, const char *opname, u_int32_t flags, const char *fmt, ...) +#else +__db_logmsg(dbenv, txnid, opname, flags, fmt, va_alist) + const DB_ENV *dbenv; + DB_TXN *txnid; + const char *opname, *fmt; + u_int32_t flags; + va_dcl +#endif +{ + va_list ap; + +#ifdef __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + __db_real_log(dbenv, txnid, opname, flags, fmt, ap); + + va_end(ap); +} + +/* + * __db_real_log -- + * Write information into the DB log. + * + * PUBLIC: void __db_real_log __P((const DB_ENV *, + * PUBLIC: DB_TXN *, const char *, u_int32_t, const char *, va_list ap)); + */ +void +#ifdef __STDC__ +__db_real_log(const DB_ENV *dbenv, DB_TXN *txnid, + const char *opname, u_int32_t flags, const char *fmt, va_list ap) +#else +__db_real_log(dbenv, txnid, opname, flags, fmt, ap) + const DB_ENV *dbenv; + DB_TXN *txnid; + const char *opname, *fmt; + u_int32_t flags; + va_list ap; +#endif +{ + DBT opdbt, msgdbt; + DB_LSN lsn; + char __logbuf[2048]; /* !!!: END OF THE STACK DON'T TRUST SPRINTF. */ + + if (!LOGGING_ON(dbenv)) + return; + + memset(&opdbt, 0, sizeof(opdbt)); + opdbt.data = (void *)opname; + opdbt.size = strlen(opname) + 1; + + memset(&msgdbt, 0, sizeof(msgdbt)); + msgdbt.data = __logbuf; + msgdbt.size = vsnprintf(__logbuf, sizeof(__logbuf), fmt, ap); + + /* + * XXX + * Explicitly discard the const. Otherwise, we have to const DB_ENV + * references throughout the logging subsystem. + */ + __db_debug_log( + (DB_ENV *)dbenv, txnid, &lsn, flags, &opdbt, -1, &msgdbt, NULL, 0); +} + +/* + * __db_unknown_flag -- report internal error + * + * PUBLIC: int __db_unknown_flag __P((DB_ENV *, char *, u_int32_t)); + */ +int +__db_unknown_flag(dbenv, routine, flag) + DB_ENV *dbenv; + char *routine; + u_int32_t flag; +{ + __db_err(dbenv, "%s: Unknown flag: 0x%x", routine, flag); + DB_ASSERT(0); + return (EINVAL); +} + +/* + * __db_unknown_type -- report internal error + * + * PUBLIC: int __db_unknown_type __P((DB_ENV *, char *, u_int32_t)); + */ +int +__db_unknown_type(dbenv, routine, type) + DB_ENV *dbenv; + char *routine; + u_int32_t type; +{ + __db_err(dbenv, "%s: Unknown db type: 0x%x", routine, type); + DB_ASSERT(0); + return (EINVAL); +} + +#ifdef DIAGNOSTIC +/* + * __db_missing_txn_err -- + * Cannot combine operations with and without transactions. + * + * PUBLIC: #ifdef DIAGNOSTIC + * PUBLIC: int __db_missing_txn_err __P((DB_ENV *)); + * PUBLIC: #endif + */ +int +__db_missing_txn_err(dbenv) + DB_ENV *dbenv; +{ + __db_err(dbenv, + "DB handle previously used in transaction, missing transaction handle."); + return (EINVAL); +} +#endif diff --git a/db/common/db_getlong.c b/db/common/db_getlong.c new file mode 100644 index 000000000..bead530cd --- /dev/null +++ b/db/common/db_getlong.c @@ -0,0 +1,159 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: db_getlong.c,v 11.11 2000/12/22 19:16:04 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#endif + +#include "db_int.h" +#include "clib_ext.h" + +/* + * __db_getlong -- + * Return a long value inside of basic parameters. + * + * PUBLIC: int __db_getlong + * PUBLIC: __P((DB *, const char *, char *, long, long, long *)); + */ +int +__db_getlong(dbp, progname, p, min, max, storep) + DB *dbp; + const char *progname; + char *p; + long min, max, *storep; +{ + long val; + char *end; + + __os_set_errno(0); + val = strtol(p, &end, 10); + if ((val == LONG_MIN || val == LONG_MAX) && + __os_get_errno() == ERANGE) { + if (dbp == NULL) { + fprintf(stderr, + "%s: %s: %s\n", progname, p, strerror(ERANGE)); + exit(1); + } + dbp->err(dbp, ERANGE, "%s", p); + return (1); + } + if (p[0] == '\0' || (end[0] != '\0' && end[0] != '\n')) { + if (dbp == NULL) { + fprintf(stderr, + "%s: %s: Invalid numeric argument\n", progname, p); + exit(1); + } + dbp->errx(dbp, "%s: Invalid numeric argument", p); + return (1); + } + if (val < min) { + if (dbp == NULL) { + fprintf(stderr, + "%s: %s: Less than minimum value (%ld)\n", + progname, p, min); + exit(1); + } + dbp->errx(dbp, "%s: Less than minimum value (%ld)", p, min); + return (1); + } + if (val > max) { + if (dbp == NULL) { + fprintf(stderr, + "%s: %s: Greater than maximum value (%ld)\n", + progname, p, max); + exit(1); + } + dbp->errx(dbp, "%s: Greater than maximum value (%ld)", p, max); + exit(1); + } + *storep = val; + return (0); +} + +/* + * __db_getulong -- + * Return an unsigned long value inside of basic parameters. + * + * PUBLIC: int __db_getulong + * PUBLIC: __P((DB *, const char *, char *, u_long, u_long, u_long *)); + */ +int +__db_getulong(dbp, progname, p, min, max, storep) + DB *dbp; + const char *progname; + char *p; + u_long min, max, *storep; +{ +#if !defined(HAVE_STRTOUL) + COMPQUIET(min, 0); + + return (__db_getlong(dbp, progname, p, 0, max, (long *)storep)); +#else + u_long val; + char *end; + + __os_set_errno(0); + val = strtoul(p, &end, 10); + if (val == ULONG_MAX && __os_get_errno() == ERANGE) { + if (dbp == NULL) { + fprintf(stderr, + "%s: %s: %s\n", progname, p, strerror(ERANGE)); + exit(1); + } + dbp->err(dbp, ERANGE, "%s", p); + return (1); + } + if (p[0] == '\0' || (end[0] != '\0' && end[0] != '\n')) { + if (dbp == NULL) { + fprintf(stderr, + "%s: %s: Invalid numeric argument\n", progname, p); + exit(1); + } + dbp->errx(dbp, "%s: Invalid numeric argument", p); + return (1); + } + if (val < min) { + if (dbp == NULL) { + fprintf(stderr, + "%s: %s: Less than minimum value (%ld)\n", + progname, p, min); + exit(1); + } + dbp->errx(dbp, "%s: Less than minimum value (%ld)", p, min); + return (1); + } + + /* + * We allow a 0 to substitute as a max value for ULONG_MAX because + * 1) accepting only a 0 value is unlikely to be necessary, and 2) + * we don't want callers to have to use ULONG_MAX explicitly, as it + * may not exist on all platforms. + */ + if (max != 0 && val > max) { + if (dbp == NULL) { + fprintf(stderr, + "%s: %s: Greater than maximum value (%ld)\n", + progname, p, max); + exit(1); + } + dbp->errx(dbp, "%s: Greater than maximum value (%ld)", p, max); + exit(1); + } + *storep = val; + return (0); +#endif /* !defined(HAVE_STRTOUL) */ +} diff --git a/db/common/db_log2.c b/db/common/db_log2.c new file mode 100644 index 000000000..95bc69499 --- /dev/null +++ b/db/common/db_log2.c @@ -0,0 +1,65 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1995, 1996 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Margo Seltzer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: db_log2.c,v 11.4 2000/02/14 02:59:41 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include +#endif + +#include "db_int.h" +#include "common_ext.h" + +/* + * PUBLIC: u_int32_t __db_log2 __P((u_int32_t)); + */ +u_int32_t +__db_log2(num) + u_int32_t num; +{ + u_int32_t i, limit; + + limit = 1; + for (i = 0; limit < num; limit = limit << 1) + ++i; + return (i); +} diff --git a/db/common/util_log.c b/db/common/util_log.c new file mode 100644 index 000000000..a4743cc2c --- /dev/null +++ b/db/common/util_log.c @@ -0,0 +1,63 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: util_log.c,v 1.7 2000/11/30 00:58:31 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#if TIME_WITH_SYS_TIME +#include +#include +#else +#if HAVE_SYS_TIME_H +#include +#else +#include +#endif +#endif + +#include +#include +#endif + +#include "db_int.h" +#include "common_ext.h" + +/* + * __db_util_logset -- + * Log that we're running. + * + * PUBLIC: int __db_util_logset __P((const char *, char *)); + */ +int +__db_util_logset(progname, fname) + const char *progname; + char *fname; +{ + FILE *fp; + time_t now; + + if ((fp = fopen(fname, "w")) == NULL) + goto err; + + (void)time(&now); + fprintf(fp, "%s: %lu %s", progname, (u_long)getpid(), ctime(&now)); + + if (fclose(fp) == EOF) + goto err; + + return (0); + +err: fprintf(stderr, "%s: %s: %s\n", progname, fname, strerror(errno)); + return (1); +} diff --git a/db/common/util_sig.c b/db/common/util_sig.c new file mode 100644 index 000000000..6fe0166fe --- /dev/null +++ b/db/common/util_sig.c @@ -0,0 +1,87 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: util_sig.c,v 1.3 2000/04/28 19:32:00 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "common_ext.h" + +static int interrupt; +static void onint __P((int)); + +/* + * onint -- + * Interrupt signal handler. + */ +static void +onint(signo) + int signo; +{ + if ((interrupt = signo) == 0) + interrupt = SIGINT; +} + +/* + * __db_util_siginit -- + * + * PUBLIC: void __db_util_siginit __P((void)); + */ +void +__db_util_siginit() +{ + /* + * Initialize the set of signals for which we want to clean up. + * Generally, we try not to leave the shared regions locked if + * we can. + */ +#ifdef SIGHUP + (void)signal(SIGHUP, onint); +#endif + (void)signal(SIGINT, onint); +#ifdef SIGPIPE + (void)signal(SIGPIPE, onint); +#endif + (void)signal(SIGTERM, onint); +} + +/* + * __db_util_interrupted -- + * Return if interrupted. + * + * PUBLIC: int __db_util_interrupted __P((void)); + */ +int +__db_util_interrupted() +{ + return (interrupt != 0); +} + +/* + * __db_util_sigresend -- + * + * PUBLIC: void __db_util_sigresend __P((void)); + */ +void +__db_util_sigresend() +{ + /* Resend any caught signal. */ + if (__db_util_interrupted != 0) { + (void)signal(interrupt, SIG_DFL); + (void)raise(interrupt); + /* NOTREACHED */ + } +} diff --git a/db/cxx/cxx_app.cpp b/db/cxx/cxx_app.cpp new file mode 100644 index 000000000..1fcf04b5c --- /dev/null +++ b/db/cxx/cxx_app.cpp @@ -0,0 +1,671 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: cxx_app.cpp,v 11.38 2000/12/21 20:30:18 dda Exp $"; +#endif /* not lint */ + +#include +#include // needed for set_error_stream +#include + +#include "db_cxx.h" +#include "cxx_int.h" + +#include "db_int.h" +#include "common_ext.h" + +// The reason for a static variable is that some structures +// (like Dbts) have no connection to any Db or DbEnv, so when +// errors occur in their methods, we must have some reasonable +// way to determine whether to throw or return errors. +// +// This variable is taken from flags whenever a DbEnv is constructed. +// Normally there is only one DbEnv per program, and even if not, +// there is typically a single policy of throwing or returning. +// +static int last_known_error_policy = ON_ERROR_UNKNOWN; + +//////////////////////////////////////////////////////////////////////// +// // +// DbEnv // +// // +//////////////////////////////////////////////////////////////////////// + +ostream *DbEnv::error_stream_ = 0; + +// _destroy_check is called when there is a user error in a +// destructor, specifically when close has not been called for an +// object (even if it was never opened). If the DbEnv is being +// destroyed we cannot always use DbEnv::error_stream_, so we'll +// use cerr in that case. +// +void DbEnv::_destroy_check(const char *str, int isDbEnv) +{ + ostream *out; + + out = error_stream_; + if (out == NULL || isDbEnv == 1) + out = &cerr; + + (*out) << "DbEnv::_destroy_check: open " << str << " object destroyed\n"; +} + +// A truism for the DbEnv object is that there is a valid +// DB_ENV handle from the constructor until close(). +// After the close, the DB_ENV handle is invalid and +// no operations are permitted on the DbEnv (other than +// destructor). Leaving the DbEnv handle open and not +// doing a close is generally considered an error. +// +// We used to allow DbEnv objects to be closed and reopened. +// This implied always keeping a valid DB_ENV object, and +// coordinating the open objects between Db/DbEnv turned +// out to be overly complicated. Now we do not allow this. + +DbEnv::DbEnv(u_int32_t flags) +: imp_(0) +, construct_error_(0) +, construct_flags_(flags) +, tx_recover_callback_(0) +, paniccall_callback_(0) +{ + int err; + + COMPQUIET(err, 0); + if ((err = initialize(0)) != 0) + DB_ERROR("DbEnv::DbEnv", err, error_policy()); +} + +DbEnv::DbEnv(DB_ENV *env, u_int32_t flags) +: imp_(0) +, construct_error_(0) +, construct_flags_(flags) +, tx_recover_callback_(0) +, paniccall_callback_(0) +{ + int err; + + COMPQUIET(err, 0); + if ((err = initialize(env)) != 0) + DB_ERROR("DbEnv::DbEnv", err, error_policy()); +} + +// Note: if the user has not closed, we call _destroy_check +// to warn against this non-safe programming practice, +// and call close anyway. +// +DbEnv::~DbEnv() +{ + DB_ENV *env = unwrap(this); + + if (env != NULL) { + _destroy_check("DbEnv", 1); + (void)env->close(env, 0); + + // extra safety + cleanup(); + } +} + +// called by Db destructor when the DbEnv is owned by DB. +void DbEnv::cleanup() +{ + DB_ENV *env = unwrap(this); + + if (env != NULL) { + env->cj_internal = 0; + imp_ = 0; + } +} + +int DbEnv::close(u_int32_t flags) +{ + DB_ENV *env = unwrap(this); + int err, init_err; + + COMPQUIET(init_err, 0); + + // after a close (no matter if success or failure), + // the underlying DB_ENV object must not be accessed, + // so we clean up in advance. + // + cleanup(); + + // It's safe to throw an error after the close, + // since our error mechanism does not peer into + // the DB* structures. + // + if ((err = env->close(env, flags)) != 0) { + DB_ERROR("DbEnv::close", err, error_policy()); + } + return (err); +} + +void DbEnv::err(int error, const char *format, ...) +{ + va_list args; + DB_ENV *env = unwrap(this); + + va_start(args, format); + __db_real_err(env, error, 1, 1, format, args); + va_end(args); +} + +void DbEnv::errx(const char *format, ...) +{ + va_list args; + DB_ENV *env = unwrap(this); + + va_start(args, format); + __db_real_err(env, 0, 0, 1, format, args); + va_end(args); +} + +// used internally during constructor +// to associate an existing DB_ENV with this DbEnv, +// or create a new one. If there is an error, +// construct_error_ is set; this is examined during open. +// +int DbEnv::initialize(DB_ENV *env) +{ + int err; + + last_known_error_policy = error_policy(); + + if (env == 0) { + // Create a new DB_ENV environment. + if ((err = ::db_env_create(&env, + construct_flags_ & ~DB_CXX_NO_EXCEPTIONS)) != 0) { + construct_error_ = err; + return (err); + } + } + imp_ = wrap(env); + env->cj_internal = this; // for DB_ENV* to DbEnv* conversion + return (0); +} + +// Return a tristate value corresponding to whether we should +// throw exceptions on errors: +// ON_ERROR_RETURN +// ON_ERROR_THROW +// ON_ERROR_UNKNOWN +// +int DbEnv::error_policy() +{ + if ((construct_flags_ & DB_CXX_NO_EXCEPTIONS) != 0) { + return (ON_ERROR_RETURN); + } + else { + return (ON_ERROR_THROW); + } +} + +// If an error occurred during the constructor, report it now. +// Otherwise, call the underlying DB->open method. +// +int DbEnv::open(const char *db_home, u_int32_t flags, int mode) +{ + DB_ENV *env = unwrap(this); + int err; + + if ((err = construct_error_) != 0) + DB_ERROR("Db::open", err, error_policy()); + else if ((err = env->open(env, db_home, flags, mode)) != 0) + DB_ERROR("DbEnv::open", err, error_policy()); + + return (err); +} + +int DbEnv::remove(const char *db_home, u_int32_t flags) +{ + DB_ENV *env; + int ret; + + env = unwrap(this); + + // after a remove (no matter if success or failure), + // the underlying DB_ENV object must not be accessed, + // so we clean up in advance. + // + cleanup(); + + if ((ret = env->remove(env, db_home, flags)) != 0) + DB_ERROR("DbEnv::remove", ret, error_policy()); + + return (ret); +} + +// Report an error associated with the DbEnv. +// error_policy is one of: +// ON_ERROR_THROW throw an error +// ON_ERROR_RETURN do nothing here, the caller will return an error +// ON_ERROR_UNKNOWN defer the policy to policy saved in DbEnv::DbEnv +// +void DbEnv::runtime_error(const char *caller, int error, int error_policy) +{ + if (error_policy == ON_ERROR_UNKNOWN) + error_policy = last_known_error_policy; + if (error_policy == ON_ERROR_THROW) { + // Creating and throwing the object in two separate + // statements seems to be necessary for HP compilers. + DbException except(caller, error); + throw except; + } +} + +// static method +char *DbEnv::strerror(int error) +{ + return (db_strerror(error)); +} + +// This is a 'glue' function declared as extern "C" so it will +// be compatible with picky compilers that do not allow mixing +// of function pointers to 'C' functions with function pointers +// to C++ functions. +// +extern "C" +void _stream_error_function_c(const char *prefix, char *message) +{ + DbEnv::_stream_error_function(prefix, message); +} + +void DbEnv::_stream_error_function(const char *prefix, char *message) +{ + // HP compilers need the extra casts, we don't know why. + if (error_stream_) { + if (prefix) { + (*error_stream_) << prefix << (const char *)": "; + } + if (message) { + (*error_stream_) << (const char *)message; + } + (*error_stream_) << (const char *)"\n"; + } +} + +// Note: This actually behaves a bit like a static function, +// since DB_ENV.db_errcall has no information about which +// db_env triggered the call. A user that has multiple DB_ENVs +// will simply not be able to have different streams for each one. +// +void DbEnv::set_error_stream(ostream *stream) +{ + DB_ENV *dbenv = unwrap(this); + + error_stream_ = stream; + dbenv->set_errcall(dbenv, (stream == 0) ? 0 : + _stream_error_function_c); +} + +// static method +char *DbEnv::version(int *major, int *minor, int *patch) +{ + return (db_version(major, minor, patch)); +} + +// This is a variant of the DB_WO_ACCESS macro to define a simple set_ +// method calling the underlying C method, but unlike a simple +// set method, it may return an error or raise an exception. +// Note this macro expects that input _argspec is an argument +// list element (e.g. "char *arg") defined in terms of "arg". +// +#define DB_DBENV_ACCESS(_name, _argspec) \ + \ +int DbEnv::set_##_name(_argspec) \ +{ \ + int ret; \ + DB_ENV *dbenv = unwrap(this); \ + \ + if ((ret = (*(dbenv->set_##_name))(dbenv, arg)) != 0) {\ + DB_ERROR("DbEnv::set_" # _name, ret, error_policy()); \ + } \ + return (ret); \ +} + +#define DB_DBENV_ACCESS_NORET(_name, _argspec) \ + \ +void DbEnv::set_##_name(_argspec) \ +{ \ + DB_ENV *dbenv = unwrap(this); \ + \ + (*(dbenv->set_##_name))(dbenv, arg); \ + return; \ +} + +DB_DBENV_ACCESS_NORET(errfile, FILE *arg) +DB_DBENV_ACCESS_NORET(errpfx, const char *arg) + +// We keep these alphabetical by field name, +// for comparison with Java's list. +// +DB_DBENV_ACCESS(data_dir, const char *arg) +DB_DBENV_ACCESS(lg_bsize, u_int32_t arg) +DB_DBENV_ACCESS(lg_dir, const char *arg) +DB_DBENV_ACCESS(lg_max, u_int32_t arg) +DB_DBENV_ACCESS(lk_detect, u_int32_t arg) +DB_DBENV_ACCESS(lk_max, u_int32_t arg) +DB_DBENV_ACCESS(lk_max_lockers, u_int32_t arg) +DB_DBENV_ACCESS(lk_max_locks, u_int32_t arg) +DB_DBENV_ACCESS(lk_max_objects, u_int32_t arg) +DB_DBENV_ACCESS(mp_mmapsize, size_t arg) +DB_DBENV_ACCESS(mutexlocks, int arg) +DB_DBENV_ACCESS(tmp_dir, const char *arg) +DB_DBENV_ACCESS(tx_max, u_int32_t arg) + +// Here are the set methods that don't fit the above mold. +// +extern "C" { + typedef void (*db_errcall_fcn_type) + (const char *, char *); +}; + +void DbEnv::set_errcall(void (*arg)(const char *, char *)) +{ + DB_ENV *dbenv = unwrap(this); + + // XXX + // We are casting from a function ptr declared with C++ + // linkage to one (same arg types) declared with C + // linkage. It's hard to imagine a pair of C/C++ + // compilers from the same vendor for which this + // won't work. Unfortunately, we can't use a + // intercept function like the others since the + // function does not have a (DbEnv*) as one of + // the args. If this causes trouble, we can pull + // the same trick we use in Java, namely stuffing + // a (DbEnv*) pointer into the prefix. We're + // avoiding this for the moment because it obfuscates. + // + (*(dbenv->set_errcall))(dbenv, (db_errcall_fcn_type)arg); +} + +int DbEnv::set_cachesize(u_int32_t gbytes, u_int32_t bytes, int ncache) +{ + int ret; + DB_ENV *dbenv = unwrap(this); + + if ((ret = + (*(dbenv->set_cachesize))(dbenv, gbytes, bytes, ncache)) != 0) + DB_ERROR("DbEnv::set_cachesize", ret, error_policy()); + + return (ret); +} + +int DbEnv::set_flags(u_int32_t flags, int onoff) +{ + int ret; + DB_ENV *dbenv = unwrap(this); + + if ((ret = (dbenv->set_flags)(dbenv, flags, onoff)) != 0) + DB_ERROR("DbEnv::set_flags", ret, error_policy()); + + return (ret); +} + +int DbEnv::set_lk_conflicts(u_int8_t *lk_conflicts, int lk_max) +{ + int ret; + DB_ENV *dbenv = unwrap(this); + + if ((ret = (*(dbenv->set_lk_conflicts)) + (dbenv, lk_conflicts, lk_max)) != 0) + DB_ERROR("DbEnv::set_lk_conflicts", ret, error_policy()); + + return (ret); +} + +// static method +int DbEnv::set_pageyield(int arg) +{ + int ret; + + if ((ret = db_env_set_pageyield(arg)) != 0) + DB_ERROR("DbEnv::set_pageyield", ret, last_known_error_policy); + + return (ret); +} + +// static method +int DbEnv::set_panicstate(int arg) +{ + int ret; + + if ((ret = db_env_set_panicstate(arg)) != 0) + DB_ERROR("DbEnv::set_panicstate", ret, last_known_error_policy); + + return (ret); +} + +// static method +int DbEnv::set_region_init(int arg) +{ + int ret; + + if ((ret = db_env_set_region_init(arg)) != 0) + DB_ERROR("DbEnv::set_region_init", ret, last_known_error_policy); + + return (ret); +} + +int DbEnv::set_server(char *host, long tsec, long ssec, u_int32_t flags) +{ + int ret; + DB_ENV *dbenv = unwrap(this); + + if ((ret = dbenv->set_server(dbenv, host, tsec, ssec, flags)) != 0) + DB_ERROR("DbEnv::set_server", ret, error_policy()); + + return (ret); +} + +int DbEnv::set_shm_key(long shm_key) +{ + int ret; + DB_ENV *dbenv = unwrap(this); + + if ((ret = dbenv->set_shm_key(dbenv, shm_key)) != 0) + DB_ERROR("DbEnv::set_shm_key", ret, error_policy()); + + return (ret); +} + +// static method +int DbEnv::set_tas_spins(u_int32_t arg) +{ + int ret; + + if ((ret = db_env_set_tas_spins(arg)) != 0) + DB_ERROR("DbEnv::set_tas_spins", ret, last_known_error_policy); + + return (ret); +} + +int DbEnv::set_verbose(u_int32_t which, int onoff) +{ + int ret; + DB_ENV *dbenv = unwrap(this); + + if ((ret = (*(dbenv->set_verbose))(dbenv, which, onoff)) != 0) + DB_ERROR("DbEnv::set_verbose", ret, error_policy()); + + return (ret); +} + +// This is a 'glue' function declared as extern "C" so it will +// be compatible with picky compilers that do not allow mixing +// of function pointers to 'C' functions with function pointers +// to C++ functions. +// +extern "C" +int _tx_recover_intercept_c(DB_ENV *env, DBT *dbt, + DB_LSN *lsn, db_recops op) +{ + return (DbEnv::_tx_recover_intercept(env, dbt, lsn, op)); +} + +int DbEnv::_tx_recover_intercept(DB_ENV *env, DBT *dbt, + DB_LSN *lsn, db_recops op) +{ + if (env == 0) { + DB_ERROR("DbEnv::tx_recover_callback", EINVAL, ON_ERROR_UNKNOWN); + return (EINVAL); + } + DbEnv *cxxenv = (DbEnv *)env->cj_internal; + if (cxxenv == 0) { + DB_ERROR("DbEnv::tx_recover_callback", EINVAL, ON_ERROR_UNKNOWN); + return (EINVAL); + } + if (cxxenv->tx_recover_callback_ == 0) { + DB_ERROR("DbEnv::tx_recover_callback", EINVAL, cxxenv->error_policy()); + return (EINVAL); + } + Dbt *cxxdbt = (Dbt *)dbt; + DbLsn *cxxlsn = (DbLsn *)lsn; + return ((*cxxenv->tx_recover_callback_)(cxxenv, cxxdbt, cxxlsn, op)); +} + +int DbEnv::set_tx_recover + (int (*arg)(DbEnv *, Dbt *, DbLsn *, db_recops)) +{ + int ret; + DB_ENV *dbenv = unwrap(this); + + tx_recover_callback_ = arg; + if ((ret = + (*(dbenv->set_tx_recover))(dbenv, _tx_recover_intercept_c)) != 0) + DB_ERROR("DbEnv::set_tx_recover", ret, error_policy()); + + return (ret); +} + +int DbEnv::set_tx_timestamp(time_t *timestamp) +{ + int ret; + DB_ENV *dbenv = unwrap(this); + + if ((ret = dbenv->set_tx_timestamp(dbenv, timestamp)) != 0) + DB_ERROR("DbEnv::set_tx_timestamp", ret, error_policy()); + + return (ret); +} + +// This is a 'glue' function declared as extern "C" so it will +// be compatible with picky compilers that do not allow mixing +// of function pointers to 'C' functions with function pointers +// to C++ functions. +// +extern "C" +void _paniccall_intercept_c(DB_ENV *env, int errval) +{ + DbEnv::_paniccall_intercept(env, errval); +} + +void DbEnv::_paniccall_intercept(DB_ENV *env, int errval) +{ + if (env == 0) { + DB_ERROR("DbEnv::paniccall_callback", EINVAL, ON_ERROR_UNKNOWN); + } + DbEnv *cxxenv = (DbEnv *)env->cj_internal; + if (cxxenv == 0) { + DB_ERROR("DbEnv::paniccall_callback", EINVAL, ON_ERROR_UNKNOWN); + } + if (cxxenv->paniccall_callback_ == 0) { + DB_ERROR("DbEnv::paniccall_callback", EINVAL, cxxenv->error_policy()); + } + (*cxxenv->paniccall_callback_)(cxxenv, errval); +} + +int DbEnv::set_paniccall(void (*arg)(DbEnv *, int)) +{ + DB_ENV *dbenv = unwrap(this); + + paniccall_callback_ = arg; + + return ((*(dbenv->set_paniccall))(dbenv, _paniccall_intercept_c)); +} + +// This is a 'glue' function declared as extern "C" so it will +// be compatible with picky compilers that do not allow mixing +// of function pointers to 'C' functions with function pointers +// to C++ functions. +// +extern "C" +int _recovery_init_intercept_c(DB_ENV *env) +{ + return (DbEnv::_recovery_init_intercept(env)); +} + +int DbEnv::_recovery_init_intercept(DB_ENV *env) +{ + if (env == 0) { + DB_ERROR("DbEnv::recovery_init_callback", EINVAL, + ON_ERROR_UNKNOWN); + } + DbEnv *cxxenv = (DbEnv *)env->cj_internal; + if (cxxenv == 0) { + DB_ERROR("DbEnv::recovery_init_callback", EINVAL, + ON_ERROR_UNKNOWN); + } + if (cxxenv->recovery_init_callback_ == 0) { + DB_ERROR("DbEnv::recovery_init_callback", EINVAL, + cxxenv->error_policy()); + } + return ((*cxxenv->recovery_init_callback_)(cxxenv)); +} + +int DbEnv::set_recovery_init(int (*arg)(DbEnv *)) +{ + DB_ENV *dbenv = unwrap(this); + + recovery_init_callback_ = arg; + + return ((*(dbenv->set_recovery_init))(dbenv, _recovery_init_intercept_c)); +} + +// This is a 'glue' function declared as extern "C" so it will +// be compatible with picky compilers that do not allow mixing +// of function pointers to 'C' functions with function pointers +// to C++ functions. +// +extern "C" +void _feedback_intercept_c(DB_ENV *env, int opcode, int pct) +{ + DbEnv::_feedback_intercept(env, opcode, pct); +} + +void DbEnv::_feedback_intercept(DB_ENV *env, int opcode, int pct) +{ + if (env == 0) { + DB_ERROR("DbEnv::feedback_callback", EINVAL, ON_ERROR_UNKNOWN); + return; + } + DbEnv *cxxenv = (DbEnv *)env->cj_internal; + if (cxxenv == 0) { + DB_ERROR("DbEnv::feedback_callback", EINVAL, ON_ERROR_UNKNOWN); + return; + } + if (cxxenv->feedback_callback_ == 0) { + DB_ERROR("DbEnv::feedback_callback", EINVAL, + cxxenv->error_policy()); + return; + } + (*cxxenv->feedback_callback_)(cxxenv, opcode, pct); +} + +int DbEnv::set_feedback(void (*arg)(DbEnv *, int, int)) +{ + DB_ENV *dbenv = unwrap(this); + + feedback_callback_ = arg; + + return ((*(dbenv->set_feedback))(dbenv, _feedback_intercept_c)); +} diff --git a/db/cxx/cxx_except.cpp b/db/cxx/cxx_except.cpp new file mode 100644 index 000000000..a62e21a76 --- /dev/null +++ b/db/cxx/cxx_except.cpp @@ -0,0 +1,132 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: cxx_except.cpp,v 11.7 2000/09/21 15:05:45 dda Exp $"; +#endif /* not lint */ + +#include + +#include "db_cxx.h" +#include "cxx_int.h" + +// tmpString is used to create strings on the stack +// +class tmpString +{ +public: + tmpString(const char *str1, + const char *str2 = 0, + const char *str3 = 0, + const char *str4 = 0, + const char *str5 = 0) + { + int len = strlen(str1); + if (str2) + len += strlen(str2); + if (str3) + len += strlen(str3); + if (str4) + len += strlen(str4); + if (str5) + len += strlen(str5); + + s_ = new char[len+1]; + + strcpy(s_, str1); + if (str2) + strcat(s_, str2); + if (str3) + strcat(s_, str3); + if (str4) + strcat(s_, str4); + if (str5) + strcat(s_, str5); + } + ~tmpString() { delete [] s_; } + operator const char *() { return (s_); } + +private: + char *s_; +}; + +// Note: would not be needed if we can inherit from exception +// It does not appear to be possible to inherit from exception +// with the current Microsoft library (VC5.0). +// +static char *dupString(const char *s) +{ + char *r = new char[strlen(s)+1]; + strcpy(r, s); + return (r); +} + +//////////////////////////////////////////////////////////////////////// +// // +// DbException // +// // +//////////////////////////////////////////////////////////////////////// + +DbException::~DbException() +{ + if (what_) + delete [] what_; +} + +DbException::DbException(int err) +: err_(err) +{ + what_ = dupString(db_strerror(err)); +} + +DbException::DbException(const char *description) +: err_(0) +{ + what_ = dupString(tmpString(description)); +} + +DbException::DbException(const char *prefix, int err) +: err_(err) +{ + what_ = dupString(tmpString(prefix, ": ", db_strerror(err))); +} + +DbException::DbException(const char *prefix1, const char *prefix2, int err) +: err_(err) +{ + what_ = dupString(tmpString(prefix1, ": ", prefix2, ": ", db_strerror(err))); +} + +DbException::DbException(const DbException &that) +: err_(that.err_) +{ + what_ = dupString(that.what_); +} + +DbException &DbException::operator = (const DbException &that) +{ + if (this != &that) { + err_ = that.err_; + if (what_) + delete [] what_; + what_ = 0; // in case new throws exception + what_ = dupString(that.what_); + } + return (*this); +} + +int DbException::get_errno() const +{ + return (err_); +} + +const char *DbException::what() const +{ + return (what_); +} diff --git a/db/cxx/cxx_lock.cpp b/db/cxx/cxx_lock.cpp new file mode 100644 index 000000000..e8ce2aa9d --- /dev/null +++ b/db/cxx/cxx_lock.cpp @@ -0,0 +1,125 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: cxx_lock.cpp,v 11.9 2000/09/21 15:05:45 dda Exp $"; +#endif /* not lint */ + +#include +#include + +#include "db_cxx.h" +#include "cxx_int.h" + +int DbEnv::lock_detect(u_int32_t flags, u_int32_t atype, int *aborted) +{ + DB_ENV *env = unwrap(this); + int err; + + if ((err = ::lock_detect(env, flags, atype, aborted)) != 0) { + DB_ERROR("DbEnv::lock_detect", err, error_policy()); + return (err); + } + return (err); +} + +int DbEnv::lock_get(u_int32_t locker, u_int32_t flags, const Dbt *obj, + db_lockmode_t lock_mode, DbLock *lock) +{ + DB_ENV *env = unwrap(this); + int err; + + if ((err = ::lock_get(env, locker, flags, obj, + lock_mode, &lock->lock_)) != 0) { + DB_ERROR("DbEnv::lock_get", err, error_policy()); + return (err); + } + return (err); +} + +int DbEnv::lock_id(u_int32_t *idp) +{ + DB_ENV *env = unwrap(this); + int err; + + if ((err = ::lock_id(env, idp)) != 0) { + DB_ERROR("DbEnv::lock_id", err, error_policy()); + } + return (err); +} + +int DbEnv::lock_stat(DB_LOCK_STAT **statp, + db_malloc_fcn_type db_malloc_fcn) +{ + DB_ENV *env = unwrap(this); + int err; + + if ((err = ::lock_stat(env, statp, db_malloc_fcn)) != 0) { + DB_ERROR("DbEnv::lock_stat", err, error_policy()); + return (err); + } + return (0); +} + +int DbEnv::lock_vec(u_int32_t locker, u_int32_t flags, + DB_LOCKREQ list[], + int nlist, DB_LOCKREQ **elist_returned) +{ + DB_ENV *env = unwrap(this); + int err; + + if ((err = ::lock_vec(env, locker, flags, list, + nlist, elist_returned)) != 0) { + DB_ERROR("DbEnv::lock_vec", err, error_policy()); + return (err); + } + return (err); +} + +//////////////////////////////////////////////////////////////////////// +// // +// DbLock // +// // +//////////////////////////////////////////////////////////////////////// + +DbLock::DbLock(DB_LOCK value) +: lock_(value) +{ +} + +DbLock::DbLock() +{ + memset(&lock_, 0, sizeof(DB_LOCK)); +} + +DbLock::DbLock(const DbLock &that) +: lock_(that.lock_) +{ +} + +DbLock &DbLock::operator = (const DbLock &that) +{ + lock_ = that.lock_; + return (*this); +} + +int DbLock::put(DbEnv *env) +{ + DB_ENV *envp = unwrap(env); + + if (!env) { + return (EINVAL); // handle never assigned + } + + int err; + if ((err = lock_put(envp, &lock_)) != 0) { + DB_ERROR("DbLock::put", err, env->error_policy()); + } + return (err); +} diff --git a/db/cxx/cxx_log.cpp b/db/cxx/cxx_log.cpp new file mode 100644 index 000000000..336b9d337 --- /dev/null +++ b/db/cxx/cxx_log.cpp @@ -0,0 +1,125 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: cxx_log.cpp,v 11.9 2000/09/21 15:05:45 dda Exp $"; +#endif /* not lint */ + +#include + +#include "db_cxx.h" +#include "cxx_int.h" + +//////////////////////////////////////////////////////////////////////// +// // +// DbLog // +// // +//////////////////////////////////////////////////////////////////////// + +int DbEnv::log_archive(char **list[], u_int32_t flags, + db_malloc_fcn_type db_malloc_fcn) +{ + int err; + DB_ENV *env = unwrap(this); + + if ((err = ::log_archive(env, list, flags, db_malloc_fcn)) != 0) { + DB_ERROR("DbEnv::log_archive", err, error_policy()); + return (err); + } + return (0); +} + +int DbEnv::log_compare(const DbLsn *lsn0, const DbLsn *lsn1) +{ + return (::log_compare(lsn0, lsn1)); +} + +int DbEnv::log_file(DbLsn *lsn, char *namep, size_t len) +{ + int err; + DB_ENV *env = unwrap(this); + + if ((err = ::log_file(env, lsn, namep, len)) != 0) { + DB_ERROR("DbEnv::log_file", err, error_policy()); + return (err); + } + return (0); +} + +int DbEnv::log_flush(const DbLsn *lsn) +{ + int err; + DB_ENV *env = unwrap(this); + + if ((err = ::log_flush(env, lsn)) != 0) { + DB_ERROR("DbEnv::log_flush", err, error_policy()); + return (err); + } + return (0); +} + +int DbEnv::log_get(DbLsn *lsn, Dbt *data, u_int32_t flags) +{ + int err; + DB_ENV *env = unwrap(this); + + if ((err = ::log_get(env, lsn, data, flags)) != 0) { + DB_ERROR("DbEnv::log_get", err, error_policy()); + return (err); + } + return (0); +} + +int DbEnv::log_put(DbLsn *lsn, const Dbt *data, u_int32_t flags) +{ + int err = 0; + DB_ENV *env = unwrap(this); + + if ((err = ::log_put(env, lsn, data, flags)) != 0) { + DB_ERROR("DbEnv::log_put", err, error_policy()); + return (err); + } + return (0); +} + +int DbEnv::log_register(Db *dbp, const char *name) +{ + int err = 0; + DB_ENV *env = unwrap(this); + + if ((err = ::log_register(env, unwrap(dbp), name)) != 0) { + DB_ERROR("DbEnv::log_register", err, error_policy()); + return (err); + } + return (0); +} + +int DbEnv::log_stat(DB_LOG_STAT **spp, db_malloc_fcn_type db_malloc_fcn) +{ + int err = 0; + DB_ENV *env = unwrap(this); + + if ((err = ::log_stat(env, spp, db_malloc_fcn)) != 0) { + DB_ERROR("DbEnv::log_stat", err, error_policy()); + return (err); + } + return (0); +} + +int DbEnv::log_unregister(Db *dbp) +{ + int err; + DB_ENV *env = unwrap(this); + + if ((err = ::log_unregister(env, unwrap(dbp))) != 0) { + DB_ERROR("DbEnv::log_unregister", err, error_policy()); + return (err); + } + return (0); +} diff --git a/db/cxx/cxx_mpool.cpp b/db/cxx/cxx_mpool.cpp new file mode 100644 index 000000000..22f4735e3 --- /dev/null +++ b/db/cxx/cxx_mpool.cpp @@ -0,0 +1,180 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: cxx_mpool.cpp,v 11.11 2000/09/21 15:05:45 dda Exp $"; +#endif /* not lint */ + +#include + +#include "db_cxx.h" +#include "cxx_int.h" + +//////////////////////////////////////////////////////////////////////// +// // +// DbMpoolFile // +// // +//////////////////////////////////////////////////////////////////////// + +DbMpoolFile::DbMpoolFile() +: imp_(0) +{ +} + +DbMpoolFile::~DbMpoolFile() +{ +} + +int DbMpoolFile::open(DbEnv *envp, const char *file, + u_int32_t flags, int mode, size_t pagesize, + DB_MPOOL_FINFO *finfop, DbMpoolFile **result) +{ + int err; + + DB_MPOOLFILE *mpf; + DB_ENV *env = unwrap(envp); + + if ((err = ::memp_fopen(env, file, flags, mode, pagesize, + finfop, &mpf)) != 0) { + DB_ERROR("DbMpoolFile::open", err, envp->error_policy()); + return (err); + } + *result = new DbMpoolFile(); + (*result)->imp_ = wrap(mpf); + return (0); +} + +int DbMpoolFile::close() +{ + DB_MPOOLFILE *mpf = unwrap(this); + int err = 0; + if (!mpf) { + err = EINVAL; + } + else if ((err = ::memp_fclose(mpf)) != 0) { + DB_ERROR("DbMpoolFile::close", err, ON_ERROR_UNKNOWN); + return (err); + } + imp_ = 0; // extra safety + + // This may seem weird, but is legal as long as we don't access + // any data before returning. + // + delete this; + return (0); +} + +int DbMpoolFile::get(db_pgno_t *pgnoaddr, u_int32_t flags, void *pagep) +{ + DB_MPOOLFILE *mpf = unwrap(this); + int err = 0; + if (!mpf) { + err = EINVAL; + } + else if ((err = ::memp_fget(mpf, pgnoaddr, flags, pagep)) != 0) { + DB_ERROR("DbMpoolFile::get", err, ON_ERROR_UNKNOWN); + } + return (err); +} + +int DbMpoolFile::put(void *pgaddr, u_int32_t flags) +{ + DB_MPOOLFILE *mpf = unwrap(this); + int err = 0; + if (!mpf) { + err = EINVAL; + } + else if ((err = ::memp_fput(mpf, pgaddr, flags)) != 0) { + DB_ERROR("DbMpoolFile::put", err, ON_ERROR_UNKNOWN); + } + return (err); +} + +int DbMpoolFile::set(void *pgaddr, u_int32_t flags) +{ + DB_MPOOLFILE *mpf = unwrap(this); + int err = 0; + if (!mpf) { + err = EINVAL; + } + else if ((err = ::memp_fset(mpf, pgaddr, flags)) != 0) { + DB_ERROR("DbMpoolFile::set", err, ON_ERROR_UNKNOWN); + } + return (err); +} + +int DbMpoolFile::sync() +{ + DB_MPOOLFILE *mpf = unwrap(this); + int err = 0; + if (!mpf) { + err = EINVAL; + } + else if ((err = ::memp_fsync(mpf)) != 0 && err != DB_INCOMPLETE) { + DB_ERROR("DbMpoolFile::sync", err, ON_ERROR_UNKNOWN); + } + return (err); +} + +//////////////////////////////////////////////////////////////////////// +// // +// DbMpool // +// // +//////////////////////////////////////////////////////////////////////// + +int DbEnv::memp_register(int ftype, + pgin_fcn_type pgin_fcn, + pgout_fcn_type pgout_fcn) +{ + DB_ENV *env = unwrap(this); + int err = 0; + + if ((err = ::memp_register(env, ftype, pgin_fcn, pgout_fcn)) != 0) { + DB_ERROR("DbEnv::memp_register", err, error_policy()); + return (err); + } + return (err); +} + +int DbEnv::memp_stat(DB_MPOOL_STAT **gsp, DB_MPOOL_FSTAT ***fsp, + db_malloc_fcn_type db_malloc_fcn) +{ + DB_ENV *env = unwrap(this); + int err = 0; + + if ((err = ::memp_stat(env, gsp, fsp, db_malloc_fcn)) != 0) { + DB_ERROR("DbEnv::memp_stat", err, error_policy()); + return (err); + } + return (err); +} + +int DbEnv::memp_sync(DbLsn *sn) +{ + DB_ENV *env = unwrap(this); + int err = 0; + + if ((err = ::memp_sync(env, sn)) != 0 && err != DB_INCOMPLETE) { + DB_ERROR("DbEnv::memp_sync", err, error_policy()); + return (err); + } + return (err); +} + +int DbEnv::memp_trickle(int pct, int *nwrotep) +{ + DB_ENV *env = unwrap(this); + int err = 0; + + if ((err = ::memp_trickle(env, pct, nwrotep)) != 0) { + DB_ERROR("DbEnv::memp_trickle", err, error_policy()); + return (err); + } + return (err); +} diff --git a/db/cxx/cxx_table.cpp b/db/cxx/cxx_table.cpp new file mode 100644 index 000000000..b7b335d26 --- /dev/null +++ b/db/cxx/cxx_table.cpp @@ -0,0 +1,808 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: cxx_table.cpp,v 11.35 2001/01/11 18:19:49 bostic Exp $"; +#endif /* not lint */ + +#include +#include + +#include "db_cxx.h" +#include "cxx_int.h" + +#include "db_int.h" +#include "db_page.h" +#include "db_ext.h" +#include "common_ext.h" + +//////////////////////////////////////////////////////////////////////// +// // +// Db // +// // +//////////////////////////////////////////////////////////////////////// + +// A truism for the DbEnv object is that there is a valid +// DB_ENV handle from the constructor until close(). +// After the close, the DB handle is invalid and +// no operations are permitted on the Db (other than +// destructor). Leaving the Db handle open and not +// doing a close is generally considered an error. +// +// We used to allow Db objects to be closed and reopened. +// This implied always keeping a valid DB object, and +// coordinating the open objects between Db/DbEnv turned +// out to be overly complicated. Now we do not allow this. + +Db::Db(DbEnv *env, u_int32_t flags) +: imp_(0) +, env_(env) +, construct_error_(0) +, flags_(0) +, construct_flags_(flags) +{ + if (env_ == 0) + flags_ |= DB_CXX_PRIVATE_ENV; + initialize(); +} + +// Note: if the user has not closed, we call _destroy_check +// to warn against this non-safe programming practice. +// We can't close, because the environment may already +// be closed/destroyed. +// +Db::~Db() +{ + DB *db; + + db = unwrap(this); + if (db != NULL) { + DbEnv::_destroy_check("Db", 0); + cleanup(); + } +} + +// private method to initialize during constructor. +// initialize must create a backing DB object, +// and if that creates a new DB_ENV, it must be tied to a new DbEnv. +// If there is an error, construct_error_ is set; this is examined +// during open. +// +int Db::initialize() +{ + u_int32_t cxx_flags; + DB *db; + int err; + DB_ENV *cenv = unwrap(env_); + + cxx_flags = construct_flags_ & DB_CXX_NO_EXCEPTIONS; + + // Create a new underlying DB object. + // We rely on the fact that if a NULL DB_ENV* is given, + // one is allocated by DB. + // + if ((err = db_create(&db, cenv, + construct_flags_ & ~cxx_flags)) != 0) { + construct_error_ = err; + return (err); + } + + // Associate the DB with this object + imp_ = wrap(db); + db->cj_internal = this; + + // Create a new DbEnv from a DB_ENV* if it was created locally. + // It is deleted in Db::close(). + // + if ((flags_ & DB_CXX_PRIVATE_ENV) != 0) + env_ = new DbEnv(db->dbenv, cxx_flags); + + return (0); +} + +// private method to cleanup after destructor or during close. +// If the environment was created by this Db object, we optionally +// delete it, or return it so the caller can delete it after +// last use. +// +void Db::cleanup() +{ + DB *db = unwrap(this); + + if (db != NULL) { + // extra safety + db->cj_internal = 0; + imp_ = 0; + + // we must dispose of the DbEnv object if + // we created it. This will be the case + // if a NULL DbEnv was passed into the constructor. + // The underlying DB_ENV object will be inaccessible + // after the close, so we must clean it up now. + // + if ((flags_ & DB_CXX_PRIVATE_ENV) != 0) { + env_->cleanup(); + delete env_; + env_ = 0; + } + } + construct_error_ = 0; +} + +// Return a tristate value corresponding to whether we should +// throw exceptions on errors: +// ON_ERROR_RETURN +// ON_ERROR_THROW +// ON_ERROR_UNKNOWN +// +int Db::error_policy() +{ + if (env_ != NULL) + return (env_->error_policy()); + else { + // If the env_ is null, that means that the user + // did not attach an environment, so the correct error + // policy can be deduced from constructor flags + // for this Db. + // + if ((construct_flags_ & DB_CXX_NO_EXCEPTIONS) != 0) { + return (ON_ERROR_RETURN); + } + else { + return (ON_ERROR_THROW); + } + } +} + +int Db::close(u_int32_t flags) +{ + DB *db = unwrap(this); + int err; + + // after a DB->close (no matter if success or failure), + // the underlying DB object must not be accessed, + // so we clean up in advance. + // + cleanup(); + + // It's safe to throw an error after the close, + // since our error mechanism does not peer into + // the DB* structures. + // + if ((err = db->close(db, flags)) != 0 && err != DB_INCOMPLETE) + DB_ERROR("Db::close", err, error_policy()); + + return (err); +} + +int Db::cursor(DbTxn *txnid, Dbc **cursorp, u_int32_t flags) +{ + DB *db = unwrap(this); + DBC *dbc = 0; + int err; + + if ((err = db->cursor(db, unwrap(txnid), &dbc, flags)) != 0) { + DB_ERROR("Db::cursor", err, error_policy()); + return (err); + } + + // The following cast implies that Dbc can be no larger than DBC + *cursorp = (Dbc*)dbc; + return (0); +} + +int Db::del(DbTxn *txnid, Dbt *key, u_int32_t flags) +{ + DB *db = unwrap(this); + int err; + + if ((err = db->del(db, unwrap(txnid), key, flags)) != 0) { + // DB_NOTFOUND is a "normal" return, so should not be + // thrown as an error + // + if (err != DB_NOTFOUND) { + DB_ERROR("Db::del", err, error_policy()); + return (err); + } + } + return (err); +} + +void Db::err(int error, const char *format, ...) +{ + va_list args; + DB *db = unwrap(this); + + va_start(args, format); + __db_real_err(db->dbenv, error, 1, 1, format, args); + va_end(args); +} + +void Db::errx(const char *format, ...) +{ + va_list args; + DB *db = unwrap(this); + + va_start(args, format); + __db_real_err(db->dbenv, 0, 0, 1, format, args); + va_end(args); +} + +int Db::fd(int *fdp) +{ + DB *db = unwrap(this); + int err; + + if ((err = db->fd(db, fdp)) != 0) { + DB_ERROR("Db::fd", err, error_policy()); + return (err); + } + return (0); +} + +// This is a 'glue' function declared as extern "C" so it will +// be compatible with picky compilers that do not allow mixing +// of function pointers to 'C' functions with function pointers +// to C++ functions. +// +extern "C" +void _db_feedback_intercept_c(DB *db, int opcode, int pct) +{ + Db::_feedback_intercept(db, opcode, pct); +} + +//static +void Db::_feedback_intercept(DB *db, int opcode, int pct) +{ + if (db == 0) { + DB_ERROR("Db::feedback_callback", EINVAL, ON_ERROR_UNKNOWN); + return; + } + Db *cxxdb = (Db *)db->cj_internal; + if (cxxdb == 0) { + DB_ERROR("Db::feedback_callback", EINVAL, ON_ERROR_UNKNOWN); + return; + } + if (cxxdb->feedback_callback_ == 0) { + DB_ERROR("Db::feedback_callback", EINVAL, cxxdb->error_policy()); + return; + } + (*cxxdb->feedback_callback_)(cxxdb, opcode, pct); +} + +int Db::set_feedback(void (*arg)(Db *, int, int)) +{ + DB *db = unwrap(this); + + feedback_callback_ = arg; + + return ((*(db->set_feedback))(db, _db_feedback_intercept_c)); +} + +// This is a 'glue' function declared as extern "C" so it will +// be compatible with picky compilers that do not allow mixing +// of function pointers to 'C' functions with function pointers +// to C++ functions. +// +extern "C" +int _db_append_recno_intercept_c(DB *db, DBT *data, db_recno_t recno) +{ + return (Db::_append_recno_intercept(db, data, recno)); +} + +//static +int Db::_append_recno_intercept(DB *db, DBT *data, db_recno_t recno) +{ + int err; + + if (db == 0) { + DB_ERROR("Db::append_recno_callback", EINVAL, ON_ERROR_UNKNOWN); + return (EINVAL); + } + Db *cxxdb = (Db *)db->cj_internal; + if (cxxdb == 0) { + DB_ERROR("Db::append_recno_callback", EINVAL, ON_ERROR_UNKNOWN); + return (EINVAL); + } + if (cxxdb->append_recno_callback_ == 0) { + DB_ERROR("Db::append_recno_callback", EINVAL, cxxdb->error_policy()); + return (EINVAL); + } + + // making these copies is slow but portable. + // Another alternative is to cast the DBT* manufactured + // by the C layer to a Dbt*. It 'should be' safe since + // Dbt is a thin shell over DBT, adding no extra data, + // but is nonportable, and could lead to errors if anything + // were added to the Dbt class. + // + Dbt cxxdbt; + memcpy((DBT *)&cxxdbt, data, sizeof(DBT)); + err = (*cxxdb->append_recno_callback_)(cxxdb, &cxxdbt, recno); + memcpy(data, (DBT *)&cxxdbt, sizeof(DBT)); + return (err); +} + +int Db::set_append_recno(int (*arg)(Db *, Dbt *, db_recno_t)) +{ + DB *db = unwrap(this); + + append_recno_callback_ = arg; + + return ((*(db->set_append_recno))(db, _db_append_recno_intercept_c)); +} + +int Db::get(DbTxn *txnid, Dbt *key, Dbt *value, u_int32_t flags) +{ + DB *db = unwrap(this); + int err; + + if ((err = db->get(db, unwrap(txnid), key, value, flags)) != 0) { + // DB_NOTFOUND and DB_KEYEMPTY are "normal" returns, + // so should not be thrown as an error + // + if (err != DB_NOTFOUND && err != DB_KEYEMPTY) { + DB_ERROR("Db::get", err, error_policy()); + return (err); + } + } + return (err); +} + +int Db::get_byteswapped() const +{ + DB *db = (DB *)unwrapConst(this); + return (db->get_byteswapped(db)); +} + +DBTYPE Db::get_type() const +{ + DB *db = (DB *)unwrapConst(this); + return ((DBTYPE)db->get_type(db)); +} + +int Db::join(Dbc **curslist, Dbc **cursorp, u_int32_t flags) +{ + // Dbc is a "compatible" subclass of DBC - + // that is, no virtual functions or even extra data members, + // so this cast, although technically non-portable, + // "should" always be okay. + // + DBC **list = (DBC **)(curslist); + DB *db = unwrap(this); + DBC *dbc = 0; + int err; + + if ((err = db->join(db, list, &dbc, flags)) != 0) { + DB_ERROR("Db::join_cursor", err, error_policy()); + return (err); + } + *cursorp = (Dbc*)dbc; + return (0); +} + +int Db::key_range(DbTxn *txnid, Dbt *key, + DB_KEY_RANGE *results, u_int32_t flags) +{ + DB *db = unwrap(this); + int err; + + if ((err = db->key_range(db, unwrap(txnid), key, + results, flags)) != 0) { + DB_ERROR("Db::key_range", err, error_policy()); + return (err); + } + return (0); +} + +// If an error occurred during the constructor, report it now. +// Otherwise, call the underlying DB->open method. +// +int Db::open(const char *file, const char *database, + DBTYPE type, u_int32_t flags, int mode) +{ + int err; + DB *db = unwrap(this); + + if ((err = construct_error_) != 0) + DB_ERROR("Db::open", construct_error_, error_policy()); + else if ((err = db->open(db, file, database, type, flags, mode)) != 0) + DB_ERROR("Db::open", err, error_policy()); + + return (err); +} + +int Db::put(DbTxn *txnid, Dbt *key, Dbt *value, u_int32_t flags) +{ + int err; + DB *db = unwrap(this); + + if ((err = db->put(db, unwrap(txnid), key, value, flags)) != 0) { + + // DB_KEYEXIST is a "normal" return, so should not be + // thrown as an error + // + if (err != DB_KEYEXIST) { + DB_ERROR("Db::put", err, error_policy()); + return (err); + } + } + return (err); +} + +int Db::rename(const char *file, const char *database, + const char *newname, u_int32_t flags) +{ + int err = 0; + DB *db = unwrap(this); + + if (!db) { + DB_ERROR("Db::rename", EINVAL, error_policy()); + return (EINVAL); + } + + // after a DB->rename (no matter if success or failure), + // the underlying DB object must not be accessed, + // so we clean up in advance. + // + cleanup(); + + if ((err = db->rename(db, file, database, newname, flags)) != 0) { + DB_ERROR("Db::rename", err, error_policy()); + return (err); + } + return (0); +} + +int Db::remove(const char *file, const char *database, u_int32_t flags) +{ + int err = 0; + DB *db = unwrap(this); + + if (!db) { + DB_ERROR("Db::remove", EINVAL, error_policy()); + return (EINVAL); + } + + // after a DB->remove (no matter if success or failure), + // the underlying DB object must not be accessed, + // so we clean up in advance. + // + cleanup(); + + if ((err = db->remove(db, file, database, flags)) != 0) + DB_ERROR("Db::remove", err, error_policy()); + + return (err); +} + +int Db::stat(void *sp, db_malloc_fcn_type db_malloc_fcn, u_int32_t flags) +{ + int err; + DB *db = unwrap(this); + + if (!db) { + DB_ERROR("Db::stat", EINVAL, error_policy()); + return (EINVAL); + } + if ((err = db->stat(db, sp, db_malloc_fcn, flags)) != 0) { + DB_ERROR("Db::stat", err, error_policy()); + return (err); + } + return (0); +} + +int Db::sync(u_int32_t flags) +{ + int err; + DB *db = unwrap(this); + + if (!db) { + DB_ERROR("Db::sync", EINVAL, error_policy()); + return (EINVAL); + } + if ((err = db->sync(db, flags)) != 0 && err != DB_INCOMPLETE) { + DB_ERROR("Db::sync", err, error_policy()); + return (err); + } + return (err); +} + +int Db::upgrade(const char *name, u_int32_t flags) +{ + int err; + DB *db = unwrap(this); + + if (!db) { + DB_ERROR("Db::upgrade", EINVAL, error_policy()); + return (EINVAL); + } + if ((err = db->upgrade(db, name, flags)) != 0) { + DB_ERROR("Db::upgrade", err, error_policy()); + return (err); + } + return (0); +} + +static int _verify_callback_cxx(void *handle, const void *str_arg) +{ + char *str; + ostream *out; + + str = (char *)str_arg; + out = (ostream *)handle; + + (*out) << str; + if (out->fail()) + return (EIO); + + return (0); +} + +// This is a 'glue' function declared as extern "C" so it will +// be compatible with picky compilers that do not allow mixing +// of function pointers to 'C' functions with function pointers +// to C++ functions. +// +extern "C" +int _verify_callback_c(void *handle, const void *str_arg) +{ + return (_verify_callback_cxx(handle, str_arg)); +} + +int Db::verify(const char *name, const char *subdb, + ostream *ostr, u_int32_t flags) +{ + int err; + DB *db = unwrap(this); + + if (!db) { + DB_ERROR("Db::verify", EINVAL, error_policy()); + return (EINVAL); + } + if ((err = __db_verify_internal(db, name, subdb, ostr, + _verify_callback_c, flags)) != 0) { + DB_ERROR("Db::verify", err, error_policy()); + return (err); + } + return (0); +} + +// This is a variant of the DB_WO_ACCESS macro to define a simple set_ +// method calling the underlying C method, but unlike a simple +// set method, it may return an error or raise an exception. +// Note this macro expects that input _argspec is an argument +// list element (e.g. "char *arg") defined in terms of "arg". +// +#define DB_DB_ACCESS(_name, _argspec) \ +\ +int Db::set_##_name(_argspec) \ +{ \ + int ret; \ + DB *db = unwrap(this); \ + \ + if ((ret = (*(db->set_##_name))(db, arg)) != 0) { \ + DB_ERROR("Db::set_" # _name, ret, error_policy()); \ + } \ + return (ret); \ +} + +#define DB_DB_ACCESS_NORET(_name, _argspec) \ + \ +void Db::set_##_name(_argspec) \ +{ \ + DB *db = unwrap(this); \ + \ + (*(db->set_##_name))(db, arg); \ + return; \ +} + +DB_DB_ACCESS(bt_compare, bt_compare_fcn_type arg) +DB_DB_ACCESS(bt_maxkey, u_int32_t arg) +DB_DB_ACCESS(bt_minkey, u_int32_t arg) +DB_DB_ACCESS(bt_prefix, bt_prefix_fcn_type arg) +DB_DB_ACCESS(dup_compare, dup_compare_fcn_type arg) +DB_DB_ACCESS_NORET(errfile, FILE *arg) +DB_DB_ACCESS_NORET(errpfx, const char *arg) +DB_DB_ACCESS(flags, u_int32_t arg) +DB_DB_ACCESS(h_ffactor, u_int32_t arg) +DB_DB_ACCESS(h_hash, h_hash_fcn_type arg) +DB_DB_ACCESS(h_nelem, u_int32_t arg) +DB_DB_ACCESS(lorder, int arg) +DB_DB_ACCESS(malloc, db_malloc_fcn_type arg) +DB_DB_ACCESS(pagesize, u_int32_t arg) +DB_DB_ACCESS(realloc, db_realloc_fcn_type arg) +DB_DB_ACCESS(re_delim, int arg) +DB_DB_ACCESS(re_len, u_int32_t arg) +DB_DB_ACCESS(re_pad, int arg) +DB_DB_ACCESS(re_source, char *arg) +DB_DB_ACCESS(q_extentsize, u_int32_t arg) + +// Here are the set methods that don't fit the above mold. +// + +void Db::set_errcall(void (*arg)(const char *, char *)) +{ + env_->set_errcall(arg); +} + +int Db::set_cachesize(u_int32_t gbytes, u_int32_t bytes, int ncache) +{ + int ret; + DB *db = unwrap(this); + + if ((ret = (*(db->set_cachesize))(db, gbytes, bytes, ncache)) != 0) { + DB_ERROR("Db::set_cachesize", ret, error_policy()); + } + return (ret); +} + +int Db::set_paniccall(void (*callback)(DbEnv *, int)) +{ + return (env_->set_paniccall(callback)); +} + +void Db::set_error_stream(ostream *error_stream) +{ + env_->set_error_stream(error_stream); +} + +//////////////////////////////////////////////////////////////////////// +// // +// Dbc // +// // +//////////////////////////////////////////////////////////////////////// + +// It's private, and should never be called, but VC4.0 needs it resolved +// +Dbc::~Dbc() +{ +} + +int Dbc::close() +{ + DBC *cursor = this; + int err; + + if ((err = cursor->c_close(cursor)) != 0) { + DB_ERROR("Db::close", err, ON_ERROR_UNKNOWN); + return (err); + } + return (0); +} + +int Dbc::count(db_recno_t *countp, u_int32_t flags_arg) +{ + DBC *cursor = this; + int err; + + if ((err = cursor->c_count(cursor, countp, flags_arg)) != 0) { + DB_ERROR("Db::count", err, ON_ERROR_UNKNOWN); + return (err); + } + return (0); +} + +int Dbc::del(u_int32_t flags_arg) +{ + DBC *cursor = this; + int err; + + if ((err = cursor->c_del(cursor, flags_arg)) != 0) { + + // DB_KEYEMPTY is a "normal" return, so should not be + // thrown as an error + // + if (err != DB_KEYEMPTY) { + DB_ERROR("Db::del", err, ON_ERROR_UNKNOWN); + return (err); + } + } + return (err); +} + +int Dbc::dup(Dbc** cursorp, u_int32_t flags_arg) +{ + DBC *cursor = this; + DBC *new_cursor = 0; + int err; + + if ((err = cursor->c_dup(cursor, &new_cursor, flags_arg)) != 0) { + DB_ERROR("Db::dup", err, ON_ERROR_UNKNOWN); + return (err); + } + + // The following cast implies that Dbc can be no larger than DBC + *cursorp = (Dbc*)new_cursor; + return (0); +} + +int Dbc::get(Dbt* key, Dbt *data, u_int32_t flags_arg) +{ + DBC *cursor = this; + int err; + + if ((err = cursor->c_get(cursor, key, data, flags_arg)) != 0) { + + // DB_NOTFOUND and DB_KEYEMPTY are "normal" returns, + // so should not be thrown as an error + // + if (err != DB_NOTFOUND && err != DB_KEYEMPTY) { + DB_ERROR("Db::get", err, ON_ERROR_UNKNOWN); + return (err); + } + } + return (err); +} + +int Dbc::put(Dbt* key, Dbt *data, u_int32_t flags_arg) +{ + DBC *cursor = this; + int err; + + if ((err = cursor->c_put(cursor, key, data, flags_arg)) != 0) { + + // DB_KEYEXIST is a "normal" return, so should not be + // thrown as an error + // + if (err != DB_KEYEXIST) { + DB_ERROR("Db::put", err, ON_ERROR_UNKNOWN); + return (err); + } + } + return (err); +} + +//////////////////////////////////////////////////////////////////////// +// // +// Dbt // +// // +//////////////////////////////////////////////////////////////////////// + +Dbt::Dbt() +{ + DBT *dbt = this; + memset(dbt, 0, sizeof(DBT)); +} + +Dbt::Dbt(void *data_arg, size_t size_arg) +{ + DBT *dbt = this; + memset(dbt, 0, sizeof(DBT)); + set_data(data_arg); + set_size(size_arg); +} + +Dbt::~Dbt() +{ +} + +Dbt::Dbt(const Dbt &that) +{ + const DBT *from = &that; + DBT *to = this; + memcpy(to, from, sizeof(DBT)); +} + +Dbt &Dbt::operator = (const Dbt &that) +{ + if (this != &that) { + const DBT *from = &that; + DBT *to = this; + memcpy(to, from, sizeof(DBT)); + } + return (*this); +} + +DB_RW_ACCESS(Dbt, void *, data, data) +DB_RW_ACCESS(Dbt, u_int32_t, size, size) +DB_RW_ACCESS(Dbt, u_int32_t, ulen, ulen) +DB_RW_ACCESS(Dbt, u_int32_t, dlen, dlen) +DB_RW_ACCESS(Dbt, u_int32_t, doff, doff) +DB_RW_ACCESS(Dbt, u_int32_t, flags, flags) diff --git a/db/cxx/cxx_txn.cpp b/db/cxx/cxx_txn.cpp new file mode 100644 index 000000000..0abae9826 --- /dev/null +++ b/db/cxx/cxx_txn.cpp @@ -0,0 +1,136 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: cxx_txn.cpp,v 11.13 2000/12/21 16:24:33 dda Exp $"; +#endif /* not lint */ + +#include + +#include "db_cxx.h" +#include "cxx_int.h" + +//////////////////////////////////////////////////////////////////////// +// // +// DbTxnMgr // +// // +//////////////////////////////////////////////////////////////////////// + +int DbEnv::txn_begin(DbTxn *pid, DbTxn **tid, u_int32_t flags) +{ + int err; + DB_ENV *env = unwrap(this); + DB_TXN *txn; + + if ((err = ::txn_begin(env, unwrap(pid), &txn, flags)) != 0) { + DB_ERROR("DbEnv::txn_begin", err, error_policy()); + return (err); + } + DbTxn *result = new DbTxn(); + result->imp_ = wrap(txn); + *tid = result; + return (err); +} + +int DbEnv::txn_checkpoint(u_int32_t kbyte, u_int32_t min, u_int32_t flags) +{ + int err; + DB_ENV *env = unwrap(this); + if ((err = ::txn_checkpoint(env, kbyte, min, flags)) != 0 && + err != DB_INCOMPLETE) { + DB_ERROR("DbEnv::txn_checkpoint", err, error_policy()); + return (err); + } + return (err); +} + +int DbEnv::txn_stat(DB_TXN_STAT **statp, db_malloc_fcn_type db_malloc_fcn) +{ + int err; + DB_ENV *env = unwrap(this); + if ((err = ::txn_stat(env, statp, db_malloc_fcn)) != 0) { + DB_ERROR("DbEnv::txn_stat", err, error_policy()); + return (err); + } + return (err); +} + +//////////////////////////////////////////////////////////////////////// +// // +// DbTxn // +// // +//////////////////////////////////////////////////////////////////////// + +DbTxn::DbTxn() +: imp_(0) +{ +} + +DbTxn::~DbTxn() +{ +} + +int DbTxn::abort() +{ + int err; + DB_TXN *txn; + + txn = unwrap(this); + err = txn_abort(txn); + + // It may seem weird to delete this, but is legal as long + // as we don't access any of its data before returning. + // + delete this; + + if (err != 0) + DB_ERROR("DbTxn::abort", err, ON_ERROR_UNKNOWN); + + return (err); +} + +int DbTxn::commit(u_int32_t flags) +{ + int err; + DB_TXN *txn; + + txn = unwrap(this); + err = txn_commit(txn, flags); + + // It may seem weird to delete this, but is legal as long + // as we don't access any of its data before returning. + // + delete this; + + if (err != 0) + DB_ERROR("DbTxn::commit", err, ON_ERROR_UNKNOWN); + + return (err); +} + +u_int32_t DbTxn::id() +{ + DB_TXN *txn; + + txn = unwrap(this); + return (txn_id(txn)); // no error +} + +int DbTxn::prepare() +{ + int err; + DB_TXN *txn; + + txn = unwrap(this); + if ((err = txn_prepare(txn)) != 0) { + DB_ERROR("DbTxn::prepare", err, ON_ERROR_UNKNOWN); + return (err); + } + return (0); +} diff --git a/db/cxx/namemap.txt b/db/cxx/namemap.txt new file mode 100644 index 000000000..752077185 --- /dev/null +++ b/db/cxx/namemap.txt @@ -0,0 +1,21 @@ +$Id: namemap.txt,v 10.4 2000/02/19 20:57:54 bostic Exp $ + +The bulk of DB provides for wrapper classes and appropriately named methods +that call into DB. For the most part, there is a straightforward mapping of +names. For the purposes of referencing documentation, this chart shows the +underlying C structure name for each C++ class. In some cases, using the +given C prefix with a C++ method name gives the underlying C function name. +For example, DbMpoolFile::close() is implemented by memp_fclose(). + +C++ C C prefix + +Db DB +DbEnv DB_ENV +Dbc DBC +DbException none +DbInfo DB_INFO +DbLock DB_LOCK lock_ +DbLsn DB_LSN +DbMpoolFile DB_MPOOL_FILE memp_ +Dbt DBT +DbTxn DB_TXN txn_ diff --git a/db/db/Design.fileop b/db/db/Design.fileop new file mode 100644 index 000000000..187f1ffaf --- /dev/null +++ b/db/db/Design.fileop @@ -0,0 +1,452 @@ +# $Id: Design.fileop,v 11.4 2000/02/19 20:57:54 bostic Exp $ + +The design of file operation recovery. + +Keith has asked me to write up notes on our current status of database +create and delete and recovery, why it's so hard, and how we've violated +all the cornerstone assumptions on which our recovery framework is based. + +I am including two documents at the end of this one. The first is the +initial design of the recoverability of file create and delete (there is +no talk of subdatabases there, because we didn't think we'd have to do +anything special there). I will annotate this document on where things +changed. + +The second is the design of recd007 which is supposed to test our ability +to recover these operations regardless of where one crashes. This test +is fundamentally different from our other recovery tests in the following +manner. Normally, the application controls transaction boundaries. +Therefore, we can perform an operation and then decide whether to commit +or abort it. In the normal recovery tests, we force the database into +each of the four possible states from a recovery perspective: + + database is pre-op, undo (do nothing) + database is pre-op, redo + database is post-op, undo + database is post-op, redo (do nothing) + +By copying databases at various points and initiating txn_commit and abort +appropriately, we can make all these things happen. Notice that the one +case we don't handle is where page A is in one state (e.g., pre-op) and +page B is in another state (e.g., post-op). I will argue that these don't +matter because each page is recovered independently. If anyone can poke +holes in this, I'm interested. + +The problem with create/delete recovery testing is that the transaction +is begun and ended all inside the library. Therefore, there is never any +point (outside the library) where we can copy files and or initiate +abort/commit. In order to still put the recovery code through its paces, +Sue designed an infrastructure that lets you tell the library where to +make copies of things and where to suddenly inject errors so that the +transaction gets aborted. This level of detail allows us to push the +create/delete recovery code through just about every recovery path +possible (although I'm sure Mike will tell me I'm wrong when he starts to +run code coverage tools). + +OK, so that's all preamble and a brief discussion of the documents I'm +enclosing. + +Why was this so hard and painful and why is the code so Q@#$!% complicated? +The following is a discussion/explanation, but to the best of my knowledge, +the structure we have in place now works. The key question we need to be +asking is, "Does this need to have to be so complex or should we redesign +portions to simplify it?" At this point, there is no obvious way to simplify +it in my book, but I may be having difficulty seeing this because my mind is +too polluted at this point. + +Our overall strategy for recovery is that we do write-ahead logging, +that is we log an operation and make sure it is on disk before any +data corresponding to the data that log record describes is on disk. +Typically we use log sequence numbers (LSNs) to mark the data so that +during recovery, we can look at the data and determine if it is in a +state before a particular log record or after a particular log record. + +In the good old days, opens were not transaction protected, so we could +do regular old opens during recovery and if the file existed, we opened +it and if it didn't (or appeared corrupt), we didn't and treated it like +a missing file. As will be discussed below in detail, our states are much +more complicated and recovery can't make such simplistic assumptions. + +Also, since we are now dealing with file system operations, we have less +control about when they actually happen and what the state of the system +can be. That is, we have to write create log records synchronously, because +the create/open system call may force a newly created (0-length) file to +disk. This file has to now be identified as being in the "being-created" +state. + +A. We used to make a number of assumptions during recovery: + +1. We could call db_open at any time and one of three things would happen: + a) the file would be opened cleanly + b) the file would not exist + c) we would encounter an error while opening the file + +Case a posed no difficulty. +In Case b, we simply spit out a warning that a file was missing and then + ignored all subsequent operations to that file. +In Case c, we reported a fatal error. + +2. We can always generate a warning if a file is missing. + +3. We never encounter NULL file names in the log. + +B. We also made some assumptions in the main-line library: + +1. If you try to open a file and it exists but is 0-length, then +someone else is trying to open it. + +2. You can write pages anywhere in a file and any non-existent pages +are 0-filled. [This breaks on Windows.] + +3. If you have proper permissions then you can always evict pages from +the buffer pool. + +4. During open, we can close the master database handle as soon as +we're done with it since all the rest of the activity will take place +on the subdatabase handle. + +In our brave new world, most of these assumptions are no longer valid. +Let's address them one at a time. + +A.1 We could call db_open at any time and one of three things would happen: + a) the file would be opened cleanly + b) the file would not exist + c) we would encounter an error while opening the file +There are now additional states. Since we are trying to make file +operations recoverable, you can now die in the middle of such an +operation and we have to be able to pick up the pieces. What this +now means is that: + + * a 0-length file can be an indication of a create in-progress + * you can have a meta-data page but no root page (of a btree) + * if a file doesn't exist, it could mean that it was just about + to be created and needs to be rolled forward. + * if you encounter an error in a file (e.g., the meta-data page + is all 0's) you could still be in mid-open. + +I have now made this all work, but it required significant changes to the +db_open code and error handling and this is the sort of change that makes +everyone nervous. + +A.2. We can always generate a warning if a file is missing. + +Now that we have a delete file method in the API, we need to make sure +that we do not generate warning messages for files that don't exist if +we see that they were explicitly deleted. + +This means that we need to save state during recovery, determine which +files were missing and were not being recreated and were not deleted and +only complain about those. + +A.3. We never encounter NULL file names in the log. + +Now that we allow tranaction protection on memory-resident files, we write +log messages for files with NULL file names. This means that our assumption +of always being able to call "db_open" on any log_register OPEN message found +in the log is no longer valid. + +B.1. If you try to open a file and it exists but is 0-length, then +someone else is trying to open it. + +As discussed for A.1, this is no longer true. It may be instead that you +are in the process of recovering a create. + +B.2. You can write pages anywhere in a file and any non-existent pages +are 0-filled. + +It turns out that this is not true on Windows. This means that places +we do group allocation (hash) must explicitly allocate each page, because +we can't count on recognizing the uninitialized pages later. + +B.3. If you have proper permissions then you can always evict pages from +the buffer pool. + +In the brave new world though, files can be deleted and they may +have pages in the mpool. If you later try to evict these, you +discover that the file doesn't exist. We'd get here when we had +to dirty pages during a remove operation. + +B.4. You can close files any time you want. + +However, if the file takes part in the open/remove transaction, +then we had better not close it until after the transaction +commits/aborts, because we need to be able to get our hands on the +dbp and the open happened in a different transaction. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +Design for recovering file create and delete in the presence of subdatabases. + +Assumptions: + Remove the O_TRUNCATE flag. + Single-thread all open/create/delete operations. + (Well, almost all; we'll optimize opens without DB_CREATE set.) + The reasoning for this is that with two simultaneous + open/creaters, during recovery, we cannot identify which + transaction successfully created files and therefore cannot + recovery correctly. + File system creates/deletes are synchronous + Once the file is open, subdatabase creates look like regular + get/put operations and a metadata page creation. + +There are 4 cases to deal with: + 1. Open/create file + 2. Open/create subdatabase + 3. Delete + 4. Recovery records + + __db_fileopen_recover + __db_metapage_recover + __db_delete_recover + existing c_put and c_get routines for subdatabase creation + + Note that the open/create of the file and the open/create of the + subdatabase need to be in the same transaction. + +1. Open/create (full file and subdb version) + +If create + LOCK_FILEOP + txn_begin + log create message (open message below) + do file system open/create + if we did not create + abort transaction (before going to open_only) + if (!subdb) + set dbp->open_txn = NULL + else + txn_begin a new transaction for the subdb open + + construct meta-data page + log meta-data page (see metapage) + write the meta-data page + * It may be the case that btrees need to log both meta-data pages + and root pages. If that is the case, I believe that we can use + this same record and recovery routines for both + + txn_commit + UNLOCK_FILEOP + +2. Delete + LOCK_FILEOP + txn_begin + log delete message (delete message below) + mv file __db.file.lsn + txn_commit + unlink __db.file.lsn + UNLOCK_FILEOP + +3. Recovery Routines + +__db_fileopen_recover + if (argp->name.size == 0 + done; + + if (redo) /* Commit */ + __os_open(argp->name, DB_OSO_CREATE, argp->mode, &fh) + __os_closehandle(fh) + if (undo) /* Abort */ + if (argp->name exists) + unlink(argp->name); + +__db_metapage_recover + if (redo) + __os_open(argp->name, 0, 0, &fh) + __os_lseek(meta data page) + __os_write(meta data page) + __os_closehandle(fh); + if (undo) + done = 0; + if (argp->name exists) + if (length of argp->name != 0) + __os_open(argp->name, 0, 0, &fh) + __os_lseek(meta data page) + __os_read(meta data page) + if (read succeeds && page lsn != current_lsn) + done = 1 + __os_closehandle(fh); + if (!done) + unlink(argp->name) + +__db_delete_recover + if (redo) + Check if the backup file still exists and if so, delete it. + + if (undo) + if (__db_appname(__db.file.lsn exists)) + mv __db_appname(__db.file.lsn) __db_appname(file) + +__db_metasub_recover + /* This is like a normal recovery routine */ + Get the metadata page + if (cmp_n && redo) + copy the log page onto the page + update the lsn + make sure page gets put dirty + else if (cmp_p && undo) + update the lsn to the lsn in the log record + make sure page gets put dirty + + if the page was modified, put it back dirty + +In db.src + +# name: filename (before call to __db_appname) +# mode: file system mode +BEGIN open +DBT name DBT s +ARG mode u_int32_t o +END + +# opcode: indicate if it is a create/delete and if it is a subdatabase +# pgsize: page size on which we're going to write the meta-data page +# pgno: page number on which to write this meta-data page +# page: the actual meta-data page +# lsn: LSN of the meta-data page -- 0 for new databases, may be non-0 +# for subdatabases. + +BEGIN metapage +ARG opcode u_int32_t x +DBT name DBT s +ARG pgno db_pgno_t d +DBT page DBT s +POINTER lsn DB_LSN * lu +END + +# We do not need a subdatabase name here because removing a subdatabase +# name is simply a regular bt_delete operation from the master database. +# It will get logged normally. +# name: filename +BEGIN delete +DBT name DBT s +END + +# We also need to reclaim pages, but we can use the existing +# bt_pg_alloc routines. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +Testing recoverability of create/delete. + +These tests are unlike other tests in that they are going to +require hooks in the library. The reason is that the create +and delete calls are internally wrapped in a transaction, so +that if the call returns, the transaction has already either +commited or aborted. Using only that interface limits what +kind of testing we can do. To match our other recovery testing +efforts, we need to add hooks to trigger aborts at particular +times in the create/delete path. + +The general recovery testing strategy is that we wish to +execute every path through every recovery routine. That +means that we try to: + catch each operation in its pre-operation state + call the recovery function with redo + call the recovery function with undo + catch each operation in its post-operation state + call the recovery function with redo + call the recovery function with undo + +In addition, there are a few critical points in the create and +delete path that we want to make sure we capture. + +1. Test Structure + +The test structure should be similar to the existing recovery +tests. We will want to have a structure in place where we +can execute different commands: + create a file/database + create a file that will contain subdatabases. + create a subdatabase + remove a subdatabase (that contains valid data) + remove a subdatabase (that does not contain any data) + remove a file that used to contain subdatabases + remove a file that contains a database + +The tricky part is capturing the state of the world at the +various points in the create/delete process. + +The critical points in the create process are: + + 1. After we've logged the create, but before we've done anything. + in db/db.c + after the open_retry + after the __crdel_fileopen_log call (and before we've + called __os_open). + + 2. Immediately after the __os_open + + 3. Immediately after each __db_log_page call + in bt_open.c + log meta-data page + log root page + in hash.c + log meta-data page + + 4. With respect to the log records above, shortly after each + log write is an memp_fput. We need to do a sync after + each memp_fput and trigger a point after that sync. + +The critical points in the remove process are: + + 1. Right after the crdel_delete_log in db/db.c + + 2. Right after the __os_rename call (below the crdel_delete_log) + + 3. After the __db_remove_callback call. + +I believe that there are the places where we'll need some sort of hook. + +2. Adding hooks to the library. + +The hooks need two components. One component is to capture the state of +the database at the hook point and the other is to trigger a txn_abort at +the hook point. The second part is fairly trivial. + +The first part requires more thought. Let me explain what we do in a +"normal" recovery test. In a normal recovery test, we save an intial +copy of the database (this copy is called init). Then we execute one +or more operations. Then, right before the commit/abort, we sync the +file, and save another copy (the afterop copy). Finally, we call txn_commit +or txn_abort, sync the file again, and save the database one last time (the +final copy). + +Then we run recovery. The first time, this should be a no-op, because +we've either committed the transaction and are checking to redo it or +we aborted the transaction, undid it on the abort and are checking to +undo it again. + +We then run recovery again on whatever database will force us through +the path that requires work. In the commit case, this means we start +with the init copy of the database and run recovery. This pushes us +through all the redo paths. In the abort case, we start with the afterop +copy which pushes us through all the undo cases. + +In some sense, we're asking the create/delete test to be more exhaustive +by defining all the trigger points, but I think that's the correct thing +to do, since the create/delete is not initiated by a user transaction. + +So, what do we have to do at the hook points? + 1. sync the file to disk. + 2. save the file itself + 3. save any files named __db_backup_name(name, &backup_name, lsn) + Since we may not know the right lsns, I think we should save + every file of the form __db.name.0xNNNNNNNN.0xNNNNNNNN into + some temporary files from which we can restore it to run + recovery. + +3. Putting it all together + +So, the three pieces are writing the test structure, putting in the hooks +and then writing the recovery portions so that we restore the right thing +that the hooks saved in order to initiate recovery. + +Some of the technical issues that need to be solved are: + How does the hook code become active (i.e., we don't + want it in there normally, but it's got to be + there when you configure for testing)? + How do you (the test) tell the library that you want a + particular hook to abort? + How do you (the test) tell the library that you want the + hook code doing its copies (do we really want + *every* test doing these copies during testing? + Maybe it's not a big deal, but maybe it is; we + should at least think about it). diff --git a/db/db/crdel.src b/db/db/crdel.src new file mode 100644 index 000000000..17c061d68 --- /dev/null +++ b/db/db/crdel.src @@ -0,0 +1,103 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: crdel.src,v 11.12 2000/12/12 17:41:48 bostic Exp $ + */ + +PREFIX crdel + +INCLUDE #include "db_config.h" +INCLUDE +INCLUDE #ifndef NO_SYSTEM_INCLUDES +INCLUDE #include +INCLUDE +INCLUDE #include +INCLUDE #include +INCLUDE #include +INCLUDE #endif +INCLUDE +INCLUDE #include "db_int.h" +INCLUDE #include "db_page.h" +INCLUDE #include "db_dispatch.h" +INCLUDE #include "db_am.h" +INCLUDE #include "txn.h" +INCLUDE + +/* + * Fileopen -- log a potential file create operation + * + * name: filename + * subname: sub database name + * mode: file system mode + */ +BEGIN fileopen 141 +DBT name DBT s +ARG mode u_int32_t o +END + +/* + * Metasub: log the creation of a subdatabase meta data page. + * + * fileid: identifies the file being acted upon. + * pgno: page number on which to write this meta-data page + * page: the actual meta-data page + * lsn: lsn of the page. + */ +BEGIN metasub 142 +ARG fileid int32_t ld +ARG pgno db_pgno_t d +DBT page DBT s +POINTER lsn DB_LSN * lu +END + +/* + * Metapage: log the creation of a meta data page for a new file. + * + * fileid: identifies the file being acted upon. + * name: file containing the page. + * pgno: page number on which to write this meta-data page + * page: the actual meta-data page + */ +BEGIN metapage 143 +ARG fileid int32_t ld +DBT name DBT s +ARG pgno db_pgno_t d +DBT page DBT s +END + +/* + * Delete: remove a file. + * Note that we don't need a special log record for subdatabase + * removes, because we use normal btree operations to remove them. + * + * name: name of the file being removed (relative to DBHOME). + */ +DEPRECATED old_delete 144 +DBT name DBT s +END + +/* + * Rename: rename a file + * We do not need this for subdatabases + * + * name: name of the file being removed (relative to DBHOME). + */ +BEGIN rename 145 +ARG fileid int32_t ld +DBT name DBT s +DBT newname DBT s +END +/* + * Delete: remove a file. + * Note that we don't need a special log record for subdatabase + * removes, because we use normal btree operations to remove them. + * + * name: name of the file being removed (relative to DBHOME). + */ +BEGIN delete 146 +ARG fileid int32_t ld +DBT name DBT s +END diff --git a/db/db/crdel_auto.c b/db/db/crdel_auto.c new file mode 100644 index 000000000..f2204410e --- /dev/null +++ b/db/db/crdel_auto.c @@ -0,0 +1,900 @@ +/* Do not edit: automatically built by gen_rec.awk. */ +#include "db_config.h" + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_dispatch.h" +#include "db_am.h" +#include "txn.h" + +int +__crdel_fileopen_log(dbenv, txnid, ret_lsnp, flags, + name, mode) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + const DBT *name; + u_int32_t mode; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t zero; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_crdel_fileopen; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(u_int32_t) + (name == NULL ? 0 : name->size) + + sizeof(mode); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + if (name == NULL) { + zero = 0; + memcpy(bp, &zero, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + } else { + memcpy(bp, &name->size, sizeof(name->size)); + bp += sizeof(name->size); + memcpy(bp, name->data, name->size); + bp += name->size; + } + memcpy(bp, &mode, sizeof(mode)); + bp += sizeof(mode); + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__crdel_fileopen_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __crdel_fileopen_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __crdel_fileopen_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]crdel_fileopen: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tname: "); + for (i = 0; i < argp->name.size; i++) { + ch = ((u_int8_t *)argp->name.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\tmode: %o\n", argp->mode); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__crdel_fileopen_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __crdel_fileopen_args **argpp; +{ + __crdel_fileopen_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__crdel_fileopen_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memset(&argp->name, 0, sizeof(argp->name)); + memcpy(&argp->name.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->name.data = bp; + bp += argp->name.size; + memcpy(&argp->mode, bp, sizeof(argp->mode)); + bp += sizeof(argp->mode); + *argpp = argp; + return (0); +} + +int +__crdel_metasub_log(dbenv, txnid, ret_lsnp, flags, + fileid, pgno, page, lsn) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + int32_t fileid; + db_pgno_t pgno; + const DBT *page; + DB_LSN * lsn; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t zero; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_crdel_metasub; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(fileid) + + sizeof(pgno) + + sizeof(u_int32_t) + (page == NULL ? 0 : page->size) + + sizeof(*lsn); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &fileid, sizeof(fileid)); + bp += sizeof(fileid); + memcpy(bp, &pgno, sizeof(pgno)); + bp += sizeof(pgno); + if (page == NULL) { + zero = 0; + memcpy(bp, &zero, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + } else { + memcpy(bp, &page->size, sizeof(page->size)); + bp += sizeof(page->size); + memcpy(bp, page->data, page->size); + bp += page->size; + } + if (lsn != NULL) + memcpy(bp, lsn, sizeof(*lsn)); + else + memset(bp, 0, sizeof(*lsn)); + bp += sizeof(*lsn); + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__crdel_metasub_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __crdel_metasub_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __crdel_metasub_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]crdel_metasub: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tpgno: %d\n", argp->pgno); + printf("\tpage: "); + for (i = 0; i < argp->page.size; i++) { + ch = ((u_int8_t *)argp->page.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\tlsn: [%lu][%lu]\n", + (u_long)argp->lsn.file, (u_long)argp->lsn.offset); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__crdel_metasub_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __crdel_metasub_args **argpp; +{ + __crdel_metasub_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__crdel_metasub_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->pgno, bp, sizeof(argp->pgno)); + bp += sizeof(argp->pgno); + memset(&argp->page, 0, sizeof(argp->page)); + memcpy(&argp->page.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->page.data = bp; + bp += argp->page.size; + memcpy(&argp->lsn, bp, sizeof(argp->lsn)); + bp += sizeof(argp->lsn); + *argpp = argp; + return (0); +} + +int +__crdel_metapage_log(dbenv, txnid, ret_lsnp, flags, + fileid, name, pgno, page) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + int32_t fileid; + const DBT *name; + db_pgno_t pgno; + const DBT *page; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t zero; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_crdel_metapage; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(fileid) + + sizeof(u_int32_t) + (name == NULL ? 0 : name->size) + + sizeof(pgno) + + sizeof(u_int32_t) + (page == NULL ? 0 : page->size); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &fileid, sizeof(fileid)); + bp += sizeof(fileid); + if (name == NULL) { + zero = 0; + memcpy(bp, &zero, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + } else { + memcpy(bp, &name->size, sizeof(name->size)); + bp += sizeof(name->size); + memcpy(bp, name->data, name->size); + bp += name->size; + } + memcpy(bp, &pgno, sizeof(pgno)); + bp += sizeof(pgno); + if (page == NULL) { + zero = 0; + memcpy(bp, &zero, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + } else { + memcpy(bp, &page->size, sizeof(page->size)); + bp += sizeof(page->size); + memcpy(bp, page->data, page->size); + bp += page->size; + } + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__crdel_metapage_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __crdel_metapage_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __crdel_metapage_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]crdel_metapage: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tname: "); + for (i = 0; i < argp->name.size; i++) { + ch = ((u_int8_t *)argp->name.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\tpgno: %d\n", argp->pgno); + printf("\tpage: "); + for (i = 0; i < argp->page.size; i++) { + ch = ((u_int8_t *)argp->page.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__crdel_metapage_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __crdel_metapage_args **argpp; +{ + __crdel_metapage_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__crdel_metapage_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memset(&argp->name, 0, sizeof(argp->name)); + memcpy(&argp->name.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->name.data = bp; + bp += argp->name.size; + memcpy(&argp->pgno, bp, sizeof(argp->pgno)); + bp += sizeof(argp->pgno); + memset(&argp->page, 0, sizeof(argp->page)); + memcpy(&argp->page.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->page.data = bp; + bp += argp->page.size; + *argpp = argp; + return (0); +} + +int +__crdel_old_delete_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __crdel_old_delete_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __crdel_old_delete_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]crdel_old_delete: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tname: "); + for (i = 0; i < argp->name.size; i++) { + ch = ((u_int8_t *)argp->name.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__crdel_old_delete_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __crdel_old_delete_args **argpp; +{ + __crdel_old_delete_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__crdel_old_delete_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memset(&argp->name, 0, sizeof(argp->name)); + memcpy(&argp->name.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->name.data = bp; + bp += argp->name.size; + *argpp = argp; + return (0); +} + +int +__crdel_rename_log(dbenv, txnid, ret_lsnp, flags, + fileid, name, newname) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + int32_t fileid; + const DBT *name; + const DBT *newname; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t zero; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_crdel_rename; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(fileid) + + sizeof(u_int32_t) + (name == NULL ? 0 : name->size) + + sizeof(u_int32_t) + (newname == NULL ? 0 : newname->size); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &fileid, sizeof(fileid)); + bp += sizeof(fileid); + if (name == NULL) { + zero = 0; + memcpy(bp, &zero, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + } else { + memcpy(bp, &name->size, sizeof(name->size)); + bp += sizeof(name->size); + memcpy(bp, name->data, name->size); + bp += name->size; + } + if (newname == NULL) { + zero = 0; + memcpy(bp, &zero, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + } else { + memcpy(bp, &newname->size, sizeof(newname->size)); + bp += sizeof(newname->size); + memcpy(bp, newname->data, newname->size); + bp += newname->size; + } + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__crdel_rename_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __crdel_rename_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __crdel_rename_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]crdel_rename: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tname: "); + for (i = 0; i < argp->name.size; i++) { + ch = ((u_int8_t *)argp->name.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\tnewname: "); + for (i = 0; i < argp->newname.size; i++) { + ch = ((u_int8_t *)argp->newname.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__crdel_rename_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __crdel_rename_args **argpp; +{ + __crdel_rename_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__crdel_rename_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memset(&argp->name, 0, sizeof(argp->name)); + memcpy(&argp->name.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->name.data = bp; + bp += argp->name.size; + memset(&argp->newname, 0, sizeof(argp->newname)); + memcpy(&argp->newname.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->newname.data = bp; + bp += argp->newname.size; + *argpp = argp; + return (0); +} + +int +__crdel_delete_log(dbenv, txnid, ret_lsnp, flags, + fileid, name) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + int32_t fileid; + const DBT *name; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t zero; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_crdel_delete; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(fileid) + + sizeof(u_int32_t) + (name == NULL ? 0 : name->size); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &fileid, sizeof(fileid)); + bp += sizeof(fileid); + if (name == NULL) { + zero = 0; + memcpy(bp, &zero, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + } else { + memcpy(bp, &name->size, sizeof(name->size)); + bp += sizeof(name->size); + memcpy(bp, name->data, name->size); + bp += name->size; + } + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__crdel_delete_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __crdel_delete_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __crdel_delete_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]crdel_delete: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tname: "); + for (i = 0; i < argp->name.size; i++) { + ch = ((u_int8_t *)argp->name.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__crdel_delete_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __crdel_delete_args **argpp; +{ + __crdel_delete_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__crdel_delete_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memset(&argp->name, 0, sizeof(argp->name)); + memcpy(&argp->name.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->name.data = bp; + bp += argp->name.size; + *argpp = argp; + return (0); +} + +int +__crdel_init_print(dbenv) + DB_ENV *dbenv; +{ + int ret; + + if ((ret = __db_add_recovery(dbenv, + __crdel_fileopen_print, DB_crdel_fileopen)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __crdel_metasub_print, DB_crdel_metasub)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __crdel_metapage_print, DB_crdel_metapage)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __crdel_old_delete_print, DB_crdel_old_delete)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __crdel_rename_print, DB_crdel_rename)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __crdel_delete_print, DB_crdel_delete)) != 0) + return (ret); + return (0); +} + +int +__crdel_init_recover(dbenv) + DB_ENV *dbenv; +{ + int ret; + + if ((ret = __db_add_recovery(dbenv, + __crdel_fileopen_recover, DB_crdel_fileopen)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __crdel_metasub_recover, DB_crdel_metasub)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __crdel_metapage_recover, DB_crdel_metapage)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __deprecated_recover, DB_crdel_old_delete)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __crdel_rename_recover, DB_crdel_rename)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __crdel_delete_recover, DB_crdel_delete)) != 0) + return (ret); + return (0); +} + diff --git a/db/db/crdel_rec.c b/db/db/crdel_rec.c new file mode 100644 index 000000000..495b92a0a --- /dev/null +++ b/db/db/crdel_rec.c @@ -0,0 +1,646 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: crdel_rec.c,v 11.43 2000/12/13 08:06:34 krinsky Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "log.h" +#include "hash.h" +#include "mp.h" +#include "db_dispatch.h" + +/* + * __crdel_fileopen_recover -- + * Recovery function for fileopen. + * + * PUBLIC: int __crdel_fileopen_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__crdel_fileopen_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __crdel_fileopen_args *argp; + DBMETA ondisk; + DB_FH fh; + size_t nr; + int do_unlink, ret; + u_int32_t b, mb, io; + char *real_name; + + COMPQUIET(info, NULL); + + real_name = NULL; + REC_PRINT(__crdel_fileopen_print); + + if ((ret = __crdel_fileopen_read(dbenv, dbtp->data, &argp)) != 0) + goto out; + /* + * If this is an in-memory database, then the name is going to + * be NULL, which looks like a 0-length name in recovery. + */ + if (argp->name.size == 0) + goto done; + + if ((ret = __db_appname(dbenv, DB_APP_DATA, + NULL, argp->name.data, 0, NULL, &real_name)) != 0) + goto out; + if (DB_REDO(op)) { + /* + * The create commited, so we need to make sure that the file + * exists. A simple open should suffice. + */ + if ((ret = __os_open(dbenv, real_name, + DB_OSO_CREATE, argp->mode, &fh)) != 0) + goto out; + if ((ret = __os_closehandle(&fh)) != 0) + goto out; + } else if (DB_UNDO(op)) { + /* + * If the file is 0-length then it was in the process of being + * created, so we should unlink it. If it is non-0 length, then + * either someone else created it and we need to leave it + * untouched or we were in the process of creating it, allocated + * the first page on a system that requires you to actually + * write pages as you allocate them, but never got any data + * on it. + * If the file doesn't exist, we never got around to creating + * it, so that's fine. + */ + if (__os_exists(real_name, NULL) != 0) + goto done; + + if ((ret = __os_open(dbenv, real_name, 0, 0, &fh)) != 0) + goto out; + if ((ret = __os_ioinfo(dbenv, + real_name, &fh, &mb, &b, &io)) != 0) + goto out; + do_unlink = 0; + if (mb != 0 || b != 0) { + /* + * We need to read the first page + * to see if its got valid data on it. + */ + if ((ret = __os_read(dbenv, &fh, + &ondisk, sizeof(ondisk), &nr)) != 0 || + nr != sizeof(ondisk)) + goto out; + if (ondisk.magic == 0) + do_unlink = 1; + } + if ((ret = __os_closehandle(&fh)) != 0) + goto out; + /* Check for 0-length and if it is, delete it. */ + if (do_unlink || (mb == 0 && b == 0)) + if ((ret = __os_unlink(dbenv, real_name)) != 0) + goto out; + } + +done: *lsnp = argp->prev_lsn; + ret = 0; + +out: if (argp != NULL) + __os_free(argp, 0); + if (real_name != NULL) + __os_freestr(real_name); + return (ret); +} + +/* + * __crdel_metasub_recover -- + * Recovery function for metasub. + * + * PUBLIC: int __crdel_metasub_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__crdel_metasub_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __crdel_metasub_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + u_int8_t *file_uid, ptype; + int cmp_p, modified, reopen, ret; + + COMPQUIET(info, NULL); + REC_PRINT(__crdel_metasub_print); + REC_INTRO(__crdel_metasub_read, 0); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) { + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + } + + modified = 0; + reopen = 0; + cmp_p = log_compare(&LSN(pagep), &argp->lsn); + CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->lsn); + + if (cmp_p == 0 && DB_REDO(op)) { + memcpy(pagep, argp->page.data, argp->page.size); + LSN(pagep) = *lsnp; + modified = 1; + /* + * If this is a meta-data page, then we must reopen; + * if it was a root page, then we do not. + */ + ptype = ((DBMETA *)argp->page.data)->type; + if (ptype == P_HASHMETA || ptype == P_BTREEMETA || + ptype == P_QAMMETA) + reopen = 1; + } else if (DB_UNDO(op)) { + /* + * We want to undo this page creation. The page creation + * happened in two parts. First, we called __bam_new which + * was logged separately. Then we wrote the meta-data onto + * the page. So long as we restore the LSN, then the recovery + * for __bam_new will do everything else. + * Don't bother checking the lsn on the page. If we + * are rolling back the next thing is that this page + * will get freed. Opening the subdb will have reinitialized + * the page, but not the lsn. + */ + LSN(pagep) = argp->lsn; + modified = 1; + } + if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) + goto out; + + /* + * If we are redoing a subdatabase create, we must close and reopen the + * file to be sure that we have the proper meta information in the + * in-memory structures + */ + if (reopen) { + /* Close cursor if it's open. */ + if (dbc != NULL) { + dbc->c_close(dbc); + dbc = NULL; + } + + if ((ret = __os_malloc(dbenv, + DB_FILE_ID_LEN, NULL, &file_uid)) != 0) + goto out; + memcpy(file_uid, &file_dbp->fileid[0], DB_FILE_ID_LEN); + ret = __log_reopen_file(dbenv, + NULL, argp->fileid, file_uid, argp->pgno); + (void)__os_free(file_uid, DB_FILE_ID_LEN); + if (ret != 0) + goto out; + } + +done: *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __crdel_metapage_recover -- + * Recovery function for metapage. + * + * PUBLIC: int __crdel_metapage_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__crdel_metapage_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __crdel_metapage_args *argp; + DB *dbp; + DBMETA *meta, ondisk; + DB_FH fh; + size_t nr; + u_int32_t b, io, mb, pagesize; + int is_done, ret; + char *real_name; + + COMPQUIET(info, NULL); + + real_name = NULL; + memset(&fh, 0, sizeof(fh)); + REC_PRINT(__crdel_metapage_print); + + if ((ret = __crdel_metapage_read(dbenv, dbtp->data, &argp)) != 0) + goto out; + + /* + * If this is an in-memory database, then the name is going to + * be NULL, which looks like a 0-length name in recovery. + */ + if (argp->name.size == 0) + goto done; + + meta = (DBMETA *)argp->page.data; + __ua_memcpy(&pagesize, &meta->pagesize, sizeof(pagesize)); + + if ((ret = __db_appname(dbenv, DB_APP_DATA, + NULL, argp->name.data, 0, NULL, &real_name)) != 0) + goto out; + if (DB_REDO(op)) { + if ((ret = __db_fileid_to_db(dbenv, + &dbp, argp->fileid, 0)) != 0) { + if (ret == DB_DELETED) + goto done; + else + goto out; + } + + /* + * We simply read the first page and if the LSN is 0, we + * write the meta-data page. + */ + if ((ret = __os_open(dbenv, real_name, 0, 0, &fh)) != 0) + goto out; + if ((ret = __os_seek(dbenv, &fh, + pagesize, argp->pgno, 0, 0, DB_OS_SEEK_SET)) != 0) + goto out; + /* + * If the read succeeds then the page exists, then we need + * to vrify that the page has actually been written, because + * on some systems (e.g., Windows) we preallocate pages because + * files aren't allowed to have holes in them. If the page + * looks good then we're done. + */ + if ((ret = __os_read(dbenv, &fh, &ondisk, + sizeof(ondisk), &nr)) == 0 && nr == sizeof(ondisk)) { + if (ondisk.magic != 0) + goto done; + if ((ret = __os_seek(dbenv, &fh, + pagesize, argp->pgno, 0, 0, DB_OS_SEEK_SET)) != 0) + goto out; + } + + /* + * Page didn't exist, update the LSN and write a new one. + * (seek pointer shouldn't have moved) + */ + __ua_memcpy(&meta->lsn, lsnp, sizeof(DB_LSN)); + if ((ret = __os_write(dbp->dbenv, &fh, + argp->page.data, argp->page.size, &nr)) != 0) + goto out; + if (nr != (size_t)argp->page.size) { + __db_err(dbenv, "Write failed during recovery"); + ret = EIO; + goto out; + } + + /* + * We must close and reopen the file to be sure + * that we have the proper meta information + * in the in memory structures + */ + + if ((ret = __log_reopen_file(dbenv, + argp->name.data, argp->fileid, + meta->uid, argp->pgno)) != 0) + goto out; + + /* Handle will be closed on exit. */ + } else if (DB_UNDO(op)) { + is_done = 0; + + /* If file does not exist, there is nothing to undo. */ + if (__os_exists(real_name, NULL) != 0) + goto done; + + /* + * Before we can look at anything on disk, we have to check + * if there is a valid dbp for this, and if there is, we'd + * better flush it. + */ + dbp = NULL; + if ((ret = + __db_fileid_to_db(dbenv, &dbp, argp->fileid, 0)) == 0) + (void)dbp->sync(dbp, 0); + + /* + * We need to make sure that we do not remove a file that + * someone else created. If the file is 0-length, then we + * can assume that we created it and remove it. If it is + * not 0-length, then we need to check the LSN and make + * sure that it's the file we created. + */ + if ((ret = __os_open(dbenv, real_name, 0, 0, &fh)) != 0) + goto out; + if ((ret = __os_ioinfo(dbenv, + real_name, &fh, &mb, &b, &io)) != 0) + goto out; + if (mb != 0 || b != 0) { + /* The file has something in it. */ + if ((ret = __os_seek(dbenv, &fh, + pagesize, argp->pgno, 0, 0, DB_OS_SEEK_SET)) != 0) + goto out; + if ((ret = __os_read(dbenv, &fh, + &ondisk, sizeof(ondisk), &nr)) != 0) + goto out; + if (log_compare(&ondisk.lsn, lsnp) != 0) + is_done = 1; + } + + /* + * Must close here, because unlink with the file open fails + * on some systems. + */ + if ((ret = __os_closehandle(&fh)) != 0) + goto out; + + if (!is_done) { + /* + * On some systems, you cannot unlink an open file so + * we close the fd in the dbp here and make sure we + * don't try to close it again. First, check for a + * saved_open_fhp, then close down the mpool. + */ + if (dbp != NULL && dbp->saved_open_fhp != NULL && + F_ISSET(dbp->saved_open_fhp, DB_FH_VALID) && + (ret = __os_closehandle(dbp->saved_open_fhp)) != 0) + goto out; + if (dbp != NULL && dbp->mpf != NULL) { + (void)__memp_fremove(dbp->mpf); + if ((ret = memp_fclose(dbp->mpf)) != 0) + goto out; + F_SET(dbp, DB_AM_DISCARD); + dbp->mpf = NULL; + } + if ((ret = __os_unlink(dbenv, real_name)) != 0) + goto out; + } + } + +done: *lsnp = argp->prev_lsn; + ret = 0; + +out: if (argp != NULL) + __os_free(argp, 0); + if (real_name != NULL) + __os_freestr(real_name); + if (F_ISSET(&fh, DB_FH_VALID)) + (void)__os_closehandle(&fh); + return (ret); +} + +/* + * __crdel_delete_recover -- + * Recovery function for delete. + * + * PUBLIC: int __crdel_delete_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__crdel_delete_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + DB *dbp; + __crdel_delete_args *argp; + int ret; + char *backup, *real_back, *real_name; + + REC_PRINT(__crdel_delete_print); + + backup = real_back = real_name = NULL; + if ((ret = __crdel_delete_read(dbenv, dbtp->data, &argp)) != 0) + goto out; + + if (DB_REDO(op)) { + /* + * On a recovery, as we recreate what was going on, we + * recreate the creation of the file. And so, even though + * it committed, we need to delete it. Try to delete it, + * but it is not an error if that delete fails. + */ + if ((ret = __db_appname(dbenv, DB_APP_DATA, + NULL, argp->name.data, 0, NULL, &real_name)) != 0) + goto out; + if (__os_exists(real_name, NULL) == 0) { + /* + * If a file is deleted and then recreated, it's + * possible for the __os_exists call above to + * return success and for us to get here, but for + * the fileid we're looking for to be marked + * deleted. In that case, we needn't redo the + * unlink even though the file exists, and it's + * not an error. + */ + ret = __db_fileid_to_db(dbenv, &dbp, argp->fileid, 0); + if (ret == 0) { + /* + * On Windows, the underlying file must be + * closed to perform a remove. + */ + (void)__memp_fremove(dbp->mpf); + if ((ret = memp_fclose(dbp->mpf)) != 0) + goto out; + dbp->mpf = NULL; + if ((ret = __os_unlink(dbenv, real_name)) != 0) + goto out; + } else if (ret != DB_DELETED) + goto out; + } + /* + * The transaction committed, so the only thing that might + * be true is that the backup file is still around. Try + * to delete it, but it's not an error if that delete fails. + */ + if ((ret = __db_backup_name(dbenv, argp->name.data, + &backup, lsnp)) != 0) + goto out; + if ((ret = __db_appname(dbenv, + DB_APP_DATA, NULL, backup, 0, NULL, &real_back)) != 0) + goto out; + if (__os_exists(real_back, NULL) == 0) + if ((ret = __os_unlink(dbenv, real_back)) != 0) + goto out; + if ((ret = __db_txnlist_delete(dbenv, info, + argp->name.data, TXNLIST_INVALID_ID, 1)) != 0) + goto out; + } else if (DB_UNDO(op)) { + /* + * Trying to undo. File may or may not have been deleted. + * Try to move the backup to the original. If the backup + * exists, then this is right. If it doesn't exist, then + * nothing will happen and that's OK. + */ + if ((ret = __db_backup_name(dbenv, argp->name.data, + &backup, lsnp)) != 0) + goto out; + if ((ret = __db_appname(dbenv, + DB_APP_DATA, NULL, backup, 0, NULL, &real_back)) != 0) + goto out; + if ((ret = __db_appname(dbenv, DB_APP_DATA, + NULL, argp->name.data, 0, NULL, &real_name)) != 0) + goto out; + if (__os_exists(real_back, NULL) == 0) + if ((ret = + __os_rename(dbenv, real_back, real_name)) != 0) + goto out; + } + + *lsnp = argp->prev_lsn; + ret = 0; + +out: if (argp != NULL) + __os_free(argp, 0); + if (backup != NULL) + __os_freestr(backup); + if (real_back != NULL) + __os_freestr(real_back); + if (real_name != NULL) + __os_freestr(real_name); + return (ret); +} +/* + * __crdel_rename_recover -- + * Recovery function for rename. + * + * PUBLIC: int __crdel_rename_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__crdel_rename_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + DB *dbp; + __crdel_rename_args *argp; + char *new_name, *real_name; + int ret, set; + + COMPQUIET(info, NULL); + + REC_PRINT(__crdel_rename_print); + + new_name = real_name = NULL; + + if ((ret = __crdel_rename_read(dbenv, dbtp->data, &argp)) != 0) + goto out; + + if ((ret = __db_fileid_to_db(dbenv, &dbp, argp->fileid, 0)) != 0) + goto out; + if (DB_REDO(op)) { + /* + * We don't use the dbp parameter to __log_filelist_update + * in the rename case, so passing NULL for it is OK. + */ + if ((ret = __log_filelist_update(dbenv, NULL, + argp->fileid, argp->newname.data, &set)) != 0) + goto out; + if (set != 0) { + if ((ret = __db_appname(dbenv, DB_APP_DATA, + NULL, argp->name.data, 0, NULL, &real_name)) != 0) + goto out; + if (__os_exists(real_name, NULL) == 0) { + if ((ret = __db_appname(dbenv, + DB_APP_DATA, NULL, argp->newname.data, + 0, NULL, &new_name)) != 0) + goto out; + /* + * On Windows, the underlying file + * must be closed to perform a remove. + * The db will be closed by a + * log_register record. Rename + * has exclusive access to the db. + */ + (void)__memp_fremove(dbp->mpf); + if ((ret = memp_fclose(dbp->mpf)) != 0) + goto out; + dbp->mpf = NULL; + if ((ret = __os_rename(dbenv, + real_name, new_name)) != 0) + goto out; + } + } + } else { + /* + * We don't use the dbp parameter to __log_filelist_update + * in the rename case, so passing NULL for it is OK. + */ + if ((ret = __log_filelist_update(dbenv, NULL, + argp->fileid, argp->name.data, &set)) != 0) + goto out; + if (set != 0) { + if ((ret = __db_appname(dbenv, DB_APP_DATA, + NULL, argp->newname.data, 0, NULL, &new_name)) != 0) + goto out; + if (__os_exists(new_name, NULL) == 0) { + if ((ret = __db_appname(dbenv, + DB_APP_DATA, NULL, argp->name.data, + 0, NULL, &real_name)) != 0) + goto out; + /* + * On Windows, the underlying file + * must be closed to perform a remove. + * The file may have already been closed + * if we are aborting the transaction. + */ + if (dbp->mpf != NULL) { + (void)__memp_fremove(dbp->mpf); + if ((ret = memp_fclose(dbp->mpf)) != 0) + goto out; + dbp->mpf = NULL; + } + if ((ret = __os_rename(dbenv, + new_name, real_name)) != 0) + goto out; + } + } + } + + *lsnp = argp->prev_lsn; + ret = 0; + +out: if (argp != NULL) + __os_free(argp, 0); + + if (new_name != NULL) + __os_free(new_name, 0); + + if (real_name != NULL) + __os_free(real_name, 0); + + return (ret); +} diff --git a/db/db/db.c b/db/db/db.c new file mode 100644 index 000000000..6e74b4b21 --- /dev/null +++ b/db/db/db.c @@ -0,0 +1,2325 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994, 1995 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: db.c,v 11.117 2001/01/11 18:19:50 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_shash.h" +#include "db_swap.h" +#include "btree.h" +#include "db_am.h" +#include "hash.h" +#include "lock.h" +#include "log.h" +#include "mp.h" +#include "qam.h" +#include "common_ext.h" + +/* Actions that __db_master_update can take. */ +typedef enum { MU_REMOVE, MU_RENAME, MU_OPEN } mu_action; + +/* Flag values that __db_file_setup can return. */ +#define DB_FILE_SETUP_CREATE 0x01 +#define DB_FILE_SETUP_ZERO 0x02 + +static int __db_file_setup __P((DB *, + const char *, u_int32_t, int, db_pgno_t, int *)); +static int __db_master_update __P((DB *, + const char *, u_int32_t, + db_pgno_t *, mu_action, const char *, u_int32_t)); +static int __db_refresh __P((DB *)); +static int __db_remove_callback __P((DB *, void *)); +static int __db_set_pgsize __P((DB *, DB_FH *, char *)); +static int __db_subdb_remove __P((DB *, const char *, const char *)); +static int __db_subdb_rename __P(( DB *, + const char *, const char *, const char *)); +#if CONFIG_TEST +static void __db_makecopy __P((const char *, const char *)); +static int __db_testdocopy __P((DB *, const char *)); +static int __qam_testdocopy __P((DB *, const char *)); +#endif + +/* + * __db_open -- + * Main library interface to the DB access methods. + * + * PUBLIC: int __db_open __P((DB *, + * PUBLIC: const char *, const char *, DBTYPE, u_int32_t, int)); + */ +int +__db_open(dbp, name, subdb, type, flags, mode) + DB *dbp; + const char *name, *subdb; + DBTYPE type; + u_int32_t flags; + int mode; +{ + DB_ENV *dbenv; + DB_LOCK open_lock; + DB *mdbp; + db_pgno_t meta_pgno; + u_int32_t ok_flags; + int ret, t_ret; + + dbenv = dbp->dbenv; + mdbp = NULL; + + /* Validate arguments. */ +#define OKFLAGS \ + (DB_CREATE | DB_EXCL | DB_FCNTL_LOCKING | \ + DB_NOMMAP | DB_RDONLY | DB_RDWRMASTER | DB_THREAD | DB_TRUNCATE) + if ((ret = __db_fchk(dbenv, "DB->open", flags, OKFLAGS)) != 0) + return (ret); + if (LF_ISSET(DB_EXCL) && !LF_ISSET(DB_CREATE)) + return (__db_ferr(dbenv, "DB->open", 1)); + if (LF_ISSET(DB_RDONLY) && LF_ISSET(DB_CREATE)) + return (__db_ferr(dbenv, "DB->open", 1)); +#ifdef HAVE_VXWORKS + if (LF_ISSET(DB_TRUNCATE)) { + __db_err(dbenv, "DB_TRUNCATE unsupported in VxWorks"); + return (__db_eopnotsup(dbenv)); + } +#endif + switch (type) { + case DB_UNKNOWN: + if (LF_ISSET(DB_CREATE|DB_TRUNCATE)) { + __db_err(dbenv, + "%s: DB_UNKNOWN type specified with DB_CREATE or DB_TRUNCATE", + name); + return (EINVAL); + } + ok_flags = 0; + break; + case DB_BTREE: + ok_flags = DB_OK_BTREE; + break; + case DB_HASH: + ok_flags = DB_OK_HASH; + break; + case DB_QUEUE: + ok_flags = DB_OK_QUEUE; + break; + case DB_RECNO: + ok_flags = DB_OK_RECNO; + break; + default: + __db_err(dbenv, "unknown type: %lu", (u_long)type); + return (EINVAL); + } + if (ok_flags) + DB_ILLEGAL_METHOD(dbp, ok_flags); + + /* The environment may have been created, but never opened. */ + if (!F_ISSET(dbenv, DB_ENV_DBLOCAL | DB_ENV_OPEN_CALLED)) { + __db_err(dbenv, "environment not yet opened"); + return (EINVAL); + } + + /* + * Historically, you could pass in an environment that didn't have a + * mpool, and DB would create a private one behind the scenes. This + * no longer works. + */ + if (!F_ISSET(dbenv, DB_ENV_DBLOCAL) && !MPOOL_ON(dbenv)) { + __db_err(dbenv, "environment did not include a memory pool."); + return (EINVAL); + } + + /* + * You can't specify threads during DB->open if subsystems in the + * environment weren't configured with them. + */ + if (LF_ISSET(DB_THREAD) && + !F_ISSET(dbenv, DB_ENV_DBLOCAL | DB_ENV_THREAD)) { + __db_err(dbenv, "environment not created using DB_THREAD"); + return (EINVAL); + } + + /* + * If the environment was configured with threads, the DB handle + * must also be free-threaded, so we force the DB_THREAD flag on. + * (See SR #2033 for why this is a requirement--recovery needs + * to be able to grab a dbp using __db_fileid_to_dbp, and it has + * no way of knowing which dbp goes with which thread, so whichever + * one it finds has to be usable in any of them.) + */ + if (F_ISSET(dbenv, DB_ENV_THREAD)) + LF_SET(DB_THREAD); + + /* DB_TRUNCATE is not transaction recoverable. */ + if (LF_ISSET(DB_TRUNCATE) && TXN_ON(dbenv)) { + __db_err(dbenv, + "DB_TRUNCATE illegal in a transaction protected environment"); + return (EINVAL); + } + + /* Subdatabase checks. */ + if (subdb != NULL) { + /* Subdatabases must be created in named files. */ + if (name == NULL) { + __db_err(dbenv, + "multiple databases cannot be created in temporary files"); + return (EINVAL); + } + + /* QAM can't be done as a subdatabase. */ + if (type == DB_QUEUE) { + __db_err(dbenv, "Queue databases must be one-per-file"); + return (EINVAL); + } + } + + /* Convert any DB->open flags. */ + if (LF_ISSET(DB_RDONLY)) + F_SET(dbp, DB_AM_RDONLY); + + /* Fill in the type. */ + dbp->type = type; + + /* + * If we're potentially creating a database, wrap the open inside of + * a transaction. + */ + if (TXN_ON(dbenv) && LF_ISSET(DB_CREATE)) + if ((ret = __db_metabegin(dbp, &open_lock)) != 0) + return (ret); + + /* + * If we're opening a subdatabase, we have to open (and potentially + * create) the main database, and then get (and potentially store) + * our base page number in that database. Then, we can finally open + * the subdatabase. + */ + if (subdb == NULL) + meta_pgno = PGNO_BASE_MD; + else { + /* + * Open the master database, optionally creating or updating + * it, and retrieve the metadata page number. + */ + if ((ret = + __db_master_open(dbp, name, flags, mode, &mdbp)) != 0) + goto err; + + /* Copy the page size and file id from the master. */ + dbp->pgsize = mdbp->pgsize; + F_SET(dbp, DB_AM_SUBDB); + memcpy(dbp->fileid, mdbp->fileid, DB_FILE_ID_LEN); + + if ((ret = __db_master_update(mdbp, + subdb, type, &meta_pgno, MU_OPEN, NULL, flags)) != 0) + goto err; + + /* + * Clear the exclusive open and truncation flags, they only + * apply to the open of the master database. + */ + LF_CLR(DB_EXCL | DB_TRUNCATE); + } + + ret = __db_dbopen(dbp, name, flags, mode, meta_pgno); + + /* + * You can open the database that describes the subdatabases in the + * rest of the file read-only. The content of each key's data is + * unspecified and applications should never be adding new records + * or updating existing records. However, during recovery, we need + * to open these databases R/W so we can redo/undo changes in them. + * Likewise, we need to open master databases read/write during + * rename and remove so we can be sure they're fully sync'ed, so + * we provide an override flag for the purpose. + */ + if (subdb == NULL && !IS_RECOVERING(dbenv) && !LF_ISSET(DB_RDONLY) && + !LF_ISSET(DB_RDWRMASTER) && F_ISSET(dbp, DB_AM_SUBDB)) { + __db_err(dbenv, + "files containing multiple databases may only be opened read-only"); + ret = EINVAL; + goto err; + } + +err: /* + * End any transaction, committing if we were successful, aborting + * otherwise. + */ + if (TXN_ON(dbenv) && LF_ISSET(DB_CREATE)) + if ((t_ret = __db_metaend(dbp, + &open_lock, ret == 0, NULL, NULL)) != 0 && ret == 0) + ret = t_ret; + + /* If we were successful, don't discard the file on close. */ + if (ret == 0) + F_CLR(dbp, DB_AM_DISCARD); + + /* If we were unsuccessful, destroy the DB handle. */ + if (ret != 0) { + /* In recovery we set log_fileid early. */ + if (IS_RECOVERING(dbenv)) + dbp->log_fileid = DB_LOGFILEID_INVALID; + __db_refresh(dbp); + } + + if (mdbp != NULL) { + /* If we were successful, don't discard the file on close. */ + if (ret == 0) + F_CLR(mdbp, DB_AM_DISCARD); + if ((t_ret = mdbp->close(mdbp, 0)) != 0 && ret == 0) + ret = t_ret; + } + + return (ret); +} + +/* + * __db_dbopen -- + * Open a database. + * PUBLIC: int __db_dbopen __P((DB *, const char *, u_int32_t, int, db_pgno_t)); + */ +int +__db_dbopen(dbp, name, flags, mode, meta_pgno) + DB *dbp; + const char *name; + u_int32_t flags; + int mode; + db_pgno_t meta_pgno; +{ + DB_ENV *dbenv; + int ret, retinfo; + + dbenv = dbp->dbenv; + + /* Set up the underlying file. */ + if ((ret = __db_file_setup(dbp, + name, flags, mode, meta_pgno, &retinfo)) != 0) + return (ret); + + /* + * If we created the file, set the truncate flag for the mpool. This + * isn't for anything we've done, it's protection against stupid user + * tricks: if the user deleted a file behind Berkeley DB's back, we + * may still have pages in the mpool that match the file's "unique" ID. + */ + if (retinfo & DB_FILE_SETUP_CREATE) + flags |= DB_TRUNCATE; + + /* Set up the underlying environment. */ + if ((ret = __db_dbenv_setup(dbp, name, flags)) != 0) + return (ret); + + /* + * Do access method specific initialization. + * + * !!! + * Set the open flag. (The underlying access method open functions + * may want to do things like acquire cursors, so the open flag has + * to be set before calling them.) + */ + F_SET(dbp, DB_OPEN_CALLED); + + if (retinfo & DB_FILE_SETUP_ZERO) + return (0); + + switch (dbp->type) { + case DB_BTREE: + ret = __bam_open(dbp, name, meta_pgno, flags); + break; + case DB_HASH: + ret = __ham_open(dbp, name, meta_pgno, flags); + break; + case DB_RECNO: + ret = __ram_open(dbp, name, meta_pgno, flags); + break; + case DB_QUEUE: + ret = __qam_open(dbp, name, meta_pgno, mode, flags); + break; + case DB_UNKNOWN: + return (__db_unknown_type(dbp->dbenv, + "__db_dbopen", dbp->type)); + break; + } + return (ret); +} + +/* + * __db_master_open -- + * Open up a handle on a master database. + * + * PUBLIC: int __db_master_open __P((DB *, + * PUBLIC: const char *, u_int32_t, int, DB **)); + */ +int +__db_master_open(subdbp, name, flags, mode, dbpp) + DB *subdbp; + const char *name; + u_int32_t flags; + int mode; + DB **dbpp; +{ + DB *dbp; + int ret; + + /* Open up a handle on the main database. */ + if ((ret = db_create(&dbp, subdbp->dbenv, 0)) != 0) + return (ret); + + /* + * It's always a btree. + * Run in the transaction we've created. + * Set the pagesize in case we're creating a new database. + * Flag that we're creating a database with subdatabases. + */ + dbp->type = DB_BTREE; + dbp->open_txn = subdbp->open_txn; + dbp->pgsize = subdbp->pgsize; + F_SET(dbp, DB_AM_SUBDB); + + if ((ret = __db_dbopen(dbp, name, flags, mode, PGNO_BASE_MD)) != 0) { + if (!F_ISSET(dbp, DB_AM_DISCARD)) + dbp->close(dbp, 0); + return (ret); + } + + *dbpp = dbp; + return (0); +} + +/* + * __db_master_update -- + * Add/Remove a subdatabase from a master database. + */ +static int +__db_master_update(mdbp, subdb, type, meta_pgnop, action, newname, flags) + DB *mdbp; + const char *subdb; + u_int32_t type; + db_pgno_t *meta_pgnop; /* may be NULL on MU_RENAME */ + mu_action action; + const char *newname; + u_int32_t flags; +{ + DB_ENV *dbenv; + DBC *dbc, *ndbc; + DBT key, data, ndata; + PAGE *p; + db_pgno_t t_pgno; + int modify, ret, t_ret; + + dbenv = mdbp->dbenv; + dbc = ndbc = NULL; + p = NULL; + + /* Might we modify the master database? If so, we'll need to lock. */ + modify = (action != MU_OPEN || LF_ISSET(DB_CREATE)) ? 1 : 0; + + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + + /* + * Open up a cursor. If this is CDB and we're creating the database, + * make it an update cursor. + */ + if ((ret = mdbp->cursor(mdbp, mdbp->open_txn, &dbc, + (CDB_LOCKING(dbenv) && modify) ? DB_WRITECURSOR : 0)) != 0) + goto err; + + /* + * Try to point the cursor at the record. + * + * If we're removing or potentially creating an entry, lock the page + * with DB_RMW. + * + * !!! + * We don't include the name's nul termination in the database. + */ + key.data = (char *)subdb; + key.size = strlen(subdb); + /* In the rename case, we do multiple cursor ops, so MALLOC is safer. */ + F_SET(&data, DB_DBT_MALLOC); + ret = dbc->c_get(dbc, &key, &data, + DB_SET | ((STD_LOCKING(dbc) && modify) ? DB_RMW : 0)); + + /* + * What we do next--whether or not we found a record for the + * specified subdatabase--depends on what the specified action is. + * Handle ret appropriately as the first statement of each case. + */ + switch (action) { + case MU_REMOVE: + /* + * We should have found something if we're removing it. Note + * that in the common case where the DB we're asking to remove + * doesn't exist, we won't get this far; __db_subdb_remove + * will already have returned an error from __db_open. + */ + if (ret != 0) + goto err; + + /* + * Delete the subdatabase entry first; if this fails, + * we don't want to touch the actual subdb pages. + */ + if ((ret = dbc->c_del(dbc, 0)) != 0) + goto err; + + /* + * We're handling actual data, not on-page meta-data, + * so it hasn't been converted to/from opposite + * endian architectures. Do it explicitly, now. + */ + memcpy(meta_pgnop, data.data, sizeof(db_pgno_t)); + DB_NTOHL(meta_pgnop); + if ((ret = memp_fget(mdbp->mpf, meta_pgnop, 0, &p)) != 0) + goto err; + + /* Free and put the page. */ + if ((ret = __db_free(dbc, p)) != 0) { + p = NULL; + goto err; + } + p = NULL; + break; + case MU_RENAME: + /* We should have found something if we're renaming it. */ + if (ret != 0) + goto err; + + /* + * Before we rename, we need to make sure we're not + * overwriting another subdatabase, or else this operation + * won't be undoable. Open a second cursor and check + * for the existence of newname; it shouldn't appear under + * us since we hold the metadata lock. + */ + if ((ret = mdbp->cursor(mdbp, mdbp->open_txn, &ndbc, 0)) != 0) + goto err; + DB_ASSERT(newname != NULL); + key.data = (void *) newname; + key.size = strlen(newname); + + /* + * We don't actually care what the meta page of the potentially- + * overwritten DB is; we just care about existence. + */ + memset(&ndata, 0, sizeof(ndata)); + F_SET(&ndata, DB_DBT_USERMEM | DB_DBT_PARTIAL); + + if ((ret = ndbc->c_get(ndbc, &key, &ndata, DB_SET)) == 0) { + /* A subdb called newname exists. Bail. */ + ret = EEXIST; + __db_err(dbenv, "rename: database %s exists", newname); + goto err; + } else if (ret != DB_NOTFOUND) + goto err; + + /* + * Now do the put first; we don't want to lose our + * sole reference to the subdb. Use the second cursor + * so that the first one continues to point to the old record. + */ + if ((ret = ndbc->c_put(ndbc, &key, &data, DB_KEYFIRST)) != 0) + goto err; + if ((ret = dbc->c_del(dbc, 0)) != 0) { + /* + * If the delete fails, try to delete the record + * we just put, in case we're not txn-protected. + */ + (void)ndbc->c_del(ndbc, 0); + goto err; + } + + break; + case MU_OPEN: + /* + * Get the subdatabase information. If it already exists, + * copy out the page number and we're done. + */ + switch (ret) { + case 0: + memcpy(meta_pgnop, data.data, sizeof(db_pgno_t)); + DB_NTOHL(meta_pgnop); + goto done; + case DB_NOTFOUND: + if (LF_ISSET(DB_CREATE)) + break; + /* + * No db_err, it is reasonable to remove a + * nonexistent db. + */ + ret = ENOENT; + goto err; + default: + goto err; + } + + if ((ret = __db_new(dbc, + type == DB_HASH ? P_HASHMETA : P_BTREEMETA, &p)) != 0) + goto err; + *meta_pgnop = PGNO(p); + + /* + * XXX + * We're handling actual data, not on-page meta-data, so it + * hasn't been converted to/from opposite endian architectures. + * Do it explicitly, now. + */ + t_pgno = PGNO(p); + DB_HTONL(&t_pgno); + memset(&ndata, 0, sizeof(ndata)); + ndata.data = &t_pgno; + ndata.size = sizeof(db_pgno_t); + if ((ret = dbc->c_put(dbc, &key, &ndata, DB_KEYLAST)) != 0) + goto err; + break; + } + +err: +done: /* + * If we allocated a page: if we're successful, mark the page dirty + * and return it to the cache, otherwise, discard/free it. + */ + if (p != NULL) { + if (ret == 0) { + if ((t_ret = + memp_fput(mdbp->mpf, p, DB_MPOOL_DIRTY)) != 0) + ret = t_ret; + /* + * Since we cannot close this file until after + * transaction commit, we need to sync the dirty + * pages, because we'll read these directly from + * disk to open. + */ + if ((t_ret = mdbp->sync(mdbp, 0)) != 0 && ret == 0) + ret = t_ret; + } else + (void)__db_free(dbc, p); + } + + /* Discard the cursor(s) and data. */ + if (data.data != NULL) + __os_free(data.data, data.size); + if (dbc != NULL && (t_ret = dbc->c_close(dbc)) != 0 && ret == 0) + ret = t_ret; + if (ndbc != NULL && (t_ret = ndbc->c_close(ndbc)) != 0 && ret == 0) + ret = t_ret; + + return (ret); +} + +/* + * __db_dbenv_setup -- + * Set up the underlying environment during a db_open. + * + * PUBLIC: int __db_dbenv_setup __P((DB *, const char *, u_int32_t)); + */ +int +__db_dbenv_setup(dbp, name, flags) + DB *dbp; + const char *name; + u_int32_t flags; +{ + DB *ldbp; + DB_ENV *dbenv; + DBT pgcookie; + DB_MPOOL_FINFO finfo; + DB_PGINFO pginfo; + int ret; + u_int32_t maxid; + + dbenv = dbp->dbenv; + + /* If we don't yet have an environment, it's time to create it. */ + if (!F_ISSET(dbenv, DB_ENV_OPEN_CALLED)) { + /* Make sure we have at least DB_MINCACHE pages in our cache. */ + if (dbenv->mp_gbytes == 0 && + dbenv->mp_bytes < dbp->pgsize * DB_MINPAGECACHE && + (ret = dbenv->set_cachesize( + dbenv, 0, dbp->pgsize * DB_MINPAGECACHE, 0)) != 0) + return (ret); + + if ((ret = dbenv->open(dbenv, NULL, DB_CREATE | + DB_INIT_MPOOL | DB_PRIVATE | LF_ISSET(DB_THREAD), 0)) != 0) + return (ret); + } + + /* Register DB's pgin/pgout functions. */ + if ((ret = + memp_register(dbenv, DB_FTYPE_SET, __db_pgin, __db_pgout)) != 0) + return (ret); + + /* + * Open a backing file in the memory pool. + * + * If we need to pre- or post-process a file's pages on I/O, set the + * file type. If it's a hash file, always call the pgin and pgout + * routines. This means that hash files can never be mapped into + * process memory. If it's a btree file and requires swapping, we + * need to page the file in and out. This has to be right -- we can't + * mmap files that are being paged in and out. + */ + memset(&finfo, 0, sizeof(finfo)); + switch (dbp->type) { + case DB_BTREE: + case DB_RECNO: + finfo.ftype = + F_ISSET(dbp, DB_AM_SWAP) ? DB_FTYPE_SET : DB_FTYPE_NOTSET; + finfo.clear_len = DB_PAGE_DB_LEN; + break; + case DB_HASH: + finfo.ftype = DB_FTYPE_SET; + finfo.clear_len = DB_PAGE_DB_LEN; + break; + case DB_QUEUE: + finfo.ftype = + F_ISSET(dbp, DB_AM_SWAP) ? DB_FTYPE_SET : DB_FTYPE_NOTSET; + finfo.clear_len = DB_PAGE_QUEUE_LEN; + break; + case DB_UNKNOWN: + /* + * If we're running in the verifier, our database might + * be corrupt and we might not know its type--but we may + * still want to be able to verify and salvage. + * + * If we can't identify the type, it's not going to be safe + * to call __db_pgin--we pretty much have to give up all + * hope of salvaging cross-endianness. Proceed anyway; + * at worst, the database will just appear more corrupt + * than it actually is, but at best, we may be able + * to salvage some data even with no metadata page. + */ + if (F_ISSET(dbp, DB_AM_VERIFYING)) { + finfo.ftype = DB_FTYPE_NOTSET; + finfo.clear_len = DB_PAGE_DB_LEN; + break; + } + return (__db_unknown_type(dbp->dbenv, + "__db_dbenv_setup", dbp->type)); + } + finfo.pgcookie = &pgcookie; + finfo.fileid = dbp->fileid; + finfo.lsn_offset = 0; + + pginfo.db_pagesize = dbp->pgsize; + pginfo.needswap = F_ISSET(dbp, DB_AM_SWAP); + pgcookie.data = &pginfo; + pgcookie.size = sizeof(DB_PGINFO); + + if ((ret = memp_fopen(dbenv, name, + LF_ISSET(DB_RDONLY | DB_NOMMAP | DB_ODDFILESIZE | DB_TRUNCATE), + 0, dbp->pgsize, &finfo, &dbp->mpf)) != 0) + return (ret); + + /* + * We may need a per-thread mutex. Allocate it from the environment + * region, there's supposed to be extra space there for that purpose. + */ + if (LF_ISSET(DB_THREAD)) { + if ((ret = __db_mutex_alloc( + dbenv, dbenv->reginfo, (MUTEX **)&dbp->mutexp)) != 0) + return (ret); + if ((ret = __db_mutex_init( + dbenv, dbp->mutexp, 0, MUTEX_THREAD)) != 0) { + __db_mutex_free(dbenv, dbenv->reginfo, dbp->mutexp); + return (ret); + } + } + + /* Get a log file id. */ + if (LOGGING_ON(dbenv) && !IS_RECOVERING(dbenv) && +#if !defined(DEBUG_ROP) + !F_ISSET(dbp, DB_AM_RDONLY) && +#endif + (ret = log_register(dbenv, dbp, name)) != 0) + return (ret); + + /* + * Insert ourselves into the DB_ENV's dblist. We allocate a + * unique ID to each {fileid, meta page number} pair, and to + * each temporary file (since they all have a zero fileid). + * This ID gives us something to use to tell which DB handles + * go with which databases in all the cursor adjustment + * routines, where we don't want to do a lot of ugly and + * expensive memcmps. + */ + MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp); + for (maxid = 0, ldbp = LIST_FIRST(&dbenv->dblist); + ldbp != NULL; ldbp = LIST_NEXT(dbp, dblistlinks)) { + if (name != NULL && + memcmp(ldbp->fileid, dbp->fileid, DB_FILE_ID_LEN) == 0 && + ldbp->meta_pgno == dbp->meta_pgno) + break; + if (ldbp->adj_fileid > maxid) + maxid = ldbp->adj_fileid; + } + + /* + * If ldbp is NULL, we didn't find a match, or we weren't + * really looking because name is NULL. Assign the dbp an + * adj_fileid one higher than the largest we found, and + * insert it at the head of the master dbp list. + * + * If ldbp is not NULL, it is a match for our dbp. Give dbp + * the same ID that ldbp has, and add it after ldbp so they're + * together in the list. + */ + if (ldbp == NULL) { + dbp->adj_fileid = maxid + 1; + LIST_INSERT_HEAD(&dbenv->dblist, dbp, dblistlinks); + } else { + dbp->adj_fileid = ldbp->adj_fileid; + LIST_INSERT_AFTER(ldbp, dbp, dblistlinks); + } + MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp); + + return (0); +} + +/* + * __db_file_setup -- + * Setup the file or in-memory data. + * Read the database metadata and resolve it with our arguments. + */ +static int +__db_file_setup(dbp, name, flags, mode, meta_pgno, retflags) + DB *dbp; + const char *name; + u_int32_t flags; + int mode; + db_pgno_t meta_pgno; + int *retflags; +{ + DB *mdb; + DBT namedbt; + DB_ENV *dbenv; + DB_FH *fhp, fh; + DB_LSN lsn; + DB_TXN *txn; + size_t nr; + u_int32_t magic, oflags; + int ret, retry_cnt, t_ret; + char *real_name, mbuf[DBMETASIZE]; + +#define IS_SUBDB_SETUP (meta_pgno != PGNO_BASE_MD) + + dbenv = dbp->dbenv; + dbp->meta_pgno = meta_pgno; + txn = NULL; + *retflags = 0; + + /* + * If we open a file handle and our caller is doing fcntl(2) locking, + * we can't close it because that would discard the caller's lock. + * Save it until we close the DB handle. + */ + if (LF_ISSET(DB_FCNTL_LOCKING)) { + if ((ret = __os_malloc(dbenv, sizeof(*fhp), NULL, &fhp)) != 0) + return (ret); + } else + fhp = &fh; + memset(fhp, 0, sizeof(*fhp)); + + /* + * If the file is in-memory, set up is simple. Otherwise, do the + * hard work of opening and reading the file. + * + * If we have a file name, try and read the first page, figure out + * what type of file it is, and initialize everything we can based + * on that file's meta-data page. + * + * !!! + * There's a reason we don't push this code down into the buffer cache. + * The problem is that there's no information external to the file that + * we can use as a unique ID. UNIX has dev/inode pairs, but they are + * not necessarily unique after reboot, if the file was mounted via NFS. + * Windows has similar problems, as the FAT filesystem doesn't maintain + * dev/inode numbers across reboot. So, we must get something from the + * file we can use to ensure that, even after a reboot, the file we're + * joining in the cache is the right file for us to join. The solution + * we use is to maintain a file ID that's stored in the database, and + * that's why we have to open and read the file before calling into the + * buffer cache. + * + * The secondary reason is that there's additional information that + * we want to have before instantiating a file in the buffer cache: + * the page size, file type (btree/hash), if swapping is required, + * and flags (DB_RDONLY, DB_CREATE, DB_TRUNCATE). We could handle + * needing this information by allowing it to be set for a file in + * the buffer cache even after the file has been opened, and, of + * course, supporting the ability to flush a file from the cache as + * necessary, e.g., if we guessed wrongly about the page size. Given + * that we have to read the file anyway to get the file ID, we might + * as well get the rest, too. + * + * Get the real file name. + */ + if (name == NULL) { + F_SET(dbp, DB_AM_INMEM); + + if (dbp->type == DB_UNKNOWN) { + __db_err(dbenv, + "DBTYPE of unknown without existing file"); + return (EINVAL); + } + real_name = NULL; + + /* Set the page size if we don't have one yet. */ + if (dbp->pgsize == 0) + dbp->pgsize = DB_DEF_IOSIZE; + + /* + * If the file is a temporary file and we're doing locking, + * then we have to create a unique file ID. We can't use our + * normal dev/inode pair (or whatever this OS uses in place of + * dev/inode pairs) because no backing file will be created + * until the mpool cache is filled forcing the buffers to disk. + * Grab a random locker ID to use as a file ID. The created + * ID must never match a potential real file ID -- we know it + * won't because real file IDs contain a time stamp after the + * dev/inode pair, and we're simply storing a 4-byte value. + * + * !!! + * Store the locker in the file id structure -- we can get it + * from there as necessary, and it saves having two copies. + */ + if (LOCKING_ON(dbenv) && + (ret = lock_id(dbenv, (u_int32_t *)dbp->fileid)) != 0) + return (ret); + + return (0); + } + + /* Get the real backing file name. */ + if ((ret = __db_appname(dbenv, + DB_APP_DATA, NULL, name, 0, NULL, &real_name)) != 0) + return (ret); + + /* + * Open the backing file. We need to make sure that multiple processes + * attempting to create the file at the same time are properly ordered + * so that only one of them creates the "unique" file ID, so we open it + * O_EXCL and O_CREAT so two simultaneous attempts to create the region + * will return failure in one of the attempts. If we're the one that + * fails, simply retry without the O_CREAT flag, which will require the + * meta-data page exist. + */ + + /* Fill in the default file mode. */ + if (mode == 0) + mode = __db_omode("rwrw--"); + + oflags = 0; + if (LF_ISSET(DB_RDONLY)) + oflags |= DB_OSO_RDONLY; + if (LF_ISSET(DB_TRUNCATE)) + oflags |= DB_OSO_TRUNC; + + retry_cnt = 0; +open_retry: + *retflags = 0; + ret = 0; + if (!IS_SUBDB_SETUP && LF_ISSET(DB_CREATE)) { + if (dbp->open_txn != NULL) { + /* + * Start a child transaction to wrap this individual + * create. + */ + if ((ret = + txn_begin(dbenv, dbp->open_txn, &txn, 0)) != 0) + goto err_msg; + + memset(&namedbt, 0, sizeof(namedbt)); + namedbt.data = (char *)name; + namedbt.size = strlen(name) + 1; + if ((ret = __crdel_fileopen_log(dbenv, txn, + &lsn, DB_FLUSH, &namedbt, mode)) != 0) + goto err_msg; + } + DB_TEST_RECOVERY(dbp, DB_TEST_PREOPEN, ret, name); + if ((ret = __os_open(dbenv, real_name, + oflags | DB_OSO_CREATE | DB_OSO_EXCL, mode, fhp)) == 0) { + DB_TEST_RECOVERY(dbp, DB_TEST_POSTOPEN, ret, name); + + /* Commit the file create. */ + if (dbp->open_txn != NULL) { + if ((ret = txn_commit(txn, DB_TXN_SYNC)) != 0) + goto err_msg; + txn = NULL; + } + + /* + * We created the file. This means that if we later + * fail, we need to delete the file and if we're going + * to do that, we need to trash any pages in the + * memory pool. Since we only know here that we + * created the file, we're going to set the flag here + * and clear it later if we commit successfully. + */ + F_SET(dbp, DB_AM_DISCARD); + *retflags |= DB_FILE_SETUP_CREATE; + } else { + /* + * Abort the file create. If the abort fails, report + * the error returned by txn_abort(), rather than the + * open error, for no particular reason. + */ + if (dbp->open_txn != NULL) { + if ((t_ret = txn_abort(txn)) != 0) { + ret = t_ret; + goto err_msg; + } + txn = NULL; + } + + /* + * If we were not doing an exclusive open, try again + * without the create flag. + */ + if (ret == EEXIST && !LF_ISSET(DB_EXCL)) { + LF_CLR(DB_CREATE); + DB_TEST_RECOVERY(dbp, + DB_TEST_POSTOPEN, ret, name); + goto open_retry; + } + } + } else + ret = __os_open(dbenv, real_name, oflags, mode, fhp); + + /* + * Be quiet if we couldn't open the file because it didn't exist + * or we did not have permission, + * the customers don't like those messages appearing in the logs. + * Otherwise, complain loudly. + */ + if (ret != 0) { + if (ret == EACCES || ret == ENOENT) + goto err; + goto err_msg; + } + + /* Set the page size if we don't have one yet. */ + if (dbp->pgsize == 0) { + if (IS_SUBDB_SETUP) { + if ((ret = __db_master_open(dbp, + name, flags, mode, &mdb)) != 0) + goto err; + dbp->pgsize = mdb->pgsize; + (void)mdb->close(mdb, 0); + } else if ((ret = __db_set_pgsize(dbp, fhp, real_name)) != 0) + goto err; + } + + /* + * Seek to the metadata offset; if it's a master database open or a + * database without subdatabases, we're seeking to 0, but that's OK. + */ + if ((ret = __os_seek(dbenv, fhp, + dbp->pgsize, meta_pgno, 0, 0, DB_OS_SEEK_SET)) != 0) + goto err_msg; + + /* + * Read the metadata page. We read DBMETASIZE bytes, which is larger + * than any access method's metadata page and smaller than any disk + * sector. + */ + if ((ret = __os_read(dbenv, fhp, mbuf, sizeof(mbuf), &nr)) != 0) + goto err_msg; + + if (nr == sizeof(mbuf)) { + /* + * Figure out what access method we're dealing with, and then + * call access method specific code to check error conditions + * based on conflicts between the found file and application + * arguments. A found file overrides some user information -- + * we don't consider it an error, for example, if the user set + * an expected byte order and the found file doesn't match it. + */ + F_CLR(dbp, DB_AM_SWAP); + magic = ((DBMETA *)mbuf)->magic; + +swap_retry: switch (magic) { + case DB_BTREEMAGIC: + if ((ret = + __bam_metachk(dbp, name, (BTMETA *)mbuf)) != 0) + goto err; + break; + case DB_HASHMAGIC: + if ((ret = + __ham_metachk(dbp, name, (HMETA *)mbuf)) != 0) + goto err; + break; + case DB_QAMMAGIC: + if ((ret = + __qam_metachk(dbp, name, (QMETA *)mbuf)) != 0) + goto err; + break; + case 0: + /* + * There are two ways we can get a 0 magic number. + * If we're creating a subdatabase, then the magic + * number will be 0. We allocate a page as part of + * finding out what the base page number will be for + * the new subdatabase, but it's not initialized in + * any way. + * + * The second case happens if we are in recovery + * and we are going to recreate a database, it's + * possible that it's page was created (on systems + * where pages must be created explicitly to avoid + * holes in files) but is still 0. + */ + if (IS_SUBDB_SETUP) { /* Case 1 */ + if ((IS_RECOVERING(dbenv) + && F_ISSET((DB_LOG *) + dbenv->lg_handle, DBLOG_FORCE_OPEN)) + || ((DBMETA *)mbuf)->pgno != PGNO_INVALID) + goto empty; + + ret = EINVAL; + goto err; + } + /* Case 2 */ + if (IS_RECOVERING(dbenv)) { + *retflags |= DB_FILE_SETUP_ZERO; + goto empty; + } + goto bad_format; + default: + if (F_ISSET(dbp, DB_AM_SWAP)) + goto bad_format; + + M_32_SWAP(magic); + F_SET(dbp, DB_AM_SWAP); + goto swap_retry; + } + } else { + /* + * Only newly created files are permitted to fail magic + * number tests. + */ + if (nr != 0 || (!IS_RECOVERING(dbenv) && IS_SUBDB_SETUP)) + goto bad_format; + + /* Let the caller know that we had a 0-length file. */ + if (!LF_ISSET(DB_CREATE | DB_TRUNCATE)) + *retflags |= DB_FILE_SETUP_ZERO; + + /* + * The only way we can reach here with the DB_CREATE flag set + * is if we created the file. If that's not the case, then + * either (a) someone else created the file but has not yet + * written out the metadata page, or (b) we truncated the file + * (DB_TRUNCATE) leaving it zero-length. In the case of (a), + * we want to sleep and give the file creator time to write + * the metadata page. In the case of (b), we want to continue. + * + * !!! + * There's a race in the case of two processes opening the file + * with the DB_TRUNCATE flag set at roughly the same time, and + * they could theoretically hurt each other. Sure hope that's + * unlikely. + */ + if (!LF_ISSET(DB_CREATE | DB_TRUNCATE) && + !IS_RECOVERING(dbenv)) { + if (retry_cnt++ < 3) { + __os_sleep(dbenv, 1, 0); + goto open_retry; + } +bad_format: if (!IS_RECOVERING(dbenv)) + __db_err(dbenv, + "%s: unexpected file type or format", name); + ret = EINVAL; + goto err; + } + + DB_ASSERT (dbp->type != DB_UNKNOWN); + +empty: /* + * The file is empty, and that's OK. If it's not a subdatabase, + * though, we do need to generate a unique file ID for it. The + * unique file ID includes a timestamp so that we can't collide + * with any other files, even when the file IDs (dev/inode pair) + * are reused. + */ + if (!IS_SUBDB_SETUP) { + if (*retflags & DB_FILE_SETUP_ZERO) + memset(dbp->fileid, 0, DB_FILE_ID_LEN); + else if ((ret = __os_fileid(dbenv, + real_name, 1, dbp->fileid)) != 0) + goto err_msg; + } + } + + if (0) { +err_msg: __db_err(dbenv, "%s: %s", name, db_strerror(ret)); + } + + /* + * Abort any running transaction -- it can only exist if something + * went wrong. + */ +err: +DB_TEST_RECOVERY_LABEL + + /* + * If we opened a file handle and our caller is doing fcntl(2) locking, + * then we can't close it because that would discard the caller's lock. + * Otherwise, close the handle. + */ + if (F_ISSET(fhp, DB_FH_VALID)) { + if (ret == 0 && LF_ISSET(DB_FCNTL_LOCKING)) + dbp->saved_open_fhp = fhp; + else + if ((t_ret = __os_closehandle(fhp)) != 0 && ret == 0) + ret = t_ret; + } + + /* + * This must be done after the file is closed, since + * txn_abort() may remove the file, and an open file + * cannot be removed on a Windows platforms. + */ + if (txn != NULL) + (void)txn_abort(txn); + + if (real_name != NULL) + __os_freestr(real_name); + + return (ret); +} + +/* + * __db_set_pgsize -- + * Set the page size based on file information. + */ +static int +__db_set_pgsize(dbp, fhp, name) + DB *dbp; + DB_FH *fhp; + char *name; +{ + DB_ENV *dbenv; + u_int32_t iopsize; + int ret; + + dbenv = dbp->dbenv; + + /* + * Use the filesystem's optimum I/O size as the pagesize if a pagesize + * not specified. Some filesystems have 64K as their optimum I/O size, + * but as that results in fairly large default caches, we limit the + * default pagesize to 16K. + */ + if ((ret = __os_ioinfo(dbenv, name, fhp, NULL, NULL, &iopsize)) != 0) { + __db_err(dbenv, "%s: %s", name, db_strerror(ret)); + return (ret); + } + if (iopsize < 512) + iopsize = 512; + if (iopsize > 16 * 1024) + iopsize = 16 * 1024; + + /* + * Sheer paranoia, but we don't want anything that's not a power-of-2 + * (we rely on that for alignment of various types on the pages), and + * we want a multiple of the sector size as well. + */ + OS_ROUNDOFF(iopsize, 512); + + dbp->pgsize = iopsize; + F_SET(dbp, DB_AM_PGDEF); + + return (0); +} + +/* + * __db_close -- + * DB destructor. + * + * PUBLIC: int __db_close __P((DB *, u_int32_t)); + */ +int +__db_close(dbp, flags) + DB *dbp; + u_int32_t flags; +{ + DB_ENV *dbenv; + DBC *dbc; + int ret, t_ret; + + ret = 0; + + dbenv = dbp->dbenv; + PANIC_CHECK(dbenv); + + /* Validate arguments. */ + if ((ret = __db_closechk(dbp, flags)) != 0) + goto err; + + /* If never opened, or not currently open, it's easy. */ + if (!F_ISSET(dbp, DB_OPEN_CALLED)) + goto never_opened; + + /* Sync the underlying access method. */ + if (!LF_ISSET(DB_NOSYNC) && !F_ISSET(dbp, DB_AM_DISCARD) && + (t_ret = dbp->sync(dbp, 0)) != 0 && ret == 0) + ret = t_ret; + + /* + * Go through the active cursors and call the cursor recycle routine, + * which resolves pending operations and moves the cursors onto the + * free list. Then, walk the free list and call the cursor destroy + * routine. + */ + while ((dbc = TAILQ_FIRST(&dbp->active_queue)) != NULL) + if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0) + ret = t_ret; + while ((dbc = TAILQ_FIRST(&dbp->free_queue)) != NULL) + if ((t_ret = __db_c_destroy(dbc)) != 0 && ret == 0) + ret = t_ret; + + /* + * Close any outstanding join cursors. Join cursors destroy + * themselves on close and have no separate destroy routine. + */ + while ((dbc = TAILQ_FIRST(&dbp->join_queue)) != NULL) + if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0) + ret = t_ret; + + /* Remove this DB handle from the DB_ENV's dblist. */ + MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp); + LIST_REMOVE(dbp, dblistlinks); + MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp); + + /* Sync the memory pool. */ + if (!LF_ISSET(DB_NOSYNC) && !F_ISSET(dbp, DB_AM_DISCARD) && + (t_ret = memp_fsync(dbp->mpf)) != 0 && + t_ret != DB_INCOMPLETE && ret == 0) + ret = t_ret; + + /* Close any handle we've been holding since the open. */ + if (dbp->saved_open_fhp != NULL && + F_ISSET(dbp->saved_open_fhp, DB_FH_VALID) && + (t_ret = __os_closehandle(dbp->saved_open_fhp)) != 0 && ret == 0) + ret = t_ret; + +never_opened: + /* + * Call the access specific close function. + * + * !!! + * Because of where the function is called in the close process, + * these routines can't do anything that would dirty pages or + * otherwise affect closing down the database. + */ + if ((t_ret = __ham_db_close(dbp)) != 0 && ret == 0) + ret = t_ret; + if ((t_ret = __bam_db_close(dbp)) != 0 && ret == 0) + ret = t_ret; + if ((t_ret = __qam_db_close(dbp)) != 0 && ret == 0) + ret = t_ret; + +err: + /* Refresh the structure and close any local environment. */ + if ((t_ret = __db_refresh(dbp)) != 0 && ret == 0) + ret = t_ret; + if (F_ISSET(dbenv, DB_ENV_DBLOCAL) && + --dbenv->dblocal_ref == 0 && + (t_ret = dbenv->close(dbenv, 0)) != 0 && ret == 0) + ret = t_ret; + + memset(dbp, CLEAR_BYTE, sizeof(*dbp)); + __os_free(dbp, sizeof(*dbp)); + + return (ret); +} + +/* + * __db_refresh -- + * Refresh the DB structure, releasing any allocated resources. + */ +static int +__db_refresh(dbp) + DB *dbp; +{ + DB_ENV *dbenv; + DBC *dbc; + int ret, t_ret; + + ret = 0; + + dbenv = dbp->dbenv; + + /* + * Go through the active cursors and call the cursor recycle routine, + * which resolves pending operations and moves the cursors onto the + * free list. Then, walk the free list and call the cursor destroy + * routine. + */ + while ((dbc = TAILQ_FIRST(&dbp->active_queue)) != NULL) + if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0) + ret = t_ret; + while ((dbc = TAILQ_FIRST(&dbp->free_queue)) != NULL) + if ((t_ret = __db_c_destroy(dbc)) != 0 && ret == 0) + ret = t_ret; + + dbp->type = 0; + + /* Close the memory pool file handle. */ + if (dbp->mpf != NULL) { + if (F_ISSET(dbp, DB_AM_DISCARD)) + (void)__memp_fremove(dbp->mpf); + if ((t_ret = memp_fclose(dbp->mpf)) != 0 && ret == 0) + ret = t_ret; + dbp->mpf = NULL; + } + + /* Discard the thread mutex. */ + if (dbp->mutexp != NULL) { + __db_mutex_free(dbenv, dbenv->reginfo, dbp->mutexp); + dbp->mutexp = NULL; + } + + /* Discard the log file id. */ + if (!IS_RECOVERING(dbenv) + && dbp->log_fileid != DB_LOGFILEID_INVALID) + (void)log_unregister(dbenv, dbp); + + F_CLR(dbp, DB_AM_DISCARD); + F_CLR(dbp, DB_AM_INMEM); + F_CLR(dbp, DB_AM_RDONLY); + F_CLR(dbp, DB_AM_SWAP); + F_CLR(dbp, DB_DBM_ERROR); + F_CLR(dbp, DB_OPEN_CALLED); + + return (ret); +} + +/* + * __db_remove + * Remove method for DB. + * + * PUBLIC: int __db_remove __P((DB *, const char *, const char *, u_int32_t)); + */ +int +__db_remove(dbp, name, subdb, flags) + DB *dbp; + const char *name, *subdb; + u_int32_t flags; +{ + DBT namedbt; + DB_ENV *dbenv; + DB_LOCK remove_lock; + DB_LSN newlsn; + int ret, t_ret, (*callback_func) __P((DB *, void *)); + char *backup, *real_back, *real_name; + void *cookie; + + dbenv = dbp->dbenv; + ret = 0; + backup = real_back = real_name = NULL; + + PANIC_CHECK(dbenv); + /* + * Cannot use DB_ILLEGAL_AFTER_OPEN here because that returns + * and we cannot return, but must deal with the error and destroy + * the handle anyway. + */ + if (F_ISSET(dbp, DB_OPEN_CALLED)) { + ret = __db_mi_open(dbp->dbenv, "remove", 1); + goto err_close; + } + + /* Validate arguments. */ + if ((ret = __db_removechk(dbp, flags)) != 0) + goto err_close; + + /* + * Subdatabases. + */ + if (subdb != NULL) { + /* Subdatabases must be created in named files. */ + if (name == NULL) { + __db_err(dbenv, + "multiple databases cannot be created in temporary files"); + goto err_close; + } + return (__db_subdb_remove(dbp, name, subdb)); + } + + if ((ret = dbp->open(dbp, + name, NULL, DB_UNKNOWN, DB_RDWRMASTER, 0)) != 0) + goto err_close; + + if (LOGGING_ON(dbenv) && (ret = __log_file_lock(dbp)) != 0) + goto err_close; + + if ((ret = dbp->sync(dbp, 0)) != 0) + goto err_close; + + /* Start the transaction and log the delete. */ + if (TXN_ON(dbenv) && (ret = __db_metabegin(dbp, &remove_lock)) != 0) + goto err_close; + + if (LOGGING_ON(dbenv)) { + memset(&namedbt, 0, sizeof(namedbt)); + namedbt.data = (char *)name; + namedbt.size = strlen(name) + 1; + + if ((ret = __crdel_delete_log(dbenv, + dbp->open_txn, &newlsn, DB_FLUSH, + dbp->log_fileid, &namedbt)) != 0) { + __db_err(dbenv, + "%s: %s", name, db_strerror(ret)); + goto err; + } + } + + /* Find the real name of the file. */ + if ((ret = __db_appname(dbenv, + DB_APP_DATA, NULL, name, 0, NULL, &real_name)) != 0) + goto err; + + /* + * XXX + * We don't bother to open the file and call __memp_fremove on the mpf. + * There is a potential race here. It is at least possible that, if + * the unique filesystem ID (dev/inode pair on UNIX) is reallocated + * within a second (the granularity of the fileID timestamp), a new + * file open will get the same fileID as the file being "removed". + * We may actually want to open the file and call __memp_fremove on + * the mpf to get around this. + */ + + /* Create name for backup file. */ + if (TXN_ON(dbenv)) { + if ((ret = + __db_backup_name(dbenv, name, &backup, &newlsn)) != 0) + goto err; + if ((ret = __db_appname(dbenv, + DB_APP_DATA, NULL, backup, 0, NULL, &real_back)) != 0) + goto err; + } + + callback_func = __db_remove_callback; + cookie = real_back; + DB_TEST_RECOVERY(dbp, DB_TEST_PRERENAME, ret, name); + if (dbp->db_am_remove != NULL && + (ret = dbp->db_am_remove(dbp, + name, subdb, &newlsn, &callback_func, &cookie)) != 0) + goto err; + /* + * On Windows, the underlying file must be closed to perform a remove. + * Nothing later in __db_remove requires that it be open, and the + * dbp->close closes it anyway, so we just close it early. + */ + (void)__memp_fremove(dbp->mpf); + if ((ret = memp_fclose(dbp->mpf)) != 0) + goto err; + dbp->mpf = NULL; + + if (TXN_ON(dbenv)) + ret = __os_rename(dbenv, real_name, real_back); + else + ret = __os_unlink(dbenv, real_name); + + DB_TEST_RECOVERY(dbp, DB_TEST_POSTRENAME, ret, name); + +err: +DB_TEST_RECOVERY_LABEL + /* + * End the transaction, committing the transaction if we were + * successful, aborting otherwise. + */ + if (dbp->open_txn != NULL && (t_ret = __db_metaend(dbp, &remove_lock, + ret == 0, callback_func, cookie)) != 0 && ret == 0) + ret = t_ret; + + /* FALLTHROUGH */ + +err_close: + if (real_back != NULL) + __os_freestr(real_back); + if (real_name != NULL) + __os_freestr(real_name); + if (backup != NULL) + __os_freestr(backup); + + /* We no longer have an mpool, so syncing would be disastrous. */ + if ((t_ret = dbp->close(dbp, DB_NOSYNC)) != 0 && ret == 0) + ret = t_ret; + + return (ret); +} + +/* + * __db_subdb_remove -- + * Remove a subdatabase. + */ +static int +__db_subdb_remove(dbp, name, subdb) + DB *dbp; + const char *name, *subdb; +{ + DB *mdbp; + DBC *dbc; + DB_ENV *dbenv; + DB_LOCK remove_lock; + db_pgno_t meta_pgno; + int ret, t_ret; + + mdbp = NULL; + dbc = NULL; + dbenv = dbp->dbenv; + + /* Start the transaction. */ + if (TXN_ON(dbenv) && (ret = __db_metabegin(dbp, &remove_lock)) != 0) + goto err_close; + + /* + * Open the subdatabase. We can use the user's DB handle for this + * purpose, I think. + */ + if ((ret = __db_open(dbp, name, subdb, DB_UNKNOWN, 0, 0)) != 0) + goto err; + + /* Free up the pages in the subdatabase. */ + switch (dbp->type) { + case DB_BTREE: + case DB_RECNO: + if ((ret = __bam_reclaim(dbp, dbp->open_txn)) != 0) + goto err; + break; + case DB_HASH: + if ((ret = __ham_reclaim(dbp, dbp->open_txn)) != 0) + goto err; + break; + default: + ret = __db_unknown_type(dbp->dbenv, + "__db_subdb_remove", dbp->type); + goto err; + } + + /* + * Remove the entry from the main database and free the subdatabase + * metadata page. + */ + if ((ret = __db_master_open(dbp, name, 0, 0, &mdbp)) != 0) + goto err; + + if ((ret = __db_master_update(mdbp, + subdb, dbp->type, &meta_pgno, MU_REMOVE, NULL, 0)) != 0) + goto err; + +err: /* + * End the transaction, committing the transaction if we were + * successful, aborting otherwise. + */ + if (dbp->open_txn != NULL && (t_ret = __db_metaend(dbp, + &remove_lock, ret == 0, NULL, NULL)) != 0 && ret == 0) + ret = t_ret; + +err_close: + /* + * Close the user's DB handle -- do this LAST to avoid smashing the + * the transaction information. + */ + if ((t_ret = dbp->close(dbp, 0)) != 0 && ret == 0) + ret = t_ret; + + if (mdbp != NULL && (t_ret = mdbp->close(mdbp, 0)) != 0 && ret == 0) + ret = t_ret; + + return (ret); +} + +/* + * __db_rename + * Rename method for DB. + * + * PUBLIC: int __db_rename __P((DB *, + * PUBLIC: const char *, const char *, const char *, u_int32_t)); + */ +int +__db_rename(dbp, filename, subdb, newname, flags) + DB *dbp; + const char *filename, *subdb, *newname; + u_int32_t flags; +{ + DBT namedbt, newnamedbt; + DB_ENV *dbenv; + DB_LOCK remove_lock; + DB_LSN newlsn; + char *real_name, *real_newname; + int ret, t_ret; + + dbenv = dbp->dbenv; + ret = 0; + real_name = real_newname = NULL; + + PANIC_CHECK(dbenv); + /* + * Cannot use DB_ILLEGAL_AFTER_OPEN here because that returns + * and we cannot return, but must deal with the error and destroy + * the handle anyway. + */ + if (F_ISSET(dbp, DB_OPEN_CALLED)) { + ret = __db_mi_open(dbp->dbenv, "rename", 1); + goto err_close; + } + + /* Validate arguments -- has same rules as remove. */ + if ((ret = __db_removechk(dbp, flags)) != 0) + goto err_close; + + /* + * Subdatabases. + */ + if (subdb != NULL) { + if (filename == NULL) { + __db_err(dbenv, + "multiple databases cannot be created in temporary files"); + goto err_close; + } + return (__db_subdb_rename(dbp, filename, subdb, newname)); + } + + if ((ret = dbp->open(dbp, + filename, NULL, DB_UNKNOWN, DB_RDWRMASTER, 0)) != 0) + goto err_close; + + if (LOGGING_ON(dbenv) && (ret = __log_file_lock(dbp)) != 0) + goto err_close; + + if ((ret = dbp->sync(dbp, 0)) != 0) + goto err_close; + + /* Start the transaction and log the rename. */ + if (TXN_ON(dbenv) && (ret = __db_metabegin(dbp, &remove_lock)) != 0) + goto err_close; + + if (LOGGING_ON(dbenv)) { + memset(&namedbt, 0, sizeof(namedbt)); + namedbt.data = (char *)filename; + namedbt.size = strlen(filename) + 1; + + memset(&newnamedbt, 0, sizeof(namedbt)); + newnamedbt.data = (char *)newname; + newnamedbt.size = strlen(newname) + 1; + + if ((ret = __crdel_rename_log(dbenv, dbp->open_txn, + &newlsn, 0, dbp->log_fileid, &namedbt, &newnamedbt)) != 0) { + __db_err(dbenv, "%s: %s", filename, db_strerror(ret)); + goto err; + } + + if ((ret = __log_filelist_update(dbenv, dbp, + dbp->log_fileid, newname, NULL)) != 0) + goto err; + } + + /* Find the real name of the file. */ + if ((ret = __db_appname(dbenv, + DB_APP_DATA, NULL, filename, 0, NULL, &real_name)) != 0) + goto err; + + /* Find the real newname of the file. */ + if ((ret = __db_appname(dbenv, + DB_APP_DATA, NULL, newname, 0, NULL, &real_newname)) != 0) + goto err; + + /* + * It is an error to rename a file over one that already exists, + * as that wouldn't be transaction-safe. + */ + if (__os_exists(real_newname, NULL) == 0) { + ret = EEXIST; + __db_err(dbenv, "rename: file %s exists", real_newname); + goto err; + } + + DB_TEST_RECOVERY(dbp, DB_TEST_PRERENAME, ret, filename); + if (dbp->db_am_rename != NULL && + (ret = dbp->db_am_rename(dbp, filename, subdb, newname)) != 0) + goto err; + /* + * We have to flush the cache for a couple of reasons. First, the + * underlying MPOOLFILE maintains a "name" that unrelated processes + * can use to open the file in order to flush pages, and that name + * is about to be wrong. Second, on Windows the unique file ID is + * generated from the file's name, not other file information as is + * the case on UNIX, and so a subsequent open of the old file name + * could conceivably result in a matching "unique" file ID. + */ + if ((ret = __memp_fremove(dbp->mpf)) != 0) + goto err; + + /* + * On Windows, the underlying file must be closed to perform a rename. + * Nothing later in __db_rename requires that it be open, and the call + * to dbp->close closes it anyway, so we just close it early. + */ + if ((ret = memp_fclose(dbp->mpf)) != 0) + goto err; + dbp->mpf = NULL; + + ret = __os_rename(dbenv, real_name, real_newname); + DB_TEST_RECOVERY(dbp, DB_TEST_POSTRENAME, ret, newname); + +DB_TEST_RECOVERY_LABEL +err: if (dbp->open_txn != NULL && (t_ret = __db_metaend(dbp, + &remove_lock, ret == 0, NULL, NULL)) != 0 && ret == 0) + ret = t_ret; + +err_close: + /* We no longer have an mpool, so syncing would be disastrous. */ + dbp->close(dbp, DB_NOSYNC); + if (real_name != NULL) + __os_freestr(real_name); + if (real_newname != NULL) + __os_freestr(real_newname); + + return (ret); +} + +/* + * __db_subdb_rename -- + * Rename a subdatabase. + */ +static int +__db_subdb_rename(dbp, name, subdb, newname) + DB *dbp; + const char *name, *subdb, *newname; +{ + DB *mdbp; + DBC *dbc; + DB_ENV *dbenv; + DB_LOCK remove_lock; + int ret, t_ret; + + mdbp = NULL; + dbc = NULL; + dbenv = dbp->dbenv; + + /* Start the transaction. */ + if (TXN_ON(dbenv) && (ret = __db_metabegin(dbp, &remove_lock)) != 0) + goto err_close; + + /* + * Open the subdatabase. We can use the user's DB handle for this + * purpose, I think. + */ + if ((ret = __db_open(dbp, name, subdb, DB_UNKNOWN, 0, 0)) != 0) + goto err; + + /* + * Rename the entry in the main database. + */ + if ((ret = __db_master_open(dbp, name, 0, 0, &mdbp)) != 0) + goto err; + + if ((ret = __db_master_update(mdbp, + subdb, dbp->type, NULL, MU_RENAME, newname, 0)) != 0) + goto err; + +err: /* + * End the transaction, committing the transaction if we were + * successful, aborting otherwise. + */ + if (dbp->open_txn != NULL && (t_ret = __db_metaend(dbp, + &remove_lock, ret == 0, NULL, NULL)) != 0 && ret == 0) + ret = t_ret; + +err_close: + /* + * Close the user's DB handle -- do this LAST to avoid smashing the + * the transaction information. + */ + if ((t_ret = dbp->close(dbp, 0)) != 0 && ret == 0) + ret = t_ret; + + if (mdbp != NULL && (t_ret = mdbp->close(mdbp, 0)) != 0 && ret == 0) + ret = t_ret; + + return (ret); +} + +/* + * __db_metabegin -- + * + * Begin a meta-data operation. This involves doing any required locking, + * potentially beginning a transaction and then telling the caller if you + * did or did not begin the transaction. + * + * The writing flag indicates if the caller is actually allowing creates + * or doing deletes (i.e., if the caller is opening and not creating, then + * we don't need to do any of this). + * PUBLIC: int __db_metabegin __P((DB *, DB_LOCK *)); + */ +int +__db_metabegin(dbp, lockp) + DB *dbp; + DB_LOCK *lockp; +{ + DB_ENV *dbenv; + DBT dbplock; + u_int32_t locker, lockval; + int ret; + + dbenv = dbp->dbenv; + + lockp->off = LOCK_INVALID; + + /* + * There is no single place where we can know that we are or are not + * going to be creating any files and/or subdatabases, so we will + * always begin a tranasaction when we start creating one. If we later + * discover that this was unnecessary, we will abort the transaction. + * Recovery is written so that if we log a file create, but then + * discover that we didn't have to do it, we recover correctly. The + * file recovery design document has details. + * + * We need to single thread all create and delete operations, so if we + * are running with locking, we must obtain a lock. We use lock_id to + * generate a unique locker id and use a handcrafted DBT as the object + * on which we are locking. + */ + if (LOCKING_ON(dbenv)) { + if ((ret = lock_id(dbenv, &locker)) != 0) + return (ret); + lockval = 0; + dbplock.data = &lockval; + dbplock.size = sizeof(lockval); + if ((ret = lock_get(dbenv, + locker, 0, &dbplock, DB_LOCK_WRITE, lockp)) != 0) + return (ret); + } + + return (txn_begin(dbenv, NULL, &dbp->open_txn, 0)); +} + +/* + * __db_metaend -- + * End a meta-data operation. + * PUBLIC: int __db_metaend __P((DB *, + * PUBLIC: DB_LOCK *, int, int (*)(DB *, void *), void *)); + */ +int +__db_metaend(dbp, lockp, commit, callback, cookie) + DB *dbp; + DB_LOCK *lockp; + int commit, (*callback) __P((DB *, void *)); + void *cookie; +{ + DB_ENV *dbenv; + int ret, t_ret; + + ret = 0; + dbenv = dbp->dbenv; + + /* End the transaction. */ + if (commit) { + if ((ret = txn_commit(dbp->open_txn, DB_TXN_SYNC)) == 0) { + /* + * Unlink any underlying file, we've committed the + * transaction. + */ + if (callback != NULL) + ret = callback(dbp, cookie); + } + } else if ((t_ret = txn_abort(dbp->open_txn)) && ret == 0) + ret = t_ret; + + /* Release our lock. */ + if (lockp->off != LOCK_INVALID && + (t_ret = lock_put(dbenv, lockp)) != 0 && ret == 0) + ret = t_ret; + + return (ret); +} + +/* + * __db_log_page + * Log a meta-data or root page during a create operation. + * + * PUBLIC: int __db_log_page __P((DB *, + * PUBLIC: const char *, DB_LSN *, db_pgno_t, PAGE *)); + */ +int +__db_log_page(dbp, name, lsn, pgno, page) + DB *dbp; + const char *name; + DB_LSN *lsn; + db_pgno_t pgno; + PAGE *page; +{ + DBT name_dbt, page_dbt; + DB_LSN new_lsn; + int ret; + + if (dbp->open_txn == NULL) + return (0); + + memset(&page_dbt, 0, sizeof(page_dbt)); + page_dbt.size = dbp->pgsize; + page_dbt.data = page; + if (pgno == PGNO_BASE_MD) { + /* + * !!! + * Make sure that we properly handle a null name. The old + * Tcl sent us pathnames of the form ""; it may be the case + * that the new Tcl doesn't do that, so we can get rid of + * the second check here. + */ + memset(&name_dbt, 0, sizeof(name_dbt)); + name_dbt.data = (char *)name; + if (name == NULL || *name == '\0') + name_dbt.size = 0; + else + name_dbt.size = strlen(name) + 1; + + ret = __crdel_metapage_log(dbp->dbenv, + dbp->open_txn, &new_lsn, DB_FLUSH, + dbp->log_fileid, &name_dbt, pgno, &page_dbt); + } else + ret = __crdel_metasub_log(dbp->dbenv, dbp->open_txn, + &new_lsn, 0, dbp->log_fileid, pgno, &page_dbt, lsn); + + if (ret == 0) + page->lsn = new_lsn; + return (ret); +} + +/* + * __db_backup_name + * Create the backup file name for a given file. + * + * PUBLIC: int __db_backup_name __P((DB_ENV *, + * PUBLIC: const char *, char **, DB_LSN *)); + */ +#undef BACKUP_PREFIX +#define BACKUP_PREFIX "__db." + +#undef MAX_LSN_TO_TEXT +#define MAX_LSN_TO_TEXT 21 +int +__db_backup_name(dbenv, name, backup, lsn) + DB_ENV *dbenv; + const char *name; + char **backup; + DB_LSN *lsn; +{ + size_t len; + int plen, ret; + char *p, *retp; + + len = strlen(name) + strlen(BACKUP_PREFIX) + MAX_LSN_TO_TEXT + 1; + + if ((ret = __os_malloc(dbenv, len, NULL, &retp)) != 0) + return (ret); + + /* + * Create the name. Backup file names are of the form: + * + * __db.name.0x[lsn-file].0x[lsn-offset] + * + * which guarantees uniqueness. + * + * However, name may contain an env-relative path in it. + * In that case, put the __db. after the last portion of + * the pathname. + */ + if ((p = __db_rpath(name)) == NULL) + snprintf(retp, len, + "%s%s.0x%x0x%x", BACKUP_PREFIX, name, + lsn->file, lsn->offset); + else { + plen = p - name + 1; + p++; + snprintf(retp, len, + "%.*s%s%s.0x%x0x%x", plen, name, BACKUP_PREFIX, p, + lsn->file, lsn->offset); + } + + *backup = retp; + return (0); +} + +/* + * __db_remove_callback -- + * Callback function -- on file remove commit, it unlinks the backing + * file. + */ +static int +__db_remove_callback(dbp, cookie) + DB *dbp; + void *cookie; +{ + return (__os_unlink(dbp->dbenv, cookie)); +} + +/* + * __dblist_get -- + * Get the first element of dbenv->dblist with + * dbp->adj_fileid matching adjid. + * + * PUBLIC: DB *__dblist_get __P((DB_ENV *, u_int32_t)); + */ +DB * +__dblist_get(dbenv, adjid) + DB_ENV *dbenv; + u_int32_t adjid; +{ + DB *dbp; + + for (dbp = LIST_FIRST(&dbenv->dblist); + dbp != NULL && dbp->adj_fileid != adjid; + dbp = LIST_NEXT(dbp, dblistlinks)) + ; + + return (dbp); +} + +#if CONFIG_TEST +/* + * __db_testcopy + * Create a copy of all backup files and our "main" DB. + * + * PUBLIC: int __db_testcopy __P((DB *, const char *)); + */ +int +__db_testcopy(dbp, name) + DB *dbp; + const char *name; +{ + if (dbp->type == DB_QUEUE) + return (__qam_testdocopy(dbp, name)); + else + return (__db_testdocopy(dbp, name)); +} + +static int +__qam_testdocopy(dbp, name) + DB *dbp; + const char *name; +{ + QUEUE_FILELIST *filelist, *fp; + char buf[256], *dir; + int ret; + + filelist = NULL; + if ((ret = __db_testdocopy(dbp, name)) != 0) + return (ret); + if (dbp->mpf != NULL && + (ret = __qam_gen_filelist(dbp, &filelist)) != 0) + return (ret); + + if (filelist == NULL) + return (0); + dir = ((QUEUE *)dbp->q_internal)->dir; + for (fp = filelist; fp->mpf != NULL; fp++) { + snprintf(buf, sizeof(buf), QUEUE_EXTENT, dir, name, fp->id); + if ((ret = __db_testdocopy(dbp, buf)) != 0) + return (ret); + } + + __os_free(filelist, 0); + return (0); +} + +/* + * __db_testdocopy + * Create a copy of all backup files and our "main" DB. + * + */ +static int +__db_testdocopy(dbp, name) + DB *dbp; + const char *name; +{ + size_t len; + int dircnt, i, ret; + char **namesp, *backup, *copy, *dir, *p, *real_name; + real_name = NULL; + /* Get the real backing file name. */ + if ((ret = __db_appname(dbp->dbenv, + DB_APP_DATA, NULL, name, 0, NULL, &real_name)) != 0) + return (ret); + + copy = backup = NULL; + namesp = NULL; + + /* + * Maximum size of file, including adding a ".afterop". + */ + len = strlen(real_name) + strlen(BACKUP_PREFIX) + MAX_LSN_TO_TEXT + 9; + + if ((ret = __os_malloc(dbp->dbenv, len, NULL, ©)) != 0) + goto out; + + if ((ret = __os_malloc(dbp->dbenv, len, NULL, &backup)) != 0) + goto out; + + /* + * First copy the file itself. + */ + snprintf(copy, len, "%s.afterop", real_name); + __db_makecopy(real_name, copy); + + if ((ret = __os_strdup(dbp->dbenv, real_name, &dir)) != 0) + goto out; + __os_freestr(real_name); + real_name = NULL; + /* + * Create the name. Backup file names are of the form: + * + * __db.name.0x[lsn-file].0x[lsn-offset] + * + * which guarantees uniqueness. We want to look for the + * backup name, followed by a '.0x' (so that if they have + * files named, say, 'a' and 'abc' we won't match 'abc' when + * looking for 'a'. + */ + snprintf(backup, len, "%s%s.0x", BACKUP_PREFIX, name); + + /* + * We need the directory path to do the __os_dirlist. + */ + p = __db_rpath(dir); + if (p != NULL) + *p = '\0'; + ret = __os_dirlist(dbp->dbenv, dir, &namesp, &dircnt); +#if DIAGNOSTIC + /* + * XXX + * To get the memory guard code to work because it uses strlen and we + * just moved the end of the string somewhere sooner. This causes the + * guard code to fail because it looks at one byte past the end of the + * string. + */ + *p = '/'; +#endif + __os_freestr(dir); + if (ret != 0) + goto out; + for (i = 0; i < dircnt; i++) { + /* + * Need to check if it is a backup file for this. + * No idea what namesp[i] may be or how long, so + * must use strncmp and not memcmp. We don't want + * to use strcmp either because we are only matching + * the first part of the real file's name. We don't + * know its LSN's. + */ + if (strncmp(namesp[i], backup, strlen(backup)) == 0) { + if ((ret = __db_appname(dbp->dbenv, DB_APP_DATA, + NULL, namesp[i], 0, NULL, &real_name)) != 0) + goto out; + + /* + * This should not happen. Check that old + * .afterop files aren't around. + * If so, just move on. + */ + if (strstr(real_name, ".afterop") != NULL) { + __os_freestr(real_name); + real_name = NULL; + continue; + } + snprintf(copy, len, "%s.afterop", real_name); + __db_makecopy(real_name, copy); + __os_freestr(real_name); + real_name = NULL; + } + } +out: + if (backup != NULL) + __os_freestr(backup); + if (copy != NULL) + __os_freestr(copy); + if (namesp != NULL) + __os_dirfree(namesp, dircnt); + if (real_name != NULL) + __os_freestr(real_name); + return (ret); +} + +static void +__db_makecopy(src, dest) + const char *src, *dest; +{ + DB_FH rfh, wfh; + size_t rcnt, wcnt; + char *buf; + + memset(&rfh, 0, sizeof(rfh)); + memset(&wfh, 0, sizeof(wfh)); + + if (__os_malloc(NULL, 1024, NULL, &buf) != 0) + return; + + if (__os_open(NULL, + src, DB_OSO_RDONLY, __db_omode("rw----"), &rfh) != 0) + goto err; + if (__os_open(NULL, dest, + DB_OSO_CREATE | DB_OSO_TRUNC, __db_omode("rw----"), &wfh) != 0) + goto err; + + for (;;) + if (__os_read(NULL, &rfh, buf, 1024, &rcnt) < 0 || rcnt == 0 || + __os_write(NULL, &wfh, buf, rcnt, &wcnt) < 0 || wcnt != rcnt) + break; + +err: __os_free(buf, 1024); + if (F_ISSET(&rfh, DB_FH_VALID)) + __os_closehandle(&rfh); + if (F_ISSET(&wfh, DB_FH_VALID)) + __os_closehandle(&wfh); +} +#endif diff --git a/db/db/db.src b/db/db/db.src new file mode 100644 index 000000000..b695e1360 --- /dev/null +++ b/db/db/db.src @@ -0,0 +1,178 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: db.src,v 11.8 2000/02/17 20:24:07 bostic Exp $ + */ + +PREFIX db + +INCLUDE #include "db_config.h" +INCLUDE +INCLUDE #ifndef NO_SYSTEM_INCLUDES +INCLUDE #include +INCLUDE +INCLUDE #include +INCLUDE #include +INCLUDE #include +INCLUDE #endif +INCLUDE +INCLUDE #include "db_int.h" +INCLUDE #include "db_page.h" +INCLUDE #include "db_dispatch.h" +INCLUDE #include "db_am.h" +INCLUDE #include "txn.h" +INCLUDE + +/* + * addrem -- Add or remove an entry from a duplicate page. + * + * opcode: identifies if this is an add or delete. + * fileid: file identifier of the file being modified. + * pgno: duplicate page number. + * indx: location at which to insert or delete. + * nbytes: number of bytes added/removed to/from the page. + * hdr: header for the data item. + * dbt: data that is deleted or is to be added. + * pagelsn: former lsn of the page. + * + * If the hdr was NULL then, the dbt is a regular B_KEYDATA. + * If the dbt was NULL then the hdr is a complete item to be + * pasted on the page. + */ +BEGIN addrem 41 +ARG opcode u_int32_t lu +ARG fileid int32_t ld +ARG pgno db_pgno_t lu +ARG indx u_int32_t lu +ARG nbytes size_t lu +DBT hdr DBT s +DBT dbt DBT s +POINTER pagelsn DB_LSN * lu +END + +/* + * split -- Handles the split of a duplicate page. + * + * opcode: defines whether we are splitting from or splitting onto + * fileid: file identifier of the file being modified. + * pgno: page number being split. + * pageimage: entire page contents. + * pagelsn: former lsn of the page. + */ +DEPRECATED split 42 +ARG opcode u_int32_t lu +ARG fileid int32_t ld +ARG pgno db_pgno_t lu +DBT pageimage DBT s +POINTER pagelsn DB_LSN * lu +END + +/* + * big -- Handles addition and deletion of big key/data items. + * + * opcode: identifies get/put. + * fileid: file identifier of the file being modified. + * pgno: page onto which data is being added/removed. + * prev_pgno: the page before the one we are logging. + * next_pgno: the page after the one we are logging. + * dbt: data being written onto the page. + * pagelsn: former lsn of the orig_page. + * prevlsn: former lsn of the prev_pgno. + * nextlsn: former lsn of the next_pgno. This is not currently used, but + * may be used later if we actually do overwrites of big key/ + * data items in place. + */ +BEGIN big 43 +ARG opcode u_int32_t lu +ARG fileid int32_t ld +ARG pgno db_pgno_t lu +ARG prev_pgno db_pgno_t lu +ARG next_pgno db_pgno_t lu +DBT dbt DBT s +POINTER pagelsn DB_LSN * lu +POINTER prevlsn DB_LSN * lu +POINTER nextlsn DB_LSN * lu +END + +/* + * ovref -- Handles increment/decrement of overflow page reference count. + * + * fileid: identifies the file being modified. + * pgno: page number whose ref count is being incremented/decremented. + * adjust: the adjustment being made. + * lsn: the page's original lsn. + */ +BEGIN ovref 44 +ARG fileid int32_t ld +ARG pgno db_pgno_t lu +ARG adjust int32_t ld +POINTER lsn DB_LSN * lu +END + +/* + * relink -- Handles relinking around a page. + * + * opcode: indicates if this is an addpage or delete page + * pgno: the page being changed. + * lsn the page's original lsn. + * prev: the previous page. + * lsn_prev: the previous page's original lsn. + * next: the next page. + * lsn_next: the previous page's original lsn. + */ +BEGIN relink 45 +ARG opcode u_int32_t lu +ARG fileid int32_t ld +ARG pgno db_pgno_t lu +POINTER lsn DB_LSN * lu +ARG prev db_pgno_t lu +POINTER lsn_prev DB_LSN * lu +ARG next db_pgno_t lu +POINTER lsn_next DB_LSN * lu +END + +/* + * Addpage -- Handles adding a new duplicate page onto the end of + * an existing duplicate page. + * fileid: identifies the file being changed. + * pgno: page number to which a new page is being added. + * lsn: lsn of pgno + * nextpgno: new page number being added. + * nextlsn: lsn of nextpgno; + */ +DEPRECATED addpage 46 +ARG fileid int32_t ld +ARG pgno db_pgno_t lu +POINTER lsn DB_LSN * lu +ARG nextpgno db_pgno_t lu +POINTER nextlsn DB_LSN * lu +END + +/* + * Debug -- log an operation upon entering an access method. + * op: Operation (cursor, c_close, c_get, c_put, c_del, + * get, put, delete). + * fileid: identifies the file being acted upon. + * key: key paramater + * data: data parameter + * flags: flags parameter + */ +BEGIN debug 47 +DBT op DBT s +ARG fileid int32_t ld +DBT key DBT s +DBT data DBT s +ARG arg_flags u_int32_t lu +END + +/* + * noop -- do nothing, but get an LSN. + */ +BEGIN noop 48 +ARG fileid int32_t ld +ARG pgno db_pgno_t lu +POINTER prevlsn DB_LSN * lu +END diff --git a/db/db/db_am.c b/db/db/db_am.c new file mode 100644 index 000000000..2d2245669 --- /dev/null +++ b/db/db/db_am.c @@ -0,0 +1,511 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: db_am.c,v 11.42 2001/01/11 18:19:50 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_shash.h" +#include "btree.h" +#include "hash.h" +#include "qam.h" +#include "lock.h" +#include "mp.h" +#include "txn.h" +#include "db_am.h" +#include "db_ext.h" + +/* + * __db_cursor -- + * Allocate and return a cursor. + * + * PUBLIC: int __db_cursor __P((DB *, DB_TXN *, DBC **, u_int32_t)); + */ +int +__db_cursor(dbp, txn, dbcp, flags) + DB *dbp; + DB_TXN *txn; + DBC **dbcp; + u_int32_t flags; +{ + DB_ENV *dbenv; + DBC *dbc; + db_lockmode_t mode; + u_int32_t op; + int ret; + + dbenv = dbp->dbenv; + + PANIC_CHECK(dbenv); + DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->cursor"); + + /* Check for invalid flags. */ + if ((ret = __db_cursorchk(dbp, flags, F_ISSET(dbp, DB_AM_RDONLY))) != 0) + return (ret); + + if ((ret = + __db_icursor(dbp, txn, dbp->type, PGNO_INVALID, 0, dbcp)) != 0) + return (ret); + dbc = *dbcp; + + /* + * If this is CDB, do all the locking in the interface, which is + * right here. + */ + if (CDB_LOCKING(dbenv)) { + op = LF_ISSET(DB_OPFLAGS_MASK); + mode = (op == DB_WRITELOCK) ? DB_LOCK_WRITE : + ((op == DB_WRITECURSOR) ? DB_LOCK_IWRITE : DB_LOCK_READ); + if ((ret = lock_get(dbenv, dbc->locker, 0, + &dbc->lock_dbt, mode, &dbc->mylock)) != 0) { + (void)__db_c_close(dbc); + return (ret); + } + if (op == DB_WRITECURSOR) + F_SET(dbc, DBC_WRITECURSOR); + if (op == DB_WRITELOCK) + F_SET(dbc, DBC_WRITER); + } + + return (0); +} + +/* + * __db_icursor -- + * Internal version of __db_cursor. If dbcp is + * non-NULL it is assumed to point to an area to + * initialize as a cursor. + * + * PUBLIC: int __db_icursor + * PUBLIC: __P((DB *, DB_TXN *, DBTYPE, db_pgno_t, int, DBC **)); + */ +int +__db_icursor(dbp, txn, dbtype, root, is_opd, dbcp) + DB *dbp; + DB_TXN *txn; + DBTYPE dbtype; + db_pgno_t root; + int is_opd; + DBC **dbcp; +{ + DBC *dbc, *adbc; + DBC_INTERNAL *cp; + DB_ENV *dbenv; + int allocated, ret; + + dbenv = dbp->dbenv; + allocated = 0; + + /* + * Take one from the free list if it's available. Take only the + * right type. With off page dups we may have different kinds + * of cursors on the queue for a single database. + */ + MUTEX_THREAD_LOCK(dbenv, dbp->mutexp); + for (dbc = TAILQ_FIRST(&dbp->free_queue); + dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) + if (dbtype == dbc->dbtype) { + TAILQ_REMOVE(&dbp->free_queue, dbc, links); + dbc->flags = 0; + break; + } + MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp); + + if (dbc == NULL) { + if ((ret = __os_calloc(dbp->dbenv, 1, sizeof(DBC), &dbc)) != 0) + return (ret); + allocated = 1; + dbc->flags = 0; + + dbc->dbp = dbp; + + /* Set up locking information. */ + if (LOCKING_ON(dbenv)) { + /* + * If we are not threaded, then there is no need to + * create new locker ids. We know that no one else + * is running concurrently using this DB, so we can + * take a peek at any cursors on the active queue. + */ + if (!DB_IS_THREADED(dbp) && + (adbc = TAILQ_FIRST(&dbp->active_queue)) != NULL) + dbc->lid = adbc->lid; + else + if ((ret = lock_id(dbenv, &dbc->lid)) != 0) + goto err; + + memcpy(dbc->lock.fileid, dbp->fileid, DB_FILE_ID_LEN); + if (CDB_LOCKING(dbenv)) { + if (F_ISSET(dbenv, DB_ENV_CDB_ALLDB)) { + /* + * If we are doing a single lock per + * environment, set up the global + * lock object just like we do to + * single thread creates. + */ + DB_ASSERT(sizeof(db_pgno_t) == + sizeof(u_int32_t)); + dbc->lock_dbt.size = sizeof(u_int32_t); + dbc->lock_dbt.data = &dbc->lock.pgno; + dbc->lock.pgno = 0; + } else { + dbc->lock_dbt.size = DB_FILE_ID_LEN; + dbc->lock_dbt.data = dbc->lock.fileid; + } + } else { + dbc->lock.type = DB_PAGE_LOCK; + dbc->lock_dbt.size = sizeof(dbc->lock); + dbc->lock_dbt.data = &dbc->lock; + } + } + /* Init the DBC internal structure. */ + switch (dbtype) { + case DB_BTREE: + case DB_RECNO: + if ((ret = __bam_c_init(dbc, dbtype)) != 0) + goto err; + break; + case DB_HASH: + if ((ret = __ham_c_init(dbc)) != 0) + goto err; + break; + case DB_QUEUE: + if ((ret = __qam_c_init(dbc)) != 0) + goto err; + break; + default: + ret = __db_unknown_type(dbp->dbenv, + "__db_icursor", dbtype); + goto err; + } + + cp = dbc->internal; + } + + /* Refresh the DBC structure. */ + dbc->dbtype = dbtype; + + if ((dbc->txn = txn) == NULL) + dbc->locker = dbc->lid; + else { + dbc->locker = txn->txnid; + txn->cursors++; + } + + if (is_opd) + F_SET(dbc, DBC_OPD); + if (F_ISSET(dbp, DB_AM_RECOVER)) + F_SET(dbc, DBC_RECOVER); + + /* Refresh the DBC internal structure. */ + cp = dbc->internal; + cp->opd = NULL; + + cp->indx = 0; + cp->page = NULL; + cp->pgno = PGNO_INVALID; + cp->root = root; + + switch (dbtype) { + case DB_BTREE: + case DB_RECNO: + if ((ret = __bam_c_refresh(dbc)) != 0) + goto err; + break; + case DB_HASH: + case DB_QUEUE: + break; + default: + ret = __db_unknown_type(dbp->dbenv, "__db_icursor", dbp->type); + goto err; + } + + MUTEX_THREAD_LOCK(dbenv, dbp->mutexp); + TAILQ_INSERT_TAIL(&dbp->active_queue, dbc, links); + F_SET(dbc, DBC_ACTIVE); + MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp); + + *dbcp = dbc; + return (0); + +err: if (allocated) + __os_free(dbc, sizeof(*dbc)); + return (ret); +} + +#ifdef DEBUG +/* + * __db_cprint -- + * Display the current cursor list. + * + * PUBLIC: int __db_cprint __P((DB *)); + */ +int +__db_cprint(dbp) + DB *dbp; +{ + static const FN fn[] = { + { DBC_ACTIVE, "active" }, + { DBC_OPD, "off-page-dup" }, + { DBC_RECOVER, "recover" }, + { DBC_RMW, "read-modify-write" }, + { DBC_WRITECURSOR, "write cursor" }, + { DBC_WRITEDUP, "internally dup'ed write cursor" }, + { DBC_WRITER, "short-term write cursor" }, + { 0, NULL } + }; + DBC *dbc; + DBC_INTERNAL *cp; + char *s; + + MUTEX_THREAD_LOCK(dbp->dbenv, dbp->mutexp); + for (dbc = TAILQ_FIRST(&dbp->active_queue); + dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) { + switch (dbc->dbtype) { + case DB_BTREE: + s = "btree"; + break; + case DB_HASH: + s = "hash"; + break; + case DB_RECNO: + s = "recno"; + break; + case DB_QUEUE: + s = "queue"; + break; + default: + DB_ASSERT(0); + return (1); + } + cp = dbc->internal; + fprintf(stderr, "%s/%#0lx: opd: %#0lx\n", + s, P_TO_ULONG(dbc), P_TO_ULONG(cp->opd)); + fprintf(stderr, "\ttxn: %#0lx lid: %lu locker: %lu\n", + P_TO_ULONG(dbc->txn), + (u_long)dbc->lid, (u_long)dbc->locker); + fprintf(stderr, "\troot: %lu page/index: %lu/%lu", + (u_long)cp->root, (u_long)cp->pgno, (u_long)cp->indx); + __db_prflags(dbc->flags, fn, stderr); + fprintf(stderr, "\n"); + + if (dbp->type == DB_BTREE) + __bam_cprint(dbc); + } + for (dbc = TAILQ_FIRST(&dbp->free_queue); + dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) + fprintf(stderr, "free: %#0lx ", P_TO_ULONG(dbc)); + fprintf(stderr, "\n"); + MUTEX_THREAD_UNLOCK(dbp->dbenv, dbp->mutexp); + + return (0); +} +#endif /* DEBUG */ + +/* + * db_fd -- + * Return a file descriptor for flock'ing. + * + * PUBLIC: int __db_fd __P((DB *, int *)); + */ +int +__db_fd(dbp, fdp) + DB *dbp; + int *fdp; +{ + DB_FH *fhp; + int ret; + + PANIC_CHECK(dbp->dbenv); + DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->fd"); + + /* + * XXX + * Truly spectacular layering violation. + */ + if ((ret = __mp_xxx_fh(dbp->mpf, &fhp)) != 0) + return (ret); + + if (F_ISSET(fhp, DB_FH_VALID)) { + *fdp = fhp->fd; + return (0); + } else { + *fdp = -1; + __db_err(dbp->dbenv, "DB does not have a valid file handle."); + return (ENOENT); + } +} + +/* + * __db_get -- + * Return a key/data pair. + * + * PUBLIC: int __db_get __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t)); + */ +int +__db_get(dbp, txn, key, data, flags) + DB *dbp; + DB_TXN *txn; + DBT *key, *data; + u_int32_t flags; +{ + DBC *dbc; + int mode, ret, t_ret; + + PANIC_CHECK(dbp->dbenv); + DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->get"); + + if ((ret = __db_getchk(dbp, key, data, flags)) != 0) + return (ret); + + mode = 0; + if (flags == DB_CONSUME || flags == DB_CONSUME_WAIT) + mode = DB_WRITELOCK; + if ((ret = dbp->cursor(dbp, txn, &dbc, mode)) != 0) + return (ret); + + DEBUG_LREAD(dbc, txn, "__db_get", key, NULL, flags); + + /* + * The DBC_TRANSIENT flag indicates that we're just doing a + * single operation with this cursor, and that in case of + * error we don't need to restore it to its old position--we're + * going to close it right away. Thus, we can perform the get + * without duplicating the cursor, saving some cycles in this + * common case. + */ + F_SET(dbc, DBC_TRANSIENT); + + ret = dbc->c_get(dbc, key, data, + flags == 0 || flags == DB_RMW ? flags | DB_SET : flags); + + if ((t_ret = __db_c_close(dbc)) != 0 && ret == 0) + ret = t_ret; + + return (ret); +} + +/* + * __db_put -- + * Store a key/data pair. + * + * PUBLIC: int __db_put __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t)); + */ +int +__db_put(dbp, txn, key, data, flags) + DB *dbp; + DB_TXN *txn; + DBT *key, *data; + u_int32_t flags; +{ + DBC *dbc; + DBT tdata; + int ret, t_ret; + + PANIC_CHECK(dbp->dbenv); + DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->put"); + + if ((ret = __db_putchk(dbp, key, data, + flags, F_ISSET(dbp, DB_AM_RDONLY), + F_ISSET(dbp, DB_AM_DUP) || F_ISSET(key, DB_DBT_DUPOK))) != 0) + return (ret); + + DB_CHECK_TXN(dbp, txn); + + if ((ret = dbp->cursor(dbp, txn, &dbc, DB_WRITELOCK)) != 0) + return (ret); + + /* + * See the comment in __db_get(). + * + * Note that the c_get in the DB_NOOVERWRITE case is safe to + * do with this flag set; if it errors in any way other than + * DB_NOTFOUND, we're going to close the cursor without doing + * anything else, and if it returns DB_NOTFOUND then it's safe + * to do a c_put(DB_KEYLAST) even if an access method moved the + * cursor, since that's not position-dependent. + */ + F_SET(dbc, DBC_TRANSIENT); + + DEBUG_LWRITE(dbc, txn, "__db_put", key, data, flags); + + if (flags == DB_NOOVERWRITE) { + flags = 0; + /* + * Set DB_DBT_USERMEM, this might be a threaded application and + * the flags checking will catch us. We don't want the actual + * data, so request a partial of length 0. + */ + memset(&tdata, 0, sizeof(tdata)); + F_SET(&tdata, DB_DBT_USERMEM | DB_DBT_PARTIAL); + + /* + * If we're doing page-level locking, set the read-modify-write + * flag, we're going to overwrite immediately. + */ + if ((ret = dbc->c_get(dbc, key, &tdata, + DB_SET | (STD_LOCKING(dbc) ? DB_RMW : 0))) == 0) + ret = DB_KEYEXIST; + else if (ret == DB_NOTFOUND) + ret = 0; + } + if (ret == 0) + ret = dbc->c_put(dbc, + key, data, flags == 0 ? DB_KEYLAST : flags); + + if ((t_ret = __db_c_close(dbc)) != 0 && ret == 0) + ret = t_ret; + + return (ret); +} + +/* + * __db_sync -- + * Flush the database cache. + * + * PUBLIC: int __db_sync __P((DB *, u_int32_t)); + */ +int +__db_sync(dbp, flags) + DB *dbp; + u_int32_t flags; +{ + int ret, t_ret; + + PANIC_CHECK(dbp->dbenv); + DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->sync"); + + if ((ret = __db_syncchk(dbp, flags)) != 0) + return (ret); + + /* Read-only trees never need to be sync'd. */ + if (F_ISSET(dbp, DB_AM_RDONLY)) + return (0); + + /* If it's a Recno tree, write the backing source text file. */ + if (dbp->type == DB_RECNO) + ret = __ram_writeback(dbp); + + /* If the tree was never backed by a database file, we're done. */ + if (F_ISSET(dbp, DB_AM_INMEM)) + return (0); + + /* Flush any dirty pages from the cache to the backing file. */ + if ((t_ret = memp_fsync(dbp->mpf)) != 0 && ret == 0) + ret = t_ret; + return (ret); +} diff --git a/db/db/db_auto.c b/db/db/db_auto.c new file mode 100644 index 000000000..23540adc2 --- /dev/null +++ b/db/db/db_auto.c @@ -0,0 +1,1270 @@ +/* Do not edit: automatically built by gen_rec.awk. */ +#include "db_config.h" + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_dispatch.h" +#include "db_am.h" +#include "txn.h" + +int +__db_addrem_log(dbenv, txnid, ret_lsnp, flags, + opcode, fileid, pgno, indx, nbytes, hdr, + dbt, pagelsn) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + u_int32_t opcode; + int32_t fileid; + db_pgno_t pgno; + u_int32_t indx; + size_t nbytes; + const DBT *hdr; + const DBT *dbt; + DB_LSN * pagelsn; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t zero; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_db_addrem; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(opcode) + + sizeof(fileid) + + sizeof(pgno) + + sizeof(indx) + + sizeof(nbytes) + + sizeof(u_int32_t) + (hdr == NULL ? 0 : hdr->size) + + sizeof(u_int32_t) + (dbt == NULL ? 0 : dbt->size) + + sizeof(*pagelsn); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &opcode, sizeof(opcode)); + bp += sizeof(opcode); + memcpy(bp, &fileid, sizeof(fileid)); + bp += sizeof(fileid); + memcpy(bp, &pgno, sizeof(pgno)); + bp += sizeof(pgno); + memcpy(bp, &indx, sizeof(indx)); + bp += sizeof(indx); + memcpy(bp, &nbytes, sizeof(nbytes)); + bp += sizeof(nbytes); + if (hdr == NULL) { + zero = 0; + memcpy(bp, &zero, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + } else { + memcpy(bp, &hdr->size, sizeof(hdr->size)); + bp += sizeof(hdr->size); + memcpy(bp, hdr->data, hdr->size); + bp += hdr->size; + } + if (dbt == NULL) { + zero = 0; + memcpy(bp, &zero, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + } else { + memcpy(bp, &dbt->size, sizeof(dbt->size)); + bp += sizeof(dbt->size); + memcpy(bp, dbt->data, dbt->size); + bp += dbt->size; + } + if (pagelsn != NULL) + memcpy(bp, pagelsn, sizeof(*pagelsn)); + else + memset(bp, 0, sizeof(*pagelsn)); + bp += sizeof(*pagelsn); + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__db_addrem_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __db_addrem_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __db_addrem_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]db_addrem: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\topcode: %lu\n", (u_long)argp->opcode); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tpgno: %lu\n", (u_long)argp->pgno); + printf("\tindx: %lu\n", (u_long)argp->indx); + printf("\tnbytes: %lu\n", (u_long)argp->nbytes); + printf("\thdr: "); + for (i = 0; i < argp->hdr.size; i++) { + ch = ((u_int8_t *)argp->hdr.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\tdbt: "); + for (i = 0; i < argp->dbt.size; i++) { + ch = ((u_int8_t *)argp->dbt.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\tpagelsn: [%lu][%lu]\n", + (u_long)argp->pagelsn.file, (u_long)argp->pagelsn.offset); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__db_addrem_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __db_addrem_args **argpp; +{ + __db_addrem_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__db_addrem_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->opcode, bp, sizeof(argp->opcode)); + bp += sizeof(argp->opcode); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->pgno, bp, sizeof(argp->pgno)); + bp += sizeof(argp->pgno); + memcpy(&argp->indx, bp, sizeof(argp->indx)); + bp += sizeof(argp->indx); + memcpy(&argp->nbytes, bp, sizeof(argp->nbytes)); + bp += sizeof(argp->nbytes); + memset(&argp->hdr, 0, sizeof(argp->hdr)); + memcpy(&argp->hdr.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->hdr.data = bp; + bp += argp->hdr.size; + memset(&argp->dbt, 0, sizeof(argp->dbt)); + memcpy(&argp->dbt.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->dbt.data = bp; + bp += argp->dbt.size; + memcpy(&argp->pagelsn, bp, sizeof(argp->pagelsn)); + bp += sizeof(argp->pagelsn); + *argpp = argp; + return (0); +} + +int +__db_split_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __db_split_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __db_split_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]db_split: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\topcode: %lu\n", (u_long)argp->opcode); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tpgno: %lu\n", (u_long)argp->pgno); + printf("\tpageimage: "); + for (i = 0; i < argp->pageimage.size; i++) { + ch = ((u_int8_t *)argp->pageimage.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\tpagelsn: [%lu][%lu]\n", + (u_long)argp->pagelsn.file, (u_long)argp->pagelsn.offset); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__db_split_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __db_split_args **argpp; +{ + __db_split_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__db_split_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->opcode, bp, sizeof(argp->opcode)); + bp += sizeof(argp->opcode); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->pgno, bp, sizeof(argp->pgno)); + bp += sizeof(argp->pgno); + memset(&argp->pageimage, 0, sizeof(argp->pageimage)); + memcpy(&argp->pageimage.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->pageimage.data = bp; + bp += argp->pageimage.size; + memcpy(&argp->pagelsn, bp, sizeof(argp->pagelsn)); + bp += sizeof(argp->pagelsn); + *argpp = argp; + return (0); +} + +int +__db_big_log(dbenv, txnid, ret_lsnp, flags, + opcode, fileid, pgno, prev_pgno, next_pgno, dbt, + pagelsn, prevlsn, nextlsn) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + u_int32_t opcode; + int32_t fileid; + db_pgno_t pgno; + db_pgno_t prev_pgno; + db_pgno_t next_pgno; + const DBT *dbt; + DB_LSN * pagelsn; + DB_LSN * prevlsn; + DB_LSN * nextlsn; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t zero; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_db_big; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(opcode) + + sizeof(fileid) + + sizeof(pgno) + + sizeof(prev_pgno) + + sizeof(next_pgno) + + sizeof(u_int32_t) + (dbt == NULL ? 0 : dbt->size) + + sizeof(*pagelsn) + + sizeof(*prevlsn) + + sizeof(*nextlsn); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &opcode, sizeof(opcode)); + bp += sizeof(opcode); + memcpy(bp, &fileid, sizeof(fileid)); + bp += sizeof(fileid); + memcpy(bp, &pgno, sizeof(pgno)); + bp += sizeof(pgno); + memcpy(bp, &prev_pgno, sizeof(prev_pgno)); + bp += sizeof(prev_pgno); + memcpy(bp, &next_pgno, sizeof(next_pgno)); + bp += sizeof(next_pgno); + if (dbt == NULL) { + zero = 0; + memcpy(bp, &zero, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + } else { + memcpy(bp, &dbt->size, sizeof(dbt->size)); + bp += sizeof(dbt->size); + memcpy(bp, dbt->data, dbt->size); + bp += dbt->size; + } + if (pagelsn != NULL) + memcpy(bp, pagelsn, sizeof(*pagelsn)); + else + memset(bp, 0, sizeof(*pagelsn)); + bp += sizeof(*pagelsn); + if (prevlsn != NULL) + memcpy(bp, prevlsn, sizeof(*prevlsn)); + else + memset(bp, 0, sizeof(*prevlsn)); + bp += sizeof(*prevlsn); + if (nextlsn != NULL) + memcpy(bp, nextlsn, sizeof(*nextlsn)); + else + memset(bp, 0, sizeof(*nextlsn)); + bp += sizeof(*nextlsn); + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__db_big_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __db_big_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __db_big_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]db_big: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\topcode: %lu\n", (u_long)argp->opcode); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tpgno: %lu\n", (u_long)argp->pgno); + printf("\tprev_pgno: %lu\n", (u_long)argp->prev_pgno); + printf("\tnext_pgno: %lu\n", (u_long)argp->next_pgno); + printf("\tdbt: "); + for (i = 0; i < argp->dbt.size; i++) { + ch = ((u_int8_t *)argp->dbt.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\tpagelsn: [%lu][%lu]\n", + (u_long)argp->pagelsn.file, (u_long)argp->pagelsn.offset); + printf("\tprevlsn: [%lu][%lu]\n", + (u_long)argp->prevlsn.file, (u_long)argp->prevlsn.offset); + printf("\tnextlsn: [%lu][%lu]\n", + (u_long)argp->nextlsn.file, (u_long)argp->nextlsn.offset); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__db_big_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __db_big_args **argpp; +{ + __db_big_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__db_big_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->opcode, bp, sizeof(argp->opcode)); + bp += sizeof(argp->opcode); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->pgno, bp, sizeof(argp->pgno)); + bp += sizeof(argp->pgno); + memcpy(&argp->prev_pgno, bp, sizeof(argp->prev_pgno)); + bp += sizeof(argp->prev_pgno); + memcpy(&argp->next_pgno, bp, sizeof(argp->next_pgno)); + bp += sizeof(argp->next_pgno); + memset(&argp->dbt, 0, sizeof(argp->dbt)); + memcpy(&argp->dbt.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->dbt.data = bp; + bp += argp->dbt.size; + memcpy(&argp->pagelsn, bp, sizeof(argp->pagelsn)); + bp += sizeof(argp->pagelsn); + memcpy(&argp->prevlsn, bp, sizeof(argp->prevlsn)); + bp += sizeof(argp->prevlsn); + memcpy(&argp->nextlsn, bp, sizeof(argp->nextlsn)); + bp += sizeof(argp->nextlsn); + *argpp = argp; + return (0); +} + +int +__db_ovref_log(dbenv, txnid, ret_lsnp, flags, + fileid, pgno, adjust, lsn) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + int32_t fileid; + db_pgno_t pgno; + int32_t adjust; + DB_LSN * lsn; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_db_ovref; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(fileid) + + sizeof(pgno) + + sizeof(adjust) + + sizeof(*lsn); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &fileid, sizeof(fileid)); + bp += sizeof(fileid); + memcpy(bp, &pgno, sizeof(pgno)); + bp += sizeof(pgno); + memcpy(bp, &adjust, sizeof(adjust)); + bp += sizeof(adjust); + if (lsn != NULL) + memcpy(bp, lsn, sizeof(*lsn)); + else + memset(bp, 0, sizeof(*lsn)); + bp += sizeof(*lsn); + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__db_ovref_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __db_ovref_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __db_ovref_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]db_ovref: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tpgno: %lu\n", (u_long)argp->pgno); + printf("\tadjust: %ld\n", (long)argp->adjust); + printf("\tlsn: [%lu][%lu]\n", + (u_long)argp->lsn.file, (u_long)argp->lsn.offset); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__db_ovref_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __db_ovref_args **argpp; +{ + __db_ovref_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__db_ovref_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->pgno, bp, sizeof(argp->pgno)); + bp += sizeof(argp->pgno); + memcpy(&argp->adjust, bp, sizeof(argp->adjust)); + bp += sizeof(argp->adjust); + memcpy(&argp->lsn, bp, sizeof(argp->lsn)); + bp += sizeof(argp->lsn); + *argpp = argp; + return (0); +} + +int +__db_relink_log(dbenv, txnid, ret_lsnp, flags, + opcode, fileid, pgno, lsn, prev, lsn_prev, + next, lsn_next) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + u_int32_t opcode; + int32_t fileid; + db_pgno_t pgno; + DB_LSN * lsn; + db_pgno_t prev; + DB_LSN * lsn_prev; + db_pgno_t next; + DB_LSN * lsn_next; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_db_relink; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(opcode) + + sizeof(fileid) + + sizeof(pgno) + + sizeof(*lsn) + + sizeof(prev) + + sizeof(*lsn_prev) + + sizeof(next) + + sizeof(*lsn_next); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &opcode, sizeof(opcode)); + bp += sizeof(opcode); + memcpy(bp, &fileid, sizeof(fileid)); + bp += sizeof(fileid); + memcpy(bp, &pgno, sizeof(pgno)); + bp += sizeof(pgno); + if (lsn != NULL) + memcpy(bp, lsn, sizeof(*lsn)); + else + memset(bp, 0, sizeof(*lsn)); + bp += sizeof(*lsn); + memcpy(bp, &prev, sizeof(prev)); + bp += sizeof(prev); + if (lsn_prev != NULL) + memcpy(bp, lsn_prev, sizeof(*lsn_prev)); + else + memset(bp, 0, sizeof(*lsn_prev)); + bp += sizeof(*lsn_prev); + memcpy(bp, &next, sizeof(next)); + bp += sizeof(next); + if (lsn_next != NULL) + memcpy(bp, lsn_next, sizeof(*lsn_next)); + else + memset(bp, 0, sizeof(*lsn_next)); + bp += sizeof(*lsn_next); + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__db_relink_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __db_relink_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __db_relink_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]db_relink: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\topcode: %lu\n", (u_long)argp->opcode); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tpgno: %lu\n", (u_long)argp->pgno); + printf("\tlsn: [%lu][%lu]\n", + (u_long)argp->lsn.file, (u_long)argp->lsn.offset); + printf("\tprev: %lu\n", (u_long)argp->prev); + printf("\tlsn_prev: [%lu][%lu]\n", + (u_long)argp->lsn_prev.file, (u_long)argp->lsn_prev.offset); + printf("\tnext: %lu\n", (u_long)argp->next); + printf("\tlsn_next: [%lu][%lu]\n", + (u_long)argp->lsn_next.file, (u_long)argp->lsn_next.offset); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__db_relink_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __db_relink_args **argpp; +{ + __db_relink_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__db_relink_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->opcode, bp, sizeof(argp->opcode)); + bp += sizeof(argp->opcode); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->pgno, bp, sizeof(argp->pgno)); + bp += sizeof(argp->pgno); + memcpy(&argp->lsn, bp, sizeof(argp->lsn)); + bp += sizeof(argp->lsn); + memcpy(&argp->prev, bp, sizeof(argp->prev)); + bp += sizeof(argp->prev); + memcpy(&argp->lsn_prev, bp, sizeof(argp->lsn_prev)); + bp += sizeof(argp->lsn_prev); + memcpy(&argp->next, bp, sizeof(argp->next)); + bp += sizeof(argp->next); + memcpy(&argp->lsn_next, bp, sizeof(argp->lsn_next)); + bp += sizeof(argp->lsn_next); + *argpp = argp; + return (0); +} + +int +__db_addpage_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __db_addpage_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __db_addpage_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]db_addpage: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tpgno: %lu\n", (u_long)argp->pgno); + printf("\tlsn: [%lu][%lu]\n", + (u_long)argp->lsn.file, (u_long)argp->lsn.offset); + printf("\tnextpgno: %lu\n", (u_long)argp->nextpgno); + printf("\tnextlsn: [%lu][%lu]\n", + (u_long)argp->nextlsn.file, (u_long)argp->nextlsn.offset); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__db_addpage_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __db_addpage_args **argpp; +{ + __db_addpage_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__db_addpage_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->pgno, bp, sizeof(argp->pgno)); + bp += sizeof(argp->pgno); + memcpy(&argp->lsn, bp, sizeof(argp->lsn)); + bp += sizeof(argp->lsn); + memcpy(&argp->nextpgno, bp, sizeof(argp->nextpgno)); + bp += sizeof(argp->nextpgno); + memcpy(&argp->nextlsn, bp, sizeof(argp->nextlsn)); + bp += sizeof(argp->nextlsn); + *argpp = argp; + return (0); +} + +int +__db_debug_log(dbenv, txnid, ret_lsnp, flags, + op, fileid, key, data, arg_flags) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + const DBT *op; + int32_t fileid; + const DBT *key; + const DBT *data; + u_int32_t arg_flags; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t zero; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_db_debug; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(u_int32_t) + (op == NULL ? 0 : op->size) + + sizeof(fileid) + + sizeof(u_int32_t) + (key == NULL ? 0 : key->size) + + sizeof(u_int32_t) + (data == NULL ? 0 : data->size) + + sizeof(arg_flags); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + if (op == NULL) { + zero = 0; + memcpy(bp, &zero, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + } else { + memcpy(bp, &op->size, sizeof(op->size)); + bp += sizeof(op->size); + memcpy(bp, op->data, op->size); + bp += op->size; + } + memcpy(bp, &fileid, sizeof(fileid)); + bp += sizeof(fileid); + if (key == NULL) { + zero = 0; + memcpy(bp, &zero, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + } else { + memcpy(bp, &key->size, sizeof(key->size)); + bp += sizeof(key->size); + memcpy(bp, key->data, key->size); + bp += key->size; + } + if (data == NULL) { + zero = 0; + memcpy(bp, &zero, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + } else { + memcpy(bp, &data->size, sizeof(data->size)); + bp += sizeof(data->size); + memcpy(bp, data->data, data->size); + bp += data->size; + } + memcpy(bp, &arg_flags, sizeof(arg_flags)); + bp += sizeof(arg_flags); + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__db_debug_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __db_debug_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __db_debug_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]db_debug: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\top: "); + for (i = 0; i < argp->op.size; i++) { + ch = ((u_int8_t *)argp->op.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tkey: "); + for (i = 0; i < argp->key.size; i++) { + ch = ((u_int8_t *)argp->key.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\tdata: "); + for (i = 0; i < argp->data.size; i++) { + ch = ((u_int8_t *)argp->data.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\targ_flags: %lu\n", (u_long)argp->arg_flags); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__db_debug_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __db_debug_args **argpp; +{ + __db_debug_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__db_debug_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memset(&argp->op, 0, sizeof(argp->op)); + memcpy(&argp->op.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->op.data = bp; + bp += argp->op.size; + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memset(&argp->key, 0, sizeof(argp->key)); + memcpy(&argp->key.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->key.data = bp; + bp += argp->key.size; + memset(&argp->data, 0, sizeof(argp->data)); + memcpy(&argp->data.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->data.data = bp; + bp += argp->data.size; + memcpy(&argp->arg_flags, bp, sizeof(argp->arg_flags)); + bp += sizeof(argp->arg_flags); + *argpp = argp; + return (0); +} + +int +__db_noop_log(dbenv, txnid, ret_lsnp, flags, + fileid, pgno, prevlsn) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + int32_t fileid; + db_pgno_t pgno; + DB_LSN * prevlsn; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_db_noop; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(fileid) + + sizeof(pgno) + + sizeof(*prevlsn); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &fileid, sizeof(fileid)); + bp += sizeof(fileid); + memcpy(bp, &pgno, sizeof(pgno)); + bp += sizeof(pgno); + if (prevlsn != NULL) + memcpy(bp, prevlsn, sizeof(*prevlsn)); + else + memset(bp, 0, sizeof(*prevlsn)); + bp += sizeof(*prevlsn); + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__db_noop_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __db_noop_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __db_noop_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]db_noop: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tpgno: %lu\n", (u_long)argp->pgno); + printf("\tprevlsn: [%lu][%lu]\n", + (u_long)argp->prevlsn.file, (u_long)argp->prevlsn.offset); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__db_noop_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __db_noop_args **argpp; +{ + __db_noop_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__db_noop_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->pgno, bp, sizeof(argp->pgno)); + bp += sizeof(argp->pgno); + memcpy(&argp->prevlsn, bp, sizeof(argp->prevlsn)); + bp += sizeof(argp->prevlsn); + *argpp = argp; + return (0); +} + +int +__db_init_print(dbenv) + DB_ENV *dbenv; +{ + int ret; + + if ((ret = __db_add_recovery(dbenv, + __db_addrem_print, DB_db_addrem)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __db_split_print, DB_db_split)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __db_big_print, DB_db_big)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __db_ovref_print, DB_db_ovref)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __db_relink_print, DB_db_relink)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __db_addpage_print, DB_db_addpage)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __db_debug_print, DB_db_debug)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __db_noop_print, DB_db_noop)) != 0) + return (ret); + return (0); +} + +int +__db_init_recover(dbenv) + DB_ENV *dbenv; +{ + int ret; + + if ((ret = __db_add_recovery(dbenv, + __db_addrem_recover, DB_db_addrem)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __deprecated_recover, DB_db_split)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __db_big_recover, DB_db_big)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __db_ovref_recover, DB_db_ovref)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __db_relink_recover, DB_db_relink)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __deprecated_recover, DB_db_addpage)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __db_debug_recover, DB_db_debug)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __db_noop_recover, DB_db_noop)) != 0) + return (ret); + return (0); +} + diff --git a/db/db/db_cam.c b/db/db/db_cam.c new file mode 100644 index 000000000..708d4cbda --- /dev/null +++ b/db/db/db_cam.c @@ -0,0 +1,974 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: db_cam.c,v 11.52 2001/01/18 15:11:16 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_shash.h" +#include "lock.h" +#include "btree.h" +#include "hash.h" +#include "qam.h" +#include "txn.h" +#include "db_ext.h" + +static int __db_c_cleanup __P((DBC *, DBC *, int)); +static int __db_c_idup __P((DBC *, DBC **, u_int32_t)); +static int __db_wrlock_err __P((DB_ENV *)); + +#define CDB_LOCKING_INIT(dbp, dbc) \ + /* \ + * If we are running CDB, this had better be either a write \ + * cursor or an immediate writer. If it's a regular writer, \ + * that means we have an IWRITE lock and we need to upgrade \ + * it to a write lock. \ + */ \ + if (CDB_LOCKING((dbp)->dbenv)) { \ + if (!F_ISSET(dbc, DBC_WRITECURSOR | DBC_WRITER)) \ + return (__db_wrlock_err(dbp->dbenv)); \ + \ + if (F_ISSET(dbc, DBC_WRITECURSOR) && \ + (ret = lock_get((dbp)->dbenv, (dbc)->locker, \ + DB_LOCK_UPGRADE, &(dbc)->lock_dbt, DB_LOCK_WRITE, \ + &(dbc)->mylock)) != 0) \ + return (ret); \ + } +#define CDB_LOCKING_DONE(dbp, dbc) \ + /* Release the upgraded lock. */ \ + if (F_ISSET(dbc, DBC_WRITECURSOR)) \ + (void)__lock_downgrade( \ + (dbp)->dbenv, &(dbc)->mylock, DB_LOCK_IWRITE, 0); +/* + * Copy the lock info from one cursor to another, so that locking + * in CDB can be done in the context of an internally-duplicated + * or off-page-duplicate cursor. + */ +#define CDB_LOCKING_COPY(dbp, dbc_o, dbc_n) \ + if (CDB_LOCKING((dbp)->dbenv) && \ + F_ISSET((dbc_o), DBC_WRITECURSOR | DBC_WRITEDUP)) { \ + memcpy(&(dbc_n)->mylock, &(dbc_o)->mylock, \ + sizeof((dbc_o)->mylock)); \ + (dbc_n)->locker = (dbc_o)->locker; \ + /* This lock isn't ours to put--just discard it on close. */ \ + F_SET((dbc_n), DBC_WRITEDUP); \ + } + +/* + * __db_c_close -- + * Close the cursor. + * + * PUBLIC: int __db_c_close __P((DBC *)); + */ +int +__db_c_close(dbc) + DBC *dbc; +{ + DB *dbp; + DBC *opd; + DBC_INTERNAL *cp; + int ret, t_ret; + + dbp = dbc->dbp; + ret = 0; + + PANIC_CHECK(dbp->dbenv); + + /* + * If the cursor is already closed we have a serious problem, and we + * assume that the cursor isn't on the active queue. Don't do any of + * the remaining cursor close processing. + */ + if (!F_ISSET(dbc, DBC_ACTIVE)) { + if (dbp != NULL) + __db_err(dbp->dbenv, "Closing closed cursor"); + + DB_ASSERT(0); + return (EINVAL); + } + + cp = dbc->internal; + opd = cp->opd; + + /* + * Remove the cursor(s) from the active queue. We may be closing two + * cursors at once here, a top-level one and a lower-level, off-page + * duplicate one. The acess-method specific cursor close routine must + * close both of them in a single call. + * + * !!! + * Cursors must be removed from the active queue before calling the + * access specific cursor close routine, btree depends on having that + * order of operations. It must also happen before any action that + * can fail and cause __db_c_close to return an error, or else calls + * here from __db_close may loop indefinitely. + */ + MUTEX_THREAD_LOCK(dbp->dbenv, dbp->mutexp); + + if (opd != NULL) { + F_CLR(opd, DBC_ACTIVE); + TAILQ_REMOVE(&dbp->active_queue, opd, links); + } + F_CLR(dbc, DBC_ACTIVE); + TAILQ_REMOVE(&dbp->active_queue, dbc, links); + + MUTEX_THREAD_UNLOCK(dbp->dbenv, dbp->mutexp); + + /* Call the access specific cursor close routine. */ + if ((t_ret = + dbc->c_am_close(dbc, PGNO_INVALID, NULL)) != 0 && ret == 0) + ret = t_ret; + + /* + * Release the lock after calling the access method specific close + * routine, a Btree cursor may have had pending deletes. + */ + if (CDB_LOCKING(dbc->dbp->dbenv)) { + /* + * If DBC_WRITEDUP is set, the cursor is an internally + * duplicated write cursor and the lock isn't ours to put. + */ + if (!F_ISSET(dbc, DBC_WRITEDUP) && + dbc->mylock.off != LOCK_INVALID) { + if ((t_ret = lock_put(dbc->dbp->dbenv, + &dbc->mylock)) != 0 && ret == 0) + ret = t_ret; + dbc->mylock.off = LOCK_INVALID; + } + + /* For safety's sake, since this is going on the free queue. */ + memset(&dbc->mylock, 0, sizeof(dbc->mylock)); + F_CLR(dbc, DBC_WRITEDUP); + } + + if (dbc->txn != NULL) + dbc->txn->cursors--; + + /* Move the cursor(s) to the free queue. */ + MUTEX_THREAD_LOCK(dbp->dbenv, dbp->mutexp); + if (opd != NULL) { + if (dbc->txn != NULL) + dbc->txn->cursors--; + TAILQ_INSERT_TAIL(&dbp->free_queue, opd, links); + opd = NULL; + } + TAILQ_INSERT_TAIL(&dbp->free_queue, dbc, links); + MUTEX_THREAD_UNLOCK(dbp->dbenv, dbp->mutexp); + + return (ret); +} + +/* + * __db_c_destroy -- + * Destroy the cursor, called after DBC->c_close. + * + * PUBLIC: int __db_c_destroy __P((DBC *)); + */ +int +__db_c_destroy(dbc) + DBC *dbc; +{ + DB *dbp; + DBC_INTERNAL *cp; + int ret; + + dbp = dbc->dbp; + cp = dbc->internal; + + /* Remove the cursor from the free queue. */ + MUTEX_THREAD_LOCK(dbp->dbenv, dbp->mutexp); + TAILQ_REMOVE(&dbp->free_queue, dbc, links); + MUTEX_THREAD_UNLOCK(dbp->dbenv, dbp->mutexp); + + /* Free up allocated memory. */ + if (dbc->rkey.data != NULL) + __os_free(dbc->rkey.data, dbc->rkey.ulen); + if (dbc->rdata.data != NULL) + __os_free(dbc->rdata.data, dbc->rdata.ulen); + + /* Call the access specific cursor destroy routine. */ + ret = dbc->c_am_destroy == NULL ? 0 : dbc->c_am_destroy(dbc); + + __os_free(dbc, sizeof(*dbc)); + + return (ret); +} + +/* + * __db_c_count -- + * Return a count of duplicate data items. + * + * PUBLIC: int __db_c_count __P((DBC *, db_recno_t *, u_int32_t)); + */ +int +__db_c_count(dbc, recnop, flags) + DBC *dbc; + db_recno_t *recnop; + u_int32_t flags; +{ + DB *dbp; + int ret; + + /* + * Cursor Cleanup Note: + * All of the cursors passed to the underlying access methods by this + * routine are not duplicated and will not be cleaned up on return. + * So, pages/locks that the cursor references must be resolved by the + * underlying functions. + */ + dbp = dbc->dbp; + + PANIC_CHECK(dbp->dbenv); + + /* Check for invalid flags. */ + if ((ret = __db_ccountchk(dbp, flags, IS_INITIALIZED(dbc))) != 0) + return (ret); + + switch (dbc->dbtype) { + case DB_QUEUE: + case DB_RECNO: + *recnop = 1; + break; + case DB_HASH: + if (dbc->internal->opd == NULL) { + if ((ret = __ham_c_count(dbc, recnop)) != 0) + return (ret); + break; + } + /* FALLTHROUGH */ + case DB_BTREE: + if ((ret = __bam_c_count(dbc, recnop)) != 0) + return (ret); + break; + default: + return (__db_unknown_type(dbp->dbenv, + "__db_c_count", dbp->type)); + } + return (0); +} + +/* + * __db_c_del -- + * Delete using a cursor. + * + * PUBLIC: int __db_c_del __P((DBC *, u_int32_t)); + */ +int +__db_c_del(dbc, flags) + DBC *dbc; + u_int32_t flags; +{ + DB *dbp; + DBC *opd; + int ret; + + /* + * Cursor Cleanup Note: + * All of the cursors passed to the underlying access methods by this + * routine are not duplicated and will not be cleaned up on return. + * So, pages/locks that the cursor references must be resolved by the + * underlying functions. + */ + dbp = dbc->dbp; + + PANIC_CHECK(dbp->dbenv); + DB_CHECK_TXN(dbp, dbc->txn); + + /* Check for invalid flags. */ + if ((ret = __db_cdelchk(dbp, flags, + F_ISSET(dbp, DB_AM_RDONLY), IS_INITIALIZED(dbc))) != 0) + return (ret); + + DEBUG_LWRITE(dbc, dbc->txn, "db_c_del", NULL, NULL, flags); + + CDB_LOCKING_INIT(dbp, dbc); + + /* + * Off-page duplicate trees are locked in the primary tree, that is, + * we acquire a write lock in the primary tree and no locks in the + * off-page dup tree. If the del operation is done in an off-page + * duplicate tree, call the primary cursor's upgrade routine first. + */ + opd = dbc->internal->opd; + if (opd == NULL) + ret = dbc->c_am_del(dbc); + else + if ((ret = dbc->c_am_writelock(dbc)) == 0) + ret = opd->c_am_del(opd); + + CDB_LOCKING_DONE(dbp, dbc); + + return (ret); +} + +/* + * __db_c_dup -- + * Duplicate a cursor + * + * PUBLIC: int __db_c_dup __P((DBC *, DBC **, u_int32_t)); + */ +int +__db_c_dup(dbc_orig, dbcp, flags) + DBC *dbc_orig; + DBC **dbcp; + u_int32_t flags; +{ + DB_ENV *dbenv; + DB *dbp; + DBC *dbc_n, *dbc_nopd; + int ret; + + dbp = dbc_orig->dbp; + dbenv = dbp->dbenv; + dbc_n = dbc_nopd = NULL; + + PANIC_CHECK(dbp->dbenv); + + /* + * We can never have two write cursors open in CDB, so do not + * allow duplication of a write cursor. + */ + if (flags != DB_POSITIONI && + F_ISSET(dbc_orig, DBC_WRITER | DBC_WRITECURSOR)) { + __db_err(dbenv, "Cannot duplicate writeable cursor"); + return (EINVAL); + } + + /* Allocate a new cursor and initialize it. */ + if ((ret = __db_c_idup(dbc_orig, &dbc_n, flags)) != 0) + goto err; + *dbcp = dbc_n; + + /* + * If we're in CDB, and this isn't an internal duplication (in which + * case we're explicitly overriding CDB locking), the duplicated + * cursor needs its own read lock. (We know it's not a write cursor + * because we wouldn't have made it this far; you can't dup them.) + */ + if (CDB_LOCKING(dbenv) && flags != DB_POSITIONI) { + DB_ASSERT(!F_ISSET(dbc_orig, DBC_WRITER | DBC_WRITECURSOR)); + + if ((ret = lock_get(dbenv, dbc_n->locker, 0, + &dbc_n->lock_dbt, DB_LOCK_READ, &dbc_n->mylock)) != 0) { + (void)__db_c_close(dbc_n); + return (ret); + } + } + + /* + * If the cursor references an off-page duplicate tree, allocate a + * new cursor for that tree and initialize it. + */ + if (dbc_orig->internal->opd != NULL) { + if ((ret = + __db_c_idup(dbc_orig->internal->opd, &dbc_nopd, flags)) != 0) + goto err; + dbc_n->internal->opd = dbc_nopd; + } + + return (0); + +err: if (dbc_n != NULL) + (void)dbc_n->c_close(dbc_n); + if (dbc_nopd != NULL) + (void)dbc_nopd->c_close(dbc_nopd); + + return (ret); +} + +/* + * __db_c_idup -- + * Internal version of __db_c_dup. + */ +static int +__db_c_idup(dbc_orig, dbcp, flags) + DBC *dbc_orig, **dbcp; + u_int32_t flags; +{ + DB *dbp; + DBC *dbc_n; + DBC_INTERNAL *int_n, *int_orig; + int ret; + + dbp = dbc_orig->dbp; + dbc_n = *dbcp; + + if ((ret = __db_icursor(dbp, dbc_orig->txn, dbc_orig->dbtype, + dbc_orig->internal->root, F_ISSET(dbc_orig, DBC_OPD), &dbc_n)) != 0) + return (ret); + + dbc_n->locker = dbc_orig->locker; + + /* If the user wants the cursor positioned, do it here. */ + if (flags == DB_POSITION || flags == DB_POSITIONI) { + int_n = dbc_n->internal; + int_orig = dbc_orig->internal; + + dbc_n->flags = dbc_orig->flags; + + int_n->indx = int_orig->indx; + int_n->pgno = int_orig->pgno; + int_n->root = int_orig->root; + int_n->lock_mode = int_orig->lock_mode; + + switch (dbc_orig->dbtype) { + case DB_QUEUE: + if ((ret = __qam_c_dup(dbc_orig, dbc_n)) != 0) + goto err; + break; + case DB_BTREE: + case DB_RECNO: + if ((ret = __bam_c_dup(dbc_orig, dbc_n)) != 0) + goto err; + break; + case DB_HASH: + if ((ret = __ham_c_dup(dbc_orig, dbc_n)) != 0) + goto err; + break; + default: + ret = __db_unknown_type(dbp->dbenv, + "__db_c_idup", dbc_orig->dbtype); + goto err; + } + } + + /* Now take care of duping the CDB information. */ + CDB_LOCKING_COPY(dbp, dbc_orig, dbc_n); + + *dbcp = dbc_n; + return (0); + +err: (void)dbc_n->c_close(dbc_n); + return (ret); +} + +/* + * __db_c_newopd -- + * Create a new off-page duplicate cursor. + * + * PUBLIC: int __db_c_newopd __P((DBC *, db_pgno_t, DBC **)); + */ +int +__db_c_newopd(dbc_parent, root, dbcp) + DBC *dbc_parent; + db_pgno_t root; + DBC **dbcp; +{ + DB *dbp; + DBC *opd; + DBTYPE dbtype; + int ret; + + dbp = dbc_parent->dbp; + dbtype = (dbp->dup_compare == NULL) ? DB_RECNO : DB_BTREE; + + if ((ret = __db_icursor(dbp, + dbc_parent->txn, dbtype, root, 1, &opd)) != 0) + return (ret); + + CDB_LOCKING_COPY(dbp, dbc_parent, opd); + + *dbcp = opd; + + return (0); +} + +/* + * __db_c_get -- + * Get using a cursor. + * + * PUBLIC: int __db_c_get __P((DBC *, DBT *, DBT *, u_int32_t)); + */ +int +__db_c_get(dbc_arg, key, data, flags) + DBC *dbc_arg; + DBT *key, *data; + u_int32_t flags; +{ + DB *dbp; + DBC *dbc, *dbc_n, *opd; + DBC_INTERNAL *cp, *cp_n; + db_pgno_t pgno; + u_int32_t tmp_flags, tmp_rmw; + u_int8_t type; + int ret, t_ret; + + /* + * Cursor Cleanup Note: + * All of the cursors passed to the underlying access methods by this + * routine are duplicated cursors. On return, any referenced pages + * will be discarded, and, if the cursor is not intended to be used + * again, the close function will be called. So, pages/locks that + * the cursor references do not need to be resolved by the underlying + * functions. + */ + dbp = dbc_arg->dbp; + dbc_n = NULL; + opd = NULL; + + PANIC_CHECK(dbp->dbenv); + + /* Check for invalid flags. */ + if ((ret = + __db_cgetchk(dbp, key, data, flags, IS_INITIALIZED(dbc_arg))) != 0) + return (ret); + + /* Clear OR'd in additional bits so we can check for flag equality. */ + tmp_rmw = LF_ISSET(DB_RMW); + LF_CLR(DB_RMW); + + DEBUG_LREAD(dbc_arg, dbc_arg->txn, "db_c_get", + flags == DB_SET || flags == DB_SET_RANGE ? key : NULL, NULL, flags); + + /* + * Return a cursor's record number. It has nothing to do with the + * cursor get code except that it was put into the interface. + */ + if (flags == DB_GET_RECNO) + return (__bam_c_rget(dbc_arg, data, flags | tmp_rmw)); + + if (flags == DB_CONSUME || flags == DB_CONSUME_WAIT) + CDB_LOCKING_INIT(dbp, dbc_arg); + + /* + * If we have an off-page duplicates cursor, and the operation applies + * to it, perform the operation. Duplicate the cursor and call the + * underlying function. + * + * Off-page duplicate trees are locked in the primary tree, that is, + * we acquire a write lock in the primary tree and no locks in the + * off-page dup tree. If the DB_RMW flag was specified and the get + * operation is done in an off-page duplicate tree, call the primary + * cursor's upgrade routine first. + */ + cp = dbc_arg->internal; + if (cp->opd != NULL && + (flags == DB_CURRENT || flags == DB_GET_BOTHC || + flags == DB_NEXT || flags == DB_NEXT_DUP || flags == DB_PREV)) { + if (tmp_rmw && (ret = dbc_arg->c_am_writelock(dbc_arg)) != 0) + return (ret); + if ((ret = __db_c_idup(cp->opd, &opd, DB_POSITIONI)) != 0) + return (ret); + + switch (ret = opd->c_am_get( + opd, key, data, flags, NULL)) { + case 0: + goto done; + case DB_NOTFOUND: + /* + * Translate DB_NOTFOUND failures for the DB_NEXT and + * DB_PREV operations into a subsequent operation on + * the parent cursor. + */ + if (flags == DB_NEXT || flags == DB_PREV) { + if ((ret = opd->c_close(opd)) != 0) + goto err; + opd = NULL; + break; + } + goto err; + default: + goto err; + } + } + + /* + * Perform an operation on the main cursor. Duplicate the cursor, + * upgrade the lock as required, and call the underlying function. + */ + switch (flags) { + case DB_CURRENT: + case DB_GET_BOTHC: + case DB_NEXT: + case DB_NEXT_DUP: + case DB_NEXT_NODUP: + case DB_PREV: + case DB_PREV_NODUP: + tmp_flags = DB_POSITIONI; + break; + default: + tmp_flags = 0; + break; + } + + /* + * If this cursor is going to be closed immediately, we don't + * need to take precautions to clean it up on error. + */ + if (F_ISSET(dbc_arg, DBC_TRANSIENT)) + dbc_n = dbc_arg; + else if ((ret = __db_c_idup(dbc_arg, &dbc_n, tmp_flags)) != 0) + goto err; + + if (tmp_rmw) + F_SET(dbc_n, DBC_RMW); + pgno = PGNO_INVALID; + ret = dbc_n->c_am_get(dbc_n, key, data, flags, &pgno); + if (tmp_rmw) + F_CLR(dbc_n, DBC_RMW); + if (ret != 0) + goto err; + + cp_n = dbc_n->internal; + + /* + * We may be referencing a new off-page duplicates tree. Acquire + * a new cursor and call the underlying function. + */ + if (pgno != PGNO_INVALID) { + if ((ret = __db_c_newopd(dbc_arg, pgno, &cp_n->opd)) != 0) + goto err; + + switch (flags) { + case DB_FIRST: + case DB_NEXT: + case DB_NEXT_NODUP: + case DB_SET: + case DB_SET_RECNO: + case DB_SET_RANGE: + tmp_flags = DB_FIRST; + break; + case DB_LAST: + case DB_PREV: + case DB_PREV_NODUP: + tmp_flags = DB_LAST; + break; + case DB_GET_BOTH: + tmp_flags = DB_GET_BOTH; + break; + case DB_GET_BOTHC: + tmp_flags = DB_GET_BOTHC; + break; + default: + ret = + __db_unknown_flag(dbp->dbenv, "__db_c_get", flags); + goto err; + } + if ((ret = cp_n->opd->c_am_get( + cp_n->opd, key, data, tmp_flags, NULL)) != 0) + goto err; + } + +done: /* + * Return a key/data item. The only exception is that we don't return + * a key if the user already gave us one, that is, if the DB_SET flag + * was set. The DB_SET flag is necessary. In a Btree, the user's key + * doesn't have to be the same as the key stored the tree, depending on + * the magic performed by the comparison function. As we may not have + * done any key-oriented operation here, the page reference may not be + * valid. Fill it in as necessary. We don't have to worry about any + * locks, the cursor must already be holding appropriate locks. + * + * XXX + * If not a Btree and DB_SET_RANGE is set, we shouldn't return a key + * either, should we? + */ + cp_n = dbc_n == NULL ? dbc_arg->internal : dbc_n->internal; + if (!F_ISSET(key, DB_DBT_ISSET)) { + if (cp_n->page == NULL && (ret = + memp_fget(dbp->mpf, &cp_n->pgno, 0, &cp_n->page)) != 0) + goto err; + + if ((ret = __db_ret(dbp, cp_n->page, cp_n->indx, + key, &dbc_arg->rkey.data, &dbc_arg->rkey.ulen)) != 0) + goto err; + } + dbc = opd != NULL ? opd : cp_n->opd != NULL ? cp_n->opd : dbc_n; + if (!F_ISSET(data, DB_DBT_ISSET)) { + type = TYPE(dbc->internal->page); + ret = __db_ret(dbp, dbc->internal->page, dbc->internal->indx + + (type == P_LBTREE || type == P_HASH ? O_INDX : 0), + data, &dbc_arg->rdata.data, &dbc_arg->rdata.ulen); + } + +err: /* Don't pass DB_DBT_ISSET back to application level, error or no. */ + F_CLR(key, DB_DBT_ISSET); + F_CLR(data, DB_DBT_ISSET); + + /* Cleanup and cursor resolution. */ + if (opd != NULL) { + if ((t_ret = + __db_c_cleanup(dbc_arg->internal->opd, + opd, ret)) != 0 && ret == 0) + ret = t_ret; + + } + + if ((t_ret = __db_c_cleanup(dbc_arg, dbc_n, ret)) != 0 && ret == 0) + ret = t_ret; + + if (flags == DB_CONSUME || flags == DB_CONSUME_WAIT) + CDB_LOCKING_DONE(dbp, dbc_arg); + return (ret); +} + +/* + * __db_c_put -- + * Put using a cursor. + * + * PUBLIC: int __db_c_put __P((DBC *, DBT *, DBT *, u_int32_t)); + */ +int +__db_c_put(dbc_arg, key, data, flags) + DBC *dbc_arg; + DBT *key, *data; + u_int32_t flags; +{ + DB *dbp; + DBC *dbc_n, *opd; + db_pgno_t pgno; + u_int32_t tmp_flags; + int ret, t_ret; + + /* + * Cursor Cleanup Note: + * All of the cursors passed to the underlying access methods by this + * routine are duplicated cursors. On return, any referenced pages + * will be discarded, and, if the cursor is not intended to be used + * again, the close function will be called. So, pages/locks that + * the cursor references do not need to be resolved by the underlying + * functions. + */ + dbp = dbc_arg->dbp; + dbc_n = NULL; + + PANIC_CHECK(dbp->dbenv); + DB_CHECK_TXN(dbp, dbc_arg->txn); + + /* Check for invalid flags. */ + if ((ret = __db_cputchk(dbp, key, data, flags, + F_ISSET(dbp, DB_AM_RDONLY), IS_INITIALIZED(dbc_arg))) != 0) + return (ret); + + DEBUG_LWRITE(dbc_arg, dbc_arg->txn, "db_c_put", + flags == DB_KEYFIRST || flags == DB_KEYLAST || + flags == DB_NODUPDATA ? key : NULL, data, flags); + + CDB_LOCKING_INIT(dbp, dbc_arg); + + /* + * If we have an off-page duplicates cursor, and the operation applies + * to it, perform the operation. Duplicate the cursor and call the + * underlying function. + * + * Off-page duplicate trees are locked in the primary tree, that is, + * we acquire a write lock in the primary tree and no locks in the + * off-page dup tree. If the put operation is done in an off-page + * duplicate tree, call the primary cursor's upgrade routine first. + */ + if (dbc_arg->internal->opd != NULL && + (flags == DB_AFTER || flags == DB_BEFORE || flags == DB_CURRENT)) { + /* + * A special case for hash off-page duplicates. Hash doesn't + * support (and is documented not to support) put operations + * relative to a cursor which references an already deleted + * item. For consistency, apply the same criteria to off-page + * duplicates as well. + */ + if (dbc_arg->dbtype == DB_HASH && F_ISSET( + ((BTREE_CURSOR *)(dbc_arg->internal->opd->internal)), + C_DELETED)) { + ret = DB_NOTFOUND; + goto err; + } + + if ((ret = dbc_arg->c_am_writelock(dbc_arg)) != 0) + return (ret); + if ((ret = __db_c_dup(dbc_arg, &dbc_n, DB_POSITIONI)) != 0) + goto err; + opd = dbc_n->internal->opd; + if ((ret = opd->c_am_put( + opd, key, data, flags, NULL)) != 0) + goto err; + goto done; + } + + /* + * Perform an operation on the main cursor. Duplicate the cursor, + * and call the underlying function. + * + * XXX: MARGO + * + tmp_flags = flags == DB_AFTER || + flags == DB_BEFORE || flags == DB_CURRENT ? DB_POSITIONI : 0; + */ + tmp_flags = DB_POSITIONI; + + /* + * If this cursor is going to be closed immediately, we don't + * need to take precautions to clean it up on error. + */ + if (F_ISSET(dbc_arg, DBC_TRANSIENT)) + dbc_n = dbc_arg; + else if ((ret = __db_c_idup(dbc_arg, &dbc_n, tmp_flags)) != 0) + goto err; + + pgno = PGNO_INVALID; + if ((ret = dbc_n->c_am_put(dbc_n, key, data, flags, &pgno)) != 0) + goto err; + + /* + * We may be referencing a new off-page duplicates tree. Acquire + * a new cursor and call the underlying function. + */ + if (pgno != PGNO_INVALID) { + if ((ret = __db_c_newopd(dbc_arg, pgno, &opd)) != 0) + goto err; + dbc_n->internal->opd = opd; + + if ((ret = opd->c_am_put( + opd, key, data, flags, NULL)) != 0) + goto err; + } + +done: +err: /* Cleanup and cursor resolution. */ + if ((t_ret = __db_c_cleanup(dbc_arg, dbc_n, ret)) != 0 && ret == 0) + ret = t_ret; + + CDB_LOCKING_DONE(dbp, dbc_arg); + + return (ret); +} + +/* + * __db_duperr() + * Error message: we don't currently support sorted duplicate duplicates. + * PUBLIC: int __db_duperr __P((DB *, u_int32_t)); + */ +int +__db_duperr(dbp, flags) + DB *dbp; + u_int32_t flags; +{ + if (flags != DB_NODUPDATA) + __db_err(dbp->dbenv, + "Duplicate data items are not supported with sorted data"); + return (DB_KEYEXIST); +} + +/* + * __db_c_cleanup -- + * Clean up duplicate cursors. + */ +static int +__db_c_cleanup(dbc, dbc_n, failed) + DBC *dbc, *dbc_n; + int failed; +{ + DB *dbp; + DBC *opd; + DBC_INTERNAL *internal; + int ret, t_ret; + + dbp = dbc->dbp; + internal = dbc->internal; + ret = 0; + + /* Discard any pages we're holding. */ + if (internal->page != NULL) { + if ((t_ret = + memp_fput(dbp->mpf, internal->page, 0)) != 0 && ret == 0) + ret = t_ret; + internal->page = NULL; + } + opd = internal->opd; + if (opd != NULL && opd->internal->page != NULL) { + if ((t_ret = memp_fput(dbp->mpf, + opd->internal->page, 0)) != 0 && ret == 0) + ret = t_ret; + opd->internal->page = NULL; + } + + /* + * If dbc_n is NULL, there's no internal cursor swapping to be + * done and no dbc_n to close--we probably did the entire + * operation on an offpage duplicate cursor. Just return. + */ + if (dbc_n == NULL) + return (ret); + + /* + * If dbc is marked DBC_TRANSIENT, we're inside a DB->{put/get} + * operation, and as an optimization we performed the operation on + * the main cursor rather than on a duplicated one. Assert + * that dbc_n == dbc (i.e., that we really did skip the + * duplication). Then just do nothing--even if there was + * an error, we're about to close the cursor, and the fact that we + * moved it isn't a user-visible violation of our "cursor + * stays put on error" rule. + */ + if (F_ISSET(dbc, DBC_TRANSIENT)) { + DB_ASSERT(dbc == dbc_n); + return (ret); + } + + if (dbc_n->internal->page != NULL) { + if ((t_ret = memp_fput(dbp->mpf, + dbc_n->internal->page, 0)) != 0 && ret == 0) + ret = t_ret; + dbc_n->internal->page = NULL; + } + opd = dbc_n->internal->opd; + if (opd != NULL && opd->internal->page != NULL) { + if ((t_ret = memp_fput(dbp->mpf, + opd->internal->page, 0)) != 0 && ret == 0) + ret = t_ret; + opd->internal->page = NULL; + } + + /* + * If we didn't fail before entering this routine or just now when + * freeing pages, swap the interesting contents of the old and new + * cursors. + */ + if (!failed && ret == 0) { + dbc->internal = dbc_n->internal; + dbc_n->internal = internal; + } + + /* + * Close the cursor we don't care about anymore. The close can fail, + * but we only expect DB_LOCK_DEADLOCK failures. This violates our + * "the cursor is unchanged on error" semantics, but since all you can + * do with a DB_LOCK_DEADLOCK failure is close the cursor, I believe + * that's OK. + * + * XXX + * There's no way to recover from failure to close the old cursor. + * All we can do is move to the new position and return an error. + * + * XXX + * We might want to consider adding a flag to the cursor, so that any + * subsequent operations other than close just return an error? + */ + if ((t_ret = dbc_n->c_close(dbc_n)) != 0 && ret == 0) + ret = t_ret; + + return (ret); +} + +/* + * __db_wrlock_err -- do not have a write lock. + */ +static int +__db_wrlock_err(dbenv) + DB_ENV *dbenv; +{ + __db_err(dbenv, "Write attempted on read-only cursor"); + return (EPERM); +} diff --git a/db/db/db_conv.c b/db/db/db_conv.c new file mode 100644 index 000000000..df60be067 --- /dev/null +++ b/db/db/db_conv.c @@ -0,0 +1,348 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994, 1995 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: db_conv.c,v 11.11 2000/11/30 00:58:31 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_swap.h" +#include "db_am.h" +#include "btree.h" +#include "hash.h" +#include "qam.h" + +/* + * __db_pgin -- + * Primary page-swap routine. + * + * PUBLIC: int __db_pgin __P((DB_ENV *, db_pgno_t, void *, DBT *)); + */ +int +__db_pgin(dbenv, pg, pp, cookie) + DB_ENV *dbenv; + db_pgno_t pg; + void *pp; + DBT *cookie; +{ + DB_PGINFO *pginfo; + + pginfo = (DB_PGINFO *)cookie->data; + + switch (((PAGE *)pp)->type) { + case P_HASH: + case P_HASHMETA: + case P_INVALID: + return (__ham_pgin(dbenv, pg, pp, cookie)); + case P_BTREEMETA: + case P_IBTREE: + case P_IRECNO: + case P_LBTREE: + case P_LDUP: + case P_LRECNO: + case P_OVERFLOW: + return (__bam_pgin(dbenv, pg, pp, cookie)); + case P_QAMMETA: + case P_QAMDATA: + return (__qam_pgin_out(dbenv, pg, pp, cookie)); + default: + break; + } + return (__db_unknown_type(dbenv, "__db_pgin", ((PAGE *)pp)->type)); +} + +/* + * __db_pgout -- + * Primary page-swap routine. + * + * PUBLIC: int __db_pgout __P((DB_ENV *, db_pgno_t, void *, DBT *)); + */ +int +__db_pgout(dbenv, pg, pp, cookie) + DB_ENV *dbenv; + db_pgno_t pg; + void *pp; + DBT *cookie; +{ + DB_PGINFO *pginfo; + + pginfo = (DB_PGINFO *)cookie->data; + + switch (((PAGE *)pp)->type) { + case P_HASH: + case P_HASHMETA: + case P_INVALID: + return (__ham_pgout(dbenv, pg, pp, cookie)); + case P_BTREEMETA: + case P_IBTREE: + case P_IRECNO: + case P_LBTREE: + case P_LDUP: + case P_LRECNO: + case P_OVERFLOW: + return (__bam_pgout(dbenv, pg, pp, cookie)); + case P_QAMMETA: + case P_QAMDATA: + return (__qam_pgin_out(dbenv, pg, pp, cookie)); + default: + break; + } + return (__db_unknown_type(dbenv, "__db_pgout", ((PAGE *)pp)->type)); +} + +/* + * __db_metaswap -- + * Byteswap the common part of the meta-data page. + * + * PUBLIC: void __db_metaswap __P((PAGE *)); + */ +void +__db_metaswap(pg) + PAGE *pg; +{ + u_int8_t *p; + + p = (u_int8_t *)pg; + + /* Swap the meta-data information. */ + SWAP32(p); /* lsn.file */ + SWAP32(p); /* lsn.offset */ + SWAP32(p); /* pgno */ + SWAP32(p); /* magic */ + SWAP32(p); /* version */ + SWAP32(p); /* pagesize */ + p += 4; /* unused, page type, unused, unused */ + SWAP32(p); /* free */ + SWAP32(p); /* alloc_lsn part 1 */ + SWAP32(p); /* alloc_lsn part 2 */ + SWAP32(p); /* cached key count */ + SWAP32(p); /* cached record count */ + SWAP32(p); /* flags */ +} + +/* + * __db_byteswap -- + * Byteswap a page. + * + * PUBLIC: int __db_byteswap __P((DB_ENV *, db_pgno_t, PAGE *, size_t, int)); + */ +int +__db_byteswap(dbenv, pg, h, pagesize, pgin) + DB_ENV *dbenv; + db_pgno_t pg; + PAGE *h; + size_t pagesize; + int pgin; +{ + BINTERNAL *bi; + BKEYDATA *bk; + BOVERFLOW *bo; + RINTERNAL *ri; + db_indx_t i, len, tmp; + u_int8_t *p, *end; + + COMPQUIET(pg, 0); + + if (pgin) { + M_32_SWAP(h->lsn.file); + M_32_SWAP(h->lsn.offset); + M_32_SWAP(h->pgno); + M_32_SWAP(h->prev_pgno); + M_32_SWAP(h->next_pgno); + M_16_SWAP(h->entries); + M_16_SWAP(h->hf_offset); + } + + switch (h->type) { + case P_HASH: + for (i = 0; i < NUM_ENT(h); i++) { + if (pgin) + M_16_SWAP(h->inp[i]); + + switch (HPAGE_TYPE(h, i)) { + case H_KEYDATA: + break; + case H_DUPLICATE: + len = LEN_HKEYDATA(h, pagesize, i); + p = HKEYDATA_DATA(P_ENTRY(h, i)); + for (end = p + len; p < end;) { + if (pgin) { + P_16_SWAP(p); + memcpy(&tmp, + p, sizeof(db_indx_t)); + p += sizeof(db_indx_t); + } else { + memcpy(&tmp, + p, sizeof(db_indx_t)); + SWAP16(p); + } + p += tmp; + SWAP16(p); + } + break; + case H_OFFDUP: + p = HOFFPAGE_PGNO(P_ENTRY(h, i)); + SWAP32(p); /* pgno */ + break; + case H_OFFPAGE: + p = HOFFPAGE_PGNO(P_ENTRY(h, i)); + SWAP32(p); /* pgno */ + SWAP32(p); /* tlen */ + break; + } + + } + + /* + * The offsets in the inp array are used to determine + * the size of entries on a page; therefore they + * cannot be converted until we've done all the + * entries. + */ + if (!pgin) + for (i = 0; i < NUM_ENT(h); i++) + M_16_SWAP(h->inp[i]); + break; + case P_LBTREE: + case P_LDUP: + case P_LRECNO: + for (i = 0; i < NUM_ENT(h); i++) { + if (pgin) + M_16_SWAP(h->inp[i]); + + /* + * In the case of on-page duplicates, key information + * should only be swapped once. + */ + if (h->type == P_LBTREE && i > 1) { + if (pgin) { + if (h->inp[i] == h->inp[i - 2]) + continue; + } else { + M_16_SWAP(h->inp[i]); + if (h->inp[i] == h->inp[i - 2]) + continue; + M_16_SWAP(h->inp[i]); + } + } + + bk = GET_BKEYDATA(h, i); + switch (B_TYPE(bk->type)) { + case B_KEYDATA: + M_16_SWAP(bk->len); + break; + case B_DUPLICATE: + case B_OVERFLOW: + bo = (BOVERFLOW *)bk; + M_32_SWAP(bo->pgno); + M_32_SWAP(bo->tlen); + break; + } + + if (!pgin) + M_16_SWAP(h->inp[i]); + } + break; + case P_IBTREE: + for (i = 0; i < NUM_ENT(h); i++) { + if (pgin) + M_16_SWAP(h->inp[i]); + + bi = GET_BINTERNAL(h, i); + M_16_SWAP(bi->len); + M_32_SWAP(bi->pgno); + M_32_SWAP(bi->nrecs); + + switch (B_TYPE(bi->type)) { + case B_KEYDATA: + break; + case B_DUPLICATE: + case B_OVERFLOW: + bo = (BOVERFLOW *)bi->data; + M_32_SWAP(bo->pgno); + M_32_SWAP(bo->tlen); + break; + } + + if (!pgin) + M_16_SWAP(h->inp[i]); + } + break; + case P_IRECNO: + for (i = 0; i < NUM_ENT(h); i++) { + if (pgin) + M_16_SWAP(h->inp[i]); + + ri = GET_RINTERNAL(h, i); + M_32_SWAP(ri->pgno); + M_32_SWAP(ri->nrecs); + + if (!pgin) + M_16_SWAP(h->inp[i]); + } + break; + case P_OVERFLOW: + case P_INVALID: + /* Nothing to do. */ + break; + default: + return (__db_unknown_type(dbenv, "__db_byteswap", h->type)); + } + + if (!pgin) { + /* Swap the header information. */ + M_32_SWAP(h->lsn.file); + M_32_SWAP(h->lsn.offset); + M_32_SWAP(h->pgno); + M_32_SWAP(h->prev_pgno); + M_32_SWAP(h->next_pgno); + M_16_SWAP(h->entries); + M_16_SWAP(h->hf_offset); + } + return (0); +} diff --git a/db/db/db_dispatch.c b/db/db/db_dispatch.c new file mode 100644 index 000000000..c9beac401 --- /dev/null +++ b/db/db/db_dispatch.c @@ -0,0 +1,983 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1995, 1996 + * The President and Fellows of Harvard University. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Margo Seltzer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: db_dispatch.c,v 11.41 2001/01/11 18:19:50 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_dispatch.h" +#include "db_am.h" +#include "log_auto.h" +#include "txn.h" +#include "txn_auto.h" +#include "log.h" + +static int __db_txnlist_find_internal __P((void *, db_txnlist_type, + u_int32_t, u_int8_t [DB_FILE_ID_LEN], DB_TXNLIST **, int)); + +/* + * __db_dispatch -- + * + * This is the transaction dispatch function used by the db access methods. + * It is designed to handle the record format used by all the access + * methods (the one automatically generated by the db_{h,log,read}.sh + * scripts in the tools directory). An application using a different + * recovery paradigm will supply a different dispatch function to txn_open. + * + * PUBLIC: int __db_dispatch __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__db_dispatch(dbenv, db, lsnp, redo, info) + DB_ENV *dbenv; /* The environment. */ + DBT *db; /* The log record upon which to dispatch. */ + DB_LSN *lsnp; /* The lsn of the record being dispatched. */ + db_recops redo; /* Redo this op (or undo it). */ + void *info; +{ + u_int32_t rectype, txnid; + int make_call, ret; + + memcpy(&rectype, db->data, sizeof(rectype)); + memcpy(&txnid, (u_int8_t *)db->data + sizeof(rectype), sizeof(txnid)); + make_call = ret = 0; + + /* + * If we find a record that is in the user's number space and they + * have specified a recovery routine, let them handle it. If they + * didn't specify a recovery routine, then we expect that they've + * followed all our rules and registered new recovery functions. + */ + switch (redo) { + case DB_TXN_ABORT: + /* + * XXX + * db_printlog depends on DB_TXN_ABORT not examining the TXN + * list. If that ever changes, fix db_printlog too. + */ + make_call = 1; + break; + case DB_TXN_OPENFILES: + if (rectype == DB_log_register) + return (dbenv->dtab[rectype](dbenv, + db, lsnp, redo, info)); + break; + case DB_TXN_BACKWARD_ROLL: + /* + * Running full recovery in the backward pass. If we've + * seen this txnid before and added to it our commit list, + * then we do nothing during this pass, unless this is a child + * commit record, in which case we need to process it. If + * we've never seen it, then we call the appropriate recovery + * routine. + * + * We need to always undo DB_db_noop records, so that we + * properly handle any aborts before the file was closed. + */ + if (rectype == DB_log_register || + rectype == DB_txn_ckp || rectype == DB_db_noop + || rectype == DB_txn_child || (txnid != 0 && + (ret = __db_txnlist_find(info, txnid)) != 0)) { + make_call = 1; + if (ret == DB_NOTFOUND && rectype != DB_txn_regop && + rectype != DB_txn_xa_regop && (ret = + __db_txnlist_add(dbenv, info, txnid, 1)) != 0) + return (ret); + } + break; + case DB_TXN_FORWARD_ROLL: + /* + * In the forward pass, if we haven't seen the transaction, + * do nothing, else recovery it. + * + * We need to always redo DB_db_noop records, so that we + * properly handle any commits after the file was closed. + */ + if (rectype == DB_log_register || + rectype == DB_txn_ckp || + rectype == DB_db_noop || + __db_txnlist_find(info, txnid) == 0) + make_call = 1; + break; + default: + return (__db_unknown_flag(dbenv, "__db_dispatch", redo)); + } + + if (make_call) { + if (rectype >= DB_user_BEGIN && dbenv->tx_recover != NULL) + return (dbenv->tx_recover(dbenv, db, lsnp, redo)); + else + return (dbenv->dtab[rectype](dbenv, db, lsnp, redo, info)); + } + + return (0); +} + +/* + * __db_add_recovery -- + * + * PUBLIC: int __db_add_recovery __P((DB_ENV *, + * PUBLIC: int (*)(DB_ENV *, DBT *, DB_LSN *, db_recops, void *), u_int32_t)); + */ +int +__db_add_recovery(dbenv, func, ndx) + DB_ENV *dbenv; + int (*func) __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + u_int32_t ndx; +{ + u_int32_t i, nsize; + int ret; + + /* Check if we have to grow the table. */ + if (ndx >= dbenv->dtab_size) { + nsize = ndx + 40; + if ((ret = __os_realloc(dbenv, + nsize * sizeof(dbenv->dtab[0]), NULL, &dbenv->dtab)) != 0) + return (ret); + for (i = dbenv->dtab_size; i < nsize; ++i) + dbenv->dtab[i] = NULL; + dbenv->dtab_size = nsize; + } + + dbenv->dtab[ndx] = func; + return (0); +} + +/* + * __deprecated_recover -- + * Stub routine for deprecated recovery functions. + * + * PUBLIC: int __deprecated_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__deprecated_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + COMPQUIET(dbenv, NULL); + COMPQUIET(dbtp, NULL); + COMPQUIET(lsnp, NULL); + COMPQUIET(op, 0); + COMPQUIET(info, NULL); + return (EINVAL); +} + +/* + * __db_txnlist_init -- + * Initialize transaction linked list. + * + * PUBLIC: int __db_txnlist_init __P((DB_ENV *, void *)); + */ +int +__db_txnlist_init(dbenv, retp) + DB_ENV *dbenv; + void *retp; +{ + DB_TXNHEAD *headp; + int ret; + + if ((ret = __os_malloc(dbenv, sizeof(DB_TXNHEAD), NULL, &headp)) != 0) + return (ret); + + LIST_INIT(&headp->head); + headp->maxid = 0; + headp->generation = 1; + + *(void **)retp = headp; + return (0); +} + +/* + * __db_txnlist_add -- + * Add an element to our transaction linked list. + * + * PUBLIC: int __db_txnlist_add __P((DB_ENV *, void *, u_int32_t, int32_t)); + */ +int +__db_txnlist_add(dbenv, listp, txnid, aborted) + DB_ENV *dbenv; + void *listp; + u_int32_t txnid; + int32_t aborted; +{ + DB_TXNHEAD *hp; + DB_TXNLIST *elp; + int ret; + + if ((ret = __os_malloc(dbenv, sizeof(DB_TXNLIST), NULL, &elp)) != 0) + return (ret); + + hp = (DB_TXNHEAD *)listp; + LIST_INSERT_HEAD(&hp->head, elp, links); + + elp->type = TXNLIST_TXNID; + elp->u.t.txnid = txnid; + elp->u.t.aborted = aborted; + if (txnid > hp->maxid) + hp->maxid = txnid; + elp->u.t.generation = hp->generation; + + return (0); +} +/* + * __db_txnlist_remove -- + * Remove an element from our transaction linked list. + * + * PUBLIC: int __db_txnlist_remove __P((void *, u_int32_t)); + */ +int +__db_txnlist_remove(listp, txnid) + void *listp; + u_int32_t txnid; +{ + DB_TXNLIST *entry; + + return (__db_txnlist_find_internal(listp, + TXNLIST_TXNID, txnid, NULL, &entry, 1)); +} + +/* __db_txnlist_close -- + * + * Call this when we close a file. It allows us to reconcile whether + * we have done any operations on this file with whether the file appears + * to have been deleted. If you never do any operations on a file, then + * we assume it's OK to appear deleted. + * + * PUBLIC: int __db_txnlist_close __P((void *, int32_t, u_int32_t)); + */ + +int +__db_txnlist_close(listp, lid, count) + void *listp; + int32_t lid; + u_int32_t count; +{ + DB_TXNHEAD *hp; + DB_TXNLIST *p; + + hp = (DB_TXNHEAD *)listp; + for (p = LIST_FIRST(&hp->head); p != NULL; p = LIST_NEXT(p, links)) { + if (p->type == TXNLIST_DELETE) + if (lid == p->u.d.fileid && + !F_ISSET(&p->u.d, TXNLIST_FLAG_CLOSED)) { + p->u.d.count += count; + return (0); + } + } + + return (0); +} + +/* + * __db_txnlist_delete -- + * + * Record that a file was missing or deleted. If the deleted + * flag is set, then we've encountered a delete of a file, else we've + * just encountered a file that is missing. The lid is the log fileid + * and is only meaningful if deleted is not equal to 0. + * + * PUBLIC: int __db_txnlist_delete __P((DB_ENV *, + * PUBLIC: void *, char *, u_int32_t, int)); + */ +int +__db_txnlist_delete(dbenv, listp, name, lid, deleted) + DB_ENV *dbenv; + void *listp; + char *name; + u_int32_t lid; + int deleted; +{ + DB_TXNHEAD *hp; + DB_TXNLIST *p; + int ret; + + hp = (DB_TXNHEAD *)listp; + for (p = LIST_FIRST(&hp->head); p != NULL; p = LIST_NEXT(p, links)) { + if (p->type == TXNLIST_DELETE) + if (strcmp(name, p->u.d.fname) == 0) { + if (deleted) + F_SET(&p->u.d, TXNLIST_FLAG_DELETED); + else + F_CLR(&p->u.d, TXNLIST_FLAG_CLOSED); + return (0); + } + } + + /* Need to add it. */ + if ((ret = __os_malloc(dbenv, sizeof(DB_TXNLIST), NULL, &p)) != 0) + return (ret); + LIST_INSERT_HEAD(&hp->head, p, links); + + p->type = TXNLIST_DELETE; + p->u.d.flags = 0; + if (deleted) + F_SET(&p->u.d, TXNLIST_FLAG_DELETED); + p->u.d.fileid = lid; + p->u.d.count = 0; + ret = __os_strdup(dbenv, name, &p->u.d.fname); + + return (ret); +} + +/* + * __db_txnlist_end -- + * Discard transaction linked list. Print out any error messages + * for deleted files. + * + * PUBLIC: void __db_txnlist_end __P((DB_ENV *, void *)); + */ +void +__db_txnlist_end(dbenv, listp) + DB_ENV *dbenv; + void *listp; +{ + DB_TXNHEAD *hp; + DB_TXNLIST *p; + DB_LOG *lp; + + hp = (DB_TXNHEAD *)listp; + lp = (DB_LOG *)dbenv->lg_handle; + while (hp != NULL && (p = LIST_FIRST(&hp->head)) != NULL) { + LIST_REMOVE(p, links); + switch (p->type) { + case TXNLIST_DELETE: + /* + * If we have a file that is not deleted and has + * some operations, we flag the warning. Since + * the file could still be open, we need to check + * the actual log table as well. + */ + if ((!F_ISSET(&p->u.d, TXNLIST_FLAG_DELETED) && + p->u.d.count != 0) || + (!F_ISSET(&p->u.d, TXNLIST_FLAG_CLOSED) && + p->u.d.fileid != (int32_t) TXNLIST_INVALID_ID && + p->u.d.fileid < lp->dbentry_cnt && + lp->dbentry[p->u.d.fileid].count != 0)) + __db_err(dbenv, "warning: %s: %s", + p->u.d.fname, db_strerror(ENOENT)); + __os_freestr(p->u.d.fname); + break; + case TXNLIST_LSN: + __os_free(p->u.l.lsn_array, + p->u.l.maxn * sizeof(DB_LSN)); + break; + default: + /* Possibly an incomplete DB_TXNLIST; just free it. */ + break; + } + __os_free(p, sizeof(DB_TXNLIST)); + } + __os_free(listp, sizeof(DB_TXNHEAD)); +} + +/* + * __db_txnlist_find -- + * Checks to see if a txnid with the current generation is in the + * txnid list. This returns DB_NOTFOUND if the item isn't in the + * list otherwise it returns (like __db_txnlist_find_internal) a + * 1 or 0 indicating if the transaction is aborted or not. A txnid + * of 0 means the record was generated while not in a transaction. + * + * PUBLIC: int __db_txnlist_find __P((void *, u_int32_t)); + */ +int +__db_txnlist_find(listp, txnid) + void *listp; + u_int32_t txnid; +{ + DB_TXNLIST *entry; + + if (txnid == 0) + return (DB_NOTFOUND); + return (__db_txnlist_find_internal(listp, + TXNLIST_TXNID, txnid, NULL, &entry, 0)); +} + +/* + * __db_txnlist_find_internal -- + * Find an entry on the transaction list. + * If the entry is not there or the list pointeris not initialized + * we return DB_NOTFOUND. If the item is found, we return the aborted + * status (1 for aborted, 0 for not aborted). Currently we always call + * this with an initialized list pointer but checking for NULL keeps it general. + */ +static int +__db_txnlist_find_internal(listp, type, txnid, uid, txnlistp, delete) + void *listp; + db_txnlist_type type; + u_int32_t txnid; + u_int8_t uid[DB_FILE_ID_LEN]; + DB_TXNLIST **txnlistp; + int delete; +{ + DB_TXNHEAD *hp; + DB_TXNLIST *p; + int ret; + + if ((hp = (DB_TXNHEAD *)listp) == NULL) + return (DB_NOTFOUND); + + for (p = LIST_FIRST(&hp->head); p != NULL; p = LIST_NEXT(p, links)) { + if (p->type != type) + continue; + switch (type) { + case TXNLIST_TXNID: + if (p->u.t.txnid != txnid || + hp->generation != p->u.t.generation) + continue; + ret = p->u.t.aborted; + break; + + case TXNLIST_PGNO: + if (memcmp(uid, p->u.p.uid, DB_FILE_ID_LEN) != 0) + continue; + + ret = 0; + break; + default: + DB_ASSERT(0); + ret = EINVAL; + } + if (delete == 1) { + LIST_REMOVE(p, links); + __os_free(p, sizeof(DB_TXNLIST)); + } else if (p != LIST_FIRST(&hp->head)) { + /* Move it to head of list. */ + LIST_REMOVE(p, links); + LIST_INSERT_HEAD(&hp->head, p, links); + } + *txnlistp = p; + return (ret); + } + + return (DB_NOTFOUND); +} + +/* + * __db_txnlist_gen -- + * Change the current generation number. + * + * PUBLIC: void __db_txnlist_gen __P((void *, int)); + */ +void +__db_txnlist_gen(listp, incr) + void *listp; + int incr; +{ + DB_TXNHEAD *hp; + + /* + * During recovery generation numbers keep track of how many "restart" + * checkpoints we've seen. Restart checkpoints occur whenever we take + * a checkpoint and there are no outstanding transactions. When that + * happens, we can reset transaction IDs back to 1. It always happens + * at recovery and it prevents us from exhausting the transaction IDs + * name space. + */ + hp = (DB_TXNHEAD *)listp; + hp->generation += incr; +} + +#define TXN_BUBBLE(AP, MAX) { \ + int __j; \ + DB_LSN __tmp; \ + \ + for (__j = 0; __j < MAX - 1; __j++) \ + if (log_compare(&AP[__j], &AP[__j + 1]) < 0) { \ + __tmp = AP[__j]; \ + AP[__j] = AP[__j + 1]; \ + AP[__j + 1] = __tmp; \ + } \ +} + +/* + * __db_txnlist_lsnadd -- + * Add to or re-sort the transaction list lsn entry. + * Note that since this is used during an abort, the __txn_undo + * code calls into the "recovery" subsystem explicitly, and there + * is only a single TXNLIST_LSN entry on the list. + * + * PUBLIC: int __db_txnlist_lsnadd __P((DB_ENV *, void *, DB_LSN *, u_int32_t)); + */ +int +__db_txnlist_lsnadd(dbenv, listp, lsnp, flags) + DB_ENV *dbenv; + void *listp; + DB_LSN *lsnp; + u_int32_t flags; +{ + DB_TXNHEAD *hp; + DB_TXNLIST *elp; + int i, ret; + + hp = (DB_TXNHEAD *)listp; + + for (elp = LIST_FIRST(&hp->head); + elp != NULL; elp = LIST_NEXT(elp, links)) + if (elp->type == TXNLIST_LSN) + break; + + if (elp == NULL) + return (EINVAL); + + if (LF_ISSET(TXNLIST_NEW)) { + if (elp->u.l.ntxns >= elp->u.l.maxn) { + if ((ret = __os_realloc(dbenv, + 2 * elp->u.l.maxn * sizeof(DB_LSN), + NULL, &elp->u.l.lsn_array)) != 0) + return (ret); + elp->u.l.maxn *= 2; + } + elp->u.l.lsn_array[elp->u.l.ntxns++] = *lsnp; + } else + /* Simply replace the 0th element. */ + elp->u.l.lsn_array[0] = *lsnp; + + /* + * If we just added a new entry and there may be NULL + * entries, so we have to do a complete bubble sort, + * not just trickle a changed entry around. + */ + for (i = 0; i < (!LF_ISSET(TXNLIST_NEW) ? 1 : elp->u.l.ntxns); i++) + TXN_BUBBLE(elp->u.l.lsn_array, elp->u.l.ntxns); + + *lsnp = elp->u.l.lsn_array[0]; + + return (0); +} + +/* + * __db_txnlist_lsnhead -- + * Return a pointer to the beginning of the lsn_array. + * + * PUBLIC: int __db_txnlist_lsnhead __P((void *, DB_LSN **)); + */ +int +__db_txnlist_lsnhead(listp, lsnpp) + void *listp; + DB_LSN **lsnpp; +{ + DB_TXNHEAD *hp; + DB_TXNLIST *elp; + + hp = (DB_TXNHEAD *)listp; + + for (elp = LIST_FIRST(&hp->head); + elp != NULL; elp = LIST_NEXT(elp, links)) + if (elp->type == TXNLIST_LSN) + break; + + if (elp == NULL) + return (EINVAL); + + *lsnpp = &elp->u.l.lsn_array[0]; + + return (0); +} + +/* + * __db_txnlist_lsninit -- + * Initialize a transaction list with an lsn array entry. + * + * PUBLIC: int __db_txnlist_lsninit __P((DB_ENV *, DB_TXNHEAD *, DB_LSN *)); + */ +int +__db_txnlist_lsninit(dbenv, hp, lsnp) + DB_ENV *dbenv; + DB_TXNHEAD *hp; + DB_LSN *lsnp; +{ + DB_TXNLIST *elp; + int ret; + + elp = NULL; + + if ((ret = __os_malloc(dbenv, sizeof(DB_TXNLIST), NULL, &elp)) != 0) + goto err; + LIST_INSERT_HEAD(&hp->head, elp, links); + + if ((ret = __os_malloc(dbenv, + 12 * sizeof(DB_LSN), NULL, &elp->u.l.lsn_array)) != 0) + goto err; + elp->type = TXNLIST_LSN; + elp->u.l.maxn = 12; + elp->u.l.ntxns = 1; + elp->u.l.lsn_array[0] = *lsnp; + + return (0); + +err: __db_txnlist_end(dbenv, hp); + return (ret); +} + +/* + * __db_add_limbo -- add pages to the limbo list. + * Get the file information and call pgnoadd + * for each page. + * + * PUBLIC: int __db_add_limbo __P((DB_ENV *, + * PUBLIC: void *, int32_t, db_pgno_t, int32_t)); + */ +int +__db_add_limbo(dbenv, info, fileid, pgno, count) + DB_ENV *dbenv; + void *info; + int32_t fileid; + db_pgno_t pgno; + int32_t count; +{ + DB_LOG *dblp; + FNAME *fnp; + int ret; + + dblp = dbenv->lg_handle; + if ((ret = __log_lid_to_fname(dblp, fileid, &fnp)) != 0) + return (ret); + + do { + if ((ret = + __db_txnlist_pgnoadd(dbenv, info, fileid, fnp->ufid, + R_ADDR(&dblp->reginfo, fnp->name_off), pgno)) != 0) + return (ret); + pgno++; + } while (--count != 0); + + return (0); +} + +/* + * __db_do_the_limbo -- move pages from limbo to free. + * + * If we are in recovery we add things to the free list without + * logging becasue we want to incrementaly apply logs that + * may be generated on another copy of this environment. + * Otherwise we just call __db_free to put the pages on + * the free list and log the activity. + * + * PUBLIC: int __db_do_the_limbo __P((DB_ENV *, DB_TXNHEAD *)); + */ +int +__db_do_the_limbo(dbenv, hp) + DB_ENV *dbenv; + DB_TXNHEAD *hp; +{ + DB *dbp; + DBC *dbc; + DBMETA *meta; + DB_TXN *txn; + DB_TXNLIST *elp; + PAGE *pagep; + db_pgno_t last_pgno, pgno; + int i, in_recover, put_page, ret, t_ret; + + dbp = NULL; + dbc = NULL; + txn = NULL; + ret = 0; + + /* Are we in recovery? */ + in_recover = F_ISSET((DB_LOG *)dbenv->lg_handle, DBLOG_RECOVER); + + for (elp = LIST_FIRST(&hp->head); + elp != NULL; elp = LIST_NEXT(elp, links)) { + if (elp->type != TXNLIST_PGNO) + continue; + + if (in_recover) { + if ((ret = db_create(&dbp, dbenv, 0)) != 0) + goto err; + + /* + * It is ok if the file is nolonger there. + */ + dbp->type = DB_UNKNOWN; + ret = __db_dbopen(dbp, + elp->u.p.fname, 0, __db_omode("rw----"), 0); + } else { + /* + * If we are in transaction undo, then we know + * the fileid is still correct. + */ + if ((ret = + __db_fileid_to_db(dbenv, &dbp, + elp->u.p.fileid, 0)) != 0 && ret != DB_DELETED) + goto err; + /* File is being destroyed. */ + if (F_ISSET(dbp, DB_AM_DISCARD)) + ret = DB_DELETED; + } + /* + * Verify that we are opening the same file that we were + * referring to when we wrote this log record. + */ + if (ret == 0 && + memcmp(elp->u.p.uid, dbp->fileid, DB_FILE_ID_LEN) == 0) { + last_pgno = PGNO_INVALID; + if (in_recover) { + pgno = PGNO_BASE_MD; + if ((ret = memp_fget(dbp->mpf, + &pgno, 0, (PAGE **)&meta)) != 0) + goto err; + last_pgno = meta->free; + /* + * Check to see if the head of the free + * list is any of the pages we are about + * to link in. We could have crashed + * after linking them in and before writing + * a checkpoint. + * It may not be the last one since + * any page may get reallocated before here. + */ + if (last_pgno != PGNO_INVALID) + for (i = 0; i < elp->u.p.nentries; i++) + if (last_pgno + == elp->u.p.pgno_array[i]) + goto done_it; + } + + for (i = 0; i < elp->u.p.nentries; i++) { + pgno = elp->u.p.pgno_array[i]; + if ((ret = memp_fget(dbp->mpf, + &pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto err; + + put_page = 1; + if (IS_ZERO_LSN(LSN(pagep))) { + P_INIT(pagep, dbp->pgsize, + pgno, PGNO_INVALID, + last_pgno, 0, P_INVALID); + + if (in_recover) { + LSN(pagep) = LSN(meta); + last_pgno = pgno; + } else { + /* + * Starting the transaction + * is postponed until we know + * we have something to do. + */ + if (txn == NULL && + (ret = txn_begin(dbenv, + NULL, &txn, 0)) != 0) + goto err; + + if (dbc == NULL && + (ret = dbp->cursor(dbp, + txn, &dbc, 0)) != 0) + goto err; + /* Turn off locking. */ + F_SET(dbc, DBC_COMPENSATE); + + /* __db_free puts the page. */ + if ((ret = + __db_free(dbc, pagep)) != 0) + goto err; + put_page = 0; + } + } + + if (put_page == 1 && + (ret = memp_fput(dbp->mpf, + pagep, DB_MPOOL_DIRTY)) != 0) + goto err; + } + if (in_recover) { + if (last_pgno == meta->free) { +done_it: + if ((ret = + memp_fput(dbp->mpf, meta, 0)) != 0) + goto err; + } else { + /* + * Flush the new free list then + * update the metapage. This is + * unlogged so we cannot have the + * metapage pointing at pages that + * are not on disk. + */ + dbp->sync(dbp, 0); + meta->free = last_pgno; + if ((ret = memp_fput(dbp->mpf, + meta, DB_MPOOL_DIRTY)) != 0) + goto err; + } + } + if (dbc != NULL && (ret = dbc->c_close(dbc)) != 0) + goto err; + dbc = NULL; + } + if (in_recover && (t_ret = dbp->close(dbp, 0)) != 0 && ret == 0) + ret = t_ret; + dbp = NULL; + __os_free(elp->u.p.fname, 0); + __os_free(elp->u.p.pgno_array, 0); + if (ret == ENOENT) + ret = 0; + else if (ret != 0) + goto err; + } + + if (txn != NULL) { + ret = txn_commit(txn, 0); + txn = NULL; + } +err: + if (dbc != NULL) + (void)dbc->c_close(dbc); + if (in_recover && dbp != NULL) + (void)dbp->close(dbp, 0); + if (txn != NULL) + (void)txn_abort(txn); + return (ret); + +} + +#define DB_TXNLIST_MAX_PGNO 8 /* A nice even number. */ + +/* + * __db_txnlist_pgnoadd -- + * Find the txnlist entry for a file and add this pgno, + * or add the list entry for the file and then add the pgno. + * + * PUBLIC: int __db_txnlist_pgnoadd __P((DB_ENV *, DB_TXNHEAD *, + * PUBLIC: int32_t, u_int8_t [DB_FILE_ID_LEN], char *, db_pgno_t)); + */ +int +__db_txnlist_pgnoadd(dbenv, hp, fileid, uid, fname, pgno) + DB_ENV *dbenv; + DB_TXNHEAD *hp; + int32_t fileid; + u_int8_t uid[DB_FILE_ID_LEN]; + char *fname; + db_pgno_t pgno; +{ + DB_TXNLIST *elp; + int len, ret; + + elp = NULL; + + if (__db_txnlist_find_internal(hp, TXNLIST_PGNO, 0, uid, &elp, 0) != 0) { + if ((ret = + __os_malloc(dbenv, sizeof(DB_TXNLIST), NULL, &elp)) != 0) + goto err; + LIST_INSERT_HEAD(&hp->head, elp, links); + elp->u.p.fileid = fileid; + memcpy(elp->u.p.uid, uid, DB_FILE_ID_LEN); + + len = strlen(fname) + 1; + if ((ret = __os_malloc(dbenv, len, NULL, &elp->u.p.fname)) != 0) + goto err; + memcpy(elp->u.p.fname, fname, len); + + elp->u.p.maxentry = 0; + elp->type = TXNLIST_PGNO; + if ((ret = __os_malloc(dbenv, + 8 * sizeof(db_pgno_t), NULL, &elp->u.p.pgno_array)) != 0) + goto err; + elp->u.p.maxentry = DB_TXNLIST_MAX_PGNO; + elp->u.p.nentries = 0; + } else if (elp->u.p.nentries == elp->u.p.maxentry) { + elp->u.p.maxentry <<= 1; + if ((ret = __os_realloc(dbenv, elp->u.p.maxentry * + sizeof(db_pgno_t), NULL, &elp->u.p.pgno_array)) != 0) + goto err; + } + + elp->u.p.pgno_array[elp->u.p.nentries++] = pgno; + + return (0); + +err: __db_txnlist_end(dbenv, hp); + return (ret); +} + +#ifdef DEBUG +/* + * __db_txnlist_print -- + * Print out the transaction list. + * + * PUBLIC: void __db_txnlist_print __P((void *)); + */ +void +__db_txnlist_print(listp) + void *listp; +{ + DB_TXNHEAD *hp; + DB_TXNLIST *p; + + hp = (DB_TXNHEAD *)listp; + + printf("Maxid: %lu Generation: %lu\n", + (u_long)hp->maxid, (u_long)hp->generation); + for (p = LIST_FIRST(&hp->head); p != NULL; p = LIST_NEXT(p, links)) { + switch (p->type) { + case TXNLIST_TXNID: + printf("TXNID: %lu(%lu)\n", + (u_long)p->u.t.txnid, (u_long)p->u.t.generation); + break; + case TXNLIST_DELETE: + printf("FILE: %s id=%d ops=%d %s %s\n", + p->u.d.fname, p->u.d.fileid, p->u.d.count, + F_ISSET(&p->u.d, TXNLIST_FLAG_DELETED) ? + "(deleted)" : "(missing)", + F_ISSET(&p->u.d, TXNLIST_FLAG_CLOSED) ? + "(closed)" : "(open)"); + + break; + default: + printf("Unrecognized type: %d\n", p->type); + break; + } + } +} +#endif diff --git a/db/db/db_dup.c b/db/db/db_dup.c new file mode 100644 index 000000000..6d8b2df95 --- /dev/null +++ b/db/db/db_dup.c @@ -0,0 +1,275 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: db_dup.c,v 11.18 2000/11/30 00:58:32 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_shash.h" +#include "btree.h" +#include "hash.h" +#include "lock.h" +#include "db_am.h" + +/* + * __db_ditem -- + * Remove an item from a page. + * + * PUBLIC: int __db_ditem __P((DBC *, PAGE *, u_int32_t, u_int32_t)); + */ +int +__db_ditem(dbc, pagep, indx, nbytes) + DBC *dbc; + PAGE *pagep; + u_int32_t indx, nbytes; +{ + DB *dbp; + DBT ldbt; + db_indx_t cnt, offset; + int ret; + u_int8_t *from; + + dbp = dbc->dbp; + if (DB_LOGGING(dbc)) { + ldbt.data = P_ENTRY(pagep, indx); + ldbt.size = nbytes; + if ((ret = __db_addrem_log(dbp->dbenv, dbc->txn, + &LSN(pagep), 0, DB_REM_DUP, dbp->log_fileid, PGNO(pagep), + (u_int32_t)indx, nbytes, &ldbt, NULL, &LSN(pagep))) != 0) + return (ret); + } + + /* + * If there's only a single item on the page, we don't have to + * work hard. + */ + if (NUM_ENT(pagep) == 1) { + NUM_ENT(pagep) = 0; + HOFFSET(pagep) = dbp->pgsize; + return (0); + } + + /* + * Pack the remaining key/data items at the end of the page. Use + * memmove(3), the regions may overlap. + */ + from = (u_int8_t *)pagep + HOFFSET(pagep); + memmove(from + nbytes, from, pagep->inp[indx] - HOFFSET(pagep)); + HOFFSET(pagep) += nbytes; + + /* Adjust the indices' offsets. */ + offset = pagep->inp[indx]; + for (cnt = 0; cnt < NUM_ENT(pagep); ++cnt) + if (pagep->inp[cnt] < offset) + pagep->inp[cnt] += nbytes; + + /* Shift the indices down. */ + --NUM_ENT(pagep); + if (indx != NUM_ENT(pagep)) + memmove(&pagep->inp[indx], &pagep->inp[indx + 1], + sizeof(db_indx_t) * (NUM_ENT(pagep) - indx)); + + return (0); +} + +/* + * __db_pitem -- + * Put an item on a page. + * + * PUBLIC: int __db_pitem + * PUBLIC: __P((DBC *, PAGE *, u_int32_t, u_int32_t, DBT *, DBT *)); + */ +int +__db_pitem(dbc, pagep, indx, nbytes, hdr, data) + DBC *dbc; + PAGE *pagep; + u_int32_t indx; + u_int32_t nbytes; + DBT *hdr, *data; +{ + DB *dbp; + BKEYDATA bk; + DBT thdr; + int ret; + u_int8_t *p; + + if (nbytes > P_FREESPACE(pagep)) { + DB_ASSERT(nbytes <= P_FREESPACE(pagep)); + return (EINVAL); + } + /* + * Put a single item onto a page. The logic figuring out where to + * insert and whether it fits is handled in the caller. All we do + * here is manage the page shuffling. We cheat a little bit in that + * we don't want to copy the dbt on a normal put twice. If hdr is + * NULL, we create a BKEYDATA structure on the page, otherwise, just + * copy the caller's information onto the page. + * + * This routine is also used to put entries onto the page where the + * entry is pre-built, e.g., during recovery. In this case, the hdr + * will point to the entry, and the data argument will be NULL. + * + * !!! + * There's a tremendous potential for off-by-one errors here, since + * the passed in header sizes must be adjusted for the structure's + * placeholder for the trailing variable-length data field. + */ + dbp = dbc->dbp; + if (DB_LOGGING(dbc)) + if ((ret = __db_addrem_log(dbp->dbenv, dbc->txn, + &LSN(pagep), 0, DB_ADD_DUP, dbp->log_fileid, PGNO(pagep), + (u_int32_t)indx, nbytes, hdr, data, &LSN(pagep))) != 0) + return (ret); + + if (hdr == NULL) { + B_TSET(bk.type, B_KEYDATA, 0); + bk.len = data == NULL ? 0 : data->size; + + thdr.data = &bk; + thdr.size = SSZA(BKEYDATA, data); + hdr = &thdr; + } + + /* Adjust the index table, then put the item on the page. */ + if (indx != NUM_ENT(pagep)) + memmove(&pagep->inp[indx + 1], &pagep->inp[indx], + sizeof(db_indx_t) * (NUM_ENT(pagep) - indx)); + HOFFSET(pagep) -= nbytes; + pagep->inp[indx] = HOFFSET(pagep); + ++NUM_ENT(pagep); + + p = P_ENTRY(pagep, indx); + memcpy(p, hdr->data, hdr->size); + if (data != NULL) + memcpy(p + hdr->size, data->data, data->size); + + return (0); +} + +/* + * __db_relink -- + * Relink around a deleted page. + * + * PUBLIC: int __db_relink __P((DBC *, u_int32_t, PAGE *, PAGE **, int)); + */ +int +__db_relink(dbc, add_rem, pagep, new_next, needlock) + DBC *dbc; + u_int32_t add_rem; + PAGE *pagep, **new_next; + int needlock; +{ + DB *dbp; + PAGE *np, *pp; + DB_LOCK npl, ppl; + DB_LSN *nlsnp, *plsnp, ret_lsn; + int ret; + + ret = 0; + np = pp = NULL; + npl.off = ppl.off = LOCK_INVALID; + nlsnp = plsnp = NULL; + dbp = dbc->dbp; + + /* + * Retrieve and lock the one/two pages. For a remove, we may need + * two pages (the before and after). For an add, we only need one + * because, the split took care of the prev. + */ + if (pagep->next_pgno != PGNO_INVALID) { + if (needlock && (ret = __db_lget(dbc, + 0, pagep->next_pgno, DB_LOCK_WRITE, 0, &npl)) != 0) + goto err; + if ((ret = memp_fget(dbp->mpf, + &pagep->next_pgno, 0, &np)) != 0) { + (void)__db_pgerr(dbp, pagep->next_pgno); + goto err; + } + nlsnp = &np->lsn; + } + if (add_rem == DB_REM_PAGE && pagep->prev_pgno != PGNO_INVALID) { + if (needlock && (ret = __db_lget(dbc, + 0, pagep->prev_pgno, DB_LOCK_WRITE, 0, &ppl)) != 0) + goto err; + if ((ret = memp_fget(dbp->mpf, + &pagep->prev_pgno, 0, &pp)) != 0) { + (void)__db_pgerr(dbp, pagep->next_pgno); + goto err; + } + plsnp = &pp->lsn; + } + + /* Log the change. */ + if (DB_LOGGING(dbc)) { + if ((ret = __db_relink_log(dbp->dbenv, dbc->txn, + &ret_lsn, 0, add_rem, dbp->log_fileid, + pagep->pgno, &pagep->lsn, + pagep->prev_pgno, plsnp, pagep->next_pgno, nlsnp)) != 0) + goto err; + if (np != NULL) + np->lsn = ret_lsn; + if (pp != NULL) + pp->lsn = ret_lsn; + if (add_rem == DB_REM_PAGE) + pagep->lsn = ret_lsn; + } + + /* + * Modify and release the two pages. + * + * !!! + * The parameter new_next gets set to the page following the page we + * are removing. If there is no following page, then new_next gets + * set to NULL. + */ + if (np != NULL) { + if (add_rem == DB_ADD_PAGE) + np->prev_pgno = pagep->pgno; + else + np->prev_pgno = pagep->prev_pgno; + if (new_next == NULL) + ret = memp_fput(dbp->mpf, np, DB_MPOOL_DIRTY); + else { + *new_next = np; + ret = memp_fset(dbp->mpf, np, DB_MPOOL_DIRTY); + } + if (ret != 0) + goto err; + if (needlock) + (void)__TLPUT(dbc, npl); + } else if (new_next != NULL) + *new_next = NULL; + + if (pp != NULL) { + pp->next_pgno = pagep->next_pgno; + if ((ret = memp_fput(dbp->mpf, pp, DB_MPOOL_DIRTY)) != 0) + goto err; + if (needlock) + (void)__TLPUT(dbc, ppl); + } + return (0); + +err: if (np != NULL) + (void)memp_fput(dbp->mpf, np, 0); + if (needlock && npl.off != LOCK_INVALID) + (void)__TLPUT(dbc, npl); + if (pp != NULL) + (void)memp_fput(dbp->mpf, pp, 0); + if (needlock && ppl.off != LOCK_INVALID) + (void)__TLPUT(dbc, ppl); + return (ret); +} diff --git a/db/db/db_iface.c b/db/db/db_iface.c new file mode 100644 index 000000000..3548a2527 --- /dev/null +++ b/db/db/db_iface.c @@ -0,0 +1,687 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: db_iface.c,v 11.34 2001/01/11 18:19:51 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_am.h" +#include "btree.h" + +static int __db_curinval __P((const DB_ENV *)); +static int __db_rdonly __P((const DB_ENV *, const char *)); +static int __dbt_ferr __P((const DB *, const char *, const DBT *, int)); + +/* + * __db_cursorchk -- + * Common cursor argument checking routine. + * + * PUBLIC: int __db_cursorchk __P((const DB *, u_int32_t, int)); + */ +int +__db_cursorchk(dbp, flags, isrdonly) + const DB *dbp; + u_int32_t flags; + int isrdonly; +{ + /* Check for invalid function flags. */ + switch (flags) { + case 0: + break; + case DB_WRITECURSOR: + if (isrdonly) + return (__db_rdonly(dbp->dbenv, "DB->cursor")); + if (!CDB_LOCKING(dbp->dbenv)) + return (__db_ferr(dbp->dbenv, "DB->cursor", 0)); + break; + case DB_WRITELOCK: + if (isrdonly) + return (__db_rdonly(dbp->dbenv, "DB->cursor")); + break; + default: + return (__db_ferr(dbp->dbenv, "DB->cursor", 0)); + } + + return (0); +} + +/* + * __db_ccountchk -- + * Common cursor count argument checking routine. + * + * PUBLIC: int __db_ccountchk __P((const DB *, u_int32_t, int)); + */ +int +__db_ccountchk(dbp, flags, isvalid) + const DB *dbp; + u_int32_t flags; + int isvalid; +{ + /* Check for invalid function flags. */ + switch (flags) { + case 0: + break; + default: + return (__db_ferr(dbp->dbenv, "DBcursor->c_count", 0)); + } + + /* + * The cursor must be initialized, return EINVAL for an invalid cursor, + * otherwise 0. + */ + return (isvalid ? 0 : __db_curinval(dbp->dbenv)); +} + +/* + * __db_cdelchk -- + * Common cursor delete argument checking routine. + * + * PUBLIC: int __db_cdelchk __P((const DB *, u_int32_t, int, int)); + */ +int +__db_cdelchk(dbp, flags, isrdonly, isvalid) + const DB *dbp; + u_int32_t flags; + int isrdonly, isvalid; +{ + /* Check for changes to a read-only tree. */ + if (isrdonly) + return (__db_rdonly(dbp->dbenv, "c_del")); + + /* Check for invalid function flags. */ + switch (flags) { + case 0: + break; + default: + return (__db_ferr(dbp->dbenv, "DBcursor->c_del", 0)); + } + + /* + * The cursor must be initialized, return EINVAL for an invalid cursor, + * otherwise 0. + */ + return (isvalid ? 0 : __db_curinval(dbp->dbenv)); +} + +/* + * __db_cgetchk -- + * Common cursor get argument checking routine. + * + * PUBLIC: int __db_cgetchk __P((const DB *, DBT *, DBT *, u_int32_t, int)); + */ +int +__db_cgetchk(dbp, key, data, flags, isvalid) + const DB *dbp; + DBT *key, *data; + u_int32_t flags; + int isvalid; +{ + int ret; + + /* + * Check for read-modify-write validity. DB_RMW doesn't make sense + * with CDB cursors since if you're going to write the cursor, you + * had to create it with DB_WRITECURSOR. Regardless, we check for + * LOCKING_ON and not STD_LOCKING, as we don't want to disallow it. + * If this changes, confirm that DB does not itself set the DB_RMW + * flag in a path where CDB may have been configured. + */ + if (LF_ISSET(DB_RMW)) { + if (!LOCKING_ON(dbp->dbenv)) { + __db_err(dbp->dbenv, + "the DB_RMW flag requires locking"); + return (EINVAL); + } + LF_CLR(DB_RMW); + } + + /* Check for invalid function flags. */ + switch (flags) { + case DB_CONSUME: + case DB_CONSUME_WAIT: + if (dbp->type != DB_QUEUE) + goto err; + break; + case DB_CURRENT: + case DB_FIRST: + case DB_GET_BOTH: + case DB_LAST: + case DB_NEXT: + case DB_NEXT_DUP: + case DB_NEXT_NODUP: + case DB_PREV: + case DB_PREV_NODUP: + case DB_SET: + case DB_SET_RANGE: + break; + case DB_GET_BOTHC: + if (dbp->type == DB_QUEUE) + goto err; + break; + case DB_GET_RECNO: + if (!F_ISSET(dbp, DB_BT_RECNUM)) + goto err; + break; + case DB_SET_RECNO: + if (!F_ISSET(dbp, DB_BT_RECNUM)) + goto err; + break; + default: +err: return (__db_ferr(dbp->dbenv, "DBcursor->c_get", 0)); + } + + /* Check for invalid key/data flags. */ + if ((ret = __dbt_ferr(dbp, "key", key, 0)) != 0) + return (ret); + if ((ret = __dbt_ferr(dbp, "data", data, 0)) != 0) + return (ret); + + /* + * The cursor must be initialized for DB_CURRENT or DB_NEXT_DUP, + * return EINVAL for an invalid cursor, otherwise 0. + */ + if (isvalid || (flags != DB_CURRENT && flags != DB_NEXT_DUP)) + return (0); + + return (__db_curinval(dbp->dbenv)); +} + +/* + * __db_cputchk -- + * Common cursor put argument checking routine. + * + * PUBLIC: int __db_cputchk __P((const DB *, + * PUBLIC: const DBT *, DBT *, u_int32_t, int, int)); + */ +int +__db_cputchk(dbp, key, data, flags, isrdonly, isvalid) + const DB *dbp; + const DBT *key; + DBT *data; + u_int32_t flags; + int isrdonly, isvalid; +{ + int key_flags, ret; + + key_flags = 0; + + /* Check for changes to a read-only tree. */ + if (isrdonly) + return (__db_rdonly(dbp->dbenv, "c_put")); + + /* Check for invalid function flags. */ + switch (flags) { + case DB_AFTER: + case DB_BEFORE: + switch (dbp->type) { + case DB_BTREE: + case DB_HASH: /* Only with unsorted duplicates. */ + if (!F_ISSET(dbp, DB_AM_DUP)) + goto err; + if (dbp->dup_compare != NULL) + goto err; + break; + case DB_QUEUE: /* Not permitted. */ + goto err; + case DB_RECNO: /* Only with mutable record numbers. */ + if (!F_ISSET(dbp, DB_RE_RENUMBER)) + goto err; + key_flags = 1; + break; + default: + goto err; + } + break; + case DB_CURRENT: + /* + * If there is a comparison function, doing a DB_CURRENT + * must not change the part of the data item that is used + * for the comparison. + */ + break; + case DB_NODUPDATA: + if (!F_ISSET(dbp, DB_AM_DUPSORT)) + goto err; + /* FALLTHROUGH */ + case DB_KEYFIRST: + case DB_KEYLAST: + if (dbp->type == DB_QUEUE || dbp->type == DB_RECNO) + goto err; + key_flags = 1; + break; + default: +err: return (__db_ferr(dbp->dbenv, "DBcursor->c_put", 0)); + } + + /* Check for invalid key/data flags. */ + if (key_flags && (ret = __dbt_ferr(dbp, "key", key, 0)) != 0) + return (ret); + if ((ret = __dbt_ferr(dbp, "data", data, 0)) != 0) + return (ret); + + /* + * The cursor must be initialized for anything other than DB_KEYFIRST + * and DB_KEYLAST, return EINVAL for an invalid cursor, otherwise 0. + */ + if (isvalid || flags == DB_KEYFIRST || + flags == DB_KEYLAST || flags == DB_NODUPDATA) + return (0); + + return (__db_curinval(dbp->dbenv)); +} + +/* + * __db_closechk -- + * DB->close flag check. + * + * PUBLIC: int __db_closechk __P((const DB *, u_int32_t)); + */ +int +__db_closechk(dbp, flags) + const DB *dbp; + u_int32_t flags; +{ + /* Check for invalid function flags. */ + switch (flags) { + case 0: + case DB_NOSYNC: + break; + default: + return (__db_ferr(dbp->dbenv, "DB->close", 0)); + } + + return (0); +} + +/* + * __db_delchk -- + * Common delete argument checking routine. + * + * PUBLIC: int __db_delchk __P((const DB *, DBT *, u_int32_t, int)); + */ +int +__db_delchk(dbp, key, flags, isrdonly) + const DB *dbp; + DBT *key; + u_int32_t flags; + int isrdonly; +{ + COMPQUIET(key, NULL); + + /* Check for changes to a read-only tree. */ + if (isrdonly) + return (__db_rdonly(dbp->dbenv, "delete")); + + /* Check for invalid function flags. */ + switch (flags) { + case 0: + break; + default: + return (__db_ferr(dbp->dbenv, "DB->del", 0)); + } + + return (0); +} + +/* + * __db_getchk -- + * Common get argument checking routine. + * + * PUBLIC: int __db_getchk __P((const DB *, const DBT *, DBT *, u_int32_t)); + */ +int +__db_getchk(dbp, key, data, flags) + const DB *dbp; + const DBT *key; + DBT *data; + u_int32_t flags; +{ + int ret; + + /* + * Check for read-modify-write validity. DB_RMW doesn't make sense + * with CDB cursors since if you're going to write the cursor, you + * had to create it with DB_WRITECURSOR. Regardless, we check for + * LOCKING_ON and not STD_LOCKING, as we don't want to disallow it. + * If this changes, confirm that DB does not itself set the DB_RMW + * flag in a path where CDB may have been configured. + */ + if (LF_ISSET(DB_RMW)) { + if (!LOCKING_ON(dbp->dbenv)) { + __db_err(dbp->dbenv, + "the DB_RMW flag requires locking"); + return (EINVAL); + } + LF_CLR(DB_RMW); + } + + /* Check for invalid function flags. */ + switch (flags) { + case 0: + case DB_GET_BOTH: + break; + case DB_SET_RECNO: + if (!F_ISSET(dbp, DB_BT_RECNUM)) + goto err; + break; + case DB_CONSUME: + case DB_CONSUME_WAIT: + if (dbp->type == DB_QUEUE) + break; + /* Fall through */ + default: +err: return (__db_ferr(dbp->dbenv, "DB->get", 0)); + } + + /* Check for invalid key/data flags. */ + if ((ret = __dbt_ferr(dbp, "key", key, flags == DB_SET_RECNO)) != 0) + return (ret); + if ((ret = __dbt_ferr(dbp, "data", data, 1)) != 0) + return (ret); + + return (0); +} + +/* + * __db_joinchk -- + * Common join argument checking routine. + * + * PUBLIC: int __db_joinchk __P((const DB *, DBC * const *, u_int32_t)); + */ +int +__db_joinchk(dbp, curslist, flags) + const DB *dbp; + DBC * const *curslist; + u_int32_t flags; +{ + DB_TXN *txn; + int i; + + switch (flags) { + case 0: + case DB_JOIN_NOSORT: + break; + default: + return (__db_ferr(dbp->dbenv, "DB->join", 0)); + } + + if (curslist == NULL || curslist[0] == NULL) { + __db_err(dbp->dbenv, + "At least one secondary cursor must be specified to DB->join"); + return (EINVAL); + } + + txn = curslist[0]->txn; + for (i = 1; curslist[i] != NULL; i++) + if (curslist[i]->txn != txn) { + __db_err(dbp->dbenv, + "All secondary cursors must share the same transaction"); + return (EINVAL); + } + + return (0); +} + +/* + * __db_joingetchk -- + * Common join_get argument checking routine. + * + * PUBLIC: int __db_joingetchk __P((const DB *, DBT *, u_int32_t)); + */ +int +__db_joingetchk(dbp, key, flags) + const DB *dbp; + DBT *key; + u_int32_t flags; +{ + + if (LF_ISSET(DB_RMW)) { + if (!LOCKING_ON(dbp->dbenv)) { + __db_err(dbp->dbenv, + "the DB_RMW flag requires locking"); + return (EINVAL); + } + LF_CLR(DB_RMW); + } + + switch (flags) { + case 0: + case DB_JOIN_ITEM: + break; + default: + return (__db_ferr(dbp->dbenv, "DBcursor->c_get", 0)); + } + + /* + * A partial get of the key of a join cursor don't make much sense; + * the entire key is necessary to query the primary database + * and find the datum, and so regardless of the size of the key + * it would not be a performance improvement. Since it would require + * special handling, we simply disallow it. + * + * A partial get of the data, however, potentially makes sense (if + * all possible data are a predictable large structure, for instance) + * and causes us no headaches, so we permit it. + */ + if (F_ISSET(key, DB_DBT_PARTIAL)) { + __db_err(dbp->dbenv, + "DB_DBT_PARTIAL may not be set on key during join_get"); + return (EINVAL); + } + + return (0); +} + +/* + * __db_putchk -- + * Common put argument checking routine. + * + * PUBLIC: int __db_putchk + * PUBLIC: __P((const DB *, DBT *, const DBT *, u_int32_t, int, int)); + */ +int +__db_putchk(dbp, key, data, flags, isrdonly, isdup) + const DB *dbp; + DBT *key; + const DBT *data; + u_int32_t flags; + int isrdonly, isdup; +{ + int ret; + + /* Check for changes to a read-only tree. */ + if (isrdonly) + return (__db_rdonly(dbp->dbenv, "put")); + + /* Check for invalid function flags. */ + switch (flags) { + case 0: + case DB_NOOVERWRITE: + break; + case DB_APPEND: + if (dbp->type != DB_RECNO && dbp->type != DB_QUEUE) + goto err; + break; + case DB_NODUPDATA: + if (F_ISSET(dbp, DB_AM_DUPSORT)) + break; + /* FALLTHROUGH */ + default: +err: return (__db_ferr(dbp->dbenv, "DB->put", 0)); + } + + /* Check for invalid key/data flags. */ + if ((ret = __dbt_ferr(dbp, "key", key, 0)) != 0) + return (ret); + if ((ret = __dbt_ferr(dbp, "data", data, 0)) != 0) + return (ret); + + /* Check for partial puts in the presence of duplicates. */ + if (isdup && F_ISSET(data, DB_DBT_PARTIAL)) { + __db_err(dbp->dbenv, +"a partial put in the presence of duplicates requires a cursor operation"); + return (EINVAL); + } + + return (0); +} + +/* + * __db_removechk -- + * DB->remove flag check. + * + * PUBLIC: int __db_removechk __P((const DB *, u_int32_t)); + */ +int +__db_removechk(dbp, flags) + const DB *dbp; + u_int32_t flags; +{ + /* Check for invalid function flags. */ + switch (flags) { + case 0: + break; + default: + return (__db_ferr(dbp->dbenv, "DB->remove", 0)); + } + + return (0); +} + +/* + * __db_statchk -- + * Common stat argument checking routine. + * + * PUBLIC: int __db_statchk __P((const DB *, u_int32_t)); + */ +int +__db_statchk(dbp, flags) + const DB *dbp; + u_int32_t flags; +{ + /* Check for invalid function flags. */ + switch (flags) { + case 0: + case DB_CACHED_COUNTS: + break; + case DB_RECORDCOUNT: + if (dbp->type == DB_RECNO) + break; + if (dbp->type == DB_BTREE && F_ISSET(dbp, DB_BT_RECNUM)) + break; + goto err; + default: +err: return (__db_ferr(dbp->dbenv, "DB->stat", 0)); + } + + return (0); +} + +/* + * __db_syncchk -- + * Common sync argument checking routine. + * + * PUBLIC: int __db_syncchk __P((const DB *, u_int32_t)); + */ +int +__db_syncchk(dbp, flags) + const DB *dbp; + u_int32_t flags; +{ + /* Check for invalid function flags. */ + switch (flags) { + case 0: + break; + default: + return (__db_ferr(dbp->dbenv, "DB->sync", 0)); + } + + return (0); +} + +/* + * __dbt_ferr -- + * Check a DBT for flag errors. + */ +static int +__dbt_ferr(dbp, name, dbt, check_thread) + const DB *dbp; + const char *name; + const DBT *dbt; + int check_thread; +{ + DB_ENV *dbenv; + int ret; + + dbenv = dbp->dbenv; + + /* + * Check for invalid DBT flags. We allow any of the flags to be + * specified to any DB or DBcursor call so that applications can + * set DB_DBT_MALLOC when retrieving a data item from a secondary + * database and then specify that same DBT as a key to a primary + * database, without having to clear flags. + */ + if ((ret = __db_fchk(dbenv, name, dbt->flags, + DB_DBT_MALLOC | DB_DBT_DUPOK | + DB_DBT_REALLOC | DB_DBT_USERMEM | DB_DBT_PARTIAL)) != 0) + return (ret); + switch (F_ISSET(dbt, DB_DBT_MALLOC | DB_DBT_REALLOC | DB_DBT_USERMEM)) { + case 0: + case DB_DBT_MALLOC: + case DB_DBT_REALLOC: + case DB_DBT_USERMEM: + break; + default: + return (__db_ferr(dbenv, name, 1)); + } + + if (check_thread && DB_IS_THREADED(dbp) && + !F_ISSET(dbt, DB_DBT_MALLOC | DB_DBT_REALLOC | DB_DBT_USERMEM)) { + __db_err(dbenv, + "DB_THREAD mandates memory allocation flag on DBT %s", + name); + return (EINVAL); + } + return (0); +} + +/* + * __db_rdonly -- + * Common readonly message. + */ +static int +__db_rdonly(dbenv, name) + const DB_ENV *dbenv; + const char *name; +{ + __db_err(dbenv, "%s: attempt to modify a read-only tree", name); + return (EACCES); +} + +/* + * __db_curinval + * Report that a cursor is in an invalid state. + */ +static int +__db_curinval(dbenv) + const DB_ENV *dbenv; +{ + __db_err(dbenv, + "Cursor position must be set before performing this operation"); + return (EINVAL); +} diff --git a/db/db/db_join.c b/db/db/db_join.c new file mode 100644 index 000000000..881dedde0 --- /dev/null +++ b/db/db/db_join.c @@ -0,0 +1,730 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: db_join.c,v 11.31 2000/12/20 22:41:54 krinsky Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_join.h" +#include "db_am.h" +#include "btree.h" + +static int __db_join_close __P((DBC *)); +static int __db_join_cmp __P((const void *, const void *)); +static int __db_join_del __P((DBC *, u_int32_t)); +static int __db_join_get __P((DBC *, DBT *, DBT *, u_int32_t)); +static int __db_join_getnext __P((DBC *, DBT *, DBT *, u_int32_t)); +static int __db_join_put __P((DBC *, DBT *, DBT *, u_int32_t)); + +/* + * Check to see if the Nth secondary cursor of join cursor jc is pointing + * to a sorted duplicate set. + */ +#define SORTED_SET(jc, n) ((jc)->j_curslist[(n)]->dbp->dup_compare != NULL) + +/* + * This is the duplicate-assisted join functionality. Right now we're + * going to write it such that we return one item at a time, although + * I think we may need to optimize it to return them all at once. + * It should be easier to get it working this way, and I believe that + * changing it should be fairly straightforward. + * + * We optimize the join by sorting cursors from smallest to largest + * cardinality. In most cases, this is indeed optimal. However, if + * a cursor with large cardinality has very few data in common with the + * first cursor, it is possible that the join will be made faster by + * putting it earlier in the cursor list. Since we have no way to detect + * cases like this, we simply provide a flag, DB_JOIN_NOSORT, which retains + * the sort order specified by the caller, who may know more about the + * structure of the data. + * + * The first cursor moves sequentially through the duplicate set while + * the others search explicitly for the duplicate in question. + * + */ + +/* + * __db_join -- + * This is the interface to the duplicate-assisted join functionality. + * In the same way that cursors mark a position in a database, a cursor + * can mark a position in a join. While most cursors are created by the + * cursor method of a DB, join cursors are created through an explicit + * call to DB->join. + * + * The curslist is an array of existing, intialized cursors and primary + * is the DB of the primary file. The data item that joins all the + * cursors in the curslist is used as the key into the primary and that + * key and data are returned. When no more items are left in the join + * set, the c_next operation off the join cursor will return DB_NOTFOUND. + * + * PUBLIC: int __db_join __P((DB *, DBC **, DBC **, u_int32_t)); + */ +int +__db_join(primary, curslist, dbcp, flags) + DB *primary; + DBC **curslist, **dbcp; + u_int32_t flags; +{ + DB_ENV *dbenv; + DBC *dbc; + JOIN_CURSOR *jc; + int ret; + u_int32_t i, ncurs, nslots; + + COMPQUIET(nslots, 0); + + PANIC_CHECK(primary->dbenv); + + if ((ret = __db_joinchk(primary, curslist, flags)) != 0) + return (ret); + + dbc = NULL; + jc = NULL; + dbenv = primary->dbenv; + + if ((ret = __os_calloc(dbenv, 1, sizeof(DBC), &dbc)) != 0) + goto err; + + if ((ret = __os_calloc(dbenv, + 1, sizeof(JOIN_CURSOR), &jc)) != 0) + goto err; + + if ((ret = __os_malloc(dbenv, 256, NULL, &jc->j_key.data)) != 0) + goto err; + jc->j_key.ulen = 256; + F_SET(&jc->j_key, DB_DBT_USERMEM); + + for (jc->j_curslist = curslist; + *jc->j_curslist != NULL; jc->j_curslist++) + ; + + /* + * The number of cursor slots we allocate is one greater than + * the number of cursors involved in the join, because the + * list is NULL-terminated. + */ + ncurs = jc->j_curslist - curslist; + nslots = ncurs + 1; + + /* + * !!! -- A note on the various lists hanging off jc. + * + * j_curslist is the initial NULL-terminated list of cursors passed + * into __db_join. The original cursors are not modified; pristine + * copies are required because, in databases with unsorted dups, we + * must reset all of the secondary cursors after the first each + * time the first one is incremented, or else we will lose data + * which happen to be sorted differently in two different cursors. + * + * j_workcurs is where we put those copies that we're planning to + * work with. They're lazily c_dup'ed from j_curslist as we need + * them, and closed when the join cursor is closed or when we need + * to reset them to their original values (in which case we just + * c_dup afresh). + * + * j_fdupcurs is an array of cursors which point to the first + * duplicate in the duplicate set that contains the data value + * we're currently interested in. We need this to make + * __db_join_get correctly return duplicate duplicates; i.e., if a + * given data value occurs twice in the set belonging to cursor #2, + * and thrice in the set belonging to cursor #3, and once in all + * the other cursors, successive calls to __db_join_get need to + * return that data item six times. To make this happen, each time + * cursor N is allowed to advance to a new datum, all cursors M + * such that M > N have to be reset to the first duplicate with + * that datum, so __db_join_get will return all the dup-dups again. + * We could just reset them to the original cursor from j_curslist, + * but that would be a bit slower in the unsorted case and a LOT + * slower in the sorted one. + * + * j_exhausted is a list of boolean values which represent + * whether or not their corresponding cursors are "exhausted", + * i.e. whether the datum under the corresponding cursor has + * been found not to exist in any unreturned combinations of + * later secondary cursors, in which case they are ready to be + * incremented. + */ + + /* We don't want to free regions whose callocs have failed. */ + jc->j_curslist = NULL; + jc->j_workcurs = NULL; + jc->j_fdupcurs = NULL; + jc->j_exhausted = NULL; + + if ((ret = __os_calloc(dbenv, nslots, sizeof(DBC *), + &jc->j_curslist)) != 0) + goto err; + if ((ret = __os_calloc(dbenv, nslots, sizeof(DBC *), + &jc->j_workcurs)) != 0) + goto err; + if ((ret = __os_calloc(dbenv, nslots, sizeof(DBC *), + &jc->j_fdupcurs)) != 0) + goto err; + if ((ret = __os_calloc(dbenv, nslots, sizeof(u_int8_t), + &jc->j_exhausted)) != 0) + goto err; + for (i = 0; curslist[i] != NULL; i++) { + jc->j_curslist[i] = curslist[i]; + jc->j_workcurs[i] = NULL; + jc->j_fdupcurs[i] = NULL; + jc->j_exhausted[i] = 0; + } + jc->j_ncurs = ncurs; + + /* + * If DB_JOIN_NOSORT is not set, optimize secondary cursors by + * sorting in order of increasing cardinality. + */ + if (!LF_ISSET(DB_JOIN_NOSORT)) + qsort(jc->j_curslist, ncurs, sizeof(DBC *), __db_join_cmp); + + /* + * We never need to reset the 0th cursor, so there's no + * solid reason to use workcurs[0] rather than curslist[0] in + * join_get. Nonetheless, it feels cleaner to do it for symmetry, + * and this is the most logical place to copy it. + * + * !!! + * There's no need to close the new cursor if we goto err only + * because this is the last thing that can fail. Modifier of this + * function beware! + */ + if ((ret = jc->j_curslist[0]->c_dup(jc->j_curslist[0], jc->j_workcurs, + DB_POSITIONI)) != 0) + goto err; + + dbc->c_close = __db_join_close; + dbc->c_del = __db_join_del; + dbc->c_get = __db_join_get; + dbc->c_put = __db_join_put; + dbc->internal = (DBC_INTERNAL *) jc; + dbc->dbp = primary; + jc->j_primary = primary; + + *dbcp = dbc; + + MUTEX_THREAD_LOCK(dbenv, primary->mutexp); + TAILQ_INSERT_TAIL(&primary->join_queue, dbc, links); + MUTEX_THREAD_UNLOCK(dbenv, primary->mutexp); + + return (0); + +err: if (jc != NULL) { + if (jc->j_curslist != NULL) + __os_free(jc->j_curslist, nslots * sizeof(DBC *)); + if (jc->j_workcurs != NULL) { + if (jc->j_workcurs[0] != NULL) + __os_free(jc->j_workcurs[0], sizeof(DBC)); + __os_free(jc->j_workcurs, nslots * sizeof(DBC *)); + } + if (jc->j_fdupcurs != NULL) + __os_free(jc->j_fdupcurs, nslots * sizeof(DBC *)); + if (jc->j_exhausted != NULL) + __os_free(jc->j_exhausted, nslots * sizeof(u_int8_t)); + __os_free(jc, sizeof(JOIN_CURSOR)); + } + if (dbc != NULL) + __os_free(dbc, sizeof(DBC)); + return (ret); +} + +static int +__db_join_put(dbc, key, data, flags) + DBC *dbc; + DBT *key; + DBT *data; + u_int32_t flags; +{ + PANIC_CHECK(dbc->dbp->dbenv); + + COMPQUIET(key, NULL); + COMPQUIET(data, NULL); + COMPQUIET(flags, 0); + return (EINVAL); +} + +static int +__db_join_del(dbc, flags) + DBC *dbc; + u_int32_t flags; +{ + PANIC_CHECK(dbc->dbp->dbenv); + + COMPQUIET(flags, 0); + return (EINVAL); +} + +static int +__db_join_get(dbc, key_arg, data_arg, flags) + DBC *dbc; + DBT *key_arg, *data_arg; + u_int32_t flags; +{ + DBT *key_n, key_n_mem; + DB *dbp; + DBC *cp; + JOIN_CURSOR *jc; + int ret; + u_int32_t i, j, operation; + + dbp = dbc->dbp; + jc = (JOIN_CURSOR *)dbc->internal; + + PANIC_CHECK(dbp->dbenv); + + operation = LF_ISSET(DB_OPFLAGS_MASK); + + if ((ret = __db_joingetchk(dbp, key_arg, flags)) != 0) + return (ret); + + /* + * Since we are fetching the key as a datum in the secondary indices, + * we must be careful of caller-specified DB_DBT_* memory + * management flags. If necessary, use a stack-allocated DBT; + * we'll appropriately copy and/or allocate the data later. + */ + if (F_ISSET(key_arg, DB_DBT_USERMEM) || + F_ISSET(key_arg, DB_DBT_MALLOC)) { + /* We just use the default buffer; no need to go malloc. */ + key_n = &key_n_mem; + memset(key_n, 0, sizeof(DBT)); + } else { + /* + * Either DB_DBT_REALLOC or the default buffer will work + * fine if we have to reuse it, as we do. + */ + key_n = key_arg; + } + + /* + * If our last attempt to do a get on the primary key failed, + * short-circuit the join and try again with the same key. + */ + if (F_ISSET(jc, JOIN_RETRY)) + goto samekey; + F_CLR(jc, JOIN_RETRY); + +retry: ret = jc->j_workcurs[0]->c_get(jc->j_workcurs[0], + &jc->j_key, key_n, jc->j_exhausted[0] ? DB_NEXT_DUP : DB_CURRENT); + + if (ret == ENOMEM) { + jc->j_key.ulen <<= 1; + if ((ret = __os_realloc(dbp->dbenv, + jc->j_key.ulen, NULL, &jc->j_key.data)) != 0) + goto mem_err; + goto retry; + } + + /* + * If ret == DB_NOTFOUND, we're out of elements of the first + * secondary cursor. This is how we finally finish the join + * if all goes well. + */ + if (ret != 0) + goto err; + + /* + * If jc->j_exhausted[0] == 1, we've just advanced the first cursor, + * and we're going to want to advance all the cursors that point to + * the first member of a duplicate duplicate set (j_fdupcurs[1..N]). + * Close all the cursors in j_fdupcurs; we'll reopen them the + * first time through the upcoming loop. + */ + for (i = 1; i < jc->j_ncurs; i++) { + if (jc->j_fdupcurs[i] != NULL && + (ret = jc->j_fdupcurs[i]->c_close(jc->j_fdupcurs[i])) != 0) + goto err; + jc->j_fdupcurs[i] = NULL; + } + + /* + * If jc->j_curslist[1] == NULL, we have only one cursor in the join. + * Thus, we can safely increment that one cursor on each call + * to __db_join_get, and we signal this by setting jc->j_exhausted[0] + * right away. + * + * Otherwise, reset jc->j_exhausted[0] to 0, so that we don't + * increment it until we know we're ready to. + */ + if (jc->j_curslist[1] == NULL) + jc->j_exhausted[0] = 1; + else + jc->j_exhausted[0] = 0; + + /* We have the first element; now look for it in the other cursors. */ + for (i = 1; i < jc->j_ncurs; i++) { + DB_ASSERT(jc->j_curslist[i] != NULL); + if (jc->j_workcurs[i] == NULL) + /* If this is NULL, we need to dup curslist into it. */ + if ((ret = jc->j_curslist[i]->c_dup( + jc->j_curslist[i], jc->j_workcurs + i, + DB_POSITIONI)) != 0) + goto err; + +retry2: cp = jc->j_workcurs[i]; + + if ((ret = __db_join_getnext(cp, &jc->j_key, key_n, + jc->j_exhausted[i])) == DB_NOTFOUND) { + /* + * jc->j_workcurs[i] has no more of the datum we're + * interested in. Go back one cursor and get + * a new dup. We can't just move to a new + * element of the outer relation, because that way + * we might miss duplicate duplicates in cursor i-1. + * + * If this takes us back to the first cursor, + * -then- we can move to a new element of the outer + * relation. + */ + --i; + jc->j_exhausted[i] = 1; + + if (i == 0) { + for (j = 1; jc->j_workcurs[j] != NULL; j++) { + /* + * We're moving to a new element of + * the first secondary cursor. If + * that cursor is sorted, then any + * other sorted cursors can be safely + * reset to the first duplicate + * duplicate in the current set if we + * have a pointer to it (we can't just + * leave them be, or we'll miss + * duplicate duplicates in the outer + * relation). + * + * If the first cursor is unsorted, or + * if cursor j is unsorted, we can + * make no assumptions about what + * we're looking for next or where it + * will be, so we reset to the very + * beginning (setting workcurs NULL + * will achieve this next go-round). + * + * XXX: This is likely to break + * horribly if any two cursors are + * both sorted, but have different + * specified sort functions. For, + * now, we dismiss this as pathology + * and let strange things happen--we + * can't make rope childproof. + */ + if ((ret = jc->j_workcurs[j]->c_close( + jc->j_workcurs[j])) != 0) + goto err; + if (!SORTED_SET(jc, 0) || + !SORTED_SET(jc, j) || + jc->j_fdupcurs[j] == NULL) + /* + * Unsafe conditions; + * reset fully. + */ + jc->j_workcurs[j] = NULL; + else + /* Partial reset suffices. */ + if ((jc->j_fdupcurs[j]->c_dup( + jc->j_fdupcurs[j], + &jc->j_workcurs[j], + DB_POSITIONI)) != 0) + goto err; + jc->j_exhausted[j] = 0; + } + goto retry; + /* NOTREACHED */ + } + + /* + * We're about to advance the cursor and need to + * reset all of the workcurs[j] where j>i, so that + * we don't miss any duplicate duplicates. + */ + for (j = i + 1; + jc->j_workcurs[j] != NULL; + j++) { + if ((ret = jc->j_workcurs[j]->c_close( + jc->j_workcurs[j])) != 0) + goto err; + jc->j_exhausted[j] = 0; + if (jc->j_fdupcurs[j] != NULL && + (ret = jc->j_fdupcurs[j]->c_dup( + jc->j_fdupcurs[j], &jc->j_workcurs[j], + DB_POSITIONI)) != 0) + goto err; + else + jc->j_workcurs[j] = NULL; + } + goto retry2; + /* NOTREACHED */ + } + + if (ret == ENOMEM) { + jc->j_key.ulen <<= 1; + if ((ret = __os_realloc(dbp->dbenv, jc->j_key.ulen, + NULL, &jc->j_key.data)) != 0) { +mem_err: __db_err(dbp->dbenv, + "Allocation failed for join key, len = %lu", + (u_long)jc->j_key.ulen); + goto err; + } + goto retry2; + } + + if (ret != 0) + goto err; + + /* + * If we made it this far, we've found a matching + * datum in cursor i. Mark the current cursor + * unexhausted, so we don't miss any duplicate + * duplicates the next go-round--unless this is the + * very last cursor, in which case there are none to + * miss, and we'll need that exhausted flag to finally + * get a DB_NOTFOUND and move on to the next datum in + * the outermost cursor. + */ + if (i + 1 != jc->j_ncurs) + jc->j_exhausted[i] = 0; + else + jc->j_exhausted[i] = 1; + + /* + * If jc->j_fdupcurs[i] is NULL and the ith cursor's dups are + * sorted, then we're here for the first time since advancing + * cursor 0, and we have a new datum of interest. + * jc->j_workcurs[i] points to the beginning of a set of + * duplicate duplicates; store this into jc->j_fdupcurs[i]. + */ + if (SORTED_SET(jc, i) && jc->j_fdupcurs[i] == NULL && (ret = + cp->c_dup(cp, &jc->j_fdupcurs[i], DB_POSITIONI)) != 0) + goto err; + + } + +err: if (ret != 0) + return (ret); + + if (0) { +samekey: /* + * Get the key we tried and failed to return last time; + * it should be the current datum of all the secondary cursors. + */ + if ((ret = jc->j_workcurs[0]->c_get(jc->j_workcurs[0], + &jc->j_key, key_n, DB_CURRENT)) != 0) + return (ret); + F_CLR(jc, JOIN_RETRY); + } + + /* + * ret == 0; we have a key to return. + * + * If DB_DBT_USERMEM or DB_DBT_MALLOC is set, we need to + * copy it back into the dbt we were given for the key; + * call __db_retcopy. + * + * Otherwise, assert that we do not in fact need to copy anything + * and simply proceed. + */ + if (F_ISSET(key_arg, DB_DBT_USERMEM) || + F_ISSET(key_arg, DB_DBT_MALLOC)) { + /* + * We need to copy the key back into our original + * datum. Do so. + */ + if ((ret = __db_retcopy(dbp, + key_arg, key_n->data, key_n->size, NULL, NULL)) != 0) { + /* + * The retcopy failed, most commonly because we + * have a user buffer for the key which is too small. + * Set things up to retry next time, and return. + */ + F_SET(jc, JOIN_RETRY); + return (ret); + } + } else + DB_ASSERT(key_n == key_arg); + + /* + * If DB_JOIN_ITEM is + * set, we return it; otherwise we do the lookup in the + * primary and then return. + * + * Note that we use key_arg here; it is safe (and appropriate) + * to do so. + */ + if (operation == DB_JOIN_ITEM) + return (0); + + if ((ret = jc->j_primary->get(jc->j_primary, + jc->j_curslist[0]->txn, key_arg, data_arg, 0)) != 0) + /* + * The get on the primary failed, most commonly because we're + * using a user buffer that's not big enough. Flag our + * failure so we can return the same key next time. + */ + F_SET(jc, JOIN_RETRY); + + return (ret); +} + +static int +__db_join_close(dbc) + DBC *dbc; +{ + DB *dbp; + JOIN_CURSOR *jc; + int ret, t_ret; + u_int32_t i; + + jc = (JOIN_CURSOR *)dbc->internal; + dbp = dbc->dbp; + ret = t_ret = 0; + + /* + * Remove from active list of join cursors. Note that this + * must happen before any action that can fail and return, or else + * __db_close may loop indefinitely. + */ + MUTEX_THREAD_LOCK(dbp->dbenv, dbp->mutexp); + TAILQ_REMOVE(&dbp->join_queue, dbc, links); + MUTEX_THREAD_UNLOCK(dbp->dbenv, dbp->mutexp); + + PANIC_CHECK(dbc->dbp->dbenv); + + /* + * Close any open scratch cursors. In each case, there may + * not be as many outstanding as there are cursors in + * curslist, but we want to close whatever's there. + * + * If any close fails, there's no reason not to close everything else; + * we'll just return the error code of the last one to fail. There's + * not much the caller can do anyway, since these cursors only exist + * hanging off a db-internal data structure that they shouldn't be + * mucking with. + */ + for (i = 0; i < jc->j_ncurs; i++) { + if (jc->j_workcurs[i] != NULL && (t_ret = + jc->j_workcurs[i]->c_close(jc->j_workcurs[i])) != 0) + ret = t_ret; + if (jc->j_fdupcurs[i] != NULL && (t_ret = + jc->j_fdupcurs[i]->c_close(jc->j_fdupcurs[i])) != 0) + ret = t_ret; + } + + __os_free(jc->j_exhausted, 0); + __os_free(jc->j_curslist, 0); + __os_free(jc->j_workcurs, 0); + __os_free(jc->j_fdupcurs, 0); + __os_free(jc->j_key.data, jc->j_key.ulen); + __os_free(jc, sizeof(JOIN_CURSOR)); + __os_free(dbc, sizeof(DBC)); + + return (ret); +} + +/* + * __db_join_getnext -- + * This function replaces the DBC_CONTINUE and DBC_KEYSET + * functionality inside the various cursor get routines. + * + * If exhausted == 0, we're not done with the current datum; + * return it if it matches "matching", otherwise search + * using DB_GET_BOTHC (which is faster than iteratively doing + * DB_NEXT_DUP) forward until we find one that does. + * + * If exhausted == 1, we are done with the current datum, so just + * leap forward to searching NEXT_DUPs. + * + * If no matching datum exists, returns DB_NOTFOUND, else 0. + */ +static int +__db_join_getnext(dbc, key, data, exhausted) + DBC *dbc; + DBT *key, *data; + u_int32_t exhausted; +{ + int ret, cmp; + DB *dbp; + DBT ldata; + int (*func) __P((DB *, const DBT *, const DBT *)); + + dbp = dbc->dbp; + func = (dbp->dup_compare == NULL) ? __bam_defcmp : dbp->dup_compare; + + switch (exhausted) { + case 0: + memset(&ldata, 0, sizeof(DBT)); + /* We don't want to step on data->data; malloc. */ + F_SET(&ldata, DB_DBT_MALLOC); + if ((ret = dbc->c_get(dbc, key, &ldata, DB_CURRENT)) != 0) + break; + cmp = func(dbp, data, &ldata); + if (cmp == 0) { + /* + * We have to return the real data value. Copy + * it into data, then free the buffer we malloc'ed + * above. + */ + if ((ret = __db_retcopy(dbp, data, ldata.data, + ldata.size, &data->data, &data->size)) != 0) + return (ret); + __os_free(ldata.data, 0); + return (0); + } + + /* + * Didn't match--we want to fall through and search future + * dups. We just forget about ldata and free + * its buffer--data contains the value we're searching for. + */ + __os_free(ldata.data, 0); + /* FALLTHROUGH */ + case 1: + ret = dbc->c_get(dbc, key, data, DB_GET_BOTHC); + break; + default: + ret = EINVAL; + break; + } + + return (ret); +} + +/* + * __db_join_cmp -- + * Comparison function for sorting DBCs in cardinality order. + */ + +static int +__db_join_cmp(a, b) + const void *a, *b; +{ + DBC *dbca, *dbcb; + db_recno_t counta, countb; + + /* In case c_count fails, pretend cursors are equal. */ + counta = countb = 0; + + dbca = *((DBC * const *)a); + dbcb = *((DBC * const *)b); + + if (dbca->c_count(dbca, &counta, 0) != 0 || + dbcb->c_count(dbcb, &countb, 0) != 0) + return (0); + + return (counta - countb); +} diff --git a/db/db/db_meta.c b/db/db/db_meta.c new file mode 100644 index 000000000..5b57c3694 --- /dev/null +++ b/db/db/db_meta.c @@ -0,0 +1,309 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994, 1995 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Mike Olson. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: db_meta.c,v 11.26 2001/01/16 21:57:19 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_shash.h" +#include "lock.h" +#include "txn.h" +#include "db_am.h" +#include "btree.h" + +/* + * __db_new -- + * Get a new page, preferably from the freelist. + * + * PUBLIC: int __db_new __P((DBC *, u_int32_t, PAGE **)); + */ +int +__db_new(dbc, type, pagepp) + DBC *dbc; + u_int32_t type; + PAGE **pagepp; +{ + DBMETA *meta; + DB *dbp; + DB_LOCK metalock; + PAGE *h; + db_pgno_t pgno; + int ret; + + dbp = dbc->dbp; + meta = NULL; + h = NULL; + + pgno = PGNO_BASE_MD; + if ((ret = __db_lget(dbc, + LCK_ALWAYS, pgno, DB_LOCK_WRITE, 0, &metalock)) != 0) + goto err; + if ((ret = memp_fget(dbp->mpf, &pgno, 0, (PAGE **)&meta)) != 0) + goto err; + + if (meta->free == PGNO_INVALID) { + if ((ret = memp_fget(dbp->mpf, &pgno, DB_MPOOL_NEW, &h)) != 0) + goto err; + ZERO_LSN(h->lsn); + h->pgno = pgno; + } else { + pgno = meta->free; + if ((ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) + goto err; + meta->free = h->next_pgno; + (void)memp_fset(dbp->mpf, (PAGE *)meta, DB_MPOOL_DIRTY); + } + + DB_ASSERT(TYPE(h) == P_INVALID); + + if (TYPE(h) != P_INVALID) + return (__db_panic(dbp->dbenv, EINVAL)); + + /* Log the change. */ + if (DB_LOGGING(dbc)) { + if ((ret = __db_pg_alloc_log(dbp->dbenv, + dbc->txn, &LSN(meta), 0, dbp->log_fileid, + &LSN(meta), &h->lsn, h->pgno, + (u_int32_t)type, meta->free)) != 0) + goto err; + LSN(h) = LSN(meta); + } + + (void)memp_fput(dbp->mpf, (PAGE *)meta, DB_MPOOL_DIRTY); + (void)__TLPUT(dbc, metalock); + + P_INIT(h, dbp->pgsize, h->pgno, PGNO_INVALID, PGNO_INVALID, 0, type); + *pagepp = h; + return (0); + +err: if (h != NULL) + (void)memp_fput(dbp->mpf, h, 0); + if (meta != NULL) + (void)memp_fput(dbp->mpf, meta, 0); + (void)__TLPUT(dbc, metalock); + return (ret); +} + +/* + * __db_free -- + * Add a page to the head of the freelist. + * + * PUBLIC: int __db_free __P((DBC *, PAGE *)); + */ +int +__db_free(dbc, h) + DBC *dbc; + PAGE *h; +{ + DBMETA *meta; + DB *dbp; + DBT ldbt; + DB_LOCK metalock; + db_pgno_t pgno; + u_int32_t dirty_flag; + int ret, t_ret; + + dbp = dbc->dbp; + + /* + * Retrieve the metadata page and insert the page at the head of + * the free list. If either the lock get or page get routines + * fail, then we need to put the page with which we were called + * back because our caller assumes we take care of it. + */ + dirty_flag = 0; + pgno = PGNO_BASE_MD; + if ((ret = __db_lget(dbc, + LCK_ALWAYS, pgno, DB_LOCK_WRITE, 0, &metalock)) != 0) + goto err; + if ((ret = memp_fget(dbp->mpf, &pgno, 0, (PAGE **)&meta)) != 0) { + (void)__TLPUT(dbc, metalock); + goto err; + } + + DB_ASSERT(h->pgno != meta->free); + /* Log the change. */ + if (DB_LOGGING(dbc)) { + memset(&ldbt, 0, sizeof(ldbt)); + ldbt.data = h; + ldbt.size = P_OVERHEAD; + if ((ret = __db_pg_free_log(dbp->dbenv, + dbc->txn, &LSN(meta), 0, dbp->log_fileid, h->pgno, + &LSN(meta), &ldbt, meta->free)) != 0) { + (void)memp_fput(dbp->mpf, (PAGE *)meta, 0); + (void)__TLPUT(dbc, metalock); + return (ret); + } + LSN(h) = LSN(meta); + } + + P_INIT(h, dbp->pgsize, h->pgno, PGNO_INVALID, meta->free, 0, P_INVALID); + + meta->free = h->pgno; + + /* Discard the metadata page. */ + if ((t_ret = memp_fput(dbp->mpf, + (PAGE *)meta, DB_MPOOL_DIRTY)) != 0 && ret == 0) + ret = t_ret; + if ((t_ret = __TLPUT(dbc, metalock)) != 0 && ret == 0) + ret = t_ret; + + /* Discard the caller's page reference. */ + dirty_flag = DB_MPOOL_DIRTY; +err: if ((t_ret = memp_fput(dbp->mpf, h, dirty_flag)) != 0 && ret == 0) + ret = t_ret; + + /* + * XXX + * We have to unlock the caller's page in the caller! + */ + return (ret); +} + +#ifdef DEBUG +/* + * __db_lprint -- + * Print out the list of locks currently held by a cursor. + * + * PUBLIC: int __db_lprint __P((DBC *)); + */ +int +__db_lprint(dbc) + DBC *dbc; +{ + DB *dbp; + DB_LOCKREQ req; + + dbp = dbc->dbp; + + if (LOCKING_ON(dbp->dbenv)) { + req.op = DB_LOCK_DUMP; + lock_vec(dbp->dbenv, dbc->locker, 0, &req, 1, NULL); + } + return (0); +} +#endif + +/* + * __db_lget -- + * The standard lock get call. + * + * PUBLIC: int __db_lget __P((DBC *, + * PUBLIC: int, db_pgno_t, db_lockmode_t, int, DB_LOCK *)); + */ +int +__db_lget(dbc, flags, pgno, mode, lkflags, lockp) + DBC *dbc; + int flags, lkflags; + db_pgno_t pgno; + db_lockmode_t mode; + DB_LOCK *lockp; +{ + DB *dbp; + DB_ENV *dbenv; + DB_LOCKREQ couple[2], *reqp; + int ret; + + dbp = dbc->dbp; + dbenv = dbp->dbenv; + + /* + * We do not always check if we're configured for locking before + * calling __db_lget to acquire the lock. + */ + if (CDB_LOCKING(dbenv) + || !LOCKING_ON(dbenv) || F_ISSET(dbc, DBC_COMPENSATE) + || (!LF_ISSET(LCK_ROLLBACK) && F_ISSET(dbc, DBC_RECOVER)) + || (!LF_ISSET(LCK_ALWAYS) && F_ISSET(dbc, DBC_OPD))) { + lockp->off = LOCK_INVALID; + return (0); + } + + dbc->lock.pgno = pgno; + if (lkflags & DB_LOCK_RECORD) + dbc->lock.type = DB_RECORD_LOCK; + else + dbc->lock.type = DB_PAGE_LOCK; + lkflags &= ~DB_LOCK_RECORD; + + /* + * If the transaction enclosing this cursor has DB_LOCK_NOWAIT set, + * pass that along to the lock call. + */ + if (DB_NONBLOCK(dbc)) + lkflags |= DB_LOCK_NOWAIT; + + /* + * If the object not currently locked, acquire the lock and return, + * otherwise, lock couple. + */ + if (LF_ISSET(LCK_COUPLE)) { + couple[0].op = DB_LOCK_GET; + couple[0].obj = &dbc->lock_dbt; + couple[0].mode = mode; + couple[1].op = DB_LOCK_PUT; + couple[1].lock = *lockp; + + ret = lock_vec(dbenv, + dbc->locker, lkflags, couple, 2, &reqp); + if (ret == 0 || reqp == &couple[1]) + *lockp = couple[0].lock; + } else { + ret = lock_get(dbenv, + dbc->locker, lkflags, &dbc->lock_dbt, mode, lockp); + + if (ret != 0) + lockp->off = LOCK_INVALID; + } + + return (ret); +} diff --git a/db/db/db_method.c b/db/db/db_method.c new file mode 100644 index 000000000..01568a6e1 --- /dev/null +++ b/db/db/db_method.c @@ -0,0 +1,629 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: db_method.c,v 11.36 2000/12/21 09:17:04 krinsky Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#ifdef HAVE_RPC +#include +#endif + +#include +#endif + +#ifdef HAVE_RPC +#include "db_server.h" +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_am.h" +#include "btree.h" +#include "hash.h" +#include "qam.h" +#include "xa.h" +#include "xa_ext.h" + +#ifdef HAVE_RPC +#include "gen_client_ext.h" +#include "rpc_client_ext.h" +#endif + +static int __db_get_byteswapped __P((DB *)); +static DBTYPE + __db_get_type __P((DB *)); +static int __db_init __P((DB *, u_int32_t)); +static int __db_key_range + __P((DB *, DB_TXN *, DBT *, DB_KEY_RANGE *, u_int32_t)); +static int __db_set_append_recno __P((DB *, int (*)(DB *, DBT *, db_recno_t))); +static int __db_set_cachesize __P((DB *, u_int32_t, u_int32_t, int)); +static int __db_set_dup_compare + __P((DB *, int (*)(DB *, const DBT *, const DBT *))); +static void __db_set_errcall __P((DB *, void (*)(const char *, char *))); +static void __db_set_errfile __P((DB *, FILE *)); +static int __db_set_feedback __P((DB *, void (*)(DB *, int, int))); +static int __db_set_flags __P((DB *, u_int32_t)); +static int __db_set_lorder __P((DB *, int)); +static int __db_set_malloc __P((DB *, void *(*)(size_t))); +static int __db_set_pagesize __P((DB *, u_int32_t)); +static int __db_set_realloc __P((DB *, void *(*)(void *, size_t))); +static void __db_set_errpfx __P((DB *, const char *)); +static int __db_set_paniccall __P((DB *, void (*)(DB_ENV *, int))); +static void __dbh_err __P((DB *, int, const char *, ...)); +static void __dbh_errx __P((DB *, const char *, ...)); + +/* + * db_create -- + * DB constructor. + */ +int +db_create(dbpp, dbenv, flags) + DB **dbpp; + DB_ENV *dbenv; + u_int32_t flags; +{ + DB *dbp; + int ret; + + /* Check for invalid function flags. */ + switch (flags) { + case 0: + break; + case DB_XA_CREATE: + if (dbenv != NULL) { + __db_err(dbenv, + "XA applications may not specify an environment to db_create"); + return (EINVAL); + } + + /* + * If it's an XA database, open it within the XA environment, + * taken from the global list of environments. (When the XA + * transaction manager called our xa_start() routine the + * "current" environment was moved to the start of the list. + */ + dbenv = TAILQ_FIRST(&DB_GLOBAL(db_envq)); + break; + default: + return (__db_ferr(dbenv, "db_create", 0)); + } + + /* Allocate the DB. */ + if ((ret = __os_calloc(dbenv, 1, sizeof(*dbp), &dbp)) != 0) + return (ret); +#ifdef HAVE_RPC + if (dbenv != NULL && dbenv->cl_handle != NULL) + ret = __dbcl_init(dbp, dbenv, flags); + else +#endif + ret = __db_init(dbp, flags); + if (ret != 0) { + __os_free(dbp, sizeof(*dbp)); + return (ret); + } + + /* If we don't have an environment yet, allocate a local one. */ + if (dbenv == NULL) { + if ((ret = db_env_create(&dbenv, 0)) != 0) { + __os_free(dbp, sizeof(*dbp)); + return (ret); + } + dbenv->dblocal_ref = 0; + F_SET(dbenv, DB_ENV_DBLOCAL); + } + if (F_ISSET(dbenv, DB_ENV_DBLOCAL)) + ++dbenv->dblocal_ref; + + dbp->dbenv = dbenv; + + *dbpp = dbp; + return (0); +} + +/* + * __db_init -- + * Initialize a DB structure. + */ +static int +__db_init(dbp, flags) + DB *dbp; + u_int32_t flags; +{ + int ret; + + dbp->log_fileid = DB_LOGFILEID_INVALID; + + TAILQ_INIT(&dbp->free_queue); + TAILQ_INIT(&dbp->active_queue); + TAILQ_INIT(&dbp->join_queue); + + FLD_SET(dbp->am_ok, + DB_OK_BTREE | DB_OK_HASH | DB_OK_QUEUE | DB_OK_RECNO); + + dbp->close = __db_close; + dbp->cursor = __db_cursor; + dbp->del = NULL; /* !!! Must be set by access method. */ + dbp->err = __dbh_err; + dbp->errx = __dbh_errx; + dbp->fd = __db_fd; + dbp->get = __db_get; + dbp->get_byteswapped = __db_get_byteswapped; + dbp->get_type = __db_get_type; + dbp->join = __db_join; + dbp->key_range = __db_key_range; + dbp->open = __db_open; + dbp->put = __db_put; + dbp->remove = __db_remove; + dbp->rename = __db_rename; + dbp->set_append_recno = __db_set_append_recno; + dbp->set_cachesize = __db_set_cachesize; + dbp->set_dup_compare = __db_set_dup_compare; + dbp->set_errcall = __db_set_errcall; + dbp->set_errfile = __db_set_errfile; + dbp->set_errpfx = __db_set_errpfx; + dbp->set_feedback = __db_set_feedback; + dbp->set_flags = __db_set_flags; + dbp->set_lorder = __db_set_lorder; + dbp->set_malloc = __db_set_malloc; + dbp->set_pagesize = __db_set_pagesize; + dbp->set_paniccall = __db_set_paniccall; + dbp->set_realloc = __db_set_realloc; + dbp->stat = NULL; /* !!! Must be set by access method. */ + dbp->sync = __db_sync; + dbp->upgrade = __db_upgrade; + dbp->verify = __db_verify; + /* Access method specific. */ + if ((ret = __bam_db_create(dbp)) != 0) + return (ret); + if ((ret = __ham_db_create(dbp)) != 0) + return (ret); + if ((ret = __qam_db_create(dbp)) != 0) + return (ret); + + /* + * XA specific: must be last, as we replace methods set by the + * access methods. + */ + if (LF_ISSET(DB_XA_CREATE) && (ret = __db_xa_create(dbp)) != 0) + return (ret); + + return (0); +} + +/* + * __dbh_am_chk -- + * Error if an unreasonable method is called. + * + * PUBLIC: int __dbh_am_chk __P((DB *, u_int32_t)); + */ +int +__dbh_am_chk(dbp, flags) + DB *dbp; + u_int32_t flags; +{ + /* + * We start out allowing any access methods to be called, and as the + * application calls the methods the options become restricted. The + * idea is to quit as soon as an illegal method combination is called. + */ + if ((LF_ISSET(DB_OK_BTREE) && FLD_ISSET(dbp->am_ok, DB_OK_BTREE)) || + (LF_ISSET(DB_OK_HASH) && FLD_ISSET(dbp->am_ok, DB_OK_HASH)) || + (LF_ISSET(DB_OK_QUEUE) && FLD_ISSET(dbp->am_ok, DB_OK_QUEUE)) || + (LF_ISSET(DB_OK_RECNO) && FLD_ISSET(dbp->am_ok, DB_OK_RECNO))) { + FLD_CLR(dbp->am_ok, ~flags); + return (0); + } + + __db_err(dbp->dbenv, + "call implies an access method which is inconsistent with previous calls"); + return (EINVAL); +} + +/* + * __dbh_err -- + * Error message, including the standard error string. + */ +static void +#ifdef __STDC__ +__dbh_err(DB *dbp, int error, const char *fmt, ...) +#else +__dbh_err(dbp, error, fmt, va_alist) + DB *dbp; + int error; + const char *fmt; + va_dcl +#endif +{ + va_list ap; + +#ifdef __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + __db_real_err(dbp->dbenv, error, 1, 1, fmt, ap); + + va_end(ap); +} + +/* + * __dbh_errx -- + * Error message. + */ +static void +#ifdef __STDC__ +__dbh_errx(DB *dbp, const char *fmt, ...) +#else +__dbh_errx(dbp, fmt, va_alist) + DB *dbp; + const char *fmt; + va_dcl +#endif +{ + va_list ap; + +#ifdef __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + __db_real_err(dbp->dbenv, 0, 0, 1, fmt, ap); + + va_end(ap); +} + +/* + * __db_get_byteswapped -- + * Return if database requires byte swapping. + */ +static int +__db_get_byteswapped(dbp) + DB *dbp; +{ + DB_ILLEGAL_BEFORE_OPEN(dbp, "get_byteswapped"); + + return (F_ISSET(dbp, DB_AM_SWAP) ? 1 : 0); +} + +/* + * __db_get_type -- + * Return type of underlying database. + */ +static DBTYPE +__db_get_type(dbp) + DB *dbp; +{ + DB_ILLEGAL_BEFORE_OPEN(dbp, "get_type"); + + return (dbp->type); +} + +/* + * __db_key_range -- + * Return proportion of keys above and below given key. + */ +static int +__db_key_range(dbp, txn, key, kr, flags) + DB *dbp; + DB_TXN *txn; + DBT *key; + DB_KEY_RANGE *kr; + u_int32_t flags; +{ + COMPQUIET(txn, NULL); + COMPQUIET(key, NULL); + COMPQUIET(kr, NULL); + COMPQUIET(flags, 0); + + DB_ILLEGAL_BEFORE_OPEN(dbp, "key_range"); + DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE); + + return (EINVAL); +} + +/* + * __db_set_append_recno -- + * Set record number append routine. + */ +static int +__db_set_append_recno(dbp, func) + DB *dbp; + int (*func) __P((DB *, DBT *, db_recno_t)); +{ + DB_ILLEGAL_AFTER_OPEN(dbp, "set_append_recno"); + DB_ILLEGAL_METHOD(dbp, DB_OK_QUEUE | DB_OK_RECNO); + + dbp->db_append_recno = func; + + return (0); +} + +/* + * __db_set_cachesize -- + * Set underlying cache size. + */ +static int +__db_set_cachesize(dbp, cache_gbytes, cache_bytes, ncache) + DB *dbp; + u_int32_t cache_gbytes, cache_bytes; + int ncache; +{ + DB_ILLEGAL_IN_ENV(dbp, "set_cachesize"); + DB_ILLEGAL_AFTER_OPEN(dbp, "set_cachesize"); + + return (dbp->dbenv->set_cachesize( + dbp->dbenv, cache_gbytes, cache_bytes, ncache)); +} + +/* + * __db_set_dup_compare -- + * Set duplicate comparison routine. + */ +static int +__db_set_dup_compare(dbp, func) + DB *dbp; + int (*func) __P((DB *, const DBT *, const DBT *)); +{ + DB_ILLEGAL_AFTER_OPEN(dbp, "dup_compare"); + DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE | DB_OK_HASH); + + dbp->dup_compare = func; + + return (0); +} + +static void +__db_set_errcall(dbp, errcall) + DB *dbp; + void (*errcall) __P((const char *, char *)); +{ + dbp->dbenv->set_errcall(dbp->dbenv, errcall); +} + +static void +__db_set_errfile(dbp, errfile) + DB *dbp; + FILE *errfile; +{ + dbp->dbenv->set_errfile(dbp->dbenv, errfile); +} + +static void +__db_set_errpfx(dbp, errpfx) + DB *dbp; + const char *errpfx; +{ + dbp->dbenv->set_errpfx(dbp->dbenv, errpfx); +} + +static int +__db_set_feedback(dbp, feedback) + DB *dbp; + void (*feedback) __P((DB *, int, int)); +{ + dbp->db_feedback = feedback; + return (0); +} + +static int +__db_set_flags(dbp, flags) + DB *dbp; + u_int32_t flags; +{ + int ret; + + /* + * !!! + * The hash access method only takes two flags: DB_DUP and DB_DUPSORT. + * The Btree access method uses them for the same purposes, and so we + * resolve them there. + * + * The queue access method takes no flags. + */ + if ((ret = __bam_set_flags(dbp, &flags)) != 0) + return (ret); + if ((ret = __ram_set_flags(dbp, &flags)) != 0) + return (ret); + + return (flags == 0 ? 0 : __db_ferr(dbp->dbenv, "DB->set_flags", 0)); +} + +static int +__db_set_lorder(dbp, db_lorder) + DB *dbp; + int db_lorder; +{ + int ret; + + DB_ILLEGAL_AFTER_OPEN(dbp, "set_lorder"); + + /* Flag if the specified byte order requires swapping. */ + switch (ret = __db_byteorder(dbp->dbenv, db_lorder)) { + case 0: + F_CLR(dbp, DB_AM_SWAP); + break; + case DB_SWAPBYTES: + F_SET(dbp, DB_AM_SWAP); + break; + default: + return (ret); + /* NOTREACHED */ + } + return (0); +} + +static int +__db_set_malloc(dbp, func) + DB *dbp; + void *(*func) __P((size_t)); +{ + DB_ILLEGAL_AFTER_OPEN(dbp, "set_malloc"); + + dbp->db_malloc = func; + return (0); +} + +static int +__db_set_pagesize(dbp, db_pagesize) + DB *dbp; + u_int32_t db_pagesize; +{ + DB_ILLEGAL_AFTER_OPEN(dbp, "set_pagesize"); + + if (db_pagesize < DB_MIN_PGSIZE) { + __db_err(dbp->dbenv, "page sizes may not be smaller than %lu", + (u_long)DB_MIN_PGSIZE); + return (EINVAL); + } + if (db_pagesize > DB_MAX_PGSIZE) { + __db_err(dbp->dbenv, "page sizes may not be larger than %lu", + (u_long)DB_MAX_PGSIZE); + return (EINVAL); + } + + /* + * We don't want anything that's not a power-of-2, as we rely on that + * for alignment of various types on the pages. + */ + if ((u_int32_t)1 << __db_log2(db_pagesize) != db_pagesize) { + __db_err(dbp->dbenv, "page sizes must be a power-of-2"); + return (EINVAL); + } + + /* + * XXX + * Should we be checking for a page size that's not a multiple of 512, + * so that we never try and write less than a disk sector? + */ + dbp->pgsize = db_pagesize; + + return (0); +} + +static int +__db_set_realloc(dbp, func) + DB *dbp; + void *(*func) __P((void *, size_t)); +{ + DB_ILLEGAL_AFTER_OPEN(dbp, "set_realloc"); + + dbp->db_realloc = func; + return (0); +} + +static int +__db_set_paniccall(dbp, paniccall) + DB *dbp; + void (*paniccall) __P((DB_ENV *, int)); +{ + return (dbp->dbenv->set_paniccall(dbp->dbenv, paniccall)); +} + +#ifdef HAVE_RPC +/* + * __dbcl_init -- + * Initialize a DB structure on the server. + * + * PUBLIC: #ifdef HAVE_RPC + * PUBLIC: int __dbcl_init __P((DB *, DB_ENV *, u_int32_t)); + * PUBLIC: #endif + */ +int +__dbcl_init(dbp, dbenv, flags) + DB *dbp; + DB_ENV *dbenv; + u_int32_t flags; +{ + CLIENT *cl; + __db_create_reply *replyp; + __db_create_msg req; + int ret; + + TAILQ_INIT(&dbp->free_queue); + TAILQ_INIT(&dbp->active_queue); + /* !!! + * Note that we don't need to initialize the join_queue; it's + * not used in RPC clients. See the comment in __dbcl_db_join_ret(). + */ + + dbp->close = __dbcl_db_close; + dbp->cursor = __dbcl_db_cursor; + dbp->del = __dbcl_db_del; + dbp->err = __dbh_err; + dbp->errx = __dbh_errx; + dbp->fd = __dbcl_db_fd; + dbp->get = __dbcl_db_get; + dbp->get_byteswapped = __dbcl_db_swapped; + dbp->get_type = __db_get_type; + dbp->join = __dbcl_db_join; + dbp->key_range = __dbcl_db_key_range; + dbp->open = __dbcl_db_open; + dbp->put = __dbcl_db_put; + dbp->remove = __dbcl_db_remove; + dbp->rename = __dbcl_db_rename; + dbp->set_append_recno = __dbcl_db_set_append_recno; + dbp->set_cachesize = __dbcl_db_cachesize; + dbp->set_dup_compare = NULL; + dbp->set_errcall = __db_set_errcall; + dbp->set_errfile = __db_set_errfile; + dbp->set_errpfx = __db_set_errpfx; + dbp->set_feedback = __dbcl_db_feedback; + dbp->set_flags = __dbcl_db_flags; + dbp->set_lorder = __dbcl_db_lorder; + dbp->set_malloc = __dbcl_db_malloc; + dbp->set_pagesize = __dbcl_db_pagesize; + dbp->set_paniccall = __dbcl_db_panic; + dbp->set_q_extentsize = __dbcl_db_extentsize; + dbp->set_realloc = __dbcl_db_realloc; + dbp->stat = __dbcl_db_stat; + dbp->sync = __dbcl_db_sync; + dbp->upgrade = __dbcl_db_upgrade; + + /* + * Set all the method specific functions to client funcs as well. + */ + dbp->set_bt_compare = __dbcl_db_bt_compare; + dbp->set_bt_maxkey = __dbcl_db_bt_maxkey; + dbp->set_bt_minkey = __dbcl_db_bt_minkey; + dbp->set_bt_prefix = __dbcl_db_bt_prefix; + dbp->set_h_ffactor = __dbcl_db_h_ffactor; + dbp->set_h_hash = __dbcl_db_h_hash; + dbp->set_h_nelem = __dbcl_db_h_nelem; + dbp->set_re_delim = __dbcl_db_re_delim; + dbp->set_re_len = __dbcl_db_re_len; + dbp->set_re_pad = __dbcl_db_re_pad; + dbp->set_re_source = __dbcl_db_re_source; +/* + dbp->set_q_extentsize = __dbcl_db_q_extentsize; +*/ + + cl = (CLIENT *)dbenv->cl_handle; + req.flags = flags; + req.envpcl_id = dbenv->cl_id; + + /* + * CALL THE SERVER + */ + replyp = __db_db_create_1(&req, cl); + if (replyp == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + return (DB_NOSERVER); + } + + if ((ret = replyp->status) != 0) + return (ret); + + dbp->cl_id = replyp->dbpcl_id; + return (0); +} +#endif diff --git a/db/db/db_overflow.c b/db/db/db_overflow.c new file mode 100644 index 000000000..54f0a03aa --- /dev/null +++ b/db/db/db_overflow.c @@ -0,0 +1,681 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994, 1995 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Mike Olson. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: db_overflow.c,v 11.21 2000/11/30 00:58:32 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_am.h" +#include "db_verify.h" + +/* + * Big key/data code. + * + * Big key and data entries are stored on linked lists of pages. The initial + * reference is a structure with the total length of the item and the page + * number where it begins. Each entry in the linked list contains a pointer + * to the next page of data, and so on. + */ + +/* + * __db_goff -- + * Get an offpage item. + * + * PUBLIC: int __db_goff __P((DB *, DBT *, + * PUBLIC: u_int32_t, db_pgno_t, void **, u_int32_t *)); + */ +int +__db_goff(dbp, dbt, tlen, pgno, bpp, bpsz) + DB *dbp; + DBT *dbt; + u_int32_t tlen; + db_pgno_t pgno; + void **bpp; + u_int32_t *bpsz; +{ + DB_ENV *dbenv; + PAGE *h; + db_indx_t bytes; + u_int32_t curoff, needed, start; + u_int8_t *p, *src; + int ret; + + dbenv = dbp->dbenv; + + /* + * Check if the buffer is big enough; if it is not and we are + * allowed to malloc space, then we'll malloc it. If we are + * not (DB_DBT_USERMEM), then we'll set the dbt and return + * appropriately. + */ + if (F_ISSET(dbt, DB_DBT_PARTIAL)) { + start = dbt->doff; + needed = dbt->dlen; + } else { + start = 0; + needed = tlen; + } + + /* Allocate any necessary memory. */ + if (F_ISSET(dbt, DB_DBT_USERMEM)) { + if (needed > dbt->ulen) { + dbt->size = needed; + return (ENOMEM); + } + } else if (F_ISSET(dbt, DB_DBT_MALLOC)) { + if ((ret = __os_malloc(dbenv, + needed, dbp->db_malloc, &dbt->data)) != 0) + return (ret); + } else if (F_ISSET(dbt, DB_DBT_REALLOC)) { + if ((ret = __os_realloc(dbenv, + needed, dbp->db_realloc, &dbt->data)) != 0) + return (ret); + } else if (*bpsz == 0 || *bpsz < needed) { + if ((ret = __os_realloc(dbenv, needed, NULL, bpp)) != 0) + return (ret); + *bpsz = needed; + dbt->data = *bpp; + } else + dbt->data = *bpp; + + /* + * Step through the linked list of pages, copying the data on each + * one into the buffer. Never copy more than the total data length. + */ + dbt->size = needed; + for (curoff = 0, p = dbt->data; pgno != PGNO_INVALID && needed > 0;) { + if ((ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) { + (void)__db_pgerr(dbp, pgno); + return (ret); + } + /* Check if we need any bytes from this page. */ + if (curoff + OV_LEN(h) >= start) { + src = (u_int8_t *)h + P_OVERHEAD; + bytes = OV_LEN(h); + if (start > curoff) { + src += start - curoff; + bytes -= start - curoff; + } + if (bytes > needed) + bytes = needed; + memcpy(p, src, bytes); + p += bytes; + needed -= bytes; + } + curoff += OV_LEN(h); + pgno = h->next_pgno; + memp_fput(dbp->mpf, h, 0); + } + return (0); +} + +/* + * __db_poff -- + * Put an offpage item. + * + * PUBLIC: int __db_poff __P((DBC *, const DBT *, db_pgno_t *)); + */ +int +__db_poff(dbc, dbt, pgnop) + DBC *dbc; + const DBT *dbt; + db_pgno_t *pgnop; +{ + DB *dbp; + PAGE *pagep, *lastp; + DB_LSN new_lsn, null_lsn; + DBT tmp_dbt; + db_indx_t pagespace; + u_int32_t sz; + u_int8_t *p; + int ret; + + /* + * Allocate pages and copy the key/data item into them. Calculate the + * number of bytes we get for pages we fill completely with a single + * item. + */ + dbp = dbc->dbp; + pagespace = P_MAXSPACE(dbp->pgsize); + + lastp = NULL; + for (p = dbt->data, + sz = dbt->size; sz > 0; p += pagespace, sz -= pagespace) { + /* + * Reduce pagespace so we terminate the loop correctly and + * don't copy too much data. + */ + if (sz < pagespace) + pagespace = sz; + + /* + * Allocate and initialize a new page and copy all or part of + * the item onto the page. If sz is less than pagespace, we + * have a partial record. + */ + if ((ret = __db_new(dbc, P_OVERFLOW, &pagep)) != 0) + return (ret); + if (DB_LOGGING(dbc)) { + tmp_dbt.data = p; + tmp_dbt.size = pagespace; + ZERO_LSN(null_lsn); + if ((ret = __db_big_log(dbp->dbenv, dbc->txn, + &new_lsn, 0, DB_ADD_BIG, dbp->log_fileid, + PGNO(pagep), lastp ? PGNO(lastp) : PGNO_INVALID, + PGNO_INVALID, &tmp_dbt, &LSN(pagep), + lastp == NULL ? &null_lsn : &LSN(lastp), + &null_lsn)) != 0) + return (ret); + + /* Move lsn onto page. */ + if (lastp) + LSN(lastp) = new_lsn; + LSN(pagep) = new_lsn; + } + + P_INIT(pagep, dbp->pgsize, + PGNO(pagep), PGNO_INVALID, PGNO_INVALID, 0, P_OVERFLOW); + OV_LEN(pagep) = pagespace; + OV_REF(pagep) = 1; + memcpy((u_int8_t *)pagep + P_OVERHEAD, p, pagespace); + + /* + * If this is the first entry, update the user's info. + * Otherwise, update the entry on the last page filled + * in and release that page. + */ + if (lastp == NULL) + *pgnop = PGNO(pagep); + else { + lastp->next_pgno = PGNO(pagep); + pagep->prev_pgno = PGNO(lastp); + (void)memp_fput(dbp->mpf, lastp, DB_MPOOL_DIRTY); + } + lastp = pagep; + } + (void)memp_fput(dbp->mpf, lastp, DB_MPOOL_DIRTY); + return (0); +} + +/* + * __db_ovref -- + * Increment/decrement the reference count on an overflow page. + * + * PUBLIC: int __db_ovref __P((DBC *, db_pgno_t, int32_t)); + */ +int +__db_ovref(dbc, pgno, adjust) + DBC *dbc; + db_pgno_t pgno; + int32_t adjust; +{ + DB *dbp; + PAGE *h; + int ret; + + dbp = dbc->dbp; + if ((ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) { + (void)__db_pgerr(dbp, pgno); + return (ret); + } + + if (DB_LOGGING(dbc)) + if ((ret = __db_ovref_log(dbp->dbenv, dbc->txn, + &LSN(h), 0, dbp->log_fileid, h->pgno, adjust, + &LSN(h))) != 0) + return (ret); + OV_REF(h) += adjust; + + (void)memp_fput(dbp->mpf, h, DB_MPOOL_DIRTY); + return (0); +} + +/* + * __db_doff -- + * Delete an offpage chain of overflow pages. + * + * PUBLIC: int __db_doff __P((DBC *, db_pgno_t)); + */ +int +__db_doff(dbc, pgno) + DBC *dbc; + db_pgno_t pgno; +{ + DB *dbp; + PAGE *pagep; + DB_LSN null_lsn; + DBT tmp_dbt; + int ret; + + dbp = dbc->dbp; + do { + if ((ret = memp_fget(dbp->mpf, &pgno, 0, &pagep)) != 0) { + (void)__db_pgerr(dbp, pgno); + return (ret); + } + + DB_ASSERT(TYPE(pagep) == P_OVERFLOW); + /* + * If it's referenced by more than one key/data item, + * decrement the reference count and return. + */ + if (OV_REF(pagep) > 1) { + (void)memp_fput(dbp->mpf, pagep, 0); + return (__db_ovref(dbc, pgno, -1)); + } + + if (DB_LOGGING(dbc)) { + tmp_dbt.data = (u_int8_t *)pagep + P_OVERHEAD; + tmp_dbt.size = OV_LEN(pagep); + ZERO_LSN(null_lsn); + if ((ret = __db_big_log(dbp->dbenv, dbc->txn, + &LSN(pagep), 0, DB_REM_BIG, dbp->log_fileid, + PGNO(pagep), PREV_PGNO(pagep), NEXT_PGNO(pagep), + &tmp_dbt, &LSN(pagep), &null_lsn, &null_lsn)) != 0) + return (ret); + } + pgno = pagep->next_pgno; + if ((ret = __db_free(dbc, pagep)) != 0) + return (ret); + } while (pgno != PGNO_INVALID); + + return (0); +} + +/* + * __db_moff -- + * Match on overflow pages. + * + * Given a starting page number and a key, return <0, 0, >0 to indicate if the + * key on the page is less than, equal to or greater than the key specified. + * We optimize this by doing chunk at a time comparison unless the user has + * specified a comparison function. In this case, we need to materialize + * the entire object and call their comparison routine. + * + * PUBLIC: int __db_moff __P((DB *, const DBT *, db_pgno_t, u_int32_t, + * PUBLIC: int (*)(DB *, const DBT *, const DBT *), int *)); + */ +int +__db_moff(dbp, dbt, pgno, tlen, cmpfunc, cmpp) + DB *dbp; + const DBT *dbt; + db_pgno_t pgno; + u_int32_t tlen; + int (*cmpfunc) __P((DB *, const DBT *, const DBT *)), *cmpp; +{ + PAGE *pagep; + DBT local_dbt; + void *buf; + u_int32_t bufsize, cmp_bytes, key_left; + u_int8_t *p1, *p2; + int ret; + + /* + * If there is a user-specified comparison function, build a + * contiguous copy of the key, and call it. + */ + if (cmpfunc != NULL) { + memset(&local_dbt, 0, sizeof(local_dbt)); + buf = NULL; + bufsize = 0; + + if ((ret = __db_goff(dbp, + &local_dbt, tlen, pgno, &buf, &bufsize)) != 0) + return (ret); + /* Pass the key as the first argument */ + *cmpp = cmpfunc(dbp, dbt, &local_dbt); + __os_free(buf, bufsize); + return (0); + } + + /* While there are both keys to compare. */ + for (*cmpp = 0, p1 = dbt->data, + key_left = dbt->size; key_left > 0 && pgno != PGNO_INVALID;) { + if ((ret = memp_fget(dbp->mpf, &pgno, 0, &pagep)) != 0) + return (ret); + + cmp_bytes = OV_LEN(pagep) < key_left ? OV_LEN(pagep) : key_left; + tlen -= cmp_bytes; + key_left -= cmp_bytes; + for (p2 = + (u_int8_t *)pagep + P_OVERHEAD; cmp_bytes-- > 0; ++p1, ++p2) + if (*p1 != *p2) { + *cmpp = (long)*p1 - (long)*p2; + break; + } + pgno = NEXT_PGNO(pagep); + if ((ret = memp_fput(dbp->mpf, pagep, 0)) != 0) + return (ret); + if (*cmpp != 0) + return (0); + } + if (key_left > 0) /* DBT is longer than the page key. */ + *cmpp = 1; + else if (tlen > 0) /* DBT is shorter than the page key. */ + *cmpp = -1; + else + *cmpp = 0; + + return (0); +} + +/* + * __db_vrfy_overflow -- + * Verify overflow page. + * + * PUBLIC: int __db_vrfy_overflow __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, + * PUBLIC: u_int32_t)); + */ +int +__db_vrfy_overflow(dbp, vdp, h, pgno, flags) + DB *dbp; + VRFY_DBINFO *vdp; + PAGE *h; + db_pgno_t pgno; + u_int32_t flags; +{ + VRFY_PAGEINFO *pip; + int isbad, ret, t_ret; + + isbad = 0; + if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) + return (ret); + + if ((ret = __db_vrfy_datapage(dbp, vdp, h, pgno, flags)) != 0) { + if (ret == DB_VERIFY_BAD) + isbad = 1; + else + goto err; + } + + pip->refcount = OV_REF(h); + if (pip->refcount < 1) { + EPRINT((dbp->dbenv, + "Overflow page %lu has zero reference count", + (u_long)pgno)); + isbad = 1; + } + + /* Just store for now. */ + pip->olen = HOFFSET(h); + +err: if ((t_ret = __db_vrfy_putpageinfo(vdp, pip)) != 0) + ret = t_ret; + return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret); +} + +/* + * __db_vrfy_ovfl_structure -- + * Walk a list of overflow pages, avoiding cycles and marking + * pages seen. + * + * PUBLIC: int __db_vrfy_ovfl_structure + * PUBLIC: __P((DB *, VRFY_DBINFO *, db_pgno_t, u_int32_t, u_int32_t)); + */ +int +__db_vrfy_ovfl_structure(dbp, vdp, pgno, tlen, flags) + DB *dbp; + VRFY_DBINFO *vdp; + db_pgno_t pgno; + u_int32_t tlen; + u_int32_t flags; +{ + DB *pgset; + VRFY_PAGEINFO *pip; + db_pgno_t next, prev; + int isbad, p, ret, t_ret; + u_int32_t refcount; + + pgset = vdp->pgset; + DB_ASSERT(pgset != NULL); + isbad = 0; + + /* This shouldn't happen, but just to be sure. */ + if (!IS_VALID_PGNO(pgno)) + return (DB_VERIFY_BAD); + + /* + * Check the first prev_pgno; it ought to be PGNO_INVALID, + * since there's no prev page. + */ + if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) + return (ret); + + /* The refcount is stored on the first overflow page. */ + refcount = pip->refcount; + + if (pip->type != P_OVERFLOW) { + EPRINT((dbp->dbenv, + "Overflow page %lu of invalid type", + (u_long)pgno, (u_long)pip->type)); + ret = DB_VERIFY_BAD; + goto err; /* Unsafe to continue. */ + } + + prev = pip->prev_pgno; + if (prev != PGNO_INVALID) { + EPRINT((dbp->dbenv, + "First overflow page %lu has a prev_pgno", (u_long)pgno)); + isbad = 1; + } + + for (;;) { + /* + * This is slightly gross. Btree leaf pages reference + * individual overflow trees multiple times if the overflow page + * is the key to a duplicate set. The reference count does not + * reflect this multiple referencing. Thus, if this is called + * during the structure verification of a btree leaf page, we + * check to see whether we've seen it from a leaf page before + * and, if we have, adjust our count of how often we've seen it + * accordingly. + * + * (This will screw up if it's actually referenced--and + * correctly refcounted--from two different leaf pages, but + * that's a very unlikely brokenness that we're not checking for + * anyway.) + */ + + if (LF_ISSET(ST_OVFL_LEAF)) { + if (F_ISSET(pip, VRFY_OVFL_LEAFSEEN)) { + if ((ret = + __db_vrfy_pgset_dec(pgset, pgno)) != 0) + goto err; + } else + F_SET(pip, VRFY_OVFL_LEAFSEEN); + } + + if ((ret = __db_vrfy_pgset_get(pgset, pgno, &p)) != 0) + goto err; + + /* + * We may have seen this elsewhere, if the overflow entry + * has been promoted to an internal page. + */ + if ((u_int32_t)p > refcount) { + EPRINT((dbp->dbenv, + "Page %lu encountered twice in overflow traversal", + (u_long)pgno)); + ret = DB_VERIFY_BAD; + goto err; + } + if ((ret = __db_vrfy_pgset_inc(pgset, pgno)) != 0) + goto err; + + /* Keep a running tab on how much of the item we've seen. */ + tlen -= pip->olen; + + /* Send feedback to the application about our progress. */ + if (!LF_ISSET(DB_SALVAGE)) + __db_vrfy_struct_feedback(dbp, vdp); + + next = pip->next_pgno; + + /* Are we there yet? */ + if (next == PGNO_INVALID) + break; + + /* + * We've already checked this when we saved it, but just + * to be sure... + */ + if (!IS_VALID_PGNO(next)) { + DB_ASSERT(0); + EPRINT((dbp->dbenv, + "Overflow page %lu has bad next_pgno", + (u_long)pgno)); + ret = DB_VERIFY_BAD; + goto err; + } + + if ((ret = __db_vrfy_putpageinfo(vdp, pip)) != 0 || + (ret = __db_vrfy_getpageinfo(vdp, next, &pip)) != 0) + return (ret); + if (pip->prev_pgno != pgno) { + EPRINT((dbp->dbenv, + "Overflow page %lu has bogus prev_pgno value", + (u_long)next)); + isbad = 1; + /* + * It's safe to continue because we have separate + * cycle detection. + */ + } + + pgno = next; + } + + if (tlen > 0) { + isbad = 1; + EPRINT((dbp->dbenv, + "Overflow item incomplete on page %lu", (u_long)pgno)); + } + +err: if ((t_ret = __db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0) + ret = t_ret; + return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret); +} + +/* + * __db_safe_goff -- + * Get an overflow item, very carefully, from an untrusted database, + * in the context of the salvager. + * + * PUBLIC: int __db_safe_goff __P((DB *, VRFY_DBINFO *, db_pgno_t, + * PUBLIC: DBT *, void **, u_int32_t)); + */ +int +__db_safe_goff(dbp, vdp, pgno, dbt, buf, flags) + DB *dbp; + VRFY_DBINFO *vdp; + db_pgno_t pgno; + DBT *dbt; + void **buf; + u_int32_t flags; +{ + PAGE *h; + int ret, err_ret; + u_int32_t bytesgot, bytes; + u_int8_t *src, *dest; + + ret = DB_VERIFY_BAD; + err_ret = 0; + bytesgot = bytes = 0; + + while ((pgno != PGNO_INVALID) && (IS_VALID_PGNO(pgno))) { + /* + * Mark that we're looking at this page; if we've seen it + * already, quit. + */ + if ((ret = __db_salvage_markdone(vdp, pgno)) != 0) + break; + + if ((ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) + break; + + /* + * Make sure it's really an overflow page, unless we're + * being aggressive, in which case we pretend it is. + */ + if (!LF_ISSET(DB_AGGRESSIVE) && TYPE(h) != P_OVERFLOW) { + ret = DB_VERIFY_BAD; + break; + } + + src = (u_int8_t *)h + P_OVERHEAD; + bytes = OV_LEN(h); + + if (bytes + P_OVERHEAD > dbp->pgsize) + bytes = dbp->pgsize - P_OVERHEAD; + + if ((ret = __os_realloc(dbp->dbenv, + bytesgot + bytes, 0, buf)) != 0) + break; + + dest = (u_int8_t *)*buf + bytesgot; + bytesgot += bytes; + + memcpy(dest, src, bytes); + + pgno = NEXT_PGNO(h); + /* Not much we can do here--we don't want to quit. */ + if ((ret = memp_fput(dbp->mpf, h, 0)) != 0) + err_ret = ret; + } + + if (ret == 0) { + dbt->size = bytesgot; + dbt->data = *buf; + } + + return ((err_ret != 0 && ret == 0) ? err_ret : ret); +} diff --git a/db/db/db_pr.c b/db/db/db_pr.c new file mode 100644 index 000000000..cb977cadf --- /dev/null +++ b/db/db/db_pr.c @@ -0,0 +1,1284 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: db_pr.c,v 11.46 2001/01/22 17:25:06 krinsky Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "btree.h" +#include "hash.h" +#include "qam.h" +#include "db_am.h" +#include "db_verify.h" + +static int __db_bmeta __P((DB *, FILE *, BTMETA *, u_int32_t)); +static int __db_hmeta __P((DB *, FILE *, HMETA *, u_int32_t)); +static void __db_meta __P((DB *, DBMETA *, FILE *, FN const *, u_int32_t)); +static const char *__db_dbtype_to_string __P((DB *)); +static void __db_prdb __P((DB *, FILE *, u_int32_t)); +static FILE *__db_prinit __P((FILE *)); +static void __db_proff __P((void *)); +static int __db_prtree __P((DB *, u_int32_t)); +static void __db_psize __P((DB *)); +static int __db_qmeta __P((DB *, FILE *, QMETA *, u_int32_t)); + +/* + * 64K is the maximum page size, so by default we check for offsets larger + * than that, and, where possible, we refine the test. + */ +#define PSIZE_BOUNDARY (64 * 1024 + 1) +static size_t set_psize = PSIZE_BOUNDARY; + +static FILE *set_fp; /* Output file descriptor. */ + +/* + * __db_loadme -- + * A nice place to put a breakpoint. + * + * PUBLIC: void __db_loadme __P((void)); + */ +void +__db_loadme() +{ + getpid(); +} + +/* + * __db_dump -- + * Dump the tree to a file. + * + * PUBLIC: int __db_dump __P((DB *, char *, char *)); + */ +int +__db_dump(dbp, op, name) + DB *dbp; + char *op, *name; +{ + FILE *fp, *save_fp; + u_int32_t flags; + + COMPQUIET(save_fp, NULL); + + if (set_psize == PSIZE_BOUNDARY) + __db_psize(dbp); + + if (name != NULL) { + if ((fp = fopen(name, "w")) == NULL) + return (__os_get_errno()); + save_fp = set_fp; + set_fp = fp; + } else + fp = __db_prinit(NULL); + + for (flags = 0; *op != '\0'; ++op) + switch (*op) { + case 'a': + LF_SET(DB_PR_PAGE); + break; + case 'h': + break; + case 'r': + LF_SET(DB_PR_RECOVERYTEST); + break; + default: + return (EINVAL); + } + + __db_prdb(dbp, fp, flags); + + fprintf(fp, "%s\n", DB_LINE); + + (void)__db_prtree(dbp, flags); + + fflush(fp); + + if (name != NULL) { + fclose(fp); + set_fp = save_fp; + } + return (0); +} + +/* + * __db_prdb -- + * Print out the DB structure information. + */ +static void +__db_prdb(dbp, fp, flags) + DB *dbp; + FILE *fp; + u_int32_t flags; +{ + static const FN fn[] = { + { DB_AM_DISCARD, "discard cached pages" }, + { DB_AM_DUP, "duplicates" }, + { DB_AM_INMEM, "in-memory" }, + { DB_AM_PGDEF, "default page size" }, + { DB_AM_RDONLY, "read-only" }, + { DB_AM_SUBDB, "multiple-databases" }, + { DB_AM_SWAP, "needswap" }, + { DB_BT_RECNUM, "btree:recnum" }, + { DB_BT_REVSPLIT, "btree:no reverse split" }, + { DB_DBM_ERROR, "dbm/ndbm error" }, + { DB_OPEN_CALLED, "DB->open called" }, + { DB_RE_DELIMITER, "recno:delimiter" }, + { DB_RE_FIXEDLEN, "recno:fixed-length" }, + { DB_RE_PAD, "recno:pad" }, + { DB_RE_RENUMBER, "recno:renumber" }, + { DB_RE_SNAPSHOT, "recno:snapshot" }, + { 0, NULL } + }; + BTREE *bt; + HASH *h; + QUEUE *q; + + COMPQUIET(flags, 0); + + fprintf(fp, + "In-memory DB structure:\n%s: %#lx", + __db_dbtype_to_string(dbp), (u_long)dbp->flags); + __db_prflags(dbp->flags, fn, fp); + fprintf(fp, "\n"); + + switch (dbp->type) { + case DB_BTREE: + case DB_RECNO: + bt = dbp->bt_internal; + fprintf(fp, "bt_meta: %lu bt_root: %lu\n", + (u_long)bt->bt_meta, (u_long)bt->bt_root); + fprintf(fp, "bt_maxkey: %lu bt_minkey: %lu\n", + (u_long)bt->bt_maxkey, (u_long)bt->bt_minkey); + fprintf(fp, "bt_compare: %#lx bt_prefix: %#lx\n", + (u_long)bt->bt_compare, (u_long)bt->bt_prefix); + fprintf(fp, "bt_lpgno: %lu\n", (u_long)bt->bt_lpgno); + if (dbp->type == DB_RECNO) { + fprintf(fp, + "re_pad: %#lx re_delim: %#lx re_len: %lu re_source: %s\n", + (u_long)bt->re_pad, (u_long)bt->re_delim, + (u_long)bt->re_len, + bt->re_source == NULL ? "" : bt->re_source); + fprintf(fp, "re_modified: %d re_eof: %d re_last: %lu\n", + bt->re_modified, bt->re_eof, (u_long)bt->re_last); + } + break; + case DB_HASH: + h = dbp->h_internal; + fprintf(fp, "meta_pgno: %lu\n", (u_long)h->meta_pgno); + fprintf(fp, "h_ffactor: %lu\n", (u_long)h->h_ffactor); + fprintf(fp, "h_nelem: %lu\n", (u_long)h->h_nelem); + fprintf(fp, "h_hash: %#lx\n", (u_long)h->h_hash); + break; + case DB_QUEUE: + q = dbp->q_internal; + fprintf(fp, "q_meta: %lu\n", (u_long)q->q_meta); + fprintf(fp, "q_root: %lu\n", (u_long)q->q_root); + fprintf(fp, "re_pad: %#lx re_len: %lu\n", + (u_long)q->re_pad, (u_long)q->re_len); + fprintf(fp, "rec_page: %lu\n", (u_long)q->rec_page); + fprintf(fp, "page_ext: %lu\n", (u_long)q->page_ext); + break; + default: + break; + } +} + +/* + * __db_prtree -- + * Print out the entire tree. + */ +static int +__db_prtree(dbp, flags) + DB *dbp; + u_int32_t flags; +{ + PAGE *h; + db_pgno_t i, last; + int ret; + + if (set_psize == PSIZE_BOUNDARY) + __db_psize(dbp); + + if (dbp->type == DB_QUEUE) { + ret = __db_prqueue(dbp, flags); + goto done; + } + + /* Find out the page number of the last page in the database. */ + if ((ret = memp_fget(dbp->mpf, &last, DB_MPOOL_LAST, &h)) != 0) + return (ret); + if ((ret = memp_fput(dbp->mpf, h, 0)) != 0) + return (ret); + + /* Dump each page. */ + for (i = 0; i <= last; ++i) { + if ((ret = memp_fget(dbp->mpf, &i, 0, &h)) != 0) + return (ret); + (void)__db_prpage(dbp, h, flags); + if ((ret = memp_fput(dbp->mpf, h, 0)) != 0) + return (ret); + } + +done: + (void)fflush(__db_prinit(NULL)); + return (0); +} + +/* + * __db_meta -- + * Print out common metadata information. + */ +static void +__db_meta(dbp, dbmeta, fp, fn, flags) + DB *dbp; + DBMETA *dbmeta; + FILE *fp; + FN const *fn; + u_int32_t flags; +{ + PAGE *h; + int cnt; + db_pgno_t pgno; + u_int8_t *p; + int ret; + const char *sep; + + fprintf(fp, "\tmagic: %#lx\n", (u_long)dbmeta->magic); + fprintf(fp, "\tversion: %lu\n", (u_long)dbmeta->version); + fprintf(fp, "\tpagesize: %lu\n", (u_long)dbmeta->pagesize); + fprintf(fp, "\ttype: %lu\n", (u_long)dbmeta->type); + fprintf(fp, "\tkeys: %lu\trecords: %lu\n", + (u_long)dbmeta->key_count, (u_long)dbmeta->record_count); + + if (!LF_ISSET(DB_PR_RECOVERYTEST)) { + /* + * If we're doing recovery testing, don't display the free + * list, it may have changed and that makes the dump diff + * not work. + */ + fprintf(fp, "\tfree list: %lu", (u_long)dbmeta->free); + for (pgno = dbmeta->free, + cnt = 0, sep = ", "; pgno != PGNO_INVALID;) { + if ((ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) { + fprintf(fp, + "Unable to retrieve free-list page: %lu: %s\n", + (u_long)pgno, db_strerror(ret)); + break; + } + pgno = h->next_pgno; + (void)memp_fput(dbp->mpf, h, 0); + fprintf(fp, "%s%lu", sep, (u_long)pgno); + if (++cnt % 10 == 0) { + fprintf(fp, "\n"); + cnt = 0; + sep = "\t"; + } else + sep = ", "; + } + fprintf(fp, "\n"); + } + + if (fn != NULL) { + fprintf(fp, "\tflags: %#lx", (u_long)dbmeta->flags); + __db_prflags(dbmeta->flags, fn, fp); + fprintf(fp, "\n"); + } + + fprintf(fp, "\tuid: "); + for (p = (u_int8_t *)dbmeta->uid, + cnt = 0; cnt < DB_FILE_ID_LEN; ++cnt) { + fprintf(fp, "%x", *p++); + if (cnt < DB_FILE_ID_LEN - 1) + fprintf(fp, " "); + } + fprintf(fp, "\n"); +} + +/* + * __db_bmeta -- + * Print out the btree meta-data page. + */ +static int +__db_bmeta(dbp, fp, h, flags) + DB *dbp; + FILE *fp; + BTMETA *h; + u_int32_t flags; +{ + static const FN mfn[] = { + { BTM_DUP, "duplicates" }, + { BTM_RECNO, "recno" }, + { BTM_RECNUM, "btree:recnum" }, + { BTM_FIXEDLEN, "recno:fixed-length" }, + { BTM_RENUMBER, "recno:renumber" }, + { BTM_SUBDB, "multiple-databases" }, + { 0, NULL } + }; + + __db_meta(dbp, (DBMETA *)h, fp, mfn, flags); + + fprintf(fp, "\tmaxkey: %lu minkey: %lu\n", + (u_long)h->maxkey, (u_long)h->minkey); + if (dbp->type == DB_RECNO) + fprintf(fp, "\tre_len: %#lx re_pad: %lu\n", + (u_long)h->re_len, (u_long)h->re_pad); + fprintf(fp, "\troot: %lu\n", (u_long)h->root); + + return (0); +} + +/* + * __db_hmeta -- + * Print out the hash meta-data page. + */ +static int +__db_hmeta(dbp, fp, h, flags) + DB *dbp; + FILE *fp; + HMETA *h; + u_int32_t flags; +{ + static const FN mfn[] = { + { DB_HASH_DUP, "duplicates" }, + { DB_HASH_SUBDB, "multiple-databases" }, + { 0, NULL } + }; + int i; + + __db_meta(dbp, (DBMETA *)h, fp, mfn, flags); + + fprintf(fp, "\tmax_bucket: %lu\n", (u_long)h->max_bucket); + fprintf(fp, "\thigh_mask: %#lx\n", (u_long)h->high_mask); + fprintf(fp, "\tlow_mask: %#lx\n", (u_long)h->low_mask); + fprintf(fp, "\tffactor: %lu\n", (u_long)h->ffactor); + fprintf(fp, "\tnelem: %lu\n", (u_long)h->nelem); + fprintf(fp, "\th_charkey: %#lx\n", (u_long)h->h_charkey); + fprintf(fp, "\tspare points: "); + for (i = 0; i < NCACHED; i++) + fprintf(fp, "%lu ", (u_long)h->spares[i]); + fprintf(fp, "\n"); + + return (0); +} + +/* + * __db_qmeta -- + * Print out the queue meta-data page. + */ +static int +__db_qmeta(dbp, fp, h, flags) + DB *dbp; + FILE *fp; + QMETA *h; + u_int32_t flags; +{ + __db_meta(dbp, (DBMETA *)h, fp, NULL, flags); + + fprintf(fp, "\tfirst_recno: %lu\n", (u_long)h->first_recno); + fprintf(fp, "\tcur_recno: %lu\n", (u_long)h->cur_recno); + fprintf(fp, "\tre_len: %#lx re_pad: %lu\n", + (u_long)h->re_len, (u_long)h->re_pad); + fprintf(fp, "\trec_page: %lu\n", (u_long)h->rec_page); + fprintf(fp, "\tpage_ext: %lu\n", (u_long)h->page_ext); + + return (0); +} + +/* + * __db_prnpage + * -- Print out a specific page. + * + * PUBLIC: int __db_prnpage __P((DB *, db_pgno_t)); + */ +int +__db_prnpage(dbp, pgno) + DB *dbp; + db_pgno_t pgno; +{ + PAGE *h; + int ret; + + if (set_psize == PSIZE_BOUNDARY) + __db_psize(dbp); + + if ((ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) + return (ret); + + ret = __db_prpage(dbp, h, DB_PR_PAGE); + (void)fflush(__db_prinit(NULL)); + + (void)memp_fput(dbp->mpf, h, 0); + return (ret); +} + +/* + * __db_prpage + * -- Print out a page. + * + * PUBLIC: int __db_prpage __P((DB *, PAGE *, u_int32_t)); + */ +int +__db_prpage(dbp, h, flags) + DB *dbp; + PAGE *h; + u_int32_t flags; +{ + BINTERNAL *bi; + BKEYDATA *bk; + BTREE *t; + FILE *fp; + HOFFPAGE a_hkd; + QAMDATA *qp, *qep; + RINTERNAL *ri; + db_indx_t dlen, len, i; + db_pgno_t pgno; + db_recno_t recno; + int deleted, ret; + const char *s; + u_int32_t qlen; + u_int8_t *ep, *hk, *p; + void *sp; + + fp = __db_prinit(NULL); + + /* + * If we're doing recovery testing and this page is P_INVALID, + * assume it's a page that's on the free list, and don't display it. + */ + if (LF_ISSET(DB_PR_RECOVERYTEST) && TYPE(h) == P_INVALID) + return (0); + + s = __db_pagetype_to_string(TYPE(h)); + if (s == NULL) { + fprintf(fp, "ILLEGAL PAGE TYPE: page: %lu type: %lu\n", + (u_long)h->pgno, (u_long)TYPE(h)); + return (1); + } + + /* Page number, page type. */ + fprintf(fp, "page %lu: %s level: %lu", + (u_long)h->pgno, s, (u_long)h->level); + + /* Record count. */ + if (TYPE(h) == P_IBTREE || + TYPE(h) == P_IRECNO || (TYPE(h) == P_LRECNO && + h->pgno == ((BTREE *)dbp->bt_internal)->bt_root)) + fprintf(fp, " records: %lu", (u_long)RE_NREC(h)); + + /* LSN. */ + if (!LF_ISSET(DB_PR_RECOVERYTEST)) + fprintf(fp, " (lsn.file: %lu lsn.offset: %lu)\n", + (u_long)LSN(h).file, (u_long)LSN(h).offset); + + switch (TYPE(h)) { + case P_BTREEMETA: + return (__db_bmeta(dbp, fp, (BTMETA *)h, flags)); + case P_HASHMETA: + return (__db_hmeta(dbp, fp, (HMETA *)h, flags)); + case P_QAMMETA: + return (__db_qmeta(dbp, fp, (QMETA *)h, flags)); + case P_QAMDATA: /* Should be meta->start. */ + if (!LF_ISSET(DB_PR_PAGE)) + return (0); + + qlen = ((QUEUE *)dbp->q_internal)->re_len; + recno = (h->pgno - 1) * QAM_RECNO_PER_PAGE(dbp) + 1; + i = 0; + qep = (QAMDATA *)((u_int8_t *)h + set_psize - qlen); + for (qp = QAM_GET_RECORD(dbp, h, i); qp < qep; + recno++, i++, qp = QAM_GET_RECORD(dbp, h, i)) { + if (!F_ISSET(qp, QAM_SET)) + continue; + + fprintf(fp, "%s", + F_ISSET(qp, QAM_VALID) ? "\t" : " D"); + fprintf(fp, "[%03lu] %4lu ", + (u_long)recno, (u_long)qp - (u_long)h); + __db_pr(qp->data, qlen); + } + return (0); + } + + /* LSN. */ + if (LF_ISSET(DB_PR_RECOVERYTEST)) + fprintf(fp, " (lsn.file: %lu lsn.offset: %lu)\n", + (u_long)LSN(h).file, (u_long)LSN(h).offset); + + t = dbp->bt_internal; + + s = "\t"; + if (TYPE(h) != P_IBTREE && TYPE(h) != P_IRECNO) { + fprintf(fp, "%sprev: %4lu next: %4lu", + s, (u_long)PREV_PGNO(h), (u_long)NEXT_PGNO(h)); + s = " "; + } + if (TYPE(h) == P_OVERFLOW) { + fprintf(fp, "%sref cnt: %4lu ", s, (u_long)OV_REF(h)); + __db_pr((u_int8_t *)h + P_OVERHEAD, OV_LEN(h)); + return (0); + } + fprintf(fp, "%sentries: %4lu", s, (u_long)NUM_ENT(h)); + fprintf(fp, " offset: %4lu\n", (u_long)HOFFSET(h)); + + if (TYPE(h) == P_INVALID || !LF_ISSET(DB_PR_PAGE)) + return (0); + + ret = 0; + for (i = 0; i < NUM_ENT(h); i++) { + if (P_ENTRY(h, i) - (u_int8_t *)h < P_OVERHEAD || + (size_t)(P_ENTRY(h, i) - (u_int8_t *)h) >= set_psize) { + fprintf(fp, + "ILLEGAL PAGE OFFSET: indx: %lu of %lu\n", + (u_long)i, (u_long)h->inp[i]); + ret = EINVAL; + continue; + } + deleted = 0; + switch (TYPE(h)) { + case P_HASH: + case P_IBTREE: + case P_IRECNO: + sp = P_ENTRY(h, i); + break; + case P_LBTREE: + sp = P_ENTRY(h, i); + deleted = i % 2 == 0 && + B_DISSET(GET_BKEYDATA(h, i + O_INDX)->type); + break; + case P_LDUP: + case P_LRECNO: + sp = P_ENTRY(h, i); + deleted = B_DISSET(GET_BKEYDATA(h, i)->type); + break; + default: + fprintf(fp, + "ILLEGAL PAGE ITEM: %lu\n", (u_long)TYPE(h)); + ret = EINVAL; + continue; + } + fprintf(fp, "%s", deleted ? " D" : "\t"); + fprintf(fp, "[%03lu] %4lu ", (u_long)i, (u_long)h->inp[i]); + switch (TYPE(h)) { + case P_HASH: + hk = sp; + switch (HPAGE_PTYPE(hk)) { + case H_OFFDUP: + memcpy(&pgno, + HOFFDUP_PGNO(hk), sizeof(db_pgno_t)); + fprintf(fp, + "%4lu [offpage dups]\n", (u_long)pgno); + break; + case H_DUPLICATE: + /* + * If this is the first item on a page, then + * we cannot figure out how long it is, so + * we only print the first one in the duplicate + * set. + */ + if (i != 0) + len = LEN_HKEYDATA(h, 0, i); + else + len = 1; + + fprintf(fp, "Duplicates:\n"); + for (p = HKEYDATA_DATA(hk), + ep = p + len; p < ep;) { + memcpy(&dlen, p, sizeof(db_indx_t)); + p += sizeof(db_indx_t); + fprintf(fp, "\t\t"); + __db_pr(p, dlen); + p += sizeof(db_indx_t) + dlen; + } + break; + case H_KEYDATA: + __db_pr(HKEYDATA_DATA(hk), + LEN_HKEYDATA(h, i == 0 ? set_psize : 0, i)); + break; + case H_OFFPAGE: + memcpy(&a_hkd, hk, HOFFPAGE_SIZE); + fprintf(fp, + "overflow: total len: %4lu page: %4lu\n", + (u_long)a_hkd.tlen, (u_long)a_hkd.pgno); + break; + } + break; + case P_IBTREE: + bi = sp; + fprintf(fp, "count: %4lu pgno: %4lu type: %4lu", + (u_long)bi->nrecs, (u_long)bi->pgno, + (u_long)bi->type); + switch (B_TYPE(bi->type)) { + case B_KEYDATA: + __db_pr(bi->data, bi->len); + break; + case B_DUPLICATE: + case B_OVERFLOW: + __db_proff(bi->data); + break; + default: + fprintf(fp, "ILLEGAL BINTERNAL TYPE: %lu\n", + (u_long)B_TYPE(bi->type)); + ret = EINVAL; + break; + } + break; + case P_IRECNO: + ri = sp; + fprintf(fp, "entries %4lu pgno %4lu\n", + (u_long)ri->nrecs, (u_long)ri->pgno); + break; + case P_LBTREE: + case P_LDUP: + case P_LRECNO: + bk = sp; + switch (B_TYPE(bk->type)) { + case B_KEYDATA: + __db_pr(bk->data, bk->len); + break; + case B_DUPLICATE: + case B_OVERFLOW: + __db_proff(bk); + break; + default: + fprintf(fp, + "ILLEGAL DUPLICATE/LBTREE/LRECNO TYPE: %lu\n", + (u_long)B_TYPE(bk->type)); + ret = EINVAL; + break; + } + break; + } + } + (void)fflush(fp); + return (ret); +} + +/* + * __db_pr -- + * Print out a data element. + * + * PUBLIC: void __db_pr __P((u_int8_t *, u_int32_t)); + */ +void +__db_pr(p, len) + u_int8_t *p; + u_int32_t len; +{ + FILE *fp; + u_int lastch; + int i; + + fp = __db_prinit(NULL); + + fprintf(fp, "len: %3lu", (u_long)len); + lastch = '.'; + if (len != 0) { + fprintf(fp, " data: "); + for (i = len <= 20 ? len : 20; i > 0; --i, ++p) { + lastch = *p; + if (isprint((int)*p) || *p == '\n') + fprintf(fp, "%c", *p); + else + fprintf(fp, "0x%.2x", (u_int)*p); + } + if (len > 20) { + fprintf(fp, "..."); + lastch = '.'; + } + } + if (lastch != '\n') + fprintf(fp, "\n"); +} + +/* + * __db_prdbt -- + * Print out a DBT data element. + * + * PUBLIC: int __db_prdbt __P((DBT *, int, const char *, void *, + * PUBLIC: int (*)(void *, const void *), int, VRFY_DBINFO *)); + */ +int +__db_prdbt(dbtp, checkprint, prefix, handle, callback, is_recno, vdp) + DBT *dbtp; + int checkprint; + const char *prefix; + void *handle; + int (*callback) __P((void *, const void *)); + int is_recno; + VRFY_DBINFO *vdp; +{ + static const char hex[] = "0123456789abcdef"; + db_recno_t recno; + u_int32_t len; + int ret; +#define DBTBUFLEN 100 + char *p, *hp, buf[DBTBUFLEN], hbuf[DBTBUFLEN]; + + if (vdp != NULL) { + /* + * If vdp is non-NULL, we might be the first key in the + * "fake" subdatabase used for key/data pairs we can't + * associate with a known subdb. + * + * Check and clear the SALVAGE_PRINTHEADER flag; if + * it was set, print a subdatabase header. + */ + if (F_ISSET(vdp, SALVAGE_PRINTHEADER)) + (void)__db_prheader(NULL, "__OTHER__", 0, 0, + handle, callback, vdp, 0); + F_CLR(vdp, SALVAGE_PRINTHEADER); + F_SET(vdp, SALVAGE_PRINTFOOTER); + } + + /* + * !!! + * This routine is the routine that dumps out items in the format + * used by db_dump(1) and db_load(1). This means that the format + * cannot change. + */ + if (prefix != NULL && (ret = callback(handle, prefix)) != 0) + return (ret); + if (is_recno) { + /* + * We're printing a record number, and this has to be done + * in a platform-independent way. So we use the numeral in + * straight ASCII. + */ + __ua_memcpy(&recno, dbtp->data, sizeof(recno)); + snprintf(buf, DBTBUFLEN, "%lu", (u_long)recno); + + /* If we're printing data as hex, print keys as hex too. */ + if (!checkprint) { + for (len = strlen(buf), p = buf, hp = hbuf; + len-- > 0; ++p) { + *hp++ = hex[(u_int8_t)(*p & 0xf0) >> 4]; + *hp++ = hex[*p & 0x0f]; + } + *hp = '\0'; + ret = callback(handle, hbuf); + } else + ret = callback(handle, buf); + + if (ret != 0) + return (ret); + } else if (checkprint) { + for (len = dbtp->size, p = dbtp->data; len--; ++p) + if (isprint((int)*p)) { + if (*p == '\\' && + (ret = callback(handle, "\\")) != 0) + return (ret); + snprintf(buf, DBTBUFLEN, "%c", *p); + if ((ret = callback(handle, buf)) != 0) + return (ret); + } else { + snprintf(buf, DBTBUFLEN, "\\%c%c", + hex[(u_int8_t)(*p & 0xf0) >> 4], + hex[*p & 0x0f]); + if ((ret = callback(handle, buf)) != 0) + return (ret); + } + } else + for (len = dbtp->size, p = dbtp->data; len--; ++p) { + snprintf(buf, DBTBUFLEN, "%c%c", + hex[(u_int8_t)(*p & 0xf0) >> 4], + hex[*p & 0x0f]); + if ((ret = callback(handle, buf)) != 0) + return (ret); + } + + return (callback(handle, "\n")); +} + +/* + * __db_proff -- + * Print out an off-page element. + */ +static void +__db_proff(vp) + void *vp; +{ + FILE *fp; + BOVERFLOW *bo; + + fp = __db_prinit(NULL); + + bo = vp; + switch (B_TYPE(bo->type)) { + case B_OVERFLOW: + fprintf(fp, "overflow: total len: %4lu page: %4lu\n", + (u_long)bo->tlen, (u_long)bo->pgno); + break; + case B_DUPLICATE: + fprintf(fp, "duplicate: page: %4lu\n", (u_long)bo->pgno); + break; + } +} + +/* + * __db_prflags -- + * Print out flags values. + * + * PUBLIC: void __db_prflags __P((u_int32_t, const FN *, FILE *)); + */ +void +__db_prflags(flags, fn, fp) + u_int32_t flags; + FN const *fn; + FILE *fp; +{ + const FN *fnp; + int found; + const char *sep; + + sep = " ("; + for (found = 0, fnp = fn; fnp->mask != 0; ++fnp) + if (LF_ISSET(fnp->mask)) { + fprintf(fp, "%s%s", sep, fnp->name); + sep = ", "; + found = 1; + } + if (found) + fprintf(fp, ")"); +} + +/* + * __db_prinit -- + * Initialize tree printing routines. + */ +static FILE * +__db_prinit(fp) + FILE *fp; +{ + if (set_fp == NULL) + set_fp = fp == NULL ? stdout : fp; + return (set_fp); +} + +/* + * __db_psize -- + * Get the page size. + */ +static void +__db_psize(dbp) + DB *dbp; +{ + DBMETA *mp; + db_pgno_t pgno; + + set_psize = PSIZE_BOUNDARY - 1; + + pgno = PGNO_BASE_MD; + if (memp_fget(dbp->mpf, &pgno, 0, &mp) != 0) + return; + + switch (mp->magic) { + case DB_BTREEMAGIC: + case DB_HASHMAGIC: + case DB_QAMMAGIC: + set_psize = mp->pagesize; + break; + } + (void)memp_fput(dbp->mpf, mp, 0); +} + +/* + * __db_dbtype_to_string -- + * Return the name of the database type. + */ +static const char * +__db_dbtype_to_string(dbp) + DB *dbp; +{ + switch (dbp->type) { + case DB_BTREE: + return ("btree"); + case DB_HASH: + return ("hash"); + break; + case DB_RECNO: + return ("recno"); + break; + case DB_QUEUE: + return ("queue"); + default: + return ("UNKNOWN TYPE"); + } + /* NOTREACHED */ +} + +/* + * __db_pagetype_to_string -- + * Return the name of the specified page type. + * + * PUBLIC: const char *__db_pagetype_to_string __P((u_int32_t)); + */ +const char * +__db_pagetype_to_string(type) + u_int32_t type; +{ + char *s; + + s = NULL; + switch (type) { + case P_BTREEMETA: + s = "btree metadata"; + break; + case P_LDUP: + s = "duplicate"; + break; + case P_HASH: + s = "hash"; + break; + case P_HASHMETA: + s = "hash metadata"; + break; + case P_IBTREE: + s = "btree internal"; + break; + case P_INVALID: + s = "invalid"; + break; + case P_IRECNO: + s = "recno internal"; + break; + case P_LBTREE: + s = "btree leaf"; + break; + case P_LRECNO: + s = "recno leaf"; + break; + case P_OVERFLOW: + s = "overflow"; + break; + case P_QAMMETA: + s = "queue metadata"; + break; + case P_QAMDATA: + s = "queue"; + break; + default: + /* Just return a NULL. */ + break; + } + return (s); +} + +/* + * __db_prheader -- + * Write out header information in the format expected by db_load. + * + * PUBLIC: int __db_prheader __P((DB *, char *, int, int, void *, + * PUBLIC: int (*)(void *, const void *), VRFY_DBINFO *, db_pgno_t)); + */ +int +__db_prheader(dbp, subname, pflag, keyflag, handle, callback, vdp, meta_pgno) + DB *dbp; + char *subname; + int pflag, keyflag; + void *handle; + int (*callback) __P((void *, const void *)); + VRFY_DBINFO *vdp; + db_pgno_t meta_pgno; +{ + DB_BTREE_STAT *btsp; + DB_ENV *dbenv; + DB_HASH_STAT *hsp; + DB_QUEUE_STAT *qsp; + VRFY_PAGEINFO *pip; + char *buf; + int buflen, ret, t_ret; + u_int32_t dbtype; + + btsp = NULL; + hsp = NULL; + qsp = NULL; + ret = 0; + buf = NULL; + COMPQUIET(buflen, 0); + + if (dbp == NULL) + dbenv = NULL; + else + dbenv = dbp->dbenv; + + /* + * If we've been passed a verifier statistics object, use + * that; we're being called in a context where dbp->stat + * is unsafe. + */ + if (vdp != NULL) { + if ((ret = __db_vrfy_getpageinfo(vdp, meta_pgno, &pip)) != 0) + return (ret); + } else + pip = NULL; + + /* + * If dbp is NULL, we're being called from inside __db_prdbt, + * and this is a special subdatabase for "lost" items. Make it a btree. + * Otherwise, set dbtype to the appropriate type for the specified + * meta page, or the type of the dbp. + */ + if (dbp == NULL) + dbtype = DB_BTREE; + else if (pip != NULL) + switch (pip->type) { + case P_BTREEMETA: + if (F_ISSET(pip, VRFY_IS_RECNO)) + dbtype = DB_RECNO; + else + dbtype = DB_BTREE; + break; + case P_HASHMETA: + dbtype = DB_HASH; + break; + default: + /* + * If the meta page is of a bogus type, it's + * because we have a badly corrupt database. + * (We must be in the verifier for pip to be non-NULL.) + * Pretend we're a Btree and salvage what we can. + */ + DB_ASSERT(F_ISSET(dbp, DB_AM_VERIFYING)); + dbtype = DB_BTREE; + break; + } + else + dbtype = dbp->type; + + if ((ret = callback(handle, "VERSION=3\n")) != 0) + goto err; + if (pflag) { + if ((ret = callback(handle, "format=print\n")) != 0) + goto err; + } else if ((ret = callback(handle, "format=bytevalue\n")) != 0) + goto err; + + /* + * 64 bytes is long enough, as a minimum bound, for any of the + * fields besides subname. Subname can be anything, and so + * 64 + subname is big enough for all the things we need to print here. + */ + buflen = 64 + ((subname != NULL) ? strlen(subname) : 0); + if ((ret = __os_malloc(dbenv, buflen, NULL, &buf)) != 0) + goto err; + if (subname != NULL) { + snprintf(buf, buflen, "database=%s\n", subname); + if ((ret = callback(handle, buf)) != 0) + goto err; + } + switch (dbtype) { + case DB_BTREE: + if ((ret = callback(handle, "type=btree\n")) != 0) + goto err; + if (pip != NULL) { + if (F_ISSET(pip, VRFY_HAS_RECNUMS)) + if ((ret = + callback(handle, "recnum=1\n")) != 0) + goto err; + if (pip->bt_maxkey != 0) { + snprintf(buf, buflen, + "bt_maxkey=%lu\n", (u_long)pip->bt_maxkey); + if ((ret = callback(handle, buf)) != 0) + goto err; + } + if (pip->bt_minkey != 0 && + pip->bt_minkey != DEFMINKEYPAGE) { + snprintf(buf, buflen, + "bt_minkey=%lu\n", (u_long)pip->bt_minkey); + if ((ret = callback(handle, buf)) != 0) + goto err; + } + break; + } + if ((ret = dbp->stat(dbp, &btsp, NULL, 0)) != 0) { + dbp->err(dbp, ret, "DB->stat"); + goto err; + } + if (F_ISSET(dbp, DB_BT_RECNUM)) + if ((ret = callback(handle, "recnum=1\n")) != 0) + goto err; + if (btsp->bt_maxkey != 0) { + snprintf(buf, buflen, + "bt_maxkey=%lu\n", (u_long)btsp->bt_maxkey); + if ((ret = callback(handle, buf)) != 0) + goto err; + } + if (btsp->bt_minkey != 0 && btsp->bt_minkey != DEFMINKEYPAGE) { + snprintf(buf, buflen, + "bt_minkey=%lu\n", (u_long)btsp->bt_minkey); + if ((ret = callback(handle, buf)) != 0) + goto err; + } + break; + case DB_HASH: + if ((ret = callback(handle, "type=hash\n")) != 0) + goto err; + if (pip != NULL) { + if (pip->h_ffactor != 0) { + snprintf(buf, buflen, + "h_ffactor=%lu\n", (u_long)pip->h_ffactor); + if ((ret = callback(handle, buf)) != 0) + goto err; + } + if (pip->h_nelem != 0) { + snprintf(buf, buflen, + "h_nelem=%lu\n", (u_long)pip->h_nelem); + if ((ret = callback(handle, buf)) != 0) + goto err; + } + break; + } + if ((ret = dbp->stat(dbp, &hsp, NULL, 0)) != 0) { + dbp->err(dbp, ret, "DB->stat"); + goto err; + } + if (hsp->hash_ffactor != 0) { + snprintf(buf, buflen, + "h_ffactor=%lu\n", (u_long)hsp->hash_ffactor); + if ((ret = callback(handle, buf)) != 0) + goto err; + } + if (hsp->hash_nelem != 0 || hsp->hash_nkeys != 0) { + snprintf(buf, buflen, "h_nelem=%lu\n", + hsp->hash_nelem > hsp->hash_nkeys ? + (u_long)hsp->hash_nelem : (u_long)hsp->hash_nkeys); + if ((ret = callback(handle, buf)) != 0) + goto err; + } + break; + case DB_QUEUE: + if ((ret = callback(handle, "type=queue\n")) != 0) + goto err; + if (vdp != NULL) { + snprintf(buf, + buflen, "re_len=%lu\n", (u_long)vdp->re_len); + if ((ret = callback(handle, buf)) != 0) + goto err; + break; + } + if ((ret = dbp->stat(dbp, &qsp, NULL, 0)) != 0) { + dbp->err(dbp, ret, "DB->stat"); + goto err; + } + snprintf(buf, buflen, "re_len=%lu\n", (u_long)qsp->qs_re_len); + if (qsp->qs_re_pad != 0 && qsp->qs_re_pad != ' ') + snprintf(buf, buflen, "re_pad=%#x\n", qsp->qs_re_pad); + if ((ret = callback(handle, buf)) != 0) + goto err; + break; + case DB_RECNO: + if ((ret = callback(handle, "type=recno\n")) != 0) + goto err; + if (pip != NULL) { + if (F_ISSET(pip, VRFY_IS_RRECNO)) + if ((ret = + callback(handle, "renumber=1\n")) != 0) + goto err; + if (pip->re_len > 0) { + snprintf(buf, buflen, + "re_len=%lu\n", (u_long)pip->re_len); + if ((ret = callback(handle, buf)) != 0) + goto err; + } + break; + } + if ((ret = dbp->stat(dbp, &btsp, NULL, 0)) != 0) { + dbp->err(dbp, ret, "DB->stat"); + goto err; + } + if (F_ISSET(dbp, DB_RE_RENUMBER)) + if ((ret = callback(handle, "renumber=1\n")) != 0) + goto err; + if (F_ISSET(dbp, DB_RE_FIXEDLEN)) { + snprintf(buf, buflen, + "re_len=%lu\n", (u_long)btsp->bt_re_len); + if ((ret = callback(handle, buf)) != 0) + goto err; + } + if (btsp->bt_re_pad != 0 && btsp->bt_re_pad != ' ') { + snprintf(buf, buflen, "re_pad=%#x\n", btsp->bt_re_pad); + if ((ret = callback(handle, buf)) != 0) + goto err; + } + break; + case DB_UNKNOWN: + DB_ASSERT(0); /* Impossible. */ + __db_err(dbp->dbenv, "Impossible DB type in __db_prheader"); + ret = EINVAL; + goto err; + } + + if (pip != NULL) { + if (F_ISSET(pip, VRFY_HAS_DUPS)) + if ((ret = callback(handle, "duplicates=1\n")) != 0) + goto err; + if (F_ISSET(pip, VRFY_HAS_DUPSORT)) + if ((ret = callback(handle, "dupsort=1\n")) != 0) + goto err; + /* We should handle page size. XXX */ + } else { + if (F_ISSET(dbp, DB_AM_DUP)) + if ((ret = callback(handle, "duplicates=1\n")) != 0) + goto err; + if (F_ISSET(dbp, DB_AM_DUPSORT)) + if ((ret = callback(handle, "dupsort=1\n")) != 0) + goto err; + if (!F_ISSET(dbp, DB_AM_PGDEF)) { + snprintf(buf, buflen, + "db_pagesize=%lu\n", (u_long)dbp->pgsize); + if ((ret = callback(handle, buf)) != 0) + goto err; + } + } + + if (keyflag && (ret = callback(handle, "keys=1\n")) != 0) + goto err; + + ret = callback(handle, "HEADER=END\n"); + +err: if (pip != NULL && + (t_ret = __db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0) + ret = t_ret; + if (btsp != NULL) + __os_free(btsp, 0); + if (hsp != NULL) + __os_free(hsp, 0); + if (qsp != NULL) + __os_free(qsp, 0); + if (buf != NULL) + __os_free(buf, buflen); + + return (ret); +} + +/* + * __db_prfooter -- + * Print the footer that marks the end of a DB dump. This is trivial, + * but for consistency's sake we don't want to put its literal contents + * in multiple places. + * + * PUBLIC: int __db_prfooter __P((void *, int (*)(void *, const void *))); + */ +int +__db_prfooter(handle, callback) + void *handle; + int (*callback) __P((void *, const void *)); +{ + return (callback(handle, "DATA=END\n")); +} diff --git a/db/db/db_rec.c b/db/db/db_rec.c new file mode 100644 index 000000000..998d07429 --- /dev/null +++ b/db/db/db_rec.c @@ -0,0 +1,529 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: db_rec.c,v 11.10 2000/08/03 15:32:19 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "log.h" +#include "hash.h" + +/* + * PUBLIC: int __db_addrem_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + * + * This log message is generated whenever we add or remove a duplicate + * to/from a duplicate page. On recover, we just do the opposite. + */ +int +__db_addrem_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __db_addrem_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + u_int32_t change; + int cmp_n, cmp_p, ret; + + COMPQUIET(info, NULL); + REC_PRINT(__db_addrem_print); + REC_INTRO(__db_addrem_read, 1); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) { + if (DB_UNDO(op)) { + /* + * We are undoing and the page doesn't exist. That + * is equivalent to having a pagelsn of 0, so we + * would not have to undo anything. In this case, + * don't bother creating a page. + */ + goto done; + } else + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } + + cmp_n = log_compare(lsnp, &LSN(pagep)); + cmp_p = log_compare(&LSN(pagep), &argp->pagelsn); + CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->pagelsn); + change = 0; + if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == DB_ADD_DUP) || + (cmp_n == 0 && DB_UNDO(op) && argp->opcode == DB_REM_DUP)) { + + /* Need to redo an add, or undo a delete. */ + if ((ret = __db_pitem(dbc, pagep, argp->indx, argp->nbytes, + argp->hdr.size == 0 ? NULL : &argp->hdr, + argp->dbt.size == 0 ? NULL : &argp->dbt)) != 0) + goto out; + + change = DB_MPOOL_DIRTY; + + } else if ((cmp_n == 0 && DB_UNDO(op) && argp->opcode == DB_ADD_DUP) || + (cmp_p == 0 && DB_REDO(op) && argp->opcode == DB_REM_DUP)) { + /* Need to undo an add, or redo a delete. */ + if ((ret = __db_ditem(dbc, + pagep, argp->indx, argp->nbytes)) != 0) + goto out; + change = DB_MPOOL_DIRTY; + } + + if (change) { + if (DB_REDO(op)) + LSN(pagep) = *lsnp; + else + LSN(pagep) = argp->pagelsn; + } + + if ((ret = memp_fput(mpf, pagep, change)) != 0) + goto out; + +done: *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * PUBLIC: int __db_big_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__db_big_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __db_big_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + u_int32_t change; + int cmp_n, cmp_p, ret; + + COMPQUIET(info, NULL); + REC_PRINT(__db_big_print); + REC_INTRO(__db_big_read, 1); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) { + if (DB_UNDO(op)) { + /* + * We are undoing and the page doesn't exist. That + * is equivalent to having a pagelsn of 0, so we + * would not have to undo anything. In this case, + * don't bother creating a page. + */ + ret = 0; + goto ppage; + } else + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } + + /* + * There are three pages we need to check. The one on which we are + * adding data, the previous one whose next_pointer may have + * been updated, and the next one whose prev_pointer may have + * been updated. + */ + cmp_n = log_compare(lsnp, &LSN(pagep)); + cmp_p = log_compare(&LSN(pagep), &argp->pagelsn); + CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->pagelsn); + change = 0; + if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == DB_ADD_BIG) || + (cmp_n == 0 && DB_UNDO(op) && argp->opcode == DB_REM_BIG)) { + /* We are either redo-ing an add, or undoing a delete. */ + P_INIT(pagep, file_dbp->pgsize, argp->pgno, argp->prev_pgno, + argp->next_pgno, 0, P_OVERFLOW); + OV_LEN(pagep) = argp->dbt.size; + OV_REF(pagep) = 1; + memcpy((u_int8_t *)pagep + P_OVERHEAD, argp->dbt.data, + argp->dbt.size); + PREV_PGNO(pagep) = argp->prev_pgno; + change = DB_MPOOL_DIRTY; + } else if ((cmp_n == 0 && DB_UNDO(op) && argp->opcode == DB_ADD_BIG) || + (cmp_p == 0 && DB_REDO(op) && argp->opcode == DB_REM_BIG)) { + /* + * We are either undo-ing an add or redo-ing a delete. + * The page is about to be reclaimed in either case, so + * there really isn't anything to do here. + */ + change = DB_MPOOL_DIRTY; + } + if (change) + LSN(pagep) = DB_REDO(op) ? *lsnp : argp->pagelsn; + + if ((ret = memp_fput(mpf, pagep, change)) != 0) + goto out; + + /* Now check the previous page. */ +ppage: if (argp->prev_pgno != PGNO_INVALID) { + change = 0; + if ((ret = memp_fget(mpf, &argp->prev_pgno, 0, &pagep)) != 0) { + if (DB_UNDO(op)) { + /* + * We are undoing and the page doesn't exist. + * That is equivalent to having a pagelsn of 0, + * so we would not have to undo anything. In + * this case, don't bother creating a page. + */ + *lsnp = argp->prev_lsn; + ret = 0; + goto npage; + } else + if ((ret = memp_fget(mpf, &argp->prev_pgno, + DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } + + cmp_n = log_compare(lsnp, &LSN(pagep)); + cmp_p = log_compare(&LSN(pagep), &argp->prevlsn); + CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->prevlsn); + + if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == DB_ADD_BIG) || + (cmp_n == 0 && DB_UNDO(op) && argp->opcode == DB_REM_BIG)) { + /* Redo add, undo delete. */ + NEXT_PGNO(pagep) = argp->pgno; + change = DB_MPOOL_DIRTY; + } else if ((cmp_n == 0 && + DB_UNDO(op) && argp->opcode == DB_ADD_BIG) || + (cmp_p == 0 && DB_REDO(op) && argp->opcode == DB_REM_BIG)) { + /* Redo delete, undo add. */ + NEXT_PGNO(pagep) = argp->next_pgno; + change = DB_MPOOL_DIRTY; + } + if (change) + LSN(pagep) = DB_REDO(op) ? *lsnp : argp->prevlsn; + if ((ret = memp_fput(mpf, pagep, change)) != 0) + goto out; + } + + /* Now check the next page. Can only be set on a delete. */ +npage: if (argp->next_pgno != PGNO_INVALID) { + change = 0; + if ((ret = memp_fget(mpf, &argp->next_pgno, 0, &pagep)) != 0) { + if (DB_UNDO(op)) { + /* + * We are undoing and the page doesn't exist. + * That is equivalent to having a pagelsn of 0, + * so we would not have to undo anything. In + * this case, don't bother creating a page. + */ + goto done; + } else + if ((ret = memp_fget(mpf, &argp->next_pgno, + DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } + + cmp_n = log_compare(lsnp, &LSN(pagep)); + cmp_p = log_compare(&LSN(pagep), &argp->nextlsn); + CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->nextlsn); + if (cmp_p == 0 && DB_REDO(op)) { + PREV_PGNO(pagep) = PGNO_INVALID; + change = DB_MPOOL_DIRTY; + } else if (cmp_n == 0 && DB_UNDO(op)) { + PREV_PGNO(pagep) = argp->pgno; + change = DB_MPOOL_DIRTY; + } + if (change) + LSN(pagep) = DB_REDO(op) ? *lsnp : argp->nextlsn; + if ((ret = memp_fput(mpf, pagep, change)) != 0) + goto out; + } + +done: *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __db_ovref_recover -- + * Recovery function for __db_ovref(). + * + * PUBLIC: int __db_ovref_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__db_ovref_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __db_ovref_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp, modified, ret; + + COMPQUIET(info, NULL); + REC_PRINT(__db_ovref_print); + REC_INTRO(__db_ovref_read, 1); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) { + if (DB_UNDO(op)) + goto done; + (void)__db_pgerr(file_dbp, argp->pgno); + goto out; + } + + modified = 0; + cmp = log_compare(&LSN(pagep), &argp->lsn); + CHECK_LSN(op, cmp, &LSN(pagep), &argp->lsn); + if (cmp == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + OV_REF(pagep) += argp->adjust; + + pagep->lsn = *lsnp; + modified = 1; + } else if (log_compare(lsnp, &LSN(pagep)) == 0 && DB_UNDO(op)) { + /* Need to undo update described. */ + OV_REF(pagep) -= argp->adjust; + + pagep->lsn = argp->lsn; + modified = 1; + } + if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) + goto out; + +done: *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __db_relink_recover -- + * Recovery function for relink. + * + * PUBLIC: int __db_relink_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__db_relink_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __db_relink_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + COMPQUIET(info, NULL); + REC_PRINT(__db_relink_print); + REC_INTRO(__db_relink_read, 1); + + /* + * There are up to three pages we need to check -- the page, and the + * previous and next pages, if they existed. For a page add operation, + * the current page is the result of a split and is being recovered + * elsewhere, so all we need do is recover the next page. + */ + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) { + if (DB_REDO(op)) { + (void)__db_pgerr(file_dbp, argp->pgno); + goto out; + } + goto next2; + } + modified = 0; + if (argp->opcode == DB_ADD_PAGE) + goto next1; + + cmp_p = log_compare(&LSN(pagep), &argp->lsn); + CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->lsn); + if (cmp_p == 0 && DB_REDO(op)) { + /* Redo the relink. */ + pagep->lsn = *lsnp; + modified = 1; + } else if (log_compare(lsnp, &LSN(pagep)) == 0 && DB_UNDO(op)) { + /* Undo the relink. */ + pagep->next_pgno = argp->next; + pagep->prev_pgno = argp->prev; + + pagep->lsn = argp->lsn; + modified = 1; + } +next1: if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) + goto out; + +next2: if ((ret = memp_fget(mpf, &argp->next, 0, &pagep)) != 0) { + if (DB_REDO(op)) { + (void)__db_pgerr(file_dbp, argp->next); + goto out; + } + goto prev; + } + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + cmp_p = log_compare(&LSN(pagep), &argp->lsn_next); + CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->lsn_next); + if ((argp->opcode == DB_REM_PAGE && cmp_p == 0 && DB_REDO(op)) || + (argp->opcode == DB_ADD_PAGE && cmp_n == 0 && DB_UNDO(op))) { + /* Redo the remove or undo the add. */ + pagep->prev_pgno = argp->prev; + + modified = 1; + } else if ((argp->opcode == DB_REM_PAGE && cmp_n == 0 && DB_UNDO(op)) || + (argp->opcode == DB_ADD_PAGE && cmp_p == 0 && DB_REDO(op))) { + /* Undo the remove or redo the add. */ + pagep->prev_pgno = argp->pgno; + + modified = 1; + } + if (modified == 1) { + if (DB_UNDO(op)) + pagep->lsn = argp->lsn_next; + else + pagep->lsn = *lsnp; + } + if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) + goto out; + if (argp->opcode == DB_ADD_PAGE) + goto done; + +prev: if ((ret = memp_fget(mpf, &argp->prev, 0, &pagep)) != 0) { + if (DB_REDO(op)) { + (void)__db_pgerr(file_dbp, argp->prev); + goto out; + } + goto done; + } + modified = 0; + cmp_p = log_compare(&LSN(pagep), &argp->lsn_prev); + CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->lsn_prev); + if (cmp_p == 0 && DB_REDO(op)) { + /* Redo the relink. */ + pagep->next_pgno = argp->next; + + modified = 1; + } else if (log_compare(lsnp, &LSN(pagep)) == 0 && DB_UNDO(op)) { + /* Undo the relink. */ + pagep->next_pgno = argp->pgno; + + modified = 1; + } + if (modified == 1) { + if (DB_UNDO(op)) + pagep->lsn = argp->lsn_prev; + else + pagep->lsn = *lsnp; + } + if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) + goto out; + +done: *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __db_debug_recover -- + * Recovery function for debug. + * + * PUBLIC: int __db_debug_recover __P((DB_ENV *, + * PUBLIC: DBT *, DB_LSN *, db_recops, void *)); + */ +int +__db_debug_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __db_debug_args *argp; + int ret; + + COMPQUIET(op, 0); + COMPQUIET(dbenv, NULL); + COMPQUIET(info, NULL); + + REC_PRINT(__db_debug_print); + REC_NOOP_INTRO(__db_debug_read); + + *lsnp = argp->prev_lsn; + ret = 0; + + REC_NOOP_CLOSE; +} + +/* + * __db_noop_recover -- + * Recovery function for noop. + * + * PUBLIC: int __db_noop_recover __P((DB_ENV *, + * PUBLIC: DBT *, DB_LSN *, db_recops, void *)); + */ +int +__db_noop_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __db_noop_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + u_int32_t change; + int cmp_n, cmp_p, ret; + + COMPQUIET(info, NULL); + REC_PRINT(__db_noop_print); + REC_INTRO(__db_noop_read, 0); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + goto out; + + cmp_n = log_compare(lsnp, &LSN(pagep)); + cmp_p = log_compare(&LSN(pagep), &argp->prevlsn); + CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->prevlsn); + change = 0; + if (cmp_p == 0 && DB_REDO(op)) { + LSN(pagep) = *lsnp; + change = DB_MPOOL_DIRTY; + } else if (cmp_n == 0 && DB_UNDO(op)) { + LSN(pagep) = argp->prevlsn; + change = DB_MPOOL_DIRTY; + } + ret = memp_fput(mpf, pagep, change); + +done: *lsnp = argp->prev_lsn; +out: REC_CLOSE; +} diff --git a/db/db/db_reclaim.c b/db/db/db_reclaim.c new file mode 100644 index 000000000..739f34840 --- /dev/null +++ b/db/db/db_reclaim.c @@ -0,0 +1,134 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: db_reclaim.c,v 11.5 2000/04/07 14:26:58 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_am.h" + +/* + * Assume that we enter with a valid pgno. We traverse a set of + * duplicate pages. The format of the callback routine is: + * callback(dbp, page, cookie, did_put). did_put is an output + * value that will be set to 1 by the callback routine if it + * already put the page back. Otherwise, this routine must + * put the page. + * + * PUBLIC: int __db_traverse_dup __P((DB *, + * PUBLIC: db_pgno_t, int (*)(DB *, PAGE *, void *, int *), void *)); + */ +int +__db_traverse_dup(dbp, pgno, callback, cookie) + DB *dbp; + db_pgno_t pgno; + int (*callback) __P((DB *, PAGE *, void *, int *)); + void *cookie; +{ + PAGE *p; + int did_put, i, opgno, ret; + + do { + did_put = 0; + if ((ret = memp_fget(dbp->mpf, &pgno, 0, &p)) != 0) + return (ret); + pgno = NEXT_PGNO(p); + + for (i = 0; i < NUM_ENT(p); i++) { + if (B_TYPE(GET_BKEYDATA(p, i)->type) == B_OVERFLOW) { + opgno = GET_BOVERFLOW(p, i)->pgno; + if ((ret = __db_traverse_big(dbp, + opgno, callback, cookie)) != 0) + goto err; + } + } + + if ((ret = callback(dbp, p, cookie, &did_put)) != 0) + goto err; + + if (!did_put) + if ((ret = memp_fput(dbp->mpf, p, 0)) != 0) + return (ret); + } while (pgno != PGNO_INVALID); + + if (0) { +err: if (did_put == 0) + (void)memp_fput(dbp->mpf, p, 0); + } + return (ret); +} + +/* + * __db_traverse_big + * Traverse a chain of overflow pages and call the callback routine + * on each one. The calling convention for the callback is: + * callback(dbp, page, cookie, did_put), + * where did_put is a return value indicating if the page in question has + * already been returned to the mpool. + * + * PUBLIC: int __db_traverse_big __P((DB *, + * PUBLIC: db_pgno_t, int (*)(DB *, PAGE *, void *, int *), void *)); + */ +int +__db_traverse_big(dbp, pgno, callback, cookie) + DB *dbp; + db_pgno_t pgno; + int (*callback) __P((DB *, PAGE *, void *, int *)); + void *cookie; +{ + PAGE *p; + int did_put, ret; + + do { + did_put = 0; + if ((ret = memp_fget(dbp->mpf, &pgno, 0, &p)) != 0) + return (ret); + pgno = NEXT_PGNO(p); + if ((ret = callback(dbp, p, cookie, &did_put)) == 0 && + !did_put) + ret = memp_fput(dbp->mpf, p, 0); + } while (ret == 0 && pgno != PGNO_INVALID); + + return (ret); +} + +/* + * __db_reclaim_callback + * This is the callback routine used during a delete of a subdatabase. + * we are traversing a btree or hash table and trying to free all the + * pages. Since they share common code for duplicates and overflow + * items, we traverse them identically and use this routine to do the + * actual free. The reason that this is callback is because hash uses + * the same traversal code for statistics gathering. + * + * PUBLIC: int __db_reclaim_callback __P((DB *, PAGE *, void *, int *)); + */ +int +__db_reclaim_callback(dbp, p, cookie, putp) + DB *dbp; + PAGE *p; + void *cookie; + int *putp; +{ + int ret; + + COMPQUIET(dbp, NULL); + + if ((ret = __db_free(cookie, p)) != 0) + return (ret); + *putp = 1; + + return (0); +} diff --git a/db/db/db_ret.c b/db/db/db_ret.c new file mode 100644 index 000000000..0782de3e4 --- /dev/null +++ b/db/db/db_ret.c @@ -0,0 +1,160 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: db_ret.c,v 11.12 2000/11/30 00:58:33 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "btree.h" +#include "db_am.h" + +/* + * __db_ret -- + * Build return DBT. + * + * PUBLIC: int __db_ret __P((DB *, + * PUBLIC: PAGE *, u_int32_t, DBT *, void **, u_int32_t *)); + */ +int +__db_ret(dbp, h, indx, dbt, memp, memsize) + DB *dbp; + PAGE *h; + u_int32_t indx; + DBT *dbt; + void **memp; + u_int32_t *memsize; +{ + BKEYDATA *bk; + HOFFPAGE ho; + BOVERFLOW *bo; + u_int32_t len; + u_int8_t *hk; + void *data; + + switch (TYPE(h)) { + case P_HASH: + hk = P_ENTRY(h, indx); + if (HPAGE_PTYPE(hk) == H_OFFPAGE) { + memcpy(&ho, hk, sizeof(HOFFPAGE)); + return (__db_goff(dbp, dbt, + ho.tlen, ho.pgno, memp, memsize)); + } + len = LEN_HKEYDATA(h, dbp->pgsize, indx); + data = HKEYDATA_DATA(hk); + break; + case P_LBTREE: + case P_LDUP: + case P_LRECNO: + bk = GET_BKEYDATA(h, indx); + if (B_TYPE(bk->type) == B_OVERFLOW) { + bo = (BOVERFLOW *)bk; + return (__db_goff(dbp, dbt, + bo->tlen, bo->pgno, memp, memsize)); + } + len = bk->len; + data = bk->data; + break; + default: + return (__db_pgfmt(dbp, h->pgno)); + } + + return (__db_retcopy(dbp, dbt, data, len, memp, memsize)); +} + +/* + * __db_retcopy -- + * Copy the returned data into the user's DBT, handling special flags. + * + * PUBLIC: int __db_retcopy __P((DB *, DBT *, + * PUBLIC: void *, u_int32_t, void **, u_int32_t *)); + */ +int +__db_retcopy(dbp, dbt, data, len, memp, memsize) + DB *dbp; + DBT *dbt; + void *data; + u_int32_t len; + void **memp; + u_int32_t *memsize; +{ + DB_ENV *dbenv; + int ret; + + dbenv = dbp == NULL ? NULL : dbp->dbenv; + + /* If returning a partial record, reset the length. */ + if (F_ISSET(dbt, DB_DBT_PARTIAL)) { + data = (u_int8_t *)data + dbt->doff; + if (len > dbt->doff) { + len -= dbt->doff; + if (len > dbt->dlen) + len = dbt->dlen; + } else + len = 0; + } + + /* + * Return the length of the returned record in the DBT size field. + * This satisfies the requirement that if we're using user memory + * and insufficient memory was provided, return the amount necessary + * in the size field. + */ + dbt->size = len; + + /* + * Allocate memory to be owned by the application: DB_DBT_MALLOC, + * DB_DBT_REALLOC. + * + * !!! + * We always allocate memory, even if we're copying out 0 bytes. This + * guarantees consistency, i.e., the application can always free memory + * without concern as to how many bytes of the record were requested. + * + * Use the memory specified by the application: DB_DBT_USERMEM. + * + * !!! + * If the length we're going to copy is 0, the application-supplied + * memory pointer is allowed to be NULL. + */ + if (F_ISSET(dbt, DB_DBT_MALLOC)) { + if ((ret = __os_malloc(dbenv, len, + dbp == NULL ? NULL : dbp->db_malloc, &dbt->data)) != 0) + return (ret); + } else if (F_ISSET(dbt, DB_DBT_REALLOC)) { + if ((ret = __os_realloc(dbenv, len, + dbp == NULL ? NULL : dbp->db_realloc, &dbt->data)) != 0) + return (ret); + } else if (F_ISSET(dbt, DB_DBT_USERMEM)) { + if (len != 0 && (dbt->data == NULL || dbt->ulen < len)) + return (ENOMEM); + } else if (memp == NULL || memsize == NULL) { + return (EINVAL); + } else { + if (len != 0 && (*memsize == 0 || *memsize < len)) { + if ((ret = __os_realloc(dbenv, len, NULL, memp)) != 0) { + *memsize = 0; + return (ret); + } + *memsize = len; + } + dbt->data = *memp; + } + + if (len != 0) + memcpy(dbt->data, data, len); + return (0); +} diff --git a/db/db/db_upg.c b/db/db/db_upg.c new file mode 100644 index 000000000..d8573146a --- /dev/null +++ b/db/db/db_upg.c @@ -0,0 +1,338 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: db_upg.c,v 11.20 2000/12/12 17:35:30 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_swap.h" +#include "btree.h" +#include "hash.h" +#include "qam.h" + +static int (* const func_31_list[P_PAGETYPE_MAX]) + __P((DB *, char *, u_int32_t, DB_FH *, PAGE *, int *)) = { + NULL, /* P_INVALID */ + NULL, /* __P_DUPLICATE */ + __ham_31_hash, /* P_HASH */ + NULL, /* P_IBTREE */ + NULL, /* P_IRECNO */ + __bam_31_lbtree, /* P_LBTREE */ + NULL, /* P_LRECNO */ + NULL, /* P_OVERFLOW */ + __ham_31_hashmeta, /* P_HASHMETA */ + __bam_31_btreemeta, /* P_BTREEMETA */ +}; + +static int __db_page_pass __P((DB *, char *, u_int32_t, int (* const []) + (DB *, char *, u_int32_t, DB_FH *, PAGE *, int *), DB_FH *)); + +/* + * __db_upgrade -- + * Upgrade an existing database. + * + * PUBLIC: int __db_upgrade __P((DB *, const char *, u_int32_t)); + */ +int +__db_upgrade(dbp, fname, flags) + DB *dbp; + const char *fname; + u_int32_t flags; +{ + DB_ENV *dbenv; + DB_FH fh; + size_t n; + int ret, t_ret; + u_int8_t mbuf[256]; + char *real_name; + + dbenv = dbp->dbenv; + + /* Validate arguments. */ + if ((ret = __db_fchk(dbenv, "DB->upgrade", flags, DB_DUPSORT)) != 0) + return (ret); + + /* Get the real backing file name. */ + if ((ret = __db_appname(dbenv, + DB_APP_DATA, NULL, fname, 0, NULL, &real_name)) != 0) + return (ret); + + /* Open the file. */ + if ((ret = __os_open(dbenv, real_name, 0, 0, &fh)) != 0) { + __db_err(dbenv, "%s: %s", real_name, db_strerror(ret)); + return (ret); + } + + /* Initialize the feedback. */ + if (dbp->db_feedback != NULL) + dbp->db_feedback(dbp, DB_UPGRADE, 0); + + /* + * Read the metadata page. We read 256 bytes, which is larger than + * any access method's metadata page and smaller than any disk sector. + */ + if ((ret = __os_read(dbenv, &fh, mbuf, sizeof(mbuf), &n)) != 0) + goto err; + + switch (((DBMETA *)mbuf)->magic) { + case DB_BTREEMAGIC: + switch (((DBMETA *)mbuf)->version) { + case 6: + /* + * Before V7 not all pages had page types, so we do the + * single meta-data page by hand. + */ + if ((ret = + __bam_30_btreemeta(dbp, real_name, mbuf)) != 0) + goto err; + if ((ret = __os_seek(dbenv, + &fh, 0, 0, 0, 0, DB_OS_SEEK_SET)) != 0) + goto err; + if ((ret = __os_write(dbenv, &fh, mbuf, 256, &n)) != 0) + goto err; + /* FALLTHROUGH */ + case 7: + /* + * We need the page size to do more. Rip it out of + * the meta-data page. + */ + memcpy(&dbp->pgsize, mbuf + 20, sizeof(u_int32_t)); + + if ((ret = __db_page_pass( + dbp, real_name, flags, func_31_list, &fh)) != 0) + goto err; + /* FALLTHROUGH */ + case 8: + break; + default: + __db_err(dbenv, "%s: unsupported btree version: %lu", + real_name, (u_long)((DBMETA *)mbuf)->version); + ret = DB_OLD_VERSION; + goto err; + } + break; + case DB_HASHMAGIC: + switch (((DBMETA *)mbuf)->version) { + case 4: + case 5: + /* + * Before V6 not all pages had page types, so we do the + * single meta-data page by hand. + */ + if ((ret = + __ham_30_hashmeta(dbp, real_name, mbuf)) != 0) + goto err; + if ((ret = __os_seek(dbenv, + &fh, 0, 0, 0, 0, DB_OS_SEEK_SET)) != 0) + goto err; + if ((ret = __os_write(dbenv, &fh, mbuf, 256, &n)) != 0) + goto err; + + /* + * Before V6, we created hash pages one by one as they + * were needed, using hashhdr.ovfl_point to reserve + * a block of page numbers for them. A consequence + * of this was that, if no overflow pages had been + * created, the current doubling might extend past + * the end of the database file. + * + * In DB 3.X, we now create all the hash pages + * belonging to a doubling atomicly; it's not + * safe to just save them for later, because when + * we create an overflow page we'll just create + * a new last page (whatever that may be). Grow + * the database to the end of the current doubling. + */ + if ((ret = + __ham_30_sizefix(dbp, &fh, real_name, mbuf)) != 0) + goto err; + /* FALLTHROUGH */ + case 6: + /* + * We need the page size to do more. Rip it out of + * the meta-data page. + */ + memcpy(&dbp->pgsize, mbuf + 20, sizeof(u_int32_t)); + + if ((ret = __db_page_pass( + dbp, real_name, flags, func_31_list, &fh)) != 0) + goto err; + /* FALLTHROUGH */ + case 7: + break; + default: + __db_err(dbenv, "%s: unsupported hash version: %lu", + real_name, (u_long)((DBMETA *)mbuf)->version); + ret = DB_OLD_VERSION; + goto err; + } + break; + case DB_QAMMAGIC: + switch (((DBMETA *)mbuf)->version) { + case 1: + /* + * If we're in a Queue database, the only page that + * needs upgrading is the meta-database page, don't + * bother with a full pass. + */ + if ((ret = __qam_31_qammeta(dbp, real_name, mbuf)) != 0) + return (ret); + /* FALLTHROUGH */ + case 2: + if ((ret = __qam_32_qammeta(dbp, real_name, mbuf)) != 0) + return (ret); + if ((ret = __os_seek(dbenv, + &fh, 0, 0, 0, 0, DB_OS_SEEK_SET)) != 0) + goto err; + if ((ret = __os_write(dbenv, &fh, mbuf, 256, &n)) != 0) + goto err; + /* FALLTHROUGH */ + case 3: + break; + default: + __db_err(dbenv, "%s: unsupported queue version: %lu", + real_name, (u_long)((DBMETA *)mbuf)->version); + ret = DB_OLD_VERSION; + goto err; + } + break; + default: + M_32_SWAP(((DBMETA *)mbuf)->magic); + switch (((DBMETA *)mbuf)->magic) { + case DB_BTREEMAGIC: + case DB_HASHMAGIC: + case DB_QAMMAGIC: + __db_err(dbenv, + "%s: DB->upgrade only supported on native byte-order systems", + real_name); + break; + default: + __db_err(dbenv, + "%s: unrecognized file type", real_name); + break; + } + ret = EINVAL; + goto err; + } + + ret = __os_fsync(dbenv, &fh); + +err: if ((t_ret = __os_closehandle(&fh)) != 0 && ret == 0) + ret = t_ret; + __os_freestr(real_name); + + /* We're done. */ + if (dbp->db_feedback != NULL) + dbp->db_feedback(dbp, DB_UPGRADE, 100); + + return (ret); +} + +/* + * __db_page_pass -- + * Walk the pages of the database, upgrading whatever needs it. + */ +static int +__db_page_pass(dbp, real_name, flags, fl, fhp) + DB *dbp; + char *real_name; + u_int32_t flags; + int (* const fl[P_PAGETYPE_MAX]) + __P((DB *, char *, u_int32_t, DB_FH *, PAGE *, int *)); + DB_FH *fhp; +{ + DB_ENV *dbenv; + PAGE *page; + db_pgno_t i, pgno_last; + size_t n; + int dirty, ret; + + dbenv = dbp->dbenv; + + /* Determine the last page of the file. */ + if ((ret = __db_lastpgno(dbp, real_name, fhp, &pgno_last)) != 0) + return (ret); + + /* Allocate memory for a single page. */ + if ((ret = __os_malloc(dbenv, dbp->pgsize, NULL, &page)) != 0) + return (ret); + + /* Walk the file, calling the underlying conversion functions. */ + for (i = 0; i < pgno_last; ++i) { + if (dbp->db_feedback != NULL) + dbp->db_feedback(dbp, DB_UPGRADE, (i * 100)/pgno_last); + if ((ret = __os_seek(dbenv, + fhp, dbp->pgsize, i, 0, 0, DB_OS_SEEK_SET)) != 0) + break; + if ((ret = __os_read(dbenv, fhp, page, dbp->pgsize, &n)) != 0) + break; + dirty = 0; + if (fl[TYPE(page)] != NULL && (ret = fl[TYPE(page)] + (dbp, real_name, flags, fhp, page, &dirty)) != 0) + break; + if (dirty) { + if ((ret = __os_seek(dbenv, + fhp, dbp->pgsize, i, 0, 0, DB_OS_SEEK_SET)) != 0) + break; + if ((ret = __os_write(dbenv, + fhp, page, dbp->pgsize, &n)) != 0) + break; + } + } + + __os_free(page, dbp->pgsize); + return (ret); +} + +/* + * __db_lastpgno -- + * Return the current last page number of the file. + * + * PUBLIC: int __db_lastpgno __P((DB *, char *, DB_FH *, db_pgno_t *)); + */ +int +__db_lastpgno(dbp, real_name, fhp, pgno_lastp) + DB *dbp; + char *real_name; + DB_FH *fhp; + db_pgno_t *pgno_lastp; +{ + DB_ENV *dbenv; + db_pgno_t pgno_last; + u_int32_t mbytes, bytes; + int ret; + + dbenv = dbp->dbenv; + + if ((ret = __os_ioinfo(dbenv, + real_name, fhp, &mbytes, &bytes, NULL)) != 0) { + __db_err(dbenv, "%s: %s", real_name, db_strerror(ret)); + return (ret); + } + + /* Page sizes have to be a power-of-two. */ + if (bytes % dbp->pgsize != 0) { + __db_err(dbenv, + "%s: file size not a multiple of the pagesize", real_name); + return (EINVAL); + } + pgno_last = mbytes * (MEGABYTE / dbp->pgsize); + pgno_last += bytes / dbp->pgsize; + + *pgno_lastp = pgno_last; + return (0); +} diff --git a/db/db/db_upg_opd.c b/db/db/db_upg_opd.c new file mode 100644 index 000000000..a7be784af --- /dev/null +++ b/db/db/db_upg_opd.c @@ -0,0 +1,353 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: db_upg_opd.c,v 11.9 2000/11/30 00:58:33 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_swap.h" +#include "btree.h" +#include "hash.h" +#include "qam.h" + +static int __db_build_bi __P((DB *, DB_FH *, PAGE *, PAGE *, u_int32_t, int *)); +static int __db_build_ri __P((DB *, DB_FH *, PAGE *, PAGE *, u_int32_t, int *)); +static int __db_up_ovref __P((DB *, DB_FH *, db_pgno_t)); + +#define GET_PAGE(dbp, fhp, pgno, page) { \ + if ((ret = __os_seek(dbp->dbenv, \ + fhp, (dbp)->pgsize, pgno, 0, 0, DB_OS_SEEK_SET)) != 0) \ + goto err; \ + if ((ret = __os_read(dbp->dbenv, \ + fhp, page, (dbp)->pgsize, &n)) != 0) \ + goto err; \ +} +#define PUT_PAGE(dbp, fhp, pgno, page) { \ + if ((ret = __os_seek(dbp->dbenv, \ + fhp, (dbp)->pgsize, pgno, 0, 0, DB_OS_SEEK_SET)) != 0) \ + goto err; \ + if ((ret = __os_write(dbp->dbenv, \ + fhp, page, (dbp)->pgsize, &n)) != 0) \ + goto err; \ +} + +/* + * __db_31_offdup -- + * Convert 3.0 off-page duplicates to 3.1 off-page duplicates. + * + * PUBLIC: int __db_31_offdup __P((DB *, char *, DB_FH *, int, db_pgno_t *)); + */ +int +__db_31_offdup(dbp, real_name, fhp, sorted, pgnop) + DB *dbp; + char *real_name; + DB_FH *fhp; + int sorted; + db_pgno_t *pgnop; +{ + PAGE *ipage, *page; + db_indx_t indx; + db_pgno_t cur_cnt, i, next_cnt, pgno, *pgno_cur, pgno_last; + db_pgno_t *pgno_next, pgno_max, *tmp; + db_recno_t nrecs; + size_t n; + int level, nomem, ret; + + ipage = page = NULL; + pgno_cur = pgno_next = NULL; + + /* Allocate room to hold a page. */ + if ((ret = __os_malloc(dbp->dbenv, dbp->pgsize, NULL, &page)) != 0) + goto err; + + /* + * Walk the chain of 3.0 off-page duplicates. Each one is converted + * in place to a 3.1 off-page duplicate page. If the duplicates are + * sorted, they are converted to a Btree leaf page, otherwise to a + * Recno leaf page. + */ + for (nrecs = 0, cur_cnt = pgno_max = 0, + pgno = *pgnop; pgno != PGNO_INVALID;) { + if (pgno_max == cur_cnt) { + pgno_max += 20; + if ((ret = __os_realloc(dbp->dbenv, pgno_max * + sizeof(db_pgno_t), NULL, &pgno_cur)) != 0) + goto err; + } + pgno_cur[cur_cnt++] = pgno; + + GET_PAGE(dbp, fhp, pgno, page); + nrecs += NUM_ENT(page); + LEVEL(page) = LEAFLEVEL; + TYPE(page) = sorted ? P_LDUP : P_LRECNO; + /* + * !!! + * DB didn't zero the LSNs on off-page duplicates pages. + */ + ZERO_LSN(LSN(page)); + PUT_PAGE(dbp, fhp, pgno, page); + + pgno = NEXT_PGNO(page); + } + + /* If we only have a single page, it's easy. */ + if (cur_cnt > 1) { + /* + * pgno_cur is the list of pages we just converted. We're + * going to walk that list, but we'll need to create a new + * list while we do so. + */ + if ((ret = __os_malloc(dbp->dbenv, + cur_cnt * sizeof(db_pgno_t), NULL, &pgno_next)) != 0) + goto err; + + /* Figure out where we can start allocating new pages. */ + if ((ret = __db_lastpgno(dbp, real_name, fhp, &pgno_last)) != 0) + goto err; + + /* Allocate room for an internal page. */ + if ((ret = __os_malloc(dbp->dbenv, + dbp->pgsize, NULL, &ipage)) != 0) + goto err; + PGNO(ipage) = PGNO_INVALID; + } + + /* + * Repeatedly walk the list of pages, building internal pages, until + * there's only one page at a level. + */ + for (level = LEAFLEVEL + 1; cur_cnt > 1; ++level) { + for (indx = 0, i = next_cnt = 0; i < cur_cnt;) { + if (indx == 0) { + P_INIT(ipage, dbp->pgsize, pgno_last, + PGNO_INVALID, PGNO_INVALID, + level, sorted ? P_IBTREE : P_IRECNO); + ZERO_LSN(LSN(ipage)); + + pgno_next[next_cnt++] = pgno_last++; + } + + GET_PAGE(dbp, fhp, pgno_cur[i], page); + + /* + * If the duplicates are sorted, put the first item on + * the lower-level page onto a Btree internal page. If + * the duplicates are not sorted, create an internal + * Recno structure on the page. If either case doesn't + * fit, push out the current page and start a new one. + */ + nomem = 0; + if (sorted) { + if ((ret = __db_build_bi( + dbp, fhp, ipage, page, indx, &nomem)) != 0) + goto err; + } else + if ((ret = __db_build_ri( + dbp, fhp, ipage, page, indx, &nomem)) != 0) + goto err; + if (nomem) { + indx = 0; + PUT_PAGE(dbp, fhp, PGNO(ipage), ipage); + } else { + ++indx; + ++NUM_ENT(ipage); + ++i; + } + } + + /* + * Push out the last internal page. Set the top-level record + * count if we've reached the top. + */ + if (next_cnt == 1) + RE_NREC_SET(ipage, nrecs); + PUT_PAGE(dbp, fhp, PGNO(ipage), ipage); + + /* Swap the current and next page number arrays. */ + cur_cnt = next_cnt; + tmp = pgno_cur; + pgno_cur = pgno_next; + pgno_next = tmp; + } + + *pgnop = pgno_cur[0]; + +err: if (pgno_cur != NULL) + __os_free(pgno_cur, 0); + if (pgno_next != NULL) + __os_free(pgno_next, 0); + if (ipage != NULL) + __os_free(ipage, dbp->pgsize); + if (page != NULL) + __os_free(page, dbp->pgsize); + + return (ret); +} + +/* + * __db_build_bi -- + * Build a BINTERNAL entry for a parent page. + */ +static int +__db_build_bi(dbp, fhp, ipage, page, indx, nomemp) + DB *dbp; + DB_FH *fhp; + PAGE *ipage, *page; + u_int32_t indx; + int *nomemp; +{ + BINTERNAL bi, *child_bi; + BKEYDATA *child_bk; + u_int8_t *p; + int ret; + + switch (TYPE(page)) { + case P_IBTREE: + child_bi = GET_BINTERNAL(page, 0); + if (P_FREESPACE(ipage) < BINTERNAL_PSIZE(child_bi->len)) { + *nomemp = 1; + return (0); + } + ipage->inp[indx] = + HOFFSET(ipage) -= BINTERNAL_SIZE(child_bi->len); + p = P_ENTRY(ipage, indx); + + bi.len = child_bi->len; + B_TSET(bi.type, child_bi->type, 0); + bi.pgno = PGNO(page); + bi.nrecs = __bam_total(page); + memcpy(p, &bi, SSZA(BINTERNAL, data)); + p += SSZA(BINTERNAL, data); + memcpy(p, child_bi->data, child_bi->len); + + /* Increment the overflow ref count. */ + if (B_TYPE(child_bi->type) == B_OVERFLOW) + if ((ret = __db_up_ovref(dbp, fhp, + ((BOVERFLOW *)(child_bi->data))->pgno)) != 0) + return (ret); + break; + case P_LDUP: + child_bk = GET_BKEYDATA(page, 0); + switch (B_TYPE(child_bk->type)) { + case B_KEYDATA: + if (P_FREESPACE(ipage) < + BINTERNAL_PSIZE(child_bk->len)) { + *nomemp = 1; + return (0); + } + ipage->inp[indx] = + HOFFSET(ipage) -= BINTERNAL_SIZE(child_bk->len); + p = P_ENTRY(ipage, indx); + + bi.len = child_bk->len; + B_TSET(bi.type, child_bk->type, 0); + bi.pgno = PGNO(page); + bi.nrecs = __bam_total(page); + memcpy(p, &bi, SSZA(BINTERNAL, data)); + p += SSZA(BINTERNAL, data); + memcpy(p, child_bk->data, child_bk->len); + break; + case B_OVERFLOW: + if (P_FREESPACE(ipage) < + BINTERNAL_PSIZE(BOVERFLOW_SIZE)) { + *nomemp = 1; + return (0); + } + ipage->inp[indx] = + HOFFSET(ipage) -= BINTERNAL_SIZE(BOVERFLOW_SIZE); + p = P_ENTRY(ipage, indx); + + bi.len = BOVERFLOW_SIZE; + B_TSET(bi.type, child_bk->type, 0); + bi.pgno = PGNO(page); + bi.nrecs = __bam_total(page); + memcpy(p, &bi, SSZA(BINTERNAL, data)); + p += SSZA(BINTERNAL, data); + memcpy(p, child_bk, BOVERFLOW_SIZE); + + /* Increment the overflow ref count. */ + if ((ret = __db_up_ovref(dbp, fhp, + ((BOVERFLOW *)child_bk)->pgno)) != 0) + return (ret); + break; + default: + return (__db_pgfmt(dbp, PGNO(page))); + } + break; + default: + return (__db_pgfmt(dbp, PGNO(page))); + } + + return (0); +} + +/* + * __db_build_ri -- + * Build a RINTERNAL entry for an internal parent page. + */ +static int +__db_build_ri(dbp, fhp, ipage, page, indx, nomemp) + DB *dbp; + DB_FH *fhp; + PAGE *ipage, *page; + u_int32_t indx; + int *nomemp; +{ + RINTERNAL ri; + + COMPQUIET(dbp, NULL); + COMPQUIET(fhp, NULL); + + if (P_FREESPACE(ipage) < RINTERNAL_PSIZE) { + *nomemp = 1; + return (0); + } + + ri.pgno = PGNO(page); + ri.nrecs = __bam_total(page); + ipage->inp[indx] = HOFFSET(ipage) -= RINTERNAL_SIZE; + memcpy(P_ENTRY(ipage, indx), &ri, RINTERNAL_SIZE); + + return (0); +} + +/* + * __db_up_ovref -- + * Increment/decrement the reference count on an overflow page. + */ +static int +__db_up_ovref(dbp, fhp, pgno) + DB *dbp; + DB_FH *fhp; + db_pgno_t pgno; +{ + PAGE *page; + size_t n; + int ret; + + /* Allocate room to hold a page. */ + if ((ret = __os_malloc(dbp->dbenv, dbp->pgsize, NULL, &page)) != 0) + return (ret); + + GET_PAGE(dbp, fhp, pgno, page); + ++OV_REF(page); + PUT_PAGE(dbp, fhp, pgno, page); + +err: __os_free(page, dbp->pgsize); + + return (ret); +} diff --git a/db/db/db_vrfy.c b/db/db/db_vrfy.c new file mode 100644 index 000000000..3509e05e9 --- /dev/null +++ b/db/db/db_vrfy.c @@ -0,0 +1,2340 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: db_vrfy.c,v 1.53 2001/01/11 18:19:51 bostic Exp $ + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: db_vrfy.c,v 1.53 2001/01/11 18:19:51 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_swap.h" +#include "db_verify.h" +#include "db_ext.h" +#include "btree.h" +#include "hash.h" +#include "qam.h" + +static int __db_guesspgsize __P((DB_ENV *, DB_FH *)); +static int __db_is_valid_magicno __P((u_int32_t, DBTYPE *)); +static int __db_is_valid_pagetype __P((u_int32_t)); +static int __db_meta2pgset + __P((DB *, VRFY_DBINFO *, db_pgno_t, u_int32_t, DB *)); +static int __db_salvage_subdbs + __P((DB *, VRFY_DBINFO *, void *, + int(*)(void *, const void *), u_int32_t, int *)); +static int __db_salvage_unknowns + __P((DB *, VRFY_DBINFO *, void *, + int (*)(void *, const void *), u_int32_t)); +static int __db_vrfy_common + __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, u_int32_t)); +static int __db_vrfy_freelist __P((DB *, VRFY_DBINFO *, db_pgno_t, u_int32_t)); +static int __db_vrfy_invalid + __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, u_int32_t)); +static int __db_vrfy_orderchkonly __P((DB *, + VRFY_DBINFO *, const char *, const char *, u_int32_t)); +static int __db_vrfy_pagezero __P((DB *, VRFY_DBINFO *, DB_FH *, u_int32_t)); +static int __db_vrfy_subdbs + __P((DB *, VRFY_DBINFO *, const char *, u_int32_t)); +static int __db_vrfy_structure + __P((DB *, VRFY_DBINFO *, const char *, db_pgno_t, u_int32_t)); +static int __db_vrfy_walkpages + __P((DB *, VRFY_DBINFO *, void *, int (*)(void *, const void *), + u_int32_t)); + +/* + * This is the code for DB->verify, the DB database consistency checker. + * For now, it checks all subdatabases in a database, and verifies + * everything it knows how to (i.e. it's all-or-nothing, and one can't + * check only for a subset of possible problems). + */ + +/* + * __db_verify -- + * Walk the entire file page-by-page, either verifying with or without + * dumping in db_dump -d format, or DB_SALVAGE-ing whatever key/data + * pairs can be found and dumping them in standard (db_load-ready) + * dump format. + * + * (Salvaging isn't really a verification operation, but we put it + * here anyway because it requires essentially identical top-level + * code.) + * + * flags may be 0, DB_NOORDERCHK, DB_ORDERCHKONLY, or DB_SALVAGE + * (and optionally DB_AGGRESSIVE). + * + * __db_verify itself is simply a wrapper to __db_verify_internal, + * which lets us pass appropriate equivalents to FILE * in from the + * non-C APIs. + * + * PUBLIC: int __db_verify + * PUBLIC: __P((DB *, const char *, const char *, FILE *, u_int32_t)); + */ +int +__db_verify(dbp, file, database, outfile, flags) + DB *dbp; + const char *file, *database; + FILE *outfile; + u_int32_t flags; +{ + + return (__db_verify_internal(dbp, + file, database, outfile, __db_verify_callback, flags)); +} + +/* + * __db_verify_callback -- + * Callback function for using pr_* functions from C. + * + * PUBLIC: int __db_verify_callback __P((void *, const void *)); + */ +int +__db_verify_callback(handle, str_arg) + void *handle; + const void *str_arg; +{ + char *str; + FILE *f; + + str = (char *)str_arg; + f = (FILE *)handle; + + if (fprintf(f, "%s", str) != (int)strlen(str)) + return (EIO); + + return (0); +} + +/* + * __db_verify_internal -- + * Inner meat of __db_verify. + * + * PUBLIC: int __db_verify_internal __P((DB *, const char *, + * PUBLIC: const char *, void *, int (*)(void *, const void *), u_int32_t)); + */ +int +__db_verify_internal(dbp_orig, name, subdb, handle, callback, flags) + DB *dbp_orig; + const char *name, *subdb; + void *handle; + int (*callback) __P((void *, const void *)); + u_int32_t flags; +{ + DB *dbp; + DB_ENV *dbenv; + DB_FH fh, *fhp; + PAGE *h; + VRFY_DBINFO *vdp; + db_pgno_t last; + int has, ret, isbad; + char *real_name; + + dbenv = dbp_orig->dbenv; + vdp = NULL; + real_name = NULL; + ret = isbad = 0; + + memset(&fh, 0, sizeof(fh)); + fhp = &fh; + + PANIC_CHECK(dbenv); + DB_ILLEGAL_AFTER_OPEN(dbp_orig, "verify"); + +#define OKFLAGS (DB_AGGRESSIVE | DB_NOORDERCHK | DB_ORDERCHKONLY | DB_SALVAGE) + if ((ret = __db_fchk(dbenv, "DB->verify", flags, OKFLAGS)) != 0) + return (ret); + + /* + * DB_SALVAGE is mutually exclusive with the other flags except + * DB_AGGRESSIVE. + */ + if (LF_ISSET(DB_SALVAGE) && + (flags & ~DB_AGGRESSIVE) != DB_SALVAGE) + return (__db_ferr(dbenv, "__db_verify", 1)); + + if (LF_ISSET(DB_ORDERCHKONLY) && flags != DB_ORDERCHKONLY) + return (__db_ferr(dbenv, "__db_verify", 1)); + + if (LF_ISSET(DB_ORDERCHKONLY) && subdb == NULL) { + __db_err(dbenv, "DB_ORDERCHKONLY requires a database name"); + return (EINVAL); + } + + /* + * Forbid working in an environment that uses transactions or + * locking; we're going to be looking at the file freely, + * and while we're not going to modify it, we aren't obeying + * locking conventions either. + */ + if (TXN_ON(dbenv) || LOCKING_ON(dbenv) || LOGGING_ON(dbenv)) { + dbp_orig->errx(dbp_orig, + "verify may not be used with transactions, logging, or locking"); + return (EINVAL); + /* NOTREACHED */ + } + + /* Create a dbp to use internally, which we can close at our leisure. */ + if ((ret = db_create(&dbp, dbenv, 0)) != 0) + goto err; + + F_SET(dbp, DB_AM_VERIFYING); + + /* Copy the supplied pagesize, which we use if the file one is bogus. */ + if (dbp_orig->pgsize >= DB_MIN_PGSIZE && + dbp_orig->pgsize <= DB_MAX_PGSIZE) + dbp->set_pagesize(dbp, dbp_orig->pgsize); + + /* Copy the feedback function, if present, and initialize it. */ + if (!LF_ISSET(DB_SALVAGE) && dbp_orig->db_feedback != NULL) { + dbp->set_feedback(dbp, dbp_orig->db_feedback); + dbp->db_feedback(dbp, DB_VERIFY, 0); + } + + /* + * Copy the comparison and hashing functions. Note that + * even if the database is not a hash or btree, the respective + * internal structures will have been initialized. + */ + if (dbp_orig->dup_compare != NULL && + (ret = dbp->set_dup_compare(dbp, dbp_orig->dup_compare)) != 0) + goto err; + if (((BTREE *)dbp_orig->bt_internal)->bt_compare != NULL && + (ret = dbp->set_bt_compare(dbp, + ((BTREE *)dbp_orig->bt_internal)->bt_compare)) != 0) + goto err; + if (((HASH *)dbp_orig->h_internal)->h_hash != NULL && + (ret = dbp->set_h_hash(dbp, + ((HASH *)dbp_orig->h_internal)->h_hash)) != 0) + goto err; + + /* + * We don't know how large the cache is, and if the database + * in question uses a small page size--which we don't know + * yet!--it may be uncomfortably small for the default page + * size [#2143]. However, the things we need temporary + * databases for in dbinfo are largely tiny, so using a + * 1024-byte pagesize is probably not going to be a big hit, + * and will make us fit better into small spaces. + */ + if ((ret = __db_vrfy_dbinfo_create(dbenv, 1024, &vdp)) != 0) + goto err; + + /* Find the real name of the file. */ + if ((ret = __db_appname(dbenv, + DB_APP_DATA, NULL, name, 0, NULL, &real_name)) != 0) + goto err; + + /* + * Our first order of business is to verify page 0, which is + * the metadata page for the master database of subdatabases + * or of the only database in the file. We want to do this by hand + * rather than just calling __db_open in case it's corrupt--various + * things in __db_open might act funny. + * + * Once we know the metadata page is healthy, I believe that it's + * safe to open the database normally and then use the page swapping + * code, which makes life easier. + */ + if ((ret = __os_open(dbenv, real_name, DB_OSO_RDONLY, 0444, fhp)) != 0) + goto err; + + /* Verify the metadata page 0; set pagesize and type. */ + if ((ret = __db_vrfy_pagezero(dbp, vdp, fhp, flags)) != 0) { + if (ret == DB_VERIFY_BAD) + isbad = 1; + else + goto err; + } + + /* + * We can assume at this point that dbp->pagesize and dbp->type are + * set correctly, or at least as well as they can be, and that + * locking, logging, and txns are not in use. Thus we can trust + * the memp code not to look at the page, and thus to be safe + * enough to use. + * + * The dbp is not open, but the file is open in the fhp, and we + * cannot assume that __db_open is safe. Call __db_dbenv_setup, + * the [safe] part of __db_open that initializes the environment-- + * and the mpool--manually. + */ + if ((ret = __db_dbenv_setup(dbp, + name, DB_ODDFILESIZE | DB_RDONLY)) != 0) + return (ret); + + /* Mark the dbp as opened, so that we correctly handle its close. */ + F_SET(dbp, DB_OPEN_CALLED); + + /* + * Find out the page number of the last page in the database. + * + * XXX: This currently fails if the last page is of bad type, + * because it calls __db_pgin and that pukes. This is bad. + */ + if ((ret = memp_fget(dbp->mpf, &last, DB_MPOOL_LAST, &h)) != 0) + goto err; + if ((ret = memp_fput(dbp->mpf, h, 0)) != 0) + goto err; + + vdp->last_pgno = last; + + /* + * DB_ORDERCHKONLY is a special case; our file consists of + * several subdatabases, which use different hash, bt_compare, + * and/or dup_compare functions. Consequently, we couldn't verify + * sorting and hashing simply by calling DB->verify() on the file. + * DB_ORDERCHKONLY allows us to come back and check those things; it + * requires a subdatabase, and assumes that everything but that + * database's sorting/hashing is correct. + */ + if (LF_ISSET(DB_ORDERCHKONLY)) { + ret = __db_vrfy_orderchkonly(dbp, vdp, name, subdb, flags); + goto done; + } + + /* + * When salvaging, we use a db to keep track of whether we've seen a + * given overflow or dup page in the course of traversing normal data. + * If in the end we have not, we assume its key got lost and print it + * with key "UNKNOWN". + */ + if (LF_ISSET(DB_SALVAGE)) { + if ((ret = __db_salvage_init(vdp)) != 0) + return (ret); + + /* + * If we're not being aggressive, attempt to crack subdbs. + * "has" will indicate whether the attempt has succeeded + * (even in part), meaning that we have some semblance of + * subdbs; on the walkpages pass, we print out + * whichever data pages we have not seen. + */ + has = 0; + if (!LF_ISSET(DB_AGGRESSIVE) && (__db_salvage_subdbs(dbp, + vdp, handle, callback, flags, &has)) != 0) + isbad = 1; + + /* + * If we have subdatabases, we need to signal that if + * any keys are found that don't belong to a subdatabase, + * they'll need to have an "__OTHER__" subdatabase header + * printed first. Flag this. Else, print a header for + * the normal, non-subdb database. + */ + if (has == 1) + F_SET(vdp, SALVAGE_PRINTHEADER); + else if ((ret = __db_prheader(dbp, + NULL, 0, 0, handle, callback, vdp, PGNO_BASE_MD)) != 0) + goto err; + } + + if ((ret = + __db_vrfy_walkpages(dbp, vdp, handle, callback, flags)) != 0) { + if (ret == DB_VERIFY_BAD) + isbad = 1; + else if (ret != 0) + goto err; + } + + /* If we're verifying, verify inter-page structure. */ + if (!LF_ISSET(DB_SALVAGE) && isbad == 0) + if ((ret = + __db_vrfy_structure(dbp, vdp, name, 0, flags)) != 0) { + if (ret == DB_VERIFY_BAD) + isbad = 1; + else if (ret != 0) + goto err; + } + + /* + * If we're salvaging, output with key UNKNOWN any overflow or dup pages + * we haven't been able to put in context. Then destroy the salvager's + * state-saving database. + */ + if (LF_ISSET(DB_SALVAGE)) { + if ((ret = __db_salvage_unknowns(dbp, + vdp, handle, callback, flags)) != 0) + isbad = 1; + /* No return value, since there's little we can do. */ + __db_salvage_destroy(vdp); + } + + if (0) { +err: (void)__db_err(dbenv, "%s: %s", name, db_strerror(ret)); + } + + if (LF_ISSET(DB_SALVAGE) && + (has == 0 || F_ISSET(vdp, SALVAGE_PRINTFOOTER))) + (void)__db_prfooter(handle, callback); + + /* Send feedback that we're done. */ +done: if (!LF_ISSET(DB_SALVAGE) && dbp->db_feedback != NULL) + dbp->db_feedback(dbp, DB_VERIFY, 100); + + if (F_ISSET(fhp, DB_FH_VALID)) + (void)__os_closehandle(fhp); + if (dbp) + (void)dbp->close(dbp, 0); + if (vdp) + (void)__db_vrfy_dbinfo_destroy(vdp); + if (real_name) + __os_freestr(real_name); + + if ((ret == 0 && isbad == 1) || ret == DB_VERIFY_FATAL) + ret = DB_VERIFY_BAD; + + return (ret); +} + +/* + * __db_vrfy_pagezero -- + * Verify the master metadata page. Use seek, read, and a local buffer + * rather than the DB paging code, for safety. + * + * Must correctly (or best-guess) set dbp->type and dbp->pagesize. + */ +static int +__db_vrfy_pagezero(dbp, vdp, fhp, flags) + DB *dbp; + VRFY_DBINFO *vdp; + DB_FH *fhp; + u_int32_t flags; +{ + DBMETA *meta; + DB_ENV *dbenv; + VRFY_PAGEINFO *pip; + db_pgno_t freelist; + int t_ret, ret, nr, swapped; + u_int8_t mbuf[DBMETASIZE]; + + swapped = ret = t_ret = 0; + freelist = 0; + dbenv = dbp->dbenv; + meta = (DBMETA *)mbuf; + dbp->type = DB_UNKNOWN; + + /* + * Seek to the metadata page. + * Note that if we're just starting a verification, dbp->pgsize + * may be zero; this is okay, as we want page zero anyway and + * 0*0 == 0. + */ + if ((ret = __os_seek(dbenv, fhp, 0, 0, 0, 0, DB_OS_SEEK_SET)) != 0) + goto err; + + if ((ret = __os_read(dbenv, fhp, mbuf, DBMETASIZE, (size_t *)&nr)) != 0) + goto err; + + if (nr != DBMETASIZE) { + EPRINT((dbp->dbenv, + "Incomplete metadata page %lu", (u_long)PGNO_BASE_MD)); + t_ret = DB_VERIFY_FATAL; + goto err; + } + + /* + * Check all of the fields that we can. + */ + + /* 08-11: Current page number. Must == pgno. */ + /* Note that endianness doesn't matter--it's zero. */ + if (meta->pgno != PGNO_BASE_MD) { + EPRINT((dbp->dbenv, "Bad pgno: was %lu, should be %lu", + (u_long)meta->pgno, (u_long)PGNO_BASE_MD)); + ret = DB_VERIFY_BAD; + } + + /* 12-15: Magic number. Must be one of valid set. */ + if (__db_is_valid_magicno(meta->magic, &dbp->type)) + swapped = 0; + else { + M_32_SWAP(meta->magic); + if (__db_is_valid_magicno(meta->magic, + &dbp->type)) + swapped = 1; + else { + EPRINT((dbp->dbenv, + "Bad magic number: %lu", (u_long)meta->magic)); + ret = DB_VERIFY_BAD; + } + } + + /* + * 16-19: Version. Must be current; for now, we + * don't support verification of old versions. + */ + if (swapped) + M_32_SWAP(meta->version); + if ((dbp->type == DB_BTREE && meta->version != DB_BTREEVERSION) || + (dbp->type == DB_HASH && meta->version != DB_HASHVERSION) || + (dbp->type == DB_QUEUE && meta->version != DB_QAMVERSION)) { + ret = DB_VERIFY_BAD; + EPRINT((dbp->dbenv, "%s%s", "Old or incorrect DB ", + "version; extraneous errors may result")); + } + + /* + * 20-23: Pagesize. Must be power of two, + * greater than 512, and less than 64K. + */ + if (swapped) + M_32_SWAP(meta->pagesize); + if (IS_VALID_PAGESIZE(meta->pagesize)) + dbp->pgsize = meta->pagesize; + else { + EPRINT((dbp->dbenv, + "Bad page size: %lu", (u_long)meta->pagesize)); + ret = DB_VERIFY_BAD; + + /* + * Now try to settle on a pagesize to use. + * If the user-supplied one is reasonable, + * use it; else, guess. + */ + if (!IS_VALID_PAGESIZE(dbp->pgsize)) + dbp->pgsize = __db_guesspgsize(dbenv, fhp); + } + + /* + * 25: Page type. Must be correct for dbp->type, + * which is by now set as well as it can be. + */ + /* Needs no swapping--only one byte! */ + if ((dbp->type == DB_BTREE && meta->type != P_BTREEMETA) || + (dbp->type == DB_HASH && meta->type != P_HASHMETA) || + (dbp->type == DB_QUEUE && meta->type != P_QAMMETA)) { + ret = DB_VERIFY_BAD; + EPRINT((dbp->dbenv, "Bad page type: %lu", (u_long)meta->type)); + } + + /* + * 28-31: Free list page number. + * We'll verify its sensibility when we do inter-page + * verification later; for now, just store it. + */ + if (swapped) + M_32_SWAP(meta->free); + freelist = meta->free; + + /* + * Initialize vdp->pages to fit a single pageinfo structure for + * this one page. We'll realloc later when we know how many + * pages there are. + */ + if ((ret = __db_vrfy_getpageinfo(vdp, PGNO_BASE_MD, &pip)) != 0) + return (ret); + pip->pgno = PGNO_BASE_MD; + pip->type = meta->type; + + /* + * Signal that we still have to check the info specific to + * a given type of meta page. + */ + F_SET(pip, VRFY_INCOMPLETE); + + pip->free = freelist; + + if ((ret = __db_vrfy_putpageinfo(vdp, pip)) != 0) + return (ret); + + /* Set up the dbp's fileid. We don't use the regular open path. */ + memcpy(dbp->fileid, meta->uid, DB_FILE_ID_LEN); + + if (0) { +err: __db_err(dbenv, "%s", db_strerror(ret)); + } + + if (swapped == 1) + F_SET(dbp, DB_AM_SWAP); + if (t_ret != 0) + ret = t_ret; + return (ret); +} + +/* + * __db_vrfy_walkpages -- + * Main loop of the verifier/salvager. Walks through, + * page by page, and verifies all pages and/or prints all data pages. + */ +static int +__db_vrfy_walkpages(dbp, vdp, handle, callback, flags) + DB *dbp; + VRFY_DBINFO *vdp; + void *handle; + int (*callback) __P((void *, const void *)); + u_int32_t flags; +{ + DB_ENV *dbenv; + PAGE *h; + db_pgno_t i; + int ret, t_ret, isbad; + + ret = isbad = t_ret = 0; + dbenv = dbp->dbenv; + + if ((ret = __db_fchk(dbenv, + "__db_vrfy_walkpages", flags, OKFLAGS)) != 0) + return (ret); + + for (i = 0; i <= vdp->last_pgno; i++) { + /* + * If DB_SALVAGE is set, we inspect our database of + * completed pages, and skip any we've already printed in + * the subdb pass. + */ + if (LF_ISSET(DB_SALVAGE) && (__db_salvage_isdone(vdp, i) != 0)) + continue; + + /* If an individual page get fails, keep going. */ + if ((t_ret = memp_fget(dbp->mpf, &i, 0, &h)) != 0) { + if (ret == 0) + ret = t_ret; + continue; + } + + if (LF_ISSET(DB_SALVAGE)) { + /* + * We pretty much don't want to quit unless a + * bomb hits. May as well return that something + * was screwy, however. + */ + if ((t_ret = __db_salvage(dbp, + vdp, i, h, handle, callback, flags)) != 0) { + if (ret == 0) + ret = t_ret; + isbad = 1; + } + } else { + /* + * Verify info common to all page + * types. + */ + if (i != PGNO_BASE_MD) + if ((t_ret = __db_vrfy_common(dbp, + vdp, h, i, flags)) == DB_VERIFY_BAD) + isbad = 1; + + switch (TYPE(h)) { + case P_INVALID: + t_ret = __db_vrfy_invalid(dbp, + vdp, h, i, flags); + break; + case __P_DUPLICATE: + isbad = 1; + EPRINT((dbp->dbenv, + "Old-style duplicate page: %lu", + (u_long)i)); + break; + case P_HASH: + t_ret = __ham_vrfy(dbp, + vdp, h, i, flags); + break; + case P_IBTREE: + case P_IRECNO: + case P_LBTREE: + case P_LDUP: + t_ret = __bam_vrfy(dbp, + vdp, h, i, flags); + break; + case P_LRECNO: + t_ret = __ram_vrfy_leaf(dbp, + vdp, h, i, flags); + break; + case P_OVERFLOW: + t_ret = __db_vrfy_overflow(dbp, + vdp, h, i, flags); + break; + case P_HASHMETA: + t_ret = __ham_vrfy_meta(dbp, + vdp, (HMETA *)h, i, flags); + break; + case P_BTREEMETA: + t_ret = __bam_vrfy_meta(dbp, + vdp, (BTMETA *)h, i, flags); + break; + case P_QAMMETA: + t_ret = __qam_vrfy_meta(dbp, + vdp, (QMETA *)h, i, flags); + break; + case P_QAMDATA: + t_ret = __qam_vrfy_data(dbp, + vdp, (QPAGE *)h, i, flags); + break; + default: + EPRINT((dbp->dbenv, + "Unknown page type: %lu", (u_long)TYPE(h))); + isbad = 1; + break; + } + + /* + * Set up error return. + */ + if (t_ret == DB_VERIFY_BAD) + isbad = 1; + else if (t_ret == DB_VERIFY_FATAL) + goto err; + else + ret = t_ret; + + /* + * Provide feedback to the application about our + * progress. The range 0-50% comes from the fact + * that this is the first of two passes through the + * database (front-to-back, then top-to-bottom). + */ + if (dbp->db_feedback != NULL) + dbp->db_feedback(dbp, DB_VERIFY, + (i + 1) * 50 / (vdp->last_pgno + 1)); + } + + if ((t_ret = memp_fput(dbp->mpf, h, 0)) != 0 && ret == 0) + ret = t_ret; + } + + if (0) { +err: if ((t_ret = memp_fput(dbp->mpf, h, 0)) != 0) + return (ret == 0 ? t_ret : ret); + return (DB_VERIFY_BAD); + } + + return ((isbad == 1 && ret == 0) ? DB_VERIFY_BAD : ret); +} + +/* + * __db_vrfy_structure-- + * After a beginning-to-end walk through the database has been + * completed, put together the information that has been collected + * to verify the overall database structure. + * + * Should only be called if we want to do a database verification, + * i.e. if DB_SALVAGE is not set. + */ +static int +__db_vrfy_structure(dbp, vdp, dbname, meta_pgno, flags) + DB *dbp; + VRFY_DBINFO *vdp; + const char *dbname; + db_pgno_t meta_pgno; + u_int32_t flags; +{ + DB *pgset; + DB_ENV *dbenv; + VRFY_PAGEINFO *pip; + db_pgno_t i; + int ret, isbad, hassubs, p; + + isbad = 0; + pip = NULL; + dbenv = dbp->dbenv; + pgset = vdp->pgset; + + if ((ret = __db_fchk(dbenv, "DB->verify", flags, OKFLAGS)) != 0) + return (ret); + if (LF_ISSET(DB_SALVAGE)) { + __db_err(dbenv, "__db_vrfy_structure called with DB_SALVAGE"); + return (EINVAL); + } + + /* + * Providing feedback here is tricky; in most situations, + * we fetch each page one more time, but we do so in a top-down + * order that depends on the access method. Worse, we do this + * recursively in btree, such that on any call where we're traversing + * a subtree we don't know where that subtree is in the whole database; + * worse still, any given database may be one of several subdbs. + * + * The solution is to decrement a counter vdp->pgs_remaining each time + * we verify (and call feedback on) a page. We may over- or + * under-count, but the structure feedback function will ensure that we + * never give a percentage under 50 or over 100. (The first pass + * covered the range 0-50%.) + */ + if (dbp->db_feedback != NULL) + vdp->pgs_remaining = vdp->last_pgno + 1; + + /* + * Call the appropriate function to downwards-traverse the db type. + */ + switch(dbp->type) { + case DB_BTREE: + case DB_RECNO: + if ((ret = __bam_vrfy_structure(dbp, vdp, 0, flags)) != 0) { + if (ret == DB_VERIFY_BAD) + isbad = 1; + else + goto err; + } + + /* + * If we have subdatabases and we know that the database is, + * thus far, sound, it's safe to walk the tree of subdatabases. + * Do so, and verify the structure of the databases within. + */ + if ((ret = __db_vrfy_getpageinfo(vdp, 0, &pip)) != 0) + goto err; + hassubs = F_ISSET(pip, VRFY_HAS_SUBDBS); + if ((ret = __db_vrfy_putpageinfo(vdp, pip)) != 0) + goto err; + + if (isbad == 0 && hassubs) + if ((ret = + __db_vrfy_subdbs(dbp, vdp, dbname, flags)) != 0) { + if (ret == DB_VERIFY_BAD) + isbad = 1; + else + goto err; + } + break; + case DB_HASH: + if ((ret = __ham_vrfy_structure(dbp, vdp, 0, flags)) != 0) { + if (ret == DB_VERIFY_BAD) + isbad = 1; + else + goto err; + } + break; + case DB_QUEUE: + if ((ret = __qam_vrfy_structure(dbp, vdp, flags)) != 0) { + if (ret == DB_VERIFY_BAD) + isbad = 1; + } + + /* + * Queue pages may be unreferenced and totally zeroed, if + * they're empty; queue doesn't have much structure, so + * this is unlikely to be wrong in any troublesome sense. + * Skip to "err". + */ + goto err; + /* NOTREACHED */ + default: + /* This should only happen if the verifier is somehow broken. */ + DB_ASSERT(0); + ret = EINVAL; + goto err; + /* NOTREACHED */ + } + + /* Walk free list. */ + if ((ret = + __db_vrfy_freelist(dbp, vdp, meta_pgno, flags)) == DB_VERIFY_BAD) + isbad = 1; + + /* + * If structure checks up until now have failed, it's likely that + * checking what pages have been missed will result in oodles of + * extraneous error messages being EPRINTed. Skip to the end + * if this is the case; we're going to be printing at least one + * error anyway, and probably all the more salient ones. + */ + if (ret != 0 || isbad == 1) + goto err; + + /* + * Make sure no page has been missed and that no page is still marked + * "all zeroes" (only certain hash pages can be, and they're unmarked + * in __ham_vrfy_structure). + */ + for (i = 0; i < vdp->last_pgno + 1; i++) { + if ((ret = __db_vrfy_getpageinfo(vdp, i, &pip)) != 0) + goto err; + if ((ret = __db_vrfy_pgset_get(pgset, i, &p)) != 0) + goto err; + if (p == 0) { + EPRINT((dbp->dbenv, + "Unreferenced page %lu", (u_long)i)); + isbad = 1; + } + + if (F_ISSET(pip, VRFY_IS_ALLZEROES)) { + EPRINT((dbp->dbenv, + "Totally zeroed page %lu", (u_long)i)); + isbad = 1; + } + if ((ret = __db_vrfy_putpageinfo(vdp, pip)) != 0) + goto err; + pip = NULL; + } + +err: if (pip != NULL) + (void)__db_vrfy_putpageinfo(vdp, pip); + + return ((isbad == 1 && ret == 0) ? DB_VERIFY_BAD : ret); +} + +/* + * __db_is_valid_pagetype + */ +static int +__db_is_valid_pagetype(type) + u_int32_t type; +{ + switch (type) { + case P_INVALID: /* Order matches ordinal value. */ + case P_HASH: + case P_IBTREE: + case P_IRECNO: + case P_LBTREE: + case P_LRECNO: + case P_OVERFLOW: + case P_HASHMETA: + case P_BTREEMETA: + case P_QAMMETA: + case P_QAMDATA: + case P_LDUP: + return (1); + } + return (0); +} + +/* + * __db_is_valid_magicno + */ +static int +__db_is_valid_magicno(magic, typep) + u_int32_t magic; + DBTYPE *typep; +{ + switch (magic) { + case DB_BTREEMAGIC: + *typep = DB_BTREE; + return (1); + case DB_HASHMAGIC: + *typep = DB_HASH; + return (1); + case DB_QAMMAGIC: + *typep = DB_QUEUE; + return (1); + } + *typep = DB_UNKNOWN; + return (0); +} + +/* + * __db_vrfy_common -- + * Verify info common to all page types. + */ +static int +__db_vrfy_common(dbp, vdp, h, pgno, flags) + DB *dbp; + VRFY_DBINFO *vdp; + PAGE *h; + db_pgno_t pgno; + u_int32_t flags; +{ + VRFY_PAGEINFO *pip; + int ret, t_ret; + u_int8_t *p; + + if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) + return (ret); + + pip->pgno = pgno; + F_CLR(pip, VRFY_IS_ALLZEROES); + + /* + * Hash expands the table by leaving some pages between the + * old last and the new last totally zeroed. Its pgin function + * should fix things, but we might not be using that (e.g. if + * we're a subdatabase). + * + * Queue will create sparse files if sparse record numbers are used. + */ + if (pgno != 0 && PGNO(h) == 0) { + for (p = (u_int8_t *)h; p < (u_int8_t *)h + dbp->pgsize; p++) + if (*p != 0) { + EPRINT((dbp->dbenv, + "Page %lu should be zeroed and is not", + (u_long)pgno)); + ret = DB_VERIFY_BAD; + goto err; + } + /* + * It's totally zeroed; mark it as a hash, and we'll + * check that that makes sense structurally later. + * (The queue verification doesn't care, since queues + * don't really have much in the way of structure.) + */ + pip->type = P_HASH; + F_SET(pip, VRFY_IS_ALLZEROES); + ret = 0; + goto err; /* well, not really an err. */ + } + + if (PGNO(h) != pgno) { + EPRINT((dbp->dbenv, + "Bad page number: %lu should be %lu", + (u_long)h->pgno, (u_long)pgno)); + ret = DB_VERIFY_BAD; + } + + if (!__db_is_valid_pagetype(h->type)) { + EPRINT((dbp->dbenv, "Bad page type: %lu", (u_long)h->type)); + ret = DB_VERIFY_BAD; + } + pip->type = h->type; + +err: if ((t_ret = __db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0) + ret = t_ret; + + return (ret); +} + +/* + * __db_vrfy_invalid -- + * Verify P_INVALID page. + * (Yes, there's not much to do here.) + */ +static int +__db_vrfy_invalid(dbp, vdp, h, pgno, flags) + DB *dbp; + VRFY_DBINFO *vdp; + PAGE *h; + db_pgno_t pgno; + u_int32_t flags; +{ + VRFY_PAGEINFO *pip; + int ret, t_ret; + + if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) + return (ret); + pip->next_pgno = pip->prev_pgno = 0; + + if (!IS_VALID_PGNO(NEXT_PGNO(h))) { + EPRINT((dbp->dbenv, + "Invalid next_pgno %lu on page %lu", + (u_long)NEXT_PGNO(h), (u_long)pgno)); + ret = DB_VERIFY_BAD; + } else + pip->next_pgno = NEXT_PGNO(h); + + if ((t_ret = __db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0) + ret = t_ret; + return (ret); +} + +/* + * __db_vrfy_datapage -- + * Verify elements common to data pages (P_HASH, P_LBTREE, + * P_IBTREE, P_IRECNO, P_LRECNO, P_OVERFLOW, P_DUPLICATE)--i.e., + * those defined in the PAGE structure. + * + * Called from each of the per-page routines, after the + * all-page-type-common elements of pip have been verified and filled + * in. + * + * PUBLIC: int __db_vrfy_datapage + * PUBLIC: __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, u_int32_t)); + */ +int +__db_vrfy_datapage(dbp, vdp, h, pgno, flags) + DB *dbp; + VRFY_DBINFO *vdp; + PAGE *h; + db_pgno_t pgno; + u_int32_t flags; +{ + VRFY_PAGEINFO *pip; + int isbad, ret, t_ret; + + if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) + return (ret); + isbad = 0; + + /* + * prev_pgno and next_pgno: store for inter-page checks, + * verify that they point to actual pages and not to self. + * + * !!! + * Internal btree pages do not maintain these fields (indeed, + * they overload them). Skip. + */ + if (TYPE(h) != P_IBTREE && TYPE(h) != P_IRECNO) { + if (!IS_VALID_PGNO(PREV_PGNO(h)) || PREV_PGNO(h) == pip->pgno) { + isbad = 1; + EPRINT((dbp->dbenv, "Page %lu: Invalid prev_pgno %lu", + (u_long)pip->pgno, (u_long)PREV_PGNO(h))); + } + if (!IS_VALID_PGNO(NEXT_PGNO(h)) || NEXT_PGNO(h) == pip->pgno) { + isbad = 1; + EPRINT((dbp->dbenv, "Page %lu: Invalid next_pgno %lu", + (u_long)pip->pgno, (u_long)NEXT_PGNO(h))); + } + pip->prev_pgno = PREV_PGNO(h); + pip->next_pgno = NEXT_PGNO(h); + } + + /* + * Verify the number of entries on the page. + * There is no good way to determine if this is accurate; the + * best we can do is verify that it's not more than can, in theory, + * fit on the page. Then, we make sure there are at least + * this many valid elements in inp[], and hope that this catches + * most cases. + */ + if (TYPE(h) != P_OVERFLOW) { + if (BKEYDATA_PSIZE(0) * NUM_ENT(h) > dbp->pgsize) { + isbad = 1; + EPRINT((dbp->dbenv, + "Page %lu: Too many entries: %lu", + (u_long)pgno, (u_long)NUM_ENT(h))); + } + pip->entries = NUM_ENT(h); + } + + /* + * btree level. Should be zero unless we're a btree; + * if we are a btree, should be between LEAFLEVEL and MAXBTREELEVEL, + * and we need to save it off. + */ + switch (TYPE(h)) { + case P_IBTREE: + case P_IRECNO: + if (LEVEL(h) < LEAFLEVEL + 1 || LEVEL(h) > MAXBTREELEVEL) { + isbad = 1; + EPRINT((dbp->dbenv, "Bad btree level %lu on page %lu", + (u_long)LEVEL(h), (u_long)pgno)); + } + pip->bt_level = LEVEL(h); + break; + case P_LBTREE: + case P_LDUP: + case P_LRECNO: + if (LEVEL(h) != LEAFLEVEL) { + isbad = 1; + EPRINT((dbp->dbenv, + "Btree leaf page %lu has incorrect level %lu", + (u_long)pgno, (u_long)LEVEL(h))); + } + break; + default: + if (LEVEL(h) != 0) { + isbad = 1; + EPRINT((dbp->dbenv, + "Nonzero level %lu in non-btree database page %lu", + (u_long)LEVEL(h), (u_long)pgno)); + } + break; + } + + /* + * Even though inp[] occurs in all PAGEs, we look at it in the + * access-method-specific code, since btree and hash treat + * item lengths very differently, and one of the most important + * things we want to verify is that the data--as specified + * by offset and length--cover the right part of the page + * without overlaps, gaps, or violations of the page boundary. + */ + if ((t_ret = __db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0) + ret = t_ret; + + return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret); +} + +/* + * __db_vrfy_meta-- + * Verify the access-method common parts of a meta page, using + * normal mpool routines. + * + * PUBLIC: int __db_vrfy_meta + * PUBLIC: __P((DB *, VRFY_DBINFO *, DBMETA *, db_pgno_t, u_int32_t)); + */ +int +__db_vrfy_meta(dbp, vdp, meta, pgno, flags) + DB *dbp; + VRFY_DBINFO *vdp; + DBMETA *meta; + db_pgno_t pgno; + u_int32_t flags; +{ + DBTYPE dbtype, magtype; + VRFY_PAGEINFO *pip; + int isbad, ret, t_ret; + + isbad = 0; + if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) + return (ret); + + /* type plausible for a meta page */ + switch (meta->type) { + case P_BTREEMETA: + dbtype = DB_BTREE; + break; + case P_HASHMETA: + dbtype = DB_HASH; + break; + case P_QAMMETA: + dbtype = DB_QUEUE; + break; + default: + /* The verifier should never let us get here. */ + DB_ASSERT(0); + ret = EINVAL; + goto err; + } + + /* magic number valid */ + if (!__db_is_valid_magicno(meta->magic, &magtype)) { + isbad = 1; + EPRINT((dbp->dbenv, + "Magic number invalid on page %lu", (u_long)pgno)); + } + if (magtype != dbtype) { + isbad = 1; + EPRINT((dbp->dbenv, + "Magic number does not match type of page %lu", + (u_long)pgno)); + } + + /* version */ + if ((dbtype == DB_BTREE && meta->version != DB_BTREEVERSION) || + (dbtype == DB_HASH && meta->version != DB_HASHVERSION) || + (dbtype == DB_QUEUE && meta->version != DB_QAMVERSION)) { + isbad = 1; + EPRINT((dbp->dbenv, "%s%s", "Old of incorrect DB ", + "version; extraneous errors may result")); + } + + /* pagesize */ + if (meta->pagesize != dbp->pgsize) { + isbad = 1; + EPRINT((dbp->dbenv, + "Invalid pagesize %lu on page %lu", + (u_long)meta->pagesize, (u_long)pgno)); + } + + /* free list */ + /* + * If this is not the main, master-database meta page, it + * should not have a free list. + */ + if (pgno != PGNO_BASE_MD && meta->free != PGNO_INVALID) { + isbad = 1; + EPRINT((dbp->dbenv, + "Nonempty free list on subdatabase metadata page %lu", + pgno)); + } + + /* Can correctly be PGNO_INVALID--that's just the end of the list. */ + if (meta->free != PGNO_INVALID && IS_VALID_PGNO(meta->free)) + pip->free = meta->free; + else if (!IS_VALID_PGNO(meta->free)) { + isbad = 1; + EPRINT((dbp->dbenv, + "Nonsensical free list pgno %lu on page %lu", + (u_long)meta->free, (u_long)pgno)); + } + + /* + * We have now verified the common fields of the metadata page. + * Clear the flag that told us they had been incompletely checked. + */ + F_CLR(pip, VRFY_INCOMPLETE); + +err: if ((t_ret = __db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0) + ret = t_ret; + + return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret); +} + +/* + * __db_vrfy_freelist -- + * Walk free list, checking off pages and verifying absence of + * loops. + */ +static int +__db_vrfy_freelist(dbp, vdp, meta, flags) + DB *dbp; + VRFY_DBINFO *vdp; + db_pgno_t meta; + u_int32_t flags; +{ + DB *pgset; + VRFY_PAGEINFO *pip; + db_pgno_t pgno; + int p, ret, t_ret; + + pgset = vdp->pgset; + DB_ASSERT(pgset != NULL); + + if ((ret = __db_vrfy_getpageinfo(vdp, meta, &pip)) != 0) + return (ret); + for (pgno = pip->free; pgno != PGNO_INVALID; pgno = pip->next_pgno) { + if ((ret = __db_vrfy_putpageinfo(vdp, pip)) != 0) + return (ret); + + /* This shouldn't happen, but just in case. */ + if (!IS_VALID_PGNO(pgno)) { + EPRINT((dbp->dbenv, + "Invalid next_pgno on free list page %lu", + (u_long)pgno)); + return (DB_VERIFY_BAD); + } + + /* Detect cycles. */ + if ((ret = __db_vrfy_pgset_get(pgset, pgno, &p)) != 0) + return (ret); + if (p != 0) { + EPRINT((dbp->dbenv, + "Page %lu encountered a second time on free list", + (u_long)pgno)); + return (DB_VERIFY_BAD); + } + if ((ret = __db_vrfy_pgset_inc(pgset, pgno)) != 0) + return (ret); + + if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) + return (ret); + + if (pip->type != P_INVALID) { + EPRINT((dbp->dbenv, + "Non-invalid page %lu on free list", (u_long)pgno)); + ret = DB_VERIFY_BAD; /* unsafe to continue */ + break; + } + } + + if ((t_ret = __db_vrfy_putpageinfo(vdp, pip)) != 0) + ret = t_ret; + return (ret); +} + +/* + * __db_vrfy_subdbs -- + * Walk the known-safe master database of subdbs with a cursor, + * verifying the structure of each subdatabase we encounter. + */ +static int +__db_vrfy_subdbs(dbp, vdp, dbname, flags) + DB *dbp; + VRFY_DBINFO *vdp; + const char *dbname; + u_int32_t flags; +{ + DB *mdbp; + DBC *dbc; + DBT key, data; + VRFY_PAGEINFO *pip; + db_pgno_t meta_pgno; + int ret, t_ret, isbad; + u_int8_t type; + + isbad = 0; + dbc = NULL; + + if ((ret = __db_master_open(dbp, dbname, DB_RDONLY, 0, &mdbp)) != 0) + return (ret); + + if ((ret = + __db_icursor(mdbp, NULL, DB_BTREE, PGNO_INVALID, 0, &dbc)) != 0) + goto err; + + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + while ((ret = dbc->c_get(dbc, &key, &data, DB_NEXT)) == 0) { + if (data.size != sizeof(db_pgno_t)) { + EPRINT((dbp->dbenv, "Database entry of invalid size")); + isbad = 1; + goto err; + } + memcpy(&meta_pgno, data.data, data.size); + /* + * Subdatabase meta pgnos are stored in network byte + * order for cross-endian compatibility. Swap if appropriate. + */ + DB_NTOHL(&meta_pgno); + if (meta_pgno == PGNO_INVALID || meta_pgno > vdp->last_pgno) { + EPRINT((dbp->dbenv, + "Database entry references invalid page %lu", + (u_long)meta_pgno)); + isbad = 1; + goto err; + } + if ((ret = __db_vrfy_getpageinfo(vdp, meta_pgno, &pip)) != 0) + goto err; + type = pip->type; + if ((ret = __db_vrfy_putpageinfo(vdp, pip)) != 0) + goto err; + switch (type) { + case P_BTREEMETA: + if ((ret = __bam_vrfy_structure( + dbp, vdp, meta_pgno, flags)) != 0) { + if (ret == DB_VERIFY_BAD) + isbad = 1; + else + goto err; + } + break; + case P_HASHMETA: + if ((ret = __ham_vrfy_structure( + dbp, vdp, meta_pgno, flags)) != 0) { + if (ret == DB_VERIFY_BAD) + isbad = 1; + else + goto err; + } + break; + case P_QAMMETA: + default: + EPRINT((dbp->dbenv, + "Database entry references page %lu of invalid type %lu", + (u_long)meta_pgno, (u_long)type)); + ret = DB_VERIFY_BAD; + goto err; + /* NOTREACHED */ + } + } + + if (ret == DB_NOTFOUND) + ret = 0; + +err: if (dbc != NULL && (t_ret = __db_c_close(dbc)) != 0 && ret == 0) + ret = t_ret; + + if ((t_ret = mdbp->close(mdbp, 0)) != 0 && ret == 0) + ret = t_ret; + + return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret); +} + +/* + * __db_vrfy_struct_feedback -- + * Provide feedback during top-down database structure traversal. + * (See comment at the beginning of __db_vrfy_structure.) + * + * PUBLIC: int __db_vrfy_struct_feedback __P((DB *, VRFY_DBINFO *)); + */ +int +__db_vrfy_struct_feedback(dbp, vdp) + DB *dbp; + VRFY_DBINFO *vdp; +{ + int progress; + + if (dbp->db_feedback == NULL) + return (0); + + if (vdp->pgs_remaining > 0) + vdp->pgs_remaining--; + + /* Don't allow a feedback call of 100 until we're really done. */ + progress = 100 - (vdp->pgs_remaining * 50 / (vdp->last_pgno + 1)); + dbp->db_feedback(dbp, DB_VERIFY, progress == 100 ? 99 : progress); + + return (0); +} + +/* + * __db_vrfy_orderchkonly -- + * Do an sort-order/hashing check on a known-otherwise-good subdb. + */ +static int +__db_vrfy_orderchkonly(dbp, vdp, name, subdb, flags) + DB *dbp; + VRFY_DBINFO *vdp; + const char *name, *subdb; + u_int32_t flags; +{ + BTMETA *btmeta; + DB *mdbp, *pgset; + DBC *pgsc; + DBT key, data; + HASH *h_internal; + HMETA *hmeta; + PAGE *h, *currpg; + db_pgno_t meta_pgno, p, pgno; + u_int32_t bucket; + int t_ret, ret; + + currpg = h = NULL; + pgsc = NULL; + pgset = NULL; + + LF_CLR(DB_NOORDERCHK); + + /* Open the master database and get the meta_pgno for the subdb. */ + if ((ret = db_create(&mdbp, NULL, 0)) != 0) + return (ret); + if ((ret = __db_master_open(dbp, name, DB_RDONLY, 0, &mdbp)) != 0) + goto err; + + memset(&key, 0, sizeof(key)); + key.data = (void *)subdb; + memset(&data, 0, sizeof(data)); + if ((ret = dbp->get(dbp, NULL, &key, &data, 0)) != 0) + goto err; + + if (data.size != sizeof(db_pgno_t)) { + EPRINT((dbp->dbenv, "Database entry of invalid size")); + ret = DB_VERIFY_BAD; + goto err; + } + + memcpy(&meta_pgno, data.data, data.size); + + if ((ret = memp_fget(dbp->mpf, &meta_pgno, 0, &h)) != 0) + goto err; + + if ((ret = __db_vrfy_pgset(dbp->dbenv, dbp->pgsize, &pgset)) != 0) + goto err; + + switch (TYPE(h)) { + case P_BTREEMETA: + btmeta = (BTMETA *)h; + if (F_ISSET(&btmeta->dbmeta, BTM_RECNO)) { + /* Recnos have no order to check. */ + ret = 0; + goto err; + } + if ((ret = + __db_meta2pgset(dbp, vdp, meta_pgno, flags, pgset)) != 0) + goto err; + if ((ret = pgset->cursor(pgset, NULL, &pgsc, 0)) != 0) + goto err; + while ((ret = __db_vrfy_pgset_next(pgsc, &p)) == 0) { + if ((ret = memp_fget(dbp->mpf, &p, 0, &currpg)) != 0) + goto err; + if ((ret = __bam_vrfy_itemorder(dbp, + NULL, currpg, p, NUM_ENT(currpg), 1, + F_ISSET(&btmeta->dbmeta, BTM_DUP), flags)) != 0) + goto err; + if ((ret = memp_fput(dbp->mpf, currpg, 0)) != 0) + goto err; + currpg = NULL; + } + if ((ret = pgsc->c_close(pgsc)) != 0) + goto err; + break; + case P_HASHMETA: + hmeta = (HMETA *)h; + h_internal = (HASH *)dbp->h_internal; + /* + * Make sure h_charkey is right. + */ + if (h_internal == NULL || h_internal->h_hash == NULL) { + EPRINT((dbp->dbenv, + "DB_ORDERCHKONLY requires that a hash function be set")); + ret = DB_VERIFY_BAD; + goto err; + } + if (hmeta->h_charkey != + h_internal->h_hash(dbp, CHARKEY, sizeof(CHARKEY))) { + EPRINT((dbp->dbenv, + "Incorrect hash function for database")); + ret = DB_VERIFY_BAD; + goto err; + } + + /* + * Foreach bucket, verify hashing on each page in the + * corresponding chain of pages. + */ + for (bucket = 0; bucket <= hmeta->max_bucket; bucket++) { + pgno = BS_TO_PAGE(bucket, hmeta->spares); + while (pgno != PGNO_INVALID) { + if ((ret = memp_fget(dbp->mpf, + &pgno, 0, &currpg)) != 0) + goto err; + if ((ret = __ham_vrfy_hashing(dbp, + NUM_ENT(currpg),hmeta, bucket, pgno, + flags, h_internal->h_hash)) != 0) + goto err; + pgno = NEXT_PGNO(currpg); + if ((ret = memp_fput(dbp->mpf, currpg, 0)) != 0) + goto err; + currpg = NULL; + } + } + break; + default: + EPRINT((dbp->dbenv, "Database meta page %lu of bad type %lu", + (u_long)meta_pgno, (u_long)TYPE(h))); + ret = DB_VERIFY_BAD; + break; + } + +err: if (pgsc != NULL) + (void)pgsc->c_close(pgsc); + if (pgset != NULL) + (void)pgset->close(pgset, 0); + if (h != NULL && (t_ret = memp_fput(dbp->mpf, h, 0)) != 0) + ret = t_ret; + if (currpg != NULL && (t_ret = memp_fput(dbp->mpf, currpg, 0)) != 0) + ret = t_ret; + if ((t_ret = mdbp->close(mdbp, 0)) != 0) + ret = t_ret; + return (ret); +} + +/* + * __db_salvage -- + * Walk through a page, salvaging all likely or plausible (w/ + * DB_AGGRESSIVE) key/data pairs. + * + * PUBLIC: int __db_salvage __P((DB *, VRFY_DBINFO *, db_pgno_t, PAGE *, + * PUBLIC: void *, int (*)(void *, const void *), u_int32_t)); + */ +int +__db_salvage(dbp, vdp, pgno, h, handle, callback, flags) + DB *dbp; + VRFY_DBINFO *vdp; + db_pgno_t pgno; + PAGE *h; + void *handle; + int (*callback) __P((void *, const void *)); + u_int32_t flags; +{ + DB_ASSERT(LF_ISSET(DB_SALVAGE)); + + /* If we got this page in the subdb pass, we can safely skip it. */ + if (__db_salvage_isdone(vdp, pgno)) + return (0); + + switch (TYPE(h)) { + case P_HASH: + return (__ham_salvage(dbp, + vdp, pgno, h, handle, callback, flags)); + /* NOTREACHED */ + case P_LBTREE: + return (__bam_salvage(dbp, + vdp, pgno, P_LBTREE, h, handle, callback, NULL, flags)); + /* NOTREACHED */ + case P_LDUP: + return (__db_salvage_markneeded(vdp, pgno, SALVAGE_LDUP)); + /* NOTREACHED */ + case P_OVERFLOW: + return (__db_salvage_markneeded(vdp, pgno, SALVAGE_OVERFLOW)); + /* NOTREACHED */ + case P_LRECNO: + /* + * Recnos are tricky -- they may represent dup pages, or + * they may be subdatabase/regular database pages in their + * own right. If the former, they need to be printed with a + * key, preferably when we hit the corresponding datum in + * a btree/hash page. If the latter, there is no key. + * + * If a database is sufficiently frotzed, we're not going + * to be able to get this right, so we best-guess: just + * mark it needed now, and if we're really a normal recno + * database page, the "unknowns" pass will pick us up. + */ + return (__db_salvage_markneeded(vdp, pgno, SALVAGE_LRECNO)); + /* NOTREACHED */ + case P_IBTREE: + case P_INVALID: + case P_IRECNO: + case __P_DUPLICATE: + default: + /* XXX: Should we be more aggressive here? */ + break; + } + return (0); +} + +/* + * __db_salvage_unknowns -- + * Walk through the salvager database, printing with key "UNKNOWN" + * any pages we haven't dealt with. + */ +static int +__db_salvage_unknowns(dbp, vdp, handle, callback, flags) + DB *dbp; + VRFY_DBINFO *vdp; + void *handle; + int (*callback) __P((void *, const void *)); + u_int32_t flags; +{ + DBT unkdbt, key, *dbt; + PAGE *h; + db_pgno_t pgno; + u_int32_t pgtype; + int ret, err_ret; + void *ovflbuf; + + memset(&unkdbt, 0, sizeof(DBT)); + unkdbt.size = strlen("UNKNOWN") + 1; + unkdbt.data = "UNKNOWN"; + + if ((ret = __os_malloc(dbp->dbenv, dbp->pgsize, 0, &ovflbuf)) != 0) + return (ret); + + err_ret = 0; + while ((ret = __db_salvage_getnext(vdp, &pgno, &pgtype)) == 0) { + dbt = NULL; + + if ((ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) { + err_ret = ret; + continue; + } + + switch (pgtype) { + case SALVAGE_LDUP: + case SALVAGE_LRECNODUP: + dbt = &unkdbt; + /* FALLTHROUGH */ + case SALVAGE_LBTREE: + case SALVAGE_LRECNO: + if ((ret = __bam_salvage(dbp, vdp, pgno, pgtype, + h, handle, callback, dbt, flags)) != 0) + err_ret = ret; + break; + case SALVAGE_OVERFLOW: + /* + * XXX: + * This may generate multiple "UNKNOWN" keys in + * a database with no dups. What to do? + */ + if ((ret = __db_safe_goff(dbp, + vdp, pgno, &key, &ovflbuf, flags)) != 0) { + err_ret = ret; + continue; + } + if ((ret = __db_prdbt(&key, + 0, " ", handle, callback, 0, NULL)) != 0) { + err_ret = ret; + continue; + } + if ((ret = __db_prdbt(&unkdbt, + 0, " ", handle, callback, 0, NULL)) != 0) + err_ret = ret; + break; + case SALVAGE_HASH: + if ((ret = __ham_salvage( + dbp, vdp, pgno, h, handle, callback, flags)) != 0) + err_ret = ret; + break; + case SALVAGE_INVALID: + case SALVAGE_IGNORE: + default: + /* + * Shouldn't happen, but if it does, just do what the + * nice man says. + */ + DB_ASSERT(0); + break; + } + if ((ret = memp_fput(dbp->mpf, h, 0)) != 0) + err_ret = ret; + } + + __os_free(ovflbuf, 0); + + if (err_ret != 0 && ret == 0) + ret = err_ret; + + return (ret == DB_NOTFOUND ? 0 : ret); +} + +/* + * Offset of the ith inp array entry, which we can compare to the offset + * the entry stores. + */ +#define INP_OFFSET(h, i) \ + ((db_indx_t)((u_int8_t *)(h)->inp + (i) - (u_int8_t *)(h))) + +/* + * __db_vrfy_inpitem -- + * Verify that a single entry in the inp array is sane, and update + * the high water mark and current item offset. (The former of these is + * used for state information between calls, and is required; it must + * be initialized to the pagesize before the first call.) + * + * Returns DB_VERIFY_FATAL if inp has collided with the data, + * since verification can't continue from there; returns DB_VERIFY_BAD + * if anything else is wrong. + * + * PUBLIC: int __db_vrfy_inpitem __P((DB *, PAGE *, + * PUBLIC: db_pgno_t, u_int32_t, int, u_int32_t, u_int32_t *, u_int32_t *)); + */ +int +__db_vrfy_inpitem(dbp, h, pgno, i, is_btree, flags, himarkp, offsetp) + DB *dbp; + PAGE *h; + db_pgno_t pgno; + u_int32_t i; + int is_btree; + u_int32_t flags, *himarkp, *offsetp; +{ + BKEYDATA *bk; + db_indx_t offset, len; + + DB_ASSERT(himarkp != NULL); + + /* + * Check that the inp array, which grows from the beginning of the + * page forward, has not collided with the data, which grow from the + * end of the page backward. + */ + if (h->inp + i >= (db_indx_t *)((u_int8_t *)h + *himarkp)) { + /* We've collided with the data. We need to bail. */ + EPRINT((dbp->dbenv, + "Page %lu entries listing %lu overlaps data", + (u_long)pgno, (u_long)i)); + return (DB_VERIFY_FATAL); + } + + offset = h->inp[i]; + + /* + * Check that the item offset is reasonable: it points somewhere + * after the inp array and before the end of the page. + */ + if (offset <= INP_OFFSET(h, i) || offset > dbp->pgsize) { + EPRINT((dbp->dbenv, + "Bad offset %lu at page %lu index %lu", + (u_long)offset, (u_long)pgno, (u_long)i)); + return (DB_VERIFY_BAD); + } + + /* Update the high-water mark (what HOFFSET should be) */ + if (offset < *himarkp) + *himarkp = offset; + + if (is_btree) { + /* + * Check that the item length remains on-page. + */ + bk = GET_BKEYDATA(h, i); + + /* + * We need to verify the type of the item here; + * we can't simply assume that it will be one of the + * expected three. If it's not a recognizable type, + * it can't be considered to have a verifiable + * length, so it's not possible to certify it as safe. + */ + switch (B_TYPE(bk->type)) { + case B_KEYDATA: + len = bk->len; + break; + case B_DUPLICATE: + case B_OVERFLOW: + len = BOVERFLOW_SIZE; + break; + default: + EPRINT((dbp->dbenv, + "Item %lu on page %lu of unrecognizable type", + i, pgno)); + return (DB_VERIFY_BAD); + } + + if ((size_t)(offset + len) > dbp->pgsize) { + EPRINT((dbp->dbenv, + "Item %lu on page %lu extends past page boundary", + (u_long)i, (u_long)pgno)); + return (DB_VERIFY_BAD); + } + } + + if (offsetp != NULL) + *offsetp = offset; + return (0); +} + +/* + * __db_vrfy_duptype-- + * Given a page number and a set of flags to __bam_vrfy_subtree, + * verify that the dup tree type is correct--i.e., it's a recno + * if DUPSORT is not set and a btree if it is. + * + * PUBLIC: int __db_vrfy_duptype + * PUBLIC: __P((DB *, VRFY_DBINFO *, db_pgno_t, u_int32_t)); + */ +int +__db_vrfy_duptype(dbp, vdp, pgno, flags) + DB *dbp; + VRFY_DBINFO *vdp; + db_pgno_t pgno; + u_int32_t flags; +{ + VRFY_PAGEINFO *pip; + int ret, isbad; + + isbad = 0; + + if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) + return (ret); + + switch (pip->type) { + case P_IBTREE: + case P_LDUP: + if (!LF_ISSET(ST_DUPSORT)) { + EPRINT((dbp->dbenv, + "Sorted duplicate set at page %lu in unsorted-dup database", + (u_long)pgno)); + isbad = 1; + } + break; + case P_IRECNO: + case P_LRECNO: + if (LF_ISSET(ST_DUPSORT)) { + EPRINT((dbp->dbenv, + "Unsorted duplicate set at page %lu in sorted-dup database", + (u_long)pgno)); + isbad = 1; + } + break; + default: + EPRINT((dbp->dbenv, + "Duplicate page %lu of inappropriate type %lu", + (u_long)pgno, (u_long)pip->type)); + isbad = 1; + break; + } + + if ((ret = __db_vrfy_putpageinfo(vdp, pip)) != 0) + return (ret); + return (isbad == 1 ? DB_VERIFY_BAD : 0); +} + +/* + * __db_salvage_duptree -- + * Attempt to salvage a given duplicate tree, given its alleged root. + * + * The key that corresponds to this dup set has been passed to us + * in DBT *key. Because data items follow keys, though, it has been + * printed once already. + * + * The basic idea here is that pgno ought to be a P_LDUP, a P_LRECNO, a + * P_IBTREE, or a P_IRECNO. If it's an internal page, use the verifier + * functions to make sure it's safe; if it's not, we simply bail and the + * data will have to be printed with no key later on. if it is safe, + * recurse on each of its children. + * + * Whether or not it's safe, if it's a leaf page, __bam_salvage it. + * + * At all times, use the DB hanging off vdp to mark and check what we've + * done, so each page gets printed exactly once and we don't get caught + * in any cycles. + * + * PUBLIC: int __db_salvage_duptree __P((DB *, VRFY_DBINFO *, db_pgno_t, + * PUBLIC: DBT *, void *, int (*)(void *, const void *), u_int32_t)); + */ +int +__db_salvage_duptree(dbp, vdp, pgno, key, handle, callback, flags) + DB *dbp; + VRFY_DBINFO *vdp; + db_pgno_t pgno; + DBT *key; + void *handle; + int (*callback) __P((void *, const void *)); + u_int32_t flags; +{ + PAGE *h; + int ret, t_ret; + + if (pgno == PGNO_INVALID || !IS_VALID_PGNO(pgno)) + return (DB_VERIFY_BAD); + + /* We have a plausible page. Try it. */ + if ((ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) + return (ret); + + switch (TYPE(h)) { + case P_IBTREE: + case P_IRECNO: + if ((ret = __db_vrfy_common(dbp, vdp, h, pgno, flags)) != 0) + goto err; + if ((ret = __bam_vrfy(dbp, + vdp, h, pgno, flags | DB_NOORDERCHK)) != 0 || + (ret = __db_salvage_markdone(vdp, pgno)) != 0) + goto err; + /* + * We have a known-healthy internal page. Walk it. + */ + if ((ret = __bam_salvage_walkdupint(dbp, vdp, h, key, + handle, callback, flags)) != 0) + goto err; + break; + case P_LRECNO: + case P_LDUP: + if ((ret = __bam_salvage(dbp, + vdp, pgno, TYPE(h), h, handle, callback, key, flags)) != 0) + goto err; + break; + default: + ret = DB_VERIFY_BAD; + goto err; + /* NOTREACHED */ + } + +err: if ((t_ret = memp_fput(dbp->mpf, h, 0)) != 0 && ret == 0) + ret = t_ret; + return (ret); +} + +/* + * __db_salvage_subdbs -- + * Check and see if this database has subdbs; if so, try to salvage + * them independently. + */ +static int +__db_salvage_subdbs(dbp, vdp, handle, callback, flags, hassubsp) + DB *dbp; + VRFY_DBINFO *vdp; + void *handle; + int (*callback) __P((void *, const void *)); + u_int32_t flags; + int *hassubsp; +{ + BTMETA *btmeta; + DB *pgset; + DBC *pgsc; + PAGE *h; + db_pgno_t p, meta_pgno; + int ret, err_ret; + + err_ret = 0; + pgsc = NULL; + pgset = NULL; + + meta_pgno = PGNO_BASE_MD; + if ((ret = memp_fget(dbp->mpf, &meta_pgno, 0, &h)) != 0) + return (ret); + + if (TYPE(h) == P_BTREEMETA) + btmeta = (BTMETA *)h; + else { + /* Not a btree metadata, ergo no subdbs, so just return. */ + ret = 0; + goto err; + } + + /* If it's not a safe page, bail on the attempt. */ + if ((ret = __db_vrfy_common(dbp, vdp, h, PGNO_BASE_MD, flags)) != 0 || + (ret = __bam_vrfy_meta(dbp, vdp, btmeta, PGNO_BASE_MD, flags)) != 0) + goto err; + + if (!F_ISSET(&btmeta->dbmeta, BTM_SUBDB)) { + /* No subdbs, just return. */ + ret = 0; + goto err; + } + + /* We think we've got subdbs. Mark it so. */ + *hassubsp = 1; + + if ((ret = memp_fput(dbp->mpf, h, 0)) != 0) + return (ret); + + /* + * We have subdbs. Try to crack them. + * + * To do so, get a set of leaf pages in the master + * database, and then walk each of the valid ones, salvaging + * subdbs as we go. If any prove invalid, just drop them; we'll + * pick them up on a later pass. + */ + if ((ret = __db_vrfy_pgset(dbp->dbenv, dbp->pgsize, &pgset)) != 0) + return (ret); + if ((ret = + __db_meta2pgset(dbp, vdp, PGNO_BASE_MD, flags, pgset)) != 0) + goto err; + + if ((ret = pgset->cursor(pgset, NULL, &pgsc, 0)) != 0) + goto err; + while ((ret = __db_vrfy_pgset_next(pgsc, &p)) == 0) { + if ((ret = memp_fget(dbp->mpf, &p, 0, &h)) != 0) { + err_ret = ret; + continue; + } + if ((ret = __db_vrfy_common(dbp, vdp, h, p, flags)) != 0 || + (ret = __bam_vrfy(dbp, + vdp, h, p, flags | DB_NOORDERCHK)) != 0) + goto nextpg; + if (TYPE(h) != P_LBTREE) + goto nextpg; + else if ((ret = __db_salvage_subdbpg( + dbp, vdp, h, handle, callback, flags)) != 0) + err_ret = ret; +nextpg: if ((ret = memp_fput(dbp->mpf, h, 0)) != 0) + err_ret = ret; + } + + if (ret != DB_NOTFOUND) + goto err; + if ((ret = pgsc->c_close(pgsc)) != 0) + goto err; + + ret = pgset->close(pgset, 0); + return ((ret == 0 && err_ret != 0) ? err_ret : ret); + + /* NOTREACHED */ + +err: if (pgsc != NULL) + (void)pgsc->c_close(pgsc); + if (pgset != NULL) + (void)pgset->close(pgset, 0); + (void)memp_fput(dbp->mpf, h, 0); + return (ret); +} + +/* + * __db_salvage_subdbpg -- + * Given a known-good leaf page in the master database, salvage all + * leaf pages corresponding to each subdb. + * + * PUBLIC: int __db_salvage_subdbpg + * PUBLIC: __P((DB *, VRFY_DBINFO *, PAGE *, void *, + * PUBLIC: int (*)(void *, const void *), u_int32_t)); + */ +int +__db_salvage_subdbpg(dbp, vdp, master, handle, callback, flags) + DB *dbp; + VRFY_DBINFO *vdp; + PAGE *master; + void *handle; + int (*callback) __P((void *, const void *)); + u_int32_t flags; +{ + BKEYDATA *bkkey, *bkdata; + BOVERFLOW *bo; + DB *pgset; + DBC *pgsc; + DBT key; + PAGE *subpg; + db_indx_t i; + db_pgno_t meta_pgno, p; + int ret, err_ret, t_ret; + char *subdbname; + + ret = err_ret = 0; + subdbname = NULL; + + if ((ret = __db_vrfy_pgset(dbp->dbenv, dbp->pgsize, &pgset)) != 0) + return (ret); + + /* + * For each entry, get and salvage the set of pages + * corresponding to that entry. + */ + for (i = 0; i < NUM_ENT(master); i += P_INDX) { + bkkey = GET_BKEYDATA(master, i); + bkdata = GET_BKEYDATA(master, i + O_INDX); + + /* Get the subdatabase name. */ + if (B_TYPE(bkkey->type) == B_OVERFLOW) { + /* + * We can, in principle anyway, have a subdb + * name so long it overflows. Ick. + */ + bo = (BOVERFLOW *)bkkey; + if ((ret = __db_safe_goff(dbp, vdp, bo->pgno, &key, + (void **)&subdbname, flags)) != 0) { + err_ret = DB_VERIFY_BAD; + continue; + } + + /* Nul-terminate it. */ + if ((ret = __os_realloc(dbp->dbenv, + key.size + 1, NULL, &subdbname)) != 0) + goto err; + subdbname[key.size] = '\0'; + } else if (B_TYPE(bkkey->type == B_KEYDATA)) { + if ((ret = __os_realloc(dbp->dbenv, + bkkey->len + 1, NULL, &subdbname)) != 0) + goto err; + memcpy(subdbname, bkkey->data, bkkey->len); + subdbname[bkkey->len] = '\0'; + } + + /* Get the corresponding pgno. */ + if (bkdata->len != sizeof(db_pgno_t)) { + err_ret = DB_VERIFY_BAD; + continue; + } + memcpy(&meta_pgno, bkdata->data, sizeof(db_pgno_t)); + + /* If we can't get the subdb meta page, just skip the subdb. */ + if (!IS_VALID_PGNO(meta_pgno) || + (ret = memp_fget(dbp->mpf, &meta_pgno, 0, &subpg)) != 0) { + err_ret = ret; + continue; + } + + /* + * Verify the subdatabase meta page. This has two functions. + * First, if it's bad, we have no choice but to skip the subdb + * and let the pages just get printed on a later pass. Second, + * the access-method-specific meta verification routines record + * the various state info (such as the presence of dups) + * that we need for __db_prheader(). + */ + if ((ret = + __db_vrfy_common(dbp, vdp, subpg, meta_pgno, flags)) != 0) { + err_ret = ret; + (void)memp_fput(dbp->mpf, subpg, 0); + continue; + } + switch (TYPE(subpg)) { + case P_BTREEMETA: + if ((ret = __bam_vrfy_meta(dbp, + vdp, (BTMETA *)subpg, meta_pgno, flags)) != 0) { + err_ret = ret; + (void)memp_fput(dbp->mpf, subpg, 0); + continue; + } + break; + case P_HASHMETA: + if ((ret = __ham_vrfy_meta(dbp, + vdp, (HMETA *)subpg, meta_pgno, flags)) != 0) { + err_ret = ret; + (void)memp_fput(dbp->mpf, subpg, 0); + continue; + } + break; + default: + /* This isn't an appropriate page; skip this subdb. */ + err_ret = DB_VERIFY_BAD; + continue; + /* NOTREACHED */ + } + + if ((ret = memp_fput(dbp->mpf, subpg, 0)) != 0) { + err_ret = ret; + continue; + } + + /* Print a subdatabase header. */ + if ((ret = __db_prheader(dbp, + subdbname, 0, 0, handle, callback, vdp, meta_pgno)) != 0) + goto err; + + if ((ret = __db_meta2pgset(dbp, vdp, meta_pgno, + flags, pgset)) != 0) { + err_ret = ret; + continue; + } + + if ((ret = pgset->cursor(pgset, NULL, &pgsc, 0)) != 0) + goto err; + while ((ret = __db_vrfy_pgset_next(pgsc, &p)) == 0) { + if ((ret = memp_fget(dbp->mpf, &p, 0, &subpg)) != 0) { + err_ret = ret; + continue; + } + if ((ret = __db_salvage(dbp, vdp, p, subpg, + handle, callback, flags)) != 0) + err_ret = ret; + if ((ret = memp_fput(dbp->mpf, subpg, 0)) != 0) + err_ret = ret; + } + + if (ret != DB_NOTFOUND) + goto err; + + if ((ret = pgsc->c_close(pgsc)) != 0) + goto err; + if ((ret = __db_prfooter(handle, callback)) != 0) + goto err; + } +err: if (subdbname) + __os_free(subdbname, 0); + + if ((t_ret = pgset->close(pgset, 0)) != 0) + ret = t_ret; + + if ((t_ret = __db_salvage_markdone(vdp, PGNO(master))) != 0) + return (t_ret); + + return ((err_ret != 0) ? err_ret : ret); +} + +/* + * __db_meta2pgset -- + * Given a known-safe meta page number, return the set of pages + * corresponding to the database it represents. Return DB_VERIFY_BAD if + * it's not a suitable meta page or is invalid. + */ +static int +__db_meta2pgset(dbp, vdp, pgno, flags, pgset) + DB *dbp; + VRFY_DBINFO *vdp; + db_pgno_t pgno; + u_int32_t flags; + DB *pgset; +{ + PAGE *h; + int ret, t_ret; + + if ((ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) + return (ret); + + switch (TYPE(h)) { + case P_BTREEMETA: + ret = __bam_meta2pgset(dbp, vdp, (BTMETA *)h, flags, pgset); + break; + case P_HASHMETA: + ret = __ham_meta2pgset(dbp, vdp, (HMETA *)h, flags, pgset); + break; + default: + ret = DB_VERIFY_BAD; + break; + } + + if ((t_ret = memp_fput(dbp->mpf, h, 0)) != 0) + return (t_ret); + return (ret); +} + +/* + * __db_guesspgsize -- + * Try to guess what the pagesize is if the one on the meta page + * and the one in the db are invalid. + */ +static int +__db_guesspgsize(dbenv, fhp) + DB_ENV *dbenv; + DB_FH *fhp; +{ + db_pgno_t i; + size_t nr; + u_int32_t guess; + u_int8_t type; + int ret; + + for (guess = DB_MAX_PGSIZE; guess >= DB_MIN_PGSIZE; guess >>= 1) { + /* + * We try to read three pages ahead after the first one + * and make sure we have plausible types for all of them. + * If the seeks fail, continue with a smaller size; + * we're probably just looking past the end of the database. + * If they succeed and the types are reasonable, also continue + * with a size smaller; we may be looking at pages N, + * 2N, and 3N for some N > 1. + * + * As soon as we hit an invalid type, we stop and return + * our previous guess; that last one was probably the page size. + */ + for (i = 1; i <= 3; i++) { + if ((ret = __os_seek(dbenv, fhp, guess, + i, SSZ(DBMETA, type), 0, DB_OS_SEEK_SET)) != 0) + break; + if ((ret = __os_read(dbenv, + fhp, &type, 1, &nr)) != 0 || nr == 0) + break; + if (type == P_INVALID || type >= P_PAGETYPE_MAX) + return (guess << 1); + } + } + + /* + * If we're just totally confused--the corruption takes up most of the + * beginning pages of the database--go with the default size. + */ + return (DB_DEF_IOSIZE); +} diff --git a/db/db/db_vrfyutil.c b/db/db/db_vrfyutil.c new file mode 100644 index 000000000..89dccdcc7 --- /dev/null +++ b/db/db/db_vrfyutil.c @@ -0,0 +1,830 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: db_vrfyutil.c,v 11.11 2000/11/28 21:36:04 bostic Exp $ + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: db_vrfyutil.c,v 11.11 2000/11/28 21:36:04 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_verify.h" +#include "db_ext.h" + +static int __db_vrfy_pgset_iinc __P((DB *, db_pgno_t, int)); + +/* + * __db_vrfy_dbinfo_create -- + * Allocate and initialize a VRFY_DBINFO structure. + * + * PUBLIC: int __db_vrfy_dbinfo_create + * PUBLIC: __P((DB_ENV *, u_int32_t, VRFY_DBINFO **)); + */ +int +__db_vrfy_dbinfo_create (dbenv, pgsize, vdpp) + DB_ENV *dbenv; + u_int32_t pgsize; + VRFY_DBINFO **vdpp; +{ + DB *cdbp, *pgdbp, *pgset; + VRFY_DBINFO *vdp; + int ret; + + vdp = NULL; + cdbp = pgdbp = pgset = NULL; + + if ((ret = __os_calloc(NULL, + 1, sizeof(VRFY_DBINFO), (void **)&vdp)) != 0) + goto err; + + if ((ret = db_create(&cdbp, dbenv, 0)) != 0) + goto err; + + if ((ret = cdbp->set_flags(cdbp, DB_DUP | DB_DUPSORT)) != 0) + goto err; + + if ((ret = cdbp->set_pagesize(cdbp, pgsize)) != 0) + goto err; + + if ((ret = + cdbp->open(cdbp, NULL, NULL, DB_BTREE, DB_CREATE, 0600)) != 0) + goto err; + + if ((ret = db_create(&pgdbp, dbenv, 0)) != 0) + goto err; + + if ((ret = pgdbp->set_pagesize(pgdbp, pgsize)) != 0) + goto err; + + if ((ret = + pgdbp->open(pgdbp, NULL, NULL, DB_BTREE, DB_CREATE, 0600)) != 0) + goto err; + + if ((ret = __db_vrfy_pgset(dbenv, pgsize, &pgset)) != 0) + goto err; + + LIST_INIT(&vdp->subdbs); + LIST_INIT(&vdp->activepips); + + vdp->cdbp = cdbp; + vdp->pgdbp = pgdbp; + vdp->pgset = pgset; + *vdpp = vdp; + return (0); + +err: if (cdbp != NULL) + (void)cdbp->close(cdbp, 0); + if (pgdbp != NULL) + (void)pgdbp->close(pgdbp, 0); + if (vdp != NULL) + __os_free(vdp, sizeof(VRFY_DBINFO)); + return (ret); +} + +/* + * __db_vrfy_dbinfo_destroy -- + * Destructor for VRFY_DBINFO. Destroys VRFY_PAGEINFOs and deallocates + * structure. + * + * PUBLIC: int __db_vrfy_dbinfo_destroy __P((VRFY_DBINFO *)); + */ +int +__db_vrfy_dbinfo_destroy(vdp) + VRFY_DBINFO *vdp; +{ + VRFY_CHILDINFO *c, *d; + int t_ret, ret; + + ret = 0; + + for (c = LIST_FIRST(&vdp->subdbs); c != NULL; c = d) { + d = LIST_NEXT(c, links); + __os_free(c, 0); + } + + if ((t_ret = vdp->pgdbp->close(vdp->pgdbp, 0)) != 0) + ret = t_ret; + + if ((t_ret = vdp->cdbp->close(vdp->cdbp, 0)) != 0 && ret == 0) + ret = t_ret; + + if ((t_ret = vdp->pgset->close(vdp->pgset, 0)) != 0 && ret == 0) + ret = t_ret; + + DB_ASSERT(LIST_FIRST(&vdp->activepips) == NULL); + + __os_free(vdp, sizeof(VRFY_DBINFO)); + return (ret); +} + +/* + * __db_vrfy_getpageinfo -- + * Get a PAGEINFO structure for a given page, creating it if necessary. + * + * PUBLIC: int __db_vrfy_getpageinfo + * PUBLIC: __P((VRFY_DBINFO *, db_pgno_t, VRFY_PAGEINFO **)); + */ +int +__db_vrfy_getpageinfo(vdp, pgno, pipp) + VRFY_DBINFO *vdp; + db_pgno_t pgno; + VRFY_PAGEINFO **pipp; +{ + DBT key, data; + DB *pgdbp; + VRFY_PAGEINFO *pip; + int ret; + + /* + * We want a page info struct. There are three places to get it from, + * in decreasing order of preference: + * + * 1. vdp->activepips. If it's already "checked out", we're + * already using it, we return the same exact structure with a + * bumped refcount. This is necessary because this code is + * replacing array accesses, and it's common for f() to make some + * changes to a pip, and then call g() and h() which each make + * changes to the same pip. vdps are never shared between threads + * (they're never returned to the application), so this is safe. + * 2. The pgdbp. It's not in memory, but it's in the database, so + * get it, give it a refcount of 1, and stick it on activepips. + * 3. malloc. It doesn't exist yet; create it, then stick it on + * activepips. We'll put it in the database when we putpageinfo + * later. + */ + + /* Case 1. */ + for (pip = LIST_FIRST(&vdp->activepips); pip != NULL; + pip = LIST_NEXT(pip, links)) + if (pip->pgno == pgno) + /* Found it. */ + goto found; + + /* Case 2. */ + pgdbp = vdp->pgdbp; + memset(&key, 0, sizeof(DBT)); + memset(&data, 0, sizeof(DBT)); + F_SET(&data, DB_DBT_MALLOC); + key.data = &pgno; + key.size = sizeof(db_pgno_t); + + if ((ret = pgdbp->get(pgdbp, NULL, &key, &data, 0)) == 0) { + /* Found it. */ + DB_ASSERT(data.size = sizeof(VRFY_PAGEINFO)); + pip = data.data; + DB_ASSERT(pip->pi_refcount == 0); + LIST_INSERT_HEAD(&vdp->activepips, pip, links); + goto found; + } else if (ret != DB_NOTFOUND) /* Something nasty happened. */ + return (ret); + + /* Case 3 */ + if ((ret = __db_vrfy_pageinfo_create(&pip)) != 0) + return (ret); + + LIST_INSERT_HEAD(&vdp->activepips, pip, links); +found: pip->pi_refcount++; + + *pipp = pip; + + DB_ASSERT(pip->pi_refcount > 0); + return (0); +} + +/* + * __db_vrfy_putpageinfo -- + * Put back a VRFY_PAGEINFO that we're done with. + * + * PUBLIC: int __db_vrfy_putpageinfo __P((VRFY_DBINFO *, VRFY_PAGEINFO *)); + */ +int +__db_vrfy_putpageinfo(vdp, pip) + VRFY_DBINFO *vdp; + VRFY_PAGEINFO *pip; +{ + DBT key, data; + DB *pgdbp; + VRFY_PAGEINFO *p; + int ret; +#ifdef DIAGNOSTIC + int found; + + found = 0; +#endif + + if (--pip->pi_refcount > 0) + return (0); + + pgdbp = vdp->pgdbp; + memset(&key, 0, sizeof(DBT)); + memset(&data, 0, sizeof(DBT)); + + key.data = &pip->pgno; + key.size = sizeof(db_pgno_t); + data.data = pip; + data.size = sizeof(VRFY_PAGEINFO); + + if ((ret = pgdbp->put(pgdbp, NULL, &key, &data, 0)) != 0) + return (ret); + + for (p = LIST_FIRST(&vdp->activepips); p != NULL; + p = LIST_NEXT(p, links)) + if (p == pip) { +#ifdef DIAGNOSTIC + found++; +#endif + DB_ASSERT(p->pi_refcount == 0); + LIST_REMOVE(p, links); + break; + } +#ifdef DIAGNOSTIC + DB_ASSERT(found == 1); +#endif + + DB_ASSERT(pip->pi_refcount == 0); + __os_free(pip, 0); + return (0); +} + +/* + * __db_vrfy_pgset -- + * Create a temporary database for the storing of sets of page numbers. + * (A mapping from page number to int, used by the *_meta2pgset functions, + * as well as for keeping track of which pages the verifier has seen.) + * + * PUBLIC: int __db_vrfy_pgset __P((DB_ENV *, u_int32_t, DB **)); + */ +int +__db_vrfy_pgset(dbenv, pgsize, dbpp) + DB_ENV *dbenv; + u_int32_t pgsize; + DB **dbpp; +{ + DB *dbp; + int ret; + + if ((ret = db_create(&dbp, dbenv, 0)) != 0) + return (ret); + if ((ret = dbp->set_pagesize(dbp, pgsize)) != 0) + goto err; + if ((ret = dbp->open(dbp, NULL, NULL, DB_BTREE, DB_CREATE, 0600)) == 0) + *dbpp = dbp; + else +err: (void)dbp->close(dbp, 0); + + return (ret); +} + +/* + * __db_vrfy_pgset_get -- + * Get the value associated in a page set with a given pgno. Return + * a 0 value (and succeed) if we've never heard of this page. + * + * PUBLIC: int __db_vrfy_pgset_get __P((DB *, db_pgno_t, int *)); + */ +int +__db_vrfy_pgset_get(dbp, pgno, valp) + DB *dbp; + db_pgno_t pgno; + int *valp; +{ + DBT key, data; + int ret, val; + + memset(&key, 0, sizeof(DBT)); + memset(&data, 0, sizeof(DBT)); + + key.data = &pgno; + key.size = sizeof(db_pgno_t); + data.data = &val; + data.ulen = sizeof(int); + F_SET(&data, DB_DBT_USERMEM); + + if ((ret = dbp->get(dbp, NULL, &key, &data, 0)) == 0) { + DB_ASSERT(data.size = sizeof(int)); + memcpy(&val, data.data, sizeof(int)); + } else if (ret == DB_NOTFOUND) + val = 0; + else + return (ret); + + *valp = val; + return (0); +} + +/* + * __db_vrfy_pgset_inc -- + * Increment the value associated with a pgno by 1. + * + * PUBLIC: int __db_vrfy_pgset_inc __P((DB *, db_pgno_t)); + */ +int +__db_vrfy_pgset_inc(dbp, pgno) + DB *dbp; + db_pgno_t pgno; +{ + + return (__db_vrfy_pgset_iinc(dbp, pgno, 1)); +} + +/* + * __db_vrfy_pgset_dec -- + * Increment the value associated with a pgno by 1. + * + * PUBLIC: int __db_vrfy_pgset_dec __P((DB *, db_pgno_t)); + */ +int +__db_vrfy_pgset_dec(dbp, pgno) + DB *dbp; + db_pgno_t pgno; +{ + + return (__db_vrfy_pgset_iinc(dbp, pgno, -1)); +} + +/* + * __db_vrfy_pgset_iinc -- + * Increment the value associated with a pgno by i. + * + */ +static int +__db_vrfy_pgset_iinc(dbp, pgno, i) + DB *dbp; + db_pgno_t pgno; + int i; +{ + DBT key, data; + int ret; + int val; + + memset(&key, 0, sizeof(DBT)); + memset(&data, 0, sizeof(DBT)); + + val = 0; + + key.data = &pgno; + key.size = sizeof(db_pgno_t); + data.data = &val; + data.ulen = sizeof(int); + F_SET(&data, DB_DBT_USERMEM); + + if ((ret = dbp->get(dbp, NULL, &key, &data, 0)) == 0) { + DB_ASSERT(data.size = sizeof(int)); + memcpy(&val, data.data, sizeof(int)); + } else if (ret != DB_NOTFOUND) + return (ret); + + data.size = sizeof(int); + val += i; + + return (dbp->put(dbp, NULL, &key, &data, 0)); +} + +/* + * __db_vrfy_pgset_next -- + * Given a cursor open in a pgset database, get the next page in the + * set. + * + * PUBLIC: int __db_vrfy_pgset_next __P((DBC *, db_pgno_t *)); + */ +int +__db_vrfy_pgset_next(dbc, pgnop) + DBC *dbc; + db_pgno_t *pgnop; +{ + DBT key, data; + db_pgno_t pgno; + int ret; + + memset(&key, 0, sizeof(DBT)); + memset(&data, 0, sizeof(DBT)); + /* We don't care about the data, just the keys. */ + F_SET(&data, DB_DBT_USERMEM | DB_DBT_PARTIAL); + F_SET(&key, DB_DBT_USERMEM); + key.data = &pgno; + key.ulen = sizeof(db_pgno_t); + + if ((ret = dbc->c_get(dbc, &key, &data, DB_NEXT)) != 0) + return (ret); + + DB_ASSERT(key.size == sizeof(db_pgno_t)); + *pgnop = pgno; + + return (0); +} + +/* + * __db_vrfy_childcursor -- + * Create a cursor to walk the child list with. Returns with a nonzero + * final argument if the specified page has no children. + * + * PUBLIC: int __db_vrfy_childcursor __P((VRFY_DBINFO *, DBC **)); + */ +int +__db_vrfy_childcursor(vdp, dbcp) + VRFY_DBINFO *vdp; + DBC **dbcp; +{ + DB *cdbp; + DBC *dbc; + int ret; + + cdbp = vdp->cdbp; + + if ((ret = cdbp->cursor(cdbp, NULL, &dbc, 0)) == 0) + *dbcp = dbc; + + return (ret); +} + +/* + * __db_vrfy_childput -- + * Add a child structure to the set for a given page. + * + * PUBLIC: int __db_vrfy_childput + * PUBLIC: __P((VRFY_DBINFO *, db_pgno_t, VRFY_CHILDINFO *)); + */ +int +__db_vrfy_childput(vdp, pgno, cip) + VRFY_DBINFO *vdp; + db_pgno_t pgno; + VRFY_CHILDINFO *cip; +{ + DBT key, data; + DB *cdbp; + int ret; + + cdbp = vdp->cdbp; + memset(&key, 0, sizeof(DBT)); + memset(&data, 0, sizeof(DBT)); + + key.data = &pgno; + key.size = sizeof(db_pgno_t); + + data.data = cip; + data.size = sizeof(VRFY_CHILDINFO); + + /* + * Don't add duplicate (data) entries for a given child, and accept + * DB_KEYEXIST as a successful return; we only need to verify + * each child once, even if a child (such as an overflow key) is + * multiply referenced. + */ + ret = cdbp->put(cdbp, NULL, &key, &data, DB_NODUPDATA); + return (ret == DB_KEYEXIST ? 0 : ret); +} + +/* + * __db_vrfy_ccset -- + * Sets a cursor created with __db_vrfy_childcursor to the first + * child of the given pgno, and returns it in the third arg. + * + * PUBLIC: int __db_vrfy_ccset __P((DBC *, db_pgno_t, VRFY_CHILDINFO **)); + */ +int +__db_vrfy_ccset(dbc, pgno, cipp) + DBC *dbc; + db_pgno_t pgno; + VRFY_CHILDINFO **cipp; +{ + DBT key, data; + int ret; + + memset(&key, 0, sizeof(DBT)); + memset(&data, 0, sizeof(DBT)); + + key.data = &pgno; + key.size = sizeof(db_pgno_t); + + if ((ret = dbc->c_get(dbc, &key, &data, DB_SET)) != 0) + return (ret); + + DB_ASSERT(data.size == sizeof(VRFY_CHILDINFO)); + *cipp = (VRFY_CHILDINFO *)data.data; + + return (0); +} + +/* + * __db_vrfy_ccnext -- + * Gets the next child of the given cursor created with + * __db_vrfy_childcursor, and returns it in the memory provided in the + * second arg. + * + * PUBLIC: int __db_vrfy_ccnext __P((DBC *, VRFY_CHILDINFO **)); + */ +int +__db_vrfy_ccnext(dbc, cipp) + DBC *dbc; + VRFY_CHILDINFO **cipp; +{ + DBT key, data; + int ret; + + memset(&key, 0, sizeof(DBT)); + memset(&data, 0, sizeof(DBT)); + + if ((ret = dbc->c_get(dbc, &key, &data, DB_NEXT_DUP)) != 0) + return (ret); + + DB_ASSERT(data.size == sizeof(VRFY_CHILDINFO)); + *cipp = (VRFY_CHILDINFO *)data.data; + + return (0); +} + +/* + * __db_vrfy_ccclose -- + * Closes the cursor created with __db_vrfy_childcursor. + * + * This doesn't actually do anything interesting now, but it's + * not inconceivable that we might change the internal database usage + * and keep the interfaces the same, and a function call here or there + * seldom hurts anyone. + * + * PUBLIC: int __db_vrfy_ccclose __P((DBC *)); + */ +int +__db_vrfy_ccclose(dbc) + DBC *dbc; +{ + + return (dbc->c_close(dbc)); +} + +/* + * __db_vrfy_pageinfo_create -- + * Constructor for VRFY_PAGEINFO; allocates and initializes. + * + * PUBLIC: int __db_vrfy_pageinfo_create __P((VRFY_PAGEINFO **)); + */ +int +__db_vrfy_pageinfo_create(pgipp) + VRFY_PAGEINFO **pgipp; +{ + VRFY_PAGEINFO *pgip; + int ret; + + if ((ret = __os_calloc(NULL, + 1, sizeof(VRFY_PAGEINFO), (void **)&pgip)) != 0) + return (ret); + + DB_ASSERT(pgip->pi_refcount == 0); + + *pgipp = pgip; + return (0); +} + +/* + * __db_salvage_init -- + * Set up salvager database. + * + * PUBLIC: int __db_salvage_init __P((VRFY_DBINFO *)); + */ +int +__db_salvage_init(vdp) + VRFY_DBINFO *vdp; +{ + DB *dbp; + int ret; + + if ((ret = db_create(&dbp, NULL, 0)) != 0) + return (ret); + + if ((ret = dbp->set_pagesize(dbp, 1024)) != 0) + goto err; + + if ((ret = dbp->open(dbp, NULL, NULL, DB_BTREE, DB_CREATE, 0)) != 0) + goto err; + + vdp->salvage_pages = dbp; + return (0); + +err: (void)dbp->close(dbp, 0); + return (ret); +} + +/* + * __db_salvage_destroy -- + * Close salvager database. + * PUBLIC: void __db_salvage_destroy __P((VRFY_DBINFO *)); + */ +void +__db_salvage_destroy(vdp) + VRFY_DBINFO *vdp; +{ + (void)vdp->salvage_pages->close(vdp->salvage_pages, 0); +} + +/* + * __db_salvage_getnext -- + * Get the next (first) unprinted page in the database of pages we need to + * print still. Delete entries for any already-printed pages we encounter + * in this search, as well as the page we're returning. + * + * PUBLIC: int __db_salvage_getnext + * PUBLIC: __P((VRFY_DBINFO *, db_pgno_t *, u_int32_t *)); + */ +int +__db_salvage_getnext(vdp, pgnop, pgtypep) + VRFY_DBINFO *vdp; + db_pgno_t *pgnop; + u_int32_t *pgtypep; +{ + DB *dbp; + DBC *dbc; + DBT key, data; + int ret; + u_int32_t pgtype; + + dbp = vdp->salvage_pages; + + memset(&key, 0, sizeof(DBT)); + memset(&data, 0, sizeof(DBT)); + + if ((ret = dbp->cursor(dbp, NULL, &dbc, 0)) != 0) + return (ret); + + while ((ret = dbc->c_get(dbc, &key, &data, DB_NEXT)) == 0) { + DB_ASSERT(data.size == sizeof(u_int32_t)); + memcpy(&pgtype, data.data, sizeof(pgtype)); + + if ((ret = dbc->c_del(dbc, 0)) != 0) + goto err; + if (pgtype != SALVAGE_IGNORE) + goto found; + } + + /* No more entries--ret probably equals DB_NOTFOUND. */ + + if (0) { +found: DB_ASSERT(key.size == sizeof(db_pgno_t)); + DB_ASSERT(data.size == sizeof(u_int32_t)); + + *pgnop = *(db_pgno_t *)key.data; + *pgtypep = *(u_int32_t *)data.data; + } + +err: (void)dbc->c_close(dbc); + return (ret); +} + +/* + * __db_salvage_isdone -- + * Return whether or not the given pgno is already marked + * SALVAGE_IGNORE (meaning that we don't need to print it again). + * + * Returns DB_KEYEXIST if it is marked, 0 if not, or another error on + * error. + * + * PUBLIC: int __db_salvage_isdone __P((VRFY_DBINFO *, db_pgno_t)); + */ +int +__db_salvage_isdone(vdp, pgno) + VRFY_DBINFO *vdp; + db_pgno_t pgno; +{ + DBT key, data; + DB *dbp; + int ret; + u_int32_t currtype; + + dbp = vdp->salvage_pages; + + memset(&key, 0, sizeof(DBT)); + memset(&data, 0, sizeof(DBT)); + + currtype = SALVAGE_INVALID; + data.data = &currtype; + data.ulen = sizeof(u_int32_t); + data.flags = DB_DBT_USERMEM; + + key.data = &pgno; + key.size = sizeof(db_pgno_t); + + /* + * Put an entry for this page, with pgno as key and type as data, + * unless it's already there and is marked done. + * If it's there and is marked anything else, that's fine--we + * want to mark it done. + */ + ret = dbp->get(dbp, NULL, &key, &data, 0); + if (ret == 0) { + /* + * The key's already here. Check and see if it's already + * marked done. If it is, return DB_KEYEXIST. If it's not, + * return 0. + */ + if (currtype == SALVAGE_IGNORE) + return (DB_KEYEXIST); + else + return (0); + } else if (ret != DB_NOTFOUND) + return (ret); + + /* The pgno is not yet marked anything; return 0. */ + return (0); +} + +/* + * __db_salvage_markdone -- + * Mark as done a given page. + * + * PUBLIC: int __db_salvage_markdone __P((VRFY_DBINFO *, db_pgno_t)); + */ +int +__db_salvage_markdone(vdp, pgno) + VRFY_DBINFO *vdp; + db_pgno_t pgno; +{ + DBT key, data; + DB *dbp; + int pgtype, ret; + u_int32_t currtype; + + pgtype = SALVAGE_IGNORE; + dbp = vdp->salvage_pages; + + memset(&key, 0, sizeof(DBT)); + memset(&data, 0, sizeof(DBT)); + + currtype = SALVAGE_INVALID; + data.data = &currtype; + data.ulen = sizeof(u_int32_t); + data.flags = DB_DBT_USERMEM; + + key.data = &pgno; + key.size = sizeof(db_pgno_t); + + /* + * Put an entry for this page, with pgno as key and type as data, + * unless it's already there and is marked done. + * If it's there and is marked anything else, that's fine--we + * want to mark it done, but db_salvage_isdone only lets + * us know if it's marked IGNORE. + * + * We don't want to return DB_KEYEXIST, though; this will + * likely get passed up all the way and make no sense to the + * application. Instead, use DB_VERIFY_BAD to indicate that + * we've seen this page already--it probably indicates a + * multiply-linked page. + */ + if ((ret = __db_salvage_isdone(vdp, pgno)) != 0) + return (ret == DB_KEYEXIST ? DB_VERIFY_BAD : ret); + + data.size = sizeof(u_int32_t); + data.data = &pgtype; + + return (dbp->put(dbp, NULL, &key, &data, 0)); +} + +/* + * __db_salvage_markneeded -- + * If it has not yet been printed, make note of the fact that a page + * must be dealt with later. + * + * PUBLIC: int __db_salvage_markneeded + * PUBLIC: __P((VRFY_DBINFO *, db_pgno_t, u_int32_t)); + */ +int +__db_salvage_markneeded(vdp, pgno, pgtype) + VRFY_DBINFO *vdp; + db_pgno_t pgno; + u_int32_t pgtype; +{ + DB *dbp; + DBT key, data; + int ret; + + dbp = vdp->salvage_pages; + + memset(&key, 0, sizeof(DBT)); + memset(&data, 0, sizeof(DBT)); + + key.data = &pgno; + key.size = sizeof(db_pgno_t); + + data.data = &pgtype; + data.size = sizeof(u_int32_t); + + /* + * Put an entry for this page, with pgno as key and type as data, + * unless it's already there, in which case it's presumably + * already been marked done. + */ + ret = dbp->put(dbp, NULL, &key, &data, DB_NOOVERWRITE); + return (ret == DB_KEYEXIST ? 0 : ret); +} diff --git a/db/db185/db185.c b/db/db185/db185.c new file mode 100644 index 000000000..843275424 --- /dev/null +++ b/db/db185/db185.c @@ -0,0 +1,593 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char copyright[] = + "Copyright (c) 1996-2000\nSleepycat Software Inc. All rights reserved.\n"; +static const char revid[] = + "$Id: db185.c,v 11.15 2001/01/23 21:27:03 bostic Exp $"; +#endif + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#endif + +#include "db_int.h" +#include "db185_int.h" + +static int db185_close __P((DB185 *)); +static int db185_compare __P((DB *, const DBT *, const DBT *)); +static int db185_del __P((const DB185 *, const DBT185 *, u_int)); +static int db185_fd __P((const DB185 *)); +static int db185_get __P((const DB185 *, const DBT185 *, DBT185 *, u_int)); +static u_int32_t + db185_hash __P((DB *, const void *, u_int32_t)); +static void db185_openstderr __P((DB_FH *)); +static size_t db185_prefix __P((DB *, const DBT *, const DBT *)); +static int db185_put __P((const DB185 *, DBT185 *, const DBT185 *, u_int)); +static int db185_seq __P((const DB185 *, DBT185 *, DBT185 *, u_int)); +static int db185_sync __P((const DB185 *, u_int)); + +DB185 * +__db185_open(file, oflags, mode, type, openinfo) + const char *file; + int oflags, mode; + DBTYPE type; + const void *openinfo; +{ + const BTREEINFO *bi; + const HASHINFO *hi; + const RECNOINFO *ri; + DB *dbp; + DB185 *db185p; + DB_FH fh; + size_t nw; + int ret; + + dbp = NULL; + db185p = NULL; + + if ((ret = db_create(&dbp, NULL, 0)) != 0) + goto err; + + if ((ret = __os_calloc(NULL, 1, sizeof(DB185), &db185p)) != 0) + goto err; + + /* + * !!! + * The DBTYPE enum wasn't initialized in DB 185, so it's off-by-one + * from DB 2.0. + */ + switch (type) { + case 0: /* DB_BTREE */ + type = DB_BTREE; + if ((bi = openinfo) != NULL) { + if (bi->flags & ~R_DUP) + goto einval; + if (bi->flags & R_DUP) + (void)dbp->set_flags(dbp, DB_DUP); + if (bi->cachesize != 0) + (void)dbp->set_cachesize + (dbp, 0, bi->cachesize, 0); + if (bi->minkeypage != 0) + (void)dbp->set_bt_minkey(dbp, bi->minkeypage); + if (bi->psize != 0) + (void)dbp->set_pagesize(dbp, bi->psize); + /* + * !!! + * Comparisons and prefix calls work because the DBT + * structures in 1.85 and 2.0 have the same initial + * fields. + */ + if (bi->prefix != NULL) { + db185p->prefix = bi->prefix; + dbp->set_bt_prefix(dbp, db185_prefix); + } + if (bi->compare != NULL) { + db185p->compare = bi->compare; + dbp->set_bt_compare(dbp, db185_compare); + } + if (bi->lorder != 0) + dbp->set_lorder(dbp, bi->lorder); + } + break; + case 1: /* DB_HASH */ + type = DB_HASH; + if ((hi = openinfo) != NULL) { + if (hi->bsize != 0) + (void)dbp->set_pagesize(dbp, hi->bsize); + if (hi->ffactor != 0) + (void)dbp->set_h_ffactor(dbp, hi->ffactor); + if (hi->nelem != 0) + (void)dbp->set_h_nelem(dbp, hi->nelem); + if (hi->cachesize != 0) + (void)dbp->set_cachesize + (dbp, 0, hi->cachesize, 0); + if (hi->hash != NULL) { + db185p->hash = hi->hash; + (void)dbp->set_h_hash(dbp, db185_hash); + } + if (hi->lorder != 0) + dbp->set_lorder(dbp, hi->lorder); + } + + break; + case 2: /* DB_RECNO */ + type = DB_RECNO; + + /* DB 1.85 did renumbering by default. */ + (void)dbp->set_flags(dbp, DB_RENUMBER); + + /* + * !!! + * The file name given to DB 1.85 recno is the name of the DB + * 2.0 backing file. If the file doesn't exist, create it if + * the user has the O_CREAT flag set, DB 1.85 did it for you, + * and DB 2.0 doesn't. + * + * !!! + * Setting the file name to NULL specifies that we're creating + * a temporary backing file, in DB 2.X. If we're opening the + * DB file read-only, change the flags to read-write, because + * temporary backing files cannot be opened read-only, and DB + * 2.X will return an error. We are cheating here -- if the + * application does a put on the database, it will succeed -- + * although that would be a stupid thing for the application + * to do. + * + * !!! + * Note, the file name in DB 1.85 was a const -- we don't do + * that in DB 2.0, so do that cast. + */ + if (file != NULL) { + if (oflags & O_CREAT && __os_exists(file, NULL) != 0) + if (__os_openhandle(NULL, file, + oflags, mode, &fh) == 0) + (void)__os_closehandle(&fh); + (void)dbp->set_re_source(dbp, file); + + if (O_RDONLY) + oflags &= ~O_RDONLY; + oflags |= O_RDWR; + file = NULL; + } + + if ((ri = openinfo) != NULL) { + /* + * !!! + * We can't support the bfname field. + */ +#define BFMSG "DB: DB 1.85's recno bfname field is not supported.\n" + if (ri->bfname != NULL) { + db185_openstderr(&fh); + (void)__os_write(NULL, &fh, + BFMSG, sizeof(BFMSG) - 1, &nw); + goto einval; + } + + if (ri->flags & ~(R_FIXEDLEN | R_NOKEY | R_SNAPSHOT)) + goto einval; + if (ri->flags & R_FIXEDLEN) { + if (ri->bval != 0) + (void)dbp->set_re_pad(dbp, ri->bval); + if (ri->reclen != 0) + (void)dbp->set_re_len(dbp, ri->reclen); + } else + if (ri->bval != 0) + (void)dbp->set_re_delim(dbp, ri->bval); + + /* + * !!! + * We ignore the R_NOKEY flag, but that's okay, it was + * only an optimization that was never implemented. + */ + if (ri->flags & R_SNAPSHOT) + (void)dbp->set_flags(dbp, DB_SNAPSHOT); + + if (ri->cachesize != 0) + (void)dbp->set_cachesize + (dbp, 0, ri->cachesize, 0); + if (ri->psize != 0) + (void)dbp->set_pagesize(dbp, ri->psize); + if (ri->lorder != 0) + dbp->set_lorder(dbp, ri->lorder); + } + break; + default: + goto einval; + } + + db185p->close = db185_close; + db185p->del = db185_del; + db185p->fd = db185_fd; + db185p->get = db185_get; + db185p->put = db185_put; + db185p->seq = db185_seq; + db185p->sync = db185_sync; + + /* + * Store a reference so we can indirect from the DB 1.85 structure + * to the underlying DB structure, and vice-versa. This has to be + * done BEFORE the DB::open method call because the hash callback + * is exercised as part of hash database initialiation. + * + * XXX + * Overload the cj_internal field for this purpose. + */ + db185p->dbp = dbp; + dbp->cj_internal = db185p; + + /* Open the database. */ + if ((ret = dbp->open(dbp, + file, NULL, type, __db_oflags(oflags), mode)) != 0) + goto err; + + /* Create the cursor used for sequential ops. */ + if ((ret = dbp->cursor(dbp, NULL, &((DB185 *)db185p)->dbc, 0)) != 0) + goto err; + + return (db185p); + +einval: ret = EINVAL; + +err: if (db185p != NULL) + __os_free(db185p, sizeof(DB185)); + if (dbp != NULL) + (void)dbp->close(dbp, 0); + + __os_set_errno(ret); + return (NULL); +} + +static int +db185_close(db185p) + DB185 *db185p; +{ + DB *dbp; + int ret; + + dbp = db185p->dbp; + + ret = dbp->close(dbp, 0); + + __os_free(db185p, sizeof(DB185)); + + if (ret == 0) + return (0); + + __os_set_errno(ret); + return (-1); +} + +static int +db185_del(db185p, key185, flags) + const DB185 *db185p; + const DBT185 *key185; + u_int flags; +{ + DB *dbp; + DBT key; + int ret; + + dbp = db185p->dbp; + + memset(&key, 0, sizeof(key)); + key.data = key185->data; + key.size = key185->size; + + if (flags & ~R_CURSOR) + goto einval; + if (flags & R_CURSOR) + ret = db185p->dbc->c_del(db185p->dbc, 0); + else + ret = dbp->del(dbp, NULL, &key, 0); + + switch (ret) { + case 0: + return (0); + case DB_NOTFOUND: + return (1); + } + + __os_set_errno(ret); + return (-1); + +einval: __os_set_errno(EINVAL); + return (-1); +} + +static int +db185_fd(db185p) + const DB185 *db185p; +{ + DB *dbp; + int fd, ret; + + dbp = db185p->dbp; + + if ((ret = dbp->fd(dbp, &fd)) == 0) + return (fd); + + __os_set_errno(ret); + return (-1); +} + +static int +db185_get(db185p, key185, data185, flags) + const DB185 *db185p; + const DBT185 *key185; + DBT185 *data185; + u_int flags; +{ + DB *dbp; + DBT key, data; + int ret; + + dbp = db185p->dbp; + + memset(&key, 0, sizeof(key)); + key.data = key185->data; + key.size = key185->size; + memset(&data, 0, sizeof(data)); + data.data = data185->data; + data.size = data185->size; + + if (flags) + goto einval; + + switch (ret = dbp->get(dbp, NULL, &key, &data, 0)) { + case 0: + data185->data = data.data; + data185->size = data.size; + return (0); + case DB_NOTFOUND: + return (1); + } + + __os_set_errno(ret); + return (-1); + +einval: __os_set_errno(EINVAL); + return (-1); +} + +static int +db185_put(db185p, key185, data185, flags) + const DB185 *db185p; + DBT185 *key185; + const DBT185 *data185; + u_int flags; +{ + DB *dbp; + DBC *dbcp_put; + DBT key, data; + int ret; + + dbp = db185p->dbp; + + memset(&key, 0, sizeof(key)); + key.data = key185->data; + key.size = key185->size; + memset(&data, 0, sizeof(data)); + data.data = data185->data; + data.size = data185->size; + + switch (flags) { + case 0: + ret = dbp->put(dbp, NULL, &key, &data, 0); + break; + case R_CURSOR: + ret = db185p->dbc->c_put(db185p->dbc, &key, &data, DB_CURRENT); + break; + case R_IAFTER: + case R_IBEFORE: + if (dbp->type != DB_RECNO) + goto einval; + + if ((ret = dbp->cursor(dbp, NULL, &dbcp_put, 0)) != 0) { + __os_set_errno(ret); + return (-1); + } + if ((ret = + dbcp_put->c_get(dbcp_put, &key, &data, DB_SET)) != 0) { + (void)dbcp_put->c_close(dbcp_put); + __os_set_errno(ret); + return (-1); + } + memset(&data, 0, sizeof(data)); + data.data = data185->data; + data.size = data185->size; + ret = dbcp_put->c_put(dbcp_put, + &key, &data, flags == R_IAFTER ? DB_AFTER : DB_BEFORE); + (void)dbcp_put->c_close(dbcp_put); + __os_set_errno(ret); + break; + case R_NOOVERWRITE: + ret = dbp->put(dbp, NULL, &key, &data, DB_NOOVERWRITE); + break; + case R_SETCURSOR: + if (dbp->type != DB_BTREE && dbp->type != DB_RECNO) + goto einval; + + if ((ret = dbp->put(dbp, NULL, &key, &data, 0)) != 0) + break; + ret = + db185p->dbc->c_get(db185p->dbc, &key, &data, DB_SET_RANGE); + break; + default: + goto einval; + } + + switch (ret) { + case 0: + key185->data = key.data; + key185->size = key.size; + return (0); + case DB_KEYEXIST: + return (1); + } + __os_set_errno(ret); + return (-1); + +einval: __os_set_errno(EINVAL); + return (-1); +} + +static int +db185_seq(db185p, key185, data185, flags) + const DB185 *db185p; + DBT185 *key185, *data185; + u_int flags; +{ + DB *dbp; + DBT key, data; + int ret; + + dbp = db185p->dbp; + + memset(&key, 0, sizeof(key)); + key.data = key185->data; + key.size = key185->size; + memset(&data, 0, sizeof(data)); + data.data = data185->data; + data.size = data185->size; + + switch (flags) { + case R_CURSOR: + flags = DB_SET_RANGE; + break; + case R_FIRST: + flags = DB_FIRST; + break; + case R_LAST: + if (dbp->type != DB_BTREE && dbp->type != DB_RECNO) + goto einval; + flags = DB_LAST; + break; + case R_NEXT: + flags = DB_NEXT; + break; + case R_PREV: + if (dbp->type != DB_BTREE && dbp->type != DB_RECNO) + goto einval; + flags = DB_PREV; + break; + default: + goto einval; + } + switch (ret = db185p->dbc->c_get(db185p->dbc, &key, &data, flags)) { + case 0: + key185->data = key.data; + key185->size = key.size; + data185->data = data.data; + data185->size = data.size; + return (0); + case DB_NOTFOUND: + return (1); + } + + __os_set_errno(ret); + return (-1); + +einval: __os_set_errno(EINVAL); + return (-1); +} + +static int +db185_sync(db185p, flags) + const DB185 *db185p; + u_int flags; +{ + DB *dbp; + DB_FH fh; + size_t nw; + int ret; + + dbp = db185p->dbp; + + switch (flags) { + case 0: + break; + case R_RECNOSYNC: + /* + * !!! + * We can't support the R_RECNOSYNC flag. + */ +#define RSMSG "DB: DB 1.85's R_RECNOSYNC sync flag is not supported.\n" + db185_openstderr(&fh); + (void)__os_write(NULL, &fh, RSMSG, sizeof(RSMSG) - 1, &nw); + goto einval; + default: + goto einval; + } + + if ((ret = dbp->sync(dbp, 0)) == 0) + return (0); + + __os_set_errno(ret); + return (-1); + +einval: __os_set_errno(EINVAL); + return (-1); +} + +static void +db185_openstderr(fhp) + DB_FH *fhp; +{ + /* Dummy up the results of an __os_openhandle() on stderr. */ + memset(fhp, 0, sizeof(*fhp)); + F_SET(fhp, DB_FH_VALID); + +#ifndef STDERR_FILENO +#define STDERR_FILENO 2 +#endif + fhp->fd = STDERR_FILENO; +} + +/* + * db185_compare -- + * Cutout routine to call the user's Btree comparison function. + */ +static int +db185_compare(dbp, a, b) + DB *dbp; + const DBT *a, *b; +{ + return (((DB185 *)dbp->cj_internal)->compare(a, b)); +} + +/* + * db185_prefix -- + * Cutout routine to call the user's Btree prefix function. + */ +static size_t +db185_prefix(dbp, a, b) + DB *dbp; + const DBT *a, *b; +{ + return (((DB185 *)dbp->cj_internal)->prefix(a, b)); +} + +/* + * db185_hash -- + * Cutout routine to call the user's hash function. + */ +static u_int32_t +db185_hash(dbp, key, len) + DB *dbp; + const void *key; + u_int32_t len; +{ + return (((DB185 *)dbp->cj_internal)->hash(key, (size_t)len)); +} diff --git a/db/db185/db185_int.h b/db/db185/db185_int.h new file mode 100644 index 000000000..172019d3f --- /dev/null +++ b/db/db185/db185_int.h @@ -0,0 +1,129 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: db185_int.h,v 11.7 2001/01/22 22:22:46 krinsky Exp $ + */ + +#ifndef _DB185_H_ +#define _DB185_H_ + +/* Routine flags. */ +#define R_CURSOR 1 /* del, put, seq */ +#define __R_UNUSED 2 /* UNUSED */ +#define R_FIRST 3 /* seq */ +#define R_IAFTER 4 /* put (RECNO) */ +#define R_IBEFORE 5 /* put (RECNO) */ +#define R_LAST 6 /* seq (BTREE, RECNO) */ +#define R_NEXT 7 /* seq */ +#define R_NOOVERWRITE 8 /* put */ +#define R_PREV 9 /* seq (BTREE, RECNO) */ +#define R_SETCURSOR 10 /* put (RECNO) */ +#define R_RECNOSYNC 11 /* sync (RECNO) */ + +typedef struct { + void *data; /* data */ + size_t size; /* data length */ +} DBT185; + +/* Access method description structure. */ +typedef struct __db185 { + DBTYPE type; /* Underlying db type. */ + int (*close) __P((struct __db185 *)); + int (*del) __P((const struct __db185 *, const DBT185 *, u_int)); + int (*get) + __P((const struct __db185 *, const DBT185 *, DBT185 *, u_int)); + int (*put) + __P((const struct __db185 *, DBT185 *, const DBT185 *, u_int)); + int (*seq) + __P((const struct __db185 *, DBT185 *, DBT185 *, u_int)); + int (*sync) __P((const struct __db185 *, u_int)); + DB *dbp; /* DB structure. Was void *internal. */ + int (*fd) __P((const struct __db185 *)); + + /* + * !!! + * The following elements added to the end of the DB 1.85 DB + * structure. + */ + DBC *dbc; /* DB cursor. */ + /* Various callback functions. */ + int (*compare) __P((const DBT *, const DBT *)); + size_t (*prefix) __P((const DBT *, const DBT *)); + u_int32_t (*hash) __P((const void *, size_t)); +} DB185; + +/* Structure used to pass parameters to the btree routines. */ +typedef struct { +#define R_DUP 0x01 /* duplicate keys */ + u_int32_t flags; + u_int32_t cachesize; /* bytes to cache */ + u_int32_t maxkeypage; /* maximum keys per page */ + u_int32_t minkeypage; /* minimum keys per page */ + u_int32_t psize; /* page size */ + int (*compare) /* comparison function */ + __P((const DBT *, const DBT *)); + size_t (*prefix) /* prefix function */ + __P((const DBT *, const DBT *)); + int lorder; /* byte order */ +} BTREEINFO; + +/* Structure used to pass parameters to the hashing routines. */ +typedef struct { + u_int32_t bsize; /* bucket size */ + u_int32_t ffactor; /* fill factor */ + u_int32_t nelem; /* number of elements */ + u_int32_t cachesize; /* bytes to cache */ + u_int32_t /* hash function */ + (*hash) __P((const void *, size_t)); + int lorder; /* byte order */ +} HASHINFO; + +/* Structure used to pass parameters to the record routines. */ +typedef struct { +#define R_FIXEDLEN 0x01 /* fixed-length records */ +#define R_NOKEY 0x02 /* key not required */ +#define R_SNAPSHOT 0x04 /* snapshot the input */ + u_int32_t flags; + u_int32_t cachesize; /* bytes to cache */ + u_int32_t psize; /* page size */ + int lorder; /* byte order */ + size_t reclen; /* record length (fixed-length records) */ + u_char bval; /* delimiting byte (variable-length records */ + char *bfname; /* btree file name */ +} RECNOINFO; +#endif /* !_DB185_H_ */ diff --git a/db/db_archive/db_archive.c b/db/db_archive/db_archive.c new file mode 100644 index 000000000..7c91e42f3 --- /dev/null +++ b/db/db_archive/db_archive.c @@ -0,0 +1,164 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char copyright[] = + "Copyright (c) 1996-2000\nSleepycat Software Inc. All rights reserved.\n"; +static const char revid[] = + "$Id: db_archive.c,v 11.18 2001/01/18 18:36:56 bostic Exp $"; +#endif + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#endif + +#include "db_int.h" +#include "common_ext.h" + +int main __P((int, char *[])); +void usage __P((void)); +void version_check __P((void)); + +DB_ENV *dbenv; +const char + *progname = "db_archive"; /* Program name. */ + +int +main(argc, argv) + int argc; + char *argv[]; +{ + extern char *optarg; + extern int optind; + u_int32_t flags; + int ch, e_close, exitval, ret, verbose; + char **file, *home, **list; + + version_check(); + + flags = 0; + e_close = exitval = verbose = 0; + home = NULL; + while ((ch = getopt(argc, argv, "ah:lsVv")) != EOF) + switch (ch) { + case 'a': + LF_SET(DB_ARCH_ABS); + break; + case 'h': + home = optarg; + break; + case 'l': + LF_SET(DB_ARCH_LOG); + break; + case 's': + LF_SET(DB_ARCH_DATA); + break; + case 'V': + printf("%s\n", db_version(NULL, NULL, NULL)); + exit(0); + case 'v': + verbose = 1; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (argc != 0) + usage(); + + /* Handle possible interruptions. */ + __db_util_siginit(); + + /* + * Create an environment object and initialize it for error + * reporting. + */ + if ((ret = db_env_create(&dbenv, 0)) != 0) { + fprintf(stderr, + "%s: db_env_create: %s\n", progname, db_strerror(ret)); + goto shutdown; + } + e_close = 1; + + dbenv->set_errfile(dbenv, stderr); + dbenv->set_errpfx(dbenv, progname); + + if (verbose) + (void)dbenv->set_verbose(dbenv, DB_VERB_CHKPOINT, 1); + + /* + * If attaching to a pre-existing environment fails, create a + * private one and try again. + */ + if ((ret = dbenv->open(dbenv, + home, DB_JOINENV | DB_USE_ENVIRON, 0)) != 0 && + (ret = dbenv->open(dbenv, home, DB_CREATE | + DB_INIT_LOG | DB_INIT_TXN | DB_PRIVATE | DB_USE_ENVIRON, 0)) != 0) { + dbenv->err(dbenv, ret, "open"); + goto shutdown; + } + + /* Get the list of names. */ + if ((ret = log_archive(dbenv, &list, flags, NULL)) != 0) { + dbenv->err(dbenv, ret, "log_archive"); + goto shutdown; + } + + /* Print the list of names. */ + if (list != NULL) { + for (file = list; *file != NULL; ++file) + printf("%s\n", *file); + __os_free(list, 0); + } + + if (0) { +shutdown: exitval = 1; + } + if (e_close && (ret = dbenv->close(dbenv, 0)) != 0) { + exitval = 1; + fprintf(stderr, + "%s: dbenv->close: %s\n", progname, db_strerror(ret)); + } + + /* Resend any caught signal. */ + __db_util_sigresend(); + + return (exitval); +} + +void +usage() +{ + (void)fprintf(stderr, "usage: db_archive [-alsVv] [-h home]\n"); + exit (1); +} + +void +version_check() +{ + int v_major, v_minor, v_patch; + + /* Make sure we're loaded with the right version of the DB library. */ + (void)db_version(&v_major, &v_minor, &v_patch); + if (v_major != DB_VERSION_MAJOR || + v_minor != DB_VERSION_MINOR || v_patch != DB_VERSION_PATCH) { + fprintf(stderr, + "%s: version %d.%d.%d doesn't match library version %d.%d.%d\n", + progname, DB_VERSION_MAJOR, DB_VERSION_MINOR, + DB_VERSION_PATCH, v_major, v_minor, v_patch); + exit (1); + } +} diff --git a/db/db_checkpoint/db_checkpoint.c b/db/db_checkpoint/db_checkpoint.c new file mode 100644 index 000000000..c7d16e023 --- /dev/null +++ b/db/db_checkpoint/db_checkpoint.c @@ -0,0 +1,237 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char copyright[] = + "Copyright (c) 1996-2000\nSleepycat Software Inc. All rights reserved.\n"; +static const char revid[] = + "$Id: db_checkpoint.c,v 11.25 2001/01/18 18:36:57 bostic Exp $"; +#endif + +#ifndef NO_SYSTEM_INCLUDES +#include + +#if TIME_WITH_SYS_TIME +#include +#include +#else +#if HAVE_SYS_TIME_H +#include +#else +#include +#endif +#endif + +#include +#include +#include +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "btree.h" +#include "hash.h" +#include "qam.h" +#include "common_ext.h" +#include "clib_ext.h" + +char *check __P((DB_ENV *, long, long)); +int main __P((int, char *[])); +void usage __P((void)); +void version_check __P((void)); + +DB_ENV *dbenv; +const char + *progname = "db_checkpoint"; /* Program name. */ + +int +main(argc, argv) + int argc; + char *argv[]; +{ + extern char *optarg; + extern int optind; + time_t now; + long argval; + u_int32_t flags, kbytes, minutes, seconds; + int ch, e_close, exitval, once, ret, verbose; + char *home, *logfile; + + version_check(); + + /* + * !!! + * Don't allow a fully unsigned 32-bit number, some compilers get + * upset and require it to be specified in hexadecimal and so on. + */ +#define MAX_UINT32_T 2147483647 + + kbytes = minutes = 0; + e_close = exitval = once = verbose = 0; + flags = 0; + home = logfile = NULL; + while ((ch = getopt(argc, argv, "1h:k:L:p:Vv")) != EOF) + switch (ch) { + case '1': + once = 1; + flags = DB_FORCE; + break; + case 'h': + home = optarg; + break; + case 'k': + (void)__db_getlong(NULL, progname, + optarg, 1, (long)MAX_UINT32_T, &argval); + kbytes = argval; + break; + case 'L': + logfile = optarg; + break; + case 'p': + (void)__db_getlong(NULL, progname, + optarg, 1, (long)MAX_UINT32_T, &argval); + minutes = argval; + break; + case 'V': + printf("%s\n", db_version(NULL, NULL, NULL)); + exit(0); + case 'v': + verbose = 1; + break; + case '?': + default: + usage(); + goto shutdown; + } + argc -= optind; + argv += optind; + + if (argc != 0) + usage(); + + if (once == 0 && kbytes == 0 && minutes == 0) { + (void)fprintf(stderr, + "%s: at least one of -1, -k and -p must be specified\n", + progname); + exit (1); + } + + /* Handle possible interruptions. */ + __db_util_siginit(); + + /* Log our process ID. */ + if (logfile != NULL && __db_util_logset(progname, logfile)) + goto shutdown; + + /* + * Create an environment object and initialize it for error + * reporting. + */ + if ((ret = db_env_create(&dbenv, 0)) != 0) { + fprintf(stderr, + "%s: db_env_create: %s\n", progname, db_strerror(ret)); + goto shutdown; + } + e_close = 1; + + dbenv->set_errfile(dbenv, stderr); + dbenv->set_errpfx(dbenv, progname); + + /* Initialize the environment. */ + if ((ret = dbenv->open(dbenv, + home, DB_JOINENV | DB_USE_ENVIRON, 0)) != 0) { + dbenv->err(dbenv, ret, "open"); + goto shutdown; + } + + /* Register the standard pgin/pgout functions, in case we do I/O. */ + if ((ret = + memp_register(dbenv, DB_FTYPE_SET, __db_pgin, __db_pgout)) != 0) { + dbenv->err(dbenv, ret, + "failed to register access method functions"); + goto shutdown; + } + + /* + * If we have only a time delay, then we'll sleep the right amount + * to wake up when a checkpoint is necessary. If we have a "kbytes" + * field set, then we'll check every 30 seconds. + */ + seconds = kbytes != 0 ? 30 : minutes * 60; + while (!__db_util_interrupted()) { + if (verbose) { + (void)time(&now); + dbenv->errx(dbenv, "checkpoint: %s", ctime(&now)); + } + + ret = txn_checkpoint(dbenv, kbytes, minutes, flags); + while (ret == DB_INCOMPLETE) { + if (verbose) + dbenv->errx(dbenv, + "checkpoint did not finish, retrying\n"); + (void)__os_sleep(dbenv, 2, 0); + ret = txn_checkpoint(dbenv, 0, 0, flags); + } + if (ret != 0) { + dbenv->err(dbenv, ret, "txn_checkpoint"); + goto shutdown; + } + + if (once) + break; + + (void)__os_sleep(dbenv, seconds, 0); + } + + if (0) { +shutdown: exitval = 1; + } + + /* Clean up the logfile. */ + if (logfile != NULL) + remove(logfile); + + /* Clean up the environment. */ + if (e_close && (ret = dbenv->close(dbenv, 0)) != 0) { + exitval = 1; + fprintf(stderr, + "%s: dbenv->close: %s\n", progname, db_strerror(ret)); + } + + /* Resend any caught signal. */ + __db_util_sigresend(); + + return (exitval); +} + +void +usage() +{ + (void)fprintf(stderr, + "usage: db_checkpoint [-1Vv] [-h home] [-k kbytes] [-L file] [-p min]\n"); + exit(1); +} + +void +version_check() +{ + int v_major, v_minor, v_patch; + + /* Make sure we're loaded with the right version of the DB library. */ + (void)db_version(&v_major, &v_minor, &v_patch); + if (v_major != DB_VERSION_MAJOR || + v_minor != DB_VERSION_MINOR || v_patch != DB_VERSION_PATCH) { + fprintf(stderr, + "%s: version %d.%d.%d doesn't match library version %d.%d.%d\n", + progname, DB_VERSION_MAJOR, DB_VERSION_MINOR, + DB_VERSION_PATCH, v_major, v_minor, v_patch); + exit (1); + } +} diff --git a/db/db_deadlock/db_deadlock.c b/db/db_deadlock/db_deadlock.c new file mode 100644 index 000000000..ac151db12 --- /dev/null +++ b/db/db_deadlock/db_deadlock.c @@ -0,0 +1,222 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char copyright[] = + "Copyright (c) 1996-2000\nSleepycat Software Inc. All rights reserved.\n"; +static const char revid[] = + "$Id: db_deadlock.c,v 11.19 2001/01/18 18:36:57 bostic Exp $"; +#endif + +#ifndef NO_SYSTEM_INCLUDES +#include + +#if TIME_WITH_SYS_TIME +#include +#include +#else +#if HAVE_SYS_TIME_H +#include +#else +#include +#endif +#endif + +#include +#include +#include +#include +#endif + +#include "db_int.h" +#include "clib_ext.h" + +int main __P((int, char *[])); +void usage __P((void)); +void version_check __P((void)); + +DB_ENV *dbenv; +const char + *progname = "db_deadlock"; /* Program name. */ + +int +main(argc, argv) + int argc; + char *argv[]; +{ + extern char *optarg; + extern int optind; + u_int32_t atype; + time_t now; + long usecs; + u_int32_t flags; + int ch, e_close, exitval, ret, verbose; + char *home, *logfile; + + version_check(); + + atype = DB_LOCK_DEFAULT; + home = logfile = NULL; + usecs = 0; + flags = 0; + e_close = exitval = verbose = 0; + while ((ch = getopt(argc, argv, "a:h:L:t:Vvw")) != EOF) + switch (ch) { + case 'a': + switch (optarg[0]) { + case 'o': + atype = DB_LOCK_OLDEST; + break; + case 'y': + atype = DB_LOCK_YOUNGEST; + break; + default: + usage(); + /* NOTREACHED */ + } + if (optarg[1] != '\0') + usage(); + break; + case 'h': + home = optarg; + break; + case 'L': + logfile = optarg; + break; + case 't': + (void)__db_getlong(NULL, + progname, optarg, 1, LONG_MAX, &usecs); + usecs *= 1000000; + break; + case 'V': + printf("%s\n", db_version(NULL, NULL, NULL)); + exit(0); + case 'v': + verbose = 1; + break; + case 'w': + LF_SET(DB_LOCK_CONFLICT); + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (argc != 0) + usage(); + + if (usecs == 0 && !LF_ISSET(DB_LOCK_CONFLICT)) { + fprintf(stderr, + "%s: at least one of -t and -w must be specified\n", + progname); + exit(1); + } + + /* + * We detect every 100ms (100000 us) when we're running in + * DB_LOCK_CONFLICT mode. + */ + if (usecs == 0) + usecs = 100000; + + /* Handle possible interruptions. */ + __db_util_siginit(); + + /* Log our process ID. */ + if (logfile != NULL && __db_util_logset(progname, logfile)) + goto shutdown; + + /* + * Create an environment object and initialize it for error + * reporting. + */ + if ((ret = db_env_create(&dbenv, 0)) != 0) { + fprintf(stderr, + "%s: db_env_create: %s\n", progname, db_strerror(ret)); + goto shutdown; + } + e_close = 1; + + dbenv->set_errfile(dbenv, stderr); + dbenv->set_errpfx(dbenv, progname); + + if (verbose) { + (void)dbenv->set_verbose(dbenv, DB_VERB_DEADLOCK, 1); + (void)dbenv->set_verbose(dbenv, DB_VERB_WAITSFOR, 1); + } + + /* An environment is required. */ + if ((ret = dbenv->open(dbenv, home, + DB_JOINENV | DB_USE_ENVIRON, 0)) != 0) { + dbenv->err(dbenv, ret, "open"); + goto shutdown; + } + + while (!__db_util_interrupted()) { + if (verbose) { + (void)time(&now); + dbenv->errx(dbenv, "running at %.24s", ctime(&now)); + } + + if ((ret = lock_detect(dbenv, flags, atype, NULL)) != 0) { + dbenv->err(dbenv, ret, "lock_detect"); + goto shutdown; + } + + /* Make a pass every "usecs" usecs. */ + (void)__os_sleep(dbenv, 0, usecs); + } + + if (0) { +shutdown: exitval = 1; + } + + /* Clean up the logfile. */ + if (logfile != NULL) + remove(logfile); + + /* Clean up the environment. */ + if (e_close && (ret = dbenv->close(dbenv, 0)) != 0) { + exitval = 1; + fprintf(stderr, + "%s: dbenv->close: %s\n", progname, db_strerror(ret)); + } + + /* Resend any caught signal. */ + __db_util_sigresend(); + + return (exitval); +} + +void +usage() +{ + (void)fprintf(stderr, + "usage: db_deadlock [-Vvw] [-a o | y] [-h home] [-L file] [-t sec]\n"); + exit(1); +} + +void +version_check() +{ + int v_major, v_minor, v_patch; + + /* Make sure we're loaded with the right version of the DB library. */ + (void)db_version(&v_major, &v_minor, &v_patch); + if (v_major != DB_VERSION_MAJOR || + v_minor != DB_VERSION_MINOR || v_patch != DB_VERSION_PATCH) { + fprintf(stderr, + "%s: version %d.%d.%d doesn't match library version %d.%d.%d\n", + progname, DB_VERSION_MAJOR, DB_VERSION_MINOR, + DB_VERSION_PATCH, v_major, v_minor, v_patch); + exit (1); + } +} diff --git a/db/db_dump/db_dump.c b/db/db_dump/db_dump.c new file mode 100644 index 000000000..ba24dd6cc --- /dev/null +++ b/db/db_dump/db_dump.c @@ -0,0 +1,517 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char copyright[] = + "Copyright (c) 1996-2000\nSleepycat Software Inc. All rights reserved.\n"; +static const char revid[] = + "$Id: db_dump.c,v 11.41 2001/01/18 18:36:57 bostic Exp $"; +#endif + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_shash.h" +#include "btree.h" +#include "hash.h" +#include "lock.h" + +void configure __P((char *)); +int db_init __P((char *)); +int dump __P((DB *, int, int)); +int dump_sub __P((DB *, char *, int, int)); +int is_sub __P((DB *, int *)); +int main __P((int, char *[])); +int show_subs __P((DB *)); +void usage __P((void)); +void version_check __P((void)); + +DB_ENV *dbenv; +const char + *progname = "db_dump"; /* Program name. */ + +int +main(argc, argv) + int argc; + char *argv[]; +{ + extern char *optarg; + extern int optind; + DB *dbp; + int ch, d_close; + int e_close, exitval; + int lflag, nflag, pflag, ret, rflag, Rflag, subs, keyflag; + char *dopt, *home, *subname; + + version_check(); + + dbp = NULL; + d_close = e_close = exitval = lflag = nflag = pflag = rflag = Rflag = 0; + keyflag = 0; + dopt = home = subname = NULL; + while ((ch = getopt(argc, argv, "d:f:h:klNprRs:V")) != EOF) + switch (ch) { + case 'd': + dopt = optarg; + break; + case 'f': + if (freopen(optarg, "w", stdout) == NULL) { + fprintf(stderr, "%s: %s: reopen: %s\n", + progname, optarg, strerror(errno)); + exit (1); + } + break; + case 'h': + home = optarg; + break; + case 'k': + keyflag = 1; + break; + case 'l': + lflag = 1; + break; + case 'N': + nflag = 1; + if ((ret = db_env_set_panicstate(0)) != 0) { + fprintf(stderr, + "%s: db_env_set_panicstate: %s\n", + progname, db_strerror(ret)); + return (1); + } + break; + case 'p': + pflag = 1; + break; + case 's': + subname = optarg; + break; + case 'R': + Rflag = 1; + /* DB_AGGRESSIVE requires DB_SALVAGE */ + /* FALLTHROUGH */ + case 'r': + rflag = 1; + break; + case 'V': + printf("%s\n", db_version(NULL, NULL, NULL)); + exit(0); + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (argc != 1) + usage(); + + if (dopt != NULL && pflag) { + fprintf(stderr, + "%s: the -d and -p options may not both be specified\n", + progname); + exit (1); + } + if (lflag && subname != NULL) { + fprintf(stderr, + "%s: the -l and -s options may not both be specified\n", + progname); + exit (1); + } + + if (keyflag && rflag) { + fprintf(stderr, "%s: %s", + "the -k and -r or -R options may not both be specified\n", + progname); + exit(1); + } + + if (subname != NULL && rflag) { + fprintf(stderr, "%s: %s", + "the -s and -r or R options may not both be specified\n", + progname); + exit(1); + } + + /* Handle possible interruptions. */ + __db_util_siginit(); + + /* + * Create an environment object and initialize it for error + * reporting. + */ + if ((ret = db_env_create(&dbenv, 0)) != 0) { + fprintf(stderr, + "%s: db_env_create: %s\n", progname, db_strerror(ret)); + goto err; + } + e_close = 1; + + dbenv->set_errfile(dbenv, stderr); + dbenv->set_errpfx(dbenv, progname); + + if (nflag && (ret = dbenv->set_mutexlocks(dbenv, 0)) != 0) { + dbenv->err(dbenv, ret, "set_mutexlocks"); + goto err; + } + + /* Initialize the environment. */ + if (db_init(home) != 0) + goto err; + + /* Create the DB object and open the file. */ + if ((ret = db_create(&dbp, dbenv, 0)) != 0) { + dbenv->err(dbenv, ret, "db_create"); + goto err; + } + d_close = 1; + + /* + * If we're salvaging, don't do an open; it might not be safe. + * Dispatch now into the salvager. + */ + if (rflag) { + if ((ret = dbp->verify(dbp, argv[0], NULL, stdout, + DB_SALVAGE | (Rflag ? DB_AGGRESSIVE : 0))) != 0) + goto err; + exitval = 0; + goto done; + } + + if ((ret = dbp->open(dbp, + argv[0], subname, DB_UNKNOWN, DB_RDONLY, 0)) != 0) { + dbp->err(dbp, ret, "open: %s", argv[0]); + goto err; + } + + if (dopt != NULL) { + if (__db_dump(dbp, dopt, NULL)) { + dbp->err(dbp, ret, "__db_dump: %s", argv[0]); + goto err; + } + } else if (lflag) { + if (is_sub(dbp, &subs)) + goto err; + if (subs == 0) { + dbp->errx(dbp, + "%s: does not contain multiple databases", argv[0]); + goto err; + } + if (show_subs(dbp)) + goto err; + } else { + subs = 0; + if (subname == NULL && is_sub(dbp, &subs)) + goto err; + if (subs) { + if (dump_sub(dbp, argv[0], pflag, keyflag)) + goto err; + } else + if (__db_prheader(dbp, NULL, pflag, keyflag, stdout, + __db_verify_callback, NULL, 0) || + dump(dbp, pflag, keyflag)) + goto err; + } + + if (0) { +err: exitval = 1; + } +done: if (d_close && (ret = dbp->close(dbp, 0)) != 0) { + exitval = 1; + dbp->err(dbp, ret, "close"); + } + if (e_close && (ret = dbenv->close(dbenv, 0)) != 0) { + exitval = 1; + fprintf(stderr, + "%s: dbenv->close: %s\n", progname, db_strerror(ret)); + } + + /* Resend any caught signal. */ + __db_util_sigresend(); + + return (exitval); +} + +/* + * db_init -- + * Initialize the environment. + */ +int +db_init(home) + char *home; +{ + int ret; + + /* + * Try and use the underlying environment when opening a database. We + * wish to use the buffer pool so our information is as up-to-date as + * possible, even if the mpool cache hasn't been flushed; we wish to + * use the locking system, if present, so that we are safe to use with + * transactions. (We don't need to use transactions explicitly, as + * we're read-only.) + * + * Note that in CDB, too, this will configure our environment + * appropriately, and our cursors will (correctly) do locking as CDB + * read cursors. + */ + if (dbenv->open(dbenv, home, DB_JOINENV | DB_USE_ENVIRON, 0) == 0) + return (0); + + /* + * An environment is required because we may be trying to look at + * databases in directories other than the current one. We could + * avoid using an environment iff the -h option wasn't specified, + * but that seems like more work than it's worth. + * + * No environment exists (or, at least no environment that includes + * an mpool region exists). Create one, but make it private so that + * no files are actually created. + */ + if ((ret = dbenv->open(dbenv, home, + DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE | DB_USE_ENVIRON, 0)) == 0) + return (0); + + /* An environment is required. */ + dbenv->err(dbenv, ret, "open"); + return (1); +} + +/* + * is_sub -- + * Return if the database contains subdatabases. + */ +int +is_sub(dbp, yesno) + DB *dbp; + int *yesno; +{ + DB_BTREE_STAT *btsp; + DB_HASH_STAT *hsp; + int ret; + + switch (dbp->type) { + case DB_BTREE: + case DB_RECNO: + if ((ret = dbp->stat(dbp, &btsp, NULL, 0)) != 0) { + dbp->err(dbp, ret, "DB->stat"); + return (ret); + } + *yesno = btsp->bt_metaflags & BTM_SUBDB ? 1 : 0; + break; + case DB_HASH: + if ((ret = dbp->stat(dbp, &hsp, NULL, 0)) != 0) { + dbp->err(dbp, ret, "DB->stat"); + return (ret); + } + *yesno = hsp->hash_metaflags & DB_HASH_SUBDB ? 1 : 0; + break; + case DB_QUEUE: + break; + default: + dbp->errx(dbp, "unknown database type"); + return (1); + } + return (0); +} + +/* + * dump_sub -- + * Dump out the records for a DB containing subdatabases. + */ +int +dump_sub(parent_dbp, parent_name, pflag, keyflag) + DB *parent_dbp; + char *parent_name; + int pflag, keyflag; +{ + DB *dbp; + DBC *dbcp; + DBT key, data; + int ret; + char *subdb; + + /* + * Get a cursor and step through the database, dumping out each + * subdatabase. + */ + if ((ret = parent_dbp->cursor(parent_dbp, NULL, &dbcp, 0)) != 0) { + dbenv->err(dbenv, ret, "DB->cursor"); + return (1); + } + + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + while ((ret = dbcp->c_get(dbcp, &key, &data, DB_NEXT)) == 0) { + /* Nul terminate the subdatabase name. */ + if ((subdb = malloc(key.size + 1)) == NULL) { + dbenv->err(dbenv, ENOMEM, NULL); + return (1); + } + memcpy(subdb, key.data, key.size); + subdb[key.size] = '\0'; + + /* Create the DB object and open the file. */ + if ((ret = db_create(&dbp, dbenv, 0)) != 0) { + dbenv->err(dbenv, ret, "db_create"); + free(subdb); + return (1); + } + if ((ret = dbp->open(dbp, + parent_name, subdb, DB_UNKNOWN, DB_RDONLY, 0)) != 0) + dbp->err(dbp, ret, + "DB->open: %s:%s", parent_name, subdb); + if (ret == 0 && + (__db_prheader(dbp, subdb, pflag, keyflag, stdout, + __db_verify_callback, NULL, 0) || + dump(dbp, pflag, keyflag))) + ret = 1; + (void)dbp->close(dbp, 0); + free(subdb); + if (ret != 0) + return (1); + } + if (ret != DB_NOTFOUND) { + dbp->err(dbp, ret, "DBcursor->get"); + return (1); + } + + if ((ret = dbcp->c_close(dbcp)) != 0) { + dbp->err(dbp, ret, "DBcursor->close"); + return (1); + } + + return (0); +} + +/* + * show_subs -- + * Display the subdatabases for a database. + */ +int +show_subs(dbp) + DB *dbp; +{ + DBC *dbcp; + DBT key, data; + int ret; + + /* + * Get a cursor and step through the database, printing out the key + * of each key/data pair. + */ + if ((ret = dbp->cursor(dbp, NULL, &dbcp, 0)) != 0) { + dbp->err(dbp, ret, "DB->cursor"); + return (1); + } + + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + while ((ret = dbcp->c_get(dbcp, &key, &data, DB_NEXT)) == 0) { + if ((ret = __db_prdbt(&key, 1, NULL, stdout, + __db_verify_callback, 0, NULL)) != 0) { + dbp->errx(dbp, NULL); + return (1); + } + } + if (ret != DB_NOTFOUND) { + dbp->err(dbp, ret, "DBcursor->get"); + return (1); + } + + if ((ret = dbcp->c_close(dbcp)) != 0) { + dbp->err(dbp, ret, "DBcursor->close"); + return (1); + } + return (0); +} + +/* + * dump -- + * Dump out the records for a DB. + */ +int +dump(dbp, pflag, keyflag) + DB *dbp; + int pflag, keyflag; +{ + DBC *dbcp; + DBT key, data; + int ret, is_recno; + + /* + * Get a cursor and step through the database, printing out each + * key/data pair. + */ + if ((ret = dbp->cursor(dbp, NULL, &dbcp, 0)) != 0) { + dbp->err(dbp, ret, "DB->cursor"); + return (1); + } + + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + is_recno = (dbp->type == DB_RECNO || dbp->type == DB_QUEUE); + keyflag = is_recno ? keyflag : 1; + while ((ret = dbcp->c_get(dbcp, &key, &data, DB_NEXT)) == 0) + if ((keyflag && (ret = __db_prdbt(&key, + pflag, " ", stdout, __db_verify_callback, + is_recno, NULL)) != 0) || (ret = + __db_prdbt(&data, pflag, " ", stdout, + __db_verify_callback, 0, NULL)) != 0) { + dbp->errx(dbp, NULL); + return (1); + } + if (ret != DB_NOTFOUND) { + dbp->err(dbp, ret, "DBcursor->get"); + return (1); + } + + if ((ret = dbcp->c_close(dbcp)) != 0) { + dbp->err(dbp, ret, "DBcursor->close"); + return (1); + } + + (void)__db_prfooter(stdout, __db_verify_callback); + return (0); +} + +/* + * usage -- + * Display the usage message. + */ +void +usage() +{ + (void)fprintf(stderr, "usage: %s\n", +"db_dump [-klNprRV] [-d ahr] [-f output] [-h home] [-s database] db_file"); + exit(1); +} + +void +version_check() +{ + int v_major, v_minor, v_patch; + + /* Make sure we're loaded with the right version of the DB library. */ + (void)db_version(&v_major, &v_minor, &v_patch); + if (v_major != DB_VERSION_MAJOR || + v_minor != DB_VERSION_MINOR || v_patch != DB_VERSION_PATCH) { + fprintf(stderr, + "%s: version %d.%d.%d doesn't match library version %d.%d.%d\n", + progname, DB_VERSION_MAJOR, DB_VERSION_MINOR, + DB_VERSION_PATCH, v_major, v_minor, v_patch); + exit (1); + } +} diff --git a/db/db_dump185/db_dump185.c b/db/db_dump185/db_dump185.c new file mode 100644 index 000000000..4b57fffd2 --- /dev/null +++ b/db/db_dump185/db_dump185.c @@ -0,0 +1,353 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#ifndef lint +static char copyright[] = + "Copyright (c) 1996-2000\nSleepycat Software Inc. All rights reserved.\n"; +static char revid[] = + "$Id: db_dump185.c,v 11.8 2001/01/10 17:26:21 bostic Exp $"; +#endif + +#include + +#include +#include +#include +#include +#include +#include + +#include + +/* Hash Table Information */ +typedef struct hashhdr185 { /* Disk resident portion */ + int magic; /* Magic NO for hash tables */ + int version; /* Version ID */ + u_int32_t lorder; /* Byte Order */ + int bsize; /* Bucket/Page Size */ + int bshift; /* Bucket shift */ + int dsize; /* Directory Size */ + int ssize; /* Segment Size */ + int sshift; /* Segment shift */ + int ovfl_point; /* Where overflow pages are being + * allocated */ + int last_freed; /* Last overflow page freed */ + int max_bucket; /* ID of Maximum bucket in use */ + int high_mask; /* Mask to modulo into entire table */ + int low_mask; /* Mask to modulo into lower half of + * table */ + int ffactor; /* Fill factor */ + int nkeys; /* Number of keys in hash table */ +} HASHHDR185; +typedef struct htab185 { /* Memory resident data structure */ + HASHHDR185 hdr; /* Header */ +} HTAB185; + +/* Hash Table Information */ +typedef struct hashhdr186 { /* Disk resident portion */ + int32_t magic; /* Magic NO for hash tables */ + int32_t version; /* Version ID */ + int32_t lorder; /* Byte Order */ + int32_t bsize; /* Bucket/Page Size */ + int32_t bshift; /* Bucket shift */ + int32_t ovfl_point; /* Where overflow pages are being allocated */ + int32_t last_freed; /* Last overflow page freed */ + int32_t max_bucket; /* ID of Maximum bucket in use */ + int32_t high_mask; /* Mask to modulo into entire table */ + int32_t low_mask; /* Mask to modulo into lower half of table */ + int32_t ffactor; /* Fill factor */ + int32_t nkeys; /* Number of keys in hash table */ + int32_t hdrpages; /* Size of table header */ + int32_t h_charkey; /* value of hash(CHARKEY) */ +#define NCACHED 32 /* number of bit maps and spare points */ + int32_t spares[NCACHED];/* spare pages for overflow */ + u_int16_t bitmaps[NCACHED]; /* address of overflow page bitmaps */ +} HASHHDR186; +typedef struct htab186 { /* Memory resident data structure */ + HASHHDR186 hdr; /* Header */ +} HTAB186; + +typedef struct _epgno { + u_int32_t pgno; /* the page number */ + u_int16_t index; /* the index on the page */ +} EPGNO; + +typedef struct _epg { + void *page; /* the (pinned) page */ + u_int16_t index; /* the index on the page */ +} EPG; + +typedef struct _cursor { + EPGNO pg; /* B: Saved tree reference. */ + DBT key; /* B: Saved key, or key.data == NULL. */ + u_int32_t rcursor; /* R: recno cursor (1-based) */ + +#define CURS_ACQUIRE 0x01 /* B: Cursor needs to be reacquired. */ +#define CURS_AFTER 0x02 /* B: Unreturned cursor after key. */ +#define CURS_BEFORE 0x04 /* B: Unreturned cursor before key. */ +#define CURS_INIT 0x08 /* RB: Cursor initialized. */ + u_int8_t flags; +} CURSOR; + +/* The in-memory btree/recno data structure. */ +typedef struct _btree { + void *bt_mp; /* memory pool cookie */ + + void *bt_dbp; /* pointer to enclosing DB */ + + EPG bt_cur; /* current (pinned) page */ + void *bt_pinned; /* page pinned across calls */ + + CURSOR bt_cursor; /* cursor */ + + EPGNO bt_stack[50]; /* stack of parent pages */ + EPGNO *bt_sp; /* current stack pointer */ + + DBT bt_rkey; /* returned key */ + DBT bt_rdata; /* returned data */ + + int bt_fd; /* tree file descriptor */ + + u_int32_t bt_free; /* next free page */ + u_int32_t bt_psize; /* page size */ + u_int16_t bt_ovflsize; /* cut-off for key/data overflow */ + int bt_lorder; /* byte order */ + /* sorted order */ + enum { NOT, BACK, FORWARD } bt_order; + EPGNO bt_last; /* last insert */ + + /* B: key comparison function */ + int (*bt_cmp) __P((DBT *, DBT *)); + /* B: prefix comparison function */ + size_t (*bt_pfx) __P((DBT *, DBT *)); + /* R: recno input function */ + int (*bt_irec) __P((struct _btree *, u_int32_t)); + + FILE *bt_rfp; /* R: record FILE pointer */ + int bt_rfd; /* R: record file descriptor */ + + void *bt_cmap; /* R: current point in mapped space */ + void *bt_smap; /* R: start of mapped space */ + void *bt_emap; /* R: end of mapped space */ + size_t bt_msize; /* R: size of mapped region. */ + + u_int32_t bt_nrecs; /* R: number of records */ + size_t bt_reclen; /* R: fixed record length */ + u_char bt_bval; /* R: delimiting byte/pad character */ + +/* + * NB: + * B_NODUPS and R_RECNO are stored on disk, and may not be changed. + */ +#define B_INMEM 0x00001 /* in-memory tree */ +#define B_METADIRTY 0x00002 /* need to write metadata */ +#define B_MODIFIED 0x00004 /* tree modified */ +#define B_NEEDSWAP 0x00008 /* if byte order requires swapping */ +#define B_RDONLY 0x00010 /* read-only tree */ + +#define B_NODUPS 0x00020 /* no duplicate keys permitted */ +#define R_RECNO 0x00080 /* record oriented tree */ + +#define R_CLOSEFP 0x00040 /* opened a file pointer */ +#define R_EOF 0x00100 /* end of input file reached. */ +#define R_FIXLEN 0x00200 /* fixed length records */ +#define R_MEMMAPPED 0x00400 /* memory mapped file. */ +#define R_INMEM 0x00800 /* in-memory file */ +#define R_MODIFIED 0x01000 /* modified file */ +#define R_RDONLY 0x02000 /* read-only file */ + +#define B_DB_LOCK 0x04000 /* DB_LOCK specified. */ +#define B_DB_SHMEM 0x08000 /* DB_SHMEM specified. */ +#define B_DB_TXN 0x10000 /* DB_TXN specified. */ + u_int32_t flags; +} BTREE; + +void db_btree __P((DB *, int)); +void db_hash __P((DB *, int)); +void dbt_dump __P((DBT *)); +void dbt_print __P((DBT *)); +int main __P((int, char *[])); +void usage __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + extern char *optarg; + extern int optind; + DB *dbp; + DBT key, data; + int ch, pflag, rval; + + pflag = 0; + while ((ch = getopt(argc, argv, "f:p")) != EOF) + switch (ch) { + case 'f': + if (freopen(optarg, "w", stdout) == NULL) { + fprintf(stderr, "db_dump185: %s: %s\n", + optarg, strerror(errno)); + exit (1); + } + break; + case 'p': + pflag = 1; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (argc != 1) + usage(); + + if ((dbp = dbopen(argv[0], O_RDONLY, 0, DB_BTREE, NULL)) == NULL) { + if ((dbp = + dbopen(argv[0], O_RDONLY, 0, DB_HASH, NULL)) == NULL) { + fprintf(stderr, + "db_dump185: %s: %s\n", argv[0], strerror(errno)); + exit (1); + } + db_hash(dbp, pflag); + } else + db_btree(dbp, pflag); + + /* + * !!! + * DB 1.85 DBTs are a subset of DB 2.0 DBTs, so we just use the + * new dump/print routines. + */ + if (pflag) + while (!(rval = dbp->seq(dbp, &key, &data, R_NEXT))) { + dbt_print(&key); + dbt_print(&data); + } + else + while (!(rval = dbp->seq(dbp, &key, &data, R_NEXT))) { + dbt_dump(&key); + dbt_dump(&data); + } + + if (rval == -1) { + fprintf(stderr, "db_dump185: seq: %s\n", strerror(errno)); + exit (1); + } + return (0); +} + +/* + * db_hash -- + * Dump out hash header information. + */ +void +db_hash(dbp, pflag) + DB *dbp; + int pflag; +{ + HTAB185 *hash185p; + HTAB186 *hash186p; + + printf("format=%s\n", pflag ? "print" : "bytevalue"); + printf("type=hash\n"); + + /* DB 1.85 was version 2, DB 1.86 was version 3. */ + hash185p = dbp->internal; + if (hash185p->hdr.version > 2) { + hash186p = dbp->internal; + printf("h_ffactor=%lu\n", (u_long)hash186p->hdr.ffactor); + if (hash186p->hdr.lorder != 0) + printf("db_lorder=%lu\n", (u_long)hash186p->hdr.lorder); + printf("db_pagesize=%lu\n", (u_long)hash186p->hdr.bsize); + } else { + printf("h_ffactor=%lu\n", (u_long)hash185p->hdr.ffactor); + if (hash185p->hdr.lorder != 0) + printf("db_lorder=%lu\n", (u_long)hash185p->hdr.lorder); + printf("db_pagesize=%lu\n", (u_long)hash185p->hdr.bsize); + } + printf("HEADER=END\n"); +} + +/* + * db_btree -- + * Dump out btree header information. + */ +void +db_btree(dbp, pflag) + DB *dbp; + int pflag; +{ + BTREE *btp; + + btp = dbp->internal; + + printf("format=%s\n", pflag ? "print" : "bytevalue"); + printf("type=btree\n"); +#ifdef NOT_AVAILABLE_IN_185 + printf("bt_minkey=%lu\n", (u_long)XXX); + printf("bt_maxkey=%lu\n", (u_long)XXX); +#endif + if (btp->bt_lorder != 0) + printf("db_lorder=%lu\n", (u_long)btp->bt_lorder); + printf("db_pagesize=%lu\n", (u_long)btp->bt_psize); + if (!(btp->flags & B_NODUPS)) + printf("duplicates=1\n"); + printf("HEADER=END\n"); +} + +static char hex[] = "0123456789abcdef"; + +/* + * dbt_dump -- + * Write out a key or data item using byte values. + */ +void +dbt_dump(dbtp) + DBT *dbtp; +{ + size_t len; + u_int8_t *p; + + for (len = dbtp->size, p = dbtp->data; len--; ++p) + (void)printf("%c%c", + hex[(*p & 0xf0) >> 4], hex[*p & 0x0f]); + printf("\n"); +} + +/* + * dbt_print -- + * Write out a key or data item using printable characters. + */ +void +dbt_print(dbtp) + DBT *dbtp; +{ + size_t len; + u_int8_t *p; + + for (len = dbtp->size, p = dbtp->data; len--; ++p) + if (isprint((int)*p)) { + if (*p == '\\') + (void)printf("\\"); + (void)printf("%c", *p); + } else + (void)printf("\\%c%c", + hex[(*p & 0xf0) >> 4], hex[*p & 0x0f]); + printf("\n"); +} + +/* + * usage -- + * Display the usage message. + */ +void +usage() +{ + (void)fprintf(stderr, "usage: db_dump185 [-p] [-f file] db_file\n"); + exit(1); +} diff --git a/db/db_load/db_load.c b/db/db_load/db_load.c new file mode 100644 index 000000000..33e2eb5e0 --- /dev/null +++ b/db/db_load/db_load.c @@ -0,0 +1,998 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char copyright[] = + "Copyright (c) 1996-2000\nSleepycat Software Inc. All rights reserved.\n"; +static const char revid[] = + "$Id: db_load.c,v 11.33 2001/01/22 17:25:07 krinsky Exp $"; +#endif + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#include +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_am.h" +#include "clib_ext.h" + +void badend __P((void)); +void badnum __P((void)); +int configure __P((DB *, char **, char **, int *)); +int db_init __P((char *)); +int dbt_rdump __P((DBT *)); +int dbt_rprint __P((DBT *)); +int dbt_rrecno __P((DBT *, int)); +int digitize __P((int, int *)); +int load __P((char *, DBTYPE, char **, int, u_int32_t)); +int main __P((int, char *[])); +int rheader __P((DB *, DBTYPE *, char **, int *, int *)); +void usage __P((void)); +void version_check __P((void)); + +int endodata; /* Reached the end of a database. */ +int endofile; /* Reached the end of the input. */ +int existed; /* Tried to load existing key. */ +u_long lineno; /* Input file line number. */ +int version = 1; /* Input version. */ + +DB_ENV *dbenv; +const char + *progname = "db_load"; /* Program name. */ + +int +main(argc, argv) + int argc; + char *argv[]; +{ + extern char *optarg; + extern int optind; + DBTYPE dbtype; + u_int32_t db_nooverwrite; + int ch, exitval, no_header, ret; + char **clist, **clp, *home; + + version_check(); + + home = NULL; + db_nooverwrite = 0; + exitval = no_header = 0; + dbtype = DB_UNKNOWN; + + /* Allocate enough room for configuration arguments. */ + if ((clp = clist = (char **)calloc(argc + 1, sizeof(char *))) == NULL) { + fprintf(stderr, "%s: %s\n", progname, strerror(ENOMEM)); + exit(1); + } + + while ((ch = getopt(argc, argv, "c:f:h:nTt:V")) != EOF) + switch (ch) { + case 'c': + *clp++ = optarg; + break; + case 'f': + if (freopen(optarg, "r", stdin) == NULL) { + fprintf(stderr, "%s: %s: reopen: %s\n", + progname, optarg, strerror(errno)); + exit(1); + } + break; + case 'h': + home = optarg; + break; + case 'n': + db_nooverwrite = DB_NOOVERWRITE; + break; + case 'T': + no_header = 1; + break; + case 't': + if (strcmp(optarg, "btree") == 0) { + dbtype = DB_BTREE; + break; + } + if (strcmp(optarg, "hash") == 0) { + dbtype = DB_HASH; + break; + } + if (strcmp(optarg, "recno") == 0) { + dbtype = DB_RECNO; + break; + } + if (strcmp(optarg, "queue") == 0) { + dbtype = DB_QUEUE; + break; + } + usage(); + /* NOTREACHED */ + case 'V': + printf("%s\n", db_version(NULL, NULL, NULL)); + exit(0); + case '?': + default: + usage(); + /* NOTREACHED */ + } + argc -= optind; + argv += optind; + + if (argc != 1) + usage(); + + /* Handle possible interruptions. */ + __db_util_siginit(); + + /* + * Create an environment object initialized for error reporting, and + * then open it. + */ + if ((ret = db_env_create(&dbenv, 0)) != 0) { + fprintf(stderr, + "%s: db_env_create: %s\n", progname, db_strerror(ret)); + goto shutdown; + } + dbenv->set_errfile(dbenv, stderr); + dbenv->set_errpfx(dbenv, progname); + if (db_init(home) != 0) + goto shutdown; + + while (!endofile) + if (load(argv[0], + dbtype, clist, no_header, db_nooverwrite) != 0) + goto shutdown; + + if (0) { +shutdown: exitval = 1; + } + if ((ret = dbenv->close(dbenv, 0)) != 0) { + exitval = 1; + fprintf(stderr, + "%s: dbenv->close: %s\n", progname, db_strerror(ret)); + } + + /* Resend any caught signal. */ + __db_util_sigresend(); + + /* Return 0 on success, 1 if keys existed already, and 2 on failure. */ + return (exitval == 0 ? (existed == 0 ? 0 : 1) : 2); +} + +/* + * load -- + * Load a database. + */ +int +load(name, argtype, clist, no_header, db_nooverwrite) + char *name, **clist; + DBTYPE argtype; + int no_header; + u_int32_t db_nooverwrite; +{ + DB *dbp; + DBT key, rkey, data, *readp, *writep; + DBTYPE dbtype; + DB_TXN *ctxn, *txn; + db_recno_t recno, datarecno; + int checkprint, hexkeys, keys, ret, rval; + int keyflag, ascii_recno; + char *subdb; + + endodata = 0; + subdb = NULL; + ctxn = txn = NULL; + memset(&key, 0, sizeof(DBT)); + memset(&data, 0, sizeof(DBT)); + memset(&rkey, 0, sizeof(DBT)); + + /* Create the DB object. */ + if ((ret = db_create(&dbp, dbenv, 0)) != 0) { + dbenv->err(dbenv, ret, "db_create"); + return (1); + } + + dbtype = DB_UNKNOWN; + keys = -1; + hexkeys = -1; + keyflag = -1; + /* Read the header -- if there's no header, we expect flat text. */ + if (no_header) { + checkprint = 1; + dbtype = argtype; + } else { + if (rheader(dbp, &dbtype, &subdb, &checkprint, &keys) != 0) + goto err; + if (endofile) + goto done; + } + + /* + * Apply command-line configuration changes. (We apply command-line + * configuration changes to all databases that are loaded, e.g., all + * subdatabases.) + */ + if (configure(dbp, clist, &subdb, &keyflag)) + goto err; + + if (keys != 1) { + if (keyflag == 1) { + dbp->err(dbp, EINVAL, "No keys specified in file"); + goto err; + } + } + else if (keyflag == 0) { + dbp->err(dbp, EINVAL, "Keys specified in file"); + goto err; + } + else + keyflag = 1; + + if (dbtype == DB_BTREE || dbtype == DB_HASH) { + if (keyflag == 0) + dbp->err(dbp, + EINVAL, "Btree and Hash must specify keys"); + else + keyflag = 1; + } + + if (argtype != DB_UNKNOWN) { + + if (dbtype == DB_RECNO || dbtype == DB_QUEUE) + if (keyflag != 1 && argtype != DB_RECNO + && argtype != DB_QUEUE) { + dbenv->errx(dbenv, + "improper database type conversion specified"); + goto err; + } + dbtype = argtype; + } + + if (dbtype == DB_UNKNOWN) { + dbenv->errx(dbenv, "no database type specified"); + goto err; + } + + if (keyflag == -1) + keyflag = 0; + + /* + * Recno keys have only been printed in hexadecimal starting + * with db_dump format version 3 (DB 3.2). + * + * !!! + * Note that version is set in rheader(), which must be called before + * this assignment. + */ + hexkeys = (version >= 3 && keyflag == 1 && checkprint == 0); + + if (keyflag == 1 && (dbtype == DB_RECNO || dbtype == DB_QUEUE)) + ascii_recno = 1; + else + ascii_recno = 0; + + /* Open the DB file. */ + if ((ret = dbp->open(dbp, + name, subdb, dbtype, DB_CREATE, __db_omode("rwrwrw"))) != 0) { + dbp->err(dbp, ret, "DB->open: %s", name); + goto err; + } + + /* Initialize the key/data pair. */ + readp = &key; + writep = &key; + if (dbtype == DB_RECNO || dbtype == DB_QUEUE) { + key.size = sizeof(recno); + if (keyflag) { + key.data = &datarecno; + if (checkprint) { + readp = &rkey; + goto key_data; + } + } + else + key.data = &recno; + } else +key_data: if ((readp->data = + (void *)malloc(readp->ulen = 1024)) == NULL) { + dbenv->err(dbenv, ENOMEM, NULL); + goto err; + } + if ((data.data = (void *)malloc(data.ulen = 1024)) == NULL) { + dbenv->err(dbenv, ENOMEM, NULL); + goto err; + } + + if (TXN_ON(dbenv) && (ret = txn_begin(dbenv, NULL, &txn, 0)) != 0) + goto err; + + /* Get each key/data pair and add them to the database. */ + for (recno = 1; !__db_util_interrupted(); ++recno) { + if (!keyflag) + if (checkprint) { + if (dbt_rprint(&data)) + goto err; + } else { + if (dbt_rdump(&data)) + goto err; + } + else + if (checkprint) { + if (dbt_rprint(readp)) + goto err; + if (!endodata && dbt_rprint(&data)) + goto fmt; + } else { + if (ascii_recno) { + if (dbt_rrecno(readp, hexkeys)) + goto err; + } else + if (dbt_rdump(readp)) + goto err; + if (!endodata && dbt_rdump(&data)) { +fmt: dbenv->errx(dbenv, + "odd number of key/data pairs"); + goto err; + } + } + if (endodata) + break; + if (readp != writep) { + if (sscanf(readp->data, "%ud", &datarecno) != 1) + dbenv->errx(dbenv, + "%s: non-integer key at line: %d", + name, !keyflag ? recno : recno * 2 - 1); + if (datarecno == 0) + dbenv->errx(dbenv, "%s: zero key at line: %d", + name, + !keyflag ? recno : recno * 2 - 1); + } +retry: if (txn != NULL) + if ((ret = txn_begin(dbenv, txn, &ctxn, 0)) != 0) + goto err; + switch (ret = + dbp->put(dbp, txn, writep, &data, db_nooverwrite)) { + case 0: + if (ctxn != NULL) { + if ((ret = + txn_commit(ctxn, DB_TXN_NOSYNC)) != 0) + goto err; + ctxn = NULL; + } + break; + case DB_KEYEXIST: + existed = 1; + dbenv->errx(dbenv, + "%s: line %d: key already exists, not loaded:", + name, + !keyflag ? recno : recno * 2 - 1); + + (void)__db_prdbt(&key, checkprint, 0, stderr, + __db_verify_callback, 0, NULL); + break; + case DB_LOCK_DEADLOCK: + /* If we have a child txn, retry--else it's fatal. */ + if (ctxn != NULL) { + if ((ret = txn_abort(ctxn)) != 0) + goto err; + ctxn = NULL; + goto retry; + } + /* FALLTHROUGH */ + default: + dbenv->err(dbenv, ret, NULL); + if (ctxn != NULL) { + (void)txn_abort(ctxn); + ctxn = NULL; + } + goto err; + } + if (ctxn != NULL) { + if ((ret = txn_abort(ctxn)) != 0) + goto err; + ctxn = NULL; + } + } +done: rval = 0; + DB_ASSERT(ctxn == NULL); + if (txn != NULL && (ret = txn_commit(txn, 0)) != 0) { + txn = NULL; + goto err; + } + + if (0) { +err: rval = 1; + DB_ASSERT(ctxn == NULL); + if (txn != NULL) + (void)txn_abort(txn); + } + + /* Close the database. */ + if ((ret = dbp->close(dbp, 0)) != 0) { + dbp->err(dbp, ret, "DB->close"); + rval = 1; + } + + /* Free allocated memory. */ + if (subdb != NULL) + free(subdb); + if (dbtype != DB_RECNO && dbtype != DB_QUEUE) + free(key.data); + if (rkey.data != NULL) + free(rkey.data); + free(data.data); + + return (rval); +} + +/* + * db_init -- + * Initialize the environment. + */ +int +db_init(home) + char *home; +{ + u_int32_t flags; + int ret; + + /* We may be loading into a live environment. Try and join. */ + flags = DB_USE_ENVIRON | + DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN; + if (dbenv->open(dbenv, home, flags, 0) == 0) + return (0); + + /* + * We're trying to load a database. + * + * An environment is required because we may be trying to look at + * databases in directories other than the current one. We could + * avoid using an environment iff the -h option wasn't specified, + * but that seems like more work than it's worth. + * + * No environment exists (or, at least no environment that includes + * an mpool region exists). Create one, but make it private so that + * no files are actually created. + */ + LF_CLR(DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_TXN); + LF_SET(DB_CREATE | DB_PRIVATE); + if ((ret = dbenv->open(dbenv, home, flags, 0)) == 0) + return (0); + + /* An environment is required. */ + dbenv->err(dbenv, ret, "DBENV->open"); + return (1); +} + +#define FLAG(name, value, keyword, flag) \ + if (strcmp(name, keyword) == 0) { \ + switch (*value) { \ + case '1': \ + if ((ret = dbp->set_flags(dbp, flag)) != 0) { \ + dbp->err(dbp, ret, "%s: set_flags: %s", \ + progname, name); \ + return (1); \ + } \ + break; \ + case '0': \ + break; \ + default: \ + badnum(); \ + return (1); \ + } \ + continue; \ + } +#define NUMBER(name, value, keyword, func) \ + if (strcmp(name, keyword) == 0) { \ + if (__db_getlong(dbp, \ + NULL, value, 1, LONG_MAX, &val) != 0) \ + return (1); \ + if ((ret = dbp->func(dbp, val)) != 0) \ + goto nameerr; \ + continue; \ + } +#define STRING(name, value, keyword, func) \ + if (strcmp(name, keyword) == 0) { \ + if ((ret = dbp->func(dbp, value[0])) != 0) \ + goto nameerr; \ + continue; \ + } + +/* + * configure -- + * Handle command-line configuration options. + */ +int +configure(dbp, clp, subdbp, keysp) + DB *dbp; + char **clp, **subdbp; + int *keysp; +{ + long val; + int ret, savech; + char *name, *value; + + for (; (name = *clp) != NULL; *--value = savech, ++clp) { + if ((value = strchr(name, '=')) == NULL) { + dbp->errx(dbp, + "command-line configuration uses name=value format"); + return (1); + } + savech = *value; + *value++ = '\0'; + + if (strcmp(name, "database") == 0 || + strcmp(name, "subdatabase") == 0) { + if ((*subdbp = strdup(value)) == NULL) { + dbp->err(dbp, ENOMEM, NULL); + return (1); + } + continue; + } + if (strcmp(name, "keys") == 0) { + if (strcmp(value, "1") == 0) + *keysp = 1; + else if (strcmp(value, "0") == 0) + *keysp = 0; + else { + badnum(); + return (1); + } + continue; + } + +#ifdef notyet + NUMBER(name, value, "bt_maxkey", set_bt_maxkey); +#endif + NUMBER(name, value, "bt_minkey", set_bt_minkey); + NUMBER(name, value, "db_lorder", set_lorder); + NUMBER(name, value, "db_pagesize", set_pagesize); + FLAG(name, value, "duplicates", DB_DUP); + FLAG(name, value, "dupsort", DB_DUPSORT); + NUMBER(name, value, "h_ffactor", set_h_ffactor); + NUMBER(name, value, "h_nelem", set_h_nelem); + NUMBER(name, value, "re_len", set_re_len); + STRING(name, value, "re_pad", set_re_pad); + FLAG(name, value, "recnum", DB_RECNUM); + FLAG(name, value, "renumber", DB_RENUMBER); + + dbp->errx(dbp, + "unknown command-line configuration keyword"); + return (1); + } + return (0); + +nameerr: + dbp->err(dbp, ret, "%s: %s=%s", progname, name, value); + return (1); +} + +/* + * rheader -- + * Read the header message. + */ +int +rheader(dbp, dbtypep, subdbp, checkprintp, keysp) + DB *dbp; + DBTYPE *dbtypep; + char **subdbp; + int *checkprintp, *keysp; +{ + long val; + int first, ret; + char *name, *value, *p, buf[128]; + + *dbtypep = DB_UNKNOWN; + *checkprintp = 0; + + for (first = 1;; first = 0) { + ++lineno; + + /* If we don't see the expected information, it's an error. */ + if (fgets(buf, sizeof(buf), stdin) == NULL) { + if (!first || ferror(stdin)) + goto badfmt; + endofile = 1; + break; + } + if ((p = strchr(name = buf, '=')) == NULL) + goto badfmt; + *p++ = '\0'; + if ((p = strchr(value = p, '\n')) == NULL) + goto badfmt; + *p = '\0'; + if (name[0] == '\0' || value[0] == '\0') + goto badfmt; + + if (strcmp(name, "HEADER") == 0) + break; + if (strcmp(name, "VERSION") == 0) { + /* + * Version 1 didn't have a "VERSION" header line. We + * only support versions 1, 2, and 3 of the dump format. + */ + version = atoi(value); + + if (version > 3) { + dbp->errx(dbp, + "line %lu: VERSION %d is unsupported", + lineno, version); + return (1); + } + continue; + } + if (strcmp(name, "format") == 0) { + if (strcmp(value, "bytevalue") == 0) { + *checkprintp = 0; + continue; + } + if (strcmp(value, "print") == 0) { + *checkprintp = 1; + continue; + } + goto badfmt; + } + if (strcmp(name, "type") == 0) { + if (strcmp(value, "btree") == 0) { + *dbtypep = DB_BTREE; + continue; + } + if (strcmp(value, "hash") == 0) { + *dbtypep = DB_HASH; + continue; + } + if (strcmp(value, "recno") == 0) { + *dbtypep = DB_RECNO; + continue; + } + if (strcmp(value, "queue") == 0) { + *dbtypep = DB_QUEUE; + continue; + } + dbp->errx(dbp, "line %lu: unknown type", lineno); + return (1); + } + if (strcmp(name, "database") == 0 || + strcmp(name, "subdatabase") == 0) { + if ((*subdbp = strdup(value)) == NULL) { + dbp->err(dbp, ENOMEM, NULL); + return (1); + } + continue; + } + if (strcmp(name, "keys") == 0) { + if (strcmp(value, "1") == 0) + *keysp = 1; + else if (strcmp(value, "0") == 0) + *keysp = 0; + else { + badnum(); + return (1); + } + continue; + } + +#ifdef notyet + NUMBER(name, value, "bt_maxkey", set_bt_maxkey); +#endif + NUMBER(name, value, "bt_minkey", set_bt_minkey); + NUMBER(name, value, "db_lorder", set_lorder); + NUMBER(name, value, "db_pagesize", set_pagesize); + FLAG(name, value, "duplicates", DB_DUP); + FLAG(name, value, "dupsort", DB_DUPSORT); + NUMBER(name, value, "h_ffactor", set_h_ffactor); + NUMBER(name, value, "h_nelem", set_h_nelem); + NUMBER(name, value, "re_len", set_re_len); + STRING(name, value, "re_pad", set_re_pad); + FLAG(name, value, "recnum", DB_RECNUM); + FLAG(name, value, "renumber", DB_RENUMBER); + + dbp->errx(dbp, + "unknown input-file header configuration keyword"); + return (1); + } + return (0); + +nameerr: + dbp->err(dbp, ret, "%s: %s=%s", progname, name, value); + return (1); + +badfmt: + dbp->errx(dbp, "line %lu: unexpected format", lineno); + return (1); +} + +/* + * dbt_rprint -- + * Read a printable line into a DBT structure. + */ +int +dbt_rprint(dbtp) + DBT *dbtp; +{ + u_int32_t len; + u_int8_t *p; + int c1, c2, e, escape, first; + char buf[32]; + + ++lineno; + + first = 1; + e = escape = 0; + for (p = dbtp->data, len = 0; (c1 = getchar()) != '\n';) { + if (c1 == EOF) { + if (len == 0) { + endofile = endodata = 1; + return (0); + } + badend(); + return (1); + } + if (first) { + first = 0; + if (version > 1) { + if (c1 != ' ') { + buf[0] = c1; + if (fgets(buf + 1, + sizeof(buf) - 1, stdin) == NULL || + strcmp(buf, "DATA=END\n") != 0) { + badend(); + return (1); + } + endodata = 1; + return (0); + } + continue; + } + } + if (escape) { + if (c1 != '\\') { + if ((c2 = getchar()) == EOF) { + badend(); + return (1); + } + c1 = digitize(c1, &e) << 4 | digitize(c2, &e); + if (e) + return (1); + } + escape = 0; + } else + if (c1 == '\\') { + escape = 1; + continue; + } + if (len >= dbtp->ulen - 10) { + dbtp->ulen *= 2; + if ((dbtp->data = + (void *)realloc(dbtp->data, dbtp->ulen)) == NULL) { + dbenv->err(dbenv, ENOMEM, NULL); + return (1); + } + p = (u_int8_t *)dbtp->data + len; + } + ++len; + *p++ = c1; + } + dbtp->size = len; + + return (0); +} + +/* + * dbt_rdump -- + * Read a byte dump line into a DBT structure. + */ +int +dbt_rdump(dbtp) + DBT *dbtp; +{ + u_int32_t len; + u_int8_t *p; + int c1, c2, e, first; + char buf[32]; + + ++lineno; + + first = 1; + e = 0; + for (p = dbtp->data, len = 0; (c1 = getchar()) != '\n';) { + if (c1 == EOF) { + if (len == 0) { + endofile = endodata = 1; + return (0); + } + badend(); + return (1); + } + if (first) { + first = 0; + if (version > 1) { + if (c1 != ' ') { + buf[0] = c1; + if (fgets(buf + 1, + sizeof(buf) - 1, stdin) == NULL || + strcmp(buf, "DATA=END\n") != 0) { + badend(); + return (1); + } + endodata = 1; + return (0); + } + continue; + } + } + if ((c2 = getchar()) == EOF) { + badend(); + return (1); + } + if (len >= dbtp->ulen - 10) { + dbtp->ulen *= 2; + if ((dbtp->data = + (void *)realloc(dbtp->data, dbtp->ulen)) == NULL) { + dbenv->err(dbenv, ENOMEM, NULL); + return (1); + } + p = (u_int8_t *)dbtp->data + len; + } + ++len; + *p++ = digitize(c1, &e) << 4 | digitize(c2, &e); + if (e) + return (1); + } + dbtp->size = len; + + return (0); +} + +/* + * dbt_rrecno -- + * Read a record number dump line into a DBT structure. + */ +int +dbt_rrecno(dbtp, ishex) + DBT *dbtp; + int ishex; +{ + char buf[32], *p, *q; + + ++lineno; + + if (fgets(buf, sizeof(buf), stdin) == NULL) { + endofile = endodata = 1; + return (0); + } + + if (strcmp(buf, "DATA=END\n") == 0) { + endodata = 1; + return (0); + } + + if (buf[0] != ' ') + goto bad; + + /* + * If we're expecting a hex key, do an in-place conversion + * of hex to straight ASCII before calling __db_getulong(). + */ + if (ishex) { + for (p = q = buf + 1; *q != '\0' && *q != '\n';) { + /* + * 0-9 in hex are 0x30-0x39, so this is easy. + * We should alternate between 3's and [0-9], and + * if the [0-9] are something unexpected, + * __db_getulong will fail, so we only need to catch + * end-of-string conditions. + */ + if (*q++ != '3') + goto bad; + if (*q == '\n' || *q == '\0') + goto bad; + *p++ = *q++; + } + *p = '\0'; + } + + if (__db_getulong(NULL, + progname, buf + 1, 0, 0, (u_long *)dbtp->data)) { +bad: badend(); + return (1); + } + + dbtp->size = sizeof(db_recno_t); + return (0); +} + +/* + * digitize -- + * Convert a character to an integer. + */ +int +digitize(c, errorp) + int c, *errorp; +{ + switch (c) { /* Don't depend on ASCII ordering. */ + case '0': return (0); + case '1': return (1); + case '2': return (2); + case '3': return (3); + case '4': return (4); + case '5': return (5); + case '6': return (6); + case '7': return (7); + case '8': return (8); + case '9': return (9); + case 'a': return (10); + case 'b': return (11); + case 'c': return (12); + case 'd': return (13); + case 'e': return (14); + case 'f': return (15); + } + + dbenv->errx(dbenv, "unexpected hexadecimal value"); + *errorp = 1; + + return (0); +} + +/* + * badnum -- + * Display the bad number message. + */ +void +badnum() +{ + dbenv->errx(dbenv, + "boolean name=value pairs require a value of 0 or 1"); +} + +/* + * badend -- + * Display the bad end to input message. + */ +void +badend() +{ + dbenv->errx(dbenv, "unexpected end of input data or key/data pair"); +} + +/* + * usage -- + * Display the usage message. + */ +void +usage() +{ + (void)fprintf(stderr, "%s\n\t%s\n", + "usage: db_load [-nTV]", + "[-c name=value] [-f file] [-h home] [-t btree | hash | recno] db_file"); + exit(1); +} + +void +version_check() +{ + int v_major, v_minor, v_patch; + + /* Make sure we're loaded with the right version of the DB library. */ + (void)db_version(&v_major, &v_minor, &v_patch); + if (v_major != DB_VERSION_MAJOR || + v_minor != DB_VERSION_MINOR || v_patch != DB_VERSION_PATCH) { + fprintf(stderr, + "%s: version %d.%d.%d doesn't match library version %d.%d.%d\n", + progname, DB_VERSION_MAJOR, DB_VERSION_MINOR, + DB_VERSION_PATCH, v_major, v_minor, v_patch); + exit (1); + } +} diff --git a/db/db_printlog/README b/db/db_printlog/README new file mode 100644 index 000000000..7d8da505e --- /dev/null +++ b/db/db_printlog/README @@ -0,0 +1,25 @@ +# $Id: README,v 10.5 1999/11/21 23:08:01 bostic Exp $ + +Berkeley DB log dump utility. This utility dumps out a DB log in human +readable form, a record at a time, to assist in recovery and transaction +abort debugging. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +commit.awk Output transaction ID of committed transactions. + +count.awk Print out the number of log records for transactions + that we encountered. + +fileid.awk Take a comma-separated list of file numbers and spit out + all the log records that affect those file numbers. + +pgno.awk Take a comma-separated list of page numbers and spit + out all the log records that affect those page numbers. + +range.awk Print out a range of the log. + +status.awk Read through db_printlog output and list the transactions + encountered, and whether they commited or aborted. + +txn.awk Print out all the records for a comma-separated list of + transaction IDs. diff --git a/db/db_printlog/commit.awk b/db/db_printlog/commit.awk new file mode 100644 index 000000000..66391d3fb --- /dev/null +++ b/db/db_printlog/commit.awk @@ -0,0 +1,7 @@ +# $Id: commit.awk,v 10.2 1999/11/21 18:01:42 bostic Exp $ +# +# Output tid of committed transactions. + +/txn_regop/ { + print $5 +} diff --git a/db/db_printlog/count.awk b/db/db_printlog/count.awk new file mode 100644 index 000000000..1d5a29195 --- /dev/null +++ b/db/db_printlog/count.awk @@ -0,0 +1,9 @@ +# $Id: count.awk,v 10.2 1999/11/21 18:01:42 bostic Exp $ +# +# Print out the number of log records for transactions that we +# encountered. + +/^\[/{ + if ($5 != 0) + print $5 +} diff --git a/db/db_printlog/db_printlog.c b/db/db_printlog/db_printlog.c new file mode 100644 index 000000000..8b9fb74a6 --- /dev/null +++ b/db/db_printlog/db_printlog.c @@ -0,0 +1,200 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char copyright[] = + "Copyright (c) 1996-2000\nSleepycat Software Inc. All rights reserved.\n"; +static const char revid[] = + "$Id: db_printlog.c,v 11.23 2001/01/18 18:36:58 bostic Exp $"; +#endif + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "btree.h" +#include "db_am.h" +#include "hash.h" +#include "log.h" +#include "qam.h" +#include "txn.h" + +int main __P((int, char *[])); +void usage __P((void)); +void version_check __P((void)); + +DB_ENV *dbenv; +const char + *progname = "db_printlog"; /* Program name. */ + +int +main(argc, argv) + int argc; + char *argv[]; +{ + extern char *optarg; + extern int optind; + DBT data; + DB_LSN key; + int ch, e_close, exitval, nflag, ret; + char *home; + + version_check(); + + e_close = exitval = 0; + nflag = 0; + home = NULL; + while ((ch = getopt(argc, argv, "h:NV")) != EOF) + switch (ch) { + case 'h': + home = optarg; + break; + case 'N': + nflag = 1; + if ((ret = db_env_set_panicstate(0)) != 0) { + fprintf(stderr, + "%s: db_env_set_panicstate: %s\n", + progname, db_strerror(ret)); + return (1); + } + break; + case 'V': + printf("%s\n", db_version(NULL, NULL, NULL)); + exit(0); + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (argc > 0) + usage(); + + /* Handle possible interruptions. */ + __db_util_siginit(); + + /* + * Create an environment object and initialize it for error + * reporting. + */ + if ((ret = db_env_create(&dbenv, 0)) != 0) { + fprintf(stderr, + "%s: db_env_create: %s\n", progname, db_strerror(ret)); + goto shutdown; + } + e_close = 1; + + dbenv->set_errfile(dbenv, stderr); + dbenv->set_errpfx(dbenv, progname); + + if (nflag && (ret = dbenv->set_mutexlocks(dbenv, 0)) != 0) { + dbenv->err(dbenv, ret, "set_mutexlocks"); + goto shutdown; + } + + /* + * An environment is required, but as all we're doing is reading log + * files, we create one if it doesn't already exist. If we create + * it, create it private so it automatically goes away when we're done. + */ + if ((ret = dbenv->open(dbenv, home, + DB_JOINENV | DB_USE_ENVIRON, 0)) != 0 && + (ret = dbenv->open(dbenv, home, + DB_CREATE | DB_INIT_LOG | DB_PRIVATE | DB_USE_ENVIRON, 0)) != 0) { + dbenv->err(dbenv, ret, "open"); + goto shutdown; + } + + /* Initialize print callbacks. */ + if ((ret = __bam_init_print(dbenv)) != 0 || + (ret = __crdel_init_print(dbenv)) != 0 || + (ret = __db_init_print(dbenv)) != 0 || + (ret = __qam_init_print(dbenv)) != 0 || + (ret = __ham_init_print(dbenv)) != 0 || + (ret = __log_init_print(dbenv)) != 0 || + (ret = __txn_init_print(dbenv)) != 0) { + dbenv->err(dbenv, ret, "callback: initialization"); + goto shutdown; + } + + memset(&data, 0, sizeof(data)); + while (!__db_util_interrupted()) { + if ((ret = log_get(dbenv, &key, &data, DB_NEXT)) != 0) { + if (ret == DB_NOTFOUND) + break; + dbenv->err(dbenv, ret, "log_get"); + goto shutdown; + } + + /* + * XXX + * We use DB_TXN_ABORT as our op because that's the only op + * that calls the underlying recovery function without any + * consideration as to the contents of the transaction list. + */ + ret = __db_dispatch(dbenv, &data, &key, DB_TXN_ABORT, NULL); + + /* + * XXX + * Just in case the underlying routines don't flush. + */ + (void)fflush(stdout); + + if (ret != 0) { + dbenv->err(dbenv, ret, "tx: dispatch"); + goto shutdown; + } + } + + if (0) { +shutdown: exitval = 1; + } + if (e_close && (ret = dbenv->close(dbenv, 0)) != 0) { + exitval = 1; + fprintf(stderr, + "%s: dbenv->close: %s\n", progname, db_strerror(ret)); + } + + /* Resend any caught signal. */ + __db_util_sigresend(); + + return (exitval); +} + +void +usage() +{ + fprintf(stderr, "usage: db_printlog [-NV] [-h home]\n"); + exit (1); +} + +void +version_check() +{ + int v_major, v_minor, v_patch; + + /* Make sure we're loaded with the right version of the DB library. */ + (void)db_version(&v_major, &v_minor, &v_patch); + if (v_major != DB_VERSION_MAJOR || + v_minor != DB_VERSION_MINOR || v_patch != DB_VERSION_PATCH) { + fprintf(stderr, + "%s: version %d.%d.%d doesn't match library version %d.%d.%d\n", + progname, DB_VERSION_MAJOR, DB_VERSION_MINOR, + DB_VERSION_PATCH, v_major, v_minor, v_patch); + exit (1); + } +} diff --git a/db/db_printlog/dbname.awk b/db/db_printlog/dbname.awk new file mode 100644 index 000000000..d07033512 --- /dev/null +++ b/db/db_printlog/dbname.awk @@ -0,0 +1,79 @@ +# $Id: dbname.awk,v 1.2 2000/08/03 15:06:39 ubell Exp $ +# +# Take a comma-separated list of database names and spit out all the +# log records that affect those databases. + +NR == 1 { + nfiles = 0 + while ((ndx = index(DBNAME, ",")) != 0) { + filenames[nfiles] = substr(DBNAME, 1, ndx - 1) 0; + DBNAME = substr(DBNAME, ndx + 1, length(DBNAME) - ndx); + files[nfiles] = -1 + nfiles++ + } + filenames[nfiles] = DBNAME 0; + files[nfiles] = -1 + myfile = -1; +} + +/^\[.*log_register/ { + register = 1; +} +/opcode:/ { + if (register == 1) { + if ($2 == 1) + register = 3; + else + register = $2; + } +} +/name:/ { + if (register >= 2) { + for (i = 0; i <= nfiles; i++) { + if ($2 == filenames[i]) { + if (register == 2) { + printme = 0; + myfile = -1; + files[i] = -1; + } else { + myfile = i; + } + break; + } + } + } + register = 0; +} +/fileid:/{ + if (myfile != -1) { + files[myfile] = $2; + printme = 1; + register = 0; + myfile = -1; + } else + for (i = 0; i <= nfiles; i++) + if ($2 == files[i]) { + printme = 1 + break; + } +} + + + +/^\[/{ + if (printme == 1) { + printf("%s\n", rec); + printme = 0 + } + rec = ""; + + rec = $0 +} +/^ /{ + rec = sprintf("%s\n%s", rec, $0); +} + +END { + if (printme == 1) + printf("%s\n", rec); +} diff --git a/db/db_printlog/fileid.awk b/db/db_printlog/fileid.awk new file mode 100644 index 000000000..020644039 --- /dev/null +++ b/db/db_printlog/fileid.awk @@ -0,0 +1,37 @@ +# $Id: fileid.awk,v 10.4 2000/07/17 22:07:17 ubell Exp $ +# +# Take a comma-separated list of file numbers and spit out all the +# log records that affect those file numbers. + +NR == 1 { + nfiles = 0 + while ((ndx = index(FILEID, ",")) != 0) { + files[nfiles] = substr(FILEID, 1, ndx - 1); + FILEID = substr(FILEID, ndx + 1, length(FILEID) - ndx); + nfiles++ + } + files[nfiles] = FILEID; +} + +/^\[/{ + if (printme == 1) { + printf("%s\n", rec); + printme = 0 + } + rec = ""; + + rec = $0 +} +/^ /{ + rec = sprintf("%s\n%s", rec, $0); +} +/fileid/{ + for (i = 0; i <= nfiles; i++) + if ($2 == files[i]) + printme = 1 +} + +END { + if (printme == 1) + printf("%s\n", rec); +} diff --git a/db/db_printlog/pgno.awk b/db/db_printlog/pgno.awk new file mode 100644 index 000000000..289fa853b --- /dev/null +++ b/db/db_printlog/pgno.awk @@ -0,0 +1,47 @@ +# $Id: pgno.awk,v 10.3 2000/07/17 22:07:17 ubell Exp $ +# +# Take a comma-separated list of page numbers and spit out all the +# log records that affect those page numbers. + +NR == 1 { + npages = 0 + while ((ndx = index(PGNO, ",")) != 0) { + pgno[npages] = substr(PGNO, 1, ndx - 1); + PGNO = substr(PGNO, ndx + 1, length(PGNO) - ndx); + npages++ + } + pgno[npages] = PGNO; +} + +/^\[/{ + if (printme == 1) { + printf("%s\n", rec); + printme = 0 + } + rec = ""; + + rec = $0 +} +/^ /{ + rec = sprintf("%s\n%s", rec, $0); +} +/pgno/{ + for (i = 0; i <= npages; i++) + if ($2 == pgno[i]) + printme = 1 +} +/right/{ + for (i = 0; i <= npages; i++) + if ($2 == pgno[i]) + printme = 1 +} +/left/{ + for (i = 0; i <= npages; i++) + if ($2 == pgno[i]) + printme = 1 +} + +END { + if (printme == 1) + printf("%s\n", rec); +} diff --git a/db/db_printlog/range.awk b/db/db_printlog/range.awk new file mode 100644 index 000000000..7abb410b4 --- /dev/null +++ b/db/db_printlog/range.awk @@ -0,0 +1,27 @@ +# $Id: range.awk,v 10.2 1999/11/21 18:01:42 bostic Exp $ +# +# Print out a range of the log + +/^\[/{ + l = length($1) - 1; + i = index($1, "]"); + file = substr($1, 2, i - 2); + file += 0; + start = i + 2; + offset = substr($1, start, l - start + 1); + i = index(offset, "]"); + offset = substr($1, start, i - 1); + offset += 0; + + if ((file == START_FILE && offset >= START_OFFSET || file > START_FILE)\ + && (file < END_FILE || (file == END_FILE && offset < END_OFFSET))) + printme = 1 + else if (file == END_FILE && offset > END_OFFSET || file > END_FILE) + exit + else + printme = 0 +} +{ + if (printme == 1) + print $0 +} diff --git a/db/db_printlog/rectype.awk b/db/db_printlog/rectype.awk new file mode 100644 index 000000000..7f7b2f5ee --- /dev/null +++ b/db/db_printlog/rectype.awk @@ -0,0 +1,27 @@ +# $Id: rectype.awk,v 11.3 2000/07/17 22:00:49 ubell Exp $ +# +# Print out a range of the log +# Command line should set RECTYPE to the a comma separated list +# of the rectypes (or partial strings of rectypes) sought. +NR == 1 { + ntypes = 0 + while ((ndx = index(RECTYPE, ",")) != 0) { + types[ntypes] = substr(RECTYPE, 1, ndx - 1); + RECTYPE = substr(RECTYPE, ndx + 1, length(RECTYPE) - ndx); + ntypes++ + } + types[ntypes] = RECTYPE; +} + +/^\[/{ + printme = 0 + for (i = 0; i <= ntypes; i++) + if (index($1, types[i]) != 0) { + printme = 1 + break; + } +} +{ + if (printme == 1) + print $0 +} diff --git a/db/db_printlog/status.awk b/db/db_printlog/status.awk new file mode 100644 index 000000000..42e24b078 --- /dev/null +++ b/db/db_printlog/status.awk @@ -0,0 +1,26 @@ +# $Id: status.awk,v 10.2 1999/11/21 18:01:43 bostic Exp $ +# +# Read through db_printlog output and list all the transactions encountered +# and whether they commited or aborted. +# +# 1 = started +# 2 = commited +BEGIN { + cur_txn = 0 +} +/^\[/{ + if (status[$5] == 0) { + status[$5] = 1; + txns[cur_txn] = $5; + cur_txn++; + } +} +/txn_regop/ { + status[$5] = 2 +} +END { + for (i = 0; i < cur_txn; i++) { + printf("%s\t%s\n", + txns[i], status[txns[i]] == 1 ? "ABORT" : "COMMIT"); + } +} diff --git a/db/db_printlog/txn.awk b/db/db_printlog/txn.awk new file mode 100644 index 000000000..be8c44e10 --- /dev/null +++ b/db/db_printlog/txn.awk @@ -0,0 +1,34 @@ +# $Id: txn.awk,v 10.3 2000/07/17 22:07:17 ubell Exp $ +# +# Print out all the records for a comma-separated list of transaction ids. +NR == 1 { + ntxns = 0 + while ((ndx = index(TXN, ",")) != 0) { + txn[ntxns] = substr(TXN, 1, ndx - 1); + TXN = substr(TXN, ndx + 1, length(TXN) - ndx); + ntxns++ + } + txn[ntxns] = TXN; +} + +/^\[/{ + if (printme == 1) { + printf("%s\n", rec); + printme = 0 + } + rec = ""; + + for (i = 0; i <= ntxns; i++) + if (txn[i] == $5) { + rec = $0 + printme = 1 + } +} +/^ /{ + rec = sprintf("%s\n%s", rec, $0); +} + +END { + if (printme == 1) + printf("%s\n", rec); +} diff --git a/db/db_recover/db_recover.c b/db/db_recover/db_recover.c new file mode 100644 index 000000000..59ab8bcef --- /dev/null +++ b/db/db_recover/db_recover.c @@ -0,0 +1,288 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char copyright[] = + "Copyright (c) 1996-2000\nSleepycat Software Inc. All rights reserved.\n"; +static const char revid[] = + "$Id: db_recover.c,v 11.17 2001/01/18 18:36:58 bostic Exp $"; +#endif + +#ifndef NO_SYSTEM_INCLUDES +#include + +#if TIME_WITH_SYS_TIME +#include +#include +#else +#if HAVE_SYS_TIME_H +#include +#else +#include +#endif +#endif + +#include +#include +#include +#endif + +#include "db_int.h" +#include "common_ext.h" +#include "txn.h" + +int main __P((int, char *[])); +void read_timestamp __P((char *, time_t *)); +void usage __P((void)); +void version_check __P((void)); + +DB_ENV *dbenv; +const char + *progname = "db_recover"; /* Program name. */ + +int +main(argc, argv) + int argc; + char *argv[]; +{ + extern char *optarg; + extern int optind; + DB_TXNREGION *region; + time_t now, timestamp; + u_int32_t flags; + int ch, exitval, fatal_recover, ret, verbose; + char *home; + + version_check(); + + home = NULL; + timestamp = 0; + exitval = fatal_recover = verbose = 0; + while ((ch = getopt(argc, argv, "ch:t:Vv")) != EOF) + switch (ch) { + case 'c': + fatal_recover = 1; + break; + case 'h': + home = optarg; + break; + case 't': + read_timestamp(optarg, ×tamp); + break; + case 'V': + printf("%s\n", db_version(NULL, NULL, NULL)); + exit(0); + case 'v': + verbose = 1; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (argc != 0) + usage(); + + /* Handle possible interruptions. */ + __db_util_siginit(); + + /* + * Create an environment object and initialize it for error + * reporting. + */ + if ((ret = db_env_create(&dbenv, 0)) != 0) { + fprintf(stderr, + "%s: db_env_create: %s\n", progname, db_strerror(ret)); + exit (1); + } + dbenv->set_errfile(dbenv, stderr); + dbenv->set_errpfx(dbenv, progname); + if (verbose) { + (void)dbenv->set_verbose(dbenv, DB_VERB_RECOVERY, 1); + (void)dbenv->set_verbose(dbenv, DB_VERB_CHKPOINT, 1); + } + if (timestamp && + (ret = dbenv->set_tx_timestamp(dbenv, ×tamp)) != 0) { + dbenv->err(dbenv, ret, "DBENV->set_timestamp"); + goto shutdown; + } + + /* + * Initialize the environment -- we don't actually do anything + * else, that all that's needed to run recovery. + * + * Note that we specify a private environment, as we're about to + * create a region, and we don't want to to leave it around. If + * we leave the region around, the application that should create + * it will simply join it instead, and will then be running with + * incorrectly sized (and probably terribly small) caches. + */ + flags = 0; + LF_SET(DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | + DB_INIT_MPOOL | DB_INIT_TXN | DB_PRIVATE | DB_USE_ENVIRON); + LF_SET(fatal_recover ? DB_RECOVER_FATAL : DB_RECOVER); + if ((ret = dbenv->open(dbenv, home, flags, 0)) != 0) { + dbenv->err(dbenv, ret, "DBENV->open"); + goto shutdown; + } + + if (verbose) { + (void)time(&now); + region = ((DB_TXNMGR *)dbenv->tx_handle)->reginfo.primary; + dbenv->errx(dbenv, "Recovery complete at %.24s", ctime(&now)); + dbenv->errx(dbenv, "%s %lx %s [%lu][%lu]", + "Maximum transaction id", (u_long)region->last_txnid, + "Recovery checkpoint", (u_long)region->last_ckp.file, + (u_long)region->last_ckp.offset); + } + + if (0) { +shutdown: exitval = 1; + } + + /* Clean up the environment. */ + if ((ret = dbenv->close(dbenv, 0)) != 0) { + exitval = 1; + fprintf(stderr, + "%s: dbenv->close: %s\n", progname, db_strerror(ret)); + } + + /* Resend any caught signal. */ + __db_util_sigresend(); + + return (exitval); +} + +#define ATOI2(ar) ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2; + +/* + * read_timestamp -- + * Convert a time argument to Epoch seconds. + * + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +void +read_timestamp(arg, timep) + char *arg; + time_t *timep; +{ + struct tm *t; + time_t now; + int yearset; + char *p; + /* Start with the current time. */ + (void)time(&now); + if ((t = localtime(&now)) == NULL) { + fprintf(stderr, + "%s: localtime: %s\n", progname, strerror(errno)); + exit (1); + } + /* [[CC]YY]MMDDhhmm[.SS] */ + if ((p = strchr(arg, '.')) == NULL) + t->tm_sec = 0; /* Seconds defaults to 0. */ + else { + if (strlen(p + 1) != 2) + goto terr; + *p++ = '\0'; + t->tm_sec = ATOI2(p); + } + + yearset = 0; + switch(strlen(arg)) { + case 12: /* CCYYMMDDhhmm */ + t->tm_year = ATOI2(arg); + t->tm_year *= 100; + yearset = 1; + /* FALLTHOUGH */ + case 10: /* YYMMDDhhmm */ + if (yearset) { + yearset = ATOI2(arg); + t->tm_year += yearset; + } else { + yearset = ATOI2(arg); + if (yearset < 69) + t->tm_year = yearset + 2000; + else + t->tm_year = yearset + 1900; + } + t->tm_year -= 1900; /* Convert to UNIX time. */ + /* FALLTHROUGH */ + case 8: /* MMDDhhmm */ + t->tm_mon = ATOI2(arg); + --t->tm_mon; /* Convert from 01-12 to 00-11 */ + t->tm_mday = ATOI2(arg); + t->tm_hour = ATOI2(arg); + t->tm_min = ATOI2(arg); + break; + default: + goto terr; + } + + t->tm_isdst = -1; /* Figure out DST. */ + + *timep = mktime(t); + if (*timep == -1) { +terr: fprintf(stderr, + "%s: out of range or illegal time specification: [[CC]YY]MMDDhhmm[.SS]", + progname); + exit (1); + } +} + +void +usage() +{ + (void)fprintf(stderr, + "usage: db_recover [-cVv] [-h home] [-t [[CC]YY]MMDDhhmm[.SS]]\n"); + exit(1); +} + +void +version_check() +{ + int v_major, v_minor, v_patch; + + /* Make sure we're loaded with the right version of the DB library. */ + (void)db_version(&v_major, &v_minor, &v_patch); + if (v_major != DB_VERSION_MAJOR || + v_minor != DB_VERSION_MINOR || v_patch != DB_VERSION_PATCH) { + fprintf(stderr, + "%s: version %d.%d.%d doesn't match library version %d.%d.%d\n", + progname, DB_VERSION_MAJOR, DB_VERSION_MINOR, + DB_VERSION_PATCH, v_major, v_minor, v_patch); + exit (1); + } +} diff --git a/db/db_stat/db_stat.c b/db/db_stat/db_stat.c new file mode 100644 index 000000000..9d80caa48 --- /dev/null +++ b/db/db_stat/db_stat.c @@ -0,0 +1,989 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char copyright[] = + "Copyright (c) 1996-2000\nSleepycat Software Inc. All rights reserved.\n"; +static const char revid[] = + "$Id: db_stat.c,v 11.42 2001/01/18 18:36:59 bostic Exp $"; +#endif + +#ifndef NO_SYSTEM_INCLUDES +#include + +#if TIME_WITH_SYS_TIME +#include +#include +#else +#if HAVE_SYS_TIME_H +#include +#else +#include +#endif +#endif + +#include +#include +#include +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_shash.h" +#include "lock.h" +#include "mp.h" + +#define PCT(f, t, pgsize) \ + ((t) == 0 ? 0 : \ + (((double)(((t) * (pgsize)) - (f)) / ((t) * (pgsize))) * 100)) + +typedef enum { T_NOTSET, T_DB, T_ENV, T_LOCK, T_LOG, T_MPOOL, T_TXN } test_t; + +int argcheck __P((char *, const char *)); +int btree_stats __P((DB_ENV *, DB *, DB_BTREE_STAT *)); +int db_init __P((char *, test_t)); +void dl __P((const char *, u_long)); +void dl_bytes __P((const char *, u_long, u_long, u_long)); +int env_stats __P((DB_ENV *)); +int hash_stats __P((DB_ENV *, DB *)); +int lock_ok __P((char *)); +int lock_stats __P((DB_ENV *)); +int log_stats __P((DB_ENV *)); +int main __P((int, char *[])); +int mpool_ok __P((char *)); +int mpool_stats __P((DB_ENV *)); +void prflags __P((u_int32_t, const FN *)); +int queue_stats __P((DB_ENV *, DB *)); +int txn_compare __P((const void *, const void *)); +int txn_stats __P((DB_ENV *)); +void usage __P((void)); +void version_check __P((void)); + +DB_ENV *dbenv; +char *internal; +const char + *progname = "db_stat"; /* Program name. */ + +int +main(argc, argv) + int argc; + char *argv[]; +{ + extern char *optarg; + extern int optind; + DB_BTREE_STAT *sp; + DB *alt_dbp, *dbp; + test_t ttype; + int ch, checked, d_close, e_close, exitval, nflag, ret; + char *db, *home, *subdb; + + version_check(); + + dbp = NULL; + ttype = T_NOTSET; + nflag = 0; + d_close = e_close = exitval = 0; + db = home = subdb = NULL; + while ((ch = getopt(argc, argv, "C:cd:eh:lM:mNs:tV")) != EOF) + switch (ch) { + case 'C': + ttype = T_LOCK; + if (!argcheck(internal = optarg, "Acflmo")) + usage(); + break; + case 'c': + ttype = T_LOCK; + break; + case 'd': + db = optarg; + ttype = T_DB; + break; + case 'e': + ttype = T_ENV; + break; + case 'h': + home = optarg; + break; + case 'l': + ttype = T_LOG; + break; + case 'M': + ttype = T_MPOOL; + if (!argcheck(internal = optarg, "Ahlm")) + usage(); + break; + case 'm': + ttype = T_MPOOL; + break; + case 'N': + nflag = 1; + if ((ret = db_env_set_panicstate(0)) != 0) { + fprintf(stderr, + "%s: db_env_set_panicstate: %s\n", + progname, db_strerror(ret)); + return (1); + } + break; + case 's': + subdb = optarg; + ttype = T_DB; + break; + case 't': + ttype = T_TXN; + break; + case 'V': + printf("%s\n", db_version(NULL, NULL, NULL)); + exit(0); + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + switch (ttype) { + case T_DB: + if (db == NULL) + usage(); + break; + case T_NOTSET: + usage(); + /* NOTREACHED */ + default: + break; + } + + /* Handle possible interruptions. */ + __db_util_siginit(); + + /* + * Create an environment object and initialize it for error + * reporting. + */ + if ((ret = db_env_create(&dbenv, 0)) != 0) { + fprintf(stderr, + "%s: db_env_create: %s\n", progname, db_strerror(ret)); + goto shutdown; + } + e_close = 1; + + dbenv->set_errfile(dbenv, stderr); + dbenv->set_errpfx(dbenv, progname); + + if (nflag && (ret = dbenv->set_mutexlocks(dbenv, 0)) != 0) { + dbenv->err(dbenv, ret, "set_mutexlocks"); + goto shutdown; + } + + /* Initialize the environment. */ + if (db_init(home, ttype) != 0) + goto shutdown; + + switch (ttype) { + case T_DB: + /* Create the DB object and open the file. */ + if ((ret = db_create(&dbp, dbenv, 0)) != 0) { + dbenv->err(dbenv, ret, "db_create"); + goto shutdown; + } + + if ((ret = + dbp->open(dbp, db, subdb, DB_UNKNOWN, DB_RDONLY, 0)) != 0) { + dbp->err(dbp, ret, "open: %s", db); + goto shutdown; + } + + /* + * See if we can open this db read/write to update counts. + * If its a master-db then we cannot. So check to see, + * if its btree then it might be. + */ + checked = 0; + if (subdb == NULL && dbp->type == DB_BTREE) { + if ((ret = dbp->stat(dbp, &sp, NULL, 0)) != 0) { + dbp->err(dbp, ret, "dbp->stat"); + return (1); + } + checked = 1; + } + + if (subdb != NULL || + dbp->type != DB_BTREE || + (sp->bt_metaflags & BTM_SUBDB) == 0) { + if ((ret = db_create(&alt_dbp, dbenv, 0)) != 0) { + dbenv->err(dbenv, ret, "db_create"); + goto shutdown; + } + if ((ret = dbp->open(alt_dbp, + db, subdb, DB_UNKNOWN, 0, 0)) == 0) { + (void)dbp->close(dbp, 0); + dbp = alt_dbp; + } + /* Need to run again to update counts */ + checked = 0; + } + + d_close = 1; + switch (dbp->type) { + case DB_BTREE: + case DB_RECNO: + if (btree_stats(dbenv, dbp, checked == 1 ? sp : NULL)) + goto shutdown; + break; + case DB_HASH: + if (hash_stats(dbenv, dbp)) + goto shutdown; + break; + case DB_QUEUE: + if (queue_stats(dbenv, dbp)) + goto shutdown; + break; + case DB_UNKNOWN: + abort(); /* Impossible. */ + /* NOTREACHED */ + } + break; + case T_ENV: + if (env_stats(dbenv)) + exitval = 1; + break; + case T_LOCK: + if (lock_stats(dbenv)) + exitval = 1; + break; + case T_LOG: + if (log_stats(dbenv)) + exitval = 1; + break; + case T_MPOOL: + if (mpool_stats(dbenv)) + exitval = 1; + break; + case T_TXN: + if (txn_stats(dbenv)) + exitval = 1; + break; + case T_NOTSET: + abort(); /* Impossible. */ + /* NOTREACHED */ + } + + if (0) { +shutdown: exitval = 1; + } + if (d_close && (ret = dbp->close(dbp, 0)) != 0) { + exitval = 1; + dbp->err(dbp, ret, "close"); + } + if (e_close && (ret = dbenv->close(dbenv, 0)) != 0) { + exitval = 1; + fprintf(stderr, + "%s: dbenv->close: %s\n", progname, db_strerror(ret)); + } + + /* Resend any caught signal. */ + __db_util_sigresend(); + + return (exitval); +} + +/* + * env_stats -- + * Display environment statistics. + */ +int +env_stats(dbenvp) + DB_ENV *dbenvp; +{ + REGENV renv; + REGION *rp, regs[1024]; + int n, ret; + const char *lable; + + n = sizeof(regs) / sizeof(regs[0]); + if ((ret = __db_e_stat(dbenvp, &renv, regs, &n)) != 0) { + dbenvp->err(dbenvp, ret, "__db_e_stat"); + return (1); + } + + printf("%d.%d.%d\tEnvironment version.\n", + renv.majver, renv.minver, renv.patch); + printf("%lx\tMagic number.\n", (u_long)renv.magic); + printf("%d\tPanic value.\n", renv.panic); + + /* Adjust the reference count for us... */ + printf("%d\tReferences.\n", renv.refcnt - 1); + + dl("Locks granted without waiting.\n", + (u_long)renv.mutex.mutex_set_nowait); + dl("Locks granted after waiting.\n", + (u_long)renv.mutex.mutex_set_wait); + + while (n > 0) { + printf("%s\n", DB_LINE); + rp = ®s[--n]; + switch (rp->type) { + case REGION_TYPE_ENV: + lable = "Environment"; + break; + case REGION_TYPE_LOCK: + lable = "Lock"; + break; + case REGION_TYPE_LOG: + lable = "Log"; + break; + case REGION_TYPE_MPOOL: + lable = "Mpool"; + break; + case REGION_TYPE_MUTEX: + lable = "Mutex"; + break; + case REGION_TYPE_TXN: + lable = "Txn"; + break; + case INVALID_REGION_TYPE: + default: + lable = "Invalid"; + break; + } + printf("%s Region: %d.\n", lable, rp->id); + dl_bytes("Size", (u_long)0, (u_long)0, (u_long)rp->size); + printf("%ld\tSegment ID.\n", rp->segid); + dl("Locks granted without waiting.\n", + (u_long)rp->mutex.mutex_set_nowait); + dl("Locks granted after waiting.\n", + (u_long)rp->mutex.mutex_set_wait); + } + + return (0); +} + +/* + * btree_stats -- + * Display btree/recno statistics. + */ +int +btree_stats(dbenvp, dbp, msp) + DB_ENV *dbenvp; + DB *dbp; + DB_BTREE_STAT *msp; +{ + static const FN fn[] = { + { BTM_DUP, "duplicates" }, + { BTM_FIXEDLEN, "fixed-length" }, + { BTM_RECNO, "recno" }, + { BTM_RECNUM, "record-numbers" }, + { BTM_RENUMBER, "renumber" }, + { BTM_SUBDB, "multiple-databases" }, + { 0, NULL } + }; + DB_BTREE_STAT *sp; + int ret; + + COMPQUIET(dbenvp, NULL); + + if (msp != NULL) + sp = msp; + else if ((ret = dbp->stat(dbp, &sp, NULL, 0)) != 0) { + dbp->err(dbp, ret, "dbp->stat"); + return (1); + } + + printf("%lx\tBtree magic number.\n", (u_long)sp->bt_magic); + printf("%lu\tBtree version number.\n", (u_long)sp->bt_version); + prflags(sp->bt_metaflags, fn); + if (dbp->type == DB_BTREE) { +#ifdef NOT_IMPLEMENTED + dl("Maximum keys per-page.\n", (u_long)sp->bt_maxkey); +#endif + dl("Minimum keys per-page.\n", (u_long)sp->bt_minkey); + } + if (dbp->type == DB_RECNO) { + dl("Fixed-length record size.\n", (u_long)sp->bt_re_len); + if (isprint(sp->bt_re_pad) && !isspace(sp->bt_re_pad)) + printf("%c\tFixed-length record pad.\n", + (int)sp->bt_re_pad); + else + printf("0x%x\tFixed-length record pad.\n", + (int)sp->bt_re_pad); + } + dl("Underlying database page size.\n", (u_long)sp->bt_pagesize); + dl("Number of levels in the tree.\n", (u_long)sp->bt_levels); + dl(dbp->type == DB_BTREE ? + "Number of unique keys in the tree.\n" : + "Number of records in the tree.\n", (u_long)sp->bt_nkeys); + dl("Number of data items in the tree.\n", (u_long)sp->bt_ndata); + + dl("Number of tree internal pages.\n", (u_long)sp->bt_int_pg); + dl("Number of bytes free in tree internal pages", + (u_long)sp->bt_int_pgfree); + printf(" (%.0f%% ff).\n", + PCT(sp->bt_int_pgfree, sp->bt_int_pg, sp->bt_pagesize)); + + dl("Number of tree leaf pages.\n", (u_long)sp->bt_leaf_pg); + dl("Number of bytes free in tree leaf pages", + (u_long)sp->bt_leaf_pgfree); + printf(" (%.0f%% ff).\n", + PCT(sp->bt_leaf_pgfree, sp->bt_leaf_pg, sp->bt_pagesize)); + + dl("Number of tree duplicate pages.\n", (u_long)sp->bt_dup_pg); + dl("Number of bytes free in tree duplicate pages", + (u_long)sp->bt_dup_pgfree); + printf(" (%.0f%% ff).\n", + PCT(sp->bt_dup_pgfree, sp->bt_dup_pg, sp->bt_pagesize)); + + dl("Number of tree overflow pages.\n", (u_long)sp->bt_over_pg); + dl("Number of bytes free in tree overflow pages", + (u_long)sp->bt_over_pgfree); + printf(" (%.0f%% ff).\n", + PCT(sp->bt_over_pgfree, sp->bt_over_pg, sp->bt_pagesize)); + + dl("Number of pages on the free list.\n", (u_long)sp->bt_free); + + return (0); +} + +/* + * hash_stats -- + * Display hash statistics. + */ +int +hash_stats(dbenvp, dbp) + DB_ENV *dbenvp; + DB *dbp; +{ + static const FN fn[] = { + { DB_HASH_DUP, "duplicates" }, + { DB_HASH_SUBDB,"multiple-databases" }, + { 0, NULL } + }; + DB_HASH_STAT *sp; + int ret; + + COMPQUIET(dbenvp, NULL); + + if ((ret = dbp->stat(dbp, &sp, NULL, 0)) != 0) { + dbp->err(dbp, ret, "dbp->stat"); + return (1); + } + + printf("%lx\tHash magic number.\n", (u_long)sp->hash_magic); + printf("%lu\tHash version number.\n", (u_long)sp->hash_version); + prflags(sp->hash_metaflags, fn); + dl("Underlying database page size.\n", (u_long)sp->hash_pagesize); + dl("Number of keys in the database.\n", (u_long)sp->hash_nkeys); + dl("Number of data items in the database.\n", (u_long)sp->hash_ndata); + + dl("Number of hash buckets.\n", (u_long)sp->hash_buckets); + dl("Number of bytes free on bucket pages", (u_long)sp->hash_bfree); + printf(" (%.0f%% ff).\n", + PCT(sp->hash_bfree, sp->hash_buckets, sp->hash_pagesize)); + + dl("Number of overflow pages.\n", (u_long)sp->hash_bigpages); + dl("Number of bytes free in overflow pages", + (u_long)sp->hash_big_bfree); + printf(" (%.0f%% ff).\n", + PCT(sp->hash_big_bfree, sp->hash_bigpages, sp->hash_pagesize)); + + dl("Number of bucket overflow pages.\n", (u_long)sp->hash_overflows); + dl("Number of bytes free in bucket overflow pages", + (u_long)sp->hash_ovfl_free); + printf(" (%.0f%% ff).\n", + PCT(sp->hash_ovfl_free, sp->hash_overflows, sp->hash_pagesize)); + + dl("Number of duplicate pages.\n", (u_long)sp->hash_dup); + dl("Number of bytes free in duplicate pages", + (u_long)sp->hash_dup_free); + printf(" (%.0f%% ff).\n", + PCT(sp->hash_dup_free, sp->hash_dup, sp->hash_pagesize)); + + dl("Number of pages on the free list.\n", (u_long)sp->hash_free); + + return (0); +} + +/* + * queue_stats -- + * Display queue statistics. + */ +int +queue_stats(dbenvp, dbp) + DB_ENV *dbenvp; + DB *dbp; +{ + DB_QUEUE_STAT *sp; + int ret; + + COMPQUIET(dbenvp, NULL); + + if ((ret = dbp->stat(dbp, &sp, NULL, 0)) != 0) { + dbp->err(dbp, ret, "dbp->stat"); + return (1); + } + + printf("%lx\tQueue magic number.\n", (u_long)sp->qs_magic); + printf("%lu\tQueue version number.\n", (u_long)sp->qs_version); + dl("Fixed-length record size.\n", (u_long)sp->qs_re_len); + if (isprint(sp->qs_re_pad) && !isspace(sp->qs_re_pad)) + printf("%c\tFixed-length record pad.\n", (int)sp->qs_re_pad); + else + printf("0x%x\tFixed-length record pad.\n", (int)sp->qs_re_pad); + dl("Underlying database page size.\n", (u_long)sp->qs_pagesize); + dl("Number of records in the database.\n", (u_long)sp->qs_nkeys); + dl("Number of database pages.\n", (u_long)sp->qs_pages); + dl("Number of bytes free in database pages", (u_long)sp->qs_pgfree); + printf(" (%.0f%% ff).\n", + PCT(sp->qs_pgfree, sp->qs_pages, sp->qs_pagesize)); + printf("%lu\tFirst undeleted record.\n", (u_long)sp->qs_first_recno); + printf( + "%lu\tLast allocated record number.\n", (u_long)sp->qs_cur_recno); + + return (0); +} + +/* + * lock_stats -- + * Display lock statistics. + */ +int +lock_stats(dbenvp) + DB_ENV *dbenvp; +{ + DB_LOCK_STAT *sp; + int ret; + + if (internal != NULL) { + __lock_dump_region(dbenvp, internal, stdout); + return (0); + } + + if ((ret = lock_stat(dbenvp, &sp, NULL)) != 0) { + dbenvp->err(dbenvp, ret, NULL); + return (1); + } + + dl("Last allocated locker ID.\n", (u_long)sp->st_lastid); + dl("Number of lock modes.\n", (u_long)sp->st_nmodes); + dl("Maximum number of locks possible.\n", (u_long)sp->st_maxlocks); + dl("Maximum number of lockers possible.\n", (u_long)sp->st_maxlockers); + dl("Maximum number of objects possible.\n", (u_long)sp->st_maxobjects); + dl("Current locks.\n", (u_long)sp->st_nlocks); + dl("Maximum number of locks so far.\n", (u_long)sp->st_maxnlocks); + dl("Current number of lockers.\n", (u_long)sp->st_nlockers); + dl("Maximum number lockers so far.\n", (u_long)sp->st_maxnlockers); + dl("Current number lock objects.\n", (u_long)sp->st_nobjects); + dl("Maximum number of lock objects so far.\n", + (u_long)sp->st_maxnobjects); + dl("Number of lock requests.\n", (u_long)sp->st_nrequests); + dl("Number of lock releases.\n", (u_long)sp->st_nreleases); + dl("Number of lock requests that would have waited.\n", + (u_long)sp->st_nnowaits); + dl("Number of lock conflicts.\n", (u_long)sp->st_nconflicts); + dl("Number of deadlocks.\n", (u_long)sp->st_ndeadlocks); + dl_bytes("Lock region size", + (u_long)0, (u_long)0, (u_long)sp->st_regsize); + dl("The number of region locks granted without waiting.\n", + (u_long)sp->st_region_nowait); + dl("The number of region locks granted after waiting.\n", + (u_long)sp->st_region_wait); + + return (0); +} + +/* + * log_stats -- + * Display log statistics. + */ +int +log_stats(dbenvp) + DB_ENV *dbenvp; +{ + DB_LOG_STAT *sp; + int ret; + + if ((ret = log_stat(dbenvp, &sp, NULL)) != 0) { + dbenvp->err(dbenvp, ret, NULL); + return (1); + } + + printf("%lx\tLog magic number.\n", (u_long)sp->st_magic); + printf("%lu\tLog version number.\n", (u_long)sp->st_version); + dl_bytes("Log region size", + (u_long)0, (u_long)0, (u_long)sp->st_regsize); + dl_bytes("Log record cache size", + (u_long)0, (u_long)0, (u_long)sp->st_lg_bsize); + printf("%#o\tLog file mode.\n", sp->st_mode); + if (sp->st_lg_max % MEGABYTE == 0) + printf("%luMb\tLog file size.\n", + (u_long)sp->st_lg_max / MEGABYTE); + else if (sp->st_lg_max % 1024 == 0) + printf("%luKb\tLog file size.\n", (u_long)sp->st_lg_max / 1024); + else + printf("%lu\tLog file size.\n", (u_long)sp->st_lg_max); + dl_bytes("Log bytes written", + (u_long)0, (u_long)sp->st_w_mbytes, (u_long)sp->st_w_bytes); + dl_bytes("Log bytes written since last checkpoint", + (u_long)0, (u_long)sp->st_wc_mbytes, (u_long)sp->st_wc_bytes); + dl("Total log file writes.\n", (u_long)sp->st_wcount); + dl("Total log file write due to overflow.\n", + (u_long)sp->st_wcount_fill); + dl("Total log file flushes.\n", (u_long)sp->st_scount); + printf("%lu\tCurrent log file number.\n", (u_long)sp->st_cur_file); + printf("%lu\tCurrent log file offset.\n", (u_long)sp->st_cur_offset); + dl("The number of region locks granted without waiting.\n", + (u_long)sp->st_region_nowait); + dl("The number of region locks granted after waiting.\n", + (u_long)sp->st_region_wait); + + return (0); +} + +/* + * mpool_stats -- + * Display mpool statistics. + */ +int +mpool_stats(dbenvp) + DB_ENV *dbenvp; +{ + DB_MPOOL_FSTAT **fsp; + DB_MPOOL_STAT *gsp; + int ret; + + if (internal != NULL) { + __memp_dump_region(dbenvp, internal, stdout); + return (1); + } + + if ((ret = memp_stat(dbenvp, &gsp, &fsp, NULL)) != 0) { + dbenvp->err(dbenvp, ret, NULL); + return (1); + } + + dl_bytes("Total cache size", + (u_long)gsp->st_gbytes, (u_long)0, (u_long)gsp->st_bytes); + dl("Number of caches.\n", (u_long)gsp->st_ncache); + dl("Pool individual cache size.\n", (u_long)gsp->st_regsize); + dl("Requested pages found in the cache", (u_long)gsp->st_cache_hit); + if (gsp->st_cache_hit + gsp->st_cache_miss != 0) + printf(" (%.0f%%)", ((double)gsp->st_cache_hit / + (gsp->st_cache_hit + gsp->st_cache_miss)) * 100); + printf(".\n"); + dl("Requested pages mapped into the process' address space.\n", + (u_long)gsp->st_map); + dl("Requested pages not found in the cache.\n", + (u_long)gsp->st_cache_miss); + dl("Pages created in the cache.\n", (u_long)gsp->st_page_create); + dl("Pages read into the cache.\n", (u_long)gsp->st_page_in); + dl("Pages written from the cache to the backing file.\n", + (u_long)gsp->st_page_out); + dl("Clean pages forced from the cache.\n", + (u_long)gsp->st_ro_evict); + dl("Dirty pages forced from the cache.\n", + (u_long)gsp->st_rw_evict); + dl("Dirty buffers written by trickle-sync thread.\n", + (u_long)gsp->st_page_trickle); + dl("Current clean buffer count.\n", + (u_long)gsp->st_page_clean); + dl("Current dirty buffer count.\n", + (u_long)gsp->st_page_dirty); + dl("Number of hash buckets used for page location.\n", + (u_long)gsp->st_hash_buckets); + dl("Total number of times hash chains searched for a page.\n", + (u_long)gsp->st_hash_searches); + dl("The longest hash chain searched for a page.\n", + (u_long)gsp->st_hash_longest); + dl("Total number of hash buckets examined for page location.\n", + (u_long)gsp->st_hash_examined); + dl("The number of region locks granted without waiting.\n", + (u_long)gsp->st_region_nowait); + dl("The number of region locks granted after waiting.\n", + (u_long)gsp->st_region_wait); + + for (; fsp != NULL && *fsp != NULL; ++fsp) { + printf("%s\n", DB_LINE); + printf("Pool File: %s\n", (*fsp)->file_name); + dl("Page size.\n", (u_long)(*fsp)->st_pagesize); + dl("Requested pages found in the cache", + (u_long)(*fsp)->st_cache_hit); + if ((*fsp)->st_cache_hit + (*fsp)->st_cache_miss != 0) + printf(" (%.0f%%)", ((double)(*fsp)->st_cache_hit / + ((*fsp)->st_cache_hit + (*fsp)->st_cache_miss)) * + 100); + printf(".\n"); + dl("Requested pages mapped into the process' address space.\n", + (u_long)(*fsp)->st_map); + dl("Requested pages not found in the cache.\n", + (u_long)(*fsp)->st_cache_miss); + dl("Pages created in the cache.\n", + (u_long)(*fsp)->st_page_create); + dl("Pages read into the cache.\n", + (u_long)(*fsp)->st_page_in); + dl("Pages written from the cache to the backing file.\n", + (u_long)(*fsp)->st_page_out); + } + + return (0); +} + +/* + * txn_stats -- + * Display transaction statistics. + */ +int +txn_stats(dbenvp) + DB_ENV *dbenvp; +{ + DB_TXN_STAT *sp; + u_int32_t i; + int ret; + const char *p; + + if ((ret = txn_stat(dbenvp, &sp, NULL)) != 0) { + dbenvp->err(dbenvp, ret, NULL); + return (1); + } + + p = sp->st_last_ckp.file == 0 ? + "No checkpoint LSN." : "File/offset for last checkpoint LSN."; + printf("%lu/%lu\t%s\n", + (u_long)sp->st_last_ckp.file, (u_long)sp->st_last_ckp.offset, p); + p = sp->st_pending_ckp.file == 0 ? + "No pending checkpoint LSN." : + "File/offset for last pending checkpoint LSN."; + printf("%lu/%lu\t%s\n", + (u_long)sp->st_pending_ckp.file, + (u_long)sp->st_pending_ckp.offset, p); + if (sp->st_time_ckp == 0) + printf("0\tNo checkpoint timestamp.\n"); + else + printf("%.24s\tCheckpoint timestamp.\n", + ctime(&sp->st_time_ckp)); + printf("%lx\tLast transaction ID allocated.\n", + (u_long)sp->st_last_txnid); + dl("Maximum number of active transactions possible.\n", + (u_long)sp->st_maxtxns); + dl("Active transactions.\n", (u_long)sp->st_nactive); + dl("Maximum active transactions.\n", (u_long)sp->st_maxnactive); + dl("Number of transactions begun.\n", (u_long)sp->st_nbegins); + dl("Number of transactions aborted.\n", (u_long)sp->st_naborts); + dl("Number of transactions committed.\n", (u_long)sp->st_ncommits); + dl_bytes("Transaction region size", + (u_long)0, (u_long)0, (u_long)sp->st_regsize); + dl("The number of region locks granted without waiting.\n", + (u_long)sp->st_region_nowait); + dl("The number of region locks granted after waiting.\n", + (u_long)sp->st_region_wait); + qsort(sp->st_txnarray, + sp->st_nactive, sizeof(sp->st_txnarray[0]), txn_compare); + for (i = 0; i < sp->st_nactive; ++i) + printf("\tid: %lx; initial LSN file/offest %lu/%lu\n", + (u_long)sp->st_txnarray[i].txnid, + (u_long)sp->st_txnarray[i].lsn.file, + (u_long)sp->st_txnarray[i].lsn.offset); + + return (0); +} + +int +txn_compare(a1, b1) + const void *a1, *b1; +{ + const DB_TXN_ACTIVE *a, *b; + + a = a1; + b = b1; + + if (a->txnid > b->txnid) + return (1); + if (a->txnid < b->txnid) + return (-1); + return (0); +} + +/* + * dl -- + * Display a big value. + */ +void +dl(msg, value) + const char *msg; + u_long value; +{ + /* + * Two formats: if less than 10 million, display as the number, if + * greater than 10 million display as ###M. + */ + if (value < 10000000) + printf("%lu\t%s", value, msg); + else + printf("%luM\t%s", value / 1000000, msg); +} + +/* + * dl_bytes -- + * Display a big number of bytes. + */ +void +dl_bytes(msg, gbytes, mbytes, bytes) + const char *msg; + u_long gbytes, mbytes, bytes; +{ + const char *sep; + u_long sbytes; + int showbytes; + + sbytes = bytes; + while (bytes > MEGABYTE) { + ++mbytes; + bytes -= MEGABYTE; + } + while (mbytes > GIGABYTE / MEGABYTE) { + ++gbytes; + --mbytes; + } + + sep = ""; + showbytes = 0; + if (gbytes > 0) { + printf("%luGB", gbytes); + sep = " "; + showbytes = 1; + } + if (mbytes > 0) { + printf("%s%luMB", sep, mbytes); + sep = " "; + showbytes = 1; + } + if (bytes > 1024) { + printf("%s%luKB", sep, bytes / 1024); + bytes %= 1024; + sep = " "; + showbytes = 1; + } + if (bytes > 0) + printf("%s%luB", sep, bytes); + printf("\t%s", msg); + if (showbytes) + printf(" (%lu bytes)", sbytes); + printf(".\n"); +} + +/* + * prflags -- + * Print out flag values. + */ +void +prflags(flags, fnp) + u_int32_t flags; + const FN *fnp; +{ + const char *sep; + + sep = "\t"; + printf("Flags:"); + for (; fnp->mask != 0; ++fnp) + if (fnp->mask & flags) { + printf("%s%s", sep, fnp->name); + sep = ", "; + } + printf("\n"); +} + +/* + * db_init -- + * Initialize the environment. + */ +int +db_init(home, ttype) + char *home; + test_t ttype; +{ + int ret; + + /* + * If our environment open fails, and we're trying to look at a + * shared region, it's a hard failure. + */ + if ((ret = dbenv->open(dbenv, + home, DB_JOINENV | DB_USE_ENVIRON, 0)) == 0) + return (0); + if (ttype != T_DB) { + dbenv->err(dbenv, ret, "DBENV->open%s%s", + home == NULL ? "" : ": ", home == NULL ? "" : home); + return (1); + } + + /* + * We're trying to look at a database. + * + * An environment is required because we may be trying to look at + * databases in directories other than the current one. We could + * avoid using an environment iff the -h option wasn't specified, + * but that seems like more work than it's worth. + * + * + * No environment exists. Create one, but make it private so that + * no files are actually created. + * + * Note that we will probably just drop core if the environment + * we joined above does not include a memory pool. This is probably + * acceptable; trying to use an existing shared environment that + * does not contain a memory pool to look at a database can + * be safely construed as operator error, I think. + */ + if ((ret = dbenv->open(dbenv, home, + DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE | DB_USE_ENVIRON, 0)) == 0) + return (0); + + /* An environment is required. */ + dbenv->err(dbenv, ret, "open"); + return (1); +} + +/* + * argcheck -- + * Return if argument flags are okay. + */ +int +argcheck(arg, ok_args) + char *arg; + const char *ok_args; +{ + for (; *arg != '\0'; ++arg) + if (strchr(ok_args, *arg) == NULL) + return (0); + return (1); +} + +void +usage() +{ + fprintf(stderr, "usage: db_stat %s\n", + "[-celmNtV] [-C Acflmo] [-d file [-s file]] [-h home] [-M Ahlm]"); + exit (1); +} + +void +version_check() +{ + int v_major, v_minor, v_patch; + + /* Make sure we're loaded with the right version of the DB library. */ + (void)db_version(&v_major, &v_minor, &v_patch); + if (v_major != DB_VERSION_MAJOR || + v_minor != DB_VERSION_MINOR || v_patch != DB_VERSION_PATCH) { + fprintf(stderr, + "%s: version %d.%d.%d doesn't match library version %d.%d.%d\n", + progname, DB_VERSION_MAJOR, DB_VERSION_MINOR, + DB_VERSION_PATCH, v_major, v_minor, v_patch); + exit (1); + } +} diff --git a/db/db_upgrade/db_upgrade.c b/db/db_upgrade/db_upgrade.c new file mode 100644 index 000000000..dc29b6c7e --- /dev/null +++ b/db/db_upgrade/db_upgrade.c @@ -0,0 +1,173 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char copyright[] = + "Copyright (c) 1996-2000\nSleepycat Software Inc. All rights reserved.\n"; +static const char revid[] = + "$Id: db_upgrade.c,v 1.13 2001/01/18 18:36:59 bostic Exp $"; +#endif + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#include +#endif + +#include "db_int.h" + +int main __P((int, char *[])); +void usage __P((void)); +void version_check __P((void)); + +const char + *progname = "db_upgrade"; /* Program name. */ + +int +main(argc, argv) + int argc; + char *argv[]; +{ + extern char *optarg; + extern int optind; + DB *dbp; + DB_ENV *dbenv; + u_int32_t flags; + int ch, e_close, exitval, nflag, ret, t_ret; + char *home; + + version_check(); + + dbenv = NULL; + flags = nflag = 0; + e_close = exitval = 0; + home = NULL; + while ((ch = getopt(argc, argv, "h:NsV")) != EOF) + switch (ch) { + case 'h': + home = optarg; + break; + case 'N': + nflag = 1; + if ((ret = db_env_set_panicstate(0)) != 0) { + fprintf(stderr, + "%s: db_env_set_panicstate: %s\n", + progname, db_strerror(ret)); + exit (1); + } + break; + case 's': + LF_SET(DB_DUPSORT); + break; + case 'V': + printf("%s\n", db_version(NULL, NULL, NULL)); + exit(0); + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (argc <= 0) + usage(); + + /* Handle possible interruptions. */ + __db_util_siginit(); + + /* + * Create an environment object and initialize it for error + * reporting. + */ + if ((ret = db_env_create(&dbenv, 0)) != 0) { + fprintf(stderr, "%s: db_env_create: %s\n", + progname, db_strerror(ret)); + goto shutdown; + } + e_close = 1; + + dbenv->set_errfile(dbenv, stderr); + dbenv->set_errpfx(dbenv, progname); + + if (nflag && (ret = dbenv->set_mutexlocks(dbenv, 0)) != 0) { + dbenv->err(dbenv, ret, "set_mutexlocks"); + goto shutdown; + } + + /* + * If attaching to a pre-existing environment fails, create a + * private one and try again. + */ + if ((ret = dbenv->open(dbenv, + home, DB_JOINENV | DB_USE_ENVIRON, 0)) != 0 && + (ret = dbenv->open(dbenv, home, + DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE | DB_USE_ENVIRON, 0)) != 0) { + dbenv->err(dbenv, ret, "open"); + goto shutdown; + } + + for (; !__db_util_interrupted() && argv[0] != NULL; ++argv) { + if ((ret = db_create(&dbp, dbenv, 0)) != 0) { + fprintf(stderr, + "%s: db_create: %s\n", progname, db_strerror(ret)); + goto shutdown; + } + dbp->set_errfile(dbp, stderr); + dbp->set_errpfx(dbp, progname); + if ((ret = dbp->upgrade(dbp, argv[0], flags)) != 0) + dbp->err(dbp, ret, "DB->upgrade: %s", argv[0]); + if ((t_ret = dbp->close(dbp, 0)) != 0 && ret == 0) { + dbp->err(dbp, ret, "DB->close: %s", argv[0]); + ret = t_ret; + } + if (ret != 0) + goto shutdown; + } + + if (0) { +shutdown: exitval = 1; + } + if (e_close && (ret = dbenv->close(dbenv, 0)) != 0) { + exitval = 1; + fprintf(stderr, + "%s: dbenv->close: %s\n", progname, db_strerror(ret)); + } + + /* Resend any caught signal. */ + __db_util_sigresend(); + + return (exitval); +} + +void +usage() +{ + fprintf(stderr, "usage: db_upgrade [-NsV] [-h home] db_file ...\n"); + exit (1); +} + +void +version_check() +{ + int v_major, v_minor, v_patch; + + /* Make sure we're loaded with the right version of the DB library. */ + (void)db_version(&v_major, &v_minor, &v_patch); + if (v_major != DB_VERSION_MAJOR || + v_minor != DB_VERSION_MINOR || v_patch != DB_VERSION_PATCH) { + fprintf(stderr, + "%s: version %d.%d.%d doesn't match library version %d.%d.%d\n", + progname, DB_VERSION_MAJOR, DB_VERSION_MINOR, + DB_VERSION_PATCH, v_major, v_minor, v_patch); + exit (1); + } +} diff --git a/db/db_verify/db_verify.c b/db/db_verify/db_verify.c new file mode 100644 index 000000000..3bbf14caa --- /dev/null +++ b/db/db_verify/db_verify.c @@ -0,0 +1,182 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char copyright[] = + "Copyright (c) 1996-2000\nSleepycat Software Inc. All rights reserved.\n"; +static const char revid[] = + "$Id: db_verify.c,v 1.15 2001/01/18 18:36:59 bostic Exp $"; +#endif + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#include +#endif + +#include "db_int.h" + +int main __P((int, char *[])); +void usage __P((void)); +void version_check __P((void)); + +const char + *progname = "db_verify"; /* Program name. */ + +int +main(argc, argv) + int argc; + char *argv[]; +{ + extern char *optarg; + extern int optind; + DB *dbp; + DB_ENV *dbenv; + int ch, e_close, exitval, nflag, quiet, ret, t_ret; + char *home; + + version_check(); + + dbenv = NULL; + e_close = exitval = nflag = quiet = 0; + home = NULL; + while ((ch = getopt(argc, argv, "h:NqV")) != EOF) + switch (ch) { + case 'h': + home = optarg; + break; + case 'N': + nflag = 1; + if ((ret = db_env_set_panicstate(0)) != 0) { + fprintf(stderr, + "%s: db_env_set_panicstate: %s\n", + progname, db_strerror(ret)); + exit (1); + } + break; + break; + case 'q': + quiet = 1; + break; + case 'V': + printf("%s\n", db_version(NULL, NULL, NULL)); + exit(0); + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (argc <= 0) + usage(); + + /* Handle possible interruptions. */ + __db_util_siginit(); + + /* + * Create an environment object and initialize it for error + * reporting. + */ + if ((ret = db_env_create(&dbenv, 0)) != 0) { + fprintf(stderr, "%s: db_env_create: %s\n", + progname, db_strerror(ret)); + goto shutdown; + } + e_close = 1; + + /* + * XXX + * We'd prefer to have error output configured while calling + * db_env_create, but there's no way to turn it off once it's + * turned on. + */ + if (!quiet) { + dbenv->set_errfile(dbenv, stderr); + dbenv->set_errpfx(dbenv, progname); + } + + if (nflag && (ret = dbenv->set_mutexlocks(dbenv, 0)) != 0) { + dbenv->err(dbenv, ret, "set_mutexlocks"); + goto shutdown; + } + + /* + * Attach to an mpool if it exists, but if that fails, attach + * to a private region. + */ + if ((ret = dbenv->open(dbenv, + home, DB_INIT_MPOOL | DB_USE_ENVIRON, 0)) != 0 && + (ret = dbenv->open(dbenv, home, + DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE | DB_USE_ENVIRON, 0)) != 0) { + dbenv->err(dbenv, ret, "open"); + goto shutdown; + } + + for (; !__db_util_interrupted() && argv[0] != NULL; ++argv) { + if ((ret = db_create(&dbp, dbenv, 0)) != 0) { + fprintf(stderr, + "%s: db_create: %s\n", progname, db_strerror(ret)); + goto shutdown; + } + if (!quiet) { + dbp->set_errfile(dbp, stderr); + dbp->set_errpfx(dbp, progname); + } + if ((ret = dbp->verify(dbp, argv[0], NULL, NULL, 0)) != 0) + dbp->err(dbp, ret, "DB->verify: %s", argv[0]); + if ((t_ret = dbp->close(dbp, 0)) != 0 && ret == 0) { + dbp->err(dbp, ret, "DB->close: %s", argv[0]); + ret = t_ret; + } + if (ret != 0) + goto shutdown; + } + + if (0) { +shutdown: exitval = 1; + } + if (e_close && (ret = dbenv->close(dbenv, 0)) != 0) { + exitval = 1; + fprintf(stderr, + "%s: dbenv->close: %s\n", progname, db_strerror(ret)); + } + + /* Resend any caught signal. */ + __db_util_sigresend(); + + return (exitval); +} + +void +usage() +{ + fprintf(stderr, "usage: db_verify [-NqV] [-h home] db_file ...\n"); + exit (1); +} + +void +version_check() +{ + int v_major, v_minor, v_patch; + + /* Make sure we're loaded with the right version of the DB library. */ + (void)db_version(&v_major, &v_minor, &v_patch); + if (v_major != DB_VERSION_MAJOR || + v_minor != DB_VERSION_MINOR || v_patch != DB_VERSION_PATCH) { + fprintf(stderr, + "%s: version %d.%d.%d doesn't match library version %d.%d.%d\n", + progname, DB_VERSION_MAJOR, DB_VERSION_MINOR, + DB_VERSION_PATCH, v_major, v_minor, v_patch); + exit (1); + } +} diff --git a/db/dbm/dbm.c b/db/dbm/dbm.c new file mode 100644 index 000000000..e5f423572 --- /dev/null +++ b/db/dbm/dbm.c @@ -0,0 +1,489 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993 + * Margo Seltzer. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Margo Seltzer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: dbm.c,v 11.7 2000/11/30 00:58:35 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#endif + +#define DB_DBM_HSEARCH 1 +#include "db_int.h" + +/* + * + * This package provides dbm and ndbm compatible interfaces to DB. + * + * The DBM routines, which call the NDBM routines. + */ +static DBM *__cur_db; + +static void __db_no_open __P((void)); + +int +__db_dbm_init(file) + char *file; +{ + if (__cur_db != NULL) + (void)dbm_close(__cur_db); + if ((__cur_db = + dbm_open(file, O_CREAT | O_RDWR, __db_omode("rw----"))) != NULL) + return (0); + if ((__cur_db = dbm_open(file, O_RDONLY, 0)) != NULL) + return (0); + return (-1); +} + +int +__db_dbm_close() +{ + if (__cur_db != NULL) { + dbm_close(__cur_db); + __cur_db = NULL; + } + return (0); +} + +datum +__db_dbm_fetch(key) + datum key; +{ + datum item; + + if (__cur_db == NULL) { + __db_no_open(); + item.dptr = 0; + return (item); + } + return (dbm_fetch(__cur_db, key)); +} + +datum +__db_dbm_firstkey() +{ + datum item; + + if (__cur_db == NULL) { + __db_no_open(); + item.dptr = 0; + return (item); + } + return (dbm_firstkey(__cur_db)); +} + +datum +__db_dbm_nextkey(key) + datum key; +{ + datum item; + + COMPQUIET(key.dsize, 0); + + if (__cur_db == NULL) { + __db_no_open(); + item.dptr = 0; + return (item); + } + return (dbm_nextkey(__cur_db)); +} + +int +__db_dbm_delete(key) + datum key; +{ + if (__cur_db == NULL) { + __db_no_open(); + return (-1); + } + return (dbm_delete(__cur_db, key)); +} + +int +__db_dbm_store(key, dat) + datum key, dat; +{ + if (__cur_db == NULL) { + __db_no_open(); + return (-1); + } + return (dbm_store(__cur_db, key, dat, DBM_REPLACE)); +} + +static void +__db_no_open() +{ + (void)fprintf(stderr, "dbm: no open database.\n"); +} + +/* + * This package provides dbm and ndbm compatible interfaces to DB. + * + * The NDBM routines, which call the DB routines. + */ +/* + * Returns: + * *DBM on success + * NULL on failure + */ +DBM * +__db_ndbm_open(file, oflags, mode) + const char *file; + int oflags, mode; +{ + DB *dbp; + DBC *dbc; + int ret; + char path[MAXPATHLEN]; + + /* + * !!! + * Don't use sprintf(3)/snprintf(3) -- the former is dangerous, and + * the latter isn't standard, and we're manipulating strings handed + * us by the application. + */ + if (strlen(file) + strlen(DBM_SUFFIX) + 1 > sizeof(path)) { + __os_set_errno(ENAMETOOLONG); + return (NULL); + } + (void)strcpy(path, file); + (void)strcat(path, DBM_SUFFIX); + if ((ret = db_create(&dbp, NULL, 0)) != 0) { + __os_set_errno(ret); + return (NULL); + } + + /* + * !!! + * The historic ndbm library corrected for opening O_WRONLY. + */ + if (oflags & O_WRONLY) { + oflags &= ~O_WRONLY; + oflags |= O_RDWR; + } + + if ((ret = dbp->set_pagesize(dbp, 4096)) != 0 || + (ret = dbp->set_h_ffactor(dbp, 40)) != 0 || + (ret = dbp->set_h_nelem(dbp, 1)) != 0 || + (ret = dbp->open(dbp, + path, NULL, DB_HASH, __db_oflags(oflags), mode)) != 0) { + __os_set_errno(ret); + return (NULL); + } + + if ((ret = dbp->cursor(dbp, NULL, &dbc, 0)) != 0) { + (void)dbp->close(dbp, 0); + __os_set_errno(ret); + return (NULL); + } + + return ((DBM *)dbc); +} + +/* + * Returns: + * Nothing. + */ +void +__db_ndbm_close(dbm) + DBM *dbm; +{ + DBC *dbc; + + dbc = (DBC *)dbm; + + (void)dbc->dbp->close(dbc->dbp, 0); +} + +/* + * Returns: + * DATUM on success + * NULL on failure + */ +datum +__db_ndbm_fetch(dbm, key) + DBM *dbm; + datum key; +{ + DBC *dbc; + DBT _key, _data; + datum data; + int ret; + + dbc = (DBC *)dbm; + + memset(&_key, 0, sizeof(DBT)); + memset(&_data, 0, sizeof(DBT)); + _key.size = key.dsize; + _key.data = key.dptr; + + /* + * Note that we can't simply use the dbc we have to do a c_get/SET, + * because that cursor is the one used for sequential iteration and + * it has to remain stable in the face of intervening gets and puts. + */ + if ((ret = dbc->dbp->get(dbc->dbp, NULL, &_key, &_data, 0)) == 0) { + data.dptr = _data.data; + data.dsize = _data.size; + } else { + data.dptr = NULL; + data.dsize = 0; + if (ret == DB_NOTFOUND) + __os_set_errno(ENOENT); + else { + __os_set_errno(ret); + F_SET(dbc->dbp, DB_DBM_ERROR); + } + } + return (data); +} + +/* + * Returns: + * DATUM on success + * NULL on failure + */ +datum +__db_ndbm_firstkey(dbm) + DBM *dbm; +{ + DBC *dbc; + DBT _key, _data; + datum key; + int ret; + + dbc = (DBC *)dbm; + + memset(&_key, 0, sizeof(DBT)); + memset(&_data, 0, sizeof(DBT)); + + if ((ret = dbc->c_get(dbc, &_key, &_data, DB_FIRST)) == 0) { + key.dptr = _key.data; + key.dsize = _key.size; + } else { + key.dptr = NULL; + key.dsize = 0; + if (ret == DB_NOTFOUND) + __os_set_errno(ENOENT); + else { + __os_set_errno(ret); + F_SET(dbc->dbp, DB_DBM_ERROR); + } + } + return (key); +} + +/* + * Returns: + * DATUM on success + * NULL on failure + */ +datum +__db_ndbm_nextkey(dbm) + DBM *dbm; +{ + DBC *dbc; + DBT _key, _data; + datum key; + int ret; + + dbc = (DBC *)dbm; + + memset(&_key, 0, sizeof(DBT)); + memset(&_data, 0, sizeof(DBT)); + + if ((ret = dbc->c_get(dbc, &_key, &_data, DB_NEXT)) == 0) { + key.dptr = _key.data; + key.dsize = _key.size; + } else { + key.dptr = NULL; + key.dsize = 0; + if (ret == DB_NOTFOUND) + __os_set_errno(ENOENT); + else { + __os_set_errno(ret); + F_SET(dbc->dbp, DB_DBM_ERROR); + } + } + return (key); +} + +/* + * Returns: + * 0 on success + * <0 failure + */ +int +__db_ndbm_delete(dbm, key) + DBM *dbm; + datum key; +{ + DBC *dbc; + DBT _key; + int ret; + + dbc = (DBC *)dbm; + + memset(&_key, 0, sizeof(DBT)); + _key.data = key.dptr; + _key.size = key.dsize; + + if ((ret = dbc->dbp->del(dbc->dbp, NULL, &_key, 0)) == 0) + return (0); + + if (ret == DB_NOTFOUND) + __os_set_errno(ENOENT); + else { + __os_set_errno(ret); + F_SET(dbc->dbp, DB_DBM_ERROR); + } + return (-1); +} + +/* + * Returns: + * 0 on success + * <0 failure + * 1 if DBM_INSERT and entry exists + */ +int +__db_ndbm_store(dbm, key, data, flags) + DBM *dbm; + datum key, data; + int flags; +{ + DBC *dbc; + DBT _key, _data; + int ret; + + dbc = (DBC *)dbm; + + memset(&_key, 0, sizeof(DBT)); + _key.data = key.dptr; + _key.size = key.dsize; + + memset(&_data, 0, sizeof(DBT)); + _data.data = data.dptr; + _data.size = data.dsize; + + if ((ret = dbc->dbp->put(dbc->dbp, NULL, + &_key, &_data, flags == DBM_INSERT ? DB_NOOVERWRITE : 0)) == 0) + return (0); + + if (ret == DB_KEYEXIST) + return (1); + + __os_set_errno(ret); + F_SET(dbc->dbp, DB_DBM_ERROR); + return (-1); +} + +int +__db_ndbm_error(dbm) + DBM *dbm; +{ + DBC *dbc; + + dbc = (DBC *)dbm; + + return (F_ISSET(dbc->dbp, DB_DBM_ERROR)); +} + +int +__db_ndbm_clearerr(dbm) + DBM *dbm; +{ + DBC *dbc; + + dbc = (DBC *)dbm; + + F_CLR(dbc->dbp, DB_DBM_ERROR); + return (0); +} + +/* + * Returns: + * 1 if read-only + * 0 if not read-only + */ +int +__db_ndbm_rdonly(dbm) + DBM *dbm; +{ + DBC *dbc; + + dbc = (DBC *)dbm; + + return (F_ISSET(dbc->dbp, DB_AM_RDONLY) ? 1 : 0); +} + +/* + * XXX + * We only have a single file descriptor that we can return, not two. Return + * the same one for both files. Hopefully, the user is using it for locking + * and picked one to use at random. + */ +int +__db_ndbm_dirfno(dbm) + DBM *dbm; +{ + return (dbm_pagfno(dbm)); +} + +int +__db_ndbm_pagfno(dbm) + DBM *dbm; +{ + DBC *dbc; + int fd; + + dbc = (DBC *)dbm; + + (void)dbc->dbp->fd(dbc->dbp, &fd); + return (fd); +} diff --git a/db/dist/Makefile.in b/db/dist/Makefile.in new file mode 100644 index 000000000..73f82cd56 --- /dev/null +++ b/db/dist/Makefile.in @@ -0,0 +1,999 @@ +# $Id: Makefile.in,v 11.66 2000/11/27 16:27:51 bostic Exp $ + +srcdir= @srcdir@/.. +builddir=. + +################################################## +# C, C++ +################################################## +CPPFLAGS= -I$(builddir) -I$(srcdir)/include @CPPFLAGS@ +CFLAGS= -c $(CPPFLAGS) @CFLAGS@ +CXXFLAGS= -c $(CPPFLAGS) @CXXFLAGS@ + +CC= @MAKEFILE_CC@ +CCLINK= @MAKEFILE_CCLINK@ +CXX= @MAKEFILE_CXX@ + +INSTALLER= @INSTALLER@ + +LDFLAGS= @LDFLAGS@ +LIBDB_ARGS= @LIBDB_ARGS@ +LIBJSO_LIBS= @LIBJSO_LIBS@ +LIBS= @LIBS@ +LIBSO_LIBS= @LIBSO_LIBS@ +LIBTOOL= @LIBTOOL@ +LIBTSO_LIBS= @LIBTSO_LIBS@ +LIBXSO_LIBS= @LIBXSO_LIBS@ + +POSTLINK= @POSTLINK@ +SOLINK= @SOLINK@ +SOFLAGS= @SOFLAGS@ +SOMAJOR= @DB_VERSION_MAJOR@ +SOVERSION= @DB_VERSION_MAJOR@.@DB_VERSION_MINOR@ + +libdb= libdb.a + +libso_base= libdb +libso_linkname= $(libso_base)-$(SOVERSION).la +libso= $(libso_base)-$(SOVERSION).@SOSUFFIX@ +libso_target= $(libso_base)-$(SOVERSION).la +libso_default= $(libso_base).@SOSUFFIX@ +libso_major= $(libso_base)-$(SOMAJOR).@SOSUFFIX@ + +################################################## +# C++ +# +# C++ support is optional, and it can be used with or without shared libraries. +# You must configure it using: +# --enable-cxx +################################################## +libcxx= libdb_cxx.a +libxso_base= libdb_cxx +libxso= $(libxso_base)-$(SOVERSION).@SOSUFFIX@ +libxso_target= $(libxso_base)-$(SOVERSION).la +libxso_default= $(libxso_base).@SOSUFFIX@ +libxso_major= $(libxso_base)-$(SOMAJOR).@SOSUFFIX@ + +################################################## +# JAVA +# +# Java support is optional and requires shared librarires. +# You must configure it using: +# --enable-java --enable-dynamic +################################################## +CLASSPATH= $(JAVA_CLASSTOP) +JAR= @JAR@ +JAVAC= env CLASSPATH=$(CLASSPATH) @JAVAC@ +JAVACFLAGS= @JAVACFLAGS@ +JAVA_BUILTFILE= .javabuilt +JAVA_CLASSTOP= $(srcdir)/java/classes +JAVA_SRCDIR= $(srcdir)/java/src +JAVA_DBREL= com/sleepycat/db +JAVA_DBDIR= $(JAVA_SRCDIR)/$(JAVA_DBREL) +JAVA_EXDIR= $(JAVA_SRCDIR)/com/sleepycat/examples + +libj_jarfile= db.jar +libjso_base= libdb_java +libjso= $(libjso_base)-$(SOVERSION).@SOSUFFIX@ +libjso_target= $(libjso_base)-$(SOVERSION).la +libjso_default= $(libjso_base).@SOSUFFIX@ +libjso_major= $(libjso_base)-$(SOMAJOR).@SOSUFFIX@ +libjso_g= $(libjso_base)-$(SOVERSION)_g.@SOSUFFIX@ + +################################################## +# TCL +# +# Tcl support is optional and requires shared libraries. +# You must configure it using: +# --enable-tcl --with-tcl=DIR --enable-dynamic +################################################## +TCFLAGS= @TCFLAGS@ +libtso_base= libdb_tcl +libtso= $(libtso_base)-$(SOVERSION).@SOSUFFIX@ +libtso_target= $(libtso_base)-$(SOVERSION).la +libtso_default= $(libtso_base).@SOSUFFIX@ +libtso_major= $(libtso_base)-$(SOMAJOR).@SOSUFFIX@ + +################################################## +# DB_DUMP185 UTILITY +# +# The db_dump185 application should be compiled using the system's db.h file +# (which should be a DB 1.85/1.86 include file), and the system's 1.85/1.86 +# object library. To include the right db.h, don't include -I$(builddir) on +# the compile line. You may also need to add a local include directory and +# local libraries, for example. Do that by adding -I options to the DB185INC +# line, and -l options to the DB185LIB line. +################################################## +DB185INC= -c @CFLAGS@ -I$(srcdir)/include @CPPFLAGS@ +DB185LIB= + +################################################## +# INSTALLATION DIRECTORIES AND PERMISSIONS +################################################## +prefix= @prefix@ +exec_prefix=@exec_prefix@ +bindir= @bindir@ +includedir=@includedir@ +libdir= @libdir@ +docdir= $(prefix)/docs + +dmode= 755 +emode= 555 +fmode= 444 + +transform=@program_transform_name@ + +################################################## +# PATHS FOR STANDARD USER-LEVEL COMMANDS +################################################## +SHELL= @db_cv_path_sh@ +ar= @db_cv_path_ar@ cr +chmod= @db_cv_path_chmod@ +cp= @db_cv_path_cp@ +ln= @db_cv_path_ln@ +mkdir= @db_cv_path_mkdir@ +ranlib= @db_cv_path_ranlib@ +rm= @db_cv_path_rm@ +strip= @db_cv_path_strip@ + +################################################## +# NOTHING BELOW THIS LINE SHOULD EVER NEED TO BE MODIFIED. +################################################## +OBJS= @ADDITIONAL_OBJS@ @LIBOBJS@ @RPC_OBJS@ bt_compare@o@ bt_conv@o@ \ + bt_curadj@o@ bt_cursor@o@ bt_delete@o@ bt_method@o@ bt_open@o@ \ + bt_put@o@ bt_rec@o@ bt_reclaim@o@ bt_recno@o@ bt_rsearch@o@ \ + bt_search@o@ bt_split@o@ bt_stat@o@ bt_upgrade@o@ bt_verify@o@ \ + btree_auto@o@ crdel_auto@o@ crdel_rec@o@ db@o@ db_am@o@ db_auto@o@ \ + db_byteorder@o@ db_cam@o@ db_conv@o@ db_dispatch@o@ db_dup@o@ \ + db_err@o@ db_getlong@o@ db_iface@o@ db_join@o@ db_log2@o@ \ + db_meta@o@ db_method@o@ db_overflow@o@ db_pr@o@ db_rec@o@ \ + db_reclaim@o@ db_ret@o@ db_salloc@o@ db_shash@o@ db_upg@o@ \ + db_upg_opd@o@ db_vrfy@o@ db_vrfyutil@o@ dbm@o@ env_method@o@ \ + env_open@o@ env_recover@o@ env_region@o@ hash@o@ hash_auto@o@ \ + hash_conv@o@ hash_dup@o@ hash_func@o@ hash_meta@o@ hash_method@o@ \ + hash_page@o@ hash_rec@o@ hash_reclaim@o@ hash_stat@o@ hash_upgrade@o@ \ + hash_verify@o@ hsearch@o@ lock@o@ lock_conflict@o@ \ + lock_deadlock@o@ lock_method@o@ lock_region@o@ lock_stat@o@ \ + lock_util@o@ log@o@ log_archive@o@ log_auto@o@ log_compare@o@ \ + log_findckp@o@ log_get@o@ log_method@o@ log_put@o@ log_rec@o@ \ + log_register@o@ mp_alloc@o@ mp_bh@o@ mp_fget@o@ mp_fopen@o@ \ + mp_fput@o@ mp_fset@o@ mp_method@o@ mp_region@o@ mp_register@o@ \ + mp_stat@o@ mp_sync@o@ mp_trickle@o@ mutex@o@ os_abs@o@ \ + os_alloc@o@ os_dir@o@ os_errno@o@ os_fid@o@ os_finit@o@ \ + os_fsync@o@ os_handle@o@ os_map@o@ os_method@o@ os_oflags@o@ \ + os_open@o@ os_region@o@ os_rename@o@ os_root@o@ os_rpath@o@ \ + os_rw@o@ os_seek@o@ os_sleep@o@ os_spin@o@ os_stat@o@ \ + os_tmpdir@o@ os_unlink@o@ qam@o@ qam_auto@o@ qam_conv@o@ qam_files@o@ \ + qam_method@o@ qam_open@o@ qam_rec@o@ qam_stat@o@ qam_upgrade@o@ \ + qam_verify@o@ txn@o@ txn_auto@o@ txn_rec@o@ txn_region@o@ xa@o@ \ + xa_db@o@ xa_map@o@ + +COBJS= cxx_app@o@ cxx_except@o@ cxx_lock@o@ cxx_log@o@ cxx_mpool@o@ \ + cxx_table@o@ cxx_txn@o@ + +DBSOBJS=dbs@o@ dbs_am@o@ dbs_checkpoint@o@ dbs_debug@o@ dbs_handles@o@ \ + dbs_log@o@ dbs_qam@o@ dbs_spawn@o@ dbs_trickle@o@ dbs_util@o@ \ + dbs_yield@o@ + +EOBJS= ex_access@o@ ex_btrec@o@ ex_dbclient@o@ ex_env@o@ ex_lock@o@ \ + ex_mpool@o@ ex_thread@o@ ex_tpcb@o@ + +JOBJS= java_Db@o@ java_DbEnv@o@ java_DbLock@o@ java_DbLsn@o@ java_DbTxn@o@ \ + java_Dbc@o@ java_Dbt@o@ java_info@o@ java_locked@o@ java_util@o@ + +RPC_OBJS=client@o@ db_server_clnt@o@ db_server_xdr@o@ gen_client@o@ \ + gen_client_ret@o@ +RPC_SRV=db_server_proc@o@ db_server_svc@o@ db_server_util@o@ gen_db_server@o@ + +TOBJS= tcl_compat@o@ tcl_db@o@ tcl_db_pkg@o@ tcl_dbcursor@o@ tcl_env@o@ \ + tcl_internal@o@ tcl_lock@o@ tcl_log@o@ tcl_mp@o@ tcl_txn@o@ + +UOBJS= db_archive@o@ db_checkpoint@o@ db_deadlock@o@ db_dump185@o@ \ + db_dump@o@ db_load@o@ db_printlog@o@ db_recover@o@ db_stat@o@ \ + db_upgrade@o@ db_verify@o@ util_log@o@ util_sig@o@ + +PROGS= @ADDITIONAL_PROGS@ db_archive db_checkpoint db_deadlock \ + db_dump db_load db_printlog db_recover db_stat db_upgrade db_verify + +JAVA_DBSRCS=\ + $(JAVA_DBDIR)/Db.java $(JAVA_DBDIR)/DbAppendRecno.java \ + $(JAVA_DBDIR)/DbBtreeCompare.java \ + $(JAVA_DBDIR)/DbBtreePrefix.java $(JAVA_DBDIR)/DbBtreeStat.java \ + $(JAVA_DBDIR)/DbConstants.java $(JAVA_DBDIR)/DbDeadlockException.java \ + $(JAVA_DBDIR)/DbDupCompare.java $(JAVA_DBDIR)/DbEnv.java \ + $(JAVA_DBDIR)/DbEnvFeedback.java $(JAVA_DBDIR)/DbErrcall.java \ + $(JAVA_DBDIR)/DbException.java $(JAVA_DBDIR)/DbFeedback.java \ + $(JAVA_DBDIR)/DbHash.java $(JAVA_DBDIR)/DbHashStat.java \ + $(JAVA_DBDIR)/DbKeyRange.java $(JAVA_DBDIR)/DbLock.java \ + $(JAVA_DBDIR)/DbLockStat.java $(JAVA_DBDIR)/DbLogStat.java \ + $(JAVA_DBDIR)/DbLsn.java $(JAVA_DBDIR)/DbMemoryException.java \ + $(JAVA_DBDIR)/DbMpoolFStat.java $(JAVA_DBDIR)/DbMpoolStat.java \ + $(JAVA_DBDIR)/DbOutputStreamErrcall.java \ + $(JAVA_DBDIR)/DbQueueStat.java $(JAVA_DBDIR)/DbRecoveryInit.java \ + $(JAVA_DBDIR)/DbRunRecoveryException.java $(JAVA_DBDIR)/DbTxn.java \ + $(JAVA_DBDIR)/DbTxnRecover.java $(JAVA_DBDIR)/DbTxnStat.java \ + $(JAVA_DBDIR)/Dbc.java $(JAVA_DBDIR)/Dbt.java + +JAVA_EXSRCS=\ + $(JAVA_EXDIR)/AccessExample.java \ + $(JAVA_EXDIR)/BtRecExample.java \ + $(JAVA_EXDIR)/EnvExample.java \ + $(JAVA_EXDIR)/LockExample.java \ + $(JAVA_EXDIR)/TpcbExample.java + +################################################## +# Note: Berkeley DB Makefiles are configured to build either a static or +# a dynamic library. You should not attempt to build both library types +# in the same directory, as they have incompatible object file formats. +# To build both static and dynamic libraries, create two separate build +# directories, and configure and build them separately. +################################################## +all: @DEFAULT_LIB@ @ADDITIONAL_LIBS@ @ADDITIONAL_LANG@ $(PROGS) + +$(libdb): $(OBJS) + $(ar) $@ $(OBJS) + test ! -f $(ranlib) || $(ranlib) $@ + +$(libcxx): $(COBJS) $(OBJS) + $(ar) $@ $(COBJS) $(OBJS) + test ! -f $(ranlib) || $(ranlib) $@ + +$(libso_target): $(OBJS) + $(SOLINK) $(SOFLAGS) -o $(libso_target) \ + $(OBJS) $(LDFLAGS) $(LIBSO_LIBS) + +$(libxso_target): $(COBJS) $(OBJS) + $(SOLINK) $(SOFLAGS) -o $(libxso_target) \ + $(COBJS) $(OBJS) $(LDFLAGS) $(LIBXSO_LIBS) + +$(libjso_target): $(JOBJS) $(OBJS) + $(SOLINK) $(SOFLAGS) -o $(libjso_target) \ + $(JOBJS) $(OBJS) $(LDFLAGS) $(LIBJSO_LIBS) + +$(libtso_target): $(TOBJS) $(OBJS) + $(SOLINK) $(SOFLAGS) -o $(libtso_target) \ + $(TOBJS) $(OBJS) $(LDFLAGS) $(LIBTSO_LIBS) + +################################################## +# Creating individual dependencies and actions for building class +# files is possible, but it is very messy and error prone. +################################################## +java: $(JAVA_CLASSTOP) $(JAVA_BUILTFILE) + +$(JAVA_BUILTFILE): $(JAVA_DBSRCS) $(JAVA_EXSRCS) + @test -f $(rm) || (echo 'rm not found.'; exit 1) + @test -f $(cp) || (echo 'cp not found.'; exit 1) + $(JAVAC) -d $(JAVA_CLASSTOP) $(JAVACFLAGS) $(JAVA_DBSRCS) + @cd $(JAVA_CLASSTOP) && $(JAR) cf $(libj_jarfile) $(JAVA_DBREL) + $(JAVAC) -d $(JAVA_CLASSTOP) $(JAVACFLAGS) $(JAVA_EXSRCS) + @echo This file helps with building java using make > $(JAVA_BUILTFILE) + +$(JAVA_CLASSTOP): + @test -f $(mkdir) || (echo 'mkdir not found.'; exit 1) + $(mkdir) $(JAVA_CLASSTOP) + +################################################## +# Utilities +################################################## +berkeley_db_svc: $(RPC_SRV) util_log@o@ @DEFAULT_LIB@ + $(CCLINK) -o $@ $(LDFLAGS) $(RPC_SRV) util_log@o@ $(LIBDB_ARGS) $(LIBS) + $(POSTLINK) $@ + +db_archive: db_archive@o@ util_sig@o@ @DEFAULT_LIB@ + $(CCLINK) -o $@ $(LDFLAGS) \ + db_archive@o@ util_sig@o@ $(LIBDB_ARGS) $(LIBS) + $(POSTLINK) $@ + +db_checkpoint: db_checkpoint@o@ util_log@o@ util_sig@o@ @DEFAULT_LIB@ + $(CCLINK) -o $@ $(LDFLAGS) \ + db_checkpoint@o@ util_log@o@ util_sig@o@ $(LIBDB_ARGS) $(LIBS) + $(POSTLINK) $@ + +db_deadlock: db_deadlock@o@ util_log@o@ util_sig@o@ @DEFAULT_LIB@ + $(CCLINK) -o $@ $(LDFLAGS) \ + db_deadlock@o@ util_log@o@ util_sig@o@ $(LIBDB_ARGS) $(LIBS) + $(POSTLINK) $@ + +db_dump: db_dump@o@ util_sig@o@ @DEFAULT_LIB@ + $(CCLINK) -o $@ $(LDFLAGS) db_dump@o@ util_sig@o@ $(LIBDB_ARGS) $(LIBS) + $(POSTLINK) $@ + +db_dump185: db_dump185@o@ @LIBOBJS@ + $(CCLINK) -o $@ $(LDFLAGS) db_dump185@o@ @LIBOBJS@ $(DB185LIB) + $(POSTLINK) $@ + +db_load: db_load@o@ util_sig@o@ @DEFAULT_LIB@ + $(CCLINK) -o $@ $(LDFLAGS) db_load@o@ util_sig@o@ $(LIBDB_ARGS) $(LIBS) + $(POSTLINK) $@ + +db_printlog: db_printlog@o@ util_sig@o@ @DEFAULT_LIB@ + $(CCLINK) -o $@ $(LDFLAGS) \ + db_printlog@o@ util_sig@o@ $(LIBDB_ARGS) $(LIBS) + $(POSTLINK) $@ + +db_recover: db_recover@o@ util_sig@o@ @DEFAULT_LIB@ + $(CCLINK) -o $@ $(LDFLAGS) \ + db_recover@o@ util_sig@o@ $(LIBDB_ARGS) $(LIBS) + $(POSTLINK) $@ + +db_stat: db_stat@o@ util_sig@o@ @DEFAULT_LIB@ + $(CCLINK) -o $@ $(LDFLAGS) db_stat@o@ util_sig@o@ $(LIBDB_ARGS) $(LIBS) + $(POSTLINK) $@ + +db_upgrade: db_upgrade@o@ util_sig@o@ @DEFAULT_LIB@ + $(CCLINK) -o $@ $(LDFLAGS) \ + db_upgrade@o@ util_sig@o@ $(LIBDB_ARGS) $(LIBS) + $(POSTLINK) $@ + +db_verify: db_verify@o@ util_sig@o@ @DEFAULT_LIB@ + $(CCLINK) -o $@ $(LDFLAGS) \ + db_verify@o@ util_sig@o@ $(LIBDB_ARGS) $(LIBS) + $(POSTLINK) $@ + +################################################## +# Example programs +################################################## +ex_access: ex_access@o@ @DEFAULT_LIB@ + $(CCLINK) -o $@ $(LDFLAGS) ex_access@o@ $(LIBDB_ARGS) $(LIBS) + $(POSTLINK) $@ + +ex_btrec: ex_btrec@o@ @DEFAULT_LIB@ + $(CCLINK) -o $@ $(LDFLAGS) ex_btrec@o@ $(LIBDB_ARGS) $(LIBS) + $(POSTLINK) $@ + +ex_dbclient: ex_dbclient@o@ @DEFAULT_LIB@ + $(CCLINK) -o $@ $(LDFLAGS) ex_dbclient@o@ $(LIBDB_ARGS) $(LIBS) + $(POSTLINK) $@ + +ex_env: ex_env@o@ @DEFAULT_LIB@ + $(CCLINK) -o $@ $(LDFLAGS) ex_env@o@ $(LIBDB_ARGS) $(LIBS) + $(POSTLINK) $@ + +ex_lock: ex_lock@o@ @DEFAULT_LIB@ + $(CCLINK) -o $@ $(LDFLAGS) ex_lock@o@ $(LIBDB_ARGS) $(LIBS) + $(POSTLINK) $@ + +ex_mpool: ex_mpool@o@ @DEFAULT_LIB@ + $(CCLINK) -o $@ $(LDFLAGS) ex_mpool@o@ $(LIBDB_ARGS) $(LIBS) + $(POSTLINK) $@ + +ex_thread: ex_thread@o@ @DEFAULT_LIB@ + $(CCLINK) -o $@ $(LDFLAGS) ex_thread@o@ $(LIBDB_ARGS) $(LIBS) + $(POSTLINK) $@ + +ex_tpcb: ex_tpcb@o@ @DEFAULT_LIB@ + $(CCLINK) -o $@ $(LDFLAGS) ex_tpcb@o@ $(LIBDB_ARGS) $(LIBS) + $(POSTLINK) $@ + +################################################## +# Multi-threaded tester. +################################################## +dbs: $(DBSOBJS) @DEFAULT_LIB@ + $(CCLINK) -o $@ $(LDFLAGS) $(DBSOBJS) $(LIBDB_ARGS) @DBS_LIBS@ $(LIBS) + $(POSTLINK) $@ + +################################################## +# Standard Makefile targets. +################################################## +RMLIST= berkeley_db_svc db_dump185 dbs ex_access ex_btrec ex_dbclient \ + ex_env ex_lock ex_mpool ex_thread ex_tpcb +clean: + $(rm) -f $(OBJS) + $(rm) -f $(COBJS) $(DBSOBJS) $(EOBJS) $(CEOBJS) $(JOBJS) + $(rm) -f $(TOBJS) $(UOBJS) $(RPC_OBJS) $(RPC_SRV) + $(rm) -f $(PROGS) $(RMLIST) + $(rm) -f *@o@ *.o *.lo core *.core + $(rm) -rf ALL.OUT TESTDIR + $(rm) -rf .libs $(libdb) $(libcxx) + $(rm) -rf $(libso_target) $(libso) $(libso_default) $(libso_major) + $(rm) -rf $(libxso_target) $(libxso) $(libxso_default) $(libxso_major) + $(rm) -rf $(libtso_target) $(libtso) $(libtso_default) $(libtso_major) + $(rm) -rf $(libjso_target) $(libjso) $(libjso_default) $(libjso_major) + +depend obj: + +realclean distclean: clean + $(rm) -f Makefile config.cache config.log config.status db_config.h + $(rm) -f confdefs.h db.h db_int.h db_185.h include.tcl libtool + +install: all install_setup \ + install_include install_lib install_utilities install_docs + +uninstall: uninstall_utilities uninstall_include uninstall_lib uninstall_docs + +install_setup: + @test -f $(chmod) || (echo 'chmod not found.'; exit 1) + @test -f $(cp) || (echo 'cp not found.'; exit 1) + @test -f $(mkdir) || (echo 'mkdir not found.'; exit 1) + @test -f $(rm) || (echo 'rm not found.'; exit 1) + +install_include: + @echo "Installing DB include files: $(includedir) ..." + @test -d $(includedir) || \ + ($(mkdir) -p $(includedir) && $(chmod) $(dmode) $(includedir)) + @cd $(includedir) && $(rm) -f db.h db_185.h db_cxx.h + @$(cp) -p db.h \ + $(srcdir)/include/db_cxx.h @ADDITIONAL_INCS@ $(includedir) + @cd $(includedir) && $(chmod) $(fmode) db.h db_cxx.h @ADDITIONAL_INCS@ + +uninstall_include: + -cd $(includedir) && $(rm) -f db.h db_185.h db_cxx.h + +install_lib: @DEFAULT_INSTALL@ + +uninstall_lib: + -cd $(libdir) && $(rm) -f $(libdb) $(libcxx) \ + $(libso_target) $(libso) $(libso_default) $(libso_major) \ + $(libxso_target) $(libxso) $(libxso_default) $(libxso_major) \ + $(libtso_target) $(libtso) $(libtso_default) $(libtso_major) \ + $(libjso_target) $(libjso) $(libjso_default) $(libjso_major) \ + $(libj_jarfile) + +install_static: + @echo "Installing DB library: $(libdir) ..." + @test -d $(libdir) || \ + ($(mkdir) -p $(libdir) && $(chmod) $(dmode) $(libdir)) + @cd $(libdir) && $(rm) -f $(libdb) + @$(cp) -p $(libdb) $(libdir) + @cd $(libdir) && $(chmod) $(fmode) $(libdb) + +install_static_cxx: + @echo "Installing DB C++ static library: $(libdir) ..." + @test -d $(libdir) || \ + ($(mkdir) -p $(libdir) && $(chmod) $(dmode) $(libdir)) + @cd $(libdir) && $(rm) -f $(libcxx) + @$(cp) -p $(libcxx) $(libdir) + @cd $(libdir) && $(chmod) $(fmode) $(libcxx) + +install_dynamic: + @echo "Installing DB library: $(libdir) ..." + @test -d $(libdir) || \ + ($(mkdir) -p $(libdir) && $(chmod) $(dmode) $(libdir)) + @cd $(libdir) && $(rm) -f \ + $(libso_target) $(libso) $(libso_default) $(libso_major) + @$(INSTALLER) $(libso_target) $(libdir) + @cd $(libdir) && $(ln) -s $(libso) $(libso_default) + @cd $(libdir) && $(ln) -s $(libso) $(libso_major) + @$(LIBTOOL) --mode=finish $(libdir) + +install_dynamic_cxx: + @echo "Installing DB C++ library: $(libdir) ..." + @test -d $(libdir) || \ + ($(mkdir) -p $(libdir) && $(chmod) $(dmode) $(libdir)) + @cd $(libdir) && $(rm) -f \ + $(libxso_target) $(libxso) $(libxso_default) $(libxso_major) + @$(INSTALLER) $(libxso_target) $(libdir) + @cd $(libdir) && $(ln) -s $(libxso) $(libxso_default) + @cd $(libdir) && $(ln) -s $(libxso) $(libxso_major) + +install_tcl: + @echo "Installing DB Tcl library: $(libdir) ..." + @test -d $(libdir) || \ + ($(mkdir) -p $(libdir) && $(chmod) $(dmode) $(libdir)) + @cd $(libdir) && $(rm) -f \ + $(libtso_target) $(libtso) $(libtso_default) $(libtso_major) + @$(INSTALLER) $(libtso_target) $(libdir) + @cd $(libdir) && $(ln) -s $(libtso) $(libtso_default) + @cd $(libdir) && $(ln) -s $(libtso) $(libtso_major) + +install_java: + @echo "Installing DB Java library: $(libdir) ..." + @test -d $(libdir) || \ + ($(mkdir) -p $(libdir) && $(chmod) $(dmode) $(libdir)) + @cd $(libdir) && $(rm) -f \ + $(libjso_target) $(libjso) $(libjso_default) $(libjso_major) + @$(INSTALLER) $(libjso_target) $(libdir) + @cd $(libdir) && $(ln) -s $(libjso) $(libjso_default) + @cd $(libdir) && $(ln) -s $(libjso) $(libjso_major) + @cd $(libdir) && $(ln) -s $(libjso) $(libjso_g) + @$(cp) $(JAVA_CLASSTOP)/$(libj_jarfile) $(libdir) + +install_utilities: + @echo "Installing DB utilities: $(bindir) ..." + @test -d $(bindir) || \ + ($(mkdir) -p $(bindir) && $(chmod) $(dmode) $(bindir)) + @cd $(bindir) && $(rm) -f $(PROGS) + @$(INSTALLER) -fp $(PROGS) $(bindir) + @cd $(bindir) && (test ! -f $(strip) || $(strip) $(PROGS)) + @cd $(bindir) && $(chmod) $(emode) $(PROGS) + +uninstall_utilities: + -cd $(bindir) && $(rm) -f $(PROGS) + +install_docs: + @echo "Installing documentation: $(docdir) ..." + @test -d $(docdir) || \ + ($(mkdir) -p $(docdir) && $(chmod) $(dmode) $(docdir)) + @cd $(docdir) && $(rm) -rf * + @cd $(srcdir)/docs && $(cp) -pr * $(docdir)/ + +uninstall_docs: + -cd $(docdir) && $(rm) -rf * + +################################################## +# Object build rules. +################################################## +# Utilities +db_archive@o@: $(srcdir)/db_archive/db_archive.c + $(CC) $(CFLAGS) $? +db_checkpoint@o@: $(srcdir)/db_checkpoint/db_checkpoint.c + $(CC) $(CFLAGS) $? +db_deadlock@o@: $(srcdir)/db_deadlock/db_deadlock.c + $(CC) $(CFLAGS) $? +db_dump@o@: $(srcdir)/db_dump/db_dump.c + $(CC) $(CFLAGS) $? +db_dump185@o@: $(srcdir)/db_dump185/db_dump185.c + $(CC) $(DB185INC) $? +db_load@o@: $(srcdir)/db_load/db_load.c + $(CC) $(CFLAGS) $? +db_printlog@o@: $(srcdir)/db_printlog/db_printlog.c + $(CC) $(CFLAGS) $? +db_recover@o@: $(srcdir)/db_recover/db_recover.c + $(CC) $(CFLAGS) $? +db_stat@o@: $(srcdir)/db_stat/db_stat.c + $(CC) $(CFLAGS) $? +db_upgrade@o@: $(srcdir)/db_upgrade/db_upgrade.c + $(CC) $(CFLAGS) $? +db_verify@o@: $(srcdir)/db_verify/db_verify.c + $(CC) $(CFLAGS) $? + +# Examples +ex_access@o@: $(srcdir)/examples_c/ex_access.c + $(CC) $(CFLAGS) $? +ex_btrec@o@: $(srcdir)/examples_c/ex_btrec.c + $(CC) $(CFLAGS) $? +ex_dbclient@o@: $(srcdir)/examples_c/ex_dbclient.c + $(CC) $(CFLAGS) $? +ex_env@o@: $(srcdir)/examples_c/ex_env.c + $(CC) $(CFLAGS) $? +ex_lock@o@: $(srcdir)/examples_c/ex_lock.c + $(CC) $(CFLAGS) $? +ex_mpool@o@: $(srcdir)/examples_c/ex_mpool.c + $(CC) $(CFLAGS) $? +ex_thread@o@: $(srcdir)/examples_c/ex_thread.c + $(CC) $(CFLAGS) $? +ex_tpcb@o@: $(srcdir)/examples_c/ex_tpcb.c + $(CC) $(CFLAGS) $? + +# DB files +crdel_auto@o@: $(srcdir)/db/crdel_auto.c + $(CC) $(CFLAGS) $? +crdel_rec@o@: $(srcdir)/db/crdel_rec.c + $(CC) $(CFLAGS) $? +db@o@: $(srcdir)/db/db.c + $(CC) $(CFLAGS) $? +db_am@o@: $(srcdir)/db/db_am.c + $(CC) $(CFLAGS) $? +db_auto@o@: $(srcdir)/db/db_auto.c + $(CC) $(CFLAGS) $? +db_cam@o@: $(srcdir)/db/db_cam.c + $(CC) $(CFLAGS) $? +db_conv@o@: $(srcdir)/db/db_conv.c + $(CC) $(CFLAGS) $? +db_dispatch@o@: $(srcdir)/db/db_dispatch.c + $(CC) $(CFLAGS) $? +db_dup@o@: $(srcdir)/db/db_dup.c + $(CC) $(CFLAGS) $? +db_iface@o@: $(srcdir)/db/db_iface.c + $(CC) $(CFLAGS) $? +db_join@o@: $(srcdir)/db/db_join.c + $(CC) $(CFLAGS) $? +db_meta@o@: $(srcdir)/db/db_meta.c + $(CC) $(CFLAGS) $? +db_method@o@: $(srcdir)/db/db_method.c + $(CC) $(CFLAGS) $? +db_overflow@o@: $(srcdir)/db/db_overflow.c + $(CC) $(CFLAGS) $? +db_pr@o@: $(srcdir)/db/db_pr.c + $(CC) $(CFLAGS) $? +db_rec@o@: $(srcdir)/db/db_rec.c + $(CC) $(CFLAGS) $? +db_reclaim@o@: $(srcdir)/db/db_reclaim.c + $(CC) $(CFLAGS) $? +db_ret@o@: $(srcdir)/db/db_ret.c + $(CC) $(CFLAGS) $? +db_upg@o@: $(srcdir)/db/db_upg.c + $(CC) $(CFLAGS) $? +db_upg_opd@o@: $(srcdir)/db/db_upg_opd.c + $(CC) $(CFLAGS) $? +db_vrfy@o@: $(srcdir)/db/db_vrfy.c + $(CC) $(CFLAGS) $? +db_vrfyutil@o@: $(srcdir)/db/db_vrfyutil.c + $(CC) $(CFLAGS) $? + +# Environment files +db_salloc@o@: $(srcdir)/env/db_salloc.c + $(CC) $(CFLAGS) $? +db_shash@o@: $(srcdir)/env/db_shash.c + $(CC) $(CFLAGS) $? +env_method@o@: $(srcdir)/env/env_method.c + $(CC) $(CFLAGS) $? +env_open@o@: $(srcdir)/env/env_open.c + $(CC) $(CFLAGS) $? +env_recover@o@: $(srcdir)/env/env_recover.c + $(CC) $(CFLAGS) $? +env_region@o@: $(srcdir)/env/env_region.c + $(CC) $(CFLAGS) $? + +# Common files +db_byteorder@o@: $(srcdir)/common/db_byteorder.c + $(CC) $(CFLAGS) $? +db_err@o@: $(srcdir)/common/db_err.c + $(CC) $(CFLAGS) $? +db_getlong@o@: $(srcdir)/common/db_getlong.c + $(CC) $(CFLAGS) $? +db_log2@o@: $(srcdir)/common/db_log2.c + $(CC) $(CFLAGS) $? +util_log@o@: $(srcdir)/common/util_log.c + $(CC) $(CFLAGS) $? +util_sig@o@: $(srcdir)/common/util_sig.c + $(CC) $(CFLAGS) $? + +# Btree files +bt_compare@o@: $(srcdir)/btree/bt_compare.c + $(CC) $(CFLAGS) $? +bt_conv@o@: $(srcdir)/btree/bt_conv.c + $(CC) $(CFLAGS) $? +bt_curadj@o@: $(srcdir)/btree/bt_curadj.c + $(CC) $(CFLAGS) $? +bt_cursor@o@: $(srcdir)/btree/bt_cursor.c + $(CC) $(CFLAGS) $? +bt_delete@o@: $(srcdir)/btree/bt_delete.c + $(CC) $(CFLAGS) $? +bt_method@o@: $(srcdir)/btree/bt_method.c + $(CC) $(CFLAGS) $? +bt_open@o@: $(srcdir)/btree/bt_open.c + $(CC) $(CFLAGS) $? +bt_put@o@: $(srcdir)/btree/bt_put.c + $(CC) $(CFLAGS) $? +bt_rec@o@: $(srcdir)/btree/bt_rec.c + $(CC) $(CFLAGS) $? +bt_reclaim@o@: $(srcdir)/btree/bt_reclaim.c + $(CC) $(CFLAGS) $? +bt_recno@o@: $(srcdir)/btree/bt_recno.c + $(CC) $(CFLAGS) $? +bt_rsearch@o@: $(srcdir)/btree/bt_rsearch.c + $(CC) $(CFLAGS) $? +bt_search@o@: $(srcdir)/btree/bt_search.c + $(CC) $(CFLAGS) $? +bt_split@o@: $(srcdir)/btree/bt_split.c + $(CC) $(CFLAGS) $? +bt_stack@o@: $(srcdir)/btree/bt_stack.c + $(CC) $(CFLAGS) $? +bt_stat@o@: $(srcdir)/btree/bt_stat.c + $(CC) $(CFLAGS) $? +bt_upgrade@o@: $(srcdir)/btree/bt_upgrade.c + $(CC) $(CFLAGS) $? +bt_verify@o@: $(srcdir)/btree/bt_verify.c + $(CC) $(CFLAGS) $? +btree_auto@o@: $(srcdir)/btree/btree_auto.c + $(CC) $(CFLAGS) $? + +# Queue files +qam@o@: $(srcdir)/qam/qam.c + $(CC) $(CFLAGS) $? +qam_auto@o@: $(srcdir)/qam/qam_auto.c + $(CC) $(CFLAGS) $? +qam_conv@o@: $(srcdir)/qam/qam_conv.c + $(CC) $(CFLAGS) $? +qam_files@o@: $(srcdir)/qam/qam_files.c + $(CC) $(CFLAGS) $? +qam_method@o@: $(srcdir)/qam/qam_method.c + $(CC) $(CFLAGS) $? +qam_open@o@: $(srcdir)/qam/qam_open.c + $(CC) $(CFLAGS) $? +qam_rec@o@: $(srcdir)/qam/qam_rec.c + $(CC) $(CFLAGS) $? +qam_stat@o@: $(srcdir)/qam/qam_stat.c + $(CC) $(CFLAGS) $? +qam_upgrade@o@: $(srcdir)/qam/qam_upgrade.c + $(CC) $(CFLAGS) $? +qam_verify@o@: $(srcdir)/qam/qam_verify.c + $(CC) $(CFLAGS) $? + +# C++ files +cxx_app@o@: $(srcdir)/cxx/cxx_app.cpp + $(CXX) $(CXXFLAGS) $? +cxx_except@o@: $(srcdir)/cxx/cxx_except.cpp + $(CXX) $(CXXFLAGS) $? +cxx_lock@o@: $(srcdir)/cxx/cxx_lock.cpp + $(CXX) $(CXXFLAGS) $? +cxx_log@o@: $(srcdir)/cxx/cxx_log.cpp + $(CXX) $(CXXFLAGS) $? +cxx_mpool@o@: $(srcdir)/cxx/cxx_mpool.cpp + $(CXX) $(CXXFLAGS) $? +cxx_table@o@: $(srcdir)/cxx/cxx_table.cpp + $(CXX) $(CXXFLAGS) $? +cxx_txn@o@: $(srcdir)/cxx/cxx_txn.cpp + $(CXX) $(CXXFLAGS) $? + +# Java files +java_Db@o@::$(srcdir)/libdb_java/java_Db.c + $(CC) $(CFLAGS) $? +java_DbEnv@o@: $(srcdir)/libdb_java/java_DbEnv.c + $(CC) $(CFLAGS) $? +java_DbLock@o@: $(srcdir)/libdb_java/java_DbLock.c + $(CC) $(CFLAGS) $? +java_DbLsn@o@: $(srcdir)/libdb_java/java_DbLsn.c + $(CC) $(CFLAGS) $? +java_DbTxn@o@: $(srcdir)/libdb_java/java_DbTxn.c + $(CC) $(CFLAGS) $? +java_Dbc@o@: $(srcdir)/libdb_java/java_Dbc.c + $(CC) $(CFLAGS) $? +java_Dbt@o@: $(srcdir)/libdb_java/java_Dbt.c + $(CC) $(CFLAGS) $? +java_info@o@: $(srcdir)/libdb_java/java_info.c + $(CC) $(CFLAGS) $? +java_locked@o@: $(srcdir)/libdb_java/java_locked.c + $(CC) $(CFLAGS) $? +java_util@o@: $(srcdir)/libdb_java/java_util.c + $(CC) $(CFLAGS) $? + +# Tcl files +tcl_compat@o@: $(srcdir)/tcl/tcl_compat.c + $(CC) $(CFLAGS) $(TCFLAGS) $? +tcl_db@o@: $(srcdir)/tcl/tcl_db.c + $(CC) $(CFLAGS) $(TCFLAGS) $? +tcl_db_pkg@o@: $(srcdir)/tcl/tcl_db_pkg.c + $(CC) $(CFLAGS) $(TCFLAGS) $? +tcl_dbcursor@o@: $(srcdir)/tcl/tcl_dbcursor.c + $(CC) $(CFLAGS) $(TCFLAGS) $? +tcl_env@o@: $(srcdir)/tcl/tcl_env.c + $(CC) $(CFLAGS) $(TCFLAGS) $? +tcl_internal@o@: $(srcdir)/tcl/tcl_internal.c + $(CC) $(CFLAGS) $(TCFLAGS) $? +tcl_lock@o@: $(srcdir)/tcl/tcl_lock.c + $(CC) $(CFLAGS) $(TCFLAGS) $? +tcl_log@o@: $(srcdir)/tcl/tcl_log.c + $(CC) $(CFLAGS) $(TCFLAGS) $? +tcl_mp@o@: $(srcdir)/tcl/tcl_mp.c + $(CC) $(CFLAGS) $(TCFLAGS) $? +tcl_txn@o@: $(srcdir)/tcl/tcl_txn.c + $(CC) $(CFLAGS) $(TCFLAGS) $? + +# Hash files +hash_auto@o@: $(srcdir)/hash/hash_auto.c + $(CC) $(CFLAGS) $? +hash@o@: $(srcdir)/hash/hash.c + $(CC) $(CFLAGS) $? +hash_conv@o@: $(srcdir)/hash/hash_conv.c + $(CC) $(CFLAGS) $? +hash_dup@o@: $(srcdir)/hash/hash_dup.c + $(CC) $(CFLAGS) $? +hash_func@o@: $(srcdir)/hash/hash_func.c + $(CC) $(CFLAGS) $? +hash_meta@o@: $(srcdir)/hash/hash_meta.c + $(CC) $(CFLAGS) $? +hash_method@o@: $(srcdir)/hash/hash_method.c + $(CC) $(CFLAGS) $? +hash_page@o@: $(srcdir)/hash/hash_page.c + $(CC) $(CFLAGS) $? +hash_rec@o@: $(srcdir)/hash/hash_rec.c + $(CC) $(CFLAGS) $? +hash_reclaim@o@: $(srcdir)/hash/hash_reclaim.c + $(CC) $(CFLAGS) $? +hash_stat@o@: $(srcdir)/hash/hash_stat.c + $(CC) $(CFLAGS) $? +hash_upgrade@o@: $(srcdir)/hash/hash_upgrade.c + $(CC) $(CFLAGS) $? +hash_verify@o@: $(srcdir)/hash/hash_verify.c + $(CC) $(CFLAGS) $? + +# Lock files +lock@o@: $(srcdir)/lock/lock.c + $(CC) $(CFLAGS) $? +lock_conflict@o@:$(srcdir)/lock/lock_conflict.c + $(CC) $(CFLAGS) $? +lock_deadlock@o@:$(srcdir)/lock/lock_deadlock.c + $(CC) $(CFLAGS) $? +lock_method@o@:$(srcdir)/lock/lock_method.c + $(CC) $(CFLAGS) $? +lock_region@o@:$(srcdir)/lock/lock_region.c + $(CC) $(CFLAGS) $? +lock_stat@o@:$(srcdir)/lock/lock_stat.c + $(CC) $(CFLAGS) $? +lock_util@o@:$(srcdir)/lock/lock_util.c + $(CC) $(CFLAGS) $? + +# Log files +log@o@: $(srcdir)/log/log.c + $(CC) $(CFLAGS) $? +log_archive@o@: $(srcdir)/log/log_archive.c + $(CC) $(CFLAGS) $? +log_auto@o@: $(srcdir)/log/log_auto.c + $(CC) $(CFLAGS) $? +log_compare@o@: $(srcdir)/log/log_compare.c + $(CC) $(CFLAGS) $? +log_findckp@o@: $(srcdir)/log/log_findckp.c + $(CC) $(CFLAGS) $? +log_get@o@: $(srcdir)/log/log_get.c + $(CC) $(CFLAGS) $? +log_method@o@: $(srcdir)/log/log_method.c + $(CC) $(CFLAGS) $? +log_put@o@: $(srcdir)/log/log_put.c + $(CC) $(CFLAGS) $? +log_rec@o@: $(srcdir)/log/log_rec.c + $(CC) $(CFLAGS) $? +log_register@o@: $(srcdir)/log/log_register.c + $(CC) $(CFLAGS) $? + +# Mpool files +mp_alloc@o@: $(srcdir)/mp/mp_alloc.c + $(CC) $(CFLAGS) $? +mp_bh@o@: $(srcdir)/mp/mp_bh.c + $(CC) $(CFLAGS) $? +mp_fget@o@: $(srcdir)/mp/mp_fget.c + $(CC) $(CFLAGS) $? +mp_fopen@o@: $(srcdir)/mp/mp_fopen.c + $(CC) $(CFLAGS) $? +mp_fput@o@: $(srcdir)/mp/mp_fput.c + $(CC) $(CFLAGS) $? +mp_fset@o@: $(srcdir)/mp/mp_fset.c + $(CC) $(CFLAGS) $? +mp_method@o@: $(srcdir)/mp/mp_method.c + $(CC) $(CFLAGS) $? +mp_region@o@: $(srcdir)/mp/mp_region.c + $(CC) $(CFLAGS) $? +mp_register@o@: $(srcdir)/mp/mp_register.c + $(CC) $(CFLAGS) $? +mp_stat@o@: $(srcdir)/mp/mp_stat.c + $(CC) $(CFLAGS) $? +mp_sync@o@: $(srcdir)/mp/mp_sync.c + $(CC) $(CFLAGS) $? +mp_trickle@o@: $(srcdir)/mp/mp_trickle.c + $(CC) $(CFLAGS) $? + +# Mutex files +mutex@o@: $(srcdir)/mutex/mutex.c + $(CC) $(CFLAGS) $? +mut_fcntl@o@: $(srcdir)/mutex/mut_fcntl.c + $(CC) $(CFLAGS) $? +mut_pthread@o@: $(srcdir)/mutex/mut_pthread.c + $(CC) $(CFLAGS) $? +mut_tas@o@: $(srcdir)/mutex/mut_tas.c + $(CC) $(CFLAGS) $? +# UTS4 spinlock assembly. +uts4_cc@o@: $(srcdir)/mutex/uts4_cc.s + $(AS) $(ASFLAGS) -o $@ $? + +# Transaction files +txn@o@: $(srcdir)/txn/txn.c + $(CC) $(CFLAGS) $? +txn_auto@o@: $(srcdir)/txn/txn_auto.c + $(CC) $(CFLAGS) $? +txn_rec@o@: $(srcdir)/txn/txn_rec.c + $(CC) $(CFLAGS) $? +txn_region@o@: $(srcdir)/txn/txn_region.c + $(CC) $(CFLAGS) $? + +# XA files +xa@o@: $(srcdir)/xa/xa.c + $(CC) $(CFLAGS) $? +xa_db@o@: $(srcdir)/xa/xa_db.c + $(CC) $(CFLAGS) $? +xa_map@o@: $(srcdir)/xa/xa_map.c + $(CC) $(CFLAGS) $? + +# RPC client files +client@o@: $(srcdir)/rpc_client/client.c + $(CC) $(CFLAGS) $? +db_server_clnt@o@: $(srcdir)/rpc_client/db_server_clnt.c + $(CC) $(CFLAGS) $? +gen_client@o@: $(srcdir)/rpc_client/gen_client.c + $(CC) $(CFLAGS) $? +gen_client_ret@o@: $(srcdir)/rpc_client/gen_client_ret.c + $(CC) $(CFLAGS) $? + +# RPC server files +db_server_proc@o@: $(srcdir)/rpc_server/db_server_proc.c + $(CC) $(CFLAGS) $? +db_server_svc@o@: $(srcdir)/rpc_server/db_server_svc.c + $(CC) $(CFLAGS) $? +db_server_util@o@: $(srcdir)/rpc_server/db_server_util.c + $(CC) $(CFLAGS) $? +db_server_xdr@o@: $(srcdir)/rpc_server/db_server_xdr.c + $(CC) $(CFLAGS) $? +gen_db_server@o@: $(srcdir)/rpc_server/gen_db_server.c + $(CC) $(CFLAGS) $? + +# Historic compatibility files +db185@o@: $(srcdir)/db185/db185.c + $(CC) $(CFLAGS) $? +dbm@o@: $(srcdir)/dbm/dbm.c + $(CC) $(CFLAGS) $? +hsearch@o@: $(srcdir)/hsearch/hsearch.c + $(CC) $(CFLAGS) $? + +# OS specific files +os_abs@o@: $(srcdir)/os/os_abs.c + $(CC) $(CFLAGS) $? +os_alloc@o@: $(srcdir)/os/os_alloc.c + $(CC) $(CFLAGS) $? +os_dir@o@: $(srcdir)/os/os_dir.c + $(CC) $(CFLAGS) $? +os_errno@o@: $(srcdir)/os/os_errno.c + $(CC) $(CFLAGS) $? +os_fid@o@: $(srcdir)/os/os_fid.c + $(CC) $(CFLAGS) $? +os_finit@o@: $(srcdir)/os/os_finit.c + $(CC) $(CFLAGS) $? +os_fsync@o@: $(srcdir)/os/os_fsync.c + $(CC) $(CFLAGS) $? +os_handle@o@: $(srcdir)/os/os_handle.c + $(CC) $(CFLAGS) $? +os_map@o@: $(srcdir)/os/os_map.c + $(CC) $(CFLAGS) $? +os_method@o@: $(srcdir)/os/os_method.c + $(CC) $(CFLAGS) $? +os_oflags@o@: $(srcdir)/os/os_oflags.c + $(CC) $(CFLAGS) $? +os_open@o@: $(srcdir)/os/os_open.c + $(CC) $(CFLAGS) $? +os_region@o@: $(srcdir)/os/os_region.c + $(CC) $(CFLAGS) $? +os_rename@o@: $(srcdir)/os/os_rename.c + $(CC) $(CFLAGS) $? +os_root@o@: $(srcdir)/os/os_root.c + $(CC) $(CFLAGS) $? +os_rpath@o@: $(srcdir)/os/os_rpath.c + $(CC) $(CFLAGS) $? +os_rw@o@: $(srcdir)/os/os_rw.c + $(CC) $(CFLAGS) $? +os_seek@o@: $(srcdir)/os/os_seek.c + $(CC) $(CFLAGS) $? +os_sleep@o@: $(srcdir)/os/os_sleep.c + $(CC) $(CFLAGS) $? +os_spin@o@: $(srcdir)/os/os_spin.c + $(CC) $(CFLAGS) $? +os_stat@o@: $(srcdir)/os/os_stat.c + $(CC) $(CFLAGS) $? +os_tmpdir@o@: $(srcdir)/os/os_tmpdir.c + $(CC) $(CFLAGS) $? +os_unlink@o@: $(srcdir)/os/os_unlink.c + $(CC) $(CFLAGS) $? + +# Dbs. +dbs@o@: $(srcdir)/test_server/dbs.c + $(CC) $(CFLAGS) -I$(srcdir)/test_server $? +dbs_am@o@: $(srcdir)/test_server/dbs_am.c + $(CC) $(CFLAGS) -I$(srcdir)/test_server $? +dbs_checkpoint@o@: $(srcdir)/test_server/dbs_checkpoint.c + $(CC) $(CFLAGS) -I$(srcdir)/test_server $? +dbs_debug@o@: $(srcdir)/test_server/dbs_debug.c + $(CC) $(CFLAGS) -I$(srcdir)/test_server $? +dbs_handles@o@: $(srcdir)/test_server/dbs_handles.c + $(CC) $(CFLAGS) -I$(srcdir)/test_server $? +dbs_log@o@: $(srcdir)/test_server/dbs_log.c + $(CC) $(CFLAGS) -I$(srcdir)/test_server $? +dbs_qam@o@: $(srcdir)/test_server/dbs_qam.c + $(CC) $(CFLAGS) -I$(srcdir)/test_server $? +dbs_spawn@o@: $(srcdir)/test_server/dbs_spawn.c + $(CC) $(CFLAGS) -I$(srcdir)/test_server $? +dbs_trickle@o@: $(srcdir)/test_server/dbs_trickle.c + $(CC) $(CFLAGS) -I$(srcdir)/test_server $? +dbs_util@o@: $(srcdir)/test_server/dbs_util.c + $(CC) $(CFLAGS) -I$(srcdir)/test_server $? +dbs_yield@o@: $(srcdir)/test_server/dbs_yield.c + $(CC) $(CFLAGS) -I$(srcdir)/test_server $? + +# Replacement files +getcwd@o@: $(srcdir)/clib/getcwd.c + $(CC) $(CFLAGS) $? +getopt@o@: $(srcdir)/clib/getopt.c + $(CC) $(CFLAGS) $? +memcmp@o@: $(srcdir)/clib/memcmp.c + $(CC) $(CFLAGS) $? +memcpy@o@: $(srcdir)/clib/memmove.c + $(CC) -DMEMCOPY $(CFLAGS) $? -o $@ +memmove@o@: $(srcdir)/clib/memmove.c + $(CC) -DMEMMOVE $(CFLAGS) $? +raise@o@: $(srcdir)/clib/raise.c + $(CC) $(CFLAGS) $? +strcasecmp@o@: $(srcdir)/clib/strcasecmp.c + $(CC) $(CFLAGS) $? +snprintf@o@: $(srcdir)/clib/snprintf.c + $(CC) $(CFLAGS) $? +strerror@o@: $(srcdir)/clib/strerror.c + $(CC) $(CFLAGS) $? +vsnprintf@o@: $(srcdir)/clib/vsnprintf.c + $(CC) $(CFLAGS) $? diff --git a/db/dist/RELEASE b/db/dist/RELEASE new file mode 100644 index 000000000..495c12637 --- /dev/null +++ b/db/dist/RELEASE @@ -0,0 +1,8 @@ +# $Id: RELEASE,v 11.72 2001/01/24 15:20:14 bostic Exp $ + +DB_VERSION_MAJOR=3 +DB_VERSION_MINOR=2 +DB_VERSION_PATCH=9 +DB_RELEASE_DATE=`date "+%B %e, %Y"` + +DB_VERSION_STRING="Sleepycat Software: Berkeley DB $DB_VERSION_MAJOR.$DB_VERSION_MINOR.$DB_VERSION_PATCH: ($DB_RELEASE_DATE)" diff --git a/db/dist/acconfig.h b/db/dist/acconfig.h new file mode 100644 index 000000000..e30d0e3d2 --- /dev/null +++ b/db/dist/acconfig.h @@ -0,0 +1,108 @@ +/* + * $Id: acconfig.h,v 11.29 2000/09/20 16:30:33 bostic Exp $ + */ + +/* Define if you are building a version for running the test suite. */ +#undef CONFIG_TEST + +/* Define if you want a debugging version. */ +#undef DEBUG + +/* Define if you want a version that logs read operations. */ +#undef DEBUG_ROP + +/* Define if you want a version that logs write operations. */ +#undef DEBUG_WOP + +/* Define if you want a version with run-time diagnostic checking. */ +#undef DIAGNOSTIC + +/* Define if you want to mask harmless unitialized memory read/writes. */ +#undef UMRW + +/* Define if fcntl/F_SETFD denies child access to file descriptors. */ +#undef HAVE_FCNTL_F_SETFD + +/* Define if building big-file environment (e.g., AIX, HP/UX, Solaris). */ +#undef HAVE_FILE_OFFSET_BITS + +/* Mutex possibilities. */ +#undef HAVE_MUTEX_68K_GCC_ASSEMBLY +#undef HAVE_MUTEX_AIX_CHECK_LOCK +#undef HAVE_MUTEX_ALPHA_GCC_ASSEMBLY +#undef HAVE_MUTEX_HPPA_GCC_ASSEMBLY +#undef HAVE_MUTEX_HPPA_MSEM_INIT +#undef HAVE_MUTEX_IA64_GCC_ASSEMBLY +#undef HAVE_MUTEX_MACOS +#undef HAVE_MUTEX_MSEM_INIT +#undef HAVE_MUTEX_PPC_GCC_ASSEMBLY +#undef HAVE_MUTEX_PTHREADS +#undef HAVE_MUTEX_RELIANTUNIX_INITSPIN +#undef HAVE_MUTEX_SCO_X86_CC_ASSEMBLY +#undef HAVE_MUTEX_SEMA_INIT +#undef HAVE_MUTEX_SGI_INIT_LOCK +#undef HAVE_MUTEX_SOLARIS_LOCK_TRY +#undef HAVE_MUTEX_SOLARIS_LWP +#undef HAVE_MUTEX_SPARC_GCC_ASSEMBLY +#undef HAVE_MUTEX_THREADS +#undef HAVE_MUTEX_UI_THREADS +#undef HAVE_MUTEX_UTS_CC_ASSEMBLY +#undef HAVE_MUTEX_VMS +#undef HAVE_MUTEX_VXWORKS +#undef HAVE_MUTEX_WIN16 +#undef HAVE_MUTEX_WIN32 +#undef HAVE_MUTEX_X86_GCC_ASSEMBLY + +/* Define if building on QNX. */ +#undef HAVE_QNX + +/* Define if building RPC client/server. */ +#undef HAVE_RPC + +/* Define if your sprintf returns a pointer, not a length. */ +#undef SPRINTF_RET_CHARPNT + +@BOTTOM@ + +/* + * Big-file configuration. + */ +#ifdef HAVE_FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 64 +#endif + +/* + * Don't step on the namespace. Other libraries may have their own + * implementations of these functions, we don't want to use their + * implementations or force them to use ours based on the load order. + */ +#ifndef HAVE_GETCWD +#define getcwd __db_Cgetcwd +#endif +#ifndef HAVE_GETOPT +#define getopt __db_Cgetopt +#endif +#ifndef HAVE_MEMCMP +#define memcmp __db_Cmemcmp +#endif +#ifndef HAVE_MEMCPY +#define memcpy __db_Cmemcpy +#endif +#ifndef HAVE_MEMMOVE +#define memmove __db_Cmemmove +#endif +#ifndef HAVE_RAISE +#define raise __db_Craise +#endif +#ifndef HAVE_SNPRINTF +#define snprintf __db_Csnprintf +#endif +#ifndef HAVE_STRCASECMP +#define strcasecmp __db_Cstrcasecmp +#endif +#ifndef HAVE_STRERROR +#define strerror __db_Cstrerror +#endif +#ifndef HAVE_VSNPRINTF +#define vsnprintf __db_Cvsnprintf +#endif diff --git a/db/dist/aclocal/mutex.m4 b/db/dist/aclocal/mutex.m4 new file mode 100644 index 000000000..5f16ee0e1 --- /dev/null +++ b/db/dist/aclocal/mutex.m4 @@ -0,0 +1,395 @@ +dnl $Id: mutex.m4,v 11.20 2000/12/20 22:16:56 bostic Exp $ + +dnl Figure out mutexes for this compiler/architecture. +AC_DEFUN(AM_DEFINE_MUTEXES, [ + +AC_CACHE_CHECK([for mutexes], db_cv_mutex, [dnl +db_cv_mutex=no + +orig_libs=$LIBS + +dnl User-specified POSIX mutexes. +dnl +dnl Assume that -lpthread exists when the user specifies POSIX mutexes. (I +dnl only expect this option to be used on Solaris, which has -lpthread.) +if test "$db_cv_posixmutexes" = yes; then + db_cv_mutex="posix_only" +fi + +dnl User-specified UI mutexes. +dnl +dnl Assume that -lthread exists when the user specifies UI mutexes. (I only +dnl expect this option to be used on Solaris, which has -lthread.) +if test "$db_cv_uimutexes" = yes; then + db_cv_mutex="ui_only" +fi + +dnl LWP threads: _lwp_XXX +dnl +dnl Test for LWP threads before testing for UI/POSIX threads, we prefer them +dnl on Solaris. There are two reasons: the Solaris C library has UI/POSIX +dnl interface stubs, but they're broken, configuring them for inter-process +dnl mutexes doesn't return an error, but it doesn't work either. Second, +dnl there's a bug in SunOS 5.7 where applications get pwrite, not pwrite64, +dnl if they load the C library before the appropriate threads library, e.g., +dnl tclsh using dlopen to load the DB library. Anyway, by using LWP threads +dnl we avoid answering lots of user questions, not to mention the bugs. +if test "$db_cv_mutex" = no; then +AC_TRY_RUN([ +#include +main(){ + static lwp_mutex_t mi = SHAREDMUTEX; + static lwp_cond_t ci = SHAREDCV; + lwp_mutex_t mutex = mi; + lwp_cond_t cond = ci; + exit ( + _lwp_mutex_lock(&mutex) || + _lwp_mutex_unlock(&mutex)); +}], [db_cv_mutex="Solaris/lwp"]) +fi + +dnl UI threads: thr_XXX +dnl +dnl Try with and without the -lthread library. +if test "$db_cv_mutex" = no -o "$db_cv_mutex" = "ui_only"; then +LIBS="-lthread $LIBS" +AC_TRY_RUN([ +#include +#include +main(){ + mutex_t mutex; + cond_t cond; + int type = USYNC_PROCESS; + exit ( + mutex_init(&mutex, type, NULL) || + cond_init(&cond, type, NULL) || + mutex_lock(&mutex) || + mutex_unlock(&mutex)); +}], [db_cv_mutex="UI/threads/library"]) +LIBS="$orig_libs" +fi +if test "$db_cv_mutex" = no -o "$db_cv_mutex" = "ui_only"; then +AC_TRY_RUN([ +#include +#include +main(){ + mutex_t mutex; + cond_t cond; + int type = USYNC_PROCESS; + exit ( + mutex_init(&mutex, type, NULL) || + cond_init(&cond, type, NULL) || + mutex_lock(&mutex) || + mutex_unlock(&mutex)); +}], [db_cv_mutex="UI/threads"]) +fi +if test "$db_cv_mutex" = "ui_only"; then + AC_MSG_ERROR([unable to find UI mutex interfaces]) +fi + + +dnl POSIX.1 pthreads: pthread_XXX +dnl +dnl Try with and without the -lpthread library. +if test "$db_cv_mutex" = no -o "$db_cv_mutex" = "posix_only"; then +AC_TRY_RUN([ +#include +main(){ + pthread_cond_t cond; + pthread_mutex_t mutex; + pthread_condattr_t condattr; + pthread_mutexattr_t mutexattr; + exit ( + pthread_condattr_init(&condattr) || + pthread_condattr_setpshared(&condattr, PTHREAD_PROCESS_SHARED) || + pthread_mutexattr_init(&mutexattr) || + pthread_mutexattr_setpshared(&mutexattr, PTHREAD_PROCESS_SHARED) || + pthread_cond_init(&cond, &condattr) || + pthread_mutex_init(&mutex, &mutexattr) || + pthread_mutex_lock(&mutex) || + pthread_mutex_unlock(&mutex) || + pthread_mutex_destroy(&mutex) || + pthread_cond_destroy(&cond) || + pthread_condattr_destroy(&condattr) || + pthread_mutexattr_destroy(&mutexattr)); +}], [db_cv_mutex="POSIX/pthreads"]) +fi +if test "$db_cv_mutex" = no -o "$db_cv_mutex" = "posix_only"; then +LIBS="-lpthread $LIBS" +AC_TRY_RUN([ +#include +main(){ + pthread_cond_t cond; + pthread_mutex_t mutex; + pthread_condattr_t condattr; + pthread_mutexattr_t mutexattr; + exit ( + pthread_condattr_init(&condattr) || + pthread_condattr_setpshared(&condattr, PTHREAD_PROCESS_SHARED) || + pthread_mutexattr_init(&mutexattr) || + pthread_mutexattr_setpshared(&mutexattr, PTHREAD_PROCESS_SHARED) || + pthread_cond_init(&cond, &condattr) || + pthread_mutex_init(&mutex, &mutexattr) || + pthread_mutex_lock(&mutex) || + pthread_mutex_unlock(&mutex) || + pthread_mutex_destroy(&mutex) || + pthread_cond_destroy(&cond) || + pthread_condattr_destroy(&condattr) || + pthread_mutexattr_destroy(&mutexattr)); +}], [db_cv_mutex="POSIX/pthreads/library"]) +LIBS="$orig_libs" +fi +if test "$db_cv_mutex" = "posix_only"; then + AC_MSG_ERROR([unable to find POSIX mutex interfaces]) +fi + +dnl msemaphore: HPPA only +dnl Try HPPA before general msem test, it needs special alignment. +if test "$db_cv_mutex" = no; then +AC_TRY_RUN([ +#include +main(){ +#if defined(__hppa) + typedef msemaphore tsl_t; + msemaphore x; + msem_init(&x, 0); + msem_lock(&x, 0); + msem_unlock(&x, 0); + exit(0); +#else + exit(1); +#endif +}], [db_cv_mutex="HP/msem_init"]) +fi + +dnl msemaphore: AIX, OSF/1 +if test "$db_cv_mutex" = no; then +AC_TRY_RUN([ +#include +#include ; +main(){ + typedef msemaphore tsl_t; + msemaphore x; + msem_init(&x, 0); + msem_lock(&x, 0); + msem_unlock(&x, 0); + exit(0); +}], [db_cv_mutex="UNIX/msem_init"]) +fi + +dnl ReliantUNIX +if test "$db_cv_mutex" = no; then +LIBS="$LIBS -lmproc" +AC_TRY_LINK([#include ], +[typedef spinlock_t tsl_t; +spinlock_t x; initspin(&x, 1); cspinlock(&x); spinunlock(&x);], +[db_cv_mutex="ReliantUNIX/initspin"]) +LIBS="$orig_libs" +fi + +dnl SCO: UnixWare has threads in libthread, but OpenServer doesn't. +if test "$db_cv_mutex" = no; then +AC_TRY_RUN([ +main(){ +#if defined(__USLC__) + exit(0); +#endif + exit(1); +}], [db_cv_mutex="SCO/x86/cc-assembly"]) +fi + +dnl abilock_t: SGI +if test "$db_cv_mutex" = no; then +AC_TRY_LINK([#include ], +[typedef abilock_t tsl_t; +abilock_t x; init_lock(&x); acquire_lock(&x); release_lock(&x);], +[db_cv_mutex="SGI/init_lock"]) +fi + +dnl sema_t: Solaris +dnl The sema_XXX calls do not work on Solaris 5.5. I see no reason to ever +dnl turn this test on, unless we find some other platform that uses the old +dnl POSIX.1 interfaces. (I plan to move directly to pthreads on Solaris.) +if test "$db_cv_mutex" = DOESNT_WORK; then +AC_TRY_LINK([#include ], +[typedef sema_t tsl_t; + sema_t x; + sema_init(&x, 1, USYNC_PROCESS, NULL); sema_wait(&x); sema_post(&x);], +[db_cv_mutex="UNIX/sema_init"]) +fi + +dnl _lock_try/_lock_clear: Solaris +dnl On Solaris systems without Pthread or UI mutex interfaces, DB uses the +dnl undocumented _lock_try _lock_clear function calls instead of either the +dnl sema_trywait(3T) or sema_wait(3T) function calls. This is because of +dnl problems in those interfaces in some releases of the Solaris C library. +if test "$db_cv_mutex" = no; then +AC_TRY_LINK([#include ], +[typedef lock_t tsl_t; + lock_t x; + _lock_try(&x); _lock_clear(&x);], +[db_cv_mutex="Solaris/_lock_try"]) +fi + +dnl _check_lock/_clear_lock: AIX +if test "$db_cv_mutex" = no; then +AC_TRY_LINK([#include ], +[int x; _check_lock(&x,0,1); _clear_lock(&x,0);], +[db_cv_mutex="AIX/_check_lock"]) +fi + +dnl Alpha/gcc: OSF/1 +dnl The alpha/gcc code doesn't work as far as I know. There are +dnl two versions, both have problems. See Support Request #1583. +if test "$db_cv_mutex" = DOESNT_WORK; then +AC_TRY_RUN([main(){ +#if defined(__alpha) +#if defined(__GNUC__) +exit(0); +#endif +#endif +exit(1);}], +[db_cv_mutex="ALPHA/gcc-assembly"]) +fi + +dnl PaRisc/gcc: HP/UX +if test "$db_cv_mutex" = no; then +AC_TRY_RUN([main(){ +#if defined(__hppa) +#if defined(__GNUC__) +exit(0); +#endif +#endif +exit(1);}], +[db_cv_mutex="HPPA/gcc-assembly"]) +fi + +dnl PPC/gcc: +if test "$db_cv_mutex" = no; then +AC_TRY_RUN([main(){ +#if defined(__powerpc__) +#if defined(__GNUC__) +exit(0); +#endif +#endif +exit(1);}], +[db_cv_mutex="PPC/gcc-assembly"]) +fi + +dnl Sparc/gcc: SunOS, Solaris +dnl The sparc/gcc code doesn't always work, specifically, I've seen assembler +dnl failures from the stbar instruction on SunOS 4.1.4/sun4c and gcc 2.7.2.2. +if test "$db_cv_mutex" = DOESNT_WORK; then +AC_TRY_RUN([main(){ +#if defined(__sparc__) +#if defined(__GNUC__) + exit(0); +#endif +#endif + exit(1); +}], [db_cv_mutex="Sparc/gcc-assembly"]) +fi + +dnl 68K/gcc: SunOS +if test "$db_cv_mutex" = no; then +AC_TRY_RUN([main(){ +#if (defined(mc68020) || defined(sun3)) +#if defined(__GNUC__) + exit(0); +#endif +#endif + exit(1); +}], [db_cv_mutex="68K/gcc-assembly"]) +fi + +dnl x86/gcc: FreeBSD, NetBSD, BSD/OS, Linux +if test "$db_cv_mutex" = no; then +AC_TRY_RUN([main(){ +#if defined(i386) || defined(__i386__) +#if defined(__GNUC__) + exit(0); +#endif +#endif + exit(1); +}], [db_cv_mutex="x86/gcc-assembly"]) +fi + +dnl ia86/gcc: Linux +if test "$db_cv_mutex" = no; then +AC_TRY_RUN([main(){ +#if defined(__ia64) +#if defined(__GNUC__) + exit(0); +#endif +#endif + exit(1); +}], [db_cv_mutex="ia64/gcc-assembly"]) +fi + +dnl: uts/cc: UTS +if test "$db_cv_mutex" = no; then +AC_TRY_RUN([main(){ +#if defined(_UTS) + exit(0); +#endif + exit(1); +}], [db_cv_mutex="UTS/cc-assembly"]) +fi +]) + +if test "$db_cv_mutex" = no; then + AC_MSG_WARN( + [THREAD MUTEXES NOT AVAILABLE FOR THIS COMPILER/ARCHITECTURE.]) + ADDITIONAL_OBJS="mut_fcntl${o} $ADDITIONAL_OBJS" +else + AC_DEFINE(HAVE_MUTEX_THREADS) +fi + +case "$db_cv_mutex" in +68K/gcc-assembly) ADDITIONAL_OBJS="mut_tas${o} $ADDITIONAL_OBJS" + AC_DEFINE(HAVE_MUTEX_68K_GCC_ASSEMBLY);; +AIX/_check_lock) ADDITIONAL_OBJS="mut_tas${o} $ADDITIONAL_OBJS" + AC_DEFINE(HAVE_MUTEX_AIX_CHECK_LOCK);; +ALPHA/gcc-assembly) ADDITIONAL_OBJS="mut_tas${o} $ADDITIONAL_OBJS" + AC_DEFINE(HAVE_MUTEX_ALPHA_GCC_ASSEMBLY);; +HP/msem_init) ADDITIONAL_OBJS="mut_tas${o} $ADDITIONAL_OBJS" + AC_DEFINE(HAVE_MUTEX_HPPA_MSEM_INIT);; +HPPA/gcc-assembly) ADDITIONAL_OBJS="mut_tas${o} $ADDITIONAL_OBJS" + AC_DEFINE(HAVE_MUTEX_HPPA_GCC_ASSEMBLY);; +ia64/gcc-assembly) ADDITIONAL_OBJS="mut_tas${o} $ADDITIONAL_OBJS" + AC_DEFINE(HAVE_MUTEX_IA64_GCC_ASSEMBLY);; +POSIX/pthreads) ADDITIONAL_OBJS="mut_pthread${o} $ADDITIONAL_OBJS" + AC_DEFINE(HAVE_MUTEX_PTHREADS);; +POSIX/pthreads/library) LIBS="-lpthread $LIBS" + ADDITIONAL_OBJS="mut_pthread${o} $ADDITIONAL_OBJS" + AC_DEFINE(HAVE_MUTEX_PTHREADS);; +PPC/gcc-assembly) ADDITIONAL_OBJS="mut_tas${o} $ADDITIONAL_OBJS" + AC_DEFINE(HAVE_MUTEX_PPC_GCC_ASSEMBLY);; +ReliantUNIX/initspin) LIBS="$LIBS -lmproc" + ADDITIONAL_OBJS="mut_tas${o} $ADDITIONAL_OBJS" + AC_DEFINE(HAVE_MUTEX_RELIANTUNIX_INITSPIN);; +SCO/x86/cc-assembly) ADDITIONAL_OBJS="mut_tas${o} $ADDITIONAL_OBJS" + AC_DEFINE(HAVE_MUTEX_SCO_X86_CC_ASSEMBLY);; +SGI/init_lock) ADDITIONAL_OBJS="mut_tas${o} $ADDITIONAL_OBJS" + AC_DEFINE(HAVE_MUTEX_SGI_INIT_LOCK);; +Solaris/_lock_try) ADDITIONAL_OBJS="mut_tas${o} $ADDITIONAL_OBJS" + AC_DEFINE(HAVE_MUTEX_SOLARIS_LOCK_TRY);; +Solaris/lwp) ADDITIONAL_OBJS="mut_pthread${o} $ADDITIONAL_OBJS" + AC_DEFINE(HAVE_MUTEX_SOLARIS_LWP);; +Sparc/gcc-assembly) ADDITIONAL_OBJS="mut_tas${o} $ADDITIONAL_OBJS" + AC_DEFINE(HAVE_MUTEX_SPARC_GCC_ASSEMBLY);; +UI/threads) ADDITIONAL_OBJS="mut_pthread${o} $ADDITIONAL_OBJS" + AC_DEFINE(HAVE_MUTEX_UI_THREADS);; +UI/threads/library) LIBS="-lthread $LIBS" + ADDITIONAL_OBJS="mut_pthread${o} $ADDITIONAL_OBJS" + AC_DEFINE(HAVE_MUTEX_UI_THREADS);; +UNIX/msem_init) ADDITIONAL_OBJS="mut_tas${o} $ADDITIONAL_OBJS" + AC_DEFINE(HAVE_MUTEX_MSEM_INIT);; +UNIX/sema_init) ADDITIONAL_OBJS="mut_tas${o} $ADDITIONAL_OBJS" + AC_DEFINE(HAVE_MUTEX_SEMA_INIT);; +UTS/cc-assembly) ADDITIONAL_OBJS="$ADDITIONAL_OBJS uts4.cc${o}" + AC_DEFINE(HAVE_MUTEX_UTS_CC_ASSEMBLY);; +x86/gcc-assembly) ADDITIONAL_OBJS="mut_tas${o} $ADDITIONAL_OBJS" + AC_DEFINE(HAVE_MUTEX_X86_GCC_ASSEMBLY);; +esac +])dnl diff --git a/db/dist/aclocal/options.m4 b/db/dist/aclocal/options.m4 new file mode 100644 index 000000000..c51a39524 --- /dev/null +++ b/db/dist/aclocal/options.m4 @@ -0,0 +1,121 @@ +dnl $Id: options.m4,v 11.10 2000/07/07 15:50:39 bostic Exp $ + +dnl Process user-specified options. +AC_DEFUN(AM_OPTIONS_SET, [ + +AC_MSG_CHECKING(if --disable-bigfile option specified) +AC_ARG_ENABLE(bigfile, + [ --disable-bigfile Disable AIX, HP/UX, Solaris big files.], + [db_cv_bigfile="yes"], [db_cv_bigfile="no"]) +AC_MSG_RESULT($db_cv_bigfile) + +AC_MSG_CHECKING(if --enable-compat185 option specified) +AC_ARG_ENABLE(compat185, + [ --enable-compat185 Build DB 1.85 compatibility API.], + [db_cv_compat185="$enable_compat185"], [db_cv_compat185="no"]) +AC_MSG_RESULT($db_cv_compat185) + +AC_MSG_CHECKING(if --enable-cxx option specified) +AC_ARG_ENABLE(cxx, + [ --enable-cxx Build C++ API.], + [db_cv_cxx="$enable_cxx"], [db_cv_cxx="no"]) +AC_MSG_RESULT($db_cv_cxx) + +AC_MSG_CHECKING(if --enable-debug option specified) +AC_ARG_ENABLE(debug, + [ --enable-debug Build a debugging version.], + [db_cv_debug="$enable_debug"], [db_cv_debug="no"]) +AC_MSG_RESULT($db_cv_debug) + +AC_MSG_CHECKING(if --enable-debug_rop option specified) +AC_ARG_ENABLE(debug_rop, + [ --enable-debug_rop Build a version that logs read operations.], + [db_cv_debug_rop="$enable_debug_rop"], [db_cv_debug_rop="no"]) +AC_MSG_RESULT($db_cv_debug_rop) + +AC_MSG_CHECKING(if --enable-debug_wop option specified) +AC_ARG_ENABLE(debug_wop, + [ --enable-debug_wop Build a version that logs write operations.], + [db_cv_debug_wop="$enable_debug_wop"], [db_cv_debug_wop="no"]) +AC_MSG_RESULT($db_cv_debug_wop) + +AC_MSG_CHECKING(if --enable-diagnostic option specified) +AC_ARG_ENABLE(diagnostic, + [ --enable-diagnostic Build a version with run-time diagnostics.], + [db_cv_diagnostic="$enable_diagnostic"], [db_cv_diagnostic="no"]) +AC_MSG_RESULT($db_cv_diagnostic) + +AC_MSG_CHECKING(if --enable-dump185 option specified) +AC_ARG_ENABLE(dump185, + [ --enable-dump185 Build db_dump185(1) to dump 1.85 databases.], + [db_cv_dump185="$enable_dump185"], [db_cv_dump185="no"]) +AC_MSG_RESULT($db_cv_dump185) + +AC_MSG_CHECKING(if --enable-dynamic option specified) +AC_ARG_ENABLE(dynamic, + [ --enable-dynamic Build with dynamic libraries.], + [db_cv_dynamic="$enable_dynamic"], [db_cv_dynamic="no"]) +AC_MSG_RESULT($db_cv_dynamic) + +AC_MSG_CHECKING(if --enable-java option specified) +AC_ARG_ENABLE(java, + [ --enable-java Build Java API.], + [db_cv_java="$enable_java"], [db_cv_java="no"]) +AC_MSG_RESULT($db_cv_java) + +AC_MSG_CHECKING(if --enable-posixmutexes option specified) +AC_ARG_ENABLE(posixmutexes, + [ --enable-posixmutexes Force use of POSIX standard mutexes.], + [db_cv_posixmutexes="$enable_posixmutexes"], [db_cv_posixmutexes="no"]) +AC_MSG_RESULT($db_cv_posixmutexes) + +AC_MSG_CHECKING(if --enable-rpc option specified) +AC_ARG_ENABLE(rpc, + [ --enable-rpc Build RPC client/server.], + [db_cv_rpc="$enable_rpc"], [db_cv_rpc="no"]) +AC_MSG_RESULT($db_cv_rpc) + +dnl --enable-shared is an alias for --enable-dynamic. We support it for +dnl compatibility with other applications, e.g., Tcl. +AC_MSG_CHECKING(if --enable-shared option specified) +AC_ARG_ENABLE(shared, + [ --enable-shared Build with dynamic libraries.], + [db_cv_shared="$enable_shared"], [db_cv_shared="no"]) +AC_MSG_RESULT($db_cv_shared) +if test "$db_cv_shared" != "no"; then + db_cv_dynamic="yes" +fi + +AC_MSG_CHECKING(if --enable-tcl option specified) +AC_ARG_ENABLE(tcl, + [ --enable-tcl Build Tcl API.], + [db_cv_tcl="$enable_tcl"], [db_cv_tcl="no"]) +AC_MSG_RESULT($db_cv_tcl) + +AC_MSG_CHECKING(if --enable-test option specified) +AC_ARG_ENABLE(test, + [ --enable-test Configure to run the test suite.], + [db_cv_test="$enable_test"], [db_cv_test="no"]) +AC_MSG_RESULT($db_cv_test) + +AC_MSG_CHECKING(if --enable-uimutexes option specified) +AC_ARG_ENABLE(uimutexes, + [ --enable-uimutexes Force use of Unix International mutexes.], + [db_cv_uimutexes="$enable_uimutexes"], [db_cv_uimutexes="no"]) +AC_MSG_RESULT($db_cv_uimutexes) + +AC_MSG_CHECKING(if --enable-umrw option specified) +AC_ARG_ENABLE(umrw, + [ --enable-umrw Mask harmless unitialized memory read/writes.], + [db_cv_umrw="$enable_umrw"], [db_cv_umrw="no"]) +AC_MSG_RESULT($db_cv_umrw) + +AC_MSG_CHECKING([if --with-tcl option specified]) +AC_ARG_WITH(tcl, + [ --with-tcl=DIR Directory location of tclConfig.sh.], + with_tclconfig=${withval}, with_tclconfig="no") +AC_MSG_RESULT($with_tclconfig) +if test "$with_tclconfig" != "no"; then + db_cv_tcl="yes" +fi +])dnl diff --git a/db/dist/aclocal/programs.m4 b/db/dist/aclocal/programs.m4 new file mode 100644 index 000000000..9ec04f4d8 --- /dev/null +++ b/db/dist/aclocal/programs.m4 @@ -0,0 +1,48 @@ +dnl $Id: programs.m4,v 11.11 2000/03/30 21:20:50 bostic Exp $ + +dnl Check for programs used in building/installation. +AC_DEFUN(AM_PROGRAMS_SET, [ + +AC_PATH_PROG(db_cv_path_ar, ar, missing_ar) +if test "$db_cv_path_ar" = missing_ar; then + AC_MSG_ERROR([No ar utility found.]) +fi +AC_PATH_PROG(db_cv_path_chmod, chmod, missing_chmod) +if test "$db_cv_path_chmod" = missing_chmod; then + AC_MSG_ERROR([No chmod utility found.]) +fi +AC_PATH_PROG(db_cv_path_cp, cp, missing_cp) +if test "$db_cv_path_cp" = missing_cp; then + AC_MSG_ERROR([No cp utility found.]) +fi +AC_PATH_PROG(db_cv_path_ln, ln, missing_ln) +if test "$db_cv_path_ln" = missing_ln; then + AC_MSG_ERROR([No ln utility found.]) +fi +AC_PATH_PROG(db_cv_path_mkdir, mkdir, missing_mkdir) +if test "$db_cv_path_mkdir" = missing_mkdir; then + AC_MSG_ERROR([No mkdir utility found.]) +fi +AC_PATH_PROG(db_cv_path_ranlib, ranlib, missing_ranlib) +AC_PATH_PROG(db_cv_path_rm, rm, missing_rm) +if test "$db_cv_path_rm" = missing_rm; then + AC_MSG_ERROR([No rm utility found.]) +fi +AC_PATH_PROG(db_cv_path_sh, sh, missing_sh) +if test "$db_cv_path_sh" = missing_sh; then + AC_MSG_ERROR([No sh utility found.]) +fi +AC_PATH_PROG(db_cv_path_strip, strip, missing_strip) +if test "$db_cv_path_strip" = missing_strip; then + AC_MSG_ERROR([No strip utility found.]) +fi + +dnl Check for programs used in testing. +if test "$db_cv_test" = "yes"; then + AC_PATH_PROG(db_cv_path_kill, kill, missing_kill) + if test "$db_cv_path_kill" = missing_kill; then + AC_MSG_ERROR([No kill utility found.]) + fi +fi + +])dnl diff --git a/db/dist/aclocal/tcl.m4 b/db/dist/aclocal/tcl.m4 new file mode 100644 index 000000000..3d0aec2e8 --- /dev/null +++ b/db/dist/aclocal/tcl.m4 @@ -0,0 +1,126 @@ +dnl $Id: tcl.m4,v 11.5 2000/06/27 13:21:28 bostic Exp $ + +dnl The SC_* macros in this file are from the unix/tcl.m4 files in the Tcl +dnl 8.3.0 distribution, with some minor changes. For this reason, license +dnl terms for the Berkeley DB distribution dist/aclocal/tcl.m4 file are as +dnl follows (copied from the license.terms file in the Tcl 8.3 distribution): +dnl +dnl This software is copyrighted by the Regents of the University of +dnl California, Sun Microsystems, Inc., Scriptics Corporation, +dnl and other parties. The following terms apply to all files associated +dnl with the software unless explicitly disclaimed in individual files. +dnl +dnl The authors hereby grant permission to use, copy, modify, distribute, +dnl and license this software and its documentation for any purpose, provided +dnl that existing copyright notices are retained in all copies and that this +dnl notice is included verbatim in any distributions. No written agreement, +dnl license, or royalty fee is required for any of the authorized uses. +dnl Modifications to this software may be copyrighted by their authors +dnl and need not follow the licensing terms described here, provided that +dnl the new terms are clearly indicated on the first page of each file where +dnl they apply. +dnl +dnl IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +dnl FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +dnl ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +dnl DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +dnl POSSIBILITY OF SUCH DAMAGE. +dnl +dnl THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +dnl INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, +dnl FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE +dnl IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE +dnl NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR +dnl MODIFICATIONS. +dnl +dnl GOVERNMENT USE: If you are acquiring this software on behalf of the +dnl U.S. government, the Government shall have only "Restricted Rights" +dnl in the software and related documentation as defined in the Federal +dnl Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you +dnl are acquiring the software on behalf of the Department of Defense, the +dnl software shall be classified as "Commercial Computer Software" and the +dnl Government shall have only "Restricted Rights" as defined in Clause +dnl 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +dnl authors grant the U.S. Government and others acting in its behalf +dnl permission to use and distribute the software in accordance with the +dnl terms specified in this license. + +AC_DEFUN(SC_PATH_TCLCONFIG, [ + AC_CACHE_VAL(ac_cv_c_tclconfig,[ + + # First check to see if --with-tclconfig was specified. + if test "${with_tclconfig}" != no; then + if test -f "${with_tclconfig}/tclConfig.sh" ; then + ac_cv_c_tclconfig=`(cd ${with_tclconfig}; pwd)` + else + AC_MSG_ERROR([${with_tclconfig} directory doesn't contain tclConfig.sh]) + fi + fi + + # check in a few common install locations + if test x"${ac_cv_c_tclconfig}" = x ; then + for i in `ls -d /usr/local/lib 2>/dev/null` ; do + if test -f "$i/tclConfig.sh" ; then + ac_cv_c_tclconfig=`(cd $i; pwd)` + break + fi + done + fi + + ]) + + if test x"${ac_cv_c_tclconfig}" = x ; then + TCL_BIN_DIR="# no Tcl configs found" + AC_MSG_ERROR(can't find Tcl configuration definitions) + else + TCL_BIN_DIR=${ac_cv_c_tclconfig} + fi +]) + +AC_DEFUN(SC_LOAD_TCLCONFIG, [ + AC_MSG_CHECKING([for existence of $TCL_BIN_DIR/tclConfig.sh]) + + if test -f "$TCL_BIN_DIR/tclConfig.sh" ; then + AC_MSG_RESULT([loading]) + . $TCL_BIN_DIR/tclConfig.sh + else + AC_MSG_RESULT([file not found]) + fi + + # + # The eval is required to do the TCL_DBGX substitution in the + # TCL_LIB_FILE variable + # + eval TCL_LIB_FILE="${TCL_LIB_FILE}" + eval TCL_LIB_FLAG="${TCL_LIB_FLAG}" + eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\"" + + AC_SUBST(TCL_BIN_DIR) + AC_SUBST(TCL_SRC_DIR) + AC_SUBST(TCL_LIB_FILE) + + AC_SUBST(TCL_TCLSH) + TCL_TCLSH="${TCL_PREFIX}/bin/tclsh${TCL_VERSION}" +]) + +dnl Optional Tcl API. +AC_DEFUN(AM_TCL_LOAD, [ +if test "$db_cv_tcl" != no; then + if test "$db_cv_dynamic" != "yes"; then + AC_MSG_ERROR([--with-tcl requires --enable-dynamic]) + fi + + AC_SUBST(TCFLAGS) + + SC_PATH_TCLCONFIG + SC_LOAD_TCLCONFIG + + if test x"$TCL_PREFIX" != x && test -f "$TCL_PREFIX/include/tcl.h"; then + TCFLAGS="-I$TCL_PREFIX/include" + fi + + LIBS="$LIBS $TCL_LIB_SPEC $TCL_LIBS" + + ADDITIONAL_LIBS="$ADDITIONAL_LIBS \$(libtso_target)" + DEFAULT_INSTALL="${DEFAULT_INSTALL} install_tcl" +fi]) diff --git a/db/dist/aclocal/types.m4 b/db/dist/aclocal/types.m4 new file mode 100644 index 000000000..a9a03ab6d --- /dev/null +++ b/db/dist/aclocal/types.m4 @@ -0,0 +1,139 @@ +dnl $Id: types.m4,v 11.4 1999/12/04 19:18:28 bostic Exp $ + +dnl Check for the standard shorthand types. +AC_DEFUN(AM_SHORTHAND_TYPES, [dnl + +AC_SUBST(ssize_t_decl) +AC_CACHE_CHECK([for ssize_t], db_cv_ssize_t, [dnl +AC_TRY_COMPILE([#include ], ssize_t foo;, + [db_cv_ssize_t=yes], [db_cv_ssize_t=no])]) +if test "$db_cv_ssize_t" = no; then + ssize_t_decl="typedef int ssize_t;" +fi + +AC_SUBST(u_char_decl) +AC_CACHE_CHECK([for u_char], db_cv_uchar, [dnl +AC_TRY_COMPILE([#include ], u_char foo;, + [db_cv_uchar=yes], [db_cv_uchar=no])]) +if test "$db_cv_uchar" = no; then + u_char_decl="typedef unsigned char u_char;" +fi + +AC_SUBST(u_short_decl) +AC_CACHE_CHECK([for u_short], db_cv_ushort, [dnl +AC_TRY_COMPILE([#include ], u_short foo;, + [db_cv_ushort=yes], [db_cv_ushort=no])]) +if test "$db_cv_ushort" = no; then + u_short_decl="typedef unsigned short u_short;" +fi + +AC_SUBST(u_int_decl) +AC_CACHE_CHECK([for u_int], db_cv_uint, [dnl +AC_TRY_COMPILE([#include ], u_int foo;, + [db_cv_uint=yes], [db_cv_uint=no])]) +if test "$db_cv_uint" = no; then + u_int_decl="typedef unsigned int u_int;" +fi + +AC_SUBST(u_long_decl) +AC_CACHE_CHECK([for u_long], db_cv_ulong, [dnl +AC_TRY_COMPILE([#include ], u_long foo;, + [db_cv_ulong=yes], [db_cv_ulong=no])]) +if test "$db_cv_ulong" = no; then + u_long_decl="typedef unsigned long u_long;" +fi + +dnl DB/Vi use specific integer sizes. +AC_SUBST(u_int8_decl) +AC_CACHE_CHECK([for u_int8_t], db_cv_uint8, [dnl +AC_TRY_COMPILE([#include ], u_int8_t foo;, + [db_cv_uint8=yes], + AC_TRY_RUN([main(){exit(sizeof(unsigned char) != 1);}], + [db_cv_uint8="unsigned char"], [db_cv_uint8=no]))]) +if test "$db_cv_uint8" = no; then + AC_MSG_ERROR(No unsigned 8-bit integral type.) +fi +if test "$db_cv_uint8" != yes; then + u_int8_decl="typedef $db_cv_uint8 u_int8_t;" +fi + +AC_SUBST(u_int16_decl) +AC_CACHE_CHECK([for u_int16_t], db_cv_uint16, [dnl +AC_TRY_COMPILE([#include ], u_int16_t foo;, + [db_cv_uint16=yes], +AC_TRY_RUN([main(){exit(sizeof(unsigned short) != 2);}], + [db_cv_uint16="unsigned short"], +AC_TRY_RUN([main(){exit(sizeof(unsigned int) != 2);}], + [db_cv_uint16="unsigned int"], [db_cv_uint16=no])))]) +if test "$db_cv_uint16" = no; then + AC_MSG_ERROR([No unsigned 16-bit integral type.]) +fi +if test "$db_cv_uint16" != yes; then + u_int16_decl="typedef $db_cv_uint16 u_int16_t;" +fi + +AC_SUBST(int16_decl) +AC_CACHE_CHECK([for int16_t], db_cv_int16, [dnl +AC_TRY_COMPILE([#include ], int16_t foo;, + [db_cv_int16=yes], +AC_TRY_RUN([main(){exit(sizeof(short) != 2);}], + [db_cv_int16="short"], +AC_TRY_RUN([main(){exit(sizeof(int) != 2);}], + [db_cv_int16="int"], [db_cv_int16=no])))]) +if test "$db_cv_int16" = no; then + AC_MSG_ERROR([No signed 16-bit integral type.]) +fi +if test "$db_cv_int16" != yes; then + int16_decl="typedef $db_cv_int16 int16_t;" +fi + +AC_SUBST(u_int32_decl) +AC_CACHE_CHECK([for u_int32_t], db_cv_uint32, [dnl +AC_TRY_COMPILE([#include ], u_int32_t foo;, + [db_cv_uint32=yes], +AC_TRY_RUN([main(){exit(sizeof(unsigned int) != 4);}], + [db_cv_uint32="unsigned int"], +AC_TRY_RUN([main(){exit(sizeof(unsigned long) != 4);}], + [db_cv_uint32="unsigned long"], [db_cv_uint32=no])))]) +if test "$db_cv_uint32" = no; then + AC_MSG_ERROR([No unsigned 32-bit integral type.]) +fi +if test "$db_cv_uint32" != yes; then + u_int32_decl="typedef $db_cv_uint32 u_int32_t;" +fi + +AC_SUBST(int32_decl) +AC_CACHE_CHECK([for int32_t], db_cv_int32, [dnl +AC_TRY_COMPILE([#include ], int32_t foo;, + [db_cv_int32=yes], +AC_TRY_RUN([main(){exit(sizeof(int) != 4);}], + [db_cv_int32="int"], +AC_TRY_RUN([main(){exit(sizeof(long) != 4);}], + [db_cv_int32="long"], [db_cv_int32=no])))]) +if test "$db_cv_int32" = no; then + AC_MSG_ERROR([No signed 32-bit integral type.]) +fi +if test "$db_cv_int32" != yes; then + int32_decl="typedef $db_cv_int32 int32_t;" +fi + +dnl Figure out largest integral type. +AC_SUBST(db_align_t_decl) +AC_CACHE_CHECK([for largest integral type], db_cv_align_t, [dnl +AC_TRY_COMPILE([#include ], long long foo;, + [db_cv_align_t="unsigned long long"], [db_cv_align_t="unsigned long"])]) +db_align_t_decl="typedef $db_cv_align_t db_align_t;" + +dnl Figure out integral type the same size as a pointer. +AC_SUBST(db_alignp_t_decl) +AC_CACHE_CHECK([for integral type equal to pointer size], db_cv_alignp_t, [dnl +db_cv_alignp_t=$db_cv_align_t +AC_TRY_RUN([main(){exit(sizeof(unsigned int) != sizeof(char *));}], + [db_cv_alignp_t="unsigned int"]) +AC_TRY_RUN([main(){exit(sizeof(unsigned long) != sizeof(char *));}], + [db_cv_alignp_t="unsigned long"]) +AC_TRY_RUN([main(){exit(sizeof(unsigned long long) != sizeof(char *));}], + [db_cv_alignp_t="unsigned long long"])]) +db_alignp_t_decl="typedef $db_cv_alignp_t db_alignp_t;" + +])dnl diff --git a/db/dist/build/chk.def b/db/dist/build/chk.def new file mode 100755 index 000000000..abd12b839 --- /dev/null +++ b/db/dist/build/chk.def @@ -0,0 +1,50 @@ +#!/bin/sh - +# +# $Id: chk.def,v 1.4 2000/12/12 18:20:59 bostic Exp $ +# +# Check to make sure we haven't forgotten to add any interfaces +# to the Win32 libdb.def file. + +# Run from the top-level directory. +[ -f db_config.h ] && cd .. + +f=build_win32/libdb.def +t1=/tmp/__1 +t2=/tmp/__2 + +sed '/; /d' $f | + egrep @ | + awk '{print $1}' | + sed -e '/db_xa_switch/d' \ + -e '/^__/d' -e '/^;/d' | + sort > ${t1} + +egrep __P include/db.src | + sed '/^[a-z]/!d' | + awk '{print $2}' | + sed 's/^\*//' | + sed '/^__/d' | sort > ${t2} + +if cmp -s ${t1} ${t2} ; then + : +else + echo "<<< libdb.def" + echo ">>> DB include files" + diff ${t1} ${t2} +fi + +# Check to make sure we don't have any extras in the libdb.def file. +sed '/; /d' $f | + egrep @ | + awk '{print $1}' | + sed -e '/__db_global_values/d' > ${t1} + +for i in `cat ${t1}`; do + if egrep $i */*.c > /dev/null; then + : + else + echo "$f: $i not found in DB sources" + fi +done + +rm -f ${t1} ${t2} diff --git a/db/dist/build/chk.define b/db/dist/build/chk.define new file mode 100755 index 000000000..9e2aa0db4 --- /dev/null +++ b/db/dist/build/chk.define @@ -0,0 +1,55 @@ +#!/bin/sh - +# +# $Id: chk.define,v 1.8 2000/12/12 18:20:59 bostic Exp $ +# +# Check to make sure that all #defines are actually used. + +# Run from the top-level directory. +[ -f db_config.h ] && cd .. + +t1=/tmp/__1 + +egrep '^#define' include/*.h | + sed -e '/db_185.h/d' -e '/xa.h/d' | + awk '{print $2}' | + sed -e '/^B_DELETE/d' \ + -e '/^B_MAX/d' \ + -e '/^CIRCLEQ/d' \ + -e '/^DB_RO_ACCESS/d' \ + -e '/^DEFINE_DB_CLASS/d' \ + -e '/^LIST/d' \ + -e '/^LOG_OP/d' \ + -e '/^MINFILL/d' \ + -e '/^MUTEX_FIELDS/d' \ + -e '/^NCACHED2X/d' \ + -e '/^NCACHED30/d' \ + -e '/^PAIR_MASK/d' \ + -e '/^POWER_OF_TWO/d' \ + -e '/^P_16_COPY/d' \ + -e '/^P_32_COPY/d' \ + -e '/^P_32_SWAP/d' \ + -e '/^SH_CIRCLEQ/d' \ + -e '/^SH_LIST/d' \ + -e '/^SH_TAILQ/d' \ + -e '/^TAILQ/d' \ + -e '/UNUSED/d' \ + -e '/^WRAPPED_CLASS/d' \ + -e '/^XA_$/d' \ + -e '/^_DB_SERVER_H_RPCGEN/d' \ + -e '/_AUTO_H$/d' \ + -e '/_H_$/d' \ + -e '/ext_h_/d' \ + -e '/^i_/d' \ + -e 's/(.*//' | sort > ${t1} + +for i in `cat ${t1}`; do + if egrep -w $i */*.c */*.cpp > /dev/null; then + :; + else + f=`egrep -l $i include/*.h | + sed 's;include/;;' | tr -s "[:space:]" " "` + echo "$i: $f" + fi +done | sort +1 + +rm -f ${t1} diff --git a/db/dist/build/chk.offt b/db/dist/build/chk.offt new file mode 100755 index 000000000..ea7f0b914 --- /dev/null +++ b/db/dist/build/chk.offt @@ -0,0 +1,19 @@ +#!/bin/sh - +# +# $Id: chk.offt,v 1.3 2000/12/12 18:20:59 bostic Exp $ +# +# Make sure that no off_t's have snuck into the release. + +# Run from the top-level directory. +[ -f db_config.h ] && cd .. + +egrep -w off_t */*.[ch] | +sed -e "/#undef off_t/d" \ + -e "/mp_fopen.c:.*can't use off_t's here/d" \ + -e "/mp_fopen.c:.*size or type off_t's or/d" \ + -e "/mp_fopen.c:.*where an off_t is 32-bits/d" \ + -e "/os_map.c:.*(off_t)0))/d" \ + -e "/os_rw.c:.*(off_t)db_iop->pgno/d" \ + -e "/os_seek.c:.*off_t offset;/d" \ + -e "/os_seek.c:.*offset = /d" \ + -e "/test_vxworks\/vx_mutex.c:/d" diff --git a/db/dist/build/chk.srcfiles b/db/dist/build/chk.srcfiles new file mode 100755 index 000000000..cfd6f955e --- /dev/null +++ b/db/dist/build/chk.srcfiles @@ -0,0 +1,29 @@ +#!/bin/sh - +# +# $Id: chk.srcfiles,v 1.3 2000/12/12 18:20:59 bostic Exp $ +# +# Check to make sure we haven't forgotten to add any files to the list +# of source files Win32 uses to build its dsp files. + +# Run from the top-level directory. +[ -f db_config.h ] && cd .. + +f=dist/srcfiles.in +t1=/tmp/__1 +t2=/tmp/__2 + +sed -e '/^[ #]/d' \ + -e '/^$/d' < $f | + awk '{print $1}' > ${t1} +find . -type f | + sed -e 's/^\.\///' | + egrep '\.c$|\.cpp$|\.def$|\.rc$' | + sed -e '/dist\/build\/chk.def/d' \ + -e '/perl.DB_File\/version.c/d' | + sort > ${t2} + +cmp ${t1} ${t2} > /dev/null || +(echo "<<< srcfiles.in >>> existing files" && \ + diff ${t1} ${t2} | tee /tmp/_f) + +rm -f ${t1} ${t2} diff --git a/db/dist/build/chk.tags b/db/dist/build/chk.tags new file mode 100755 index 000000000..fa67927e7 --- /dev/null +++ b/db/dist/build/chk.tags @@ -0,0 +1,39 @@ +#!/bin/sh - +# +# $Id: chk.tags,v 1.5 2000/12/22 15:35:32 bostic Exp $ +# +# Check to make sure we don't need any more symbolic links to tags files. + +# Run from the top-level directory. +[ -f db_config.h ] && cd .. + +t1=/tmp/__1 +t2=/tmp/__2 + +(ls -F | egrep / | sort | + sed -e 's/\///' \ + -e '/^CVS$/d' \ + -e '/^build_vxworks$/d' \ + -e '/^build_win32$/d' \ + -e '/^docs$/d' \ + -e '/^docs.text$/d' \ + -e '/^docs_src$/d' \ + -e '/^docs_text$/d' \ + -e '/^java$/d' \ + -e '/^perl.BerkeleyDB$/d' \ + -e '/^perl.DB_File$/d' \ + -e '/^test$/d' \ + -e '/^test_purify$/d' \ + -e '/^test_thread$/d' \ + -e '/^test_vxworks$/d') > ${t1} + +(ls */tags | sed 's/\/tags$//' | sort) > ${t2} +if diff ${t1} ${t2} > /dev/null; then + : +else + echo "<<< source tree" + echo ">>> tags files" + diff ${t1} ${t2} +fi + +rm -f ${t1} ${t2} diff --git a/db/dist/build/script b/db/dist/build/script new file mode 100644 index 000000000..8eef3099f --- /dev/null +++ b/db/dist/build/script @@ -0,0 +1,94 @@ +#!/bin/sh - +# $Id: script,v 1.21 2001/01/19 18:13:16 bostic Exp $ +# +# Build the distribution archives. +# +# A set of commands intended to be cut and pasted into a csh window. + +# Development tree, release home. +setenv D /a/db + +# Update the release number. +cd $D/dist +vi RELEASE +setenv VERSION \ +`sh -c '. RELEASE; echo $DB_VERSION_MAJOR.$DB_VERSION_MINOR.$DB_VERSION_PATCH'` +echo "Version: $VERSION" + +# Make sure the source tree is up-to-date, generate new support files, and +# commit anything that's changed. +cd $D && cvs -q update +cd $D/dist && sh s_all +cd $D && cvs -q commit + +# Build the documentation. +cd $D/docs_src && make clean +cd $D/docs_src && make +cd $D/docs_src && make && make check + +# Copy a development tree into a release tree. +setenv R /a/db-$VERSION +rm -rf $R && mkdir -p $R +cd $D && tar cf - \ +`cvs -q status | sed -n -e "/Repository/s;.*/CVSROOT/db/;;" -e "s/,v//p"` | \ +(cd $R && tar xpf -) + +# Fix symbolic links and permissions. +cd $R/dist && sh s_perm +cd $R/dist && sh s_symlink + +# Build the documents. +cd $R/docs_src && make + +# Build a version. +cd $R && rm -rf build_run && mkdir build_run +cd $R/build_run && ~bostic/bin/dbconf && make >& mklog + +# Smoke test. +./ex_access + +# Check the install +make prefix=`pwd`/BDB install + +# Run distribution check scripts +$R/dist/build/chk.def +$R/dist/build/chk.define +$R/dist/build/chk.offt +$R/dist/build/chk.srcfiles +$R/dist/build/chk.tags + +# Clean up the tree. +cd $R && rm -rf build_run docs_src +cd $R && rm -rf test_thread test_purify test_server test_vxworks test/TODO +cd $R && rm -rf test/upgrade/databases && mkdir test/upgrade/databases + +# ACQUIRE ROOT PRIVILEGES +cd $R && find . -type d | xargs chmod 775 +cd $R && find . -type f | xargs chmod 444 +cd $R/dist && sh s_perm +chown -R 100.100 $R +# DISCARD ROOT PRIVILEGES + +# Compare this release with the last one. +set LR=3.1.X +cd $R/.. && gzcat /a/releases/db-${LR}.tar.gz | tar xf - +cd $R/../db-${LR} && find . | sort > /tmp/__OLD +cd $R && find . | sort > /tmp/__NEW +diff -c /tmp/__OLD /tmp/__NEW + +# Create the tar archive release. +setenv T "$R/../db-$VERSION.tar.gz" +cd $R/.. && tar cf - db-$VERSION | gzip --best > $T +chmod 444 $T + +# Create the zip archive release. +# +# Remove symbolic links to tags files. They're large and we don't want to +# store real symbolic links in the archive for portability reasons. +# ACQUIRE ROOT PRIVILEGES +cd $R && rm -f `find . -type l -name 'tags'` +# DISCARD ROOT PRIVILEGES + +setenv T "$R/../db-$VERSION.zip" +cd $R/.. && zip -r - db-$VERSION > $T +chmod 444 $T diff --git a/db/dist/config.guess b/db/dist/config.guess new file mode 100755 index 000000000..08e8a750a --- /dev/null +++ b/db/dist/config.guess @@ -0,0 +1,1289 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000 +# Free Software Foundation, Inc. + +version='2000-09-05' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Written by Per Bothner . +# Please send patches to . +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit system type (host/target name). +# +# Only a few systems have been added to this list; please add others +# (but try to keep the structure clean). +# + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of this system. + +Operation modes: + -h, --help print this help, then exit + -V, --version print version number, then exit" + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case "$1" in + --version | --vers* | -V ) + echo "$version" ; exit 0 ;; + --help | --h* | -h ) + echo "$usage"; exit 0 ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + exec >&2 + echo "$me: invalid option $1" + echo "$help" + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +# Use $HOST_CC if defined. $CC may point to a cross-compiler +if test x"$CC_FOR_BUILD" = x; then + if test x"$HOST_CC" != x; then + CC_FOR_BUILD="$HOST_CC" + else + if test x"$CC" != x; then + CC_FOR_BUILD="$CC" + else + CC_FOR_BUILD=cc + fi + fi +fi + + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 8/24/94.) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +dummy=dummy-$$ +trap 'rm -f $dummy.c $dummy.o $dummy; exit 1' 1 2 15 + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # Netbsd (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # Determine the machine/vendor (is the vendor relevant). + case "${UNAME_MACHINE}" in + amiga) machine=m68k-unknown ;; + arm32) machine=arm-unknown ;; + atari*) machine=m68k-atari ;; + sun3*) machine=m68k-sun ;; + mac68k) machine=m68k-apple ;; + macppc) machine=powerpc-apple ;; + hp3[0-9][05]) machine=m68k-hp ;; + ibmrt|romp-ibm) machine=romp-ibm ;; + *) machine=${UNAME_MACHINE}-unknown ;; + esac + # The Operating System including object format. + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep __ELF__ >/dev/null + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + # The OS release + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit 0 ;; + alpha:OSF1:*:*) + if test $UNAME_RELEASE = "V4.0"; then + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + fi + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + cat <$dummy.s + .data +\$Lformat: + .byte 37,100,45,37,120,10,0 # "%d-%x\n" + + .text + .globl main + .align 4 + .ent main +main: + .frame \$30,16,\$26,0 + ldgp \$29,0(\$27) + .prologue 1 + .long 0x47e03d80 # implver \$0 + lda \$2,-1 + .long 0x47e20c21 # amask \$2,\$1 + lda \$16,\$Lformat + mov \$0,\$17 + not \$1,\$18 + jsr \$26,printf + ldgp \$29,0(\$26) + mov 0,\$16 + jsr \$26,exit + .end main +EOF + $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null + if test "$?" = 0 ; then + case `./$dummy` in + 0-0) + UNAME_MACHINE="alpha" + ;; + 1-0) + UNAME_MACHINE="alphaev5" + ;; + 1-1) + UNAME_MACHINE="alphaev56" + ;; + 1-101) + UNAME_MACHINE="alphapca56" + ;; + 2-303) + UNAME_MACHINE="alphaev6" + ;; + 2-307) + UNAME_MACHINE="alphaev67" + ;; + esac + fi + rm -f $dummy.s $dummy + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit 0 ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit 0 ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit 0 ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit 0;; + amiga:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit 0 ;; + arc64:OpenBSD:*:*) + echo mips64el-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + hkmips:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + pmax:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sgi:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + wgrisc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit 0 ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit 0;; + SR2?01:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit 0;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit 0 ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit 0 ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + i86pc:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit 0 ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit 0 ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit 0 ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit 0 ;; + atari*:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit 0 ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit 0 ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit 0 ;; + sun3*:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme88k:OpenBSD:*:*) + echo m88k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit 0 ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit 0 ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit 0 ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD $dummy.c -o $dummy \ + && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ + && rm $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + echo mips-mips-riscos${UNAME_RELEASE} + exit 0 ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit 0 ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit 0 ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit 0 ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit 0 ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit 0 ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit 0 ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit 0 ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit 0 ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit 0 ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit 0 ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i?86:AIX:*:*) + echo i386-ibm-aix + exit 0 ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + echo rs6000-ibm-aix3.2.5 + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit 0 ;; + *:AIX:*:4) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'` + if /usr/sbin/lsattr -EHl ${IBM_CPU_ID} | grep POWER >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=4.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit 0 ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit 0 ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit 0 ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit 0 ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit 0 ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit 0 ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit 0 ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit 0 ;; + 9000/[34678]??:HP-UX:*:*) + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null ) && HP_ARCH=`./$dummy` + rm -f $dummy.c $dummy + esac + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit 0 ;; + 3050*:HI-UX:*:*) + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + echo unknown-hitachi-hiuxwe2 + exit 0 ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit 0 ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit 0 ;; + *9??*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit 0 ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit 0 ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit 0 ;; + i?86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit 0 ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit 0 ;; + hppa*:OpenBSD:*:*) + echo hppa-unknown-openbsd + exit 0 ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit 0 ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit 0 ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit 0 ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit 0 ;; + CRAY*X-MP:*:*:*) + echo xmp-cray-unicos + exit 0 ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} + exit 0 ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ + exit 0 ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*T3E:*:*:*) + echo alpha-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY-2:*:*:*) + echo cray2-cray-unicos + exit 0 ;; + F300:UNIX_System_V:*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit 0 ;; + F301:UNIX_System_V:*:*) + echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'` + exit 0 ;; + hp300:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + i?86:BSD/386:*:* | i?86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit 0 ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; + *:FreeBSD:*:*) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit 0 ;; + *:OpenBSD:*:*) + echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit 0 ;; + i*:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit 0 ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit 0 ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i386-pc-interix + exit 0 ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit 0 ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit 0 ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + *:GNU:*:*) + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit 0 ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit 0 ;; + *:Linux:*:*) + + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. cd to the root directory to prevent + # problems with other programs or directories called `ld' in the path. + ld_help_string=`cd /; ld --help 2>&1` + ld_supported_emulations=`echo $ld_help_string \ + | sed -ne '/supported emulations:/!d + s/[ ][ ]*/ /g + s/.*supported emulations: *// + s/ .*// + p'` + case "$ld_supported_emulations" in + *ia64) + echo "${UNAME_MACHINE}-unknown-linux" + exit 0 + ;; + i?86linux) + echo "${UNAME_MACHINE}-pc-linux-gnuaout" + exit 0 + ;; + elf_i?86) + TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" + ;; + i?86coff) + echo "${UNAME_MACHINE}-pc-linux-gnucoff" + exit 0 + ;; + sparclinux) + echo "${UNAME_MACHINE}-unknown-linux-gnuaout" + exit 0 + ;; + armlinux) + echo "${UNAME_MACHINE}-unknown-linux-gnuaout" + exit 0 + ;; + elf32arm*) + echo "${UNAME_MACHINE}-unknown-linux-gnuoldld" + exit 0 + ;; + armelf_linux*) + echo "${UNAME_MACHINE}-unknown-linux-gnu" + exit 0 + ;; + m68klinux) + echo "${UNAME_MACHINE}-unknown-linux-gnuaout" + exit 0 + ;; + elf32ppc | elf32ppclinux) + # Determine Lib Version + cat >$dummy.c < +#if defined(__GLIBC__) +extern char __libc_version[]; +extern char __libc_release[]; +#endif +main(argc, argv) + int argc; + char *argv[]; +{ +#if defined(__GLIBC__) + printf("%s %s\n", __libc_version, __libc_release); +#else + printf("unkown\n"); +#endif + return 0; +} +EOF + LIBC="" + $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null + if test "$?" = 0 ; then + ./$dummy | grep 1\.99 > /dev/null + if test "$?" = 0 ; then + LIBC="libc1" + fi + fi + rm -f $dummy.c $dummy + echo powerpc-unknown-linux-gnu${LIBC} + exit 0 + ;; + shelf_linux) + echo "${UNAME_MACHINE}-unknown-linux-gnu" + exit 0 + ;; + esac + + if test "${UNAME_MACHINE}" = "alpha" ; then + cat <$dummy.s + .data + \$Lformat: + .byte 37,100,45,37,120,10,0 # "%d-%x\n" + + .text + .globl main + .align 4 + .ent main + main: + .frame \$30,16,\$26,0 + ldgp \$29,0(\$27) + .prologue 1 + .long 0x47e03d80 # implver \$0 + lda \$2,-1 + .long 0x47e20c21 # amask \$2,\$1 + lda \$16,\$Lformat + mov \$0,\$17 + not \$1,\$18 + jsr \$26,printf + ldgp \$29,0(\$26) + mov 0,\$16 + jsr \$26,exit + .end main +EOF + LIBC="" + $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null + if test "$?" = 0 ; then + case `./$dummy` in + 0-0) + UNAME_MACHINE="alpha" + ;; + 1-0) + UNAME_MACHINE="alphaev5" + ;; + 1-1) + UNAME_MACHINE="alphaev56" + ;; + 1-101) + UNAME_MACHINE="alphapca56" + ;; + 2-303) + UNAME_MACHINE="alphaev6" + ;; + 2-307) + UNAME_MACHINE="alphaev67" + ;; + esac + + objdump --private-headers $dummy | \ + grep ld.so.1 > /dev/null + if test "$?" = 0 ; then + LIBC="libc1" + fi + fi + rm -f $dummy.s $dummy + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0 + elif test "${UNAME_MACHINE}" = "mips" ; then + cat >$dummy.c < /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif +#ifdef __MIPSEB__ + printf ("%s-unknown-linux-gnu\n", argv[1]); +#endif +#ifdef __MIPSEL__ + printf ("%sel-unknown-linux-gnu\n", argv[1]); +#endif + return 0; +} +EOF + $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + elif test "${UNAME_MACHINE}" = "s390"; then + echo s390-ibm-linux && exit 0 + elif test "${UNAME_MACHINE}" = "x86_64"; then + echo x86_64-unknown-linux-gnu && exit 0 + else + # Either a pre-BFD a.out linker (linux-gnuoldld) + # or one that does not give us useful --help. + # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout. + # If ld does not provide *any* "supported emulations:" + # that means it is gnuoldld. + echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations:" + test $? != 0 && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0 + + case "${UNAME_MACHINE}" in + i?86) + VENDOR=pc; + ;; + *) + VENDOR=unknown; + ;; + esac + # Determine whether the default compiler is a.out or elf + cat >$dummy.c < +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif +#ifdef __ELF__ +# ifdef __GLIBC__ +# if __GLIBC__ >= 2 + printf ("%s-${VENDOR}-linux-gnu\n", argv[1]); +# else + printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); +# endif +# else + printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); +# endif +#else + printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]); +#endif + return 0; +} +EOF + $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0 + fi ;; +# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. earlier versions +# are messed up and put the nodename in both sysname and nodename. + i?86:DYNIX/ptx:4*:*) + echo i386-sequent-sysv4 + exit 0 ;; + i?86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit 0 ;; + i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit 0 ;; + i?86:*:5:7*) + # Fixed at (any) Pentium or better + UNAME_MACHINE=i586 + if [ ${UNAME_SYSTEM} = "UnixWare" ] ; then + echo ${UNAME_MACHINE}-sco-sysv${UNAME_RELEASE}uw${UNAME_VERSION} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE} + fi + exit 0 ;; + i?86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')` + (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|egrep '^Machine.*Pent ?II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit 0 ;; + i?86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit 0 ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit 0 ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit 0 ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit 0 ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit 0 ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit 0 ;; + M68*:*:R3V[567]*:*) + test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; + 3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4.3${OS_REL} && exit 0 + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4 && exit 0 ;; + m68*:LynxOS:2.*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit 0 ;; + i?86:LynxOS:2.*:* | i?86:LynxOS:3.[01]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit 0 ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit 0 ;; + PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit 0 ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit 0 ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit 0 ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit 0 ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit 0 ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit 0 ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit 0 ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit 0 ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit 0 ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit 0 ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit 0 ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit 0 ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit 0 ;; + *:Darwin:*:*) + echo `uname -p`-apple-darwin${UNAME_RELEASE} + exit 0 ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + if test "${UNAME_MACHINE}" = "x86pc"; then + UNAME_MACHINE=pc + fi + echo `uname -p`-${UNAME_MACHINE}-nto-qnx + exit 0 ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit 0 ;; + NSR-[KW]:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit 0 ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit 0 ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit 0 ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit 0 ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +#if !defined (ultrix) + printf ("vax-dec-bsd\n"); exit (0); +#else + printf ("vax-dec-ultrix\n"); exit (0); +#endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm $dummy.c $dummy && exit 0 +rm -f $dummy.c $dummy + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit 0 ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + c34*) + echo c34-convex-bsd + exit 0 ;; + c38*) + echo c38-convex-bsd + exit 0 ;; + c4*) + echo c4-convex-bsd + exit 0 ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess version = $version + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "version='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/db/dist/config.hin b/db/dist/config.hin new file mode 100644 index 000000000..d153bc0f8 --- /dev/null +++ b/db/dist/config.hin @@ -0,0 +1,231 @@ +/* config.hin. Generated automatically from configure.in by autoheader. */ + +/* Define to empty if the keyword does not work. */ +#undef const + +/* Define if your struct stat has st_blksize. */ +#undef HAVE_ST_BLKSIZE + +/* Define to `int' if doesn't define. */ +#undef mode_t + +/* Define to `long' if doesn't define. */ +#undef off_t + +/* Define to `int' if doesn't define. */ +#undef pid_t + +/* Define to `unsigned' if doesn't define. */ +#undef size_t + +/* Define if the `S_IS*' macros in do not work properly. */ +#undef STAT_MACROS_BROKEN + +/* Define if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define if you can safely include both and . */ +#undef TIME_WITH_SYS_TIME + +/* Define if your processor stores words with the most significant + byte first (like Motorola and SPARC, unlike Intel and VAX). */ +#undef WORDS_BIGENDIAN + +/* Define if you are building a version for running the test suite. */ +#undef CONFIG_TEST + +/* Define if you want a debugging version. */ +#undef DEBUG + +/* Define if you want a version that logs read operations. */ +#undef DEBUG_ROP + +/* Define if you want a version that logs write operations. */ +#undef DEBUG_WOP + +/* Define if you want a version with run-time diagnostic checking. */ +#undef DIAGNOSTIC + +/* Define if you want to mask harmless unitialized memory read/writes. */ +#undef UMRW + +/* Define if fcntl/F_SETFD denies child access to file descriptors. */ +#undef HAVE_FCNTL_F_SETFD + +/* Define if building big-file environment (e.g., AIX, HP/UX, Solaris). */ +#undef HAVE_FILE_OFFSET_BITS + +/* Mutex possibilities. */ +#undef HAVE_MUTEX_68K_GCC_ASSEMBLY +#undef HAVE_MUTEX_AIX_CHECK_LOCK +#undef HAVE_MUTEX_ALPHA_GCC_ASSEMBLY +#undef HAVE_MUTEX_HPPA_GCC_ASSEMBLY +#undef HAVE_MUTEX_HPPA_MSEM_INIT +#undef HAVE_MUTEX_IA64_GCC_ASSEMBLY +#undef HAVE_MUTEX_MACOS +#undef HAVE_MUTEX_MSEM_INIT +#undef HAVE_MUTEX_PPC_GCC_ASSEMBLY +#undef HAVE_MUTEX_PTHREADS +#undef HAVE_MUTEX_RELIANTUNIX_INITSPIN +#undef HAVE_MUTEX_SCO_X86_CC_ASSEMBLY +#undef HAVE_MUTEX_SEMA_INIT +#undef HAVE_MUTEX_SGI_INIT_LOCK +#undef HAVE_MUTEX_SOLARIS_LOCK_TRY +#undef HAVE_MUTEX_SOLARIS_LWP +#undef HAVE_MUTEX_SPARC_GCC_ASSEMBLY +#undef HAVE_MUTEX_THREADS +#undef HAVE_MUTEX_UI_THREADS +#undef HAVE_MUTEX_UTS_CC_ASSEMBLY +#undef HAVE_MUTEX_VMS +#undef HAVE_MUTEX_VXWORKS +#undef HAVE_MUTEX_WIN16 +#undef HAVE_MUTEX_WIN32 +#undef HAVE_MUTEX_X86_GCC_ASSEMBLY + +/* Define if building on QNX. */ +#undef HAVE_QNX + +/* Define if building RPC client/server. */ +#undef HAVE_RPC + +/* Define if your sprintf returns a pointer, not a length. */ +#undef SPRINTF_RET_CHARPNT + +/* Define if you have the getcwd function. */ +#undef HAVE_GETCWD + +/* Define if you have the getopt function. */ +#undef HAVE_GETOPT + +/* Define if you have the getuid function. */ +#undef HAVE_GETUID + +/* Define if you have the memcmp function. */ +#undef HAVE_MEMCMP + +/* Define if you have the memcpy function. */ +#undef HAVE_MEMCPY + +/* Define if you have the memmove function. */ +#undef HAVE_MEMMOVE + +/* Define if you have the mlock function. */ +#undef HAVE_MLOCK + +/* Define if you have the mmap function. */ +#undef HAVE_MMAP + +/* Define if you have the munlock function. */ +#undef HAVE_MUNLOCK + +/* Define if you have the munmap function. */ +#undef HAVE_MUNMAP + +/* Define if you have the pread function. */ +#undef HAVE_PREAD + +/* Define if you have the pstat_getdynamic function. */ +#undef HAVE_PSTAT_GETDYNAMIC + +/* Define if you have the pwrite function. */ +#undef HAVE_PWRITE + +/* Define if you have the qsort function. */ +#undef HAVE_QSORT + +/* Define if you have the raise function. */ +#undef HAVE_RAISE + +/* Define if you have the sched_yield function. */ +#undef HAVE_SCHED_YIELD + +/* Define if you have the select function. */ +#undef HAVE_SELECT + +/* Define if you have the shmget function. */ +#undef HAVE_SHMGET + +/* Define if you have the snprintf function. */ +#undef HAVE_SNPRINTF + +/* Define if you have the strcasecmp function. */ +#undef HAVE_STRCASECMP + +/* Define if you have the strerror function. */ +#undef HAVE_STRERROR + +/* Define if you have the strtoul function. */ +#undef HAVE_STRTOUL + +/* Define if you have the sysconf function. */ +#undef HAVE_SYSCONF + +/* Define if you have the vsnprintf function. */ +#undef HAVE_VSNPRINTF + +/* Define if you have the yield function. */ +#undef HAVE_YIELD + +/* Define if you have the header file. */ +#undef HAVE_DIRENT_H + +/* Define if you have the header file. */ +#undef HAVE_NDIR_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_DIR_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_NDIR_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_SELECT_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define if you have the nsl library (-lnsl). */ +#undef HAVE_LIBNSL + +/* + * Big-file configuration. + */ +#ifdef HAVE_FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 64 +#endif + +/* + * Don't step on the namespace. Other libraries may have their own + * implementations of these functions, we don't want to use their + * implementations or force them to use ours based on the load order. + */ +#ifndef HAVE_GETCWD +#define getcwd __db_Cgetcwd +#endif +#ifndef HAVE_GETOPT +#define getopt __db_Cgetopt +#endif +#ifndef HAVE_MEMCMP +#define memcmp __db_Cmemcmp +#endif +#ifndef HAVE_MEMCPY +#define memcpy __db_Cmemcpy +#endif +#ifndef HAVE_MEMMOVE +#define memmove __db_Cmemmove +#endif +#ifndef HAVE_RAISE +#define raise __db_Craise +#endif +#ifndef HAVE_SNPRINTF +#define snprintf __db_Csnprintf +#endif +#ifndef HAVE_STRCASECMP +#define strcasecmp __db_Cstrcasecmp +#endif +#ifndef HAVE_STRERROR +#define strerror __db_Cstrerror +#endif +#ifndef HAVE_VSNPRINTF +#define vsnprintf __db_Cvsnprintf +#endif diff --git a/db/dist/config.sub b/db/dist/config.sub new file mode 100755 index 000000000..42fc991d0 --- /dev/null +++ b/db/dist/config.sub @@ -0,0 +1,1328 @@ +#! /bin/sh +# Configuration validation subroutine script, version 1.1. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000 +# Free Software Foundation, Inc. + +version='2000-09-11' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Please send patches to . +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -V, --version print version number, then exit" + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case "$1" in + --version | --vers* | -V ) + echo "$version" ; exit 0 ;; + --help | --h* | -h ) + echo "$usage"; exit 0 ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + exec >&2 + echo "$me: invalid option $1" + echo "$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit 0;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis) + os= + basic_machine=$1 + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + tahoe | i860 | ia64 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \ + | arme[lb] | armv[2345] | armv[345][lb] | pyramid | mn10200 | mn10300 | tron | a29k \ + | 580 | i960 | h8300 \ + | x86 | ppcbe | mipsbe | mipsle | shbe | shle | armbe | armle \ + | hppa | hppa1.0 | hppa1.1 | hppa2.0 | hppa2.0w | hppa2.0n \ + | hppa64 \ + | alpha | alphaev[4-8] | alphaev56 | alphapca5[67] \ + | alphaev6[78] \ + | we32k | ns16k | clipper | i370 | sh | sh[34] \ + | powerpc | powerpcle \ + | 1750a | dsp16xx | pdp11 | mips16 | mips64 | mipsel | mips64el \ + | mips64orion | mips64orionel | mipstx39 | mipstx39el \ + | mips64vr4300 | mips64vr4300el | mips64vr4100 | mips64vr4100el \ + | mips64vr5000 | miprs64vr5000el | mcore \ + | sparc | sparclet | sparclite | sparc64 | sparcv9 | v850 | c4x \ + | thumb | d10v | d30v | fr30 | avr) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | z8k | v70 | h8500 | w65 | pj | pjl) + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i[234567]86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + # FIXME: clean up the formatting here. + vax-* | tahoe-* | i[234567]86-* | i860-* | ia64-* | m32r-* | m68k-* | m68000-* \ + | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \ + | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \ + | power-* | none-* | 580-* | cray2-* | h8300-* | h8500-* | i960-* \ + | xmp-* | ymp-* \ + | x86-* | ppcbe-* | mipsbe-* | mipsle-* | shbe-* | shle-* | armbe-* | armle-* \ + | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* | hppa2.0w-* \ + | hppa2.0n-* | hppa64-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphapca5[67]-* \ + | alphaev6[78]-* \ + | we32k-* | cydra-* | ns16k-* | pn-* | np1-* | xps100-* \ + | clipper-* | orion-* \ + | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \ + | sparc64-* | sparcv9-* | sparc86x-* | mips16-* | mips64-* | mipsel-* \ + | mips64el-* | mips64orion-* | mips64orionel-* \ + | mips64vr4100-* | mips64vr4100el-* | mips64vr4300-* | mips64vr4300el-* \ + | mipstx39-* | mipstx39el-* | mcore-* \ + | f301-* | armv*-* | s390-* | sv1-* | t3e-* \ + | m88110-* | m680[01234]0-* | m683?2-* | m68360-* | z8k-* | d10v-* \ + | thumb-* | v850-* | d30v-* | tic30-* | c30-* | fr30-* \ + | bs2000-* | tic54x-* | c54x-* | x86_64-*) + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | ymp) + basic_machine=ymp-cray + os=-unicos + ;; + cray2) + basic_machine=cray2-cray + os=-unicos + ;; + [ctj]90-cray) + basic_machine=c90-cray + os=-unicos + ;; + crds | unos) + basic_machine=m68k-crds + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i[34567]86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i[34567]86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i[34567]86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i[34567]86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + i386-go32 | go32) + basic_machine=i386-unknown + os=-go32 + ;; + i386-mingw32 | mingw32) + basic_machine=i386-unknown + os=-mingw32 + ;; + i[34567]86-pw32 | pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mipsel*-linux*) + basic_machine=mipsel-unknown + os=-linux-gnu + ;; + mips*-linux*) + basic_machine=mips-unknown + os=-linux-gnu + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + mmix*) + basic_machine=mmix-knuth + os=-mmixware + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + msdos) + basic_machine=i386-unknown + os=-msdos + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pentium | p5 | k5 | k6 | nexen) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon) + basic_machine=i686-pc + ;; + pentiumii | pentium2) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexen-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=rs6000-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sparclite-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=t3e-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xmp) + basic_machine=xmp-cray + os=-unicos + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + mips) + if [ x$os = x-linux-gnu ]; then + basic_machine=mips-unknown + else + basic_machine=mips-mips + fi + ;; + romp) + basic_machine=romp-ibm + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh3 | sh4) + base_machine=sh-unknown + ;; + sparc | sparcv9) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + c4x*) + basic_machine=c4x-none + os=-coff + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ + | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i[34567]86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto*) + os=-nto-qnx + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -*MiNT) + os=-mint + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-ibm) + os=-aix + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f301-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -vxsim* | -vxworks*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -*MiNT) + vendor=atari + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "version='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/db/dist/configure b/db/dist/configure new file mode 100755 index 000000000..387421304 --- /dev/null +++ b/db/dist/configure @@ -0,0 +1,5811 @@ +#! /bin/sh + +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version 2.13 +# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +# Any additions from configure.in: +ac_default_prefix=/usr/local/BerkeleyDB.@DB_VERSION_MAJOR@.@DB_VERSION_MINOR@ +ac_help="$ac_help + --disable-bigfile Disable AIX, HP/UX, Solaris big files." +ac_help="$ac_help + --enable-compat185 Build DB 1.85 compatibility API." +ac_help="$ac_help + --enable-cxx Build C++ API." +ac_help="$ac_help + --enable-debug Build a debugging version." +ac_help="$ac_help + --enable-debug_rop Build a version that logs read operations." +ac_help="$ac_help + --enable-debug_wop Build a version that logs write operations." +ac_help="$ac_help + --enable-diagnostic Build a version with run-time diagnostics." +ac_help="$ac_help + --enable-dump185 Build db_dump185(1) to dump 1.85 databases." +ac_help="$ac_help + --enable-dynamic Build with dynamic libraries." +ac_help="$ac_help + --enable-java Build Java API." +ac_help="$ac_help + --enable-posixmutexes Force use of POSIX standard mutexes." +ac_help="$ac_help + --enable-rpc Build RPC client/server." +ac_help="$ac_help + --enable-shared Build with dynamic libraries." +ac_help="$ac_help + --enable-tcl Build Tcl API." +ac_help="$ac_help + --enable-test Configure to run the test suite." +ac_help="$ac_help + --enable-uimutexes Force use of Unix International mutexes." +ac_help="$ac_help + --enable-umrw Mask harmless unitialized memory read/writes." +ac_help="$ac_help + --with-tcl=DIR Directory location of tclConfig.sh." + +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +x_includes=NONE +x_libraries=NONE +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +# Initialize some other variables. +subdirs= +MFLAGS= MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} +# Maximum number of lines to put in a shell here document. +ac_max_here_lines=12 + +ac_prev= +for ac_option +do + + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + case "$ac_option" in + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) ac_optarg= ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case "$ac_option" in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build="$ac_optarg" ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [same as prefix] + --bindir=DIR user executables in DIR [EPREFIX/bin] + --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] + --libexecdir=DIR program executables in DIR [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data in DIR + [PREFIX/share] + --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data in DIR + [PREFIX/com] + --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] + --libdir=DIR object code libraries in DIR [EPREFIX/lib] + --includedir=DIR C header files in DIR [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM + run sed PROGRAM on installed program names +EOF + cat << EOF +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +EOF + if test -n "$ac_help"; then + echo "--enable and --with options recognized:$ac_help" + fi + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version 2.13" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes="$ac_optarg" ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries="$ac_optarg" ;; + + -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } + ;; + + *) + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then + echo "configure: warning: $ac_option: invalid host type" 1>&2 + fi + if test "x$nonopt" != xNONE; then + { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } +fi + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 6 checking for... messages and results +# 5 compiler messages saved in config.log +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&5 + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set these to C if already set. These must not be set unconditionally +# because not all systems understand e.g. LANG=C (notably SCO). +# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! +# Non-C LC_CTYPE values break the ctype check. +if test "${LANG+set}" = set; then LANG=C; export LANG; fi +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi +if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +ac_unique_file=../db/db.c + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=$0 + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } + else + { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } + fi +fi +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` + +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + echo "loading site script $ac_site_file" + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +ac_exeext= +ac_objext=o +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + + + + +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; } +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +echo "configure:595: checking for a BSD compatible install" >&5 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + + +# Make sure we can run config.sub. +if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then : +else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } +fi + +echo $ac_n "checking host system type""... $ac_c" 1>&6 +echo "configure:654: checking host system type" >&5 + +host_alias=$host +case "$host_alias" in +NONE) + case $nonopt in + NONE) + if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then : + else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; } + fi ;; + *) host_alias=$nonopt ;; + esac ;; +esac + +host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias` +host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$host" 1>&6 + +if test "$program_transform_name" = s,x,x,; then + program_transform_name= +else + # Double any \ or $. echo might interpret backslashes. + cat <<\EOF_SED > conftestsed +s,\\,\\\\,g; s,\$,$$,g +EOF_SED + program_transform_name="`echo $program_transform_name|sed -f conftestsed`" + rm -f conftestsed +fi +test "$program_prefix" != NONE && + program_transform_name="s,^,${program_prefix},; $program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s,\$\$,${program_suffix},; $program_transform_name" + +# sed with no file args requires a program. +test "$program_transform_name" = "" && program_transform_name="s,x,x," + + +echo $ac_n "checking if building in the top-level directory""... $ac_c" 1>&6 +echo "configure:695: checking if building in the top-level directory" >&5 + test -d db_archive && { echo "configure: error: +Berkeley DB cannot be built in the top-level distribution directory." 1>&2; exit 1; } +echo "$ac_t""no" 1>&6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +o=.o +INSTALLER="\$(cp)" +DEFAULT_LIB="\$(libdb)" +DEFAULT_INSTALL="install_static" + + + +DB_VERSION_MAJOR=3 + +DB_VERSION_MINOR=2 + +DB_VERSION_PATCH=9 + +DB_VERSION_STRING="\"Sleepycat Software: Berkeley DB 3.2.9: (January 24, 2001)\"" + + + + + + +echo $ac_n "checking if --disable-bigfile option specified""... $ac_c" 1>&6 +echo "configure:756: checking if --disable-bigfile option specified" >&5 +# Check whether --enable-bigfile or --disable-bigfile was given. +if test "${enable_bigfile+set}" = set; then + enableval="$enable_bigfile" + db_cv_bigfile="yes" +else + db_cv_bigfile="no" +fi + +echo "$ac_t""$db_cv_bigfile" 1>&6 + +echo $ac_n "checking if --enable-compat185 option specified""... $ac_c" 1>&6 +echo "configure:768: checking if --enable-compat185 option specified" >&5 +# Check whether --enable-compat185 or --disable-compat185 was given. +if test "${enable_compat185+set}" = set; then + enableval="$enable_compat185" + db_cv_compat185="$enable_compat185" +else + db_cv_compat185="no" +fi + +echo "$ac_t""$db_cv_compat185" 1>&6 + +echo $ac_n "checking if --enable-cxx option specified""... $ac_c" 1>&6 +echo "configure:780: checking if --enable-cxx option specified" >&5 +# Check whether --enable-cxx or --disable-cxx was given. +if test "${enable_cxx+set}" = set; then + enableval="$enable_cxx" + db_cv_cxx="$enable_cxx" +else + db_cv_cxx="no" +fi + +echo "$ac_t""$db_cv_cxx" 1>&6 + +echo $ac_n "checking if --enable-debug option specified""... $ac_c" 1>&6 +echo "configure:792: checking if --enable-debug option specified" >&5 +# Check whether --enable-debug or --disable-debug was given. +if test "${enable_debug+set}" = set; then + enableval="$enable_debug" + db_cv_debug="$enable_debug" +else + db_cv_debug="no" +fi + +echo "$ac_t""$db_cv_debug" 1>&6 + +echo $ac_n "checking if --enable-debug_rop option specified""... $ac_c" 1>&6 +echo "configure:804: checking if --enable-debug_rop option specified" >&5 +# Check whether --enable-debug_rop or --disable-debug_rop was given. +if test "${enable_debug_rop+set}" = set; then + enableval="$enable_debug_rop" + db_cv_debug_rop="$enable_debug_rop" +else + db_cv_debug_rop="no" +fi + +echo "$ac_t""$db_cv_debug_rop" 1>&6 + +echo $ac_n "checking if --enable-debug_wop option specified""... $ac_c" 1>&6 +echo "configure:816: checking if --enable-debug_wop option specified" >&5 +# Check whether --enable-debug_wop or --disable-debug_wop was given. +if test "${enable_debug_wop+set}" = set; then + enableval="$enable_debug_wop" + db_cv_debug_wop="$enable_debug_wop" +else + db_cv_debug_wop="no" +fi + +echo "$ac_t""$db_cv_debug_wop" 1>&6 + +echo $ac_n "checking if --enable-diagnostic option specified""... $ac_c" 1>&6 +echo "configure:828: checking if --enable-diagnostic option specified" >&5 +# Check whether --enable-diagnostic or --disable-diagnostic was given. +if test "${enable_diagnostic+set}" = set; then + enableval="$enable_diagnostic" + db_cv_diagnostic="$enable_diagnostic" +else + db_cv_diagnostic="no" +fi + +echo "$ac_t""$db_cv_diagnostic" 1>&6 + +echo $ac_n "checking if --enable-dump185 option specified""... $ac_c" 1>&6 +echo "configure:840: checking if --enable-dump185 option specified" >&5 +# Check whether --enable-dump185 or --disable-dump185 was given. +if test "${enable_dump185+set}" = set; then + enableval="$enable_dump185" + db_cv_dump185="$enable_dump185" +else + db_cv_dump185="no" +fi + +echo "$ac_t""$db_cv_dump185" 1>&6 + +echo $ac_n "checking if --enable-dynamic option specified""... $ac_c" 1>&6 +echo "configure:852: checking if --enable-dynamic option specified" >&5 +# Check whether --enable-dynamic or --disable-dynamic was given. +if test "${enable_dynamic+set}" = set; then + enableval="$enable_dynamic" + db_cv_dynamic="$enable_dynamic" +else + db_cv_dynamic="no" +fi + +echo "$ac_t""$db_cv_dynamic" 1>&6 + +echo $ac_n "checking if --enable-java option specified""... $ac_c" 1>&6 +echo "configure:864: checking if --enable-java option specified" >&5 +# Check whether --enable-java or --disable-java was given. +if test "${enable_java+set}" = set; then + enableval="$enable_java" + db_cv_java="$enable_java" +else + db_cv_java="no" +fi + +echo "$ac_t""$db_cv_java" 1>&6 + +echo $ac_n "checking if --enable-posixmutexes option specified""... $ac_c" 1>&6 +echo "configure:876: checking if --enable-posixmutexes option specified" >&5 +# Check whether --enable-posixmutexes or --disable-posixmutexes was given. +if test "${enable_posixmutexes+set}" = set; then + enableval="$enable_posixmutexes" + db_cv_posixmutexes="$enable_posixmutexes" +else + db_cv_posixmutexes="no" +fi + +echo "$ac_t""$db_cv_posixmutexes" 1>&6 + +echo $ac_n "checking if --enable-rpc option specified""... $ac_c" 1>&6 +echo "configure:888: checking if --enable-rpc option specified" >&5 +# Check whether --enable-rpc or --disable-rpc was given. +if test "${enable_rpc+set}" = set; then + enableval="$enable_rpc" + db_cv_rpc="$enable_rpc" +else + db_cv_rpc="no" +fi + +echo "$ac_t""$db_cv_rpc" 1>&6 + +echo $ac_n "checking if --enable-shared option specified""... $ac_c" 1>&6 +echo "configure:900: checking if --enable-shared option specified" >&5 +# Check whether --enable-shared or --disable-shared was given. +if test "${enable_shared+set}" = set; then + enableval="$enable_shared" + db_cv_shared="$enable_shared" +else + db_cv_shared="no" +fi + +echo "$ac_t""$db_cv_shared" 1>&6 +if test "$db_cv_shared" != "no"; then + db_cv_dynamic="yes" +fi + +echo $ac_n "checking if --enable-tcl option specified""... $ac_c" 1>&6 +echo "configure:915: checking if --enable-tcl option specified" >&5 +# Check whether --enable-tcl or --disable-tcl was given. +if test "${enable_tcl+set}" = set; then + enableval="$enable_tcl" + db_cv_tcl="$enable_tcl" +else + db_cv_tcl="no" +fi + +echo "$ac_t""$db_cv_tcl" 1>&6 + +echo $ac_n "checking if --enable-test option specified""... $ac_c" 1>&6 +echo "configure:927: checking if --enable-test option specified" >&5 +# Check whether --enable-test or --disable-test was given. +if test "${enable_test+set}" = set; then + enableval="$enable_test" + db_cv_test="$enable_test" +else + db_cv_test="no" +fi + +echo "$ac_t""$db_cv_test" 1>&6 + +echo $ac_n "checking if --enable-uimutexes option specified""... $ac_c" 1>&6 +echo "configure:939: checking if --enable-uimutexes option specified" >&5 +# Check whether --enable-uimutexes or --disable-uimutexes was given. +if test "${enable_uimutexes+set}" = set; then + enableval="$enable_uimutexes" + db_cv_uimutexes="$enable_uimutexes" +else + db_cv_uimutexes="no" +fi + +echo "$ac_t""$db_cv_uimutexes" 1>&6 + +echo $ac_n "checking if --enable-umrw option specified""... $ac_c" 1>&6 +echo "configure:951: checking if --enable-umrw option specified" >&5 +# Check whether --enable-umrw or --disable-umrw was given. +if test "${enable_umrw+set}" = set; then + enableval="$enable_umrw" + db_cv_umrw="$enable_umrw" +else + db_cv_umrw="no" +fi + +echo "$ac_t""$db_cv_umrw" 1>&6 + +echo $ac_n "checking if --with-tcl option specified""... $ac_c" 1>&6 +echo "configure:963: checking if --with-tcl option specified" >&5 +# Check whether --with-tcl or --without-tcl was given. +if test "${with_tcl+set}" = set; then + withval="$with_tcl" + with_tclconfig=${withval} +else + with_tclconfig="no" +fi + +echo "$ac_t""$with_tclconfig" 1>&6 +if test "$with_tclconfig" != "no"; then + db_cv_tcl="yes" +fi + + +optimize_def="-O" +case "$host_os" in +aix4.*) optimize_def="-O2" + CC=${CC-"xlc_r"} + CPPFLAGS="-D_THREAD_SAFE $CPPFLAGS" + LIBTSO_LIBS="\$(LIBS)";; +bsdi3*) CC=${CC-"shlicc2"} + optimize_def="-O2" + LIBS="-lipc $LIBS";; +bsdi*) optimize_def="-O2";; +freebsd*) optimize_def="-O2" + CPPFLAGS="-D_THREAD_SAFE $CPPFLAGS" + LIBS="-pthread";; +hpux*) CPPFLAGS="-D_REENTRANT $CPPFLAGS";; +irix*) optimize_def="-O2" + CPPFLAGS="-D_SGI_MP_SOURCE $CPPFLAGS";; +linux*) optimize_def="-O2" + CFLAGS="-D_GNU_SOURCE" + CPPFLAGS="-D_REENTRANT $CPPFLAGS";; +mpeix*) CPPFLAGS="-D_POSIX_SOURCE -D_SOCKET_SOURCE $CPPFLAGS" + LIBS="-lsocket -lsvipc $LIBS";; +osf*) CPPFLAGS="-D_REENTRANT $CPPFLAGS";; +*qnx) cat >> confdefs.h <<\EOF +#define HAVE_QNX 1 +EOF +;; +sco3.2v4*) CC=${CC-"cc -belf"} + LIBS="-lsocket -lnsl_s $LIBS";; +sco*) CC=${CC-"cc -belf"} + LIBS="-lsocket -lnsl $LIBS";; +solaris*) CPPFLAGS="-D_REENTRANT $CPPFLAGS";; +esac + +CFLAGS=${CFLAGS-$optimize_def} +CXXFLAGS=${CXXFLAGS-"$CFLAGS"} + +if test "$db_cv_debug" = yes; then + cat >> confdefs.h <<\EOF +#define DEBUG 1 +EOF + + CFLAGS="$CFLAGS -g" + CXXFLAGS="$CXXFLAGS -g" +fi + +# Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1026: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="cc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +# Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1055: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +# Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1084: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1114: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_prog_rejected=no + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + break + fi + done + IFS="$ac_save_ifs" +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" "$@" + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + if test -z "$CC"; then + case "`uname -s`" in + *win32* | *WIN32*) + # Extract the first word of "cl", so it can be a program name with args. +set dummy cl; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1165: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="cl" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + ;; + esac + fi + test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } +fi + +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:1197: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +cat > conftest.$ac_ext << EOF + +#line 1208 "configure" +#include "confdefs.h" + +main(){return(0);} +EOF +if { (eval echo configure:1213: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + ac_cv_prog_cc_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cc_cross=no + else + ac_cv_prog_cc_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cc_works=no +fi +rm -fr conftest* +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 +if test $ac_cv_prog_cc_works = no; then + { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:1239: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 +cross_compiling=$ac_cv_prog_cc_cross + +echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 +echo "configure:1244: checking whether we are using GNU C" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gcc" 1>&6 + +if test $ac_cv_prog_gcc = yes; then + GCC=yes +else + GCC= +fi + +ac_test_CFLAGS="${CFLAGS+set}" +ac_save_CFLAGS="$CFLAGS" +CFLAGS= +echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 +echo "configure:1272: checking whether ${CC-cc} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_cc_g=yes +else + ac_cv_prog_cc_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi + + +MAKEFILE_CC=${CC} +MAKEFILE_CCLINK="\$(CC)" +MAKEFILE_CXX="nocxx" + +if test "$db_cv_diagnostic" = yes; then + cat >> confdefs.h <<\EOF +#define DIAGNOSTIC 1 +EOF + +fi +if test "$db_cv_debug_rop" = yes; then + cat >> confdefs.h <<\EOF +#define DEBUG_ROP 1 +EOF + +fi +if test "$db_cv_debug_wop" = yes; then + cat >> confdefs.h <<\EOF +#define DEBUG_WOP 1 +EOF + +fi +if test "$db_cv_umrw" = yes; then + cat >> confdefs.h <<\EOF +#define UMRW 1 +EOF + +fi +if test "$db_cv_test" = yes; then + cat >> confdefs.h <<\EOF +#define CONFIG_TEST 1 +EOF + +fi + +if test "$db_cv_cxx" = "yes"; then + if test "$GCC" != "yes"; then + case "$host_os" in + aix*) # Extract the first word of "xlC_r", so it can be a program name with args. +set dummy xlC_r; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1345: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CCC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CCC"; then + ac_cv_prog_CCC="$CCC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CCC="xlC_r" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CCC="$ac_cv_prog_CCC" +if test -n "$CCC"; then + echo "$ac_t""$CCC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi +;; + hpux*) # Extract the first word of "aCC", so it can be a program name with args. +set dummy aCC; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1374: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CCC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CCC"; then + ac_cv_prog_CCC="$CCC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CCC="aCC" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CCC="$ac_cv_prog_CCC" +if test -n "$CCC"; then + echo "$ac_t""$CCC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi +;; + osf*) # Extract the first word of "cxx", so it can be a program name with args. +set dummy cxx; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1403: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CCC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CCC"; then + ac_cv_prog_CCC="$CCC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CCC="cxx" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CCC="$ac_cv_prog_CCC" +if test -n "$CCC"; then + echo "$ac_t""$CCC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi +;; + solaris*) # Extract the first word of "CC", so it can be a program name with args. +set dummy CC; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1432: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CCC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CCC"; then + ac_cv_prog_CCC="$CCC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CCC="CC" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CCC="$ac_cv_prog_CCC" +if test -n "$CCC"; then + echo "$ac_t""$CCC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi +;; + esac + fi + for ac_prog in $CCC c++ g++ gcc CC cxx cc++ cl +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1465: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CXX'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CXX="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CXX="$ac_cv_prog_CXX" +if test -n "$CXX"; then + echo "$ac_t""$CXX" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$CXX" && break +done +test -n "$CXX" || CXX="gcc" + + +echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:1497: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works" >&5 + +ac_ext=C +# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cxx_cross + +cat > conftest.$ac_ext << EOF + +#line 1508 "configure" +#include "confdefs.h" + +int main(){return(0);} +EOF +if { (eval echo configure:1513: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + ac_cv_prog_cxx_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cxx_cross=no + else + ac_cv_prog_cxx_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cxx_works=no +fi +rm -fr conftest* +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +echo "$ac_t""$ac_cv_prog_cxx_works" 1>&6 +if test $ac_cv_prog_cxx_works = no; then + { echo "configure: error: installation or configuration problem: C++ compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:1539: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cxx_cross" 1>&6 +cross_compiling=$ac_cv_prog_cxx_cross + +echo $ac_n "checking whether we are using GNU C++""... $ac_c" 1>&6 +echo "configure:1544: checking whether we are using GNU C++" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gxx'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.C <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gxx=yes +else + ac_cv_prog_gxx=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gxx" 1>&6 + +if test $ac_cv_prog_gxx = yes; then + GXX=yes +else + GXX= +fi + +ac_test_CXXFLAGS="${CXXFLAGS+set}" +ac_save_CXXFLAGS="$CXXFLAGS" +CXXFLAGS= +echo $ac_n "checking whether ${CXX-g++} accepts -g""... $ac_c" 1>&6 +echo "configure:1572: checking whether ${CXX-g++} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cxx_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.cc +if test -z "`${CXX-g++} -g -c conftest.cc 2>&1`"; then + ac_cv_prog_cxx_g=yes +else + ac_cv_prog_cxx_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cxx_g" 1>&6 +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS="$ac_save_CXXFLAGS" +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi + + MAKEFILE_CXX=${CXX} +fi + +if test "$GXX" = "yes"; then + CXXVERSION=`${MAKEFILE_CXX} --version` + case ${CXXVERSION} in + 1.*|2.[01234567].*|*-1.*|*-2.[01234567].* ) + CXXFLAGS="-fhandle-exceptions $CXXFLAGS";; + * ) CXXFLAGS="-fexceptions $CXXFLAGS";; + esac +fi + +export CC CCC +CCC=CXX + +LIBDB_ARGS="libdb.a" +LIBTOOL="nolibtool" +POSTLINK="@true" +SOSUFFIX="so" +if test "$db_cv_dynamic" = "yes"; then + SAVE_CC="${MAKEFILE_CC}" + SAVE_CXX="${MAKEFILE_CXX}" + + # Configure libtool. + echo $ac_n "checking libtool configuration""... $ac_c" 1>&6 +echo "configure:1628: checking libtool configuration" >&5 + echo "$ac_t""" 1>&6 + ${CONFIG_SHELL-/bin/sh} $srcdir/ltconfig \ + --no-verify $srcdir/ltmain.sh \ + --output=./libtool $host_os \ + --disable-static \ + || { echo "configure: error: libtool configure failed" 1>&2; exit 1; } + + SOSUFFIX=`sed -e '/^library_names_spec=/!d' -e 's/.*\.\([a-zA-Z0-9_]*\).*/\1/' ./libtool` + DEFAULT_LIB="\$(libso_target)" + DEFAULT_INSTALL="install_dynamic" + LIBDB_ARGS="\$(libso_linkname)" + LIBTOOL="\$(SHELL) ./libtool" + + MAKEFILE_CC="\$(LIBTOOL) --mode=compile ${SAVE_CC}" + MAKEFILE_CXX="\$(LIBTOOL) --mode=compile ${SAVE_CXX}" + MAKEFILE_CCLINK="\$(LIBTOOL) --mode=link ${SAVE_CC}" + + INSTALLER="\$(LIBTOOL) --mode=install cp" + POSTLINK="\$(LIBTOOL) --mode=execute true" + SOLINK="\$(LIBTOOL) --mode=link ${SAVE_CC} -avoid-version" + SOFLAGS="-rpath \$(libdir)" + o=".lo" +fi + +if test "$db_cv_cxx" = "yes"; then + if test "$db_cv_dynamic" = "yes"; then + ADDITIONAL_LIBS="$ADDITIONAL_LIBS \$(libxso_target)" + DEFAULT_INSTALL="${DEFAULT_INSTALL} install_dynamic_cxx" + else + ADDITIONAL_LIBS="$ADDITIONAL_LIBS \$(libcxx)" + DEFAULT_INSTALL="${DEFAULT_INSTALL} install_static_cxx" + fi +fi + +if test "$db_cv_java" = "yes"; then + if test "$db_cv_dynamic" != "yes"; then + { echo "configure: error: --enable-java requires --enable-dynamic" 1>&2; exit 1; } + fi + + # Extract the first word of "javac", so it can be a program name with args. +set dummy javac; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1671: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_JAVAC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$JAVAC"; then + ac_cv_prog_JAVAC="$JAVAC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_JAVAC="javac" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_JAVAC" && ac_cv_prog_JAVAC="nojavac" +fi +fi +JAVAC="$ac_cv_prog_JAVAC" +if test -n "$JAVAC"; then + echo "$ac_t""$JAVAC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + if test "$JAVAC" = "nojavac"; then + { echo "configure: error: no javac compiler in PATH" 1>&2; exit 1; } + fi + # Extract the first word of "jar", so it can be a program name with args. +set dummy jar; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1704: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_JAR'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$JAR"; then + ac_cv_prog_JAR="$JAR" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_JAR="jar" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_JAR" && ac_cv_prog_JAR="nojar" +fi +fi +JAR="$ac_cv_prog_JAR" +if test -n "$JAR"; then + echo "$ac_t""$JAR" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + if test "$JAR" = "nojar"; then + { echo "configure: error: no jar utility in PATH" 1>&2; exit 1; } + fi + # Extract the first word of "javac", so it can be a program name with args. +set dummy javac; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1737: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_JAVACABS'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$JAVACABS" in + /*) + ac_cv_path_JAVACABS="$JAVACABS" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_JAVACABS="$JAVACABS" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_JAVACABS="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_JAVACABS" && ac_cv_path_JAVACABS="nojavac" + ;; +esac +fi +JAVACABS="$ac_cv_path_JAVACABS" +if test -n "$JAVACABS"; then + echo "$ac_t""$JAVACABS" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + ADDITIONAL_LIBS="$ADDITIONAL_LIBS \$(libjso_target)" + ADDITIONAL_LANG="$ADDITIONAL_LANG java" + DEFAULT_INSTALL="${DEFAULT_INSTALL} install_java" + + while ls -ld "$JAVACABS" 2>/dev/null | grep " -> " >/dev/null; do + echo $ac_n "checking symlink for $JAVACABS""... $ac_c" 1>&6 +echo "configure:1776: checking symlink for $JAVACABS" >&5 + JAVACLINK=`ls -ld $JAVACABS | sed 's/.* -> //'` + case "$JAVACLINK" in + /*) JAVACABS="$JAVACLINK";; + *) JAVACABS=`echo "X$JAVACABS" | sed -e 's/^X//' -e 's:[^/]*$::'`"$JAVACLINK";; + esac + echo "$ac_t""$JAVACABS" 1>&6 + done + JTOPDIR=`echo "$JAVACABS" | sed -e 's://*:/:g' -e 's:/[^/]*$::'` + if test -f "$JTOPDIR/include/jni.h"; then + CPPFLAGS="$CPPFLAGSS -I$JTOPDIR/include" + else + JTOPDIR=`echo "$JTOPDIR" | sed -e 's:/[^/]*$::'` + if test -f "$JTOPDIR/include/jni.h"; then + CPPFLAGS="$CPPFLAGS -I$JTOPDIR/include" + else + { echo "configure: error: cannot find java include files" 1>&2; exit 1; } + fi + fi + + case "$host_os" in + solaris*) JINCSUBDIRS="solaris";; + linux*) JINCSUBDIRS="linux genunix";; + *) JINCSUBDIRS="genunix";; + esac + + for JINCSUBDIR in $JINCSUBDIRS + do + if test -d "$JTOPDIR/include/$JINCSUBDIR"; then + CPPFLAGS="$CPPFLAGS -I$JTOPDIR/include/$JINCSUBDIR" + fi + done +else + JAVAC=nojavac +fi + +if test "$db_cv_rpc" = "yes"; then + cat >> confdefs.h <<\EOF +#define HAVE_RPC 1 +EOF + + + RPC_OBJS="\$(RPC_OBJS)" + ADDITIONAL_PROGS="berkeley_db_svc $ADDITIONAL_PROGS" + + case "$host_os" in + hpux*) + echo $ac_n "checking for svc_run""... $ac_c" 1>&6 +echo "configure:1824: checking for svc_run" >&5 +if eval "test \"`echo '$''{'ac_cv_func_svc_run'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char svc_run(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_svc_run) || defined (__stub___svc_run) +choke me +#else +svc_run(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1852: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_svc_run=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_svc_run=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'svc_run`\" = yes"; then + echo "$ac_t""yes" 1>&6 + : +else + echo "$ac_t""no" 1>&6 +echo $ac_n "checking for svc_run in -lnsl""... $ac_c" 1>&6 +echo "configure:1870: checking for svc_run in -lnsl" >&5 +ac_lib_var=`echo nsl'_'svc_run | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lnsl $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + LIBS="-lnsl $LIBS"; LIBTSO_LIBS="-lnsl $LIBTSO_LIBS" +else + echo "$ac_t""no" 1>&6 +fi + +fi +;; + solaris*) + echo $ac_n "checking for svc_run""... $ac_c" 1>&6 +echo "configure:1913: checking for svc_run" >&5 +if eval "test \"`echo '$''{'ac_cv_func_svc_run'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char svc_run(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_svc_run) || defined (__stub___svc_run) +choke me +#else +svc_run(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1941: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_svc_run=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_svc_run=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'svc_run`\" = yes"; then + echo "$ac_t""yes" 1>&6 + : +else + echo "$ac_t""no" 1>&6 +echo $ac_n "checking for svc_run in -lnsl""... $ac_c" 1>&6 +echo "configure:1959: checking for svc_run in -lnsl" >&5 +ac_lib_var=`echo nsl'_'svc_run | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lnsl $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo nsl | sed -e 's/^a-zA-Z0-9_/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <&6 +fi + +fi +;; + esac +fi + + +if test "$db_cv_tcl" != no; then + if test "$db_cv_dynamic" != "yes"; then + { echo "configure: error: --with-tcl requires --enable-dynamic" 1>&2; exit 1; } + fi + + + + + if eval "test \"`echo '$''{'ac_cv_c_tclconfig'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + + + # First check to see if --with-tclconfig was specified. + if test "${with_tclconfig}" != no; then + if test -f "${with_tclconfig}/tclConfig.sh" ; then + ac_cv_c_tclconfig=`(cd ${with_tclconfig}; pwd)` + else + { echo "configure: error: ${with_tclconfig} directory doesn't contain tclConfig.sh" 1>&2; exit 1; } + fi + fi + + # check in a few common install locations + if test x"${ac_cv_c_tclconfig}" = x ; then + for i in `ls -d /usr/local/lib 2>/dev/null` ; do + if test -f "$i/tclConfig.sh" ; then + ac_cv_c_tclconfig=`(cd $i; pwd)` + break + fi + done + fi + + +fi + + + if test x"${ac_cv_c_tclconfig}" = x ; then + TCL_BIN_DIR="# no Tcl configs found" + { echo "configure: error: can't find Tcl configuration definitions" 1>&2; exit 1; } + else + TCL_BIN_DIR=${ac_cv_c_tclconfig} + fi + + + echo $ac_n "checking for existence of $TCL_BIN_DIR/tclConfig.sh""... $ac_c" 1>&6 +echo "configure:2056: checking for existence of $TCL_BIN_DIR/tclConfig.sh" >&5 + + if test -f "$TCL_BIN_DIR/tclConfig.sh" ; then + echo "$ac_t""loading" 1>&6 + . $TCL_BIN_DIR/tclConfig.sh + else + echo "$ac_t""file not found" 1>&6 + fi + + # + # The eval is required to do the TCL_DBGX substitution in the + # TCL_LIB_FILE variable + # + eval TCL_LIB_FILE="${TCL_LIB_FILE}" + eval TCL_LIB_FLAG="${TCL_LIB_FLAG}" + eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\"" + + + + + + + TCL_TCLSH="${TCL_PREFIX}/bin/tclsh${TCL_VERSION}" + + + if test x"$TCL_PREFIX" != x && test -f "$TCL_PREFIX/include/tcl.h"; then + TCFLAGS="-I$TCL_PREFIX/include" + fi + + LIBS="$LIBS $TCL_LIB_SPEC $TCL_LIBS" + + ADDITIONAL_LIBS="$ADDITIONAL_LIBS \$(libtso_target)" + DEFAULT_INSTALL="${DEFAULT_INSTALL} install_tcl" +fi + +if test "$db_cv_compat185" = "yes"; then + ADDITIONAL_INCS="db_185.h $ADDITIONAL_INCS" + ADDITIONAL_OBJS="db185${o} $ADDITIONAL_OBJS" +fi + +if test "$db_cv_dump185" = "yes"; then + ADDITIONAL_PROGS="db_dump185 $ADDITIONAL_PROGS" +fi + +echo $ac_n "checking for pthread_create in -lpthread""... $ac_c" 1>&6 +echo "configure:2101: checking for pthread_create in -lpthread" >&5 +ac_lib_var=`echo pthread'_'pthread_create | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lpthread $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + DBS_LIBS=-lpthread +else + echo "$ac_t""no" 1>&6 +fi + + +echo $ac_n "checking whether byte ordering is bigendian""... $ac_c" 1>&6 +echo "configure:2142: checking whether byte ordering is bigendian" >&5 +if eval "test \"`echo '$''{'ac_cv_c_bigendian'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_cv_c_bigendian=unknown +# See if sys/param.h defines the BYTE_ORDER macro. +cat > conftest.$ac_ext < +#include +int main() { + +#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN + bogus endian macros +#endif +; return 0; } +EOF +if { (eval echo configure:2160: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + # It does; now see whether it defined to BIG_ENDIAN or not. +cat > conftest.$ac_ext < +#include +int main() { + +#if BYTE_ORDER != BIG_ENDIAN + not big endian +#endif +; return 0; } +EOF +if { (eval echo configure:2175: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_c_bigendian=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_c_bigendian=no +fi +rm -f conftest* +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* +if test $ac_cv_c_bigendian = unknown; then +if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_c_bigendian=no +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_c_bigendian=yes +fi +rm -fr conftest* +fi + +fi +fi + +echo "$ac_t""$ac_cv_c_bigendian" 1>&6 +if test $ac_cv_c_bigendian = yes; then + cat >> confdefs.h <<\EOF +#define WORDS_BIGENDIAN 1 +EOF + +fi + +echo $ac_n "checking for working const""... $ac_c" 1>&6 +echo "configure:2232: checking for working const" >&5 +if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <j = 5; +} +{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; +} + +; return 0; } +EOF +if { (eval echo configure:2286: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_c_const=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_c_const=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_c_const" 1>&6 +if test $ac_cv_c_const = no; then + cat >> confdefs.h <<\EOF +#define const +EOF + +fi + +echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +echo "configure:2307: checking how to run the C preprocessor" >&5 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2328: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -E -traditional-cpp" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2345: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -nologo -E" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2362: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 + +echo $ac_n "checking whether stat file-mode macros are broken""... $ac_c" 1>&6 +echo "configure:2387: checking whether stat file-mode macros are broken" >&5 +if eval "test \"`echo '$''{'ac_cv_header_stat_broken'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include + +#if defined(S_ISBLK) && defined(S_IFDIR) +# if S_ISBLK (S_IFDIR) +You lose. +# endif +#endif + +#if defined(S_ISBLK) && defined(S_IFCHR) +# if S_ISBLK (S_IFCHR) +You lose. +# endif +#endif + +#if defined(S_ISLNK) && defined(S_IFREG) +# if S_ISLNK (S_IFREG) +You lose. +# endif +#endif + +#if defined(S_ISSOCK) && defined(S_IFREG) +# if S_ISSOCK (S_IFREG) +You lose. +# endif +#endif + +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "You lose" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_header_stat_broken=yes +else + rm -rf conftest* + ac_cv_header_stat_broken=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_header_stat_broken" 1>&6 +if test $ac_cv_header_stat_broken = yes; then + cat >> confdefs.h <<\EOF +#define STAT_MACROS_BROKEN 1 +EOF + +fi + +echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6 +echo "configure:2443: checking whether time.h and sys/time.h may both be included" >&5 +if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +#include +int main() { +struct tm *tp; +; return 0; } +EOF +if { (eval echo configure:2457: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_header_time=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_time=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_header_time" 1>&6 +if test $ac_cv_header_time = yes; then + cat >> confdefs.h <<\EOF +#define TIME_WITH_SYS_TIME 1 +EOF + +fi + +echo $ac_n "checking for st_blksize in struct stat""... $ac_c" 1>&6 +echo "configure:2478: checking for st_blksize in struct stat" >&5 +if eval "test \"`echo '$''{'ac_cv_struct_st_blksize'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +int main() { +struct stat s; s.st_blksize; +; return 0; } +EOF +if { (eval echo configure:2491: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_struct_st_blksize=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_struct_st_blksize=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_struct_st_blksize" 1>&6 +if test $ac_cv_struct_st_blksize = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_ST_BLKSIZE 1 +EOF + +fi + +echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 +echo "configure:2512: checking for ANSI C header files" >&5 +if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +#include +#include +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2525: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + ac_cv_header_stdc=yes +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. +cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "memchr" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. +cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "free" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. +if test "$cross_compiling" = yes; then + : +else + cat > conftest.$ac_ext < +#define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int main () { int i; for (i = 0; i < 256; i++) +if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); +exit (0); } + +EOF +if { (eval echo configure:2592: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + : +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_header_stdc=no +fi +rm -fr conftest* +fi + +fi +fi + +echo "$ac_t""$ac_cv_header_stdc" 1>&6 +if test $ac_cv_header_stdc = yes; then + cat >> confdefs.h <<\EOF +#define STDC_HEADERS 1 +EOF + +fi + +echo $ac_n "checking for mode_t""... $ac_c" 1>&6 +echo "configure:2616: checking for mode_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_mode_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#if STDC_HEADERS +#include +#include +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "(^|[^a-zA-Z_0-9])mode_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_mode_t=yes +else + rm -rf conftest* + ac_cv_type_mode_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_mode_t" 1>&6 +if test $ac_cv_type_mode_t = no; then + cat >> confdefs.h <<\EOF +#define mode_t int +EOF + +fi + +echo $ac_n "checking for off_t""... $ac_c" 1>&6 +echo "configure:2649: checking for off_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#if STDC_HEADERS +#include +#include +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "(^|[^a-zA-Z_0-9])off_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_off_t=yes +else + rm -rf conftest* + ac_cv_type_off_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_off_t" 1>&6 +if test $ac_cv_type_off_t = no; then + cat >> confdefs.h <<\EOF +#define off_t long +EOF + +fi + +echo $ac_n "checking for pid_t""... $ac_c" 1>&6 +echo "configure:2682: checking for pid_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#if STDC_HEADERS +#include +#include +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "(^|[^a-zA-Z_0-9])pid_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_pid_t=yes +else + rm -rf conftest* + ac_cv_type_pid_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_pid_t" 1>&6 +if test $ac_cv_type_pid_t = no; then + cat >> confdefs.h <<\EOF +#define pid_t int +EOF + +fi + +echo $ac_n "checking for size_t""... $ac_c" 1>&6 +echo "configure:2715: checking for size_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#if STDC_HEADERS +#include +#include +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "(^|[^a-zA-Z_0-9])size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_size_t=yes +else + rm -rf conftest* + ac_cv_type_size_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_size_t" 1>&6 +if test $ac_cv_type_size_t = no; then + cat >> confdefs.h <<\EOF +#define size_t unsigned +EOF + +fi + + + + +echo $ac_n "checking for ssize_t""... $ac_c" 1>&6 +echo "configure:2751: checking for ssize_t" >&5 +if eval "test \"`echo '$''{'db_cv_ssize_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +int main() { +ssize_t foo; +; return 0; } +EOF +if { (eval echo configure:2763: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + db_cv_ssize_t=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + db_cv_ssize_t=no +fi +rm -f conftest* +fi + +echo "$ac_t""$db_cv_ssize_t" 1>&6 +if test "$db_cv_ssize_t" = no; then + ssize_t_decl="typedef int ssize_t;" +fi + + +echo $ac_n "checking for u_char""... $ac_c" 1>&6 +echo "configure:2782: checking for u_char" >&5 +if eval "test \"`echo '$''{'db_cv_uchar'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +int main() { +u_char foo; +; return 0; } +EOF +if { (eval echo configure:2794: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + db_cv_uchar=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + db_cv_uchar=no +fi +rm -f conftest* +fi + +echo "$ac_t""$db_cv_uchar" 1>&6 +if test "$db_cv_uchar" = no; then + u_char_decl="typedef unsigned char u_char;" +fi + + +echo $ac_n "checking for u_short""... $ac_c" 1>&6 +echo "configure:2813: checking for u_short" >&5 +if eval "test \"`echo '$''{'db_cv_ushort'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +int main() { +u_short foo; +; return 0; } +EOF +if { (eval echo configure:2825: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + db_cv_ushort=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + db_cv_ushort=no +fi +rm -f conftest* +fi + +echo "$ac_t""$db_cv_ushort" 1>&6 +if test "$db_cv_ushort" = no; then + u_short_decl="typedef unsigned short u_short;" +fi + + +echo $ac_n "checking for u_int""... $ac_c" 1>&6 +echo "configure:2844: checking for u_int" >&5 +if eval "test \"`echo '$''{'db_cv_uint'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +int main() { +u_int foo; +; return 0; } +EOF +if { (eval echo configure:2856: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + db_cv_uint=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + db_cv_uint=no +fi +rm -f conftest* +fi + +echo "$ac_t""$db_cv_uint" 1>&6 +if test "$db_cv_uint" = no; then + u_int_decl="typedef unsigned int u_int;" +fi + + +echo $ac_n "checking for u_long""... $ac_c" 1>&6 +echo "configure:2875: checking for u_long" >&5 +if eval "test \"`echo '$''{'db_cv_ulong'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +int main() { +u_long foo; +; return 0; } +EOF +if { (eval echo configure:2887: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + db_cv_ulong=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + db_cv_ulong=no +fi +rm -f conftest* +fi + +echo "$ac_t""$db_cv_ulong" 1>&6 +if test "$db_cv_ulong" = no; then + u_long_decl="typedef unsigned long u_long;" +fi + + +echo $ac_n "checking for u_int8_t""... $ac_c" 1>&6 +echo "configure:2906: checking for u_int8_t" >&5 +if eval "test \"`echo '$''{'db_cv_uint8'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +int main() { +u_int8_t foo; +; return 0; } +EOF +if { (eval echo configure:2918: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + db_cv_uint8=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + db_cv_uint8="unsigned char" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + db_cv_uint8=no +fi +rm -fr conftest* +fi + +fi +rm -f conftest* +fi + +echo "$ac_t""$db_cv_uint8" 1>&6 +if test "$db_cv_uint8" = no; then + { echo "configure: error: No unsigned 8-bit integral type." 1>&2; exit 1; } +fi +if test "$db_cv_uint8" != yes; then + u_int8_decl="typedef $db_cv_uint8 u_int8_t;" +fi + + +echo $ac_n "checking for u_int16_t""... $ac_c" 1>&6 +echo "configure:2959: checking for u_int16_t" >&5 +if eval "test \"`echo '$''{'db_cv_uint16'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +int main() { +u_int16_t foo; +; return 0; } +EOF +if { (eval echo configure:2971: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + db_cv_uint16=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + db_cv_uint16="unsigned short" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + db_cv_uint16="unsigned int" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + db_cv_uint16=no +fi +rm -fr conftest* +fi + +fi +rm -fr conftest* +fi + +fi +rm -f conftest* +fi + +echo "$ac_t""$db_cv_uint16" 1>&6 +if test "$db_cv_uint16" = no; then + { echo "configure: error: No unsigned 16-bit integral type." 1>&2; exit 1; } +fi +if test "$db_cv_uint16" != yes; then + u_int16_decl="typedef $db_cv_uint16 u_int16_t;" +fi + + +echo $ac_n "checking for int16_t""... $ac_c" 1>&6 +echo "configure:3031: checking for int16_t" >&5 +if eval "test \"`echo '$''{'db_cv_int16'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +int main() { +int16_t foo; +; return 0; } +EOF +if { (eval echo configure:3043: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + db_cv_int16=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + db_cv_int16="short" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + db_cv_int16="int" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + db_cv_int16=no +fi +rm -fr conftest* +fi + +fi +rm -fr conftest* +fi + +fi +rm -f conftest* +fi + +echo "$ac_t""$db_cv_int16" 1>&6 +if test "$db_cv_int16" = no; then + { echo "configure: error: No signed 16-bit integral type." 1>&2; exit 1; } +fi +if test "$db_cv_int16" != yes; then + int16_decl="typedef $db_cv_int16 int16_t;" +fi + + +echo $ac_n "checking for u_int32_t""... $ac_c" 1>&6 +echo "configure:3103: checking for u_int32_t" >&5 +if eval "test \"`echo '$''{'db_cv_uint32'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +int main() { +u_int32_t foo; +; return 0; } +EOF +if { (eval echo configure:3115: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + db_cv_uint32=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + db_cv_uint32="unsigned int" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + db_cv_uint32="unsigned long" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + db_cv_uint32=no +fi +rm -fr conftest* +fi + +fi +rm -fr conftest* +fi + +fi +rm -f conftest* +fi + +echo "$ac_t""$db_cv_uint32" 1>&6 +if test "$db_cv_uint32" = no; then + { echo "configure: error: No unsigned 32-bit integral type." 1>&2; exit 1; } +fi +if test "$db_cv_uint32" != yes; then + u_int32_decl="typedef $db_cv_uint32 u_int32_t;" +fi + + +echo $ac_n "checking for int32_t""... $ac_c" 1>&6 +echo "configure:3175: checking for int32_t" >&5 +if eval "test \"`echo '$''{'db_cv_int32'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +int main() { +int32_t foo; +; return 0; } +EOF +if { (eval echo configure:3187: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + db_cv_int32=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + db_cv_int32="int" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + db_cv_int32="long" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + db_cv_int32=no +fi +rm -fr conftest* +fi + +fi +rm -fr conftest* +fi + +fi +rm -f conftest* +fi + +echo "$ac_t""$db_cv_int32" 1>&6 +if test "$db_cv_int32" = no; then + { echo "configure: error: No signed 32-bit integral type." 1>&2; exit 1; } +fi +if test "$db_cv_int32" != yes; then + int32_decl="typedef $db_cv_int32 int32_t;" +fi + + +echo $ac_n "checking for largest integral type""... $ac_c" 1>&6 +echo "configure:3247: checking for largest integral type" >&5 +if eval "test \"`echo '$''{'db_cv_align_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +int main() { +long long foo; +; return 0; } +EOF +if { (eval echo configure:3259: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + db_cv_align_t="unsigned long long" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + db_cv_align_t="unsigned long" +fi +rm -f conftest* +fi + +echo "$ac_t""$db_cv_align_t" 1>&6 +db_align_t_decl="typedef $db_cv_align_t db_align_t;" + + +echo $ac_n "checking for integral type equal to pointer size""... $ac_c" 1>&6 +echo "configure:3276: checking for integral type equal to pointer size" >&5 +if eval "test \"`echo '$''{'db_cv_alignp_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + db_cv_alignp_t=$db_cv_align_t +if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + db_cv_alignp_t="unsigned int" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -fr conftest* +fi + +if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + db_cv_alignp_t="unsigned long" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -fr conftest* +fi + +if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + db_cv_alignp_t="unsigned long long" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$db_cv_alignp_t" 1>&6 +db_alignp_t_decl="typedef $db_cv_alignp_t db_alignp_t;" + + + +ac_header_dirent=no +for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6 +echo "configure:3347: checking for $ac_hdr that defines DIR" >&5 +if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include <$ac_hdr> +int main() { +DIR *dirp = 0; +; return 0; } +EOF +if { (eval echo configure:3360: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + eval "ac_cv_header_dirent_$ac_safe=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_dirent_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done +# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. +if test $ac_header_dirent = dirent.h; then +echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6 +echo "configure:3385: checking for opendir in -ldir" >&5 +ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ldir $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + LIBS="$LIBS -ldir" +else + echo "$ac_t""no" 1>&6 +fi + +else +echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6 +echo "configure:3426: checking for opendir in -lx" >&5 +ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lx $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + LIBS="$LIBS -lx" +else + echo "$ac_t""no" 1>&6 +fi + +fi + +for ac_hdr in sys/select.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:3471: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:3481: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + +for ac_hdr in sys/time.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:3511: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:3521: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + + + + +echo $ac_n "checking for mutexes""... $ac_c" 1>&6 +echo "configure:3551: checking for mutexes" >&5 +if eval "test \"`echo '$''{'db_cv_mutex'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + db_cv_mutex=no + +orig_libs=$LIBS + +if test "$db_cv_posixmutexes" = yes; then + db_cv_mutex="posix_only" +fi + +if test "$db_cv_uimutexes" = yes; then + db_cv_mutex="ui_only" +fi + +if test "$db_cv_mutex" = no; then +if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +main(){ + static lwp_mutex_t mi = SHAREDMUTEX; + static lwp_cond_t ci = SHAREDCV; + lwp_mutex_t mutex = mi; + lwp_cond_t cond = ci; + exit ( + _lwp_mutex_lock(&mutex) || + _lwp_mutex_unlock(&mutex)); +} +EOF +if { (eval echo configure:3586: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + db_cv_mutex="Solaris/lwp" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -fr conftest* +fi + +fi + +if test "$db_cv_mutex" = no -o "$db_cv_mutex" = "ui_only"; then +LIBS="-lthread $LIBS" +if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +#include +main(){ + mutex_t mutex; + cond_t cond; + int type = USYNC_PROCESS; + exit ( + mutex_init(&mutex, type, NULL) || + cond_init(&cond, type, NULL) || + mutex_lock(&mutex) || + mutex_unlock(&mutex)); +} +EOF +if { (eval echo configure:3620: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + db_cv_mutex="UI/threads/library" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -fr conftest* +fi + +LIBS="$orig_libs" +fi +if test "$db_cv_mutex" = no -o "$db_cv_mutex" = "ui_only"; then +if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +#include +main(){ + mutex_t mutex; + cond_t cond; + int type = USYNC_PROCESS; + exit ( + mutex_init(&mutex, type, NULL) || + cond_init(&cond, type, NULL) || + mutex_lock(&mutex) || + mutex_unlock(&mutex)); +} +EOF +if { (eval echo configure:3653: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + db_cv_mutex="UI/threads" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -fr conftest* +fi + +fi +if test "$db_cv_mutex" = "ui_only"; then + { echo "configure: error: unable to find UI mutex interfaces" 1>&2; exit 1; } +fi + + +if test "$db_cv_mutex" = no -o "$db_cv_mutex" = "posix_only"; then +if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +main(){ + pthread_cond_t cond; + pthread_mutex_t mutex; + pthread_condattr_t condattr; + pthread_mutexattr_t mutexattr; + exit ( + pthread_condattr_init(&condattr) || + pthread_condattr_setpshared(&condattr, PTHREAD_PROCESS_SHARED) || + pthread_mutexattr_init(&mutexattr) || + pthread_mutexattr_setpshared(&mutexattr, PTHREAD_PROCESS_SHARED) || + pthread_cond_init(&cond, &condattr) || + pthread_mutex_init(&mutex, &mutexattr) || + pthread_mutex_lock(&mutex) || + pthread_mutex_unlock(&mutex) || + pthread_mutex_destroy(&mutex) || + pthread_cond_destroy(&cond) || + pthread_condattr_destroy(&condattr) || + pthread_mutexattr_destroy(&mutexattr)); +} +EOF +if { (eval echo configure:3698: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + db_cv_mutex="POSIX/pthreads" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -fr conftest* +fi + +fi +if test "$db_cv_mutex" = no -o "$db_cv_mutex" = "posix_only"; then +LIBS="-lpthread $LIBS" +if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +main(){ + pthread_cond_t cond; + pthread_mutex_t mutex; + pthread_condattr_t condattr; + pthread_mutexattr_t mutexattr; + exit ( + pthread_condattr_init(&condattr) || + pthread_condattr_setpshared(&condattr, PTHREAD_PROCESS_SHARED) || + pthread_mutexattr_init(&mutexattr) || + pthread_mutexattr_setpshared(&mutexattr, PTHREAD_PROCESS_SHARED) || + pthread_cond_init(&cond, &condattr) || + pthread_mutex_init(&mutex, &mutexattr) || + pthread_mutex_lock(&mutex) || + pthread_mutex_unlock(&mutex) || + pthread_mutex_destroy(&mutex) || + pthread_cond_destroy(&cond) || + pthread_condattr_destroy(&condattr) || + pthread_mutexattr_destroy(&mutexattr)); +} +EOF +if { (eval echo configure:3739: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + db_cv_mutex="POSIX/pthreads/library" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -fr conftest* +fi + +LIBS="$orig_libs" +fi +if test "$db_cv_mutex" = "posix_only"; then + { echo "configure: error: unable to find POSIX mutex interfaces" 1>&2; exit 1; } +fi + +if test "$db_cv_mutex" = no; then +if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +main(){ +#if defined(__hppa) + typedef msemaphore tsl_t; + msemaphore x; + msem_init(&x, 0); + msem_lock(&x, 0); + msem_unlock(&x, 0); + exit(0); +#else + exit(1); +#endif +} +EOF +if { (eval echo configure:3777: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + db_cv_mutex="HP/msem_init" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -fr conftest* +fi + +fi + +if test "$db_cv_mutex" = no; then +if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +#include ; +main(){ + typedef msemaphore tsl_t; + msemaphore x; + msem_init(&x, 0); + msem_lock(&x, 0); + msem_unlock(&x, 0); + exit(0); +} +EOF +if { (eval echo configure:3808: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + db_cv_mutex="UNIX/msem_init" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -fr conftest* +fi + +fi + +if test "$db_cv_mutex" = no; then +LIBS="$LIBS -lmproc" +cat > conftest.$ac_ext < +int main() { +typedef spinlock_t tsl_t; +spinlock_t x; initspin(&x, 1); cspinlock(&x); spinunlock(&x); +; return 0; } +EOF +if { (eval echo configure:3831: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + db_cv_mutex="ReliantUNIX/initspin" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* +LIBS="$orig_libs" +fi + +if test "$db_cv_mutex" = no; then +if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + db_cv_mutex="SCO/x86/cc-assembly" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -fr conftest* +fi + +fi + +if test "$db_cv_mutex" = no; then +cat > conftest.$ac_ext < +int main() { +typedef abilock_t tsl_t; +abilock_t x; init_lock(&x); acquire_lock(&x); release_lock(&x); +; return 0; } +EOF +if { (eval echo configure:3879: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + db_cv_mutex="SGI/init_lock" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* +fi + +if test "$db_cv_mutex" = DOESNT_WORK; then +cat > conftest.$ac_ext < +int main() { +typedef sema_t tsl_t; + sema_t x; + sema_init(&x, 1, USYNC_PROCESS, NULL); sema_wait(&x); sema_post(&x); +; return 0; } +EOF +if { (eval echo configure:3900: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + db_cv_mutex="UNIX/sema_init" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* +fi + +if test "$db_cv_mutex" = no; then +cat > conftest.$ac_ext < +int main() { +typedef lock_t tsl_t; + lock_t x; + _lock_try(&x); _lock_clear(&x); +; return 0; } +EOF +if { (eval echo configure:3921: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + db_cv_mutex="Solaris/_lock_try" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* +fi + +if test "$db_cv_mutex" = no; then +cat > conftest.$ac_ext < +int main() { +int x; _check_lock(&x,0,1); _clear_lock(&x,0); +; return 0; } +EOF +if { (eval echo configure:3940: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + db_cv_mutex="AIX/_check_lock" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* +fi + +if test "$db_cv_mutex" = DOESNT_WORK; then +if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + db_cv_mutex="ALPHA/gcc-assembly" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -fr conftest* +fi + +fi + +if test "$db_cv_mutex" = no; then +if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + db_cv_mutex="HPPA/gcc-assembly" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -fr conftest* +fi + +fi + +if test "$db_cv_mutex" = no; then +if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + db_cv_mutex="PPC/gcc-assembly" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -fr conftest* +fi + +fi + +if test "$db_cv_mutex" = DOESNT_WORK; then +if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + db_cv_mutex="Sparc/gcc-assembly" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -fr conftest* +fi + +fi + +if test "$db_cv_mutex" = no; then +if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + db_cv_mutex="68K/gcc-assembly" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -fr conftest* +fi + +fi + +if test "$db_cv_mutex" = no; then +if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + db_cv_mutex="x86/gcc-assembly" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -fr conftest* +fi + +fi + +if test "$db_cv_mutex" = no; then +if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + db_cv_mutex="ia64/gcc-assembly" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -fr conftest* +fi + +fi + +if test "$db_cv_mutex" = no; then +if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + db_cv_mutex="UTS/cc-assembly" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -fr conftest* +fi + +fi + +fi + +echo "$ac_t""$db_cv_mutex" 1>&6 + +if test "$db_cv_mutex" = no; then + echo "configure: warning: THREAD MUTEXES NOT AVAILABLE FOR THIS COMPILER/ARCHITECTURE." 1>&2 + ADDITIONAL_OBJS="mut_fcntl${o} $ADDITIONAL_OBJS" +else + cat >> confdefs.h <<\EOF +#define HAVE_MUTEX_THREADS 1 +EOF + +fi + +case "$db_cv_mutex" in +68K/gcc-assembly) ADDITIONAL_OBJS="mut_tas${o} $ADDITIONAL_OBJS" + cat >> confdefs.h <<\EOF +#define HAVE_MUTEX_68K_GCC_ASSEMBLY 1 +EOF +;; +AIX/_check_lock) ADDITIONAL_OBJS="mut_tas${o} $ADDITIONAL_OBJS" + cat >> confdefs.h <<\EOF +#define HAVE_MUTEX_AIX_CHECK_LOCK 1 +EOF +;; +ALPHA/gcc-assembly) ADDITIONAL_OBJS="mut_tas${o} $ADDITIONAL_OBJS" + cat >> confdefs.h <<\EOF +#define HAVE_MUTEX_ALPHA_GCC_ASSEMBLY 1 +EOF +;; +HP/msem_init) ADDITIONAL_OBJS="mut_tas${o} $ADDITIONAL_OBJS" + cat >> confdefs.h <<\EOF +#define HAVE_MUTEX_HPPA_MSEM_INIT 1 +EOF +;; +HPPA/gcc-assembly) ADDITIONAL_OBJS="mut_tas${o} $ADDITIONAL_OBJS" + cat >> confdefs.h <<\EOF +#define HAVE_MUTEX_HPPA_GCC_ASSEMBLY 1 +EOF +;; +ia64/gcc-assembly) ADDITIONAL_OBJS="mut_tas${o} $ADDITIONAL_OBJS" + cat >> confdefs.h <<\EOF +#define HAVE_MUTEX_IA64_GCC_ASSEMBLY 1 +EOF +;; +POSIX/pthreads) ADDITIONAL_OBJS="mut_pthread${o} $ADDITIONAL_OBJS" + cat >> confdefs.h <<\EOF +#define HAVE_MUTEX_PTHREADS 1 +EOF +;; +POSIX/pthreads/library) LIBS="-lpthread $LIBS" + ADDITIONAL_OBJS="mut_pthread${o} $ADDITIONAL_OBJS" + cat >> confdefs.h <<\EOF +#define HAVE_MUTEX_PTHREADS 1 +EOF +;; +PPC/gcc-assembly) ADDITIONAL_OBJS="mut_tas${o} $ADDITIONAL_OBJS" + cat >> confdefs.h <<\EOF +#define HAVE_MUTEX_PPC_GCC_ASSEMBLY 1 +EOF +;; +ReliantUNIX/initspin) LIBS="$LIBS -lmproc" + ADDITIONAL_OBJS="mut_tas${o} $ADDITIONAL_OBJS" + cat >> confdefs.h <<\EOF +#define HAVE_MUTEX_RELIANTUNIX_INITSPIN 1 +EOF +;; +SCO/x86/cc-assembly) ADDITIONAL_OBJS="mut_tas${o} $ADDITIONAL_OBJS" + cat >> confdefs.h <<\EOF +#define HAVE_MUTEX_SCO_X86_CC_ASSEMBLY 1 +EOF +;; +SGI/init_lock) ADDITIONAL_OBJS="mut_tas${o} $ADDITIONAL_OBJS" + cat >> confdefs.h <<\EOF +#define HAVE_MUTEX_SGI_INIT_LOCK 1 +EOF +;; +Solaris/_lock_try) ADDITIONAL_OBJS="mut_tas${o} $ADDITIONAL_OBJS" + cat >> confdefs.h <<\EOF +#define HAVE_MUTEX_SOLARIS_LOCK_TRY 1 +EOF +;; +Solaris/lwp) ADDITIONAL_OBJS="mut_pthread${o} $ADDITIONAL_OBJS" + cat >> confdefs.h <<\EOF +#define HAVE_MUTEX_SOLARIS_LWP 1 +EOF +;; +Sparc/gcc-assembly) ADDITIONAL_OBJS="mut_tas${o} $ADDITIONAL_OBJS" + cat >> confdefs.h <<\EOF +#define HAVE_MUTEX_SPARC_GCC_ASSEMBLY 1 +EOF +;; +UI/threads) ADDITIONAL_OBJS="mut_pthread${o} $ADDITIONAL_OBJS" + cat >> confdefs.h <<\EOF +#define HAVE_MUTEX_UI_THREADS 1 +EOF +;; +UI/threads/library) LIBS="-lthread $LIBS" + ADDITIONAL_OBJS="mut_pthread${o} $ADDITIONAL_OBJS" + cat >> confdefs.h <<\EOF +#define HAVE_MUTEX_UI_THREADS 1 +EOF +;; +UNIX/msem_init) ADDITIONAL_OBJS="mut_tas${o} $ADDITIONAL_OBJS" + cat >> confdefs.h <<\EOF +#define HAVE_MUTEX_MSEM_INIT 1 +EOF +;; +UNIX/sema_init) ADDITIONAL_OBJS="mut_tas${o} $ADDITIONAL_OBJS" + cat >> confdefs.h <<\EOF +#define HAVE_MUTEX_SEMA_INIT 1 +EOF +;; +UTS/cc-assembly) ADDITIONAL_OBJS="$ADDITIONAL_OBJS uts4.cc${o}" + cat >> confdefs.h <<\EOF +#define HAVE_MUTEX_UTS_CC_ASSEMBLY 1 +EOF +;; +x86/gcc-assembly) ADDITIONAL_OBJS="mut_tas${o} $ADDITIONAL_OBJS" + cat >> confdefs.h <<\EOF +#define HAVE_MUTEX_X86_GCC_ASSEMBLY 1 +EOF +;; +esac + + +for ac_func in getcwd getopt memcmp memcpy memmove +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:4298: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:4326: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +LIBOBJS="$LIBOBJS ${ac_func}.${ac_objext}" +fi +done + + +for ac_func in raise snprintf strcasecmp strerror vsnprintf +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:4355: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:4383: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +LIBOBJS="$LIBOBJS ${ac_func}.${ac_objext}" +fi +done + + + +tmp="`echo \"$LIBOBJS\" | sed \"s/\.o/${o}/g\"`" +LIBOBJS="$tmp" + +for ac_func in getuid pstat_getdynamic sysconf sched_yield strtoul yield +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:4416: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:4444: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + + +case "$host_os" in +hpux*) + echo "configure: warning: pread/pwrite interfaces ignored on $host_os." 1>&2;; +*) for ac_func in pread pwrite +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:4475: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:4503: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + +esac + +echo $ac_n "checking for fcntl/F_SETFD""... $ac_c" 1>&6 +echo "configure:4530: checking for fcntl/F_SETFD" >&5 +if eval "test \"`echo '$''{'db_cv_fcntl_f_setfd'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +#include +main(){exit(fcntl(1, F_SETFD, 1) == -1);} +EOF +if { (eval echo configure:4545: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + db_cv_fcntl_f_setfd=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + db_cv_fcntl_f_setfd=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$db_cv_fcntl_f_setfd" 1>&6 +if test "$db_cv_fcntl_f_setfd" = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_FCNTL_F_SETFD 1 +EOF + +fi + +case "$host_os" in +aux*) ADDITIONAL_OBJS="getopt${o} $ADDITIONAL_OBJS";; +esac + + +for ac_func in qsort +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:4575: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:4603: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +{ echo "configure: error: No qsort library function." 1>&2; exit 1; } +fi +done + +for ac_func in select +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:4631: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:4659: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +{ echo "configure: error: No select library function." 1>&2; exit 1; } +fi +done + + +echo $ac_n "checking for int type sprintf return value""... $ac_c" 1>&6 +echo "configure:4686: checking for int type sprintf return value" >&5 +if eval "test \"`echo '$''{'db_cv_sprintf_count'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + db_cv_sprintf_count=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + db_cv_sprintf_count=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$db_cv_sprintf_count" 1>&6 +if test "$db_cv_sprintf_count" = no; then + cat >> confdefs.h <<\EOF +#define SPRINTF_RET_CHARPNT 1 +EOF + +fi + +if test "$db_cv_bigfile" = no; then + case "$host_os" in + solaris2.8|hpux*) + if test "$db_cv_cxx" = "yes"; then + echo "configure: warning: Large file and C++ API support are incompatible on HP-UX" 1>&2 + echo "configure: warning: and Solaris 8; large file support has been turned off." 1>&2 + else + cat >> confdefs.h <<\EOF +#define HAVE_FILE_OFFSET_BITS 1 +EOF + + fi;; + aix*|solaris*|linux*) + cat >> confdefs.h <<\EOF +#define HAVE_FILE_OFFSET_BITS 1 +EOF +;; + esac +fi + +mmap_ok=no +case "$host_os" in +bsdi3*|bsdi4.0) + echo "configure: warning: mlock(2) interface ignored on BSD/OS 3.X and 4.0." 1>&2 + mmap_ok=yes + for ac_func in mmap munmap +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:4748: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:4776: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +mmap_ok=no +fi +done +;; +ultrix*) + echo "configure: warning: mmap(2) interface ignored on Ultrix." 1>&2;; +*) + mmap_ok=yes + for ac_func in mlock munlock +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:4808: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:4836: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + + for ac_func in mmap munmap +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:4863: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:4891: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +mmap_ok=no +fi +done +;; +esac + +shmget_ok=no +case "$host_os" in +sunos*) + echo "configure: warning: shmget(2) interface ignored on SunOS." 1>&2;; +*) + shmget_ok=yes + for ac_func in shmget +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:4927: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:4955: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +shmget_ok=no +fi +done +;; +esac + +if test "$mmap_ok" = no -a "$shmget_ok" = no; then + echo "configure: warning: Neither mmap/munmap(2) or shmget(2) library functions." 1>&2 +fi + + + +# Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:4991: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_db_cv_path_ar'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$db_cv_path_ar" in + /*) + ac_cv_path_db_cv_path_ar="$db_cv_path_ar" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_db_cv_path_ar="$db_cv_path_ar" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_db_cv_path_ar="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_db_cv_path_ar" && ac_cv_path_db_cv_path_ar="missing_ar" + ;; +esac +fi +db_cv_path_ar="$ac_cv_path_db_cv_path_ar" +if test -n "$db_cv_path_ar"; then + echo "$ac_t""$db_cv_path_ar" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test "$db_cv_path_ar" = missing_ar; then + { echo "configure: error: No ar utility found." 1>&2; exit 1; } +fi +# Extract the first word of "chmod", so it can be a program name with args. +set dummy chmod; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:5030: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_db_cv_path_chmod'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$db_cv_path_chmod" in + /*) + ac_cv_path_db_cv_path_chmod="$db_cv_path_chmod" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_db_cv_path_chmod="$db_cv_path_chmod" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_db_cv_path_chmod="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_db_cv_path_chmod" && ac_cv_path_db_cv_path_chmod="missing_chmod" + ;; +esac +fi +db_cv_path_chmod="$ac_cv_path_db_cv_path_chmod" +if test -n "$db_cv_path_chmod"; then + echo "$ac_t""$db_cv_path_chmod" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test "$db_cv_path_chmod" = missing_chmod; then + { echo "configure: error: No chmod utility found." 1>&2; exit 1; } +fi +# Extract the first word of "cp", so it can be a program name with args. +set dummy cp; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:5069: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_db_cv_path_cp'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$db_cv_path_cp" in + /*) + ac_cv_path_db_cv_path_cp="$db_cv_path_cp" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_db_cv_path_cp="$db_cv_path_cp" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_db_cv_path_cp="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_db_cv_path_cp" && ac_cv_path_db_cv_path_cp="missing_cp" + ;; +esac +fi +db_cv_path_cp="$ac_cv_path_db_cv_path_cp" +if test -n "$db_cv_path_cp"; then + echo "$ac_t""$db_cv_path_cp" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test "$db_cv_path_cp" = missing_cp; then + { echo "configure: error: No cp utility found." 1>&2; exit 1; } +fi +# Extract the first word of "ln", so it can be a program name with args. +set dummy ln; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:5108: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_db_cv_path_ln'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$db_cv_path_ln" in + /*) + ac_cv_path_db_cv_path_ln="$db_cv_path_ln" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_db_cv_path_ln="$db_cv_path_ln" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_db_cv_path_ln="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_db_cv_path_ln" && ac_cv_path_db_cv_path_ln="missing_ln" + ;; +esac +fi +db_cv_path_ln="$ac_cv_path_db_cv_path_ln" +if test -n "$db_cv_path_ln"; then + echo "$ac_t""$db_cv_path_ln" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test "$db_cv_path_ln" = missing_ln; then + { echo "configure: error: No ln utility found." 1>&2; exit 1; } +fi +# Extract the first word of "mkdir", so it can be a program name with args. +set dummy mkdir; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:5147: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_db_cv_path_mkdir'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$db_cv_path_mkdir" in + /*) + ac_cv_path_db_cv_path_mkdir="$db_cv_path_mkdir" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_db_cv_path_mkdir="$db_cv_path_mkdir" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_db_cv_path_mkdir="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_db_cv_path_mkdir" && ac_cv_path_db_cv_path_mkdir="missing_mkdir" + ;; +esac +fi +db_cv_path_mkdir="$ac_cv_path_db_cv_path_mkdir" +if test -n "$db_cv_path_mkdir"; then + echo "$ac_t""$db_cv_path_mkdir" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test "$db_cv_path_mkdir" = missing_mkdir; then + { echo "configure: error: No mkdir utility found." 1>&2; exit 1; } +fi +# Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:5186: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_db_cv_path_ranlib'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$db_cv_path_ranlib" in + /*) + ac_cv_path_db_cv_path_ranlib="$db_cv_path_ranlib" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_db_cv_path_ranlib="$db_cv_path_ranlib" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_db_cv_path_ranlib="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_db_cv_path_ranlib" && ac_cv_path_db_cv_path_ranlib="missing_ranlib" + ;; +esac +fi +db_cv_path_ranlib="$ac_cv_path_db_cv_path_ranlib" +if test -n "$db_cv_path_ranlib"; then + echo "$ac_t""$db_cv_path_ranlib" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +# Extract the first word of "rm", so it can be a program name with args. +set dummy rm; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:5222: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_db_cv_path_rm'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$db_cv_path_rm" in + /*) + ac_cv_path_db_cv_path_rm="$db_cv_path_rm" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_db_cv_path_rm="$db_cv_path_rm" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_db_cv_path_rm="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_db_cv_path_rm" && ac_cv_path_db_cv_path_rm="missing_rm" + ;; +esac +fi +db_cv_path_rm="$ac_cv_path_db_cv_path_rm" +if test -n "$db_cv_path_rm"; then + echo "$ac_t""$db_cv_path_rm" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test "$db_cv_path_rm" = missing_rm; then + { echo "configure: error: No rm utility found." 1>&2; exit 1; } +fi +# Extract the first word of "sh", so it can be a program name with args. +set dummy sh; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:5261: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_db_cv_path_sh'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$db_cv_path_sh" in + /*) + ac_cv_path_db_cv_path_sh="$db_cv_path_sh" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_db_cv_path_sh="$db_cv_path_sh" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_db_cv_path_sh="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_db_cv_path_sh" && ac_cv_path_db_cv_path_sh="missing_sh" + ;; +esac +fi +db_cv_path_sh="$ac_cv_path_db_cv_path_sh" +if test -n "$db_cv_path_sh"; then + echo "$ac_t""$db_cv_path_sh" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test "$db_cv_path_sh" = missing_sh; then + { echo "configure: error: No sh utility found." 1>&2; exit 1; } +fi +# Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:5300: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_db_cv_path_strip'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$db_cv_path_strip" in + /*) + ac_cv_path_db_cv_path_strip="$db_cv_path_strip" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_db_cv_path_strip="$db_cv_path_strip" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_db_cv_path_strip="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_db_cv_path_strip" && ac_cv_path_db_cv_path_strip="missing_strip" + ;; +esac +fi +db_cv_path_strip="$ac_cv_path_db_cv_path_strip" +if test -n "$db_cv_path_strip"; then + echo "$ac_t""$db_cv_path_strip" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test "$db_cv_path_strip" = missing_strip; then + { echo "configure: error: No strip utility found." 1>&2; exit 1; } +fi + +if test "$db_cv_test" = "yes"; then + # Extract the first word of "kill", so it can be a program name with args. +set dummy kill; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:5341: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_db_cv_path_kill'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$db_cv_path_kill" in + /*) + ac_cv_path_db_cv_path_kill="$db_cv_path_kill" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_db_cv_path_kill="$db_cv_path_kill" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_db_cv_path_kill="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_db_cv_path_kill" && ac_cv_path_db_cv_path_kill="missing_kill" + ;; +esac +fi +db_cv_path_kill="$ac_cv_path_db_cv_path_kill" +if test -n "$db_cv_path_kill"; then + echo "$ac_t""$db_cv_path_kill" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + if test "$db_cv_path_kill" = missing_kill; then + { echo "configure: error: No kill utility found." 1>&2; exit 1; } + fi +fi + + + +CREATE_LIST="Makefile + include.tcl:../test/include.tcl + db.h:../include/db.src + db_int.h:../include/db_int.src" +if test "$db_cv_compat185" = "yes"; then + CREATE_LIST="${CREATE_LIST} db_185.h:../include/db_185.h" +fi +trap '' 1 2 15 +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +DEFS=-DHAVE_CONFIG_H + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS </dev/null | sed 1q`: +# +# $0 $ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +for ac_option +do + case "\$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" + exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version 2.13" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "\$ac_cs_usage"; exit 0 ;; + *) echo "\$ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir +ac_given_INSTALL="$INSTALL" + +trap 'rm -fr `echo "${CREATE_LIST} db_config.h:config.hin" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 +EOF +cat >> $CONFIG_STATUS < conftest.subs <<\\CEOF +$ac_vpsub +$extrasub +s%@SHELL@%$SHELL%g +s%@CFLAGS@%$CFLAGS%g +s%@CPPFLAGS@%$CPPFLAGS%g +s%@CXXFLAGS@%$CXXFLAGS%g +s%@FFLAGS@%$FFLAGS%g +s%@DEFS@%$DEFS%g +s%@LDFLAGS@%$LDFLAGS%g +s%@LIBS@%$LIBS%g +s%@exec_prefix@%$exec_prefix%g +s%@prefix@%$prefix%g +s%@program_transform_name@%$program_transform_name%g +s%@bindir@%$bindir%g +s%@sbindir@%$sbindir%g +s%@libexecdir@%$libexecdir%g +s%@datadir@%$datadir%g +s%@sysconfdir@%$sysconfdir%g +s%@sharedstatedir@%$sharedstatedir%g +s%@localstatedir@%$localstatedir%g +s%@libdir@%$libdir%g +s%@includedir@%$includedir%g +s%@oldincludedir@%$oldincludedir%g +s%@infodir@%$infodir%g +s%@mandir@%$mandir%g +s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g +s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g +s%@INSTALL_DATA@%$INSTALL_DATA%g +s%@host@%$host%g +s%@host_alias@%$host_alias%g +s%@host_cpu@%$host_cpu%g +s%@host_vendor@%$host_vendor%g +s%@host_os@%$host_os%g +s%@ADDITIONAL_INCS@%$ADDITIONAL_INCS%g +s%@ADDITIONAL_LANG@%$ADDITIONAL_LANG%g +s%@ADDITIONAL_LIBS@%$ADDITIONAL_LIBS%g +s%@ADDITIONAL_OBJS@%$ADDITIONAL_OBJS%g +s%@ADDITIONAL_PROGS@%$ADDITIONAL_PROGS%g +s%@CXX@%$CXX%g +s%@DBS_LIBS@%$DBS_LIBS%g +s%@DEFAULT_INSTALL@%$DEFAULT_INSTALL%g +s%@DEFAULT_LIB@%$DEFAULT_LIB%g +s%@INSTALLER@%$INSTALLER%g +s%@INSTALL_LIBS@%$INSTALL_LIBS%g +s%@JAR@%$JAR%g +s%@JAVAC@%$JAVAC%g +s%@JAVACFLAGS@%$JAVACFLAGS%g +s%@LIBDB_ARGS@%$LIBDB_ARGS%g +s%@LIBJSO_LIBS@%$LIBJSO_LIBS%g +s%@LIBSO_LIBS@%$LIBSO_LIBS%g +s%@LIBTOOL@%$LIBTOOL%g +s%@LIBTSO_LIBS@%$LIBTSO_LIBS%g +s%@LIBXSO_LIBS@%$LIBXSO_LIBS%g +s%@MAKEFILE_CC@%$MAKEFILE_CC%g +s%@MAKEFILE_CCLINK@%$MAKEFILE_CCLINK%g +s%@MAKEFILE_CXX@%$MAKEFILE_CXX%g +s%@POSTLINK@%$POSTLINK%g +s%@RPC_OBJS@%$RPC_OBJS%g +s%@SOFLAGS@%$SOFLAGS%g +s%@SOLINK@%$SOLINK%g +s%@SOSUFFIX@%$SOSUFFIX%g +s%@o@%$o%g +s%@DB_VERSION_MAJOR@%$DB_VERSION_MAJOR%g +s%@DB_VERSION_MINOR@%$DB_VERSION_MINOR%g +s%@DB_VERSION_PATCH@%$DB_VERSION_PATCH%g +s%@DB_VERSION_STRING@%$DB_VERSION_STRING%g +s%@CC@%$CC%g +s%@CCC@%$CCC%g +s%@JAVACABS@%$JAVACABS%g +s%@TCFLAGS@%$TCFLAGS%g +s%@TCL_BIN_DIR@%$TCL_BIN_DIR%g +s%@TCL_SRC_DIR@%$TCL_SRC_DIR%g +s%@TCL_LIB_FILE@%$TCL_LIB_FILE%g +s%@TCL_TCLSH@%$TCL_TCLSH%g +s%@CPP@%$CPP%g +s%@ssize_t_decl@%$ssize_t_decl%g +s%@u_char_decl@%$u_char_decl%g +s%@u_short_decl@%$u_short_decl%g +s%@u_int_decl@%$u_int_decl%g +s%@u_long_decl@%$u_long_decl%g +s%@u_int8_decl@%$u_int8_decl%g +s%@u_int16_decl@%$u_int16_decl%g +s%@int16_decl@%$int16_decl%g +s%@u_int32_decl@%$u_int32_decl%g +s%@int32_decl@%$int32_decl%g +s%@db_align_t_decl@%$db_align_t_decl%g +s%@db_alignp_t_decl@%$db_alignp_t_decl%g +s%@LIBOBJS@%$LIBOBJS%g +s%@db_cv_path_ar@%$db_cv_path_ar%g +s%@db_cv_path_chmod@%$db_cv_path_chmod%g +s%@db_cv_path_cp@%$db_cv_path_cp%g +s%@db_cv_path_ln@%$db_cv_path_ln%g +s%@db_cv_path_mkdir@%$db_cv_path_mkdir%g +s%@db_cv_path_ranlib@%$db_cv_path_ranlib%g +s%@db_cv_path_rm@%$db_cv_path_rm%g +s%@db_cv_path_sh@%$db_cv_path_sh%g +s%@db_cv_path_strip@%$db_cv_path_strip%g +s%@db_cv_path_kill@%$db_cv_path_kill%g + +CEOF +EOF + +cat >> $CONFIG_STATUS <<\EOF + +# Split the substitutions into bite-sized pieces for seds with +# small command number limits, like on Digital OSF/1 and HP-UX. +ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. +ac_file=1 # Number of current file. +ac_beg=1 # First line for current file. +ac_end=$ac_max_sed_cmds # Line after last line for current file. +ac_more_lines=: +ac_sed_cmds="" +while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file + else + sed "${ac_end}q" conftest.subs > conftest.s$ac_file + fi + if test ! -s conftest.s$ac_file; then + ac_more_lines=false + rm -f conftest.s$ac_file + else + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f conftest.s$ac_file" + else + ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" + fi + ac_file=`expr $ac_file + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_cmds` + fi +done +if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat +fi +EOF + +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + case "$ac_given_INSTALL" in + [/$]*) INSTALL="$ac_given_INSTALL" ;; + *) INSTALL="$ac_dots$ac_given_INSTALL" ;; + esac + + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +s%@INSTALL@%$INSTALL%g +" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file +fi; done +rm -f conftest.s* + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='\([ ][ ]*\)[^ ]*%\1#\2' +ac_dC='\3' +ac_dD='%g' +# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". +ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='\([ ]\)%\1#\2define\3' +ac_uC=' ' +ac_uD='\4%g' +# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_eB='$%\1#\2define\3' +ac_eC=' ' +ac_eD='%g' + +if test "${CONFIG_HEADERS+set}" != set; then +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +fi +for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + echo creating $ac_file + + rm -f conftest.frag conftest.in conftest.out + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + cat $ac_file_inputs > conftest.in + +EOF + +# Transform confdefs.h into a sed script conftest.vals that substitutes +# the proper values into config.h.in to produce config.h. And first: +# Protect against being on the right side of a sed subst in config.status. +# Protect against being in an unquoted here document in config.status. +rm -f conftest.vals +cat > conftest.hdr <<\EOF +s/[\\&%]/\\&/g +s%[\\$`]%\\&%g +s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp +s%ac_d%ac_u%gp +s%ac_u%ac_e%gp +EOF +sed -n -f conftest.hdr confdefs.h > conftest.vals +rm -f conftest.hdr + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >> conftest.vals <<\EOF +s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */% +EOF + +# Break up conftest.vals because some shells have a limit on +# the size of here documents, and old seds have small limits too. + +rm -f conftest.tail +while : +do + ac_lines=`grep -c . conftest.vals` + # grep -c gives empty output for an empty file on some AIX systems. + if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi + # Write a limited-size here document to conftest.frag. + echo ' cat > conftest.frag <> $CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS + echo 'CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in +' >> $CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail + rm -f conftest.vals + mv conftest.tail conftest.vals +done +rm -f conftest.vals + +cat >> $CONFIG_STATUS <<\EOF + rm -f conftest.frag conftest.h + echo "/* $ac_file. Generated automatically by configure. */" > conftest.h + cat conftest.in >> conftest.h + rm -f conftest.in + if cmp -s $ac_file conftest.h 2>/dev/null; then + echo "$ac_file is unchanged" + rm -f conftest.h + else + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + fi + rm -f $ac_file + mv conftest.h $ac_file + fi +fi; done + +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF + +exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 + diff --git a/db/dist/configure.in b/db/dist/configure.in new file mode 100644 index 000000000..6c2a0c5d0 --- /dev/null +++ b/db/dist/configure.in @@ -0,0 +1,501 @@ +dnl $Id: configure.in,v 11.77 2001/01/18 19:05:25 bostic Exp $ +dnl Process this file with autoconf to produce a configure script. + +AC_INIT(../db/db.c) +AC_CONFIG_HEADER(db_config.h:config.hin) + +dnl Configure setup. +AC_PROG_INSTALL() +AC_CANONICAL_HOST +AC_ARG_PROGRAM() + +dnl We cannot build in the top-level directory. +AC_MSG_CHECKING(if building in the top-level directory) +[ test -d db_archive ] && AC_MSG_ERROR([ +Berkeley DB cannot be built in the top-level distribution directory.]) +AC_MSG_RESULT(no) + +dnl Substitution variables. +AC_SUBST(ADDITIONAL_INCS) +AC_SUBST(ADDITIONAL_LANG) +AC_SUBST(ADDITIONAL_LIBS) +AC_SUBST(ADDITIONAL_OBJS) +AC_SUBST(ADDITIONAL_PROGS) +AC_SUBST(CFLAGS) +AC_SUBST(CPPFLAGS) +AC_SUBST(CXX) +AC_SUBST(CXXFLAGS) +AC_SUBST(DBS_LIBS) +AC_SUBST(DEFAULT_INSTALL) +AC_SUBST(DEFAULT_LIB) +AC_SUBST(INSTALLER) +AC_SUBST(INSTALL_LIBS) +AC_SUBST(JAR) +AC_SUBST(JAVAC) +AC_SUBST(JAVACFLAGS) +AC_SUBST(LDFLAGS) +AC_SUBST(LIBDB_ARGS) +AC_SUBST(LIBJSO_LIBS) +AC_SUBST(LIBS) +AC_SUBST(LIBSO_LIBS) +AC_SUBST(LIBTOOL) +AC_SUBST(LIBTSO_LIBS) +AC_SUBST(LIBXSO_LIBS) +AC_SUBST(MAKEFILE_CC) +AC_SUBST(MAKEFILE_CCLINK) +AC_SUBST(MAKEFILE_CXX) +AC_SUBST(POSTLINK) +AC_SUBST(RPC_OBJS) +AC_SUBST(SOFLAGS) +AC_SUBST(SOLINK) +AC_SUBST(SOSUFFIX) + +dnl $o is set to ".o" or ".lo", and is the file suffix used in the +dnl Makefile instead of .o +AC_SUBST(o) +o=.o +INSTALLER="\$(cp)" +DEFAULT_LIB="\$(libdb)" +DEFAULT_INSTALL="install_static" + +dnl Set the version. +AM_VERSION_SET + +dnl Set the default installation location. +AC_PREFIX_DEFAULT(/usr/local/BerkeleyDB.@DB_VERSION_MAJOR@.@DB_VERSION_MINOR@) + +dnl Process all options before using them. This is necessary because there +dnl are dependencies among them. +AM_OPTIONS_SET + +dnl This is where we handle stuff that autoconf can't handle: compiler, +dnl preprocessor and load flags, libraries that the standard tests don't +dnl look for. The default optimization is -O. We would like to set the +dnl default optimization for systems using gcc to -O2, but we can't. By +dnl the time we know we're using gcc, it's too late to set optimization +dnl flags. +dnl +dnl There are additional libraries we need for some compiler/architecture +dnl combinations. +dnl +dnl Some architectures require DB to be compiled with special flags and/or +dnl libraries for threaded applications +dnl +dnl The makefile CC may be different than the CC used in config testing, +dnl because the makefile CC may be set to use $(LIBTOOL). +dnl +dnl XXX +dnl Don't override anything if it's already set from the environment. +optimize_def="-O" +case "$host_os" in +aix4.*) optimize_def="-O2" + CC=${CC-"xlc_r"} + CPPFLAGS="-D_THREAD_SAFE $CPPFLAGS" + LIBTSO_LIBS="\$(LIBS)";; +bsdi3*) CC=${CC-"shlicc2"} + optimize_def="-O2" + LIBS="-lipc $LIBS";; +bsdi*) optimize_def="-O2";; +freebsd*) optimize_def="-O2" + CPPFLAGS="-D_THREAD_SAFE $CPPFLAGS" + LIBS="-pthread";; +hpux*) CPPFLAGS="-D_REENTRANT $CPPFLAGS";; +irix*) optimize_def="-O2" + CPPFLAGS="-D_SGI_MP_SOURCE $CPPFLAGS";; +linux*) optimize_def="-O2" + CFLAGS="-D_GNU_SOURCE" + CPPFLAGS="-D_REENTRANT $CPPFLAGS";; +mpeix*) CPPFLAGS="-D_POSIX_SOURCE -D_SOCKET_SOURCE $CPPFLAGS" + LIBS="-lsocket -lsvipc $LIBS";; +osf*) CPPFLAGS="-D_REENTRANT $CPPFLAGS";; +*qnx) AC_DEFINE(HAVE_QNX);; +sco3.2v4*) CC=${CC-"cc -belf"} + LIBS="-lsocket -lnsl_s $LIBS";; +sco*) CC=${CC-"cc -belf"} + LIBS="-lsocket -lnsl $LIBS";; +solaris*) CPPFLAGS="-D_REENTRANT $CPPFLAGS";; +esac + +dnl Set CFLAGS/CXXFLAGS. We MUST set the flags before we call autoconf +dnl compiler configuration macros, because if we don't, they set CFLAGS +dnl to no optimization and -g, which isn't what we want. +CFLAGS=${CFLAGS-$optimize_def} +CXXFLAGS=${CXXFLAGS-"$CFLAGS"} + +dnl If the user wants a debugging environment, add -g to the CFLAGS value. +dnl +dnl XXX +dnl Some compilers can't mix optimizing and debug flags. The only way to +dnl handle this is to specify CFLAGS in the environment before configuring. +if test "$db_cv_debug" = yes; then + AC_DEFINE(DEBUG) + CFLAGS="$CFLAGS -g" + CXXFLAGS="$CXXFLAGS -g" +fi + +dnl The default compiler is cc (NOT gcc), the default CFLAGS is as specified +dnl above, NOT what is set by AC_PROG_CC, as it won't set optimization flags. +dnl We still call AC_PROG_CC so that we get the other side-effects. +AC_CHECK_PROG(CC, cc, cc) +AC_CHECK_PROG(CC, gcc, gcc) +AC_PROG_CC + +dnl Because of dynamic library building, the ${CC} used for config tests +dnl may be different than the ${CC} we want to put in the Makefile. +dnl The latter is known as ${MAKEFILE_CC} in this script. +MAKEFILE_CC=${CC} +MAKEFILE_CCLINK="\$(CC)" +MAKEFILE_CXX="nocxx" + +dnl Set some #defines based on configuration options. +if test "$db_cv_diagnostic" = yes; then + AC_DEFINE(DIAGNOSTIC) +fi +if test "$db_cv_debug_rop" = yes; then + AC_DEFINE(DEBUG_ROP) +fi +if test "$db_cv_debug_wop" = yes; then + AC_DEFINE(DEBUG_WOP) +fi +if test "$db_cv_umrw" = yes; then + AC_DEFINE(UMRW) +fi +if test "$db_cv_test" = yes; then + AC_DEFINE(CONFIG_TEST) +fi + +dnl See if we need the C++ compiler at all. If so, we'd like to find one that +dnl interoperates with the C compiler we chose. Since we prefered cc over gcc, +dnl we'll also prefer the vendor's compiler over g++/gcc. If we're wrong, the +dnl user can set CC and CXX in their environment before running configure. +dnl +dnl AC_PROG_CXX sets CXX, but it uses $CXX and $CCC (in that order) as its +dnl first choices. +if test "$db_cv_cxx" = "yes"; then + if test "$GCC" != "yes"; then + case "$host_os" in + aix*) AC_CHECK_PROG(CCC, xlC_r, xlC_r);; + hpux*) AC_CHECK_PROG(CCC, aCC, aCC);; + osf*) AC_CHECK_PROG(CCC, cxx, cxx);; + solaris*) AC_CHECK_PROG(CCC, CC, CC);; + esac + fi + AC_PROG_CXX + MAKEFILE_CXX=${CXX} +fi + +dnl XXX +dnl Versions of GCC up to 2.8.0 required -fhandle-exceptions, but it is +dnl renamed as -fexceptions and is the default in versions 2.8.0 and after. +dnl +dnl $GXX may be set as a result of enabling C++ or Java. +if test "$GXX" = "yes"; then + CXXVERSION=`${MAKEFILE_CXX} --version` + case ${CXXVERSION} in + 1.*|2.[[01234567]].*|*-1.*|*-2.[[01234567]].* ) + CXXFLAGS="-fhandle-exceptions $CXXFLAGS";; + * ) CXXFLAGS="-fexceptions $CXXFLAGS";; + esac +fi + +dnl Export our compiler preferences for the libtool configuration. +export CC CCC +CCC=CXX + +dnl Dynamic library and libtool configuration; optional, but required for +dnl Tcl or Java support. +LIBDB_ARGS="libdb.a" +LIBTOOL="nolibtool" +POSTLINK="@true" +SOSUFFIX="so" +if test "$db_cv_dynamic" = "yes"; then + SAVE_CC="${MAKEFILE_CC}" + SAVE_CXX="${MAKEFILE_CXX}" + + # Configure libtool. + AC_MSG_CHECKING(libtool configuration) + AC_MSG_RESULT([]) + ${CONFIG_SHELL-/bin/sh} $srcdir/ltconfig \ + --no-verify $srcdir/ltmain.sh \ + --output=./libtool $host_os \ + --disable-static \ + || AC_MSG_ERROR([libtool configure failed]) + + SOSUFFIX=`sed -e '/^library_names_spec=/!d' -e 's/.*\.\([[a-zA-Z0-9_]]*\).*/\1/' ./libtool` + DEFAULT_LIB="\$(libso_target)" + DEFAULT_INSTALL="install_dynamic" + LIBDB_ARGS="\$(libso_linkname)" + LIBTOOL="\$(SHELL) ./libtool" + + MAKEFILE_CC="\$(LIBTOOL) --mode=compile ${SAVE_CC}" + MAKEFILE_CXX="\$(LIBTOOL) --mode=compile ${SAVE_CXX}" + MAKEFILE_CCLINK="\$(LIBTOOL) --mode=link ${SAVE_CC}" + + INSTALLER="\$(LIBTOOL) --mode=install cp" + POSTLINK="\$(LIBTOOL) --mode=execute true" + SOLINK="\$(LIBTOOL) --mode=link ${SAVE_CC} -avoid-version" + SOFLAGS="-rpath \$(libdir)" + o=".lo" +fi + +dnl Optional C++ API. +if test "$db_cv_cxx" = "yes"; then + if test "$db_cv_dynamic" = "yes"; then + ADDITIONAL_LIBS="$ADDITIONAL_LIBS \$(libxso_target)" + DEFAULT_INSTALL="${DEFAULT_INSTALL} install_dynamic_cxx" + else + ADDITIONAL_LIBS="$ADDITIONAL_LIBS \$(libcxx)" + DEFAULT_INSTALL="${DEFAULT_INSTALL} install_static_cxx" + fi +fi + +dnl Optional Java API. +if test "$db_cv_java" = "yes"; then + if test "$db_cv_dynamic" != "yes"; then + AC_MSG_ERROR([--enable-java requires --enable-dynamic]) + fi + + AC_CHECK_PROG(JAVAC, javac, javac, nojavac) + if test "$JAVAC" = "nojavac"; then + AC_MSG_ERROR([no javac compiler in PATH]) + fi + AC_CHECK_PROG(JAR, jar, jar, nojar) + if test "$JAR" = "nojar"; then + AC_MSG_ERROR([no jar utility in PATH]) + fi + AC_PATH_PROG(JAVACABS, javac, nojavac) + ADDITIONAL_LIBS="$ADDITIONAL_LIBS \$(libjso_target)" + ADDITIONAL_LANG="$ADDITIONAL_LANG java" + DEFAULT_INSTALL="${DEFAULT_INSTALL} install_java" + +dnl find the include directory relative to the javac executable + while ls -ld "$JAVACABS" 2>/dev/null | grep " -> " >/dev/null; do + AC_MSG_CHECKING(symlink for $JAVACABS) + JAVACLINK=`ls -ld $JAVACABS | sed 's/.* -> //'` + case "$JAVACLINK" in + /*) JAVACABS="$JAVACLINK";; +dnl 'X' avoids triggering unwanted echo options. + *) JAVACABS=`echo "X$JAVACABS" | sed -e 's/^X//' -e 's:[[^/]]*$::'`"$JAVACLINK";; + esac + AC_MSG_RESULT($JAVACABS) + done + JTOPDIR=`echo "$JAVACABS" | sed -e 's://*:/:g' -e 's:/[[^/]]*$::'` + if test -f "$JTOPDIR/include/jni.h"; then + CPPFLAGS="$CPPFLAGSS -I$JTOPDIR/include" + else + JTOPDIR=`echo "$JTOPDIR" | sed -e 's:/[[^/]]*$::'` + if test -f "$JTOPDIR/include/jni.h"; then + CPPFLAGS="$CPPFLAGS -I$JTOPDIR/include" + else + AC_MSG_ERROR([cannot find java include files]) + fi + fi + +dnl get the likely subdirectories for system specific java includes + case "$host_os" in + solaris*) JINCSUBDIRS="solaris";; + linux*) JINCSUBDIRS="linux genunix";; + *) JINCSUBDIRS="genunix";; + esac + + for JINCSUBDIR in $JINCSUBDIRS + do + if test -d "$JTOPDIR/include/$JINCSUBDIR"; then + CPPFLAGS="$CPPFLAGS -I$JTOPDIR/include/$JINCSUBDIR" + fi + done +else + JAVAC=nojavac +fi + +dnl Optional RPC client/server. +if test "$db_cv_rpc" = "yes"; then + AC_DEFINE(HAVE_RPC) + + RPC_OBJS="\$(RPC_OBJS)" + ADDITIONAL_PROGS="berkeley_db_svc $ADDITIONAL_PROGS" + + case "$host_os" in + hpux*) + AC_CHECK_FUNC(svc_run,, + AC_CHECK_LIB(nsl, svc_run, + LIBS="-lnsl $LIBS"; LIBTSO_LIBS="-lnsl $LIBTSO_LIBS"));; + solaris*) + AC_CHECK_FUNC(svc_run,, AC_CHECK_LIB(nsl, svc_run));; + esac +fi + +AM_TCL_LOAD + +dnl Optional DB 1.85 compatibility API. +if test "$db_cv_compat185" = "yes"; then + ADDITIONAL_INCS="db_185.h $ADDITIONAL_INCS" + ADDITIONAL_OBJS="db185${o} $ADDITIONAL_OBJS" +fi + +dnl Optional utilities. +if test "$db_cv_dump185" = "yes"; then + ADDITIONAL_PROGS="db_dump185 $ADDITIONAL_PROGS" +fi + +dnl Test Server. +dnl Include -lpthread if the library exists. +AC_CHECK_LIB(pthread, pthread_create, DBS_LIBS=-lpthread) + +dnl Checks for typedefs, structures, and system/compiler characteristics. +AC_C_BIGENDIAN +AC_C_CONST +AC_HEADER_STAT +AC_HEADER_TIME +AC_STRUCT_ST_BLKSIZE +AC_TYPE_MODE_T +AC_TYPE_OFF_T +AC_TYPE_PID_T +AC_TYPE_SIZE_T + +dnl Define any short-hand types we're missing. +AM_SHORTHAND_TYPES + +dnl Checks for header files. +AC_HEADER_DIRENT +AC_CHECK_HEADERS(sys/select.h) +AC_CHECK_HEADERS(sys/time.h) + +dnl Check for mutexes. We do this here because it changes $LIBS. +AM_DEFINE_MUTEXES + +dnl Checks for system functions for which we have replacements. +dnl +dnl XXX +dnl The only portable getcwd call is getcwd(char *, size_t), where the +dnl buffer is non-NULL -- Solaris can't handle a NULL buffer, and they +dnl deleted getwd(). +AC_REPLACE_FUNCS(getcwd getopt memcmp memcpy memmove) +AC_REPLACE_FUNCS(raise snprintf strcasecmp strerror vsnprintf) + +dnl XXX +dnl Nasty hack. AC_REPLACE_FUNCS added entries of the form xxx.o to the +dnl LIBOBJS variable. They have to be xxx.lo if we are building shared +dnl libraries. Use sed, configure already requires it. +tmp="`echo \"$LIBOBJS\" | sed \"s/\.o/${o}/g\"`" +LIBOBJS="$tmp" + +dnl Check for system functions we optionally use. +AC_CHECK_FUNCS(getuid pstat_getdynamic sysconf sched_yield strtoul yield) + +dnl Pread/pwrite. +dnl +dnl HP-UX has pread/pwrite, but it doesn't work with bigfile support. +case "$host_os" in +hpux*) + AC_MSG_WARN([pread/pwrite interfaces ignored on $host_os.]);; +*) AC_CHECK_FUNCS(pread pwrite) +esac + +dnl Check for fcntl(2) to deny child process access to file descriptors. +AC_CACHE_CHECK([for fcntl/F_SETFD], db_cv_fcntl_f_setfd, [dnl +AC_TRY_RUN([ +#include +#include +main(){exit(fcntl(1, F_SETFD, 1) == -1);}], + [db_cv_fcntl_f_setfd=yes], [db_cv_fcntl_f_setfd=no])]) +if test "$db_cv_fcntl_f_setfd" = yes; then + AC_DEFINE(HAVE_FCNTL_F_SETFD) +fi + +dnl A/UX has a broken getopt(3). +case "$host_os" in +aux*) ADDITIONAL_OBJS="getopt${o} $ADDITIONAL_OBJS";; +esac + +dnl Checks for system functions for which we don't have replacements. + +dnl We require qsort(3) and select(2). +AC_CHECK_FUNCS(qsort, , AC_MSG_ERROR([No qsort library function.])) +AC_CHECK_FUNCS(select, , AC_MSG_ERROR([No select library function.])) + +dnl Some versions of sprintf return a pointer to the first argument instead +dnl of a character count. We assume that the return value of snprintf and +dnl vsprintf etc. will be the same as sprintf, and check the easy one. +AC_CACHE_CHECK([for int type sprintf return value], db_cv_sprintf_count, [dnl +AC_TRY_RUN([main(){char buf[20]; exit(sprintf(buf, "XXX") != 3);}], + [db_cv_sprintf_count=yes], [db_cv_sprintf_count=no])]) +if test "$db_cv_sprintf_count" = no; then + AC_DEFINE(SPRINTF_RET_CHARPNT) +fi + +dnl Vendors are doing 64-bit lseek in different ways. +dnl AIX, HP/UX, Solaris and Linux all use _FILE_OFFSET_BITS +dnl to specify a "big-file" environment. +dnl +dnl You can't build C++ with big-file support on HP-UX, the include files +dnl are wrong. On Solaris 8, included with big-file support +dnl is not compatible with C++. +if test "$db_cv_bigfile" = no; then + case "$host_os" in + solaris2.8|hpux*) + if test "$db_cv_cxx" = "yes"; then + AC_MSG_WARN([Large file and C++ API support are incompatible on HP-UX]) + AC_MSG_WARN([and Solaris 8; large file support has been turned off.]) + else + AC_DEFINE(HAVE_FILE_OFFSET_BITS) + fi;; + aix*|solaris*|linux*) + AC_DEFINE(HAVE_FILE_OFFSET_BITS);; + esac +fi + +dnl Figure out how to create shared regions. +dnl +dnl First, we look for mmap. +dnl +dnl BSD/OS has mlock(2), but it doesn't work until the 4.1 release. +dnl +dnl Nextstep (version 3.3) apparently supports mmap(2) (the mmap symbol +dnl is defined in the C library) but does not support munmap(2). Don't +dnl try to use mmap if we can't find munmap. +dnl +dnl Ultrix has mmap(2), but it doesn't work. +mmap_ok=no +case "$host_os" in +bsdi3*|bsdi4.0) + AC_MSG_WARN([mlock(2) interface ignored on BSD/OS 3.X and 4.0.]) + mmap_ok=yes + AC_CHECK_FUNCS(mmap munmap, , mmap_ok=no);; +ultrix*) + AC_MSG_WARN([mmap(2) interface ignored on Ultrix.]);; +*) + mmap_ok=yes + AC_CHECK_FUNCS(mlock munlock) + AC_CHECK_FUNCS(mmap munmap, , mmap_ok=no);; +esac + +dnl Second, we look for shmget. +dnl +dnl SunOS has the shmget(2) interfaces, but there appears to be a missing +dnl #include file, so we ignore them. +shmget_ok=no +case "$host_os" in +sunos*) + AC_MSG_WARN([shmget(2) interface ignored on SunOS.]);; +*) + shmget_ok=yes + AC_CHECK_FUNCS(shmget, , shmget_ok=no);; +esac + +dnl We require either mmap/munmap(2) or shmget(2). +if test "$mmap_ok" = no -a "$shmget_ok" = no; then + AC_MSG_WARN([Neither mmap/munmap(2) or shmget(2) library functions.]) +fi + +dnl Check for programs used in building and installation. +AM_PROGRAMS_SET + +CREATE_LIST="Makefile + include.tcl:../test/include.tcl + db.h:../include/db.src + db_int.h:../include/db_int.src" +if test "$db_cv_compat185" = "yes"; then + CREATE_LIST="${CREATE_LIST} db_185.h:../include/db_185.h" +fi +AC_OUTPUT(${CREATE_LIST}) diff --git a/db/dist/gen_rec.awk b/db/dist/gen_rec.awk new file mode 100644 index 000000000..5953ee051 --- /dev/null +++ b/db/dist/gen_rec.awk @@ -0,0 +1,475 @@ +#!/bin/sh - +# +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: gen_rec.awk,v 11.26 2001/01/08 21:06:46 bostic Exp $ +# + +# This awk script generates all the log, print, and read routines for the DB +# logging. It also generates a template for the recovery functions (these +# functions must still be edited, but are highly stylized and the initial +# template gets you a fair way along the path). +# +# For a given file prefix.src, we generate a file prefix_auto.c, and a file +# prefix_auto.h that contains: +# +# external declarations for the file's functions +# defines for the physical record types +# (logical types are defined in each subsystem manually) +# structures to contain the data unmarshalled from the log. +# +# This awk script requires that five variables be set when it is called: +# +# source_file -- the C source file being created +# subsystem -- the subsystem prefix, e.g., "db" +# header_file -- the C #include file being created +# template_file -- the template file being created +# template_dir -- the directory to find the source template +# +# And stdin must be the input file that defines the recovery setup. + +BEGIN { + if (source_file == "" || subsystem == "" || + header_file == "" || template_file == "" || template_dir == "") { + print "Usage: gen_rec.awk requires five variables to be set:" + print "\tsource_file\t-- the C source file being created" + print "\tsubsystem\t-- the subsystem prefix, e.g., \"db\"" + print "\theader_file\t-- the C #include file being created" + print "\ttemplate_file\t-- the template file being created" + print "\ttemplate_dir\t-- the directory to find the source template" + exit + } + FS="[\t ][\t ]*" + CFILE=source_file + NAME=subsystem + HFILE=header_file + TFILE=template_file + TDIR=template_dir +} +/^[ ]*PREFIX/ { + prefix = $2 + num_funcs = 0; + + # Start .c file. + printf("/* Do not edit: automatically built by gen_rec.awk. */\n") \ + > CFILE + + # Start .h file, make the entire file conditional. + printf("/* Do not edit: automatically built by gen_rec.awk. */\n\n") \ + > HFILE + printf("#ifndef\t%s_AUTO_H\n#define\t%s_AUTO_H\n", prefix, prefix) \ + >> HFILE; + + # Write recovery template file headers + # This assumes we're doing DB recovery. + printf("#include \"db_config.h\"\n\n") > TFILE + printf("#ifndef NO_SYSTEM_INCLUDES\n") >> TFILE + printf("#include \n\n") >> TFILE + printf("#include \n") >> TFILE + printf("#endif\n\n") >> TFILE + printf("#include \"db_int.h\"\n") >> TFILE + printf("#include \"db_page.h\"\n") >> TFILE + printf("#include \"%s.h\"\n", prefix) >> TFILE + printf("#include \"log.h\"\n\n") >> TFILE +} +/^[ ]*INCLUDE/ { + if ($3 == "") + printf("%s\n", $2) >> CFILE + else + printf("%s %s\n", $2, $3) >> CFILE +} +/^[ ]*(BEGIN|DEPRECATED)/ { + if (in_begin) { + print "Invalid format: missing END statement" + exit + } + in_begin = 1; + is_dbt = 0; + is_deprecated = ($1 == "DEPRECATED"); + nvars = 0; + + thisfunc = $2; + funcname = sprintf("%s_%s", prefix, $2); + + rectype = $3; + + funcs[num_funcs] = funcname; + funcs_dep[num_funcs] = is_deprecated; + ++num_funcs; +} +/^[ ]*(ARG|DBT|POINTER)/ { + vars[nvars] = $2; + types[nvars] = $3; + atypes[nvars] = $1; + modes[nvars] = $1; + formats[nvars] = $NF; + for (i = 4; i < NF; i++) + types[nvars] = sprintf("%s %s", types[nvars], $i); + + if ($1 == "ARG") + sizes[nvars] = sprintf("sizeof(%s)", $2); + else if ($1 == "POINTER") + sizes[nvars] = sprintf("sizeof(*%s)", $2); + else { # DBT + sizes[nvars] = \ + sprintf("sizeof(u_int32_t) + (%s == NULL ? 0 : %s->size)", \ + $2, $2); + is_dbt = 1; + } + nvars++; +} +/^[ ]*END/ { + if (!in_begin) { + print "Invalid format: missing BEGIN statement" + exit; + } + + # Declare the record type. + printf("\n#define\tDB_%s\t%d\n", funcname, rectype) >> HFILE + + # Structure declaration. + printf("typedef struct _%s_args {\n", funcname) >> HFILE + + # Here are the required fields for every structure + printf("\tu_int32_t type;\n\tDB_TXN *txnid;\n") >> HFILE + printf("\tDB_LSN prev_lsn;\n") >>HFILE + + # Here are the specified fields. + for (i = 0; i < nvars; i++) { + t = types[i]; + if (modes[i] == "POINTER") { + ndx = index(t, "*"); + t = substr(types[i], 0, ndx - 2); + } + printf("\t%s\t%s;\n", t, vars[i]) >> HFILE + } + printf("} __%s_args;\n\n", funcname) >> HFILE + + # Output the log, print and read functions. + if (!is_deprecated) + log_function(); + print_function(); + read_function(); + + # Recovery template + cmd = sprintf("sed -e s/PREF/%s/ -e s/FUNC/%s/ < %s/rec_ctemp >> %s", + prefix, thisfunc, TDIR, TFILE) + system(cmd); + + # Done writing stuff, reset and continue. + in_begin = 0; +} + +END { + # Print initialization routine; function prototype + printf("int __%s_init_print __P((DB_ENV *));\n", prefix) >> HFILE; + + # Create the routine to call db_add_recovery(print_fn, id) + printf("int\n__%s_init_print(dbenv)\n", prefix) >> CFILE; + printf("\tDB_ENV *dbenv;\n{\n\tint ret;\n\n") >> CFILE; + for (i = 0; i < num_funcs; i++) { + printf("\tif ((ret = __db_add_recovery(dbenv,\n") >> CFILE; + printf("\t __%s_print, DB_%s)) != 0)\n", \ + funcs[i], funcs[i]) >> CFILE; + printf("\t\treturn (ret);\n") >> CFILE; + } + printf("\treturn (0);\n}\n\n") >> CFILE; + + # Recover initialization routine + printf("int __%s_init_recover __P((DB_ENV *));\n", prefix) >> HFILE; + + # Create the routine to call db_add_recovery(func, id) + printf("int\n__%s_init_recover(dbenv)\n", prefix) >> CFILE; + printf("\tDB_ENV *dbenv;\n{\n\tint ret;\n\n") >> CFILE; + for (i = 0; i < num_funcs; i++) { + printf("\tif ((ret = __db_add_recovery(dbenv,\n") >> CFILE; + if (funcs_dep[i] == 1) + printf("\t __deprecated_recover, DB_%s)) != 0)\n", \ + funcs[i]) >> CFILE; + else + printf("\t __%s_recover, DB_%s)) != 0)\n", \ + funcs[i], funcs[i]) >> CFILE; + printf("\t\treturn (ret);\n") >> CFILE; + } + printf("\treturn (0);\n}\n\n") >> CFILE; + + # End the conditional for the HFILE + printf("#endif\n") >> HFILE; +} + +function log_function() { + # Write the log function; function prototype + printf("int __%s_log __P((", funcname) >> HFILE; + printf("DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t") >> HFILE; + for (i = 0; i < nvars; i++) { + printf(", ") >> HFILE; + if (modes[i] == "DBT") + printf("const ") >> HFILE; + printf("%s", types[i]) >> HFILE; + if (modes[i] == "DBT") + printf(" *") >> HFILE; + } + printf("));\n") >> HFILE; + + # Function declaration + printf("int\n__%s_log(dbenv, txnid, ret_lsnp, flags", \ + funcname) >> CFILE; + for (i = 0; i < nvars; i++) { + printf(",") >> CFILE; + if ((i % 6) == 0) + printf("\n\t") >> CFILE; + else + printf(" ") >> CFILE; + printf("%s", vars[i]) >> CFILE; + } + printf(")\n") >> CFILE; + + # Now print the parameters + printf("\tDB_ENV *dbenv;\n") >> CFILE; + printf("\tDB_TXN *txnid;\n\tDB_LSN *ret_lsnp;\n") >> CFILE; + printf("\tu_int32_t flags;\n") >> CFILE; + for (i = 0; i < nvars; i++) { + if (modes[i] == "DBT") + printf("\tconst %s *%s;\n", types[i], vars[i]) >> CFILE; + else + printf("\t%s %s;\n", types[i], vars[i]) >> CFILE; + } + + # Function body and local decls + printf("{\n") >> CFILE; + printf("\tDBT logrec;\n") >> CFILE; + printf("\tDB_LSN *lsnp, null_lsn;\n") >> CFILE; + if (is_dbt == 1) + printf("\tu_int32_t zero;\n") >> CFILE; + printf("\tu_int32_t rectype, txn_num;\n") >> CFILE; + printf("\tint ret;\n") >> CFILE; + printf("\tu_int8_t *bp;\n\n") >> CFILE; + + # Initialization + printf("\trectype = DB_%s;\n", funcname) >> CFILE; + printf("\tif (txnid != NULL &&\n") >> CFILE; + printf("\t TAILQ_FIRST(&txnid->kids) != NULL &&\n") >> CFILE; + printf("\t (ret = __txn_activekids(dbenv, rectype, txnid)) != 0)\n")\ + >> CFILE; + printf("\t\treturn (ret);\n") >> CFILE; + printf("\ttxn_num = txnid == NULL ? 0 : txnid->txnid;\n") >> CFILE; + printf("\tif (txnid == NULL) {\n") >> CFILE; + printf("\t\tZERO_LSN(null_lsn);\n") >> CFILE; + printf("\t\tlsnp = &null_lsn;\n") >> CFILE; + printf("\t} else\n\t\tlsnp = &txnid->last_lsn;\n") >> CFILE; + + # Malloc + printf("\tlogrec.size = sizeof(rectype) + ") >> CFILE; + printf("sizeof(txn_num) + sizeof(DB_LSN)") >> CFILE; + for (i = 0; i < nvars; i++) + printf("\n\t + %s", sizes[i]) >> CFILE; + printf(";\n\tif ((ret = ") >> CFILE; + printf(\ + "__os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0)\n")\ + >> CFILE; + printf("\t\treturn (ret);\n\n") >> CFILE; + + # Copy args into buffer + printf("\tbp = logrec.data;\n") >> CFILE; + printf("\tmemcpy(bp, &rectype, sizeof(rectype));\n") >> CFILE; + printf("\tbp += sizeof(rectype);\n") >> CFILE; + printf("\tmemcpy(bp, &txn_num, sizeof(txn_num));\n") >> CFILE; + printf("\tbp += sizeof(txn_num);\n") >> CFILE; + printf("\tmemcpy(bp, lsnp, sizeof(DB_LSN));\n") >> CFILE; + printf("\tbp += sizeof(DB_LSN);\n") >> CFILE; + + for (i = 0; i < nvars; i ++) { + if (modes[i] == "ARG") { + printf("\tmemcpy(bp, &%s, %s);\n", \ + vars[i], sizes[i]) >> CFILE; + printf("\tbp += %s;\n", sizes[i]) >> CFILE; + } else if (modes[i] == "DBT") { + printf("\tif (%s == NULL) {\n", vars[i]) >> CFILE; + printf("\t\tzero = 0;\n") >> CFILE; + printf("\t\tmemcpy(bp, &zero, sizeof(u_int32_t));\n") \ + >> CFILE; + printf("\t\tbp += sizeof(u_int32_t);\n") >> CFILE; + printf("\t} else {\n") >> CFILE; + printf("\t\tmemcpy(bp, &%s->size, ", vars[i]) >> CFILE; + printf("sizeof(%s->size));\n", vars[i]) >> CFILE; + printf("\t\tbp += sizeof(%s->size);\n", vars[i]) \ + >> CFILE; + printf("\t\tmemcpy(bp, %s->data, %s->size);\n", \ + vars[i], vars[i]) >> CFILE; + printf("\t\tbp += %s->size;\n\t}\n", vars[i]) >> CFILE; + } else { # POINTER + printf("\tif (%s != NULL)\n", vars[i]) >> CFILE; + printf("\t\tmemcpy(bp, %s, %s);\n", vars[i], \ + sizes[i]) >> CFILE; + printf("\telse\n") >> CFILE; + printf("\t\tmemset(bp, 0, %s);\n", sizes[i]) >> CFILE; + printf("\tbp += %s;\n", sizes[i]) >> CFILE; + } + } + + # Error checking + printf("\tDB_ASSERT((u_int32_t)") >> CFILE; + printf("(bp - (u_int8_t *)logrec.data) == logrec.size);\n") >> CFILE; + + # Issue log call + # The logging system cannot call the public log_put routine + # due to mutual exclusion constraints. So, if we are + # generating code for the log subsystem, use the internal + # __log_put. + if (prefix == "log") + printf("\tret = __log_put\(dbenv, ret_lsnp, ") >> CFILE; + else + printf("\tret = log_put(dbenv, ret_lsnp, ") >> CFILE; + printf("(DBT *)&logrec, flags);\n") >> CFILE; + + # Update the transactions last_lsn + printf("\tif (txnid != NULL)\n") >> CFILE; + printf("\t\ttxnid->last_lsn = *ret_lsnp;\n") >> CFILE; + + # Free and return + printf("\t__os_free(logrec.data, logrec.size);\n") >> CFILE; + printf("\treturn (ret);\n}\n\n") >> CFILE; +} + +function print_function() { + # Write the print function; function prototype + printf("int __%s_print", funcname) >> HFILE; + printf(" __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));\n") \ + >> HFILE; + + # Function declaration + printf("int\n__%s_print(dbenv, ", funcname) >> CFILE; + printf("dbtp, lsnp, notused2, notused3)\n") >> CFILE; + printf("\tDB_ENV *dbenv;\n") >> CFILE; + printf("\tDBT *dbtp;\n") >> CFILE; + printf("\tDB_LSN *lsnp;\n") >> CFILE; + printf("\tdb_recops notused2;\n\tvoid *notused3;\n{\n") >> CFILE; + + # Locals + printf("\t__%s_args *argp;\n", funcname) >> CFILE; + printf("\tu_int32_t i;\n\tu_int ch;\n\tint ret;\n\n") >> CFILE; + + # Get rid of complaints about unused parameters. + printf("\ti = 0;\n\tch = 0;\n") >> CFILE; + printf("\tnotused2 = DB_TXN_ABORT;\n\tnotused3 = NULL;\n\n") >> CFILE; + + # Call read routine to initialize structure + printf("\tif ((ret = __%s_read(dbenv, dbtp->data, &argp)) != 0)\n", \ + funcname) >> CFILE; + printf("\t\treturn (ret);\n") >> CFILE; + + # Print values in every record + printf("\tprintf(\"[%%lu][%%lu]%s: ", funcname) >> CFILE; + printf("rec: %%lu txnid %%lx ") >> CFILE; + printf("prevlsn [%%lu][%%lu]\\n\",\n") >> CFILE; + printf("\t (u_long)lsnp->file,\n") >> CFILE; + printf("\t (u_long)lsnp->offset,\n") >> CFILE; + printf("\t (u_long)argp->type,\n") >> CFILE; + printf("\t (u_long)argp->txnid->txnid,\n") >> CFILE; + printf("\t (u_long)argp->prev_lsn.file,\n") >> CFILE; + printf("\t (u_long)argp->prev_lsn.offset);\n") >> CFILE; + + # Now print fields of argp + for (i = 0; i < nvars; i ++) { + printf("\tprintf(\"\\t%s: ", vars[i]) >> CFILE; + + if (modes[i] == "DBT") { + printf("\");\n") >> CFILE; + printf("\tfor (i = 0; i < ") >> CFILE; + printf("argp->%s.size; i++) {\n", vars[i]) >> CFILE; + printf("\t\tch = ((u_int8_t *)argp->%s.data)[i];\n", \ + vars[i]) >> CFILE; + printf("\t\tif (isprint(ch) || ch == 0xa)\n") >> CFILE; + printf("\t\t\tputchar(ch);\n") >> CFILE; + printf("\t\telse\n") >> CFILE; + printf("\t\t\tprintf(\"%%#x \", ch);\n") >> CFILE; + printf("\t}\n\tprintf(\"\\n\");\n") >> CFILE; + } else if (types[i] == "DB_LSN *") { + printf("[%%%s][%%%s]\\n\",\n", \ + formats[i], formats[i]) >> CFILE; + printf("\t (u_long)argp->%s.file,", \ + vars[i]) >> CFILE; + printf(" (u_long)argp->%s.offset);\n", \ + vars[i]) >> CFILE; + } else { + if (formats[i] == "lx") + printf("0x") >> CFILE; + printf("%%%s\\n\", ", formats[i]) >> CFILE; + if (formats[i] == "lx" || formats[i] == "lu") + printf("(u_long)") >> CFILE; + if (formats[i] == "ld") + printf("(long)") >> CFILE; + printf("argp->%s);\n", vars[i]) >> CFILE; + } + } + printf("\tprintf(\"\\n\");\n") >> CFILE; + printf("\t__os_free(argp, 0);\n") >> CFILE; + printf("\treturn (0);\n") >> CFILE; + printf("}\n\n") >> CFILE; +} + +function read_function() { + # Write the read function; function prototype + printf("int __%s_read __P((DB_ENV *, void *, ", funcname) >> HFILE; + printf("__%s_args **));\n", funcname) >> HFILE; + + # Function declaration + printf("int\n__%s_read(dbenv, recbuf, argpp)\n", funcname) >> CFILE; + + # Now print the parameters + printf("\tDB_ENV *dbenv;\n") >> CFILE; + printf("\tvoid *recbuf;\n") >> CFILE; + printf("\t__%s_args **argpp;\n", funcname) >> CFILE; + + # Function body and local decls + printf("{\n\t__%s_args *argp;\n", funcname) >> CFILE; + printf("\tu_int8_t *bp;\n") >> CFILE; + printf("\tint ret;\n") >> CFILE; + + printf("\n\tret = __os_malloc(dbenv, sizeof(") >> CFILE; + printf("__%s_args) +\n\t sizeof(DB_TXN), NULL, &argp);\n", \ + funcname) >> CFILE; + printf("\tif (ret != 0)\n\t\treturn (ret);\n") >> CFILE; + + # Set up the pointers to the txnid and the prev lsn + printf("\targp->txnid = (DB_TXN *)&argp[1];\n") >> CFILE; + + # First get the record type, prev_lsn, and txnid fields. + + printf("\tbp = recbuf;\n") >> CFILE; + printf("\tmemcpy(&argp->type, bp, sizeof(argp->type));\n") >> CFILE; + printf("\tbp += sizeof(argp->type);\n") >> CFILE; + printf("\tmemcpy(&argp->txnid->txnid, bp, ") >> CFILE; + printf("sizeof(argp->txnid->txnid));\n") >> CFILE; + printf("\tbp += sizeof(argp->txnid->txnid);\n") >> CFILE; + printf("\tmemcpy(&argp->prev_lsn, bp, sizeof(DB_LSN));\n") >> CFILE; + printf("\tbp += sizeof(DB_LSN);\n") >> CFILE; + + # Now get rest of data. + for (i = 0; i < nvars; i ++) { + if (modes[i] == "DBT") { + printf("\tmemset(&argp->%s, 0, sizeof(argp->%s));\n", \ + vars[i], vars[i]) >> CFILE; + printf("\tmemcpy(&argp->%s.size, ", vars[i]) >> CFILE; + printf("bp, sizeof(u_int32_t));\n") >> CFILE; + printf("\tbp += sizeof(u_int32_t);\n") >> CFILE; + printf("\targp->%s.data = bp;\n", vars[i]) >> CFILE; + printf("\tbp += argp->%s.size;\n", vars[i]) >> CFILE; + } else if (modes[i] == "ARG") { + printf("\tmemcpy(&argp->%s, bp, %s%s));\n", \ + vars[i], "sizeof(argp->", vars[i]) >> CFILE; + printf("\tbp += sizeof(argp->%s);\n", vars[i]) >> CFILE; + } else { # POINTER + printf("\tmemcpy(&argp->%s, bp, ", vars[i]) >> CFILE; + printf(" sizeof(argp->%s));\n", vars[i]) >> CFILE; + printf("\tbp += sizeof(argp->%s);\n", vars[i]) >> CFILE; + } + } + + # Free and return + printf("\t*argpp = argp;\n") >> CFILE; + printf("\treturn (0);\n}\n\n") >> CFILE; +} diff --git a/db/dist/gen_rpc.awk b/db/dist/gen_rpc.awk new file mode 100644 index 000000000..6c3bffc1a --- /dev/null +++ b/db/dist/gen_rpc.awk @@ -0,0 +1,1482 @@ +# +# $Id: gen_rpc.awk,v 11.25 2001/01/02 20:04:55 sue Exp $ +# Awk script for generating client/server RPC code. +# +# This awk script generates most of the RPC routines for DB client/server +# use. It also generates a template for server and client procedures. These +# functions must still be edited, but are highly stylized and the initial +# template gets you a fair way along the path). +# +# This awk script requires that these variables be set when it is called: +# +# client_file -- the C source file being created for client code +# cproto_file -- the header file create for client prototypes +# ctmpl_file -- the C template file being created for client code +# sed_file -- the sed file created to alter server proc code +# server_file -- the C source file being created for server code +# sproto_file -- the header file create for server prototypes +# stmpl_file -- the C template file being created for server code +# xdr_file -- the XDR message file created +# +# And stdin must be the input file that defines the RPC setup. +BEGIN { + if (client_file == "" || cproto_file == "" || ctmpl_file == "" || + sed_file == "" || server_file == "" || + sproto_file == "" || stmpl_file == "" || xdr_file == "") { + print "Usage: gen_rpc.awk requires these variables be set:" + print "\tclient_file\t-- the client C source file being created" + print "\tcproto_file\t-- the client prototype header created" + print "\tctmpl_file\t-- the client template file being created" + print "\tsed_file\t-- the sed command file being created" + print "\tserver_file\t-- the server C source file being created" + print "\tsproto_file\t-- the server prototype header created" + print "\tstmpl_file\t-- the server template file being created" + print "\txdr_file\t-- the XDR message file being created" + error = 1; exit + } + + FS="\t\t*" + CFILE=client_file + printf("/* Do not edit: automatically built by gen_rpc.awk. */\n") \ + > CFILE + + CHFILE=cproto_file + printf("/* Do not edit: automatically built by gen_rpc.awk. */\n") \ + > CHFILE + + TFILE = ctmpl_file + printf("/* Do not edit: automatically built by gen_rpc.awk. */\n") \ + > TFILE + + SFILE = server_file + printf("/* Do not edit: automatically built by gen_rpc.awk. */\n") \ + > SFILE + + SHFILE=sproto_file + printf("/* Do not edit: automatically built by gen_rpc.awk. */\n") \ + > SHFILE + + # Server procedure template and a sed file to massage an existing + # template source file to change args. + # SEDFILE should be same name as PFILE but .c + # + PFILE = stmpl_file + SEDFILE = sed_file + printf("") > SEDFILE + printf("/* Do not edit: automatically built by gen_rpc.awk. */\n") \ + > PFILE + + XFILE = xdr_file + printf("/* Do not edit: automatically built by gen_rpc.awk. */\n") \ + > XFILE + nendlist = 1; +} +END { + printf("#endif /* HAVE_RPC */\n") >> CFILE + printf("#endif /* HAVE_RPC */\n") >> TFILE + printf("program DB_SERVERPROG {\n") >> XFILE + printf("\tversion DB_SERVERVERS {\n") >> XFILE + + for (i = 1; i < nendlist; ++i) + printf("\t\t%s;\n", endlist[i]) >> XFILE + + printf("\t} = 1;\n") >> XFILE + printf("} = 351457;\n") >> XFILE +} + +/^[ ]*BEGIN/ { + name = $2; + msgid = $3; + nofunc_code = 0; + funcvars = 0; + gen_code = 1; + ret_code = 0; + if ($4 == "NOCLNTCODE") + gen_code = 0; + if ($4 == "NOFUNC") + nofunc_code = 1; + if ($4 == "RETCODE") + ret_code = 1; + + nvars = 0; + rvars = 0; + newvars = 0; + db_handle = 0; + env_handle = 0; + dbc_handle = 0; + txn_handle = 0; + mp_handle = 0; + dbt_handle = 0; + xdr_free = 0; +} +/^[ ]*ARG/ { + rpc_type[nvars] = $2; + c_type[nvars] = $3; + pr_type[nvars] = $3; + args[nvars] = $4; + func_arg[nvars] = 0; + if (rpc_type[nvars] == "LIST") { + list_type[nvars] = $5; + } else + list_type[nvars] = 0; + + if (c_type[nvars] == "DBT *") + dbt_handle = 1; + + if (c_type[nvars] == "DB_ENV *") { + ctp_type[nvars] = "CT_ENV"; + env_handle = 1; + env_idx = nvars; + } + + if (c_type[nvars] == "DB *") { + ctp_type[nvars] = "CT_DB"; + db_handle = 1; + db_idx = nvars; + } + + if (c_type[nvars] == "DBC *") { + ctp_type[nvars] = "CT_CURSOR"; + dbc_handle = 1; + dbc_idx = nvars; + } + + if (c_type[nvars] == "DB_TXN *") { + ctp_type[nvars] = "CT_TXN"; + txn_handle = 1; + txn_idx = nvars; + } + + if (c_type[nvars] == "DB_MPOOLFILE *") { + mp_handle = 1; + mp_idx = nvars; + } + + ++nvars; +} +/^[ ]*FUNCPROT/ { + pr_type[nvars] = $2; +} +/^[ ]*FUNCARG/ { + rpc_type[nvars] = "IGNORE"; + c_type[nvars] = $2; + args[nvars] = sprintf("func%d", funcvars); + func_arg[nvars] = 1; + ++funcvars; + ++nvars; +} +/^[ ]*RET/ { + ret_type[rvars] = $2; + retc_type[rvars] = $3; + retargs[rvars] = $4; + if (ret_type[rvars] == "LIST" || ret_type[rvars] == "DBT") { + xdr_free = 1; + } + if (ret_type[rvars] == "LIST") { + retlist_type[rvars] = $5; + } else + retlist_type[rvars] = 0; + + ++rvars; +} +/^[ ]*END/ { + # + # ===================================================== + # Generate Client Nofunc code first if necessary + # NOTE: This code must be first, because we don't want any + # other code other than this function, so before we write + # out to the XDR and server files, we just generate this + # and move on if this is all we are doing. + # + if (nofunc_code == 1) { + # + # First time through, put out the general illegal function + # + if (first_nofunc == 0) { + printf("int __dbcl_rpc_illegal ") >> CHFILE + printf("__P((DB_ENV *, char *));\n") >> CHFILE + printf("int\n__dbcl_rpc_illegal(dbenv, name)\n") \ + >> CFILE + printf("\tDB_ENV *dbenv;\n\tchar *name;\n") >> CFILE + printf("{\n\t__db_err(dbenv,\n") >> CFILE + printf("\t \"%%s method meaningless in RPC") >> CFILE + printf(" environment\", name);\n") >> CFILE + printf("\treturn (__db_eopnotsup(dbenv));\n") >> CFILE + printf("}\n\n") >> CFILE + first_nofunc = 1 + } + # + # If we are doing a list, spit out prototype decl. + # + for (i = 0; i < nvars; i++) { + if (rpc_type[i] != "LIST") + continue; + printf("static int __dbcl_%s_%slist __P((", \ + name, args[i]) >> CFILE + printf("__%s_%slist **, ", name, args[i]) >> CFILE + if (list_type[i] == "STRING") + printf("%s));\n", c_type[i]) >> CFILE + if (list_type[i] == "INT") + printf("u_int32_t));\n") >> CFILE + if (list_type[i] == "ID") + printf("%s));\n", c_type[i]) >> CFILE + printf("static void __dbcl_%s_%sfree __P((", \ + name, args[i]) >> CFILE + printf("__%s_%slist **));\n", name, args[i]) >> CFILE + } + # + # Spit out PUBLIC prototypes. + # + printf("int __dbcl_%s __P((",name) >> CHFILE + sep = ""; + for (i = 0; i < nvars; ++i) { + printf("%s%s", sep, pr_type[i]) >> CHFILE + sep = ", "; + } + printf("));\n") >> CHFILE + # + # Spit out function name/args. + # + printf("int\n") >> CFILE + printf("__dbcl_%s(", name) >> CFILE + sep = ""; + for (i = 0; i < nvars; ++i) { + printf("%s%s", sep, args[i]) >> CFILE + sep = ", "; + } + printf(")\n") >> CFILE + + for (i = 0; i < nvars; ++i) + if (func_arg[i] == 0) + printf("\t%s %s;\n", c_type[i], args[i]) \ + >> CFILE + else + printf("\t%s;\n", c_type[i]) >> CFILE + + # + # Call error function and return EINVAL + # + printf("{\n") >> CFILE + + # + # If we don't have a local env, set one. + # + if (env_handle == 0) { + printf("\tDB_ENV *dbenv;\n\n") >> CFILE + if (db_handle) + printf("\tdbenv = %s->dbenv;\n", \ + args[db_idx]) >> CFILE + else if (dbc_handle) + printf("\tdbenv = %s->dbp->dbenv;\n", \ + args[dbc_idx]) >> CFILE + else if (txn_handle) + printf("\tdbenv = %s->mgrp->dbenv;\n", \ + args[txn_idx]) >> CFILE + else if (mp_handle) + printf("\tdbenv = %s->dbmp->dbenv;\n", \ + args[mp_idx]) >> CFILE + else + printf("\tdbenv = NULL;\n") >> CFILE + } + # + # Quiet the compiler for all variables. + # + # NOTE: Index 'i' starts at 1, not 0. Our first arg is + # the handle we need to get to the env, and we do not want + # to COMPQUIET that one. + for (i = 1; i < nvars; ++i) { + if (rpc_type[i] == "CONST" || rpc_type[i] == "DBT" || + rpc_type[i] == "LIST" || rpc_type[i] == "STRING") { + printf("\tCOMPQUIET(%s, NULL);\n", args[i]) \ + >> CFILE + } + if (rpc_type[i] == "INT" || rpc_type[i] == "IGNORE" || + rpc_type[i] == "ID") { + printf("\tCOMPQUIET(%s, 0);\n", args[i]) \ + >> CFILE + } + } + + if (!env_handle) { + printf("\treturn (__dbcl_rpc_illegal(dbenv, ") >> CFILE + printf("\"%s\"));\n", name) >> CFILE + } else + printf("\treturn (__dbcl_rpc_illegal(%s, \"%s\"));\n", \ + args[env_idx], name) >> CFILE + printf("}\n\n") >> CFILE + + next; + } + + # + # ===================================================== + # XDR messages. + # + printf("\n") >> XFILE + # + # If there are any lists, generate the structure to contain them. + # + for (i = 0; i < nvars; ++i) { + if (rpc_type[i] == "LIST") { + printf("struct __%s_%slist {\n", name, args[i]) >> XFILE + printf("\topaque ent<>;\n") >> XFILE + printf("\t__%s_%slist *next;\n", name, args[i]) >> XFILE + printf("};\n\n") >> XFILE + } + } + printf("struct __%s_msg {\n", name) >> XFILE + for (i = 0; i < nvars; ++i) { + if (rpc_type[i] == "ID") { + printf("\tunsigned int %scl_id;\n", args[i]) >> XFILE + } + if (rpc_type[i] == "STRING") { + printf("\tstring %s<>;\n", args[i]) >> XFILE + } + if (rpc_type[i] == "INT") { + printf("\tunsigned int %s;\n", args[i]) >> XFILE + } + if (rpc_type[i] == "DBT") { + printf("\tunsigned int %sdlen;\n", args[i]) >> XFILE + printf("\tunsigned int %sdoff;\n", args[i]) >> XFILE + printf("\tunsigned int %sflags;\n", args[i]) >> XFILE + printf("\topaque %sdata<>;\n", args[i]) >> XFILE + } + if (rpc_type[i] == "LIST") { + printf("\t__%s_%slist *%slist;\n", \ + name, args[i], args[i]) >> XFILE + } + } + printf("};\n") >> XFILE + + printf("\n") >> XFILE + # + # If there are any lists, generate the structure to contain them. + # + for (i = 0; i < rvars; ++i) { + if (ret_type[i] == "LIST") { + printf("struct __%s_%sreplist {\n", \ + name, retargs[i]) >> XFILE + printf("\topaque ent<>;\n") >> XFILE + printf("\t__%s_%sreplist *next;\n", \ + name, retargs[i]) >> XFILE + printf("};\n\n") >> XFILE + } + } + # + # Generate the reply message + # + printf("struct __%s_reply {\n", name) >> XFILE + printf("\tunsigned int status;\n") >> XFILE + for (i = 0; i < rvars; ++i) { + if (ret_type[i] == "ID") { + printf("\tunsigned int %scl_id;\n", retargs[i]) >> XFILE + } + if (ret_type[i] == "STRING") { + printf("\tstring %s<>;\n", retargs[i]) >> XFILE + } + if (ret_type[i] == "INT") { + printf("\tunsigned int %s;\n", retargs[i]) >> XFILE + } + if (ret_type[i] == "DBL") { + printf("\tdouble %s;\n", retargs[i]) >> XFILE + } + if (ret_type[i] == "DBT") { + printf("\topaque %sdata<>;\n", retargs[i]) >> XFILE + } + if (ret_type[i] == "LIST") { + printf("\t__%s_%sreplist *%slist;\n", \ + name, retargs[i], retargs[i]) >> XFILE + } + } + printf("};\n") >> XFILE + + endlist[nendlist] = \ + sprintf("__%s_reply __DB_%s(__%s_msg) = %d", \ + name, name, name, nendlist); + nendlist++; + + # + # ===================================================== + # File headers, if necessary. + # + if (first == 0) { + printf("#include \"db_config.h\"\n") >> CFILE + printf("\n") >> CFILE + printf("#ifdef HAVE_RPC\n") >> CFILE + printf("#ifndef NO_SYSTEM_INCLUDES\n") >> CFILE + printf("#include \n") >> CFILE + printf("#include \n") >> CFILE + printf("#include \n") >> CFILE + printf("\n") >> CFILE + printf("#include \n") >> CFILE + printf("#include \n") >> CFILE + printf("#endif\n") >> CFILE + printf("#include \"db_server.h\"\n") >> CFILE + printf("\n") >> CFILE + printf("#include \"db_int.h\"\n") >> CFILE + printf("#include \"db_page.h\"\n") >> CFILE + printf("#include \"db_ext.h\"\n") >> CFILE + printf("#include \"mp.h\"\n") >> CFILE + printf("#include \"rpc_client_ext.h\"\n") >> CFILE + printf("#include \"txn.h\"\n") >> CFILE + printf("\n") >> CFILE + n = split(CHFILE, hpieces, "/"); + printf("#include \"%s\"\n", hpieces[n]) >> CFILE + printf("\n") >> CFILE + + printf("#include \"db_config.h\"\n") >> TFILE + printf("\n") >> TFILE + printf("#ifdef HAVE_RPC\n") >> TFILE + printf("#ifndef NO_SYSTEM_INCLUDES\n") >> TFILE + printf("#include \n") >> TFILE + printf("#include \n") >> TFILE + printf("\n") >> TFILE + printf("#include \n") >> TFILE + printf("#include \n") >> TFILE + printf("#endif\n") >> TFILE + printf("#include \"db_server.h\"\n") >> TFILE + printf("\n") >> TFILE + printf("#include \"db_int.h\"\n") >> TFILE + printf("#include \"db_page.h\"\n") >> TFILE + printf("#include \"db_ext.h\"\n") >> TFILE + printf("#include \"txn.h\"\n") >> TFILE + printf("\n") >> TFILE + n = split(CHFILE, hpieces, "/"); + printf("#include \"%s\"\n", hpieces[n]) >> TFILE + printf("\n") >> TFILE + + printf("#include \"db_config.h\"\n") >> SFILE + printf("\n") >> SFILE + printf("#ifndef NO_SYSTEM_INCLUDES\n") >> SFILE + printf("#include \n") >> SFILE + printf("\n") >> SFILE + printf("#include \n") >> SFILE + printf("#include \n") >> SFILE + printf("\n") >> SFILE + printf("#include \n") >> SFILE + printf("#include \n") >> SFILE + printf("#endif\n") >> SFILE + printf("#include \"db_server.h\"\n") >> SFILE + printf("\n") >> SFILE + printf("#include \"db_int.h\"\n") >> SFILE + printf("#include \"db_server_int.h\"\n") >> SFILE + printf("#include \"rpc_server_ext.h\"\n") >> SFILE + printf("\n") >> SFILE + n = split(SHFILE, hpieces, "/"); + printf("#include \"%s\"\n", hpieces[n]) >> SFILE + printf("\n") >> SFILE + + printf("#include \"db_config.h\"\n") >> PFILE + printf("\n") >> PFILE + printf("#ifndef NO_SYSTEM_INCLUDES\n") >> PFILE + printf("#include \n") >> PFILE + printf("\n") >> PFILE + printf("#include \n") >> PFILE + printf("\n") >> PFILE + printf("#include \n") >> PFILE + printf("#include \n") >> PFILE + printf("#include \"db_server.h\"\n") >> PFILE + printf("#endif\n") >> PFILE + printf("\n") >> PFILE + printf("#include \"db_int.h\"\n") >> PFILE + printf("#include \"db_server_int.h\"\n") >> PFILE + printf("#include \"rpc_server_ext.h\"\n") >> PFILE + printf("\n") >> PFILE + n = split(SHFILE, hpieces, "/"); + printf("#include \"%s\"\n", hpieces[n]) >> PFILE + printf("\n") >> PFILE + + first = 1; + } + + # + # ===================================================== + # Server functions. + # + # If we are doing a list, send out local list prototypes. + # + for (i = 0; i < nvars; ++i) { + if (rpc_type[i] != "LIST") + continue; + if (list_type[i] != "STRING" && list_type[i] != "INT" && + list_type[i] != "ID") + continue; + printf("int __db_%s_%slist __P((", name, args[i]) >> SFILE + printf("__%s_%slist *, ", name, args[i]) >> SFILE + if (list_type[i] == "STRING") { + printf("char ***));\n") >> SFILE + } + if (list_type[i] == "INT" || list_type[i] == "ID") { + printf("u_int32_t **));\n") >> SFILE + } + printf("void __db_%s_%sfree __P((", name, args[i]) >> SFILE + if (list_type[i] == "STRING") + printf("char **));\n\n") >> SFILE + if (list_type[i] == "INT" || list_type[i] == "ID") + printf("u_int32_t *));\n\n") >> SFILE + + } + # + # First spit out PUBLIC prototypes for server functions. + # + printf("__%s_reply * __db_%s_%d __P((__%s_msg *));\n", \ + name, name, msgid, name) >> SHFILE + + printf("__%s_reply *\n", name) >> SFILE + printf("__db_%s_%d(req)\n", name, msgid) >> SFILE + printf("\t__%s_msg *req;\n", name) >> SFILE; + printf("{\n") >> SFILE + doing_list = 0; + # + # If we are doing a list, decompose it for server proc we'll call. + # + for (i = 0; i < nvars; ++i) { + if (rpc_type[i] != "LIST") + continue; + doing_list = 1; + if (list_type[i] == "STRING") + printf("\tchar **__db_%slist;\n", args[i]) >> SFILE + if (list_type[i] == "ID" || list_type[i] == "INT") + printf("\tu_int32_t *__db_%slist;\n", args[i]) >> SFILE + } + if (doing_list) + printf("\tint ret;\n") >> SFILE + printf("\tstatic __%s_reply reply; /* must be static */\n", \ + name) >> SFILE + if (xdr_free) { + printf("\tstatic int __%s_free = 0; /* must be static */\n\n", \ + name) >> SFILE + printf("\tif (__%s_free)\n", name) >> SFILE + printf("\t\txdr_free((xdrproc_t)xdr___%s_reply, (void *)&reply);\n", \ + name) >> SFILE + printf("\t__%s_free = 0;\n", name) >> SFILE + printf("\n\t/* Reinitialize allocated fields */\n") >> SFILE + for (i = 0; i < rvars; ++i) { + if (ret_type[i] == "LIST") { + printf("\treply.%slist = NULL;\n", \ + retargs[i]) >> SFILE + } + if (ret_type[i] == "DBT") { + printf("\treply.%sdata.%sdata_val = NULL;\n", \ + retargs[i], retargs[i]) >> SFILE + } + } + } + + need_out = 0; + for (i = 0; i < nvars; ++i) { + if (rpc_type[i] == "LIST") { + printf("\n\tif ((ret = __db_%s_%slist(", \ + name, args[i]) >> SFILE + printf("req->%slist, &__db_%slist)) != 0)\n", \ + args[i], args[i]) >> SFILE + printf("\t\tgoto out;\n") >> SFILE + need_out = 1; + } + } + + # + # Compose server proc to call. Decompose message components as args. + # + printf("\n\t__%s_%d_proc(", name, msgid) >> SFILE + sep = ""; + for (i = 0; i < nvars; ++i) { + if (rpc_type[i] == "ID") { + printf("%sreq->%scl_id", sep, args[i]) >> SFILE + } + if (rpc_type[i] == "STRING") { + printf("%s(*req->%s == '\\0') ? NULL : req->%s", \ + sep, args[i], args[i]) >> SFILE + } + if (rpc_type[i] == "INT") { + printf("%sreq->%s", sep, args[i]) >> SFILE + } + if (rpc_type[i] == "LIST") { + printf("%s__db_%slist", sep, args[i]) >> SFILE + } + if (rpc_type[i] == "DBT") { + printf("%sreq->%sdlen", sep, args[i]) >> SFILE + sep = ",\n\t "; + printf("%sreq->%sdoff", sep, args[i]) >> SFILE + printf("%sreq->%sflags", sep, args[i]) >> SFILE + printf("%sreq->%sdata.%sdata_val", \ + sep, args[i], args[i]) >> SFILE + printf("%sreq->%sdata.%sdata_len", \ + sep, args[i], args[i]) >> SFILE + } + sep = ",\n\t "; + } + printf("%s&reply", sep) >> SFILE + if (xdr_free) + printf("%s&__%s_free);\n", sep, name) >> SFILE + else + printf(");\n\n") >> SFILE + for (i = 0; i < nvars; ++i) { + if (rpc_type[i] == "LIST") { + printf("\t__db_%s_%sfree(__db_%slist);\n", \ + name, args[i], args[i]) >> SFILE + } + } + if (need_out) { + printf("\nout:\n") >> SFILE + } + printf("\treturn (&reply);\n") >> SFILE + printf("}\n\n") >> SFILE + + # + # If we are doing a list, write list functions for this op. + # + for (i = 0; i < nvars; ++i) { + if (rpc_type[i] != "LIST") + continue; + if (list_type[i] != "STRING" && list_type[i] != "INT" && + list_type[i] != "ID") + continue; + printf("int\n") >> SFILE + printf("__db_%s_%slist(locp, ppp)\n", name, args[i]) >> SFILE + printf("\t__%s_%slist *locp;\n", name, args[i]) >> SFILE + if (list_type[i] == "STRING") { + printf("\tchar ***ppp;\n{\n") >> SFILE + printf("\tchar **pp;\n") >> SFILE + } + if (list_type[i] == "INT" || list_type[i] == "ID") { + printf("\tu_int32_t **ppp;\n{\n") >> SFILE + printf("\tu_int32_t *pp;\n") >> SFILE + } + printf("\tint cnt, ret, size;\n") >> SFILE + printf("\t__%s_%slist *nl;\n\n", name, args[i]) >> SFILE + printf("\tfor (cnt = 0, nl = locp;") >> SFILE + printf(" nl != NULL; cnt++, nl = nl->next)\n\t\t;\n\n") >> SFILE + printf("\tif (cnt == 0) {\n") >> SFILE + printf("\t\t*ppp = NULL;\n") >> SFILE + printf("\t\treturn (0);\n\t}\n") >> SFILE + printf("\tsize = sizeof(*pp) * (cnt + 1);\n") >> SFILE + printf("\tif ((ret = __os_malloc(NULL, size, ") >> SFILE + printf("NULL, ppp)) != 0)\n") >> SFILE + printf("\t\treturn (ret);\n") >> SFILE + printf("\tmemset(*ppp, 0, size);\n") >> SFILE + printf("\tfor (pp = *ppp, nl = locp;") >> SFILE + printf(" nl != NULL; nl = nl->next, pp++) {\n") >> SFILE + if (list_type[i] == "STRING") { + printf("\t\tif ((ret = __os_malloc(NULL ,") >> SFILE + printf("nl->ent.ent_len + 1, NULL, pp)) != 0)\n") \ + >> SFILE + printf("\t\t\tgoto out;\n") >> SFILE + printf("\t\tif ((ret = __os_strdup(NULL, ") >> SFILE + printf("(char *)nl->ent.ent_val, pp)) != 0)\n") >> SFILE + printf("\t\t\tgoto out;\n") >> SFILE + } + if (list_type[i] == "INT" || list_type[i] == "ID") + printf("\t\t*pp = *(u_int32_t *)nl->ent.ent_val;\n") \ + >> SFILE + printf("\t}\n") >> SFILE + printf("\treturn (0);\n") >> SFILE + if (list_type[i] == "STRING") { + printf("out:\n") >> SFILE + printf("\t__db_%s_%sfree(*ppp);\n", \ + name, args[i]) >> SFILE + printf("\treturn (ret);\n") >> SFILE + } + printf("}\n\n") >> SFILE + + printf("void\n") >> SFILE + printf("__db_%s_%sfree(pp)\n", name, args[i]) >> SFILE + + if (list_type[i] == "STRING") + printf("\tchar **pp;\n") >> SFILE + if (list_type[i] == "INT" || list_type[i] == "ID") + printf("\tu_int32_t *pp;\n") >> SFILE + + printf("{\n") >> SFILE + printf("\tsize_t size;\n") >> SFILE + + if (list_type[i] == "STRING") + printf("\tchar **p;\n\n") >> SFILE + if (list_type[i] == "INT" || list_type[i] == "ID") + printf("\tu_int32_t *p;\n\n") >> SFILE + + printf("\tif (pp == NULL)\n\t\treturn;\n") >> SFILE + printf("\tsize = sizeof(*p);\n") >> SFILE + printf("\tfor (p = pp; *p != 0; p++) {\n") >> SFILE + printf("\t\tsize += sizeof(*p);\n") >> SFILE + + if (list_type[i] == "STRING") + printf("\t\t__os_free(*p, strlen(*p)+1);\n") >> SFILE + printf("\t}\n") >> SFILE + printf("\t__os_free(pp, size);\n") >> SFILE + printf("}\n\n") >> SFILE + } + + # + # ===================================================== + # Generate Procedure Template Server code + # + # Produce SED file commands if needed at the same time + # + # Start with PUBLIC prototypes + # + printf("void __%s_%d_proc __P((", name, msgid) >> SHFILE + sep = ""; + argcount = 0; + for (i = 0; i < nvars; ++i) { + argcount++; + split_lines(1); + if (argcount == 0) { + sep = ""; + } + if (rpc_type[i] == "IGNORE") + continue; + if (rpc_type[i] == "ID") { + printf("%slong", sep) >> SHFILE + } + if (rpc_type[i] == "STRING") { + printf("%schar *", sep) >> SHFILE + } + if (rpc_type[i] == "INT") { + printf("%su_int32_t", sep) >> SHFILE + } + if (rpc_type[i] == "LIST" && list_type[i] == "STRING") { + printf("%schar **", sep) >> SHFILE + } + if (rpc_type[i] == "LIST" && list_type[i] == "INT") { + printf("%su_int32_t *", sep) >> SHFILE + } + if (rpc_type[i] == "LIST" && list_type[i] == "ID") { + printf("%su_int32_t *", sep) >> SHFILE + } + if (rpc_type[i] == "DBT") { + printf("%su_int32_t", sep) >> SHFILE + sep = ", "; + argcount++; + split_lines(1); + if (argcount == 0) { + sep = ""; + } else { + sep = ", "; + } + printf("%su_int32_t", sep) >> SHFILE + argcount++; + split_lines(1); + if (argcount == 0) { + sep = ""; + } else { + sep = ", "; + } + printf("%su_int32_t", sep) >> SHFILE + argcount++; + split_lines(1); + if (argcount == 0) { + sep = ""; + } else { + sep = ", "; + } + printf("%svoid *", sep) >> SHFILE + argcount++; + split_lines(1); + if (argcount == 0) { + sep = ""; + } else { + sep = ", "; + } + printf("%su_int32_t", sep) >> SHFILE + } + sep = ", "; + } + printf("%s__%s_reply *", sep, name) >> SHFILE + if (xdr_free) { + printf("%sint *));\n", sep) >> SHFILE + } else { + printf("));\n") >> SHFILE + } + # + # Spit out function name and arg list + # + printf("/^\\/\\* BEGIN __%s_%d_proc/,/^\\/\\* END __%s_%d_proc/c\\\n", \ + name, msgid, name, msgid) >> SEDFILE + + printf("/* BEGIN __%s_%d_proc */\n", name, msgid) >> PFILE + printf("/* BEGIN __%s_%d_proc */\\\n", name, msgid) >> SEDFILE + printf("void\n") >> PFILE + printf("void\\\n") >> SEDFILE + printf("__%s_%d_proc(", name, msgid) >> PFILE + printf("__%s_%d_proc(", name, msgid) >> SEDFILE + sep = ""; + argcount = 0; + for (i = 0; i < nvars; ++i) { + argcount++; + split_lines(0); + if (argcount == 0) { + sep = ""; + } + if (rpc_type[i] == "IGNORE") + continue; + if (rpc_type[i] == "ID") { + printf("%s%scl_id", sep, args[i]) >> PFILE + printf("%s%scl_id", sep, args[i]) >> SEDFILE + } + if (rpc_type[i] == "STRING") { + printf("%s%s", sep, args[i]) >> PFILE + printf("%s%s", sep, args[i]) >> SEDFILE + } + if (rpc_type[i] == "INT") { + printf("%s%s", sep, args[i]) >> PFILE + printf("%s%s", sep, args[i]) >> SEDFILE + } + if (rpc_type[i] == "LIST") { + printf("%s%slist", sep, args[i]) >> PFILE + printf("%s%slist", sep, args[i]) >> SEDFILE + } + if (rpc_type[i] == "DBT") { + printf("%s%sdlen", sep, args[i]) >> PFILE + printf("%s%sdlen", sep, args[i]) >> SEDFILE + sep = ", "; + argcount++; + split_lines(0); + if (argcount == 0) { + sep = ""; + } else { + sep = ", "; + } + printf("%s%sdoff", sep, args[i]) >> PFILE + printf("%s%sdoff", sep, args[i]) >> SEDFILE + argcount++; + split_lines(0); + if (argcount == 0) { + sep = ""; + } else { + sep = ", "; + } + printf("%s%sflags", sep, args[i]) >> PFILE + printf("%s%sflags", sep, args[i]) >> SEDFILE + argcount++; + split_lines(0); + if (argcount == 0) { + sep = ""; + } else { + sep = ", "; + } + printf("%s%sdata", sep, args[i]) >> PFILE + printf("%s%sdata", sep, args[i]) >> SEDFILE + argcount++; + split_lines(0); + if (argcount == 0) { + sep = ""; + } else { + sep = ", "; + } + printf("%s%ssize", sep, args[i]) >> PFILE + printf("%s%ssize", sep, args[i]) >> SEDFILE + } + sep = ", "; + } + printf("%sreplyp",sep) >> PFILE + printf("%sreplyp",sep) >> SEDFILE + if (xdr_free) { + printf("%sfreep)\n",sep) >> PFILE + printf("%sfreep)\\\n",sep) >> SEDFILE + } else { + printf(")\n") >> PFILE + printf(")\\\n") >> SEDFILE + } + # + # Spit out arg types/names; + # + for (i = 0; i < nvars; ++i) { + if (rpc_type[i] == "ID") { + printf("\tlong %scl_id;\n", args[i]) >> PFILE + printf("\\\tlong %scl_id;\\\n", args[i]) >> SEDFILE + } + if (rpc_type[i] == "STRING") { + printf("\tchar *%s;\n", args[i]) >> PFILE + printf("\\\tchar *%s;\\\n", args[i]) >> SEDFILE + } + if (rpc_type[i] == "INT") { + printf("\tu_int32_t %s;\n", args[i]) >> PFILE + printf("\\\tu_int32_t %s;\\\n", args[i]) >> SEDFILE + } + if (rpc_type[i] == "LIST" && list_type[i] == "STRING") { + printf("\tchar ** %slist;\n", args[i]) >> PFILE + printf("\\\tchar ** %slist;\\\n", args[i]) >> SEDFILE + } + if (rpc_type[i] == "LIST" && list_type[i] == "INT") { + printf("\tu_int32_t * %slist;\n", args[i]) >> PFILE + printf("\\\tu_int32_t * %slist;\\\n", \ + args[i]) >> SEDFILE + } + if (rpc_type[i] == "LIST" && list_type[i] == "ID") { + printf("\tu_int32_t * %slist;\n", args[i]) >> PFILE + printf("\\\tu_int32_t * %slist;\\\n", args[i]) \ + >> SEDFILE + } + if (rpc_type[i] == "DBT") { + printf("\tu_int32_t %sdlen;\n", args[i]) >> PFILE + printf("\\\tu_int32_t %sdlen;\\\n", args[i]) >> SEDFILE + printf("\tu_int32_t %sdoff;\n", args[i]) >> PFILE + printf("\\\tu_int32_t %sdoff;\\\n", args[i]) >> SEDFILE + printf("\tu_int32_t %sflags;\n", args[i]) >> PFILE + printf("\\\tu_int32_t %sflags;\\\n", args[i]) >> SEDFILE + printf("\tvoid *%sdata;\n", args[i]) >> PFILE + printf("\\\tvoid *%sdata;\\\n", args[i]) >> SEDFILE + printf("\tu_int32_t %ssize;\n", args[i]) >> PFILE + printf("\\\tu_int32_t %ssize;\\\n", args[i]) >> SEDFILE + } + } + printf("\t__%s_reply *replyp;\n",name) >> PFILE + printf("\\\t__%s_reply *replyp;\\\n",name) >> SEDFILE + if (xdr_free) { + printf("\tint * freep;\n") >> PFILE + printf("\\\tint * freep;\\\n") >> SEDFILE + } + + printf("/* END __%s_%d_proc */\n", name, msgid) >> PFILE + printf("/* END __%s_%d_proc */\n", name, msgid) >> SEDFILE + + # + # Function body + # + printf("{\n") >> PFILE + printf("\tint ret;\n") >> PFILE + for (i = 0; i < nvars; ++i) { + if (rpc_type[i] == "ID") { + printf("\t%s %s;\n", c_type[i], args[i]) >> PFILE + printf("\tct_entry *%s_ctp;\n", args[i]) >> PFILE + } + } + printf("\n") >> PFILE + for (i = 0; i < nvars; ++i) { + if (rpc_type[i] == "ID") { + printf("\tACTIVATE_CTP(%s_ctp, %scl_id, %s);\n", \ + args[i], args[i], ctp_type[i]) >> PFILE + printf("\t%s = (%s)%s_ctp->ct_anyp;\n", \ + args[i], c_type[i], args[i]) >> PFILE + } + } + printf("\n\t/*\n\t * XXX Code goes here\n\t */\n\n") >> PFILE + printf("\treplyp->status = ret;\n") >> PFILE + printf("\treturn;\n") >> PFILE + printf("}\n\n") >> PFILE + + # + # If we don't want client code generated, go on to next. + # + if (gen_code == 0) + next; + + # + # ===================================================== + # Generate Client code + # + # If we are doing a list, spit out prototype decl. + # + for (i = 0; i < nvars; i++) { + if (rpc_type[i] != "LIST") + continue; + printf("static int __dbcl_%s_%slist __P((", \ + name, args[i]) >> CFILE + printf("__%s_%slist **, ", name, args[i]) >> CFILE + if (list_type[i] == "STRING") + printf("%s));\n", c_type[i]) >> CFILE + if (list_type[i] == "INT") + printf("u_int32_t));\n") >> CFILE + if (list_type[i] == "ID") + printf("%s));\n", c_type[i]) >> CFILE + printf("static void __dbcl_%s_%sfree __P((", \ + name, args[i]) >> CFILE + printf("__%s_%slist **));\n", name, args[i]) >> CFILE + } + # + # Spit out PUBLIC prototypes. + # + printf("int __dbcl_%s __P((",name) >> CHFILE + sep = ""; + for (i = 0; i < nvars; ++i) { + printf("%s%s", sep, pr_type[i]) >> CHFILE + sep = ", "; + } + printf("));\n") >> CHFILE + # + # Spit out function name/args. + # + printf("int\n") >> CFILE + printf("__dbcl_%s(", name) >> CFILE + sep = ""; + for (i = 0; i < nvars; ++i) { + printf("%s%s", sep, args[i]) >> CFILE + sep = ", "; + } + printf(")\n") >> CFILE + + for (i = 0; i < nvars; ++i) + if (func_arg[i] == 0) + printf("\t%s %s;\n", c_type[i], args[i]) >> CFILE + else + printf("\t%s;\n", c_type[i]) >> CFILE + + printf("{\n") >> CFILE + printf("\tCLIENT *cl;\n") >> CFILE + printf("\t__%s_msg req;\n", name) >> CFILE + printf("\tstatic __%s_reply *replyp = NULL;\n", name) >> CFILE; + printf("\tint ret;\n") >> CFILE + if (!env_handle) + printf("\tDB_ENV *dbenv;\n") >> CFILE + + printf("\n") >> CFILE + printf("\tret = 0;\n") >> CFILE + if (!env_handle) { + printf("\tdbenv = NULL;\n") >> CFILE + if (db_handle) + printf("\tdbenv = %s->dbenv;\n", args[db_idx]) >> CFILE + else if (dbc_handle) + printf("\tdbenv = %s->dbp->dbenv;\n", \ + args[dbc_idx]) >> CFILE + else if (txn_handle) + printf("\tdbenv = %s->mgrp->dbenv;\n", \ + args[txn_idx]) >> CFILE + printf("\tif (dbenv == NULL || dbenv->cl_handle == NULL) {\n") \ + >> CFILE + printf("\t\t__db_err(dbenv, \"No server environment.\");\n") \ + >> CFILE + } else { + printf("\tif (%s == NULL || %s->cl_handle == NULL) {\n", \ + args[env_idx], args[env_idx]) >> CFILE + printf("\t\t__db_err(%s, \"No server environment.\");\n", \ + args[env_idx]) >> CFILE + } + printf("\t\treturn (DB_NOSERVER);\n") >> CFILE + printf("\t}\n") >> CFILE + printf("\n") >> CFILE + + # + # Free old reply if there was one. + # + printf("\tif (replyp != NULL) {\n") >> CFILE + printf("\t\txdr_free((xdrproc_t)xdr___%s_reply, (void *)replyp);\n", \ + name) >> CFILE + printf("\t\treplyp = NULL;\n\t}\n") >> CFILE + if (!env_handle) + printf("\tcl = (CLIENT *)dbenv->cl_handle;\n") >> CFILE + else + printf("\tcl = (CLIENT *)%s->cl_handle;\n", \ + args[env_idx]) >> CFILE + + printf("\n") >> CFILE + + # + # If there is a function arg, check that it is NULL + # + for (i = 0; i < nvars; ++i) { + if (func_arg[i] != 1) + continue; + printf("\tif (%s != NULL) {\n", args[i]) >> CFILE + printf("\t\t__db_err(%s, ", args[env_idx]) >> CFILE + printf("\"User functions not supported in RPC.\");\n") >> CFILE + printf("\t\treturn (EINVAL);\n\t}\n") >> CFILE + } + + # + # Compose message components + # + for (i = 0; i < nvars; ++i) { + if (rpc_type[i] == "ID") { + printf("\tif (%s == NULL)\n", args[i]) >> CFILE + printf("\t\treq.%scl_id = 0;\n\telse\n", \ + args[i]) >> CFILE + if (c_type[i] == "DB_TXN *") { + printf("\t\treq.%scl_id = %s->txnid;\n", \ + args[i], args[i]) >> CFILE + } else { + printf("\t\treq.%scl_id = %s->cl_id;\n", \ + args[i], args[i]) >> CFILE + } + } + if (rpc_type[i] == "INT") { + printf("\treq.%s = %s;\n", args[i], args[i]) >> CFILE + } + if (rpc_type[i] == "STRING") { + printf("\tif (%s == NULL)\n", args[i]) >> CFILE + printf("\t\treq.%s = \"\";\n", args[i]) >> CFILE + printf("\telse\n") >> CFILE + printf("\t\treq.%s = (char *)%s;\n", \ + args[i], args[i]) >> CFILE + } + if (rpc_type[i] == "DBT") { + printf("\treq.%sdlen = %s->dlen;\n", \ + args[i], args[i]) >> CFILE + printf("\treq.%sdoff = %s->doff;\n", \ + args[i], args[i]) >> CFILE + printf("\treq.%sflags = %s->flags;\n", \ + args[i], args[i]) >> CFILE + printf("\treq.%sdata.%sdata_val = %s->data;\n", \ + args[i], args[i], args[i]) >> CFILE + printf("\treq.%sdata.%sdata_len = %s->size;\n", \ + args[i], args[i], args[i]) >> CFILE + } + if (rpc_type[i] == "LIST") { + printf("\tif ((ret = __dbcl_%s_%slist(", \ + name, args[i]) >> CFILE + printf("&req.%slist, %s)) != 0)\n", \ + args[i], args[i]) >> CFILE + printf("\t\tgoto out;\n") >> CFILE + } + } + + printf("\n") >> CFILE + printf("\treplyp = __db_%s_%d(&req, cl);\n", name, msgid) >> CFILE + printf("\tif (replyp == NULL) {\n") >> CFILE + if (!env_handle) { + printf("\t\t__db_err(dbenv, ") >> CFILE + printf("clnt_sperror(cl, \"Berkeley DB\"));\n") >> CFILE + } else { + printf("\t\t__db_err(%s, ", args[env_idx]) >> CFILE + printf("clnt_sperror(cl, \"Berkeley DB\"));\n") >> CFILE + } + printf("\t\tret = DB_NOSERVER;\n") >> CFILE + printf("\t\tgoto out;\n") >> CFILE + printf("\t}\n") >> CFILE + + if (ret_code == 0) { + printf("\tret = replyp->status;\n") >> CFILE + } else { + for (i = 0; i < nvars; ++i) { + if (rpc_type[i] == "LIST") { + printf("\t__dbcl_%s_%sfree(&req.%slist);\n", \ + name, args[i], args[i]) >> CFILE + } + } + printf("\treturn (__dbcl_%s_ret(", name) >> CFILE + sep = ""; + for (i = 0; i < nvars; ++i) { + printf("%s%s", sep, args[i]) >> CFILE + sep = ", "; + } + printf("%sreplyp));\n", sep) >> CFILE + } + printf("out:\n") >> CFILE + for (i = 0; i < nvars; ++i) { + if (rpc_type[i] == "LIST") { + printf("\t__dbcl_%s_%sfree(&req.%slist);\n", \ + name, args[i], args[i]) >> CFILE + } + } + printf("\treturn (ret);\n") >> CFILE + printf("}\n\n") >> CFILE + + # + # If we are doing a list, write list functions for op. + # + for (i = 0; i < nvars; i++) { + if (rpc_type[i] != "LIST") + continue; + printf("int\n__dbcl_%s_%slist(locp, pp)\n", \ + name, args[i]) >> CFILE + printf("\t__%s_%slist **locp;\n", name, args[i]) >> CFILE + if (list_type[i] == "STRING") + printf("\t%s pp;\n{\n\t%s p;\n", \ + c_type[i], c_type[i]) >> CFILE + if (list_type[i] == "INT") + printf("\tu_int32_t *pp;\n{\n\tu_int32_t *p, *q;\n") \ + >> CFILE + if (list_type[i] == "ID") + printf("\t%s pp;\n{\n\t%s p;\n\tu_int32_t *q;\n", \ + c_type[i], c_type[i]) >> CFILE + + printf("\tint ret;\n") >> CFILE + printf("\t__%s_%slist *nl, **nlp;\n\n", name, args[i]) >> CFILE + printf("\t*locp = NULL;\n") >> CFILE + printf("\tif (pp == NULL)\n\t\treturn (0);\n") >> CFILE + printf("\tnlp = locp;\n") >> CFILE + printf("\tfor (p = pp; *p != 0; p++) {\n") >> CFILE + printf("\t\tif ((ret = __os_malloc(NULL, ") >> CFILE + printf("sizeof(*nl), NULL, nlp)) != 0)\n") >> CFILE + printf("\t\t\tgoto out;\n") >> CFILE + printf("\t\tnl = *nlp;\n") >> CFILE + printf("\t\tnl->next = NULL;\n") >> CFILE + printf("\t\tnl->ent.ent_val = NULL;\n") >> CFILE + printf("\t\tnl->ent.ent_len = 0;\n") >> CFILE + if (list_type[i] == "STRING") { + printf("\t\tif ((ret = __os_strdup(NULL, ") >> CFILE + printf("*p, &nl->ent.ent_val)) != 0)\n") >> CFILE + printf("\t\t\tgoto out;\n") >> CFILE + printf("\t\tnl->ent.ent_len = strlen(*p)+1;\n") >> CFILE + } + if (list_type[i] == "INT") { + printf("\t\tif ((ret = __os_malloc(NULL, ") >> CFILE + printf("sizeof(%s), NULL, &nl->ent.ent_val)) != 0)\n", \ + c_type[i]) >> CFILE + printf("\t\t\tgoto out;\n") >> CFILE + printf("\t\tq = (u_int32_t *)nl->ent.ent_val;\n") \ + >> CFILE + printf("\t\t*q = *p;\n") >> CFILE + printf("\t\tnl->ent.ent_len = sizeof(%s);\n", \ + c_type[i]) >> CFILE + } + if (list_type[i] == "ID") { + printf("\t\tif ((ret = __os_malloc(NULL, ") >> CFILE + printf("sizeof(u_int32_t),") >> CFILE + printf(" NULL, &nl->ent.ent_val)) != 0)\n") >> CFILE + printf("\t\t\tgoto out;\n") >> CFILE + printf("\t\tq = (u_int32_t *)nl->ent.ent_val;\n") \ + >> CFILE + printf("\t\t*q = (*p)->cl_id;\n") >> CFILE + printf("\t\tnl->ent.ent_len = sizeof(u_int32_t);\n") \ + >> CFILE + } + printf("\t\tnlp = &nl->next;\n") >> CFILE + printf("\t}\n") >> CFILE + printf("\treturn (0);\n") >> CFILE + printf("out:\n") >> CFILE + printf("\t__dbcl_%s_%sfree(locp);\n", name, args[i]) >> CFILE + printf("\treturn (ret);\n") >> CFILE + + printf("}\n\n") >> CFILE + + printf("void\n__dbcl_%s_%sfree(locp)\n", name, args[i]) >> CFILE + printf("\t__%s_%slist **locp;\n", name, args[i]) >> CFILE + printf("{\n") >> CFILE + printf("\t__%s_%slist *nl, *nl1;\n\n", name, args[i]) >> CFILE + printf("\tif (locp == NULL)\n\t\treturn;\n") >> CFILE + printf("\tfor (nl = *locp; nl != NULL; nl = nl1) {\n") >> CFILE + printf("\t\tnl1 = nl->next;\n") >> CFILE + printf("\t\tif (nl->ent.ent_val)\n") >> CFILE + printf("\t\t\t__os_free(nl->ent.ent_val, nl->ent.ent_len);\n") \ + >> CFILE + printf("\t\t__os_free(nl, sizeof(*nl));\n") >> CFILE + printf("\t}\n}\n\n") >> CFILE + } + # + # Generate Client Template code + # + if (ret_code) { + # + # If we are doing a list, write prototypes + # + for (i = 0; i < rvars; ++i) { + if (ret_type[i] != "LIST") + continue; + if (retlist_type[i] != "STRING" && + retlist_type[i] != "INT" && list_type[i] != "ID") + continue; + printf("int __db_%s_%sreplist __P((", \ + name, retargs[i]) >> TFILE + printf("__%s_%sreplist, ", \ + name, retargs[i]) >> TFILE + if (retlist_type[i] == "STRING") { + printf("char ***));\n") >> TFILE + } + if (retlist_type[i] == "INT" || + retlist_type[i] == "ID") { + printf("u_int32_t **));\n") >> TFILE + } + printf("void __db_%s_%sfree __P((", \ + name, retargs[i]) >> TFILE + if (retlist_type[i] == "STRING") + printf("char **));\n") >> TFILE + if (retlist_type[i] == "INT" || retlist_type[i] == "ID") + printf("u_int32_t *));\n\n") >> TFILE + } + + printf("int __dbcl_%s_ret __P((", name) >> CHFILE + sep = ""; + for (i = 0; i < nvars; ++i) { + printf("%s%s", sep, pr_type[i]) >> CHFILE + sep = ", "; + } + printf("%s__%s_reply *));\n", sep, name) >> CHFILE + + printf("int\n") >> TFILE + printf("__dbcl_%s_ret(", name) >> TFILE + sep = ""; + for (i = 0; i < nvars; ++i) { + printf("%s%s", sep, args[i]) >> TFILE + sep = ", "; + } + printf("%sreplyp)\n",sep) >> TFILE + + for (i = 0; i < nvars; ++i) + if (func_arg[i] == 0) + printf("\t%s %s;\n", c_type[i], args[i]) \ + >> TFILE + else + printf("\t%s;\n", c_type[i]) >> TFILE + printf("\t__%s_reply *replyp;\n", name) >> TFILE; + printf("{\n") >> TFILE + printf("\tint ret;\n") >> TFILE + # + # Local vars in template + # + for (i = 0; i < rvars; ++i) { + if (ret_type[i] == "ID" || ret_type[i] == "STRING" || + ret_type[i] == "INT" || ret_type[i] == "DBL") { + printf("\t%s %s;\n", \ + retc_type[i], retargs[i]) >> TFILE + } else if (ret_type[i] == "LIST") { + if (retlist_type[i] == "STRING") + printf("\tchar **__db_%slist;\n", \ + retargs[i]) >> TFILE + if (retlist_type[i] == "ID" || + retlist_type[i] == "INT") + printf("\tu_int32_t *__db_%slist;\n", \ + retargs[i]) >> TFILE + } else { + printf("\t/* %s %s; */\n", \ + ret_type[i], retargs[i]) >> TFILE + } + } + # + # Client return code + # + printf("\n") >> TFILE + printf("\tif (replyp->status != 0)\n") >> TFILE + printf("\t\treturn (replyp->status);\n") >> TFILE + for (i = 0; i < rvars; ++i) { + varname = ""; + if (ret_type[i] == "ID") { + varname = sprintf("%scl_id", retargs[i]); + } + if (ret_type[i] == "STRING") { + varname = retargs[i]; + } + if (ret_type[i] == "INT" || ret_type[i] == "DBL") { + varname = retargs[i]; + } + if (ret_type[i] == "DBT") { + varname = sprintf("%sdata", retargs[i]); + } + if (ret_type[i] == "ID" || ret_type[i] == "STRING" || + ret_type[i] == "INT" || ret_type[i] == "DBL") { + printf("\t%s = replyp->%s;\n", \ + retargs[i], varname) >> TFILE + } else if (ret_type[i] == "LIST") { + printf("\n\tif ((ret = __db_%s_%slist(", \ + name, retargs[i]) >> TFILE + printf("replyp->%slist, &__db_%slist)) != 0)", \ + retargs[i], retargs[i]) >> TFILE + printf("\n\t\treturn (ret);\n") >> TFILE + printf("\n\t/*\n") >> TFILE + printf("\t * XXX Handle list\n") >> TFILE + printf("\t */\n\n") >> TFILE + printf("\t__db_%s_%sfree(__db_%slist);\n", \ + name, retargs[i], retargs[i]) >> TFILE + } else { + printf("\t/* Handle replyp->%s; */\n", \ + varname) >> TFILE + } + } + printf("\n\t/*\n\t * XXX Code goes here\n\t */\n\n") >> TFILE + printf("\treturn (replyp->status);\n") >> TFILE + printf("}\n\n") >> TFILE + # + # If we are doing a list, write list functions for this op. + # + for (i = 0; i < rvars; ++i) { + if (ret_type[i] != "LIST") + continue; + if (retlist_type[i] != "STRING" && + retlist_type[i] != "INT" && list_type[i] != "ID") + continue; + printf("int\n") >> TFILE + printf("__db_%s_%sreplist(locp, ppp)\n", \ + name, retargs[i]) >> TFILE + printf("\t__%s_%sreplist *locp;\n", \ + name, retargs[i]) >> TFILE + if (retlist_type[i] == "STRING") { + printf("\tchar ***ppp;\n{\n") >> TFILE + printf("\tchar **pp;\n") >> TFILE + } + if (retlist_type[i] == "INT" || + retlist_type[i] == "ID") { + printf("\tu_int32_t **ppp;\n{\n") >> TFILE + printf("\tu_int32_t *pp;\n") >> TFILE + } + + printf("\tint cnt, ret, size;\n") >> TFILE + printf("\t__%s_%sreplist *nl;\n\n", \ + name, retargs[i]) >> TFILE + printf("\tfor (cnt = 0, nl = locp; ") >> TFILE + printf("nl != NULL; cnt++, nl = nl->next)\n\t\t;\n\n") \ + >> TFILE + printf("\tif (cnt == 0) {\n") >> TFILE + printf("\t\t*ppp = NULL;\n") >> TFILE + printf("\t\treturn (0);\n\t}\n") >> TFILE + printf("\tsize = sizeof(*pp) * cnt;\n") >> TFILE + printf("\tif ((ret = __os_malloc(NULL, ") >> TFILE + printf("size, NULL, ppp)) != 0)\n") >> TFILE + printf("\t\treturn (ret);\n") >> TFILE + printf("\tmemset(*ppp, 0, size);\n") >> TFILE + printf("\tfor (pp = *ppp, nl = locp; ") >> TFILE + printf("nl != NULL; nl = nl->next, pp++) {\n") >> TFILE + if (retlist_type[i] == "STRING") { + printf("\t\tif ((ret = __os_malloc(NULL, ") \ + >> TFILE + printf("nl->ent.ent_len + 1, NULL,") >> TFILE + printf(" pp)) != 0)\n") >> TFILE + printf("\t\t\tgoto out;\n") >> TFILE + printf("\t\tif ((ret = __os_strdup(") >> TFILE + printf("NULL, (char *)nl->ent.ent_val,") \ + >> TFILE + printf(" pp)) != 0)\n") >> TFILE + printf("\t\t\tgoto out;\n") >> TFILE + } + if (retlist_type[i] == "INT" || + retlist_type[i] == "ID") { + printf("\t\t*pp = *(u_int32_t *)") >> TFILE + printf("nl->ent.ent_val;\n") >> TFILE + } + printf("\t}\n") >> TFILE + printf("\treturn (0);\n") >> TFILE + printf("out:\n") >> TFILE + printf("\t__db_%s_%sfree(*ppp);\n", \ + name, retargs[i]) >> TFILE + printf("\treturn (ret);\n") >> TFILE + printf("}\n\n") >> TFILE + + printf("void\n") >> TFILE + printf("__db_%s_%sfree(pp)\n", \ + name, retargs[i]) >> TFILE + + if (retlist_type[i] == "STRING") + printf("\tchar **pp;\n") >> TFILE + if (retlist_type[i] == "INT" || retlist_type[i] == "ID") + printf("\tu_int32_t *pp;\n") >> TFILE + + printf("{\n") >> TFILE + printf("\tsize_t size;\n") >> TFILE + + if (retlist_type[i] == "STRING") + printf("\tchar **p;\n\n") >> TFILE + if (retlist_type[i] == "INT" || retlist_type[i] == "ID") + printf("\tu_int32_t *p;\n\n") >> TFILE + + printf("\tif (pp == NULL)\n\t\treturn;\n") >> TFILE + printf("\tsize = sizeof(*p);\n") >> TFILE + printf("\tfor (p = pp; *p != 0; p++) {\n") >> TFILE + printf("\t\tsize += sizeof(*p);\n") >> TFILE + + if (retlist_type[i] == "STRING") + printf("\t\t__os_free(*p, strlen(*p)+1);\n") \ + >> TFILE + printf("\t}\n") >> TFILE + printf("\t__os_free(pp, size);\n") >> TFILE + printf("}\n\n") >> TFILE + } + } +} + +# +# split_lines -- +# Add line separators to pretty-print the output. +function split_lines(is_public) { + if (argcount > 3) { + # Reset the counter, remove any trailing whitespace from + # the separator. + argcount = 0; + sub("[ ]$", "", sep) + + if (is_public) { + printf("%s\n\t", sep) >> SHFILE + } else { + printf("%s\n\t\t", sep) >> PFILE + printf("%s\\\n\\\t\\\t", sep) >> SEDFILE + } + } +} diff --git a/db/dist/install-sh b/db/dist/install-sh new file mode 100755 index 000000000..b41a24591 --- /dev/null +++ b/db/dist/install-sh @@ -0,0 +1,251 @@ +#!/bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5 (mit/util/scripts/install.sh). +# +# Copyright 1991 by the Massachusetts Institute of Technology +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation, and that the name of M.I.T. not be used in advertising or +# publicity pertaining to distribution of the software without specific, +# written prior permission. M.I.T. makes no representations about the +# suitability of this software for any purpose. It is provided "as is" +# without express or implied warranty. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + chmodcmd="" + else + instcmd=$mkdirprog + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' + ' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/db/dist/ltconfig b/db/dist/ltconfig new file mode 100644 index 000000000..f78afda0e --- /dev/null +++ b/db/dist/ltconfig @@ -0,0 +1,3136 @@ +#! /bin/sh + +# ltconfig - Create a system-specific libtool. +# Copyright (C) 1996-1999 Free Software Foundation, Inc. +# Originally by Gordon Matzigkeit , 1996 +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# A lot of this script is taken from autoconf-2.10. + +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} +echo=echo +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then + # Yippee, $echo works! + : +else + # Restart under the correct shell. + exec "$SHELL" "$0" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat </dev/null`} + case X$UNAME in + *-DOS) PATH_SEPARATOR=';' ;; + *) PATH_SEPARATOR=':' ;; + esac +fi + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +if test "X${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi + +if test "X${echo_test_string+set}" != Xset; then + # find a string as large as possible, as long as the shell can cope with it + for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do + # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... + if (echo_test_string="`eval $cmd`") 2>/dev/null && + echo_test_string="`eval $cmd`" && + (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null; then + break + fi + done +fi + +if test "X`($echo '\t') 2>/dev/null`" != 'X\t' || + test "X`($echo "$echo_test_string") 2>/dev/null`" != X"$echo_test_string"; then + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" + for dir in $PATH /usr/ucb; do + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + test "X`($dir/echo "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then + echo="$dir/echo" + break + fi + done + IFS="$save_ifs" + + if test "X$echo" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && + test "X`(print -r "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + echo='print -r' + elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running ltconfig again with it. + ORIGINAL_CONFIG_SHELL="${CONFIG_SHELL-/bin/sh}" + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" --no-reexec ${1+"$@"} + else + # Try using printf. + echo='printf "%s\n"' + if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + test "X`($echo "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then + # Cool, printf works + : + elif test "X`("$ORIGINAL_CONFIG_SHELL" "$0" --fallback-echo '\t') 2>/dev/null`" = 'X\t' && + test "X`("$ORIGINAL_CONFIG_SHELL" "$0" --fallback-echo "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then + CONFIG_SHELL="$ORIGINAL_CONFIG_SHELL" + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + echo="$CONFIG_SHELL $0 --fallback-echo" + elif test "X`("$CONFIG_SHELL" "$0" --fallback-echo '\t') 2>/dev/null`" = 'X\t' && + test "X`("$CONFIG_SHELL" "$0" --fallback-echo "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then + echo="$CONFIG_SHELL $0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do + if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null; then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "$0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec "${ORIGINAL_CONFIG_SHELL}" "$0" ${1+"$@"} + else + # Oops. We lost completely, so just stick with echo. + echo=echo + fi + fi + fi + fi +fi + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='sed -e s/^X//' +sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# The name of this program. +progname=`$echo "X$0" | $Xsed -e 's%^.*/%%'` + +# Constants: +PROGRAM=ltconfig +PACKAGE=libtool +VERSION=1.3.5 +TIMESTAMP=" (1.385.2.206 2000/05/27 11:12:27)" +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +rm="rm -f" + +help="Try \`$progname --help' for more information." + +# Global variables: +default_ofile=libtool +can_build_shared=yes +enable_shared=yes +# All known linkers require a `.a' archive for static linking (except M$VC, +# which needs '.lib'). +enable_static=yes +enable_fast_install=yes +enable_dlopen=unknown +enable_win32_dll=no +ltmain= +silent= +srcdir= +ac_config_guess= +ac_config_sub= +host= +nonopt= +ofile="$default_ofile" +verify_host=yes +with_gcc=no +with_gnu_ld=no +need_locks=yes +ac_ext=c +objext=o +libext=a +exeext= +cache_file= + +old_AR="$AR" +old_CC="$CC" +old_CFLAGS="$CFLAGS" +old_CPPFLAGS="$CPPFLAGS" +old_LDFLAGS="$LDFLAGS" +old_LD="$LD" +old_LN_S="$LN_S" +old_LIBS="$LIBS" +old_NM="$NM" +old_RANLIB="$RANLIB" +old_DLLTOOL="$DLLTOOL" +old_OBJDUMP="$OBJDUMP" +old_AS="$AS" + +# Parse the command line options. +args= +prev= +for option +do + case "$option" in + -*=*) optarg=`echo "$option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + eval "$prev=\$option" + prev= + continue + fi + + case "$option" in + --help) cat <&2 + echo "$help" 1>&2 + exit 1 + ;; + + *) + if test -z "$ltmain"; then + ltmain="$option" + elif test -z "$host"; then +# This generates an unnecessary warning for sparc-sun-solaris4.1.3_U1 +# if test -n "`echo $option| sed 's/[-a-z0-9.]//g'`"; then +# echo "$progname: warning \`$option' is not a valid host type" 1>&2 +# fi + host="$option" + else + echo "$progname: too many arguments" 1>&2 + echo "$help" 1>&2 + exit 1 + fi ;; + esac +done + +if test -z "$ltmain"; then + echo "$progname: you must specify a LTMAIN file" 1>&2 + echo "$help" 1>&2 + exit 1 +fi + +if test ! -f "$ltmain"; then + echo "$progname: \`$ltmain' does not exist" 1>&2 + echo "$help" 1>&2 + exit 1 +fi + +# Quote any args containing shell metacharacters. +ltconfig_args= +for arg +do + case "$arg" in + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ltconfig_args="$ltconfig_args '$arg'" ;; + *) ltconfig_args="$ltconfig_args $arg" ;; + esac +done + +# A relevant subset of AC_INIT. + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 5 compiler messages saved in config.log +# 6 checking for... messages and results +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>>./config.log + +# NLS nuisances. +# Only set LANG and LC_ALL to C if already set. +# These must not be set unconditionally because not all systems understand +# e.g. LANG=C (notably SCO). +if test "X${LC_ALL+set}" = Xset; then LC_ALL=C; export LC_ALL; fi +if test "X${LANG+set}" = Xset; then LANG=C; export LANG; fi + +if test -n "$cache_file" && test -r "$cache_file"; then + echo "loading cache $cache_file within ltconfig" + . $cache_file +fi + +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + +if test -z "$srcdir"; then + # Assume the source directory is the same one as the path to LTMAIN. + srcdir=`$echo "X$ltmain" | $Xsed -e 's%/[^/]*$%%'` + test "$srcdir" = "$ltmain" && srcdir=. +fi + +trap "$rm conftest*; exit 1" 1 2 15 +if test "$verify_host" = yes; then + # Check for config.guess and config.sub. + ac_aux_dir= + for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/config.guess; then + ac_aux_dir=$ac_dir + break + fi + done + if test -z "$ac_aux_dir"; then + echo "$progname: cannot find config.guess in $srcdir $srcdir/.. $srcdir/../.." 1>&2 + echo "$help" 1>&2 + exit 1 + fi + ac_config_guess=$ac_aux_dir/config.guess + ac_config_sub=$ac_aux_dir/config.sub + + # Make sure we can run config.sub. + if $SHELL $ac_config_sub sun4 >/dev/null 2>&1; then : + else + echo "$progname: cannot run $ac_config_sub" 1>&2 + echo "$help" 1>&2 + exit 1 + fi + + echo $ac_n "checking host system type""... $ac_c" 1>&6 + + host_alias=$host + case "$host_alias" in + "") + if host_alias=`$SHELL $ac_config_guess`; then : + else + echo "$progname: cannot guess host type; you must specify one" 1>&2 + echo "$help" 1>&2 + exit 1 + fi ;; + esac + host=`$SHELL $ac_config_sub $host_alias` + echo "$ac_t$host" 1>&6 + + # Make sure the host verified. + test -z "$host" && exit 1 + +elif test -z "$host"; then + echo "$progname: you must specify a host type if you use \`--no-verify'" 1>&2 + echo "$help" 1>&2 + exit 1 +else + host_alias=$host +fi + +# Transform linux* to *-*-linux-gnu*, to support old configure scripts. +case "$host_os" in +linux-gnu*) ;; +linux*) host=`echo $host | sed 's/^\(.*-.*-linux\)\(.*\)$/\1-gnu\2/'` +esac + +host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + +case "$host_os" in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR cru $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +# Set a sane default for `AR'. +test -z "$AR" && AR=ar + +# Set a sane default for `OBJDUMP'. +test -z "$OBJDUMP" && OBJDUMP=objdump + +# If RANLIB is not set, then run the test. +if test "${RANLIB+set}" != "set"; then + result=no + + echo $ac_n "checking for ranlib... $ac_c" 1>&6 + IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" + for dir in $PATH; do + test -z "$dir" && dir=. + if test -f $dir/ranlib || test -f $dir/ranlib$ac_exeext; then + RANLIB="ranlib" + result="ranlib" + break + fi + done + IFS="$save_ifs" + + echo "$ac_t$result" 1>&6 +fi + +if test -n "$RANLIB"; then + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" + old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds" +fi + +# Set sane defaults for `DLLTOOL', `OBJDUMP', and `AS', used on cygwin. +test -z "$DLLTOOL" && DLLTOOL=dlltool +test -z "$OBJDUMP" && OBJDUMP=objdump +test -z "$AS" && AS=as + +# Check to see if we are using GCC. +if test "$with_gcc" != yes || test -z "$CC"; then + # If CC is not set, then try to find GCC or a usable CC. + if test -z "$CC"; then + echo $ac_n "checking for gcc... $ac_c" 1>&6 + IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" + for dir in $PATH; do + test -z "$dir" && dir=. + if test -f $dir/gcc || test -f $dir/gcc$ac_exeext; then + CC="gcc" + break + fi + done + IFS="$save_ifs" + + if test -n "$CC"; then + echo "$ac_t$CC" 1>&6 + else + echo "$ac_t"no 1>&6 + fi + fi + + # Not "gcc", so try "cc", rejecting "/usr/ucb/cc". + if test -z "$CC"; then + echo $ac_n "checking for cc... $ac_c" 1>&6 + IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" + cc_rejected=no + for dir in $PATH; do + test -z "$dir" && dir=. + if test -f $dir/cc || test -f $dir/cc$ac_exeext; then + if test "$dir/cc" = "/usr/ucb/cc"; then + cc_rejected=yes + continue + fi + CC="cc" + break + fi + done + IFS="$save_ifs" + if test $cc_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same name, so the bogon will be chosen + # first if we set CC to just the name; use the full file name. + shift + set dummy "$dir/cc" "$@" + shift + CC="$@" + fi + fi + + if test -n "$CC"; then + echo "$ac_t$CC" 1>&6 + else + echo "$ac_t"no 1>&6 + fi + + if test -z "$CC"; then + echo "$progname: error: no acceptable cc found in \$PATH" 1>&2 + exit 1 + fi + fi + + # Now see if the compiler is really GCC. + with_gcc=no + echo $ac_n "checking whether we are using GNU C... $ac_c" 1>&6 + echo "$progname:581: checking whether we are using GNU C" >&5 + + $rm conftest.c + cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + with_gcc=yes + fi + $rm conftest.c + echo "$ac_t$with_gcc" 1>&6 +fi + +# Allow CC to be a program name with arguments. +set dummy $CC +compiler="$2" + +echo $ac_n "checking for object suffix... $ac_c" 1>&6 +$rm conftest* +echo 'int i = 1;' > conftest.c +echo "$progname:603: checking for object suffix" >& 5 +if { (eval echo $progname:604: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; }; then + # Append any warnings to the config.log. + cat conftest.err 1>&5 + + for ac_file in conftest.*; do + case $ac_file in + *.c) ;; + *) objext=`echo $ac_file | sed -e s/conftest.//` ;; + esac + done +else + cat conftest.err 1>&5 + echo "$progname: failed program was:" >&5 + cat conftest.c >&5 +fi +$rm conftest* +echo "$ac_t$objext" 1>&6 + +echo $ac_n "checking for executable suffix... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_exeext'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_cv_exeext="no" + $rm conftest* + echo 'main () { return 0; }' > conftest.c + echo "$progname:629: checking for executable suffix" >& 5 + if { (eval echo $progname:630: \"$ac_link\") 1>&5; (eval $ac_link) 2>conftest.err; }; then + # Append any warnings to the config.log. + cat conftest.err 1>&5 + + for ac_file in conftest.*; do + case $ac_file in + *.c | *.err | *.$objext ) ;; + *) ac_cv_exeext=.`echo $ac_file | sed -e s/conftest.//` ;; + esac + done + else + cat conftest.err 1>&5 + echo "$progname: failed program was:" >&5 + cat conftest.c >&5 + fi + $rm conftest* +fi +if test "X$ac_cv_exeext" = Xno; then + exeext="" +else + exeext="$ac_cv_exeext" +fi +echo "$ac_t$ac_cv_exeext" 1>&6 + +echo $ac_n "checking for $compiler option to produce PIC... $ac_c" 1>&6 +pic_flag= +special_shlib_compile_flags= +wl= +link_static_flag= +no_builtin_flag= + +if test "$with_gcc" = yes; then + wl='-Wl,' + link_static_flag='-static' + + case "$host_os" in + beos* | irix5* | irix6* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + aix*) + # Below there is a dirty hack to force normal static linking with -ldl + # The problem is because libdl dynamically linked with both libc and + # libC (AIX C++ library), which obviously doesn't included in libraries + # list by gcc. This cause undefined symbols with -static flags. + # This hack allows C programs to be linked with "-static -ldl", but + # we not sure about C++ programs. + link_static_flag="$link_static_flag ${wl}-lC" + ;; + cygwin* | mingw* | os2*) + # We can build DLLs from non-PIC. + ;; + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + pic_flag='-m68020 -resident32 -malways-restore-a4' + ;; + sysv4*MP*) + if test -d /usr/nec; then + pic_flag=-Kconform_pic + fi + ;; + *) + pic_flag='-fPIC' + ;; + esac +else + # PORTME Check for PIC flags for the system compiler. + case "$host_os" in + aix3* | aix4*) + # All AIX code is PIC. + link_static_flag='-bnso -bI:/lib/syscalls.exp' + ;; + + hpux9* | hpux10* | hpux11*) + # Is there a better link_static_flag that works with the bundled CC? + wl='-Wl,' + link_static_flag="${wl}-a ${wl}archive" + pic_flag='+Z' + ;; + + irix5* | irix6*) + wl='-Wl,' + link_static_flag='-non_shared' + # PIC (with -KPIC) is the default. + ;; + + cygwin* | mingw* | os2*) + # We can build DLLs from non-PIC. + ;; + + osf3* | osf4* | osf5*) + # All OSF/1 code is PIC. + wl='-Wl,' + link_static_flag='-non_shared' + ;; + + sco3.2v5*) + pic_flag='-Kpic' + link_static_flag='-dn' + special_shlib_compile_flags='-belf' + ;; + + solaris*) + pic_flag='-KPIC' + link_static_flag='-Bstatic' + wl='-Wl,' + ;; + + sunos4*) + pic_flag='-PIC' + link_static_flag='-Bstatic' + wl='-Qoption ld ' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + pic_flag='-KPIC' + link_static_flag='-Bstatic' + wl='-Wl,' + ;; + + uts4*) + pic_flag='-pic' + link_static_flag='-Bstatic' + ;; + sysv4*MP*) + if test -d /usr/nec ;then + pic_flag='-Kconform_pic' + link_static_flag='-Bstatic' + fi + ;; + *) + can_build_shared=no + ;; + esac +fi + +if test -n "$pic_flag"; then + echo "$ac_t$pic_flag" 1>&6 + + # Check to make sure the pic_flag actually works. + echo $ac_n "checking if $compiler PIC flag $pic_flag works... $ac_c" 1>&6 + $rm conftest* + echo "int some_variable = 0;" > conftest.c + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $pic_flag -DPIC" + echo "$progname:776: checking if $compiler PIC flag $pic_flag works" >&5 + if { (eval echo $progname:777: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; } && test -s conftest.$objext; then + # Append any warnings to the config.log. + cat conftest.err 1>&5 + + case "$host_os" in + hpux9* | hpux10* | hpux11*) + # On HP-UX, both CC and GCC only warn that PIC is supported... then they + # create non-PIC objects. So, if there were any warnings, we assume that + # PIC is not supported. + if test -s conftest.err; then + echo "$ac_t"no 1>&6 + can_build_shared=no + pic_flag= + else + echo "$ac_t"yes 1>&6 + pic_flag=" $pic_flag" + fi + ;; + *) + echo "$ac_t"yes 1>&6 + pic_flag=" $pic_flag" + ;; + esac + else + # Append any errors to the config.log. + cat conftest.err 1>&5 + can_build_shared=no + pic_flag= + echo "$ac_t"no 1>&6 + fi + CFLAGS="$save_CFLAGS" + $rm conftest* +else + echo "$ac_t"none 1>&6 +fi + +# Check to see if options -o and -c are simultaneously supported by compiler +echo $ac_n "checking if $compiler supports -c -o file.o... $ac_c" 1>&6 +$rm -r conftest 2>/dev/null +mkdir conftest +cd conftest +$rm conftest* +echo "int some_variable = 0;" > conftest.c +mkdir out +# According to Tom Tromey, Ian Lance Taylor reported there are C compilers +# that will create temporary files in the current directory regardless of +# the output directory. Thus, making CWD read-only will cause this test +# to fail, enabling locking or at least warning the user not to do parallel +# builds. +chmod -w . +save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -o out/conftest2.o" +echo "$progname:829: checking if $compiler supports -c -o file.o" >&5 +if { (eval echo $progname:830: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.o; then + + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s out/conftest.err; then + echo "$ac_t"no 1>&6 + compiler_c_o=no + else + echo "$ac_t"yes 1>&6 + compiler_c_o=yes + fi +else + # Append any errors to the config.log. + cat out/conftest.err 1>&5 + compiler_c_o=no + echo "$ac_t"no 1>&6 +fi +CFLAGS="$save_CFLAGS" +chmod u+w . +$rm conftest* out/* +rmdir out +cd .. +rmdir conftest +$rm -r conftest 2>/dev/null + +if test x"$compiler_c_o" = x"yes"; then + # Check to see if we can write to a .lo + echo $ac_n "checking if $compiler supports -c -o file.lo... $ac_c" 1>&6 + $rm conftest* + echo "int some_variable = 0;" > conftest.c + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -c -o conftest.lo" + echo "$progname:862: checking if $compiler supports -c -o file.lo" >&5 +if { (eval echo $progname:863: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; } && test -s conftest.lo; then + + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + echo "$ac_t"no 1>&6 + compiler_o_lo=no + else + echo "$ac_t"yes 1>&6 + compiler_o_lo=yes + fi + else + # Append any errors to the config.log. + cat conftest.err 1>&5 + compiler_o_lo=no + echo "$ac_t"no 1>&6 + fi + CFLAGS="$save_CFLAGS" + $rm conftest* +else + compiler_o_lo=no +fi + +# Check to see if we can do hard links to lock some files if needed +hard_links="nottested" +if test "$compiler_c_o" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + echo $ac_n "checking if we can lock with hard links... $ac_c" 1>&6 + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + echo "$ac_t$hard_links" 1>&6 + $rm conftest* + if test "$hard_links" = no; then + echo "*** WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2 + need_locks=warn + fi +else + need_locks=no +fi + +if test "$with_gcc" = yes; then + # Check to see if options -fno-rtti -fno-exceptions are supported by compiler + echo $ac_n "checking if $compiler supports -fno-rtti -fno-exceptions ... $ac_c" 1>&6 + $rm conftest* + echo "int some_variable = 0;" > conftest.c + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -fno-rtti -fno-exceptions -c conftest.c" + echo "$progname:914: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 + if { (eval echo $progname:915: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; } && test -s conftest.o; then + + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + echo "$ac_t"no 1>&6 + compiler_rtti_exceptions=no + else + echo "$ac_t"yes 1>&6 + compiler_rtti_exceptions=yes + fi + else + # Append any errors to the config.log. + cat conftest.err 1>&5 + compiler_rtti_exceptions=no + echo "$ac_t"no 1>&6 + fi + CFLAGS="$save_CFLAGS" + $rm conftest* + + if test "$compiler_rtti_exceptions" = "yes"; then + no_builtin_flag=' -fno-builtin -fno-rtti -fno-exceptions' + else + no_builtin_flag=' -fno-builtin' + fi + +fi + +# Check for any special shared library compilation flags. +if test -n "$special_shlib_compile_flags"; then + echo "$progname: warning: \`$CC' requires \`$special_shlib_compile_flags' to build shared libraries" 1>&2 + if echo "$old_CC $old_CFLAGS " | egrep -e "[ ]$special_shlib_compile_flags[ ]" >/dev/null; then : + else + echo "$progname: add \`$special_shlib_compile_flags' to the CC or CFLAGS env variable and reconfigure" 1>&2 + can_build_shared=no + fi +fi + +echo $ac_n "checking if $compiler static flag $link_static_flag works... $ac_c" 1>&6 +$rm conftest* +echo 'main(){return(0);}' > conftest.c +save_LDFLAGS="$LDFLAGS" +LDFLAGS="$LDFLAGS $link_static_flag" +echo "$progname:958: checking if $compiler static flag $link_static_flag works" >&5 +if { (eval echo $progname:959: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + echo "$ac_t$link_static_flag" 1>&6 +else + echo "$ac_t"none 1>&6 + link_static_flag= +fi +LDFLAGS="$save_LDFLAGS" +$rm conftest* + +if test -z "$LN_S"; then + # Check to see if we can use ln -s, or we need hard links. + echo $ac_n "checking whether ln -s works... $ac_c" 1>&6 + $rm conftest.dat + if ln -s X conftest.dat 2>/dev/null; then + $rm conftest.dat + LN_S="ln -s" + else + LN_S=ln + fi + if test "$LN_S" = "ln -s"; then + echo "$ac_t"yes 1>&6 + else + echo "$ac_t"no 1>&6 + fi +fi + +# Make sure LD is an absolute path. +if test -z "$LD"; then + ac_prog=ld + if test "$with_gcc" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + echo $ac_n "checking for ld used by GCC... $ac_c" 1>&6 + echo "$progname:991: checking for ld used by GCC" >&5 + ac_prog=`($CC -print-prog-name=ld) 2>&5` + case "$ac_prog" in + # Accept absolute paths. + [\\/]* | [A-Za-z]:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the path of ld + ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we are not using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac + elif test "$with_gnu_ld" = yes; then + echo $ac_n "checking for GNU ld... $ac_c" 1>&6 + echo "$progname:1015: checking for GNU ld" >&5 + else + echo $ac_n "checking for non-GNU ld""... $ac_c" 1>&6 + echo "$progname:1018: checking for non-GNU ld" >&5 + fi + + if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + if "$LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then + test "$with_gnu_ld" != no && break + else + test "$with_gnu_ld" != yes && break + fi + fi + done + IFS="$ac_save_ifs" + fi + + if test -n "$LD"; then + echo "$ac_t$LD" 1>&6 + else + echo "$ac_t"no 1>&6 + fi + + if test -z "$LD"; then + echo "$progname: error: no acceptable ld found in \$PATH" 1>&2 + exit 1 + fi +fi + +# Check to see if it really is or is not GNU ld. +echo $ac_n "checking if the linker ($LD) is GNU ld... $ac_c" 1>&6 +# I'd rather use --version here, but apparently some GNU ld's only accept -v. +if $LD -v 2>&1 &5; then + with_gnu_ld=yes +else + with_gnu_ld=no +fi +echo "$ac_t$with_gnu_ld" 1>&6 + +# See if the linker supports building shared libraries. +echo $ac_n "checking whether the linker ($LD) supports shared libraries... $ac_c" 1>&6 + +allow_undefined_flag= +no_undefined_flag= +need_lib_prefix=unknown +need_version=unknown +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +archive_cmds= +archive_expsym_cmds= +old_archive_from_new_cmds= +export_dynamic_flag_spec= +whole_archive_flag_spec= +thread_safe_flag_spec= +hardcode_libdir_flag_spec= +hardcode_libdir_separator= +hardcode_direct=no +hardcode_minus_L=no +hardcode_shlibpath_var=unsupported +runpath_var= +always_export_symbols=no +export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | sed '\''s/.* //'\'' | sort | uniq > $export_symbols' +# include_expsyms should be a list of space-separated symbols to be *always* +# included in the symbol list +include_expsyms= +# exclude_expsyms can be an egrep regular expression of symbols to exclude +# it will be wrapped by ` (' and `)$', so one must not match beginning or +# end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', +# as well as any symbol that contains `d'. +exclude_expsyms="_GLOBAL_OFFSET_TABLE_" +# Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out +# platforms (ab)use it in PIC code, but their linkers get confused if +# the symbol is explicitly referenced. Since portable code cannot +# rely on this symbol name, it's probably fine to never include it in +# preloaded symbol tables. + +case "$host_os" in +cygwin* | mingw*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$with_gcc" != yes; then + with_gnu_ld=no + fi + ;; + +esac + +ld_shlibs=yes +if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # See if GNU ld supports shared libraries. + case "$host_os" in + aix3* | aix4*) + # On AIX, the GNU linker is very broken + ld_shlibs=no + cat <&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +EOF + ;; + + amigaos*) + archive_cmds='$rm $objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $objdir/a2ixlibrary.data~$AR cru $lib $libobjs~$RANLIB $lib~(cd $objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we can use + # them. + ld_shlibs=no + ;; + + beos*) + if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds='$CC -nostart $libobjs $deplibs $linkopts ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs=no + fi + ;; + + cygwin* | mingw*) + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + allow_undefined_flag=unsupported + always_export_symbols=yes + + # Extract the symbol export list from an `--export-all' def file, + # then regenerate the def file from the symbol export list, so that + # the compiled dll only exports the symbol export list. + # Be careful not to strip the DATA tag left by newer dlltools. + export_symbols_cmds='test -f $objdir/$soname-ltdll.c || sed -e "/^# \/\* ltdll\.c starts here \*\//,/^# \/\* ltdll.c ends here \*\// { s/^# //; p; }" -e d < $0 > $objdir/$soname-ltdll.c~ + test -f $objdir/$soname-ltdll.$objext || (cd $objdir && $CC -c $soname-ltdll.c)~ + $DLLTOOL --export-all --exclude-symbols DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12 --output-def $objdir/$soname-def $objdir/$soname-ltdll.$objext $libobjs $convenience~ + sed -e "1,/EXPORTS/d" -e "s/ @ [0-9]*//" -e "s/ *;.*$//" < $objdir/$soname-def > $export_symbols' + + # If DATA tags from a recent dlltool are present, honour them! + archive_expsym_cmds='echo EXPORTS > $objdir/$soname-def~ + _lt_hint=1; + cat $export_symbols | while read symbol; do + set dummy \$symbol; + case \$# in + 2) echo " \$2 @ \$_lt_hint ; " >> $objdir/$soname-def;; + *) echo " \$2 @ \$_lt_hint \$3 ; " >> $objdir/$soname-def;; + esac; + _lt_hint=`expr 1 + \$_lt_hint`; + done~ + test -f $objdir/$soname-ltdll.c || sed -e "/^# \/\* ltdll\.c starts here \*\//,/^# \/\* ltdll.c ends here \*\// { s/^# //; p; }" -e d < $0 > $objdir/$soname-ltdll.c~ + test -f $objdir/$soname-ltdll.$objext || (cd $objdir && $CC -c $soname-ltdll.c)~ + $CC -Wl,--base-file,$objdir/$soname-base -Wl,--dll -nostartfiles -Wl,-e,__cygwin_dll_entry@12 -o $lib $objdir/$soname-ltdll.$objext $libobjs $deplibs $linkopts~ + $DLLTOOL --as=$AS --dllname $soname --exclude-symbols DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12 --def $objdir/$soname-def --base-file $objdir/$soname-base --output-exp $objdir/$soname-exp~ + $CC -Wl,--base-file,$objdir/$soname-base $objdir/$soname-exp -Wl,--dll -nostartfiles -Wl,-e,__cygwin_dll_entry@12 -o $lib $objdir/$soname-ltdll.$objext $libobjs $deplibs $linkopts~ + $DLLTOOL --as=$AS --dllname $soname --exclude-symbols DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12 --def $objdir/$soname-def --base-file $objdir/$soname-base --output-exp $objdir/$soname-exp~ + $CC $objdir/$soname-exp -Wl,--dll -nostartfiles -Wl,-e,__cygwin_dll_entry@12 -o $lib $objdir/$soname-ltdll.$objext $libobjs $deplibs $linkopts' + + old_archive_from_new_cmds='$DLLTOOL --as=$AS --dllname $soname --def $objdir/$soname-def --output-lib $objdir/$libname.a' + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + archive_cmds='$LD -Bshareable $libobjs $deplibs $linkopts -o $lib' + # can we support soname and/or expsyms with a.out? -oliva + fi + ;; + + solaris* | sysv5*) + if $LD -v 2>&1 | egrep 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + cat <&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +EOF + elif $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + + sunos4*) + archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linkopts' + wlarc= + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + *) + if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + + if test "$ld_shlibs" = yes; then + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec='${wl}--export-dynamic' + case $host_os in + cygwin* | mingw*) + # dlltool doesn't understand --whole-archive et. al. + whole_archive_flag_spec= + ;; + *) + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | egrep 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec= + fi + ;; + esac + fi +else + # PORTME fill in a description of your system's linker (not GNU ld) + case "$host_os" in + aix3*) + allow_undefined_flag=unsupported + always_export_symbols=yes + archive_expsym_cmds='$LD -o $objdir/$soname $libobjs $deplibs $linkopts -bE:$export_symbols -T512 -H512 -bM:SRE~$AR cru $lib $objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$with_gcc" = yes && test -z "$link_static_flag"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + + aix4*) + hardcode_libdir_flag_spec='${wl}-b ${wl}nolibpath ${wl}-b ${wl}libpath:$libdir:/usr/lib:/lib' + hardcode_libdir_separator=':' + if test "$with_gcc" = yes; then + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + hardcode_direct=yes + else + # We have old collect2 + hardcode_direct=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + shared_flag='-shared' + else + shared_flag='${wl}-bM:SRE' + hardcode_direct=yes + fi + allow_undefined_flag=' ${wl}-berok' + archive_cmds="\$CC $shared_flag"' -o $objdir/$soname $libobjs $deplibs $linkopts ${wl}-bexpall ${wl}-bnoentry${allow_undefined_flag}' + archive_expsym_cmds="\$CC $shared_flag"' -o $objdir/$soname $libobjs $deplibs $linkopts ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}' + #### local change for Sleepycat DB: + # On AIX 4.3.2 (at least), -bexpall exports too much, + # causing symbol conflicts. This was: + # case "$host_os" in aix4.[01]|aix4.[01].*) + case "$host_os" in aix4.*) + # According to Greg Wooledge, -bexpall is only supported from AIX 4.2 on + always_export_symbols=yes ;; + esac + ;; + + amigaos*) + archive_cmds='$rm $objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $objdir/a2ixlibrary.data~$AR cru $lib $libobjs~$RANLIB $lib~(cd $objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + # see comment about different semantics on the GNU ld section + ld_shlibs=no + ;; + + cygwin* | mingw*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $lib $libobjs $linkopts `echo "$deplibs" | sed -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_from_new_cmds='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds='lib /OUT:$oldlib$oldobjs' + fix_srcfile_path='`cygpath -w $srcfile`' + ;; + + freebsd1*) + ld_shlibs=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linkopts /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linkopts' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd*) + archive_cmds='$CC -shared -o $lib $libobjs $deplibs $linkopts' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + hpux9* | hpux10* | hpux11*) + case "$host_os" in + hpux9*) archive_cmds='$rm $objdir/$soname~$LD -b +b $install_libdir -o $objdir/$soname $libobjs $deplibs $linkopts~test $objdir/$soname = $lib || mv $objdir/$soname $lib' ;; + *) archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linkopts' ;; + esac + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + hardcode_minus_L=yes # Not in the search PATH, but as the default + # location of the library. + export_dynamic_flag_spec='${wl}-E' + ;; + + irix5* | irix6*) + if test "$with_gcc" = yes; then + archive_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' + else + archive_cmds='$LD -shared $libobjs $deplibs $linkopts -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' + fi + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linkopts' # a.out + else + archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linkopts' # ELF + fi + hardcode_libdir_flag_spec='${wl}-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + openbsd*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linkopts' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + archive_cmds='$echo "LIBRARY $libname INITINSTANCE" > $objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $objdir/$libname.def~$echo DATA >> $objdir/$libname.def~$echo " SINGLE NONSHARED" >> $objdir/$libname.def~$echo EXPORTS >> $objdir/$libname.def~emxexp $libobjs >> $objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $linkopts $objdir/$libname.def' + old_archive_from_new_cmds='emximp -o $objdir/$libname.a $objdir/$libname.def' + ;; + + osf3*) + if test "$with_gcc" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $linkopts ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linkopts -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' + fi + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + + osf4* | osf5*) # As osf3* with the addition of the -msym flag + if test "$with_gcc" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $linkopts ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linkopts -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' + fi + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + rhapsody*) + archive_cmds='$CC -bundle -undefined suppress -o $lib $libobjs $deplibs $linkopts' + hardcode_libdir_flags_spec='-L$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + sco3.2v5*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ;; + + solaris*) + no_undefined_flag=' -z text' + # $CC -shared without GNU ld will not create a library from C++ + # object files and a static libstdc++, better avoid it by now + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linkopts' + archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linkopts~$rm $lib.exp' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_shlibpath_var=no + case "$host_os" in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) # Supported since Solaris 2.6 (maybe 2.5.1?) + whole_archive_flag_spec='-z allextract$convenience -z defaultextract' ;; + esac + ;; + + sunos4*) + archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linkopts' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + sysv4) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $linkopts' + else + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts' + fi + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + + sysv4.3*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts' + hardcode_shlibpath_var=no + export_dynamic_flag_spec='-Bexport' + ;; + + sysv5*) + no_undefined_flag=' -z text' + # $CC -shared without GNU ld will not create a library from C++ + # object files and a static libstdc++, better avoid it by now + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linkopts' + archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linkopts~$rm $lib.exp' + hardcode_libdir_flag_spec= + hardcode_shlibpath_var=no + runpath_var='LD_RUN_PATH' + ;; + + uts4*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + dgux*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs=yes + fi + ;; + + sysv4.2uw2*) + archive_cmds='$LD -G -o $lib $libobjs $deplibs $linkopts' + hardcode_direct=yes + hardcode_minus_L=no + hardcode_shlibpath_var=no + hardcode_runpath_var=yes + runpath_var=LD_RUN_PATH + ;; + + unixware7*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts' + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + *) + ld_shlibs=no + ;; + esac +fi +echo "$ac_t$ld_shlibs" 1>&6 +test "$ld_shlibs" = no && can_build_shared=no + +if test -z "$NM"; then + echo $ac_n "checking for BSD-compatible nm... $ac_c" 1>&6 + case "$NM" in + [\\/]* | [A-Za-z]:[\\/]*) ;; # Let the user override the test with a path. + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" + for ac_dir in $PATH /usr/ucb /usr/ccs/bin /bin; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/nm || test -f $ac_dir/nm$ac_exeext; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + if ($ac_dir/nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then + NM="$ac_dir/nm -B" + break + elif ($ac_dir/nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then + NM="$ac_dir/nm -p" + break + else + NM=${NM="$ac_dir/nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + fi + fi + done + IFS="$ac_save_ifs" + test -z "$NM" && NM=nm + ;; + esac + echo "$ac_t$NM" 1>&6 +fi + +# Check for command to grab the raw symbol name followed by C symbol from nm. +echo $ac_n "checking command to parse $NM output... $ac_c" 1>&6 + +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[BCDEGRST]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([_A-Za-z][_A-Za-z0-9]*\)' + +# Transform the above into a raw symbol and a C symbol. +symxfrm='\1 \2\3 \3' + +# Transform an extracted symbol line into a proper C declaration +global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern char \1;/p'" + +# Define system-specific variables. +case "$host_os" in +aix*) + symcode='[BCDT]' + ;; +cygwin* | mingw*) + symcode='[ABCDGISTW]' + ;; +hpux*) # Its linker distinguishes data from code symbols + global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern char \1();/p' -e 's/^. .* \(.*\)$/extern char \1;/p'" + ;; +irix*) + symcode='[BCDEGRST]' + ;; +solaris*) + symcode='[BDT]' + ;; +sysv4) + symcode='[DFNSTU]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +if $NM -V 2>&1 | egrep '(GNU|with BFD)' > /dev/null; then + symcode='[ABCDGISTW]' +fi + +# Try without a prefix undercore, then with it. +for ac_symprfx in "" "_"; do + + # Write the raw and C identifiers. + global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode\)[ ][ ]*\($ac_symprfx\)$sympat$/$symxfrm/p'" + + # Check to see that the pipe works correctly. + pipe_works=no + $rm conftest* + cat > conftest.c <&5 + if { (eval echo $progname:1654: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; } && test -s conftest.$objext; then + # Now try to grab the symbols. + nlist=conftest.nm + if { echo "$progname:1657: eval \"$NM conftest.$objext | $global_symbol_pipe > $nlist\"" >&5; eval "$NM conftest.$objext | $global_symbol_pipe > $nlist 2>&5"; } && test -s "$nlist"; then + + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if egrep ' nm_test_var$' "$nlist" >/dev/null; then + if egrep ' nm_test_func$' "$nlist" >/dev/null; then + cat < conftest.c +#ifdef __cplusplus +extern "C" { +#endif + +EOF + # Now generate the symbol file. + eval "$global_symbol_to_cdecl"' < "$nlist" >> conftest.c' + + cat <> conftest.c +#if defined (__STDC__) && __STDC__ +# define lt_ptr_t void * +#else +# define lt_ptr_t char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + lt_ptr_t address; +} +lt_preloaded_symbols[] = +{ +EOF + sed 's/^. \(.*\) \(.*\)$/ {"\2", (lt_ptr_t) \&\2},/' < "$nlist" >> conftest.c + cat <<\EOF >> conftest.c + {0, (lt_ptr_t) 0} +}; + +#ifdef __cplusplus +} +#endif +EOF + # Now try linking the two files. + mv conftest.$objext conftstm.$objext + save_LIBS="$LIBS" + save_CFLAGS="$CFLAGS" + LIBS="conftstm.$objext" + CFLAGS="$CFLAGS$no_builtin_flag" + if { (eval echo $progname:1709: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + pipe_works=yes + else + echo "$progname: failed program was:" >&5 + cat conftest.c >&5 + fi + LIBS="$save_LIBS" + else + echo "cannot find nm_test_func in $nlist" >&5 + fi + else + echo "cannot find nm_test_var in $nlist" >&5 + fi + else + echo "cannot run $global_symbol_pipe" >&5 + fi + else + echo "$progname: failed program was:" >&5 + cat conftest.c >&5 + fi + $rm conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + global_symbol_pipe= + fi +done +if test "$pipe_works" = yes; then + echo "${ac_t}ok" 1>&6 +else + echo "${ac_t}failed" 1>&6 +fi + +if test -z "$global_symbol_pipe"; then + global_symbol_to_cdecl= +fi + +# Check hardcoding attributes. +echo $ac_n "checking how to hardcode library paths into programs... $ac_c" 1>&6 +hardcode_action= +if test -n "$hardcode_libdir_flag_spec" || \ + test -n "$runpath_var"; then + + # We can hardcode non-existant directories. + if test "$hardcode_direct" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$hardcode_shlibpath_var" != no && + test "$hardcode_minus_L" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action=unsupported +fi +echo "$ac_t$hardcode_action" 1>&6 + + +reload_flag= +reload_cmds='$LD$reload_flag -o $output$reload_objs' +echo $ac_n "checking for $LD option to reload object files... $ac_c" 1>&6 +# PORTME Some linkers may need a different reload flag. +reload_flag='-r' +echo "$ac_t$reload_flag" 1>&6 +test -n "$reload_flag" && reload_flag=" $reload_flag" + +# PORTME Fill in your ld.so characteristics +library_names_spec= +libname_spec='lib$name' +soname_spec= +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +file_magic_cmd= +file_magic_test_file= +deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# `unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [regex]' -- check by looking for files in library path +# which responds to the $file_magic_cmd with a given egrep regex. +# If you have `file' or equivalent on your system and you're not sure +# whether `pass_all' will *always* work, you probably want this one. +echo $ac_n "checking dynamic linker characteristics... $ac_c" 1>&6 +case "$host_os" in +aix3*) + version_type=linux + library_names_spec='${libname}${release}.so$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}.so$major' + ;; + +aix4*) + version_type=linux + # AIX has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + # We preserve .a as extension for shared libraries though AIX4.2 + # and later linker supports .so + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.a' + shlibpath_var=LIBPATH + deplibs_check_method=pass_all + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "(cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a)"; (cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a) || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}.so' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + deplibs_check_method=pass_all + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + +bsdi4*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' + file_magic_cmd=/usr/bin/file + file_magic_test_file=/shlib/libc.so + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + export_dynamic_flag_spec=-rdynamic + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw*) + version_type=windows + need_version=no + need_lib_prefix=no + if test "$with_gcc" = yes; then + library_names_spec='${libname}`echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll $libname.a' + else + library_names_spec='${libname}`echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll $libname.lib' + fi + dynamic_linker='Win32 ld.exe' + deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + file_magic_cmd='${OBJDUMP} -f' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd*) + objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout` + version_type=freebsd-$objformat + case "$version_type" in + freebsd-elf*) + deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB shared object' + file_magic_cmd=/usr/bin/file + file_magic_test_file=`echo /usr/lib/libc.so*` + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + deplibs_check_method=unknown + library_names_spec='${libname}${release}.so$versuffix $libname.so$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case "$host_os" in + freebsd2* | freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + ;; + *) # from 3.2 on + shlibpath_overrides_runpath=no + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so${major} ${libname}.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + dynamic_linker="$host_os dld.sl" + version_type=sunos + need_lib_prefix=no + need_version=no + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}.sl$versuffix ${libname}${release}.sl$major $libname.sl' + soname_spec='${libname}${release}.sl$major' + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + + #### local change for Sleepycat DB: [#1990] + # The following 3 lines added, otherwise dependent libraries are not allowed + # on HP. We use dependent libraries in a very straightforward way, to + # incorporate -lnsl into libtcl.sl, and for testing only. + deplibs_check_method='file_magic PA-RISC[1-9][0-9.]* shared library' + file_magic_cmd=/usr/bin/file + file_magic_test_file=`echo /lib/libc.sl*` + ;; + +irix5* | irix6*) + version_type=irix + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}.so.$major' + library_names_spec='${libname}${release}.so.$versuffix ${libname}${release}.so.$major ${libname}${release}.so $libname.so' + case "$host_os" in + irix5*) + libsuff= shlibsuff= + # this will be overridden with pass_all, but let us keep it just in case + deplibs_check_method="file_magic ELF 32-bit MSB dynamic lib MIPS - version 1" + ;; + *) + case "$LD" in # libtool.m4 will add one of these switches to LD + *-32|*"-32 ") libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 ") libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + file_magic_cmd=/usr/bin/file + file_magic_test_file=`echo /lib${libsuff}/libc.so*` + deplibs_check_method='pass_all' + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux-gnuoldld* | linux-gnuaout* | linux-gnucoff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux-gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + deplibs_check_method=pass_all + + if test -f /lib/ld.so.1; then + dynamic_linker='GNU ld.so' + else + # Only the GNU ld.so supports shared libraries on MkLinux. + case "$host_cpu" in + powerpc*) dynamic_linker=no ;; + *) dynamic_linker='Linux ld.so' ;; + esac + fi + ;; + +netbsd*) + version_type=sunos + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major ${libname}${release}.so ${libname}.so' + soname_spec='${libname}${release}.so$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + ;; + +openbsd*) + version_type=sunos + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + need_version=no + fi + library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + ;; + +os2*) + libname_spec='$name' + need_lib_prefix=no + library_names_spec='$libname.dll $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_version=no + soname_spec='${libname}${release}.so' + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so' + shlibpath_var=LD_LIBRARY_PATH + # this will be overridden with pass_all, but let us keep it just in case + deplibs_check_method='file_magic COFF format alpha shared library' + file_magic_cmd=/usr/bin/file + file_magic_test_file=/shlib/libc.so + deplibs_check_method='pass_all' + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rhapsody*) + version_type=sunos + library_names_spec='${libname}.so' + soname_spec='${libname}.so' + shlibpath_var=DYLD_LIBRARY_PATH + deplibs_check_method=pass_all + ;; + +sco3.2v5*) + version_type=osf + soname_spec='${libname}${release}.so$major' + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + shlibpath_var=LD_LIBRARY_PATH + #### local change for Sleepycat DB: + # The following line added, otherwise dependent libraries are not allowed + # on SCO. We use dependent libraries in a very straightforward way. + deplibs_check_method='pass_all' + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + deplibs_check_method="file_magic ELF [0-9][0-9]-bit [LM]SB dynamic lib" + file_magic_cmd=/usr/bin/file + file_magic_test_file=/lib/libc.so + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + version_type=linux + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + case "$host_vendor" in + sequent) + file_magic_cmd='/bin/file' + deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' + ;; + ncr) + deplibs_check_method='pass_all' + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' + file_magic_cmd=/usr/bin/file + file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + esac + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname.so.$versuffix $libname.so.$major $libname.so' + soname_spec='$libname.so.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +#### local change for Sleepycat DB: +# Add in the QNX support from QNX. +nto-qnx) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + deplibs_check_method='pass_all' + ;; + +*) + dynamic_linker=no + ;; +esac +echo "$ac_t$dynamic_linker" 1>&6 +test "$dynamic_linker" = no && can_build_shared=no + +# Report the final consequences. +echo "checking if libtool supports shared libraries... $can_build_shared" 1>&6 + +# Only try to build win32 dlls if AC_LIBTOOL_WIN32_DLL was used in +# configure.in, otherwise build static only libraries. +case "$host_os" in +cygwin* | mingw* | os2*) + if test x$can_build_shared = xyes; then + test x$enable_win32_dll = xno && can_build_shared=no + echo "checking if package supports dlls... $can_build_shared" 1>&6 + fi +;; +esac + +if test -n "$file_magic_test_file" && test -n "$file_magic_cmd"; then + case "$deplibs_check_method" in + "file_magic "*) + file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + egrep "$file_magic_regex" > /dev/null; then + : + else + cat <&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac +fi + +echo $ac_n "checking whether to build shared libraries... $ac_c" 1>&6 +test "$can_build_shared" = "no" && enable_shared=no + +# On AIX, shared libraries and static libraries use the same namespace, and +# are all built from PIC. +case "$host_os" in +aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + +aix4*) + test "$enable_shared" = yes && enable_static=no + ;; +esac + +echo "$ac_t$enable_shared" 1>&6 + +# Make sure either enable_shared or enable_static is yes. +test "$enable_shared" = yes || enable_static=yes + +echo "checking whether to build static libraries... $enable_static" 1>&6 + +if test "$hardcode_action" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + +echo $ac_n "checking for objdir... $ac_c" 1>&6 +rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + objdir=_libs +fi +rmdir .libs 2>/dev/null +echo "$ac_t$objdir" 1>&6 + +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else +if eval "test \"`echo '$''{'lt_cv_dlopen'+set}'`\" != set"; then + lt_cv_dlopen=no lt_cv_dlopen_libs= +echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6 +echo "$progname:2248: checking for dlopen in -ldl" >&5 +ac_lib_var=`echo dl'_'dlopen | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ldl $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + echo "$ac_t""no" 1>&6 +echo $ac_n "checking for dlopen""... $ac_c" 1>&6 +echo "$progname:2288: checking for dlopen" >&5 +if eval "test \"`echo '$''{'ac_cv_func_dlopen'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_dlopen) || defined (__stub___dlopen) +choke me +#else +dlopen(); +#endif + +; return 0; } +EOF +if { (eval echo $progname:2318: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_dlopen=yes" +else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_dlopen=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_func_'dlopen`\" = yes"; then + echo "$ac_t""yes" 1>&6 + lt_cv_dlopen="dlopen" +else + echo "$ac_t""no" 1>&6 +echo $ac_n "checking for dld_link in -ldld""... $ac_c" 1>&6 +echo "$progname:2335: checking for dld_link in -ldld" >&5 +ac_lib_var=`echo dld'_'dld_link | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ldld $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" +else + echo "$ac_t""no" 1>&6 +echo $ac_n "checking for shl_load""... $ac_c" 1>&6 +echo "$progname:2375: checking for shl_load" >&5 +if eval "test \"`echo '$''{'ac_cv_func_shl_load'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char shl_load(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_shl_load) || defined (__stub___shl_load) +choke me +#else +shl_load(); +#endif + +; return 0; } +EOF +if { (eval echo $progname:2405: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_shl_load=yes" +else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_shl_load=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'shl_load`\" = yes"; then + echo "$ac_t""yes" 1>&6 + lt_cv_dlopen="shl_load" +else + echo "$ac_t""no" 1>&6 +echo $ac_n "checking for shl_load in -ldld""... $ac_c" 1>&6 +echo "$progname:2423: checking for shl_load in -ldld" >&5 +ac_lib_var=`echo dld'_'shl_load | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ldld $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" +else + echo "$ac_t""no" 1>&6 +fi + + +fi + + +fi + + +fi + + +fi + +fi + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + fi + + case "$lt_cv_dlopen" in + dlopen) +for ac_hdr in dlfcn.h; do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "$progname:2488: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +int fnord = 0; +EOF +ac_try="$ac_compile >/dev/null 2>conftest.out" +{ (eval echo $progname:2498: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi +done + + if test "x$ac_cv_header_dlfcn_h" = xyes; then + CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + fi + eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + LIBS="$lt_cv_dlopen_libs $LIBS" + + echo $ac_n "checking whether a program can dlopen itself""... $ac_c" 1>&6 +echo "$progname:2526: checking whether a program can dlopen itself" >&5 +if test "${lt_cv_dlopen_self+set}" = set; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + lt_cv_dlopen_self=cross + else + cat > conftest.c < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LTDL_GLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LTDL_GLOBAL DL_GLOBAL +# else +# define LTDL_GLOBAL 0 +# endif +#endif + +/* We may have to define LTDL_LAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LTDL_LAZY_OR_NOW +# ifdef RTLD_LAZY +# define LTDL_LAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LTDL_LAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LTDL_LAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LTDL_LAZY_OR_NOW DL_NOW +# else +# define LTDL_LAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +fnord() { int i=42;} +main() { void *self, *ptr1, *ptr2; self=dlopen(0,LTDL_GLOBAL|LTDL_LAZY_OR_NOW); + if(self) { ptr1=dlsym(self,"fnord"); ptr2=dlsym(self,"_fnord"); + if(ptr1 || ptr2) { dlclose(self); exit(0); } } exit(1); } + +EOF +if { (eval echo $progname:2580: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + lt_cv_dlopen_self=yes +else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + lt_cv_dlopen_self=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$lt_cv_dlopen_self" 1>&6 + + if test "$lt_cv_dlopen_self" = yes; then + LDFLAGS="$LDFLAGS $link_static_flag" + echo $ac_n "checking whether a statically linked program can dlopen itself""... $ac_c" 1>&6 +echo "$progname:2599: checking whether a statically linked program can dlopen itself" >&5 +if test "${lt_cv_dlopen_self_static+set}" = set; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + lt_cv_dlopen_self_static=cross + else + cat > conftest.c < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LTDL_GLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LTDL_GLOBAL DL_GLOBAL +# else +# define LTDL_GLOBAL 0 +# endif +#endif + +/* We may have to define LTDL_LAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LTDL_LAZY_OR_NOW +# ifdef RTLD_LAZY +# define LTDL_LAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LTDL_LAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LTDL_LAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LTDL_LAZY_OR_NOW DL_NOW +# else +# define LTDL_LAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +fnord() { int i=42;} +main() { void *self, *ptr1, *ptr2; self=dlopen(0,LTDL_GLOBAL|LTDL_LAZY_OR_NOW); + if(self) { ptr1=dlsym(self,"fnord"); ptr2=dlsym(self,"_fnord"); + if(ptr1 || ptr2) { dlclose(self); exit(0); } } exit(1); } + +EOF +if { (eval echo $progname:2653: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + lt_cv_dlopen_self_static=yes +else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + lt_cv_dlopen_self_static=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$lt_cv_dlopen_self_static" 1>&6 +fi + ;; + esac + + case "$lt_cv_dlopen_self" in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case "$lt_cv_dlopen_self_static" in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi + +# Copy echo and quote the copy, instead of the original, because it is +# used later. +ltecho="$echo" +if test "X$ltecho" = "X$CONFIG_SHELL $0 --fallback-echo"; then + ltecho="$CONFIG_SHELL \$0 --fallback-echo" +fi +LTSHELL="$SHELL" + +LTCONFIG_VERSION="$VERSION" + +# Only quote variables if we're using ltmain.sh. +case "$ltmain" in +*.sh) + # Now quote all the things that may contain metacharacters. + for var in ltecho old_CC old_CFLAGS old_CPPFLAGS \ + old_LD old_LDFLAGS old_LIBS \ + old_NM old_RANLIB old_LN_S old_DLLTOOL old_OBJDUMP old_AS \ + AR CC LD LN_S NM LTSHELL LTCONFIG_VERSION \ + reload_flag reload_cmds wl \ + pic_flag link_static_flag no_builtin_flag export_dynamic_flag_spec \ + thread_safe_flag_spec whole_archive_flag_spec libname_spec \ + library_names_spec soname_spec \ + RANLIB old_archive_cmds old_archive_from_new_cmds old_postinstall_cmds \ + old_postuninstall_cmds archive_cmds archive_expsym_cmds postinstall_cmds postuninstall_cmds \ + file_magic_cmd export_symbols_cmds deplibs_check_method allow_undefined_flag no_undefined_flag \ + finish_cmds finish_eval global_symbol_pipe global_symbol_to_cdecl \ + hardcode_libdir_flag_spec hardcode_libdir_separator \ + sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ + compiler_c_o compiler_o_lo need_locks exclude_expsyms include_expsyms; do + + case "$var" in + reload_cmds | old_archive_cmds | old_archive_from_new_cmds | \ + old_postinstall_cmds | old_postuninstall_cmds | \ + export_symbols_cmds | archive_cmds | archive_expsym_cmds | \ + postinstall_cmds | postuninstall_cmds | \ + finish_cmds | sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) + # Double-quote double-evaled strings. + eval "$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" + ;; + *) + eval "$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" + ;; + esac + done + + case "$ltecho" in + *'\$0 --fallback-echo"') + ltecho=`$echo "X$ltecho" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` + ;; + esac + + trap "$rm \"$ofile\"; exit 1" 1 2 15 + echo "creating $ofile" + $rm "$ofile" + cat < "$ofile" +#! $SHELL + +# `$echo "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) +# NOTE: Changes made to this file will be lost: look at ltconfig or ltmain.sh. +# +# Copyright (C) 1996-1999 Free Software Foundation, Inc. +# Originally by Gordon Matzigkeit , 1996 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="sed -e s/^X//" + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +if test "X\${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi + +### BEGIN LIBTOOL CONFIG +EOF + cfgfile="$ofile" + ;; + +*) + # Double-quote the variables that need it (for aesthetics). + for var in old_CC old_CFLAGS old_CPPFLAGS \ + old_LD old_LDFLAGS old_LIBS \ + old_NM old_RANLIB old_LN_S old_DLLTOOL old_OBJDUMP old_AS; do + eval "$var=\\\"\$var\\\"" + done + + # Just create a config file. + cfgfile="$ofile.cfg" + trap "$rm \"$cfgfile\"; exit 1" 1 2 15 + echo "creating $cfgfile" + $rm "$cfgfile" + cat < "$cfgfile" +# `$echo "$cfgfile" | sed 's%^.*/%%'` - Libtool configuration file. +# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) +EOF + ;; +esac + +cat <> "$cfgfile" +# Libtool was configured as follows, on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# +# CC=$old_CC CFLAGS=$old_CFLAGS CPPFLAGS=$old_CPPFLAGS \\ +# LD=$old_LD LDFLAGS=$old_LDFLAGS LIBS=$old_LIBS \\ +# NM=$old_NM RANLIB=$old_RANLIB LN_S=$old_LN_S \\ +# DLLTOOL=$old_DLLTOOL OBJDUMP=$old_OBJDUMP AS=$old_AS \\ +# $0$ltconfig_args +# +# Compiler and other test output produced by $progname, useful for +# debugging $progname, is in ./config.log if it exists. + +# The version of $progname that generated this script. +LTCONFIG_VERSION=$LTCONFIG_VERSION + +# Shell to use when invoking shell scripts. +SHELL=$LTSHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host + +# An echo program that does not interpret backslashes. +echo=$ltecho + +# The archiver. +AR=$AR + +# The default C compiler. +CC=$CC + +# The linker used to build libraries. +LD=$LD + +# Whether we need hard or soft links. +LN_S=$LN_S + +# A BSD-compatible nm program. +NM=$NM + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$reload_flag +reload_cmds=$reload_cmds + +# How to pass a linker flag through the compiler. +wl=$wl + +# Object file suffix (normally "o"). +objext="$objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$pic_flag + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$compiler_c_o + +# Can we write directly to a .lo ? +compiler_o_lo=$compiler_o_lo + +# Must we lock files when doing compilation ? +need_locks=$need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$link_static_flag + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$no_builtin_flag + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$export_dynamic_flag_spec + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$whole_archive_flag_spec + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$thread_safe_flag_spec + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$RANLIB +old_archive_cmds=$old_archive_cmds +old_postinstall_cmds=$old_postinstall_cmds +old_postuninstall_cmds=$old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$old_archive_from_new_cmds + +# Commands used to build and install a shared archive. +archive_cmds=$archive_cmds +archive_expsym_cmds=$archive_expsym_cmds +postinstall_cmds=$postinstall_cmds +postuninstall_cmds=$postuninstall_cmds + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$allow_undefined_flag + +# Flag that forces no undefined symbols. +no_undefined_flag=$no_undefined_flag + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$global_symbol_to_cdecl + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$hardcode_libdir_flag_spec + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$hardcode_libdir_separator + +# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$hardcode_direct + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$hardcode_minus_L + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path="$fix_srcfile_path" + +# Set to yes if exported symbols are required. +always_export_symbols=$always_export_symbols + +# The commands to list exported symbols. +export_symbols_cmds=$export_symbols_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$exclude_expsyms + +# Symbols that must always be exported. +include_expsyms=$include_expsyms + +EOF + +case "$ltmain" in +*.sh) + echo '### END LIBTOOL CONFIG' >> "$ofile" + echo >> "$ofile" + case "$host_os" in + aix3*) + cat <<\EOF >> "$ofile" + +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +EOF + ;; + esac + + # Append the ltmain.sh script. + sed '$q' "$ltmain" >> "$ofile" || (rm -f "$ofile"; exit 1) + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + + chmod +x "$ofile" + ;; + +*) + # Compile the libtool program. + echo "FIXME: would compile $ltmain" + ;; +esac + +test -n "$cache_file" || exit 0 + +# AC_CACHE_SAVE +trap '' 1 2 15 +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +exit 0 + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: +#! /bin/bash diff --git a/db/dist/ltmain.sh b/db/dist/ltmain.sh new file mode 100644 index 000000000..5eb329149 --- /dev/null +++ b/db/dist/ltmain.sh @@ -0,0 +1,4029 @@ +# ltmain.sh - Provide generalized library-building support services. +# NOTE: Changing this file will not affect anything until you rerun ltconfig. +# +# Copyright (C) 1996-1999 Free Software Foundation, Inc. +# Originally by Gordon Matzigkeit , 1996 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Check that we have a working $echo. +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then + # Yippee, $echo works! + : +else + # Restart under the correct shell, and then maybe $echo will work. + exec $SHELL "$0" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat <&2 + echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit 1 +fi + +if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then + echo "$modename: not configured to build any kind of library" 1>&2 + echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit 1 +fi + +# Global variables. +mode=$default_mode +nonopt= +prev= +prevopt= +run= +show="$echo" +show_help= +execute_dlfiles= +lo2o="s/\\.lo\$/.${objext}/" +o2lo="s/\\.${objext}\$/.lo/" + +# Parse our command line options once, thoroughly. +while test $# -gt 0 +do + arg="$1" + shift + + case "$arg" in + -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case "$prev" in + execute_dlfiles) + eval "$prev=\"\$$prev \$arg\"" + ;; + *) + eval "$prev=\$arg" + ;; + esac + + prev= + prevopt= + continue + fi + + # Have we seen a non-optional argument yet? + case "$arg" in + --help) + show_help=yes + ;; + + --version) + echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP" + exit 0 + ;; + + --config) + sed -e '1,/^### BEGIN LIBTOOL CONFIG/d' -e '/^### END LIBTOOL CONFIG/,$d' $0 + exit 0 + ;; + + --debug) + echo "$progname: enabling shell trace mode" + set -x + ;; + + --dry-run | -n) + run=: + ;; + + --features) + echo "host: $host" + if test "$build_libtool_libs" = yes; then + echo "enable shared libraries" + else + echo "disable shared libraries" + fi + if test "$build_old_libs" = yes; then + echo "enable static libraries" + else + echo "disable static libraries" + fi + exit 0 + ;; + + --finish) mode="finish" ;; + + --mode) prevopt="--mode" prev=mode ;; + --mode=*) mode="$optarg" ;; + + --quiet | --silent) + show=: + ;; + + -dlopen) + prevopt="-dlopen" + prev=execute_dlfiles + ;; + + -*) + $echo "$modename: unrecognized option \`$arg'" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + + *) + nonopt="$arg" + break + ;; + esac +done + +if test -n "$prevopt"; then + $echo "$modename: option \`$prevopt' requires an argument" 1>&2 + $echo "$help" 1>&2 + exit 1 +fi + +if test -z "$show_help"; then + + # Infer the operation mode. + if test -z "$mode"; then + case "$nonopt" in + *cc | *++ | gcc* | *-gcc*) + mode=link + for arg + do + case "$arg" in + -c) + mode=compile + break + ;; + esac + done + ;; + *db | *dbx | *strace | *truss) + mode=execute + ;; + *install*|cp|mv) + mode=install + ;; + *rm) + mode=uninstall + ;; + *) + # If we have no mode, but dlfiles were specified, then do execute mode. + test -n "$execute_dlfiles" && mode=execute + + # Just use the default operation mode. + if test -z "$mode"; then + if test -n "$nonopt"; then + $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2 + else + $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2 + fi + fi + ;; + esac + fi + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$execute_dlfiles" && test "$mode" != execute; then + $echo "$modename: unrecognized option \`-dlopen'" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + # Change the help message to a mode-specific one. + generic_help="$help" + help="Try \`$modename --help --mode=$mode' for more information." + + # These modes are in order of execution frequency so that they run quickly. + case "$mode" in + # libtool compile mode + compile) + modename="$modename: compile" + # Get the compilation command and the source file. + base_compile= + lastarg= + srcfile="$nonopt" + suppress_output= + + user_target=no + for arg + do + # Accept any command-line options. + case "$arg" in + -o) + if test "$user_target" != "no"; then + $echo "$modename: you cannot specify \`-o' more than once" 1>&2 + exit 1 + fi + user_target=next + ;; + + -static) + build_old_libs=yes + continue + ;; + esac + + case "$user_target" in + next) + # The next one is the -o target name + user_target=yes + continue + ;; + yes) + # We got the output file + user_target=set + libobj="$arg" + continue + ;; + esac + + # Accept the current argument as the source file. + lastarg="$srcfile" + srcfile="$arg" + + # Aesthetically quote the previous argument. + + # Backslashify any backslashes, double quotes, and dollar signs. + # These are the only characters that are still specially + # interpreted inside of double-quoted scrings. + lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"` + + # Double-quote args containing other shell metacharacters. + # Many Bourne shells cannot handle close brackets correctly in scan + # sets, so we specify it separately. + case "$lastarg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + lastarg="\"$lastarg\"" + ;; + esac + + # Add the previous argument to base_compile. + if test -z "$base_compile"; then + base_compile="$lastarg" + else + base_compile="$base_compile $lastarg" + fi + done + + case "$user_target" in + set) + ;; + no) + # Get the name of the library object. + libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'` + ;; + *) + $echo "$modename: you must specify a target with \`-o'" 1>&2 + exit 1 + ;; + esac + + # Recognize several different file suffixes. + # If the user specifies -o file.o, it is replaced with file.lo + xform='[cCFSfmso]' + case "$libobj" in + *.ada) xform=ada ;; + *.adb) xform=adb ;; + *.ads) xform=ads ;; + *.asm) xform=asm ;; + *.c++) xform=c++ ;; + *.cc) xform=cc ;; + *.cpp) xform=cpp ;; + *.cxx) xform=cxx ;; + *.f90) xform=f90 ;; + *.for) xform=for ;; + esac + + libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"` + + case "$libobj" in + *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;; + *) + $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2 + exit 1 + ;; + esac + + if test -z "$base_compile"; then + $echo "$modename: you must specify a compilation command" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + # Delete any leftover library objects. + if test "$build_old_libs" = yes; then + removelist="$obj $libobj" + else + removelist="$libobj" + fi + + $run $rm $removelist + trap "$run $rm $removelist; exit 1" 1 2 15 + + # Calculate the filename of the output object if compiler does + # not support -o with -c + if test "$compiler_c_o" = no; then + output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\..*$%%'`.${objext} + lockfile="$output_obj.lock" + removelist="$removelist $output_obj $lockfile" + trap "$run $rm $removelist; exit 1" 1 2 15 + else + need_locks=no + lockfile= + fi + + # Lock this critical section if it is needed + # We use this script file to make the link, it avoids creating a new file + if test "$need_locks" = yes; then + until ln "$0" "$lockfile" 2>/dev/null; do + $show "Waiting for $lockfile to be removed" + sleep 2 + done + elif test "$need_locks" = warn; then + if test -f "$lockfile"; then + echo "\ +*** ERROR, $lockfile exists and contains: +`cat $lockfile 2>/dev/null` + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit 1 + fi + echo $srcfile > "$lockfile" + fi + + if test -n "$fix_srcfile_path"; then + eval srcfile=\"$fix_srcfile_path\" + fi + + # Only build a PIC object if we are building libtool libraries. + if test "$build_libtool_libs" = yes; then + # Without this assignment, base_compile gets emptied. + fbsd_hideous_sh_bug=$base_compile + + # All platforms use -DPIC, to notify preprocessed assembler code. + command="$base_compile $srcfile $pic_flag -DPIC" + if test "$build_old_libs" = yes; then + lo_libobj="$libobj" + dir=`$echo "X$libobj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$dir" = "X$libobj"; then + dir="$objdir" + else + dir="$dir/$objdir" + fi + libobj="$dir/"`$echo "X$libobj" | $Xsed -e 's%^.*/%%'` + + if test -d "$dir"; then + $show "$rm $libobj" + $run $rm $libobj + else + $show "$mkdir $dir" + $run $mkdir $dir + status=$? + if test $status -ne 0 && test ! -d $dir; then + exit $status + fi + fi + fi + if test "$compiler_o_lo" = yes; then + output_obj="$libobj" + command="$command -o $output_obj" + elif test "$compiler_c_o" = yes; then + output_obj="$obj" + command="$command -o $output_obj" + fi + + $run $rm "$output_obj" + $show "$command" + if $run eval "$command"; then : + else + test -n "$output_obj" && $run $rm $removelist + exit 1 + fi + + if test "$need_locks" = warn && + test x"`cat $lockfile 2>/dev/null`" != x"$srcfile"; then + echo "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit 1 + fi + + # Just move the object if needed, then go on to compile the next one + if test x"$output_obj" != x"$libobj"; then + $show "$mv $output_obj $libobj" + if $run $mv $output_obj $libobj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + fi + + # If we have no pic_flag, then copy the object into place and finish. + if test -z "$pic_flag" && test "$build_old_libs" = yes; then + # Rename the .lo from within objdir to obj + if test -f $obj; then + $show $rm $obj + $run $rm $obj + fi + + $show "$mv $libobj $obj" + if $run $mv $libobj $obj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + + xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$obj"; then + xdir="." + else + xdir="$xdir" + fi + baseobj=`$echo "X$obj" | $Xsed -e "s%.*/%%"` + libobj=`$echo "X$baseobj" | $Xsed -e "$o2lo"` + # Now arrange that obj and lo_libobj become the same file + $show "(cd $xdir && $LN_S $baseobj $libobj)" + if $run eval '(cd $xdir && $LN_S $baseobj $libobj)'; then + exit 0 + else + error=$? + $run $rm $removelist + exit $error + fi + fi + + # Allow error messages only from the first compilation. + suppress_output=' >/dev/null 2>&1' + fi + + # Only build a position-dependent object if we build old libraries. + if test "$build_old_libs" = yes; then + command="$base_compile $srcfile" + if test "$compiler_c_o" = yes; then + command="$command -o $obj" + output_obj="$obj" + fi + + # Suppress compiler output if we already did a PIC compilation. + command="$command$suppress_output" + $run $rm "$output_obj" + $show "$command" + if $run eval "$command"; then : + else + $run $rm $removelist + exit 1 + fi + + if test "$need_locks" = warn && + test x"`cat $lockfile 2>/dev/null`" != x"$srcfile"; then + echo "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit 1 + fi + + # Just move the object if needed + if test x"$output_obj" != x"$obj"; then + $show "$mv $output_obj $obj" + if $run $mv $output_obj $obj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + fi + + # Create an invalid libtool object if no PIC, so that we do not + # accidentally link it into a program. + if test "$build_libtool_libs" != yes; then + $show "echo timestamp > $libobj" + $run eval "echo timestamp > \$libobj" || exit $? + else + # Move the .lo from within objdir + $show "$mv $libobj $lo_libobj" + if $run $mv $libobj $lo_libobj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + fi + fi + + # Unlock the critical section if it was locked + if test "$need_locks" != no; then + $rm "$lockfile" + fi + + exit 0 + ;; + + # libtool link mode + link) + modename="$modename: link" + case "$host" in + *-*-cygwin* | *-*-mingw* | *-*-os2*) + # It is impossible to link a dll without this setting, and + # we shouldn't force the makefile maintainer to figure out + # which system we are compiling for in order to pass an extra + # flag for every libtool invokation. + # allow_undefined=no + + # FIXME: Unfortunately, there are problems with the above when trying + # to make a dll which has undefined symbols, in which case not + # even a static library is built. For now, we need to specify + # -no-undefined on the libtool link line when we can be certain + # that all symbols are satisfied, otherwise we get a static library. + allow_undefined=yes + + # This is a source program that is used to create dlls on Windows + # Don't remove nor modify the starting and closing comments +# /* ltdll.c starts here */ +# #define WIN32_LEAN_AND_MEAN +# #include +# #undef WIN32_LEAN_AND_MEAN +# #include +# +# #ifndef __CYGWIN__ +# # ifdef __CYGWIN32__ +# # define __CYGWIN__ __CYGWIN32__ +# # endif +# #endif +# +# #ifdef __cplusplus +# extern "C" { +# #endif +# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved); +# #ifdef __cplusplus +# } +# #endif +# +# #ifdef __CYGWIN__ +# #include +# DECLARE_CYGWIN_DLL( DllMain ); +# #endif +# HINSTANCE __hDllInstance_base; +# +# BOOL APIENTRY +# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved) +# { +# __hDllInstance_base = hInst; +# return TRUE; +# } +# /* ltdll.c ends here */ + # This is a source program that is used to create import libraries + # on Windows for dlls which lack them. Don't remove nor modify the + # starting and closing comments +# /* impgen.c starts here */ +# /* Copyright (C) 1999 Free Software Foundation, Inc. +# +# This file is part of GNU libtool. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# */ +# +# #include /* for printf() */ +# #include /* for open(), lseek(), read() */ +# #include /* for O_RDONLY, O_BINARY */ +# #include /* for strdup() */ +# +# static unsigned int +# pe_get16 (fd, offset) +# int fd; +# int offset; +# { +# unsigned char b[2]; +# lseek (fd, offset, SEEK_SET); +# read (fd, b, 2); +# return b[0] + (b[1]<<8); +# } +# +# static unsigned int +# pe_get32 (fd, offset) +# int fd; +# int offset; +# { +# unsigned char b[4]; +# lseek (fd, offset, SEEK_SET); +# read (fd, b, 4); +# return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24); +# } +# +# static unsigned int +# pe_as32 (ptr) +# void *ptr; +# { +# unsigned char *b = ptr; +# return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24); +# } +# +# int +# main (argc, argv) +# int argc; +# char *argv[]; +# { +# int dll; +# unsigned long pe_header_offset, opthdr_ofs, num_entries, i; +# unsigned long export_rva, export_size, nsections, secptr, expptr; +# unsigned long name_rvas, nexp; +# unsigned char *expdata, *erva; +# char *filename, *dll_name; +# +# filename = argv[1]; +# +# dll = open(filename, O_RDONLY|O_BINARY); +# if (!dll) +# return 1; +# +# dll_name = filename; +# +# for (i=0; filename[i]; i++) +# if (filename[i] == '/' || filename[i] == '\\' || filename[i] == ':') +# dll_name = filename + i +1; +# +# pe_header_offset = pe_get32 (dll, 0x3c); +# opthdr_ofs = pe_header_offset + 4 + 20; +# num_entries = pe_get32 (dll, opthdr_ofs + 92); +# +# if (num_entries < 1) /* no exports */ +# return 1; +# +# export_rva = pe_get32 (dll, opthdr_ofs + 96); +# export_size = pe_get32 (dll, opthdr_ofs + 100); +# nsections = pe_get16 (dll, pe_header_offset + 4 +2); +# secptr = (pe_header_offset + 4 + 20 + +# pe_get16 (dll, pe_header_offset + 4 + 16)); +# +# expptr = 0; +# for (i = 0; i < nsections; i++) +# { +# char sname[8]; +# unsigned long secptr1 = secptr + 40 * i; +# unsigned long vaddr = pe_get32 (dll, secptr1 + 12); +# unsigned long vsize = pe_get32 (dll, secptr1 + 16); +# unsigned long fptr = pe_get32 (dll, secptr1 + 20); +# lseek(dll, secptr1, SEEK_SET); +# read(dll, sname, 8); +# if (vaddr <= export_rva && vaddr+vsize > export_rva) +# { +# expptr = fptr + (export_rva - vaddr); +# if (export_rva + export_size > vaddr + vsize) +# export_size = vsize - (export_rva - vaddr); +# break; +# } +# } +# +# expdata = (unsigned char*)malloc(export_size); +# lseek (dll, expptr, SEEK_SET); +# read (dll, expdata, export_size); +# erva = expdata - export_rva; +# +# nexp = pe_as32 (expdata+24); +# name_rvas = pe_as32 (expdata+32); +# +# printf ("EXPORTS\n"); +# for (i = 0; i&2 + fi + if test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + else + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + fi + build_libtool_libs=no + build_old_libs=yes + prefer_static_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + while test $# -gt 0; do + arg="$1" + shift + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case "$prev" in + output) + compile_command="$compile_command @OUTPUT@" + finalize_command="$finalize_command @OUTPUT@" + ;; + esac + + case "$prev" in + dlfiles|dlprefiles) + if test "$preload" = no; then + # Add the symbol object into the linking commands. + compile_command="$compile_command @SYMFILE@" + finalize_command="$finalize_command @SYMFILE@" + preload=yes + fi + case "$arg" in + *.la | *.lo) ;; # We handle these cases below. + force) + if test "$dlself" = no; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test "$prev" = dlprefiles; then + dlself=yes + elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + else + dlprefiles="$dlprefiles $arg" + fi + prev= + ;; + esac + ;; + expsyms) + export_symbols="$arg" + if test ! -f "$arg"; then + $echo "$modename: symbol file \`$arg' does not exist" + exit 1 + fi + prev= + continue + ;; + expsyms_regex) + export_symbols_regex="$arg" + prev= + continue + ;; + release) + release="-$arg" + prev= + continue + ;; + rpath | xrpath) + # We need an absolute path. + case "$arg" in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + $echo "$modename: only absolute run-paths are allowed" 1>&2 + exit 1 + ;; + esac + if test "$prev" = rpath; then + case "$rpath " in + *" $arg "*) ;; + *) rpath="$rpath $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) xrpath="$xrpath $arg" ;; + esac + fi + prev= + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi + + prevarg="$arg" + + case "$arg" in + -all-static) + if test -n "$link_static_flag"; then + compile_command="$compile_command $link_static_flag" + finalize_command="$finalize_command $link_static_flag" + fi + continue + ;; + + -allow-undefined) + # FIXME: remove this flag sometime in the future. + $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2 + continue + ;; + + -avoid-version) + avoid_version=yes + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + export_dynamic=yes + continue + ;; + + -export-symbols | -export-symbols-regex) + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + $echo "$modename: not more than one -exported-symbols argument allowed" + exit 1 + fi + if test "X$arg" = "X-export-symbols"; then + prev=expsyms + else + prev=expsyms_regex + fi + continue + ;; + + -L*) + dir=`$echo "X$arg" | $Xsed -e 's/^-L//'` + # We need an absolute path. + case "$dir" in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2 + $echo "$modename: passing it literally to the linker, although it might fail" 1>&2 + absdir="$dir" + fi + dir="$absdir" + ;; + esac + case " $deplibs " in + *" $arg "*) ;; + *) deplibs="$deplibs $arg";; + esac + case " $lib_search_path " in + *" $dir "*) ;; + *) lib_search_path="$lib_search_path $dir";; + esac + case "$host" in + *-*-cygwin* | *-*-mingw* | *-*-os2*) + dllsearchdir=`cd "$dir" && pwd || echo "$dir"` + case ":$dllsearchpath:" in + ::) dllsearchpath="$dllsearchdir";; + *":$dllsearchdir:"*) ;; + *) dllsearchpath="$dllsearchpath:$dllsearchdir";; + esac + ;; + esac + ;; + + -l*) + if test "$arg" = "-lc"; then + case "$host" in + *-*-cygwin* | *-*-mingw* | *-*-os2* | *-*-beos*) + # These systems don't actually have c library (as such) + continue + ;; + esac + elif test "$arg" = "-lm"; then + case "$host" in + *-*-cygwin* | *-*-beos*) + # These systems don't actually have math library (as such) + continue + ;; + esac + fi + deplibs="$deplibs $arg" + ;; + + -module) + module=yes + continue + ;; + + -no-undefined) + allow_undefined=no + continue + ;; + + -o) prev=output ;; + + -release) + prev=release + continue + ;; + + -rpath) + prev=rpath + continue + ;; + + -R) + prev=xrpath + continue + ;; + + -R*) + dir=`$echo "X$arg" | $Xsed -e 's/^-R//'` + # We need an absolute path. + case "$dir" in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + $echo "$modename: only absolute run-paths are allowed" 1>&2 + exit 1 + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + continue + ;; + + -static) + # If we have no pic_flag, then this is the same as -all-static. + if test -z "$pic_flag" && test -n "$link_static_flag"; then + compile_command="$compile_command $link_static_flag" + finalize_command="$finalize_command $link_static_flag" + fi + continue + ;; + + -thread-safe) + thread_safe=yes + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + + # Some other compiler flag. + -* | +*) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case "$arg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + ;; + + *.o | *.obj | *.a | *.lib) + # A standard object. + objs="$objs $arg" + ;; + + *.lo) + # A library object. + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + if test "$build_libtool_libs" = yes && test "$dlopen" = yes; then + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles "`$echo "X$arg" | $Xsed -e "$lo2o"` + prev= + fi + libobjs="$libobjs $arg" + ;; + + *.la) + # A libtool-controlled library. + + dlname= + libdir= + library_names= + old_library= + + # Check to see that this really is a libtool archive. + if (sed -e '2q' $arg | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$arg' is not a valid libtool archive" 1>&2 + exit 1 + fi + + # If the library was installed with an old release of libtool, + # it will not redefine variable installed. + installed=yes + + # Read the .la file + # If there is no directory component, then add one. + case "$arg" in + */* | *\\*) . $arg ;; + *) . ./$arg ;; + esac + + # Get the name of the library we link against. + linklib= + for l in $old_library $library_names; do + linklib="$l" + done + + if test -z "$linklib"; then + $echo "$modename: cannot find name of link library for \`$arg'" 1>&2 + exit 1 + fi + + # Find the relevant object directory and library name. + name=`$echo "X$arg" | $Xsed -e 's%^.*/%%' -e 's/\.la$//' -e 's/^lib//'` + + if test "X$installed" = Xyes; then + dir="$libdir" + else + dir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$dir" = "X$arg"; then + dir="$objdir" + else + dir="$dir/$objdir" + fi + fi + + if test -n "$dependency_libs"; then + # Extract -R and -L from dependency_libs + temp_deplibs= + for deplib in $dependency_libs; do + case "$deplib" in + -R*) temp_xrpath=`$echo "X$deplib" | $Xsed -e 's/^-R//'` + case " $rpath $xrpath " in + *" $temp_xrpath "*) ;; + *) xrpath="$xrpath $temp_xrpath";; + esac;; + -L*) case "$compile_command $temp_deplibs " in + *" $deplib "*) ;; + *) temp_deplibs="$temp_deplibs $deplib";; + esac + temp_dir=`$echo "X$deplib" | $Xsed -e 's/^-L//'` + case " $lib_search_path " in + *" $temp_dir "*) ;; + *) lib_search_path="$lib_search_path $temp_dir";; + esac + ;; + *) temp_deplibs="$temp_deplibs $deplib";; + esac + done + dependency_libs="$temp_deplibs" + fi + + if test -z "$libdir"; then + # It is a libtool convenience library, so add in its objects. + convenience="$convenience $dir/$old_library" + old_convenience="$old_convenience $dir/$old_library" + deplibs="$deplibs$dependency_libs" + compile_command="$compile_command $dir/$old_library$dependency_libs" + finalize_command="$finalize_command $dir/$old_library$dependency_libs" + continue + fi + + # This library was specified with -dlopen. + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + if test -z "$dlname" || test "$dlopen" != yes || test "$build_libtool_libs" = no; then + # If there is no dlname, no dlopen support or we're linking statically, + # we need to preload. + prev=dlprefiles + else + # We should not create a dependency on this library, but we + # may need any libraries it requires. + compile_command="$compile_command$dependency_libs" + finalize_command="$finalize_command$dependency_libs" + prev= + continue + fi + fi + + # The library was specified with -dlpreopen. + if test "$prev" = dlprefiles; then + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + dlprefiles="$dlprefiles $dir/$old_library" + else + dlprefiles="$dlprefiles $dir/$linklib" + fi + prev= + fi + + if test -n "$library_names" && + { test "$prefer_static_libs" = no || test -z "$old_library"; }; then + link_against_libtool_libs="$link_against_libtool_libs $arg" + if test -n "$shlibpath_var"; then + # Make sure the rpath contains only unique directories. + case "$temp_rpath " in + *" $dir "*) ;; + *) temp_rpath="$temp_rpath $dir" ;; + esac + fi + + # We need an absolute path. + case "$dir" in + [\\/] | [A-Za-z]:[\\/]*) absdir="$dir" ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2 + $echo "$modename: passing it literally to the linker, although it might fail" 1>&2 + absdir="$dir" + fi + ;; + esac + + # This is the magic to use -rpath. + # Skip directories that are in the system default run-time + # search path, unless they have been requested with -R. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + + lib_linked=yes + case "$hardcode_action" in + immediate | unsupported) + if test "$hardcode_direct" = no; then + compile_command="$compile_command $dir/$linklib" + deplibs="$deplibs $dir/$linklib" + case "$host" in + *-*-cygwin* | *-*-mingw* | *-*-os2*) + dllsearchdir=`cd "$dir" && pwd || echo "$dir"` + if test -n "$dllsearchpath"; then + dllsearchpath="$dllsearchpath:$dllsearchdir" + else + dllsearchpath="$dllsearchdir" + fi + ;; + esac + elif test "$hardcode_minus_L" = no; then + case "$host" in + *-*-sunos*) + compile_shlibpath="$compile_shlibpath$dir:" + ;; + esac + case "$compile_command " in + *" -L$dir "*) ;; + *) compile_command="$compile_command -L$dir";; + esac + compile_command="$compile_command -l$name" + deplibs="$deplibs -L$dir -l$name" + elif test "$hardcode_shlibpath_var" = no; then + case ":$compile_shlibpath:" in + *":$dir:"*) ;; + *) compile_shlibpath="$compile_shlibpath$dir:";; + esac + compile_command="$compile_command -l$name" + deplibs="$deplibs -l$name" + else + lib_linked=no + fi + ;; + + relink) + if test "$hardcode_direct" = yes; then + compile_command="$compile_command $absdir/$linklib" + deplibs="$deplibs $absdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + case "$compile_command " in + *" -L$absdir "*) ;; + *) compile_command="$compile_command -L$absdir";; + esac + compile_command="$compile_command -l$name" + deplibs="$deplibs -L$absdir -l$name" + elif test "$hardcode_shlibpath_var" = yes; then + case ":$compile_shlibpath:" in + *":$absdir:"*) ;; + *) compile_shlibpath="$compile_shlibpath$absdir:";; + esac + compile_command="$compile_command -l$name" + deplibs="$deplibs -l$name" + else + lib_linked=no + fi + ;; + + *) + lib_linked=no + ;; + esac + + if test "$lib_linked" != yes; then + $echo "$modename: configuration error: unsupported hardcode properties" + exit 1 + fi + + # Finalize command for both is simple: just hardcode it. + if test "$hardcode_direct" = yes; then + finalize_command="$finalize_command $libdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + case "$finalize_command " in + *" -L$libdir "*) ;; + *) finalize_command="$finalize_command -L$libdir";; + esac + finalize_command="$finalize_command -l$name" + elif test "$hardcode_shlibpath_var" = yes; then + case ":$finalize_shlibpath:" in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:";; + esac + finalize_command="$finalize_command -l$name" + else + # We cannot seem to hardcode it, guess we'll fake it. + case "$finalize_command " in + *" -L$dir "*) ;; + *) finalize_command="$finalize_command -L$libdir";; + esac + finalize_command="$finalize_command -l$name" + fi + else + # Transform directly to old archives if we don't build new libraries. + if test -n "$pic_flag" && test -z "$old_library"; then + $echo "$modename: cannot find static library for \`$arg'" 1>&2 + exit 1 + fi + + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test "$hardcode_direct" != unsupported; then + test -n "$old_library" && linklib="$old_library" + compile_command="$compile_command $dir/$linklib" + finalize_command="$finalize_command $dir/$linklib" + else + case "$compile_command " in + *" -L$dir "*) ;; + *) compile_command="$compile_command -L$dir";; + esac + compile_command="$compile_command -l$name" + case "$finalize_command " in + *" -L$dir "*) ;; + *) finalize_command="$finalize_command -L$dir";; + esac + finalize_command="$finalize_command -l$name" + fi + fi + + # Add in any libraries that this one depends upon. + compile_command="$compile_command$dependency_libs" + finalize_command="$finalize_command$dependency_libs" + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case "$arg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + ;; + esac + + # Now actually substitute the argument into the commands. + if test -n "$arg"; then + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + fi + done + + if test -n "$prev"; then + $echo "$modename: the \`$prevarg' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then + eval arg=\"$export_dynamic_flag_spec\" + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + fi + + oldlibs= + # calculate the name of the file, without its directory + outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'` + libobjs_save="$libobjs" + + case "$output" in + "") + $echo "$modename: you must specify an output file" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + + *.a | *.lib) + if test -n "$link_against_libtool_libs"; then + $echo "$modename: error: cannot link libtool libraries into archives" 1>&2 + exit 1 + fi + + if test -n "$deplibs"; then + $echo "$modename: warning: \`-l' and \`-L' are ignored for archives" 1>&2 + fi + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2 + fi + + if test -n "$rpath"; then + $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2 + fi + + if test -n "$xrpath"; then + $echo "$modename: warning: \`-R' is ignored for archives" 1>&2 + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for archives" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for archives" 1>&2 + fi + + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2 + fi + + # Now set the variables for building old libraries. + build_libtool_libs=no + oldlibs="$output" + ;; + + *.la) + # Make sure we only generate libraries of the form `libNAME.la'. + case "$outputname" in + lib*) + name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` + eval libname=\"$libname_spec\" + ;; + *) + if test "$module" = no; then + $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + if test "$need_lib_prefix" != no; then + # Add the "lib" prefix for modules if required + name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` + eval libname=\"$libname_spec\" + else + libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` + fi + ;; + esac + + output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'` + if test "X$output_objdir" = "X$output"; then + output_objdir="$objdir" + else + output_objdir="$output_objdir/$objdir" + fi + + if test -n "$objs"; then + $echo "$modename: cannot build libtool library \`$output' from non-libtool objects:$objs" 2>&1 + exit 1 + fi + + # How the heck are we supposed to write a wrapper for a shared library? + if test -n "$link_against_libtool_libs"; then + $echo "$modename: error: cannot link shared libraries into libtool libraries" 1>&2 + exit 1 + fi + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen' is ignored for libtool libraries" 1>&2 + fi + + set dummy $rpath + if test $# -gt 2; then + $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2 + fi + install_libdir="$2" + + oldlibs= + if test -z "$rpath"; then + if test "$build_libtool_libs" = yes; then + # Building a libtool convenience library. + libext=al + oldlibs="$output_objdir/$libname.$libext $oldlibs" + build_libtool_libs=convenience + build_old_libs=yes + fi + dependency_libs="$deplibs" + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for convenience libraries" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2 + fi + else + + # Parse the version information argument. + IFS="${IFS= }"; save_ifs="$IFS"; IFS=':' + set dummy $vinfo 0 0 0 + IFS="$save_ifs" + + if test -n "$8"; then + $echo "$modename: too many parameters to \`-version-info'" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + current="$2" + revision="$3" + age="$4" + + # Check that each of the things are valid numbers. + case "$current" in + 0 | [1-9] | [1-9][0-9]*) ;; + *) + $echo "$modename: CURRENT \`$current' is not a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit 1 + ;; + esac + + case "$revision" in + 0 | [1-9] | [1-9][0-9]*) ;; + *) + $echo "$modename: REVISION \`$revision' is not a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit 1 + ;; + esac + + case "$age" in + 0 | [1-9] | [1-9][0-9]*) ;; + *) + $echo "$modename: AGE \`$age' is not a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit 1 + ;; + esac + + if test $age -gt $current; then + $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit 1 + fi + + # Calculate the version variables. + major= + versuffix= + verstring= + case "$version_type" in + none) ;; + + irix) + major=`expr $current - $age + 1` + versuffix="$major.$revision" + verstring="sgi$major.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$revision + while test $loop != 0; do + iface=`expr $revision - $loop` + loop=`expr $loop - 1` + verstring="sgi$major.$iface:$verstring" + done + ;; + + linux) + major=.`expr $current - $age` + versuffix="$major.$age.$revision" + ;; + + osf) + major=`expr $current - $age` + versuffix=".$current.$age.$revision" + verstring="$current.$age.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$age + while test $loop != 0; do + iface=`expr $current - $loop` + loop=`expr $loop - 1` + verstring="$verstring:${iface}.0" + done + + # Make executables depend on our current version. + verstring="$verstring:${current}.0" + ;; + + sunos) + major=".$current" + versuffix=".$current.$revision" + ;; + + freebsd-aout) + major=".$current" + versuffix=".$current.$revision"; + ;; + + freebsd-elf) + major=".$current" + versuffix=".$current"; + ;; + + windows) + # Like Linux, but with '-' rather than '.', since we only + # want one extension on Windows 95. + major=`expr $current - $age` + versuffix="-$major-$age-$revision" + ;; + + *) + $echo "$modename: unknown library version type \`$version_type'" 1>&2 + echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit 1 + ;; + esac + + # Clear the version info if we defaulted, and they specified a release. + if test -z "$vinfo" && test -n "$release"; then + major= + verstring="0.0" + if test "$need_version" = no; then + versuffix= + else + versuffix=".0.0" + fi + fi + + # Remove version info from name if versioning should be avoided + if test "$avoid_version" = yes && test "$need_version" = no; then + major= + versuffix= + verstring="" + fi + + # Check to see if the archive will have undefined symbols. + if test "$allow_undefined" = yes; then + if test "$allow_undefined_flag" = unsupported; then + $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2 + build_libtool_libs=no + build_old_libs=yes + fi + else + # Don't allow undefined symbols. + allow_undefined_flag="$no_undefined_flag" + fi + + dependency_libs="$deplibs" + case "$host" in + *-*-cygwin* | *-*-mingw* | *-*-os2* | *-*-beos*) + # these systems don't actually have a c library (as such)! + ;; + + #### local change for Sleepycat DB: [#2380] + # The following case is added, since the linker's -pthread + # option implicitly controls use of -lc or -lc_r. + *freebsd*) + # defer to whether the user wants -lc, or -lc_r + ;; + + *) + # Add libc to deplibs on all other systems. + deplibs="$deplibs -lc" + ;; + esac + fi + + # Create the output directory, or remove our outputs if we need to. + if test -d $output_objdir; then + $show "${rm}r $output_objdir/$outputname $output_objdir/$libname.* $output_objdir/${libname}${release}.*" + $run ${rm}r $output_objdir/$outputname $output_objdir/$libname.* $output_objdir/${libname}${release}.* + else + $show "$mkdir $output_objdir" + $run $mkdir $output_objdir + status=$? + if test $status -ne 0 && test ! -d $output_objdir; then + exit $status + fi + fi + + # Now set the variables for building old libraries. + if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then + oldlibs="$oldlibs $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP` + fi + + if test "$build_libtool_libs" = yes; then + # Transform deplibs into only deplibs that can be linked in shared. + name_save=$name + libname_save=$libname + release_save=$release + versuffix_save=$versuffix + major_save=$major + # I'm not sure if I'm treating the release correctly. I think + # release should show up in the -l (ie -lgmp5) so we don't want to + # add it in twice. Is that correct? + release="" + versuffix="" + major="" + newdeplibs= + droppeddeps=no + case "$deplibs_check_method" in + pass_all) + # Don't check for shared/static. Everything works. + # This might be a little naive. We might want to check + # whether the library exists or not. But this is on + # osf3 & osf4 and I'm not really sure... Just + # implementing what was already the behaviour. + newdeplibs=$deplibs + ;; + test_compile) + # This code stresses the "libraries are programs" paradigm to its + # limits. Maybe even breaks it. We compile a program, linking it + # against the deplibs as a proxy for the library. Then we can check + # whether they linked in statically or dynamically with ldd. + $rm conftest.c + cat > conftest.c </dev/null` + for potent_lib in $potential_libs; do + # Follow soft links. + if ls -lLd "$potent_lib" 2>/dev/null \ + | grep " -> " >/dev/null; then + continue + fi + # The statement above tries to avoid entering an + # endless loop below, in case of cyclic links. + # We might still enter an endless loop, since a link + # loop can be closed while we follow links, + # but so what? + potlib="$potent_lib" + while test -h "$potlib" 2>/dev/null; do + potliblink=`ls -ld $potlib | sed 's/.* -> //'` + case "$potliblink" in + [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; + *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \ + | sed 10q \ + | egrep "$file_magic_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + if test -n "$a_deplib" ; then + droppeddeps=yes + echo + echo "*** Warning: This library needs some functionality provided by $a_deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have." + fi + else + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + fi + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs="" + if $echo "X $deplibs" | $Xsed -e 's/ -lc$//' \ + -e 's/ -[LR][^ ]*//g' -e 's/[ ]//g' | + grep . >/dev/null; then + echo + if test "X$deplibs_check_method" = "Xnone"; then + echo "*** Warning: inter-library dependencies are not supported in this platform." + else + echo "*** Warning: inter-library dependencies are not known to be supported." + fi + echo "*** All declared inter-library dependencies are being dropped." + droppeddeps=yes + fi + ;; + esac + versuffix=$versuffix_save + major=$major_save + release=$release_save + libname=$libname_save + name=$name_save + + if test "$droppeddeps" = yes; then + if test "$module" = yes; then + echo + echo "*** Warning: libtool could not satisfy all declared inter-library" + echo "*** dependencies of module $libname. Therefore, libtool will create" + echo "*** a static module, that should work as long as the dlopening" + echo "*** application is linked with the -dlopen flag." + if test -z "$global_symbol_pipe"; then + echo + echo "*** However, this would only work if libtool was able to extract symbol" + echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + echo "*** not find such a program. So, this module is probably useless." + echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + else + echo "*** The inter-library dependencies that have been dropped here will be" + echo "*** automatically added whenever a program is linked with this library" + echo "*** or is declared to -dlopen it." + fi + fi + # Done checking deplibs! + deplibs=$newdeplibs + fi + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + + # Test again, we may have decided not to build it any more + if test "$build_libtool_libs" = yes; then + # Get the real and link names of the library. + eval library_names=\"$library_names_spec\" + set dummy $library_names + realname="$2" + shift; shift + + if test -n "$soname_spec"; then + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + + lib="$output_objdir/$realname" + for link + do + linknames="$linknames $link" + done + + # Ensure that we have .o objects for linkers which dislike .lo + # (e.g. aix) in case we are running --disable-static + for obj in $libobjs; do + xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$obj"; then + xdir="." + else + xdir="$xdir" + fi + baseobj=`$echo "X$obj" | $Xsed -e 's%^.*/%%'` + oldobj=`$echo "X$baseobj" | $Xsed -e "$lo2o"` + if test ! -f $xdir/$oldobj; then + $show "(cd $xdir && ${LN_S} $baseobj $oldobj)" + $run eval '(cd $xdir && ${LN_S} $baseobj $oldobj)' || exit $? + fi + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then + $show "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $run $rm $export_symbols + eval cmds=\"$export_symbols_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + if test -n "$export_symbols_regex"; then + $show "egrep -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\"" + $run eval 'egrep -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + $show "$mv \"${export_symbols}T\" \"$export_symbols\"" + $run eval '$mv "${export_symbols}T" "$export_symbols"' + fi + fi + fi + + if test -n "$export_symbols" && test -n "$include_expsyms"; then + $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"' + fi + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + else + gentop="$output_objdir/${outputname}x" + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + $show "mkdir $gentop" + $run mkdir "$gentop" + status=$? + if test $status -ne 0 && test ! -d "$gentop"; then + exit $status + fi + generated="$generated $gentop" + + for xlib in $convenience; do + # Extract the objects. + case "$xlib" in + [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; + *) xabs=`pwd`"/$xlib" ;; + esac + xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` + xdir="$gentop/$xlib" + + $show "${rm}r $xdir" + $run ${rm}r "$xdir" + $show "mkdir $xdir" + $run mkdir "$xdir" + status=$? + if test $status -ne 0 && test ! -d "$xdir"; then + exit $status + fi + $show "(cd $xdir && $AR x $xabs)" + $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? + + libobjs="$libobjs "`find $xdir -name \*.o -print -o -name \*.lo -print | $NL2SP` + done + fi + fi + + if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then + eval flag=\"$thread_safe_flag_spec\" + linkopts="$linkopts $flag" + fi + + # Do each of the archive commands. + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + eval cmds=\"$archive_expsym_cmds\" + else + eval cmds=\"$archive_cmds\" + fi + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + # Create links to the real library. + for linkname in $linknames; do + if test "$realname" != "$linkname"; then + $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)" + $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $? + fi + done + + # If -module or -export-dynamic was specified, set the dlname. + if test "$module" = yes || test "$export_dynamic" = yes; then + # On all known operating systems, these are identical. + dlname="$soname" + fi + fi + ;; + + *.lo | *.o | *.obj) + if test -n "$link_against_libtool_libs"; then + $echo "$modename: error: cannot link libtool libraries into objects" 1>&2 + exit 1 + fi + + if test -n "$deplibs"; then + $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2 + fi + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2 + fi + + if test -n "$rpath"; then + $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2 + fi + + if test -n "$xrpath"; then + $echo "$modename: warning: \`-R' is ignored for objects" 1>&2 + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for objects" 1>&2 + fi + + case "$output" in + *.lo) + if test -n "$objs"; then + $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2 + exit 1 + fi + libobj="$output" + obj=`$echo "X$output" | $Xsed -e "$lo2o"` + ;; + *) + libobj= + obj="$output" + ;; + esac + + # Delete the old objects. + $run $rm $obj $libobj + + # Objects from convenience libraries. This assumes + # single-version convenience libraries. Whenever we create + # different ones for PIC/non-PIC, this we'll have to duplicate + # the extraction. + reload_conv_objs= + gentop= + # reload_cmds runs $LD directly, so let us get rid of + # -Wl from whole_archive_flag_spec + wl= + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval reload_conv_objs=\"\$reload_objs $whole_archive_flag_spec\" + else + gentop="$output_objdir/${obj}x" + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + $show "mkdir $gentop" + $run mkdir "$gentop" + status=$? + if test $status -ne 0 && test ! -d "$gentop"; then + exit $status + fi + generated="$generated $gentop" + + for xlib in $convenience; do + # Extract the objects. + case "$xlib" in + [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; + *) xabs=`pwd`"/$xlib" ;; + esac + xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` + xdir="$gentop/$xlib" + + $show "${rm}r $xdir" + $run ${rm}r "$xdir" + $show "mkdir $xdir" + $run mkdir "$xdir" + status=$? + if test $status -ne 0 && test ! -d "$xdir"; then + exit $status + fi + $show "(cd $xdir && $AR x $xabs)" + $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? + + reload_conv_objs="$reload_objs "`find $xdir -name \*.o -print -o -name \*.lo -print | $NL2SP` + done + fi + fi + + # Create the old-style object. + reload_objs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" + + output="$obj" + eval cmds=\"$reload_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + # Exit if we aren't doing a library object file. + if test -z "$libobj"; then + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + exit 0 + fi + + if test "$build_libtool_libs" != yes; then + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + $show "echo timestamp > $libobj" + $run eval "echo timestamp > $libobj" || exit $? + exit 0 + fi + + if test -n "$pic_flag"; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs $reload_conv_objs" + output="$libobj" + eval cmds=\"$reload_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + else + # Just create a symlink. + $show $rm $libobj + $run $rm $libobj + xdir=`$echo "X$libobj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$libobj"; then + xdir="." + else + xdir="$xdir" + fi + baseobj=`$echo "X$libobj" | $Xsed -e 's%^.*/%%'` + oldobj=`$echo "X$baseobj" | $Xsed -e "$lo2o"` + $show "(cd $xdir && $LN_S $oldobj $baseobj)" + $run eval '(cd $xdir && $LN_S $oldobj $baseobj)' || exit $? + fi + + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + exit 0 + ;; + + # Anything else should be a program. + *) + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for programs" 1>&2 + fi + + if test "$preload" = yes; then + if test "$dlopen" = unknown && test "$dlopen_self" = unknown && + test "$dlopen_self_static" = unknown; then + $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support." + fi + fi + + if test -n "$rpath$xrpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath $xrpath; do + # This is the magic to use -rpath. + case "$compile_rpath " in + *" $libdir "*) ;; + *) compile_rpath="$compile_rpath $libdir" ;; + esac + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + fi + + # Now hardcode the library paths + rpath= + hardcode_libdirs= + for libdir in $compile_rpath $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case "$hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator" in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + compile_rpath="$rpath" + + rpath= + hardcode_libdirs= + for libdir in $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case "$hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator" in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + finalize_rpath="$rpath" + + output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'` + if test "X$output_objdir" = "X$output"; then + output_objdir="$objdir" + else + output_objdir="$output_objdir/$objdir" + fi + + # Create the binary in the object directory, then wrap it. + if test ! -d $output_objdir; then + $show "$mkdir $output_objdir" + $run $mkdir $output_objdir + status=$? + if test $status -ne 0 && test ! -d $output_objdir; then + exit $status + fi + fi + + if test -n "$libobjs" && test "$build_old_libs" = yes; then + # Transform all the library objects into standard objects. + compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + fi + + dlsyms= + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + if test -n "$NM" && test -n "$global_symbol_pipe"; then + dlsyms="${outputname}S.c" + else + $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2 + fi + fi + + if test -n "$dlsyms"; then + case "$dlsyms" in + "") ;; + *.c) + # Discover the nlist of each of the dlfiles. + nlist="$output_objdir/${outputname}.nm" + + $show "$rm $nlist ${nlist}S ${nlist}T" + $run $rm "$nlist" "${nlist}S" "${nlist}T" + + # Parse the name list into a source file. + $show "creating $output_objdir/$dlsyms" + + test -z "$run" && $echo > "$output_objdir/$dlsyms" "\ +/* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */ +/* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +/* Prevent the only kind of declaration conflicts we can make. */ +#define lt_preloaded_symbols some_other_symbol + +/* External symbol declarations for the compiler. */\ +" + + if test "$dlself" = yes; then + $show "generating symbol list for \`$output'" + + test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist" + + # Add our own program objects to the symbol list. + progfiles=`$echo "X$objs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + for arg in $progfiles; do + $show "extracting global C symbols from \`$arg'" + $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" + done + + if test -n "$exclude_expsyms"; then + $run eval 'egrep -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' + $run eval '$mv "$nlist"T "$nlist"' + fi + + if test -n "$export_symbols_regex"; then + $run eval 'egrep -e "$export_symbols_regex" "$nlist" > "$nlist"T' + $run eval '$mv "$nlist"T "$nlist"' + fi + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + export_symbols="$output_objdir/$output.exp" + $run $rm $export_symbols + $run eval "sed -n -e '/^: @PROGRAM@$/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' + else + $run eval "sed -e 's/\([][.*^$]\)/\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$output.exp"' + $run eval 'grep -f "$output_objdir/$output.exp" < "$nlist" > "$nlist"T' + $run eval 'mv "$nlist"T "$nlist"' + fi + fi + + for arg in $dlprefiles; do + $show "extracting global C symbols from \`$arg'" + name=`echo "$arg" | sed -e 's%^.*/%%'` + $run eval 'echo ": $name " >> "$nlist"' + $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" + done + + if test -z "$run"; then + # Make sure we have at least an empty file. + test -f "$nlist" || : > "$nlist" + + if test -n "$exclude_expsyms"; then + egrep -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T + $mv "$nlist"T "$nlist" + fi + + # Try sorting and uniquifying the output. + if grep -v "^: " < "$nlist" | sort +2 | uniq > "$nlist"S; then + : + else + grep -v "^: " < "$nlist" > "$nlist"S + fi + + if test -f "$nlist"S; then + eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"' + else + echo '/* NONE */' >> "$output_objdir/$dlsyms" + fi + + $echo >> "$output_objdir/$dlsyms" "\ + +#undef lt_preloaded_symbols + +#if defined (__STDC__) && __STDC__ +# define lt_ptr_t void * +#else +# define lt_ptr_t char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + lt_ptr_t address; +} +lt_preloaded_symbols[] = +{\ +" + + sed -n -e 's/^: \([^ ]*\) $/ {\"\1\", (lt_ptr_t) 0},/p' \ + -e 's/^. \([^ ]*\) \([^ ]*\)$/ {"\2", (lt_ptr_t) \&\2},/p' \ + < "$nlist" >> "$output_objdir/$dlsyms" + + $echo >> "$output_objdir/$dlsyms" "\ + {0, (lt_ptr_t) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif\ +" + fi + + pic_flag_for_symtable= + case "$host" in + # compiling the symbol table file with pic_flag works around + # a FreeBSD bug that causes programs to crash when -lm is + # linked before any other PIC object. But we must not use + # pic_flag when linking with -static. The problem exists in + # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. + *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) + case "$compile_command " in + *" -static "*) ;; + *) pic_flag_for_symtable=" $pic_flag -DPIC -DFREEBSD_WORKAROUND";; + esac;; + *-*-hpux*) + case "$compile_command " in + *" -static "*) ;; + *) pic_flag_for_symtable=" $pic_flag -DPIC";; + esac + esac + + # Now compile the dynamic symbol file. + $show "(cd $output_objdir && $CC -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")" + $run eval '(cd $output_objdir && $CC -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $? + + # Clean up the generated files. + $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T" + $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T" + + # Transform the symbol file into the correct name. + compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` + ;; + *) + $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2 + exit 1 + ;; + esac + else + # We keep going just in case the user didn't refer to + # lt_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + + # Nullify the symbol file. + compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"` + fi + + if test -z "$link_against_libtool_libs" || test "$build_libtool_libs" != yes; then + # Replace the output file specification. + compile_command=`$echo "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + link_command="$compile_command$compile_rpath" + + # We have no uninstalled library dependencies, so finalize right now. + $show "$link_command" + $run eval "$link_command" + status=$? + + # Delete the generated files. + if test -n "$dlsyms"; then + $show "$rm $output_objdir/${outputname}S.${objext}" + $run $rm "$output_objdir/${outputname}S.${objext}" + fi + + exit $status + fi + + if test -n "$shlibpath_var"; then + # We should set the shlibpath_var + rpath= + for dir in $temp_rpath; do + case "$dir" in + [\\/]* | [A-Za-z]:[\\/]*) + # Absolute path. + rpath="$rpath$dir:" + ;; + *) + # Relative path: add a thisdir entry. + rpath="$rpath\$thisdir/$dir:" + ;; + esac + done + temp_rpath="$rpath" + fi + + if test -n "$compile_shlibpath$finalize_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + compile_var= + finalize_var= + if test -n "$runpath_var"; then + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + compile_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + if test -n "$finalize_perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $finalize_perm_rpath; do + rpath="$rpath$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test "$hardcode_action" = relink; then + # Fast installation is not supported + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + + $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2 + $echo "$modename: \`$output' will be relinked during installation" 1>&2 + else + if test "$fast_install" != no; then + link_command="$finalize_var$compile_command$finalize_rpath" + if test "$fast_install" = yes; then + relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'` + else + # fast_install is set to needless + relink_command= + fi + else + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + fi + fi + + # Replace the output file specification. + link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` + + # Delete the old output files. + $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname + + $show "$link_command" + $run eval "$link_command" || exit $? + + # Now create the wrapper script. + $show "creating $output" + + # Quote the relink command for shipping. + if test -n "$relink_command"; then + relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"` + fi + + # Quote $echo for shipping. + if test "X$echo" = "X$SHELL $0 --fallback-echo"; then + case "$0" in + [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $0 --fallback-echo";; + *) qecho="$SHELL `pwd`/$0 --fallback-echo";; + esac + qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"` + else + qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"` + fi + + # Only actually do things if our run command is non-null. + if test -z "$run"; then + # win32 will think the script is a binary if it has + # a .exe suffix, so we strip it off here. + case $output in + *.exe) output=`echo $output|sed 's,.exe$,,'` ;; + esac + $rm $output + trap "$rm $output; exit 1" 1 2 15 + + $echo > $output "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='sed -e 1s/^X//' +sed_quote_subst='$sed_quote_subst' + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +if test \"\${CDPATH+set}\" = set; then CDPATH=:; export CDPATH; fi + +relink_command=\"$relink_command\" + +# This environment variable determines our operation mode. +if test \"\$libtool_install_magic\" = \"$magic\"; then + # install mode needs the following variable: + link_against_libtool_libs='$link_against_libtool_libs' +else + # When we are sourced in execute mode, \$file and \$echo are already set. + if test \"\$libtool_execute_magic\" != \"$magic\"; then + echo=\"$qecho\" + file=\"\$0\" + # Make sure echo works. + if test \"X\$1\" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift + elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then + # Yippee, \$echo works! + : + else + # Restart under the correct shell, and then maybe \$echo will work. + exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"} + fi + fi\ +" + $echo >> $output "\ + + # Find the directory that this script lives in. + thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` + test \"x\$thisdir\" = \"x\$file\" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld \"\$file\" | sed -n 's/.*-> //p'\` + while test -n \"\$file\"; do + destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test \"x\$destdir\" != \"x\$file\"; then + case \"\$destdir\" in + [\\/]* | [A-Za-z]:[\\/]*) thisdir=\"\$destdir\" ;; + *) thisdir=\"\$thisdir/\$destdir\" ;; + esac + fi + + file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | sed -n 's/.*-> //p'\` + done + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test "$fast_install" = yes; then + echo >> $output "\ + program=lt-'$outputname' + progdir=\"\$thisdir/$objdir\" + + if test ! -f \"\$progdir/\$program\" || \\ + { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | sed 1q\`; \\ + test \"X\$file\" != \"X\$progdir/\$program\"; }; then + + file=\"\$\$-\$program\" + + if test ! -d \"\$progdir\"; then + $mkdir \"\$progdir\" + else + $rm \"\$progdir/\$file\" + fi" + + echo >> $output "\ + + # relink executable if necessary + if test -n \"\$relink_command\"; then + if (cd \"\$thisdir\" && eval \$relink_command); then : + else + $rm \"\$progdir/\$file\" + exit 1 + fi + fi + + $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || + { $rm \"\$progdir/\$program\"; + $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; } + $rm \"\$progdir/\$file\" + fi" + else + echo >> $output "\ + program='$outputname' + progdir=\"\$thisdir/$objdir\" +" + fi + + echo >> $output "\ + + if test -f \"\$progdir/\$program\"; then" + + # Export our shlibpath_var if we have one. + if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + $echo >> $output "\ + # Add our own library path to $shlibpath_var + $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" + + # Some systems cannot cope with colon-terminated $shlibpath_var + # The second colon is a workaround for a bug in BeOS R4 sed + $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\` + + export $shlibpath_var +" + fi + + # fixup the dll searchpath if we need to. + if test -n "$dllsearchpath"; then + $echo >> $output "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + $echo >> $output "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. +" + case $host in + # win32 systems need to use the prog path for dll + # lookup to work + *-*-cygwin*) + $echo >> $output "\ + exec \$progdir/\$program \${1+\"\$@\"} +" + ;; + + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2*) + $echo >> $output "\ + exec \$progdir\\\\\$program \${1+\"\$@\"} +" + ;; + + *) + $echo >> $output "\ + # Export the path to the program. + PATH=\"\$progdir:\$PATH\" + export PATH + + exec \$program \${1+\"\$@\"} +" + ;; + esac + $echo >> $output "\ + \$echo \"\$0: cannot exec \$program \${1+\"\$@\"}\" + exit 1 + fi + else + # The program doesn't exist. + \$echo \"\$0: error: \$progdir/\$program does not exist\" 1>&2 + \$echo \"This script is just a wrapper for \$program.\" 1>&2 + echo \"See the $PACKAGE documentation for more information.\" 1>&2 + exit 1 + fi +fi\ +" + chmod +x $output + fi + exit 0 + ;; + esac + + # See if we need to build an old-fashioned archive. + for oldlib in $oldlibs; do + + if test "$build_libtool_libs" = convenience; then + oldobjs="$libobjs_save" + addlibs="$convenience" + build_libtool_libs=no + else + if test "$build_libtool_libs" = module; then + oldobjs="$libobjs_save" + build_libtool_libs=no + else + oldobjs="$objs "`$echo "X$libobjs_save" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP` + fi + addlibs="$old_convenience" + fi + + if test -n "$addlibs"; then + gentop="$output_objdir/${outputname}x" + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + $show "mkdir $gentop" + $run mkdir "$gentop" + status=$? + if test $status -ne 0 && test ! -d "$gentop"; then + exit $status + fi + generated="$generated $gentop" + + # Add in members from convenience archives. + for xlib in $addlibs; do + # Extract the objects. + case "$xlib" in + [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; + *) xabs=`pwd`"/$xlib" ;; + esac + xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` + xdir="$gentop/$xlib" + + $show "${rm}r $xdir" + $run ${rm}r "$xdir" + $show "mkdir $xdir" + $run mkdir "$xdir" + status=$? + if test $status -ne 0 && test ! -d "$xdir"; then + exit $status + fi + $show "(cd $xdir && $AR x $xabs)" + $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? + + oldobjs="$oldobjs "`find $xdir -name \*.${objext} -print -o -name \*.lo -print | $NL2SP` + done + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then + eval cmds=\"$old_archive_from_new_cmds\" + else + # Ensure that we have .o objects in place in case we decided + # not to build a shared library, and have fallen back to building + # static libs even though --disable-static was passed! + for oldobj in $oldobjs; do + if test ! -f $oldobj; then + xdir=`$echo "X$oldobj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$oldobj"; then + xdir="." + else + xdir="$xdir" + fi + baseobj=`$echo "X$oldobj" | $Xsed -e 's%^.*/%%'` + obj=`$echo "X$baseobj" | $Xsed -e "$o2lo"` + $show "(cd $xdir && ${LN_S} $obj $baseobj)" + $run eval '(cd $xdir && ${LN_S} $obj $baseobj)' || exit $? + fi + done + + eval cmds=\"$old_archive_cmds\" + fi + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + done + + if test -n "$generated"; then + $show "${rm}r$generated" + $run ${rm}r$generated + fi + + # Now create the libtool archive. + case "$output" in + *.la) + old_library= + test "$build_old_libs" = yes && old_library="$libname.$libext" + $show "creating $output" + + if test -n "$xrpath"; then + temp_xrpath= + for libdir in $xrpath; do + temp_xrpath="$temp_xrpath -R$libdir" + done + dependency_libs="$temp_xrpath $dependency_libs" + fi + + # Only create the output if not a dry run. + if test -z "$run"; then + for installed in no yes; do + if test "$installed" = yes; then + if test -z "$install_libdir"; then + break + fi + output="$output_objdir/$outputname"i + fi + $rm $output + $echo > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='$dlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Libraries that this one depends upon. +dependency_libs='$dependency_libs' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Is this an already installed library? +installed=$installed + +# Directory that this library needs to be installed in: +libdir='$install_libdir'\ +" + done + fi + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)" + $run eval "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)" || exit $? + ;; + esac + exit 0 + ;; + + # libtool install mode + install) + modename="$modename: install" + + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh; then + # Aesthetically quote it. + arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"` + case "$arg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + install_prog="$arg " + arg="$1" + shift + else + install_prog= + arg="$nonopt" + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case "$arg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog$arg" + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=no + stripme= + for arg + do + if test -n "$dest"; then + files="$files $dest" + dest="$arg" + continue + fi + + case "$arg" in + -d) isdir=yes ;; + -f) prev="-f" ;; + -g) prev="-g" ;; + -m) prev="-m" ;; + -o) prev="-o" ;; + -s) + stripme=" -s" + continue + ;; + -*) ;; + + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + prev= + else + dest="$arg" + continue + fi + ;; + esac + + # Aesthetically quote the argument. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case "$arg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog $arg" + done + + if test -z "$install_prog"; then + $echo "$modename: you must specify an install program" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + if test -n "$prev"; then + $echo "$modename: the \`$prev' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + if test -z "$files"; then + if test -z "$dest"; then + $echo "$modename: no file or destination specified" 1>&2 + else + $echo "$modename: you must specify a destination" 1>&2 + fi + $echo "$help" 1>&2 + exit 1 + fi + + # Strip any trailing slash from the destination. + dest=`$echo "X$dest" | $Xsed -e 's%/$%%'` + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=yes + if test "$isdir" = yes; then + destdir="$dest" + destname= + else + destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'` + test "X$destdir" = "X$dest" && destdir=. + destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'` + + # Not a directory, so check to see that there is only one file specified. + set dummy $files + if test $# -gt 2; then + $echo "$modename: \`$dest' is not a directory" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + fi + case "$destdir" in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + for file in $files; do + case "$file" in + *.lo) ;; + *) + $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case "$file" in + *.a | *.lib) + # Do the static libraries later. + staticlibs="$staticlibs $file" + ;; + + *.la) + # Check to see that this really is a libtool archive. + if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$file' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + library_names= + old_library= + # If there is no directory component, then add one. + case "$file" in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) current_libdirs="$current_libdirs $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) future_libdirs="$future_libdirs $libdir" ;; + esac + fi + + dir="`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/" + test "X$dir" = "X$file/" && dir= + dir="$dir$objdir" + + # See the names of the shared library. + set dummy $library_names + if test -n "$2"; then + realname="$2" + shift + shift + + # Install the shared library and build the symlinks. + $show "$install_prog $dir/$realname $destdir/$realname" + $run eval "$install_prog $dir/$realname $destdir/$realname" || exit $? + + if test $# -gt 0; then + # Delete the old symlinks, and create new ones. + for linkname + do + if test "$linkname" != "$realname"; then + $show "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)" + $run eval "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)" + fi + done + fi + + # Do each command in the postinstall commands. + lib="$destdir/$realname" + eval cmds=\"$postinstall_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + # Install the pseudo-library for information purposes. + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + instname="$dir/$name"i + $show "$install_prog $instname $destdir/$name" + $run eval "$install_prog $instname $destdir/$name" || exit $? + + # Maybe install the static library, too. + test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + destfile="$destdir/$destfile" + fi + + # Deduce the name of the destination old-style object file. + case "$destfile" in + *.lo) + staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"` + ;; + *.o | *.obj) + staticdest="$destfile" + destfile= + ;; + *) + $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + esac + + # Install the libtool object if requested. + if test -n "$destfile"; then + $show "$install_prog $file $destfile" + $run eval "$install_prog $file $destfile" || exit $? + fi + + # Install the old object if enabled. + if test "$build_old_libs" = yes; then + # Deduce the name of the old-style object file. + staticobj=`$echo "X$file" | $Xsed -e "$lo2o"` + + $show "$install_prog $staticobj $staticdest" + $run eval "$install_prog \$staticobj \$staticdest" || exit $? + fi + exit 0 + ;; + + *) + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + destfile="$destdir/$destfile" + fi + + # Do a test to see if this is really a libtool program. + if (sed -e '4q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + link_against_libtool_libs= + relink_command= + + # If there is no directory component, then add one. + case "$file" in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Check the variables that should have been set. + if test -z "$link_against_libtool_libs"; then + $echo "$modename: invalid libtool wrapper script \`$file'" 1>&2 + exit 1 + fi + + finalize=yes + for lib in $link_against_libtool_libs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + # If there is no directory component, then add one. + case "$lib" in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + fi + libfile="$libdir/`$echo "X$lib" | $Xsed -e 's%^.*/%%g'`" + if test -n "$libdir" && test ! -f "$libfile"; then + $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2 + finalize=no + fi + done + + outputname= + if test "$fast_install" = no && test -n "$relink_command"; then + if test "$finalize" = yes && test -z "$run"; then + tmpdir="/tmp" + test -n "$TMPDIR" && tmpdir="$TMPDIR" + tmpdir="$tmpdir/libtool-$$" + if $mkdir -p "$tmpdir" && chmod 700 "$tmpdir"; then : + else + $echo "$modename: error: cannot create temporary directory \`$tmpdir'" 1>&2 + continue + fi + outputname="$tmpdir/$file" + # Replace the output file specification. + relink_command=`$echo "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'` + + $show "$relink_command" + if $run eval "$relink_command"; then : + else + $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 + ${rm}r "$tmpdir" + continue + fi + file="$outputname" + else + $echo "$modename: warning: cannot relink \`$file'" 1>&2 + fi + else + # Install the binary that we compiled earlier. + file=`$echo "X$file" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + $show "$install_prog$stripme $file $destfile" + $run eval "$install_prog\$stripme \$file \$destfile" || exit $? + test -n "$outputname" && ${rm}r "$tmpdir" + ;; + esac + done + + for file in $staticlibs; do + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + + # Set up the ranlib parameters. + oldlib="$destdir/$name" + + $show "$install_prog $file $oldlib" + $run eval "$install_prog \$file \$oldlib" || exit $? + + # Do each command in the postinstall commands. + eval cmds=\"$old_postinstall_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + done + + if test -n "$future_libdirs"; then + $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2 + fi + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + test -n "$run" && current_libdirs=" -n$current_libdirs" + exec $SHELL $0 --finish$current_libdirs + exit 1 + fi + + exit 0 + ;; + + # libtool finish mode + finish) + modename="$modename: finish" + libdirs="$nonopt" + admincmds= + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + for dir + do + libdirs="$libdirs $dir" + done + + for libdir in $libdirs; do + if test -n "$finish_cmds"; then + # Do each command in the finish commands. + eval cmds=\"$finish_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || admincmds="$admincmds + $cmd" + done + IFS="$save_ifs" + fi + if test -n "$finish_eval"; then + # Do the single finish_eval. + eval cmds=\"$finish_eval\" + $run eval "$cmds" || admincmds="$admincmds + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + test "$show" = : && exit 0 + + echo "----------------------------------------------------------------------" + echo "Libraries have been installed in:" + for libdir in $libdirs; do + echo " $libdir" + done + echo + echo "If you ever happen to want to link against installed libraries" + echo "in a given directory, LIBDIR, you must either use libtool, and" + echo "specify the full pathname of the library, or use \`-LLIBDIR'" + echo "flag during linking and do at least one of the following:" + if test -n "$shlibpath_var"; then + echo " - add LIBDIR to the \`$shlibpath_var' environment variable" + echo " during execution" + fi + if test -n "$runpath_var"; then + echo " - add LIBDIR to the \`$runpath_var' environment variable" + echo " during linking" + fi + if test -n "$hardcode_libdir_flag_spec"; then + libdir=LIBDIR + eval flag=\"$hardcode_libdir_flag_spec\" + + echo " - use the \`$flag' linker flag" + fi + if test -n "$admincmds"; then + echo " - have your system administrator run these commands:$admincmds" + fi + if test -f /etc/ld.so.conf; then + echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" + fi + echo + echo "See any operating system documentation about shared libraries for" + echo "more information, such as the ld(1) and ld.so(8) manual pages." + echo "----------------------------------------------------------------------" + exit 0 + ;; + + # libtool execute mode + execute) + modename="$modename: execute" + + # The first argument is the command name. + cmd="$nonopt" + if test -z "$cmd"; then + $echo "$modename: you must specify a COMMAND" 1>&2 + $echo "$help" + exit 1 + fi + + # Handle -dlopen flags immediately. + for file in $execute_dlfiles; do + if test ! -f "$file"; then + $echo "$modename: \`$file' is not a file" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + dir= + case "$file" in + *.la) + # Check to see that this really is a libtool archive. + if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + # Read the libtool library. + dlname= + library_names= + + # If there is no directory component, then add one. + case "$file" in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'" + continue + fi + + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + + if test -f "$dir/$objdir/$dlname"; then + dir="$dir/$objdir" + else + $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2 + exit 1 + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + ;; + + *) + $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2 + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir="$absdir" + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic="$magic" + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case "$file" in + -*) ;; + *) + # Do a test to see if this is really a libtool program. + if (sed -e '4q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + # If there is no directory component, then add one. + case "$file" in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Transform arg to wrapped name. + file="$progdir/$program" + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"` + args="$args \"$file\"" + done + + if test -z "$run"; then + if test -n "$shlibpath_var"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + fi + + # Restore saved enviroment variables + if test "${save_LC_ALL+set}" = set; then + LC_ALL="$save_LC_ALL"; export LC_ALL + fi + if test "${save_LANG+set}" = set; then + LANG="$save_LANG"; export LANG + fi + + # Now actually exec the command. + eval "exec \$cmd$args" + + $echo "$modename: cannot exec \$cmd$args" + exit 1 + else + # Display what would be done. + if test -n "$shlibpath_var"; then + eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\"" + $echo "export $shlibpath_var" + fi + $echo "$cmd$args" + exit 0 + fi + ;; + + # libtool uninstall mode + uninstall) + modename="$modename: uninstall" + rm="$nonopt" + files= + + for arg + do + case "$arg" in + -*) rm="$rm $arg" ;; + *) files="$files $arg" ;; + esac + done + + if test -z "$rm"; then + $echo "$modename: you must specify an RM program" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + for file in $files; do + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + + rmfiles="$file" + + case "$name" in + *.la) + # Possibly a libtool archive, so verify it. + if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + . $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + rmfiles="$rmfiles $dir/$n" + done + test -n "$old_library" && rmfiles="$rmfiles $dir/$old_library" + + $show "$rm $rmfiles" + $run $rm $rmfiles + + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + eval cmds=\"$postuninstall_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" + done + IFS="$save_ifs" + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + eval cmds=\"$old_postuninstall_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" + done + IFS="$save_ifs" + fi + + # FIXME: should reinstall the best remaining shared library. + fi + ;; + + *.lo) + if test "$build_old_libs" = yes; then + oldobj=`$echo "X$name" | $Xsed -e "$lo2o"` + rmfiles="$rmfiles $dir/$oldobj" + fi + $show "$rm $rmfiles" + $run $rm $rmfiles + ;; + + *) + $show "$rm $rmfiles" + $run $rm $rmfiles + ;; + esac + done + exit 0 + ;; + + "") + $echo "$modename: you must specify a MODE" 1>&2 + $echo "$generic_help" 1>&2 + exit 1 + ;; + esac + + $echo "$modename: invalid operation mode \`$mode'" 1>&2 + $echo "$generic_help" 1>&2 + exit 1 +fi # test -z "$show_help" + +# We need to display help for each of the modes. +case "$mode" in +"") $echo \ +"Usage: $modename [OPTION]... [MODE-ARG]... + +Provide generalized library-building support services. + + --config show all configuration variables + --debug enable verbose shell tracing +-n, --dry-run display commands without modifying any files + --features display basic configuration information and exit + --finish same as \`--mode=finish' + --help display this help message and exit + --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS] + --quiet same as \`--silent' + --silent don't print informational messages + --version print version information + +MODE must be one of the following: + + compile compile a source file into a libtool object + execute automatically set library path, then run a program + finish complete the installation of libtool libraries + install install libraries or executables + link create a library or an executable + uninstall remove libraries from an installed directory + +MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for +a more detailed description of MODE." + exit 0 + ;; + +compile) + $echo \ +"Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +This mode accepts the following additional options: + + -o OUTPUT-FILE set the output file name to OUTPUT-FILE + -static always build a \`.o' file suitable for static linking + +COMPILE-COMMAND is a command to be used in creating a \`standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix \`.c' with the +library object suffix, \`.lo'." + ;; + +execute) + $echo \ +"Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to \`-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments." + ;; + +finish) + $echo \ +"Usage: $modename [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the \`--dry-run' option if you just want to see what would be executed." + ;; + +install) + $echo \ +"Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the \`install' or \`cp' program. + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized)." + ;; + +link) + $echo \ +"Usage: $modename [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -avoid-version do not add a version suffix if possible + -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -export-symbols SYMFILE + try to export only the symbols listed in SYMFILE + -export-symbols-regex REGEX + try to export only the symbols matching REGEX + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -module build a library that can dlopened + -no-undefined declare that a library does not refer to external symbols + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -release RELEASE specify package release information + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries + -static do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + +All other options (arguments beginning with \`-') are ignored. + +Every other argument is treated as a filename. Files ending in \`.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in \`.la', then a libtool library is created, +only library objects (\`.lo' files) may be specified, and \`-rpath' is +required, except when creating a convenience library. + +If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created +using \`ar' and \`ranlib', or on Windows using \`lib'. + +If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file +is created, otherwise an executable program is created." + ;; + +uninstall) + $echo \ +"Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM." + ;; + +*) + $echo "$modename: invalid operation mode \`$mode'" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; +esac + +echo +$echo "Try \`$modename --help' for more information about other modes." + +exit 0 + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: +#! /bin/bash diff --git a/db/dist/rec_ctemp b/db/dist/rec_ctemp new file mode 100644 index 000000000..6be6d3166 --- /dev/null +++ b/db/dist/rec_ctemp @@ -0,0 +1,62 @@ +/* + * __PREF_FUNC_recover -- + * Recovery function for FUNC. + * + * PUBLIC: int __PREF_FUNC_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__PREF_FUNC_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __PREF_FUNC_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__PREF_FUNC_print); + REC_INTRO(__PREF_FUNC_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + diff --git a/db/dist/s_all b/db/dist/s_all new file mode 100644 index 000000000..dab6c7591 --- /dev/null +++ b/db/dist/s_all @@ -0,0 +1,16 @@ +#!/bin/sh - +# $Id: s_all,v 1.7 2000/12/22 15:35:32 bostic Exp $ + +sh s_perm # permissions. +sh s_symlink # symbolic links. +sh s_config # autoconf. +sh s_readme # db/README file. +sh s_recover # logging/recovery files. +sh s_rpc # RPC files. +sh s_include # standard include files. +sh s_win32 # Win32 include files. +sh s_win32_dsp # Win32 build environment. +sh s_vxworks # VxWorks include files. +sh s_java # Java support. +sh s_tcl # Tcl support. +sh s_tags # Tags files. diff --git a/db/dist/s_config b/db/dist/s_config new file mode 100755 index 000000000..870109c38 --- /dev/null +++ b/db/dist/s_config @@ -0,0 +1,37 @@ +#!/bin/sh - +# $Id: s_config,v 1.3 2000/07/13 18:38:46 bostic Exp $ +# +# Build the autoconfiguration files. + +msgm4="dnl DO NOT EDIT: automatically built by dist/s_config." + +. ./RELEASE + +echo "Building aclocal.m4" +rm -f aclocal.m4 +(echo "$msgm4" && + echo "AC_DEFUN(AM_VERSION_SET, [" && + echo "AC_SUBST(DB_VERSION_MAJOR)" && + echo "DB_VERSION_MAJOR=$DB_VERSION_MAJOR" && + echo "AC_SUBST(DB_VERSION_MINOR)" && + echo "DB_VERSION_MINOR=$DB_VERSION_MINOR" && + echo "AC_SUBST(DB_VERSION_PATCH)" && + echo "DB_VERSION_PATCH=$DB_VERSION_PATCH" && + echo "AC_SUBST(DB_VERSION_STRING)" && + echo "DB_VERSION_STRING=\"\\\"$DB_VERSION_STRING\\\"\"" && + echo "])dnl" && + cat aclocal/*.m4) > aclocal.m4 +chmod 444 aclocal.m4 + +rm -f config.hin +echo "Building config.hin (autoheader)" +(autoheader configure.in > config.hin) 2>&1 | \ + sed '/warning: AC_TRY_RUN called without default/d' +chmod 444 config.hin + +rm -f configure +echo "Building configure (autoconf)" +autoconf 2>&1 | sed '/warning: AC_TRY_RUN called without default/d' + +chmod 555 configure config.guess config.sub install-sh +rm -f aclocal.m4 diff --git a/db/dist/s_include b/db/dist/s_include new file mode 100755 index 000000000..fee6e5033 --- /dev/null +++ b/db/dist/s_include @@ -0,0 +1,33 @@ +#!/bin/sh - +# $Id: s_include,v 1.7 2000/07/13 18:38:46 bostic Exp $ +# +# Build the automatically generated function prototype files. + +msgc="/* DO NOT EDIT: automatically built by dist/s_include. */" +cxx_if="#if defined(__cplusplus)" +cxx_head="extern \"C\" {" +cxx_foot="}" +cxx_endif="#endif" + +tmp=/tmp/__db_inc.$$ +trap 'rm -f $tmp ; exit 0' 0 1 2 3 13 15 + +for i in db btree clib common env hash \ + lock log mp mutex os qam rpc_client rpc_server tcl txn xa; do + f=../include/${i}_ext.h + (echo "$msgc" && + echo "#ifndef _${i}_ext_h_" && + echo "#define _${i}_ext_h_" && + echo "$cxx_if" && + echo "$cxx_head" && + echo "$cxx_endif" && + sed -n "s/^ \* PUBLIC:[ ]\(.*\)/\1/p" ../$i/*.c; + [ $i = os ] && + sed -n "s/^ \* PUBLIC:[ ]\(.*\)/\1/p" ../os_win32/*.c; + echo "$cxx_if" && + echo "$cxx_foot" && + echo "$cxx_endif" && + echo "#endif /* _${i}_ext_h_ */") > $tmp + cmp $tmp $f > /dev/null 2>&1 || + (echo "Building $f" && rm -f $f && cp $tmp $f && chmod 444 $f) +done diff --git a/db/dist/s_java b/db/dist/s_java new file mode 100755 index 000000000..f324678ab --- /dev/null +++ b/db/dist/s_java @@ -0,0 +1,31 @@ +#!/bin/sh - +# $Id: s_java,v 1.3 2000/07/13 18:38:46 bostic Exp $ +# +# Build the Java files. + +msgcxx="// DO NOT EDIT: automatically built by dist/s_java." + +. RELEASE + +f=../java/src/com/sleepycat/db/DbConstants.java +echo "Building $f" +rm -f $f +(echo "$msgcxx" && \ + echo && + echo 'package com.sleepycat.db;' && + echo && + echo 'public class DbConstants' && + echo '{' && + egrep '^#define.DB_' ../include/db.src | \ + sed -e '/"/d' \ + -e '/@DB_VERSION_/d' \ + -e '/DB_REDO/d' \ + -e '/DB_UNDO/d' \ + -e 's/[()]/ /g' \ + -e 's/\/\*/ /' | \ + awk '{ print "\tpublic static final int " $2 " = " $3 ";" }' && + echo " public static final int DB_VERSION_MAJOR = $DB_VERSION_MAJOR;" && + echo " public static final int DB_VERSION_MINOR = $DB_VERSION_MINOR;" && + echo " public static final int DB_VERSION_PATCH = $DB_VERSION_PATCH;" && + echo '}') > $f +chmod 444 $f diff --git a/db/dist/s_perm b/db/dist/s_perm new file mode 100755 index 000000000..4b0997f2f --- /dev/null +++ b/db/dist/s_perm @@ -0,0 +1,37 @@ +#!/bin/sh - +# $Id: s_perm,v 1.9 2001/01/24 15:55:38 bostic Exp $ + +echo 'Updating Berkeley DB source tree permissions...' + +run() +{ + echo " $1 ($2)" + if [ -f "../$1" ]; then + chmod "$2" "../$1" + else + echo "$1: no such file or directory" + exit 1 + fi +} + +run dist/build/chk.def 0555 +run dist/build/chk.define 0555 +run dist/build/chk.offt 0555 +run dist/build/chk.srcfiles 0555 +run dist/build/chk.tags 0555 +run dist/config.guess 0555 +run dist/config.sub 0555 +run dist/configure 0555 +run dist/install-sh 0555 +run dist/s_config 0555 +run dist/s_include 0555 +run dist/s_java 0555 +run dist/s_perm 0555 +run dist/s_readme 0555 +run dist/s_recover 0555 +run dist/s_symlink 0555 +run dist/s_tags 0555 +run dist/s_tcl 0555 +run dist/s_win32 0555 +run perl.BerkeleyDB/dbinfo 0555 +run perl.BerkeleyDB/mkpod 0555 diff --git a/db/dist/s_readme b/db/dist/s_readme new file mode 100755 index 000000000..9ff8a69bc --- /dev/null +++ b/db/dist/s_readme @@ -0,0 +1,18 @@ +#!/bin/sh - +# $Id: s_readme,v 1.2 2000/01/27 21:42:18 bostic Exp $ +# +# Build the README. + +. RELEASE + +f=../README +echo "Building $f" +rm -f $f +(echo "$DB_VERSION_STRING" && + echo "" && + echo -n "This is version " && + echo -n "$DB_VERSION_MAJOR.$DB_VERSION_MINOR.$DB_VERSION_PATCH" && + echo " of Berkeley DB from Sleepycat Software. To view" && + echo "the release and installation documentation, load the distribution file" && + echo "docs/index.html into your web browser.") > $f +chmod 444 $f diff --git a/db/dist/s_recover b/db/dist/s_recover new file mode 100755 index 000000000..0e8b3731c --- /dev/null +++ b/db/dist/s_recover @@ -0,0 +1,56 @@ +#!/bin/sh - +# $Id: s_recover,v 1.3 2000/03/30 05:24:36 krinsky Exp $ +# +# Build the automatically generated logging/recovery files. + +DIR="db btree hash log qam txn" + +t=/tmp/__db_$$ +loglist=../test/logtrack.list +rm -f $t +rm -f $loglist + +trap 'rm -f $t; exit 1' 1 2 3 13 15 + +# Check to make sure we haven't duplicated a log record entry, and build +# the list of log record types that the test suite uses. +for i in $DIR; do + p=none + for f in ../$i/*.src; do + # Grab the PREFIX; there should only be one per file, and + # so it's okay to just take the first. + grep '^PREFIX' $f | head -1 + egrep '^DEPRECATED[ ]|^BEGIN[ ]' $f | \ + awk '{print $1 "\t" $2 "\t" $3}' + + done +done > $loglist +grep -v '^PREFIX' $loglist | awk '{print $2 "\t" $3}' | sort +1 -n | \ + uniq -d -f 1 > $t +[ -s $t ] && { + echo "DUPLICATE LOG VALUES:" + cat $t + rm -f $t + exit 1 +} +rm -f $t + +for i in db btree hash log qam txn; do + for f in ../$i/*.src; do + subsystem=`basename $f .src` + header_file=../include/${subsystem}_auto.h + source_file=../$i/${subsystem}_auto.c + template_file=template/rec_${subsystem} + template_source=. + + echo "Building $source_file, $header_file, $template_file" + rm -f $header_file $source_file $template_file + awk -f gen_rec.awk \ + -v subsystem=$subsystem \ + -v source_file=$source_file \ + -v header_file=$header_file \ + -v template_file=$template_file \ + -v template_dir=. < $f + chmod 444 $header_file $source_file $template_file + done +done diff --git a/db/dist/s_rpc b/db/dist/s_rpc new file mode 100644 index 000000000..88c9f47cb --- /dev/null +++ b/db/dist/s_rpc @@ -0,0 +1,70 @@ +#!/bin/sh - +# $Id: s_rpc,v 11.6 2000/04/26 19:15:51 sue Exp $ +# +# Build the automatically generated RPC files + +echo "Building RPC client/server files" + +client_file=../rpc_client/gen_client.c +cproto_file=../include/gen_client_ext.h +ctmpl_file=./template/gen_client_ret +header_file=../include/db_server.h +rpcclnt_file=../rpc_client/db_server_clnt.c +rpcsvc_file=../rpc_server/db_server_svc.c +rpcxdr_file=../rpc_server/db_server_xdr.c +sed_file=../rpc_server/db_server_proc.sed +server_file=../rpc_server/gen_db_server.c +sproto_file=../include/gen_server_ext.h +stmpl_file=./template/db_server_proc +xdr_file=../rpc_server/db_server.x + +# +# NOTE: We do NOT want to remove proc_file. It is what we apply +# sed_file to, but we do not want to remove it. +# +proc_file=../rpc_server/db_server_proc.c +svrsed_file=../rpc_server/db_server_svc.sed +rpcsed_file=../rpc_server/db_server.sed + +rm -f $client_file $cproto_file $ctmpl_file $header_file $rpcsvc_file \ + $rpcclnt_file $rpcxdr_file $sed_file $server_file $sproto_file \ + $stmpl_file $xdr_file + +# +# Generate client/server/XDR code +# +awk -f gen_rpc.awk \ + -v client_file=$client_file \ + -v cproto_file=$cproto_file \ + -v ctmpl_file=$ctmpl_file \ + -v sed_file=$sed_file \ + -v server_file=$server_file \ + -v sproto_file=$sproto_file \ + -v stmpl_file=$stmpl_file \ + -v xdr_file=$xdr_file < ../rpc_server/rpc.src +chmod 444 $client_file $server_file + +# +# Now run rpcgen to generate all our sources from the XDR file +# +rpcgen -h $xdr_file > $header_file +rpcgen -l $xdr_file > $rpcclnt_file +rpcgen -s tcp $xdr_file > $rpcsvc_file +rpcgen -c $xdr_file > $rpcxdr_file + +# Run server files through sed +sed -f $svrsed_file $rpcsvc_file > ${rpcsvc_file}.new +mv ${rpcsvc_file}.new $rpcsvc_file +sed -f $sed_file $proc_file > ${proc_file}.new +mv ${proc_file}.new $proc_file + +# Run rpcgen files through sed to add HAVE_RPC ifdef +sed -f $rpcsed_file $rpcsvc_file > ${rpcsvc_file}.new +mv ${rpcsvc_file}.new $rpcsvc_file +sed -f $rpcsed_file $rpcxdr_file > ${rpcxdr_file}.new +mv ${rpcxdr_file}.new $rpcxdr_file +sed -f $rpcsed_file $rpcclnt_file > ${rpcclnt_file}.new +mv ${rpcclnt_file}.new $rpcclnt_file + +chmod 444 $header_file $rpcclnt_file $rpcsvc_file $rpcxdr_file + diff --git a/db/dist/s_symlink b/db/dist/s_symlink new file mode 100755 index 000000000..70efa4455 --- /dev/null +++ b/db/dist/s_symlink @@ -0,0 +1,91 @@ +#!/bin/sh - +# $Id: s_symlink,v 1.9 2000/09/05 21:27:04 bostic Exp $ + +echo 'Creating Berkeley DB source tree symbolic links...' + +build() +{ + echo " $1 -> $2" + (cd ../`dirname $1` && rm -f `basename $1` && ln -s $2 `basename $1`) +} + +build btree/tags ../dist/tags +build build_unix/tags ../dist/tags +build clib/tags ../dist/tags +build common/tags ../dist/tags +build cxx/tags ../dist/tags +build db/tags ../dist/tags +build db185/tags ../dist/tags +build db_archive/tags ../dist/tags +build db_checkpoint/tags ../dist/tags +build db_deadlock/tags ../dist/tags +build db_dump/tags ../dist/tags +build db_dump185/tags ../dist/tags +build db_load/tags ../dist/tags +build db_printlog/tags ../dist/tags +build db_recover/tags ../dist/tags +build db_stat/tags ../dist/tags +build db_upgrade/tags ../dist/tags +build db_verify/tags ../dist/tags +build dbm/tags ../dist/tags +build docs_src/api_cxx/Makefile ../api_c/Makefile +build docs_src/api_cxx/m4.seealso ../api_c/m4.seealso +build docs_src/api_cxx/spell.ok ../api_c/spell.ok +build docs_src/api_java/Makefile ../api_c/Makefile +build docs_src/api_java/java_index.so ../api_cxx/cxx_index.so +build docs_src/api_java/m4.seealso ../api_c/m4.seealso +build docs_src/api_java/spell.ok ../api_c/spell.ok +build docs_src/api_tcl/spell.ok ../api_c/spell.ok +build docs_src/ref/am/spell.ok ../spell.ok +build docs_src/ref/am_conf/spell.ok ../spell.ok +build docs_src/ref/arch/spell.ok ../spell.ok +build docs_src/ref/build_unix/spell.ok ../spell.ok +build docs_src/ref/build_vxworks/spell.ok ../spell.ok +build docs_src/ref/build_win/spell.ok ../spell.ok +build docs_src/ref/cam/spell.ok ../spell.ok +build docs_src/ref/debug/spell.ok ../spell.ok +build docs_src/ref/distrib/spell.ok ../spell.ok +build docs_src/ref/dumpload/spell.ok ../spell.ok +build docs_src/ref/env/spell.ok ../spell.ok +build docs_src/ref/install/spell.ok ../spell.ok +build docs_src/ref/intro/spell.ok ../spell.ok +build docs_src/ref/java/spell.ok ../spell.ok +build docs_src/ref/lock/spell.ok ../spell.ok +build docs_src/ref/log/spell.ok ../spell.ok +build docs_src/ref/mp/spell.ok ../spell.ok +build docs_src/ref/perl/spell.ok ../spell.ok +build docs_src/ref/program/spell.ok ../spell.ok +build docs_src/ref/refs/spell.ok ../spell.ok +build docs_src/ref/rpc/spell.ok ../spell.ok +build docs_src/ref/sendmail/spell.ok ../spell.ok +build docs_src/ref/simple_tut/spell.ok ../spell.ok +build docs_src/ref/tcl/spell.ok ../spell.ok +build docs_src/ref/test/spell.ok ../spell.ok +build docs_src/ref/transapp/spell.ok ../spell.ok +build docs_src/ref/txn/spell.ok ../spell.ok +build docs_src/ref/upgrade.2.0/spell.ok ../spell.ok +build docs_src/ref/upgrade.3.0/spell.ok ../spell.ok +build docs_src/ref/upgrade.3.1/spell.ok ../spell.ok +build docs_src/ref/upgrade.3.2/spell.ok ../spell.ok +build docs_src/ref/xa/spell.ok ../spell.ok +build env/tags ../dist/tags +build examples_c/tags ../dist/tags +build examples_cxx/tags ../dist/tags +build examples_java java/src/com/sleepycat/examples +build hash/tags ../dist/tags +build hsearch/tags ../dist/tags +build include/tags ../dist/tags +build libdb_java/tags ../dist/tags +build lock/tags ../dist/tags +build log/tags ../dist/tags +build mp/tags ../dist/tags +build mutex/tags ../dist/tags +build os/tags ../dist/tags +build os_vxworks/tags ../dist/tags +build os_win32/tags ../dist/tags +build qam/tags ../dist/tags +build rpc_client/tags ../dist/tags +build rpc_server/tags ../dist/tags +build tcl/tags ../dist/tags +build txn/tags ../dist/tags +build xa/tags ../dist/tags diff --git a/db/dist/s_tags b/db/dist/s_tags new file mode 100755 index 000000000..834600b9f --- /dev/null +++ b/db/dist/s_tags @@ -0,0 +1,47 @@ +#!/bin/sh - +# $Id: s_tags,v 1.5 2000/09/05 21:27:04 bostic Exp $ +# +# Build tags files. + +files="../include/*.h \ + ../include/*.src \ + ../btree/*.[ch] \ + ../clib/*.[ch] \ + ../common/*.[ch] \ + ../db/*.[ch] \ + ../db185/*.[ch] \ + ../dbm/*.[ch] \ + ../env/*.[ch] \ + ../hash/*.[ch] \ + ../hsearch/*.[ch] \ + ../libdb_java/*.[ch] \ + ../lock/*.[ch] \ + ../log/*.[ch] \ + ../mp/*.[ch] \ + ../mutex/*.[ch] \ + ../os/*.[ch] \ + ../qam/*.[ch] \ + ../rpc_client/*.[ch] \ + ../rpc_server/*.[ch] \ + ../tcl/*.[ch] \ + ../txn/*.[ch] \ + ../xa/*.[ch]" + +f=tags +echo "Building $f" +rm -f $f + +# Figure out what flags this ctags accepts. +flags="" +if ctags -d ../db/db.c 2>/dev/null; then + flags="-d $flags" +fi +if ctags -t ../db/db.c 2>/dev/null; then + flags="-t $flags" +fi +if ctags -w ../db/db.c 2>/dev/null; then + flags="-w $flags" +fi + +ctags $flags $files 2>/dev/null +chmod 444 $f diff --git a/db/dist/s_tcl b/db/dist/s_tcl new file mode 100755 index 000000000..7350e9a49 --- /dev/null +++ b/db/dist/s_tcl @@ -0,0 +1,53 @@ +#!/bin/sh - +# $Id: s_tcl,v 1.14 2000/11/09 19:24:07 sue Exp $ +# +# Build the Tcl test files. + +msgshb="# DO NOT EDIT BELOW THIS LINE: automatically built by dist/s_tcl." + +. RELEASE + +f=../test/include.tcl +echo "Building $f" +rm -f $f +(echo "set tclsh_path @TCL_TCLSH@" && \ + echo "set tcllib .libs/libdb_tcl-@DB_VERSION_MAJOR@.@DB_VERSION_MINOR@.@SOSUFFIX@" && \ + echo "set rpc_server localhost" && \ + echo "set rpc_path ." && \ + echo "set test_path @srcdir@/../test" && \ + echo "" && \ + echo "set KILL \"@db_cv_path_kill@\"" && \ + echo "" && \ + echo "$msgshb" && \ + echo "" && \ + echo "global dict" && \ + echo "global testdir" && \ + echo "global util_path" && \ + echo "set testdir ./TESTDIR" && \ + echo "set rpc_testdir \$rpc_path/TESTDIR" && \ + echo "" && \ + echo "global is_hp_test" && \ + echo "global is_qnx_test" && \ + echo "global is_windows_test") > $f +chmod 444 $f + +f=../build_win32/include.tcl +echo "Building $f" +rm -f $f +(echo "set tclsh_path SET_YOUR_TCLSH_PATH" && \ + echo "set test_path ../test" && \ + echo "set tcllib ./Debug/libdb_tcl${DB_VERSION_MAJOR}${DB_VERSION_MINOR}d.dll" && \ + echo "" && \ + echo "set KILL ./dbkill.exe" && \ + echo "" && \ + echo "$msgshb" && \ + echo "" && \ + echo "global dict" && \ + echo "global testdir" && \ + echo "global util_path" && \ + echo "set testdir ./TESTDIR" && \ + echo "" && \ + echo "global is_hp_test" && \ + echo "global is_qnx_test" && \ + echo "global is_windows_test") > $f +chmod 444 $f diff --git a/db/dist/s_vxworks b/db/dist/s_vxworks new file mode 100644 index 000000000..edf058df7 --- /dev/null +++ b/db/dist/s_vxworks @@ -0,0 +1,48 @@ +#!/bin/sh - +# $Id: s_vxworks,v 1.3 2000/07/13 18:38:46 bostic Exp $ +# +# Build the VxWorks files. + +msgc="/* DO NOT EDIT: automatically built by dist/s_vxworks. */" + +. RELEASE + +t=/tmp/__db_$$ +rm -f $t + +trap 'rm -f $t ; exit 1' 1 2 3 13 15 + +f=../build_vxworks/db.h +echo "Building $f" +rm -f $f +cat < $t +s/@u_int8_decl@/typedef unsigned char u_int8_t;/ +s/@u_int16_decl@/typedef unsigned short u_int16_t;/ +s/@u_int32_decl@/typedef unsigned int u_int32_t;/ +/@int16_decl@/d +/@int32_decl@/d +/@u_char_decl@/d +/@u_short_decl@/d +/@u_int_decl@/d +/@u_long_decl@/d +/@ssize_t_decl@/d +s/@DB_VERSION_MAJOR@/$DB_VERSION_MAJOR/ +s/@DB_VERSION_MINOR@/$DB_VERSION_MINOR/ +s/@DB_VERSION_PATCH@/$DB_VERSION_PATCH/ +s/@DB_VERSION_STRING@/"$DB_VERSION_STRING"/ +ENDOFSEDTEXT +(echo "$msgc" && sed -f $t ../include/db.src) > $f +chmod 444 $f + +f=../build_vxworks/db_int.h +echo "Building $f" +rm -f $f +cat < $t +s/\(PATH_SEPARATOR[^"]*"\)\/"/\1\/\\\\\\\\\\"/ +s/@db_align_t_decl@/typedef unsigned long db_align_t;/ +s/@db_alignp_t_decl@/typedef unsigned long db_alignp_t;/ +ENDOFSEDTEXT +(echo "$msgc" && sed -f $t ../include/db_int.src) > $f +chmod 444 $f + +rm -f $t diff --git a/db/dist/s_win32 b/db/dist/s_win32 new file mode 100755 index 000000000..f989a615e --- /dev/null +++ b/db/dist/s_win32 @@ -0,0 +1,67 @@ +#!/bin/sh - +# $Id: s_win32,v 1.9 2000/09/20 15:29:54 bostic Exp $ +# +# Build Windows/32 include files. + +msgc="/* DO NOT EDIT: automatically built by dist/s_win32. */" + +. RELEASE + +t=/tmp/__db_$$ +rm -f $t + +trap 'rm -f $t ; exit 1' 1 2 3 13 15 + +f=../build_win32/db.h +echo "Building $f" +rm -f $f +cat < $t +s/@u_int8_decl@/typedef unsigned char u_int8_t;/ +s/@int16_decl@/typedef short int16_t;/ +s/@u_int16_decl@/typedef unsigned short u_int16_t;/ +s/@int32_decl@/typedef int int32_t;/ +s/@u_int32_decl@/typedef unsigned int u_int32_t;/ +/@u_char_decl@/{ + i\\ + #if !defined(_WINSOCKAPI_) + s/@u_char_decl@/typedef unsigned char u_char;/ +} +s/@u_short_decl@/typedef unsigned short u_short;/ +s/@u_int_decl@/typedef unsigned int u_int;/ +/@u_long_decl@/{ + s/@u_long_decl@/typedef unsigned long u_long;/ + a\\ + #endif +} +s/@ssize_t_decl@/typedef int ssize_t;/ +s/@DB_VERSION_MAJOR@/$DB_VERSION_MAJOR/ +s/@DB_VERSION_MINOR@/$DB_VERSION_MINOR/ +s/@DB_VERSION_PATCH@/$DB_VERSION_PATCH/ +s/@DB_VERSION_STRING@/"$DB_VERSION_STRING"/ +ENDOFSEDTEXT +(echo "$msgc" && sed -f $t ../include/db.src) > $f +chmod 444 $f + +f=../build_win32/db_int.h +echo "Building $f" +rm -f $f +cat < $t +s/\(PATH_SEPARATOR[^"]*"\)\/"/\1\\\\\\\\\\/:\"/ +s/@db_align_t_decl@/typedef unsigned long db_align_t;/ +s/@db_alignp_t_decl@/typedef unsigned long db_alignp_t;/ +ENDOFSEDTEXT +(echo "$msgc" && sed -f $t ../include/db_int.src) > $f +chmod 444 $f + +f=../build_win32/libdb.rc +echo "Building $f" +rm -f $f +cat < $t +s/%MAJOR%/$DB_VERSION_MAJOR/ +s/%MINOR%/$DB_VERSION_MINOR/ +s/%PATCH%/$DB_VERSION_PATCH/ +ENDOFSEDTEXT +sed -f $t ../build_win32/libdbrc.src > $f +chmod 444 $f + +rm -f $t diff --git a/db/dist/s_win32_dsp b/db/dist/s_win32_dsp new file mode 100644 index 000000000..8abee7c1a --- /dev/null +++ b/db/dist/s_win32_dsp @@ -0,0 +1,98 @@ +#!/bin/sh - +# $Id: s_win32_dsp,v 1.3 2000/12/02 04:36:47 dda Exp $ +# +# Build Windows/32 .dsp files. + +. RELEASE + +BUILDDIR=../build_win32 +SRCFILES=srcfiles.in + +create_dsp() +{ + projname="$1" # name of the .dsp file + match="$2" # the string used to egrep the $sources file + sources="$3" # a modified version of $SRCFILES to facilitate matches + dsptemplate="$4" # overall template file for the .dsp + srctemplate="$5" # template file for the src file fragments + + dspoutput=$BUILDDIR/$projname.dsp + + echo "Building $dspoutput" + rm -f $dspoutput.insert + for srcpath in `egrep "$match" $sources | sed -e 's/[ ].*//'` + do + # take the path name and break it up, converting / to \\. + # so many backslashes needed because of shell quoting and + # sed quoting -- we'll end up with two backslashes for every + # forward slash, but we need that when feeding that to the + # later sed command. + set - `echo $srcpath | sed -e 's;\(.*\)/;../\\1 ;' \ + -e 's;../build_win32;.;' \ + -e 's;/;\\\\\\\\;g'` + srcdir="$1" + srcfile="$2" + sed -e "s/@srcdir@/$srcdir/g" \ + -e "s/@srcfile@/$srcfile/g" \ + < $srctemplate >> $dspoutput.insert + done + sed -e "/@SOURCE_FILES@/r$dspoutput.insert" \ + -e "/@SOURCE_FILES@/d" \ + -e "s/@project_name@/$projname/g" \ + -e "s/@DB_VERSION_MAJOR@/$DB_VERSION_MAJOR/g" \ + -e "s/@DB_VERSION_MINOR@/$DB_VERSION_MINOR/g" \ + < $dsptemplate > $dspoutput.new + rm -f $dspoutput $dspoutput.insert + mv $dspoutput.new $dspoutput +} + +TMPA=/tmp/swin32dsp$$a +trap "rm -f $TMPA; exit 1" 1 2 3 15 + +# create a copy of the srcfiles with comments and 'skip' lines removed. +# add a space at the end of each list of modules so that each module +# can be unambiguously matched e.g. ' dynamic ' +# +sed -e "s/#.*$//" \ + -e "/^[ ]*$/d" \ + -e "s/[ ][ ]*/ /" \ + -e "s/[ ]*$//" \ + -e "/ skip$/d" \ + -e "s/$/ /" < $SRCFILES > $TMPA + +# get a list of all modules mentioned +# +MODULES="`sed -e 's/^[^ ]* //' < $TMPA \ + | tr ' ' '\012' | sort | uniq`" + +for module in $MODULES +do + case "$module" in + dynamic ) + create_dsp db_dll " $module " $TMPA \ + $BUILDDIR/dynamic_dsp.src $BUILDDIR/srcfile_dsp.src + ;; + java ) + create_dsp db_java " $module " $TMPA \ + $BUILDDIR/java_dsp.src $BUILDDIR/srcfile_dsp.src + ;; + tcl ) + create_dsp db_tcl " $module " $TMPA \ + $BUILDDIR/tcl_dsp.src $BUILDDIR/srcfile_dsp.src + ;; + static ) + create_dsp db_static " $module " $TMPA \ + $BUILDDIR/static_dsp.src $BUILDDIR/srcfile_dsp.src + ;; + app=* ) + appname=`echo $module | sed -e 's/^app=//'` + create_dsp $appname " $module " $TMPA \ + $BUILDDIR/app_dsp.src $BUILDDIR/srcfile_dsp.src + ;; + * ) + echo "s_win32_dsp: module name $module in $SRCFILES is unknown type" + ;; + esac +done + +rm -f $TMPA diff --git a/db/dist/srcfiles.in b/db/dist/srcfiles.in new file mode 100644 index 000000000..bfc564e13 --- /dev/null +++ b/db/dist/srcfiles.in @@ -0,0 +1,269 @@ +# $Id: srcfiles.in,v 1.7 2000/11/30 18:42:21 dda Exp $ +# +# This is an input file for the s_win32_dsp script. It describes every +# source files used by Windows, and lists those that aren't as well, +# as a completeness sanity check. +# +# Please keep this list sorted alphabetically! +# +# Each non-blank, non-comment line is of the form +# filename module [ module ...] +# +# The possible modules, including the name of the project (.dsp) file: +# +# app=NAME this is linked into application NAME.exe (db_NAME.dsp) +# dynamic file appears in the DLL (db_dll.dsp) +# java file appears in the java DLL (db_java.dsp) +# skip this file is not used by Windows +# static file appears in the static library (db_static.dsp) +# tcl file appears in the tcl DLL (db_tcl.dsp) + +btree/bt_compare.c dynamic static +btree/bt_conv.c dynamic static +btree/bt_curadj.c dynamic static +btree/bt_cursor.c dynamic static +btree/bt_delete.c dynamic static +btree/bt_method.c dynamic static +btree/bt_open.c dynamic static +btree/bt_put.c dynamic static +btree/bt_rec.c dynamic static +btree/bt_reclaim.c dynamic static +btree/bt_recno.c dynamic static +btree/bt_rsearch.c dynamic static +btree/bt_search.c dynamic static +btree/bt_split.c dynamic static +btree/bt_stat.c dynamic static +btree/bt_upgrade.c dynamic static +btree/bt_verify.c dynamic static +btree/btree_auto.c dynamic static +build_win32/dbkill.cpp skip +build_win32/dllmain.c dynamic +build_win32/libdb.def dynamic +build_win32/libdb.rc dynamic +build_win32/libdb_tcl.def tcl +clib/getcwd.c skip +clib/getopt.c skip # must be linked into each app +clib/memcmp.c skip +clib/memmove.c skip +clib/raise.c skip +clib/snprintf.c skip +clib/strcasecmp.c dynamic static +clib/strerror.c skip +clib/vsnprintf.c skip +common/db_byteorder.c dynamic static +common/db_err.c dynamic static +common/db_getlong.c dynamic static +common/db_log2.c dynamic static +common/util_log.c dynamic static +common/util_sig.c dynamic static +cxx/cxx_app.cpp dynamic static +cxx/cxx_except.cpp dynamic static +cxx/cxx_lock.cpp dynamic static +cxx/cxx_log.cpp dynamic static +cxx/cxx_mpool.cpp dynamic static +cxx/cxx_table.cpp dynamic static +cxx/cxx_txn.cpp dynamic static +db/crdel_auto.c dynamic static +db/crdel_rec.c dynamic static +db/db.c dynamic static +db/db_am.c dynamic static +db/db_auto.c dynamic static +db/db_cam.c dynamic static +db/db_conv.c dynamic static +db/db_dispatch.c dynamic static +db/db_dup.c dynamic static +db/db_iface.c dynamic static +db/db_join.c dynamic static +db/db_meta.c dynamic static +db/db_method.c dynamic static +db/db_overflow.c dynamic static +db/db_pr.c dynamic static +db/db_rec.c dynamic static +db/db_reclaim.c dynamic static +db/db_ret.c dynamic static +db/db_upg.c dynamic static +db/db_upg_opd.c dynamic static +db/db_vrfy.c dynamic static +db/db_vrfyutil.c dynamic static +db185/db185.c skip +db_archive/db_archive.c app=db_archive +db_checkpoint/db_checkpoint.c app=db_checkpoint +db_deadlock/db_deadlock.c app=db_deadlock +db_dump/db_dump.c app=db_dump +db_dump185/db_dump185.c skip +db_load/db_load.c app=db_load +db_printlog/db_printlog.c app=db_printlog +db_recover/db_recover.c app=db_recover +db_stat/db_stat.c app=db_stat +db_upgrade/db_upgrade.c app=db_upgrade +db_verify/db_verify.c app=db_verify +dbm/dbm.c dynamic static +env/db_salloc.c dynamic static +env/db_shash.c dynamic static +env/env_method.c dynamic static +env/env_open.c dynamic static +env/env_recover.c dynamic static +env/env_region.c dynamic static +examples_c/ex_access.c app=ex_access +examples_c/ex_btrec.c app=ex_btrec +examples_c/ex_dbclient.c skip +examples_c/ex_env.c app=ex_env +examples_c/ex_lock.c app=ex_lock +examples_c/ex_mpool.c app=ex_mpool +examples_c/ex_thread.c skip +examples_c/ex_tpcb.c app=ex_tpcb +examples_cxx/AccessExample.cpp app=excxx_access +examples_cxx/BtRecExample.cpp app=excxx_btrec +examples_cxx/EnvExample.cpp app=excxx_env +examples_cxx/LockExample.cpp app=excxx_lock +examples_cxx/MpoolExample.cpp app=excxx_mpool +examples_cxx/TpcbExample.cpp app=excxx_tpcb +hash/hash.c dynamic static +hash/hash_auto.c dynamic static +hash/hash_conv.c dynamic static +hash/hash_dup.c dynamic static +hash/hash_func.c dynamic static +hash/hash_meta.c dynamic static +hash/hash_method.c dynamic static +hash/hash_page.c dynamic static +hash/hash_rec.c dynamic static +hash/hash_reclaim.c dynamic static +hash/hash_stat.c dynamic static +hash/hash_upgrade.c dynamic static +hash/hash_verify.c dynamic static +hsearch/hsearch.c dynamic static +libdb_java/java_Db.c java +libdb_java/java_DbEnv.c java +libdb_java/java_DbLock.c java +libdb_java/java_DbLsn.c java +libdb_java/java_DbTxn.c java +libdb_java/java_Dbc.c java +libdb_java/java_Dbt.c java +libdb_java/java_info.c java +libdb_java/java_locked.c java +libdb_java/java_util.c java +lock/lock.c dynamic static +lock/lock_conflict.c dynamic static +lock/lock_deadlock.c dynamic static +lock/lock_method.c dynamic static +lock/lock_region.c dynamic static +lock/lock_stat.c dynamic static +lock/lock_util.c dynamic static +log/log.c dynamic static +log/log_archive.c dynamic static +log/log_auto.c dynamic static +log/log_compare.c dynamic static +log/log_findckp.c dynamic static +log/log_get.c dynamic static +log/log_method.c dynamic static +log/log_put.c dynamic static +log/log_rec.c dynamic static +log/log_register.c dynamic static +mp/mp_alloc.c dynamic static +mp/mp_bh.c dynamic static +mp/mp_fget.c dynamic static +mp/mp_fopen.c dynamic static +mp/mp_fput.c dynamic static +mp/mp_fset.c dynamic static +mp/mp_method.c dynamic static +mp/mp_region.c dynamic static +mp/mp_register.c dynamic static +mp/mp_stat.c dynamic static +mp/mp_sync.c dynamic static +mp/mp_trickle.c dynamic static +mutex/mut_fcntl.c skip +mutex/mut_pthread.c skip +mutex/mut_tas.c dynamic static +mutex/mutex.c dynamic static +os/os_abs.c skip +os/os_alloc.c dynamic static +os/os_dir.c skip +os/os_errno.c skip +os/os_fid.c skip +os/os_finit.c skip +os/os_fsync.c dynamic static +os/os_handle.c dynamic static +os/os_map.c skip +os/os_method.c dynamic static +os/os_oflags.c dynamic static +os/os_open.c skip +os/os_region.c dynamic static +os/os_rename.c skip +os/os_root.c dynamic static +os/os_rpath.c dynamic static +os/os_rw.c dynamic static +os/os_seek.c skip +os/os_sleep.c skip +os/os_spin.c skip +os/os_stat.c dynamic static +os/os_tmpdir.c dynamic static +os/os_unlink.c dynamic static +os_vxworks/os_abs.c skip +os_vxworks/os_finit.c skip +os_vxworks/os_map.c skip +os_win32/os_abs.c dynamic static +os_win32/os_dir.c dynamic static +os_win32/os_errno.c dynamic static +os_win32/os_fid.c dynamic static +os_win32/os_finit.c dynamic static +os_win32/os_map.c dynamic static +os_win32/os_open.c dynamic static +os_win32/os_rename.c dynamic static +os_win32/os_seek.c dynamic static +os_win32/os_sleep.c dynamic static +os_win32/os_spin.c dynamic static +os_win32/os_type.c dynamic static +qam/qam.c dynamic static +qam/qam_auto.c dynamic static +qam/qam_conv.c dynamic static +qam/qam_files.c dynamic static +qam/qam_method.c dynamic static +qam/qam_open.c dynamic static +qam/qam_rec.c dynamic static +qam/qam_stat.c dynamic static +qam/qam_upgrade.c dynamic static +qam/qam_verify.c dynamic static +rpc_client/client.c skip +rpc_client/db_server_clnt.c skip +rpc_client/gen_client.c skip +rpc_client/gen_client_ret.c skip +rpc_server/db_server_proc.c skip +rpc_server/db_server_svc.c skip +rpc_server/db_server_util.c skip +rpc_server/db_server_xdr.c skip +rpc_server/gen_db_server.c skip +tcl/tcl_compat.c tcl +tcl/tcl_db.c tcl +tcl/tcl_db_pkg.c tcl +tcl/tcl_dbcursor.c tcl +tcl/tcl_env.c tcl +tcl/tcl_internal.c tcl +tcl/tcl_lock.c tcl +tcl/tcl_log.c tcl +tcl/tcl_mp.c tcl +tcl/tcl_txn.c tcl +test_server/dbs.c skip +test_server/dbs_am.c skip +test_server/dbs_checkpoint.c skip +test_server/dbs_debug.c skip +test_server/dbs_handles.c skip +test_server/dbs_log.c skip +test_server/dbs_qam.c skip +test_server/dbs_spawn.c skip +test_server/dbs_trickle.c skip +test_server/dbs_util.c skip +test_server/dbs_yield.c skip +test_thread/lock.c skip +test_thread/log.c skip +test_thread/mpool.c skip +test_thread/mutex.c skip +test_vxworks/vx_mutex.c skip +test_vxworks/vxtpcb_files.c skip +test_vxworks/vxtpcb_onefile.c skip +txn/txn.c dynamic static +txn/txn_auto.c dynamic static +txn/txn_rec.c dynamic static +txn/txn_region.c dynamic static +xa/xa.c dynamic static +xa/xa_db.c dynamic static +xa/xa_map.c dynamic static diff --git a/db/dist/template/db_server_proc b/db/dist/template/db_server_proc new file mode 100644 index 000000000..3fc732218 --- /dev/null +++ b/db/dist/template/db_server_proc @@ -0,0 +1,1057 @@ +/* Do not edit: automatically built by gen_rpc.awk. */ +#include "db_config.h" + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include + +#include +#include +#include "db_server.h" +#endif + +#include "db_int.h" +#include "db_server_int.h" +#include "rpc_server_ext.h" + +#include "gen_server_ext.h" + +/* BEGIN __env_cachesize_1_proc */ +void +__env_cachesize_1_proc(dbenvcl_id, gbytes, bytes, + ncache, replyp) + long dbenvcl_id; + u_int32_t gbytes; + u_int32_t bytes; + u_int32_t ncache; + __env_cachesize_reply *replyp; +/* END __env_cachesize_1_proc */ +{ + int ret; + DB_ENV * dbenv; + ct_entry *dbenv_ctp; + + ACTIVATE_CTP(dbenv_ctp, dbenvcl_id, CT_ENV); + dbenv = (DB_ENV *)dbenv_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __env_close_1_proc */ +void +__env_close_1_proc(dbenvcl_id, flags, replyp) + long dbenvcl_id; + u_int32_t flags; + __env_close_reply *replyp; +/* END __env_close_1_proc */ +{ + int ret; + DB_ENV * dbenv; + ct_entry *dbenv_ctp; + + ACTIVATE_CTP(dbenv_ctp, dbenvcl_id, CT_ENV); + dbenv = (DB_ENV *)dbenv_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __env_create_1_proc */ +void +__env_create_1_proc(timeout, replyp) + u_int32_t timeout; + __env_create_reply *replyp; +/* END __env_create_1_proc */ +{ + int ret; + + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __env_flags_1_proc */ +void +__env_flags_1_proc(dbenvcl_id, flags, onoff, replyp) + long dbenvcl_id; + u_int32_t flags; + u_int32_t onoff; + __env_flags_reply *replyp; +/* END __env_flags_1_proc */ +{ + int ret; + DB_ENV * dbenv; + ct_entry *dbenv_ctp; + + ACTIVATE_CTP(dbenv_ctp, dbenvcl_id, CT_ENV); + dbenv = (DB_ENV *)dbenv_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __env_open_1_proc */ +void +__env_open_1_proc(dbenvcl_id, home, flags, + mode, replyp) + long dbenvcl_id; + char *home; + u_int32_t flags; + u_int32_t mode; + __env_open_reply *replyp; +/* END __env_open_1_proc */ +{ + int ret; + DB_ENV * dbenv; + ct_entry *dbenv_ctp; + + ACTIVATE_CTP(dbenv_ctp, dbenvcl_id, CT_ENV); + dbenv = (DB_ENV *)dbenv_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __env_remove_1_proc */ +void +__env_remove_1_proc(dbenvcl_id, home, flags, replyp) + long dbenvcl_id; + char *home; + u_int32_t flags; + __env_remove_reply *replyp; +/* END __env_remove_1_proc */ +{ + int ret; + DB_ENV * dbenv; + ct_entry *dbenv_ctp; + + ACTIVATE_CTP(dbenv_ctp, dbenvcl_id, CT_ENV); + dbenv = (DB_ENV *)dbenv_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __txn_abort_1_proc */ +void +__txn_abort_1_proc(txnpcl_id, replyp) + long txnpcl_id; + __txn_abort_reply *replyp; +/* END __txn_abort_1_proc */ +{ + int ret; + DB_TXN * txnp; + ct_entry *txnp_ctp; + + ACTIVATE_CTP(txnp_ctp, txnpcl_id, CT_TXN); + txnp = (DB_TXN *)txnp_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __txn_begin_1_proc */ +void +__txn_begin_1_proc(envpcl_id, parentcl_id, + flags, replyp) + long envpcl_id; + long parentcl_id; + u_int32_t flags; + __txn_begin_reply *replyp; +/* END __txn_begin_1_proc */ +{ + int ret; + DB_ENV * envp; + ct_entry *envp_ctp; + DB_TXN * parent; + ct_entry *parent_ctp; + + ACTIVATE_CTP(envp_ctp, envpcl_id, CT_ENV); + envp = (DB_ENV *)envp_ctp->ct_anyp; + ACTIVATE_CTP(parent_ctp, parentcl_id, CT_TXN); + parent = (DB_TXN *)parent_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __txn_commit_1_proc */ +void +__txn_commit_1_proc(txnpcl_id, flags, replyp) + long txnpcl_id; + u_int32_t flags; + __txn_commit_reply *replyp; +/* END __txn_commit_1_proc */ +{ + int ret; + DB_TXN * txnp; + ct_entry *txnp_ctp; + + ACTIVATE_CTP(txnp_ctp, txnpcl_id, CT_TXN); + txnp = (DB_TXN *)txnp_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __db_bt_maxkey_1_proc */ +void +__db_bt_maxkey_1_proc(dbpcl_id, maxkey, replyp) + long dbpcl_id; + u_int32_t maxkey; + __db_bt_maxkey_reply *replyp; +/* END __db_bt_maxkey_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __db_bt_minkey_1_proc */ +void +__db_bt_minkey_1_proc(dbpcl_id, minkey, replyp) + long dbpcl_id; + u_int32_t minkey; + __db_bt_minkey_reply *replyp; +/* END __db_bt_minkey_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __db_close_1_proc */ +void +__db_close_1_proc(dbpcl_id, flags, replyp) + long dbpcl_id; + u_int32_t flags; + __db_close_reply *replyp; +/* END __db_close_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __db_create_1_proc */ +void +__db_create_1_proc(flags, envpcl_id, replyp) + u_int32_t flags; + long envpcl_id; + __db_create_reply *replyp; +/* END __db_create_1_proc */ +{ + int ret; + DB_ENV * envp; + ct_entry *envp_ctp; + + ACTIVATE_CTP(envp_ctp, envpcl_id, CT_ENV); + envp = (DB_ENV *)envp_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __db_del_1_proc */ +void +__db_del_1_proc(dbpcl_id, txnpcl_id, keydlen, + keydoff, keyflags, keydata, keysize, + flags, replyp) + long dbpcl_id; + long txnpcl_id; + u_int32_t keydlen; + u_int32_t keydoff; + u_int32_t keyflags; + void *keydata; + u_int32_t keysize; + u_int32_t flags; + __db_del_reply *replyp; +/* END __db_del_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + DB_TXN * txnp; + ct_entry *txnp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + ACTIVATE_CTP(txnp_ctp, txnpcl_id, CT_TXN); + txnp = (DB_TXN *)txnp_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __db_extentsize_1_proc */ +void +__db_extentsize_1_proc(dbpcl_id, extentsize, replyp) + long dbpcl_id; + u_int32_t extentsize; + __db_extentsize_reply *replyp; +/* END __db_extentsize_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __db_flags_1_proc */ +void +__db_flags_1_proc(dbpcl_id, flags, replyp) + long dbpcl_id; + u_int32_t flags; + __db_flags_reply *replyp; +/* END __db_flags_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __db_get_1_proc */ +void +__db_get_1_proc(dbpcl_id, txnpcl_id, keydlen, + keydoff, keyflags, keydata, keysize, + datadlen, datadoff, dataflags, datadata, + datasize, flags, replyp, freep) + long dbpcl_id; + long txnpcl_id; + u_int32_t keydlen; + u_int32_t keydoff; + u_int32_t keyflags; + void *keydata; + u_int32_t keysize; + u_int32_t datadlen; + u_int32_t datadoff; + u_int32_t dataflags; + void *datadata; + u_int32_t datasize; + u_int32_t flags; + __db_get_reply *replyp; + int * freep; +/* END __db_get_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + DB_TXN * txnp; + ct_entry *txnp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + ACTIVATE_CTP(txnp_ctp, txnpcl_id, CT_TXN); + txnp = (DB_TXN *)txnp_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __db_h_ffactor_1_proc */ +void +__db_h_ffactor_1_proc(dbpcl_id, ffactor, replyp) + long dbpcl_id; + u_int32_t ffactor; + __db_h_ffactor_reply *replyp; +/* END __db_h_ffactor_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __db_h_nelem_1_proc */ +void +__db_h_nelem_1_proc(dbpcl_id, nelem, replyp) + long dbpcl_id; + u_int32_t nelem; + __db_h_nelem_reply *replyp; +/* END __db_h_nelem_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __db_key_range_1_proc */ +void +__db_key_range_1_proc(dbpcl_id, txnpcl_id, keydlen, + keydoff, keyflags, keydata, keysize, + flags, replyp) + long dbpcl_id; + long txnpcl_id; + u_int32_t keydlen; + u_int32_t keydoff; + u_int32_t keyflags; + void *keydata; + u_int32_t keysize; + u_int32_t flags; + __db_key_range_reply *replyp; +/* END __db_key_range_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + DB_TXN * txnp; + ct_entry *txnp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + ACTIVATE_CTP(txnp_ctp, txnpcl_id, CT_TXN); + txnp = (DB_TXN *)txnp_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __db_lorder_1_proc */ +void +__db_lorder_1_proc(dbpcl_id, lorder, replyp) + long dbpcl_id; + u_int32_t lorder; + __db_lorder_reply *replyp; +/* END __db_lorder_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __db_open_1_proc */ +void +__db_open_1_proc(dbpcl_id, name, subdb, + type, flags, mode, replyp) + long dbpcl_id; + char *name; + char *subdb; + u_int32_t type; + u_int32_t flags; + u_int32_t mode; + __db_open_reply *replyp; +/* END __db_open_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __db_pagesize_1_proc */ +void +__db_pagesize_1_proc(dbpcl_id, pagesize, replyp) + long dbpcl_id; + u_int32_t pagesize; + __db_pagesize_reply *replyp; +/* END __db_pagesize_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __db_put_1_proc */ +void +__db_put_1_proc(dbpcl_id, txnpcl_id, keydlen, + keydoff, keyflags, keydata, keysize, + datadlen, datadoff, dataflags, datadata, + datasize, flags, replyp, freep) + long dbpcl_id; + long txnpcl_id; + u_int32_t keydlen; + u_int32_t keydoff; + u_int32_t keyflags; + void *keydata; + u_int32_t keysize; + u_int32_t datadlen; + u_int32_t datadoff; + u_int32_t dataflags; + void *datadata; + u_int32_t datasize; + u_int32_t flags; + __db_put_reply *replyp; + int * freep; +/* END __db_put_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + DB_TXN * txnp; + ct_entry *txnp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + ACTIVATE_CTP(txnp_ctp, txnpcl_id, CT_TXN); + txnp = (DB_TXN *)txnp_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __db_re_delim_1_proc */ +void +__db_re_delim_1_proc(dbpcl_id, delim, replyp) + long dbpcl_id; + u_int32_t delim; + __db_re_delim_reply *replyp; +/* END __db_re_delim_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __db_re_len_1_proc */ +void +__db_re_len_1_proc(dbpcl_id, len, replyp) + long dbpcl_id; + u_int32_t len; + __db_re_len_reply *replyp; +/* END __db_re_len_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __db_re_pad_1_proc */ +void +__db_re_pad_1_proc(dbpcl_id, pad, replyp) + long dbpcl_id; + u_int32_t pad; + __db_re_pad_reply *replyp; +/* END __db_re_pad_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __db_remove_1_proc */ +void +__db_remove_1_proc(dbpcl_id, name, subdb, + flags, replyp) + long dbpcl_id; + char *name; + char *subdb; + u_int32_t flags; + __db_remove_reply *replyp; +/* END __db_remove_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __db_rename_1_proc */ +void +__db_rename_1_proc(dbpcl_id, name, subdb, + newname, flags, replyp) + long dbpcl_id; + char *name; + char *subdb; + char *newname; + u_int32_t flags; + __db_rename_reply *replyp; +/* END __db_rename_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __db_stat_1_proc */ +void +__db_stat_1_proc(dbpcl_id, + flags, replyp, freep) + long dbpcl_id; + u_int32_t flags; + __db_stat_reply *replyp; + int * freep; +/* END __db_stat_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __db_swapped_1_proc */ +void +__db_swapped_1_proc(dbpcl_id, replyp) + long dbpcl_id; + __db_swapped_reply *replyp; +/* END __db_swapped_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __db_sync_1_proc */ +void +__db_sync_1_proc(dbpcl_id, flags, replyp) + long dbpcl_id; + u_int32_t flags; + __db_sync_reply *replyp; +/* END __db_sync_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __db_cursor_1_proc */ +void +__db_cursor_1_proc(dbpcl_id, txnpcl_id, + flags, replyp) + long dbpcl_id; + long txnpcl_id; + u_int32_t flags; + __db_cursor_reply *replyp; +/* END __db_cursor_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + DB_TXN * txnp; + ct_entry *txnp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + ACTIVATE_CTP(txnp_ctp, txnpcl_id, CT_TXN); + txnp = (DB_TXN *)txnp_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __db_join_1_proc */ +void +__db_join_1_proc(dbpcl_id, curslist, + flags, replyp) + long dbpcl_id; + u_int32_t * curslist; + u_int32_t flags; + __db_join_reply *replyp; +/* END __db_join_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __dbc_close_1_proc */ +void +__dbc_close_1_proc(dbccl_id, replyp) + long dbccl_id; + __dbc_close_reply *replyp; +/* END __dbc_close_1_proc */ +{ + int ret; + DBC * dbc; + ct_entry *dbc_ctp; + + ACTIVATE_CTP(dbc_ctp, dbccl_id, CT_CURSOR); + dbc = (DBC *)dbc_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __dbc_count_1_proc */ +void +__dbc_count_1_proc(dbccl_id, flags, replyp) + long dbccl_id; + u_int32_t flags; + __dbc_count_reply *replyp; +/* END __dbc_count_1_proc */ +{ + int ret; + DBC * dbc; + ct_entry *dbc_ctp; + + ACTIVATE_CTP(dbc_ctp, dbccl_id, CT_CURSOR); + dbc = (DBC *)dbc_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __dbc_del_1_proc */ +void +__dbc_del_1_proc(dbccl_id, flags, replyp) + long dbccl_id; + u_int32_t flags; + __dbc_del_reply *replyp; +/* END __dbc_del_1_proc */ +{ + int ret; + DBC * dbc; + ct_entry *dbc_ctp; + + ACTIVATE_CTP(dbc_ctp, dbccl_id, CT_CURSOR); + dbc = (DBC *)dbc_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __dbc_dup_1_proc */ +void +__dbc_dup_1_proc(dbccl_id, flags, replyp) + long dbccl_id; + u_int32_t flags; + __dbc_dup_reply *replyp; +/* END __dbc_dup_1_proc */ +{ + int ret; + DBC * dbc; + ct_entry *dbc_ctp; + + ACTIVATE_CTP(dbc_ctp, dbccl_id, CT_CURSOR); + dbc = (DBC *)dbc_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __dbc_get_1_proc */ +void +__dbc_get_1_proc(dbccl_id, keydlen, keydoff, + keyflags, keydata, keysize, datadlen, + datadoff, dataflags, datadata, datasize, + flags, replyp, freep) + long dbccl_id; + u_int32_t keydlen; + u_int32_t keydoff; + u_int32_t keyflags; + void *keydata; + u_int32_t keysize; + u_int32_t datadlen; + u_int32_t datadoff; + u_int32_t dataflags; + void *datadata; + u_int32_t datasize; + u_int32_t flags; + __dbc_get_reply *replyp; + int * freep; +/* END __dbc_get_1_proc */ +{ + int ret; + DBC * dbc; + ct_entry *dbc_ctp; + + ACTIVATE_CTP(dbc_ctp, dbccl_id, CT_CURSOR); + dbc = (DBC *)dbc_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + +/* BEGIN __dbc_put_1_proc */ +void +__dbc_put_1_proc(dbccl_id, keydlen, keydoff, + keyflags, keydata, keysize, datadlen, + datadoff, dataflags, datadata, datasize, + flags, replyp, freep) + long dbccl_id; + u_int32_t keydlen; + u_int32_t keydoff; + u_int32_t keyflags; + void *keydata; + u_int32_t keysize; + u_int32_t datadlen; + u_int32_t datadoff; + u_int32_t dataflags; + void *datadata; + u_int32_t datasize; + u_int32_t flags; + __dbc_put_reply *replyp; + int * freep; +/* END __dbc_put_1_proc */ +{ + int ret; + DBC * dbc; + ct_entry *dbc_ctp; + + ACTIVATE_CTP(dbc_ctp, dbccl_id, CT_CURSOR); + dbc = (DBC *)dbc_ctp->ct_anyp; + + /* + * XXX Code goes here + */ + + replyp->status = ret; + return; +} + diff --git a/db/dist/template/gen_client_ret b/db/dist/template/gen_client_ret new file mode 100644 index 000000000..81e14d8b2 --- /dev/null +++ b/db/dist/template/gen_client_ret @@ -0,0 +1,522 @@ +/* Do not edit: automatically built by gen_rpc.awk. */ +#include "db_config.h" + +#ifdef HAVE_RPC +#ifndef NO_SYSTEM_INCLUDES +#include +#include + +#include +#include +#endif +#include "db_server.h" + +#include "db_int.h" +#include "db_page.h" +#include "db_ext.h" +#include "txn.h" + +#include "gen_client_ext.h" + +int +__dbcl_env_close_ret(dbenv, flags, replyp) + DB_ENV * dbenv; + u_int32_t flags; + __env_close_reply *replyp; +{ + int ret; + + if (replyp->status != 0) + return (replyp->status); + + /* + * XXX Code goes here + */ + + return (replyp->status); +} + +int +__dbcl_env_open_ret(dbenv, home, flags, mode, replyp) + DB_ENV * dbenv; + const char * home; + u_int32_t flags; + int mode; + __env_open_reply *replyp; +{ + int ret; + + if (replyp->status != 0) + return (replyp->status); + + /* + * XXX Code goes here + */ + + return (replyp->status); +} + +int +__dbcl_env_remove_ret(dbenv, home, flags, replyp) + DB_ENV * dbenv; + const char * home; + u_int32_t flags; + __env_remove_reply *replyp; +{ + int ret; + + if (replyp->status != 0) + return (replyp->status); + + /* + * XXX Code goes here + */ + + return (replyp->status); +} + +int +__dbcl_txn_abort_ret(txnp, replyp) + DB_TXN * txnp; + __txn_abort_reply *replyp; +{ + int ret; + + if (replyp->status != 0) + return (replyp->status); + + /* + * XXX Code goes here + */ + + return (replyp->status); +} + +int +__dbcl_txn_begin_ret(envp, parent, txnpp, flags, replyp) + DB_ENV * envp; + DB_TXN * parent; + DB_TXN ** txnpp; + u_int32_t flags; + __txn_begin_reply *replyp; +{ + int ret; + long txnid; + + if (replyp->status != 0) + return (replyp->status); + txnid = replyp->txnidcl_id; + + /* + * XXX Code goes here + */ + + return (replyp->status); +} + +int +__dbcl_txn_commit_ret(txnp, flags, replyp) + DB_TXN * txnp; + u_int32_t flags; + __txn_commit_reply *replyp; +{ + int ret; + + if (replyp->status != 0) + return (replyp->status); + + /* + * XXX Code goes here + */ + + return (replyp->status); +} + +int +__dbcl_db_close_ret(dbp, flags, replyp) + DB * dbp; + u_int32_t flags; + __db_close_reply *replyp; +{ + int ret; + + if (replyp->status != 0) + return (replyp->status); + + /* + * XXX Code goes here + */ + + return (replyp->status); +} + +int +__dbcl_db_get_ret(dbp, txnp, key, data, flags, replyp) + DB * dbp; + DB_TXN * txnp; + DBT * key; + DBT * data; + u_int32_t flags; + __db_get_reply *replyp; +{ + int ret; + /* DBT key; */ + /* DBT data; */ + + if (replyp->status != 0) + return (replyp->status); + /* Handle replyp->keydata; */ + /* Handle replyp->datadata; */ + + /* + * XXX Code goes here + */ + + return (replyp->status); +} + +int +__dbcl_db_key_range_ret(dbp, txnp, key, range, flags, replyp) + DB * dbp; + DB_TXN * txnp; + DBT * key; + DB_KEY_RANGE * range; + u_int32_t flags; + __db_key_range_reply *replyp; +{ + int ret; + double less; + double equal; + double greater; + + if (replyp->status != 0) + return (replyp->status); + less = replyp->less; + equal = replyp->equal; + greater = replyp->greater; + + /* + * XXX Code goes here + */ + + return (replyp->status); +} + +int +__dbcl_db_open_ret(dbp, name, subdb, type, flags, mode, replyp) + DB * dbp; + const char * name; + const char * subdb; + DBTYPE type; + u_int32_t flags; + int mode; + __db_open_reply *replyp; +{ + int ret; + DBTYPE type; + u_int32_t dbflags; + + if (replyp->status != 0) + return (replyp->status); + type = replyp->type; + dbflags = replyp->dbflags; + + /* + * XXX Code goes here + */ + + return (replyp->status); +} + +int +__dbcl_db_put_ret(dbp, txnp, key, data, flags, replyp) + DB * dbp; + DB_TXN * txnp; + DBT * key; + DBT * data; + u_int32_t flags; + __db_put_reply *replyp; +{ + int ret; + /* DBT key; */ + + if (replyp->status != 0) + return (replyp->status); + /* Handle replyp->keydata; */ + + /* + * XXX Code goes here + */ + + return (replyp->status); +} + +int +__dbcl_db_remove_ret(dbp, name, subdb, flags, replyp) + DB * dbp; + const char * name; + const char * subdb; + u_int32_t flags; + __db_remove_reply *replyp; +{ + int ret; + + if (replyp->status != 0) + return (replyp->status); + + /* + * XXX Code goes here + */ + + return (replyp->status); +} + +int +__dbcl_db_rename_ret(dbp, name, subdb, newname, flags, replyp) + DB * dbp; + const char * name; + const char * subdb; + const char * newname; + u_int32_t flags; + __db_rename_reply *replyp; +{ + int ret; + + if (replyp->status != 0) + return (replyp->status); + + /* + * XXX Code goes here + */ + + return (replyp->status); +} + +int __db_db_stat_statsreplist __P((__db_stat_statsreplist, u_int32_t **)); +void __db_db_stat_statsfree __P((u_int32_t *)); + +int +__dbcl_db_stat_ret(dbp, sp, func0, flags, replyp) + DB * dbp; + void * sp; + void *(*func0) __P((size_t)); + u_int32_t flags; + __db_stat_reply *replyp; +{ + int ret; + u_int32_t *__db_statslist; + + if (replyp->status != 0) + return (replyp->status); + + if ((ret = __db_db_stat_statslist(replyp->statslist, &__db_statslist)) != 0) + return (ret); + + /* + * XXX Handle list + */ + + __db_db_stat_statsfree(__db_statslist); + + /* + * XXX Code goes here + */ + + return (replyp->status); +} + +int +__db_db_stat_statsreplist(locp, ppp) + __db_stat_statsreplist *locp; + u_int32_t **ppp; +{ + u_int32_t *pp; + int cnt, ret, size; + __db_stat_statsreplist *nl; + + for (cnt = 0, nl = locp; nl != NULL; cnt++, nl = nl->next) + ; + + if (cnt == 0) { + *ppp = NULL; + return (0); + } + size = sizeof(*pp) * cnt; + if ((ret = __os_malloc(NULL, size, NULL, ppp)) != 0) + return (ret); + memset(*ppp, 0, size); + for (pp = *ppp, nl = locp; nl != NULL; nl = nl->next, pp++) { + *pp = *(u_int32_t *)nl->ent.ent_val; + } + return (0); +out: + __db_db_stat_statsfree(*ppp); + return (ret); +} + +void +__db_db_stat_statsfree(pp) + u_int32_t *pp; +{ + size_t size; + u_int32_t *p; + + if (pp == NULL) + return; + size = sizeof(*p); + for (p = pp; *p != 0; p++) { + size += sizeof(*p); + } + __os_free(pp, size); +} + +int +__dbcl_db_cursor_ret(dbp, txnp, dbcpp, flags, replyp) + DB * dbp; + DB_TXN * txnp; + DBC ** dbcpp; + u_int32_t flags; + __db_cursor_reply *replyp; +{ + int ret; + long dbcid; + + if (replyp->status != 0) + return (replyp->status); + dbcid = replyp->dbcidcl_id; + + /* + * XXX Code goes here + */ + + return (replyp->status); +} + +int +__dbcl_db_join_ret(dbp, curs, dbcp, flags, replyp) + DB * dbp; + DBC ** curs; + DBC ** dbcp; + u_int32_t flags; + __db_join_reply *replyp; +{ + int ret; + long dbcid; + + if (replyp->status != 0) + return (replyp->status); + dbcid = replyp->dbcidcl_id; + + /* + * XXX Code goes here + */ + + return (replyp->status); +} + +int +__dbcl_dbc_close_ret(dbc, replyp) + DBC * dbc; + __dbc_close_reply *replyp; +{ + int ret; + + if (replyp->status != 0) + return (replyp->status); + + /* + * XXX Code goes here + */ + + return (replyp->status); +} + +int +__dbcl_dbc_count_ret(dbc, countp, flags, replyp) + DBC * dbc; + db_recno_t * countp; + u_int32_t flags; + __dbc_count_reply *replyp; +{ + int ret; + db_recno_t dupcount; + + if (replyp->status != 0) + return (replyp->status); + dupcount = replyp->dupcount; + + /* + * XXX Code goes here + */ + + return (replyp->status); +} + +int +__dbcl_dbc_dup_ret(dbc, dbcp, flags, replyp) + DBC * dbc; + DBC ** dbcp; + u_int32_t flags; + __dbc_dup_reply *replyp; +{ + int ret; + long dbcid; + + if (replyp->status != 0) + return (replyp->status); + dbcid = replyp->dbcidcl_id; + + /* + * XXX Code goes here + */ + + return (replyp->status); +} + +int +__dbcl_dbc_get_ret(dbc, key, data, flags, replyp) + DBC * dbc; + DBT * key; + DBT * data; + u_int32_t flags; + __dbc_get_reply *replyp; +{ + int ret; + /* DBT key; */ + /* DBT data; */ + + if (replyp->status != 0) + return (replyp->status); + /* Handle replyp->keydata; */ + /* Handle replyp->datadata; */ + + /* + * XXX Code goes here + */ + + return (replyp->status); +} + +int +__dbcl_dbc_put_ret(dbc, key, data, flags, replyp) + DBC * dbc; + DBT * key; + DBT * data; + u_int32_t flags; + __dbc_put_reply *replyp; +{ + int ret; + /* DBT key; */ + + if (replyp->status != 0) + return (replyp->status); + /* Handle replyp->keydata; */ + + /* + * XXX Code goes here + */ + + return (replyp->status); +} + +#endif /* HAVE_RPC */ diff --git a/db/dist/template/rec_btree b/db/dist/template/rec_btree new file mode 100644 index 000000000..6c954db1a --- /dev/null +++ b/db/dist/template/rec_btree @@ -0,0 +1,943 @@ +#include "db_config.h" + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "bam.h" +#include "log.h" + +/* + * __bam_pg_alloc_recover -- + * Recovery function for pg_alloc. + * + * PUBLIC: int __bam_pg_alloc_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__bam_pg_alloc_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __bam_pg_alloc_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__bam_pg_alloc_print); + REC_INTRO(__bam_pg_alloc_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __bam_pg_alloc1_recover -- + * Recovery function for pg_alloc1. + * + * PUBLIC: int __bam_pg_alloc1_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__bam_pg_alloc1_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __bam_pg_alloc1_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__bam_pg_alloc1_print); + REC_INTRO(__bam_pg_alloc1_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __bam_pg_free_recover -- + * Recovery function for pg_free. + * + * PUBLIC: int __bam_pg_free_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__bam_pg_free_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __bam_pg_free_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__bam_pg_free_print); + REC_INTRO(__bam_pg_free_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __bam_pg_free1_recover -- + * Recovery function for pg_free1. + * + * PUBLIC: int __bam_pg_free1_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__bam_pg_free1_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __bam_pg_free1_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__bam_pg_free1_print); + REC_INTRO(__bam_pg_free1_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __bam_split1_recover -- + * Recovery function for split1. + * + * PUBLIC: int __bam_split1_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__bam_split1_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __bam_split1_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__bam_split1_print); + REC_INTRO(__bam_split1_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __bam_split_recover -- + * Recovery function for split. + * + * PUBLIC: int __bam_split_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__bam_split_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __bam_split_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__bam_split_print); + REC_INTRO(__bam_split_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __bam_rsplit1_recover -- + * Recovery function for rsplit1. + * + * PUBLIC: int __bam_rsplit1_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__bam_rsplit1_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __bam_rsplit1_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__bam_rsplit1_print); + REC_INTRO(__bam_rsplit1_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __bam_rsplit_recover -- + * Recovery function for rsplit. + * + * PUBLIC: int __bam_rsplit_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__bam_rsplit_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __bam_rsplit_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__bam_rsplit_print); + REC_INTRO(__bam_rsplit_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __bam_adj_recover -- + * Recovery function for adj. + * + * PUBLIC: int __bam_adj_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__bam_adj_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __bam_adj_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__bam_adj_print); + REC_INTRO(__bam_adj_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __bam_cadjust_recover -- + * Recovery function for cadjust. + * + * PUBLIC: int __bam_cadjust_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__bam_cadjust_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __bam_cadjust_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__bam_cadjust_print); + REC_INTRO(__bam_cadjust_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __bam_cdel_recover -- + * Recovery function for cdel. + * + * PUBLIC: int __bam_cdel_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__bam_cdel_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __bam_cdel_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__bam_cdel_print); + REC_INTRO(__bam_cdel_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __bam_repl_recover -- + * Recovery function for repl. + * + * PUBLIC: int __bam_repl_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__bam_repl_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __bam_repl_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__bam_repl_print); + REC_INTRO(__bam_repl_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __bam_root_recover -- + * Recovery function for root. + * + * PUBLIC: int __bam_root_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__bam_root_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __bam_root_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__bam_root_print); + REC_INTRO(__bam_root_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __bam_curadj_recover -- + * Recovery function for curadj. + * + * PUBLIC: int __bam_curadj_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__bam_curadj_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __bam_curadj_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__bam_curadj_print); + REC_INTRO(__bam_curadj_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __bam_rcuradj_recover -- + * Recovery function for rcuradj. + * + * PUBLIC: int __bam_rcuradj_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__bam_rcuradj_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __bam_rcuradj_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__bam_rcuradj_print); + REC_INTRO(__bam_rcuradj_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + diff --git a/db/dist/template/rec_crdel b/db/dist/template/rec_crdel new file mode 100644 index 000000000..352e9ae5f --- /dev/null +++ b/db/dist/template/rec_crdel @@ -0,0 +1,385 @@ +#include "db_config.h" + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "crdel.h" +#include "log.h" + +/* + * __crdel_fileopen_recover -- + * Recovery function for fileopen. + * + * PUBLIC: int __crdel_fileopen_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__crdel_fileopen_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __crdel_fileopen_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__crdel_fileopen_print); + REC_INTRO(__crdel_fileopen_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __crdel_metasub_recover -- + * Recovery function for metasub. + * + * PUBLIC: int __crdel_metasub_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__crdel_metasub_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __crdel_metasub_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__crdel_metasub_print); + REC_INTRO(__crdel_metasub_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __crdel_metapage_recover -- + * Recovery function for metapage. + * + * PUBLIC: int __crdel_metapage_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__crdel_metapage_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __crdel_metapage_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__crdel_metapage_print); + REC_INTRO(__crdel_metapage_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __crdel_old_delete_recover -- + * Recovery function for old_delete. + * + * PUBLIC: int __crdel_old_delete_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__crdel_old_delete_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __crdel_old_delete_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__crdel_old_delete_print); + REC_INTRO(__crdel_old_delete_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __crdel_rename_recover -- + * Recovery function for rename. + * + * PUBLIC: int __crdel_rename_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__crdel_rename_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __crdel_rename_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__crdel_rename_print); + REC_INTRO(__crdel_rename_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __crdel_delete_recover -- + * Recovery function for delete. + * + * PUBLIC: int __crdel_delete_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__crdel_delete_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __crdel_delete_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__crdel_delete_print); + REC_INTRO(__crdel_delete_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + diff --git a/db/dist/template/rec_db b/db/dist/template/rec_db new file mode 100644 index 000000000..69d941351 --- /dev/null +++ b/db/dist/template/rec_db @@ -0,0 +1,509 @@ +#include "db_config.h" + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db.h" +#include "log.h" + +/* + * __db_addrem_recover -- + * Recovery function for addrem. + * + * PUBLIC: int __db_addrem_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__db_addrem_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __db_addrem_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__db_addrem_print); + REC_INTRO(__db_addrem_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __db_split_recover -- + * Recovery function for split. + * + * PUBLIC: int __db_split_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__db_split_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __db_split_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__db_split_print); + REC_INTRO(__db_split_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __db_big_recover -- + * Recovery function for big. + * + * PUBLIC: int __db_big_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__db_big_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __db_big_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__db_big_print); + REC_INTRO(__db_big_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __db_ovref_recover -- + * Recovery function for ovref. + * + * PUBLIC: int __db_ovref_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__db_ovref_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __db_ovref_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__db_ovref_print); + REC_INTRO(__db_ovref_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __db_relink_recover -- + * Recovery function for relink. + * + * PUBLIC: int __db_relink_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__db_relink_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __db_relink_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__db_relink_print); + REC_INTRO(__db_relink_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __db_addpage_recover -- + * Recovery function for addpage. + * + * PUBLIC: int __db_addpage_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__db_addpage_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __db_addpage_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__db_addpage_print); + REC_INTRO(__db_addpage_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __db_debug_recover -- + * Recovery function for debug. + * + * PUBLIC: int __db_debug_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__db_debug_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __db_debug_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__db_debug_print); + REC_INTRO(__db_debug_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __db_noop_recover -- + * Recovery function for noop. + * + * PUBLIC: int __db_noop_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__db_noop_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __db_noop_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__db_noop_print); + REC_INTRO(__db_noop_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + diff --git a/db/dist/template/rec_hash b/db/dist/template/rec_hash new file mode 100644 index 000000000..bcee2131c --- /dev/null +++ b/db/dist/template/rec_hash @@ -0,0 +1,881 @@ +#include "db_config.h" + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "ham.h" +#include "log.h" + +/* + * __ham_insdel_recover -- + * Recovery function for insdel. + * + * PUBLIC: int __ham_insdel_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__ham_insdel_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __ham_insdel_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__ham_insdel_print); + REC_INTRO(__ham_insdel_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __ham_newpage_recover -- + * Recovery function for newpage. + * + * PUBLIC: int __ham_newpage_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__ham_newpage_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __ham_newpage_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__ham_newpage_print); + REC_INTRO(__ham_newpage_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __ham_splitmeta_recover -- + * Recovery function for splitmeta. + * + * PUBLIC: int __ham_splitmeta_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__ham_splitmeta_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __ham_splitmeta_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__ham_splitmeta_print); + REC_INTRO(__ham_splitmeta_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __ham_splitdata_recover -- + * Recovery function for splitdata. + * + * PUBLIC: int __ham_splitdata_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__ham_splitdata_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __ham_splitdata_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__ham_splitdata_print); + REC_INTRO(__ham_splitdata_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __ham_replace_recover -- + * Recovery function for replace. + * + * PUBLIC: int __ham_replace_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__ham_replace_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __ham_replace_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__ham_replace_print); + REC_INTRO(__ham_replace_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __ham_newpgno_recover -- + * Recovery function for newpgno. + * + * PUBLIC: int __ham_newpgno_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__ham_newpgno_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __ham_newpgno_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__ham_newpgno_print); + REC_INTRO(__ham_newpgno_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __ham_ovfl_recover -- + * Recovery function for ovfl. + * + * PUBLIC: int __ham_ovfl_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__ham_ovfl_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __ham_ovfl_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__ham_ovfl_print); + REC_INTRO(__ham_ovfl_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __ham_copypage_recover -- + * Recovery function for copypage. + * + * PUBLIC: int __ham_copypage_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__ham_copypage_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __ham_copypage_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__ham_copypage_print); + REC_INTRO(__ham_copypage_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __ham_metagroup_recover -- + * Recovery function for metagroup. + * + * PUBLIC: int __ham_metagroup_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__ham_metagroup_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __ham_metagroup_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__ham_metagroup_print); + REC_INTRO(__ham_metagroup_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __ham_groupalloc1_recover -- + * Recovery function for groupalloc1. + * + * PUBLIC: int __ham_groupalloc1_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__ham_groupalloc1_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __ham_groupalloc1_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__ham_groupalloc1_print); + REC_INTRO(__ham_groupalloc1_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __ham_groupalloc2_recover -- + * Recovery function for groupalloc2. + * + * PUBLIC: int __ham_groupalloc2_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__ham_groupalloc2_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __ham_groupalloc2_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__ham_groupalloc2_print); + REC_INTRO(__ham_groupalloc2_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __ham_groupalloc_recover -- + * Recovery function for groupalloc. + * + * PUBLIC: int __ham_groupalloc_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__ham_groupalloc_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __ham_groupalloc_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__ham_groupalloc_print); + REC_INTRO(__ham_groupalloc_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __ham_curadj_recover -- + * Recovery function for curadj. + * + * PUBLIC: int __ham_curadj_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__ham_curadj_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __ham_curadj_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__ham_curadj_print); + REC_INTRO(__ham_curadj_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __ham_chgpg_recover -- + * Recovery function for chgpg. + * + * PUBLIC: int __ham_chgpg_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__ham_chgpg_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __ham_chgpg_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__ham_chgpg_print); + REC_INTRO(__ham_chgpg_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + diff --git a/db/dist/template/rec_log b/db/dist/template/rec_log new file mode 100644 index 000000000..1ce40b378 --- /dev/null +++ b/db/dist/template/rec_log @@ -0,0 +1,137 @@ +#include "db_config.h" + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "log.h" +#include "log.h" + +/* + * __log_register1_recover -- + * Recovery function for register1. + * + * PUBLIC: int __log_register1_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__log_register1_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __log_register1_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__log_register1_print); + REC_INTRO(__log_register1_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __log_register_recover -- + * Recovery function for register. + * + * PUBLIC: int __log_register_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__log_register_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __log_register_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__log_register_print); + REC_INTRO(__log_register_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + diff --git a/db/dist/template/rec_qam b/db/dist/template/rec_qam new file mode 100644 index 000000000..fcd24d6a2 --- /dev/null +++ b/db/dist/template/rec_qam @@ -0,0 +1,509 @@ +#include "db_config.h" + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "qam.h" +#include "log.h" + +/* + * __qam_inc_recover -- + * Recovery function for inc. + * + * PUBLIC: int __qam_inc_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__qam_inc_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __qam_inc_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__qam_inc_print); + REC_INTRO(__qam_inc_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __qam_incfirst_recover -- + * Recovery function for incfirst. + * + * PUBLIC: int __qam_incfirst_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__qam_incfirst_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __qam_incfirst_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__qam_incfirst_print); + REC_INTRO(__qam_incfirst_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __qam_mvptr_recover -- + * Recovery function for mvptr. + * + * PUBLIC: int __qam_mvptr_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__qam_mvptr_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __qam_mvptr_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__qam_mvptr_print); + REC_INTRO(__qam_mvptr_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __qam_del_recover -- + * Recovery function for del. + * + * PUBLIC: int __qam_del_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__qam_del_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __qam_del_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__qam_del_print); + REC_INTRO(__qam_del_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __qam_add_recover -- + * Recovery function for add. + * + * PUBLIC: int __qam_add_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__qam_add_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __qam_add_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__qam_add_print); + REC_INTRO(__qam_add_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __qam_delete_recover -- + * Recovery function for delete. + * + * PUBLIC: int __qam_delete_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__qam_delete_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __qam_delete_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__qam_delete_print); + REC_INTRO(__qam_delete_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __qam_rename_recover -- + * Recovery function for rename. + * + * PUBLIC: int __qam_rename_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__qam_rename_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __qam_rename_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__qam_rename_print); + REC_INTRO(__qam_rename_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __qam_delext_recover -- + * Recovery function for delext. + * + * PUBLIC: int __qam_delext_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__qam_delext_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __qam_delext_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__qam_delext_print); + REC_INTRO(__qam_delext_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + diff --git a/db/dist/template/rec_txn b/db/dist/template/rec_txn new file mode 100644 index 000000000..c66d604f5 --- /dev/null +++ b/db/dist/template/rec_txn @@ -0,0 +1,509 @@ +#include "db_config.h" + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "txn.h" +#include "log.h" + +/* + * __txn_old_regop_recover -- + * Recovery function for old_regop. + * + * PUBLIC: int __txn_old_regop_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__txn_old_regop_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __txn_old_regop_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__txn_old_regop_print); + REC_INTRO(__txn_old_regop_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __txn_regop_recover -- + * Recovery function for regop. + * + * PUBLIC: int __txn_regop_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__txn_regop_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __txn_regop_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__txn_regop_print); + REC_INTRO(__txn_regop_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __txn_old_ckp_recover -- + * Recovery function for old_ckp. + * + * PUBLIC: int __txn_old_ckp_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__txn_old_ckp_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __txn_old_ckp_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__txn_old_ckp_print); + REC_INTRO(__txn_old_ckp_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __txn_ckp_recover -- + * Recovery function for ckp. + * + * PUBLIC: int __txn_ckp_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__txn_ckp_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __txn_ckp_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__txn_ckp_print); + REC_INTRO(__txn_ckp_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __txn_xa_regop_old_recover -- + * Recovery function for xa_regop_old. + * + * PUBLIC: int __txn_xa_regop_old_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__txn_xa_regop_old_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __txn_xa_regop_old_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__txn_xa_regop_old_print); + REC_INTRO(__txn_xa_regop_old_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __txn_xa_regop_recover -- + * Recovery function for xa_regop. + * + * PUBLIC: int __txn_xa_regop_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__txn_xa_regop_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __txn_xa_regop_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__txn_xa_regop_print); + REC_INTRO(__txn_xa_regop_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __txn_child_old_recover -- + * Recovery function for child_old. + * + * PUBLIC: int __txn_child_old_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__txn_child_old_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __txn_child_old_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__txn_child_old_print); + REC_INTRO(__txn_child_old_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __txn_child_recover -- + * Recovery function for child. + * + * PUBLIC: int __txn_child_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__txn_child_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __txn_child_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, modified, ret; + + REC_PRINT(__txn_child_print); + REC_INTRO(__txn_child_read); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + goto out; + } + + modified = 0; + cmp_n = log_compare(lsnp, &LSN(pagep)); + + /* + * Use this when there is something like "pagelsn" in the argp + * structure. Sometimes, you might need to compare meta-data + * lsn's instead. + * + * cmp_p = log_compare(&LSN(pagep), argp->pagelsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + if (ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) + goto out; + + *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + diff --git a/db/docs/api_c/c_index.html b/db/docs/api_c/c_index.html new file mode 100644 index 000000000..4b6023c80 --- /dev/null +++ b/db/docs/api_c/c_index.html @@ -0,0 +1,172 @@ + + + + + +Berkeley DB: C Interface by Function/Structure + + + + +

C Interface by Function/Structure

+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Database EnvironmentDescription
db_env_createCreate an environment handle
DBENV->closeClose an environment
DBENV->errError message with error string
DBENV->errxError message
DBENV->openOpen an environment
DBENV->removeRemove an environment
DBENV->set_cachesizeSet the environment cache size
DBENV->set_data_dirSet the environment data directory
DBENV->set_errcallSet error message callback
DBENV->set_errfileSet error message FILE
DBENV->set_errpfxSet error message prefix
DBENV->set_feedbackSet feedback callback
DBENV->set_flagsEnvironment configuration
DBENV->set_mutexlocksTurn off mutual exclusion locking
DBENV->set_paniccallSet panic callback
DBENV->set_recovery_initSet recovery initialization callback
DBENV->set_serverEstablish server connection
DBENV->set_shm_keySet system memory shared segment ID
DBENV->set_tmp_dirSet the environment temporary file directory
DBENV->set_verboseSet verbose messages
db_strerrorError strings
db_versionReturn version information
Database OperationsDescription
db_createCreate a database handle
DB->closeClose a database
DB->delDelete items from a database
DB->errError message with error string
DB->errxError message
DB->fdReturn a file descriptor from a database
DB->getGet items from a database
DB->get_byteswappedReturn if the underlying database is in host order
DB->get_typeReturn the database type
DB->joinPerform a database join on cursors
DB->key_rangeReturn estimate of key location
DB->openOpen a database
DB->putStore items into a database
DB->removeRemove a database
DB->renameRename a database
DB->set_append_recnoSet record append callback
DB->set_bt_compareSet a Btree comparison function
DB->set_bt_minkeySet the minimum number of keys per Btree page
DB->set_bt_prefixSet a Btree prefix comparison function
DB->set_cachesizeSet the database cache size
DB->set_dup_compareSet a duplicate comparison function
DB->set_errcallSet error message callback
DB->set_errfileSet error message FILE
DB->set_errpfxSet error message prefix
DB->set_feedbackSet feedback callback
DB->set_flagsGeneral database configuration
DB->set_h_ffactorSet the Hash table density
DB->set_h_hashSet a hashing function
DB->set_h_nelemSet the Hash table size
DB->set_lorderSet the database byte order
DB->set_mallocSet a local space allocation function
DB->set_pagesizeSet the underlying database page size
DB->set_paniccallSet panic callback
DB->set_q_extentsizeSet Queue database extent size
DB->set_re_delimSet the variable-length record delimiter
DB->set_re_lenSet the fixed-length record length
DB->set_re_padSet the fixed-length record pad byte
DB->set_re_sourceSet the backing Recno text file
DB->set_reallocSet a local space allocation function
DB->statReturn database statistics
DB->syncFlush a database to stable storage
DB->upgradeUpgrade a database
DB->verifyVerify/salvage a database
Database CursorsDescription
DB->cursorOpen a cursor into a database
DBcursor->c_closeClose a cursor
DBcursor->c_countReturn count of duplicates
DBcursor->c_delDelete by cursor
DBcursor->c_dupDuplicate a cursor
DBcursor->c_getRetrieve by cursor
DBcursor->c_putStore by cursor
Lock ManagerDescription
DBENV->set_lk_conflictsSet lock conflicts matrix
DBENV->set_lk_detectSet automatic deadlock detection
DBENV->set_lk_maxSet maximum number of locks (Deprecated)
DBENV->set_lk_max_locksSet maximum number of locks
DBENV->set_lk_max_lockersSet maximum number of lockers
DBENV->set_lk_max_objectsSet maximum number of lock objects
lock_detectPerform deadlock detection
lock_getAcquire a lock
lock_idAcquire a locker ID
lock_putRelease a lock
lock_statReturn lock subsystem statistics
lock_vecAcquire/release locks
Log ManagerDescription
DBENV->set_lg_bsizeSet log buffer size
DBENV->set_lg_dirSet the environment logging directory
DBENV->set_lg_maxSet log file size
log_archiveList log and database files
log_compareCompare two Log Sequence Numbers
log_fileMap Log Sequence Numbers to log files
log_flushFlush log records
log_getGet a log record
log_putWrite a log record
log_registerRegister a file name with the log manager
log_statReturn log subsystem statistics
log_unregisterUnregister a file name with the log manager
Buffer PoolDescription
DBENV->set_cachesizeSet the environment cache size
DBENV->set_mp_mmapsizeSet maximum mapped-in database file size
memp_fcloseClose a file in a buffer pool
memp_fgetGet a page from a file in a buffer pool
memp_fopenOpen a file in a buffer pool
memp_fputReturn a page to a buffer pool
memp_fsetModify meta information for buffer pool page
memp_fsyncFlush pages from a file in a buffer pool
memp_registerRegister input/output functions for a file in a buffer pool
memp_statReturn buffer pool statistics
memp_syncFlush pages from a buffer pool
memp_trickleTrickle flush pages from a buffer pool
Transaction ManagerDescription
DBENV->set_tx_maxSet maximum number of transactions
DBENV->set_tx_recoverSet transaction abort recover function
DBENV->set_tx_timestampSet recovery timestamp
txn_abortAbort a transaction
txn_beginBegin a transaction
txn_checkpointCheckpoint the transaction subsystem
txn_commitCommit a transaction
txn_idReturn a transaction ID
txn_preparePrepare a transaction for commit
txn_statReturn transaction subsystem statistics
Historic InterfacesDescription
dbmUNIX Dbm/Ndbm Interfaces
hsearchUNIX Hsearch Interfaces
Data StructuresDescription
DBTDBT structures
DB_LSNDB_LSN structures
DB Library ConfigurationDescription
db_env_set_pageyieldYield the processor on each page access
db_env_set_panicstateReset panic state
db_env_set_region_initFault in shared regions on initial access
db_env_set_tas_spinsSet the number of test-and-set spins
DB System Call ConfigurationDescription
db_env_set_func_closeReplace underlying Berkeley DB system interfaces
db_env_set_func_dirfree
db_env_set_func_dirlist
db_env_set_func_exists
db_env_set_func_free
db_env_set_func_fsync
db_env_set_func_ioinfo
db_env_set_func_malloc
db_env_set_func_map
db_env_set_func_open
db_env_set_func_read
db_env_set_func_realloc
db_env_set_func_rename
db_env_set_func_seek
db_env_set_func_sleep
db_env_set_func_unlink
db_env_set_func_unmap
db_env_set_func_write
db_env_set_func_yield
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/c_pindex.html b/db/docs/api_c/c_pindex.html new file mode 100644 index 000000000..725bf0068 --- /dev/null +++ b/db/docs/api_c/c_pindex.html @@ -0,0 +1,530 @@ + + +Berkeley DB: C Interface Index + + + + +

C Interface Index

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
configuring Berkeley DB 1.85 API compatibility
building a utility to dump Berkeley DB 1.85 databases
Upgrading to release 2.0
Upgrading to release 3.0
Upgrading to release 3.1
Upgrading to release 3.2
selecting an access method
access methods
AIX
data alignment
programmatic APIs
utility to archive log files
berkeley_db_svc
building for UNIX
building for UNIX FAQ
building for VxWorks
building for VxWorks FAQ
building for Win32
building for Windows FAQ
selecting a byte order
byte ordering
configuring the C++ API
flushing the database cache
selecting a cache size
catastrophic recovery
Patches, Updates and Change logs
utility to take checkpoints
memp_fopenclear_len
closing a cursor
closing a database
specifying a Btree comparison function
changing compile or load options
Concurrent Data Store
configuring Berkeley DB for UNIX systems
recovering corrupted databases
counting data items for a key
closing a cursor
deleting records with a cursor
duplicating a cursor
retrieving records with a cursor
storing records with a cursor
cursor stability
database cursors
DBTdata
utility to upgrade database files
utility to verify database files
DBcursor->c_putDB_AFTER
DB->verifyDB_AGGRESSIVE
DB->putDB_APPEND
log_archiveDB_ARCH_ABS
log_archiveDB_ARCH_DATA
db_archive
log_archiveDB_ARCH_LOG
DBcursor->c_putDB_BEFORE
DB->statDB_CACHED_COUNTS
DBENV->set_flagsDB_CDB_ALLDB
log_getDB_CHECKPOINT
log_putDB_CHECKPOINT
db_checkpoint
db_env_createDB_CLIENT
File namingDB_CONFIG
DB->getDB_CONSUME
DB->getDB_CONSUME_WAIT
db_create
DB->openDB_CREATE
DBENV->openDB_CREATE
memp_fopenDB_CREATE
log_putDB_CURLSN
DBcursor->c_getDB_CURRENT
DBcursor->c_putDB_CURRENT
log_getDB_CURRENT
DBcursor->c_close
DBcursor->c_count
DBcursor->c_del
DBcursor->c_dup
DBcursor->c_get
DBcursor->c_put
DBTDB_DBT_MALLOC
DBTDB_DBT_PARTIAL
DBTDB_DBT_REALLOC
DBTDB_DBT_USERMEM
db_deadlock
db_dump
DB->set_flagsDB_DUP
DB->set_flagsDB_DUPSORT
DB->upgradeDB_DUPSORT
db_env_create
DBENV->close
DBENV->err
DBENV->open
DBENV->remove
DBENV->set_cachesize
DBENV->set_data_dir
DBENV->set_errcall
DBENV->set_errfile
DBENV->set_errpfx
DBENV->set_feedback
DBENV->set_flags
DBENV->set_lg_bsize
DBENV->set_lg_dir
DBENV->set_lg_max
DBENV->set_lk_conflicts
DBENV->set_lk_detect
DBENV->set_lk_max
DBENV->set_lk_max_lockers
DBENV->set_lk_max_locks
DBENV->set_lk_max_objects
DBENV->set_mp_mmapsize
DBENV->set_mutexlocks
DBENV->set_paniccall
DBENV->set_recovery_init
DBENV->set_server
DBENV->set_shm_key
DBENV->set_tmp_dir
DBENV->set_tx_max
DBENV->set_tx_recover
DBENV->set_tx_timestamp
DBENV->set_verbose
db_env_set_func_close
db_env_set_func_dirfree
db_env_set_func_dirlist
db_env_set_func_exists
db_env_set_func_free
db_env_set_func_fsync
db_env_set_func_ioinfo
db_env_set_func_malloc
db_env_set_func_map
db_env_set_func_open
db_env_set_func_read
db_env_set_func_realloc
db_env_set_func_rename
db_env_set_func_seek
db_env_set_func_sleep
db_env_set_func_unlink
db_env_set_func_unmap
db_env_set_func_write
db_env_set_func_yield
db_env_set_pageyield
db_env_set_panicstate
db_env_set_region_init
db_env_set_tas_spins
DB->openDB_EXCL
DBcursor->c_getDB_FIRST
log_getDB_FIRST
log_putDB_FLUSH
DBENV->removeDB_FORCE
txn_checkpointDB_FORCE
DB->getDB_GET_BOTH
DBcursor->c_getDB_GET_BOTH
DBcursor->c_getDB_GET_RECNO
DB->close
DB->cursor
DB->del
DB->fd
DB->get
DB->get_byteswapped
DB->get_type
DB->join
DB->key_range
DB->open
DB->put
DB->remove
DB->rename
DB->set_append_recno
DB->set_bt_compare
DB->set_bt_minkey
DB->set_bt_prefix
DB->set_cachesize
DB->set_dup_compare
DB->set_errcall
DB->set_errfile
DB->set_errpfx
DB->set_feedback
DB->set_flags
DB->set_h_ffactor
DB->set_h_hash
DB->set_h_nelem
DB->set_lorder
DB->set_malloc
DB->set_pagesize
DB->set_paniccall
DB->set_q_extentsize
DB->set_realloc
DB->set_re_delim
DB->set_re_len
DB->set_re_pad
DB->set_re_source
DB->stat
DB->sync
DB->upgrade
DB->verify
File namingDB_HOME
File namingdb_home
DB->close DB_INCOMPLETE
DBENV->openDB_INIT_CDB
DBENV->openDB_INIT_LOCK
DBENV->openDB_INIT_LOG
DBENV->openDB_INIT_MPOOL
DBENV->openDB_INIT_TXN
DBENV->openDB_JOINENV
DB->joinDB_JOIN_ITEM
DBcursor->c_getDB_JOIN_ITEM
DB->joinDB_JOIN_NOSORT
Error returns to applicationsDB_KEYEMPTY
DBcursor->c_putDB_KEYFIRST
DBcursor->c_putDB_KEYLAST
DBcursor->c_getDB_LAST
log_getDB_LAST
db_load
lock_detectDB_LOCK_CONFLICT
Error returns to applicationsDB_LOCK_DEADLOCK
DBENV->set_lk_detectDB_LOCK_DEFAULT
DBENV->openDB_LOCKDOWN
lock_vecDB_LOCK_GET
lock_getDB_LOCK_NOTGRANTED
lock_vecDB_LOCK_NOTGRANTED
Error returns to applicationsDB_LOCK_NOTGRANTED
lock_getDB_LOCK_NOWAIT
lock_vecDB_LOCK_NOWAIT
DBENV->set_lk_detectDB_LOCK_OLDEST
lock_vecDB_LOCK_PUT
lock_vecDB_LOCK_PUT_ALL
lock_vecDB_LOCK_PUT_OBJ
DBENV->set_lk_detectDB_LOCK_RANDOM
DBENV->set_lk_detectDB_LOCK_YOUNGEST
DB_LSN
dbm/ndbm
memp_fputDB_MPOOL_CLEAN
memp_fsetDB_MPOOL_CLEAN
memp_fgetDB_MPOOL_CREATE
memp_fputDB_MPOOL_DIRTY
memp_fsetDB_MPOOL_DIRTY
memp_fputDB_MPOOL_DISCARD
memp_fsetDB_MPOOL_DISCARD
memp_fgetDB_MPOOL_LAST
memp_fgetDB_MPOOL_NEW
DBcursor->c_getDB_NEXT
log_getDB_NEXT
DBcursor->c_getDB_NEXT_DUP
DBcursor->c_getDB_NEXT_NODUP
DB->putDB_NODUPDATA
DBcursor->c_putDB_NODUPDATA
DB->openDB_NOMMAP
DBENV->set_flagsDB_NOMMAP
memp_fopenDB_NOMMAP
DB->verifyDB_NOORDERCHK
DB->putDB_NOOVERWRITE
DBENV->set_serverDB_NOSERVER
DBENV->set_serverDB_NOSERVER_ID
DB->closeDB_NOSYNC
Error returns to applicationsDB_NOTFOUND
DB->openDB_OLD_VERSION
DB->upgradeDB_OLD_VERSION
DB->verifyDB_ORDERCHKONLY
DBcursor->c_dupDB_POSITION
DBcursor->c_getDB_PREV
log_getDB_PREV
DBcursor->c_getDB_PREV_NODUP
db_printlog
DBENV->openDB_PRIVATE
DB->openDB_RDONLY
memp_fopenDB_RDONLY
DB->set_flagsDB_RECNUM
DB->statDB_RECORDCOUNT
DBENV->openDB_RECOVER
DBENV->set_feedbackDB_RECOVER
db_recover
DBENV->openDB_RECOVER_FATAL
DB->set_flagsDB_RENUMBER
DB->set_flagsDB_REVSPLITOFF
DB->getDB_RMW
DB->joinDB_RMW
DBcursor->c_getDB_RMW
Error returns to applicationsDB_RUNRECOVERY
DB->verifyDB_SALVAGE
DBcursor->c_getDB_SET
log_getDB_SET
DBcursor->c_getDB_SET_RANGE
DB->getDB_SET_RECNO
DBcursor->c_getDB_SET_RECNO
DB->set_flagsDB_SNAPSHOT
db_stat
db_strerror
DBENV->openDB_SYSTEM_MEM
DB->openDB_THREAD
DBENV->openDB_THREAD
DB->openDB_TRUNCATE
DBENV->set_tx_recoverDB_TXN_ABORT
DBENV->set_tx_recoverDB_TXN_BACKWARD_ROLL
DBENV->set_tx_recoverDB_TXN_FORWARD_ROLL
DBENV->set_flagsDB_TXN_NOSYNC
txn_beginDB_TXN_NOSYNC
txn_commitDB_TXN_NOSYNC
txn_beginDB_TXN_NOWAIT
txn_beginDB_TXN_SYNC
txn_commitDB_TXN_SYNC
DB->set_feedbackDB_UPGRADE
db_upgrade
DBENV->openDB_USE_ENVIRON
DBENV->removeDB_USE_ENVIRON
DBENV->openDB_USE_ENVIRON_ROOT
DBENV->removeDB_USE_ENVIRON_ROOT
DBENV->set_verboseDB_VERB_CHKPOINT
DBENV->set_verboseDB_VERB_DEADLOCK
DBENV->set_verboseDB_VERB_RECOVERY
DBENV->set_verboseDB_VERB_WAITSFOR
DB->set_feedbackDB_VERIFY
db_verify
db_version
DB->cursorDB_WRITECURSOR
db_createDB_XA_CREATE
deadlocks
utility to detect deadlocks
debugging applications
deleting records
deleting records with a cursor
Configuring Berkeley DB--disable-bigfile
disk space requirements
DBTdlen
DBTdoff
utility to dump databases as text files
duplicate data items
duplicating a cursor
configuring dynamic shared libraries
Configuring Berkeley DB--enable-compat185
Configuring Berkeley DB--enable-cxx
Configuring Berkeley DB--enable-debug
Configuring Berkeley DB--enable-debug_rop
Configuring Berkeley DB--enable-debug_wop
Configuring Berkeley DB--enable-diagnostic
Configuring Berkeley DB--enable-dump185
Configuring Berkeley DB--enable-dynamic
Configuring Berkeley DB--enable-java
Configuring Berkeley DB--enable-posixmutexes
Configuring Berkeley DB--enable-rpc
Configuring Berkeley DB--enable-shared
Configuring Berkeley DB--enable-tcl
Configuring Berkeley DB--enable-test
Configuring Berkeley DB--enable-uimutexes
Configuring Berkeley DB--enable-umrw
byte endian
database environment
environment variables
error handling
error name space
error returns
/etc/magic
selecting a Queue extent size
Java FAQ
Tcl FAQ
configuring without large file support
file utility
memp_fopenfileid
recovery and filesystem operations
remote filesystems
page fill factor
FreeBSD
Berkeley DB free-threaded handles
memp_fopenftype
specifying a database hash
hash table size
HP-UX
hsearch
installing Berkeley DB for UNIX systems
interface compatibility
IRIX
configuring the Java API
Java compatibility
Java configuration
Java FAQ
logical join
key/data pairs
retrieved key/data permanence
database limits
Linux
changing compile or load options
utility to load text files into databases
lock_veclock
standard lock modes
lock_detect
lock_get
lock_id
page-level locking
two-phase locking
locking and non-Berkeley DB applications
locking configuration
locking conventions
Berkeley DB Concurrent Data Store locking conventions
locking introduction
sizing the locking subsystem
locking without transactions
lock_put
lock_stat
lock_vec
log file limits
log file removal
utility to display log files as text
log_archive
log_compare
log_file
log_flush
log_get
logging configuration
logging introduction
log_put
log_register
log_stat
log_unregister
memp_fopenlsn_offset
memory pool configuration
memp_fclose
memp_fget
memp_fopen
memp_fput
memp_fset
memp_fsync
memp_register
memp_stat
memp_sync
memp_trickle
lock_vecmode
Berkeley DB library name spaces
file naming
retrieving Btree records by number
lock_vecobj
lock_vecop
opening a database
OSF/1
selecting a page size
partial record storage and retrieval
Patches, Updates and Change logs
Perl
retrieved key/data permanence
memp_fopenpgcookie
Sleepycat Software's Berkeley DB products
QNX
logical record number format
logical record numbers
managing record-based databases
logically renumbering records
utility to recover database environments
Berkeley DB recoverability
retrieving records
retrieving records with a cursor
RPC client
configuring a RPC client/server
utility to support RPC client/server
RPC server
database salvage
SCO
Berkeley DB handle scope
security
Sendmail
configuring shared libraries
shared libraries
application signal handling
DBTsize
Sleepycat Software
Solaris
source code layout
cursor stability
database statistics
utility to display database and environment statistics
storing records
storing records with a cursor
SunOS
loading Berkeley DB with Tcl
using Berkeley DB with Tcl
configuring the Tcl API
Tcl API programming notes
Tcl FAQ
configuring the test suite
running the test suite
running the test suite under UNIX
running the test suite under Windows
text backing files
loading text into databases
dumping/loading text to/from databases
building threaded applications
transaction configuration
transaction limits
administering transaction protected applications
archival in transaction protected applications
checkpoints in transaction protected applications
deadlock detection in transaction protected applications
recovery in transaction protected applications
transaction throughput
Transactional Data Store
Berkeley DB and transactions
nested transactions
configuring Berkeley DB with the Tuxedo System
txn_abort
txn_begin
txn_checkpoint
txn_commit
txn_id
txn_prepare
txn_stat
DBTulen
Ultrix
building for UNIX FAQ
configuring Berkeley DB for UNIX systems
Patches, Updates and Change logs
utility to upgrade database files
upgrading databases
utilities
database verification
utility to verify database files
building for VxWorks FAQ
VxWorks notes
running the test suite under Windows
building for Windows FAQ
Windows notes
Configuring Berkeley DB--with-tcl=DIR
XA Resource Manager
+
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_close.html b/db/docs/api_c/db_close.html new file mode 100644 index 000000000..f6c763c5b --- /dev/null +++ b/db/docs/api_c/db_close.html @@ -0,0 +1,119 @@ + + + + + +Berkeley DB: DB->close + + + + + + + +
+

DB->close

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DB->close(DB *db, u_int32_t flags); +

+

Description

+

The DB->close function flushes any cached database information to disk, +closes any open cursors, frees any allocated resources, and closes any +underlying files. Since key/data pairs are cached in memory, failing to +sync the file with the DB->close or DB->sync function may result +in inconsistent or lost information. +

The flags parameter must be set to 0 or the following value: +

+

DB_NOSYNC
Do not flush cached information to disk. +

The DB_NOSYNC flag is a dangerous option. It should only be set +if the application is doing logging (with transactions) so that the +database is recoverable after a system or application crash, or if the +database is always generated from scratch after any system or application +crash. +

It is important to understand that flushing cached information to disk +only minimizes the window of opportunity for corrupted data. +While unlikely, it is possible for database corruption to happen if a +system or application crash occurs while writing data to the database. +To ensure that database corruption never occurs, applications must either: +use transactions and logging with automatic recovery, use logging and +application-specific recovery, or edit a copy of the database, +and, once all applications using the database have successfully called +DB->close, atomically replace the original database with the +updated copy. +

+

When multiple threads are using the Berkeley DB handle concurrently, only a single +thread may call the DB->close function. +

Once DB->close has been called, regardless of its return, the +DB handle may not be accessed again. + +

The DB->close function returns a non-zero error value on failure, 0 on success, and returns DB_INCOMPLETE if the underlying database still has +dirty pages in the cache. (The only reason to return +DB_INCOMPLETE is if another thread of control was writing pages +in the underlying database file at the same time as the +DB->close function was called. For this reason, a return of +DB_INCOMPLETE can normally be ignored, or, in cases where it is +a possible return value, the DB_NOSYNC option should probably +have been specified.) +

The DB->close function returns a non-zero error value on failure and 0 on success. +

Errors

+

The DB->close function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the DB->close function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+db_create, +DB->close, +DB->cursor, +DB->del, +DB->err, +DB->fd, +DB->get, +DB->get_byteswapped, +DB->get_type, +DB->join, +DB->key_range, +DB->open, +DB->put, +DB->remove, +DB->set_bt_compare, +DB->set_bt_minkey, +DB->set_bt_prefix, +DB->set_cachesize, +DB->set_dup_compare, +DB->set_errcall, +DB->set_errfile, +DB->set_errpfx, +DB->set_flags, +DB->set_h_ffactor, +DB->set_h_hash, +DB->set_h_nelem, +DB->set_lorder, +DB->set_malloc, +DB->set_pagesize, +DB->set_paniccall, +DB->set_q_extentsize, +DB->set_realloc, +DB->set_re_delim, +DB->set_re_len, +DB->set_re_pad, +DB->set_re_source, +DB->stat, +DB->sync, +DB->upgrade +and +DB->verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_create.html b/db/docs/api_c/db_create.html new file mode 100644 index 000000000..c1fd3fca1 --- /dev/null +++ b/db/docs/api_c/db_create.html @@ -0,0 +1,107 @@ + + + + + +Berkeley DB: db_create + + + + + + + +
+

db_create

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +db_create(DB **dbp, DB_ENV *dbenv, u_int32_t flags); +

+

Description

+

The db_create function creates a DB structure which is the +handle for a Berkeley DB database. A pointer to this structure is returned +in the memory referenced by db. +

If the dbenv argument is NULL, the database is standalone, i.e., +it is not part of any Berkeley DB environment. +

If the dbenv argument is not NULL, the database is created within +the specified Berkeley DB environment. The database access methods +automatically make calls to the other subsystems in Berkeley DB based on the +enclosing environment. For example, if the environment has been +configured to use locking, then the access methods will automatically +acquire the correct locks when reading and writing pages of the database. +

The flags parameter must be set to 0 or one of the following +values: +

+

DB_XA_CREATE
Instead of creating a standalone database, create a database intended to +be accessed via applications running under a X/Open conformant Transaction +Manager. The database will be opened in the environment specified by the +OPENINFO parameter of the GROUPS section of the ubbconfig file. See the +XA Resource Manager chapter in the +Reference Guide for more information. +
+

The DB handle contains a special field, "app_private", which +is declared as type "void *". This field is provided for the use of +the application program. It is initialized to NULL and is not further +used by Berkeley DB in any way. +

The db_create function returns a non-zero error value on failure and 0 on success. +

Errors

+

The db_create function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the db_create function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+db_create, +DB->close, +DB->cursor, +DB->del, +DB->err, +DB->fd, +DB->get, +DB->get_byteswapped, +DB->get_type, +DB->join, +DB->key_range, +DB->open, +DB->put, +DB->remove, +DB->set_bt_compare, +DB->set_bt_minkey, +DB->set_bt_prefix, +DB->set_cachesize, +DB->set_dup_compare, +DB->set_errcall, +DB->set_errfile, +DB->set_errpfx, +DB->set_flags, +DB->set_h_ffactor, +DB->set_h_hash, +DB->set_h_nelem, +DB->set_lorder, +DB->set_malloc, +DB->set_pagesize, +DB->set_paniccall, +DB->set_q_extentsize, +DB->set_realloc, +DB->set_re_delim, +DB->set_re_len, +DB->set_re_pad, +DB->set_re_source, +DB->stat, +DB->sync, +DB->upgrade +and +DB->verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_cursor.html b/db/docs/api_c/db_cursor.html new file mode 100644 index 000000000..1fb6616ab --- /dev/null +++ b/db/docs/api_c/db_cursor.html @@ -0,0 +1,103 @@ + + + + + +Berkeley DB: DB->cursor + + + + + + + +
+

DB->cursor

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DB->cursor(DB *db, + DB_TXN *txnid, DBC **cursorp, u_int32_t flags); +

+

Description

+

The DB->cursor function +creates a cursor and copies a pointer to it into the memory referenced +by cursorp. +

If the file is being accessed under transaction protection, the +txnid parameter is a transaction ID returned from +txn_begin, otherwise, NULL. +

If transaction protection is enabled, cursors must be opened and closed +within the context of a transaction, and the txnid parameter +specifies the transaction context in which the cursor may be used. +

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +

+

DB_WRITECURSOR
Specify that the cursor will be used to update the database. This +flag should only be set when the DB_INIT_CDB flag +was specified to DBENV->open. +
+

The DB->cursor function returns a non-zero error value on failure and 0 on success. +

Errors

+

The DB->cursor function may fail and return a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +
+

The DB->cursor function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the DB->cursor function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+db_create, +DB->close, +DB->cursor, +DB->del, +DB->err, +DB->fd, +DB->get, +DB->get_byteswapped, +DB->get_type, +DB->join, +DB->key_range, +DB->open, +DB->put, +DB->remove, +DB->set_bt_compare, +DB->set_bt_minkey, +DB->set_bt_prefix, +DB->set_cachesize, +DB->set_dup_compare, +DB->set_errcall, +DB->set_errfile, +DB->set_errpfx, +DB->set_flags, +DB->set_h_ffactor, +DB->set_h_hash, +DB->set_h_nelem, +DB->set_lorder, +DB->set_malloc, +DB->set_pagesize, +DB->set_paniccall, +DB->set_q_extentsize, +DB->set_realloc, +DB->set_re_delim, +DB->set_re_len, +DB->set_re_pad, +DB->set_re_source, +DB->stat, +DB->sync, +DB->upgrade +and +DB->verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_del.html b/db/docs/api_c/db_del.html new file mode 100644 index 000000000..b273d29fd --- /dev/null +++ b/db/docs/api_c/db_del.html @@ -0,0 +1,101 @@ + + + + + +Berkeley DB: DB->del + + + + + + + +
+

DB->del

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DB->del(DB *db, DB_TXN *txnid, DBT *key, u_int32_t flags); +

+

Description

+

The DB->del function removes key/data pairs from the database. The +key/data pair associated with the specified key is discarded from +the database. In the presence of duplicate key values, all records +associated with the designated key will be discarded. +

If the file is being accessed under transaction protection, the +txnid parameter is a transaction ID returned from +txn_begin, otherwise, NULL. +

The flags parameter is currently unused, and must be set to 0. +

The DB->del function returns a non-zero error value on failure, 0 on success, and DB_NOTFOUND if the specified key did not exist in +the file. +

Errors

+

The DB->del function may fail and return a non-zero error for the following conditions: +

+

DB_LOCK_DEADLOCK
The operation was selected to resolve a deadlock. +
+

+

EACCES
An attempt was made to modify a read-only database. +
+

+

EINVAL
An invalid flag value or parameter was specified. +
+

The DB->del function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the DB->del function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+db_create, +DB->close, +DB->cursor, +DB->del, +DB->err, +DB->fd, +DB->get, +DB->get_byteswapped, +DB->get_type, +DB->join, +DB->key_range, +DB->open, +DB->put, +DB->remove, +DB->set_bt_compare, +DB->set_bt_minkey, +DB->set_bt_prefix, +DB->set_cachesize, +DB->set_dup_compare, +DB->set_errcall, +DB->set_errfile, +DB->set_errpfx, +DB->set_flags, +DB->set_h_ffactor, +DB->set_h_hash, +DB->set_h_nelem, +DB->set_lorder, +DB->set_malloc, +DB->set_pagesize, +DB->set_paniccall, +DB->set_q_extentsize, +DB->set_realloc, +DB->set_re_delim, +DB->set_re_len, +DB->set_re_pad, +DB->set_re_source, +DB->stat, +DB->sync, +DB->upgrade +and +DB->verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_err.html b/db/docs/api_c/db_err.html new file mode 100644 index 000000000..1eae12fab --- /dev/null +++ b/db/docs/api_c/db_err.html @@ -0,0 +1,93 @@ + + + + + +Berkeley DB: DBENV->err + + + + + + + +
+

DBENV->err

+
+APIRef +
+


+ +

+#include <db.h>
+

+void +DBENV->err(DB_ENV *dbenv, int error, const char *fmt, ...); +

+void +DBENV->errx(DB_ENV *dbenv, const char *fmt, ...); +

+void +DB->err(DB *db, int error, const char *fmt, ...); +

+void +DB->errx(DB *db, const char *fmt, ...); +

+

Description

+

The DBENV->err, DBENV->errx, DB->err and +DB->errx functions provide error messaging functionality for +applications written using the Berkeley DB library. +

The DBENV->err function constructs an error message consisting of the +following elements: +

+

An optional prefix string
If no error callback function has been set using the +DBENV->set_errcall function, any prefix string specified using the +DBENV->set_errpfx function, followed by two separating characters: a colon +and a <space> character. +

An optional printf-style message
The supplied message fmt, if non-NULL, where the ANSI C X3.159-1989 (ANSI C) +printf function specifies how subsequent arguments are converted for +output. +

A separator
Two separating characters: a colon and a <space> character. +

A standard error string
The standard system or Berkeley DB library error string associated with the +error value, as returned by the db_strerror function. +
+
+

This constructed error message is then handled as follows: +

+

If an error callback function has been set (see DB->set_errcall +and DBENV->set_errcall), that function is called with two +arguments: any prefix string specified (see DB->set_errpfx and +DBENV->set_errpfx), and the error message. +

If a C library FILE * has been set (see DB->set_errfile and +DBENV->set_errfile), the error message is written to that output +stream. +

If none of these output options has been configured, the error message +is written to stderr, the standard error output stream.

+

The DBENV->errx and DB->errx functions perform identically to the +DBENV->err and DB->err functions except that they do not append +the final separator characters and standard error string to the error +message. +

See Also

+DBENV->close, +db_env_create, +DBENV->open, +DBENV->remove, +DBENV->err, +db_strerror, +db_version, +DBENV->set_cachesize, +DBENV->set_errcall, +DBENV->set_errfile, +DBENV->set_errpfx, +DBENV->set_flags, +DBENV->set_mutexlocks, +DBENV->set_paniccall, +and +DBENV->set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_fd.html b/db/docs/api_c/db_fd.html new file mode 100644 index 000000000..2a385c1b3 --- /dev/null +++ b/db/docs/api_c/db_fd.html @@ -0,0 +1,92 @@ + + + + + +Berkeley DB: DB->fd + + + + + + + +
+

DB->fd

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DB->fd(DB *db, int *fdp); +

+

Description

+

The DB->fd function +copies a file descriptor representative of the underlying database into +the memory referenced by fdp. A file descriptor referencing the +same file will be returned to all processes that call DB->open with +the same file argument. This file descriptor may be safely used +as an argument to the fcntl(2) and flock(2) locking +functions. The file descriptor is not necessarily associated with any of +the underlying files actually used by the access method. +

The DB->fd function only supports a coarse-grained form of locking. +Applications should use the lock manager where possible. +

The DB->fd function returns a non-zero error value on failure and 0 on success. +

Errors

+

The DB->fd function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the DB->fd function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+db_create, +DB->close, +DB->cursor, +DB->del, +DB->err, +DB->fd, +DB->get, +DB->get_byteswapped, +DB->get_type, +DB->join, +DB->key_range, +DB->open, +DB->put, +DB->remove, +DB->set_bt_compare, +DB->set_bt_minkey, +DB->set_bt_prefix, +DB->set_cachesize, +DB->set_dup_compare, +DB->set_errcall, +DB->set_errfile, +DB->set_errpfx, +DB->set_flags, +DB->set_h_ffactor, +DB->set_h_hash, +DB->set_h_nelem, +DB->set_lorder, +DB->set_malloc, +DB->set_pagesize, +DB->set_paniccall, +DB->set_q_extentsize, +DB->set_realloc, +DB->set_re_delim, +DB->set_re_len, +DB->set_re_pad, +DB->set_re_source, +DB->stat, +DB->sync, +DB->upgrade +and +DB->verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_get.html b/db/docs/api_c/db_get.html new file mode 100644 index 000000000..c6cc3fcce --- /dev/null +++ b/db/docs/api_c/db_get.html @@ -0,0 +1,156 @@ + + + + + +Berkeley DB: DB->get + + + + + + + +
+

DB->get

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DB->get(DB *db, + DB_TXN *txnid, DBT *key, DBT *data, u_int32_t flags); +

+

Description

+

The DB->get function retrieves key/data pairs from the database. The +address +and length of the data associated with the specified key are +returned in the structure referenced by data. +

In the presence of duplicate key values, DB->get will return the +first data item for the designated key. Duplicates are sorted by insert +order except where this order has been overridden by cursor operations. +Retrieval of duplicates requires the use of cursor operations. +See DBcursor->c_get for details. +

If the file is being accessed under transaction protection, the +txnid parameter is a transaction ID returned from +txn_begin, otherwise, NULL. +

The flags parameter must be set to 0 or one of the following +values: +

+

DB_CONSUME
Return the record number and data from the available record closest to +the head of the queue and delete the record. The cursor will be +positioned on the deleted record. The record number will be returned +in key as described in DBT. The data will be returned +in the data parameter. A record is available if it is not +deleted and is not currently locked. The underlying database must be +of type Queue for DB_CONSUME to be specified. +

DB_CONSUME_WAIT
The DB_CONSUME_WAIT flag is the same as the DB_CONSUME +flag except that if the Queue database is empty, the thread of control +will wait until there is data in the queue before returning. The +underlying database must be of type Queue for DB_CONSUME_WAIT +to be specified. +

DB_GET_BOTH
Retrieve the key/data pair only if both the key and data match the +arguments. +

DB_SET_RECNO
Retrieve the specified numbered key/data pair from a database. +Upon return, both the key and data items will have been +filled in, not just the data item as is done for all other uses of the +DB->get function. +

The data field of the specified key +must be a pointer to a logical record number (i.e., a db_recno_t). +This record number determines the record to be retrieved. +

For DB_SET_RECNO to be specified, the underlying database must be +of type Btree and it must have been created with the DB_RECNUM flag. +

+

In addition, the following flag may be set by bitwise inclusively OR'ing it into the +flags parameter: +

+

DB_RMW
Acquire write locks instead of read locks when doing the retrieval. +Setting this flag may decrease the likelihood of deadlock during a +read-modify-write cycle by immediately acquiring the write lock during +the read part of the cycle so that another thread of control acquiring +a read lock for the same item, in its own read-modify-write cycle, will +not result in deadlock. +

As the DB->get interface will not hold locks across +Berkeley DB interface calls in non-transactional environments, the +DB_RMW flag to the DB->get call is only meaningful in +the presence of transactions. +

+

If the database is a Queue or Recno database and the requested key exists, +but was never explicitly created by the application or was later deleted, +the DB->get function returns DB_KEYEMPTY. +

Otherwise, if the requested key is not in the database, the +DB->get function returns DB_NOTFOUND. +

Otherwise, the DB->get function returns a non-zero error value on failure and 0 on success. +

Errors

+

The DB->get function may fail and return a non-zero error for the following conditions: +

+

DB_LOCK_DEADLOCK
The operation was selected to resolve a deadlock. +
+

+

ENOMEM
There was insufficient memory to return the requested item. +
+

+

EINVAL
An invalid flag value or parameter was specified. +

A record number of 0 was specified. +

The DB_THREAD flag was specified to the +DB->open function and none of the DB_DBT_MALLOC, +DB_DBT_REALLOC or DB_DBT_USERMEM flags were set in the +DBT. +

+

The DB->get function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the DB->get function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+db_create, +DB->close, +DB->cursor, +DB->del, +DB->err, +DB->fd, +DB->get, +DB->get_byteswapped, +DB->get_type, +DB->join, +DB->key_range, +DB->open, +DB->put, +DB->remove, +DB->set_bt_compare, +DB->set_bt_minkey, +DB->set_bt_prefix, +DB->set_cachesize, +DB->set_dup_compare, +DB->set_errcall, +DB->set_errfile, +DB->set_errpfx, +DB->set_flags, +DB->set_h_ffactor, +DB->set_h_hash, +DB->set_h_nelem, +DB->set_lorder, +DB->set_malloc, +DB->set_pagesize, +DB->set_paniccall, +DB->set_q_extentsize, +DB->set_realloc, +DB->set_re_delim, +DB->set_re_len, +DB->set_re_pad, +DB->set_re_source, +DB->stat, +DB->sync, +DB->upgrade +and +DB->verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_get_byteswapped.html b/db/docs/api_c/db_get_byteswapped.html new file mode 100644 index 000000000..205ddb794 --- /dev/null +++ b/db/docs/api_c/db_get_byteswapped.html @@ -0,0 +1,84 @@ + + + + + +Berkeley DB: DB->get_byteswapped + + + + + + + +
+

DB->get_byteswapped

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DB->get_byteswapped(DB *db); +

+

Description

+

The DB->get_byteswapped function returns +0 +if the underlying database files were created on an architecture +of the same byte order as the current one, and +1 +if they were not (i.e., big-endian on a little-endian machine or +vice-versa). This field may be used to determine if application +data needs to be adjusted for this architecture or not. +

See Also

+db_create, +DB->close, +DB->cursor, +DB->del, +DB->err, +DB->fd, +DB->get, +DB->get_byteswapped, +DB->get_type, +DB->join, +DB->key_range, +DB->open, +DB->put, +DB->remove, +DB->set_bt_compare, +DB->set_bt_minkey, +DB->set_bt_prefix, +DB->set_cachesize, +DB->set_dup_compare, +DB->set_errcall, +DB->set_errfile, +DB->set_errpfx, +DB->set_flags, +DB->set_h_ffactor, +DB->set_h_hash, +DB->set_h_nelem, +DB->set_lorder, +DB->set_malloc, +DB->set_pagesize, +DB->set_paniccall, +DB->set_q_extentsize, +DB->set_realloc, +DB->set_re_delim, +DB->set_re_len, +DB->set_re_pad, +DB->set_re_source, +DB->stat, +DB->sync, +DB->upgrade +and +DB->verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_get_type.html b/db/docs/api_c/db_get_type.html new file mode 100644 index 000000000..a1905c782 --- /dev/null +++ b/db/docs/api_c/db_get_type.html @@ -0,0 +1,81 @@ + + + + + +Berkeley DB: DB->get_type + + + + + + + +
+

DB->get_type

+
+APIRef +
+


+ +

+#include <db.h>
+

+DBTYPE +DB->get_type(DB *db); +

+

Description

+

The DB->get_type function returns the type of the underlying access method +(and file format). It returns one of DB_BTREE, +DB_HASH or DB_RECNO. This value may be used to +determine the type of the database after a return from DB->open +with the type argument set to DB_UNKNOWN. +

See Also

+db_create, +DB->close, +DB->cursor, +DB->del, +DB->err, +DB->fd, +DB->get, +DB->get_byteswapped, +DB->get_type, +DB->join, +DB->key_range, +DB->open, +DB->put, +DB->remove, +DB->set_bt_compare, +DB->set_bt_minkey, +DB->set_bt_prefix, +DB->set_cachesize, +DB->set_dup_compare, +DB->set_errcall, +DB->set_errfile, +DB->set_errpfx, +DB->set_flags, +DB->set_h_ffactor, +DB->set_h_hash, +DB->set_h_nelem, +DB->set_lorder, +DB->set_malloc, +DB->set_pagesize, +DB->set_paniccall, +DB->set_q_extentsize, +DB->set_realloc, +DB->set_re_delim, +DB->set_re_len, +DB->set_re_pad, +DB->set_re_source, +DB->stat, +DB->sync, +DB->upgrade +and +DB->verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_join.html b/db/docs/api_c/db_join.html new file mode 100644 index 000000000..13fe95d84 --- /dev/null +++ b/db/docs/api_c/db_join.html @@ -0,0 +1,151 @@ + + + + + +Berkeley DB: DB->join + + + + + + + +
+

DB->join

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DB->join(DB *primary, + DBC **curslist, DBC **dbcp, u_int32_t flags); +

+

Description

+

The DB->join function creates a specialized cursor for use in performing +joins on secondary indexes. For information on how to organize your data +to use this functionality, see Logical +join. +

The primary argument contains the DB handle of the primary +database, which is keyed by the data values found in entries in the +curslist. +

The curslist argument contains a NULL terminated array of cursors. +Each cursor must have been initialized to reference the key on which the +underlying database should be joined. Typically, this initialization is done +by a DBcursor->c_get call with the DB_SET flag specified. Once the +cursors have been passed as part of a curslist, they should not +be accessed or modified until the newly created join cursor has been closed, +or else inconsistent results may be returned. +

Joined values are retrieved by doing a sequential iteration over the first +cursor in the curslist argument, and a nested iteration over each +secondary cursor in the order they are specified in the curslist +argument. This requires database traversals to search for the current +datum in all the cursors after the first. For this reason, the best join +performance normally results from sorting the cursors from the one that +references the least number of data items to the one that references the +most. By default, DB->join does this sort on behalf of its caller. +

The flags parameter must be set to 0 or the following value: +

+

DB_JOIN_NOSORT
Do not sort the cursors based on the number of data items they reference. +If the data are structured such that cursors with many data items also +share many common elements, higher performance will result from listing +those cursors before cursors with fewer data items, that is, a sort order +other than the default. The DB_JOIN_NOSORT flag permits +applications to perform join optimization prior to calling DB->join. +
+

A newly created cursor is returned in the memory location referenced by +dbcp and has the standard cursor functions: +

+

DBcursor->c_get
Iterates over the values associated with the keys to which each item in +curslist has been initialized. Any data value which appears in +all items specified by the curslist argument is then used as a +key into the primary, and the key/data pair found in the +primary is returned. +

The flags parameter must be set to 0 or the following value: +

+

DB_JOIN_ITEM
Do not use the data value found in all of the cursors as a lookup +key for the primary, but simply return it in the key parameter +instead. The data parameter is left unchanged. +
+

In addition, the following flag may be set by bitwise inclusively OR'ing it into the +flags parameter: +

+

DB_RMW
Acquire write locks instead of read locks when doing the retrieval. +Setting this flag may decrease the likelihood of deadlock during a +read-modify-write cycle by immediately acquiring the write lock during +the read part of the cycle so that another thread of control acquiring +a read lock for the same item, in its own read-modify-write cycle, will +not result in deadlock. +
+

DBcursor->c_put
Returns EINVAL. +

DBcursor->c_del
Returns EINVAL. +

DBcursor->c_close
Close the returned cursor and release all resources. (Closing the cursors +in curslist is the responsibility of the caller.) +
+

For the returned join cursor to be used in a transaction protected manner, +the cursors listed in curslist must have been created within the +context of the same transaction. +

The DB->join function returns a non-zero error value on failure and 0 on success. +

Errors

+

The DB->join function may fail and return a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +

The DBcursor->c_put or DBcursor->c_del functions were called. +

+

The DB->join function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the DB->join function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+db_create, +DB->close, +DB->cursor, +DB->del, +DB->err, +DB->fd, +DB->get, +DB->get_byteswapped, +DB->get_type, +DB->join, +DB->key_range, +DB->open, +DB->put, +DB->remove, +DB->set_bt_compare, +DB->set_bt_minkey, +DB->set_bt_prefix, +DB->set_cachesize, +DB->set_dup_compare, +DB->set_errcall, +DB->set_errfile, +DB->set_errpfx, +DB->set_flags, +DB->set_h_ffactor, +DB->set_h_hash, +DB->set_h_nelem, +DB->set_lorder, +DB->set_malloc, +DB->set_pagesize, +DB->set_paniccall, +DB->set_q_extentsize, +DB->set_realloc, +DB->set_re_delim, +DB->set_re_len, +DB->set_re_pad, +DB->set_re_source, +DB->stat, +DB->sync, +DB->upgrade +and +DB->verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_key_range.html b/db/docs/api_c/db_key_range.html new file mode 100644 index 000000000..1e3c4c91f --- /dev/null +++ b/db/docs/api_c/db_key_range.html @@ -0,0 +1,106 @@ + + + + + +Berkeley DB: DB->key_range + + + + + + + +
+

DB->key_range

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DB->key_range(DB *db, DB_TXN *txnid, + DBT *key, DB_KEY_RANGE *key_range, u_int32_t flags); +

+

Description

+

The DB->key_range function returns an estimate of the proportion of keys +that are less than, equal to and greater than the specified key. The +underlying database must be of type Btree. +

The information is returned in the key_range argument, which +contains three elements of type double, less, equal and +greater. Values are in the range of 0 to 1, e.g., if the field +less is 0.05, that indicates that 5% of the keys in the database +are less than the key argument. The value for equal will be zero +if there is no matching key and non-zero otherwise. +

If the file is being accessed under transaction protection, the +txnid parameter is a transaction ID returned from +txn_begin, otherwise, NULL. +The DB->key_range function does not retain the locks it acquires for the +life of the transaction, so estimates may not be repeatable. +

The flags parameter is currently unused, and must be set to 0. +

The DB->key_range function returns a non-zero error value on failure and 0 on success. +

Errors

+

The DB->key_range function may fail and return a non-zero error for the following conditions: +

+

DB_LOCK_DEADLOCK
The operation was selected to resolve a deadlock. +
+

+

EINVAL
An invalid flag value or parameter was specified. +

The underlying database was not of type Btree. +

+

The DB->key_range function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the DB->key_range function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+db_create, +DB->close, +DB->cursor, +DB->del, +DB->err, +DB->fd, +DB->get, +DB->get_byteswapped, +DB->get_type, +DB->join, +DB->key_range, +DB->open, +DB->put, +DB->remove, +DB->set_bt_compare, +DB->set_bt_minkey, +DB->set_bt_prefix, +DB->set_cachesize, +DB->set_dup_compare, +DB->set_errcall, +DB->set_errfile, +DB->set_errpfx, +DB->set_flags, +DB->set_h_ffactor, +DB->set_h_hash, +DB->set_h_nelem, +DB->set_lorder, +DB->set_malloc, +DB->set_pagesize, +DB->set_paniccall, +DB->set_q_extentsize, +DB->set_realloc, +DB->set_re_delim, +DB->set_re_len, +DB->set_re_pad, +DB->set_re_source, +DB->stat, +DB->sync, +DB->upgrade +and +DB->verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_lsn.html b/db/docs/api_c/db_lsn.html new file mode 100644 index 000000000..1fc62e5e6 --- /dev/null +++ b/db/docs/api_c/db_lsn.html @@ -0,0 +1,36 @@ + + + + + +Berkeley DB: DB_LSN + + + + + + + +
+

DB_LSN

+
+APIRef +
+


+ +

+#include <db.h>
+

+

Description

+

A DB_LSN is a log sequence number, which indicates a +unique position in the log. The DB_LSN structure is completely +opaque, and no application should ever need to look inside. +DB_LSN structures are used by the logging and memory pool +subsystems. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_open.html b/db/docs/api_c/db_open.html new file mode 100644 index 000000000..afd410223 --- /dev/null +++ b/db/docs/api_c/db_open.html @@ -0,0 +1,182 @@ + + + + + +Berkeley DB: DB->open + + + + + + + +
+

DB->open

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DB->open(DB *db, const char *file, + const char *database, DBTYPE type, u_int32_t flags, int mode); +

+

Description

+

The currently supported Berkeley DB file formats (or access methods) +are Btree, Hash, Queue and Recno. The Btree format is a representation +of a sorted, balanced tree structure. The Hash format is an extensible, +dynamic hashing scheme. The Queue format supports fast access to +fixed-length records accessed by sequentially or logical record number. +The Recno format supports fixed- or variable-length records, accessed +sequentially or by logical record number, and optionally retrieved from +a flat text file. +

Storage and retrieval for the Berkeley DB access methods are based on key/data +pairs, see DBT for more information. +

The DB->open interface opens the database represented by the +file and database arguments for both reading and writing. +The file argument is used as the name of a physical file on disk +that will be used to back the database. The database argument is +optional and allows applications to have multiple logical databases in a +single physical file. While no database argument needs to be +specified, it is an error to attempt to open a second database in a +file that was not initially created using a database name. +In-memory databases never intended to be preserved on disk may +be created by setting both the file and database arguments +to NULL. Note that in-memory databases can only ever be shared by +sharing the single database handle that created them, in circumstances +where doing so is safe. +

The type argument is of type DBTYPE +and must be set to one of DB_BTREE, DB_HASH, +DB_QUEUE, DB_RECNO or DB_UNKNOWN, except +that databases of type DB_QUEUE are restricted to one per +file. If type is DB_UNKNOWN, the database must +already exist and DB->open will automatically determine its type. +The DB->get_type function may be used to determine the underlying type of +databases opened using DB_UNKNOWN. +

The flags and mode arguments specify how files will be opened +and/or created if they do not already exist. +

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +

+

DB_CREATE
Create any underlying files, as necessary. If the files do not already +exist and the DB_CREATE flag is not specified, the call will fail. +

DB_EXCL
Return an error if the file already exists. Underlying filesystem +primitives are used to implement this flag. For this reason it is only +applicable to the physical file and cannot be used to test if a database +in a file already exists. +

The DB_EXCL flag is only meaningful when specified with the +DB_CREATE flag. +

DB_NOMMAP
Do not map this database into process memory (see the description of the +DBENV->set_mp_mmapsize function for further information). +

DB_RDONLY
Open the database for reading only. Any attempt to modify items in the +database will fail regardless of the actual permissions of any underlying +files. +

DB_THREAD
Cause the DB handle returned by DB->open to be +free-threaded, that is, useable by multiple threads within a +single address space. +

DB_TRUNCATE
Physically truncate the underlying file, discarding all previous databases +it might have held. Underlying filesystem primitives are used to +implement this flag. For this reason it is only applicable to the +physical file and cannot be used to discard databases within a file. +

The DB_TRUNCATE flag cannot be transaction protected, and it is +an error to specify it in a transaction protected environment. +

+

On UNIX systems, or in IEEE/ANSI Std 1003.1 (POSIX) environments, all files created by the access methods +are created with mode mode (as described in chmod(2)) and +modified by the process' umask value at the time of creation (see +umask(2)). The group ownership of created files is based on +the system and directory defaults, and is not further specified by Berkeley DB. +If mode is 0, files are created readable and writeable by both +owner and group. On Windows systems, the mode argument is ignored. +

Calling DB->open is a reasonably expensive operation, and +maintaining a set of open databases will normally be preferable to +repeatedly open and closing the database for each new query. +

The DB->open function returns a non-zero error value on failure and 0 on success. +

Environment Variables

+

+

DB_HOME
If the dbenv argument to db_create was initialized using +DBENV->open the environment variable DB_HOME may be used +as the path of the database environment home. Specifically, DB->open +is affected by the configuration value DB_DATA_DIR. +
+

+

TMPDIR
If the file and dbenv arguments to DB->open are +NULL, the environment variable TMPDIR may be used as a +directory in which to create a temporary backing file. +
+

Errors

+

The DB->open function may fail and return a non-zero error for the following conditions: +

+

DB_OLD_VERSION
The database cannot be opened without being first upgraded. +

EEXIST
DB_CREATE and DB_EXCL were specified and the file exists. +

EINVAL
An invalid flag value or parameter was specified (e.g., unknown database +type, page size, hash function, pad byte, byte order) or a flag value +or parameter that is incompatible with the specified database. +

+The DB_THREAD flag was specified and spinlocks are not +implemented for this architecture. +

The DB_THREAD flag was specified to DB->open, but was not +specified to the DBENV->open call for the environment in which the +DB handle was created. +

A re_source file was specified with either the DB_THREAD +flag or the provided database environment supports transaction +processing. +

ENOENT
A non-existent re_source file was specified. +
+

The DB->open function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the DB->open function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+db_create, +DB->close, +DB->cursor, +DB->del, +DB->err, +DB->fd, +DB->get, +DB->get_byteswapped, +DB->get_type, +DB->join, +DB->key_range, +DB->open, +DB->put, +DB->remove, +DB->set_bt_compare, +DB->set_bt_minkey, +DB->set_bt_prefix, +DB->set_cachesize, +DB->set_dup_compare, +DB->set_errcall, +DB->set_errfile, +DB->set_errpfx, +DB->set_flags, +DB->set_h_ffactor, +DB->set_h_hash, +DB->set_h_nelem, +DB->set_lorder, +DB->set_malloc, +DB->set_pagesize, +DB->set_paniccall, +DB->set_q_extentsize, +DB->set_realloc, +DB->set_re_delim, +DB->set_re_len, +DB->set_re_pad, +DB->set_re_source, +DB->stat, +DB->sync, +DB->upgrade +and +DB->verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_put.html b/db/docs/api_c/db_put.html new file mode 100644 index 000000000..85c63b7cc --- /dev/null +++ b/db/docs/api_c/db_put.html @@ -0,0 +1,136 @@ + + + + + +Berkeley DB: DB->put + + + + + + + +
+

DB->put

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DB->put(DB *db, + DB_TXN *txnid, DBT *key, DBT *data, u_int32_t flags); +

+

Description

+

The DB->put function stores key/data pairs in the database. The default +behavior of the DB->put function is to enter the new key/data +pair, replacing any previously existing key if duplicates are disallowed, +or adding a duplicate data item if duplicates are allowed. If the database +supports duplicates, the DB->put function adds the new data value at the +end of the duplicate set. If the database supports sorted duplicates, +the new data value is inserted at the correct sorted location. +

If the file is being accessed under transaction protection, the +txnid parameter is a transaction ID returned from +txn_begin, otherwise, NULL. +

The flags parameter must be set to 0 or one of the following +values: +

+

DB_APPEND
Append the key/data pair to the end of the database. For the +DB_APPEND flag to be specified, the underlying database must be +a Queue or Recno database. The record number allocated to the record is +returned in the specified key. +

There is a minor behavioral difference between the Recno and Queue access +methods for the DB_APPEND flag. If a transaction enclosing a +DB->put operation with the DB_APPEND flag aborts, the +record number may be decremented (and later re-allocated by a subsequent +DB_APPEND operation) by the Recno access method, but will not be +decremented or re-allocated by the Queue access method. +

DB_NODUPDATA
In the case of the Btree and Hash access methods, enter the new key/data +pair only if it does not already appear in the database. If the +key/data pair already appears in the database, DB_KEYEXIST is +returned. The DB_NODUPDATA flag may only be specified if the +underlying database has been configured to support sorted duplicates. +

The DB_NODUPDATA flag may not be specified to the Queue or Recno +access methods. +

DB_NOOVERWRITE
Enter the new key/data pair only if the key does not already appear in +the database. If the key already appears in the database, +DB_KEYEXIST is returned. Even if the database allows duplicates, +a call to DB->put with the DB_NOOVERWRITE flag set will +fail if the key already exists in the database. +
+

Otherwise, the DB->put function returns a non-zero error value on failure and 0 on success. +

Errors

+

The DB->put function may fail and return a non-zero error for the following conditions: +

+

DB_LOCK_DEADLOCK
The operation was selected to resolve a deadlock. +
+

+

EACCES
An attempt was made to modify a read-only database. +
+

+

EINVAL
An invalid flag value or parameter was specified. +

A record number of 0 was specified. +

An attempt was made to add a record to a fixed-length database that was too +large to fit. +

An attempt was made to do a partial put. +

+

+

ENOSPC
A btree exceeded the maximum btree depth (255). +
+

The DB->put function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the DB->put function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+db_create, +DB->close, +DB->cursor, +DB->del, +DB->err, +DB->fd, +DB->get, +DB->get_byteswapped, +DB->get_type, +DB->join, +DB->key_range, +DB->open, +DB->put, +DB->remove, +DB->set_bt_compare, +DB->set_bt_minkey, +DB->set_bt_prefix, +DB->set_cachesize, +DB->set_dup_compare, +DB->set_errcall, +DB->set_errfile, +DB->set_errpfx, +DB->set_flags, +DB->set_h_ffactor, +DB->set_h_hash, +DB->set_h_nelem, +DB->set_lorder, +DB->set_malloc, +DB->set_pagesize, +DB->set_paniccall, +DB->set_q_extentsize, +DB->set_realloc, +DB->set_re_delim, +DB->set_re_len, +DB->set_re_pad, +DB->set_re_source, +DB->stat, +DB->sync, +DB->upgrade +and +DB->verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_remove.html b/db/docs/api_c/db_remove.html new file mode 100644 index 000000000..e8dae8645 --- /dev/null +++ b/db/docs/api_c/db_remove.html @@ -0,0 +1,108 @@ + + + + + +Berkeley DB: DB->remove + + + + + + + +
+

DB->remove

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DB->remove(DB *db, + const char *file, const char *database, u_int32_t flags); +

+

Description

+

The DB->remove interface removes the database specified by the +file and database arguments. If no database is +specified, the physical file represented by file is removed, +incidentally removing all databases that it contained. +

If a physical file is being removed and logging is currently enabled in +the database environment, no database in the file may be open when the +DB->remove function is called. Otherwise, no reference count of database +use is maintained by Berkeley DB. Applications should not remove databases that +are currently in use. In particular, some architectures do not permit +the removal of files with open handles. On these architectures, attempts +to remove databases that are currently in use will fail. +

The flags parameter is currently unused, and must be set to 0. +

Once DB->remove has been called, regardless of its return, the +DB handle may not be accessed again. +

The DB->remove function returns a non-zero error value on failure and 0 on success. +

Environment Variables

+

+

DB_HOME
If the dbenv argument to db_create was initialized using +DBENV->open the environment variable DB_HOME may be used +as the path of the database environment home. Specifically, DB->remove +is affected by the configuration value DB_DATA_DIR. +
+

Errors

+

The DB->remove function may fail and return a non-zero error for the following conditions: +

+

EINVAL
A database in the file is currently open. +
+

The DB->remove function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the DB->remove function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+db_create, +DB->close, +DB->cursor, +DB->del, +DB->err, +DB->fd, +DB->get, +DB->get_byteswapped, +DB->get_type, +DB->join, +DB->key_range, +DB->open, +DB->put, +DB->remove, +DB->set_bt_compare, +DB->set_bt_minkey, +DB->set_bt_prefix, +DB->set_cachesize, +DB->set_dup_compare, +DB->set_errcall, +DB->set_errfile, +DB->set_errpfx, +DB->set_flags, +DB->set_h_ffactor, +DB->set_h_hash, +DB->set_h_nelem, +DB->set_lorder, +DB->set_malloc, +DB->set_pagesize, +DB->set_paniccall, +DB->set_q_extentsize, +DB->set_realloc, +DB->set_re_delim, +DB->set_re_len, +DB->set_re_pad, +DB->set_re_source, +DB->stat, +DB->sync, +DB->upgrade +and +DB->verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_rename.html b/db/docs/api_c/db_rename.html new file mode 100644 index 000000000..ff90836c6 --- /dev/null +++ b/db/docs/api_c/db_rename.html @@ -0,0 +1,109 @@ + + + + + +Berkeley DB: DB->rename + + + + + + + +
+

DB->rename

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DB->rename(DB *db, const char *file, + const char *database, const char *newname, u_int32_t flags); +

+

Description

+

The DB->rename interface renames the database specified by the +file and database arguments to newname. If no +database is specified, the physical file represented by +file is renamed, incidentally renaming all databases that it +contained. +

If a physical file is being renamed and logging is currently enabled in +the database environment, no database in the file may be open when the +DB->rename function is called. Otherwise, no reference count of database +use is maintained by Berkeley DB. Applications should not rename databases that +are currently in use. In particular, some architectures do not permit +renaming files with open handles. On these architectures, attempts to +rename databases that are currently in use will fail. +

The flags parameter is currently unused, and must be set to 0. +

Once DB->rename has been called, regardless of its return, the +DB handle may not be accessed again. +

The DB->rename function returns a non-zero error value on failure and 0 on success. +

Environment Variables

+

+

DB_HOME
If the dbenv argument to db_create was initialized using +DBENV->open the environment variable DB_HOME may be used +as the path of the database environment home. Specifically, DB->rename +is affected by the configuration value DB_DATA_DIR. +
+

Errors

+

The DB->rename function may fail and return a non-zero error for the following conditions: +

+

EINVAL
A database in the file is currently open. +
+

The DB->rename function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the DB->rename function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+db_create, +DB->close, +DB->cursor, +DB->del, +DB->err, +DB->fd, +DB->get, +DB->get_byteswapped, +DB->get_type, +DB->join, +DB->key_range, +DB->open, +DB->put, +DB->remove, +DB->set_bt_compare, +DB->set_bt_minkey, +DB->set_bt_prefix, +DB->set_cachesize, +DB->set_dup_compare, +DB->set_errcall, +DB->set_errfile, +DB->set_errpfx, +DB->set_flags, +DB->set_h_ffactor, +DB->set_h_hash, +DB->set_h_nelem, +DB->set_lorder, +DB->set_malloc, +DB->set_pagesize, +DB->set_paniccall, +DB->set_q_extentsize, +DB->set_realloc, +DB->set_re_delim, +DB->set_re_len, +DB->set_re_pad, +DB->set_re_source, +DB->stat, +DB->sync, +DB->upgrade +and +DB->verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_set_append_recno.html b/db/docs/api_c/db_set_append_recno.html new file mode 100644 index 000000000..4b90190ff --- /dev/null +++ b/db/docs/api_c/db_set_append_recno.html @@ -0,0 +1,66 @@ + + + + + +Berkeley DB: DB->set_append_recno + + + + + + + +
+

DB->set_append_recno

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DB->set_append_recno(DB *, + int (*db_append_recno_fcn)(DB *dbp, DBT *data, db_recno_t recno)); +

+

Description

+

When using the DB_APPEND option of the DB->put method, +it may be useful to modify the stored data based on the generated key. +If a callback function is specified using the +DB->set_append_recno function, it will be called after the record number +has been selected but before the data has been stored. +The callback function must return 0 on success and errno or +a value outside of the Berkeley DB error name space on failure. +

The called function must take three arguments: a reference to the +enclosing database handle, the data DBT to be stored and the +selected record number. The called function may then modify the data +DBT. +

The DB->set_append_recno interface may only be used to configure Berkeley DB before +the DB->open interface is called. +

The DB->set_append_recno function returns a non-zero error value on failure and 0 on success. +

See Also

+DBENV->close, +db_env_create, +DBENV->open, +DBENV->remove, +DBENV->err, +db_strerror, +db_version, +DBENV->set_cachesize, +DBENV->set_errcall, +DBENV->set_errfile, +DBENV->set_errpfx, +DBENV->set_flags, +DBENV->set_mutexlocks, +DBENV->set_paniccall, +and +DBENV->set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_set_bt_compare.html b/db/docs/api_c/db_set_bt_compare.html new file mode 100644 index 000000000..bf38ee51d --- /dev/null +++ b/db/docs/api_c/db_set_bt_compare.html @@ -0,0 +1,105 @@ + + + + + +Berkeley DB: DB->set_bt_compare + + + + + + + +
+

DB->set_bt_compare

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DB->set_bt_compare(DB *db, + int (*bt_compare_fcn)(DB *, const DBT *, const DBT *)); +

+

Description

+

Set the Btree key comparison function. The comparison function is +called when it is necessary to compare a key specified by the +application with a key currently stored in the tree. The first argument +to the comparison function is the DBT representing the +application supplied key, the second is the current tree's key. +

The comparison function must return an integer value less than, equal +to, or greater than zero if the first key argument is considered to be +respectively less than, equal to, or greater than the second key +argument. In addition, the comparison function must cause the keys in +the database to be well-ordered. The comparison function +must correctly handle any key values used by the application (possibly +including zero-length keys). In addition, when Btree key prefix +comparison is being performed (see DB->set_bt_prefix for more +information), the comparison routine may be passed a prefix of any +database key. The data and size fields of the +DBT are the only fields that may be used for the purposes of +this comparison. +

If no comparison function is specified, the keys are compared lexically, +with shorter keys collating before longer keys. The same comparison +method must be used each time a particular Btree is opened. +

The DB->set_bt_compare interface may only be used to configure Berkeley DB before +the DB->open interface is called. +

The DB->set_bt_compare function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DB->open was called. +

+

See Also

+db_create, +DB->close, +DB->cursor, +DB->del, +DB->err, +DB->fd, +DB->get, +DB->get_byteswapped, +DB->get_type, +DB->join, +DB->key_range, +DB->open, +DB->put, +DB->remove, +DB->set_bt_compare, +DB->set_bt_minkey, +DB->set_bt_prefix, +DB->set_cachesize, +DB->set_dup_compare, +DB->set_errcall, +DB->set_errfile, +DB->set_errpfx, +DB->set_flags, +DB->set_h_ffactor, +DB->set_h_hash, +DB->set_h_nelem, +DB->set_lorder, +DB->set_malloc, +DB->set_pagesize, +DB->set_paniccall, +DB->set_q_extentsize, +DB->set_realloc, +DB->set_re_delim, +DB->set_re_len, +DB->set_re_pad, +DB->set_re_source, +DB->stat, +DB->sync, +DB->upgrade +and +DB->verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_set_bt_minkey.html b/db/docs/api_c/db_set_bt_minkey.html new file mode 100644 index 000000000..c36f3637b --- /dev/null +++ b/db/docs/api_c/db_set_bt_minkey.html @@ -0,0 +1,92 @@ + + + + + +Berkeley DB: DB->set_bt_minkey + + + + + + + +
+

DB->set_bt_minkey

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DB->set_bt_minkey(DB *db, u_int32_t bt_minkey); +

+

Description

+

Set the minimum number of keys that will be stored on any single +Btree page. +

This value is used to determine which keys will be stored on overflow +pages, i.e. if a key or data item is larger than the underlying database +page size divided by the bt_minkey value, it will be stored on +overflow pages instead of within the page itself. The bt_minkey +value specified must be at least 2; if bt_minkey is not explicitly +set, a value of 2 is used. +

The DB->set_bt_minkey interface may only be used to configure Berkeley DB before +the DB->open interface is called. +

The DB->set_bt_minkey function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DB->open was called. +

+

See Also

+db_create, +DB->close, +DB->cursor, +DB->del, +DB->err, +DB->fd, +DB->get, +DB->get_byteswapped, +DB->get_type, +DB->join, +DB->key_range, +DB->open, +DB->put, +DB->remove, +DB->set_bt_compare, +DB->set_bt_minkey, +DB->set_bt_prefix, +DB->set_cachesize, +DB->set_dup_compare, +DB->set_errcall, +DB->set_errfile, +DB->set_errpfx, +DB->set_flags, +DB->set_h_ffactor, +DB->set_h_hash, +DB->set_h_nelem, +DB->set_lorder, +DB->set_malloc, +DB->set_pagesize, +DB->set_paniccall, +DB->set_q_extentsize, +DB->set_realloc, +DB->set_re_delim, +DB->set_re_len, +DB->set_re_pad, +DB->set_re_source, +DB->stat, +DB->sync, +DB->upgrade +and +DB->verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_set_bt_prefix.html b/db/docs/api_c/db_set_bt_prefix.html new file mode 100644 index 000000000..88bf3157f --- /dev/null +++ b/db/docs/api_c/db_set_bt_prefix.html @@ -0,0 +1,106 @@ + + + + + +Berkeley DB: DB->set_bt_prefix + + + + + + + +
+

DB->set_bt_prefix

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DB->set_bt_prefix(DB *db, + size_t (*bt_prefix_fcn)(DB *, const DBT *, const DBT *)); +

+

Description

+

Set the Btree prefix function. The prefix function must return the +number of bytes of the second key argument that would be required by +the Btree key comparison function to determine the second key argument's +ordering relationship with respect to the first key argument. If the +two keys are equal, the key length should be returned. The prefix +function must correctly handle any key values used by the application +(possibly including zero-length keys). The data and +size fields of the DBT are the only fields that may be +used for the purposes of this determination. +

The prefix function is used to determine the amount by which keys stored +on the Btree internal pages can be safely truncated without losing their +uniqueness. See the Btree +prefix comparison section of the Reference Guide for more details about +how this works. The usefulness of this is data dependent, but in some +data sets can produce significantly reduced tree sizes and search times. +

If no prefix function or key comparison function is specified by the +application, a default lexical comparison function is used as the prefix +function. If no prefix function is specified and a key comparison +function is specified, no prefix function is used. It is an error to +specify a prefix function without also specifying a key comparison +function. +

The DB->set_bt_prefix interface may only be used to configure Berkeley DB before +the DB->open interface is called. +

The DB->set_bt_prefix function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DB->open was called. +

+

See Also

+db_create, +DB->close, +DB->cursor, +DB->del, +DB->err, +DB->fd, +DB->get, +DB->get_byteswapped, +DB->get_type, +DB->join, +DB->key_range, +DB->open, +DB->put, +DB->remove, +DB->set_bt_compare, +DB->set_bt_minkey, +DB->set_bt_prefix, +DB->set_cachesize, +DB->set_dup_compare, +DB->set_errcall, +DB->set_errfile, +DB->set_errpfx, +DB->set_flags, +DB->set_h_ffactor, +DB->set_h_hash, +DB->set_h_nelem, +DB->set_lorder, +DB->set_malloc, +DB->set_pagesize, +DB->set_paniccall, +DB->set_q_extentsize, +DB->set_realloc, +DB->set_re_delim, +DB->set_re_len, +DB->set_re_pad, +DB->set_re_source, +DB->stat, +DB->sync, +DB->upgrade +and +DB->verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_set_cachesize.html b/db/docs/api_c/db_set_cachesize.html new file mode 100644 index 000000000..fd7176cbf --- /dev/null +++ b/db/docs/api_c/db_set_cachesize.html @@ -0,0 +1,107 @@ + + + + + + +Berkeley DB: DB->set_cachesize + + + + + + + +
+

DB->set_cachesize

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DB->set_cachesize(DB *db, + u_int32_t gbytes, u_int32_t bytes, int ncache); +

+

Description

+

Set the size of the database's shared memory buffer pool, i.e., the cache, +to gbytes gigabytes plus bytes. The cache should be the +size of the normal working data set of the application, with some small +amount of additional memory for unusual situations. (Note, the working +set is not the same as the number of simultaneously referenced pages, and +should be quite a bit larger!) +

The default cache size is 256KB, and may not be specified as less than +20KB. Any cache size less than 500MB is automatically increased by 25% +to account for buffer pool overhead, cache sizes larger than 500MB are +used as specified. For information on tuning the Berkeley DB cache size, see +Selecting a cache size. +

It is possible to specify caches to Berkeley DB that are large enough so that +they cannot be allocated contiguously on some architectures, e.g., some +releases of Solaris limit the amount of memory that may be allocated +contiguously by a process. If ncache is 0 or 1, the cache will +be allocated contiguously in memory. If it is greater than 1, the cache +will be broken up into ncache equally sized separate pieces of +memory. +

As databases opened within Berkeley DB environments use the cache specified to +the environment, it is an error to attempt to set a cache in a database +created within an environment. +

The DB->set_cachesize interface may only be used to configure Berkeley DB before +the DB->open interface is called. +

The DB->set_cachesize function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

The specified cache size was impossibly small. +

+

See Also

+db_create, +DB->close, +DB->cursor, +DB->del, +DB->err, +DB->fd, +DB->get, +DB->get_byteswapped, +DB->get_type, +DB->join, +DB->key_range, +DB->open, +DB->put, +DB->remove, +DB->set_bt_compare, +DB->set_bt_minkey, +DB->set_bt_prefix, +DB->set_cachesize, +DB->set_dup_compare, +DB->set_errcall, +DB->set_errfile, +DB->set_errpfx, +DB->set_flags, +DB->set_h_ffactor, +DB->set_h_hash, +DB->set_h_nelem, +DB->set_lorder, +DB->set_malloc, +DB->set_pagesize, +DB->set_paniccall, +DB->set_q_extentsize, +DB->set_realloc, +DB->set_re_delim, +DB->set_re_len, +DB->set_re_pad, +DB->set_re_source, +DB->stat, +DB->sync, +DB->upgrade +and +DB->verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_set_dup_compare.html b/db/docs/api_c/db_set_dup_compare.html new file mode 100644 index 000000000..2ac6ed9de --- /dev/null +++ b/db/docs/api_c/db_set_dup_compare.html @@ -0,0 +1,102 @@ + + + + + +Berkeley DB: DB->set_dup_compare + + + + + + + +
+

DB->set_dup_compare

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DB->set_dup_compare(DB *db, + int (*dup_compare_fcn)(DB *, const DBT *, const DBT *)); +

+

Description

+

Set the duplicate data item comparison function. The comparison function +is called when it is necessary to compare a data item specified by the +application with a data item currently stored in the tree. The first +argument to the comparison function is the DBT representing the +application's data item, the second is the current tree's data item. +

The comparison function must return an integer value less than, equal +to, or greater than zero if the first data item argument is considered +to be respectively less than, equal to, or greater than the second data +item argument. In addition, the comparison function must cause the data +items in the set to be well-ordered. The comparison function +must correctly handle any data item values used by the application +(possibly including zero-length data items). The data and +size fields of the DBT are the only fields that may be +used for the purposes of this comparison. +

If no comparison function is specified, the data items are compared +lexically, with shorter data items collating before longer data items. +The same duplicate data item comparison method must be used each time +a particular Btree is opened. +

The DB->set_dup_compare interface may only be used to configure Berkeley DB before +the DB->open interface is called. +

The DB->set_dup_compare function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

See Also

+db_create, +DB->close, +DB->cursor, +DB->del, +DB->err, +DB->fd, +DB->get, +DB->get_byteswapped, +DB->get_type, +DB->join, +DB->key_range, +DB->open, +DB->put, +DB->remove, +DB->set_bt_compare, +DB->set_bt_minkey, +DB->set_bt_prefix, +DB->set_cachesize, +DB->set_dup_compare, +DB->set_errcall, +DB->set_errfile, +DB->set_errpfx, +DB->set_flags, +DB->set_h_ffactor, +DB->set_h_hash, +DB->set_h_nelem, +DB->set_lorder, +DB->set_malloc, +DB->set_pagesize, +DB->set_paniccall, +DB->set_q_extentsize, +DB->set_realloc, +DB->set_re_delim, +DB->set_re_len, +DB->set_re_pad, +DB->set_re_source, +DB->stat, +DB->sync, +DB->upgrade +and +DB->verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_set_errcall.html b/db/docs/api_c/db_set_errcall.html new file mode 100644 index 000000000..97d8d9a3a --- /dev/null +++ b/db/docs/api_c/db_set_errcall.html @@ -0,0 +1,76 @@ + + + + + + +Berkeley DB: DB->set_errcall + + + + + + + +
+

DB->set_errcall

+
+APIRef +
+


+ +

+#include <db.h>
+

+void +DB->set_errcall(DB *, + void (*db_errcall_fcn)(const char *errpfx, char *msg)); +

+

Description

+When an error occurs in the Berkeley DB library, a Berkeley DB error or an error +return value is returned by the function. In some cases, however, +the errno value may be insufficient to completely describe +the cause of the error especially during initial application debugging. +

The DB->set_errcall function is used to enhance the mechanism for reporting error +messages to the application. In some cases, when an error occurs, Berkeley DB +will call db_errcall_fcn with additional error information. The +function must be declared with two arguments; the first will be the prefix +string (as previously set by DB->set_errpfx or +DBENV->set_errpfx), the second will be the error message string. +It is up to the db_errcall_fcn function to display the error +message in an appropriate manner. +

Alternatively, you can use the DB->set_errfile or +DBENV->set_errfile functions to display the additional information +via a C library FILE *. +

This error logging enhancement does not slow performance or significantly +increase application size, and may be run during normal operation as well +as during application debugging. +

For DB handles opened inside of Berkeley DB environments, calling the +DB->set_errcall function affects the entire environment and is equivalent to calling +the DBENV->set_errcall function. +

The DB->set_errcall interface may be used to configure Berkeley DB at any time +during the life of the application. +

See Also

+DBENV->close, +db_env_create, +DBENV->open, +DBENV->remove, +DBENV->err, +db_strerror, +db_version, +DBENV->set_cachesize, +DBENV->set_errcall, +DBENV->set_errfile, +DBENV->set_errpfx, +DBENV->set_flags, +DBENV->set_mutexlocks, +DBENV->set_paniccall, +and +DBENV->set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_set_errfile.html b/db/docs/api_c/db_set_errfile.html new file mode 100644 index 000000000..5d160ed5c --- /dev/null +++ b/db/docs/api_c/db_set_errfile.html @@ -0,0 +1,73 @@ + + + + + + +Berkeley DB: DB->set_errfile + + + + + + + +
+

DB->set_errfile

+
+APIRef +
+


+ +

+#include <db.h>
+

+void +DB->set_errfile(DB *db, FILE *errfile); +

+

Description

+When an error occurs in the Berkeley DB library, a Berkeley DB error or an error +return value is returned by the function. In some cases, however, +the errno value may be insufficient to completely describe +the cause of the error especially during initial application debugging. +

The DB->set_errfile function is used to enhance the mechanism for reporting error +messages to the application by setting a C library FILE * to be used for +displaying additional Berkeley DB error messages. In some cases, when an error +occurs, Berkeley DB will output an additional error message to the specified +file reference. +

The error message will consist of the prefix string and a colon +(":") (if a prefix string was previously specified using +DB->set_errpfx or DBENV->set_errpfx), an error string, and +a trailing <newline> character. +

This error logging enhancement does not slow performance or significantly +increase application size, and may be run during normal operation as well +as during application debugging. +

For DB handles opened inside of Berkeley DB environments, calling the +DB->set_errfile function affects the entire environment and is equivalent to calling +the DBENV->set_errfile function. +

The DB->set_errfile interface may be used to configure Berkeley DB at any time +during the life of the application. +

See Also

+DBENV->close, +db_env_create, +DBENV->open, +DBENV->remove, +DBENV->err, +db_strerror, +db_version, +DBENV->set_cachesize, +DBENV->set_errcall, +DBENV->set_errfile, +DBENV->set_errpfx, +DBENV->set_flags, +DBENV->set_mutexlocks, +DBENV->set_paniccall, +and +DBENV->set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_set_errpfx.html b/db/docs/api_c/db_set_errpfx.html new file mode 100644 index 000000000..baf8f61fe --- /dev/null +++ b/db/docs/api_c/db_set_errpfx.html @@ -0,0 +1,62 @@ + + + + + +Berkeley DB: DB->set_errpfx + + + + + + + +
+

DB->set_errpfx

+
+APIRef +
+


+ +

+#include <db.h>
+

+void +DB->set_errpfx(DB *db, const char *errpfx); +

+

Description

+

Set the prefix string that appears before error messages issued by Berkeley DB. +

The DB->set_errpfx function does not copy the memory referenced by the +errpfx argument, rather, it maintains a reference to it. This +allows applications to modify the error message prefix at any time, +without repeatedly calling DB->set_errpfx, but means that the +memory must be maintained until the handle is closed. +

For DB handles opened inside of Berkeley DB environments, calling the +DB->set_errpfx function affects the entire environment and is equivalent to calling +the DBENV->set_errpfx function. +

The DB->set_errpfx interface may be used to configure Berkeley DB at any time +during the life of the application. +

See Also

+DBENV->close, +db_env_create, +DBENV->open, +DBENV->remove, +DBENV->err, +db_strerror, +db_version, +DBENV->set_cachesize, +DBENV->set_errcall, +DBENV->set_errfile, +DBENV->set_errpfx, +DBENV->set_flags, +DBENV->set_mutexlocks, +DBENV->set_paniccall, +and +DBENV->set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_set_feedback.html b/db/docs/api_c/db_set_feedback.html new file mode 100644 index 000000000..213060ee7 --- /dev/null +++ b/db/docs/api_c/db_set_feedback.html @@ -0,0 +1,95 @@ + + + + + +Berkeley DB: DB->set_feedback + + + + + + + +
+

DB->set_feedback

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DB->set_feedback(DB *, + void (*db_feedback_fcn)(DB *dbp, int opcode, int pct)); +

+

Description

+

Some operations performed by the Berkeley DB library can take non-trivial +amounts of time. The DB->set_feedback function can be used by +applications to monitor progress within these operations. +

When an operation is likely to take a long time, Berkeley DB will call the +specified callback function. This function must be declared with +three arguments: the first will be a reference to the enclosing database +handle, the second a flag value, and the third the percent of the +operation that has been completed, specified as an integer value between +0 and 100. It is up to the callback function to display this +information in an appropriate manner. +

The opcode argument may take on any of the following values: +

+

DB_UPGRADE
The underlying database is being upgraded. +

DB_VERIFY
The underlying database is being verified. +
+

The DB->set_feedback interface may be used to configure Berkeley DB at any time +during the life of the application. +

The DB->set_feedback function returns a non-zero error value on failure and 0 on success. +

See Also

+db_create, +DB->close, +DB->cursor, +DB->del, +DB->err, +DB->fd, +DB->get, +DB->get_byteswapped, +DB->get_type, +DB->join, +DB->key_range, +DB->open, +DB->put, +DB->remove, +DB->set_bt_compare, +DB->set_bt_minkey, +DB->set_bt_prefix, +DB->set_cachesize, +DB->set_dup_compare, +DB->set_errcall, +DB->set_errfile, +DB->set_errpfx, +DB->set_flags, +DB->set_h_ffactor, +DB->set_h_hash, +DB->set_h_nelem, +DB->set_lorder, +DB->set_malloc, +DB->set_pagesize, +DB->set_paniccall, +DB->set_q_extentsize, +DB->set_realloc, +DB->set_re_delim, +DB->set_re_len, +DB->set_re_pad, +DB->set_re_source, +DB->stat, +DB->sync, +DB->upgrade +and +DB->verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_set_flags.html b/db/docs/api_c/db_set_flags.html new file mode 100644 index 000000000..f18233817 --- /dev/null +++ b/db/docs/api_c/db_set_flags.html @@ -0,0 +1,181 @@ + + + + + +Berkeley DB: DB->set_flags + + + + + + + +
+

DB->set_flags

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DB->set_flags(DB *db, u_int32_t flags); +

+

Description

+

Calling DB->set_flags is additive, there is no way to clear flags. +

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +

Btree

+

The following flags may be specified for the Btree access method: +

+

DB_DUP
Permit duplicate data items in the tree, i.e. insertion when the key of +the key/data pair being inserted already exists in the tree will be +successful. The ordering of duplicates in the tree is determined by the +order of insertion, unless the ordering is otherwise specified by use of +a cursor operation. It is an error to specify both DB_DUP and +DB_RECNUM. +

DB_DUPSORT
Permit duplicate data items in the tree, i.e. insertion when the key of +the key/data pair being inserted already exists in the tree will be +successful. The ordering of duplicates in the tree is determined by the +duplicate comparison function. +If the application does not specify a comparison function using the +DB->set_dup_compare function, a default, lexical comparison will be +used. +It is an error to specify both DB_DUPSORT and DB_RECNUM. +

DB_RECNUM
Support retrieval from the Btree using record numbers. For more +information, see the DB_GET_RECNO flag to the DB->get and +DBcursor->c_get methods. +

Logical record numbers in Btree databases are mutable in the face of +record insertion or deletion. See the DB_RENUMBER flag in the Recno +access method information for further discussion. +

Maintaining record counts within a Btree introduces a serious point of +contention, namely the page locations where the record counts are stored. +In addition, the entire tree must be locked during both insertions and +deletions, effectively single-threading the tree for those operations. +Specifying DB_RECNUM can result in serious performance degradation for +some applications and data sets. +

It is an error to specify both DB_DUP and DB_RECNUM. +

DB_REVSPLITOFF
Turn off reverse splitting in the Btree. As pages are emptied in a +database, the Berkeley DB Btree implementation attempts to coalesce empty pages +into higher-level pages in order to keep the tree as small as possible +and minimize tree search time. This can hurt performance in applications +with cyclical data demands, that is, applications where the database grows +and shrinks repeatedly. For example, because Berkeley DB does page-level +locking, the maximum level of concurrency in a database of 2 pages is far +smaller than that in a database of 100 pages, and so a database that has +shrunk to a minimal size can cause severe deadlocking when a new cycle of +data insertion begins. +
+

Hash

+

The following flags may be specified for the Hash access method: +

+

DB_DUP
Permit duplicate data items in the tree, i.e. insertion when the key of +the key/data pair being inserted already exists in the tree will be +successful. The ordering of duplicates in the tree is determined by the +order of insertion, unless the ordering is otherwise specified by use of +a cursor operation. It is an error to specify both DB_DUP and +DB_RECNUM. +

DB_DUPSORT
Permit duplicate data items in the tree, i.e. insertion when the key of +the key/data pair being inserted already exists in the tree will be +successful. The ordering of duplicates in the tree is determined by the +duplicate comparison function. +If the application does not specify a comparison function using the +DB->set_dup_compare function, a default, lexical comparison will be +used. +It is an error to specify both DB_DUPSORT and DB_RECNUM. +
+

Queue

+

There are no additional flags that may be specified for the Queue access +method. +

Recno

+

The following flags may be specified for the Recno access method: +

+

DB_RENUMBER
Specifying the DB_RENUMBER flag causes the logical record numbers to be +mutable, and change as records are added to and deleted from the database. +For example, the deletion of record number 4 causes records numbered 5 +and greater to be renumbered downward by 1. If a cursor was positioned +to record number 4 before the deletion, it will reference the new record +number 4, if any such record exists, after the deletion. If a cursor was +positioned after record number 4 before the deletion, it will be shifted +downward 1 logical record, continuing to reference the same record as it +did before. +

Using the DB->put or DBcursor->c_put interfaces to create new +records will cause the creation of multiple records if the record number +is more than one greater than the largest record currently in the +database. For example, creating record 28, when record 25 was previously +the last record in the database, will create records 26 and 27 as well as +28. Attempts to retrieve records that were created in this manner will +result in an error return of DB_KEYEMPTY. +

If a created record is not at the end of the database, all records +following the new record will be automatically renumbered upward by 1. +For example, the creation of a new record numbered 8 causes records +numbered 8 and greater to be renumbered upward by 1. If a cursor was +positioned to record number 8 or greater before the insertion, it will be +shifted upward 1 logical record, continuing to reference the same record +as it did before. +

For these reasons, concurrent access to a Recno database with the +DB_RENUMBER flag specified may be largely meaningless, although +it is supported. +

DB_SNAPSHOT
This flag specifies that any specified re_source file be read in +its entirety when DB->open is called. If this flag is not +specified, the re_source file may be read lazily. +
+

The DB->set_flags interface may only be used to configure Berkeley DB before +the DB->open interface is called. +

The DB->set_flags function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

See Also

+db_create, +DB->close, +DB->cursor, +DB->del, +DB->err, +DB->fd, +DB->get, +DB->get_byteswapped, +DB->get_type, +DB->join, +DB->key_range, +DB->open, +DB->put, +DB->remove, +DB->set_bt_compare, +DB->set_bt_minkey, +DB->set_bt_prefix, +DB->set_cachesize, +DB->set_dup_compare, +DB->set_errcall, +DB->set_errfile, +DB->set_errpfx, +DB->set_flags, +DB->set_h_ffactor, +DB->set_h_hash, +DB->set_h_nelem, +DB->set_lorder, +DB->set_malloc, +DB->set_pagesize, +DB->set_paniccall, +DB->set_q_extentsize, +DB->set_realloc, +DB->set_re_delim, +DB->set_re_len, +DB->set_re_pad, +DB->set_re_source, +DB->stat, +DB->sync, +DB->upgrade +and +DB->verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_set_h_ffactor.html b/db/docs/api_c/db_set_h_ffactor.html new file mode 100644 index 000000000..c3bbb607e --- /dev/null +++ b/db/docs/api_c/db_set_h_ffactor.html @@ -0,0 +1,93 @@ + + + + + +Berkeley DB: DB->set_h_ffactor + + + + + + + +
+

DB->set_h_ffactor

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DB->set_h_ffactor(DB *db, u_int32_t h_ffactor); +

+

Description

+

Set the desired density within the hash table. +

The density is an approximation of the number of keys allowed to +accumulate in any one bucket, determining when the hash table grows or +shrinks. If you know the average sizes of the keys and data in your +dataset, setting the fill factor can enhance performance. A reasonable +rule computing fill factor is to set it to: +

(pagesize - 32) / (average_key_size + average_data_size + 8)
+

If no value is specified, the fill factor will be selected dynamically as +pages are filled. +

The DB->set_h_ffactor interface may only be used to configure Berkeley DB before +the DB->open interface is called. +

The DB->set_h_ffactor function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DB->open was called. +

+

See Also

+db_create, +DB->close, +DB->cursor, +DB->del, +DB->err, +DB->fd, +DB->get, +DB->get_byteswapped, +DB->get_type, +DB->join, +DB->key_range, +DB->open, +DB->put, +DB->remove, +DB->set_bt_compare, +DB->set_bt_minkey, +DB->set_bt_prefix, +DB->set_cachesize, +DB->set_dup_compare, +DB->set_errcall, +DB->set_errfile, +DB->set_errpfx, +DB->set_flags, +DB->set_h_ffactor, +DB->set_h_hash, +DB->set_h_nelem, +DB->set_lorder, +DB->set_malloc, +DB->set_pagesize, +DB->set_paniccall, +DB->set_q_extentsize, +DB->set_realloc, +DB->set_re_delim, +DB->set_re_len, +DB->set_re_pad, +DB->set_re_source, +DB->stat, +DB->sync, +DB->upgrade +and +DB->verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_set_h_hash.html b/db/docs/api_c/db_set_h_hash.html new file mode 100644 index 000000000..cae03fa72 --- /dev/null +++ b/db/docs/api_c/db_set_h_hash.html @@ -0,0 +1,97 @@ + + + + + +Berkeley DB: DB->set_h_hash + + + + + + + +
+

DB->set_h_hash

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DB->set_h_hash(DB *db, + u_int32_t (*h_hash_fcn)(DB *, const void *bytes, u_int32_t length)); +

+

Description

+

Set a user defined hash method; if no hash method is specified, a default +hash method is used. Since no hash method performs equally well on all +possible data, the user may find that the built-in hash method performs +poorly with a particular data set. User specified hash functions must +take a pointer to a byte string and a length as arguments and return a +value of type +u_int32_t. +The hash function must handle any key values used by the application +(possibly including zero-length keys). +

If a hash method is specified, DB->open will attempt to determine +if the hash method specified is the same as the one with which the database +was created, and will fail if it detects that it is not. +

The DB->set_h_hash interface may only be used to configure Berkeley DB before +the DB->open interface is called. +

The DB->set_h_hash function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DB->open was called. +

+

See Also

+db_create, +DB->close, +DB->cursor, +DB->del, +DB->err, +DB->fd, +DB->get, +DB->get_byteswapped, +DB->get_type, +DB->join, +DB->key_range, +DB->open, +DB->put, +DB->remove, +DB->set_bt_compare, +DB->set_bt_minkey, +DB->set_bt_prefix, +DB->set_cachesize, +DB->set_dup_compare, +DB->set_errcall, +DB->set_errfile, +DB->set_errpfx, +DB->set_flags, +DB->set_h_ffactor, +DB->set_h_hash, +DB->set_h_nelem, +DB->set_lorder, +DB->set_malloc, +DB->set_pagesize, +DB->set_paniccall, +DB->set_q_extentsize, +DB->set_realloc, +DB->set_re_delim, +DB->set_re_len, +DB->set_re_pad, +DB->set_re_source, +DB->stat, +DB->sync, +DB->upgrade +and +DB->verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_set_h_nelem.html b/db/docs/api_c/db_set_h_nelem.html new file mode 100644 index 000000000..d052afff7 --- /dev/null +++ b/db/docs/api_c/db_set_h_nelem.html @@ -0,0 +1,88 @@ + + + + + +Berkeley DB: DB->set_h_nelem + + + + + + + +
+

DB->set_h_nelem

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DB->set_h_nelem(DB *db, u_int32_t h_nelem); +

+

Description

+

Set an estimate of the final size of the hash table. +

If not set or set too low, hash tables will still expand gracefully +as keys are entered, although a slight performance degradation may be +noticed. +

The DB->set_h_nelem interface may only be used to configure Berkeley DB before +the DB->open interface is called. +

The DB->set_h_nelem function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DB->open was called. +

+

See Also

+db_create, +DB->close, +DB->cursor, +DB->del, +DB->err, +DB->fd, +DB->get, +DB->get_byteswapped, +DB->get_type, +DB->join, +DB->key_range, +DB->open, +DB->put, +DB->remove, +DB->set_bt_compare, +DB->set_bt_minkey, +DB->set_bt_prefix, +DB->set_cachesize, +DB->set_dup_compare, +DB->set_errcall, +DB->set_errfile, +DB->set_errpfx, +DB->set_flags, +DB->set_h_ffactor, +DB->set_h_hash, +DB->set_h_nelem, +DB->set_lorder, +DB->set_malloc, +DB->set_pagesize, +DB->set_paniccall, +DB->set_q_extentsize, +DB->set_realloc, +DB->set_re_delim, +DB->set_re_len, +DB->set_re_pad, +DB->set_re_source, +DB->stat, +DB->sync, +DB->upgrade +and +DB->verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_set_lorder.html b/db/docs/api_c/db_set_lorder.html new file mode 100644 index 000000000..a9a3c9230 --- /dev/null +++ b/db/docs/api_c/db_set_lorder.html @@ -0,0 +1,94 @@ + + + + + +Berkeley DB: DB->set_lorder + + + + + + + +
+

DB->set_lorder

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DB->set_lorder(DB *db, int lorder); +

+

Description

+

Set the byte order for integers in the stored database metadata. The +number should represent the order as an integer, for example, big endian +order is the number 4,321, and little endian order is the number 1,234. +If lorder is not explicitly set, the host order of the machine +where the Berkeley DB library was compiled is used. +

The value of lorder is ignored except when databases are being +created. If a database already exists, the byte order it uses is +determined when the database is opened. +

The access methods provide no guarantees about the byte ordering of the +application data stored in the database, and applications are responsible +for maintaining any necessary ordering. +

The DB->set_lorder interface may only be used to configure Berkeley DB before +the DB->open interface is called. +

The DB->set_lorder function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

See Also

+db_create, +DB->close, +DB->cursor, +DB->del, +DB->err, +DB->fd, +DB->get, +DB->get_byteswapped, +DB->get_type, +DB->join, +DB->key_range, +DB->open, +DB->put, +DB->remove, +DB->set_bt_compare, +DB->set_bt_minkey, +DB->set_bt_prefix, +DB->set_cachesize, +DB->set_dup_compare, +DB->set_errcall, +DB->set_errfile, +DB->set_errpfx, +DB->set_flags, +DB->set_h_ffactor, +DB->set_h_hash, +DB->set_h_nelem, +DB->set_lorder, +DB->set_malloc, +DB->set_pagesize, +DB->set_paniccall, +DB->set_q_extentsize, +DB->set_realloc, +DB->set_re_delim, +DB->set_re_len, +DB->set_re_pad, +DB->set_re_source, +DB->stat, +DB->sync, +DB->upgrade +and +DB->verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_set_malloc.html b/db/docs/api_c/db_set_malloc.html new file mode 100644 index 000000000..2d13196a3 --- /dev/null +++ b/db/docs/api_c/db_set_malloc.html @@ -0,0 +1,98 @@ + + + + + +Berkeley DB: DB->set_malloc + + + + + + + +
+

DB->set_malloc

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DB->set_malloc(DB *db, void *(*db_malloc)(size_t size)); +

+

Description

+

Set the allocation function used by the DB methods to allocate +memory in which to return key/data items to the application. +

The DB_DBT_MALLOC flag, when specified in the DBT object, +will cause the DB methods to allocate and re-allocate memory which +then becomes the responsibility of the calling application. See DBT +for more information. +

On systems where there may be multiple library versions of malloc (notably +Windows NT), specifying the DB_DBT_MALLOC flag will fail because +the DB library will allocate memory from a different heap than +the application will use to free it. To avoid this problem, the +DB->set_malloc function can be used to pass Berkeley DB a reference to the +application's allocation routine, in which case it will be used to +allocate the memory returned when the DB_DBT_MALLOC flag is set. +

The function specified must match the calling conventions of the +ANSI C X3.159-1989 (ANSI C) library routine of the same name. +

The DB->set_malloc interface may only be used to configure Berkeley DB before +the DB->open interface is called. +

The DB->set_malloc function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

See Also

+db_create, +DB->close, +DB->cursor, +DB->del, +DB->err, +DB->fd, +DB->get, +DB->get_byteswapped, +DB->get_type, +DB->join, +DB->key_range, +DB->open, +DB->put, +DB->remove, +DB->set_bt_compare, +DB->set_bt_minkey, +DB->set_bt_prefix, +DB->set_cachesize, +DB->set_dup_compare, +DB->set_errcall, +DB->set_errfile, +DB->set_errpfx, +DB->set_flags, +DB->set_h_ffactor, +DB->set_h_hash, +DB->set_h_nelem, +DB->set_lorder, +DB->set_malloc, +DB->set_pagesize, +DB->set_paniccall, +DB->set_q_extentsize, +DB->set_realloc, +DB->set_re_delim, +DB->set_re_len, +DB->set_re_pad, +DB->set_re_source, +DB->stat, +DB->sync, +DB->upgrade +and +DB->verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_set_pagesize.html b/db/docs/api_c/db_set_pagesize.html new file mode 100644 index 000000000..7fa4af53d --- /dev/null +++ b/db/docs/api_c/db_set_pagesize.html @@ -0,0 +1,90 @@ + + + + + +Berkeley DB: DB->set_pagesize + + + + + + + +
+

DB->set_pagesize

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DB->set_pagesize(DB *db, u_int32_t pagesize); +

+

Description

+

Set the size of the pages used to hold items in the database, in bytes. +The minimum page size is 512 bytes and the maximum page size is 64K bytes. +If the page size is not explicitly set, one is selected based on the +underlying filesystem I/O block size. The automatically selected size +has a lower limit of 512 bytes and an upper limit of 16K bytes. +

For information on tuning the Berkeley DB page size, see +Selecting a page size. +

The DB->set_pagesize interface may only be used to configure Berkeley DB before +the DB->open interface is called. +

The DB->set_pagesize function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

See Also

+db_create, +DB->close, +DB->cursor, +DB->del, +DB->err, +DB->fd, +DB->get, +DB->get_byteswapped, +DB->get_type, +DB->join, +DB->key_range, +DB->open, +DB->put, +DB->remove, +DB->set_bt_compare, +DB->set_bt_minkey, +DB->set_bt_prefix, +DB->set_cachesize, +DB->set_dup_compare, +DB->set_errcall, +DB->set_errfile, +DB->set_errpfx, +DB->set_flags, +DB->set_h_ffactor, +DB->set_h_hash, +DB->set_h_nelem, +DB->set_lorder, +DB->set_malloc, +DB->set_pagesize, +DB->set_paniccall, +DB->set_q_extentsize, +DB->set_realloc, +DB->set_re_delim, +DB->set_re_len, +DB->set_re_pad, +DB->set_re_source, +DB->stat, +DB->sync, +DB->upgrade +and +DB->verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_set_paniccall.html b/db/docs/api_c/db_set_paniccall.html new file mode 100644 index 000000000..506272c96 --- /dev/null +++ b/db/docs/api_c/db_set_paniccall.html @@ -0,0 +1,70 @@ + + + + + + +Berkeley DB: DB->set_paniccall + + + + + + + +
+

DB->set_paniccall

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DB->set_paniccall(DB *db, + void (*paniccall)(DB_ENV *, int errval)); +

+

Description

+

Errors can occur in the Berkeley DB library where the only solution is to shut +down the application and run recovery. (For example, if Berkeley DB is unable +to write log records to disk because there is insufficient disk space.) +In these cases, the value DB_RUNRECOVERY is returned by Berkeley DB. +

In these cases, it is also often simpler to shut down the application when +such errors occur rather than attempting to gracefully return up the stack. +The DB->set_paniccall function is used to specify a function to be called when +DB_RUNRECOVERY is about to be returned from a Berkeley DB method. When +called, the dbenv argument will be a reference to the current +environment, and the errval argument is the error value that would +have been returned to the calling function. +

For DB handles opened inside of Berkeley DB environments, calling the +DB->set_paniccall function affects the entire environment and is equivalent to calling +the DBENV->set_paniccall function. +

The DB->set_paniccall interface may be used to configure Berkeley DB at any time +during the life of the application. +

The DB->set_paniccall function returns a non-zero error value on failure and 0 on success. +

See Also

+DBENV->close, +db_env_create, +DBENV->open, +DBENV->remove, +DBENV->err, +db_strerror, +db_version, +DBENV->set_cachesize, +DBENV->set_errcall, +DBENV->set_errfile, +DBENV->set_errpfx, +DBENV->set_flags, +DBENV->set_mutexlocks, +DBENV->set_paniccall, +and +DBENV->set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_set_q_extentsize.html b/db/docs/api_c/db_set_q_extentsize.html new file mode 100644 index 000000000..7ab89bdba --- /dev/null +++ b/db/docs/api_c/db_set_q_extentsize.html @@ -0,0 +1,90 @@ + + + + + +Berkeley DB: DB->set_q_extentsize + + + + + + + +
+

DB->set_q_extentsize

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DB->set_q_extentsize(DB *db, u_int32_t extentsize); +

+

Description

+

Set the size of the extents used to hold pages in a Queue database, +specified as a number of pages. Each extent is created as a separate +physical file. If no extent size is set, the default behavior is to +create only a single underlying database file. +

For information on tuning the extent size, see +Selecting a extent size. +

The DB->set_q_extentsize interface may only be used to configure Berkeley DB before +the DB->open interface is called. +

The DB->set_q_extentsize function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DB->open was called. +

+

See Also

+db_create, +DB->close, +DB->cursor, +DB->del, +DB->err, +DB->fd, +DB->get, +DB->get_byteswapped, +DB->get_type, +DB->join, +DB->key_range, +DB->open, +DB->put, +DB->remove, +DB->set_bt_compare, +DB->set_bt_minkey, +DB->set_bt_prefix, +DB->set_cachesize, +DB->set_dup_compare, +DB->set_errcall, +DB->set_errfile, +DB->set_errpfx, +DB->set_flags, +DB->set_h_ffactor, +DB->set_h_hash, +DB->set_h_nelem, +DB->set_lorder, +DB->set_malloc, +DB->set_pagesize, +DB->set_paniccall, +DB->set_q_extentsize, +DB->set_realloc, +DB->set_re_delim, +DB->set_re_len, +DB->set_re_pad, +DB->set_re_source, +DB->stat, +DB->sync, +DB->upgrade +and +DB->verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_set_re_delim.html b/db/docs/api_c/db_set_re_delim.html new file mode 100644 index 000000000..6101130a5 --- /dev/null +++ b/db/docs/api_c/db_set_re_delim.html @@ -0,0 +1,90 @@ + + + + + +Berkeley DB: DB->set_re_delim + + + + + + + +
+

DB->set_re_delim

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DB->set_re_delim(DB *db, int re_delim); +

+

Description

+

Set the delimiting byte used to mark the end of a record in the backing +source file for the Recno access method. +

This byte is used for variable length records, if the re_source +file is specified. If the re_source file is specified and no +delimiting byte was specified, <newline> characters (i.e. +ASCII 0x0a) are interpreted as end-of-record markers. +

The DB->set_re_delim interface may only be used to configure Berkeley DB before +the DB->open interface is called. +

The DB->set_re_delim function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DB->open was called. +

+

See Also

+db_create, +DB->close, +DB->cursor, +DB->del, +DB->err, +DB->fd, +DB->get, +DB->get_byteswapped, +DB->get_type, +DB->join, +DB->key_range, +DB->open, +DB->put, +DB->remove, +DB->set_bt_compare, +DB->set_bt_minkey, +DB->set_bt_prefix, +DB->set_cachesize, +DB->set_dup_compare, +DB->set_errcall, +DB->set_errfile, +DB->set_errpfx, +DB->set_flags, +DB->set_h_ffactor, +DB->set_h_hash, +DB->set_h_nelem, +DB->set_lorder, +DB->set_malloc, +DB->set_pagesize, +DB->set_paniccall, +DB->set_q_extentsize, +DB->set_realloc, +DB->set_re_delim, +DB->set_re_len, +DB->set_re_pad, +DB->set_re_source, +DB->stat, +DB->sync, +DB->upgrade +and +DB->verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_set_re_len.html b/db/docs/api_c/db_set_re_len.html new file mode 100644 index 000000000..67b67ddfc --- /dev/null +++ b/db/docs/api_c/db_set_re_len.html @@ -0,0 +1,94 @@ + + + + + +Berkeley DB: DB->set_re_len + + + + + + + +
+

DB->set_re_len

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DB->set_re_len(DB *db, u_int32_t re_len); +

+

Description

+

For the Queue access method, specify that the records are of length +re_len. +

For the Recno access method, specify that the records are fixed-length, +not byte delimited, and are of length re_len. +

Any records added to the database that are less than re_len bytes +long are automatically padded (see DB->set_re_pad for more +information). +

Any attempt to insert records into the database that are greater than +re_len bytes long will cause the call to fail immediately and +return an error. +

The DB->set_re_len interface may only be used to configure Berkeley DB before +the DB->open interface is called. +

The DB->set_re_len function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DB->open was called. +

+

See Also

+db_create, +DB->close, +DB->cursor, +DB->del, +DB->err, +DB->fd, +DB->get, +DB->get_byteswapped, +DB->get_type, +DB->join, +DB->key_range, +DB->open, +DB->put, +DB->remove, +DB->set_bt_compare, +DB->set_bt_minkey, +DB->set_bt_prefix, +DB->set_cachesize, +DB->set_dup_compare, +DB->set_errcall, +DB->set_errfile, +DB->set_errpfx, +DB->set_flags, +DB->set_h_ffactor, +DB->set_h_hash, +DB->set_h_nelem, +DB->set_lorder, +DB->set_malloc, +DB->set_pagesize, +DB->set_paniccall, +DB->set_q_extentsize, +DB->set_realloc, +DB->set_re_delim, +DB->set_re_len, +DB->set_re_pad, +DB->set_re_source, +DB->stat, +DB->sync, +DB->upgrade +and +DB->verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_set_re_pad.html b/db/docs/api_c/db_set_re_pad.html new file mode 100644 index 000000000..43a6f947f --- /dev/null +++ b/db/docs/api_c/db_set_re_pad.html @@ -0,0 +1,88 @@ + + + + + +Berkeley DB: DB->set_re_pad + + + + + + + +
+

DB->set_re_pad

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DB->set_re_pad(DB *db, int re_pad); +

+

Description

+

Set the padding character for short, fixed-length records for the Queue +and Recno access methods. +

If no pad character is specified, <space> characters (i.e., +ASCII 0x20) are used for padding. +

The DB->set_re_pad interface may only be used to configure Berkeley DB before +the DB->open interface is called. +

The DB->set_re_pad function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DB->open was called. +

+

See Also

+db_create, +DB->close, +DB->cursor, +DB->del, +DB->err, +DB->fd, +DB->get, +DB->get_byteswapped, +DB->get_type, +DB->join, +DB->key_range, +DB->open, +DB->put, +DB->remove, +DB->set_bt_compare, +DB->set_bt_minkey, +DB->set_bt_prefix, +DB->set_cachesize, +DB->set_dup_compare, +DB->set_errcall, +DB->set_errfile, +DB->set_errpfx, +DB->set_flags, +DB->set_h_ffactor, +DB->set_h_hash, +DB->set_h_nelem, +DB->set_lorder, +DB->set_malloc, +DB->set_pagesize, +DB->set_paniccall, +DB->set_q_extentsize, +DB->set_realloc, +DB->set_re_delim, +DB->set_re_len, +DB->set_re_pad, +DB->set_re_source, +DB->stat, +DB->sync, +DB->upgrade +and +DB->verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_set_re_source.html b/db/docs/api_c/db_set_re_source.html new file mode 100644 index 000000000..1a57cfea3 --- /dev/null +++ b/db/docs/api_c/db_set_re_source.html @@ -0,0 +1,130 @@ + + + + + +Berkeley DB: DB->set_re_source + + + + + + + +
+

DB->set_re_source

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DB->set_re_source(DB *db, char *re_source); +

+

Description

+

Set the underlying source file for the Recno access method. The purpose +of the re_source value is to provide fast access and modification +to databases that are normally stored as flat text files. +

If the re_source field is set, it specifies an underlying flat +text database file that is read to initialize a transient record number +index. In the case of variable length records, the records are separated +as specified by DB->set_re_delim. For example, standard UNIX +byte stream files can be interpreted as a sequence of variable length +records separated by <newline> characters. +

In addition, when cached data would normally be written back to the +underlying database file (e.g., the DB->close or DB->sync +methods are called), the in-memory copy of the database will be written +back to the re_source file. +

By default, the backing source file is read lazily, i.e., records are not +read from the file until they are requested by the application. +If multiple processes (not threads) are accessing a Recno database +concurrently and either inserting or deleting records, the backing source +file must be read in its entirety before more than a single process +accesses the database, and only that process should specify the backing +source file as part of the DB->open call. See the DB_SNAPSHOT +flag for more information. +

Reading and writing the backing source file specified by re_source +cannot be transactionally protected because it involves filesystem +operations that are not part of the Db transaction methodology. +For this reason, if a temporary database is used to hold the records, +i.e., a NULL was specified as the file argument to DB->open, +it is possible to lose the contents of the re_source file, e.g., +if the system crashes at the right instant. +If a file is used to hold the database, i.e., a file name was specified +as the file argument to DB->open, normal database +recovery on that file can be used to prevent information loss, +although it is still possible that the contents of re_source +will be lost if the system crashes. +

The re_source file must already exist (but may be zero-length) when +DB->open is called. +

It is not an error to specify a read-only re_source file when +creating a database, nor is it an error to modify the resulting database. +However, any attempt to write the changes to the backing source file using +either the DB->sync or DB->close functions will fail, of course. +Specify the DB_NOSYNC flag to the DB->close function to stop it +from attempting to write the changes to the backing file, instead, they +will be silently discarded. +

For all of the above reasons, the re_source field is generally +used to specify databases that are read-only for DB applications, +and that are either generated on the fly by software tools, or modified +using a different mechanism, e.g., a text editor. +

The DB->set_re_source interface may only be used to configure Berkeley DB before +the DB->open interface is called. +

The DB->set_re_source function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DB->open was called. +

+

See Also

+db_create, +DB->close, +DB->cursor, +DB->del, +DB->err, +DB->fd, +DB->get, +DB->get_byteswapped, +DB->get_type, +DB->join, +DB->key_range, +DB->open, +DB->put, +DB->remove, +DB->set_bt_compare, +DB->set_bt_minkey, +DB->set_bt_prefix, +DB->set_cachesize, +DB->set_dup_compare, +DB->set_errcall, +DB->set_errfile, +DB->set_errpfx, +DB->set_flags, +DB->set_h_ffactor, +DB->set_h_hash, +DB->set_h_nelem, +DB->set_lorder, +DB->set_malloc, +DB->set_pagesize, +DB->set_paniccall, +DB->set_q_extentsize, +DB->set_realloc, +DB->set_re_delim, +DB->set_re_len, +DB->set_re_pad, +DB->set_re_source, +DB->stat, +DB->sync, +DB->upgrade +and +DB->verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_set_realloc.html b/db/docs/api_c/db_set_realloc.html new file mode 100644 index 000000000..b3d8a05f7 --- /dev/null +++ b/db/docs/api_c/db_set_realloc.html @@ -0,0 +1,99 @@ + + + + + +Berkeley DB: DB->set_realloc + + + + + + + +
+

DB->set_realloc

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DB->set_realloc(DB *db, + void *(*db_realloc_fcn)(void *ptr, size_t size)); +

+

Description

+

Set the realloc function used by the DB methods to allocate memory +in which to return key/data items to the application. +

The DB_DBT_REALLOC flag, when specified in the DBT object, +will cause the DB methods to allocate and re-allocate memory which +then becomes the responsibility of the calling application. See DBT +for more information. +

On systems where there may be multiple library versions of realloc (notably +Windows NT), specifying the DB_DBT_REALLOC flag will fail because +the DB library will allocate memory from a different heap than +the application will use to free it. To avoid this problem, the +DB->set_realloc function can be used to pass Berkeley DB a reference to the +application's allocation routine, in which case it will be used to +allocate the memory returned when the DB_DBT_REALLOC flag is set. +

The function specified must match the calling conventions of the +ANSI C X3.159-1989 (ANSI C) library routine of the same name. +

The DB->set_realloc interface may only be used to configure Berkeley DB before +the DB->open interface is called. +

The DB->set_realloc function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

See Also

+db_create, +DB->close, +DB->cursor, +DB->del, +DB->err, +DB->fd, +DB->get, +DB->get_byteswapped, +DB->get_type, +DB->join, +DB->key_range, +DB->open, +DB->put, +DB->remove, +DB->set_bt_compare, +DB->set_bt_minkey, +DB->set_bt_prefix, +DB->set_cachesize, +DB->set_dup_compare, +DB->set_errcall, +DB->set_errfile, +DB->set_errpfx, +DB->set_flags, +DB->set_h_ffactor, +DB->set_h_hash, +DB->set_h_nelem, +DB->set_lorder, +DB->set_malloc, +DB->set_pagesize, +DB->set_paniccall, +DB->set_q_extentsize, +DB->set_realloc, +DB->set_re_delim, +DB->set_re_len, +DB->set_re_pad, +DB->set_re_source, +DB->stat, +DB->sync, +DB->upgrade +and +DB->verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_stat.html b/db/docs/api_c/db_stat.html new file mode 100644 index 000000000..92412d76d --- /dev/null +++ b/db/docs/api_c/db_stat.html @@ -0,0 +1,195 @@ + + + + + +Berkeley DB: DB->stat + + + + + + + +
+

DB->stat

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DB->stat(DB *db, + void *sp, void *(*db_malloc)(size_t), u_int32_t flags); +

+

Description

+

The DB->stat function creates a statistical structure and +copies a pointer to it into user-specified memory locations. +Specifically, if sp is non-NULL, a pointer to the statistics +for the database are copied into the memory location it references. +

Statistical structures are created in allocated memory. If db_malloc is non-NULL, it +is called to allocate the memory, otherwise, the library function +malloc(3) is used. The function db_malloc must match +the calling conventions of the malloc(3) library routine. +Regardless, the caller is responsible for deallocating the returned +memory. To deallocate returned memory, free the returned memory +reference, references inside the returned memory do not need to be +individually freed. +

The flags parameter must be set to 0 or the following value: +

+

DB_CACHED_COUNTS
Return a cached count of the keys and records in a database. This flag +makes it possible for applications to request an possibly approximate key +and record count without incurring the performance penalty of traversing +the entire database. The statistics information described for the access +method XX_nkeys and XX_ndata fields below is filled in, +but no other information is collected. If the cached information has +never been set, the fields will be returned set to 0. +

DB_RECORDCOUNT
Return a count of the records in a Btree or Recno Access Method database. +This flag makes it possible for applications to request a record count +without incurring the performance penalty of traversing the entire +database. The statistics information described for the bt_nkeys +field below is filled in, but no other information is collected. +

This option is only available for Recno databases, or Btree databases +where the underlying database was created with the DB_RECNUM +flag. +

+

The DB->stat function may access all of the pages in the database, +incurring a severe performance penalty as well as possibly flushing the +underlying buffer pool. +

In the presence of multiple threads or processes accessing an active +database, the information returned by DB->stat may be out-of-date. +

If the database was not opened readonly and the DB_CACHED_COUNTS +flag was not specified, the cached key and record numbers will be updated +after the statistical information has been gathered. +

The DB->stat function cannot be transaction protected. For this reason, +it should be called in a thread of control that has no open cursors or +active transactions. +

The DB->stat function returns a non-zero error value on failure and 0 on success. +

Hash Statistics

+

In the case of a Hash database, +the statistics are stored in a structure of type DB_HASH_STAT. The +following fields will be filled in: +

+

u_int32_t hash_magic;
Magic number that identifies the file as a Hash file. +
u_int32_t hash_version;
The version of the Hash database. +
u_int32_t hash_nkeys;
The number of unique keys in the database. +
u_int32_t hash_ndata;
The number of key/data pairs in the database.] +
u_int32_t hash_pagesize;
The underlying Hash database page (and bucket) size. +
u_int32_t hash_nelem;
The estimated size of the hash table specified at database creation time. +
u_int32_t hash_ffactor;
The desired fill factor (number of items per bucket) specified at database +creation time. +
u_int32_t hash_buckets;
The number of hash buckets. +
u_int32_t hash_free;
The number of pages on the free list. +
u_int32_t hash_bfree;
The number of bytes free on bucket pages. +
u_int32_t hash_bigpages;
The number of big key/data pages. +
u_int32_t hash_big_bfree;
The number of bytes free on big item pages. +
u_int32_t hash_overflows;
The number of overflow pages (overflow pages are pages that contain items +that did not fit in the main bucket page). +
u_int32_t hash_ovfl_free;
The number of bytes free on overflow pages. +
u_int32_t hash_dup;
The number of duplicate pages. +
u_int32_t hash_dup_free;
The number of bytes free on duplicate pages. +
+

Btree and Recno Statistics

+

In the case of a Btree or Recno database, +the statistics are stored in a structure of type DB_BTREE_STAT. The +following fields will be filled in: +

+

u_int32_t bt_magic;
Magic number that identifies the file as a Btree database. +
u_int32_t bt_version;
The version of the Btree database. +
u_int32_t bt_nkeys;
For the Btree Access Method, the number of unique keys in the database. +

For the Recno Access Method, the number of records in the database. +

u_int32_t bt_ndata;
For the Btree Access Method, the number of key/data pairs in the database. +

For the Recno Access Method, the number of records in the database. If +the database has been configured to not re-number records during +deletion, the number of records will only reflect undeleted records. +

u_int32_t bt_pagesize;
Underlying database page size. +
u_int32_t bt_minkey;
The minimum keys per page. +
u_int32_t bt_re_len;
The length of fixed-length records. +
u_int32_t bt_re_pad;
The padding byte value for fixed-length records. +
u_int32_t bt_levels;
Number of levels in the database. +
u_int32_t bt_int_pg;
Number of database internal pages. +
u_int32_t bt_leaf_pg;
Number of database leaf pages. +
u_int32_t bt_dup_pg;
Number of database duplicate pages. +
u_int32_t bt_over_pg;
Number of database overflow pages. +
u_int32_t bt_free;
Number of pages on the free list. +
u_int32_t bt_int_pgfree;
Number of bytes free in database internal pages. +
u_int32_t bt_leaf_pgfree;
Number of bytes free in database leaf pages. +
u_int32_t bt_dup_pgfree;
Number of bytes free in database duplicate pages. +
u_int32_t bt_over_pgfree;
Number of bytes free in database overflow pages. +
+

Queue Statistics

+

In the case of a Queue database, +the statistics are stored in a structure of type DB_QUEUE_STAT. The +following fields will be filled in: +

+

u_int32_t qs_magic;
Magic number that identifies the file as a Queue file. +
u_int32_t qs_version;
The version of the Queue file type. +
u_int32_t qs_nkeys;
The number of records in the database. +
u_int32_t qs_ndata;
The number of records in the database. +
u_int32_t qs_pagesize;
Underlying database page size. +
u_int32_t qs_pages;
Number of pages in the database. +
u_int32_t qs_re_len;
The length of the records. +
u_int32_t qs_re_pad;
The padding byte value for the records. +
u_int32_t qs_pgfree;
Number of bytes free in database pages. +
u_int32_t qs_start;
Start offset. +
u_int32_t qs_first_recno;
First undeleted record in the database. +
u_int32_t qs_cur_recno;
Last allocated record number in the database. +
+

The DB->stat function returns a non-zero error value on failure and 0 on success. +

Errors

+

The DB->stat function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the DB->stat function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+db_create, +DB->close, +DB->cursor, +DB->del, +DB->err, +DB->fd, +DB->get, +DB->get_byteswapped, +DB->get_type, +DB->join, +DB->key_range, +DB->open, +DB->put, +DB->remove, +DB->set_bt_compare, +DB->set_bt_minkey, +DB->set_bt_prefix, +DB->set_cachesize, +DB->set_dup_compare, +DB->set_errcall, +DB->set_errfile, +DB->set_errpfx, +DB->set_flags, +DB->set_h_ffactor, +DB->set_h_hash, +DB->set_h_nelem, +DB->set_lorder, +DB->set_malloc, +DB->set_pagesize, +DB->set_paniccall, +DB->set_q_extentsize, +DB->set_realloc, +DB->set_re_delim, +DB->set_re_len, +DB->set_re_pad, +DB->set_re_source, +DB->stat, +DB->sync, +DB->upgrade +and +DB->verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_sync.html b/db/docs/api_c/db_sync.html new file mode 100644 index 000000000..6af624a88 --- /dev/null +++ b/db/docs/api_c/db_sync.html @@ -0,0 +1,98 @@ + + + + + +Berkeley DB: DB->sync + + + + + + + +
+

DB->sync

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DB->sync(DB *db, u_int32_t flags); +

+

Description

+

The DB->sync function flushes any cached information to disk. +

If the database is in memory only, the DB->sync function has no effect and +will always succeed. +

The flags parameter is currently unused, and must be set to 0. +

See DB->close for a discussion of Berkeley DB and cached data. +

The DB->sync function returns a non-zero error value on failure, 0 on success, and returns DB_INCOMPLETE if the underlying database still has +dirty pages in the cache. (The only reason to return +DB_INCOMPLETE is if another thread of control was writing pages +in the underlying database file at the same time as the +DB->sync function was being called. For this reason, a return of +DB_INCOMPLETE can normally be ignored, or, in cases where it is +a possible return value, there may be no reason to call +DB->sync.) +

Errors

+

The DB->sync function may fail and return a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +
+

The DB->sync function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the DB->sync function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+db_create, +DB->close, +DB->cursor, +DB->del, +DB->err, +DB->fd, +DB->get, +DB->get_byteswapped, +DB->get_type, +DB->join, +DB->key_range, +DB->open, +DB->put, +DB->remove, +DB->set_bt_compare, +DB->set_bt_minkey, +DB->set_bt_prefix, +DB->set_cachesize, +DB->set_dup_compare, +DB->set_errcall, +DB->set_errfile, +DB->set_errpfx, +DB->set_flags, +DB->set_h_ffactor, +DB->set_h_hash, +DB->set_h_nelem, +DB->set_lorder, +DB->set_malloc, +DB->set_pagesize, +DB->set_paniccall, +DB->set_q_extentsize, +DB->set_realloc, +DB->set_re_delim, +DB->set_re_len, +DB->set_re_pad, +DB->set_re_source, +DB->stat, +DB->sync, +DB->upgrade +and +DB->verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_upgrade.html b/db/docs/api_c/db_upgrade.html new file mode 100644 index 000000000..e31b4d447 --- /dev/null +++ b/db/docs/api_c/db_upgrade.html @@ -0,0 +1,135 @@ + + + + + +Berkeley DB: DB->upgrade + + + + + + + +
+

DB->upgrade

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DB->upgrade(DB *db, const char *file, u_int32_t flags); +

+

Description

+

The DB->upgrade function upgrades all of the databases included in the +file file, if necessary. If no upgrade is necessary, +DB->upgrade always returns success. +

Database upgrades are done in place and are destructive, e.g., if pages +need to be allocated and no disk space is available, the database may be +left corrupted. Backups should be made before databases are upgraded. +See Upgrading databases for more +information. +

Unlike all other database operations, DB->upgrade may only be done +on a system with the same byte-order as the database. +

The flags parameter must be set to 0 or one of the following +values: +

+

DB_DUPSORT
This flag is only meaningful when upgrading databases from +releases before the Berkeley DB 3.1 release. +

As part of the upgrade from the Berkeley DB 3.0 release to the 3.1 release, the +on-disk format of duplicate data items changed. To correctly upgrade the +format requires applications specify if duplicate data items in the +database are sorted or not. Specifying the DB_DUPSORT flag +informs DB->upgrade that the duplicates are sorted, otherwise they +are assumed to be unsorted. Incorrectly specifying the value of this flag +may lead to database corruption. +

Further, because the DB->upgrade function upgrades a physical file +(including all of the databases it contains), it is not possible to use +DB->upgrade to upgrade files where some of the databases it +includes have sorted duplicate data items and some of the databases it +includes have unsorted duplicate data items. If the file does not have +more than a single database, or the databases do not support duplicate +data items, or all of the databases that support duplicate data items +support the same style of duplicates (either sorted or unsorted), +DB->upgrade will work correctly as long as the DB_DUPSORT +flag is correctly specified. Otherwise, the file cannot be upgraded using +DB->upgrade, and must be upgraded manually by dumping and +re-loading the databases. +

+

The DB->upgrade function returns a non-zero error value on failure and 0 on success. +

The DB->upgrade function is the underlying function used by the db_upgrade utility. +See the db_upgrade utility source code for an example of using DB->upgrade +in a IEEE/ANSI Std 1003.1 (POSIX) environment. +

Environment Variables

+

+

DB_HOME
If the dbenv argument to db_create was initialized using +DBENV->open the environment variable DB_HOME may be used +as the path of the database environment home. Specifically, DB->upgrade +is affected by the configuration value DB_DATA_DIR. +
+

Errors

+

The DB->upgrade function may fail and return a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +

The database is not in the same byte-order as the system. +

+

+

DB_OLD_VERSION
The database cannot be upgraded by this version of the Berkeley DB software. +
+

The DB->upgrade function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the DB->upgrade function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+db_create, +DB->close, +DB->cursor, +DB->del, +DB->err, +DB->fd, +DB->get, +DB->get_byteswapped, +DB->get_type, +DB->join, +DB->key_range, +DB->open, +DB->put, +DB->remove, +DB->set_bt_compare, +DB->set_bt_minkey, +DB->set_bt_prefix, +DB->set_cachesize, +DB->set_dup_compare, +DB->set_errcall, +DB->set_errfile, +DB->set_errpfx, +DB->set_flags, +DB->set_h_ffactor, +DB->set_h_hash, +DB->set_h_nelem, +DB->set_lorder, +DB->set_malloc, +DB->set_pagesize, +DB->set_paniccall, +DB->set_q_extentsize, +DB->set_realloc, +DB->set_re_delim, +DB->set_re_len, +DB->set_re_pad, +DB->set_re_source, +DB->stat, +DB->sync, +DB->upgrade +and +DB->verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/db_verify.html b/db/docs/api_c/db_verify.html new file mode 100644 index 000000000..d011d90ab --- /dev/null +++ b/db/docs/api_c/db_verify.html @@ -0,0 +1,150 @@ + + + + + +Berkeley DB: DB->verify + + + + + + + +
+

DB->verify

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DB->verify(DB *db, const char *file, + const char *database, FILE *outfile, u_int32_t flags); +

+

Description

+

The DB->verify function verifies the integrity of all databases in the +file specified by the file argument, and optionally outputs the databases' +key/data pairs to a file stream. +

The flags parameter must be set to 0 or one of the following +values: +

+

DB_SALVAGE
Write the key/data pairs from all databases in the file to the file stream +named in +the outfile argument. The output format is the same as that +specified for the db_dump utility and can be used as input for +the db_load utility. +

Because the key/data pairs are output in page order as opposed to the sort +order used by db_dump, using DB->verify to dump key/data +pairs normally produces less than optimal loads for Btree databases. +

+

In addition, the following flags may be set by bitwise inclusively OR'ing them into the +flags parameter: +

+

DB_AGGRESSIVE
Output all the key/data pairs in the file that can be found. +By default, DB->verify does not assume corruption. For example, +if a key/data pair on a page is marked as deleted, it is not then written +to the output file. When DB_AGGRESSIVE is specified, corruption +is assumed, and any key/data pair that can be found is written. In this +case, key/data pairs that are corrupted or have been deleted may appear +in the output (even if the file being salvaged is in no way corrupt), and +the output will almost certainly require editing before being loaded into +a database. +

DB_NOORDERCHK
Skip the database checks for btree and duplicate sort order and for +hashing. +

The DB->verify function normally verifies that btree keys and duplicate +items are correctly sorted and hash keys are correctly hashed. If the +file being verified contains multiple databases using differing sorting +or hashing algorithms, some of them must necessarily fail database +verification as only one sort order or hash function can be specified +before DB->verify is called. To verify files with multiple +databases having differing sorting orders or hashing functions, first +perform verification of the file as a whole by using the +DB_NOORDERCHK flag, and then individually verify the sort order +and hashing function for each database in the file using the +DB_ORDERCHKONLY flag. +

DB_ORDERCHKONLY
Perform the database checks for btree and duplicate sort order and for +hashing, skipped by DB_NOORDERCHK. +

When this flag is specified, a database argument should also be +specified, indicating the database in the physical file which is to be +checked. This flag is only safe to use on databases that have already +successfully been verified using DB->verify with the +DB_NOORDERCHK flag set. +

+

The database argument must be set to NULL except when the +DB_ORDERCHKONLY flag is set. +

The DB->verify function returns a non-zero error value on failure, 0 on success, and DB_VERIFY_BAD if a database is corrupted. When the +DB_SALVAGE flag is specified, the DB_VERIFY_BAD return +means that all key/data pairs in the file may not have been successfully +output. +

The DB->verify function is the underlying function used by the db_verify utility. +See the db_verify utility source code for an example of using DB->verify +in a IEEE/ANSI Std 1003.1 (POSIX) environment. +

Environment Variables

+

+

DB_HOME
If the dbenv argument to db_create was initialized using +DBENV->open the environment variable DB_HOME may be used +as the path of the database environment home. Specifically, DB->verify +is affected by the configuration value DB_DATA_DIR. +
+

Errors

+

The DB->verify function may fail and return a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +
+

The DB->verify function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the DB->verify function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+db_create, +DB->close, +DB->cursor, +DB->del, +DB->err, +DB->fd, +DB->get, +DB->get_byteswapped, +DB->get_type, +DB->join, +DB->key_range, +DB->open, +DB->put, +DB->remove, +DB->set_bt_compare, +DB->set_bt_minkey, +DB->set_bt_prefix, +DB->set_cachesize, +DB->set_dup_compare, +DB->set_errcall, +DB->set_errfile, +DB->set_errpfx, +DB->set_flags, +DB->set_h_ffactor, +DB->set_h_hash, +DB->set_h_nelem, +DB->set_lorder, +DB->set_malloc, +DB->set_pagesize, +DB->set_paniccall, +DB->set_q_extentsize, +DB->set_realloc, +DB->set_re_delim, +DB->set_re_len, +DB->set_re_pad, +DB->set_re_source, +DB->stat, +DB->sync, +DB->upgrade +and +DB->verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/dbc_close.html b/db/docs/api_c/dbc_close.html new file mode 100644 index 000000000..20eb28d95 --- /dev/null +++ b/db/docs/api_c/dbc_close.html @@ -0,0 +1,64 @@ + + + + + +Berkeley DB: DBcursor->c_close + + + + + + + +
+

DBcursor->c_close

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DBcursor->c_close(DBC *cursor); +

+

Description

+

The DBcursor->c_close function discards the cursor. +

It is possible for the DBcursor->c_close function to return +DB_LOCK_DEADLOCK, signaling that any enclosing transaction should +be aborted. If the application is already intending to abort the +transaction, this error should be ignored, and the application should +proceed. +

Once DBcursor->c_close has been called, regardless of its return, the +cursor handle may not be used again. +

The DBcursor->c_close function returns a non-zero error value on failure and 0 on success. +

Errors

+

The DBcursor->c_close function may fail and return a non-zero error for the following conditions: +

+

DB_LOCK_DEADLOCK
The operation was selected to resolve a deadlock. +
+

+

EINVAL
An invalid flag value or parameter was specified. +

The cursor was previously closed. +

+

The DBcursor->c_close function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the DBcursor->c_close function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBcursor->c_close, +DBcursor->c_count, +DBcursor->c_del, +DBcursor->c_dup, +DBcursor->c_get +and +DBcursor->c_put. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/dbc_count.html b/db/docs/api_c/dbc_count.html new file mode 100644 index 000000000..434a0ce8c --- /dev/null +++ b/db/docs/api_c/dbc_count.html @@ -0,0 +1,55 @@ + + + + + +Berkeley DB: DBcursor->c_count + + + + + + + +
+

DBcursor->c_count

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DBC->c_count(DBC *cursor, db_recno_t *countp, u_int32_t flags); +

+

Description

+

The DBcursor->c_count function returns a count of the number of duplicate data +items for the key referenced by the +cursor into the memory location referenced by countp. +If the underlying database does not support duplicate data items the call +will still succeed and a count of 1 will be returned. +

The flags parameter is currently unused, and must be set to 0. +

If the cursor argument is not yet initialized, the DBcursor->c_count function will return EINVAL. +

Otherwise, the DBcursor->c_count function returns a non-zero error value on failure and 0 on success. +

Errors

+

The DBcursor->c_count function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the DBcursor->c_count function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBcursor->c_close, +DBcursor->c_count, +DBcursor->c_del, +DBcursor->c_dup, +DBcursor->c_get +and +DBcursor->c_put. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/dbc_del.html b/db/docs/api_c/dbc_del.html new file mode 100644 index 000000000..110d97471 --- /dev/null +++ b/db/docs/api_c/dbc_del.html @@ -0,0 +1,68 @@ + + + + + +Berkeley DB: DBcursor->c_del + + + + + + + +
+

DBcursor->c_del

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DBcursor->c_del(DBC *cursor, u_int32_t flags); +

+

Description

+

The DBcursor->c_del function deletes the key/data pair currently referenced by +the cursor. +

The flags parameter is currently unused, and must be set to 0. +

The cursor position is unchanged after a delete, and subsequent calls to +cursor functions expecting the cursor to reference an existing key will +fail. +

If the element has already been deleted, DBcursor->c_del will return +DB_KEYEMPTY. +

If the cursor is not yet initialized, the DBcursor->c_del function will return EINVAL. +

Otherwise, the DBcursor->c_del function returns a non-zero error value on failure and 0 on success. +

Errors

+

The DBcursor->c_del function may fail and return a non-zero error for the following conditions: +

+

DB_LOCK_DEADLOCK
The operation was selected to resolve a deadlock. +
+

+

EINVAL
An invalid flag value or parameter was specified. +
+

+

EPERM
Write attempted on read-only cursor when the DB_INIT_CDB flag was +specified to DBENV->open. +
+

The DBcursor->c_del function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the DBcursor->c_del function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBcursor->c_close, +DBcursor->c_count, +DBcursor->c_del, +DBcursor->c_dup, +DBcursor->c_get +and +DBcursor->c_put. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/dbc_dup.html b/db/docs/api_c/dbc_dup.html new file mode 100644 index 000000000..42e3531ca --- /dev/null +++ b/db/docs/api_c/dbc_dup.html @@ -0,0 +1,72 @@ + + + + + +Berkeley DB: DBcursor->c_dup + + + + + + + +
+

DBcursor->c_dup

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DBC->c_dup(DBC *cursor, DBC **cursorp, u_int32_t flags); +

+

Description

+

The DBcursor->c_dup function creates a new cursor that uses the same transaction +and locker ID as the original cursor. This is useful when an application +is using locking and requires two or more cursors in the same thread of +control. +

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +

+

DB_POSITION
The newly created cursor is initialized to reference the same position +in the database as the original cursor and hold the same locks. If the +DB_POSITION flag is not specified, then the created cursor is +uninitialized and will behave like a cursor newly created using +DB->cursor. +
+

When using the Berkeley DB Concurrent Data Store product, there can be only one active write cursor +at a time. For this reason, attempting to duplicate a cursor for which +the DB_WRITECURSOR flag was specified during creation will return +an error. +

If the cursor argument is not yet initialized, the DBcursor->c_dup function will return EINVAL. +

Otherwise, the DBcursor->c_dup function returns a non-zero error value on failure and 0 on success. +

Errors

+

The DBcursor->c_dup function may fail and return a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +

The cursor argument was created using the +DB_WRITECURSOR flag in the Berkeley DB Concurrent Data Store product. +

+

The DBcursor->c_dup function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the DBcursor->c_dup function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBcursor->c_close, +DBcursor->c_count, +DBcursor->c_del, +DBcursor->c_dup, +DBcursor->c_get +and +DBcursor->c_put. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/dbc_get.html b/db/docs/api_c/dbc_get.html new file mode 100644 index 000000000..014661f33 --- /dev/null +++ b/db/docs/api_c/dbc_get.html @@ -0,0 +1,167 @@ + + + + + +Berkeley DB: DBcursor->c_get + + + + + + + +
+

DBcursor->c_get

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DBcursor->c_get(DBC *cursor, + DBT *key, DBT *data, u_int32_t flags); +

+

Description

+

The DBcursor->c_get function retrieves key/data pairs from the database. The +address and length of the key +are returned in the object referenced by key (except for the case +of the DB_SET flag where the key object is unchanged), +and the address and length of +the data are returned in the object referenced by data. +

Modifications to the database during a sequential scan will be reflected +in the scan, i.e. records inserted behind a cursor will not be returned +while records inserted in front of a cursor will be returned. +

In Queue and Recno databases, missing entries (i.e., entries that were +never explicitly created or that were created and then deleted), will be +skipped during a sequential scan. +

If multiple threads or processes insert items into the same database file +without using locking, the results are undefined. +For more detail, +see Cursor stability. +

The flags parameter must be set to one of the following values: +

+

DB_CURRENT
Return the key/data pair currently referenced by the cursor. +

If the cursor key/data pair was deleted, DBcursor->c_get will return +DB_KEYEMPTY. +

If the cursor is not yet initialized, the DBcursor->c_get function will return EINVAL. +

DB_FIRST, DB_LAST
The cursor is set to reference the first (last) key/data pair of the +database, and that pair is returned. In the presence of duplicate key +values, the first (last) data item in the set of duplicates is returned. +

If the database is a Queue or Recno database, DBcursor->c_get using the +DB_FIRST (DB_LAST) flags will ignore any keys that exist +but were never explicitly created by the application or were created and +later deleted. +

If the database is empty, DBcursor->c_get will return DB_NOTFOUND. +

DB_GET_BOTH
The DB_GET_BOTH flag is identical to the DB_SET flag, +except that both the key and the data arguments must be matched by the +key and data item in the database. +

DB_GET_RECNO
Return the record number associated with the cursor. The record number +will be returned in data as described in DBT. The +key parameter is ignored. +

For DB_GET_RECNO to be specified, the underlying database must be +of type Btree and it must have been created with the DB_RECNUM +flag. +

DB_JOIN_ITEM
Do not use the data value found in all of the cursors as a lookup key for +the primary database, but simply return it in the key parameter instead. +The data parameter is left unchanged. +

For DB_JOIN_ITEM to be specified, the underlying cursor must have +been returned from the DB->join function. +

DB_NEXT, DB_PREV
If the cursor is not yet initialized, DB_NEXT (DB_PREV) +is identical to DB_FIRST (DB_LAST). Otherwise, the cursor +is moved to the next (previous) key/data pair of the database, and that +pair is returned. In the presence of duplicate key values, the value of +the key may not change. +

If the database is a Queue or Recno database, DBcursor->c_get using the +DB_NEXT (DB_PREV) flag will skip any keys that exist but +were never explicitly created by the application or were created and later +deleted. +

If the cursor is already on the last (first) record in the database, +DBcursor->c_get will return DB_NOTFOUND. +

DB_NEXT_DUP
If the next key/data pair of the database is a duplicate record for the +current key/data pair, the cursor is moved to the next key/data pair of +the database, and that pair is returned. Otherwise, DBcursor->c_get will +return DB_NOTFOUND. +

If the cursor is not yet initialized, the DBcursor->c_get function will return EINVAL. +

DB_NEXT_NODUP, DB_PREV_NODUP
If the cursor is not yet initialized, DB_NEXT_NODUP +(DB_PREV_NODUP) is identical to DB_FIRST +(DB_LAST). Otherwise, the cursor is moved to the next (previous) +non-duplicate key/data pair of the database, and that pair is returned. +

If the database is a Queue or Recno database, DBcursor->c_get using the +DB_NEXT_NODUP (DB_PREV_NODUP) flags will ignore any keys +that exist but were never explicitly created by the application or were +created and later deleted. +

If no non-duplicate key/data pairs occur after (before) the cursor +position in the database, DBcursor->c_get will return DB_NOTFOUND. +

DB_SET
Move the cursor to the specified key/data pair of the database, and +return the datum associated with the given key. +

In the presence of duplicate key values, DBcursor->c_get will return the +first data item for the given key. +

If the database is a Queue or Recno database and the requested key exists, +but was never explicitly created by the application or was later deleted, +DBcursor->c_get will return DB_KEYEMPTY. +

If no matching keys are found, DBcursor->c_get will return +DB_NOTFOUND. +

DB_SET_RANGE
The DB_SET_RANGE flag is identical to the DB_SET flag, +except that the key is returned as well as the data item, and, in the case +of the Btree access method, the returned key/data pair is the smallest +key greater than or equal to the specified key (as determined by the +comparison function), permitting partial key matches and range +searches. +

DB_SET_RECNO
Move the cursor to the specific numbered record of the database, and +return the associated key/data pair. The data field of the +specified key +must be a pointer to a memory location from which a db_recno_t +may be read, as described in DBT. This memory location will be +read to determine the record to be retrieved. +

For DB_SET_RECNO to be specified, the underlying database must be +of type Btree and it must have been created with the DB_RECNUM +flag. +

+

In addition, the following flag may be set by bitwise inclusively OR'ing it into the +flags parameter: +

+

DB_RMW
Acquire write locks instead of read locks when doing the retrieval. +Setting this flag may decrease the likelihood of deadlock during a +read-modify-write cycle by immediately acquiring the write lock during +the read part of the cycle so that another thread of control acquiring +a read lock for the same item, in its own read-modify-write cycle, will +not result in deadlock. +
+

Otherwise, the DBcursor->c_get function returns a non-zero error value on failure and 0 on success. +

If DBcursor->c_get fails for any reason, the state of the cursor will be +unchanged. +

Errors

+

The DBcursor->c_get function may fail and return a non-zero error for the following conditions: +

+

DB_LOCK_DEADLOCK
The operation was selected to resolve a deadlock. +
+

+

ENOMEM
There was insufficient memory to return the requested item. +
+

+

EINVAL
An invalid flag value or parameter was specified. +

The specified cursor was not currently initialized. +

+

The DBcursor->c_get function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the DBcursor->c_get function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBcursor->c_close, +DBcursor->c_count, +DBcursor->c_del, +DBcursor->c_dup, +DBcursor->c_get +and +DBcursor->c_put. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/dbc_put.html b/db/docs/api_c/dbc_put.html new file mode 100644 index 000000000..9a8a0e895 --- /dev/null +++ b/db/docs/api_c/dbc_put.html @@ -0,0 +1,154 @@ + + + + + +Berkeley DB: DBcursor->c_put + + + + + + + +
+

DBcursor->c_put

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DBcursor->c_put(DBC *, DBT *key, DBT *data, u_int32_t flags); +

+

Description

+

The DBcursor->c_put function stores key/data pairs into the database. +

The flags parameter must be set to one of the following values: +

+

DB_AFTER
In the case of the Btree and Hash access methods, insert the data +element as a duplicate element of the key referenced by the cursor. +The new element appears immediately after the current cursor position. +It is an error to specify DB_AFTER if the underlying Btree or +Hash database does not support duplicate data items. The key +parameter is ignored. +

In the case of the Recno access method, it is an error to specify +DB_AFTER if the underlying Recno database was not created with +the DB_RENUMBER flag. If the DB_RENUMBER flag was +specified, a new key is created, all records after the inserted item +are automatically renumbered, and the key of the new record is returned +in the structure referenced by the parameter key. The initial +value of the key parameter is ignored. See DB->open +for more information. +

The DB_AFTER flag may not be specified to the Queue access method. +

If the current cursor record has already been deleted and the underlying +access method is Hash, DBcursor->c_put will return DB_NOTFOUND. +If the underlying access method is Btree or Recno, the operation will +succeed. +

If the cursor is not yet initialized or a duplicate sort function has been +specified, the DBcursor->c_put function will return EINVAL. +

DB_BEFORE
In the case of the Btree and Hash access methods, insert the data element +as a duplicate element of the key referenced by the cursor. The new +element appears immediately before the current cursor position. It is +an error to specify DB_BEFORE if the underlying Btree or Hash +database does not support duplicate data items. The key +parameter is ignored. +

In the case of the Recno access method, it is an error to specify +DB_BEFORE if the underlying Recno database was not created with +the DB_RENUMBER flag. If the DB_RENUMBER flag was +specified, a new key is created, the current record and all records +after it are automatically renumbered, and the key of the new record is +returned in the structure referenced by the parameter key. The +initial value of the key parameter is ignored. See +DB->open for more information. +

The DB_BEFORE flag may not be specified to the Queue access method. +

If the current cursor record has already been deleted and the underlying +access method is Hash, DBcursor->c_put will return DB_NOTFOUND. +If the underlying access method is Btree or Recno, the operation will +succeed. +

If the cursor is not yet initialized or a duplicate sort function has been +specified, DBcursor->c_put will return EINVAL. +

DB_CURRENT
Overwrite the data of the key/data pair referenced by the cursor with the +specified data item. The key parameter is ignored. +

If a duplicate sort function has been specified and the data item of the +current referenced key/data pair does not compare equally to the data +parameter, DBcursor->c_put will return EINVAL. +

If the current cursor record has already been deleted and the underlying +access method is Hash, DBcursor->c_put will return DB_NOTFOUND. +If the underlying access method is Btree, Queue or Recno, the operation +will succeed. +

If the cursor is not yet initialized, DBcursor->c_put will return EINVAL. +

DB_KEYFIRST
In the case of the Btree and Hash access methods, insert the specified +key/data pair into the database. +

If the underlying database supports duplicate data items, and if the +key already exists in the database and a duplicate sort function has +been specified, the inserted data item is added in its sorted location. +If the key already exists in the database and no duplicate sort function +has been specified, the inserted data item is added as the first of the +data items for that key. +

The DB_KEYFIRST flag may not be specified to the Queue or Recno +access methods. +

DB_KEYLAST
In the case of the Btree and Hash access methods, insert the specified +key/data pair into the database. +

If the underlying database supports duplicate data items, and if the +key already exists in the database and a duplicate sort function has +been specified, the inserted data item is added in its sorted location. +If the key already exists in the database, and no duplicate sort +function has been specified, the inserted data item is added as the last +of the data items for that key. +

The DB_KEYLAST flag may not be specified to the Queue or Recno +access methods. +

DB_NODUPDATA
In the case of the Btree and Hash access methods, insert the specified +key/data pair into the database unless it already exists in the database. +If the key/data pair already appears in the database, DB_KEYEXIST +is returned. The DB_NODUPDATA flag may only be specified if +the underlying database has been configured to support sorted duplicate +data items. +

The DB_NODUPDATA flag may not be specified to the Queue or Recno +access methods. +

+

Otherwise, the DBcursor->c_put function returns a non-zero error value on failure and 0 on success. +

If DBcursor->c_put fails for any reason, the state of the cursor will be +unchanged. If DBcursor->c_put succeeds and an item is inserted into the +database, the cursor is always positioned to reference the newly inserted +item. +

Errors

+

The DBcursor->c_put function may fail and return a non-zero error for the following conditions: +

+

DB_LOCK_DEADLOCK
The operation was selected to resolve a deadlock. +
+

+

EACCES
An attempt was made to modify a read-only database. +
+

+

EINVAL
An invalid flag value or parameter was specified. +

The DB_BEFORE or DB_AFTER flags were specified, and the +underlying access method is Queue. +

An attempt was made to add a record to a fixed-length database that was too +large to fit. +

+

+

EPERM
Write attempted on read-only cursor when the DB_INIT_CDB flag was +specified to DBENV->open. +
+

The DBcursor->c_put function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the DBcursor->c_put function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBcursor->c_close, +DBcursor->c_count, +DBcursor->c_del, +DBcursor->c_dup, +DBcursor->c_get +and +DBcursor->c_put. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/dbm.html b/db/docs/api_c/dbm.html new file mode 100644 index 000000000..783d59e62 --- /dev/null +++ b/db/docs/api_c/dbm.html @@ -0,0 +1,220 @@ + + + + + +Berkeley DB: dbm/ndbm + + + + + + + +
+

dbm/ndbm

+
+APIRef +
+


+ +

+#define DB_DBM_HSEARCH    1
+#include <db.h>
+

+typedef struct { + char *dptr; + int dsize; +} datum; +


+

Dbm Functions

+int +dbminit(char *file); +

+int +dbmclose(); +

+datum +fetch(datum key); +

+int +store(datum key, datum content); +

+int +delete(datum key); +

+datum +firstkey(void); +

+datum +nextkey(datum key); +


+

Ndbm Functions

+DBM * +dbm_open(char *file, int flags, int mode); +

+void +dbm_close(DBM *db); +

+datum +dbm_fetch(DBM *db, datum key); +

+int +dbm_store(DBM *db, datum key, datum content, int flags); +

+int +dbm_delete(DBM *db, datum key); +

+datum +dbm_firstkey(DBM *db); +

+datum +dbm_nextkey(DBM *db); +

+int +dbm_error(DBM *db); +

+int +dbm_clearerr(DBM *db); +

+

Description

+

The dbm interfaces to the Berkeley DB library are intended to provide +high-performance implementations and source code compatibility for +applications written to historic interfaces. They are not recommended +for any other purpose. The historic dbm database format +is not supported, and databases previously built using the real +dbm libraries cannot be read by the Berkeley DB functions. +

To compile dbm applications, replace the application's +#include of the dbm or ndbm include file (e.g., +#include <dbm.h> or #include <ndbm.h>) +with the following two lines: +

#define DB_DBM_HSEARCH    1
+#include <db.h>
+

and recompile. If the application attempts to load against a dbm library +(e.g., -ldbm), remove the library from the load line. +

Key and content arguments are objects described by the +datum typedef. A datum specifies a string of +dsize bytes pointed to by dptr. Arbitrary binary data, +as well as normal text strings, is allowed. +

Dbm Functions

+

Before a database can be accessed, it must be opened by dbminit. +This will open and/or create the database file.db. If created, +the database file is created read/write by owner only (as described in +chmod(2) and modified by the process' umask value at the time +of creation (see umask(2)). The group ownership of created +files is based on the system and directory defaults, and is not further +specified by Berkeley DB. +

A database may be closed, and any held resources released, by calling +dbmclose. +

Once open, the data stored under a key is accessed by fetch and +data is placed under a key by store. A key (and its associated +contents) is deleted by delete. A linear pass through all keys +in a database may be made, in an (apparently) random order, by use of +firstkey and nextkey. The firstkey function will return +the first key in the database. The nextkey function will return the next +key in the database. +

The following code will traverse the data base: +

for (key = firstkey();
+    key.dptr != NULL; key = nextkey(key)) {
+	...
+}
+

Ndbm Functions

+

Before a database can be accessed, it must be opened by dbm_open. +This will open and/or create the database file file.db depending +on the flags parameter (see open(2)). If created, the database +file is created with mode mode (as described in chmod(2)) and modified by the process' umask value at the time of creation (see +umask(2)). The group ownership of created files is based on +the system and directory defaults, and is not further specified by +Berkeley DB. +

Once open, the data stored under a key is accessed by dbm_fetch +and data is placed under a key by dbm_store. The flags +field can be either DBM_INSERT or DBM_REPLACE. +DBM_INSERT will only insert new entries into the database and will +not change an existing entry with the same key. DBM_REPLACE will +replace an existing entry if it has the same key. A key (and its +associated contents) is deleted by dbm_delete. A linear pass +through all keys in a database may be made, in an (apparently) random +order, by use of dbm_firstkey and dbm_nextkey. The +dbm_firstkey function will return the first key in the database. The +dbm_nextkey function will return the next key in the database. +

The following code will traverse the data base: +

for (key = dbm_firstkey(db);
+    key.dptr != NULL; key = dbm_nextkey(db)) {
+	...
+}
+

Compatibility Notes

+

The historic dbm library created two underlying database files, +traditionally named file.dir and file.pag. The Berkeley DB +library creates a single database file named file.db. +Applications that are aware of the underlying database file names may +require additional source code modifications. +

The historic dbminit interface required that the underlying +.dir and .pag files already exist (empty databases were +created by first manually creating zero-length .dir and +.pag files). Applications that expect to create databases using +this method may require additional source code modifications. +

The historic dbm_dirfno and dbm_pagfno macros are +supported, but will return identical file descriptors as there is only a +single underlying file used by the Berkeley DB hashing access method. +Applications using both file descriptors for locking may require +additional source code modifications. +

If applications using the dbm interface exits without first +closing the database, it may lose updates because the Berkeley DB library +buffers writes to underlying databases. Such applications will require +additional source code modifications to work correctly with the Berkeley DB +library. +

Dbm Diagnostics

+

The dbminit function returns -1 on failure, setting errno, +and 0 on success. +

The fetch function sets the dptr field of the returned +datum to NULL on failure, setting errno, +and returns a non-NULL dptr on success. +

The store function returns -1 on failure, setting errno, +and 0 on success. +

The delete function returns -1 on failure, setting errno, +and 0 on success. +

The firstkey function sets the dptr field of the returned +datum to NULL on failure, setting errno, +and returns a non-NULL dptr on success. +

The nextkey function sets the dptr field of the returned +datum to NULL on failure, setting errno, +and returns a non-NULL dptr on success. +

Errors

+

The dbminit, fetch, store, delete, firstkey and nextkey functions may fail +and return a non-zero error for errors specified for other Berkeley DB and C +library or system functions. +

Ndbm Diagnostics

+

The dbm_close function returns non-zero when an error has occurred reading or +writing the database. +

The dbm_close function resets the error condition on the named database. +

The dbm_open function returns NULL on failure, setting errno, +and 0 on success. +

The dbm_fetch function sets the dptr field of the returned +datum to NULL on failure, setting errno, +and returns a non-NULL dptr on success. +

The dbm_store function returns -1 on failure, setting errno, +0 on success, and 1 if DBM_INSERT was set and the specified key already +existed in the database. +

The dbm_delete function returns -1 on failure, setting errno, +and 0 on success. +

The dbm_firstkey function sets the dptr field of the returned +datum to NULL on failure, setting errno, +and returns a non-NULL dptr on success. +

The dbm_nextkey function sets the dptr field of the returned +datum to NULL on failure, setting errno, +and returns a non-NULL dptr on success. +

The dbm_close function returns -1 on failure, setting errno, +and 0 on success. +

The dbm_close function returns -1 on failure, setting errno, +and 0 on success. +

Errors

+

The dbm_open, dbm_close, dbm_fetch, dbm_store, dbm_delete, dbm_firstkey +and dbm_nextkey functions may fail and return a non-zero error for errors +specified for other Berkeley DB and C library or system functions. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/dbt.html b/db/docs/api_c/dbt.html new file mode 100644 index 000000000..a0c3e76db --- /dev/null +++ b/db/docs/api_c/dbt.html @@ -0,0 +1,158 @@ + + + + + +Berkeley DB: DBT + + + + + + +

Key/Data Pairs

+

Storage and retrieval for the Berkeley DB access methods are based on key/data +pairs. Both key and data items are represented by the DBT data structure. +(The name DBT is a mnemonic for data base thang, and was used +because no one could think of a reasonable name that wasn't already in +use somewhere else.) Key and data byte strings may reference strings of +zero length up to strings of essentially unlimited length. See +Database limits for more +information. +

typedef struct {
+	void *data;
+	u_int32_t size;
+	u_int32_t ulen;
+	u_int32_t dlen;
+	u_int32_t doff;
+	u_int32_t flags;
+} DBT;
+

In order to ensure compatibility with future releases of Berkeley DB, all fields +of the DBT structure that are not explicitly set should be initialized to +0 before the first time the structure is used. Do this by declaring the +structure external or static, or by calling the C library routine +bzero(3) or memset(3). +

By default, the flags structure element is expected to be 0. In +this default case, when the application is providing Berkeley DB a key or data +item to store into the database, Berkeley DB expects the data structure +element to point to a byte string of size bytes. When returning +a key/data item to the application, Berkeley DB will store into the data +structure element a pointer to a byte string of size bytes, and +the memory referenced by the pointer will be allocated and managed by Berkeley DB. +

The elements of the DBT structure are defined as follows: +

+

void *data;
A pointer to a byte string. +

u_int32_t size;
The length of data, in bytes. +

u_int32_t ulen;
The size of the user's buffer (referenced by data), in bytes. +This location is not written by the Berkeley DB functions. +

Note that applications can determine the length of a record by setting +the ulen field to 0 and checking the return value in the +size field. See the DB_DBT_USERMEM flag for more information. +

u_int32_t dlen;
The length of the partial record being read or written by the application, +in bytes. See the DB_DBT_PARTIAL flag for more information. +

u_int32_t doff;
The offset of the partial record being read or written by the application, +in bytes. See the DB_DBT_PARTIAL flag for more information. +

u_int32_t flags;
+

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +

+

DB_DBT_MALLOC
When this flag is set Berkeley DB will allocate memory for the returned key +or data item (using malloc(3), or the user-specified malloc +function) and return a pointer to it in the data field of the +key or data DBT structure. As any allocated memory becomes the +responsibility of the calling application, the caller must be able to +determine if memory was allocated. +

It is an error to specify more than one of DB_DBT_MALLOC, +DB_DBT_REALLOC and DB_DBT_USERMEM. +

DB_DBT_REALLOC
When this flag is set Berkeley DB will allocate memory for the returned key +or data item (using realloc(3), or the user-specified realloc +function) and return a pointer to it in the data field of the +key or data DBT structure. As any allocated memory becomes the +responsibility of the calling application, the caller must be able to +determine if memory was allocated. +

The difference between DB_DBT_MALLOC and DB_DBT_REALLOC +is that the latter will call realloc(3) instead of +malloc(3), so the allocated memory will be grown as necessary +instead of the application doing repeated free/malloc calls. +

It is an error to specify more than one of DB_DBT_MALLOC, +DB_DBT_REALLOC and DB_DBT_USERMEM. +

DB_DBT_USERMEM
The data field of the key or data structure must reference +memory that is at least ulen bytes in length. If the length of +the requested item is less than or equal to that number of bytes, the +item is copied into the memory referenced by the data field. +Otherwise, the size field is set to the length needed for the +requested item, and the error ENOMEM is returned. +

It is an error to specify more than one of DB_DBT_MALLOC, +DB_DBT_REALLOC and DB_DBT_USERMEM. +

DB_DBT_PARTIAL
Do partial retrieval or storage of an item. If the calling application +is doing a get, the dlen bytes starting doff bytes from +the beginning of the retrieved data record are returned as if they +comprised the entire record. If any or all of the specified bytes do +not exist in the record, the get is successful and the existing bytes +or nul bytes are returned. +

For example, if the data portion of a retrieved record was 100 bytes, +and a partial retrieval was done using a DBT having a dlen +field of 20 and a doff field of 85, the get call would succeed, +the data field would reference the last 15 bytes of the record, +and the size field would be set to 15. +

If the calling application is doing a put, the dlen bytes +starting doff bytes from the beginning of the specified key's +data record are replaced by the data specified by the data +and size structure elements. +If dlen is smaller than size, the record will grow, +and if dlen is larger than size, the record will shrink. +If the specified bytes do not exist, the record will be extended using +nul bytes as necessary, and the put call will succeed. +

It is an error to attempt a partial put using the DB->put function +in a database that supports duplicate records. +Partial puts in databases supporting duplicate records must be done +using a DBcursor->c_put function. +

It is an error to attempt a partial put with differing dlen and +size values in Queue or Recno databases with fixed-length records. +

For example, if the data portion of a retrieved record was 100 bytes, +and a partial put was done using a DBT having a dlen field of 20, +a doff field of 85, and a size field of 30, the resulting +record would be 115 bytes in length, where the last 30 bytes would be +those specified by the put call. +

+
+ +

Retrieved key/data permanence

+

When using the non-cursor Berkeley DB calls to retrieve key/data items (e.g., +DB->get), the memory referenced by the pointer stored into the +Dbt is only valid until the next call to Berkeley DB using the Db +handle returned by DB->open. (This includes any use of +the returned Db handle, including by another thread of control +within the process. For this reason, when multiple threads are using the +returned Db handle concurrently, one of the DB_DBT_MALLOC, +DB_DBT_REALLOC or DB_DBT_USERMEM flags must be specified +with any non-cursor Dbt used for key or data retrieval.) +

When using the cursor Berkeley DB calls to retrieve key/data items (e.g., +DBcursor->c_get), the memory referenced by the pointer into the +Dbt is only valid until the next call to Berkeley DB using the +DBC handle returned by DB->cursor. + +

Data alignment

+

The Berkeley DB access methods provide no guarantees about key/data byte string +alignment, and applications are responsible for arranging any necessary +alignment. The DB_DBT_MALLOC, DB_DBT_REALLOC and +DB_DBT_USERMEM flags may be used to store returned items in memory +of arbitrary alignment. + +

Logical Record Numbers

+

In all cases for the Queue and Recno access methods, and when calling the +DB->get and DBcursor->c_get functions with the +DB_SET_RECNO flag specified, the data field of the key +must be a pointer to a memory location of type db_recno_t, as +typedef'd in the #include <db.h> include file. This type is a 32-bit +unsigned type, (which limits the number of logical records in a Queue or +Recno database, and the maximum logical record which may be directly +retrieved from a Btree database, to 4,294,967,296). The size +field of the key should be the size of that type, i.e., in the C +programming language, sizeof(db_recno_t). +

Logical record numbers are 1-based, not 0-based, i.e., the first record +in the database is record number 1. + +

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/env_close.html b/db/docs/api_c/env_close.html new file mode 100644 index 000000000..fdb11e2e1 --- /dev/null +++ b/db/docs/api_c/env_close.html @@ -0,0 +1,84 @@ + + + + + +Berkeley DB: DBENV->close + + + + + + + +
+

DBENV->close

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DBENV->close(DB_ENV *dbenv, u_int32_t flags); +

+

Description

+

The DBENV->close function closes the Berkeley DB environment, freeing any +allocated resources and closing any underlying subsystems. +

Calling DBENV->close does not imply closing any databases that were +opened in the environment. +

The flags parameter is currently unused, and must be set to 0. +

Where the environment was initialized with the DB_INIT_LOCK flag, +calling DBENV->close does not release any locks still held by the +closing process, providing functionality for long-lived locks. +Processes that wish to have all their locks +released can do so by issuing the appropriate lock_vec call. +

Where the environment was initialized with the DB_INIT_MPOOL +flag, calling DBENV->close implies calls to memp_fclose for +any remaining open files in the memory pool that were returned to this +process by calls to memp_fopen. It does not imply a call to +memp_fsync for those files. +

Where the environment was initialized with the DB_INIT_TXN flag, +calling DBENV->close aborts any uncommitted transactions. +(Applications are should not depend on this behavior. If the process' has +already closed a database handle which is necessary to abort an +uncommitted transaction, the Berkeley DB environment must then require that +recovery be run before further operations are done, since once a +transaction exists that cannot be committed or aborted, no future +checkpoint can ever succeed.) +

In multi-threaded applications, only a single thread may call +DBENV->close. +

Once DBENV->close has been called, regardless of its return, +the Berkeley DB environment handle may not be accessed again. +

The DBENV->close function returns a non-zero error value on failure and 0 on success. +

Errors

+

The DBENV->close function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the DBENV->close function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBENV->close, +db_env_create, +DBENV->open, +DBENV->remove, +DBENV->err, +db_strerror, +db_version, +DBENV->set_cachesize, +DBENV->set_errcall, +DBENV->set_errfile, +DBENV->set_errpfx, +DBENV->set_flags, +DBENV->set_mutexlocks, +DBENV->set_paniccall, +and +DBENV->set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/env_create.html b/db/docs/api_c/env_create.html new file mode 100644 index 000000000..26ffb204e --- /dev/null +++ b/db/docs/api_c/env_create.html @@ -0,0 +1,74 @@ + + + + + +Berkeley DB: db_env_create + + + + + + + +
+

db_env_create

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +db_env_create(DB_ENV **dbenvp, u_int32_t flags); +

+

Description

+

The db_env_create function creates a DB_ENV structure which is +the handle for a Berkeley DB environment. A pointer to this structure is +returned in the memory referenced by dbenvp. +

The flags parameter must be set to 0 or the following value: +

+

DB_CLIENT
Create a client environment to connect to a server. +

The DB_CLIENT flag indicates to the system that this environment +is remote on a server. The use of this flag causes the environment +methods to use functions that call a server instead of local functions. +Prior to making any environment or database method calls, the application +must call the DBENV->set_server function to establish the +connection to the server. +

+

The DB_ENV handle contains a special field, "app_private", which +is declared as type "void *". This field is provided for the use of +the application program. It is initialized to NULL and is not further +used by Berkeley DB in any way. +

The db_env_create function returns a non-zero error value on failure and 0 on success. +

Errors

+

The db_env_create function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the db_env_create function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBENV->close, +db_env_create, +DBENV->open, +DBENV->remove, +DBENV->err, +db_strerror, +db_version, +DBENV->set_cachesize, +DBENV->set_errcall, +DBENV->set_errfile, +DBENV->set_errpfx, +DBENV->set_flags, +DBENV->set_mutexlocks, +DBENV->set_paniccall, +and +DBENV->set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/env_open.html b/db/docs/api_c/env_open.html new file mode 100644 index 000000000..677f40c15 --- /dev/null +++ b/db/docs/api_c/env_open.html @@ -0,0 +1,205 @@ + + + + + +Berkeley DB: DBENV->open + + + + + + + +
+

DBENV->open

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DBENV->open(DB_ENV *, char *db_home, u_int32_t flags, int mode); +

+

Description

+

The DBENV->open function is the interface for opening the Berkeley DB +environment. It provides a structure for creating a consistent +environment for processes using one or more of the features of Berkeley DB. +

The db_home argument to DBENV->open (and file name +resolution in general) is described in +Berkeley DB File Naming. +

The flags argument specifies the subsystems that are initialized +and how the application's environment affects Berkeley DB file naming, among +other things. +

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +

As there are a large number of flags that can be specified, they have been +grouped together by functionality. The first group of flags indicate +which of the Berkeley DB subsystems should be initialized: +

+

DB_JOINENV
Join an existing environment. This option allows applications to +join an existing environment without knowing which Berkeley DB subsystems +the environment supports. +

DB_INIT_CDB
Initialize locking for the Berkeley DB Concurrent Data Store +product. In this mode, Berkeley DB provides multiple reader/single writer +access. The only other subsystem that should be specified with the +DB_INIT_CDB flag is DB_INIT_MPOOL. +

Access method calls are largely unchanged when using this flag, although +any cursors through which update operations (e.g., DBcursor->c_put, +DBcursor->c_del) will be made must have the DB_WRITECURSOR value +set in the flags parameter to the cursor call that creates the cursor. +See DB->cursor for more information. +

DB_INIT_LOCK
Initialize the locking subsystem. This subsystem should be used when +multiple processes or threads are going to be reading and writing a Berkeley DB +database, so that they do not interfere with each other. If all threads +are accessing the database(s) read-only, then locking is unnecessary. +When the DB_INIT_LOCK flag is specified, it is usually necessary to run +the deadlock detector, as well. See db_deadlock and +lock_detect for more information. +

DB_INIT_LOG
Initialize the logging subsystem. This subsystem is used when recovery +from application or system failure is necessary. +

The log is stored in one or more files in the environment directory. +Each file is named using the format log.NNNNNNNNNN, where +NNNNNNNNNN is the sequence number of the file within the log. +For further information, see +Log File Limits. +

If the log region is being created and log files are already present, the +log files are reviewed and subsequent log writes are appended +to the end of the log, rather than overwriting current log entries. +

DB_INIT_MPOOL
Initialize the shared memory buffer pool subsystem. This subsystem is +used whenever the application is using any Berkeley DB access method. +

DB_INIT_TXN
Initialize the transaction subsystem. This subsystem is used when +recovery and atomicity of multiple operations and recovery are important. +The DB_INIT_TXN flag implies the DB_INIT_LOG flag. +
+

The second group of flags govern what recovery, if any, is performed when +the environment is initialized: +

+

DB_RECOVER
Run normal recovery on this environment before opening it for normal use. +If this flag is set, the DB_CREATE flag must also be set since the regions +will be removed and recreated. +

DB_RECOVER_FATAL
Run catastrophic recovery on this environment before opening it for normal +use. If this flag is set, the DB_CREATE flag must also be set since the +regions will be removed and recreated. +
+

A standard part of the recovery process is to remove the existing Berkeley DB +environment and create a new one in which to perform recovery. If the +thread of control performing recovery does not specify the correct region +initialization information (e.g., the correct memory pool cache size), +the result can be an application running in an environment with incorrect +cache and other subsystem sizes. For this reason, the thread of control +performing recovery should either specify correct configuration +information before calling the DBENV->open function, or it should remove +the environment after recovery is completed, leaving creation of the +correctly sized environment to a subsequent call to DBENV->open. +

All Berkeley DB recovery processing must be single-threaded, that is, only a +single thread of control may perform recovery or access a Berkeley DB +environment while recovery is being performed. As it is not an error to +specify DB_RECOVER for an environment for which no recovery is +required, it is reasonable programming practice for the thread of control +responsible for performing recovery and creating the environment to always +specify the DB_RECOVER flag during startup. +

The DBENV->open function returns successfully if DB_RECOVER +or DB_RECOVER_FATAL is specified and no log files exist, so it is +necessary to ensure all necessary log files are present before running +recovery. For further information, consult db_archive and +db_recover. +

The third group of flags govern file naming extensions in the environment: +

+ +

DB_USE_ENVIRON
The Berkeley DB process' environment may be permitted to specify information to +be used when naming files; see Berkeley DB +File Naming. As permitting users to specify which files are used can +create security problems, environment information will be used in file +naming for all users only if the DB_USE_ENVIRON flag is set. +

DB_USE_ENVIRON_ROOT
The Berkeley DB process' environment may be permitted to specify information to +be used when naming files; see Berkeley DB +File Naming. As permitting users to specify which files are used can +create security problems, if the DB_USE_ENVIRON_ROOT flag is set, +environment information will be used for file naming only for users with +appropriate permissions (e.g., on UNIX systems, users with a user-ID of 0). +
+

Finally, there are a few additional, unrelated flags: +

+

DB_CREATE
Cause Berkeley DB subsystems to create any underlying files, as necessary. +

DB_LOCKDOWN
Lock shared Berkeley DB environment files and memory mapped databases into memory. +

DB_PRIVATE
Specify that the environment will only be accessed by a single process +(although that process may be multi-threaded). This flag has two effects +on the Berkeley DB environment. First, all underlying data structures are +allocated from per-process memory instead of from shared memory that is +potentially accessible to more than a single process. Second, mutexes +are only configured to work between threads. +

This flag should not be specified if more than a single process is +accessing the environment, as it is likely to cause database corruption +and unpredictable behavior, e.g., if both a server application and the +Berkeley DB utility db_stat will access the environment, the +DB_PRIVATE flag should not be specified. +

DB_SYSTEM_MEM
Allocate memory from system shared memory instead of from memory backed +by the filesystem. See Shared Memory +Regions for more information. +

DB_THREAD
Cause the DB_ENV handle returned by DBENV->open to be +free-threaded, that is, useable by multiple threads within a +single address space. +
+

On UNIX systems, or in IEEE/ANSI Std 1003.1 (POSIX) environments, all files created by Berkeley DB +are created with mode mode (as described in chmod(2)) and +modified by the process' umask value at the time of creation (see +umask(2)). The group ownership of created files is based on +the system and directory defaults, and is not further specified by Berkeley DB. +If mode is 0, files are created readable and writeable by both +owner and group. On Windows systems, the mode argument is ignored. +

The DBENV->open function returns a non-zero error value on failure and 0 on success. +

Environment Variables

+

+

DB_HOME
The environment variable DB_HOME may be used as the path of +the database home as described in +Berkeley DB File Naming. +
+

Errors

+

The DBENV->open function may fail and return a non-zero error for the following conditions: +

+

EAGAIN
The shared memory region was locked and (repeatedly) unavailable. +
+

+

EINVAL
An invalid flag value or parameter was specified. +

+The DB_THREAD flag was specified and spinlocks are not +implemented for this architecture. +

The DB_HOME or TMPDIR environment variables were set but empty. +

An incorrectly formatted NAME VALUE entry or line was found. +

+

+

ENOSPC
HP-UX only: a previously created Berkeley DB environment for this process still +exists. +
+

The DBENV->open function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the DBENV->open function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBENV->close, +db_env_create, +DBENV->open, +DBENV->remove, +DBENV->err, +db_strerror, +db_version, +DBENV->set_cachesize, +DBENV->set_errcall, +DBENV->set_errfile, +DBENV->set_errpfx, +DBENV->set_flags, +DBENV->set_mutexlocks, +DBENV->set_paniccall, +and +DBENV->set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/env_remove.html b/db/docs/api_c/env_remove.html new file mode 100644 index 000000000..2d7279d79 --- /dev/null +++ b/db/docs/api_c/env_remove.html @@ -0,0 +1,125 @@ + + + + + +Berkeley DB: DBENV->remove + + + + + + + +
+

DBENV->remove

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DBENV->remove(DB_ENV *, char *db_home, u_int32_t flags); +

+

Description

+

The DBENV->remove function destroys a Berkeley DB environment, if it is not +currently in use. The environment regions, including any backing files, +are removed. Any log or database files and the environment directory are +not removed. +

The db_home argument to DBENV->remove is described in +Berkeley DB File Naming. +

If there are processes that have called DBENV->open without +calling DBENV->close (i.e., there are processes currently using +the environment), DBENV->remove will fail without further action, +unless the DB_FORCE flag is set, in which case +DBENV->remove will attempt to remove the environment regardless +of any processes still using it. +

The result of attempting to forcibly destroy the environment when it is +in use is unspecified. Processes using an environment often maintain open +file descriptors for shared regions within it. On UNIX systems, the +environment removal will usually succeed and processes that have already +joined the region will continue to run in that region without change, +however processes attempting to join the environment will either fail or +create new regions. On other systems (e.g., Windows/NT), where the +unlink(2) system call will fail if any process has an open +file descriptor for the file, the region removal will fail. +

Calling DBENV->remove should not be necessary for most applications, +as the Berkeley DB environment is cleaned up as part of normal database recovery +procedures, however, applications may wish to call DBENV->remove +as part of application shutdown to free up system resources. +Specifically, when the DB_SYSTEM_MEM flag was specified to +DBENV->open, it may be useful to call DBENV->remove in order +to release system shared memory segments that have been allocated. +

In the case of catastrophic or system failure, database recovery must be +performed (see db_recover), or the DB_RECOVER and +DB_RECOVER_FATAL flags to DBENV->open must be specified +when the environment is re-opened. Alternatively, if recovery is not +required because no database state is maintained across failures, and +the DB_SYSTEM_MEM flag was not specified when the environment +was created, it is possible to clean up an environment by removing all +of the files in the environment directory that begin with the string +prefix "__db", as no backing files are created in any other directory. +

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +

+

DB_FORCE
If the DB_FORCE flag is set, the environment is removed regardless +of any processes that may still using it, and, no locks are acquired +during this process. (Generally, the DB_FORCE flag is only +specified when applications were unable to shut down cleanly, and there +is a risk that an application may have died holding a Berkeley DB lock.) + +

DB_USE_ENVIRON
The Berkeley DB process' environment may be permitted to specify information to +be used when naming files; see Berkeley DB +File Naming. As permitting users to specify which files are used can +create security problems, environment information will be used in file +naming for all users only if the DB_USE_ENVIRON flag is set. +

DB_USE_ENVIRON_ROOT
The Berkeley DB process' environment may be permitted to specify information to +be used when naming files; see Berkeley DB +File Naming. As permitting users to specify which files are used can +create security problems, if the DB_USE_ENVIRON_ROOT flag is set, +environment information will be used for file naming only for users with +appropriate permissions (e.g., on UNIX systems, users with a user-ID of 0). +
+

In multi-threaded applications, only a single thread may call +DBENV->remove. +

A DB_ENV handle which has already been used to open an +environment should not be used to call the DBENV->remove function, a new +DB_ENV handle should be created for that purpose. +

Once DBENV->remove has been called, regardless of its return, +the Berkeley DB environment handle may not be accessed again. +

The DBENV->remove function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EBUSY
The shared memory region was in use and the force flag was not set. +
+

The DBENV->remove function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the DBENV->remove function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBENV->close, +db_env_create, +DBENV->open, +DBENV->remove, +DBENV->err, +db_strerror, +db_version, +DBENV->set_cachesize, +DBENV->set_errcall, +DBENV->set_errfile, +DBENV->set_errpfx, +DBENV->set_flags, +DBENV->set_mutexlocks, +DBENV->set_paniccall, +and +DBENV->set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/env_set_cachesize.html b/db/docs/api_c/env_set_cachesize.html new file mode 100644 index 000000000..ba7980bb7 --- /dev/null +++ b/db/docs/api_c/env_set_cachesize.html @@ -0,0 +1,87 @@ + + + + + + +Berkeley DB: DBENV->set_cachesize + + + + + + + +
+

DBENV->set_cachesize

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DBENV->set_cachesize(DB_ENV *dbenv, + u_int32_t gbytes, u_int32_t bytes, int ncache); +

+

Description

+

Set the size of the database's shared memory buffer pool, i.e., the cache, +to gbytes gigabytes plus bytes. The cache should be the +size of the normal working data set of the application, with some small +amount of additional memory for unusual situations. (Note, the working +set is not the same as the number of simultaneously referenced pages, and +should be quite a bit larger!) +

The default cache size is 256KB, and may not be specified as less than +20KB. Any cache size less than 500MB is automatically increased by 25% +to account for buffer pool overhead, cache sizes larger than 500MB are +used as specified. For information on tuning the Berkeley DB cache size, see +Selecting a cache size. +

It is possible to specify caches to Berkeley DB that are large enough so that +they cannot be allocated contiguously on some architectures, e.g., some +releases of Solaris limit the amount of memory that may be allocated +contiguously by a process. If ncache is 0 or 1, the cache will +be allocated contiguously in memory. If it is greater than 1, the cache +will be broken up into ncache equally sized separate pieces of +memory. +

The DBENV->set_cachesize interface may only be used to configure Berkeley DB before +the DBENV->open interface is called. +

The DBENV->set_cachesize function returns a non-zero error value on failure and 0 on success. +

The database environment's cache size may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_cachesize", one or more whitespace characters, +and the three arguments specified to this interface, separated by whitespace +characters, for example, "set_cachesize 1 500 2". Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DBENV->open was called. +

The specified cache size was impossibly small. +

+

See Also

+DBENV->close, +db_env_create, +DBENV->open, +DBENV->remove, +DBENV->err, +db_strerror, +db_version, +DBENV->set_cachesize, +DBENV->set_errcall, +DBENV->set_errfile, +DBENV->set_errpfx, +DBENV->set_flags, +DBENV->set_mutexlocks, +DBENV->set_paniccall, +and +DBENV->set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/env_set_data_dir.html b/db/docs/api_c/env_set_data_dir.html new file mode 100644 index 000000000..68db6dc47 --- /dev/null +++ b/db/docs/api_c/env_set_data_dir.html @@ -0,0 +1,77 @@ + + + + + +Berkeley DB: DBENV->set_data_dir + + + + + + + +
+

DBENV->set_data_dir

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DBENV->set_data_dir(DB_ENV *dbenv, const char *dir); +

+

Description

+

Set the path of a directory to be used as the location of the access +method database files. Paths specified to the DB->open function +will be searched relative to this path. Paths set using this interface +are additive, and specifying more than one will result in each specified +directory being searched for database files. If any directories are +specified, created database files will always be created in the first path +specified. +

If no database directories are specified, database files can only exist +in the environment home directory. See Berkeley DB File Naming for more information. +

For the greatest degree of recoverability from system or application +failure, database files and log files should be located on separate +physical devices. +

The DBENV->set_data_dir interface may only be used to configure Berkeley DB before +the DBENV->open interface is called. +

The DBENV->set_data_dir function returns a non-zero error value on failure and 0 on success. +

The database environment's data directory may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_data_dir", one or more whitespace characters, +and the directory name. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DBENV->open was called. +

+

See Also

+DBENV->close, +db_env_create, +DBENV->open, +DBENV->remove, +DBENV->err, +db_strerror, +db_version, +DBENV->set_cachesize, +DBENV->set_errcall, +DBENV->set_errfile, +DBENV->set_errpfx, +DBENV->set_flags, +DBENV->set_mutexlocks, +DBENV->set_paniccall, +and +DBENV->set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/env_set_errcall.html b/db/docs/api_c/env_set_errcall.html new file mode 100644 index 000000000..660943070 --- /dev/null +++ b/db/docs/api_c/env_set_errcall.html @@ -0,0 +1,73 @@ + + + + + + +Berkeley DB: DBENV->set_errcall + + + + + + + +
+

DBENV->set_errcall

+
+APIRef +
+


+ +

+#include <db.h>
+

+void +DBENV->set_errcall(DB_ENV *dbenv, + void (*db_errcall_fcn)(const char *errpfx, char *msg)); +

+

Description

+When an error occurs in the Berkeley DB library, a Berkeley DB error or an error +return value is returned by the function. In some cases, however, +the errno value may be insufficient to completely describe +the cause of the error especially during initial application debugging. +

The DBENV->set_errcall function is used to enhance the mechanism for reporting error +messages to the application. In some cases, when an error occurs, Berkeley DB +will call db_errcall_fcn with additional error information. The +function must be declared with two arguments; the first will be the prefix +string (as previously set by DB->set_errpfx or +DBENV->set_errpfx), the second will be the error message string. +It is up to the db_errcall_fcn function to display the error +message in an appropriate manner. +

Alternatively, you can use the DB->set_errfile or +DBENV->set_errfile functions to display the additional information +via a C library FILE *. +

This error logging enhancement does not slow performance or significantly +increase application size, and may be run during normal operation as well +as during application debugging. +

The DBENV->set_errcall interface may be used to configure Berkeley DB at any time +during the life of the application. +

See Also

+DBENV->close, +db_env_create, +DBENV->open, +DBENV->remove, +DBENV->err, +db_strerror, +db_version, +DBENV->set_cachesize, +DBENV->set_errcall, +DBENV->set_errfile, +DBENV->set_errpfx, +DBENV->set_flags, +DBENV->set_mutexlocks, +DBENV->set_paniccall, +and +DBENV->set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/env_set_errfile.html b/db/docs/api_c/env_set_errfile.html new file mode 100644 index 000000000..ba1dd75f2 --- /dev/null +++ b/db/docs/api_c/env_set_errfile.html @@ -0,0 +1,70 @@ + + + + + + +Berkeley DB: DBENV->set_errfile + + + + + + + +
+

DBENV->set_errfile

+
+APIRef +
+


+ +

+#include <db.h>
+

+void +DBENV->set_errfile(DB_ENV *dbenv, FILE *errfile); +

+

Description

+When an error occurs in the Berkeley DB library, a Berkeley DB error or an error +return value is returned by the function. In some cases, however, +the errno value may be insufficient to completely describe +the cause of the error especially during initial application debugging. +

The DBENV->set_errfile function is used to enhance the mechanism for reporting error +messages to the application by setting a C library FILE * to be used for +displaying additional Berkeley DB error messages. In some cases, when an error +occurs, Berkeley DB will output an additional error message to the specified +file reference. +

The error message will consist of the prefix string and a colon +(":") (if a prefix string was previously specified using +DB->set_errpfx or DBENV->set_errpfx), an error string, and +a trailing <newline> character. +

This error logging enhancement does not slow performance or significantly +increase application size, and may be run during normal operation as well +as during application debugging. +

The DBENV->set_errfile interface may be used to configure Berkeley DB at any time +during the life of the application. +

See Also

+DBENV->close, +db_env_create, +DBENV->open, +DBENV->remove, +DBENV->err, +db_strerror, +db_version, +DBENV->set_cachesize, +DBENV->set_errcall, +DBENV->set_errfile, +DBENV->set_errpfx, +DBENV->set_flags, +DBENV->set_mutexlocks, +DBENV->set_paniccall, +and +DBENV->set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/env_set_errpfx.html b/db/docs/api_c/env_set_errpfx.html new file mode 100644 index 000000000..be803070c --- /dev/null +++ b/db/docs/api_c/env_set_errpfx.html @@ -0,0 +1,59 @@ + + + + + +Berkeley DB: DBENV->set_errpfx + + + + + + + +
+

DBENV->set_errpfx

+
+APIRef +
+


+ +

+#include <db.h>
+

+void +DBENV->set_errpfx(DB_ENV *dbenv, const char *errpfx); +

+

Description

+

Set the prefix string that appears before error messages issued by Berkeley DB. +

The DBENV->set_errpfx function does not copy the memory referenced by the +errpfx argument, rather, it maintains a reference to it. This +allows applications to modify the error message prefix at any time, +without repeatedly calling DBENV->set_errpfx, but means that the +memory must be maintained until the handle is closed. +

The DBENV->set_errpfx interface may be used to configure Berkeley DB at any time +during the life of the application. +

See Also

+DBENV->close, +db_env_create, +DBENV->open, +DBENV->remove, +DBENV->err, +db_strerror, +db_version, +DBENV->set_cachesize, +DBENV->set_errcall, +DBENV->set_errfile, +DBENV->set_errpfx, +DBENV->set_flags, +DBENV->set_mutexlocks, +DBENV->set_paniccall, +and +DBENV->set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/env_set_feedback.html b/db/docs/api_c/env_set_feedback.html new file mode 100644 index 000000000..743f7772f --- /dev/null +++ b/db/docs/api_c/env_set_feedback.html @@ -0,0 +1,69 @@ + + + + + +Berkeley DB: DBENV->set_feedback + + + + + + + +
+

DBENV->set_feedback

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DBENV->set_feedback(DB_ENV *, + void (*db_feedback_fcn)(DB_ENV *, int opcode, int pct)); +

+

Description

+

Some operations performed by the Berkeley DB library can take non-trivial +amounts of time. The DBENV->set_feedback function can be used by +applications to monitor progress within these operations. +

When an operation is likely to take a long time, Berkeley DB will call the +specified callback function. This function must be declared with +three arguments: the first will be a reference to the enclosing +environment, the second a flag value, and the third the percent of the +operation that has been completed, specified as an integer value between +0 and 100. It is up to the callback function to display this +information in an appropriate manner. +

The opcode argument may take on any of the following values: +

+

DB_RECOVER
The environment is being recovered. +
+

The DBENV->set_feedback interface may be used to configure Berkeley DB at any time +during the life of the application. +

The DBENV->set_feedback function returns a non-zero error value on failure and 0 on success. +

See Also

+DBENV->close, +db_env_create, +DBENV->open, +DBENV->remove, +DBENV->err, +db_strerror, +db_version, +DBENV->set_cachesize, +DBENV->set_errcall, +DBENV->set_errfile, +DBENV->set_errpfx, +DBENV->set_flags, +DBENV->set_mutexlocks, +DBENV->set_paniccall, +and +DBENV->set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/env_set_flags.html b/db/docs/api_c/env_set_flags.html new file mode 100644 index 000000000..6dfc09508 --- /dev/null +++ b/db/docs/api_c/env_set_flags.html @@ -0,0 +1,84 @@ + + + + + +Berkeley DB: DBENV->set_flags + + + + + + + +
+

DBENV->set_flags

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DBENV->set_flags(DB_ENV *dbenv, u_int32_t flags, int onoff); +

+

Description

+

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +If onoff is zero, the specified flags are cleared, otherwise they +are set. +

+

DB_CDB_ALLDB
For Berkeley DB Concurrent Data Store applications, perform locking on an environment-wide basis +rather than per-database. This flag may only be used to configure Berkeley DB +before the DBENV->open interface is called. +

DB_NOMMAP
Copy read-only database files in this environment into the local cache +instead of potentially mapping them into process memory (see the +description of the DBENV->set_mp_mmapsize function for further information). +

DB_TXN_NOSYNC
Do not synchronously flush the log on transaction commit or prepare. +This means that transactions exhibit the ACI (atomicity, consistency and +isolation) properties, but not D (durability), i.e., database integrity +will be maintained but it is possible that some number of the most +recently committed transactions may be undone during recovery instead of +being redone. +

The number of transactions that are potentially at risk is governed by +how often the log is checkpointed (see db_checkpoint for more +information) and how many log updates can fit on a single log page. +

+

The DBENV->set_flags function returns a non-zero error value on failure and 0 on success. +

The database environment's flag values may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_flags", one or more whitespace characters, +and the interface flag argument as a string, for example, "set_flags +DB_TXN_NOSYNC". Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

See Also

+DBENV->close, +db_env_create, +DBENV->open, +DBENV->remove, +DBENV->err, +db_strerror, +db_version, +DBENV->set_cachesize, +DBENV->set_errcall, +DBENV->set_errfile, +DBENV->set_errpfx, +DBENV->set_flags, +DBENV->set_mutexlocks, +DBENV->set_paniccall, +and +DBENV->set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/env_set_lg_bsize.html b/db/docs/api_c/env_set_lg_bsize.html new file mode 100644 index 000000000..85e6dc121 --- /dev/null +++ b/db/docs/api_c/env_set_lg_bsize.html @@ -0,0 +1,68 @@ + + + + + +Berkeley DB: DBENV->set_lg_bsize + + + + + + + +
+

DBENV->set_lg_bsize

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DBENV->set_lg_bsize(DB_ENV *dbenv, u_int32_t lg_bsize); +

+

Description

+

Set the size of the in-memory log buffer, in bytes. By default, or if +the value is set to 0, a size of 32K is used. +

Log information is stored in-memory until the storage space fills up +or transaction commit forces the information to be flushed to stable +storage. In the presence of long-running transactions or transactions +producing large amounts of data, larger buffer sizes can increase +throughput. +

The DBENV->set_lg_bsize interface may only be used to configure Berkeley DB before +the DBENV->open interface is called. +

The DBENV->set_lg_bsize function returns a non-zero error value on failure and 0 on success. +

The database environment's log buffer size may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_lg_bsize", one or more whitespace characters, +and the size in bytes. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DBENV->open was called. +

+

See Also

+DBENV->set_lg_bsize, +DBENV->set_lg_max, +log_archive, +log_compare, +log_file, +log_flush, +log_get, +log_put, +log_register, +log_stat +and +log_unregister. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/env_set_lg_dir.html b/db/docs/api_c/env_set_lg_dir.html new file mode 100644 index 000000000..a8d5c8614 --- /dev/null +++ b/db/docs/api_c/env_set_lg_dir.html @@ -0,0 +1,73 @@ + + + + + +Berkeley DB: DBENV->set_lg_dir + + + + + + + +
+

DBENV->set_lg_dir

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DBENV->set_lg_dir(DB_ENV *dbenv, const char *dir); +

+

Description

+

The path of a directory to be used as the location of logging files. +Log files created by the Log Manager subsystem will be created in this +directory. +

If no logging directory is specified, log files are created in the +environment home directory. See Berkeley DB File Naming for more information. +

For the greatest degree of recoverability from system or application +failure, database files and log files should be located on separate +physical devices. +

The DBENV->set_lg_dir interface may only be used to configure Berkeley DB before +the DBENV->open interface is called. +

The DBENV->set_lg_dir function returns a non-zero error value on failure and 0 on success. +

The database environment's logging directory may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_lg_dir", one or more whitespace characters, +and the directory name. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DBENV->open was called. +

+

See Also

+DBENV->close, +db_env_create, +DBENV->open, +DBENV->remove, +DBENV->err, +db_strerror, +db_version, +DBENV->set_cachesize, +DBENV->set_errcall, +DBENV->set_errfile, +DBENV->set_errpfx, +DBENV->set_flags, +DBENV->set_mutexlocks, +DBENV->set_paniccall, +and +DBENV->set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/env_set_lg_max.html b/db/docs/api_c/env_set_lg_max.html new file mode 100644 index 000000000..4625db434 --- /dev/null +++ b/db/docs/api_c/env_set_lg_max.html @@ -0,0 +1,68 @@ + + + + + +Berkeley DB: DBENV->set_lg_max + + + + + + + +
+

DBENV->set_lg_max

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DBENV->set_lg_max(DB_ENV *dbenv, u_int32_t lg_max); +

+

Description

+

Set the maximum size of a single file in the log, in bytes. Because +DB_LSN file offsets are unsigned 4-byte values, the set value may +not be larger than the maximum unsigned 4-byte value. By default, or if +the value is set to 0, a size of 10MB is used. +

See Log File Limits +for more information. +

The DBENV->set_lg_max interface may only be used to configure Berkeley DB before +the DBENV->open interface is called. +

The DBENV->set_lg_max function returns a non-zero error value on failure and 0 on success. +

The database environment's log file size may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_lg_max", one or more whitespace characters, +and the size in bytes. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DBENV->open was called. +

The specified log file size was too large. +

+

See Also

+DBENV->set_lg_bsize, +DBENV->set_lg_max, +log_archive, +log_compare, +log_file, +log_flush, +log_get, +log_put, +log_register, +log_stat +and +log_unregister. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/env_set_lk_conflicts.html b/db/docs/api_c/env_set_lk_conflicts.html new file mode 100644 index 000000000..689464736 --- /dev/null +++ b/db/docs/api_c/env_set_lk_conflicts.html @@ -0,0 +1,69 @@ + + + + + +Berkeley DB: DBENV->set_lk_conflicts + + + + + + + +
+

DBENV->set_lk_conflicts

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DBENV->set_lk_conflicts(DB_ENV *dbenv, + u_int8_t *conflicts, int nmodes); +

+

Description

+

Set the locking conflicts matrix. +The conflicts argument +is an nmodes by nmodes array. +A non-0 value for the array element: +

conflicts[requested_mode][held_mode]
+

indicates that requested_mode and held_mode conflict. The +not-granted mode must be represented by 0. +

If no conflicts value is specified, the conflicts array +db_rw_conflicts is used; see Standard Lock Modes for a description of that array. +

The DBENV->set_lk_conflicts interface may only be used to configure Berkeley DB before +the DBENV->open interface is called. +

The DBENV->set_lk_conflicts function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DBENV->open was called. +

+

+

ENOMEM
No memory was available to copy the conflicts array. +
+

See Also

+DBENV->set_lk_conflicts, +DBENV->set_lk_detect, +DBENV->set_lk_max_locks, +DBENV->set_lk_max_lockers, +DBENV->set_lk_max_objects, +DBENV->set_lk_max, +lock_detect, +lock_get, +lock_id, +lock_put, +lock_stat +and +lock_vec. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/env_set_lk_detect.html b/db/docs/api_c/env_set_lk_detect.html new file mode 100644 index 000000000..460651a0d --- /dev/null +++ b/db/docs/api_c/env_set_lk_detect.html @@ -0,0 +1,72 @@ + + + + + +Berkeley DB: DBENV->set_lk_detect + + + + + + + +
+

DBENV->set_lk_detect

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DBENV->set_lk_detect(DB_ENV *dbenv, u_int32_t detect); +

+

Description

+

Set if the deadlock detector is to be run whenever a lock conflict occurs, +and specify which transaction should be aborted in the case of a deadlock. +The specified value must be one of the following list: +

+

DB_LOCK_DEFAULT
Use the default policy as specified by db_deadlock. +
DB_LOCK_OLDEST
Abort the oldest transaction. +
DB_LOCK_RANDOM
Abort a random transaction involved in the deadlock. +
DB_LOCK_YOUNGEST
Abort the youngest transaction. +
+

The DBENV->set_lk_detect interface may only be used to configure Berkeley DB before +the DBENV->open interface is called. +

The DBENV->set_lk_detect function returns a non-zero error value on failure and 0 on success. +

The database environment's deadlock detector configuration may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_lk_detect", one or more whitespace characters, +and the interface detect argument as a string, for example, +"set_lk_detect DB_LOCK_OLDEST". Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DBENV->open was called. +

+

See Also

+DBENV->set_lk_conflicts, +DBENV->set_lk_detect, +DBENV->set_lk_max_locks, +DBENV->set_lk_max_lockers, +DBENV->set_lk_max_objects, +DBENV->set_lk_max, +lock_detect, +lock_get, +lock_id, +lock_put, +lock_stat +and +lock_vec. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/env_set_lk_max.html b/db/docs/api_c/env_set_lk_max.html new file mode 100644 index 000000000..1e9832b59 --- /dev/null +++ b/db/docs/api_c/env_set_lk_max.html @@ -0,0 +1,72 @@ + + + + + +Berkeley DB: DBENV->set_lk_max + + + + + + + +
+

DBENV->set_lk_max

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DBENV->set_lk_max(DB_ENV *dbenv, u_int32_t max); +

+

Description

+

The DBENV->set_lk_max function interface has been deprecated in favor of +the DBENV->set_lk_max_locks, DBENV->set_lk_max_lockers, +and DBENV->set_lk_max_objects functions. Please update your applications. +

Set each of the maximum number of locks, lockers and lock objects +supported by the Berkeley DB lock subsystem to max. This value is +used by DBENV->open to estimate how much space to allocate for +various lock-table data structures. For specific information on +configuring the size of the lock subsystem, see +Configuring locking: sizing the +system. +

The DBENV->set_lk_max interface may only be used to configure Berkeley DB before +the DBENV->open interface is called. +

The DBENV->set_lk_max function returns a non-zero error value on failure and 0 on success. +

The database environment's maximum number of locks may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_lk_max", one or more whitespace characters, +and the number of locks. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DBENV->open was called. +

+

See Also

+DBENV->set_lk_conflicts, +DBENV->set_lk_detect, +DBENV->set_lk_max_locks, +DBENV->set_lk_max_lockers, +DBENV->set_lk_max_objects, +DBENV->set_lk_max, +lock_detect, +lock_get, +lock_id, +lock_put, +lock_stat +and +lock_vec. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/env_set_lk_max_lockers.html b/db/docs/api_c/env_set_lk_max_lockers.html new file mode 100644 index 000000000..e41a943fd --- /dev/null +++ b/db/docs/api_c/env_set_lk_max_lockers.html @@ -0,0 +1,68 @@ + + + + + +Berkeley DB: DBENV->set_lk_max_lockers + + + + + + + +
+

DBENV->set_lk_max_lockers

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DBENV->set_lk_max_lockers(DB_ENV *dbenv, u_int32_t max); +

+

Description

+

Set the maximum number of simultaneous locking entities supported by +the Berkeley DB lock subsystem. This value is used by DBENV->open to +estimate how much space to allocate for various lock-table data +structures. For specific information on configuring the size of the +lock subsystem, see +Configuring locking: sizing the system. +

The DBENV->set_lk_max_lockers interface may only be used to configure Berkeley DB before +the DBENV->open interface is called. +

The DBENV->set_lk_max_lockers function returns a non-zero error value on failure and 0 on success. +

The database environment's maximum number of lockers may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_lk_max_lockers", one or more whitespace characters, +and the number of lockers. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DBENV->open was called. +

+

See Also

+DBENV->set_lk_conflicts, +DBENV->set_lk_detect, +DBENV->set_lk_max_locks, +DBENV->set_lk_max_lockers, +DBENV->set_lk_max_objects, +DBENV->set_lk_max, +lock_detect, +lock_get, +lock_id, +lock_put, +lock_stat +and +lock_vec. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/env_set_lk_max_locks.html b/db/docs/api_c/env_set_lk_max_locks.html new file mode 100644 index 000000000..a908b288f --- /dev/null +++ b/db/docs/api_c/env_set_lk_max_locks.html @@ -0,0 +1,67 @@ + + + + + +Berkeley DB: DBENV->set_lk_max_locks + + + + + + + +
+

DBENV->set_lk_max_locks

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DBENV->set_lk_max_locks(DB_ENV *dbenv, u_int32_t max); +

+

Description

+

Set the maximum number of locks supported by the Berkeley DB lock subsystem. +This value is used by DBENV->open to estimate how much space to +allocate for various lock-table data structures. For specific +information on configuring the size of the lock subsystem, see +Configuring locking: sizing the system. +

The DBENV->set_lk_max_locks interface may only be used to configure Berkeley DB before +the DBENV->open interface is called. +

The DBENV->set_lk_max_locks function returns a non-zero error value on failure and 0 on success. +

The database environment's maximum number of locks may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_lk_max_locks", one or more whitespace characters, +and the number of locks. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DBENV->open was called. +

+

See Also

+DBENV->set_lk_conflicts, +DBENV->set_lk_detect, +DBENV->set_lk_max_locks, +DBENV->set_lk_max_lockers, +DBENV->set_lk_max_objects, +DBENV->set_lk_max, +lock_detect, +lock_get, +lock_id, +lock_put, +lock_stat +and +lock_vec. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/env_set_lk_max_objects.html b/db/docs/api_c/env_set_lk_max_objects.html new file mode 100644 index 000000000..8fba15876 --- /dev/null +++ b/db/docs/api_c/env_set_lk_max_objects.html @@ -0,0 +1,68 @@ + + + + + +Berkeley DB: DBENV->set_lk_max_objects + + + + + + + +
+

DBENV->set_lk_max_objects

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DBENV->set_lk_max_objects(DB_ENV *dbenv, u_int32_t max); +

+

Description

+

Set the maximum number of simultaneously locked objects supported by +the Berkeley DB lock subsystem. This value is used by DBENV->open to +estimate how much space to allocate for various lock-table data +structures. For specific information on configuring the size of the +lock subsystem, see +Configuring locking: sizing the system. +

The DBENV->set_lk_max_objects interface may only be used to configure Berkeley DB before +the DBENV->open interface is called. +

The DBENV->set_lk_max_objects function returns a non-zero error value on failure and 0 on success. +

The database environment's maximum number of objects may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_lk_max_objects", one or more whitespace characters, +and the number of objects. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DBENV->open was called. +

+

See Also

+DBENV->set_lk_conflicts, +DBENV->set_lk_detect, +DBENV->set_lk_max_locks, +DBENV->set_lk_max_lockers, +DBENV->set_lk_max_objects, +DBENV->set_lk_max, +lock_detect, +lock_get, +lock_id, +lock_put, +lock_stat +and +lock_vec. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/env_set_mp_mmapsize.html b/db/docs/api_c/env_set_mp_mmapsize.html new file mode 100644 index 000000000..3f87a140a --- /dev/null +++ b/db/docs/api_c/env_set_mp_mmapsize.html @@ -0,0 +1,71 @@ + + + + + +Berkeley DB: DBENV->set_mp_mmapsize + + + + + + + +
+

DBENV->set_mp_mmapsize

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DBENV->set_mp_mmapsize(DB_ENV *dbenv, size_t mp_mmapsize); +

+

Description

+

Files that are opened read-only in the pool (and that satisfy a few other +criteria) are, by default, mapped into the process address space instead +of being copied into the local cache. This can result in better-than-usual +performance, as available virtual memory is normally much larger than the +local cache, and page faults are faster than page copying on many systems. +However, in the presence of limited virtual memory it can cause resource +starvation, and in the presence of large databases, it can result in immense +process sizes. +

Set the maximum file size, in bytes, for a file to be mapped into the +process address space. If no value is specified, it defaults to 10MB. +

The DBENV->set_mp_mmapsize interface may only be used to configure Berkeley DB before +the DBENV->open interface is called. +

The DBENV->set_mp_mmapsize function returns a non-zero error value on failure and 0 on success. +

The database environment's maximum mapped file size may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_mp_mmapsize", one or more whitespace characters, +and the size in bytes. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DBENV->open was called. +

+

See Also

+DBENV->set_mp_mmapsize, +memp_fclose, +memp_fget, +memp_fopen, +memp_fput, +memp_fset, +memp_fsync, +memp_register, +memp_stat, +memp_sync +and +memp_trickle. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/env_set_mutexlocks.html b/db/docs/api_c/env_set_mutexlocks.html new file mode 100644 index 000000000..a5fa2aa34 --- /dev/null +++ b/db/docs/api_c/env_set_mutexlocks.html @@ -0,0 +1,59 @@ + + + + + +Berkeley DB: DBENV->set_mutexlocks + + + + + + + +
+

DBENV->set_mutexlocks

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DBENV->set_mutexlocks(DB_ENV *dbenv, int do_lock); +

+

Description

+

Toggle mutex locks. Setting do_lock to a zero value causes +Berkeley DB to grant all requested mutual exclusion mutexes without regard +for their availability. +

This functionality should never be used for any other purpose than +debugging. +

The DBENV->set_mutexlocks interface may be used to configure Berkeley DB at any time +during the life of the application. +

The DBENV->set_mutexlocks function returns a non-zero error value on failure and 0 on success. +

See Also

+DBENV->close, +db_env_create, +DBENV->open, +DBENV->remove, +DBENV->err, +db_strerror, +db_version, +DBENV->set_cachesize, +DBENV->set_errcall, +DBENV->set_errfile, +DBENV->set_errpfx, +DBENV->set_flags, +DBENV->set_mutexlocks, +DBENV->set_paniccall, +and +DBENV->set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/env_set_pageyield.html b/db/docs/api_c/env_set_pageyield.html new file mode 100644 index 000000000..953724085 --- /dev/null +++ b/db/docs/api_c/env_set_pageyield.html @@ -0,0 +1,68 @@ + + + + + +Berkeley DB: db_env_set_pageyield + + + + + + + +
+

db_env_set_pageyield

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +db_env_set_pageyield(int pageyield); +

+

Description

+

Yield the processor whenever requesting a page from the cache. Setting +pageyield to a non-zero value causes Berkeley DB to yield the processor +any time a thread requests a page from the cache. +

The db_env_set_pageyield interface affects the entire application, not a single +database or database environment. +

While the db_env_set_pageyield interface may be used to configure Berkeley DB at any time +during the life of the application, it should normally be called before +making any calls to the db_env_create or db_create functions. +

This functionality should never be used for any other purpose than stress +testing. +

The db_env_set_pageyield interface may be used to configure Berkeley DB at any time +during the life of the application. +

The db_env_set_pageyield function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

See Also

+DBENV->close, +db_env_create, +DBENV->open, +DBENV->remove, +DBENV->err, +db_strerror, +db_version, +DBENV->set_cachesize, +DBENV->set_errcall, +DBENV->set_errfile, +DBENV->set_errpfx, +DBENV->set_flags, +DBENV->set_mutexlocks, +DBENV->set_paniccall, +and +DBENV->set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/env_set_paniccall.html b/db/docs/api_c/env_set_paniccall.html new file mode 100644 index 000000000..a9d58a80b --- /dev/null +++ b/db/docs/api_c/env_set_paniccall.html @@ -0,0 +1,67 @@ + + + + + + +Berkeley DB: DBENV->set_paniccall + + + + + + + +
+

DBENV->set_paniccall

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DBENV->set_paniccall(DB_ENV *dbenv, + void (*paniccall)(DB_ENV *, int errval)); +

+

Description

+

Errors can occur in the Berkeley DB library where the only solution is to shut +down the application and run recovery. (For example, if Berkeley DB is unable +to write log records to disk because there is insufficient disk space.) +In these cases, the value DB_RUNRECOVERY is returned by Berkeley DB. +

In these cases, it is also often simpler to shut down the application when +such errors occur rather than attempting to gracefully return up the stack. +The DBENV->set_paniccall function is used to specify a function to be called when +DB_RUNRECOVERY is about to be returned from a Berkeley DB method. When +called, the dbenv argument will be a reference to the current +environment, and the errval argument is the error value that would +have been returned to the calling function. +

The DBENV->set_paniccall interface may be used to configure Berkeley DB at any time +during the life of the application. +

The DBENV->set_paniccall function returns a non-zero error value on failure and 0 on success. +

See Also

+DBENV->close, +db_env_create, +DBENV->open, +DBENV->remove, +DBENV->err, +db_strerror, +db_version, +DBENV->set_cachesize, +DBENV->set_errcall, +DBENV->set_errfile, +DBENV->set_errpfx, +DBENV->set_flags, +DBENV->set_mutexlocks, +DBENV->set_paniccall, +and +DBENV->set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/env_set_panicstate.html b/db/docs/api_c/env_set_panicstate.html new file mode 100644 index 000000000..6168ad9af --- /dev/null +++ b/db/docs/api_c/env_set_panicstate.html @@ -0,0 +1,64 @@ + + + + + +Berkeley DB: db_env_set_panicstate + + + + + + + +
+

db_env_set_panicstate

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +db_env_set_panicstate(int panic); +

+

Description

+

Toggle the Berkeley DB panic state. Setting panic to a non-zero value +causes Berkeley DB to refuse attempts to call Berkeley DB functions with the +DB_RUNRECOVERY error return. +

The db_env_set_panicstate interface affects the entire application, not a single +database or database environment. +

While the db_env_set_panicstate interface may be used to configure Berkeley DB at any time +during the life of the application, it should normally be called before +making any calls to the db_env_create or db_create functions. +

The db_env_set_panicstate function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

See Also

+DBENV->close, +db_env_create, +DBENV->open, +DBENV->remove, +DBENV->err, +db_strerror, +db_version, +DBENV->set_cachesize, +DBENV->set_errcall, +DBENV->set_errfile, +DBENV->set_errpfx, +DBENV->set_flags, +DBENV->set_mutexlocks, +DBENV->set_paniccall, +and +DBENV->set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/env_set_rec_init.html b/db/docs/api_c/env_set_rec_init.html new file mode 100644 index 000000000..056ec9b71 --- /dev/null +++ b/db/docs/api_c/env_set_rec_init.html @@ -0,0 +1,71 @@ + + + + + +Berkeley DB: DBENV->set_recovery_init + + + + + + + +
+

DBENV->set_recovery_init

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DBENV->set_recovery_init(DB_ENV *, + int (*db_recovery_init_fcn)(DB_ENV *)); +

+

Description

+

Applications installing application-specific recovery functions need +to be called before Berkeley DB performs recovery so they may add their recovery +functions to Berkeley DB's. +

The DBENV->set_recovery_init function supports this functionality. The +db_recovery_init_fcn function must be declared with one +argument, a reference to the enclosing Berkeley DB environment. This +function will be called after the DBENV->open has been called, +but before recovery is started. +

If the db_recovery_init_fcn function returns a non-zero value, +no recovery will be performed and DBENV->open will return the same +value to its caller. +

The DBENV->set_recovery_init interface may only be used to configure Berkeley DB before +the DBENV->open interface is called. +

The DBENV->set_recovery_init function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DBENV->open was called. +

+

See Also

+DBENV->close, +db_env_create, +DBENV->open, +DBENV->remove, +DBENV->err, +db_strerror, +db_version, +DBENV->set_cachesize, +DBENV->set_errcall, +DBENV->set_errfile, +DBENV->set_errpfx, +DBENV->set_flags, +DBENV->set_mutexlocks, +DBENV->set_paniccall, +and +DBENV->set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/env_set_region_init.html b/db/docs/api_c/env_set_region_init.html new file mode 100644 index 000000000..3c83680ad --- /dev/null +++ b/db/docs/api_c/env_set_region_init.html @@ -0,0 +1,77 @@ + + + + + +Berkeley DB: db_env_set_region_init + + + + + + + +
+

db_env_set_region_init

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +db_env_set_region_init(int region_init); +

+

Description

+

Page-fault shared regions into memory when initially creating or joining +a Berkeley DB environment. In some applications, the expense of page-faulting +the shared memory regions can affect performance, e.g., when the +page-fault occurs while holding a lock, other lock requests can convoy +and overall throughput may decrease. Setting region_init to a +non-zero value specifies that shared regions be read or written, as +appropriate, when the region is joined by the application. This forces +the underlying virtual memory and file systems to instantiate both the +necessary memory and the necessary disk space. This can also avoid +out-of-disk space failures later on. +

The db_env_set_region_init interface affects the entire application, not a single +database or database environment. +

While the db_env_set_region_init interface may be used to configure Berkeley DB at any time +during the life of the application, it should normally be called before +making any calls to the db_env_create or db_create functions. +

The db_env_set_region_init function returns a non-zero error value on failure and 0 on success. +

The database environment's initial behavior with respect to shared memory regions may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_region_init", one or more whitespace characters, +and the string "1". Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

See Also

+DBENV->close, +db_env_create, +DBENV->open, +DBENV->remove, +DBENV->err, +db_strerror, +db_version, +DBENV->set_cachesize, +DBENV->set_errcall, +DBENV->set_errfile, +DBENV->set_errpfx, +DBENV->set_flags, +DBENV->set_mutexlocks, +DBENV->set_paniccall, +and +DBENV->set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/env_set_server.html b/db/docs/api_c/env_set_server.html new file mode 100644 index 000000000..586887bfc --- /dev/null +++ b/db/docs/api_c/env_set_server.html @@ -0,0 +1,77 @@ + + + + + +Berkeley DB: DBENV->set_server + + + + + + + +
+

DBENV->set_server

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DBENV->set_server(DB_ENV *dbenv, char *host, + long cl_timeout, long sv_timeout, u_int32_t flags); +

+

Description

+

Connects to the DB server on the indicated hostname and sets up a channel +for communication. +

The cl_timeout argument specifies the number of seconds the client +should wait for results to come back from the server. Once the timeout +has expired on any communication with the server, DB_NOSERVER will +be returned. If this value is zero, a default timeout is used. +

The sv_timeout argument specifies the number of seconds the server +should allow a client connection to remain idle before assuming that +client is gone. Once that timeout has been reached, the server releases +all resources associated with that client connection. Subsequent attempts +by that client to communicate with the server result in +DB_NOSERVER_ID indicating that an invalid identifier has been +given to the server. This value can be considered a hint to the server. +The server may alter this value based on its own policies or allowed +values. If this value is zero, a default timeout is used. +

The flags parameter is currently unused, and must be set to 0. +

When the DBENV->set_server function has been called, any subsequent calls +to Berkeley DB library interfaces may return either DB_NOSERVER or +DB_NOSERVER_ID. +

The DBENV->set_server function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

dbenv_set_server +

+

See Also

+DBENV->close, +db_env_create, +DBENV->open, +DBENV->remove, +DBENV->err, +db_strerror, +db_version, +DBENV->set_cachesize, +DBENV->set_errcall, +DBENV->set_errfile, +DBENV->set_errpfx, +DBENV->set_flags, +DBENV->set_mutexlocks, +DBENV->set_paniccall, +and +DBENV->set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/env_set_shm_key.html b/db/docs/api_c/env_set_shm_key.html new file mode 100644 index 000000000..8de32ed84 --- /dev/null +++ b/db/docs/api_c/env_set_shm_key.html @@ -0,0 +1,87 @@ + + + + + +Berkeley DB: DBENV->set_shm_key + + + + + + + +
+

DBENV->set_shm_key

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DBENV->set_shm_key(DB_ENV *dbenv, long shm_key); +

+

Description

+

Specify a base segment ID for Berkeley DB environment shared memory regions +created in system memory on VxWorks or systems supporting X/Open-style +shared memory interfaces, e.g., UNIX systems supporting +shmget(2) and related System V IPC interfaces. +

This base segment ID will be used when Berkeley DB shared memory regions are +first created. It will be incremented a small integer value each time +a new shared memory region is created, that is, if the base ID is 35, +the first shared memory region created will have a segment ID of 35 and +the next one a segment ID between 36 and 40 or so. A Berkeley DB environment +always creates a master shared memory region, plus an additional shared +memory region for each of the subsystems supported by the environment +(locking, logging, memory pool and transaction), plus an additional +shared memory region for each additional memory pool cache that is +supported. Already existing regions with the same segment IDs will be +removed. See Shared Memory Regions +for more information. +

The intent behind this interface is two-fold: without it, applications +have no way to ensure that two Berkeley DB applications don't attempt to use +the same segment IDs when creating different Berkeley DB environments. In +addition, by using the same segment IDs each time the environment is +created, previously created segments will be removed, and the set of +segments on the system will not grow without bound. +

The DBENV->set_shm_key interface may only be used to configure Berkeley DB before +the DBENV->open interface is called. +

The DBENV->set_shm_key function returns a non-zero error value on failure and 0 on success. +

The database environment's base segment ID may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_shm_key", one or more whitespace characters, +and the ID. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DBENV->open was called. +

+

See Also

+DBENV->close, +db_env_create, +DBENV->open, +DBENV->remove, +DBENV->err, +db_strerror, +db_version, +DBENV->set_cachesize, +DBENV->set_errcall, +DBENV->set_errfile, +DBENV->set_errpfx, +DBENV->set_flags, +DBENV->set_mutexlocks, +DBENV->set_paniccall, +and +DBENV->set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/env_set_tas_spins.html b/db/docs/api_c/env_set_tas_spins.html new file mode 100644 index 000000000..633dcda07 --- /dev/null +++ b/db/docs/api_c/env_set_tas_spins.html @@ -0,0 +1,70 @@ + + + + + +Berkeley DB: db_env_set_tas_spins + + + + + + + +
+

db_env_set_tas_spins

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +db_env_set_tas_spins(u_int32_t tas_spins); +

+

Description

+

Specify that test-and-set mutexes should spin tas_spins times +without blocking. The value defaults to 1 on uniprocessor systems and +to 50 times the number of processors on multiprocessor systems. +

The db_env_set_tas_spins interface affects the entire application, not a single +database or database environment. +

While the db_env_set_tas_spins interface may be used to configure Berkeley DB at any time +during the life of the application, it should normally be called before +making any calls to the db_env_create or db_create functions. +

The db_env_set_tas_spins function returns a non-zero error value on failure and 0 on success. +

The database environment's test-and-set spin count may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_tas_spins", one or more whitespace characters, +and the number of spins. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

See Also

+DBENV->close, +db_env_create, +DBENV->open, +DBENV->remove, +DBENV->err, +db_strerror, +db_version, +DBENV->set_cachesize, +DBENV->set_errcall, +DBENV->set_errfile, +DBENV->set_errpfx, +DBENV->set_flags, +DBENV->set_mutexlocks, +DBENV->set_paniccall, +and +DBENV->set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/env_set_tmp_dir.html b/db/docs/api_c/env_set_tmp_dir.html new file mode 100644 index 000000000..05f3bed5d --- /dev/null +++ b/db/docs/api_c/env_set_tmp_dir.html @@ -0,0 +1,89 @@ + + + + + +Berkeley DB: DBENV->set_tmp_dir + + + + + + + +
+

DBENV->set_tmp_dir

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DBENV->set_tmp_dir(DB_ENV *dbenv, const char *dir); +

+

Description

+

The path of a directory to be used as the location of temporary files. +The files created to back in-memory access method databases will be +created relative to this path. These temporary files can be quite large, +depending on the size of the database. +

If no directories are specified, the following alternatives are checked +in the specified order. The first existing directory path is used for +all temporary files. +

    +

  1. The value of the environment variable TMPDIR. +
  2. The value of the environment variable TEMP. +
  3. The value of the environment variable TMP. +
  4. The value of the environment variable TempFolder. +
  5. The value returned by the GetTempPath interface. +
  6. The directory /var/tmp. +
  7. The directory /usr/tmp. +
  8. The directory /temp. +
  9. The directory /tmp. +
  10. The directory C:/temp. +
  11. The directory C:/tmp. +
+

Note: environment variables are only checked if one of the +DB_USE_ENVIRON or DB_USE_ENVIRON_ROOT flags were +specified. +

Note: the GetTempPath interface is only checked on Win/32 platforms. +

The DBENV->set_tmp_dir interface may only be used to configure Berkeley DB before +the DBENV->open interface is called. +

The DBENV->set_tmp_dir function returns a non-zero error value on failure and 0 on success. +

The database environment's temporary file directory may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_tmp_dir", one or more whitespace characters, +and the directory name. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DBENV->open was called. +

+

See Also

+DBENV->close, +db_env_create, +DBENV->open, +DBENV->remove, +DBENV->err, +db_strerror, +db_version, +DBENV->set_cachesize, +DBENV->set_errcall, +DBENV->set_errfile, +DBENV->set_errpfx, +DBENV->set_flags, +DBENV->set_mutexlocks, +DBENV->set_paniccall, +and +DBENV->set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/env_set_tx_max.html b/db/docs/api_c/env_set_tx_max.html new file mode 100644 index 000000000..823289552 --- /dev/null +++ b/db/docs/api_c/env_set_tx_max.html @@ -0,0 +1,67 @@ + + + + + +Berkeley DB: DBENV->set_tx_max + + + + + + + +
+

DBENV->set_tx_max

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DBENV->set_tx_max(DB_ENV *dbenv, u_int32_t tx_max); +

+

Description

+

Set the maximum number of active transactions that are supported by the +environment. This value bounds the size of backing shared memory regions. +Note that child transactions must be counted as active until their +ultimate parent commits or aborts. +

When there are more than the specified number of concurrent transactions, +calls to txn_begin will fail (until some active transactions +complete). If no value is specified, a default value of 20 is used. +

The DBENV->set_tx_max interface may only be used to configure Berkeley DB before +the DBENV->open interface is called. +

The DBENV->set_tx_max function returns a non-zero error value on failure and 0 on success. +

The database environment's maximum number of active transactions may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_tx_max", one or more whitespace characters, +and the number of transactions. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DBENV->open was called. +

+

See Also

+DBENV->set_tx_max, +DBENV->set_tx_recover, +DBENV->set_tx_timestamp, +txn_abort, +txn_begin, +txn_checkpoint, +txn_commit, +txn_id, +txn_prepare +and +txn_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/env_set_tx_recover.html b/db/docs/api_c/env_set_tx_recover.html new file mode 100644 index 000000000..9295537b5 --- /dev/null +++ b/db/docs/api_c/env_set_tx_recover.html @@ -0,0 +1,75 @@ + + + + + +Berkeley DB: DBENV->set_tx_recover + + + + + + + +
+

DBENV->set_tx_recover

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DBENV->set_tx_recover(DB_ENV *dbenv, + int (*tx_recover)(DB_ENV *dbenv, + DBT *log_rec, DB_LSN *lsn, db_recops op)); +

+

Description

+

Set the application's function to be called during transaction abort +and recovery. This function must return 0 on success and either +errno or a value outside of the Berkeley DB error name space on +failure. It takes four arguments: +

+

dbenv
A Berkeley DB environment. +

log_rec
A log record. +

lsn
A log sequence number. +

op
One of the following values: +

+

DB_TXN_BACKWARD_ROLL
The log is being read backward to determine which transactions have been +committed and to abort those operations that were not, undo the operation +described by the log record. +

DB_TXN_FORWARD_ROLL
The log is being played forward, redo the operation described by the log +record. +

DB_TXN_ABORT
The log is being read backwards during a transaction abort, undo the +operation described by the log record. +
+
+

The DBENV->set_tx_recover interface may only be used to configure Berkeley DB before +the DBENV->open interface is called. +

The DBENV->set_tx_recover function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DBENV->open was called. +

+

See Also

+DBENV->set_tx_max, +DBENV->set_tx_recover, +DBENV->set_tx_timestamp, +txn_abort, +txn_begin, +txn_checkpoint, +txn_commit, +txn_id, +txn_prepare +and +txn_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/env_set_tx_timestamp.html b/db/docs/api_c/env_set_tx_timestamp.html new file mode 100644 index 000000000..68cd0d157 --- /dev/null +++ b/db/docs/api_c/env_set_tx_timestamp.html @@ -0,0 +1,63 @@ + + + + + +Berkeley DB: DBENV->set_tx_timestamp + + + + + + + +
+

DBENV->set_tx_timestamp

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DBENV->set_tx_timestamp(DB_ENV *dbenv, time_t *timestamp); +

+

Description

+

Recover to the time specified by timestamp rather than to the most +current possible date. +The timestamp argument should be the number of seconds since 0 +hours, 0 minutes, 0 seconds, January 1, 1970, Coordinated Universal Time, +i.e., the Epoch. +

Once a database environment has been upgraded to a new version of Berkeley DB +involving a log format change (see Upgrading Berkeley DB installations, it is no longer possible to recover +to a specific time before that upgrade. +

The DBENV->set_tx_timestamp interface may only be used to configure Berkeley DB before +the DBENV->open interface is called. +

The DBENV->set_tx_timestamp function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

It is not possible to recover to the specified time using the +log files currently present in the environment. +

+

See Also

+DBENV->set_tx_max, +DBENV->set_tx_recover, +DBENV->set_tx_timestamp, +txn_abort, +txn_begin, +txn_checkpoint, +txn_commit, +txn_id, +txn_prepare +and +txn_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/env_set_verbose.html b/db/docs/api_c/env_set_verbose.html new file mode 100644 index 000000000..605fd577c --- /dev/null +++ b/db/docs/api_c/env_set_verbose.html @@ -0,0 +1,78 @@ + + + + + +Berkeley DB: DBENV->set_verbose + + + + + + + +
+

DBENV->set_verbose

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +DBENV->set_verbose(DB_ENV *dbenv, u_int32_t which, int onoff); +

+

Description

+

The DBENV->set_verbose function turns additional informational and +debugging messages in the Berkeley DB message output on and off. If +onoff is set to +non-zero, +the additional messages are output. +

The which parameter must be set to one of the following values: +

+

DB_VERB_CHKPOINT
Display checkpoint location information when searching the log for +checkpoints. +

DB_VERB_DEADLOCK
Display additional information when doing deadlock detection. +

DB_VERB_RECOVERY
Display additional information when performing recovery. +

DB_VERB_WAITSFOR
Display the waits-for table when doing deadlock detection. +
+

The DBENV->set_verbose interface may be used to configure Berkeley DB at any time +during the life of the application. +

The DBENV->set_verbose function returns a non-zero error value on failure and 0 on success. +

The database environment's verbosity may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_verbose", one or more whitespace characters, +and the interface which argument as a string, for example, +"set_verbose DB_VERB_CHKPOINT". Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

See Also

+DBENV->close, +db_env_create, +DBENV->open, +DBENV->remove, +DBENV->err, +db_strerror, +db_version, +DBENV->set_cachesize, +DBENV->set_errcall, +DBENV->set_errfile, +DBENV->set_errpfx, +DBENV->set_flags, +DBENV->set_mutexlocks, +DBENV->set_paniccall, +and +DBENV->set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/env_strerror.html b/db/docs/api_c/env_strerror.html new file mode 100644 index 000000000..e6bd190a2 --- /dev/null +++ b/db/docs/api_c/env_strerror.html @@ -0,0 +1,60 @@ + + + + + +Berkeley DB: db_strerror + + + + + + + +
+

db_strerror

+
+APIRef +
+


+ +

+#include <db.h>
+

+char * +db_strerror(int error); +

+

Description

+

The db_strerror function returns an error message string corresponding +to the error number error. This interface is a superset of the +ANSI C X3.159-1989 (ANSI C) strerror(3) interface. If the error number +error is greater than or equal to 0, then the string returned by +the system interface strerror(3) is returned. If the error +number is less than 0, an error string appropriate to the corresponding +Berkeley DB library error is returned. See +Error returns to applications +for more information. +

See Also

+DBENV->close, +db_env_create, +DBENV->open, +DBENV->remove, +DBENV->err, +db_strerror, +db_version, +DBENV->set_cachesize, +DBENV->set_errcall, +DBENV->set_errfile, +DBENV->set_errpfx, +DBENV->set_flags, +DBENV->set_mutexlocks, +DBENV->set_paniccall, +and +DBENV->set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/env_version.html b/db/docs/api_c/env_version.html new file mode 100644 index 000000000..fa7704aae --- /dev/null +++ b/db/docs/api_c/env_version.html @@ -0,0 +1,57 @@ + + + + + +Berkeley DB: db_version + + + + + + + +
+

db_version

+
+APIRef +
+


+ +

+#include <db.h>
+

+char * +db_version(int *major, int *minor, int *patch); +

+

Description

+

The db_version function returns a pointer to a string containing Berkeley DB +version information. If major is non-NULL, the major version +of the Berkeley DB release is stored in the memory it references. If +minor is non-NULL, the minor version of the Berkeley DB release is +stored in the memory it references. If patch is non-NULL, the +patch version of the Berkeley DB release is stored in the memory it references. +

See Also

+DBENV->close, +db_env_create, +DBENV->open, +DBENV->remove, +DBENV->err, +db_strerror, +db_version, +DBENV->set_cachesize, +DBENV->set_errcall, +DBENV->set_errfile, +DBENV->set_errpfx, +DBENV->set_flags, +DBENV->set_mutexlocks, +DBENV->set_paniccall, +and +DBENV->set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/hsearch.html b/db/docs/api_c/hsearch.html new file mode 100644 index 000000000..0d6d6ce51 --- /dev/null +++ b/db/docs/api_c/hsearch.html @@ -0,0 +1,107 @@ + + + + + +Berkeley DB: hsearch + + + + + + + +
+

hsearch

+
+APIRef +
+


+ +

+#define DB_DBM_HSEARCH    1
+#include <db.h>
+

+typedef enum { + FIND, ENTER +} ACTION; +

+typedef struct entry { + char *key; + void *data; +} ENTRY; +

+ENTRY * +hsearch(ENTRY item, ACTION action); +

+int +hcreate(size_t nelem); +

+void +hdestroy(void); +

+

Description

+

The hsearch interface to the Berkeley DB library is intended to +provide a high-performance implementation and source code compatibility +for applications written to the historic hsearch interface. +It is not recommended for any other purpose. +

To compile hsearch applications, replace the application's +#include of the hsearch include +file (e.g., #include <search.h>) +with the following two lines: +

+#define DB_DBM_HSEARCH    1
+#include <db.h>
+

and recompile. +

The hcreate function creates an in-memory database. The +nelem argument is an estimation of the maximum number of key/data +pairs that will be stored in the database. +

The hdestroy function discards the database. +

Database elements are structures of type ENTRY, which contain at +least two fields: key and data. The field key is +declared to be of type char * and is the key used for storage +and retrieval. The field data is declared to be of type +void * and is its associated data. +

The hsearch function retrieves key/data pairs from, and stores +key/data pairs into the database. +

The action argument must be set to one of two values: +

+

ENTER
If the key does not already appear in the database, +insert the key/data pair into the database. +If the key already appears in the database, +return a reference to an ENTRY +structure referencing the existing key and its associated data element. +

FIND
Retrieve the specified key/data pair from the database. +
+

Compatibility Notes

+

Historically, hsearch required applications to maintain the keys +and data in the application's memory for as long as the hsearch +database existed. As Berkeley DB handles key and data management internally, +there is no requirement that applications maintain local copies of key +and data items, although the only effect of doing so should be the +allocation of additional memory. +

Hsearch Diagnostics

+

The hcreate function returns 0 on failure, setting errno +and non-zero on success. +

The hsearch function returns a pointer to an ENTRY structure on +success, and NULL, setting errno, if the action +specified was FIND and the item did not appear in the database. +

Errors

+

The hcreate function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the hcreate function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

The hsearch function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the hsearch function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

In addition, the hsearch function will fail, setting errno +to 0, if the action specified was FIND and the item did not appear in +the database. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/lock_detect.html b/db/docs/api_c/lock_detect.html new file mode 100644 index 000000000..7b95e98e9 --- /dev/null +++ b/db/docs/api_c/lock_detect.html @@ -0,0 +1,73 @@ + + + + + +Berkeley DB: lock_detect + + + + + + + +
+

lock_detect

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +lock_detect(DB_ENV *env, + u_int32_t flags, u_int32_t atype, int *aborted); +

+

Description

+

The lock_detect function runs one iteration of the deadlock detector. +The deadlock detector traverses the lock table, and for each deadlock +it finds, marks one of the participating transactions for abort. +

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +

+

DB_LOCK_CONFLICT
Only run the deadlock detector if a lock conflict has occurred since +the last time that the deadlock detector was run. +
+

The atype parameter specifies which transaction to abort in the +case of deadlock. It must be set to one of possible arguments listed for +the DBENV->set_lk_detect interface. +

If the aborted parameter is non-NULL, the memory location it +references will be set to the number of transactions aborted by the +lock_detect function. +

The lock_detect function is the underlying function used by the db_deadlock utility. +See the db_deadlock utility source code for an example of using lock_detect +in a IEEE/ANSI Std 1003.1 (POSIX) environment. +

The lock_detect function returns a non-zero error value on failure and 0 on success. +

Errors

+

The lock_detect function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the lock_detect function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBENV->set_lk_conflicts, +DBENV->set_lk_detect, +DBENV->set_lk_max_locks, +DBENV->set_lk_max_lockers, +DBENV->set_lk_max_objects, +DBENV->set_lk_max, +lock_detect, +lock_get, +lock_id, +lock_put, +lock_stat +and +lock_vec. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/lock_get.html b/db/docs/api_c/lock_get.html new file mode 100644 index 000000000..8d68ba54c --- /dev/null +++ b/db/docs/api_c/lock_get.html @@ -0,0 +1,91 @@ + + + + + +Berkeley DB: lock_get + + + + + + + +
+

lock_get

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +lock_get(DB_ENV *env, u_int32_t locker, + u_int32_t flags, const DBT *obj, + const db_lockmode_t lock_mode, DB_LOCK *lock); +

+

Description

+

The lock_get function acquires a lock from the lock table, returning +information about it in +the lock argument. +

The locker argument specified to lock_get is an unsigned +32-bit integer quantity. It represents the entity requesting or releasing +the lock. +

The flags value must be set to 0 or the following value: +

+

DB_LOCK_NOWAIT
If a lock cannot be granted because the requested lock conflicts with an +existing lock, return immediately instead of waiting for the lock to +become available. +
+

The obj argument is an untyped byte string that specifies the +object to be locked or released. +

The mode argument is an index into the environment's lock conflict +array. See DBENV->set_lk_conflicts and +Standard Lock Modes +for a description of that array. +

The lock_get function may +return +one of the following values: +

+

DB_LOCK_NOTGRANTED
A lock was requested that could not be immediately granted and the +flags parameter was set to DB_LOCK_NOWAIT. +
+

Otherwise, the lock_get function returns a non-zero error value on failure and 0 on success. +

Errors

+

The lock_get function may fail and return a non-zero error for the following conditions: +

+

DB_LOCK_DEADLOCK
The operation was selected to resolve a deadlock. +
+

+

EINVAL
An invalid flag value or parameter was specified. +
+

+

ENOMEM
The maximum number of locks has been reached. +
+

The lock_get function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the lock_get function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBENV->set_lk_conflicts, +DBENV->set_lk_detect, +DBENV->set_lk_max_locks, +DBENV->set_lk_max_lockers, +DBENV->set_lk_max_objects, +DBENV->set_lk_max, +lock_detect, +lock_get, +lock_id, +lock_put, +lock_stat +and +lock_vec. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/lock_id.html b/db/docs/api_c/lock_id.html new file mode 100644 index 000000000..bd720cdb0 --- /dev/null +++ b/db/docs/api_c/lock_id.html @@ -0,0 +1,57 @@ + + + + + +Berkeley DB: lock_id + + + + + + + +
+

lock_id

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +lock_id(DB_ENV *env, u_int32_t *idp); +

+

Description

+

The lock_id function +copies a locker ID, which is guaranteed to be unique in the specified lock +table, into the memory location referenced by idp. +

The lock_id function returns a non-zero error value on failure and 0 on success. +

Errors

+

The lock_id function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the lock_id function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBENV->set_lk_conflicts, +DBENV->set_lk_detect, +DBENV->set_lk_max_locks, +DBENV->set_lk_max_lockers, +DBENV->set_lk_max_objects, +DBENV->set_lk_max, +lock_detect, +lock_get, +lock_id, +lock_put, +lock_stat +and +lock_vec. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/lock_put.html b/db/docs/api_c/lock_put.html new file mode 100644 index 000000000..777f4bdd0 --- /dev/null +++ b/db/docs/api_c/lock_put.html @@ -0,0 +1,59 @@ + + + + + +Berkeley DB: lock_put + + + + + + + +
+

lock_put

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +lock_put(DB_ENV *env, DB_LOCK *lock); +

+

Description

+

The lock_put function releases lock from the lock table. +

The lock_put function returns a non-zero error value on failure and 0 on success. +

Errors

+

The lock_put function may fail and return a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +
+

The lock_put function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the lock_put function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBENV->set_lk_conflicts, +DBENV->set_lk_detect, +DBENV->set_lk_max_locks, +DBENV->set_lk_max_lockers, +DBENV->set_lk_max_objects, +DBENV->set_lk_max, +lock_detect, +lock_get, +lock_id, +lock_put, +lock_stat +and +lock_vec. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/lock_stat.html b/db/docs/api_c/lock_stat.html new file mode 100644 index 000000000..c86024de7 --- /dev/null +++ b/db/docs/api_c/lock_stat.html @@ -0,0 +1,92 @@ + + + + + +Berkeley DB: lock_stat + + + + + + + +
+

lock_stat

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +lock_stat(DB_ENV *env, + DB_LOCK_STAT **statp, void *(*db_malloc)(size_t)); +

+

Description

+

The lock_stat function +creates a statistical structure and copies a pointer to it into a +user-specified memory location. +

Statistical structures are created in allocated memory. If db_malloc is non-NULL, it +is called to allocate the memory, otherwise, the library function +malloc(3) is used. The function db_malloc must match +the calling conventions of the malloc(3) library routine. +Regardless, the caller is responsible for deallocating the returned +memory. To deallocate returned memory, free the returned memory +reference, references inside the returned memory do not need to be +individually freed. +

The lock region statistics are stored in a structure of type +DB_LOCK_STAT. The following DB_LOCK_STAT fields will be filled in: +

+
u_int32_t st_lastid;
The last allocated lock ID. +
u_int32_t st_nmodes;
The number of lock modes. +
u_int32_t st_maxlocks;
The maximum number of locks possible. +
u_int32_t st_maxlockers;
The maximum number of lockers possible. +
u_int32_t st_maxobjects;
The maximum number of objects possible. +
u_int32_t st_nlocks;
The number of current locks. +
u_int32_t st_maxnlocks;
The maximum number of locks at any one time. +
u_int32_t st_nlockers;
The number of current lockers. +
u_int32_t st_maxnlockers;
The maximum number of lockers at any one time. +
u_int32_t st_nobjects;
The number of current objects. +
u_int32_t st_maxnobjects;
The maximum number of objects at any one time. +
u_int32_t st_nrequests;
The total number of locks requested. +
u_int32_t st_nreleases;
The total number of locks released. +
u_int32_t st_nnowaits;
The total number of lock requests that failed because +DB_LOCK_NOWAIT was set. +
u_int32_t st_nconflicts;
The total number of locks not immediately available due to conflicts. +
u_int32_t st_ndeadlocks;
The number of deadlocks detected. +
u_int32_t st_regsize;
The size of the region. +
u_int32_t st_region_wait;
The number of times that a thread of control was forced to wait before +obtaining the region lock. +
u_int32_t st_region_nowait;
The number of times that a thread of control was able to obtain +the region lock without waiting. +
+

The lock_stat function returns a non-zero error value on failure and 0 on success. +

Errors

+

The lock_stat function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the lock_stat function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBENV->set_lk_conflicts, +DBENV->set_lk_detect, +DBENV->set_lk_max_locks, +DBENV->set_lk_max_lockers, +DBENV->set_lk_max_objects, +DBENV->set_lk_max, +lock_detect, +lock_get, +lock_id, +lock_put, +lock_stat +and +lock_vec. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/lock_vec.html b/db/docs/api_c/lock_vec.html new file mode 100644 index 000000000..56d3fa96a --- /dev/null +++ b/db/docs/api_c/lock_vec.html @@ -0,0 +1,123 @@ + + + + + +Berkeley DB: lock_vec + + + + + + + +
+

lock_vec

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +lock_vec(DB_ENV *env, u_int32_t locker, u_int32_t flags, + DB_LOCKREQ list[], int nlist, DB_LOCKREQ **elistp); +

+

Description

+

The lock_vec function atomically obtains and releases one or more locks +from the lock table. The lock_vec function is intended to support +acquisition or trading of multiple locks under one lock table semaphore, +as is needed for lock coupling or in multigranularity locking for lock +escalation. +

The locker argument specified to lock_vec is an unsigned +32-bit integer quantity. It represents the entity requesting or releasing +the lock. +

The flags value must be set to 0 or the following value: +

+

DB_LOCK_NOWAIT
If a lock cannot be immediately granted because the requested lock +conflicts with an existing lock, return instead of waiting for the lock +to become available. +
+

The list array provided to lock_vec is typedef'd as +DB_LOCKREQ. A DB_LOCKREQ structure has at least the following fields, +which must be initialized before calling lock_vec: +

+

lockop_t op;
The operation to be performed, which must be set to one of the +following values: +

+

DB_LOCK_GET
Get a lock, as defined by the values of locker, obj, +and mode. Upon return from lock_vec, if the +lock field is non-NULL, a reference to the acquired lock is +stored there. (This reference is invalidated by any call to +lock_vec or lock_put that releases the lock.) +

DB_LOCK_PUT
The lock referenced by the contents of the lock field is released. +

DB_LOCK_PUT_ALL
All locks held by the locker are released. (Any locks acquired +as a part of the current call to lock_vec that appear after the +DB_LOCK_PUT_ALL entry are not considered for this +operation). +

DB_LOCK_PUT_OBJ
All locks held on the object obj are released. The mode +and locker parameters are ignored. Note that any locks acquired +as a part of the current call to lock_vec that occur before the +DB_LOCK_PUT_OBJ will also be released; those acquired afterwards +will not be released. +
+

const DBT obj;
An untyped byte string that specifies the object to be locked or released. +

const lockmode_t mode;
The lock mode, used as an index into the environment's lock conflict array. +See DBENV->set_lk_conflicts and Standard Lock Modes for a description of that array. +

DB_LOCK lock;
A lock reference. +
+

The nlist argument specifies the number of elements in the +list array. +

If any of the requested locks cannot be acquired, or any of the locks to +be released cannot be released, the operations before the failing +operation are guaranteed to have completed successfully, and +lock_vec returns a non-zero value. In addition, if elistp +is not NULL, it is set to point to the DB_LOCKREQ entry that was being +processed when the error occurred. +

The lock_vec function may +return +one of the following values: +

+

DB_LOCK_NOTGRANTED
A lock was requested that could not be immediately granted and the +flag parameter was set to DB_LOCK_NOWAIT. In this case, if +non-NULL, elistp identifies the request that was not granted. +
+

Otherwise, the lock_vec function returns a non-zero error value on failure and 0 on success. +

Errors

+

The lock_vec function may fail and return a non-zero error for the following conditions: +

+

DB_LOCK_DEADLOCK
The operation was selected to resolve a deadlock. +
+

+

EINVAL
An invalid flag value or parameter was specified. +
+

+

ENOMEM
The maximum number of locks has been reached. +
+

The lock_vec function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the lock_vec function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBENV->set_lk_conflicts, +DBENV->set_lk_detect, +DBENV->set_lk_max_locks, +DBENV->set_lk_max_lockers, +DBENV->set_lk_max_objects, +DBENV->set_lk_max, +lock_detect, +lock_get, +lock_id, +lock_put, +lock_stat +and +lock_vec. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/log_archive.html b/db/docs/api_c/log_archive.html new file mode 100644 index 000000000..6c9aea26b --- /dev/null +++ b/db/docs/api_c/log_archive.html @@ -0,0 +1,102 @@ + + + + + +Berkeley DB: log_archive + + + + + + + +
+

log_archive

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +log_archive(DB_ENV *env, char *(*listp)[], + u_int32_t flags, void *(*db_malloc)(size_t)); +

+

Description

+

The log_archive function +creates a NULL-terminated array of log or database file names and copies +a pointer to them into the user-specified memory location listp. +

By default, log_archive returns the names of all of the log files +that are no longer in use (e.g., no longer involved in active transactions), +and that may safely be archived for catastrophic recovery and then removed +from the system. If there were no file names to return, the memory location +referenced by listp will be set to NULL. +

Arrays of log file names are created in allocated memory. If db_malloc is non-NULL, it +is called to allocate the memory, otherwise, the library function +malloc(3) is used. The function db_malloc must match +the calling conventions of the malloc(3) library routine. +Regardless, the caller is responsible for deallocating the returned +memory. To deallocate returned memory, free the returned memory +reference, references inside the returned memory do not need to be +individually freed. +

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +

+

DB_ARCH_ABS
All pathnames are returned as absolute pathnames, +instead of relative to the database home directory. +

DB_ARCH_DATA
Return the database files that need to be archived in order to recover +the database from catastrophic failure. If any of the database files +have not been accessed during the lifetime of the current log files, +log_archive will not include them in this list. It is also +possible that some of the files referenced in the log have since been +deleted from the system. +

DB_ARCH_LOG
Return all the log file names regardless of whether or not they are in +use. +
+

The DB_ARCH_DATA and DB_ARCH_LOG flags are mutually +exclusive. +

See the db_archive manual page for more information on database +archival procedures. +

The log_archive function is the underlying function used by the db_archive utility. +See the db_archive utility source code for an example of using log_archive +in a IEEE/ANSI Std 1003.1 (POSIX) environment. +

The log_archive function returns a non-zero error value on failure and 0 on success. +

Bugs

+

In a threaded application (i.e., one where the environment was created +with the DB_THREAD flag specified), calling log_archive with the +DB_ARCH_DATA flag will fail, returning EINVAL. To work around this +problem, re-open the log explicitly without specifying DB_THREAD. This +restriction is expected to be removed in a future version of Berkeley DB. +

Errors

+

The log_archive function may fail and return a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +

The log was corrupted. +

+

The log_archive function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the log_archive function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBENV->set_lg_bsize, +DBENV->set_lg_max, +log_archive, +log_compare, +log_file, +log_flush, +log_get, +log_put, +log_register, +log_stat +and +log_unregister. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/log_compare.html b/db/docs/api_c/log_compare.html new file mode 100644 index 000000000..c6e7743be --- /dev/null +++ b/db/docs/api_c/log_compare.html @@ -0,0 +1,51 @@ + + + + + +Berkeley DB: log_compare + + + + + + + +
+

log_compare

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +log_compare(const DB_LSN *lsn0, const DB_LSN *lsn1); +

+

Description

+

The log_compare function allows the caller to compare two +DB_LSN structures, +returning 0 if they are equal, 1 if lsn0 is greater than +lsn1, and -1 if lsn0 is less than lsn1. +

See Also

+DBENV->set_lg_bsize, +DBENV->set_lg_max, +log_archive, +log_compare, +log_file, +log_flush, +log_get, +log_put, +log_register, +log_stat +and +log_unregister. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/log_file.html b/db/docs/api_c/log_file.html new file mode 100644 index 000000000..434380ccc --- /dev/null +++ b/db/docs/api_c/log_file.html @@ -0,0 +1,76 @@ + + + + + +Berkeley DB: log_file + + + + + + + +
+

log_file

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +log_file(DB_ENV *env, + const DB_LSN *lsn, char *namep, size_t len); +

+

Description

+

The log_file function maps +DB_LSN structures +to file names, +copying the name of the file containing the record named by lsn +into the memory location referenced by namep. +

The len argument is the length of the namep buffer in bytes. +If namep is too short to hold the file name, log_file will +return ENOMEM. +(Log file names are normally quite short, on the order of 10 characters.) +

This mapping of +DB_LSN structures +to files is needed for database administration. For example, a +transaction manager typically records the earliest +DB_LSN +needed for restart, and the database administrator may want to archive +log files to tape when they contain only +DB_LSN +entries before the earliest one needed for restart. +

The log_file function returns a non-zero error value on failure and 0 on success. +

Errors

+

The log_file function may fail and return a non-zero error for the following conditions: +

+

ENOMEM
The supplied buffer was too small to hold the log file name. +
+

The log_file function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the log_file function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBENV->set_lg_bsize, +DBENV->set_lg_max, +log_archive, +log_compare, +log_file, +log_flush, +log_get, +log_put, +log_register, +log_stat +and +log_unregister. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/log_flush.html b/db/docs/api_c/log_flush.html new file mode 100644 index 000000000..1315fc106 --- /dev/null +++ b/db/docs/api_c/log_flush.html @@ -0,0 +1,62 @@ + + + + + +Berkeley DB: log_flush + + + + + + + +
+

log_flush

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +log_flush(DB_ENV *env, const DB_LSN *lsn); +

+

Description

+

The log_flush function guarantees that all log records whose +DB_LSN values +are less than or equal to the lsn argument have been +written to disk. If lsn is NULL, all records in the +log are flushed. +

The log_flush function returns a non-zero error value on failure and 0 on success. +

Errors

+

The log_flush function may fail and return a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +
+

The log_flush function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the log_flush function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBENV->set_lg_bsize, +DBENV->set_lg_max, +log_archive, +log_compare, +log_file, +log_flush, +log_get, +log_put, +log_register, +log_stat +and +log_unregister. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/log_get.html b/db/docs/api_c/log_get.html new file mode 100644 index 000000000..05761e1ea --- /dev/null +++ b/db/docs/api_c/log_get.html @@ -0,0 +1,114 @@ + + + + + +Berkeley DB: log_get + + + + + + + +
+

log_get

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +log_get(DB_ENV *env, DB_LSN *lsn, DBT *data, u_int32_t flags); +

+

Description

+

The log_get function implements a cursor inside of the log, +retrieving records from the log according to the lsn and +flags arguments. +

The data field of the data structure is set to the record +retrieved and the size field indicates the number of bytes in the record. +See DBT for a description of other fields in the data +structure. When multiple threads are using the returned log handle +concurrently, one of the DB_DBT_MALLOC, DB_DBT_REALLOC or +DB_DBT_USERMEM flags must be specified for any DBT used +for data retrieval. +

The flags argument must be set to exactly one of the following values: +

+

DB_CHECKPOINT
The last record written with the DB_CHECKPOINT flag specified to the +log_put function is returned in the data argument. The +lsn argument is overwritten with the DB_LSN of the record +returned. If no record has been previously written with the DB_CHECKPOINT +flag specified, the first record in the log is returned. +

If the log is empty, the log_get function will return DB_NOTFOUND. +

DB_FIRST
The first record from any of the log files found in the log directory +is returned in the data argument. +The lsn argument is overwritten with the DB_LSN of the +record returned. +

If the log is empty, the log_get function will return DB_NOTFOUND. +

DB_LAST
The last record in the log is returned in the data argument. +The lsn argument is overwritten with the DB_LSN of the +record returned. +

If the log is empty, the log_get function will return DB_NOTFOUND. +

DB_NEXT
The current log position is advanced to the next record in the log and that +record is returned in the data argument. +The lsn argument is overwritten with the DB_LSN of the +record returned. +

If the pointer has not been initialized via DB_FIRST, DB_LAST, DB_SET, +DB_NEXT, or DB_PREV, log_get will return the first record in the log. +If the last log record has already been returned or the log is empty, the +log_get function will return DB_NOTFOUND. +

If the log was opened with the DB_THREAD flag set, calls to +log_get with the DB_NEXT flag set will return EINVAL. +

DB_PREV
The current log position is moved to the previous record in the log and that +record is returned in the data argument. +The lsn argument is overwritten with the DB_LSN of the +record returned. +

If the pointer has not been initialized via DB_FIRST, DB_LAST, DB_SET, +DB_NEXT, or DB_PREV, +log_get will return the last record in the log. +If the first log record has already been returned or the log is empty, the +log_get function will return DB_NOTFOUND. +

If the log was opened with the DB_THREAD flag set, calls to +log_get with the DB_PREV flag set will return EINVAL. +

DB_CURRENT
Return the log record currently referenced by the log. +

If the log pointer has not been initialized via DB_FIRST, DB_LAST, DB_SET, +DB_NEXT, or DB_PREV, or if the log was opened with the DB_THREAD flag set, +log_get will return EINVAL. +

DB_SET
Retrieve the record specified by the lsn argument. If the +specified DB_LSN is invalid (e.g., does not appear in the log) +log_get will return EINVAL. +
+

Otherwise, the log_get function returns a non-zero error value on failure and 0 on success. +

Errors

+

The log_get function may fail and return a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +

The DB_FIRST flag was specified and no log files were found. +

+

The log_get function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the log_get function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBENV->set_lg_bsize, +DBENV->set_lg_max, +log_archive, +log_compare, +log_file, +log_flush, +log_get, +log_put, +log_register, +log_stat +and +log_unregister. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/log_put.html b/db/docs/api_c/log_put.html new file mode 100644 index 000000000..945529698 --- /dev/null +++ b/db/docs/api_c/log_put.html @@ -0,0 +1,81 @@ + + + + + +Berkeley DB: log_put + + + + + + + +
+

log_put

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +log_put(DB_ENV *env, + DB_LSN *lsn, const DBT *data, u_int32_t flags); +

+

Description

+

The log_put function appends records to the log. The DB_LSN of +the put record is returned in the lsn argument. The flags +argument may be set to one of the following values: +

+

DB_CHECKPOINT
The log should write a checkpoint record, recording any information +necessary to make the log structures recoverable after a crash. +

DB_CURLSN
The DB_LSN of the next record to be put is returned in the +lsn argument. +

DB_FLUSH
The log is forced to disk after this record is written, guaranteeing +that all records with DB_LSN values less than or equal to the +one being put are on disk before this function returns (this function +is most often used for a transaction commit, see txn_commit for +more information). +

The caller is responsible for providing any necessary structure to +data. (For example, in a write-ahead logging protocol, the +application must understand what part of data is an operation +code, what part is redo information, and what part is undo information. +In addition, most transaction managers will store in data the +DB_LSN of the previous log record for the same transaction, to +support chaining back through the transaction's log records during +undo.) +

+

The log_put function returns a non-zero error value on failure and 0 on success. +

Errors

+

The log_flush function may fail and return a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +

The record to be logged is larger than the maximum log record. +

+

The log_put function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the log_put function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBENV->set_lg_bsize, +DBENV->set_lg_max, +log_archive, +log_compare, +log_file, +log_flush, +log_get, +log_put, +log_register, +log_stat +and +log_unregister. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/log_register.html b/db/docs/api_c/log_register.html new file mode 100644 index 000000000..e993feabe --- /dev/null +++ b/db/docs/api_c/log_register.html @@ -0,0 +1,64 @@ + + + + + +Berkeley DB: log_register + + + + + + + +
+

log_register

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +log_register(DB_ENV *env, DB *dbp, const char *name); +

+

Description

+

The log_register function registers a file name with the specified Berkeley DB +environment's log manager. The log manager records all file name mappings +at each checkpoint so that a recovery process can identify the file to +which a record in the log refers. +

The dbp argument should be a reference to the DB structure being +registered. The name argument should be a file name appropriate +for opening the file in the environment, during recovery. +

The log_register function returns a non-zero error value on failure and 0 on success. +

Errors

+

The log_register function may fail and return a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +
+

The log_register function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the log_register function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBENV->set_lg_bsize, +DBENV->set_lg_max, +log_archive, +log_compare, +log_file, +log_flush, +log_get, +log_put, +log_register, +log_stat +and +log_unregister. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/log_stat.html b/db/docs/api_c/log_stat.html new file mode 100644 index 000000000..819c603d3 --- /dev/null +++ b/db/docs/api_c/log_stat.html @@ -0,0 +1,90 @@ + + + + + +Berkeley DB: log_stat + + + + + + + +
+

log_stat

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +log_stat(DB_ENV *env, + DB_LOG_STAT **spp, void *(*db_malloc)(size_t)); +

+

Description

+

The log_stat function +creates a statistical structure and copies a pointer to it into a +user-specified memory location. +

Statistical structures are created in allocated memory. If db_malloc is non-NULL, it +is called to allocate the memory, otherwise, the library function +malloc(3) is used. The function db_malloc must match +the calling conventions of the malloc(3) library routine. +Regardless, the caller is responsible for deallocating the returned +memory. To deallocate returned memory, free the returned memory +reference, references inside the returned memory do not need to be +individually freed. +

The log region statistics are stored in a structure of type DB_LOG_STAT. +The following DB_LOG_STAT fields will be filled in: +

+
u_int32_t st_magic;
The magic number that identifies a file as a log file. +
u_int32_t st_version;
The version of the log file type. +
u_int32_t st_regsize;
The size of the region. +
int st_mode;
The mode of any created log files. +
u_int32_t st_lg_bsize;
The in-memory log record cache size. +
u_int32_t st_lg_max;
The maximum size of any individual file comprising the log. +
u_int32_t st_w_mbytes;
The number of megabytes written to this log. +
u_int32_t st_w_bytes;
The number of bytes over and above st_w_mbytes written to this log. +
u_int32_t st_wc_mbytes;
The number of megabytes written to this log since the last checkpoint. +
u_int32_t st_wc_bytes;
The number of bytes over and above st_wc_mbytes written to this log +since the last checkpoint. +
u_int32_t st_wcount;
The number of times the log has been written to disk. +
u_int32_t st_wcount_fill;
The number of times the log has been written to disk because the +in-memory log record cache filled up. +
u_int32_t st_scount;
The number of times the log has been flushed to disk. +
u_int32_t st_cur_file;
The current log file number. +
u_int32_t st_cur_offset;
The byte offset in the current log file. +
u_int32_t st_region_wait;
The number of times that a thread of control was forced to wait before +obtaining the region lock. +
u_int32_t st_region_nowait;
The number of times that a thread of control was able to obtain +the region lock without waiting. +
+

The log_stat function returns a non-zero error value on failure and 0 on success. +

Errors

+

The log_stat function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the log_stat function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBENV->set_lg_bsize, +DBENV->set_lg_max, +log_archive, +log_compare, +log_file, +log_flush, +log_get, +log_put, +log_register, +log_stat +and +log_unregister. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/log_unregister.html b/db/docs/api_c/log_unregister.html new file mode 100644 index 000000000..cfc1e6f2e --- /dev/null +++ b/db/docs/api_c/log_unregister.html @@ -0,0 +1,59 @@ + + + + + +Berkeley DB: log_unregister + + + + + + + +
+

log_unregister

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +log_unregister(DB_ENV *env, DB *dbp); +

+

Description

+

The log_unregister function function unregisters the file represented by +the dbp parameter from the Berkeley DB environment's log manager. +

The log_unregister function returns a non-zero error value on failure and 0 on success. +

Errors

+

The log_unregister function may fail and return a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +
+

The log_unregister function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the log_unregister function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBENV->set_lg_bsize, +DBENV->set_lg_max, +log_archive, +log_compare, +log_file, +log_flush, +log_get, +log_put, +log_register, +log_stat +and +log_unregister. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/memp_fclose.html b/db/docs/api_c/memp_fclose.html new file mode 100644 index 000000000..ae8ce3c56 --- /dev/null +++ b/db/docs/api_c/memp_fclose.html @@ -0,0 +1,61 @@ + + + + + +Berkeley DB: memp_fclose + + + + + + + +
+

memp_fclose

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +memp_fclose(DB_MPOOLFILE *mpf); +

+

Description

+

The memp_fclose function closes the source file indicated by the +DB_MPOOLFILE structure. Calling memp_fclose does not imply +a call to memp_fsync, i.e. no pages are written to the source +file as as a result of calling memp_fclose. +

In addition, if the file argument to memp_fopen was NULL, +any underlying files created for this DB_MPOOLFILE will be removed. +

Once memp_fclose has been called, regardless of its return, the +DB_MPOOLFILE handle may not be accessed again. +

The memp_fclose function returns a non-zero error value on failure and 0 on success. +

Errors

+

The memp_fclose function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the memp_fclose function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBENV->set_mp_mmapsize, +memp_fclose, +memp_fget, +memp_fopen, +memp_fput, +memp_fset, +memp_fsync, +memp_register, +memp_stat, +memp_sync +and +memp_trickle. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/memp_fget.html b/db/docs/api_c/memp_fget.html new file mode 100644 index 000000000..84b39e53e --- /dev/null +++ b/db/docs/api_c/memp_fget.html @@ -0,0 +1,98 @@ + + + + + +Berkeley DB: memp_fget + + + + + + + +
+

memp_fget

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +memp_fget(DB_MPOOLFILE *mpf, + db_pgno_t *pgnoaddr, u_int32_t flags, void **pagep); +

+

Description

+

The memp_fget function copies a pointer to the page with the page +number specified by pgnoaddr, from the source file in the +DB_MPOOLFILE, into the memory location referenced by pagep. +If the page does not exist or cannot be retrieved, memp_fget will +fail. +

Page numbers begin at 0, i.e., the first page in the file is page number +0, not page number 1. +

The returned page is size_t type aligned. +

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +

+

DB_MPOOL_CREATE
If the specified page does not exist, create it. In this case, the +pgin function, if specified, is +called. +

DB_MPOOL_LAST
Return the last page of the source file and copy its page number +to the location referenced by pgnoaddr. +

DB_MPOOL_NEW
Create a new page in the file and copy its page number to the location +referenced by pgnoaddr. In this case, the +pgin function, if specified, is +not called. +
+

The DB_MPOOL_CREATE, DB_MPOOL_LAST and +DB_MPOOL_NEW flags are mutually exclusive. +

Created pages have all their bytes set to 0, unless otherwise specified +when the file was opened. +

All pages returned by memp_fget will be retained (i.e. +pinned), in the pool until a subsequent call to +memp_fput. +

The memp_fget function returns a non-zero error value on failure and 0 on success. +

Errors

+

The memp_fget function may fail and return a non-zero error for the following conditions: +

+

EAGAIN
The page reference count has overflowed. (This should never happen unless +there's a bug in the application.) +
+

+

EINVAL
An invalid flag value or parameter was specified. +

The DB_MPOOL_NEW flag was set and the source file was not opened for writing. +

More than one of DB_MPOOL_CREATE, DB_MPOOL_LAST and DB_MPOOL_NEW was set. +

+

+

EIO
The requested page does not exist and DB_MPOOL_CREATE was not set. +
+

+

ENOMEM
The cache is full and no more pages will fit in the pool. +
+

The memp_fget function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the memp_fget function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBENV->set_mp_mmapsize, +memp_fclose, +memp_fget, +memp_fopen, +memp_fput, +memp_fset, +memp_fsync, +memp_register, +memp_stat, +memp_sync +and +memp_trickle. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/memp_fopen.html b/db/docs/api_c/memp_fopen.html new file mode 100644 index 000000000..ea0250246 --- /dev/null +++ b/db/docs/api_c/memp_fopen.html @@ -0,0 +1,157 @@ + + + + + +Berkeley DB: memp_fopen + + + + + + + +
+

memp_fopen

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +memp_fopen(DB_ENV *env, char *file, u_int32_t flags, + int mode, size_t pagesize, DB_MPOOL_FINFO *finfop, + DB_MPOOLFILE **mpf); +

+

Description

+

The memp_fopen function opens a file in the pool specified by the +DB_ENV env, copying the DB_MPOOLFILE pointer +representing it into the memory location referenced by mpf. +

The file argument is the name of the file to be opened. +If file is NULL, a private file is created that cannot be +shared with any other process (although it may be shared with +other threads). +

The flags and mode arguments specify how files will be opened +and/or created if they do not already exist. +

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +

+

DB_CREATE
Create any underlying files, as necessary. If the files do not already +exist and the DB_CREATE flag is not specified, the call will fail. +

DB_NOMMAP
Always copy this file into the local cache instead of potentially mapping +it into process memory (see the description of the +DBENV->set_mp_mmapsize function for further information). +

DB_RDONLY
Open any underlying files for reading only. Any attempt to write the file +using the pool functions will fail, regardless of the actual permissions +of the file. +
+

On UNIX systems, or in IEEE/ANSI Std 1003.1 (POSIX) environments, all files created by function memp_fopen +are created with mode mode (as described in chmod(2)) and +modified by the process' umask value at the time of creation (see +umask(2)). The group ownership of created files is based on +the system and directory defaults, and is not further specified by Berkeley DB. +If mode is 0, files are created readable and writeable by both +owner and group. On Windows systems, the mode argument is ignored. +

The pagesize argument is the size, in bytes, of the unit of transfer +between the application and the pool, although it is not necessarily the +unit of transfer between the pool and the source file. +

Files opened in the pool may be further configured based on the +finfop argument to memp_fopen (which is a pointer to a +structure of type DB_MPOOL_FINFO). No references to the finfop +structure are maintained by Berkeley DB, so it may be discarded when the +memp_fopen function returns. In order to ensure compatibility +with future releases of Berkeley DB, all fields of the DB_MPOOL_FINFO structure +that are not explicitly set should be initialized to 0 before the first +time the structure is used. Do this by declaring the structure external +or static, or by calling the C library routine bzero(3) or +memset(3). +

The fields of the DB_MPOOL_FINFO structure used by memp_fopen are +described below. If finfop is NULL or any of its fields are +set to their default value, defaults appropriate for the system are used. +

+

int ftype;
The ftype field should be the same as a ftype argument +previously specified to the memp_register function, unless no +input or output processing of the file's pages are necessary, in which +case it should be 0. (See the description of the memp_register +function for more information.) +

DBT *pgcookie;
The pgcookie field contains the byte string that is passed to the +pgin and pgout functions for this file, if any. If no +pgin or pgout functions are specified, the +pgcookie field should be NULL. (See the description of the +memp_register function for more information.) +

u_int8_t *fileid;
The fileid field is a unique identifier for the file. If the +fileid field is non-NULL, it must reference a DB_FILE_ID_LEN +length array of bytes that will be used to uniquely identify the file. +

The mpool functions must be able to uniquely identify files in order that +multiple processes wanting to share a file will correctly identify it in +the pool. +

On most UNIX/POSIX systems, the fileid field will not need to be +set and the mpool functions will simply use the file's device and inode +numbers for this purpose. On Windows systems, the mpool functions use +the values returned by GetFileInformationByHandle() by default -- these +values are known to be constant between processes and over reboot in the +case of NTFS (where they are the NTFS MFT indexes). +

On other filesystems, (e.g., FAT or NFS) these default values are not +necessarily unique between processes or across system reboots. +Applications wanting to maintain a shared memory buffer pool +between processes or across system reboots, where the pool contains pages +from files stored on such filesystems, must specify a unique file +identifier to the memp_fopen call and each process opening or +registering the file must provide the same unique identifier. +

This should not be necessary for most applications. Specifically, it is +not necessary if the memory pool is not shared between processes and is +re-instantiated after each system reboot, or the application is using the +Berkeley DB access methods instead of calling the pool functions explicitly, or +the files in the memory pool are stored on filesystems where the default +values as described above are invariant between process and across system +reboots. +

int32_t lsn_offset;
The lsn_offset field is the zero-based byte offset in the page of +the page's log sequence number (LSN), or -1 if no LSN offset is specified. +(See the description of the memp_sync function for more +information.) +

u_int32_t clear_len;
The clear_len field is the number of initial bytes in a page +that should be set to zero when the page is created as a result of the +DB_MPOOL_CREATE or DB_MPOOL_NEW flags being specified to memp_fget. +If finfop is NULL or clear_len is 0, the entire page is +cleared. +
+

The memp_fopen function returns a non-zero error value on failure and 0 on success. +

Errors

+

The memp_fopen function may fail and return a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +

The file has already been entered into the pool, and the pagesize +value is not the same as when the file was entered into the pool, or the +length of the file is not zero or a multiple of the pagesize. +

The DB_RDONLY flag was specified for an in-memory pool. +

+

+

ENOMEM
The maximum number of open files has been reached. +
+

The memp_fopen function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the memp_fopen function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBENV->set_mp_mmapsize, +memp_fclose, +memp_fget, +memp_fopen, +memp_fput, +memp_fset, +memp_fsync, +memp_register, +memp_stat, +memp_sync +and +memp_trickle. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/memp_fput.html b/db/docs/api_c/memp_fput.html new file mode 100644 index 000000000..ce382b4d0 --- /dev/null +++ b/db/docs/api_c/memp_fput.html @@ -0,0 +1,79 @@ + + + + + +Berkeley DB: memp_fput + + + + + + + +
+

memp_fput

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +memp_fput(DB_MPOOLFILE *mpf, void *pgaddr, u_int32_t flags); +

+

Description

+

The memp_fput function indicates that the page referenced by +pgaddr can be evicted from the pool. The pgaddr +argument must be an address previously returned by memp_fget. +

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +

+

DB_MPOOL_CLEAN
Clear any previously set modification information (i.e., don't bother +writing the page back to the source file). +

DB_MPOOL_DIRTY
The page has been modified and must be written to the source file +before being evicted from the pool. +

DB_MPOOL_DISCARD
The page is unlikely to be useful in the near future, +and should be discarded before other pages in the pool. +
+

The DB_MPOOL_CLEAN and DB_MPOOL_DIRTY flags are +mutually exclusive. +

The memp_fput function returns a non-zero error value on failure and 0 on success. +

Errors

+

The memp_fput function may fail and return a non-zero error for the following conditions: +

+

EACCES
The DB_MPOOL_DIRTY flag was set and the source file was not opened for +writing. +
+

+

EINVAL
An invalid flag value or parameter was specified. +

The pgaddr parameter does not reference a page returned by +memp_fget. +

More than one of DB_MPOOL_CLEAN and DB_MPOOL_DIRTY flags was set. +

+

The memp_fput function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the memp_fput function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBENV->set_mp_mmapsize, +memp_fclose, +memp_fget, +memp_fopen, +memp_fput, +memp_fset, +memp_fsync, +memp_register, +memp_stat, +memp_sync +and +memp_trickle. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/memp_fset.html b/db/docs/api_c/memp_fset.html new file mode 100644 index 000000000..73acd322c --- /dev/null +++ b/db/docs/api_c/memp_fset.html @@ -0,0 +1,72 @@ + + + + + +Berkeley DB: memp_fset + + + + + + + +
+

memp_fset

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +memp_fset(DB_MPOOLFILE *mpf, void *pgaddr, u_int32_t flags); +

+

Description

+

The memp_fset function sets the flags associated with the page referenced +by pgaddr without unpinning it from the pool. The pgaddr +argument must be an address previously returned by memp_fget. +

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +

+

DB_MPOOL_CLEAN
Clear any previously set modification information (i.e., don't bother +writing the page back to the source file). +

DB_MPOOL_DIRTY
The page has been modified and must be written to the source file +before being evicted from the pool. +

DB_MPOOL_DISCARD
The page is unlikely to be useful in the near future, +and should be discarded before other pages in the pool. +
+

The DB_MPOOL_CLEAN and DB_MPOOL_DIRTY flags are +mutually exclusive. +

The memp_fset function returns a non-zero error value on failure and 0 on success. +

Errors

+

The memp_fset function may fail and return a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +
+

The memp_fset function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the memp_fset function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBENV->set_mp_mmapsize, +memp_fclose, +memp_fget, +memp_fopen, +memp_fput, +memp_fset, +memp_fsync, +memp_register, +memp_stat, +memp_sync +and +memp_trickle. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/memp_fsync.html b/db/docs/api_c/memp_fsync.html new file mode 100644 index 000000000..ad429ccf3 --- /dev/null +++ b/db/docs/api_c/memp_fsync.html @@ -0,0 +1,59 @@ + + + + + +Berkeley DB: memp_fsync + + + + + + + +
+

memp_fsync

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +memp_fsync(DB_MPOOLFILE *mpf); +

+

Description

+

The memp_fsync function writes all pages associated with the +DB_MPOOLFILE, that were marked as modified using memp_fput +or memp_fset, back to the source file. If any of the modified +pages are also pinned (i.e., currently referenced by this or +another process) memp_fsync will ignore them. +

The memp_fsync function returns a non-zero error value on failure, 0 on success, and returns DB_INCOMPLETE if there were pages which were +modified but which memp_fsync was unable to write immediately. +

Errors

+

The memp_fsync function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the memp_fsync function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBENV->set_mp_mmapsize, +memp_fclose, +memp_fget, +memp_fopen, +memp_fput, +memp_fset, +memp_fsync, +memp_register, +memp_stat, +memp_sync +and +memp_trickle. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/memp_register.html b/db/docs/api_c/memp_register.html new file mode 100644 index 000000000..7c50a89ed --- /dev/null +++ b/db/docs/api_c/memp_register.html @@ -0,0 +1,93 @@ + + + + + +Berkeley DB: memp_register + + + + + + + +
+

memp_register

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +memp_register(DB_ENV *env, int ftype, + int (*pgin_fcn)(DB_ENV *, db_pgno_t pgno, void *pgaddr, DBT *pgcookie), + int (*pgout_fcn)(DB_ENV *, db_pgno_t pgno, void *pgaddr, DBT *pgcookie)); +

+

Description

+

The memp_register function registers page-in and page-out +functions for files of type ftype in the specified pool. +

If the pgin_fcn function is non-NULL, it is called each time +a page is read into the memory pool from a file of type ftype, or +a page is created for a file of type ftype (see the +DB_MPOOL_CREATE flag for the memp_fget function). +

If the pgout_fcn function is non-NULL, it is called each time +a page is written to a file of type ftype. +

Both the pgin_fcn and pgout_fcn functions are called with +a reference to the current environment, the page number, a pointer to the +page being read or written, and any argument pgcookie that was +specified to the memp_fopen function when the file was opened. +The pgin_fcn and pgout_fcn functions should return 0 on +success, and an applicable non-zero errno value on failure, in +which case the shared memory pool interface routine (and, by extension, +any Berkeley DB library function) calling it will also fail, returning that +errno value. +

The purpose of the memp_register function is to support processing +when pages are entered into, or flushed from, the pool. A file type must +be specified to make it possible for unrelated threads or processes, that +are sharing a pool, to evict each other's pages from the pool. +Applications should call memp_register, during initialization, +for each type of file requiring input or output processing that will be +sharing the underlying pool. (No registry is necessary for the standard +Berkeley DB access method types, as DB->open registers them +separately.) +

If a thread or process does not call memp_register for a file +type, it is impossible for it to evict pages for any file requiring input +or output processing from the pool. For this reason, +memp_register should always be called by each application sharing +a pool for each type of file included in the pool, regardless of whether +or not the application itself uses files of that type. +

There are no standard values for ftype, pgin_fcn, +pgout_fcn and pgcookie, except that the ftype +value for a file must be a non-zero positive number, as negative numbers +are reserved for internal use by the Berkeley DB library. For this reason, +applications sharing a pool must coordinate their values amongst +themselves. +

The memp_register function returns a non-zero error value on failure and 0 on success. +

Errors

+

The memp_register function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the memp_register function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBENV->set_mp_mmapsize, +memp_fclose, +memp_fget, +memp_fopen, +memp_fput, +memp_fset, +memp_fsync, +memp_register, +memp_stat, +memp_sync +and +memp_trickle. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/memp_stat.html b/db/docs/api_c/memp_stat.html new file mode 100644 index 000000000..8e9d136a9 --- /dev/null +++ b/db/docs/api_c/memp_stat.html @@ -0,0 +1,118 @@ + + + + + +Berkeley DB: memp_stat + + + + + + + +
+

memp_stat

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +memp_stat(DB_ENV *env, DB_MPOOL_STAT **gsp, + DB_MPOOL_FSTAT *(*fsp)[], void *(*db_malloc)(size_t)); +

+

Description

+

The memp_stat function method creates statistical structures and copies +pointers to them into user-specified memory locations. The statistics +include the number of files participating in the pool, the active pages +in the pool, and information as to how effective the cache has been. +

Statistical structures are created in allocated memory. If db_malloc is non-NULL, it +is called to allocate the memory, otherwise, the library function +malloc(3) is used. The function db_malloc must match +the calling conventions of the malloc(3) library routine. +Regardless, the caller is responsible for deallocating the returned +memory. To deallocate returned memory, free the returned memory +reference, references inside the returned memory do not need to be +individually freed. +

If gsp is non-NULL, the global statistics for the memory pool +mp are copied into the memory location it references. The +global statistics are stored in a structure of type DB_MPOOL_STAT. +

The following DB_MPOOL_STAT fields will be filled in: +

+
size_t st_gbytes;
Gigabytes of cache (total cache size is st_gbytes + st_bytes) +
size_t st_bytes;
Bytes of cache (total cache size is st_gbytes + st_bytes) +
u_int32_t st_ncache;
Number of caches. +
u_int32_t st_regsize;
Individual cache size. +
u_int32_t st_cache_hit;
Requested pages found in the cache. +
u_int32_t st_cache_miss;
Requested pages not found in the cache. +
u_int32_t st_map;
Requested pages mapped into the process' address space (there is no +available information as to whether or not this request caused disk I/O, +although examining the application page fault rate may be helpful). +
u_int32_t st_page_create;
Pages created in the cache. +
u_int32_t st_page_in;
Pages read into the cache. +
u_int32_t st_page_out;
Pages written from the cache to the backing file. +
u_int32_t st_ro_evict;
Clean pages forced from the cache. +
u_int32_t st_rw_evict;
Dirty pages forced from the cache. +
u_int32_t st_hash_buckets;
Number of hash buckets in buffer hash table. +
u_int32_t st_hash_searches;
Total number of buffer hash table lookups. +
u_int32_t st_hash_longest;
The longest chain ever encountered in buffer hash table lookups. +
u_int32_t st_hash_examined;
Total number of hash elements traversed during hash table lookups. +
u_int32_t st_page_clean;
Clean pages currently in the cache. +
u_int32_t st_page_dirty;
Dirty pages currently in the cache. +
u_int32_t st_page_trickle;
Dirty pages written using the memp_trickle interface. +
u_int32_t st_region_wait;
The number of times that a thread of control was forced to wait before +obtaining the region lock. +
u_int32_t st_region_nowait;
The number of times that a thread of control was able to obtain +the region lock without waiting. +
+

If fsp is non-NULL, a pointer to a NULL-terminated variable +length array of statistics for individual files, in the memory pool mp, +is copied into the memory location it references. If no individual files +currently exist in the memory pool, fsp will be set to NULL. +

The per-file statistics are stored in structures of type DB_MPOOL_FSTAT. +The following DB_MPOOL_FSTAT fields will be filled in for each file in +the pool, i.e., each element of the array: +

+
char *file_name;
The name of the file. +
size_t st_pagesize;
Page size in bytes. +
u_int32_t st_cache_hit;
Requested pages found in the cache. +
u_int32_t st_cache_miss;
Requested pages not found in the cache. +
u_int32_t st_map;
Requested pages mapped into the process' address space. +
u_int32_t st_page_create;
Pages created in the cache. +
u_int32_t st_page_in;
Pages read into the cache. +
u_int32_t st_page_out;
Pages written from the cache to the backing file. +
+

The memp_stat function returns a non-zero error value on failure and 0 on success. +

Errors

+

The memp_stat function may fail and return a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +
+

The memp_stat function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the memp_stat function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBENV->set_mp_mmapsize, +memp_fclose, +memp_fget, +memp_fopen, +memp_fput, +memp_fset, +memp_fsync, +memp_register, +memp_stat, +memp_sync +and +memp_trickle. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/memp_sync.html b/db/docs/api_c/memp_sync.html new file mode 100644 index 000000000..fc693d47e --- /dev/null +++ b/db/docs/api_c/memp_sync.html @@ -0,0 +1,83 @@ + + + + + +Berkeley DB: memp_sync + + + + + + + +
+

memp_sync

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +memp_sync(DB_ENV *env, DB_LSN *lsn); +

+

Description

+

The memp_sync function ensures that any modified pages in the pool with +log sequence numbers less than the lsn argument are written to +disk. If lsn is NULL all modified pages in the pool are +flushed. +

The primary purpose of the memp_sync function is to enable a +transaction manager to ensure, as part of a checkpoint, that all pages +modified by a certain time have been written to disk. Pages in the pool +that cannot be written back to disk immediately (e.g., that are currently +pinned) are written to disk as soon as it is possible to do so. The +expected behavior of the Berkeley DB or other transaction subsystem is to call +the memp_sync function and then, if the return indicates that some +pages could not be written immediately, to wait briefly and retry again +with the same log sequence number until the memp_sync function +returns that all pages have been written. +

To support the memp_sync functionality, it is necessary that the +pool functions know the location of the log sequence number on the page +for each file type. This location should be specified when the file is +opened using the memp_fopen function. It is not required that +the log sequence number be aligned on the page in any way. +

The memp_sync function returns a non-zero error value on failure, 0 on success, and returns DB_INCOMPLETE if there were pages which need to be +written but which memp_sync was unable to write immediately. +In addition, if memp_sync returns success, the value of +lsn will be overwritten with the largest log sequence number +from any page which was written by memp_sync to satisfy this +request. +

Errors

+

The memp_sync function may fail and return a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +

The memp_sync function was called without logging having been +initialized in the environment. +

+

The memp_sync function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the memp_sync function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBENV->set_mp_mmapsize, +memp_fclose, +memp_fget, +memp_fopen, +memp_fput, +memp_fset, +memp_fsync, +memp_register, +memp_stat, +memp_sync +and +memp_trickle. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/memp_trickle.html b/db/docs/api_c/memp_trickle.html new file mode 100644 index 000000000..d7cfd7230 --- /dev/null +++ b/db/docs/api_c/memp_trickle.html @@ -0,0 +1,66 @@ + + + + + +Berkeley DB: memp_trickle + + + + + + + +
+

memp_trickle

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +memp_trickle(DB_ENV *env, int pct, int *nwrotep); +

+

Description

+

The memp_trickle function ensures that at least pct percent of +the pages in the shared memory pool are clean by writing dirty pages to +their backing files. +If the nwrotep argument is non-NULL, the number of pages that +were written to reach the correct percentage is returned in the memory +location it references. +

The purpose of the memp_trickle function is to enable a memory +pool manager to ensure that a page is always available for reading in new +information without having to wait for a write. +

The memp_trickle function returns a non-zero error value on failure and 0 on success. +

Errors

+

The memp_trickle function may fail and return a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +
+

The memp_trickle function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the memp_trickle function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBENV->set_mp_mmapsize, +memp_fclose, +memp_fget, +memp_fopen, +memp_fput, +memp_fset, +memp_fsync, +memp_register, +memp_stat, +memp_sync +and +memp_trickle. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/pindex.src b/db/docs/api_c/pindex.src new file mode 100644 index 000000000..1818c50a6 --- /dev/null +++ b/db/docs/api_c/pindex.src @@ -0,0 +1,301 @@ +__APIREL__/api_c/db_create.html#2 @db_create +__APIREL__/api_c/db_create.html#DB_XA_CREATE db_create@DB_XA_CREATE +__APIREL__/api_c/db_err.html#2 @DBENV-__GT__err +__APIREL__/api_c/db_lsn.html#2 @DB_LSN +__APIREL__/api_c/db_set_errfile.html#2 @DB-__GT__set_errfile +__APIREL__/api_c/db_set_malloc.html#2 @DB-__GT__set_malloc +__APIREL__/api_c/db_set_paniccall.html#2 @DB-__GT__set_paniccall +__APIREL__/api_c/db_set_realloc.html#2 @DB-__GT__set_realloc +__APIREL__/api_c/dbm.html#2 @dbm/ndbm +__APIREL__/api_c/dbt.html#2 @key/data pairs +__APIREL__/api_c/dbt.html#data DBT@data +__APIREL__/api_c/dbt.html#size DBT@size +__APIREL__/api_c/dbt.html#ulen DBT@ulen +__APIREL__/api_c/dbt.html#dlen DBT@dlen +__APIREL__/api_c/dbt.html#doff DBT@doff +__APIREL__/api_c/dbt.html#DB_DBT_MALLOC DBT@DB_DBT_MALLOC +__APIREL__/api_c/dbt.html#DB_DBT_REALLOC DBT@DB_DBT_REALLOC +__APIREL__/api_c/dbt.html#DB_DBT_USERMEM DBT@DB_DBT_USERMEM +__APIREL__/api_c/dbt.html#DB_DBT_PARTIAL DBT@DB_DBT_PARTIAL +__APIREL__/api_c/dbt.html#3 retrieved key/data @permanence +__APIREL__/api_c/dbt.html#4 retrieved @key/data permanence +__APIREL__/api_c/dbt.html#5 data @alignment +__APIREL__/api_c/dbt.html#6 logical @record number format +__APIREL__/api_c/env_create.html#2 @db_env_create +__APIREL__/api_c/env_create.html#DB_CLIENT db_env_create@DB_CLIENT +__APIREL__/api_c/env_set_errfile.html#2 @DBENV-__GT__set_errfile +__APIREL__/api_c/env_set_paniccall.html#2 @DBENV-__GT__set_paniccall +__APIREL__/api_c/hsearch.html#2 @hsearch +__APIREL__/api_c/set_func_close.html#2 @db_env_set_func_close +__APIREL__/api_c/set_func_dirfree.html#2 @db_env_set_func_dirfree +__APIREL__/api_c/set_func_dirlist.html#2 @db_env_set_func_dirlist +__APIREL__/api_c/set_func_exists.html#2 @db_env_set_func_exists +__APIREL__/api_c/set_func_free.html#2 @db_env_set_func_free +__APIREL__/api_c/set_func_fsync.html#2 @db_env_set_func_fsync +__APIREL__/api_c/set_func_ioinfo.html#2 @db_env_set_func_ioinfo +__APIREL__/api_c/set_func_malloc.html#2 @db_env_set_func_malloc +__APIREL__/api_c/set_func_map.html#2 @db_env_set_func_map +__APIREL__/api_c/set_func_open.html#2 @db_env_set_func_open +__APIREL__/api_c/set_func_read.html#2 @db_env_set_func_read +__APIREL__/api_c/set_func_realloc.html#2 @db_env_set_func_realloc +__APIREL__/api_c/set_func_rename.html#2 @db_env_set_func_rename +__APIREL__/api_c/set_func_seek.html#2 @db_env_set_func_seek +__APIREL__/api_c/set_func_sleep.html#2 @db_env_set_func_sleep +__APIREL__/api_c/set_func_unlink.html#2 @db_env_set_func_unlink +__APIREL__/api_c/set_func_unmap.html#2 @db_env_set_func_unmap +__APIREL__/api_c/set_func_write.html#2 @db_env_set_func_write +__APIREL__/api_c/set_func_yield.html#2 @db_env_set_func_yield +__APIREL__/api_c/db_close.html#2 @DB-__GT__close +__APIREL__/api_c/db_close.html#DB_NOSYNC DB-__GT__close@DB_NOSYNC +__APIREL__/api_c/db_close.html#3 DB-__GT__close @DB_INCOMPLETE +__APIREL__/api_c/db_cursor.html#2 @DB-__GT__cursor +__APIREL__/api_c/db_cursor.html#DB_WRITECURSOR DB-__GT__cursor@DB_WRITECURSOR +__APIREL__/api_c/db_del.html#2 @DB-__GT__del +__APIREL__/api_c/db_fd.html#2 @DB-__GT__fd +__APIREL__/api_c/db_get.html#2 @DB-__GT__get +__APIREL__/api_c/db_get.html#DB_CONSUME DB-__GT__get@DB_CONSUME +__APIREL__/api_c/db_get.html#DB_CONSUME_WAIT DB-__GT__get@DB_CONSUME_WAIT +__APIREL__/api_c/db_get.html#DB_GET_BOTH DB-__GT__get@DB_GET_BOTH +__APIREL__/api_c/db_get.html#DB_SET_RECNO DB-__GT__get@DB_SET_RECNO +__APIREL__/api_c/db_get.html#DB_RMW DB-__GT__get@DB_RMW +__APIREL__/api_c/db_get_byteswapped.html#2 @DB-__GT__get_byteswapped +__APIREL__/api_c/db_get_type.html#2 @DB-__GT__get_type +__APIREL__/api_c/db_join.html#2 @DB-__GT__join +__APIREL__/api_c/db_join.html#DB_JOIN_NOSORT DB-__GT__join@DB_JOIN_NOSORT +__APIREL__/api_c/db_join.html#DB_JOIN_ITEM DB-__GT__join@DB_JOIN_ITEM +__APIREL__/api_c/db_join.html#DB_RMW DB-__GT__join@DB_RMW +__APIREL__/api_c/db_key_range.html#2 @DB-__GT__key_range +__APIREL__/api_c/db_open.html#2 @DB-__GT__open +__APIREL__/api_c/db_open.html#DB_CREATE DB-__GT__open@DB_CREATE +__APIREL__/api_c/db_open.html#DB_EXCL DB-__GT__open@DB_EXCL +__APIREL__/api_c/db_open.html#DB_NOMMAP DB-__GT__open@DB_NOMMAP +__APIREL__/api_c/db_open.html#DB_RDONLY DB-__GT__open@DB_RDONLY +__APIREL__/api_c/db_open.html#DB_THREAD DB-__GT__open@DB_THREAD +__APIREL__/api_c/db_open.html#DB_TRUNCATE DB-__GT__open@DB_TRUNCATE +__APIREL__/api_c/db_open.html#DB_OLD_VERSION DB-__GT__open@DB_OLD_VERSION +__APIREL__/api_c/db_put.html#2 @DB-__GT__put +__APIREL__/api_c/db_put.html#DB_APPEND DB-__GT__put@DB_APPEND +__APIREL__/api_c/db_put.html#DB_NODUPDATA DB-__GT__put@DB_NODUPDATA +__APIREL__/api_c/db_put.html#DB_NOOVERWRITE DB-__GT__put@DB_NOOVERWRITE +__APIREL__/api_c/db_remove.html#2 @DB-__GT__remove +__APIREL__/api_c/db_rename.html#2 @DB-__GT__rename +__APIREL__/api_c/db_set_append_recno.html#2 @DB-__GT__set_append_recno +__APIREL__/api_c/db_set_bt_compare.html#2 @DB-__GT__set_bt_compare +__APIREL__/api_c/db_set_bt_minkey.html#2 @DB-__GT__set_bt_minkey +__APIREL__/api_c/db_set_bt_prefix.html#2 @DB-__GT__set_bt_prefix +__APIREL__/api_c/db_set_cachesize.html#2 @DB-__GT__set_cachesize +__APIREL__/api_c/db_set_dup_compare.html#2 @DB-__GT__set_dup_compare +__APIREL__/api_c/db_set_errcall.html#2 @DB-__GT__set_errcall +__APIREL__/api_c/db_set_errpfx.html#2 @DB-__GT__set_errpfx +__APIREL__/api_c/db_set_feedback.html#2 @DB-__GT__set_feedback +__APIREL__/api_c/db_set_feedback.html#DB_UPGRADE DB-__GT__set_feedback@DB_UPGRADE +__APIREL__/api_c/db_set_feedback.html#DB_VERIFY DB-__GT__set_feedback@DB_VERIFY +__APIREL__/api_c/db_set_flags.html#2 @DB-__GT__set_flags +__APIREL__/api_c/db_set_flags.html#DB_DUP DB-__GT__set_flags@DB_DUP +__APIREL__/api_c/db_set_flags.html#DB_DUPSORT DB-__GT__set_flags@DB_DUPSORT +__APIREL__/api_c/db_set_flags.html#DB_RECNUM DB-__GT__set_flags@DB_RECNUM +__APIREL__/api_c/db_set_flags.html#DB_REVSPLITOFF DB-__GT__set_flags@DB_REVSPLITOFF +__APIREL__/api_c/db_set_flags.html#DB_DUP DB-__GT__set_flags@DB_DUP +__APIREL__/api_c/db_set_flags.html#DB_DUPSORT DB-__GT__set_flags@DB_DUPSORT +__APIREL__/api_c/db_set_flags.html#DB_RENUMBER DB-__GT__set_flags@DB_RENUMBER +__APIREL__/api_c/db_set_flags.html#DB_SNAPSHOT DB-__GT__set_flags@DB_SNAPSHOT +__APIREL__/api_c/db_set_h_ffactor.html#2 @DB-__GT__set_h_ffactor +__APIREL__/api_c/db_set_h_hash.html#2 @DB-__GT__set_h_hash +__APIREL__/api_c/db_set_h_nelem.html#2 @DB-__GT__set_h_nelem +__APIREL__/api_c/db_set_lorder.html#2 @DB-__GT__set_lorder +__APIREL__/api_c/db_set_pagesize.html#2 @DB-__GT__set_pagesize +__APIREL__/api_c/db_set_q_extentsize.html#2 @DB-__GT__set_q_extentsize +__APIREL__/api_c/db_set_re_delim.html#2 @DB-__GT__set_re_delim +__APIREL__/api_c/db_set_re_len.html#2 @DB-__GT__set_re_len +__APIREL__/api_c/db_set_re_pad.html#2 @DB-__GT__set_re_pad +__APIREL__/api_c/db_set_re_source.html#2 @DB-__GT__set_re_source +__APIREL__/api_c/db_stat.html#2 @DB-__GT__stat +__APIREL__/api_c/db_stat.html#DB_CACHED_COUNTS DB-__GT__stat@DB_CACHED_COUNTS +__APIREL__/api_c/db_stat.html#DB_RECORDCOUNT DB-__GT__stat@DB_RECORDCOUNT +__APIREL__/api_c/db_sync.html#2 @DB-__GT__sync +__APIREL__/api_c/db_upgrade.html#2 @DB-__GT__upgrade +__APIREL__/api_c/db_upgrade.html#DB_DUPSORT DB-__GT__upgrade@DB_DUPSORT +__APIREL__/api_c/db_upgrade.html#DB_OLD_VERSION DB-__GT__upgrade@DB_OLD_VERSION +__APIREL__/api_c/db_verify.html#2 @DB-__GT__verify +__APIREL__/api_c/db_verify.html#DB_SALVAGE DB-__GT__verify@DB_SALVAGE +__APIREL__/api_c/db_verify.html#DB_AGGRESSIVE DB-__GT__verify@DB_AGGRESSIVE +__APIREL__/api_c/db_verify.html#DB_NOORDERCHK DB-__GT__verify@DB_NOORDERCHK +__APIREL__/api_c/db_verify.html#DB_ORDERCHKONLY DB-__GT__verify@DB_ORDERCHKONLY +__APIREL__/api_c/dbc_close.html#2 @DBcursor-__GT__c_close +__APIREL__/api_c/dbc_count.html#2 @DBcursor-__GT__c_count +__APIREL__/api_c/dbc_del.html#2 @DBcursor-__GT__c_del +__APIREL__/api_c/dbc_dup.html#2 @DBcursor-__GT__c_dup +__APIREL__/api_c/dbc_dup.html#DB_POSITION DBcursor-__GT__c_dup@DB_POSITION +__APIREL__/api_c/dbc_get.html#2 @DBcursor-__GT__c_get +__APIREL__/api_c/dbc_get.html#DB_CURRENT DBcursor-__GT__c_get@DB_CURRENT +__APIREL__/api_c/dbc_get.html#DB_FIRST DBcursor-__GT__c_get@DB_FIRST +__APIREL__/api_c/dbc_get.html#DB_LAST DBcursor-__GT__c_get@DB_LAST +__APIREL__/api_c/dbc_get.html#DB_GET_BOTH DBcursor-__GT__c_get@DB_GET_BOTH +__APIREL__/api_c/dbc_get.html#DB_GET_RECNO DBcursor-__GT__c_get@DB_GET_RECNO +__APIREL__/api_c/dbc_get.html#DB_JOIN_ITEM DBcursor-__GT__c_get@DB_JOIN_ITEM +__APIREL__/api_c/dbc_get.html#DB_NEXT DBcursor-__GT__c_get@DB_NEXT +__APIREL__/api_c/dbc_get.html#DB_PREV DBcursor-__GT__c_get@DB_PREV +__APIREL__/api_c/dbc_get.html#DB_NEXT_DUP DBcursor-__GT__c_get@DB_NEXT_DUP +__APIREL__/api_c/dbc_get.html#DB_NEXT_NODUP DBcursor-__GT__c_get@DB_NEXT_NODUP +__APIREL__/api_c/dbc_get.html#DB_PREV_NODUP DBcursor-__GT__c_get@DB_PREV_NODUP +__APIREL__/api_c/dbc_get.html#DB_SET DBcursor-__GT__c_get@DB_SET +__APIREL__/api_c/dbc_get.html#DB_SET_RANGE DBcursor-__GT__c_get@DB_SET_RANGE +__APIREL__/api_c/dbc_get.html#DB_SET_RECNO DBcursor-__GT__c_get@DB_SET_RECNO +__APIREL__/api_c/dbc_get.html#DB_RMW DBcursor-__GT__c_get@DB_RMW +__APIREL__/api_c/dbc_put.html#2 @DBcursor-__GT__c_put +__APIREL__/api_c/dbc_put.html#DB_AFTER DBcursor-__GT__c_put@DB_AFTER +__APIREL__/api_c/dbc_put.html#DB_BEFORE DBcursor-__GT__c_put@DB_BEFORE +__APIREL__/api_c/dbc_put.html#DB_CURRENT DBcursor-__GT__c_put@DB_CURRENT +__APIREL__/api_c/dbc_put.html#DB_KEYFIRST DBcursor-__GT__c_put@DB_KEYFIRST +__APIREL__/api_c/dbc_put.html#DB_KEYLAST DBcursor-__GT__c_put@DB_KEYLAST +__APIREL__/api_c/dbc_put.html#DB_NODUPDATA DBcursor-__GT__c_put@DB_NODUPDATA +__APIREL__/api_c/env_close.html#2 @DBENV-__GT__close +__APIREL__/api_c/env_open.html#2 @DBENV-__GT__open +__APIREL__/api_c/env_open.html#DB_JOINENV DBENV-__GT__open@DB_JOINENV +__APIREL__/api_c/env_open.html#DB_INIT_CDB DBENV-__GT__open@DB_INIT_CDB +__APIREL__/api_c/env_open.html#DB_INIT_LOCK DBENV-__GT__open@DB_INIT_LOCK +__APIREL__/api_c/env_open.html#DB_INIT_LOG DBENV-__GT__open@DB_INIT_LOG +__APIREL__/api_c/env_open.html#DB_INIT_MPOOL DBENV-__GT__open@DB_INIT_MPOOL +__APIREL__/api_c/env_open.html#DB_INIT_TXN DBENV-__GT__open@DB_INIT_TXN +__APIREL__/api_c/env_open.html#DB_RECOVER DBENV-__GT__open@DB_RECOVER +__APIREL__/api_c/env_open.html#DB_RECOVER_FATAL DBENV-__GT__open@DB_RECOVER_FATAL +__APIREL__/api_c/env_open.html#DB_USE_ENVIRON DBENV-__GT__open@DB_USE_ENVIRON +__APIREL__/api_c/env_open.html#DB_USE_ENVIRON_ROOT DBENV-__GT__open@DB_USE_ENVIRON_ROOT +__APIREL__/api_c/env_open.html#DB_CREATE DBENV-__GT__open@DB_CREATE +__APIREL__/api_c/env_open.html#DB_LOCKDOWN DBENV-__GT__open@DB_LOCKDOWN +__APIREL__/api_c/env_open.html#DB_PRIVATE DBENV-__GT__open@DB_PRIVATE +__APIREL__/api_c/env_open.html#DB_SYSTEM_MEM DBENV-__GT__open@DB_SYSTEM_MEM +__APIREL__/api_c/env_open.html#DB_THREAD DBENV-__GT__open@DB_THREAD +__APIREL__/api_c/env_remove.html#2 @DBENV-__GT__remove +__APIREL__/api_c/env_remove.html#DB_FORCE DBENV-__GT__remove@DB_FORCE +__APIREL__/api_c/env_remove.html#DB_USE_ENVIRON DBENV-__GT__remove@DB_USE_ENVIRON +__APIREL__/api_c/env_remove.html#DB_USE_ENVIRON_ROOT DBENV-__GT__remove@DB_USE_ENVIRON_ROOT +__APIREL__/api_c/env_set_cachesize.html#2 @DBENV-__GT__set_cachesize +__APIREL__/api_c/env_set_data_dir.html#2 @DBENV-__GT__set_data_dir +__APIREL__/api_c/env_set_errcall.html#2 @DBENV-__GT__set_errcall +__APIREL__/api_c/env_set_errpfx.html#2 @DBENV-__GT__set_errpfx +__APIREL__/api_c/env_set_feedback.html#2 @DBENV-__GT__set_feedback +__APIREL__/api_c/env_set_feedback.html#DB_RECOVER DBENV-__GT__set_feedback@DB_RECOVER +__APIREL__/api_c/env_set_flags.html#2 @DBENV-__GT__set_flags +__APIREL__/api_c/env_set_flags.html#DB_CDB_ALLDB DBENV-__GT__set_flags@DB_CDB_ALLDB +__APIREL__/api_c/env_set_flags.html#DB_NOMMAP DBENV-__GT__set_flags@DB_NOMMAP +__APIREL__/api_c/env_set_flags.html#DB_TXN_NOSYNC DBENV-__GT__set_flags@DB_TXN_NOSYNC +__APIREL__/api_c/env_set_lg_bsize.html#2 @DBENV-__GT__set_lg_bsize +__APIREL__/api_c/env_set_lg_dir.html#2 @DBENV-__GT__set_lg_dir +__APIREL__/api_c/env_set_lg_max.html#2 @DBENV-__GT__set_lg_max +__APIREL__/api_c/env_set_lk_conflicts.html#2 @DBENV-__GT__set_lk_conflicts +__APIREL__/api_c/env_set_lk_detect.html#2 @DBENV-__GT__set_lk_detect +__APIREL__/api_c/env_set_lk_detect.html#DB_LOCK_DEFAULT DBENV-__GT__set_lk_detect@DB_LOCK_DEFAULT +__APIREL__/api_c/env_set_lk_detect.html#DB_LOCK_OLDEST DBENV-__GT__set_lk_detect@DB_LOCK_OLDEST +__APIREL__/api_c/env_set_lk_detect.html#DB_LOCK_RANDOM DBENV-__GT__set_lk_detect@DB_LOCK_RANDOM +__APIREL__/api_c/env_set_lk_detect.html#DB_LOCK_YOUNGEST DBENV-__GT__set_lk_detect@DB_LOCK_YOUNGEST +__APIREL__/api_c/env_set_lk_max.html#2 @DBENV-__GT__set_lk_max +__APIREL__/api_c/env_set_lk_max_locks.html#2 @DBENV-__GT__set_lk_max_locks +__APIREL__/api_c/env_set_lk_max_lockers.html#2 @DBENV-__GT__set_lk_max_lockers +__APIREL__/api_c/env_set_lk_max_objects.html#2 @DBENV-__GT__set_lk_max_objects +__APIREL__/api_c/env_set_mp_mmapsize.html#2 @DBENV-__GT__set_mp_mmapsize +__APIREL__/api_c/env_set_mutexlocks.html#2 @DBENV-__GT__set_mutexlocks +__APIREL__/api_c/env_set_pageyield.html#2 @db_env_set_pageyield +__APIREL__/api_c/env_set_panicstate.html#2 @db_env_set_panicstate +__APIREL__/api_c/env_set_rec_init.html#2 @DBENV-__GT__set_recovery_init +__APIREL__/api_c/env_set_region_init.html#2 @db_env_set_region_init +__APIREL__/api_c/env_set_server.html#2 @DBENV-__GT__set_server +__APIREL__/api_c/env_set_server.html#DB_NOSERVER DBENV-__GT__set_server@DB_NOSERVER +__APIREL__/api_c/env_set_server.html#DB_NOSERVER_ID DBENV-__GT__set_server@DB_NOSERVER_ID +__APIREL__/api_c/env_set_shm_key.html#2 @DBENV-__GT__set_shm_key +__APIREL__/api_c/env_set_tas_spins.html#2 @db_env_set_tas_spins +__APIREL__/api_c/env_set_tmp_dir.html#2 @DBENV-__GT__set_tmp_dir +__APIREL__/api_c/env_set_tx_max.html#2 @DBENV-__GT__set_tx_max +__APIREL__/api_c/env_set_tx_recover.html#2 @DBENV-__GT__set_tx_recover +__APIREL__/api_c/env_set_tx_recover.html#DB_TXN_BACKWARD_ROLL DBENV-__GT__set_tx_recover@DB_TXN_BACKWARD_ROLL +__APIREL__/api_c/env_set_tx_recover.html#DB_TXN_FORWARD_ROLL DBENV-__GT__set_tx_recover@DB_TXN_FORWARD_ROLL +__APIREL__/api_c/env_set_tx_recover.html#DB_TXN_ABORT DBENV-__GT__set_tx_recover@DB_TXN_ABORT +__APIREL__/api_c/env_set_tx_timestamp.html#2 @DBENV-__GT__set_tx_timestamp +__APIREL__/api_c/env_set_verbose.html#2 @DBENV-__GT__set_verbose +__APIREL__/api_c/env_set_verbose.html#DB_VERB_CHKPOINT DBENV-__GT__set_verbose@DB_VERB_CHKPOINT +__APIREL__/api_c/env_set_verbose.html#DB_VERB_DEADLOCK DBENV-__GT__set_verbose@DB_VERB_DEADLOCK +__APIREL__/api_c/env_set_verbose.html#DB_VERB_RECOVERY DBENV-__GT__set_verbose@DB_VERB_RECOVERY +__APIREL__/api_c/env_set_verbose.html#DB_VERB_WAITSFOR DBENV-__GT__set_verbose@DB_VERB_WAITSFOR +__APIREL__/api_c/env_strerror.html#2 @db_strerror +__APIREL__/api_c/env_version.html#2 @db_version +__APIREL__/api_c/lock_detect.html#2 @lock_detect +__APIREL__/api_c/lock_detect.html#DB_LOCK_CONFLICT lock_detect@DB_LOCK_CONFLICT +__APIREL__/api_c/lock_get.html#2 @lock_get +__APIREL__/api_c/lock_get.html#DB_LOCK_NOWAIT lock_get@DB_LOCK_NOWAIT +__APIREL__/api_c/lock_get.html#DB_LOCK_NOTGRANTED lock_get@DB_LOCK_NOTGRANTED +__APIREL__/api_c/lock_id.html#2 @lock_id +__APIREL__/api_c/lock_put.html#2 @lock_put +__APIREL__/api_c/lock_stat.html#2 @lock_stat +__APIREL__/api_c/lock_vec.html#2 @lock_vec +__APIREL__/api_c/lock_vec.html#DB_LOCK_NOWAIT lock_vec@DB_LOCK_NOWAIT +__APIREL__/api_c/lock_vec.html#op lock_vec@op +__APIREL__/api_c/lock_vec.html#DB_LOCK_GET lock_vec@DB_LOCK_GET +__APIREL__/api_c/lock_vec.html#DB_LOCK_PUT lock_vec@DB_LOCK_PUT +__APIREL__/api_c/lock_vec.html#DB_LOCK_PUT_ALL lock_vec@DB_LOCK_PUT_ALL +__APIREL__/api_c/lock_vec.html#DB_LOCK_PUT_OBJ lock_vec@DB_LOCK_PUT_OBJ +__APIREL__/api_c/lock_vec.html#obj lock_vec@obj +__APIREL__/api_c/lock_vec.html#mode lock_vec@mode +__APIREL__/api_c/lock_vec.html#lock lock_vec@lock +__APIREL__/api_c/lock_vec.html#DB_LOCK_NOTGRANTED lock_vec@DB_LOCK_NOTGRANTED +__APIREL__/api_c/log_archive.html#2 @log_archive +__APIREL__/api_c/log_archive.html#DB_ARCH_ABS log_archive@DB_ARCH_ABS +__APIREL__/api_c/log_archive.html#DB_ARCH_DATA log_archive@DB_ARCH_DATA +__APIREL__/api_c/log_archive.html#DB_ARCH_LOG log_archive@DB_ARCH_LOG +__APIREL__/api_c/log_compare.html#2 @log_compare +__APIREL__/api_c/log_file.html#2 @log_file +__APIREL__/api_c/log_flush.html#2 @log_flush +__APIREL__/api_c/log_get.html#2 @log_get +__APIREL__/api_c/log_get.html#DB_CHECKPOINT log_get@DB_CHECKPOINT +__APIREL__/api_c/log_get.html#DB_FIRST log_get@DB_FIRST +__APIREL__/api_c/log_get.html#DB_LAST log_get@DB_LAST +__APIREL__/api_c/log_get.html#DB_NEXT log_get@DB_NEXT +__APIREL__/api_c/log_get.html#DB_PREV log_get@DB_PREV +__APIREL__/api_c/log_get.html#DB_CURRENT log_get@DB_CURRENT +__APIREL__/api_c/log_get.html#DB_SET log_get@DB_SET +__APIREL__/api_c/log_put.html#2 @log_put +__APIREL__/api_c/log_put.html#DB_CHECKPOINT log_put@DB_CHECKPOINT +__APIREL__/api_c/log_put.html#DB_CURLSN log_put@DB_CURLSN +__APIREL__/api_c/log_put.html#DB_FLUSH log_put@DB_FLUSH +__APIREL__/api_c/log_register.html#2 @log_register +__APIREL__/api_c/log_stat.html#2 @log_stat +__APIREL__/api_c/log_unregister.html#2 @log_unregister +__APIREL__/api_c/memp_fclose.html#2 @memp_fclose +__APIREL__/api_c/memp_fget.html#2 @memp_fget +__APIREL__/api_c/memp_fget.html#DB_MPOOL_CREATE memp_fget@DB_MPOOL_CREATE +__APIREL__/api_c/memp_fget.html#DB_MPOOL_LAST memp_fget@DB_MPOOL_LAST +__APIREL__/api_c/memp_fget.html#DB_MPOOL_NEW memp_fget@DB_MPOOL_NEW +__APIREL__/api_c/memp_fopen.html#2 @memp_fopen +__APIREL__/api_c/memp_fopen.html#DB_CREATE memp_fopen@DB_CREATE +__APIREL__/api_c/memp_fopen.html#DB_NOMMAP memp_fopen@DB_NOMMAP +__APIREL__/api_c/memp_fopen.html#DB_RDONLY memp_fopen@DB_RDONLY +__APIREL__/api_c/memp_fopen.html#ftype memp_fopen@ftype +__APIREL__/api_c/memp_fopen.html#pgcookie memp_fopen@pgcookie +__APIREL__/api_c/memp_fopen.html#fileid memp_fopen@fileid +__APIREL__/api_c/memp_fopen.html#lsn_offset memp_fopen@lsn_offset +__APIREL__/api_c/memp_fopen.html#clear_len memp_fopen@clear_len +__APIREL__/api_c/memp_fput.html#2 @memp_fput +__APIREL__/api_c/memp_fput.html#DB_MPOOL_CLEAN memp_fput@DB_MPOOL_CLEAN +__APIREL__/api_c/memp_fput.html#DB_MPOOL_DIRTY memp_fput@DB_MPOOL_DIRTY +__APIREL__/api_c/memp_fput.html#DB_MPOOL_DISCARD memp_fput@DB_MPOOL_DISCARD +__APIREL__/api_c/memp_fset.html#2 @memp_fset +__APIREL__/api_c/memp_fset.html#DB_MPOOL_CLEAN memp_fset@DB_MPOOL_CLEAN +__APIREL__/api_c/memp_fset.html#DB_MPOOL_DIRTY memp_fset@DB_MPOOL_DIRTY +__APIREL__/api_c/memp_fset.html#DB_MPOOL_DISCARD memp_fset@DB_MPOOL_DISCARD +__APIREL__/api_c/memp_fsync.html#2 @memp_fsync +__APIREL__/api_c/memp_register.html#2 @memp_register +__APIREL__/api_c/memp_stat.html#2 @memp_stat +__APIREL__/api_c/memp_sync.html#2 @memp_sync +__APIREL__/api_c/memp_trickle.html#2 @memp_trickle +__APIREL__/api_c/txn_abort.html#2 @txn_abort +__APIREL__/api_c/txn_begin.html#2 @txn_begin +__APIREL__/api_c/txn_begin.html#DB_TXN_NOSYNC txn_begin@DB_TXN_NOSYNC +__APIREL__/api_c/txn_begin.html#DB_TXN_NOWAIT txn_begin@DB_TXN_NOWAIT +__APIREL__/api_c/txn_begin.html#DB_TXN_SYNC txn_begin@DB_TXN_SYNC +__APIREL__/api_c/txn_checkpoint.html#2 @txn_checkpoint +__APIREL__/api_c/txn_checkpoint.html#DB_FORCE txn_checkpoint@DB_FORCE +__APIREL__/api_c/txn_commit.html#2 @txn_commit +__APIREL__/api_c/txn_commit.html#DB_TXN_NOSYNC txn_commit@DB_TXN_NOSYNC +__APIREL__/api_c/txn_commit.html#DB_TXN_SYNC txn_commit@DB_TXN_SYNC +__APIREL__/api_c/txn_id.html#2 @txn_id +__APIREL__/api_c/txn_prepare.html#2 @txn_prepare +__APIREL__/api_c/txn_stat.html#2 @txn_stat diff --git a/db/docs/api_c/set_func_close.html b/db/docs/api_c/set_func_close.html new file mode 100644 index 000000000..0d4af0aef --- /dev/null +++ b/db/docs/api_c/set_func_close.html @@ -0,0 +1,66 @@ + + + + + +Berkeley DB: db_env_set_func_close + + + + + + + +
+

db_env_set_func_close

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +db_env_set_func_close(int (*func_close)(int fd)); +

+

Description

+

Replace Berkeley DB calls to the IEEE/ANSI Std 1003.1 (POSIX) close function +with func_close, which must conform to the standard interface. +

The db_env_set_func_close interface affects the entire application, not a single +database or database environment. +

While the db_env_set_func_close interface may be used to configure Berkeley DB at any time +during the life of the application, it should normally be called before +making any calls to the db_env_create or db_create functions. +

The db_env_set_func_close function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

See Also

+db_env_set_func_close, +db_env_set_func_dirfree, +db_env_set_func_dirlist, +db_env_set_func_exists, +db_env_set_func_free, +db_env_set_func_fsync, +db_env_set_func_ioinfo, +db_env_set_func_malloc, +db_env_set_func_map, +db_env_set_func_open, +db_env_set_func_read, +db_env_set_func_realloc, +db_env_set_func_seek, +db_env_set_func_sleep, +db_env_set_func_unlink, +db_env_set_func_unmap, +db_env_set_func_write +and +db_env_set_func_yield. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/set_func_dirfree.html b/db/docs/api_c/set_func_dirfree.html new file mode 100644 index 000000000..249f69cc6 --- /dev/null +++ b/db/docs/api_c/set_func_dirfree.html @@ -0,0 +1,75 @@ + + + + + +Berkeley DB: db_env_set_func_dirfree + + + + + + + +
+

db_env_set_func_dirfree

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +db_env_set_func_dirfree(void (*func_dirfree)(char **namesp, int cnt)); +

+

Description

+

The Berkeley DB library requires the ability to return any memory allocated as part +of the routine which reads through a directory and creates a list of files +that that the directory contains (see db_env_set_func_dirlist). +The func_dirfree argument must conform to the following interface: +

int dirfree(char **namesp, int cnt);
+

The namesp and cnt arguments are the same values as were +returned by the db_env_set_func_dirlist function. +

The func_dirfree function must return the value of errno on +failure and 0 on success. +

The db_env_set_func_dirfree interface affects the entire application, not a single +database or database environment. +

While the db_env_set_func_dirfree interface may be used to configure Berkeley DB at any time +during the life of the application, it should normally be called before +making any calls to the db_env_create or db_create functions. +

The db_env_set_func_dirfree interface may only be used to configure Berkeley DB before +the DBENV->open interface is called. +

The db_env_set_func_dirfree function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

See Also

+db_env_set_func_close, +db_env_set_func_dirfree, +db_env_set_func_dirlist, +db_env_set_func_exists, +db_env_set_func_free, +db_env_set_func_fsync, +db_env_set_func_ioinfo, +db_env_set_func_malloc, +db_env_set_func_map, +db_env_set_func_open, +db_env_set_func_read, +db_env_set_func_realloc, +db_env_set_func_seek, +db_env_set_func_sleep, +db_env_set_func_unlink, +db_env_set_func_unmap, +db_env_set_func_write +and +db_env_set_func_yield. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/set_func_dirlist.html b/db/docs/api_c/set_func_dirlist.html new file mode 100644 index 000000000..5025912e5 --- /dev/null +++ b/db/docs/api_c/set_func_dirlist.html @@ -0,0 +1,78 @@ + + + + + +Berkeley DB: db_env_set_func_dirlist + + + + + + + +
+

db_env_set_func_dirlist

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +db_env_set_func_dirlist( + int (*func_dirlist)(const char *dir, char ***namesp, int *cntp)); +

+

Description

+

The Berkeley DB library requires the ability to read through a directory and +create a list of files that that the directory contains. The +func_dirlist argument must conform to the following interface: +

int dirlist(const char *dir, char ***namesp, int *cntp);
+

The dir argument is the name of the directory to be searched. +The function must return a pointer to an array of nul-terminated file +names in the memory location referenced by the argument namesp, +and a count of the number of elements in the array in the memory location +referenced by cntp. +

The func_dirlist function must return the value of errno on +failure and 0 on success. +

The db_env_set_func_dirlist interface affects the entire application, not a single +database or database environment. +

While the db_env_set_func_dirlist interface may be used to configure Berkeley DB at any time +during the life of the application, it should normally be called before +making any calls to the db_env_create or db_create functions. +

The db_env_set_func_dirlist interface may only be used to configure Berkeley DB before +the DBENV->open interface is called. +

The db_env_set_func_dirlist function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

See Also

+db_env_set_func_close, +db_env_set_func_dirfree, +db_env_set_func_dirlist, +db_env_set_func_exists, +db_env_set_func_free, +db_env_set_func_fsync, +db_env_set_func_ioinfo, +db_env_set_func_malloc, +db_env_set_func_map, +db_env_set_func_open, +db_env_set_func_read, +db_env_set_func_realloc, +db_env_set_func_seek, +db_env_set_func_sleep, +db_env_set_func_unlink, +db_env_set_func_unmap, +db_env_set_func_write +and +db_env_set_func_yield. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/set_func_exists.html b/db/docs/api_c/set_func_exists.html new file mode 100644 index 000000000..0b38b1e22 --- /dev/null +++ b/db/docs/api_c/set_func_exists.html @@ -0,0 +1,75 @@ + + + + + +Berkeley DB: db_env_set_func_exists + + + + + + + +
+

db_env_set_func_exists

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +db_env_set_func_exists(int (*func_exists)(const char *path, int *isdirp)); +

+

Description

+

The Berkeley DB library requires the ability to determine if a file exists, and +optionally, if it is a file of type directory. The func argument +must conform to the following interface: +

int exists(const char *path, int *isdirp);
+

The path argument is the pathname of the file to be checked. +

If the isdirp argument is non-NULL, it must be set to non-0 if +path is a directory, and 0 if path is not a directory. +

The func_exists function must return the value of errno on +failure and 0 on success. +

The db_env_set_func_exists interface affects the entire application, not a single +database or database environment. +

While the db_env_set_func_exists interface may be used to configure Berkeley DB at any time +during the life of the application, it should normally be called before +making any calls to the db_env_create or db_create functions. +

The db_env_set_func_exists interface may only be used to configure Berkeley DB before +the DBENV->open interface is called. +

The db_env_set_func_exists function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

See Also

+db_env_set_func_close, +db_env_set_func_dirfree, +db_env_set_func_dirlist, +db_env_set_func_exists, +db_env_set_func_free, +db_env_set_func_fsync, +db_env_set_func_ioinfo, +db_env_set_func_malloc, +db_env_set_func_map, +db_env_set_func_open, +db_env_set_func_read, +db_env_set_func_realloc, +db_env_set_func_seek, +db_env_set_func_sleep, +db_env_set_func_unlink, +db_env_set_func_unmap, +db_env_set_func_write +and +db_env_set_func_yield. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/set_func_free.html b/db/docs/api_c/set_func_free.html new file mode 100644 index 000000000..8b7b1afa6 --- /dev/null +++ b/db/docs/api_c/set_func_free.html @@ -0,0 +1,67 @@ + + + + + +Berkeley DB: db_env_set_func_free + + + + + + + +
+

db_env_set_func_free

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +db_env_set_func_free(void (*func_free)(void *ptr)); +

+

Description

+

Replace Berkeley DB calls to the ANSI C X3.159-1989 (ANSI C) standard +free function with func_free, which must conform to +the standard interface. +

The db_env_set_func_free interface affects the entire application, not a single +database or database environment. +

While the db_env_set_func_free interface may be used to configure Berkeley DB at any time +during the life of the application, it should normally be called before +making any calls to the db_env_create or db_create functions. +

The db_env_set_func_free function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

See Also

+db_env_set_func_close, +db_env_set_func_dirfree, +db_env_set_func_dirlist, +db_env_set_func_exists, +db_env_set_func_free, +db_env_set_func_fsync, +db_env_set_func_ioinfo, +db_env_set_func_malloc, +db_env_set_func_map, +db_env_set_func_open, +db_env_set_func_read, +db_env_set_func_realloc, +db_env_set_func_seek, +db_env_set_func_sleep, +db_env_set_func_unlink, +db_env_set_func_unmap, +db_env_set_func_write +and +db_env_set_func_yield. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/set_func_fsync.html b/db/docs/api_c/set_func_fsync.html new file mode 100644 index 000000000..f73956108 --- /dev/null +++ b/db/docs/api_c/set_func_fsync.html @@ -0,0 +1,66 @@ + + + + + +Berkeley DB: db_env_set_func_fsync + + + + + + + +
+

db_env_set_func_fsync

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +db_env_set_func_fsync(int (*func_fsync)(int fd)); +

+

Description

+

Replace Berkeley DB calls to the IEEE/ANSI Std 1003.1 (POSIX) fsync function +with func_fsync, which must conform to the standard interface. +

The db_env_set_func_fsync interface affects the entire application, not a single +database or database environment. +

While the db_env_set_func_fsync interface may be used to configure Berkeley DB at any time +during the life of the application, it should normally be called before +making any calls to the db_env_create or db_create functions. +

The db_env_set_func_fsync function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

See Also

+db_env_set_func_close, +db_env_set_func_dirfree, +db_env_set_func_dirlist, +db_env_set_func_exists, +db_env_set_func_free, +db_env_set_func_fsync, +db_env_set_func_ioinfo, +db_env_set_func_malloc, +db_env_set_func_map, +db_env_set_func_open, +db_env_set_func_read, +db_env_set_func_realloc, +db_env_set_func_seek, +db_env_set_func_sleep, +db_env_set_func_unlink, +db_env_set_func_unmap, +db_env_set_func_write +and +db_env_set_func_yield. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/set_func_ioinfo.html b/db/docs/api_c/set_func_ioinfo.html new file mode 100644 index 000000000..3a0143e57 --- /dev/null +++ b/db/docs/api_c/set_func_ioinfo.html @@ -0,0 +1,83 @@ + + + + + +Berkeley DB: db_env_set_func_ioinfo + + + + + + + +
+

db_env_set_func_ioinfo

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +db_env_set_func_ioinfo(int (*func_ioinfo)(const char *path, + int fd, u_int32_t *mbytesp, u_int32_t *bytesp, u_int32_t *iosizep)); +

+

Description

+

The Berkeley DB library requires the ability to determine the size and I/O +characteristics of a file. The func_ioinfo argument must conform +to the following interface: +

int ioinfo(const char *path, int fd,
+u_int32_t *mbytesp, u_int32_t *bytesp, u_int32_t *iosizep);
+

The path argument is the pathname of the file to be checked, and the +fd argument is an open file descriptor on the file. +

If the mbytesp and bytesp arguments are non-NULL, the +ioinfo function must return in them the size of the file: the +number of megabytes in the file into the memory location referenced by +the mbytesp argument, and the number of bytes over and above that +number of megabytes into the memory location referenced by the +bytesp argument. +

In addition, if the iosizep argument is non-NULL, the ioinfo +function must return the optimum granularity for I/O operations to the file +in the memory location referenced by it. +

The func_ioinfo function must return the value of errno on +failure and 0 on success. +

The db_env_set_func_ioinfo interface affects the entire application, not a single +database or database environment. +

While the db_env_set_func_ioinfo interface may be used to configure Berkeley DB at any time +during the life of the application, it should normally be called before +making any calls to the db_env_create or db_create functions. +

The db_env_set_func_ioinfo function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

See Also

+db_env_set_func_close, +db_env_set_func_dirfree, +db_env_set_func_dirlist, +db_env_set_func_exists, +db_env_set_func_free, +db_env_set_func_fsync, +db_env_set_func_ioinfo, +db_env_set_func_malloc, +db_env_set_func_map, +db_env_set_func_open, +db_env_set_func_read, +db_env_set_func_realloc, +db_env_set_func_seek, +db_env_set_func_sleep, +db_env_set_func_unlink, +db_env_set_func_unmap, +db_env_set_func_write +and +db_env_set_func_yield. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/set_func_malloc.html b/db/docs/api_c/set_func_malloc.html new file mode 100644 index 000000000..a4be5bfb0 --- /dev/null +++ b/db/docs/api_c/set_func_malloc.html @@ -0,0 +1,67 @@ + + + + + +Berkeley DB: db_env_set_func_malloc + + + + + + + +
+

db_env_set_func_malloc

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +db_env_set_func_malloc(void *(*func_malloc)(size_t size)); +

+

Description

+

Replace Berkeley DB calls to the ANSI C X3.159-1989 (ANSI C) standard +malloc function with func_malloc, which must conform to +the standard interface. +

The db_env_set_func_malloc interface affects the entire application, not a single +database or database environment. +

While the db_env_set_func_malloc interface may be used to configure Berkeley DB at any time +during the life of the application, it should normally be called before +making any calls to the db_env_create or db_create functions. +

The db_env_set_func_malloc function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

See Also

+db_env_set_func_close, +db_env_set_func_dirfree, +db_env_set_func_dirlist, +db_env_set_func_exists, +db_env_set_func_free, +db_env_set_func_fsync, +db_env_set_func_ioinfo, +db_env_set_func_malloc, +db_env_set_func_map, +db_env_set_func_open, +db_env_set_func_read, +db_env_set_func_realloc, +db_env_set_func_seek, +db_env_set_func_sleep, +db_env_set_func_unlink, +db_env_set_func_unmap, +db_env_set_func_write +and +db_env_set_func_yield. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/set_func_map.html b/db/docs/api_c/set_func_map.html new file mode 100644 index 000000000..e14e9c4aa --- /dev/null +++ b/db/docs/api_c/set_func_map.html @@ -0,0 +1,86 @@ + + + + + +Berkeley DB: db_env_set_func_map + + + + + + + +
+

db_env_set_func_map

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +db_env_set_func_map(int (*func_map)(char *path, + size_t len, int is_region, int is_rdonly, void **addr)); +

+

Description

+

The Berkeley DB library requires the ability to map a file into memory and to +create shared memory regions (which may or may not be backed by files). +The func_map argument must conform to the following interface: +

int map(char *path, size_t len,
+int is_region, int is_rdonly, void **addr);
+

The path argument is the name of a file. +

The is_region argument will be zero if the intention is to map a +file into shared memory. In this case, the map function must map +the first len bytes of the file into memory and return a pointer +to the mapped location in the memory location referenced by the argument +addr. The is_rdonly argument will be non-zero if the file +is considered read-only by the caller. +

The is_region argument will be non-zero if the memory is intended +to be used as a shared memory region for synchronization between Berkeley DB +threads/processes. In this case, the returned memory may be of any kind +(e.g., anonymous), but must be able to support semaphores. In this case, +the path argument may be ignored (although future map +calls using the same path must return the same memory), and the +is_rdonly argument will always be zero. +

The func_map function must return the value of errno on +failure and 0 on success. +

The db_env_set_func_map interface affects the entire application, not a single +database or database environment. +

While the db_env_set_func_map interface may be used to configure Berkeley DB at any time +during the life of the application, it should normally be called before +making any calls to the db_env_create or db_create functions. +

The db_env_set_func_map function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

See Also

+db_env_set_func_close, +db_env_set_func_dirfree, +db_env_set_func_dirlist, +db_env_set_func_exists, +db_env_set_func_free, +db_env_set_func_fsync, +db_env_set_func_ioinfo, +db_env_set_func_malloc, +db_env_set_func_map, +db_env_set_func_open, +db_env_set_func_read, +db_env_set_func_realloc, +db_env_set_func_seek, +db_env_set_func_sleep, +db_env_set_func_unlink, +db_env_set_func_unmap, +db_env_set_func_write +and +db_env_set_func_yield. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/set_func_open.html b/db/docs/api_c/set_func_open.html new file mode 100644 index 000000000..ff72d9882 --- /dev/null +++ b/db/docs/api_c/set_func_open.html @@ -0,0 +1,66 @@ + + + + + +Berkeley DB: db_env_set_func_open + + + + + + + +
+

db_env_set_func_open

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +db_env_set_func_open(int (*func_open)(const char *path, int flags, int mode)); +

+

Description

+

Replace Berkeley DB calls to the IEEE/ANSI Std 1003.1 (POSIX) open function +with func_open, which must conform to the standard interface. +

The db_env_set_func_open interface affects the entire application, not a single +database or database environment. +

While the db_env_set_func_open interface may be used to configure Berkeley DB at any time +during the life of the application, it should normally be called before +making any calls to the db_env_create or db_create functions. +

The db_env_set_func_open function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

See Also

+db_env_set_func_close, +db_env_set_func_dirfree, +db_env_set_func_dirlist, +db_env_set_func_exists, +db_env_set_func_free, +db_env_set_func_fsync, +db_env_set_func_ioinfo, +db_env_set_func_malloc, +db_env_set_func_map, +db_env_set_func_open, +db_env_set_func_read, +db_env_set_func_realloc, +db_env_set_func_seek, +db_env_set_func_sleep, +db_env_set_func_unlink, +db_env_set_func_unmap, +db_env_set_func_write +and +db_env_set_func_yield. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/set_func_read.html b/db/docs/api_c/set_func_read.html new file mode 100644 index 000000000..b3ee93081 --- /dev/null +++ b/db/docs/api_c/set_func_read.html @@ -0,0 +1,66 @@ + + + + + +Berkeley DB: db_env_set_func_read + + + + + + + +
+

db_env_set_func_read

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +db_env_set_func_read(ssize_t (*func_read)(int fd, void *buf, size_t nbytes)); +

+

Description

+

Replace Berkeley DB calls to the IEEE/ANSI Std 1003.1 (POSIX) read function +with func_read, which must conform to the standard interface. +

The db_env_set_func_read interface affects the entire application, not a single +database or database environment. +

While the db_env_set_func_read interface may be used to configure Berkeley DB at any time +during the life of the application, it should normally be called before +making any calls to the db_env_create or db_create functions. +

The db_env_set_func_read function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

See Also

+db_env_set_func_close, +db_env_set_func_dirfree, +db_env_set_func_dirlist, +db_env_set_func_exists, +db_env_set_func_free, +db_env_set_func_fsync, +db_env_set_func_ioinfo, +db_env_set_func_malloc, +db_env_set_func_map, +db_env_set_func_open, +db_env_set_func_read, +db_env_set_func_realloc, +db_env_set_func_seek, +db_env_set_func_sleep, +db_env_set_func_unlink, +db_env_set_func_unmap, +db_env_set_func_write +and +db_env_set_func_yield. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/set_func_realloc.html b/db/docs/api_c/set_func_realloc.html new file mode 100644 index 000000000..91e5835bc --- /dev/null +++ b/db/docs/api_c/set_func_realloc.html @@ -0,0 +1,67 @@ + + + + + +Berkeley DB: db_env_set_func_realloc + + + + + + + +
+

db_env_set_func_realloc

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +db_env_set_func_realloc(void *(*func_realloc)(void *ptr, size_t size)); +

+

Description

+

Replace Berkeley DB calls to the ANSI C X3.159-1989 (ANSI C) standard +realloc function with func_realloc, which must conform to +the standard interface. +

The db_env_set_func_realloc interface affects the entire application, not a single +database or database environment. +

While the db_env_set_func_realloc interface may be used to configure Berkeley DB at any time +during the life of the application, it should normally be called before +making any calls to the db_env_create or db_create functions. +

The db_env_set_func_realloc function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

See Also

+db_env_set_func_close, +db_env_set_func_dirfree, +db_env_set_func_dirlist, +db_env_set_func_exists, +db_env_set_func_free, +db_env_set_func_fsync, +db_env_set_func_ioinfo, +db_env_set_func_malloc, +db_env_set_func_map, +db_env_set_func_open, +db_env_set_func_read, +db_env_set_func_realloc, +db_env_set_func_seek, +db_env_set_func_sleep, +db_env_set_func_unlink, +db_env_set_func_unmap, +db_env_set_func_write +and +db_env_set_func_yield. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/set_func_rename.html b/db/docs/api_c/set_func_rename.html new file mode 100644 index 000000000..bb5886723 --- /dev/null +++ b/db/docs/api_c/set_func_rename.html @@ -0,0 +1,66 @@ + + + + + +Berkeley DB: db_env_set_func_rename + + + + + + + +
+

db_env_set_func_rename

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +db_env_set_func_rename(int (*func_rename)(int fd)); +

+

Description

+

Replace Berkeley DB calls to the IEEE/ANSI Std 1003.1 (POSIX) close function +with func_close, which must conform to the standard interface. +

The db_env_set_func_rename interface affects the entire application, not a single +database or database environment. +

While the db_env_set_func_rename interface may be used to configure Berkeley DB at any time +during the life of the application, it should normally be called before +making any calls to the db_env_create or db_create functions. +

The db_env_set_func_rename function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

See Also

+db_env_set_func_close, +db_env_set_func_dirfree, +db_env_set_func_dirlist, +db_env_set_func_exists, +db_env_set_func_free, +db_env_set_func_fsync, +db_env_set_func_ioinfo, +db_env_set_func_malloc, +db_env_set_func_map, +db_env_set_func_open, +db_env_set_func_read, +db_env_set_func_realloc, +db_env_set_func_seek, +db_env_set_func_sleep, +db_env_set_func_unlink, +db_env_set_func_unmap, +db_env_set_func_write +and +db_env_set_func_yield. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/set_func_seek.html b/db/docs/api_c/set_func_seek.html new file mode 100644 index 000000000..dd27384f6 --- /dev/null +++ b/db/docs/api_c/set_func_seek.html @@ -0,0 +1,81 @@ + + + + + +Berkeley DB: db_env_set_func_seek + + + + + + + +
+

db_env_set_func_seek

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +db_env_set_func_seek(int (*func_seek)(int fd, size_t pgsize, + db_pgno_t pageno, u_int32_t relative, int rewind, int whence)); +

+

Description

+

The Berkeley DB library requires the ability to specify that a subsequent read +from or write to a file will occur at a specific location in that file. +The func_seek argument must conform to the following interface: +

int seek(int fd, size_t pgsize, db_pgno_t pageno,
+u_int32_t relative, int rewind, int whence);
+

The fd argument is an open file descriptor on the file. +

The seek function must cause a subsequent read from or write to +the file to occur at a byte offset specified by the calculation: +

(pgsize * pageno) + relative
+

If rewind is non-zero, the byte offset is treated as a backwards +seek, not a forwards one. +

The whence argument specifies where in the file the byte offset +is relative to, as described by the IEEE/ANSI Std 1003.1 (POSIX) lseek system +call. +

The func_seek function must return the value of errno on +failure and 0 on success. +

The db_env_set_func_seek interface affects the entire application, not a single +database or database environment. +

While the db_env_set_func_seek interface may be used to configure Berkeley DB at any time +during the life of the application, it should normally be called before +making any calls to the db_env_create or db_create functions. +

The db_env_set_func_seek function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

See Also

+db_env_set_func_close, +db_env_set_func_dirfree, +db_env_set_func_dirlist, +db_env_set_func_exists, +db_env_set_func_free, +db_env_set_func_fsync, +db_env_set_func_ioinfo, +db_env_set_func_malloc, +db_env_set_func_map, +db_env_set_func_open, +db_env_set_func_read, +db_env_set_func_realloc, +db_env_set_func_seek, +db_env_set_func_sleep, +db_env_set_func_unlink, +db_env_set_func_unmap, +db_env_set_func_write +and +db_env_set_func_yield. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/set_func_sleep.html b/db/docs/api_c/set_func_sleep.html new file mode 100644 index 000000000..dd454b1a7 --- /dev/null +++ b/db/docs/api_c/set_func_sleep.html @@ -0,0 +1,76 @@ + + + + + +Berkeley DB: db_env_set_func_sleep + + + + + + + +
+

db_env_set_func_sleep

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +db_env_set_func_sleep(int (*func_sleep)(u_long seconds, u_long microseconds)); +

+

Description

+

The Berkeley DB library requires the ability to cause a process to suspend itself +for a period of time, relinquishing control of the processor to any other +waiting thread of control. The func_sleep argument must conform +to the following interface: +

int sleep(u_long seconds, u_long microseconds);
+

The seconds and microseconds arguments specify the amount +of time to wait until the suspending thread of control should run again. +

The seconds and microseconds arguments may not be +normalized when the sleep function is called, i.e., the +microseconds argument may be greater than 1000000. +

The func_sleep function must return the value of errno on +failure and 0 on success. +

The db_env_set_func_sleep interface affects the entire application, not a single +database or database environment. +

While the db_env_set_func_sleep interface may be used to configure Berkeley DB at any time +during the life of the application, it should normally be called before +making any calls to the db_env_create or db_create functions. +

The db_env_set_func_sleep function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

See Also

+db_env_set_func_close, +db_env_set_func_dirfree, +db_env_set_func_dirlist, +db_env_set_func_exists, +db_env_set_func_free, +db_env_set_func_fsync, +db_env_set_func_ioinfo, +db_env_set_func_malloc, +db_env_set_func_map, +db_env_set_func_open, +db_env_set_func_read, +db_env_set_func_realloc, +db_env_set_func_seek, +db_env_set_func_sleep, +db_env_set_func_unlink, +db_env_set_func_unmap, +db_env_set_func_write +and +db_env_set_func_yield. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/set_func_unlink.html b/db/docs/api_c/set_func_unlink.html new file mode 100644 index 000000000..1e5e8e3cb --- /dev/null +++ b/db/docs/api_c/set_func_unlink.html @@ -0,0 +1,66 @@ + + + + + +Berkeley DB: db_env_set_func_unlink + + + + + + + +
+

db_env_set_func_unlink

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +db_env_set_func_unlink(int (*func_unlink)(const char *path)); +

+

Description

+

Replace Berkeley DB calls to the IEEE/ANSI Std 1003.1 (POSIX) unlink function +with func_unlink, which must conform to the standard interface. +

The db_env_set_func_unlink interface affects the entire application, not a single +database or database environment. +

While the db_env_set_func_unlink interface may be used to configure Berkeley DB at any time +during the life of the application, it should normally be called before +making any calls to the db_env_create or db_create functions. +

The db_env_set_func_unlink function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

See Also

+db_env_set_func_close, +db_env_set_func_dirfree, +db_env_set_func_dirlist, +db_env_set_func_exists, +db_env_set_func_free, +db_env_set_func_fsync, +db_env_set_func_ioinfo, +db_env_set_func_malloc, +db_env_set_func_map, +db_env_set_func_open, +db_env_set_func_read, +db_env_set_func_realloc, +db_env_set_func_seek, +db_env_set_func_sleep, +db_env_set_func_unlink, +db_env_set_func_unmap, +db_env_set_func_write +and +db_env_set_func_yield. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/set_func_unmap.html b/db/docs/api_c/set_func_unmap.html new file mode 100644 index 000000000..07635b48a --- /dev/null +++ b/db/docs/api_c/set_func_unmap.html @@ -0,0 +1,75 @@ + + + + + +Berkeley DB: db_env_set_func_unmap + + + + + + + +
+

db_env_set_func_unmap

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +db_env_set_func_unmap(int (*func_unmap)(void *addr, size_t len)); +

+

Description

+

The Berkeley DB library requires the ability to unmap a file or shared memory +region from memory. The func_unmap argument must conform to the +following interface: +

int unmap(void *addr, size_t len);
+

The addr argument is the argument returned by the +db_env_set_func_map function when the file or region was mapped +into memory, and the len argument is the same as the len +argument specified to the db_env_set_func_map function when the +file or region was mapped into memory. +

The func_unmap function must return the value of errno on +failure and 0 on success. +

The db_env_set_func_unmap interface affects the entire application, not a single +database or database environment. +

While the db_env_set_func_unmap interface may be used to configure Berkeley DB at any time +during the life of the application, it should normally be called before +making any calls to the db_env_create or db_create functions. +

The db_env_set_func_unmap function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

See Also

+db_env_set_func_close, +db_env_set_func_dirfree, +db_env_set_func_dirlist, +db_env_set_func_exists, +db_env_set_func_free, +db_env_set_func_fsync, +db_env_set_func_ioinfo, +db_env_set_func_malloc, +db_env_set_func_map, +db_env_set_func_open, +db_env_set_func_read, +db_env_set_func_realloc, +db_env_set_func_seek, +db_env_set_func_sleep, +db_env_set_func_unlink, +db_env_set_func_unmap, +db_env_set_func_write +and +db_env_set_func_yield. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/set_func_write.html b/db/docs/api_c/set_func_write.html new file mode 100644 index 000000000..7b52b5078 --- /dev/null +++ b/db/docs/api_c/set_func_write.html @@ -0,0 +1,67 @@ + + + + + +Berkeley DB: db_env_set_func_write + + + + + + + +
+

db_env_set_func_write

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +db_env_set_func_write( + ssize_t (*func_write)(int fd, const void *buffer, size_t nbytes)); +

+

Description

+

Replace Berkeley DB calls to the IEEE/ANSI Std 1003.1 (POSIX) write function +with func_write, which must conform to the standard interface. +

The db_env_set_func_write interface affects the entire application, not a single +database or database environment. +

While the db_env_set_func_write interface may be used to configure Berkeley DB at any time +during the life of the application, it should normally be called before +making any calls to the db_env_create or db_create functions. +

The db_env_set_func_write function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

See Also

+db_env_set_func_close, +db_env_set_func_dirfree, +db_env_set_func_dirlist, +db_env_set_func_exists, +db_env_set_func_free, +db_env_set_func_fsync, +db_env_set_func_ioinfo, +db_env_set_func_malloc, +db_env_set_func_map, +db_env_set_func_open, +db_env_set_func_read, +db_env_set_func_realloc, +db_env_set_func_seek, +db_env_set_func_sleep, +db_env_set_func_unlink, +db_env_set_func_unmap, +db_env_set_func_write +and +db_env_set_func_yield. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/set_func_yield.html b/db/docs/api_c/set_func_yield.html new file mode 100644 index 000000000..23915aea6 --- /dev/null +++ b/db/docs/api_c/set_func_yield.html @@ -0,0 +1,84 @@ + + + + + +Berkeley DB: db_env_set_func_yield + + + + + + + +
+

db_env_set_func_yield

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +db_env_set_func_yield(int (*func_yield)(void)); +

+

Description

+

The Berkeley DB library requires the ability to yield the processor from the current +thread of control to any other waiting threads of control. +The func_yield argument must conform to the following interface: +

int yield(void);
+

The func_yield function must be able to cause the rescheduling +all participants in the current Berkeley DB environment, whether threaded or +not. It may be incorrect to supply a thread yield function if +more than a single process is operating in the Berkeley DB environment. This +is because many thread-yield functions will not allow other processes to +run, and the contested lock may be held by another process, not by another +thread. +

If no func_yield function is specified, or if the yield +function returns an error, the function specified by the +db_env_set_func_sleep entry will be used instead or subsequently, +i.e., if no yield function is specified, or it is possible for +the yield function to fail, the sleep function +must cause the processor to reschedule any waiting threads of +control for execution. +

The func_yield function must return the value of errno on +failure and 0 on success. +

The db_env_set_func_yield interface affects the entire application, not a single +database or database environment. +

While the db_env_set_func_yield interface may be used to configure Berkeley DB at any time +during the life of the application, it should normally be called before +making any calls to the db_env_create or db_create functions. +

The db_env_set_func_yield function returns a non-zero error value on failure and 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

See Also

+db_env_set_func_close, +db_env_set_func_dirfree, +db_env_set_func_dirlist, +db_env_set_func_exists, +db_env_set_func_free, +db_env_set_func_fsync, +db_env_set_func_ioinfo, +db_env_set_func_malloc, +db_env_set_func_map, +db_env_set_func_open, +db_env_set_func_read, +db_env_set_func_realloc, +db_env_set_func_seek, +db_env_set_func_sleep, +db_env_set_func_unlink, +db_env_set_func_unmap, +db_env_set_func_write +and +db_env_set_func_yield. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/txn_abort.html b/db/docs/api_c/txn_abort.html new file mode 100644 index 000000000..00056023a --- /dev/null +++ b/db/docs/api_c/txn_abort.html @@ -0,0 +1,63 @@ + + + + + +Berkeley DB: txn_abort + + + + + + + +
+

txn_abort

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +txn_abort(DB_TXN *tid); +

+

Description

+

The txn_abort function causes an abnormal termination of the +transaction. The log is played backwards and any necessary recovery +operations are initiated through the recover function specified +to DBENV->open. After the log processing is completed, all locks +held by the transaction are released. As is the case for +txn_commit, applications that require strict two-phase locking +should not explicitly release any locks. +

In the case of nested transactions, aborting a parent transaction causes +all children (unresolved or not) of the parent transaction to be aborted. +

Once the txn_abort function returns, the DB_TXN handle may not +be accessed again. +

The txn_abort function returns a non-zero error value on failure and 0 on success. +

Errors

+

The txn_abort function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the txn_abort function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBENV->set_tx_max, +DBENV->set_tx_recover, +DBENV->set_tx_timestamp, +txn_abort, +txn_begin, +txn_checkpoint, +txn_commit, +txn_id, +txn_prepare +and +txn_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/txn_begin.html b/db/docs/api_c/txn_begin.html new file mode 100644 index 000000000..0241d5c1f --- /dev/null +++ b/db/docs/api_c/txn_begin.html @@ -0,0 +1,93 @@ + + + + + +Berkeley DB: txn_begin + + + + + + + +
+

txn_begin

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +txn_begin(DB_ENV *env, + DB_TXN *parent, DB_TXN **tid, u_int32_t flags); +

+

Description

+

The txn_begin method creates a new transaction in the environment +and copies a pointer to a DB_TXN that uniquely identifies it into +the memory referenced by tid. +

If the parent argument is non-NULL, the new transaction will +be a nested transaction, with the transaction indicated by +parent as its parent. Transactions may be +nested to any level. +

The flags parameter must be set to 0 or one of the following +values: +

+

DB_TXN_NOSYNC
Do not synchronously flush the log when this transaction commits or +prepares. This means the transaction will exhibit the ACI (atomicity, +consistency and isolation) properties, but not D (durability), i.e., +database integrity will be maintained but it is possible that this +transaction may be undone during recovery instead of being redone. +

This behavior may be set for an entire Berkeley DB environment as part of the +DBENV->set_flags interface. +

DB_TXN_NOWAIT
If a lock is unavailable for any Berkeley DB operation performed in the context +of this transaction, return immediately instead of blocking on the lock. +The error return in the case will be DB_LOCK_NOTGRANTED. +

DB_TXN_SYNC
Synchronously flush the log when this transaction commits or prepares. +This means the transaction will exhibit all of the ACID (atomicity, +consistency and isolation and durability) properties. +

This behavior is the default for Berkeley DB environments unless the +DB_TXN_NOSYNC flag was specified to the DBENV->set_flags +interface. +

+

Note: An transaction may not span threads, +i.e., each transaction must begin and end in the same thread, and each +transaction may only be used by a single thread. +

Note: cursors may not span transactions, i.e., each cursor must be opened +and closed within a single transaction. +

Note: a parent transaction may not issue any Berkeley DB operations, except for +txn_begin, txn_abort and txn_commit, while it has +active child transactions (child transactions that have not yet been +committed or aborted). +

The txn_begin function returns a non-zero error value on failure and 0 on success. +

Errors

+

The txn_begin function may fail and return a non-zero error for the following conditions: +

+

ENOMEM
The maximum number of concurrent transactions has been reached. +
+

The txn_begin function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the txn_begin function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBENV->set_tx_max, +DBENV->set_tx_recover, +DBENV->set_tx_timestamp, +txn_abort, +txn_begin, +txn_checkpoint, +txn_commit, +txn_id, +txn_prepare +and +txn_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/txn_checkpoint.html b/db/docs/api_c/txn_checkpoint.html new file mode 100644 index 000000000..140edee57 --- /dev/null +++ b/db/docs/api_c/txn_checkpoint.html @@ -0,0 +1,75 @@ + + + + + +Berkeley DB: txn_checkpoint + + + + + + + +
+

txn_checkpoint

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +txn_checkpoint(const DB_ENV *env, + u_int32_t kbyte, u_int32_t min, u_int32_t flags); +

+

Description

+

The txn_checkpoint function flushes the underlying memory pool, +writes a checkpoint record to the log and then flushes the log. +

If either kbyte or min is non-zero, the checkpoint is only +done if there has been activity since the last checkpoint and either +more than min minutes have passed since the last checkpoint, +or if more than kbyte kilobytes of log data have been written since +the last checkpoint. +

The flags parameter must be set to 0 or one of the following +values: +

+

DB_FORCE
Force a checkpoint record even if there has been no activity since the +last checkpoint. +
+

The txn_checkpoint function returns a non-zero error value on failure, 0 on success, and returns DB_INCOMPLETE if there were pages that needed to be +written to complete the checkpoint but that memp_sync was unable +to write immediately. +

The txn_checkpoint function is the underlying function used by the db_checkpoint utility. +See the db_checkpoint utility source code for an example of using txn_checkpoint +in a IEEE/ANSI Std 1003.1 (POSIX) environment. +

Errors

+

The txn_checkpoint function may fail and return a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +
+

The txn_checkpoint function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the txn_checkpoint function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBENV->set_tx_max, +DBENV->set_tx_recover, +DBENV->set_tx_timestamp, +txn_abort, +txn_begin, +txn_checkpoint, +txn_commit, +txn_id, +txn_prepare +and +txn_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/txn_commit.html b/db/docs/api_c/txn_commit.html new file mode 100644 index 000000000..7fca3d08d --- /dev/null +++ b/db/docs/api_c/txn_commit.html @@ -0,0 +1,83 @@ + + + + + +Berkeley DB: txn_commit + + + + + + + +
+

txn_commit

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +txn_commit(DB_TXN *tid, u_int32_t flags); +

+

Description

+

The txn_commit function ends the transaction. In the case of nested +transactions, if the transaction is a parent transaction, committing +the parent transaction causes all unresolved children of the parent to +be committed. +

In the case of nested transactions, if the transaction is a child +transaction, its locks are not released, but are acquired by its parent. +While the commit of the child transaction will succeed, the actual +resolution of the child transaction is postponed until the parent +transaction is committed or aborted, i.e., if its parent transaction +commits, it will be committed, and if its parent transaction aborts, it +will be aborted. +

The flags parameter must be set to 0 or one of the following +values: +

+

DB_TXN_NOSYNC
Do not synchronously flush the log. This means the transaction will +exhibit the ACI (atomicity, consistency and isolation) properties, but +not D (durability), i.e., database integrity will be maintained but it is +possible that this transaction may be undone during recovery instead of +being redone. +

This behavior may be set for an entire Berkeley DB environment as part of the +DBENV->set_flags interface. +

DB_TXN_SYNC
Synchronously flush the log. This means the transaction will exhibit +all of the ACID (atomicity, consistency and isolation and durability) +properties. +

This behavior is the default for Berkeley DB environments unless the +DB_TXN_NOSYNC flag was specified to the DBENV->set_flags +or txn_begin interfaces. +

+

Once the txn_commit function returns, the DB_TXN handle may not +be accessed again. If txn_commit encounters an error, the +transaction and all child transactions of the transaction are aborted. +

The txn_commit function returns a non-zero error value on failure and 0 on success. +

Errors

+

The txn_commit function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the txn_commit function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBENV->set_tx_max, +DBENV->set_tx_recover, +DBENV->set_tx_timestamp, +txn_abort, +txn_begin, +txn_checkpoint, +txn_commit, +txn_id, +txn_prepare +and +txn_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/txn_id.html b/db/docs/api_c/txn_id.html new file mode 100644 index 000000000..bcda4bcdf --- /dev/null +++ b/db/docs/api_c/txn_id.html @@ -0,0 +1,50 @@ + + + + + +Berkeley DB: txn_id + + + + + + + +
+

txn_id

+
+APIRef +
+


+ +

+#include <db.h>
+

+u_int32_t +txn_id(DB_TXN *tid); +

+

Description

+

The txn_id function returns the unique transaction id associated with the +specified transaction. Locking calls made on behalf of this transaction +should use the value returned from txn_id as the locker parameter +to the lock_get or lock_vec calls. +

See Also

+DBENV->set_tx_max, +DBENV->set_tx_recover, +DBENV->set_tx_timestamp, +txn_abort, +txn_begin, +txn_checkpoint, +txn_commit, +txn_id, +txn_prepare +and +txn_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/txn_prepare.html b/db/docs/api_c/txn_prepare.html new file mode 100644 index 000000000..549a6f074 --- /dev/null +++ b/db/docs/api_c/txn_prepare.html @@ -0,0 +1,63 @@ + + + + + +Berkeley DB: txn_prepare + + + + + + + +
+

txn_prepare

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +txn_prepare(DB_TXN *tid); +

+

Description

+

The txn_prepare function initiates the beginning of a two-phase commit. +

In a distributed transaction environment, Berkeley DB can be used as a local +transaction manager. In this case, the distributed transaction manager +must send prepare messages to each local manager. The local +manager must then issue a txn_prepare and await its successful +return before responding to the distributed transaction manager. Only +after the distributed transaction manager receives successful responses +from all of its prepare messages should it issue any +commit messages. +

In the case of nested transactions, preparing a parent transaction +causes all unresolved children of the parent transaction to be prepared. +

The txn_prepare function returns a non-zero error value on failure and 0 on success. +

Errors

+

The txn_prepare function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the txn_prepare function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBENV->set_tx_max, +DBENV->set_tx_recover, +DBENV->set_tx_timestamp, +txn_abort, +txn_begin, +txn_checkpoint, +txn_commit, +txn_id, +txn_prepare +and +txn_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_c/txn_stat.html b/db/docs/api_c/txn_stat.html new file mode 100644 index 000000000..769283f93 --- /dev/null +++ b/db/docs/api_c/txn_stat.html @@ -0,0 +1,94 @@ + + + + + +Berkeley DB: txn_stat + + + + + + + +
+

txn_stat

+
+APIRef +
+


+ +

+#include <db.h>
+

+int +txn_stat(DB_ENV *env, + DB_TXN_STAT **statp, void *(*db_malloc)(size_t)); +

+

Description

+

The txn_stat function +creates a statistical structure and copies a pointer to it into a +user-specified memory location. +

Statistical structures are created in allocated memory. If db_malloc is non-NULL, it +is called to allocate the memory, otherwise, the library function +malloc(3) is used. The function db_malloc must match +the calling conventions of the malloc(3) library routine. +Regardless, the caller is responsible for deallocating the returned +memory. To deallocate returned memory, free the returned memory +reference, references inside the returned memory do not need to be +individually freed. +

The transaction region statistics are stored in a structure of type +DB_TXN_STAT. The following DB_TXN_STAT fields will be filled in: +

+
DB_LSN st_last_ckp;
The LSN of the last checkpoint. +
DB_LSN st_pending_ckp;
The LSN of any checkpoint that is currently in progress. If +st_pending_ckp is the same as st_last_ckp there +is no checkpoint in progress. +
time_t st_time_ckp;
The time the last completed checkpoint finished (as the number of seconds +since the Epoch, returned by the IEEE/ANSI Std 1003.1 (POSIX) time interface). +
u_int32_t st_last_txnid;
The last transaction ID allocated. +
u_int32_t st_maxtxns;
The maximum number of active transactions possible. +
u_int32_t st_nactive;
The number of transactions that are currently active. +
u_int32_t st_maxnactive;
The maximum number of active transactions at any one time. +
u_int32_t st_nbegins;
The number of transactions that have begun. +
u_int32_t st_naborts;
The number of transactions that have aborted. +
u_int32_t st_ncommits;
The number of transactions that have committed. +
u_int32_t st_regsize;
The size of the region. +
u_int32_t st_region_wait;
The number of times that a thread of control was forced to wait before +obtaining the region lock. +
u_int32_t st_region_nowait;
The number of times that a thread of control was able to obtain +the region lock without waiting. +
DB_TXN_ACTIVE * st_txnarray;
A pointer to an array of st_nactive DB_TXN_ACTIVE structures, +describing the currently active transactions. The following fields of +the DB_TXN_ACTIVE structure will be filled in: +

+

u_int32_t txnid;
The transaction ID as returned by txn_begin. +
u_int32_t parentid;
The transaction ID of the parent transaction (or 0, if no parent). +
DB_LSN lsn;
The log sequence number of the transaction-begin record. +
+
+

The txn_stat function returns a non-zero error value on failure and 0 on success. +

Errors

+

The txn_stat function may fail and return a non-zero error for errors specified for other Berkeley DB and C library or system functions. +If a catastrophic error has occurred, the txn_stat function may fail and return +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

See Also

+DBENV->set_tx_max, +DBENV->set_tx_recover, +DBENV->set_tx_timestamp, +txn_abort, +txn_begin, +txn_checkpoint, +txn_commit, +txn_id, +txn_prepare +and +txn_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/cxx_index.html b/db/docs/api_cxx/cxx_index.html new file mode 100644 index 000000000..1ba43a0f2 --- /dev/null +++ b/db/docs/api_cxx/cxx_index.html @@ -0,0 +1,148 @@ + + + + + +Berkeley DB: C++ Interface by Class + + + + +

C++ Interface by Class

+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ClassMethodDescription
DbEnv
Berkeley DB Environment Class

DbEnv::closeClose an environment

DbEnv::errError message with error string

DbEnv::errxError message

DbEnv::openOpen an environment

DbEnv::removeRemove an environment

DbEnv::set_cachesizeSet the environment cache size

DbEnv::set_data_dirSet the environment data directory

DbEnv::set_errcallSet error message callback

DbEnv::set_errfileSet error message FILE *

DbEnv::set_error_streamSet error message output stream

DbEnv::set_errpfxSet error message prefix

DbEnv::set_feedbackSet feedback callback

DbEnv::set_flagsEnvironment configuration

DbEnv::set_lg_bsizeSet log buffer size

DbEnv::set_lg_dirSet the environment logging directory

DbEnv::set_lg_maxSet log file size

DbEnv::set_lk_conflictsSet lock conflicts matrix

DbEnv::set_lk_detectSet automatic deadlock detection

DbEnv::set_lk_maxSet maximum number of locks (Deprecated)

DbEnv::set_lk_max_locksSet maximum number of locks

DbEnv::set_lk_max_lockersSet maximum number of lockers

DbEnv::set_lk_max_objectsSet maximum number of lock objects

DbEnv::set_mp_mmapsizeSet maximum mapped-in database file size

DbEnv::set_mutexlocksTurn off mutual exclusion locking

DbEnv::set_pageyieldYield the processor on each page access

DbEnv::set_paniccallSet panic callback

DbEnv::set_panicstateReset panic state

DbEnv::set_recovery_initSet recovery initialization callback

DbEnv::set_region_initFault in shared regions on initial access

DbEnv::set_serverEstablish server connection

DbEnv::set_shm_keySet system memory shared segment ID

DbEnv::set_tas_spinsSet the number of test-and-set spins

DbEnv::set_tmp_dirSet the environment temporary file directory

DbEnv::set_tx_maxSet maximum number of transactions

DbEnv::set_tx_recoverSet transaction abort recover function

DbEnv::set_tx_timestampSet recovery timestamp

DbEnv::set_verboseSet verbose messages

DbEnv::strerrorError strings

DbEnv::lock_detectPerform deadlock detection

DbEnv::lock_getAcquire a lock

DbEnv::lock_idAcquire a locker ID

DbEnv::lock_statReturn lock subsystem statistics

DbEnv::lock_vecAcquire/release locks

DbEnv::log_archiveList log and database files

DbEnv::log_compareCompare two Log Sequence Numbers

DbEnv::log_fileMap Log Sequence Numbers to log files

DbEnv::log_flushFlush log records

DbEnv::log_getGet a log record

DbEnv::log_putWrite a log record

DbEnv::log_registerRegister a file name with the log manager

DbEnv::log_statReturn log subsystem statistics

DbEnv::log_unregisterUnregister a file name with the log manager

DbEnv::memp_registerRegister input/output functions for a file in a buffer pool.

DbEnv::memp_statReturn buffer pool statistics

DbEnv::memp_syncFlush pages from a buffer pool

DbEnv::memp_trickleTrickle flush pages from a buffer pool

DbEnv::txn_beginBegin a transaction

DbEnv::txn_checkpointCheckpoint the transaction subsystem

DbEnv::txn_statReturn transaction subsystem statistics

DbEnv::versionReturn version information
Db
Berkeley DB Access Method Class

Db::closeClose a database

Db::cursorOpen a cursor into a database

Db::delDelete items from a database

Db::errError message with error string

Db::errxError message

Db::fdReturn a file descriptor from a database

Db::getGet items from a database

Db::get_byteswappedReturn if the underlying database is in host order

Db::get_typeReturn the database type

Db::joinPerform a database join on cursors

Db::key_rangeReturn estimate of key location

Db::openOpen a database

Db::putStore items into a database

Db::removeRemove a database

Db::renameRename a database

Db::set_append_recnoSet record append callback

Db::set_bt_compareSet a Btree comparison function

Db::set_bt_minkeySet the minimum number of keys per Btree page

Db::set_bt_prefixSet a Btree prefix comparison function

Db::set_cachesizeSet the database cache size

Db::set_dup_compareSet a duplicate comparison function

Db::set_errcallSet error message callback

Db::set_errfileSet error message FILE *

Db::set_errpfxSet error message prefix

Db::set_feedbackSet feedback callback

Db::set_flagsGeneral database configuration

Db::set_h_ffactorSet the Hash table density

Db::set_h_hashSet a hashing function

Db::set_h_nelemSet the Hash table size

Db::set_lorderSet the database byte order

Db::set_mallocSet a local space allocation function

Db::set_pagesizeSet the underlying database page size

Db::set_paniccallSet panic callback

Db::set_q_extentsizeSet Queue database extent size

Db::set_re_delimSet the variable-length record delimiter

Db::set_re_lenSet the fixed-length record length

Db::set_re_padSet the fixed-length record pad byte

Db::set_re_sourceSet the backing Recno text file

Db::set_reallocSet a local space allocation function

Db::statReturn database statistics

Db::syncFlush a database to stable storage

Db::upgradeUpgrade a database

Db::verifyVerify/upgrade a database
Dbc
Berkeley DB Cursor Class

Dbc::closeClose a cursor

Dbc::countReturn count of duplicates

Dbc::delDelete by cursor

Dbc::dupDuplicate a cursor

Dbc::getRetrieve by cursor

Dbc::putStore by cursor
Dbt
Key/Data Encoding Class
DbLock
Lock Class

DbLock::putRelease a lock
DbLsn
Log Sequence Number Class
DbMpoolFile
Memory Pool File Class

DbMpoolFile::closeClose a file in a buffer pool

DbMpoolFile::getGet page from a file in a buffer pool

DbMpoolFile::openOpen a file in a buffer pool

DbMpoolFile::putReturn a page to a buffer pool

DbMpoolFile::setModify meta information for buffer pool page

DbMpoolFile::syncFlush pages from a file in a buffer pool
DbTxn
Transaction Class

DbTxn::abortAbort a transaction

DbTxn::commitCommit a transaction

DbTxn::idReturn a transaction ID

DbTxn::preparePrepare a transaction for commit
DbException
Exception Class for Berkeley DB Activity

DbException::get_errnoGet the error value

DbException::whatGet the error string
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/cxx_pindex.html b/db/docs/api_cxx/cxx_pindex.html new file mode 100644 index 000000000..d460fcf65 --- /dev/null +++ b/db/docs/api_cxx/cxx_pindex.html @@ -0,0 +1,516 @@ + + +Berkeley DB: C++ Interface Index + + + + +

C++ Interface Index

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
configuring Berkeley DB 1.85 API compatibility
building a utility to dump Berkeley DB 1.85 databases
Upgrading to release 2.0
Upgrading to release 3.0
Upgrading to release 3.1
Upgrading to release 3.2
selecting an access method
access methods
AIX
data alignment
programmatic APIs
utility to archive log files
berkeley_db_svc
building for UNIX
building for UNIX FAQ
building for VxWorks
building for VxWorks FAQ
building for Win32
building for Windows FAQ
selecting a byte order
byte ordering
configuring the C++ API
flushing the database cache
selecting a cache size
catastrophic recovery
Patches, Updates and Change logs
utility to take checkpoints
DbMpoolFile::openclear_len
closing a cursor
closing a database
specifying a Btree comparison function
changing compile or load options
Concurrent Data Store
configuring Berkeley DB for UNIX systems
recovering corrupted databases
counting data items for a key
closing a cursor
deleting records with a cursor
duplicating a cursor
retrieving records with a cursor
storing records with a cursor
cursor stability
database cursors
Dbtdata
utility to upgrade database files
utility to verify database files
Db
Dbc::putDB_AFTER
Db::verifyDB_AGGRESSIVE
Db::putDB_APPEND
DbEnv::log_archiveDB_ARCH_ABS
DbEnv::log_archiveDB_ARCH_DATA
db_archive
DbEnv::log_archiveDB_ARCH_LOG
Dbc::putDB_BEFORE
Dbc
Db::statDB_CACHED_COUNTS
Dbc::close
Dbc::count
DbEnv::set_flagsDB_CDB_ALLDB
Dbc::del
Dbc::dup
Dbc::get
DbEnv::log_getDB_CHECKPOINT
DbEnv::log_putDB_CHECKPOINT
db_checkpoint
DbEnvDB_CLIENT
Db::close
File namingDB_CONFIG
Db::getDB_CONSUME
Db::getDB_CONSUME_WAIT
Dbc::put
Db::openDB_CREATE
DbEnv::openDB_CREATE
DbMpoolFile::openDB_CREATE
DbEnv::log_putDB_CURLSN
Dbc::getDB_CURRENT
Dbc::putDB_CURRENT
DbEnv::log_getDB_CURRENT
Db::cursor
DbDB_CXX_NO_EXCEPTIONS
DbEnvDB_CXX_NO_EXCEPTIONS
DbtDB_DBT_MALLOC
DbtDB_DBT_PARTIAL
DbtDB_DBT_REALLOC
DbtDB_DBT_USERMEM
db_deadlock
Db::del
db_dump
Db::set_flagsDB_DUP
Db::set_flagsDB_DUPSORT
Db::upgradeDB_DUPSORT
DbEnv
DbEnv::close
DbEnv::err
DbEnv::lock_detect
DbEnv::lock_get
DbEnv::lock_id
DbEnv::lock_stat
DbEnv::lock_vec
DbEnv::log_archive
DbEnv::log_compare
DbEnv::log_file
DbEnv::log_flush
DbEnv::log_get
DbEnv::log_put
DbEnv::log_register
DbEnv::log_stat
DbEnv::log_unregister
DbEnv::memp_register
DbEnv::memp_stat
DbEnv::memp_sync
DbEnv::memp_trickle
DbEnv::open
DbEnv::remove
DbEnv::set_cachesize
DbEnv::set_data_dir
DbEnv::set_errcall
DbEnv::set_errfile
DbEnv::set_error_stream
DbEnv::set_errpfx
DbEnv::set_feedback
DbEnv::set_flags
DbEnv::set_lg_bsize
DbEnv::set_lg_dir
DbEnv::set_lg_max
DbEnv::set_lk_conflicts
DbEnv::set_lk_detect
DbEnv::set_lk_max
DbEnv::set_lk_max_lockers
DbEnv::set_lk_max_locks
DbEnv::set_lk_max_objects
DbEnv::set_mp_mmapsize
DbEnv::set_mutexlocks
DbEnv::set_pageyield
DbEnv::set_paniccall
DbEnv::set_panicstate
DbEnv::set_recovery_init
DbEnv::set_region_init
DbEnv::set_server
DbEnv::set_shm_key
DbEnv::set_tas_spins
DbEnv::set_tmp_dir
DbEnv::set_tx_max
DbEnv::set_tx_recover
DbEnv::set_tx_timestamp
DbEnv::set_verbose
DbEnv::strerror
DbEnv::txn_begin
DbEnv::txn_checkpoint
DbEnv::txn_stat
DbEnv::version
DbException
DbException::get_errno
DbException::what
Db::openDB_EXCL
Db::fd
Dbc::getDB_FIRST
DbEnv::log_getDB_FIRST
DbEnv::log_putDB_FLUSH
DbEnv::removeDB_FORCE
DbEnv::txn_checkpointDB_FORCE
Db::get
Db::getDB_GET_BOTH
Dbc::getDB_GET_BOTH
Db::get_byteswapped
Dbc::getDB_GET_RECNO
Db::get_type
File namingDB_HOME
File namingdb_home
Db::close DB_INCOMPLETE
DbEnv::openDB_INIT_CDB
DbEnv::openDB_INIT_LOCK
DbEnv::openDB_INIT_LOG
DbEnv::openDB_INIT_MPOOL
DbEnv::openDB_INIT_TXN
Db::join
DbEnv::openDB_JOINENV
Db::joinDB_JOIN_ITEM
Dbc::getDB_JOIN_ITEM
Db::joinDB_JOIN_NOSORT
Error returns to applicationsDB_KEYEMPTY
Dbc::putDB_KEYFIRST
Dbc::putDB_KEYLAST
Db::key_range
Dbc::getDB_LAST
DbEnv::log_getDB_LAST
db_load
DbLock
DbEnv::lock_detectDB_LOCK_CONFLICT
Error returns to applicationsDB_LOCK_DEADLOCK
DbEnv::set_lk_detectDB_LOCK_DEFAULT
DbEnv::openDB_LOCKDOWN
DbEnv::lock_vecDB_LOCK_GET
DbEnv::lock_getDB_LOCK_NOTGRANTED
DbEnv::lock_vecDB_LOCK_NOTGRANTED
Error returns to applicationsDB_LOCK_NOTGRANTED
DbEnv::lock_getDB_LOCK_NOWAIT
DbEnv::lock_vecDB_LOCK_NOWAIT
DbEnv::set_lk_detectDB_LOCK_OLDEST
DbLock::put
DbEnv::lock_vecDB_LOCK_PUT
DbEnv::lock_vecDB_LOCK_PUT_ALL
DbEnv::lock_vecDB_LOCK_PUT_OBJ
DbEnv::set_lk_detectDB_LOCK_RANDOM
DbEnv::set_lk_detectDB_LOCK_YOUNGEST
DbLsn
DbMpoolFile::putDB_MPOOL_CLEAN
DbMpoolFile::setDB_MPOOL_CLEAN
DbMpoolFile::getDB_MPOOL_CREATE
DbMpoolFile::putDB_MPOOL_DIRTY
DbMpoolFile::setDB_MPOOL_DIRTY
DbMpoolFile::putDB_MPOOL_DISCARD
DbMpoolFile::setDB_MPOOL_DISCARD
DbMpoolFile
DbMpoolFile::close
DbMpoolFile::get
DbMpoolFile::open
DbMpoolFile::put
DbMpoolFile::set
DbMpoolFile::sync
DbMpoolFile::getDB_MPOOL_LAST
DbMpoolFile::getDB_MPOOL_NEW
Dbc::getDB_NEXT
DbEnv::log_getDB_NEXT
Dbc::getDB_NEXT_DUP
Dbc::getDB_NEXT_NODUP
Db::putDB_NODUPDATA
Dbc::putDB_NODUPDATA
Db::openDB_NOMMAP
DbEnv::set_flagsDB_NOMMAP
DbMpoolFile::openDB_NOMMAP
Db::verifyDB_NOORDERCHK
Db::putDB_NOOVERWRITE
DbEnv::set_serverDB_NOSERVER
DbEnv::set_serverDB_NOSERVER_ID
Db::closeDB_NOSYNC
Error returns to applicationsDB_NOTFOUND
Db::openDB_OLD_VERSION
Db::upgradeDB_OLD_VERSION
Db::open
Db::verifyDB_ORDERCHKONLY
Dbc::dupDB_POSITION
Dbc::getDB_PREV
DbEnv::log_getDB_PREV
Dbc::getDB_PREV_NODUP
db_printlog
DbEnv::openDB_PRIVATE
Db::put
Db::openDB_RDONLY
DbMpoolFile::openDB_RDONLY
Db::set_flagsDB_RECNUM
Db::statDB_RECORDCOUNT
DbEnv::openDB_RECOVER
DbEnv::set_feedbackDB_RECOVER
db_recover
DbEnv::openDB_RECOVER_FATAL
Db::remove
Db::rename
Db::set_flagsDB_RENUMBER
Db::set_flagsDB_REVSPLITOFF
Db::getDB_RMW
Db::joinDB_RMW
Dbc::getDB_RMW
Error returns to applicationsDB_RUNRECOVERY
Db::verifyDB_SALVAGE
Dbc::getDB_SET
DbEnv::log_getDB_SET
Db::set_append_recno
Db::set_bt_compare
Db::set_bt_minkey
Db::set_bt_prefix
Db::set_cachesize
Db::set_dup_compare
Db::set_errcall
Db::set_errfile
Db::set_errpfx
Db::set_feedback
Db::set_flags
Db::set_h_ffactor
Db::set_h_hash
Db::set_h_nelem
Db::set_lorder
Db::set_malloc
Db::set_pagesize
Db::set_paniccall
Db::set_q_extentsize
Dbc::getDB_SET_RANGE
Db::set_realloc
Db::getDB_SET_RECNO
Dbc::getDB_SET_RECNO
Db::set_re_delim
Db::set_re_len
Db::set_re_pad
Db::set_re_source
Db::set_flagsDB_SNAPSHOT
Db::stat
db_stat
Db::sync
DbEnv::openDB_SYSTEM_MEM
Dbt
Db::openDB_THREAD
DbEnv::openDB_THREAD
Db::openDB_TRUNCATE
DbTxn
DbEnv::set_tx_recoverDB_TXN_ABORT
DbTxn::abort
DbEnv::set_tx_recoverDB_TXN_BACKWARD_ROLL
DbTxn::commit
DbEnv::set_tx_recoverDB_TXN_FORWARD_ROLL
DbTxn::id
DbEnv::set_flagsDB_TXN_NOSYNC
DbEnv::txn_beginDB_TXN_NOSYNC
DbTxn::commitDB_TXN_NOSYNC
DbEnv::txn_beginDB_TXN_NOWAIT
DbTxn::prepare
DbEnv::txn_beginDB_TXN_SYNC
DbTxn::commitDB_TXN_SYNC
Db::set_feedbackDB_UPGRADE
Db::upgrade
db_upgrade
DbEnv::openDB_USE_ENVIRON
DbEnv::removeDB_USE_ENVIRON
DbEnv::openDB_USE_ENVIRON_ROOT
DbEnv::removeDB_USE_ENVIRON_ROOT
DbEnv::set_verboseDB_VERB_CHKPOINT
DbEnv::set_verboseDB_VERB_DEADLOCK
DbEnv::set_verboseDB_VERB_RECOVERY
DbEnv::set_verboseDB_VERB_WAITSFOR
Db::set_feedbackDB_VERIFY
Db::verify
db_verify
Db::cursorDB_WRITECURSOR
DbDB_XA_CREATE
deadlocks
utility to detect deadlocks
debugging applications
deleting records
deleting records with a cursor
Configuring Berkeley DB--disable-bigfile
disk space requirements
utility to dump databases as text files
duplicate data items
duplicating a cursor
configuring dynamic shared libraries
Configuring Berkeley DB--enable-compat185
Configuring Berkeley DB--enable-cxx
Configuring Berkeley DB--enable-debug
Configuring Berkeley DB--enable-debug_rop
Configuring Berkeley DB--enable-debug_wop
Configuring Berkeley DB--enable-diagnostic
Configuring Berkeley DB--enable-dump185
Configuring Berkeley DB--enable-dynamic
Configuring Berkeley DB--enable-java
Configuring Berkeley DB--enable-posixmutexes
Configuring Berkeley DB--enable-rpc
Configuring Berkeley DB--enable-shared
Configuring Berkeley DB--enable-tcl
Configuring Berkeley DB--enable-test
Configuring Berkeley DB--enable-uimutexes
Configuring Berkeley DB--enable-umrw
byte endian
database environment
environment variables
error handling
error name space
error returns
/etc/magic
selecting a Queue extent size
Java FAQ
Tcl FAQ
configuring without large file support
file utility
DbMpoolFile::openfileid
recovery and filesystem operations
remote filesystems
page fill factor
FreeBSD
Berkeley DB free-threaded handles
DbMpoolFile::openftype
specifying a database hash
hash table size
HP-UX
installing Berkeley DB for UNIX systems
interface compatibility
IRIX
configuring the Java API
Java compatibility
Java configuration
Java FAQ
logical join
key/data pairs
retrieved key/data permanence
database limits
Linux
changing compile or load options
utility to load text files into databases
DbEnv::lock_veclock
standard lock modes
page-level locking
two-phase locking
locking and non-Berkeley DB applications
locking configuration
locking conventions
Berkeley DB Concurrent Data Store locking conventions
locking introduction
sizing the locking subsystem
locking without transactions
log file limits
log file removal
utility to display log files as text
logging configuration
logging introduction
DbMpoolFile::openlsn_offset
memory pool configuration
DbEnv::lock_vecmode
Berkeley DB library name spaces
file naming
retrieving Btree records by number
DbEnv::lock_vecobj
DbEnv::lock_vecop
opening a database
OSF/1
selecting a page size
partial record storage and retrieval
Patches, Updates and Change logs
Perl
retrieved key/data permanence
DbMpoolFile::openpgcookie
Sleepycat Software's Berkeley DB products
QNX
logical record number format
logical record numbers
managing record-based databases
logically renumbering records
utility to recover database environments
Berkeley DB recoverability
retrieving records
retrieving records with a cursor
RPC client
configuring a RPC client/server
utility to support RPC client/server
RPC server
database salvage
SCO
Berkeley DB handle scope
security
Sendmail
configuring shared libraries
shared libraries
application signal handling
Sleepycat Software
Solaris
source code layout
cursor stability
database statistics
utility to display database and environment statistics
storing records
storing records with a cursor
SunOS
loading Berkeley DB with Tcl
using Berkeley DB with Tcl
configuring the Tcl API
Tcl API programming notes
Tcl FAQ
configuring the test suite
running the test suite
running the test suite under UNIX
running the test suite under Windows
text backing files
loading text into databases
dumping/loading text to/from databases
building threaded applications
transaction configuration
transaction limits
administering transaction protected applications
archival in transaction protected applications
checkpoints in transaction protected applications
deadlock detection in transaction protected applications
recovery in transaction protected applications
transaction throughput
Transactional Data Store
Berkeley DB and transactions
nested transactions
configuring Berkeley DB with the Tuxedo System
Ultrix
building for UNIX FAQ
configuring Berkeley DB for UNIX systems
Patches, Updates and Change logs
utility to upgrade database files
upgrading databases
utilities
database verification
utility to verify database files
building for VxWorks FAQ
VxWorks notes
running the test suite under Windows
building for Windows FAQ
Windows notes
Configuring Berkeley DB--with-tcl=DIR
XA Resource Manager
+
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_class.html b/db/docs/api_cxx/db_class.html new file mode 100644 index 000000000..75296aeee --- /dev/null +++ b/db/docs/api_cxx/db_class.html @@ -0,0 +1,109 @@ + + + + + +Berkeley DB: Db + + + + + + + +
+

Db

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+class Db { +public: + Db(DbEnv *dbenv, u_int32_t flags); + ~Db(); + ... +}; +

+

Description

+

This manual page describes the specific details of the Db class, +which is the center of access method activity. +

If no dbenv value is specified, the database is standalone, i.e., +it is not part of any Berkeley DB environment. +

If a dbenv value is specified, the database is created within the +specified Berkeley DB environment. The database access methods automatically +make calls to the other subsystems in Berkeley DB based on the enclosing +environment. For example, if the environment has been configured to use +locking, then the access methods will automatically acquire the correct +locks when reading and writing pages of the database. +

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +

+

DB_CXX_NO_EXCEPTIONS
The Berkeley DB C++ API supports two different error behaviors. By default, +whenever an error occurs an exception is thrown that encapsulates the +error information. This generally allows for cleaner logic for +transaction processing, as a try block can surround a single transaction. +However, if DB_CXX_NO_EXCEPTIONS is specified, exceptions are not +thrown, instead each individual function returns an error code. +

If dbenv is not null, this flag is ignored and the error behavior +of the specified environment is used instead. +

DB_XA_CREATE
Instead of creating a standalone database, create a database intended to +be accessed via applications running under a X/Open conformant Transaction +Manager. The database will be opened in the environment specified by the +OPENINFO parameter of the GROUPS section of the ubbconfig file. See the +XA Resource Manager chapter in the +Reference Guide for more information. +
+

Class

+Db +

See Also

+Db::close, +Db::cursor, +Db::del, +Db::err, +Db::fd, +Db::get, +Db::get_byteswapped, +Db::get_type, +Db::join, +Db::key_range, +Db::open, +Db::put, +Db::remove, +Db::set_bt_compare, +Db::set_bt_minkey, +Db::set_bt_prefix, +Db::set_cachesize, +Db::set_dup_compare, +Db::set_errcall, +Db::set_errfile, +Db::set_errpfx, +Db::set_flags, +Db::set_h_ffactor, +Db::set_h_hash, +Db::set_h_nelem, +Db::set_lorder, +Db::set_malloc, +Db::set_pagesize, +Db::set_paniccall, +Db::set_q_extentsize, +Db::set_realloc, +Db::set_re_delim, +Db::set_re_len, +Db::set_re_pad, +Db::set_re_source, +Db::stat, +Db::sync, +Db::upgrade +and +Db::verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_close.html b/db/docs/api_cxx/db_close.html new file mode 100644 index 000000000..fdde15bdb --- /dev/null +++ b/db/docs/api_cxx/db_close.html @@ -0,0 +1,123 @@ + + + + + +Berkeley DB: Db::close + + + + + + + +
+

Db::close

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +Db::close(u_int32_t flags); +

+

Description

+

The Db::close method flushes any cached database information to disk, +closes any open cursors, frees any allocated resources, and closes any +underlying files. Since key/data pairs are cached in memory, failing to +sync the file with the Db::close or Db::sync method may result +in inconsistent or lost information. +

The flags parameter must be set to 0 or the following value: +

+

DB_NOSYNC
Do not flush cached information to disk. +

The DB_NOSYNC flag is a dangerous option. It should only be set +if the application is doing logging (with transactions) so that the +database is recoverable after a system or application crash, or if the +database is always generated from scratch after any system or application +crash. +

It is important to understand that flushing cached information to disk +only minimizes the window of opportunity for corrupted data. +While unlikely, it is possible for database corruption to happen if a +system or application crash occurs while writing data to the database. +To ensure that database corruption never occurs, applications must either: +use transactions and logging with automatic recovery, use logging and +application-specific recovery, or edit a copy of the database, +and, once all applications using the database have successfully called +Db::close, atomically replace the original database with the +updated copy. +

+

When multiple threads are using the Berkeley DB handle concurrently, only a single +thread may call the Db::close method. +

Once Db::close has been called, regardless of its return, the +Db handle may not be accessed again. + +

The Db::close method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, 0 on success, and returns DB_INCOMPLETE if the underlying database still has +dirty pages in the cache. (The only reason to return +DB_INCOMPLETE is if another thread of control was writing pages +in the underlying database file at the same time as the +Db::close method was called. For this reason, a return of +DB_INCOMPLETE can normally be ignored, or, in cases where it is +a possible return value, the DB_NOSYNC option should probably +have been specified.) +

The Db::close method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The Db::close method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Db::close method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Class

+Db +

See Also

+Db::close, +Db::cursor, +Db::del, +Db::err, +Db::fd, +Db::get, +Db::get_byteswapped, +Db::get_type, +Db::join, +Db::key_range, +Db::open, +Db::put, +Db::remove, +Db::set_bt_compare, +Db::set_bt_minkey, +Db::set_bt_prefix, +Db::set_cachesize, +Db::set_dup_compare, +Db::set_errcall, +Db::set_errfile, +Db::set_errpfx, +Db::set_flags, +Db::set_h_ffactor, +Db::set_h_hash, +Db::set_h_nelem, +Db::set_lorder, +Db::set_malloc, +Db::set_pagesize, +Db::set_paniccall, +Db::set_q_extentsize, +Db::set_realloc, +Db::set_re_delim, +Db::set_re_len, +Db::set_re_pad, +Db::set_re_source, +Db::stat, +Db::sync, +Db::upgrade +and +Db::verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_cursor.html b/db/docs/api_cxx/db_cursor.html new file mode 100644 index 000000000..b6954b9f3 --- /dev/null +++ b/db/docs/api_cxx/db_cursor.html @@ -0,0 +1,105 @@ + + + + + +Berkeley DB: Db::cursor + + + + + + + +
+

Db::cursor

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +Db::cursor(DbTxn *txnid, Dbc **cursorp, u_int32_t flags); +

+

Description

+

The Db::cursor method +creates a cursor and copies a pointer to it into the memory referenced +by cursorp. +

If the file is being accessed under transaction protection, the +txnid parameter is a transaction ID returned from +DbEnv::txn_begin, otherwise, NULL. +

If transaction protection is enabled, cursors must be opened and closed +within the context of a transaction, and the txnid parameter +specifies the transaction context in which the cursor may be used. +

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +

+

DB_WRITECURSOR
Specify that the cursor will be used to update the database. This +flag should only be set when the DB_INIT_CDB flag +was specified to DbEnv::open. +
+

The Db::cursor method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The Db::cursor method may fail and throw an exception or return a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +
+

The Db::cursor method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Db::cursor method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Class

+Db +

See Also

+Db::close, +Db::cursor, +Db::del, +Db::err, +Db::fd, +Db::get, +Db::get_byteswapped, +Db::get_type, +Db::join, +Db::key_range, +Db::open, +Db::put, +Db::remove, +Db::set_bt_compare, +Db::set_bt_minkey, +Db::set_bt_prefix, +Db::set_cachesize, +Db::set_dup_compare, +Db::set_errcall, +Db::set_errfile, +Db::set_errpfx, +Db::set_flags, +Db::set_h_ffactor, +Db::set_h_hash, +Db::set_h_nelem, +Db::set_lorder, +Db::set_malloc, +Db::set_pagesize, +Db::set_paniccall, +Db::set_q_extentsize, +Db::set_realloc, +Db::set_re_delim, +Db::set_re_len, +Db::set_re_pad, +Db::set_re_source, +Db::stat, +Db::sync, +Db::upgrade +and +Db::verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_del.html b/db/docs/api_cxx/db_del.html new file mode 100644 index 000000000..ec30c6ad0 --- /dev/null +++ b/db/docs/api_cxx/db_del.html @@ -0,0 +1,104 @@ + + + + + +Berkeley DB: Db::del + + + + + + + +
+

Db::del

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +Db::del(DbTxn *txnid, Dbt *key, u_int32_t flags); +

+

Description

+

The Db::del method removes key/data pairs from the database. The +key/data pair associated with the specified key is discarded from +the database. In the presence of duplicate key values, all records +associated with the designated key will be discarded. +

If the file is being accessed under transaction protection, the +txnid parameter is a transaction ID returned from +DbEnv::txn_begin, otherwise, NULL. +

The flags parameter is currently unused, and must be set to 0. +

The Db::del method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, 0 on success, and DB_NOTFOUND if the specified key did not exist in +the file. +

Errors

+

The Db::del method may fail and throw an exception or return a non-zero error for the following conditions: +

+

DB_LOCK_DEADLOCK
The operation was selected to resolve a deadlock. +
+

+

EACCES
An attempt was made to modify a read-only database. +
+

+

EINVAL
An invalid flag value or parameter was specified. +
+

The Db::del method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Db::del method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Class

+Db +

See Also

+Db::close, +Db::cursor, +Db::del, +Db::err, +Db::fd, +Db::get, +Db::get_byteswapped, +Db::get_type, +Db::join, +Db::key_range, +Db::open, +Db::put, +Db::remove, +Db::set_bt_compare, +Db::set_bt_minkey, +Db::set_bt_prefix, +Db::set_cachesize, +Db::set_dup_compare, +Db::set_errcall, +Db::set_errfile, +Db::set_errpfx, +Db::set_flags, +Db::set_h_ffactor, +Db::set_h_hash, +Db::set_h_nelem, +Db::set_lorder, +Db::set_malloc, +Db::set_pagesize, +Db::set_paniccall, +Db::set_q_extentsize, +Db::set_realloc, +Db::set_re_delim, +Db::set_re_len, +Db::set_re_pad, +Db::set_re_source, +Db::stat, +Db::sync, +Db::upgrade +and +Db::verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_err.html b/db/docs/api_cxx/db_err.html new file mode 100644 index 000000000..fa0bccc39 --- /dev/null +++ b/db/docs/api_cxx/db_err.html @@ -0,0 +1,94 @@ + + + + + +Berkeley DB: DbEnv::err + + + + + + + +
+

DbEnv::err

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+DbEnv::err(int error, const char *fmt, ...); +

+DbEnv::errx(const char *fmt, ...); +

+Db::err(int error, const char *fmt, ...); +

+Db::errx(const char *fmt, ...); +

+

Description

+

The DbEnv::err, DbEnv::errx, Db::err and +Db::errx methods provide error messaging functionality for +applications written using the Berkeley DB library. +

The DbEnv::err method constructs an error message consisting of the +following elements: +

+

An optional prefix string
If no error callback method has been set using the +DbEnv::set_errcall method, any prefix string specified using the +DbEnv::set_errpfx method, followed by two separating characters: a colon +and a <space> character. +

An optional printf-style message
The supplied message fmt, if non-NULL, where the ANSI C X3.159-1989 (ANSI C) +printf function specifies how subsequent arguments are converted for +output. +

A separator
Two separating characters: a colon and a <space> character. +

A standard error string
The standard system or Berkeley DB library error string associated with the +error value, as returned by the DbEnv::strerror method. +
+
+

This constructed error message is then handled as follows: +

+

If an error callback method has been set (see Db::set_errcall +and DbEnv::set_errcall), that method is called with two +arguments: any prefix string specified (see Db::set_errpfx and +DbEnv::set_errpfx), and the error message. +

If a C library FILE * has been set (see Db::set_errfile and +DbEnv::set_errfile), the error message is written to that output +stream. +

If a C++ ostream has been set +(see DbEnv::set_error_stream), the error message is written to that +stream. +

If none of these output options has been configured, the error message +is written to stderr, the standard error output stream.

+

The DbEnv::errx and Db::errx methods perform identically to the +DbEnv::err and Db::err methods except that they do not append +the final separator characters and standard error string to the error +message. +

Class

+DbEnv +

See Also

+DbEnv::close, +DbEnv::open, +DbEnv::remove, +DbEnv::err, +DbEnv::strerror, +DbEnv::version, +DbEnv::set_cachesize, +DbEnv::set_errcall, +DbEnv::set_errfile, +DbEnv::set_error_stream, +DbEnv::set_errpfx, +DbEnv::set_flags, +DbEnv::set_mutexlocks, +DbEnv::set_paniccall, +and +DbEnv::set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_fd.html b/db/docs/api_cxx/db_fd.html new file mode 100644 index 000000000..1cb98fb6b --- /dev/null +++ b/db/docs/api_cxx/db_fd.html @@ -0,0 +1,95 @@ + + + + + +Berkeley DB: Db::fd + + + + + + + +
+

Db::fd

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +Db::fd(int *fdp); +

+

Description

+

The Db::fd method +copies a file descriptor representative of the underlying database into +the memory referenced by fdp. A file descriptor referencing the +same file will be returned to all processes that call Db::open with +the same file argument. This file descriptor may be safely used +as an argument to the fcntl(2) and flock(2) locking +functions. The file descriptor is not necessarily associated with any of +the underlying files actually used by the access method. +

The Db::fd method only supports a coarse-grained form of locking. +Applications should use the lock manager where possible. +

The Db::fd method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The Db::fd method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Db::fd method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Class

+Db +

See Also

+Db::close, +Db::cursor, +Db::del, +Db::err, +Db::fd, +Db::get, +Db::get_byteswapped, +Db::get_type, +Db::join, +Db::key_range, +Db::open, +Db::put, +Db::remove, +Db::set_bt_compare, +Db::set_bt_minkey, +Db::set_bt_prefix, +Db::set_cachesize, +Db::set_dup_compare, +Db::set_errcall, +Db::set_errfile, +Db::set_errpfx, +Db::set_flags, +Db::set_h_ffactor, +Db::set_h_hash, +Db::set_h_nelem, +Db::set_lorder, +Db::set_malloc, +Db::set_pagesize, +Db::set_paniccall, +Db::set_q_extentsize, +Db::set_realloc, +Db::set_re_delim, +Db::set_re_len, +Db::set_re_pad, +Db::set_re_source, +Db::stat, +Db::sync, +Db::upgrade +and +Db::verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_get.html b/db/docs/api_cxx/db_get.html new file mode 100644 index 000000000..0cee5526b --- /dev/null +++ b/db/docs/api_cxx/db_get.html @@ -0,0 +1,158 @@ + + + + + +Berkeley DB: Db::get + + + + + + + +
+

Db::get

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +Db::get(DbTxn *txnid, Dbt *key, Dbt *data, u_int32_t flags); +

+

Description

+

The Db::get method retrieves key/data pairs from the database. The +address +and length of the data associated with the specified key are +returned in the structure referenced by data. +

In the presence of duplicate key values, Db::get will return the +first data item for the designated key. Duplicates are sorted by insert +order except where this order has been overridden by cursor operations. +Retrieval of duplicates requires the use of cursor operations. +See Dbc::get for details. +

If the file is being accessed under transaction protection, the +txnid parameter is a transaction ID returned from +DbEnv::txn_begin, otherwise, NULL. +

The flags parameter must be set to 0 or one of the following +values: +

+

DB_CONSUME
Return the record number and data from the available record closest to +the head of the queue and delete the record. The cursor will be +positioned on the deleted record. The record number will be returned +in key as described in Dbt. The data will be returned +in the data parameter. A record is available if it is not +deleted and is not currently locked. The underlying database must be +of type Queue for DB_CONSUME to be specified. +

DB_CONSUME_WAIT
The DB_CONSUME_WAIT flag is the same as the DB_CONSUME +flag except that if the Queue database is empty, the thread of control +will wait until there is data in the queue before returning. The +underlying database must be of type Queue for DB_CONSUME_WAIT +to be specified. +

DB_GET_BOTH
Retrieve the key/data pair only if both the key and data match the +arguments. +

DB_SET_RECNO
Retrieve the specified numbered key/data pair from a database. +Upon return, both the key and data items will have been +filled in, not just the data item as is done for all other uses of the +Db::get method. +

The data field of the specified key +must be a pointer to a logical record number (i.e., a db_recno_t). +This record number determines the record to be retrieved. +

For DB_SET_RECNO to be specified, the underlying database must be +of type Btree and it must have been created with the DB_RECNUM flag. +

+

In addition, the following flag may be set by bitwise inclusively OR'ing it into the +flags parameter: +

+

DB_RMW
Acquire write locks instead of read locks when doing the retrieval. +Setting this flag may decrease the likelihood of deadlock during a +read-modify-write cycle by immediately acquiring the write lock during +the read part of the cycle so that another thread of control acquiring +a read lock for the same item, in its own read-modify-write cycle, will +not result in deadlock. +

As the Db::get interface will not hold locks across +Berkeley DB interface calls in non-transactional environments, the +DB_RMW flag to the Db::get call is only meaningful in +the presence of transactions. +

+

If the database is a Queue or Recno database and the requested key exists, +but was never explicitly created by the application or was later deleted, +the Db::get method returns DB_KEYEMPTY. +

Otherwise, if the requested key is not in the database, the +Db::get function returns DB_NOTFOUND. +

Otherwise, the Db::get method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The Db::get method may fail and throw an exception or return a non-zero error for the following conditions: +

+

DB_LOCK_DEADLOCK
The operation was selected to resolve a deadlock. +
+

+

ENOMEM
There was insufficient memory to return the requested item. +
+

+

EINVAL
An invalid flag value or parameter was specified. +

A record number of 0 was specified. +

The DB_THREAD flag was specified to the +Db::open method and none of the DB_DBT_MALLOC, +DB_DBT_REALLOC or DB_DBT_USERMEM flags were set in the +Dbt. +

+

The Db::get method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Db::get method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Class

+Db +

See Also

+Db::close, +Db::cursor, +Db::del, +Db::err, +Db::fd, +Db::get, +Db::get_byteswapped, +Db::get_type, +Db::join, +Db::key_range, +Db::open, +Db::put, +Db::remove, +Db::set_bt_compare, +Db::set_bt_minkey, +Db::set_bt_prefix, +Db::set_cachesize, +Db::set_dup_compare, +Db::set_errcall, +Db::set_errfile, +Db::set_errpfx, +Db::set_flags, +Db::set_h_ffactor, +Db::set_h_hash, +Db::set_h_nelem, +Db::set_lorder, +Db::set_malloc, +Db::set_pagesize, +Db::set_paniccall, +Db::set_q_extentsize, +Db::set_realloc, +Db::set_re_delim, +Db::set_re_len, +Db::set_re_pad, +Db::set_re_source, +Db::stat, +Db::sync, +Db::upgrade +and +Db::verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_get_byteswapped.html b/db/docs/api_cxx/db_get_byteswapped.html new file mode 100644 index 000000000..5c661fa57 --- /dev/null +++ b/db/docs/api_cxx/db_get_byteswapped.html @@ -0,0 +1,85 @@ + + + + + +Berkeley DB: Db::get_byteswapped + + + + + + + +
+

Db::get_byteswapped

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +Db::get_byteswapped(void) const; +

+

Description

+

The Db::get_byteswapped method returns +0 +if the underlying database files were created on an architecture +of the same byte order as the current one, and +1 +if they were not (i.e., big-endian on a little-endian machine or +vice-versa). This field may be used to determine if application +data needs to be adjusted for this architecture or not. +

Class

+Db +

See Also

+Db::close, +Db::cursor, +Db::del, +Db::err, +Db::fd, +Db::get, +Db::get_byteswapped, +Db::get_type, +Db::join, +Db::key_range, +Db::open, +Db::put, +Db::remove, +Db::set_bt_compare, +Db::set_bt_minkey, +Db::set_bt_prefix, +Db::set_cachesize, +Db::set_dup_compare, +Db::set_errcall, +Db::set_errfile, +Db::set_errpfx, +Db::set_flags, +Db::set_h_ffactor, +Db::set_h_hash, +Db::set_h_nelem, +Db::set_lorder, +Db::set_malloc, +Db::set_pagesize, +Db::set_paniccall, +Db::set_q_extentsize, +Db::set_realloc, +Db::set_re_delim, +Db::set_re_len, +Db::set_re_pad, +Db::set_re_source, +Db::stat, +Db::sync, +Db::upgrade +and +Db::verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_get_type.html b/db/docs/api_cxx/db_get_type.html new file mode 100644 index 000000000..755032390 --- /dev/null +++ b/db/docs/api_cxx/db_get_type.html @@ -0,0 +1,82 @@ + + + + + +Berkeley DB: Db::get_type + + + + + + + +
+

Db::get_type

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+DBTYPE +Db::get_type(void) const; +

+

Description

+

The Db::get_type method returns the type of the underlying access method +(and file format). It returns one of DB_BTREE, +DB_HASH or DB_RECNO. This value may be used to +determine the type of the database after a return from Db::open +with the type argument set to DB_UNKNOWN. +

Class

+Db +

See Also

+Db::close, +Db::cursor, +Db::del, +Db::err, +Db::fd, +Db::get, +Db::get_byteswapped, +Db::get_type, +Db::join, +Db::key_range, +Db::open, +Db::put, +Db::remove, +Db::set_bt_compare, +Db::set_bt_minkey, +Db::set_bt_prefix, +Db::set_cachesize, +Db::set_dup_compare, +Db::set_errcall, +Db::set_errfile, +Db::set_errpfx, +Db::set_flags, +Db::set_h_ffactor, +Db::set_h_hash, +Db::set_h_nelem, +Db::set_lorder, +Db::set_malloc, +Db::set_pagesize, +Db::set_paniccall, +Db::set_q_extentsize, +Db::set_realloc, +Db::set_re_delim, +Db::set_re_len, +Db::set_re_pad, +Db::set_re_source, +Db::stat, +Db::sync, +Db::upgrade +and +Db::verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_join.html b/db/docs/api_cxx/db_join.html new file mode 100644 index 000000000..6767aaf76 --- /dev/null +++ b/db/docs/api_cxx/db_join.html @@ -0,0 +1,153 @@ + + + + + +Berkeley DB: Db::join + + + + + + + +
+

Db::join

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +Db::join(Dbc **curslist, Dbc **dbcp, u_int32_t flags); +

+

Description

+

The Db::join method creates a specialized cursor for use in performing +joins on secondary indexes. For information on how to organize your data +to use this functionality, see Logical +join. +

The primary argument contains the Db handle of the primary +database, which is keyed by the data values found in entries in the +curslist. +

The curslist argument contains a NULL terminated array of cursors. +Each cursor must have been initialized to reference the key on which the +underlying database should be joined. Typically, this initialization is done +by a Dbc::get call with the DB_SET flag specified. Once the +cursors have been passed as part of a curslist, they should not +be accessed or modified until the newly created join cursor has been closed, +or else inconsistent results may be returned. +

Joined values are retrieved by doing a sequential iteration over the first +cursor in the curslist argument, and a nested iteration over each +secondary cursor in the order they are specified in the curslist +argument. This requires database traversals to search for the current +datum in all the cursors after the first. For this reason, the best join +performance normally results from sorting the cursors from the one that +references the least number of data items to the one that references the +most. By default, Db::join does this sort on behalf of its caller. +

The flags parameter must be set to 0 or the following value: +

+

DB_JOIN_NOSORT
Do not sort the cursors based on the number of data items they reference. +If the data are structured such that cursors with many data items also +share many common elements, higher performance will result from listing +those cursors before cursors with fewer data items, that is, a sort order +other than the default. The DB_JOIN_NOSORT flag permits +applications to perform join optimization prior to calling Db::join. +
+

A newly created cursor is returned in the memory location referenced by +dbcp and has the standard cursor functions: +

+

Dbc::get
Iterates over the values associated with the keys to which each item in +curslist has been initialized. Any data value which appears in +all items specified by the curslist argument is then used as a +key into the primary, and the key/data pair found in the +primary is returned. +

The flags parameter must be set to 0 or the following value: +

+

DB_JOIN_ITEM
Do not use the data value found in all of the cursors as a lookup +key for the primary, but simply return it in the key parameter +instead. The data parameter is left unchanged. +
+

In addition, the following flag may be set by bitwise inclusively OR'ing it into the +flags parameter: +

+

DB_RMW
Acquire write locks instead of read locks when doing the retrieval. +Setting this flag may decrease the likelihood of deadlock during a +read-modify-write cycle by immediately acquiring the write lock during +the read part of the cycle so that another thread of control acquiring +a read lock for the same item, in its own read-modify-write cycle, will +not result in deadlock. +
+

Dbc::put
Returns EINVAL. +

Dbc::del
Returns EINVAL. +

Dbc::close
Close the returned cursor and release all resources. (Closing the cursors +in curslist is the responsibility of the caller.) +
+

For the returned join cursor to be used in a transaction protected manner, +the cursors listed in curslist must have been created within the +context of the same transaction. +

The Db::join method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The Db::join method may fail and throw an exception or return a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +

The Dbc::put or Dbc::del functions were called. +

+

The Db::join method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Db::join method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Class

+Db +

See Also

+Db::close, +Db::cursor, +Db::del, +Db::err, +Db::fd, +Db::get, +Db::get_byteswapped, +Db::get_type, +Db::join, +Db::key_range, +Db::open, +Db::put, +Db::remove, +Db::set_bt_compare, +Db::set_bt_minkey, +Db::set_bt_prefix, +Db::set_cachesize, +Db::set_dup_compare, +Db::set_errcall, +Db::set_errfile, +Db::set_errpfx, +Db::set_flags, +Db::set_h_ffactor, +Db::set_h_hash, +Db::set_h_nelem, +Db::set_lorder, +Db::set_malloc, +Db::set_pagesize, +Db::set_paniccall, +Db::set_q_extentsize, +Db::set_realloc, +Db::set_re_delim, +Db::set_re_len, +Db::set_re_pad, +Db::set_re_source, +Db::stat, +Db::sync, +Db::upgrade +and +Db::verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_key_range.html b/db/docs/api_cxx/db_key_range.html new file mode 100644 index 000000000..980dc119a --- /dev/null +++ b/db/docs/api_cxx/db_key_range.html @@ -0,0 +1,109 @@ + + + + + +Berkeley DB: Db::key_range + + + + + + + +
+

Db::key_range

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +Db::key_range(DbTxn *txnid + Dbt *key, DB_KEY_RANGE *key_range, u_int32_t flags); +

+

Description

+

The Db::key_range method returns an estimate of the proportion of keys +that are less than, equal to and greater than the specified key. The +underlying database must be of type Btree. +

The information is returned in the key_range argument, which +contains three elements of type double, less, equal and +greater. Values are in the range of 0 to 1, e.g., if the field +less is 0.05, that indicates that 5% of the keys in the database +are less than the key argument. The value for equal will be zero +if there is no matching key and non-zero otherwise. +

If the file is being accessed under transaction protection, the +txnid parameter is a transaction ID returned from +DbEnv::txn_begin, otherwise, NULL. +The Db::key_range method does not retain the locks it acquires for the +life of the transaction, so estimates may not be repeatable. +

The flags parameter is currently unused, and must be set to 0. +

The Db::key_range method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The Db::key_range method may fail and throw an exception or return a non-zero error for the following conditions: +

+

DB_LOCK_DEADLOCK
The operation was selected to resolve a deadlock. +
+

+

EINVAL
An invalid flag value or parameter was specified. +

The underlying database was not of type Btree. +

+

The Db::key_range method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Db::key_range method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Class

+Db +

See Also

+Db::close, +Db::cursor, +Db::del, +Db::err, +Db::fd, +Db::get, +Db::get_byteswapped, +Db::get_type, +Db::join, +Db::key_range, +Db::open, +Db::put, +Db::remove, +Db::set_bt_compare, +Db::set_bt_minkey, +Db::set_bt_prefix, +Db::set_cachesize, +Db::set_dup_compare, +Db::set_errcall, +Db::set_errfile, +Db::set_errpfx, +Db::set_flags, +Db::set_h_ffactor, +Db::set_h_hash, +Db::set_h_nelem, +Db::set_lorder, +Db::set_malloc, +Db::set_pagesize, +Db::set_paniccall, +Db::set_q_extentsize, +Db::set_realloc, +Db::set_re_delim, +Db::set_re_len, +Db::set_re_pad, +Db::set_re_source, +Db::stat, +Db::sync, +Db::upgrade +and +Db::verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_open.html b/db/docs/api_cxx/db_open.html new file mode 100644 index 000000000..4c8cb75f4 --- /dev/null +++ b/db/docs/api_cxx/db_open.html @@ -0,0 +1,185 @@ + + + + + +Berkeley DB: Db::open + + + + + + + +
+

Db::open

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +Db::open(const char *file, + const char *database, DBTYPE type, u_int32_t flags, int mode); +

+

Description

+

The currently supported Berkeley DB file formats (or access methods) +are Btree, Hash, Queue and Recno. The Btree format is a representation +of a sorted, balanced tree structure. The Hash format is an extensible, +dynamic hashing scheme. The Queue format supports fast access to +fixed-length records accessed by sequentially or logical record number. +The Recno format supports fixed- or variable-length records, accessed +sequentially or by logical record number, and optionally retrieved from +a flat text file. +

Storage and retrieval for the Berkeley DB access methods are based on key/data +pairs, see Dbt for more information. +

The Db::open interface opens the database represented by the +file and database arguments for both reading and writing. +The file argument is used as the name of a physical file on disk +that will be used to back the database. The database argument is +optional and allows applications to have multiple logical databases in a +single physical file. While no database argument needs to be +specified, it is an error to attempt to open a second database in a +file that was not initially created using a database name. +In-memory databases never intended to be preserved on disk may +be created by setting both the file and database arguments +to NULL. Note that in-memory databases can only ever be shared by +sharing the single database handle that created them, in circumstances +where doing so is safe. +

The type argument is of type DBTYPE +and must be set to one of DB_BTREE, DB_HASH, +DB_QUEUE, DB_RECNO or DB_UNKNOWN, except +that databases of type DB_QUEUE are restricted to one per +file. If type is DB_UNKNOWN, the database must +already exist and Db::open will automatically determine its type. +The Db::get_type method may be used to determine the underlying type of +databases opened using DB_UNKNOWN. +

The flags and mode arguments specify how files will be opened +and/or created if they do not already exist. +

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +

+

DB_CREATE
Create any underlying files, as necessary. If the files do not already +exist and the DB_CREATE flag is not specified, the call will fail. +

DB_EXCL
Return an error if the file already exists. Underlying filesystem +primitives are used to implement this flag. For this reason it is only +applicable to the physical file and cannot be used to test if a database +in a file already exists. +

The DB_EXCL flag is only meaningful when specified with the +DB_CREATE flag. +

DB_NOMMAP
Do not map this database into process memory (see the description of the +DbEnv::set_mp_mmapsize method for further information). +

DB_RDONLY
Open the database for reading only. Any attempt to modify items in the +database will fail regardless of the actual permissions of any underlying +files. +

DB_THREAD
Cause the Db handle returned by Db::open to be +free-threaded, that is, useable by multiple threads within a +single address space. +

DB_TRUNCATE
Physically truncate the underlying file, discarding all previous databases +it might have held. Underlying filesystem primitives are used to +implement this flag. For this reason it is only applicable to the +physical file and cannot be used to discard databases within a file. +

The DB_TRUNCATE flag cannot be transaction protected, and it is +an error to specify it in a transaction protected environment. +

+

On UNIX systems, or in IEEE/ANSI Std 1003.1 (POSIX) environments, all files created by the access methods +are created with mode mode (as described in chmod(2)) and +modified by the process' umask value at the time of creation (see +umask(2)). The group ownership of created files is based on +the system and directory defaults, and is not further specified by Berkeley DB. +If mode is 0, files are created readable and writeable by both +owner and group. On Windows systems, the mode argument is ignored. +

Calling Db::open is a reasonably expensive operation, and +maintaining a set of open databases will normally be preferable to +repeatedly open and closing the database for each new query. +

The Db::open method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Environment Variables

+

+

DB_HOME
If the dbenv argument to db_create was initialized using +DbEnv::open the environment variable DB_HOME may be used +as the path of the database environment home. Specifically, Db::open +is affected by the configuration value DB_DATA_DIR. +
+

+

TMPDIR
If the file and dbenv arguments to Db::open are +NULL, the environment variable TMPDIR may be used as a +directory in which to create a temporary backing file. +
+

Errors

+

The Db::open method may fail and throw an exception or return a non-zero error for the following conditions: +

+

DB_OLD_VERSION
The database cannot be opened without being first upgraded. +

EEXIST
DB_CREATE and DB_EXCL were specified and the file exists. +

EINVAL
An invalid flag value or parameter was specified (e.g., unknown database +type, page size, hash function, pad byte, byte order) or a flag value +or parameter that is incompatible with the specified database. +

+The DB_THREAD flag was specified and spinlocks are not +implemented for this architecture. +

The DB_THREAD flag was specified to Db::open, but was not +specified to the DbEnv::open call for the environment in which the +Db handle was created. +

A re_source file was specified with either the DB_THREAD +flag or the provided database environment supports transaction +processing. +

ENOENT
A non-existent re_source file was specified. +
+

The Db::open method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Db::open method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Class

+Db +

See Also

+Db::close, +Db::cursor, +Db::del, +Db::err, +Db::fd, +Db::get, +Db::get_byteswapped, +Db::get_type, +Db::join, +Db::key_range, +Db::open, +Db::put, +Db::remove, +Db::set_bt_compare, +Db::set_bt_minkey, +Db::set_bt_prefix, +Db::set_cachesize, +Db::set_dup_compare, +Db::set_errcall, +Db::set_errfile, +Db::set_errpfx, +Db::set_flags, +Db::set_h_ffactor, +Db::set_h_hash, +Db::set_h_nelem, +Db::set_lorder, +Db::set_malloc, +Db::set_pagesize, +Db::set_paniccall, +Db::set_q_extentsize, +Db::set_realloc, +Db::set_re_delim, +Db::set_re_len, +Db::set_re_pad, +Db::set_re_source, +Db::stat, +Db::sync, +Db::upgrade +and +Db::verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_put.html b/db/docs/api_cxx/db_put.html new file mode 100644 index 000000000..5e2d1b8c4 --- /dev/null +++ b/db/docs/api_cxx/db_put.html @@ -0,0 +1,138 @@ + + + + + +Berkeley DB: Db::put + + + + + + + +
+

Db::put

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +Db::put(DbTxn *txnid, Dbt *key, Dbt *data, u_int32_t flags); +

+

Description

+

The Db::put method stores key/data pairs in the database. The default +behavior of the Db::put function is to enter the new key/data +pair, replacing any previously existing key if duplicates are disallowed, +or adding a duplicate data item if duplicates are allowed. If the database +supports duplicates, the Db::put method adds the new data value at the +end of the duplicate set. If the database supports sorted duplicates, +the new data value is inserted at the correct sorted location. +

If the file is being accessed under transaction protection, the +txnid parameter is a transaction ID returned from +DbEnv::txn_begin, otherwise, NULL. +

The flags parameter must be set to 0 or one of the following +values: +

+

DB_APPEND
Append the key/data pair to the end of the database. For the +DB_APPEND flag to be specified, the underlying database must be +a Queue or Recno database. The record number allocated to the record is +returned in the specified key. +

There is a minor behavioral difference between the Recno and Queue access +methods for the DB_APPEND flag. If a transaction enclosing a +Db::put operation with the DB_APPEND flag aborts, the +record number may be decremented (and later re-allocated by a subsequent +DB_APPEND operation) by the Recno access method, but will not be +decremented or re-allocated by the Queue access method. +

DB_NODUPDATA
In the case of the Btree and Hash access methods, enter the new key/data +pair only if it does not already appear in the database. If the +key/data pair already appears in the database, DB_KEYEXIST is +returned. The DB_NODUPDATA flag may only be specified if the +underlying database has been configured to support sorted duplicates. +

The DB_NODUPDATA flag may not be specified to the Queue or Recno +access methods. +

DB_NOOVERWRITE
Enter the new key/data pair only if the key does not already appear in +the database. If the key already appears in the database, +DB_KEYEXIST is returned. Even if the database allows duplicates, +a call to Db::put with the DB_NOOVERWRITE flag set will +fail if the key already exists in the database. +
+

Otherwise, the Db::put method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The Db::put method may fail and throw an exception or return a non-zero error for the following conditions: +

+

DB_LOCK_DEADLOCK
The operation was selected to resolve a deadlock. +
+

+

EACCES
An attempt was made to modify a read-only database. +
+

+

EINVAL
An invalid flag value or parameter was specified. +

A record number of 0 was specified. +

An attempt was made to add a record to a fixed-length database that was too +large to fit. +

An attempt was made to do a partial put. +

+

+

ENOSPC
A btree exceeded the maximum btree depth (255). +
+

The Db::put method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Db::put method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Class

+Db +

See Also

+Db::close, +Db::cursor, +Db::del, +Db::err, +Db::fd, +Db::get, +Db::get_byteswapped, +Db::get_type, +Db::join, +Db::key_range, +Db::open, +Db::put, +Db::remove, +Db::set_bt_compare, +Db::set_bt_minkey, +Db::set_bt_prefix, +Db::set_cachesize, +Db::set_dup_compare, +Db::set_errcall, +Db::set_errfile, +Db::set_errpfx, +Db::set_flags, +Db::set_h_ffactor, +Db::set_h_hash, +Db::set_h_nelem, +Db::set_lorder, +Db::set_malloc, +Db::set_pagesize, +Db::set_paniccall, +Db::set_q_extentsize, +Db::set_realloc, +Db::set_re_delim, +Db::set_re_len, +Db::set_re_pad, +Db::set_re_source, +Db::stat, +Db::sync, +Db::upgrade +and +Db::verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_remove.html b/db/docs/api_cxx/db_remove.html new file mode 100644 index 000000000..56cc5a234 --- /dev/null +++ b/db/docs/api_cxx/db_remove.html @@ -0,0 +1,110 @@ + + + + + +Berkeley DB: Db::remove + + + + + + + +
+

Db::remove

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +Db::remove(const char *file, const char *database, u_int32_t flags); +

+

Description

+

The Db::remove interface removes the database specified by the +file and database arguments. If no database is +specified, the physical file represented by file is removed, +incidentally removing all databases that it contained. +

If a physical file is being removed and logging is currently enabled in +the database environment, no database in the file may be open when the +Db::remove method is called. Otherwise, no reference count of database +use is maintained by Berkeley DB. Applications should not remove databases that +are currently in use. In particular, some architectures do not permit +the removal of files with open handles. On these architectures, attempts +to remove databases that are currently in use will fail. +

The flags parameter is currently unused, and must be set to 0. +

Once Db::remove has been called, regardless of its return, the +Db handle may not be accessed again. +

The Db::remove method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Environment Variables

+

+

DB_HOME
If the dbenv argument to db_create was initialized using +DbEnv::open the environment variable DB_HOME may be used +as the path of the database environment home. Specifically, Db::remove +is affected by the configuration value DB_DATA_DIR. +
+

Errors

+

The Db::remove method may fail and throw an exception or return a non-zero error for the following conditions: +

+

EINVAL
A database in the file is currently open. +
+

The Db::remove method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Db::remove method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Class

+Db +

See Also

+Db::close, +Db::cursor, +Db::del, +Db::err, +Db::fd, +Db::get, +Db::get_byteswapped, +Db::get_type, +Db::join, +Db::key_range, +Db::open, +Db::put, +Db::remove, +Db::set_bt_compare, +Db::set_bt_minkey, +Db::set_bt_prefix, +Db::set_cachesize, +Db::set_dup_compare, +Db::set_errcall, +Db::set_errfile, +Db::set_errpfx, +Db::set_flags, +Db::set_h_ffactor, +Db::set_h_hash, +Db::set_h_nelem, +Db::set_lorder, +Db::set_malloc, +Db::set_pagesize, +Db::set_paniccall, +Db::set_q_extentsize, +Db::set_realloc, +Db::set_re_delim, +Db::set_re_len, +Db::set_re_pad, +Db::set_re_source, +Db::stat, +Db::sync, +Db::upgrade +and +Db::verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_rename.html b/db/docs/api_cxx/db_rename.html new file mode 100644 index 000000000..03f2063d4 --- /dev/null +++ b/db/docs/api_cxx/db_rename.html @@ -0,0 +1,112 @@ + + + + + +Berkeley DB: Db::rename + + + + + + + +
+

Db::rename

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +Db::rename(const char *file, + const char *database, const char *newname, u_int32_t flags); +

+

Description

+

The Db::rename interface renames the database specified by the +file and database arguments to newname. If no +database is specified, the physical file represented by +file is renamed, incidentally renaming all databases that it +contained. +

If a physical file is being renamed and logging is currently enabled in +the database environment, no database in the file may be open when the +Db::rename method is called. Otherwise, no reference count of database +use is maintained by Berkeley DB. Applications should not rename databases that +are currently in use. In particular, some architectures do not permit +renaming files with open handles. On these architectures, attempts to +rename databases that are currently in use will fail. +

The flags parameter is currently unused, and must be set to 0. +

Once Db::rename has been called, regardless of its return, the +Db handle may not be accessed again. +

The Db::rename method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Environment Variables

+

+

DB_HOME
If the dbenv argument to db_create was initialized using +DbEnv::open the environment variable DB_HOME may be used +as the path of the database environment home. Specifically, Db::rename +is affected by the configuration value DB_DATA_DIR. +
+

Errors

+

The Db::rename method may fail and throw an exception or return a non-zero error for the following conditions: +

+

EINVAL
A database in the file is currently open. +
+

The Db::rename method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Db::rename method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Class

+Db +

See Also

+Db::close, +Db::cursor, +Db::del, +Db::err, +Db::fd, +Db::get, +Db::get_byteswapped, +Db::get_type, +Db::join, +Db::key_range, +Db::open, +Db::put, +Db::remove, +Db::set_bt_compare, +Db::set_bt_minkey, +Db::set_bt_prefix, +Db::set_cachesize, +Db::set_dup_compare, +Db::set_errcall, +Db::set_errfile, +Db::set_errpfx, +Db::set_flags, +Db::set_h_ffactor, +Db::set_h_hash, +Db::set_h_nelem, +Db::set_lorder, +Db::set_malloc, +Db::set_pagesize, +Db::set_paniccall, +Db::set_q_extentsize, +Db::set_realloc, +Db::set_re_delim, +Db::set_re_len, +Db::set_re_pad, +Db::set_re_source, +Db::stat, +Db::sync, +Db::upgrade +and +Db::verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_set_append_recno.html b/db/docs/api_cxx/db_set_append_recno.html new file mode 100644 index 000000000..296b47484 --- /dev/null +++ b/db/docs/api_cxx/db_set_append_recno.html @@ -0,0 +1,69 @@ + + + + + +Berkeley DB: Db::set_append_recno + + + + + + + +
+

Db::set_append_recno

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +Db::set_append_recno( + int (*db_append_recno_fcn)(DB *dbp, Dbt *data, db_recno_t recno)); +

+

Description

+

When using the DB_APPEND option of the Db::put method, +it may be useful to modify the stored data based on the generated key. +If a callback method is specified using the +Db::set_append_recno method, it will be called after the record number +has been selected but before the data has been stored. +The callback function must return 0 on success and errno or +a value outside of the Berkeley DB error name space on failure. +

The called function must take three arguments: a reference to the +enclosing database handle, the data Dbt to be stored and the +selected record number. The called function may then modify the data +Dbt. +

The Db::set_append_recno interface may only be used to configure Berkeley DB before +the Db::open interface is called. +

The Db::set_append_recno method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Class

+DbEnv +

See Also

+DbEnv::close, +DbEnv::open, +DbEnv::remove, +DbEnv::err, +DbEnv::strerror, +DbEnv::version, +DbEnv::set_cachesize, +DbEnv::set_errcall, +DbEnv::set_errfile, +DbEnv::set_error_stream, +DbEnv::set_errpfx, +DbEnv::set_flags, +DbEnv::set_mutexlocks, +DbEnv::set_paniccall, +and +DbEnv::set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_set_bt_compare.html b/db/docs/api_cxx/db_set_bt_compare.html new file mode 100644 index 000000000..5ca95d401 --- /dev/null +++ b/db/docs/api_cxx/db_set_bt_compare.html @@ -0,0 +1,109 @@ + + + + + +Berkeley DB: Db::set_bt_compare + + + + + + + +
+

Db::set_bt_compare

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+extern "C" { + typedef int (*bt_compare_fcn_type)(DB *, const DBT *, const DBT *); +}; +int +Db::set_bt_compare(bt_compare_fcn_type bt_compare_fcn); +

+

Description

+

Set the Btree key comparison function. The comparison function is +called when it is necessary to compare a key specified by the +application with a key currently stored in the tree. The first argument +to the comparison function is the Dbt representing the +application supplied key, the second is the current tree's key. +

The comparison function must return an integer value less than, equal +to, or greater than zero if the first key argument is considered to be +respectively less than, equal to, or greater than the second key +argument. In addition, the comparison function must cause the keys in +the database to be well-ordered. The comparison function +must correctly handle any key values used by the application (possibly +including zero-length keys). In addition, when Btree key prefix +comparison is being performed (see Db::set_bt_prefix for more +information), the comparison routine may be passed a prefix of any +database key. The data and size fields of the +Dbt are the only fields that may be used for the purposes of +this comparison. +

If no comparison function is specified, the keys are compared lexically, +with shorter keys collating before longer keys. The same comparison +method must be used each time a particular Btree is opened. +

The Db::set_bt_compare interface may only be used to configure Berkeley DB before +the Db::open interface is called. +

The Db::set_bt_compare method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after Db::open was called. +

+

Class

+Db +

See Also

+Db::close, +Db::cursor, +Db::del, +Db::err, +Db::fd, +Db::get, +Db::get_byteswapped, +Db::get_type, +Db::join, +Db::key_range, +Db::open, +Db::put, +Db::remove, +Db::set_bt_compare, +Db::set_bt_minkey, +Db::set_bt_prefix, +Db::set_cachesize, +Db::set_dup_compare, +Db::set_errcall, +Db::set_errfile, +Db::set_errpfx, +Db::set_flags, +Db::set_h_ffactor, +Db::set_h_hash, +Db::set_h_nelem, +Db::set_lorder, +Db::set_malloc, +Db::set_pagesize, +Db::set_paniccall, +Db::set_q_extentsize, +Db::set_realloc, +Db::set_re_delim, +Db::set_re_len, +Db::set_re_pad, +Db::set_re_source, +Db::stat, +Db::sync, +Db::upgrade +and +Db::verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_set_bt_minkey.html b/db/docs/api_cxx/db_set_bt_minkey.html new file mode 100644 index 000000000..c0c5aced1 --- /dev/null +++ b/db/docs/api_cxx/db_set_bt_minkey.html @@ -0,0 +1,94 @@ + + + + + +Berkeley DB: Db::set_bt_minkey + + + + + + + +
+

Db::set_bt_minkey

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +Db::set_bt_minkey(u_int32_t bt_minkey); +

+

Description

+

Set the minimum number of keys that will be stored on any single +Btree page. +

This value is used to determine which keys will be stored on overflow +pages, i.e. if a key or data item is larger than the underlying database +page size divided by the bt_minkey value, it will be stored on +overflow pages instead of within the page itself. The bt_minkey +value specified must be at least 2; if bt_minkey is not explicitly +set, a value of 2 is used. +

The Db::set_bt_minkey interface may only be used to configure Berkeley DB before +the Db::open interface is called. +

The Db::set_bt_minkey method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after Db::open was called. +

+

Class

+Db +

See Also

+Db::close, +Db::cursor, +Db::del, +Db::err, +Db::fd, +Db::get, +Db::get_byteswapped, +Db::get_type, +Db::join, +Db::key_range, +Db::open, +Db::put, +Db::remove, +Db::set_bt_compare, +Db::set_bt_minkey, +Db::set_bt_prefix, +Db::set_cachesize, +Db::set_dup_compare, +Db::set_errcall, +Db::set_errfile, +Db::set_errpfx, +Db::set_flags, +Db::set_h_ffactor, +Db::set_h_hash, +Db::set_h_nelem, +Db::set_lorder, +Db::set_malloc, +Db::set_pagesize, +Db::set_paniccall, +Db::set_q_extentsize, +Db::set_realloc, +Db::set_re_delim, +Db::set_re_len, +Db::set_re_pad, +Db::set_re_source, +Db::stat, +Db::sync, +Db::upgrade +and +Db::verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_set_bt_prefix.html b/db/docs/api_cxx/db_set_bt_prefix.html new file mode 100644 index 000000000..ecf949545 --- /dev/null +++ b/db/docs/api_cxx/db_set_bt_prefix.html @@ -0,0 +1,110 @@ + + + + + +Berkeley DB: Db::set_bt_prefix + + + + + + + +
+

Db::set_bt_prefix

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+extern "C" { + typedef size_t (*bt_prefix_fcn_type)(DB *, const DBT *, const DBT *); +}; +int +Db::set_bt_prefix(bt_prefix_fcn_type bt_prefix_fcn); +

+

Description

+

Set the Btree prefix function. The prefix function must return the +number of bytes of the second key argument that would be required by +the Btree key comparison function to determine the second key argument's +ordering relationship with respect to the first key argument. If the +two keys are equal, the key length should be returned. The prefix +function must correctly handle any key values used by the application +(possibly including zero-length keys). The data and +size fields of the Dbt are the only fields that may be +used for the purposes of this determination. +

The prefix function is used to determine the amount by which keys stored +on the Btree internal pages can be safely truncated without losing their +uniqueness. See the Btree +prefix comparison section of the Reference Guide for more details about +how this works. The usefulness of this is data dependent, but in some +data sets can produce significantly reduced tree sizes and search times. +

If no prefix function or key comparison function is specified by the +application, a default lexical comparison function is used as the prefix +function. If no prefix function is specified and a key comparison +function is specified, no prefix function is used. It is an error to +specify a prefix function without also specifying a key comparison +function. +

The Db::set_bt_prefix interface may only be used to configure Berkeley DB before +the Db::open interface is called. +

The Db::set_bt_prefix method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after Db::open was called. +

+

Class

+Db +

See Also

+Db::close, +Db::cursor, +Db::del, +Db::err, +Db::fd, +Db::get, +Db::get_byteswapped, +Db::get_type, +Db::join, +Db::key_range, +Db::open, +Db::put, +Db::remove, +Db::set_bt_compare, +Db::set_bt_minkey, +Db::set_bt_prefix, +Db::set_cachesize, +Db::set_dup_compare, +Db::set_errcall, +Db::set_errfile, +Db::set_errpfx, +Db::set_flags, +Db::set_h_ffactor, +Db::set_h_hash, +Db::set_h_nelem, +Db::set_lorder, +Db::set_malloc, +Db::set_pagesize, +Db::set_paniccall, +Db::set_q_extentsize, +Db::set_realloc, +Db::set_re_delim, +Db::set_re_len, +Db::set_re_pad, +Db::set_re_source, +Db::stat, +Db::sync, +Db::upgrade +and +Db::verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_set_cachesize.html b/db/docs/api_cxx/db_set_cachesize.html new file mode 100644 index 000000000..cc8e020cc --- /dev/null +++ b/db/docs/api_cxx/db_set_cachesize.html @@ -0,0 +1,108 @@ + + + + + + +Berkeley DB: Db::set_cachesize + + + + + + + +
+

Db::set_cachesize

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +Db::set_cachesize(u_int32_t gbytes, u_int32_t bytes, int ncache); +

+

Description

+

Set the size of the database's shared memory buffer pool, i.e., the cache, +to gbytes gigabytes plus bytes. The cache should be the +size of the normal working data set of the application, with some small +amount of additional memory for unusual situations. (Note, the working +set is not the same as the number of simultaneously referenced pages, and +should be quite a bit larger!) +

The default cache size is 256KB, and may not be specified as less than +20KB. Any cache size less than 500MB is automatically increased by 25% +to account for buffer pool overhead, cache sizes larger than 500MB are +used as specified. For information on tuning the Berkeley DB cache size, see +Selecting a cache size. +

It is possible to specify caches to Berkeley DB that are large enough so that +they cannot be allocated contiguously on some architectures, e.g., some +releases of Solaris limit the amount of memory that may be allocated +contiguously by a process. If ncache is 0 or 1, the cache will +be allocated contiguously in memory. If it is greater than 1, the cache +will be broken up into ncache equally sized separate pieces of +memory. +

As databases opened within Berkeley DB environments use the cache specified to +the environment, it is an error to attempt to set a cache in a database +created within an environment. +

The Db::set_cachesize interface may only be used to configure Berkeley DB before +the Db::open interface is called. +

The Db::set_cachesize method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

The specified cache size was impossibly small. +

+

Class

+Db +

See Also

+Db::close, +Db::cursor, +Db::del, +Db::err, +Db::fd, +Db::get, +Db::get_byteswapped, +Db::get_type, +Db::join, +Db::key_range, +Db::open, +Db::put, +Db::remove, +Db::set_bt_compare, +Db::set_bt_minkey, +Db::set_bt_prefix, +Db::set_cachesize, +Db::set_dup_compare, +Db::set_errcall, +Db::set_errfile, +Db::set_errpfx, +Db::set_flags, +Db::set_h_ffactor, +Db::set_h_hash, +Db::set_h_nelem, +Db::set_lorder, +Db::set_malloc, +Db::set_pagesize, +Db::set_paniccall, +Db::set_q_extentsize, +Db::set_realloc, +Db::set_re_delim, +Db::set_re_len, +Db::set_re_pad, +Db::set_re_source, +Db::stat, +Db::sync, +Db::upgrade +and +Db::verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_set_dup_compare.html b/db/docs/api_cxx/db_set_dup_compare.html new file mode 100644 index 000000000..7cd09ec0c --- /dev/null +++ b/db/docs/api_cxx/db_set_dup_compare.html @@ -0,0 +1,106 @@ + + + + + +Berkeley DB: Db::set_dup_compare + + + + + + + +
+

Db::set_dup_compare

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+extern "C" { + typedef int (*dup_compare_fcn_type)(DB *, const DBT *, const DBT *); +}; +int +Db::set_dup_compare(dup_compare_fcn_type dup_compare_fcn); +

+

Description

+

Set the duplicate data item comparison function. The comparison function +is called when it is necessary to compare a data item specified by the +application with a data item currently stored in the tree. The first +argument to the comparison function is the Dbt representing the +application's data item, the second is the current tree's data item. +

The comparison function must return an integer value less than, equal +to, or greater than zero if the first data item argument is considered +to be respectively less than, equal to, or greater than the second data +item argument. In addition, the comparison function must cause the data +items in the set to be well-ordered. The comparison function +must correctly handle any data item values used by the application +(possibly including zero-length data items). The data and +size fields of the Dbt are the only fields that may be +used for the purposes of this comparison. +

If no comparison function is specified, the data items are compared +lexically, with shorter data items collating before longer data items. +The same duplicate data item comparison method must be used each time +a particular Btree is opened. +

The Db::set_dup_compare interface may only be used to configure Berkeley DB before +the Db::open interface is called. +

The Db::set_dup_compare method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

Class

+Db +

See Also

+Db::close, +Db::cursor, +Db::del, +Db::err, +Db::fd, +Db::get, +Db::get_byteswapped, +Db::get_type, +Db::join, +Db::key_range, +Db::open, +Db::put, +Db::remove, +Db::set_bt_compare, +Db::set_bt_minkey, +Db::set_bt_prefix, +Db::set_cachesize, +Db::set_dup_compare, +Db::set_errcall, +Db::set_errfile, +Db::set_errpfx, +Db::set_flags, +Db::set_h_ffactor, +Db::set_h_hash, +Db::set_h_nelem, +Db::set_lorder, +Db::set_malloc, +Db::set_pagesize, +Db::set_paniccall, +Db::set_q_extentsize, +Db::set_realloc, +Db::set_re_delim, +Db::set_re_len, +Db::set_re_pad, +Db::set_re_source, +Db::stat, +Db::sync, +Db::upgrade +and +Db::verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_set_errcall.html b/db/docs/api_cxx/db_set_errcall.html new file mode 100644 index 000000000..6cc5310eb --- /dev/null +++ b/db/docs/api_cxx/db_set_errcall.html @@ -0,0 +1,79 @@ + + + + + + +Berkeley DB: Db::set_errcall + + + + + + + +
+

Db::set_errcall

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+void Db::set_errcall( + void (*db_errcall_fcn)(const char *errpfx, char *msg)); +

+

Description

+When an error occurs in the Berkeley DB library, an exception is thrown or an +error return value is returned by the method. In some cases, +however, the errno value may be insufficient to completely +describe the cause of the error, especially during initial application +debugging. +

The Db::set_errcall method is used to enhance the mechanism for reporting error +messages to the application. In some cases, when an error occurs, Berkeley DB +will call db_errcall_fcn with additional error information. The +function must be defined with two arguments; the first will be the prefix +string (as previously set by Db::set_errpfx or +DbEnv::set_errpfx), the second will be the error message string. +It is up to the db_errcall_fcn method to display the error +message in an appropriate manner. +

Alternatively, you can use the DbEnv::set_error_stream method to display +the additional information via an output stream, or the Db::set_errfile +or DbEnv::set_errfile methods to display the additional information via a C +library FILE *. You should not mix these approaches. +

This error logging enhancement does not slow performance or significantly +increase application size, and may be run during normal operation as well +as during application debugging. +

For Db handles opened inside of Berkeley DB environments, calling the +Db::set_errcall method affects the entire environment and is equivalent to calling +the DbEnv::set_errcall method. +

The Db::set_errcall interface may be used to configure Berkeley DB at any time +during the life of the application. +

Class

+DbEnv +

See Also

+DbEnv::close, +DbEnv::open, +DbEnv::remove, +DbEnv::err, +DbEnv::strerror, +DbEnv::version, +DbEnv::set_cachesize, +DbEnv::set_errcall, +DbEnv::set_errfile, +DbEnv::set_error_stream, +DbEnv::set_errpfx, +DbEnv::set_flags, +DbEnv::set_mutexlocks, +DbEnv::set_paniccall, +and +DbEnv::set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_set_errfile.html b/db/docs/api_cxx/db_set_errfile.html new file mode 100644 index 000000000..50c6bebd1 --- /dev/null +++ b/db/docs/api_cxx/db_set_errfile.html @@ -0,0 +1,80 @@ + + + + + + +Berkeley DB: Db::set_errfile + + + + + + + +
+

Db::set_errfile

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+void Db::set_errfile(FILE *errfile); +

+

Description

+When an error occurs in the Berkeley DB library, an exception is thrown or an +error return value is returned by the method. In some cases, +however, the errno value may be insufficient to completely +describe the cause of the error, especially during initial application +debugging. +

The Db::set_errfile method is used to enhance the mechanism for reporting error +messages to the application by setting a C library FILE * to be used for +displaying additional Berkeley DB error messages. In some cases, when an error +occurs, Berkeley DB will output an additional error message to the specified +file reference. +

Alternatively, you can use the DbEnv::set_error_stream method to display +the additional information via an output stream, or the +DbEnv::set_errcall method to capture the additional error information in +a way that does not use either output streams or C library FILE *'s. You +should not mix these approaches. +

The error message will consist of the prefix string and a colon +(":") (if a prefix string was previously specified using +Db::set_errpfx or DbEnv::set_errpfx), an error string, and +a trailing <newline> character. +

This error logging enhancement does not slow performance or significantly +increase application size, and may be run during normal operation as well +as during application debugging. +

For Db handles opened inside of Berkeley DB environments, calling the +Db::set_errfile method affects the entire environment and is equivalent to calling +the DbEnv::set_errfile method. +

The Db::set_errfile interface may be used to configure Berkeley DB at any time +during the life of the application. +

Class

+DbEnv +

See Also

+DbEnv::close, +DbEnv::open, +DbEnv::remove, +DbEnv::err, +DbEnv::strerror, +DbEnv::version, +DbEnv::set_cachesize, +DbEnv::set_errcall, +DbEnv::set_errfile, +DbEnv::set_error_stream, +DbEnv::set_errpfx, +DbEnv::set_flags, +DbEnv::set_mutexlocks, +DbEnv::set_paniccall, +and +DbEnv::set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_set_errpfx.html b/db/docs/api_cxx/db_set_errpfx.html new file mode 100644 index 000000000..0baa3ba67 --- /dev/null +++ b/db/docs/api_cxx/db_set_errpfx.html @@ -0,0 +1,63 @@ + + + + + +Berkeley DB: Db::set_errpfx + + + + + + + +
+

Db::set_errpfx

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+void Db::set_errpfx(const char *errpfx); +

+

Description

+

Set the prefix string that appears before error messages issued by Berkeley DB. +

The Db::set_errpfx method does not copy the memory referenced by the +errpfx argument, rather, it maintains a reference to it. This +allows applications to modify the error message prefix at any time, +without repeatedly calling Db::set_errpfx, but means that the +memory must be maintained until the handle is closed. +

For Db handles opened inside of Berkeley DB environments, calling the +Db::set_errpfx method affects the entire environment and is equivalent to calling +the DbEnv::set_errpfx method. +

The Db::set_errpfx interface may be used to configure Berkeley DB at any time +during the life of the application. +

Class

+DbEnv +

See Also

+DbEnv::close, +DbEnv::open, +DbEnv::remove, +DbEnv::err, +DbEnv::strerror, +DbEnv::version, +DbEnv::set_cachesize, +DbEnv::set_errcall, +DbEnv::set_errfile, +DbEnv::set_error_stream, +DbEnv::set_errpfx, +DbEnv::set_flags, +DbEnv::set_mutexlocks, +DbEnv::set_paniccall, +and +DbEnv::set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_set_feedback.html b/db/docs/api_cxx/db_set_feedback.html new file mode 100644 index 000000000..97a5a85b7 --- /dev/null +++ b/db/docs/api_cxx/db_set_feedback.html @@ -0,0 +1,97 @@ + + + + + +Berkeley DB: Db::set_feedback + + + + + + + +
+

Db::set_feedback

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +Db::set_feedback( + void (*db_feedback_fcn)(DB *dbp, int opcode, int pct)); +

+

Description

+

Some operations performed by the Berkeley DB library can take non-trivial +amounts of time. The Db::set_feedback method can be used by +applications to monitor progress within these operations. +

When an operation is likely to take a long time, Berkeley DB will call the +specified callback method. This method must be declared with +three arguments: the first will be a reference to the enclosing database +handle, the second a flag value, and the third the percent of the +operation that has been completed, specified as an integer value between +0 and 100. It is up to the callback method to display this +information in an appropriate manner. +

The opcode argument may take on any of the following values: +

+

DB_UPGRADE
The underlying database is being upgraded. +

DB_VERIFY
The underlying database is being verified. +
+

The Db::set_feedback interface may be used to configure Berkeley DB at any time +during the life of the application. +

The Db::set_feedback method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Class

+Db +

See Also

+Db::close, +Db::cursor, +Db::del, +Db::err, +Db::fd, +Db::get, +Db::get_byteswapped, +Db::get_type, +Db::join, +Db::key_range, +Db::open, +Db::put, +Db::remove, +Db::set_bt_compare, +Db::set_bt_minkey, +Db::set_bt_prefix, +Db::set_cachesize, +Db::set_dup_compare, +Db::set_errcall, +Db::set_errfile, +Db::set_errpfx, +Db::set_flags, +Db::set_h_ffactor, +Db::set_h_hash, +Db::set_h_nelem, +Db::set_lorder, +Db::set_malloc, +Db::set_pagesize, +Db::set_paniccall, +Db::set_q_extentsize, +Db::set_realloc, +Db::set_re_delim, +Db::set_re_len, +Db::set_re_pad, +Db::set_re_source, +Db::stat, +Db::sync, +Db::upgrade +and +Db::verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_set_flags.html b/db/docs/api_cxx/db_set_flags.html new file mode 100644 index 000000000..059810357 --- /dev/null +++ b/db/docs/api_cxx/db_set_flags.html @@ -0,0 +1,183 @@ + + + + + +Berkeley DB: Db::set_flags + + + + + + + +
+

Db::set_flags

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +Db::set_flags(u_int32_t flags); +

+

Description

+

Calling Db::set_flags is additive, there is no way to clear flags. +

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +

Btree

+

The following flags may be specified for the Btree access method: +

+

DB_DUP
Permit duplicate data items in the tree, i.e. insertion when the key of +the key/data pair being inserted already exists in the tree will be +successful. The ordering of duplicates in the tree is determined by the +order of insertion, unless the ordering is otherwise specified by use of +a cursor operation. It is an error to specify both DB_DUP and +DB_RECNUM. +

DB_DUPSORT
Permit duplicate data items in the tree, i.e. insertion when the key of +the key/data pair being inserted already exists in the tree will be +successful. The ordering of duplicates in the tree is determined by the +duplicate comparison function. +If the application does not specify a comparison function using the +Db::set_dup_compare method, a default, lexical comparison will be +used. +It is an error to specify both DB_DUPSORT and DB_RECNUM. +

DB_RECNUM
Support retrieval from the Btree using record numbers. For more +information, see the DB_GET_RECNO flag to the Db::get and +Dbc::get methods. +

Logical record numbers in Btree databases are mutable in the face of +record insertion or deletion. See the DB_RENUMBER flag in the Recno +access method information for further discussion. +

Maintaining record counts within a Btree introduces a serious point of +contention, namely the page locations where the record counts are stored. +In addition, the entire tree must be locked during both insertions and +deletions, effectively single-threading the tree for those operations. +Specifying DB_RECNUM can result in serious performance degradation for +some applications and data sets. +

It is an error to specify both DB_DUP and DB_RECNUM. +

DB_REVSPLITOFF
Turn off reverse splitting in the Btree. As pages are emptied in a +database, the Berkeley DB Btree implementation attempts to coalesce empty pages +into higher-level pages in order to keep the tree as small as possible +and minimize tree search time. This can hurt performance in applications +with cyclical data demands, that is, applications where the database grows +and shrinks repeatedly. For example, because Berkeley DB does page-level +locking, the maximum level of concurrency in a database of 2 pages is far +smaller than that in a database of 100 pages, and so a database that has +shrunk to a minimal size can cause severe deadlocking when a new cycle of +data insertion begins. +
+

Hash

+

The following flags may be specified for the Hash access method: +

+

DB_DUP
Permit duplicate data items in the tree, i.e. insertion when the key of +the key/data pair being inserted already exists in the tree will be +successful. The ordering of duplicates in the tree is determined by the +order of insertion, unless the ordering is otherwise specified by use of +a cursor operation. It is an error to specify both DB_DUP and +DB_RECNUM. +

DB_DUPSORT
Permit duplicate data items in the tree, i.e. insertion when the key of +the key/data pair being inserted already exists in the tree will be +successful. The ordering of duplicates in the tree is determined by the +duplicate comparison function. +If the application does not specify a comparison function using the +Db::set_dup_compare method, a default, lexical comparison will be +used. +It is an error to specify both DB_DUPSORT and DB_RECNUM. +
+

Queue

+

There are no additional flags that may be specified for the Queue access +method. +

Recno

+

The following flags may be specified for the Recno access method: +

+

DB_RENUMBER
Specifying the DB_RENUMBER flag causes the logical record numbers to be +mutable, and change as records are added to and deleted from the database. +For example, the deletion of record number 4 causes records numbered 5 +and greater to be renumbered downward by 1. If a cursor was positioned +to record number 4 before the deletion, it will reference the new record +number 4, if any such record exists, after the deletion. If a cursor was +positioned after record number 4 before the deletion, it will be shifted +downward 1 logical record, continuing to reference the same record as it +did before. +

Using the Db::put or Dbc::put interfaces to create new +records will cause the creation of multiple records if the record number +is more than one greater than the largest record currently in the +database. For example, creating record 28, when record 25 was previously +the last record in the database, will create records 26 and 27 as well as +28. Attempts to retrieve records that were created in this manner will +result in an error return of DB_KEYEMPTY. +

If a created record is not at the end of the database, all records +following the new record will be automatically renumbered upward by 1. +For example, the creation of a new record numbered 8 causes records +numbered 8 and greater to be renumbered upward by 1. If a cursor was +positioned to record number 8 or greater before the insertion, it will be +shifted upward 1 logical record, continuing to reference the same record +as it did before. +

For these reasons, concurrent access to a Recno database with the +DB_RENUMBER flag specified may be largely meaningless, although +it is supported. +

DB_SNAPSHOT
This flag specifies that any specified re_source file be read in +its entirety when Db::open is called. If this flag is not +specified, the re_source file may be read lazily. +
+

The Db::set_flags interface may only be used to configure Berkeley DB before +the Db::open interface is called. +

The Db::set_flags method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

Class

+Db +

See Also

+Db::close, +Db::cursor, +Db::del, +Db::err, +Db::fd, +Db::get, +Db::get_byteswapped, +Db::get_type, +Db::join, +Db::key_range, +Db::open, +Db::put, +Db::remove, +Db::set_bt_compare, +Db::set_bt_minkey, +Db::set_bt_prefix, +Db::set_cachesize, +Db::set_dup_compare, +Db::set_errcall, +Db::set_errfile, +Db::set_errpfx, +Db::set_flags, +Db::set_h_ffactor, +Db::set_h_hash, +Db::set_h_nelem, +Db::set_lorder, +Db::set_malloc, +Db::set_pagesize, +Db::set_paniccall, +Db::set_q_extentsize, +Db::set_realloc, +Db::set_re_delim, +Db::set_re_len, +Db::set_re_pad, +Db::set_re_source, +Db::stat, +Db::sync, +Db::upgrade +and +Db::verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_set_h_ffactor.html b/db/docs/api_cxx/db_set_h_ffactor.html new file mode 100644 index 000000000..fa7d4209e --- /dev/null +++ b/db/docs/api_cxx/db_set_h_ffactor.html @@ -0,0 +1,95 @@ + + + + + +Berkeley DB: Db::set_h_ffactor + + + + + + + +
+

Db::set_h_ffactor

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +Db::set_h_ffactor(u_int32_t h_ffactor); +

+

Description

+

Set the desired density within the hash table. +

The density is an approximation of the number of keys allowed to +accumulate in any one bucket, determining when the hash table grows or +shrinks. If you know the average sizes of the keys and data in your +dataset, setting the fill factor can enhance performance. A reasonable +rule computing fill factor is to set it to: +

(pagesize - 32) / (average_key_size + average_data_size + 8)
+

If no value is specified, the fill factor will be selected dynamically as +pages are filled. +

The Db::set_h_ffactor interface may only be used to configure Berkeley DB before +the Db::open interface is called. +

The Db::set_h_ffactor method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after Db::open was called. +

+

Class

+Db +

See Also

+Db::close, +Db::cursor, +Db::del, +Db::err, +Db::fd, +Db::get, +Db::get_byteswapped, +Db::get_type, +Db::join, +Db::key_range, +Db::open, +Db::put, +Db::remove, +Db::set_bt_compare, +Db::set_bt_minkey, +Db::set_bt_prefix, +Db::set_cachesize, +Db::set_dup_compare, +Db::set_errcall, +Db::set_errfile, +Db::set_errpfx, +Db::set_flags, +Db::set_h_ffactor, +Db::set_h_hash, +Db::set_h_nelem, +Db::set_lorder, +Db::set_malloc, +Db::set_pagesize, +Db::set_paniccall, +Db::set_q_extentsize, +Db::set_realloc, +Db::set_re_delim, +Db::set_re_len, +Db::set_re_pad, +Db::set_re_source, +Db::stat, +Db::sync, +Db::upgrade +and +Db::verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_set_h_hash.html b/db/docs/api_cxx/db_set_h_hash.html new file mode 100644 index 000000000..71808b081 --- /dev/null +++ b/db/docs/api_cxx/db_set_h_hash.html @@ -0,0 +1,102 @@ + + + + + +Berkeley DB: Db::set_h_hash + + + + + + + +
+

Db::set_h_hash

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+extern "C" { + typedef u_int32_t (*h_hash_fcn_type) + (DB *, const void *bytes, u_int32_t length); +}; +int +Db::set_h_hash(h_hash_fcn_type h_hash_fcn); +

+

Description

+

Set a user defined hash method; if no hash method is specified, a default +hash method is used. Since no hash method performs equally well on all +possible data, the user may find that the built-in hash method performs +poorly with a particular data set. User specified hash functions must +take a pointer to a byte string and a length as arguments and return a +value of type +u_int32_t. +The hash function must handle any key values used by the application +(possibly including zero-length keys). +

If a hash method is specified, Db::open will attempt to determine +if the hash method specified is the same as the one with which the database +was created, and will fail if it detects that it is not. +

The Db::set_h_hash interface may only be used to configure Berkeley DB before +the Db::open interface is called. +

The Db::set_h_hash method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after Db::open was called. +

+

Class

+Db +

See Also

+Db::close, +Db::cursor, +Db::del, +Db::err, +Db::fd, +Db::get, +Db::get_byteswapped, +Db::get_type, +Db::join, +Db::key_range, +Db::open, +Db::put, +Db::remove, +Db::set_bt_compare, +Db::set_bt_minkey, +Db::set_bt_prefix, +Db::set_cachesize, +Db::set_dup_compare, +Db::set_errcall, +Db::set_errfile, +Db::set_errpfx, +Db::set_flags, +Db::set_h_ffactor, +Db::set_h_hash, +Db::set_h_nelem, +Db::set_lorder, +Db::set_malloc, +Db::set_pagesize, +Db::set_paniccall, +Db::set_q_extentsize, +Db::set_realloc, +Db::set_re_delim, +Db::set_re_len, +Db::set_re_pad, +Db::set_re_source, +Db::stat, +Db::sync, +Db::upgrade +and +Db::verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_set_h_nelem.html b/db/docs/api_cxx/db_set_h_nelem.html new file mode 100644 index 000000000..55698d457 --- /dev/null +++ b/db/docs/api_cxx/db_set_h_nelem.html @@ -0,0 +1,90 @@ + + + + + +Berkeley DB: Db::set_h_nelem + + + + + + + +
+

Db::set_h_nelem

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +Db::set_h_nelem(u_int32_t h_nelem); +

+

Description

+

Set an estimate of the final size of the hash table. +

If not set or set too low, hash tables will still expand gracefully +as keys are entered, although a slight performance degradation may be +noticed. +

The Db::set_h_nelem interface may only be used to configure Berkeley DB before +the Db::open interface is called. +

The Db::set_h_nelem method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after Db::open was called. +

+

Class

+Db +

See Also

+Db::close, +Db::cursor, +Db::del, +Db::err, +Db::fd, +Db::get, +Db::get_byteswapped, +Db::get_type, +Db::join, +Db::key_range, +Db::open, +Db::put, +Db::remove, +Db::set_bt_compare, +Db::set_bt_minkey, +Db::set_bt_prefix, +Db::set_cachesize, +Db::set_dup_compare, +Db::set_errcall, +Db::set_errfile, +Db::set_errpfx, +Db::set_flags, +Db::set_h_ffactor, +Db::set_h_hash, +Db::set_h_nelem, +Db::set_lorder, +Db::set_malloc, +Db::set_pagesize, +Db::set_paniccall, +Db::set_q_extentsize, +Db::set_realloc, +Db::set_re_delim, +Db::set_re_len, +Db::set_re_pad, +Db::set_re_source, +Db::stat, +Db::sync, +Db::upgrade +and +Db::verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_set_lorder.html b/db/docs/api_cxx/db_set_lorder.html new file mode 100644 index 000000000..f25779a25 --- /dev/null +++ b/db/docs/api_cxx/db_set_lorder.html @@ -0,0 +1,96 @@ + + + + + +Berkeley DB: Db::set_lorder + + + + + + + +
+

Db::set_lorder

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +Db::set_lorder(int lorder); +

+

Description

+

Set the byte order for integers in the stored database metadata. The +number should represent the order as an integer, for example, big endian +order is the number 4,321, and little endian order is the number 1,234. +If lorder is not explicitly set, the host order of the machine +where the Berkeley DB library was compiled is used. +

The value of lorder is ignored except when databases are being +created. If a database already exists, the byte order it uses is +determined when the database is opened. +

The access methods provide no guarantees about the byte ordering of the +application data stored in the database, and applications are responsible +for maintaining any necessary ordering. +

The Db::set_lorder interface may only be used to configure Berkeley DB before +the Db::open interface is called. +

The Db::set_lorder method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

Class

+Db +

See Also

+Db::close, +Db::cursor, +Db::del, +Db::err, +Db::fd, +Db::get, +Db::get_byteswapped, +Db::get_type, +Db::join, +Db::key_range, +Db::open, +Db::put, +Db::remove, +Db::set_bt_compare, +Db::set_bt_minkey, +Db::set_bt_prefix, +Db::set_cachesize, +Db::set_dup_compare, +Db::set_errcall, +Db::set_errfile, +Db::set_errpfx, +Db::set_flags, +Db::set_h_ffactor, +Db::set_h_hash, +Db::set_h_nelem, +Db::set_lorder, +Db::set_malloc, +Db::set_pagesize, +Db::set_paniccall, +Db::set_q_extentsize, +Db::set_realloc, +Db::set_re_delim, +Db::set_re_len, +Db::set_re_pad, +Db::set_re_source, +Db::stat, +Db::sync, +Db::upgrade +and +Db::verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_set_malloc.html b/db/docs/api_cxx/db_set_malloc.html new file mode 100644 index 000000000..e38092fcb --- /dev/null +++ b/db/docs/api_cxx/db_set_malloc.html @@ -0,0 +1,103 @@ + + + + + +Berkeley DB: Db::set_malloc + + + + + + + +
+

Db::set_malloc

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+extern "C" { + typedef void *(*db_malloc_fcn_type)(size_t); +}; +int +Db::set_malloc(db_malloc_fcn_type db_malloc); +

+

Description

+

Set the allocation function used by the Db methods to allocate +memory in which to return key/data items to the application. +

The DB_DBT_MALLOC flag, when specified in the Dbt object, +will cause the Db methods to allocate and re-allocate memory which +then becomes the responsibility of the calling application. See Dbt +for more information. +

On systems where there may be multiple library versions of malloc (notably +Windows NT), specifying the DB_DBT_MALLOC flag will fail because +the Db library will allocate memory from a different heap than +the application will use to free it. To avoid this problem, the +Db::set_malloc method can be used to pass Berkeley DB a reference to the +application's allocation routine, in which case it will be used to +allocate the memory returned when the DB_DBT_MALLOC flag is set. +

The method specified must match the calling conventions of the +ANSI C X3.159-1989 (ANSI C) library routine of the same name. +

The Db::set_malloc interface may only be used to configure Berkeley DB before +the Db::open interface is called. +

The Db::set_malloc method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

Class

+Db +

See Also

+Db::close, +Db::cursor, +Db::del, +Db::err, +Db::fd, +Db::get, +Db::get_byteswapped, +Db::get_type, +Db::join, +Db::key_range, +Db::open, +Db::put, +Db::remove, +Db::set_bt_compare, +Db::set_bt_minkey, +Db::set_bt_prefix, +Db::set_cachesize, +Db::set_dup_compare, +Db::set_errcall, +Db::set_errfile, +Db::set_errpfx, +Db::set_flags, +Db::set_h_ffactor, +Db::set_h_hash, +Db::set_h_nelem, +Db::set_lorder, +Db::set_malloc, +Db::set_pagesize, +Db::set_paniccall, +Db::set_q_extentsize, +Db::set_realloc, +Db::set_re_delim, +Db::set_re_len, +Db::set_re_pad, +Db::set_re_source, +Db::stat, +Db::sync, +Db::upgrade +and +Db::verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_set_pagesize.html b/db/docs/api_cxx/db_set_pagesize.html new file mode 100644 index 000000000..114f0578a --- /dev/null +++ b/db/docs/api_cxx/db_set_pagesize.html @@ -0,0 +1,92 @@ + + + + + +Berkeley DB: Db::set_pagesize + + + + + + + +
+

Db::set_pagesize

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +Db::set_pagesize(u_int32_t pagesize); +

+

Description

+

Set the size of the pages used to hold items in the database, in bytes. +The minimum page size is 512 bytes and the maximum page size is 64K bytes. +If the page size is not explicitly set, one is selected based on the +underlying filesystem I/O block size. The automatically selected size +has a lower limit of 512 bytes and an upper limit of 16K bytes. +

For information on tuning the Berkeley DB page size, see +Selecting a page size. +

The Db::set_pagesize interface may only be used to configure Berkeley DB before +the Db::open interface is called. +

The Db::set_pagesize method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

Class

+Db +

See Also

+Db::close, +Db::cursor, +Db::del, +Db::err, +Db::fd, +Db::get, +Db::get_byteswapped, +Db::get_type, +Db::join, +Db::key_range, +Db::open, +Db::put, +Db::remove, +Db::set_bt_compare, +Db::set_bt_minkey, +Db::set_bt_prefix, +Db::set_cachesize, +Db::set_dup_compare, +Db::set_errcall, +Db::set_errfile, +Db::set_errpfx, +Db::set_flags, +Db::set_h_ffactor, +Db::set_h_hash, +Db::set_h_nelem, +Db::set_lorder, +Db::set_malloc, +Db::set_pagesize, +Db::set_paniccall, +Db::set_q_extentsize, +Db::set_realloc, +Db::set_re_delim, +Db::set_re_len, +Db::set_re_pad, +Db::set_re_source, +Db::stat, +Db::sync, +Db::upgrade +and +Db::verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_set_paniccall.html b/db/docs/api_cxx/db_set_paniccall.html new file mode 100644 index 000000000..7cd08de4a --- /dev/null +++ b/db/docs/api_cxx/db_set_paniccall.html @@ -0,0 +1,76 @@ + + + + + + +Berkeley DB: Db::set_paniccall + + + + + + + +
+

Db::set_paniccall

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +Db::set_paniccall( + void (*db_paniccall_fcn)(DbEnv *dbenv, int errval)); +

+

Description

+

Errors can occur in the Berkeley DB library where the only solution is to shut +down the application and run recovery. (For example, if Berkeley DB is unable +to write log records to disk because there is insufficient disk space.) +In these cases, when the C++ error model has been configured so that the +individual Berkeley DB methods return error codes (see DbException for +more information), the value DB_RUNRECOVERY is returned by Berkeley DB +methods. +

In these cases, it is also often simpler to shut down the application when +such errors occur rather than attempting to gracefully return up the stack. +The Db::set_paniccall method is used to specify a method to be called when +DB_RUNRECOVERY is about to be returned from a Berkeley DB method. When +called, the dbenv argument will be a reference to the current +environment, and the errval argument is the error value that would +have been returned to the calling method. +

For Db handles opened inside of Berkeley DB environments, calling the +Db::set_paniccall method affects the entire environment and is equivalent to calling +the DbEnv::set_paniccall method. +

The Db::set_paniccall interface may be used to configure Berkeley DB at any time +during the life of the application. +

The Db::set_paniccall method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Class

+DbEnv +

See Also

+DbEnv::close, +DbEnv::open, +DbEnv::remove, +DbEnv::err, +DbEnv::strerror, +DbEnv::version, +DbEnv::set_cachesize, +DbEnv::set_errcall, +DbEnv::set_errfile, +DbEnv::set_error_stream, +DbEnv::set_errpfx, +DbEnv::set_flags, +DbEnv::set_mutexlocks, +DbEnv::set_paniccall, +and +DbEnv::set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_set_q_extentsize.html b/db/docs/api_cxx/db_set_q_extentsize.html new file mode 100644 index 000000000..d9c702196 --- /dev/null +++ b/db/docs/api_cxx/db_set_q_extentsize.html @@ -0,0 +1,92 @@ + + + + + +Berkeley DB: Db::set_q_extentsize + + + + + + + +
+

Db::set_q_extentsize

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +Db::set_q_extentsize(u_int32_t extentsize); +

+

Description

+

Set the size of the extents used to hold pages in a Queue database, +specified as a number of pages. Each extent is created as a separate +physical file. If no extent size is set, the default behavior is to +create only a single underlying database file. +

For information on tuning the extent size, see +Selecting a extent size. +

The Db::set_q_extentsize interface may only be used to configure Berkeley DB before +the Db::open interface is called. +

The Db::set_q_extentsize method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after Db::open was called. +

+

Class

+Db +

See Also

+Db::close, +Db::cursor, +Db::del, +Db::err, +Db::fd, +Db::get, +Db::get_byteswapped, +Db::get_type, +Db::join, +Db::key_range, +Db::open, +Db::put, +Db::remove, +Db::set_bt_compare, +Db::set_bt_minkey, +Db::set_bt_prefix, +Db::set_cachesize, +Db::set_dup_compare, +Db::set_errcall, +Db::set_errfile, +Db::set_errpfx, +Db::set_flags, +Db::set_h_ffactor, +Db::set_h_hash, +Db::set_h_nelem, +Db::set_lorder, +Db::set_malloc, +Db::set_pagesize, +Db::set_paniccall, +Db::set_q_extentsize, +Db::set_realloc, +Db::set_re_delim, +Db::set_re_len, +Db::set_re_pad, +Db::set_re_source, +Db::stat, +Db::sync, +Db::upgrade +and +Db::verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_set_re_delim.html b/db/docs/api_cxx/db_set_re_delim.html new file mode 100644 index 000000000..c88d6e89e --- /dev/null +++ b/db/docs/api_cxx/db_set_re_delim.html @@ -0,0 +1,92 @@ + + + + + +Berkeley DB: Db::set_re_delim + + + + + + + +
+

Db::set_re_delim

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +Db::set_re_delim(int re_delim); +

+

Description

+

Set the delimiting byte used to mark the end of a record in the backing +source file for the Recno access method. +

This byte is used for variable length records, if the re_source +file is specified. If the re_source file is specified and no +delimiting byte was specified, <newline> characters (i.e. +ASCII 0x0a) are interpreted as end-of-record markers. +

The Db::set_re_delim interface may only be used to configure Berkeley DB before +the Db::open interface is called. +

The Db::set_re_delim method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after Db::open was called. +

+

Class

+Db +

See Also

+Db::close, +Db::cursor, +Db::del, +Db::err, +Db::fd, +Db::get, +Db::get_byteswapped, +Db::get_type, +Db::join, +Db::key_range, +Db::open, +Db::put, +Db::remove, +Db::set_bt_compare, +Db::set_bt_minkey, +Db::set_bt_prefix, +Db::set_cachesize, +Db::set_dup_compare, +Db::set_errcall, +Db::set_errfile, +Db::set_errpfx, +Db::set_flags, +Db::set_h_ffactor, +Db::set_h_hash, +Db::set_h_nelem, +Db::set_lorder, +Db::set_malloc, +Db::set_pagesize, +Db::set_paniccall, +Db::set_q_extentsize, +Db::set_realloc, +Db::set_re_delim, +Db::set_re_len, +Db::set_re_pad, +Db::set_re_source, +Db::stat, +Db::sync, +Db::upgrade +and +Db::verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_set_re_len.html b/db/docs/api_cxx/db_set_re_len.html new file mode 100644 index 000000000..7432ced16 --- /dev/null +++ b/db/docs/api_cxx/db_set_re_len.html @@ -0,0 +1,96 @@ + + + + + +Berkeley DB: Db::set_re_len + + + + + + + +
+

Db::set_re_len

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +Db::set_re_len(u_int32_t re_len); +

+

Description

+

For the Queue access method, specify that the records are of length +re_len. +

For the Recno access method, specify that the records are fixed-length, +not byte delimited, and are of length re_len. +

Any records added to the database that are less than re_len bytes +long are automatically padded (see Db::set_re_pad for more +information). +

Any attempt to insert records into the database that are greater than +re_len bytes long will cause the call to fail immediately and +return an error. +

The Db::set_re_len interface may only be used to configure Berkeley DB before +the Db::open interface is called. +

The Db::set_re_len method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after Db::open was called. +

+

Class

+Db +

See Also

+Db::close, +Db::cursor, +Db::del, +Db::err, +Db::fd, +Db::get, +Db::get_byteswapped, +Db::get_type, +Db::join, +Db::key_range, +Db::open, +Db::put, +Db::remove, +Db::set_bt_compare, +Db::set_bt_minkey, +Db::set_bt_prefix, +Db::set_cachesize, +Db::set_dup_compare, +Db::set_errcall, +Db::set_errfile, +Db::set_errpfx, +Db::set_flags, +Db::set_h_ffactor, +Db::set_h_hash, +Db::set_h_nelem, +Db::set_lorder, +Db::set_malloc, +Db::set_pagesize, +Db::set_paniccall, +Db::set_q_extentsize, +Db::set_realloc, +Db::set_re_delim, +Db::set_re_len, +Db::set_re_pad, +Db::set_re_source, +Db::stat, +Db::sync, +Db::upgrade +and +Db::verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_set_re_pad.html b/db/docs/api_cxx/db_set_re_pad.html new file mode 100644 index 000000000..5b9453d0d --- /dev/null +++ b/db/docs/api_cxx/db_set_re_pad.html @@ -0,0 +1,90 @@ + + + + + +Berkeley DB: Db::set_re_pad + + + + + + + +
+

Db::set_re_pad

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +Db::set_re_pad(int re_pad); +

+

Description

+

Set the padding character for short, fixed-length records for the Queue +and Recno access methods. +

If no pad character is specified, <space> characters (i.e., +ASCII 0x20) are used for padding. +

The Db::set_re_pad interface may only be used to configure Berkeley DB before +the Db::open interface is called. +

The Db::set_re_pad method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after Db::open was called. +

+

Class

+Db +

See Also

+Db::close, +Db::cursor, +Db::del, +Db::err, +Db::fd, +Db::get, +Db::get_byteswapped, +Db::get_type, +Db::join, +Db::key_range, +Db::open, +Db::put, +Db::remove, +Db::set_bt_compare, +Db::set_bt_minkey, +Db::set_bt_prefix, +Db::set_cachesize, +Db::set_dup_compare, +Db::set_errcall, +Db::set_errfile, +Db::set_errpfx, +Db::set_flags, +Db::set_h_ffactor, +Db::set_h_hash, +Db::set_h_nelem, +Db::set_lorder, +Db::set_malloc, +Db::set_pagesize, +Db::set_paniccall, +Db::set_q_extentsize, +Db::set_realloc, +Db::set_re_delim, +Db::set_re_len, +Db::set_re_pad, +Db::set_re_source, +Db::stat, +Db::sync, +Db::upgrade +and +Db::verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_set_re_source.html b/db/docs/api_cxx/db_set_re_source.html new file mode 100644 index 000000000..ea51dde62 --- /dev/null +++ b/db/docs/api_cxx/db_set_re_source.html @@ -0,0 +1,132 @@ + + + + + +Berkeley DB: Db::set_re_source + + + + + + + +
+

Db::set_re_source

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +Db::set_re_source(char *re_source); +

+

Description

+

Set the underlying source file for the Recno access method. The purpose +of the re_source value is to provide fast access and modification +to databases that are normally stored as flat text files. +

If the re_source field is set, it specifies an underlying flat +text database file that is read to initialize a transient record number +index. In the case of variable length records, the records are separated +as specified by Db::set_re_delim. For example, standard UNIX +byte stream files can be interpreted as a sequence of variable length +records separated by <newline> characters. +

In addition, when cached data would normally be written back to the +underlying database file (e.g., the Db::close or Db::sync +methods are called), the in-memory copy of the database will be written +back to the re_source file. +

By default, the backing source file is read lazily, i.e., records are not +read from the file until they are requested by the application. +If multiple processes (not threads) are accessing a Recno database +concurrently and either inserting or deleting records, the backing source +file must be read in its entirety before more than a single process +accesses the database, and only that process should specify the backing +source file as part of the Db::open call. See the DB_SNAPSHOT +flag for more information. +

Reading and writing the backing source file specified by re_source +cannot be transactionally protected because it involves filesystem +operations that are not part of the Db transaction methodology. +For this reason, if a temporary database is used to hold the records, +i.e., a NULL was specified as the file argument to Db::open, +it is possible to lose the contents of the re_source file, e.g., +if the system crashes at the right instant. +If a file is used to hold the database, i.e., a file name was specified +as the file argument to Db::open, normal database +recovery on that file can be used to prevent information loss, +although it is still possible that the contents of re_source +will be lost if the system crashes. +

The re_source file must already exist (but may be zero-length) when +Db::open is called. +

It is not an error to specify a read-only re_source file when +creating a database, nor is it an error to modify the resulting database. +However, any attempt to write the changes to the backing source file using +either the Db::sync or Db::close methods will fail, of course. +Specify the DB_NOSYNC flag to the Db::close method to stop it +from attempting to write the changes to the backing file, instead, they +will be silently discarded. +

For all of the above reasons, the re_source field is generally +used to specify databases that are read-only for Db applications, +and that are either generated on the fly by software tools, or modified +using a different mechanism, e.g., a text editor. +

The Db::set_re_source interface may only be used to configure Berkeley DB before +the Db::open interface is called. +

The Db::set_re_source method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after Db::open was called. +

+

Class

+Db +

See Also

+Db::close, +Db::cursor, +Db::del, +Db::err, +Db::fd, +Db::get, +Db::get_byteswapped, +Db::get_type, +Db::join, +Db::key_range, +Db::open, +Db::put, +Db::remove, +Db::set_bt_compare, +Db::set_bt_minkey, +Db::set_bt_prefix, +Db::set_cachesize, +Db::set_dup_compare, +Db::set_errcall, +Db::set_errfile, +Db::set_errpfx, +Db::set_flags, +Db::set_h_ffactor, +Db::set_h_hash, +Db::set_h_nelem, +Db::set_lorder, +Db::set_malloc, +Db::set_pagesize, +Db::set_paniccall, +Db::set_q_extentsize, +Db::set_realloc, +Db::set_re_delim, +Db::set_re_len, +Db::set_re_pad, +Db::set_re_source, +Db::stat, +Db::sync, +Db::upgrade +and +Db::verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_set_realloc.html b/db/docs/api_cxx/db_set_realloc.html new file mode 100644 index 000000000..e163a889c --- /dev/null +++ b/db/docs/api_cxx/db_set_realloc.html @@ -0,0 +1,103 @@ + + + + + +Berkeley DB: Db::set_realloc + + + + + + + +
+

Db::set_realloc

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+extern "C" { + typedef void *(*db_realloc_fcn_type)(void *, size_t); +}; +int +Db::set_realloc(db_realloc_fcn_type db_realloc_fcn); +

+

Description

+

Set the realloc function used by the Db methods to allocate memory +in which to return key/data items to the application. +

The DB_DBT_REALLOC flag, when specified in the Dbt object, +will cause the Db methods to allocate and re-allocate memory which +then becomes the responsibility of the calling application. See Dbt +for more information. +

On systems where there may be multiple library versions of realloc (notably +Windows NT), specifying the DB_DBT_REALLOC flag will fail because +the Db library will allocate memory from a different heap than +the application will use to free it. To avoid this problem, the +Db::set_realloc method can be used to pass Berkeley DB a reference to the +application's allocation routine, in which case it will be used to +allocate the memory returned when the DB_DBT_REALLOC flag is set. +

The method specified must match the calling conventions of the +ANSI C X3.159-1989 (ANSI C) library routine of the same name. +

The Db::set_realloc interface may only be used to configure Berkeley DB before +the Db::open interface is called. +

The Db::set_realloc method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

Class

+Db +

See Also

+Db::close, +Db::cursor, +Db::del, +Db::err, +Db::fd, +Db::get, +Db::get_byteswapped, +Db::get_type, +Db::join, +Db::key_range, +Db::open, +Db::put, +Db::remove, +Db::set_bt_compare, +Db::set_bt_minkey, +Db::set_bt_prefix, +Db::set_cachesize, +Db::set_dup_compare, +Db::set_errcall, +Db::set_errfile, +Db::set_errpfx, +Db::set_flags, +Db::set_h_ffactor, +Db::set_h_hash, +Db::set_h_nelem, +Db::set_lorder, +Db::set_malloc, +Db::set_pagesize, +Db::set_paniccall, +Db::set_q_extentsize, +Db::set_realloc, +Db::set_re_delim, +Db::set_re_len, +Db::set_re_pad, +Db::set_re_source, +Db::stat, +Db::sync, +Db::upgrade +and +Db::verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_stat.html b/db/docs/api_cxx/db_stat.html new file mode 100644 index 000000000..4245fd917 --- /dev/null +++ b/db/docs/api_cxx/db_stat.html @@ -0,0 +1,201 @@ + + + + + +Berkeley DB: Db::stat + + + + + + + +
+

Db::stat

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+extern "C" { + typedef void *(*db_malloc_fcn_type)(size_t); +}; +int +Db::stat(void *sp, db_malloc_fcn_type db_malloc, u_int32_t flags); +

+

Description

+

The Db::stat method creates a statistical structure and +copies a pointer to it into user-specified memory locations. +Specifically, if sp is non-NULL, a pointer to the statistics +for the database are copied into the memory location it references. +

Statistical structures are created in allocated memory. If db_malloc is non-NULL, it +is called to allocate the memory, otherwise, the library function +malloc(3) is used. The function db_malloc must match +the calling conventions of the malloc(3) library routine. +Regardless, the caller is responsible for deallocating the returned +memory. To deallocate returned memory, free the returned memory +reference, references inside the returned memory do not need to be +individually freed. +

The flags parameter must be set to 0 or the following value: +

+

DB_CACHED_COUNTS
Return a cached count of the keys and records in a database. This flag +makes it possible for applications to request an possibly approximate key +and record count without incurring the performance penalty of traversing +the entire database. The statistics information described for the access +method XX_nkeys and XX_ndata fields below is filled in, +but no other information is collected. If the cached information has +never been set, the fields will be returned set to 0. +

DB_RECORDCOUNT
Return a count of the records in a Btree or Recno Access Method database. +This flag makes it possible for applications to request a record count +without incurring the performance penalty of traversing the entire +database. The statistics information described for the bt_nkeys +field below is filled in, but no other information is collected. +

This option is only available for Recno databases, or Btree databases +where the underlying database was created with the DB_RECNUM +flag. +

+

The Db::stat method may access all of the pages in the database, +incurring a severe performance penalty as well as possibly flushing the +underlying buffer pool. +

In the presence of multiple threads or processes accessing an active +database, the information returned by Db::stat may be out-of-date. +

If the database was not opened readonly and the DB_CACHED_COUNTS +flag was not specified, the cached key and record numbers will be updated +after the statistical information has been gathered. +

The Db::stat method cannot be transaction protected. For this reason, +it should be called in a thread of control that has no open cursors or +active transactions. +

The Db::stat method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Hash Statistics

+

In the case of a Hash database, +the statistics are stored in a structure of type DB_HASH_STAT. The +following fields will be filled in: +

+

u_int32_t hash_magic;
Magic number that identifies the file as a Hash file. +
u_int32_t hash_version;
The version of the Hash database. +
u_int32_t hash_nkeys;
The number of unique keys in the database. +
u_int32_t hash_ndata;
The number of key/data pairs in the database.] +
u_int32_t hash_pagesize;
The underlying Hash database page (and bucket) size. +
u_int32_t hash_nelem;
The estimated size of the hash table specified at database creation time. +
u_int32_t hash_ffactor;
The desired fill factor (number of items per bucket) specified at database +creation time. +
u_int32_t hash_buckets;
The number of hash buckets. +
u_int32_t hash_free;
The number of pages on the free list. +
u_int32_t hash_bfree;
The number of bytes free on bucket pages. +
u_int32_t hash_bigpages;
The number of big key/data pages. +
u_int32_t hash_big_bfree;
The number of bytes free on big item pages. +
u_int32_t hash_overflows;
The number of overflow pages (overflow pages are pages that contain items +that did not fit in the main bucket page). +
u_int32_t hash_ovfl_free;
The number of bytes free on overflow pages. +
u_int32_t hash_dup;
The number of duplicate pages. +
u_int32_t hash_dup_free;
The number of bytes free on duplicate pages. +
+

Btree and Recno Statistics

+

In the case of a Btree or Recno database, +the statistics are stored in a structure of type DB_BTREE_STAT. The +following fields will be filled in: +

+

u_int32_t bt_magic;
Magic number that identifies the file as a Btree database. +
u_int32_t bt_version;
The version of the Btree database. +
u_int32_t bt_nkeys;
For the Btree Access Method, the number of unique keys in the database. +

For the Recno Access Method, the number of records in the database. +

u_int32_t bt_ndata;
For the Btree Access Method, the number of key/data pairs in the database. +

For the Recno Access Method, the number of records in the database. If +the database has been configured to not re-number records during +deletion, the number of records will only reflect undeleted records. +

u_int32_t bt_pagesize;
Underlying database page size. +
u_int32_t bt_minkey;
The minimum keys per page. +
u_int32_t bt_re_len;
The length of fixed-length records. +
u_int32_t bt_re_pad;
The padding byte value for fixed-length records. +
u_int32_t bt_levels;
Number of levels in the database. +
u_int32_t bt_int_pg;
Number of database internal pages. +
u_int32_t bt_leaf_pg;
Number of database leaf pages. +
u_int32_t bt_dup_pg;
Number of database duplicate pages. +
u_int32_t bt_over_pg;
Number of database overflow pages. +
u_int32_t bt_free;
Number of pages on the free list. +
u_int32_t bt_int_pgfree;
Number of bytes free in database internal pages. +
u_int32_t bt_leaf_pgfree;
Number of bytes free in database leaf pages. +
u_int32_t bt_dup_pgfree;
Number of bytes free in database duplicate pages. +
u_int32_t bt_over_pgfree;
Number of bytes free in database overflow pages. +
+

Queue Statistics

+

In the case of a Queue database, +the statistics are stored in a structure of type DB_QUEUE_STAT. The +following fields will be filled in: +

+

u_int32_t qs_magic;
Magic number that identifies the file as a Queue file. +
u_int32_t qs_version;
The version of the Queue file type. +
u_int32_t qs_nkeys;
The number of records in the database. +
u_int32_t qs_ndata;
The number of records in the database. +
u_int32_t qs_pagesize;
Underlying database page size. +
u_int32_t qs_pages;
Number of pages in the database. +
u_int32_t qs_re_len;
The length of the records. +
u_int32_t qs_re_pad;
The padding byte value for the records. +
u_int32_t qs_pgfree;
Number of bytes free in database pages. +
u_int32_t qs_start;
Start offset. +
u_int32_t qs_first_recno;
First undeleted record in the database. +
u_int32_t qs_cur_recno;
Last allocated record number in the database. +
+

The Db::stat method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The Db::stat method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Db::stat method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Class

+Db +

See Also

+Db::close, +Db::cursor, +Db::del, +Db::err, +Db::fd, +Db::get, +Db::get_byteswapped, +Db::get_type, +Db::join, +Db::key_range, +Db::open, +Db::put, +Db::remove, +Db::set_bt_compare, +Db::set_bt_minkey, +Db::set_bt_prefix, +Db::set_cachesize, +Db::set_dup_compare, +Db::set_errcall, +Db::set_errfile, +Db::set_errpfx, +Db::set_flags, +Db::set_h_ffactor, +Db::set_h_hash, +Db::set_h_nelem, +Db::set_lorder, +Db::set_malloc, +Db::set_pagesize, +Db::set_paniccall, +Db::set_q_extentsize, +Db::set_realloc, +Db::set_re_delim, +Db::set_re_len, +Db::set_re_pad, +Db::set_re_source, +Db::stat, +Db::sync, +Db::upgrade +and +Db::verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_sync.html b/db/docs/api_cxx/db_sync.html new file mode 100644 index 000000000..170d99127 --- /dev/null +++ b/db/docs/api_cxx/db_sync.html @@ -0,0 +1,101 @@ + + + + + +Berkeley DB: Db::sync + + + + + + + +
+

Db::sync

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +Db::sync(u_int32_t flags); +

+

Description

+

The Db::sync method flushes any cached information to disk. +

If the database is in memory only, the Db::sync method has no effect and +will always succeed. +

The flags parameter is currently unused, and must be set to 0. +

See Db::close for a discussion of Berkeley DB and cached data. +

The Db::sync method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, 0 on success, and returns DB_INCOMPLETE if the underlying database still has +dirty pages in the cache. (The only reason to return +DB_INCOMPLETE is if another thread of control was writing pages +in the underlying database file at the same time as the +Db::sync method was being called. For this reason, a return of +DB_INCOMPLETE can normally be ignored, or, in cases where it is +a possible return value, there may be no reason to call +Db::sync.) +

Errors

+

The Db::sync method may fail and throw an exception or return a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +
+

The Db::sync method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Db::sync method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Class

+Db +

See Also

+Db::close, +Db::cursor, +Db::del, +Db::err, +Db::fd, +Db::get, +Db::get_byteswapped, +Db::get_type, +Db::join, +Db::key_range, +Db::open, +Db::put, +Db::remove, +Db::set_bt_compare, +Db::set_bt_minkey, +Db::set_bt_prefix, +Db::set_cachesize, +Db::set_dup_compare, +Db::set_errcall, +Db::set_errfile, +Db::set_errpfx, +Db::set_flags, +Db::set_h_ffactor, +Db::set_h_hash, +Db::set_h_nelem, +Db::set_lorder, +Db::set_malloc, +Db::set_pagesize, +Db::set_paniccall, +Db::set_q_extentsize, +Db::set_realloc, +Db::set_re_delim, +Db::set_re_len, +Db::set_re_pad, +Db::set_re_source, +Db::stat, +Db::sync, +Db::upgrade +and +Db::verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_upgrade.html b/db/docs/api_cxx/db_upgrade.html new file mode 100644 index 000000000..8cbc3561f --- /dev/null +++ b/db/docs/api_cxx/db_upgrade.html @@ -0,0 +1,135 @@ + + + + + +Berkeley DB: Db::upgrade + + + + + + + +
+

Db::upgrade

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +Db::upgrade(const char *file, u_int32_t flags); +

+

Description

+

The Db::upgrade method upgrades all of the databases included in the +file file, if necessary. If no upgrade is necessary, +Db::upgrade always returns success. +

Database upgrades are done in place and are destructive, e.g., if pages +need to be allocated and no disk space is available, the database may be +left corrupted. Backups should be made before databases are upgraded. +See Upgrading databases for more +information. +

Unlike all other database operations, Db::upgrade may only be done +on a system with the same byte-order as the database. +

The flags parameter must be set to 0 or one of the following +values: +

+

DB_DUPSORT
This flag is only meaningful when upgrading databases from +releases before the Berkeley DB 3.1 release. +

As part of the upgrade from the Berkeley DB 3.0 release to the 3.1 release, the +on-disk format of duplicate data items changed. To correctly upgrade the +format requires applications specify if duplicate data items in the +database are sorted or not. Specifying the DB_DUPSORT flag +informs Db::upgrade that the duplicates are sorted, otherwise they +are assumed to be unsorted. Incorrectly specifying the value of this flag +may lead to database corruption. +

Further, because the Db::upgrade method upgrades a physical file +(including all of the databases it contains), it is not possible to use +Db::upgrade to upgrade files where some of the databases it +includes have sorted duplicate data items and some of the databases it +includes have unsorted duplicate data items. If the file does not have +more than a single database, or the databases do not support duplicate +data items, or all of the databases that support duplicate data items +support the same style of duplicates (either sorted or unsorted), +Db::upgrade will work correctly as long as the DB_DUPSORT +flag is correctly specified. Otherwise, the file cannot be upgraded using +Db::upgrade, and must be upgraded manually by dumping and +re-loading the databases. +

+

The Db::upgrade method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Environment Variables

+

+

DB_HOME
If the dbenv argument to db_create was initialized using +DbEnv::open the environment variable DB_HOME may be used +as the path of the database environment home. Specifically, Db::upgrade +is affected by the configuration value DB_DATA_DIR. +
+

Errors

+

The Db::upgrade method may fail and throw an exception or return a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +

The database is not in the same byte-order as the system. +

+

+

DB_OLD_VERSION
The database cannot be upgraded by this version of the Berkeley DB software. +
+

The Db::upgrade method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Db::upgrade method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Class

+Db +

See Also

+Db::close, +Db::cursor, +Db::del, +Db::err, +Db::fd, +Db::get, +Db::get_byteswapped, +Db::get_type, +Db::join, +Db::key_range, +Db::open, +Db::put, +Db::remove, +Db::set_bt_compare, +Db::set_bt_minkey, +Db::set_bt_prefix, +Db::set_cachesize, +Db::set_dup_compare, +Db::set_errcall, +Db::set_errfile, +Db::set_errpfx, +Db::set_flags, +Db::set_h_ffactor, +Db::set_h_hash, +Db::set_h_nelem, +Db::set_lorder, +Db::set_malloc, +Db::set_pagesize, +Db::set_paniccall, +Db::set_q_extentsize, +Db::set_realloc, +Db::set_re_delim, +Db::set_re_len, +Db::set_re_pad, +Db::set_re_source, +Db::stat, +Db::sync, +Db::upgrade +and +Db::verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/db_verify.html b/db/docs/api_cxx/db_verify.html new file mode 100644 index 000000000..7e742af4c --- /dev/null +++ b/db/docs/api_cxx/db_verify.html @@ -0,0 +1,150 @@ + + + + + +Berkeley DB: Db::verify + + + + + + + +
+

Db::verify

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +Db::verify(const char *file, + const char *database, ostream *outfile, u_int32_t flags); +

+

Description

+

The Db::verify method verifies the integrity of all databases in the +file specified by the file argument, and optionally outputs the databases' +key/data pairs to a file stream. +

The flags parameter must be set to 0 or one of the following +values: +

+

DB_SALVAGE
Write the key/data pairs from all databases in the file to the file stream +named in +the outfile argument. The output format is the same as that +specified for the db_dump utility and can be used as input for +the db_load utility. +

Because the key/data pairs are output in page order as opposed to the sort +order used by db_dump, using Db::verify to dump key/data +pairs normally produces less than optimal loads for Btree databases. +

+

In addition, the following flags may be set by bitwise inclusively OR'ing them into the +flags parameter: +

+

DB_AGGRESSIVE
Output all the key/data pairs in the file that can be found. +By default, Db::verify does not assume corruption. For example, +if a key/data pair on a page is marked as deleted, it is not then written +to the output file. When DB_AGGRESSIVE is specified, corruption +is assumed, and any key/data pair that can be found is written. In this +case, key/data pairs that are corrupted or have been deleted may appear +in the output (even if the file being salvaged is in no way corrupt), and +the output will almost certainly require editing before being loaded into +a database. +

DB_NOORDERCHK
Skip the database checks for btree and duplicate sort order and for +hashing. +

The Db::verify method normally verifies that btree keys and duplicate +items are correctly sorted and hash keys are correctly hashed. If the +file being verified contains multiple databases using differing sorting +or hashing algorithms, some of them must necessarily fail database +verification as only one sort order or hash function can be specified +before Db::verify is called. To verify files with multiple +databases having differing sorting orders or hashing functions, first +perform verification of the file as a whole by using the +DB_NOORDERCHK flag, and then individually verify the sort order +and hashing function for each database in the file using the +DB_ORDERCHKONLY flag. +

DB_ORDERCHKONLY
Perform the database checks for btree and duplicate sort order and for +hashing, skipped by DB_NOORDERCHK. +

When this flag is specified, a database argument should also be +specified, indicating the database in the physical file which is to be +checked. This flag is only safe to use on databases that have already +successfully been verified using Db::verify with the +DB_NOORDERCHK flag set. +

+

The database argument must be set to NULL except when the +DB_ORDERCHKONLY flag is set. +

The Db::verify method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, 0 on success, and DB_VERIFY_BAD if a database is corrupted. When the +DB_SALVAGE flag is specified, the DB_VERIFY_BAD return +means that all key/data pairs in the file may not have been successfully +output. +

Environment Variables

+

+

DB_HOME
If the dbenv argument to db_create was initialized using +DbEnv::open the environment variable DB_HOME may be used +as the path of the database environment home. Specifically, Db::verify +is affected by the configuration value DB_DATA_DIR. +
+

Errors

+

The Db::verify method may fail and throw an exception or return a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +
+

The Db::verify method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Db::verify method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Class

+Db +

See Also

+Db::close, +Db::cursor, +Db::del, +Db::err, +Db::fd, +Db::get, +Db::get_byteswapped, +Db::get_type, +Db::join, +Db::key_range, +Db::open, +Db::put, +Db::remove, +Db::set_bt_compare, +Db::set_bt_minkey, +Db::set_bt_prefix, +Db::set_cachesize, +Db::set_dup_compare, +Db::set_errcall, +Db::set_errfile, +Db::set_errpfx, +Db::set_flags, +Db::set_h_ffactor, +Db::set_h_hash, +Db::set_h_nelem, +Db::set_lorder, +Db::set_malloc, +Db::set_pagesize, +Db::set_paniccall, +Db::set_q_extentsize, +Db::set_realloc, +Db::set_re_delim, +Db::set_re_len, +Db::set_re_pad, +Db::set_re_source, +Db::stat, +Db::sync, +Db::upgrade +and +Db::verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/dbc_class.html b/db/docs/api_cxx/dbc_class.html new file mode 100644 index 000000000..ac8081d4a --- /dev/null +++ b/db/docs/api_cxx/dbc_class.html @@ -0,0 +1,49 @@ + + + + + +Berkeley DB: Dbc + + + + + + + +
+

Dbc

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+class Dbc { ... }; +

+

Description

+

This manual page describes the specific details of the Dbc class, +which provides cursor support for the access methods in Db. +

The Dbc functions are the library interface supporting sequential +access to the records stored by the access methods of the Berkeley DB library. +Cursors are created by calling the Db::cursor method which returns a +pointer to a Dbc object. +

Class

+Dbc +

See Also

+Dbc::close, +Dbc::count, +Dbc::del, +Dbc::dup, +Dbc::get +and +Dbc::put. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/dbc_close.html b/db/docs/api_cxx/dbc_close.html new file mode 100644 index 000000000..881bc3f7d --- /dev/null +++ b/db/docs/api_cxx/dbc_close.html @@ -0,0 +1,68 @@ + + + + + +Berkeley DB: Dbc::close + + + + + + + +
+

Dbc::close

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +Dbc::close(void); +

+

Description

+

The Dbc::close method discards the cursor. +

It is possible for the Dbc::close method to return +DB_LOCK_DEADLOCK, signaling that any enclosing transaction should +be aborted. If the application is already intending to abort the +transaction, this error should be ignored, and the application should +proceed. +

Once Dbc::close has been called, regardless of its return, the +cursor handle may not be used again. +

The Dbc::close method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The Dbc::close method may fail and throw an exception or return a non-zero error for the following conditions: +

+

DB_LOCK_DEADLOCK
The operation was selected to resolve a deadlock. +
+

+

EINVAL
An invalid flag value or parameter was specified. +

The cursor was previously closed. +

+

The Dbc::close method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Dbc::close method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Class

+Dbc +

See Also

+Dbc::close, +Dbc::count, +Dbc::del, +Dbc::dup, +Dbc::get +and +Dbc::put. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/dbc_count.html b/db/docs/api_cxx/dbc_count.html new file mode 100644 index 000000000..be8f6b8e6 --- /dev/null +++ b/db/docs/api_cxx/dbc_count.html @@ -0,0 +1,59 @@ + + + + + +Berkeley DB: Dbc::count + + + + + + + +
+

Dbc::count

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +Dbc::count(db_recno_t *countp, u_int32_t flags); +

+

Description

+

The Dbc::count method returns a count of the number of duplicate data +items for the key referenced by the +cursor into the memory location referenced by countp. +If the underlying database does not support duplicate data items the call +will still succeed and a count of 1 will be returned. +

The flags parameter is currently unused, and must be set to 0. +

If the cursor argument is not yet initialized, the Dbc::count method either returns EINVAL or throws an exception that encapsulates EINVAL. +

Otherwise, the Dbc::count method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The Dbc::count method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Dbc::count method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Class

+Dbc +

See Also

+Dbc::close, +Dbc::count, +Dbc::del, +Dbc::dup, +Dbc::get +and +Dbc::put. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/dbc_del.html b/db/docs/api_cxx/dbc_del.html new file mode 100644 index 000000000..18f6959a8 --- /dev/null +++ b/db/docs/api_cxx/dbc_del.html @@ -0,0 +1,72 @@ + + + + + +Berkeley DB: Dbc::del + + + + + + + +
+

Dbc::del

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +Dbc::del(u_int32_t flags); +

+

Description

+

The Dbc::del method deletes the key/data pair currently referenced by +the cursor. +

The flags parameter is currently unused, and must be set to 0. +

The cursor position is unchanged after a delete, and subsequent calls to +cursor functions expecting the cursor to reference an existing key will +fail. +

If the element has already been deleted, Dbc::del will return +DB_KEYEMPTY. +

If the cursor is not yet initialized, the Dbc::del method either returns EINVAL or throws an exception that encapsulates EINVAL. +

Otherwise, the Dbc::del method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The Dbc::del method may fail and throw an exception or return a non-zero error for the following conditions: +

+

DB_LOCK_DEADLOCK
The operation was selected to resolve a deadlock. +
+

+

EINVAL
An invalid flag value or parameter was specified. +
+

+

EPERM
Write attempted on read-only cursor when the DB_INIT_CDB flag was +specified to DbEnv::open. +
+

The Dbc::del method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Dbc::del method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Class

+Dbc +

See Also

+Dbc::close, +Dbc::count, +Dbc::del, +Dbc::dup, +Dbc::get +and +Dbc::put. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/dbc_dup.html b/db/docs/api_cxx/dbc_dup.html new file mode 100644 index 000000000..5dec52e46 --- /dev/null +++ b/db/docs/api_cxx/dbc_dup.html @@ -0,0 +1,76 @@ + + + + + +Berkeley DB: Dbc::dup + + + + + + + +
+

Dbc::dup

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +Dbc::dup(Dbc **cursorp, u_int32_t flags); +

+

Description

+

The Dbc::dup method creates a new cursor that uses the same transaction +and locker ID as the original cursor. This is useful when an application +is using locking and requires two or more cursors in the same thread of +control. +

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +

+

DB_POSITION
The newly created cursor is initialized to reference the same position +in the database as the original cursor and hold the same locks. If the +DB_POSITION flag is not specified, then the created cursor is +uninitialized and will behave like a cursor newly created using +Db::cursor. +
+

When using the Berkeley DB Concurrent Data Store product, there can be only one active write cursor +at a time. For this reason, attempting to duplicate a cursor for which +the DB_WRITECURSOR flag was specified during creation will return +an error. +

If the cursor argument is not yet initialized, the Dbc::dup method either returns EINVAL or throws an exception that encapsulates EINVAL. +

Otherwise, the Dbc::dup method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The Dbc::dup method may fail and throw an exception or return a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +

The cursor argument was created using the +DB_WRITECURSOR flag in the Berkeley DB Concurrent Data Store product. +

+

The Dbc::dup method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Dbc::dup method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Class

+Dbc +

See Also

+Dbc::close, +Dbc::count, +Dbc::del, +Dbc::dup, +Dbc::get +and +Dbc::put. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/dbc_get.html b/db/docs/api_cxx/dbc_get.html new file mode 100644 index 000000000..d42a194e5 --- /dev/null +++ b/db/docs/api_cxx/dbc_get.html @@ -0,0 +1,170 @@ + + + + + +Berkeley DB: Dbc::get + + + + + + + +
+

Dbc::get

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +Dbc::get(Dbt *key, Dbt *data, u_int32_t flags); +

+

Description

+

The Dbc::get method retrieves key/data pairs from the database. The +address and length of the key +are returned in the object referenced by key (except for the case +of the DB_SET flag where the key object is unchanged), +and the address and length of +the data are returned in the object referenced by data. +

Modifications to the database during a sequential scan will be reflected +in the scan, i.e. records inserted behind a cursor will not be returned +while records inserted in front of a cursor will be returned. +

In Queue and Recno databases, missing entries (i.e., entries that were +never explicitly created or that were created and then deleted), will be +skipped during a sequential scan. +

If multiple threads or processes insert items into the same database file +without using locking, the results are undefined. +For more detail, +see Cursor stability. +

The flags parameter must be set to one of the following values: +

+

DB_CURRENT
Return the key/data pair currently referenced by the cursor. +

If the cursor key/data pair was deleted, Dbc::get will return +DB_KEYEMPTY. +

If the cursor is not yet initialized, the Dbc::get method either returns EINVAL or throws an exception that encapsulates EINVAL. +

DB_FIRST, DB_LAST
The cursor is set to reference the first (last) key/data pair of the +database, and that pair is returned. In the presence of duplicate key +values, the first (last) data item in the set of duplicates is returned. +

If the database is a Queue or Recno database, Dbc::get using the +DB_FIRST (DB_LAST) flags will ignore any keys that exist +but were never explicitly created by the application or were created and +later deleted. +

If the database is empty, Dbc::get will return DB_NOTFOUND. +

DB_GET_BOTH
The DB_GET_BOTH flag is identical to the DB_SET flag, +except that both the key and the data arguments must be matched by the +key and data item in the database. +

DB_GET_RECNO
Return the record number associated with the cursor. The record number +will be returned in data as described in Dbt. The +key parameter is ignored. +

For DB_GET_RECNO to be specified, the underlying database must be +of type Btree and it must have been created with the DB_RECNUM +flag. +

DB_JOIN_ITEM
Do not use the data value found in all of the cursors as a lookup key for +the primary database, but simply return it in the key parameter instead. +The data parameter is left unchanged. +

For DB_JOIN_ITEM to be specified, the underlying cursor must have +been returned from the Db::join method. +

DB_NEXT, DB_PREV
If the cursor is not yet initialized, DB_NEXT (DB_PREV) +is identical to DB_FIRST (DB_LAST). Otherwise, the cursor +is moved to the next (previous) key/data pair of the database, and that +pair is returned. In the presence of duplicate key values, the value of +the key may not change. +

If the database is a Queue or Recno database, Dbc::get using the +DB_NEXT (DB_PREV) flag will skip any keys that exist but +were never explicitly created by the application or were created and later +deleted. +

If the cursor is already on the last (first) record in the database, +Dbc::get will return DB_NOTFOUND. +

DB_NEXT_DUP
If the next key/data pair of the database is a duplicate record for the +current key/data pair, the cursor is moved to the next key/data pair of +the database, and that pair is returned. Otherwise, Dbc::get will +return DB_NOTFOUND. +

If the cursor is not yet initialized, the Dbc::get method either returns EINVAL or throws an exception that encapsulates EINVAL. +

DB_NEXT_NODUP, DB_PREV_NODUP
If the cursor is not yet initialized, DB_NEXT_NODUP +(DB_PREV_NODUP) is identical to DB_FIRST +(DB_LAST). Otherwise, the cursor is moved to the next (previous) +non-duplicate key/data pair of the database, and that pair is returned. +

If the database is a Queue or Recno database, Dbc::get using the +DB_NEXT_NODUP (DB_PREV_NODUP) flags will ignore any keys +that exist but were never explicitly created by the application or were +created and later deleted. +

If no non-duplicate key/data pairs occur after (before) the cursor +position in the database, Dbc::get will return DB_NOTFOUND. +

DB_SET
Move the cursor to the specified key/data pair of the database, and +return the datum associated with the given key. +

In the presence of duplicate key values, Dbc::get will return the +first data item for the given key. +

If the database is a Queue or Recno database and the requested key exists, +but was never explicitly created by the application or was later deleted, +Dbc::get will return DB_KEYEMPTY. +

If no matching keys are found, Dbc::get will return +DB_NOTFOUND. +

DB_SET_RANGE
The DB_SET_RANGE flag is identical to the DB_SET flag, +except that the key is returned as well as the data item, and, in the case +of the Btree access method, the returned key/data pair is the smallest +key greater than or equal to the specified key (as determined by the +comparison method), permitting partial key matches and range +searches. +

DB_SET_RECNO
Move the cursor to the specific numbered record of the database, and +return the associated key/data pair. The data field of the +specified key +must be a pointer to a memory location from which a db_recno_t +may be read, as described in Dbt. This memory location will be +read to determine the record to be retrieved. +

For DB_SET_RECNO to be specified, the underlying database must be +of type Btree and it must have been created with the DB_RECNUM +flag. +

+

In addition, the following flag may be set by bitwise inclusively OR'ing it into the +flags parameter: +

+

DB_RMW
Acquire write locks instead of read locks when doing the retrieval. +Setting this flag may decrease the likelihood of deadlock during a +read-modify-write cycle by immediately acquiring the write lock during +the read part of the cycle so that another thread of control acquiring +a read lock for the same item, in its own read-modify-write cycle, will +not result in deadlock. +
+

Otherwise, the Dbc::get method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

If Dbc::get fails for any reason, the state of the cursor will be +unchanged. +

Errors

+

The Dbc::get method may fail and throw an exception or return a non-zero error for the following conditions: +

+

DB_LOCK_DEADLOCK
The operation was selected to resolve a deadlock. +
+

+

ENOMEM
There was insufficient memory to return the requested item. +
+

+

EINVAL
An invalid flag value or parameter was specified. +

The specified cursor was not currently initialized. +

+

The Dbc::get method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Dbc::get method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Class

+Dbc +

See Also

+Dbc::close, +Dbc::count, +Dbc::del, +Dbc::dup, +Dbc::get +and +Dbc::put. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/dbc_put.html b/db/docs/api_cxx/dbc_put.html new file mode 100644 index 000000000..05a95cd36 --- /dev/null +++ b/db/docs/api_cxx/dbc_put.html @@ -0,0 +1,158 @@ + + + + + +Berkeley DB: Dbc::put + + + + + + + +
+

Dbc::put

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +Dbc::put(Dbt *key, Dbt *data, u_int32_t flags); +

+

Description

+

The Dbc::put method stores key/data pairs into the database. +

The flags parameter must be set to one of the following values: +

+

DB_AFTER
In the case of the Btree and Hash access methods, insert the data +element as a duplicate element of the key referenced by the cursor. +The new element appears immediately after the current cursor position. +It is an error to specify DB_AFTER if the underlying Btree or +Hash database does not support duplicate data items. The key +parameter is ignored. +

In the case of the Recno access method, it is an error to specify +DB_AFTER if the underlying Recno database was not created with +the DB_RENUMBER flag. If the DB_RENUMBER flag was +specified, a new key is created, all records after the inserted item +are automatically renumbered, and the key of the new record is returned +in the structure referenced by the parameter key. The initial +value of the key parameter is ignored. See Db::open +for more information. +

The DB_AFTER flag may not be specified to the Queue access method. +

If the current cursor record has already been deleted and the underlying +access method is Hash, Dbc::put will return DB_NOTFOUND. +If the underlying access method is Btree or Recno, the operation will +succeed. +

If the cursor is not yet initialized or a duplicate sort function has been +specified, the Dbc::put function will return EINVAL. +

DB_BEFORE
In the case of the Btree and Hash access methods, insert the data element +as a duplicate element of the key referenced by the cursor. The new +element appears immediately before the current cursor position. It is +an error to specify DB_BEFORE if the underlying Btree or Hash +database does not support duplicate data items. The key +parameter is ignored. +

In the case of the Recno access method, it is an error to specify +DB_BEFORE if the underlying Recno database was not created with +the DB_RENUMBER flag. If the DB_RENUMBER flag was +specified, a new key is created, the current record and all records +after it are automatically renumbered, and the key of the new record is +returned in the structure referenced by the parameter key. The +initial value of the key parameter is ignored. See +Db::open for more information. +

The DB_BEFORE flag may not be specified to the Queue access method. +

If the current cursor record has already been deleted and the underlying +access method is Hash, Dbc::put will return DB_NOTFOUND. +If the underlying access method is Btree or Recno, the operation will +succeed. +

If the cursor is not yet initialized or a duplicate sort function has been +specified, Dbc::put will return EINVAL. +

DB_CURRENT
Overwrite the data of the key/data pair referenced by the cursor with the +specified data item. The key parameter is ignored. +

If a duplicate sort function has been specified and the data item of the +current referenced key/data pair does not compare equally to the data +parameter, Dbc::put will return EINVAL. +

If the current cursor record has already been deleted and the underlying +access method is Hash, Dbc::put will return DB_NOTFOUND. +If the underlying access method is Btree, Queue or Recno, the operation +will succeed. +

If the cursor is not yet initialized, Dbc::put will return EINVAL. +

DB_KEYFIRST
In the case of the Btree and Hash access methods, insert the specified +key/data pair into the database. +

If the underlying database supports duplicate data items, and if the +key already exists in the database and a duplicate sort function has +been specified, the inserted data item is added in its sorted location. +If the key already exists in the database and no duplicate sort function +has been specified, the inserted data item is added as the first of the +data items for that key. +

The DB_KEYFIRST flag may not be specified to the Queue or Recno +access methods. +

DB_KEYLAST
In the case of the Btree and Hash access methods, insert the specified +key/data pair into the database. +

If the underlying database supports duplicate data items, and if the +key already exists in the database and a duplicate sort function has +been specified, the inserted data item is added in its sorted location. +If the key already exists in the database, and no duplicate sort +function has been specified, the inserted data item is added as the last +of the data items for that key. +

The DB_KEYLAST flag may not be specified to the Queue or Recno +access methods. +

DB_NODUPDATA
In the case of the Btree and Hash access methods, insert the specified +key/data pair into the database unless it already exists in the database. +If the key/data pair already appears in the database, DB_KEYEXIST +is returned. The DB_NODUPDATA flag may only be specified if +the underlying database has been configured to support sorted duplicate +data items. +

The DB_NODUPDATA flag may not be specified to the Queue or Recno +access methods. +

+

Otherwise, the Dbc::put method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

If Dbc::put fails for any reason, the state of the cursor will be +unchanged. If Dbc::put succeeds and an item is inserted into the +database, the cursor is always positioned to reference the newly inserted +item. +

Errors

+

The Dbc::put method may fail and throw an exception or return a non-zero error for the following conditions: +

+

DB_LOCK_DEADLOCK
The operation was selected to resolve a deadlock. +
+

+

EACCES
An attempt was made to modify a read-only database. +
+

+

EINVAL
An invalid flag value or parameter was specified. +

The DB_BEFORE or DB_AFTER flags were specified, and the +underlying access method is Queue. +

An attempt was made to add a record to a fixed-length database that was too +large to fit. +

+

+

EPERM
Write attempted on read-only cursor when the DB_INIT_CDB flag was +specified to DbEnv::open. +
+

The Dbc::put method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Dbc::put method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Class

+Dbc +

See Also

+Dbc::close, +Dbc::count, +Dbc::del, +Dbc::dup, +Dbc::get +and +Dbc::put. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/dbenv_class.html b/db/docs/api_cxx/dbenv_class.html new file mode 100644 index 000000000..1c59dcbf1 --- /dev/null +++ b/db/docs/api_cxx/dbenv_class.html @@ -0,0 +1,76 @@ + + + + + +Berkeley DB: DbEnv + + + + + + + +
+

DbEnv

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+class DbEnv { +public: + DbEnv(u_int32 flags); + ~DbEnv(); + ... +}; +

+

Description

+

This manual page describes the specific details of the DbEnv +class, which is the center of the Berkeley DB environment. +

The following flags value may be specified: +

+

DB_CLIENT
Create a client environment to connect to a server. +

The DB_CLIENT flag indicates to the system that this environment +is remote on a server. The use of this flag causes the environment +methods to use functions that call a server instead of local functions. +Prior to making any environment or database method calls, the +application must call the DbEnv::set_server function to establish +the connection to the server. +

DB_CXX_NO_EXCEPTIONS
The Berkeley DB C++ API supports two different error behaviors. By default, +whenever an error occurs an exception is thrown that encapsulates the +error information. This generally allows for cleaner logic for +transaction processing, as a try block can surround a single +transaction. However, if DB_CXX_NO_EXCEPTIONS is specified, +exceptions are not thrown, instead each individual function returns an +error code. +
+

Class

+DbEnv +

See Also

+DbEnv::close, +DbEnv::open, +DbEnv::remove, +DbEnv::err, +DbEnv::strerror, +DbEnv::version, +DbEnv::set_cachesize, +DbEnv::set_errcall, +DbEnv::set_errfile, +DbEnv::set_error_stream, +DbEnv::set_errpfx, +DbEnv::set_flags, +DbEnv::set_mutexlocks, +DbEnv::set_paniccall, +and +DbEnv::set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/dbt_class.html b/db/docs/api_cxx/dbt_class.html new file mode 100644 index 000000000..24d18c60e --- /dev/null +++ b/db/docs/api_cxx/dbt_class.html @@ -0,0 +1,230 @@ + + + + + +Berkeley DB: Dbt + + + + + + + +
+

Dbt

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+class Dbt { +public: + void *get_data() const; + void set_data(void *); +

+ u_int32_t get_size() const; + void set_size(u_int32_t); +

+ u_int32_t get_ulen() const; + void set_ulen(u_int32_t); +

+ u_int32_t get_dlen() const; + void set_dlen(u_int32_t); +

+ u_int32_t get_doff() const; + void set_doff(u_int32_t); +

+ u_int32_t get_flags() const; + void set_flags(u_int32_t); +

+ Dbt(void *data, size_t size); + Dbt(); + Dbt(const Dbt &); + Dbt &operator = (const Dbt &); + ~Dbt(); +}; +

+

Description

+

This manual page describes the specific details of the Dbt class, +used to encode keys and data items in a database. + +

Key/Data Pairs

+

Storage and retrieval for the Db access methods are based on +key/data pairs. Both key and data items are represented by Dbt +objects. Key and data byte strings may reference strings of zero length +up to strings of essentially unlimited length. See +Database limits for more +information. +

The Dbt class provides simple access to an underlying data structure, +whose elements can be examined or changed using the set_ or +get_ methods. The remainder of the manual page sometimes refers +to these accesses using the underlying name, e.g., simply ulen +instead of Dbt::get_ulen and Dbt::set_ulen. +Dbt can be subclassed, providing a way to associate +with it additional data, or references to other structures. +

The constructors set all elements of the underlying structure to zero. +The constructor with two arguments has the effect of setting all elements +to zero except for the specified data and size elements. +

In the case where the flags structure element is 0, when the +application is providing Berkeley DB a key or data item to store into the +database, Berkeley DB expects the data object to point to a byte string +of size bytes. When returning a key/data item to the application, +Berkeley DB will store into the data object a pointer to a byte string +of size bytes, and the memory referenced by the pointer will be +allocated and managed by Berkeley DB. +

The elements of the structure underlying the Dbt class are defined as follows: +

+

void *data;
A pointer to a byte string. +This element is accessed using Dbt::get_data and +Dbt::set_data, and may be initialized using one +of the constructors. +

int offset;
The number of bytes offset into the data array to determine the +portion of the array actually used. +This element is accessed using Dbt::get_offset and +Dbt::set_offset. +

u_int32_t size;
The length of data, in bytes. +This element is accessed using Dbt::get_size and +Dbt::set_size, and may be initialized +using the constructor with two arguments. +

u_int32_t ulen;
The size of the user's buffer (referenced by data), in bytes. +This location is not written by the Db methods. +

Note that applications can determine the length of a record by setting +the ulen to 0 and checking the return value found in size. +See the DB_DBT_USERMEM flag for more information. +

This element is accessed using +Dbt::get_ulen and Dbt::set_ulen. +

u_int32_t dlen;
The length of the partial record being read or written by the application, +in bytes. +See the DB_DBT_PARTIAL flag for more information. +This element is accessed using +Dbt::get_dlen, and Dbt::set_dlen. +

u_int32_t doff;
The offset of the partial record being read or written by the application, +in bytes. +See the DB_DBT_PARTIAL flag for more information. +This element is accessed using +Dbt::get_doff and Dbt::set_doff. +

u_int32_t flags;
This element is accessed using Dbt::get_flags and +Dbt::set_flags. +

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +

+

DB_DBT_MALLOC
When this flag is set Berkeley DB will allocate memory for the returned key +or data item +(using malloc(3) or the user-specified malloc method) and +return a pointer to it in the data field of the key or data +Dbt object. As any allocated memory becomes the responsibility +of the calling application, the caller must be able to determine if +memory was allocated. +

It is an error to specify more than one of DB_DBT_MALLOC, +DB_DBT_REALLOC and DB_DBT_USERMEM. +

DB_DBT_REALLOC
When this flag is set Berkeley DB +will allocate memory for the returned key or data item (using +realloc(3) or the user-specified realloc method) and return +a pointer to it in the data field of the key or data Dbt +object. As any allocated memory becomes the responsibility of the +calling application, the caller must be able to determine if memory was +allocated. +

It is an error to specify more than one of DB_DBT_MALLOC, +DB_DBT_REALLOC and DB_DBT_USERMEM. +

DB_DBT_USERMEM
The data field of the key or data object must reference memory +that is at least ulen bytes in length. If the length of the +requested item is less than or equal to that number of bytes, the item +is copied into the memory referenced by the data field. +Otherwise, the size field is set to the length needed for the +requested item, and the error ENOMEM is returned. +

It is an error to specify more than one of DB_DBT_MALLOC, +DB_DBT_REALLOC and DB_DBT_USERMEM. +

+

If DB_DBT_MALLOC or DB_DBT_REALLOC is specified, Berkeley DB +allocates a properly sized byte array to contain the data. This can be +convenient if you know little about the nature of the data, specifically +the size of data in the database. However, if your application makes +repeated calls to retrieve keys or data, you may notice increased garbage +collection due to this allocation. If you know the maximum size of data +you are retrieving, you might decrease the memory burden and speed your +application by allocating your own byte array and using +DB_DBT_USERMEM. Even if you don't know the maximum size, you can +use this option and reallocate your array whenever your retrieval API call +returns an ENOMEM error, or throws an exception encapsulating an ENOMEM. +

+

DB_DBT_PARTIAL
Do partial retrieval or storage of an item. If the calling application +is doing a get, the dlen bytes starting doff bytes from +the beginning of the retrieved data record are returned as if they +comprised the entire record. If any or all of the specified bytes do +not exist in the record, the get is successful and the existing bytes +or nul bytes are returned. +

For example, if the data portion of a retrieved record was 100 bytes, +and a partial retrieval was done using a Dbt having a dlen +field of 20 and a doff field of 85, the get call would succeed, +the data field would reference the last 15 bytes of the record, +and the size field would be set to 15. +

If the calling application is doing a put, the dlen bytes starting +doff bytes from the beginning of the specified key's data record +are replaced by the data specified by the data and size +objects. +If dlen is smaller than size, the record will grow, and if +dlen is larger than size, the record will shrink. +If the specified bytes do not exist, the record will be extended using nul +bytes as necessary, and the put call will succeed. +

It is an error to attempt a partial put using the Db::put +method in a database that supports duplicate records. +Partial puts in databases supporting duplicate records must be done +using a Dbc method. +

It is an error to attempt a partial put with differing dlen and +size values in Queue or Recno databases with fixed-length records. +

For example, if the data portion of a retrieved record was 100 bytes, +and a partial put was done using a Dbt having a dlen +field of 20, a doff field of 85, and a size field of 30, +the resulting record would be 115 bytes in length, where the last 30 +bytes would be those specified by the put call. +

+
+ +

Retrieved key/data permanence

+

When using the non-cursor Berkeley DB calls to retrieve key/data items (e.g., +Db::get), the memory referenced by the pointer stored into the +Dbt is only valid until the next call to Berkeley DB using the +Db handle returned by Db::open. (This includes +any use of the returned Db handle, including by another +thread of control within the process. For this reason, when multiple +threads are using the returned DB handle concurrently, one of the +DB_DBT_MALLOC, DB_DBT_REALLOC or DB_DBT_USERMEM +flags must be specified for any non-cursor Dbt used for key or +data retrieval.) +

When using the cursor Berkeley DB calls to retrieve key/data items (e.g., +Dbc::get), the memory referenced by the pointer into the +Dbt is only valid until the next call to Berkeley DB using the +Dbc handle returned by Db::cursor. + +

Data alignment

+

The Berkeley DB access methods provide no guarantees about key/data byte string +alignment, and applications are responsible for arranging any necessary +alignment. The DB_DBT_MALLOC, DB_DBT_REALLOC and +DB_DBT_USERMEM flags may be used to store returned items in memory +of arbitrary alignment. + +

Logical Record Numbers

+

In all cases for the Queue and Recno access methods, and when calling the +Db::get and Dbc::get functions with the +DB_SET_RECNO flag specified, the data +field of the key must be a pointer to a memory location of type +db_recno_t, as typedef'd in the #include <db_cxx.h> include file. +This type is a 32-bit unsigned type, +(which limits the number of logical records in a Queue or Recno database, +and the maximum logical record which may be directly retrieved from a +Btree database, to 4,294,967,296). The size field of the key +should be the size of that type, i.e., +in the C programming language, sizeof(db_recno_t). +

Logical record numbers are 1-based, not 0-based, i.e., the first record +in the database is record number 1. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/env_close.html b/db/docs/api_cxx/env_close.html new file mode 100644 index 000000000..fc1ae2573 --- /dev/null +++ b/db/docs/api_cxx/env_close.html @@ -0,0 +1,87 @@ + + + + + +Berkeley DB: DbEnv::close + + + + + + + +
+

DbEnv::close

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+DbEnv::close(u_int32_t flags); +

+

Description

+

The DbEnv::close method closes the Berkeley DB environment, freeing any +allocated resources and closing any underlying subsystems. +

Calling DbEnv::close does not imply closing any databases that were +opened in the environment. +

The flags parameter is currently unused, and must be set to 0. +

Where the environment was initialized with the DB_INIT_LOCK flag, +calling DbEnv::close does not release any locks still held by the +closing process, providing functionality for long-lived locks. +Processes that wish to have all their locks +released can do so by issuing the appropriate DbEnv::lock_vec call. +

Where the environment was initialized with the DB_INIT_MPOOL +flag, calling DbEnv::close implies calls to DbMpoolFile::close for +any remaining open files in the memory pool that were returned to this +process by calls to DbMpoolFile::open. It does not imply a call to +DbMpoolFile::sync for those files. +

Where the environment was initialized with the DB_INIT_TXN flag, +calling DbEnv::close aborts any uncommitted transactions. +(Applications are should not depend on this behavior. If the process' has +already closed a database handle which is necessary to abort an +uncommitted transaction, the Berkeley DB environment must then require that +recovery be run before further operations are done, since once a +transaction exists that cannot be committed or aborted, no future +checkpoint can ever succeed.) +

In multi-threaded applications, only a single thread may call +DbEnv::close. +

Once DbEnv::close has been called, regardless of its return, +the Berkeley DB environment handle may not be accessed again. +

The DbEnv::close method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The DbEnv::close method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv::close method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Class

+DbEnv +

See Also

+DbEnv::close, +DbEnv::open, +DbEnv::remove, +DbEnv::err, +DbEnv::strerror, +DbEnv::version, +DbEnv::set_cachesize, +DbEnv::set_errcall, +DbEnv::set_errfile, +DbEnv::set_error_stream, +DbEnv::set_errpfx, +DbEnv::set_flags, +DbEnv::set_mutexlocks, +DbEnv::set_paniccall, +and +DbEnv::set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/env_open.html b/db/docs/api_cxx/env_open.html new file mode 100644 index 000000000..53c9908dc --- /dev/null +++ b/db/docs/api_cxx/env_open.html @@ -0,0 +1,209 @@ + + + + + +Berkeley DB: DbEnv::open + + + + + + + +
+

DbEnv::open

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::open(const char *db_home, u_int32_t flags, int mode); +

+

Description

+

The DbEnv::open method is the interface for opening the Berkeley DB +environment. It provides a structure for creating a consistent +environment for processes using one or more of the features of Berkeley DB. +

The db_home argument to DbEnv::open (and file name +resolution in general) is described in +Berkeley DB File Naming. +

The flags argument specifies the subsystems that are initialized +and how the application's environment affects Berkeley DB file naming, among +other things. +

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +

As there are a large number of flags that can be specified, they have been +grouped together by functionality. The first group of flags indicate +which of the Berkeley DB subsystems should be initialized: +

+

DB_JOINENV
Join an existing environment. This option allows applications to +join an existing environment without knowing which Berkeley DB subsystems +the environment supports. +

DB_INIT_CDB
Initialize locking for the Berkeley DB Concurrent Data Store +product. In this mode, Berkeley DB provides multiple reader/single writer +access. The only other subsystem that should be specified with the +DB_INIT_CDB flag is DB_INIT_MPOOL. +

Access method calls are largely unchanged when using this flag, although +any cursors through which update operations (e.g., Dbc::put, +Dbc::del) will be made must have the DB_WRITECURSOR value +set in the flags parameter to the cursor call that creates the cursor. +See Db::cursor for more information. +

DB_INIT_LOCK
Initialize the locking subsystem. This subsystem should be used when +multiple processes or threads are going to be reading and writing a Berkeley DB +database, so that they do not interfere with each other. If all threads +are accessing the database(s) read-only, then locking is unnecessary. +When the DB_INIT_LOCK flag is specified, it is usually necessary to run +the deadlock detector, as well. See db_deadlock and +DbEnv::lock_detect for more information. +

DB_INIT_LOG
Initialize the logging subsystem. This subsystem is used when recovery +from application or system failure is necessary. +

The log is stored in one or more files in the environment directory. +Each file is named using the format log.NNNNNNNNNN, where +NNNNNNNNNN is the sequence number of the file within the log. +For further information, see +Log File Limits. +

If the log region is being created and log files are already present, the +log files are reviewed and subsequent log writes are appended +to the end of the log, rather than overwriting current log entries. +

DB_INIT_MPOOL
Initialize the shared memory buffer pool subsystem. This subsystem is +used whenever the application is using any Berkeley DB access method. +

DB_INIT_TXN
Initialize the transaction subsystem. This subsystem is used when +recovery and atomicity of multiple operations and recovery are important. +The DB_INIT_TXN flag implies the DB_INIT_LOG flag. +
+

The second group of flags govern what recovery, if any, is performed when +the environment is initialized: +

+

DB_RECOVER
Run normal recovery on this environment before opening it for normal use. +If this flag is set, the DB_CREATE flag must also be set since the regions +will be removed and recreated. +

DB_RECOVER_FATAL
Run catastrophic recovery on this environment before opening it for normal +use. If this flag is set, the DB_CREATE flag must also be set since the +regions will be removed and recreated. +
+

A standard part of the recovery process is to remove the existing Berkeley DB +environment and create a new one in which to perform recovery. If the +thread of control performing recovery does not specify the correct region +initialization information (e.g., the correct memory pool cache size), +the result can be an application running in an environment with incorrect +cache and other subsystem sizes. For this reason, the thread of control +performing recovery should either specify correct configuration +information before calling the DbEnv::open method, or it should remove +the environment after recovery is completed, leaving creation of the +correctly sized environment to a subsequent call to DbEnv::open. +

All Berkeley DB recovery processing must be single-threaded, that is, only a +single thread of control may perform recovery or access a Berkeley DB +environment while recovery is being performed. As it is not an error to +specify DB_RECOVER for an environment for which no recovery is +required, it is reasonable programming practice for the thread of control +responsible for performing recovery and creating the environment to always +specify the DB_RECOVER flag during startup. +

The DbEnv::open function returns successfully if DB_RECOVER +or DB_RECOVER_FATAL is specified and no log files exist, so it is +necessary to ensure all necessary log files are present before running +recovery. For further information, consult db_archive and +db_recover. +

The third group of flags govern file naming extensions in the environment: +

+ +

DB_USE_ENVIRON
The Berkeley DB process' environment may be permitted to specify information to +be used when naming files; see Berkeley DB +File Naming. As permitting users to specify which files are used can +create security problems, environment information will be used in file +naming for all users only if the DB_USE_ENVIRON flag is set. +

DB_USE_ENVIRON_ROOT
The Berkeley DB process' environment may be permitted to specify information to +be used when naming files; see Berkeley DB +File Naming. As permitting users to specify which files are used can +create security problems, if the DB_USE_ENVIRON_ROOT flag is set, +environment information will be used for file naming only for users with +appropriate permissions (e.g., on UNIX systems, users with a user-ID of 0). +
+

Finally, there are a few additional, unrelated flags: +

+

DB_CREATE
Cause Berkeley DB subsystems to create any underlying files, as necessary. +

DB_LOCKDOWN
Lock shared Berkeley DB environment files and memory mapped databases into memory. +

DB_PRIVATE
Specify that the environment will only be accessed by a single process +(although that process may be multi-threaded). This flag has two effects +on the Berkeley DB environment. First, all underlying data structures are +allocated from per-process memory instead of from shared memory that is +potentially accessible to more than a single process. Second, mutexes +are only configured to work between threads. +

This flag should not be specified if more than a single process is +accessing the environment, as it is likely to cause database corruption +and unpredictable behavior, e.g., if both a server application and the +Berkeley DB utility db_stat will access the environment, the +DB_PRIVATE flag should not be specified. +

DB_SYSTEM_MEM
Allocate memory from system shared memory instead of from memory backed +by the filesystem. See Shared Memory +Regions for more information. +

DB_THREAD
Cause the DbEnv handle returned by DbEnv::open to be +free-threaded, that is, useable by multiple threads within a +single address space. +
+

On UNIX systems, or in IEEE/ANSI Std 1003.1 (POSIX) environments, all files created by Berkeley DB +are created with mode mode (as described in chmod(2)) and +modified by the process' umask value at the time of creation (see +umask(2)). The group ownership of created files is based on +the system and directory defaults, and is not further specified by Berkeley DB. +If mode is 0, files are created readable and writeable by both +owner and group. On Windows systems, the mode argument is ignored. +

The DbEnv::open method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Environment Variables

+

+

DB_HOME
The environment variable DB_HOME may be used as the path of +the database home as described in +Berkeley DB File Naming. +
+

Errors

+

The DbEnv::open method may fail and throw an exception or return a non-zero error for the following conditions: +

+

EAGAIN
The shared memory region was locked and (repeatedly) unavailable. +
+

+

EINVAL
An invalid flag value or parameter was specified. +

+The DB_THREAD flag was specified and spinlocks are not +implemented for this architecture. +

The DB_HOME or TMPDIR environment variables were set but empty. +

An incorrectly formatted NAME VALUE entry or line was found. +

+

+

ENOSPC
HP-UX only: a previously created Berkeley DB environment for this process still +exists. +
+

The DbEnv::open method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv::open method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Class

+DbEnv +

See Also

+DbEnv::close, +DbEnv::open, +DbEnv::remove, +DbEnv::err, +DbEnv::strerror, +DbEnv::version, +DbEnv::set_cachesize, +DbEnv::set_errcall, +DbEnv::set_errfile, +DbEnv::set_error_stream, +DbEnv::set_errpfx, +DbEnv::set_flags, +DbEnv::set_mutexlocks, +DbEnv::set_paniccall, +and +DbEnv::set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/env_remove.html b/db/docs/api_cxx/env_remove.html new file mode 100644 index 000000000..58c3ff5de --- /dev/null +++ b/db/docs/api_cxx/env_remove.html @@ -0,0 +1,129 @@ + + + + + +Berkeley DB: DbEnv::remove + + + + + + + +
+

DbEnv::remove

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::remove(const char *db_home, u_int32_t flags); +

+

Description

+

The DbEnv::remove method destroys a Berkeley DB environment, if it is not +currently in use. The environment regions, including any backing files, +are removed. Any log or database files and the environment directory are +not removed. +

The db_home argument to DbEnv::remove is described in +Berkeley DB File Naming. +

If there are processes that have called DbEnv::open without +calling DbEnv::close (i.e., there are processes currently using +the environment), DbEnv::remove will fail without further action, +unless the DB_FORCE flag is set, in which case +DbEnv::remove will attempt to remove the environment regardless +of any processes still using it. +

The result of attempting to forcibly destroy the environment when it is +in use is unspecified. Processes using an environment often maintain open +file descriptors for shared regions within it. On UNIX systems, the +environment removal will usually succeed and processes that have already +joined the region will continue to run in that region without change, +however processes attempting to join the environment will either fail or +create new regions. On other systems (e.g., Windows/NT), where the +unlink(2) system call will fail if any process has an open +file descriptor for the file, the region removal will fail. +

Calling DbEnv::remove should not be necessary for most applications, +as the Berkeley DB environment is cleaned up as part of normal database recovery +procedures, however, applications may wish to call DbEnv::remove +as part of application shutdown to free up system resources. +Specifically, when the DB_SYSTEM_MEM flag was specified to +DbEnv::open, it may be useful to call DbEnv::remove in order +to release system shared memory segments that have been allocated. +

In the case of catastrophic or system failure, database recovery must be +performed (see db_recover), or the DB_RECOVER and +DB_RECOVER_FATAL flags to DbEnv::open must be specified +when the environment is re-opened. Alternatively, if recovery is not +required because no database state is maintained across failures, and +the DB_SYSTEM_MEM flag was not specified when the environment +was created, it is possible to clean up an environment by removing all +of the files in the environment directory that begin with the string +prefix "__db", as no backing files are created in any other directory. +

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +

+

DB_FORCE
If the DB_FORCE flag is set, the environment is removed regardless +of any processes that may still using it, and, no locks are acquired +during this process. (Generally, the DB_FORCE flag is only +specified when applications were unable to shut down cleanly, and there +is a risk that an application may have died holding a Berkeley DB lock.) + +

DB_USE_ENVIRON
The Berkeley DB process' environment may be permitted to specify information to +be used when naming files; see Berkeley DB +File Naming. As permitting users to specify which files are used can +create security problems, environment information will be used in file +naming for all users only if the DB_USE_ENVIRON flag is set. +

DB_USE_ENVIRON_ROOT
The Berkeley DB process' environment may be permitted to specify information to +be used when naming files; see Berkeley DB +File Naming. As permitting users to specify which files are used can +create security problems, if the DB_USE_ENVIRON_ROOT flag is set, +environment information will be used for file naming only for users with +appropriate permissions (e.g., on UNIX systems, users with a user-ID of 0). +
+

In multi-threaded applications, only a single thread may call +DbEnv::remove. +

A DbEnv handle which has already been used to open an +environment should not be used to call the DbEnv::remove method, a new +DbEnv handle should be created for that purpose. +

Once DbEnv::remove has been called, regardless of its return, +the Berkeley DB environment handle may not be accessed again. +

The DbEnv::remove method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

+

EBUSY
The shared memory region was in use and the force flag was not set. +
+

The DbEnv::remove method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv::remove method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Class

+DbEnv +

See Also

+DbEnv::close, +DbEnv::open, +DbEnv::remove, +DbEnv::err, +DbEnv::strerror, +DbEnv::version, +DbEnv::set_cachesize, +DbEnv::set_errcall, +DbEnv::set_errfile, +DbEnv::set_error_stream, +DbEnv::set_errpfx, +DbEnv::set_flags, +DbEnv::set_mutexlocks, +DbEnv::set_paniccall, +and +DbEnv::set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/env_set_cachesize.html b/db/docs/api_cxx/env_set_cachesize.html new file mode 100644 index 000000000..57ad573cb --- /dev/null +++ b/db/docs/api_cxx/env_set_cachesize.html @@ -0,0 +1,89 @@ + + + + + + +Berkeley DB: DbEnv::set_cachesize + + + + + + + +
+

DbEnv::set_cachesize

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::set_cachesize(u_int32_t gbytes, u_int32_t bytes, int ncache); +

+

Description

+

Set the size of the database's shared memory buffer pool, i.e., the cache, +to gbytes gigabytes plus bytes. The cache should be the +size of the normal working data set of the application, with some small +amount of additional memory for unusual situations. (Note, the working +set is not the same as the number of simultaneously referenced pages, and +should be quite a bit larger!) +

The default cache size is 256KB, and may not be specified as less than +20KB. Any cache size less than 500MB is automatically increased by 25% +to account for buffer pool overhead, cache sizes larger than 500MB are +used as specified. For information on tuning the Berkeley DB cache size, see +Selecting a cache size. +

It is possible to specify caches to Berkeley DB that are large enough so that +they cannot be allocated contiguously on some architectures, e.g., some +releases of Solaris limit the amount of memory that may be allocated +contiguously by a process. If ncache is 0 or 1, the cache will +be allocated contiguously in memory. If it is greater than 1, the cache +will be broken up into ncache equally sized separate pieces of +memory. +

The DbEnv::set_cachesize interface may only be used to configure Berkeley DB before +the DbEnv::open interface is called. +

The DbEnv::set_cachesize method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

The database environment's cache size may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_cachesize", one or more whitespace characters, +and the three arguments specified to this interface, separated by whitespace +characters, for example, "set_cachesize 1 500 2". Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DbEnv::open was called. +

The specified cache size was impossibly small. +

+

Class

+DbEnv +

See Also

+DbEnv::close, +DbEnv::open, +DbEnv::remove, +DbEnv::err, +DbEnv::strerror, +DbEnv::version, +DbEnv::set_cachesize, +DbEnv::set_errcall, +DbEnv::set_errfile, +DbEnv::set_error_stream, +DbEnv::set_errpfx, +DbEnv::set_flags, +DbEnv::set_mutexlocks, +DbEnv::set_paniccall, +and +DbEnv::set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/env_set_data_dir.html b/db/docs/api_cxx/env_set_data_dir.html new file mode 100644 index 000000000..7c8bd44ff --- /dev/null +++ b/db/docs/api_cxx/env_set_data_dir.html @@ -0,0 +1,80 @@ + + + + + +Berkeley DB: DbEnv::set_data_dir + + + + + + + +
+

DbEnv::set_data_dir

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::set_data_dir(const char *dir); +

+

Description

+

Set the path of a directory to be used as the location of the access +method database files. Paths specified to the Db::open function +will be searched relative to this path. Paths set using this interface +are additive, and specifying more than one will result in each specified +directory being searched for database files. If any directories are +specified, created database files will always be created in the first path +specified. +

If no database directories are specified, database files can only exist +in the environment home directory. See Berkeley DB File Naming for more information. +

For the greatest degree of recoverability from system or application +failure, database files and log files should be located on separate +physical devices. +

The DbEnv::set_data_dir interface may only be used to configure Berkeley DB before +the DbEnv::open interface is called. +

The DbEnv::set_data_dir method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

The database environment's data directory may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_data_dir", one or more whitespace characters, +and the directory name. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DbEnv::open was called. +

+

Class

+DbEnv +

See Also

+DbEnv::close, +DbEnv::open, +DbEnv::remove, +DbEnv::err, +DbEnv::strerror, +DbEnv::version, +DbEnv::set_cachesize, +DbEnv::set_errcall, +DbEnv::set_errfile, +DbEnv::set_error_stream, +DbEnv::set_errpfx, +DbEnv::set_flags, +DbEnv::set_mutexlocks, +DbEnv::set_paniccall, +and +DbEnv::set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/env_set_errcall.html b/db/docs/api_cxx/env_set_errcall.html new file mode 100644 index 000000000..8c59632c6 --- /dev/null +++ b/db/docs/api_cxx/env_set_errcall.html @@ -0,0 +1,76 @@ + + + + + + +Berkeley DB: DbEnv::set_errcall + + + + + + + +
+

DbEnv::set_errcall

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+void DbEnv::set_errcall( + void (*db_errcall_fcn)(const char *errpfx, char *msg)); +

+

Description

+When an error occurs in the Berkeley DB library, an exception is thrown or an +error return value is returned by the method. In some cases, +however, the errno value may be insufficient to completely +describe the cause of the error, especially during initial application +debugging. +

The DbEnv::set_errcall method is used to enhance the mechanism for reporting error +messages to the application. In some cases, when an error occurs, Berkeley DB +will call db_errcall_fcn with additional error information. The +function must be defined with two arguments; the first will be the prefix +string (as previously set by Db::set_errpfx or +DbEnv::set_errpfx), the second will be the error message string. +It is up to the db_errcall_fcn method to display the error +message in an appropriate manner. +

Alternatively, you can use the DbEnv::set_error_stream method to display +the additional information via an output stream, or the Db::set_errfile +or DbEnv::set_errfile methods to display the additional information via a C +library FILE *. You should not mix these approaches. +

This error logging enhancement does not slow performance or significantly +increase application size, and may be run during normal operation as well +as during application debugging. +

The DbEnv::set_errcall interface may be used to configure Berkeley DB at any time +during the life of the application. +

Class

+DbEnv +

See Also

+DbEnv::close, +DbEnv::open, +DbEnv::remove, +DbEnv::err, +DbEnv::strerror, +DbEnv::version, +DbEnv::set_cachesize, +DbEnv::set_errcall, +DbEnv::set_errfile, +DbEnv::set_error_stream, +DbEnv::set_errpfx, +DbEnv::set_flags, +DbEnv::set_mutexlocks, +DbEnv::set_paniccall, +and +DbEnv::set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/env_set_errfile.html b/db/docs/api_cxx/env_set_errfile.html new file mode 100644 index 000000000..e9658cd18 --- /dev/null +++ b/db/docs/api_cxx/env_set_errfile.html @@ -0,0 +1,77 @@ + + + + + + +Berkeley DB: DbEnv::set_errfile + + + + + + + +
+

DbEnv::set_errfile

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+void DbEnv::set_errfile(FILE *errfile); +

+

Description

+When an error occurs in the Berkeley DB library, an exception is thrown or an +error return value is returned by the method. In some cases, +however, the errno value may be insufficient to completely +describe the cause of the error, especially during initial application +debugging. +

The DbEnv::set_errfile method is used to enhance the mechanism for reporting error +messages to the application by setting a C library FILE * to be used for +displaying additional Berkeley DB error messages. In some cases, when an error +occurs, Berkeley DB will output an additional error message to the specified +file reference. +

Alternatively, you can use the DbEnv::set_error_stream method to display +the additional information via an output stream, or the +DbEnv::set_errcall method to capture the additional error information in +a way that does not use either output streams or C library FILE *'s. You +should not mix these approaches. +

The error message will consist of the prefix string and a colon +(":") (if a prefix string was previously specified using +Db::set_errpfx or DbEnv::set_errpfx), an error string, and +a trailing <newline> character. +

This error logging enhancement does not slow performance or significantly +increase application size, and may be run during normal operation as well +as during application debugging. +

The DbEnv::set_errfile interface may be used to configure Berkeley DB at any time +during the life of the application. +

Class

+DbEnv +

See Also

+DbEnv::close, +DbEnv::open, +DbEnv::remove, +DbEnv::err, +DbEnv::strerror, +DbEnv::version, +DbEnv::set_cachesize, +DbEnv::set_errcall, +DbEnv::set_errfile, +DbEnv::set_error_stream, +DbEnv::set_errpfx, +DbEnv::set_flags, +DbEnv::set_mutexlocks, +DbEnv::set_paniccall, +and +DbEnv::set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/env_set_error_stream.html b/db/docs/api_cxx/env_set_error_stream.html new file mode 100644 index 000000000..18dc192cc --- /dev/null +++ b/db/docs/api_cxx/env_set_error_stream.html @@ -0,0 +1,74 @@ + + + + + +Berkeley DB: DbEnv::set_error_stream + + + + + + + +
+

DbEnv::set_error_stream

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+void DbEnv::set_error_stream(class ostream*); +

+

Description

+

When an error occurs in the Berkeley DB library, an exception is thrown or an +errno value is returned by the method. In some cases, +however, the errno value may be insufficient to completely +describe the cause of the error, especially during initial application +debugging. +

The DbEnv::set_error_stream method is used to enhance the mechanism for +reporting error messages to the application by setting the C++ ostream +used for displaying additional Berkeley DB error messages. In some cases, +when an error occurs, Berkeley DB will output an additional error message to +the specified stream. +

The error message will consist of the prefix string and a colon +(":") (if a prefix string was previously specified using +DbEnv::set_errpfx), an error string, and a trailing +<newline> character. +

Alternatively, you can use the DbEnv::set_errfile method to display +the additional information via a C library FILE *, or the +DbEnv::set_errcall method to capture the additional error information in +a way that does not use either output streams or C library FILE *'s. You +should not mix these approaches. +

This error logging enhancement does not slow performance or significantly +increase application size, and may be run during normal operation as well +as during application debugging. +

Class

+DbEnv +

See Also

+DbEnv::close, +DbEnv::open, +DbEnv::remove, +DbEnv::err, +DbEnv::strerror, +DbEnv::version, +DbEnv::set_cachesize, +DbEnv::set_errcall, +DbEnv::set_errfile, +DbEnv::set_error_stream, +DbEnv::set_errpfx, +DbEnv::set_flags, +DbEnv::set_mutexlocks, +DbEnv::set_paniccall, +and +DbEnv::set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/env_set_errpfx.html b/db/docs/api_cxx/env_set_errpfx.html new file mode 100644 index 000000000..62167d96e --- /dev/null +++ b/db/docs/api_cxx/env_set_errpfx.html @@ -0,0 +1,60 @@ + + + + + +Berkeley DB: DbEnv::set_errpfx + + + + + + + +
+

DbEnv::set_errpfx

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+void DbEnv::set_errpfx(const char *errpfx); +

+

Description

+

Set the prefix string that appears before error messages issued by Berkeley DB. +

The DbEnv::set_errpfx method does not copy the memory referenced by the +errpfx argument, rather, it maintains a reference to it. This +allows applications to modify the error message prefix at any time, +without repeatedly calling DbEnv::set_errpfx, but means that the +memory must be maintained until the handle is closed. +

The DbEnv::set_errpfx interface may be used to configure Berkeley DB at any time +during the life of the application. +

Class

+DbEnv +

See Also

+DbEnv::close, +DbEnv::open, +DbEnv::remove, +DbEnv::err, +DbEnv::strerror, +DbEnv::version, +DbEnv::set_cachesize, +DbEnv::set_errcall, +DbEnv::set_errfile, +DbEnv::set_error_stream, +DbEnv::set_errpfx, +DbEnv::set_flags, +DbEnv::set_mutexlocks, +DbEnv::set_paniccall, +and +DbEnv::set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/env_set_feedback.html b/db/docs/api_cxx/env_set_feedback.html new file mode 100644 index 000000000..147a5dc59 --- /dev/null +++ b/db/docs/api_cxx/env_set_feedback.html @@ -0,0 +1,72 @@ + + + + + +Berkeley DB: DbEnv::set_feedback + + + + + + + +
+

DbEnv::set_feedback

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::set_feedback( + void (*db_feedback_fcn)(DbEnv *, int opcode, int pct)); +

+

Description

+

Some operations performed by the Berkeley DB library can take non-trivial +amounts of time. The DbEnv::set_feedback method can be used by +applications to monitor progress within these operations. +

When an operation is likely to take a long time, Berkeley DB will call the +specified callback method. This method must be declared with +three arguments: the first will be a reference to the enclosing +environment, the second a flag value, and the third the percent of the +operation that has been completed, specified as an integer value between +0 and 100. It is up to the callback method to display this +information in an appropriate manner. +

The opcode argument may take on any of the following values: +

+

DB_RECOVER
The environment is being recovered. +
+

The DbEnv::set_feedback interface may be used to configure Berkeley DB at any time +during the life of the application. +

The DbEnv::set_feedback method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Class

+DbEnv +

See Also

+DbEnv::close, +DbEnv::open, +DbEnv::remove, +DbEnv::err, +DbEnv::strerror, +DbEnv::version, +DbEnv::set_cachesize, +DbEnv::set_errcall, +DbEnv::set_errfile, +DbEnv::set_error_stream, +DbEnv::set_errpfx, +DbEnv::set_flags, +DbEnv::set_mutexlocks, +DbEnv::set_paniccall, +and +DbEnv::set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/env_set_flags.html b/db/docs/api_cxx/env_set_flags.html new file mode 100644 index 000000000..ad8f4fc1c --- /dev/null +++ b/db/docs/api_cxx/env_set_flags.html @@ -0,0 +1,87 @@ + + + + + +Berkeley DB: DbEnv::set_flags + + + + + + + +
+

DbEnv::set_flags

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::set_flags(u_int32_t flags, int onoff); +

+

Description

+

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +If onoff is zero, the specified flags are cleared, otherwise they +are set. +

+

DB_CDB_ALLDB
For Berkeley DB Concurrent Data Store applications, perform locking on an environment-wide basis +rather than per-database. This flag may only be used to configure Berkeley DB +before the DbEnv::open interface is called. +

DB_NOMMAP
Copy read-only database files in this environment into the local cache +instead of potentially mapping them into process memory (see the +description of the DbEnv::set_mp_mmapsize method for further information). +

DB_TXN_NOSYNC
Do not synchronously flush the log on transaction commit or prepare. +This means that transactions exhibit the ACI (atomicity, consistency and +isolation) properties, but not D (durability), i.e., database integrity +will be maintained but it is possible that some number of the most +recently committed transactions may be undone during recovery instead of +being redone. +

The number of transactions that are potentially at risk is governed by +how often the log is checkpointed (see db_checkpoint for more +information) and how many log updates can fit on a single log page. +

+

The DbEnv::set_flags method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

The database environment's flag values may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_flags", one or more whitespace characters, +and the interface flag argument as a string, for example, "set_flags +DB_TXN_NOSYNC". Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

Class

+DbEnv +

See Also

+DbEnv::close, +DbEnv::open, +DbEnv::remove, +DbEnv::err, +DbEnv::strerror, +DbEnv::version, +DbEnv::set_cachesize, +DbEnv::set_errcall, +DbEnv::set_errfile, +DbEnv::set_error_stream, +DbEnv::set_errpfx, +DbEnv::set_flags, +DbEnv::set_mutexlocks, +DbEnv::set_paniccall, +and +DbEnv::set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/env_set_lg_bsize.html b/db/docs/api_cxx/env_set_lg_bsize.html new file mode 100644 index 000000000..fb9efecef --- /dev/null +++ b/db/docs/api_cxx/env_set_lg_bsize.html @@ -0,0 +1,71 @@ + + + + + +Berkeley DB: DbEnv::set_lg_bsize + + + + + + + +
+

DbEnv::set_lg_bsize

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::set_lg_bsize(u_int32_t lg_bsize); +

+

Description

+

Set the size of the in-memory log buffer, in bytes. By default, or if +the value is set to 0, a size of 32K is used. +

Log information is stored in-memory until the storage space fills up +or transaction commit forces the information to be flushed to stable +storage. In the presence of long-running transactions or transactions +producing large amounts of data, larger buffer sizes can increase +throughput. +

The DbEnv::set_lg_bsize interface may only be used to configure Berkeley DB before +the DbEnv::open interface is called. +

The DbEnv::set_lg_bsize method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

The database environment's log buffer size may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_lg_bsize", one or more whitespace characters, +and the size in bytes. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DbEnv::open was called. +

+

Class

+DbEnv +

See Also

+DbEnv::set_lg_bsize, +DbEnv::set_lg_max, +DbEnv::log_archive, +DbEnv::log_compare, +DbEnv::log_file, +DbEnv::log_flush, +DbEnv::log_get, +DbEnv::log_put, +DbEnv::log_register, +DbEnv::log_stat +and +DbEnv::log_unregister. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/env_set_lg_dir.html b/db/docs/api_cxx/env_set_lg_dir.html new file mode 100644 index 000000000..9a97eb3fe --- /dev/null +++ b/db/docs/api_cxx/env_set_lg_dir.html @@ -0,0 +1,76 @@ + + + + + +Berkeley DB: DbEnv::set_lg_dir + + + + + + + +
+

DbEnv::set_lg_dir

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::set_lg_dir(const char *dir); +

+

Description

+

The path of a directory to be used as the location of logging files. +Log files created by the Log Manager subsystem will be created in this +directory. +

If no logging directory is specified, log files are created in the +environment home directory. See Berkeley DB File Naming for more information. +

For the greatest degree of recoverability from system or application +failure, database files and log files should be located on separate +physical devices. +

The DbEnv::set_lg_dir interface may only be used to configure Berkeley DB before +the DbEnv::open interface is called. +

The DbEnv::set_lg_dir method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

The database environment's logging directory may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_lg_dir", one or more whitespace characters, +and the directory name. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DbEnv::open was called. +

+

Class

+DbEnv +

See Also

+DbEnv::close, +DbEnv::open, +DbEnv::remove, +DbEnv::err, +DbEnv::strerror, +DbEnv::version, +DbEnv::set_cachesize, +DbEnv::set_errcall, +DbEnv::set_errfile, +DbEnv::set_error_stream, +DbEnv::set_errpfx, +DbEnv::set_flags, +DbEnv::set_mutexlocks, +DbEnv::set_paniccall, +and +DbEnv::set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/env_set_lg_max.html b/db/docs/api_cxx/env_set_lg_max.html new file mode 100644 index 000000000..c0f27d19b --- /dev/null +++ b/db/docs/api_cxx/env_set_lg_max.html @@ -0,0 +1,71 @@ + + + + + +Berkeley DB: DbEnv::set_lg_max + + + + + + + +
+

DbEnv::set_lg_max

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::set_lg_max(u_int32_t lg_max); +

+

Description

+

Set the maximum size of a single file in the log, in bytes. Because +DbLsn file offsets are unsigned 4-byte values, the set value may +not be larger than the maximum unsigned 4-byte value. By default, or if +the value is set to 0, a size of 10MB is used. +

See Log File Limits +for more information. +

The DbEnv::set_lg_max interface may only be used to configure Berkeley DB before +the DbEnv::open interface is called. +

The DbEnv::set_lg_max method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

The database environment's log file size may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_lg_max", one or more whitespace characters, +and the size in bytes. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DbEnv::open was called. +

The specified log file size was too large. +

+

Class

+DbEnv +

See Also

+DbEnv::set_lg_bsize, +DbEnv::set_lg_max, +DbEnv::log_archive, +DbEnv::log_compare, +DbEnv::log_file, +DbEnv::log_flush, +DbEnv::log_get, +DbEnv::log_put, +DbEnv::log_register, +DbEnv::log_stat +and +DbEnv::log_unregister. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/env_set_lk_conflicts.html b/db/docs/api_cxx/env_set_lk_conflicts.html new file mode 100644 index 000000000..9ef5e8c78 --- /dev/null +++ b/db/docs/api_cxx/env_set_lk_conflicts.html @@ -0,0 +1,71 @@ + + + + + +Berkeley DB: DbEnv::set_lk_conflicts + + + + + + + +
+

DbEnv::set_lk_conflicts

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::set_lk_conflicts(u_int8_t *conflicts, int nmodes); +

+

Description

+

Set the locking conflicts matrix. +The conflicts argument +is an nmodes by nmodes array. +A non-0 value for the array element: +

conflicts[requested_mode][held_mode]
+

indicates that requested_mode and held_mode conflict. The +not-granted mode must be represented by 0. +

If no conflicts value is specified, the conflicts array +db_rw_conflicts is used; see Standard Lock Modes for a description of that array. +

The DbEnv::set_lk_conflicts interface may only be used to configure Berkeley DB before +the DbEnv::open interface is called. +

The DbEnv::set_lk_conflicts method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DbEnv::open was called. +

+

+

ENOMEM
No memory was available to copy the conflicts array. +
+

Classes

+DbEnv, DbLock +

See Also

+DbEnv::set_lk_conflicts, +DbEnv::set_lk_detect, +DbEnv::set_lk_max_locks, +DbEnv::set_lk_max_lockers, +DbEnv::set_lk_max_objects, +DbEnv::set_lk_max, +DbEnv::lock_detect, +DbEnv::lock_get, +DbEnv::lock_id, +DbLock::put, +DbEnv::lock_stat +and +DbEnv::lock_vec. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/env_set_lk_detect.html b/db/docs/api_cxx/env_set_lk_detect.html new file mode 100644 index 000000000..ee17ce2a4 --- /dev/null +++ b/db/docs/api_cxx/env_set_lk_detect.html @@ -0,0 +1,75 @@ + + + + + +Berkeley DB: DbEnv::set_lk_detect + + + + + + + +
+

DbEnv::set_lk_detect

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::set_lk_detect(u_int32_t detect); +

+

Description

+

Set if the deadlock detector is to be run whenever a lock conflict occurs, +and specify which transaction should be aborted in the case of a deadlock. +The specified value must be one of the following list: +

+

DB_LOCK_DEFAULT
Use the default policy as specified by db_deadlock. +
DB_LOCK_OLDEST
Abort the oldest transaction. +
DB_LOCK_RANDOM
Abort a random transaction involved in the deadlock. +
DB_LOCK_YOUNGEST
Abort the youngest transaction. +
+

The DbEnv::set_lk_detect interface may only be used to configure Berkeley DB before +the DbEnv::open interface is called. +

The DbEnv::set_lk_detect method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

The database environment's deadlock detector configuration may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_lk_detect", one or more whitespace characters, +and the interface detect argument as a string, for example, +"set_lk_detect DB_LOCK_OLDEST". Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DbEnv::open was called. +

+

Classes

+DbEnv, DbLock +

See Also

+DbEnv::set_lk_conflicts, +DbEnv::set_lk_detect, +DbEnv::set_lk_max_locks, +DbEnv::set_lk_max_lockers, +DbEnv::set_lk_max_objects, +DbEnv::set_lk_max, +DbEnv::lock_detect, +DbEnv::lock_get, +DbEnv::lock_id, +DbLock::put, +DbEnv::lock_stat +and +DbEnv::lock_vec. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/env_set_lk_max.html b/db/docs/api_cxx/env_set_lk_max.html new file mode 100644 index 000000000..7e614d4ac --- /dev/null +++ b/db/docs/api_cxx/env_set_lk_max.html @@ -0,0 +1,75 @@ + + + + + +Berkeley DB: DbEnv::set_lk_max + + + + + + + +
+

DbEnv::set_lk_max

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::set_lk_max(u_int32_t max); +

+

Description

+

The DbEnv::set_lk_max method interface has been deprecated in favor of +the DbEnv::set_lk_max_locks, DbEnv::set_lk_max_lockers, +and DbEnv::set_lk_max_objects methods. Please update your applications. +

Set each of the maximum number of locks, lockers and lock objects +supported by the Berkeley DB lock subsystem to max. This value is +used by DbEnv::open to estimate how much space to allocate for +various lock-table data structures. For specific information on +configuring the size of the lock subsystem, see +Configuring locking: sizing the +system. +

The DbEnv::set_lk_max interface may only be used to configure Berkeley DB before +the DbEnv::open interface is called. +

The DbEnv::set_lk_max method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

The database environment's maximum number of locks may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_lk_max", one or more whitespace characters, +and the number of locks. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DbEnv::open was called. +

+

Classes

+DbEnv, DbLock +

See Also

+DbEnv::set_lk_conflicts, +DbEnv::set_lk_detect, +DbEnv::set_lk_max_locks, +DbEnv::set_lk_max_lockers, +DbEnv::set_lk_max_objects, +DbEnv::set_lk_max, +DbEnv::lock_detect, +DbEnv::lock_get, +DbEnv::lock_id, +DbLock::put, +DbEnv::lock_stat +and +DbEnv::lock_vec. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/env_set_lk_max_lockers.html b/db/docs/api_cxx/env_set_lk_max_lockers.html new file mode 100644 index 000000000..9e84c0150 --- /dev/null +++ b/db/docs/api_cxx/env_set_lk_max_lockers.html @@ -0,0 +1,71 @@ + + + + + +Berkeley DB: DbEnv::set_lk_max_lockers + + + + + + + +
+

DbEnv::set_lk_max_lockers

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::set_lk_max_lockers(u_int32_t max); +

+

Description

+

Set the maximum number of simultaneous locking entities supported by +the Berkeley DB lock subsystem. This value is used by DbEnv::open to +estimate how much space to allocate for various lock-table data +structures. For specific information on configuring the size of the +lock subsystem, see +Configuring locking: sizing the system. +

The DbEnv::set_lk_max_lockers interface may only be used to configure Berkeley DB before +the DbEnv::open interface is called. +

The DbEnv::set_lk_max_lockers method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

The database environment's maximum number of lockers may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_lk_max_lockers", one or more whitespace characters, +and the number of lockers. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DbEnv::open was called. +

+

Classes

+DbEnv, DbLock +

See Also

+DbEnv::set_lk_conflicts, +DbEnv::set_lk_detect, +DbEnv::set_lk_max_locks, +DbEnv::set_lk_max_lockers, +DbEnv::set_lk_max_objects, +DbEnv::set_lk_max, +DbEnv::lock_detect, +DbEnv::lock_get, +DbEnv::lock_id, +DbLock::put, +DbEnv::lock_stat +and +DbEnv::lock_vec. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/env_set_lk_max_locks.html b/db/docs/api_cxx/env_set_lk_max_locks.html new file mode 100644 index 000000000..4e296e979 --- /dev/null +++ b/db/docs/api_cxx/env_set_lk_max_locks.html @@ -0,0 +1,70 @@ + + + + + +Berkeley DB: DbEnv::set_lk_max_locks + + + + + + + +
+

DbEnv::set_lk_max_locks

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::set_lk_max_locks(u_int32_t max); +

+

Description

+

Set the maximum number of locks supported by the Berkeley DB lock subsystem. +This value is used by DbEnv::open to estimate how much space to +allocate for various lock-table data structures. For specific +information on configuring the size of the lock subsystem, see +Configuring locking: sizing the system. +

The DbEnv::set_lk_max_locks interface may only be used to configure Berkeley DB before +the DbEnv::open interface is called. +

The DbEnv::set_lk_max_locks method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

The database environment's maximum number of locks may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_lk_max_locks", one or more whitespace characters, +and the number of locks. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DbEnv::open was called. +

+

Classes

+DbEnv, DbLock +

See Also

+DbEnv::set_lk_conflicts, +DbEnv::set_lk_detect, +DbEnv::set_lk_max_locks, +DbEnv::set_lk_max_lockers, +DbEnv::set_lk_max_objects, +DbEnv::set_lk_max, +DbEnv::lock_detect, +DbEnv::lock_get, +DbEnv::lock_id, +DbLock::put, +DbEnv::lock_stat +and +DbEnv::lock_vec. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/env_set_lk_max_objects.html b/db/docs/api_cxx/env_set_lk_max_objects.html new file mode 100644 index 000000000..b196cb925 --- /dev/null +++ b/db/docs/api_cxx/env_set_lk_max_objects.html @@ -0,0 +1,71 @@ + + + + + +Berkeley DB: DbEnv::set_lk_max_objects + + + + + + + +
+

DbEnv::set_lk_max_objects

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::set_lk_max_objects(u_int32_t max); +

+

Description

+

Set the maximum number of simultaneously locked objects supported by +the Berkeley DB lock subsystem. This value is used by DbEnv::open to +estimate how much space to allocate for various lock-table data +structures. For specific information on configuring the size of the +lock subsystem, see +Configuring locking: sizing the system. +

The DbEnv::set_lk_max_objects interface may only be used to configure Berkeley DB before +the DbEnv::open interface is called. +

The DbEnv::set_lk_max_objects method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

The database environment's maximum number of objects may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_lk_max_objects", one or more whitespace characters, +and the number of objects. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DbEnv::open was called. +

+

Classes

+DbEnv, DbLock +

See Also

+DbEnv::set_lk_conflicts, +DbEnv::set_lk_detect, +DbEnv::set_lk_max_locks, +DbEnv::set_lk_max_lockers, +DbEnv::set_lk_max_objects, +DbEnv::set_lk_max, +DbEnv::lock_detect, +DbEnv::lock_get, +DbEnv::lock_id, +DbLock::put, +DbEnv::lock_stat +and +DbEnv::lock_vec. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/env_set_mp_mmapsize.html b/db/docs/api_cxx/env_set_mp_mmapsize.html new file mode 100644 index 000000000..da7b3b5a6 --- /dev/null +++ b/db/docs/api_cxx/env_set_mp_mmapsize.html @@ -0,0 +1,74 @@ + + + + + +Berkeley DB: DbEnv::set_mp_mmapsize + + + + + + + +
+

DbEnv::set_mp_mmapsize

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::set_mp_mmapsize(size_t mp_mmapsize); +

+

Description

+

Files that are opened read-only in the pool (and that satisfy a few other +criteria) are, by default, mapped into the process address space instead +of being copied into the local cache. This can result in better-than-usual +performance, as available virtual memory is normally much larger than the +local cache, and page faults are faster than page copying on many systems. +However, in the presence of limited virtual memory it can cause resource +starvation, and in the presence of large databases, it can result in immense +process sizes. +

Set the maximum file size, in bytes, for a file to be mapped into the +process address space. If no value is specified, it defaults to 10MB. +

The DbEnv::set_mp_mmapsize interface may only be used to configure Berkeley DB before +the DbEnv::open interface is called. +

The DbEnv::set_mp_mmapsize method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

The database environment's maximum mapped file size may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_mp_mmapsize", one or more whitespace characters, +and the size in bytes. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DbEnv::open was called. +

+

Classes

+DbEnv, DbMpoolFile +

See Also

+DbEnv::set_mp_mmapsize, +DbMpoolFile::close, +DbMpoolFile::get, +DbMpoolFile::open, +DbMpoolFile::put, +DbMpoolFile::set, +DbMpoolFile::sync, +DbEnv::memp_register, +DbEnv::memp_stat, +DbEnv::memp_sync +and +DbEnv::memp_trickle. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/env_set_mutexlocks.html b/db/docs/api_cxx/env_set_mutexlocks.html new file mode 100644 index 000000000..b728927a2 --- /dev/null +++ b/db/docs/api_cxx/env_set_mutexlocks.html @@ -0,0 +1,62 @@ + + + + + +Berkeley DB: DbEnv::set_mutexlocks + + + + + + + +
+

DbEnv::set_mutexlocks

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::set_mutexlocks(int do_lock); +

+

Description

+

Toggle mutex locks. Setting do_lock to a zero value causes +Berkeley DB to grant all requested mutual exclusion mutexes without regard +for their availability. +

This functionality should never be used for any other purpose than +debugging. +

The DbEnv::set_mutexlocks interface may be used to configure Berkeley DB at any time +during the life of the application. +

The DbEnv::set_mutexlocks method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Class

+DbEnv +

See Also

+DbEnv::close, +DbEnv::open, +DbEnv::remove, +DbEnv::err, +DbEnv::strerror, +DbEnv::version, +DbEnv::set_cachesize, +DbEnv::set_errcall, +DbEnv::set_errfile, +DbEnv::set_error_stream, +DbEnv::set_errpfx, +DbEnv::set_flags, +DbEnv::set_mutexlocks, +DbEnv::set_paniccall, +and +DbEnv::set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/env_set_pageyield.html b/db/docs/api_cxx/env_set_pageyield.html new file mode 100644 index 000000000..01247edc5 --- /dev/null +++ b/db/docs/api_cxx/env_set_pageyield.html @@ -0,0 +1,71 @@ + + + + + +Berkeley DB: DbEnv::set_pageyield + + + + + + + +
+

DbEnv::set_pageyield

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+static int +DbEnv::set_pageyield(int pageyield); +

+

Description

+

Yield the processor whenever requesting a page from the cache. Setting +pageyield to a non-zero value causes Berkeley DB to yield the processor +any time a thread requests a page from the cache. +

The DbEnv::set_pageyield interface affects the entire application, not a single +database or database environment. +

While the DbEnv::set_pageyield interface may be used to configure Berkeley DB at any time +during the life of the application, it should normally be called before +making any calls to the db_env_create or db_create methods. +

This functionality should never be used for any other purpose than stress +testing. +

The DbEnv::set_pageyield interface may be used to configure Berkeley DB at any time +during the life of the application. +

The DbEnv::set_pageyield method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

Class

+DbEnv +

See Also

+DbEnv::close, +DbEnv::open, +DbEnv::remove, +DbEnv::err, +DbEnv::strerror, +DbEnv::version, +DbEnv::set_cachesize, +DbEnv::set_errcall, +DbEnv::set_errfile, +DbEnv::set_error_stream, +DbEnv::set_errpfx, +DbEnv::set_flags, +DbEnv::set_mutexlocks, +DbEnv::set_paniccall, +and +DbEnv::set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/env_set_paniccall.html b/db/docs/api_cxx/env_set_paniccall.html new file mode 100644 index 000000000..61950ad04 --- /dev/null +++ b/db/docs/api_cxx/env_set_paniccall.html @@ -0,0 +1,72 @@ + + + + + + +Berkeley DB: DbEnv::set_paniccall + + + + + + + +
+

DbEnv::set_paniccall

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::set_paniccall(void (*)(DbEnv *, int)); +

+

Description

+

Errors can occur in the Berkeley DB library where the only solution is to shut +down the application and run recovery. (For example, if Berkeley DB is unable +to write log records to disk because there is insufficient disk space.) +In these cases, when the C++ error model has been configured so that the +individual Berkeley DB methods return error codes (see DbException for +more information), the value DB_RUNRECOVERY is returned by Berkeley DB +methods. +

In these cases, it is also often simpler to shut down the application when +such errors occur rather than attempting to gracefully return up the stack. +The DbEnv::set_paniccall method is used to specify a method to be called when +DB_RUNRECOVERY is about to be returned from a Berkeley DB method. When +called, the dbenv argument will be a reference to the current +environment, and the errval argument is the error value that would +have been returned to the calling method. +

The DbEnv::set_paniccall interface may be used to configure Berkeley DB at any time +during the life of the application. +

The DbEnv::set_paniccall method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Class

+DbEnv +

See Also

+DbEnv::close, +DbEnv::open, +DbEnv::remove, +DbEnv::err, +DbEnv::strerror, +DbEnv::version, +DbEnv::set_cachesize, +DbEnv::set_errcall, +DbEnv::set_errfile, +DbEnv::set_error_stream, +DbEnv::set_errpfx, +DbEnv::set_flags, +DbEnv::set_mutexlocks, +DbEnv::set_paniccall, +and +DbEnv::set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/env_set_panicstate.html b/db/docs/api_cxx/env_set_panicstate.html new file mode 100644 index 000000000..6655003cc --- /dev/null +++ b/db/docs/api_cxx/env_set_panicstate.html @@ -0,0 +1,67 @@ + + + + + +Berkeley DB: DbEnv::set_panicstate + + + + + + + +
+

DbEnv::set_panicstate

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+static int +DbEnv::set_panicstate(int panic); +

+

Description

+

Toggle the Berkeley DB panic state. Setting panic to a non-zero value +causes Berkeley DB to refuse attempts to call Berkeley DB functions with the +DB_RUNRECOVERY error return. +

The DbEnv::set_panicstate interface affects the entire application, not a single +database or database environment. +

While the DbEnv::set_panicstate interface may be used to configure Berkeley DB at any time +during the life of the application, it should normally be called before +making any calls to the db_env_create or db_create methods. +

The DbEnv::set_panicstate method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

Class

+DbEnv +

See Also

+DbEnv::close, +DbEnv::open, +DbEnv::remove, +DbEnv::err, +DbEnv::strerror, +DbEnv::version, +DbEnv::set_cachesize, +DbEnv::set_errcall, +DbEnv::set_errfile, +DbEnv::set_error_stream, +DbEnv::set_errpfx, +DbEnv::set_flags, +DbEnv::set_mutexlocks, +DbEnv::set_paniccall, +and +DbEnv::set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/env_set_rec_init.html b/db/docs/api_cxx/env_set_rec_init.html new file mode 100644 index 000000000..96af59485 --- /dev/null +++ b/db/docs/api_cxx/env_set_rec_init.html @@ -0,0 +1,73 @@ + + + + + +Berkeley DB: DbEnv::set_recovery_init + + + + + + + +
+

DbEnv::set_recovery_init

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::set_recovery_init(int (*db_recovery_init_fcn)(DbEnv *)); +

+

Description

+

Applications installing application-specific recovery methods need +to be called before Berkeley DB performs recovery so they may add their recovery +methods to Berkeley DB's. +

The DbEnv::set_recovery_init method supports this functionality. The +db_recovery_init_fcn method must be declared with one +argument, a reference to the enclosing Berkeley DB environment. This +method will be called after the DbEnv::open has been called, +but before recovery is started. +

If the db_recovery_init_fcn method returns a non-zero value, +no recovery will be performed and DbEnv::open will return the same +value to its caller. +

The DbEnv::set_recovery_init interface may only be used to configure Berkeley DB before +the DbEnv::open interface is called. +

The DbEnv::set_recovery_init method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DbEnv::open was called. +

+

Class

+DbEnv +

See Also

+DbEnv::close, +DbEnv::open, +DbEnv::remove, +DbEnv::err, +DbEnv::strerror, +DbEnv::version, +DbEnv::set_cachesize, +DbEnv::set_errcall, +DbEnv::set_errfile, +DbEnv::set_error_stream, +DbEnv::set_errpfx, +DbEnv::set_flags, +DbEnv::set_mutexlocks, +DbEnv::set_paniccall, +and +DbEnv::set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/env_set_region_init.html b/db/docs/api_cxx/env_set_region_init.html new file mode 100644 index 000000000..f052adaf6 --- /dev/null +++ b/db/docs/api_cxx/env_set_region_init.html @@ -0,0 +1,80 @@ + + + + + +Berkeley DB: DbEnv::set_region_init + + + + + + + +
+

DbEnv::set_region_init

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+static int +DbEnv::set_region_init(int region_init); +

+

Description

+

Page-fault shared regions into memory when initially creating or joining +a Berkeley DB environment. In some applications, the expense of page-faulting +the shared memory regions can affect performance, e.g., when the +page-fault occurs while holding a lock, other lock requests can convoy +and overall throughput may decrease. Setting region_init to a +non-zero value specifies that shared regions be read or written, as +appropriate, when the region is joined by the application. This forces +the underlying virtual memory and file systems to instantiate both the +necessary memory and the necessary disk space. This can also avoid +out-of-disk space failures later on. +

The DbEnv::set_region_init interface affects the entire application, not a single +database or database environment. +

While the DbEnv::set_region_init interface may be used to configure Berkeley DB at any time +during the life of the application, it should normally be called before +making any calls to the db_env_create or db_create methods. +

The DbEnv::set_region_init method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

The database environment's initial behavior with respect to shared memory regions may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_region_init", one or more whitespace characters, +and the string "1". Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

Class

+DbEnv +

See Also

+DbEnv::close, +DbEnv::open, +DbEnv::remove, +DbEnv::err, +DbEnv::strerror, +DbEnv::version, +DbEnv::set_cachesize, +DbEnv::set_errcall, +DbEnv::set_errfile, +DbEnv::set_error_stream, +DbEnv::set_errpfx, +DbEnv::set_flags, +DbEnv::set_mutexlocks, +DbEnv::set_paniccall, +and +DbEnv::set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/env_set_server.html b/db/docs/api_cxx/env_set_server.html new file mode 100644 index 000000000..208c9cc9c --- /dev/null +++ b/db/docs/api_cxx/env_set_server.html @@ -0,0 +1,80 @@ + + + + + +Berkeley DB: DbEnv::set_server + + + + + + + +
+

DbEnv::set_server

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::set_server(char *host, + long cl_timeout, long sv_timeout, u_int32_t flags); +

+

Description

+

Connects to the DB server on the indicated hostname and sets up a channel +for communication. +

The cl_timeout argument specifies the number of seconds the client +should wait for results to come back from the server. Once the timeout +has expired on any communication with the server, DB_NOSERVER will +be returned. If this value is zero, a default timeout is used. +

The sv_timeout argument specifies the number of seconds the server +should allow a client connection to remain idle before assuming that +client is gone. Once that timeout has been reached, the server releases +all resources associated with that client connection. Subsequent attempts +by that client to communicate with the server result in +DB_NOSERVER_ID indicating that an invalid identifier has been +given to the server. This value can be considered a hint to the server. +The server may alter this value based on its own policies or allowed +values. If this value is zero, a default timeout is used. +

The flags parameter is currently unused, and must be set to 0. +

When the DbEnv::set_server method has been called, any subsequent calls +to Berkeley DB library interfaces may return either DB_NOSERVER or +DB_NOSERVER_ID. +

The DbEnv::set_server method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

dbenv_set_server +

+

Class

+DbEnv +

See Also

+DbEnv::close, +DbEnv::open, +DbEnv::remove, +DbEnv::err, +DbEnv::strerror, +DbEnv::version, +DbEnv::set_cachesize, +DbEnv::set_errcall, +DbEnv::set_errfile, +DbEnv::set_error_stream, +DbEnv::set_errpfx, +DbEnv::set_flags, +DbEnv::set_mutexlocks, +DbEnv::set_paniccall, +and +DbEnv::set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/env_set_shm_key.html b/db/docs/api_cxx/env_set_shm_key.html new file mode 100644 index 000000000..643bc1afd --- /dev/null +++ b/db/docs/api_cxx/env_set_shm_key.html @@ -0,0 +1,90 @@ + + + + + +Berkeley DB: DbEnv::set_shm_key + + + + + + + +
+

DbEnv::set_shm_key

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::set_shm_key(long shm_key); +

+

Description

+

Specify a base segment ID for Berkeley DB environment shared memory regions +created in system memory on VxWorks or systems supporting X/Open-style +shared memory interfaces, e.g., UNIX systems supporting +shmget(2) and related System V IPC interfaces. +

This base segment ID will be used when Berkeley DB shared memory regions are +first created. It will be incremented a small integer value each time +a new shared memory region is created, that is, if the base ID is 35, +the first shared memory region created will have a segment ID of 35 and +the next one a segment ID between 36 and 40 or so. A Berkeley DB environment +always creates a master shared memory region, plus an additional shared +memory region for each of the subsystems supported by the environment +(locking, logging, memory pool and transaction), plus an additional +shared memory region for each additional memory pool cache that is +supported. Already existing regions with the same segment IDs will be +removed. See Shared Memory Regions +for more information. +

The intent behind this interface is two-fold: without it, applications +have no way to ensure that two Berkeley DB applications don't attempt to use +the same segment IDs when creating different Berkeley DB environments. In +addition, by using the same segment IDs each time the environment is +created, previously created segments will be removed, and the set of +segments on the system will not grow without bound. +

The DbEnv::set_shm_key interface may only be used to configure Berkeley DB before +the DbEnv::open interface is called. +

The DbEnv::set_shm_key method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

The database environment's base segment ID may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_shm_key", one or more whitespace characters, +and the ID. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DbEnv::open was called. +

+

Class

+DbEnv +

See Also

+DbEnv::close, +DbEnv::open, +DbEnv::remove, +DbEnv::err, +DbEnv::strerror, +DbEnv::version, +DbEnv::set_cachesize, +DbEnv::set_errcall, +DbEnv::set_errfile, +DbEnv::set_error_stream, +DbEnv::set_errpfx, +DbEnv::set_flags, +DbEnv::set_mutexlocks, +DbEnv::set_paniccall, +and +DbEnv::set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/env_set_tas_spins.html b/db/docs/api_cxx/env_set_tas_spins.html new file mode 100644 index 000000000..fd21f03d3 --- /dev/null +++ b/db/docs/api_cxx/env_set_tas_spins.html @@ -0,0 +1,73 @@ + + + + + +Berkeley DB: DbEnv::set_tas_spins + + + + + + + +
+

DbEnv::set_tas_spins

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+static int +DbEnv::set_tas_spins(u_int32_t tas_spins); +

+

Description

+

Specify that test-and-set mutexes should spin tas_spins times +without blocking. The value defaults to 1 on uniprocessor systems and +to 50 times the number of processors on multiprocessor systems. +

The DbEnv::set_tas_spins interface affects the entire application, not a single +database or database environment. +

While the DbEnv::set_tas_spins interface may be used to configure Berkeley DB at any time +during the life of the application, it should normally be called before +making any calls to the db_env_create or db_create methods. +

The DbEnv::set_tas_spins method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

The database environment's test-and-set spin count may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_tas_spins", one or more whitespace characters, +and the number of spins. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

Class

+DbEnv +

See Also

+DbEnv::close, +DbEnv::open, +DbEnv::remove, +DbEnv::err, +DbEnv::strerror, +DbEnv::version, +DbEnv::set_cachesize, +DbEnv::set_errcall, +DbEnv::set_errfile, +DbEnv::set_error_stream, +DbEnv::set_errpfx, +DbEnv::set_flags, +DbEnv::set_mutexlocks, +DbEnv::set_paniccall, +and +DbEnv::set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/env_set_tmp_dir.html b/db/docs/api_cxx/env_set_tmp_dir.html new file mode 100644 index 000000000..5993fe8a8 --- /dev/null +++ b/db/docs/api_cxx/env_set_tmp_dir.html @@ -0,0 +1,92 @@ + + + + + +Berkeley DB: DbEnv::set_tmp_dir + + + + + + + +
+

DbEnv::set_tmp_dir

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::set_tmp_dir(const char *dir); +

+

Description

+

The path of a directory to be used as the location of temporary files. +The files created to back in-memory access method databases will be +created relative to this path. These temporary files can be quite large, +depending on the size of the database. +

If no directories are specified, the following alternatives are checked +in the specified order. The first existing directory path is used for +all temporary files. +

    +

  1. The value of the environment variable TMPDIR. +
  2. The value of the environment variable TEMP. +
  3. The value of the environment variable TMP. +
  4. The value of the environment variable TempFolder. +
  5. The value returned by the GetTempPath interface. +
  6. The directory /var/tmp. +
  7. The directory /usr/tmp. +
  8. The directory /temp. +
  9. The directory /tmp. +
  10. The directory C:/temp. +
  11. The directory C:/tmp. +
+

Note: environment variables are only checked if one of the +DB_USE_ENVIRON or DB_USE_ENVIRON_ROOT flags were +specified. +

Note: the GetTempPath interface is only checked on Win/32 platforms. +

The DbEnv::set_tmp_dir interface may only be used to configure Berkeley DB before +the DbEnv::open interface is called. +

The DbEnv::set_tmp_dir method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

The database environment's temporary file directory may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_tmp_dir", one or more whitespace characters, +and the directory name. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DbEnv::open was called. +

+

Class

+DbEnv +

See Also

+DbEnv::close, +DbEnv::open, +DbEnv::remove, +DbEnv::err, +DbEnv::strerror, +DbEnv::version, +DbEnv::set_cachesize, +DbEnv::set_errcall, +DbEnv::set_errfile, +DbEnv::set_error_stream, +DbEnv::set_errpfx, +DbEnv::set_flags, +DbEnv::set_mutexlocks, +DbEnv::set_paniccall, +and +DbEnv::set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/env_set_tx_max.html b/db/docs/api_cxx/env_set_tx_max.html new file mode 100644 index 000000000..918952894 --- /dev/null +++ b/db/docs/api_cxx/env_set_tx_max.html @@ -0,0 +1,70 @@ + + + + + +Berkeley DB: DbEnv::set_tx_max + + + + + + + +
+

DbEnv::set_tx_max

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::set_tx_max(u_int32_t tx_max); +

+

Description

+

Set the maximum number of active transactions that are supported by the +environment. This value bounds the size of backing shared memory regions. +Note that child transactions must be counted as active until their +ultimate parent commits or aborts. +

When there are more than the specified number of concurrent transactions, +calls to DbEnv::txn_begin will fail (until some active transactions +complete). If no value is specified, a default value of 20 is used. +

The DbEnv::set_tx_max interface may only be used to configure Berkeley DB before +the DbEnv::open interface is called. +

The DbEnv::set_tx_max method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

The database environment's maximum number of active transactions may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_tx_max", one or more whitespace characters, +and the number of transactions. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DbEnv::open was called. +

+

Classes

+DbEnv, DbTxn +

See Also

+DbEnv::set_tx_max, +DbEnv::set_tx_recover, +DbEnv::set_tx_timestamp, +DbTxn::abort, +DbEnv::txn_begin, +DbEnv::txn_checkpoint, +DbTxn::commit, +DbTxn::id, +DbTxn::prepare +and +DbEnv::txn_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/env_set_tx_recover.html b/db/docs/api_cxx/env_set_tx_recover.html new file mode 100644 index 000000000..08ceec64d --- /dev/null +++ b/db/docs/api_cxx/env_set_tx_recover.html @@ -0,0 +1,77 @@ + + + + + +Berkeley DB: DbEnv::set_tx_recover + + + + + + + +
+

DbEnv::set_tx_recover

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::set_tx_recover(int (*)(DbEnv *dbenv, + Dbt *log_rec, DbLsn *lsn, db_recops op)); +

+

Description

+

Set the application's method to be called during transaction abort +and recovery. This method must return 0 on success and either +errno or a value outside of the Berkeley DB error name space on +failure. It takes four arguments: +

+

dbenv
A Berkeley DB environment. +

log_rec
A log record. +

lsn
A log sequence number. +

op
One of the following values: +

+

DB_TXN_BACKWARD_ROLL
The log is being read backward to determine which transactions have been +committed and to abort those operations that were not, undo the operation +described by the log record. +

DB_TXN_FORWARD_ROLL
The log is being played forward, redo the operation described by the log +record. +

DB_TXN_ABORT
The log is being read backwards during a transaction abort, undo the +operation described by the log record. +
+
+

The DbEnv::set_tx_recover interface may only be used to configure Berkeley DB before +the DbEnv::open interface is called. +

The DbEnv::set_tx_recover method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DbEnv::open was called. +

+

Classes

+DbEnv, DbTxn +

See Also

+DbEnv::set_tx_max, +DbEnv::set_tx_recover, +DbEnv::set_tx_timestamp, +DbTxn::abort, +DbEnv::txn_begin, +DbEnv::txn_checkpoint, +DbTxn::commit, +DbTxn::id, +DbTxn::prepare +and +DbEnv::txn_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/env_set_tx_timestamp.html b/db/docs/api_cxx/env_set_tx_timestamp.html new file mode 100644 index 000000000..fa793324c --- /dev/null +++ b/db/docs/api_cxx/env_set_tx_timestamp.html @@ -0,0 +1,66 @@ + + + + + +Berkeley DB: DbEnv::set_tx_timestamp + + + + + + + +
+

DbEnv::set_tx_timestamp

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::set_tx_timestamp(time_t *timestamp); +

+

Description

+

Recover to the time specified by timestamp rather than to the most +current possible date. +The timestamp argument should be the number of seconds since 0 +hours, 0 minutes, 0 seconds, January 1, 1970, Coordinated Universal Time, +i.e., the Epoch. +

Once a database environment has been upgraded to a new version of Berkeley DB +involving a log format change (see Upgrading Berkeley DB installations, it is no longer possible to recover +to a specific time before that upgrade. +

The DbEnv::set_tx_timestamp interface may only be used to configure Berkeley DB before +the DbEnv::open interface is called. +

The DbEnv::set_tx_timestamp method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

It is not possible to recover to the specified time using the +log files currently present in the environment. +

+

Classes

+DbEnv, DbTxn +

See Also

+DbEnv::set_tx_max, +DbEnv::set_tx_recover, +DbEnv::set_tx_timestamp, +DbTxn::abort, +DbEnv::txn_begin, +DbEnv::txn_checkpoint, +DbTxn::commit, +DbTxn::id, +DbTxn::prepare +and +DbEnv::txn_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/env_set_verbose.html b/db/docs/api_cxx/env_set_verbose.html new file mode 100644 index 000000000..48b280964 --- /dev/null +++ b/db/docs/api_cxx/env_set_verbose.html @@ -0,0 +1,81 @@ + + + + + +Berkeley DB: DbEnv::set_verbose + + + + + + + +
+

DbEnv::set_verbose

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::set_verbose(u_int32_t which, int onoff); +

+

Description

+

The DbEnv::set_verbose method turns additional informational and +debugging messages in the Berkeley DB message output on and off. If +onoff is set to +non-zero, +the additional messages are output. +

The which parameter must be set to one of the following values: +

+

DB_VERB_CHKPOINT
Display checkpoint location information when searching the log for +checkpoints. +

DB_VERB_DEADLOCK
Display additional information when doing deadlock detection. +

DB_VERB_RECOVERY
Display additional information when performing recovery. +

DB_VERB_WAITSFOR
Display the waits-for table when doing deadlock detection. +
+

The DbEnv::set_verbose interface may be used to configure Berkeley DB at any time +during the life of the application. +

The DbEnv::set_verbose method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

The database environment's verbosity may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_verbose", one or more whitespace characters, +and the interface which argument as a string, for example, +"set_verbose DB_VERB_CHKPOINT". Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

Class

+DbEnv +

See Also

+DbEnv::close, +DbEnv::open, +DbEnv::remove, +DbEnv::err, +DbEnv::strerror, +DbEnv::version, +DbEnv::set_cachesize, +DbEnv::set_errcall, +DbEnv::set_errfile, +DbEnv::set_error_stream, +DbEnv::set_errpfx, +DbEnv::set_flags, +DbEnv::set_mutexlocks, +DbEnv::set_paniccall, +and +DbEnv::set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/env_strerror.html b/db/docs/api_cxx/env_strerror.html new file mode 100644 index 000000000..e1572018b --- /dev/null +++ b/db/docs/api_cxx/env_strerror.html @@ -0,0 +1,62 @@ + + + + + +Berkeley DB: DbEnv::strerror + + + + + + + +
+

DbEnv::strerror

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+static char * +DbEnv::strerror(int error); +

+

Description

+

The DbEnv::strerror method returns an error message string corresponding +to the error number error. This interface is a superset of the +ANSI C X3.159-1989 (ANSI C) strerror(3) interface. If the error number +error is greater than or equal to 0, then the string returned by +the system interface strerror(3) is returned. If the error +number is less than 0, an error string appropriate to the corresponding +Berkeley DB library error is returned. See +Error returns to applications +for more information. +

Class

+DbEnv +

See Also

+DbEnv::close, +DbEnv::open, +DbEnv::remove, +DbEnv::err, +DbEnv::strerror, +DbEnv::version, +DbEnv::set_cachesize, +DbEnv::set_errcall, +DbEnv::set_errfile, +DbEnv::set_error_stream, +DbEnv::set_errpfx, +DbEnv::set_flags, +DbEnv::set_mutexlocks, +DbEnv::set_paniccall, +and +DbEnv::set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/env_version.html b/db/docs/api_cxx/env_version.html new file mode 100644 index 000000000..8d40aa8c5 --- /dev/null +++ b/db/docs/api_cxx/env_version.html @@ -0,0 +1,59 @@ + + + + + +Berkeley DB: DbEnv::version + + + + + + + +
+

DbEnv::version

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+static char * +DbEnv::version(int *major, int *minor, int *patch); +

+

Description

+

The DbEnv::version method returns a pointer to a string containing Berkeley DB +version information. If major is non-NULL, the major version +of the Berkeley DB release is stored in the memory it references. If +minor is non-NULL, the minor version of the Berkeley DB release is +stored in the memory it references. If patch is non-NULL, the +patch version of the Berkeley DB release is stored in the memory it references. +

Class

+DbEnv +

See Also

+DbEnv::close, +DbEnv::open, +DbEnv::remove, +DbEnv::err, +DbEnv::strerror, +DbEnv::version, +DbEnv::set_cachesize, +DbEnv::set_errcall, +DbEnv::set_errfile, +DbEnv::set_error_stream, +DbEnv::set_errpfx, +DbEnv::set_flags, +DbEnv::set_mutexlocks, +DbEnv::set_paniccall, +and +DbEnv::set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/except_class.html b/db/docs/api_cxx/except_class.html new file mode 100644 index 000000000..063bede95 --- /dev/null +++ b/db/docs/api_cxx/except_class.html @@ -0,0 +1,64 @@ + + + + + +Berkeley DB: DbException + + + + + + + +
+

DbException

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+class DbException { + DbException(int err); + DbException(const char *description); + DbException(const char *prefix, int err); + DbException(const char *prefix1, const char *prefix2, int err); +}; +

+

Description

+

This manual page describes the DbException class and how it is used +by the various Berkeley DB classes. +

Most methods in the Berkeley DB classes return an int but also throw an +exception. This allows for two different error behaviors. By default, +the Berkeley DB C++ API is configured to throw an exception whenever a serious +error occurs. This generally allows for cleaner logic for transaction +processing, as a try block can surround a single transaction. +Alternatively, Berkeley DB can be configured to not throw exceptions, and +instead have the individual function return an error code, by setting +the constructor flags for the Db and DbEnv objects. +

A DbException object contains an informational string and an errno. +The errno can be obtained by using DbException::get_errno. +The informational string can be obtained by using DbException::what. +

We expect in the future that this class will inherit from the standard +class exception, but certain language implementation bugs currently +prevent this on some platforms. +

Some methods may return non-zero values without issuing an exception. +This occurs in situations that are not normally considered an error, but +when some informational status is returned. For example, Db::get +returns DB_NOTFOUND when a requested key does not appear in the database. +

Class

+DbException +

See Also

+DbException::get_errno +and +DbException::what. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/get_errno.html b/db/docs/api_cxx/get_errno.html new file mode 100644 index 000000000..25c639ac2 --- /dev/null +++ b/db/docs/api_cxx/get_errno.html @@ -0,0 +1,43 @@ + + + + + +Berkeley DB: DbException::get_errno + + + + + + + +
+

DbException::get_errno

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+const int +DbException::get_errno(); +

+

Description

+

A DbException object contains an informational string and an errno. +The errno can be obtained by using DbException::get_errno. +The informational string can be obtained by using DbException::what. +

Class

+DbException +

See Also

+DbException::get_errno +and +DbException::what. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/lock_class.html b/db/docs/api_cxx/lock_class.html new file mode 100644 index 000000000..c0aa324d9 --- /dev/null +++ b/db/docs/api_cxx/lock_class.html @@ -0,0 +1,61 @@ + + + + + +Berkeley DB: DbLock + + + + + + + +
+

DbLock

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+class DbLock { +public: + DbLock(); + DbLock(const DbLock &); + DbLock &operator = (const DbLock &); + ~DbLock(); +}; +

+

Description

+

The DbEnv lock methods and the DbLock class are used +to provide general-purpose locking. While designed to work with the +other Db classes, they are also useful for more general locking +purposes. Locks can be shared between processes. +

In most cases, when multiple threads or processes are using locking, the +deadlock detector, db_deadlock should be run. +

Classes

+DbEnv, DbLock +

See Also

+DbEnv::set_lk_conflicts, +DbEnv::set_lk_detect, +DbEnv::set_lk_max_locks, +DbEnv::set_lk_max_lockers, +DbEnv::set_lk_max_objects, +DbEnv::set_lk_max, +DbEnv::lock_detect, +DbEnv::lock_get, +DbEnv::lock_id, +DbLock::put, +DbEnv::lock_stat +and +DbEnv::lock_vec. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/lock_detect.html b/db/docs/api_cxx/lock_detect.html new file mode 100644 index 000000000..889d0f520 --- /dev/null +++ b/db/docs/api_cxx/lock_detect.html @@ -0,0 +1,73 @@ + + + + + +Berkeley DB: DbEnv::lock_detect + + + + + + + +
+

DbEnv::lock_detect

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::lock_detect(u_int32_t flags, u_int32_t atype, int *aborted); +

+

Description

+

The DbEnv::lock_detect method runs one iteration of the deadlock detector. +The deadlock detector traverses the lock table, and for each deadlock +it finds, marks one of the participating transactions for abort. +

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +

+

DB_LOCK_CONFLICT
Only run the deadlock detector if a lock conflict has occurred since +the last time that the deadlock detector was run. +
+

The atype parameter specifies which transaction to abort in the +case of deadlock. It must be set to one of possible arguments listed for +the DbEnv::set_lk_detect interface. +

If the aborted parameter is non-NULL, the memory location it +references will be set to the number of transactions aborted by the +DbEnv::lock_detect method. +

The DbEnv::lock_detect method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The DbEnv::lock_detect method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv::lock_detect method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Classes

+DbEnv, DbLock +

See Also

+DbEnv::set_lk_conflicts, +DbEnv::set_lk_detect, +DbEnv::set_lk_max_locks, +DbEnv::set_lk_max_lockers, +DbEnv::set_lk_max_objects, +DbEnv::set_lk_max, +DbEnv::lock_detect, +DbEnv::lock_get, +DbEnv::lock_id, +DbLock::put, +DbEnv::lock_stat +and +DbEnv::lock_vec. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/lock_get.html b/db/docs/api_cxx/lock_get.html new file mode 100644 index 000000000..4dae9f5dc --- /dev/null +++ b/db/docs/api_cxx/lock_get.html @@ -0,0 +1,94 @@ + + + + + +Berkeley DB: DbEnv::lock_get + + + + + + + +
+

DbEnv::lock_get

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::lock_get(u_int32_t locker, u_int32_t flags, + const Dbt *obj, const db_lockmode_t lock_mode, DbLock *lock); +

+

Description

+

The DbEnv::lock_get method acquires a lock from the lock table, returning +information about it in +the lock argument. +

The locker argument specified to DbEnv::lock_get is an unsigned +32-bit integer quantity. It represents the entity requesting or releasing +the lock. +

The flags value must be set to 0 or the following value: +

+

DB_LOCK_NOWAIT
If a lock cannot be granted because the requested lock conflicts with an +existing lock, return immediately instead of waiting for the lock to +become available. +
+

The obj argument is an untyped byte string that specifies the +object to be locked or released. +

The mode argument is an index into the environment's lock conflict +array. See DbEnv::set_lk_conflicts and +Standard Lock Modes +for a description of that array. +

The DbEnv::lock_get method may +return or throw an exception encapsulating +one of the following values: +

+

DB_LOCK_NOTGRANTED
A lock was requested that could not be immediately granted and the +flags parameter was set to DB_LOCK_NOWAIT. +
+

Otherwise, the DbEnv::lock_get method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The DbEnv::lock_get method may fail and throw an exception or return a non-zero error for the following conditions: +

+

DB_LOCK_DEADLOCK
The operation was selected to resolve a deadlock. +
+

+

EINVAL
An invalid flag value or parameter was specified. +
+

+

ENOMEM
The maximum number of locks has been reached. +
+

The DbEnv::lock_get method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv::lock_get method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Classes

+DbEnv, DbLock +

See Also

+DbEnv::set_lk_conflicts, +DbEnv::set_lk_detect, +DbEnv::set_lk_max_locks, +DbEnv::set_lk_max_lockers, +DbEnv::set_lk_max_objects, +DbEnv::set_lk_max, +DbEnv::lock_detect, +DbEnv::lock_get, +DbEnv::lock_id, +DbLock::put, +DbEnv::lock_stat +and +DbEnv::lock_vec. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/lock_id.html b/db/docs/api_cxx/lock_id.html new file mode 100644 index 000000000..72ab2a274 --- /dev/null +++ b/db/docs/api_cxx/lock_id.html @@ -0,0 +1,61 @@ + + + + + +Berkeley DB: DbEnv::lock_id + + + + + + + +
+

DbEnv::lock_id

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::lock_id(u_int32_t *idp); +

+

Description

+

The DbEnv::lock_id method +copies a locker ID, which is guaranteed to be unique in the specified lock +table, into the memory location referenced by idp. +

The DbEnv::lock_id method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The DbEnv::lock_id method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv::lock_id method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Classes

+DbEnv, DbLock +

See Also

+DbEnv::set_lk_conflicts, +DbEnv::set_lk_detect, +DbEnv::set_lk_max_locks, +DbEnv::set_lk_max_lockers, +DbEnv::set_lk_max_objects, +DbEnv::set_lk_max, +DbEnv::lock_detect, +DbEnv::lock_get, +DbEnv::lock_id, +DbLock::put, +DbEnv::lock_stat +and +DbEnv::lock_vec. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/lock_put.html b/db/docs/api_cxx/lock_put.html new file mode 100644 index 000000000..2875e4cfe --- /dev/null +++ b/db/docs/api_cxx/lock_put.html @@ -0,0 +1,63 @@ + + + + + +Berkeley DB: DbLock::put + + + + + + + +
+

DbLock::put

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbLock::put(DbEnv *env); +

+

Description

+

The DbLock::put method releases lock from the lock table. +

The DbLock::put method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The DbLock::put method may fail and throw an exception or return a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +
+

The DbLock::put method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbLock::put method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Classes

+DbEnv, DbLock +

See Also

+DbEnv::set_lk_conflicts, +DbEnv::set_lk_detect, +DbEnv::set_lk_max_locks, +DbEnv::set_lk_max_lockers, +DbEnv::set_lk_max_objects, +DbEnv::set_lk_max, +DbEnv::lock_detect, +DbEnv::lock_get, +DbEnv::lock_id, +DbLock::put, +DbEnv::lock_stat +and +DbEnv::lock_vec. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/lock_stat.html b/db/docs/api_cxx/lock_stat.html new file mode 100644 index 000000000..87bdc9d75 --- /dev/null +++ b/db/docs/api_cxx/lock_stat.html @@ -0,0 +1,98 @@ + + + + + +Berkeley DB: DbEnv::lock_stat + + + + + + + +
+

DbEnv::lock_stat

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+extern "C" { + typedef void *(*db_malloc_fcn_type)(size_t); +}; +int +DbEnv::lock_stat(DB_LOCK_STAT **statp, db_malloc_fcn_type db_malloc); +

+

Description

+

The DbEnv::lock_stat method +creates a statistical structure and copies a pointer to it into a +user-specified memory location. +

Statistical structures are created in allocated memory. If db_malloc is non-NULL, it +is called to allocate the memory, otherwise, the library function +malloc(3) is used. The function db_malloc must match +the calling conventions of the malloc(3) library routine. +Regardless, the caller is responsible for deallocating the returned +memory. To deallocate returned memory, free the returned memory +reference, references inside the returned memory do not need to be +individually freed. +

The lock region statistics are stored in a structure of type +DB_LOCK_STAT. The following DB_LOCK_STAT fields will be filled in: +

+
u_int32_t st_lastid;
The last allocated lock ID. +
u_int32_t st_nmodes;
The number of lock modes. +
u_int32_t st_maxlocks;
The maximum number of locks possible. +
u_int32_t st_maxlockers;
The maximum number of lockers possible. +
u_int32_t st_maxobjects;
The maximum number of objects possible. +
u_int32_t st_nlocks;
The number of current locks. +
u_int32_t st_maxnlocks;
The maximum number of locks at any one time. +
u_int32_t st_nlockers;
The number of current lockers. +
u_int32_t st_maxnlockers;
The maximum number of lockers at any one time. +
u_int32_t st_nobjects;
The number of current objects. +
u_int32_t st_maxnobjects;
The maximum number of objects at any one time. +
u_int32_t st_nrequests;
The total number of locks requested. +
u_int32_t st_nreleases;
The total number of locks released. +
u_int32_t st_nnowaits;
The total number of lock requests that failed because +DB_LOCK_NOWAIT was set. +
u_int32_t st_nconflicts;
The total number of locks not immediately available due to conflicts. +
u_int32_t st_ndeadlocks;
The number of deadlocks detected. +
u_int32_t st_regsize;
The size of the region. +
u_int32_t st_region_wait;
The number of times that a thread of control was forced to wait before +obtaining the region lock. +
u_int32_t st_region_nowait;
The number of times that a thread of control was able to obtain +the region lock without waiting. +
+

The DbEnv::lock_stat method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The DbEnv::lock_stat method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv::lock_stat method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Classes

+DbEnv, DbLock +

See Also

+DbEnv::set_lk_conflicts, +DbEnv::set_lk_detect, +DbEnv::set_lk_max_locks, +DbEnv::set_lk_max_lockers, +DbEnv::set_lk_max_objects, +DbEnv::set_lk_max, +DbEnv::lock_detect, +DbEnv::lock_get, +DbEnv::lock_id, +DbLock::put, +DbEnv::lock_stat +and +DbEnv::lock_vec. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/lock_vec.html b/db/docs/api_cxx/lock_vec.html new file mode 100644 index 000000000..46180f2ce --- /dev/null +++ b/db/docs/api_cxx/lock_vec.html @@ -0,0 +1,127 @@ + + + + + +Berkeley DB: DbEnv::lock_vec + + + + + + + +
+

DbEnv::lock_vec

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::lock_vec(u_int32_t locker, u_int32_t flags, + DB_LOCKREQ list[], int nlist, DB_LOCKREQ **elistp); +

+

Description

+

The DbEnv::lock_vec method atomically obtains and releases one or more locks +from the lock table. The DbEnv::lock_vec method is intended to support +acquisition or trading of multiple locks under one lock table semaphore, +as is needed for lock coupling or in multigranularity locking for lock +escalation. +

The locker argument specified to DbEnv::lock_vec is an unsigned +32-bit integer quantity. It represents the entity requesting or releasing +the lock. +

The flags value must be set to 0 or the following value: +

+

DB_LOCK_NOWAIT
If a lock cannot be immediately granted because the requested lock +conflicts with an existing lock, return instead of waiting for the lock +to become available. +
+

The list array provided to DbEnv::lock_vec is typedef'd as +DB_LOCKREQ. A DB_LOCKREQ structure has at least the following fields, +which must be initialized before calling DbEnv::lock_vec: +

+

lockop_t op;
The operation to be performed, which must be set to one of the +following values: +

+

DB_LOCK_GET
Get a lock, as defined by the values of locker, obj, +and mode. Upon return from DbEnv::lock_vec, if the +lock field is non-NULL, a reference to the acquired lock is +stored there. (This reference is invalidated by any call to +DbEnv::lock_vec or DbLock::put that releases the lock.) +

DB_LOCK_PUT
The lock referenced by the contents of the lock field is released. +

DB_LOCK_PUT_ALL
All locks held by the locker are released. (Any locks acquired +as a part of the current call to DbEnv::lock_vec that appear after the +DB_LOCK_PUT_ALL entry are not considered for this +operation). +

DB_LOCK_PUT_OBJ
All locks held on the object obj are released. The mode +and locker parameters are ignored. Note that any locks acquired +as a part of the current call to DbEnv::lock_vec that occur before the +DB_LOCK_PUT_OBJ will also be released; those acquired afterwards +will not be released. +
+

const Dbt obj;
An untyped byte string that specifies the object to be locked or released. +

const lockmode_t mode;
The lock mode, used as an index into the environment's lock conflict array. +See DbEnv::set_lk_conflicts and Standard Lock Modes for a description of that array. +

DB_LOCK lock;
A lock reference. +
+

The nlist argument specifies the number of elements in the +list array. +

If any of the requested locks cannot be acquired, or any of the locks to +be released cannot be released, the operations before the failing +operation are guaranteed to have completed successfully, and +DbEnv::lock_vec returns a non-zero value. In addition, if elistp +is not NULL, it is set to point to the DB_LOCKREQ entry that was being +processed when the error occurred. +

The DbEnv::lock_vec method may +return or throw an exception encapsulating +one of the following values: +

+

DB_LOCK_NOTGRANTED
A lock was requested that could not be immediately granted and the +flag parameter was set to DB_LOCK_NOWAIT. In this case, if +non-NULL, elistp identifies the request that was not granted. +
+

Otherwise, the DbEnv::lock_vec method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The DbEnv::lock_vec method may fail and throw an exception or return a non-zero error for the following conditions: +

+

DB_LOCK_DEADLOCK
The operation was selected to resolve a deadlock. +
+

+

EINVAL
An invalid flag value or parameter was specified. +
+

+

ENOMEM
The maximum number of locks has been reached. +
+

The DbEnv::lock_vec method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv::lock_vec method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Classes

+DbEnv, DbLock +

See Also

+DbEnv::set_lk_conflicts, +DbEnv::set_lk_detect, +DbEnv::set_lk_max_locks, +DbEnv::set_lk_max_lockers, +DbEnv::set_lk_max_objects, +DbEnv::set_lk_max, +DbEnv::lock_detect, +DbEnv::lock_get, +DbEnv::lock_id, +DbLock::put, +DbEnv::lock_stat +and +DbEnv::lock_vec. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/log_archive.html b/db/docs/api_cxx/log_archive.html new file mode 100644 index 000000000..e5436431a --- /dev/null +++ b/db/docs/api_cxx/log_archive.html @@ -0,0 +1,106 @@ + + + + + +Berkeley DB: DbEnv::log_archive + + + + + + + +
+

DbEnv::log_archive

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+extern "C" { + typedef void *(*db_malloc_fcn_type)(size_t); +}; +int +DbEnv::log_archive(char *(*listp)[], + u_int32_t flags, db_malloc_fcn_type db_malloc); +

+

Description

+

The DbEnv::log_archive method +creates a NULL-terminated array of log or database file names and copies +a pointer to them into the user-specified memory location listp. +

By default, DbEnv::log_archive returns the names of all of the log files +that are no longer in use (e.g., no longer involved in active transactions), +and that may safely be archived for catastrophic recovery and then removed +from the system. If there were no file names to return, the memory location +referenced by listp will be set to NULL. +

Arrays of log file names are created in allocated memory. If db_malloc is non-NULL, it +is called to allocate the memory, otherwise, the library function +malloc(3) is used. The function db_malloc must match +the calling conventions of the malloc(3) library routine. +Regardless, the caller is responsible for deallocating the returned +memory. To deallocate returned memory, free the returned memory +reference, references inside the returned memory do not need to be +individually freed. +

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +

+

DB_ARCH_ABS
All pathnames are returned as absolute pathnames, +instead of relative to the database home directory. +

DB_ARCH_DATA
Return the database files that need to be archived in order to recover +the database from catastrophic failure. If any of the database files +have not been accessed during the lifetime of the current log files, +DbEnv::log_archive will not include them in this list. It is also +possible that some of the files referenced in the log have since been +deleted from the system. +

DB_ARCH_LOG
Return all the log file names regardless of whether or not they are in +use. +
+

The DB_ARCH_DATA and DB_ARCH_LOG flags are mutually +exclusive. +

See the db_archive manual page for more information on database +archival procedures. +

The DbEnv::log_archive method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Bugs

+

In a threaded application (i.e., one where the environment was created +with the DB_THREAD flag specified), calling DbEnv::log_archive with the +DB_ARCH_DATA flag will fail, returning EINVAL. To work around this +problem, re-open the log explicitly without specifying DB_THREAD. This +restriction is expected to be removed in a future version of Berkeley DB. +

Errors

+

The DbEnv::log_archive method may fail and throw an exception or return a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +

The log was corrupted. +

+

The DbEnv::log_archive method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv::log_archive method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Class

+DbEnv +

See Also

+DbEnv::set_lg_bsize, +DbEnv::set_lg_max, +DbEnv::log_archive, +DbEnv::log_compare, +DbEnv::log_file, +DbEnv::log_flush, +DbEnv::log_get, +DbEnv::log_put, +DbEnv::log_register, +DbEnv::log_stat +and +DbEnv::log_unregister. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/log_compare.html b/db/docs/api_cxx/log_compare.html new file mode 100644 index 000000000..7d1b7ebb9 --- /dev/null +++ b/db/docs/api_cxx/log_compare.html @@ -0,0 +1,53 @@ + + + + + +Berkeley DB: DbEnv::log_compare + + + + + + + +
+

DbEnv::log_compare

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+static int +DbEnv::log_compare(const DbLsn *lsn0, const DbLsn *lsn1); +

+

Description

+

The DbEnv::log_compare method allows the caller to compare two +DbLsn objects, +returning 0 if they are equal, 1 if lsn0 is greater than +lsn1, and -1 if lsn0 is less than lsn1. +

Class

+DbEnv +

See Also

+DbEnv::set_lg_bsize, +DbEnv::set_lg_max, +DbEnv::log_archive, +DbEnv::log_compare, +DbEnv::log_file, +DbEnv::log_flush, +DbEnv::log_get, +DbEnv::log_put, +DbEnv::log_register, +DbEnv::log_stat +and +DbEnv::log_unregister. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/log_file.html b/db/docs/api_cxx/log_file.html new file mode 100644 index 000000000..fa0ed4e53 --- /dev/null +++ b/db/docs/api_cxx/log_file.html @@ -0,0 +1,79 @@ + + + + + +Berkeley DB: DbEnv::log_file + + + + + + + +
+

DbEnv::log_file

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::log_file(const DbLsn *lsn, char *namep, size_t len); +

+

Description

+

The DbEnv::log_file method maps +DbLsn objects +to file names, +copying the name of the file containing the record named by lsn +into the memory location referenced by namep. +

The len argument is the length of the namep buffer in bytes. +If namep is too short to hold the file name, DbEnv::log_file will +return ENOMEM. +(Log file names are normally quite short, on the order of 10 characters.) +

This mapping of +DbLsn objects +to files is needed for database administration. For example, a +transaction manager typically records the earliest +DbLsn +needed for restart, and the database administrator may want to archive +log files to tape when they contain only +DbLsn +entries before the earliest one needed for restart. +

The DbEnv::log_file method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The DbEnv::log_file method may fail and throw an exception or return a non-zero error for the following conditions: +

+

ENOMEM
The supplied buffer was too small to hold the log file name. +
+

The DbEnv::log_file method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv::log_file method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Class

+DbEnv +

See Also

+DbEnv::set_lg_bsize, +DbEnv::set_lg_max, +DbEnv::log_archive, +DbEnv::log_compare, +DbEnv::log_file, +DbEnv::log_flush, +DbEnv::log_get, +DbEnv::log_put, +DbEnv::log_register, +DbEnv::log_stat +and +DbEnv::log_unregister. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/log_flush.html b/db/docs/api_cxx/log_flush.html new file mode 100644 index 000000000..ecb13b9c0 --- /dev/null +++ b/db/docs/api_cxx/log_flush.html @@ -0,0 +1,66 @@ + + + + + +Berkeley DB: DbEnv::log_flush + + + + + + + +
+

DbEnv::log_flush

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::log_flush(const DbLsn *lsn); +

+

Description

+

The DbEnv::log_flush method guarantees that all log records whose +DbLsn values +are less than or equal to the lsn argument have been +written to disk. If lsn is NULL, all records in the +log are flushed. +

The DbEnv::log_flush method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The DbEnv::log_flush method may fail and throw an exception or return a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +
+

The DbEnv::log_flush method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv::log_flush method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Class

+DbEnv +

See Also

+DbEnv::set_lg_bsize, +DbEnv::set_lg_max, +DbEnv::log_archive, +DbEnv::log_compare, +DbEnv::log_file, +DbEnv::log_flush, +DbEnv::log_get, +DbEnv::log_put, +DbEnv::log_register, +DbEnv::log_stat +and +DbEnv::log_unregister. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/log_get.html b/db/docs/api_cxx/log_get.html new file mode 100644 index 000000000..37a8c497b --- /dev/null +++ b/db/docs/api_cxx/log_get.html @@ -0,0 +1,118 @@ + + + + + +Berkeley DB: DbEnv::log_get + + + + + + + +
+

DbEnv::log_get

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::log_get(DbLsn *lsn, Dbt *data, u_int32_t flags); +

+

Description

+

The DbEnv::log_get method implements a cursor inside of the log, +retrieving records from the log according to the lsn and +flags arguments. +

The data field of the data structure is set to the record +retrieved and the size field indicates the number of bytes in the record. +See Dbt for a description of other fields in the data +structure. When multiple threads are using the returned log handle +concurrently, one of the DB_DBT_MALLOC, DB_DBT_REALLOC or +DB_DBT_USERMEM flags must be specified for any Dbt used +for data retrieval. +

The flags argument must be set to exactly one of the following values: +

+

DB_CHECKPOINT
The last record written with the DB_CHECKPOINT flag specified to the +DbEnv::log_put method is returned in the data argument. The +lsn argument is overwritten with the DbLsn of the record +returned. If no record has been previously written with the DB_CHECKPOINT +flag specified, the first record in the log is returned. +

If the log is empty, the DbEnv::log_get method will return DB_NOTFOUND. +

DB_FIRST
The first record from any of the log files found in the log directory +is returned in the data argument. +The lsn argument is overwritten with the DbLsn of the +record returned. +

If the log is empty, the DbEnv::log_get method will return DB_NOTFOUND. +

DB_LAST
The last record in the log is returned in the data argument. +The lsn argument is overwritten with the DbLsn of the +record returned. +

If the log is empty, the DbEnv::log_get method will return DB_NOTFOUND. +

DB_NEXT
The current log position is advanced to the next record in the log and that +record is returned in the data argument. +The lsn argument is overwritten with the DbLsn of the +record returned. +

If the pointer has not been initialized via DB_FIRST, DB_LAST, DB_SET, +DB_NEXT, or DB_PREV, DbEnv::log_get will return the first record in the log. +If the last log record has already been returned or the log is empty, the +DbEnv::log_get method will return DB_NOTFOUND. +

If the log was opened with the DB_THREAD flag set, calls to +DbEnv::log_get with the DB_NEXT flag set will return EINVAL. +

DB_PREV
The current log position is moved to the previous record in the log and that +record is returned in the data argument. +The lsn argument is overwritten with the DbLsn of the +record returned. +

If the pointer has not been initialized via DB_FIRST, DB_LAST, DB_SET, +DB_NEXT, or DB_PREV, +DbEnv::log_get will return the last record in the log. +If the first log record has already been returned or the log is empty, the +DbEnv::log_get method will return DB_NOTFOUND. +

If the log was opened with the DB_THREAD flag set, calls to +DbEnv::log_get with the DB_PREV flag set will return EINVAL. +

DB_CURRENT
Return the log record currently referenced by the log. +

If the log pointer has not been initialized via DB_FIRST, DB_LAST, DB_SET, +DB_NEXT, or DB_PREV, or if the log was opened with the DB_THREAD flag set, +DbEnv::log_get will return EINVAL. +

DB_SET
Retrieve the record specified by the lsn argument. If the +specified DbLsn is invalid (e.g., does not appear in the log) +DbEnv::log_get will return EINVAL. +
+

Otherwise, the DbEnv::log_get method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The DbEnv::log_get method may fail and throw an exception or return a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +

The DB_FIRST flag was specified and no log files were found. +

+

The DbEnv::log_get method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv::log_get method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Class

+DbEnv +

See Also

+DbEnv::set_lg_bsize, +DbEnv::set_lg_max, +DbEnv::log_archive, +DbEnv::log_compare, +DbEnv::log_file, +DbEnv::log_flush, +DbEnv::log_get, +DbEnv::log_put, +DbEnv::log_register, +DbEnv::log_stat +and +DbEnv::log_unregister. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/log_put.html b/db/docs/api_cxx/log_put.html new file mode 100644 index 000000000..ecd84e33c --- /dev/null +++ b/db/docs/api_cxx/log_put.html @@ -0,0 +1,84 @@ + + + + + +Berkeley DB: DbEnv::log_put + + + + + + + +
+

DbEnv::log_put

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::log_put(DbLsn *lsn, const Dbt *data, u_int32_t flags); +

+

Description

+

The DbEnv::log_put method appends records to the log. The DbLsn of +the put record is returned in the lsn argument. The flags +argument may be set to one of the following values: +

+

DB_CHECKPOINT
The log should write a checkpoint record, recording any information +necessary to make the log structures recoverable after a crash. +

DB_CURLSN
The DbLsn of the next record to be put is returned in the +lsn argument. +

DB_FLUSH
The log is forced to disk after this record is written, guaranteeing +that all records with DbLsn values less than or equal to the +one being put are on disk before this function returns (this function +is most often used for a transaction commit, see DbTxn::commit for +more information). +

The caller is responsible for providing any necessary structure to +data. (For example, in a write-ahead logging protocol, the +application must understand what part of data is an operation +code, what part is redo information, and what part is undo information. +In addition, most transaction managers will store in data the +DbLsn of the previous log record for the same transaction, to +support chaining back through the transaction's log records during +undo.) +

+

The DbEnv::log_put method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The DbEnv::log_flush method may fail and throw an exception or return a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +

The record to be logged is larger than the maximum log record. +

+

The DbEnv::log_put method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv::log_put method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Class

+DbEnv +

See Also

+DbEnv::set_lg_bsize, +DbEnv::set_lg_max, +DbEnv::log_archive, +DbEnv::log_compare, +DbEnv::log_file, +DbEnv::log_flush, +DbEnv::log_get, +DbEnv::log_put, +DbEnv::log_register, +DbEnv::log_stat +and +DbEnv::log_unregister. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/log_register.html b/db/docs/api_cxx/log_register.html new file mode 100644 index 000000000..b837a60b3 --- /dev/null +++ b/db/docs/api_cxx/log_register.html @@ -0,0 +1,68 @@ + + + + + +Berkeley DB: DbEnv::log_register + + + + + + + +
+

DbEnv::log_register

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::log_register(Db *dbp, const char *name); +

+

Description

+

The DbEnv::log_register method registers a file name with the specified Berkeley DB +environment's log manager. The log manager records all file name mappings +at each checkpoint so that a recovery process can identify the file to +which a record in the log refers. +

The dbp argument should be a reference to the Db object being +registered. The name argument should be a file name appropriate +for opening the file in the environment, during recovery. +

The DbEnv::log_register method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The DbEnv::log_register method may fail and throw an exception or return a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +
+

The DbEnv::log_register method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv::log_register method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Class

+DbEnv +

See Also

+DbEnv::set_lg_bsize, +DbEnv::set_lg_max, +DbEnv::log_archive, +DbEnv::log_compare, +DbEnv::log_file, +DbEnv::log_flush, +DbEnv::log_get, +DbEnv::log_put, +DbEnv::log_register, +DbEnv::log_stat +and +DbEnv::log_unregister. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/log_stat.html b/db/docs/api_cxx/log_stat.html new file mode 100644 index 000000000..061685ab4 --- /dev/null +++ b/db/docs/api_cxx/log_stat.html @@ -0,0 +1,96 @@ + + + + + +Berkeley DB: DbEnv::log_stat + + + + + + + +
+

DbEnv::log_stat

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+extern "C" { + typedef void *(*db_malloc_fcn_type)(size_t); +}; +int +DbEnv::log_stat(DB_LOG_STAT **spp, db_malloc_fcn_type db_malloc); +

+

Description

+

The DbEnv::log_stat method +creates a statistical structure and copies a pointer to it into a +user-specified memory location. +

Statistical structures are created in allocated memory. If db_malloc is non-NULL, it +is called to allocate the memory, otherwise, the library function +malloc(3) is used. The function db_malloc must match +the calling conventions of the malloc(3) library routine. +Regardless, the caller is responsible for deallocating the returned +memory. To deallocate returned memory, free the returned memory +reference, references inside the returned memory do not need to be +individually freed. +

The log region statistics are stored in a structure of type DB_LOG_STAT. +The following DB_LOG_STAT fields will be filled in: +

+
u_int32_t st_magic;
The magic number that identifies a file as a log file. +
u_int32_t st_version;
The version of the log file type. +
u_int32_t st_regsize;
The size of the region. +
int st_mode;
The mode of any created log files. +
u_int32_t st_lg_bsize;
The in-memory log record cache size. +
u_int32_t st_lg_max;
The maximum size of any individual file comprising the log. +
u_int32_t st_w_mbytes;
The number of megabytes written to this log. +
u_int32_t st_w_bytes;
The number of bytes over and above st_w_mbytes written to this log. +
u_int32_t st_wc_mbytes;
The number of megabytes written to this log since the last checkpoint. +
u_int32_t st_wc_bytes;
The number of bytes over and above st_wc_mbytes written to this log +since the last checkpoint. +
u_int32_t st_wcount;
The number of times the log has been written to disk. +
u_int32_t st_wcount_fill;
The number of times the log has been written to disk because the +in-memory log record cache filled up. +
u_int32_t st_scount;
The number of times the log has been flushed to disk. +
u_int32_t st_cur_file;
The current log file number. +
u_int32_t st_cur_offset;
The byte offset in the current log file. +
u_int32_t st_region_wait;
The number of times that a thread of control was forced to wait before +obtaining the region lock. +
u_int32_t st_region_nowait;
The number of times that a thread of control was able to obtain +the region lock without waiting. +
+

The DbEnv::log_stat method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The DbEnv::log_stat method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv::log_stat method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Class

+DbEnv +

See Also

+DbEnv::set_lg_bsize, +DbEnv::set_lg_max, +DbEnv::log_archive, +DbEnv::log_compare, +DbEnv::log_file, +DbEnv::log_flush, +DbEnv::log_get, +DbEnv::log_put, +DbEnv::log_register, +DbEnv::log_stat +and +DbEnv::log_unregister. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/log_unregister.html b/db/docs/api_cxx/log_unregister.html new file mode 100644 index 000000000..364e62259 --- /dev/null +++ b/db/docs/api_cxx/log_unregister.html @@ -0,0 +1,63 @@ + + + + + +Berkeley DB: DbEnv::log_unregister + + + + + + + +
+

DbEnv::log_unregister

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::log_unregister(int32_t DB *dbp); +

+

Description

+

The DbEnv::log_unregister method function unregisters the file represented by +the dbp parameter from the Berkeley DB environment's log manager. +

The DbEnv::log_unregister method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The DbEnv::log_unregister method may fail and throw an exception or return a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +
+

The DbEnv::log_unregister method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv::log_unregister method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Class

+DbEnv +

See Also

+DbEnv::set_lg_bsize, +DbEnv::set_lg_max, +DbEnv::log_archive, +DbEnv::log_compare, +DbEnv::log_file, +DbEnv::log_flush, +DbEnv::log_get, +DbEnv::log_put, +DbEnv::log_register, +DbEnv::log_stat +and +DbEnv::log_unregister. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/lsn_class.html b/db/docs/api_cxx/lsn_class.html new file mode 100644 index 000000000..db4d56567 --- /dev/null +++ b/db/docs/api_cxx/lsn_class.html @@ -0,0 +1,38 @@ + + + + + +Berkeley DB: DbLsn + + + + + + + +
+

DbLsn

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+class DbLsn { ... }; +

+

Description

+

A DbLsn is a log sequence number that is fully +encapsulated. The class itself has no methods, other than a default +constructor, so there is no way for the user to manipulate its data +directly. +Methods always take a pointer to a DbLsn as an argument. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/memp_fclose.html b/db/docs/api_cxx/memp_fclose.html new file mode 100644 index 000000000..0906388e3 --- /dev/null +++ b/db/docs/api_cxx/memp_fclose.html @@ -0,0 +1,65 @@ + + + + + +Berkeley DB: DbMpoolFile::close + + + + + + + +
+

DbMpoolFile::close

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbMpoolFile::close(); +

+

Description

+

The DbMpoolFile::close method closes the source file indicated by the +DbMpoolFile object. Calling DbMpoolFile::close does not imply +a call to DbMpoolFile::sync, i.e. no pages are written to the source +file as as a result of calling DbMpoolFile::close. +

In addition, if the file argument to DbMpoolFile::open was NULL, +any underlying files created for this DbMpoolFile will be removed. +

Once DbMpoolFile::close has been called, regardless of its return, the +DbMpoolFile handle may not be accessed again. +

The DbMpoolFile::close method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The DbMpoolFile::close method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbMpoolFile::close method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Classes

+DbEnv, DbMpoolFile +

See Also

+DbEnv::set_mp_mmapsize, +DbMpoolFile::close, +DbMpoolFile::get, +DbMpoolFile::open, +DbMpoolFile::put, +DbMpoolFile::set, +DbMpoolFile::sync, +DbEnv::memp_register, +DbEnv::memp_stat, +DbEnv::memp_sync +and +DbEnv::memp_trickle. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/memp_fget.html b/db/docs/api_cxx/memp_fget.html new file mode 100644 index 000000000..c8067603c --- /dev/null +++ b/db/docs/api_cxx/memp_fget.html @@ -0,0 +1,101 @@ + + + + + +Berkeley DB: DbMpoolFile::get + + + + + + + +
+

DbMpoolFile::get

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbMpoolFile::get(db_pgno_t *pgnoaddr, u_int32_t flags, void **pagep); +

+

Description

+

The DbMpoolFile::get method copies a pointer to the page with the page +number specified by pgnoaddr, from the source file in the +DbMpoolFile, into the memory location referenced by pagep. +If the page does not exist or cannot be retrieved, DbMpoolFile::get will +fail. +

Page numbers begin at 0, i.e., the first page in the file is page number +0, not page number 1. +

The returned page is size_t type aligned. +

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +

+

DB_MPOOL_CREATE
If the specified page does not exist, create it. In this case, the +pgin method, if specified, is +called. +

DB_MPOOL_LAST
Return the last page of the source file and copy its page number +to the location referenced by pgnoaddr. +

DB_MPOOL_NEW
Create a new page in the file and copy its page number to the location +referenced by pgnoaddr. In this case, the +pgin method, if specified, is +not called. +
+

The DB_MPOOL_CREATE, DB_MPOOL_LAST and +DB_MPOOL_NEW flags are mutually exclusive. +

Created pages have all their bytes set to 0, unless otherwise specified +when the file was opened. +

All pages returned by DbMpoolFile::get will be retained (i.e. +pinned), in the pool until a subsequent call to +DbMpoolFile::put. +

The DbMpoolFile::get method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The DbMpoolFile::get method may fail and throw an exception or return a non-zero error for the following conditions: +

+

EAGAIN
The page reference count has overflowed. (This should never happen unless +there's a bug in the application.) +
+

+

EINVAL
An invalid flag value or parameter was specified. +

The DB_MPOOL_NEW flag was set and the source file was not opened for writing. +

More than one of DB_MPOOL_CREATE, DB_MPOOL_LAST and DB_MPOOL_NEW was set. +

+

+

EIO
The requested page does not exist and DB_MPOOL_CREATE was not set. +
+

+

ENOMEM
The cache is full and no more pages will fit in the pool. +
+

The DbMpoolFile::get method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbMpoolFile::get method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Classes

+DbEnv, DbMpoolFile +

See Also

+DbEnv::set_mp_mmapsize, +DbMpoolFile::close, +DbMpoolFile::get, +DbMpoolFile::open, +DbMpoolFile::put, +DbMpoolFile::set, +DbMpoolFile::sync, +DbEnv::memp_register, +DbEnv::memp_stat, +DbEnv::memp_sync +and +DbEnv::memp_trickle. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/memp_fopen.html b/db/docs/api_cxx/memp_fopen.html new file mode 100644 index 000000000..c993ee6f1 --- /dev/null +++ b/db/docs/api_cxx/memp_fopen.html @@ -0,0 +1,160 @@ + + + + + +Berkeley DB: DbMpoolFile::open + + + + + + + +
+

DbMpoolFile::open

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+static int +DbMpoolFile::open(DbEnv *env, const char *file, u_int32_t flags, int mode, + size_t pagesize, DB_MPOOL_FINFO *finfop, DbMpoolFile **mpf); +

+

Description

+

The DbMpoolFile::open method opens a file in the pool specified by the +DbEnv env, copying the DbMpoolFile pointer +representing it into the memory location referenced by mpf. +

The file argument is the name of the file to be opened. +If file is NULL, a private file is created that cannot be +shared with any other process (although it may be shared with +other threads). +

The flags and mode arguments specify how files will be opened +and/or created if they do not already exist. +

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +

+

DB_CREATE
Create any underlying files, as necessary. If the files do not already +exist and the DB_CREATE flag is not specified, the call will fail. +

DB_NOMMAP
Always copy this file into the local cache instead of potentially mapping +it into process memory (see the description of the +DbEnv::set_mp_mmapsize method for further information). +

DB_RDONLY
Open any underlying files for reading only. Any attempt to write the file +using the pool functions will fail, regardless of the actual permissions +of the file. +
+

On UNIX systems, or in IEEE/ANSI Std 1003.1 (POSIX) environments, all files created by function DbMpoolFile::open +are created with mode mode (as described in chmod(2)) and +modified by the process' umask value at the time of creation (see +umask(2)). The group ownership of created files is based on +the system and directory defaults, and is not further specified by Berkeley DB. +If mode is 0, files are created readable and writeable by both +owner and group. On Windows systems, the mode argument is ignored. +

The pagesize argument is the size, in bytes, of the unit of transfer +between the application and the pool, although it is not necessarily the +unit of transfer between the pool and the source file. +

Files opened in the pool may be further configured based on the +finfop argument to DbMpoolFile::open (which is a pointer to a +structure of type DB_MPOOL_FINFO). No references to the finfop +structure are maintained by Berkeley DB, so it may be discarded when the +DbMpoolFile::open function returns. In order to ensure compatibility +with future releases of Berkeley DB, all fields of the DB_MPOOL_FINFO structure +that are not explicitly set should be initialized to 0 before the first +time the structure is used. Do this by declaring the structure external +or static, or by calling the C library routine bzero(3) or +memset(3). +

The fields of the DB_MPOOL_FINFO structure used by DbMpoolFile::open are +described below. If finfop is NULL or any of its fields are +set to their default value, defaults appropriate for the system are used. +

+

int ftype;
The ftype field should be the same as a ftype argument +previously specified to the DbEnv::memp_register function, unless no +input or output processing of the file's pages are necessary, in which +case it should be 0. (See the description of the DbEnv::memp_register +function for more information.) +

DBT *pgcookie;
The pgcookie field contains the byte string that is passed to the +pgin and pgout functions for this file, if any. If no +pgin or pgout functions are specified, the +pgcookie field should be NULL. (See the description of the +DbEnv::memp_register function for more information.) +

u_int8_t *fileid;
The fileid field is a unique identifier for the file. If the +fileid field is non-NULL, it must reference a DB_FILE_ID_LEN +length array of bytes that will be used to uniquely identify the file. +

The mpool functions must be able to uniquely identify files in order that +multiple processes wanting to share a file will correctly identify it in +the pool. +

On most UNIX/POSIX systems, the fileid field will not need to be +set and the mpool functions will simply use the file's device and inode +numbers for this purpose. On Windows systems, the mpool functions use +the values returned by GetFileInformationByHandle() by default -- these +values are known to be constant between processes and over reboot in the +case of NTFS (where they are the NTFS MFT indexes). +

On other filesystems, (e.g., FAT or NFS) these default values are not +necessarily unique between processes or across system reboots. +Applications wanting to maintain a shared memory buffer pool +between processes or across system reboots, where the pool contains pages +from files stored on such filesystems, must specify a unique file +identifier to the DbMpoolFile::open call and each process opening or +registering the file must provide the same unique identifier. +

This should not be necessary for most applications. Specifically, it is +not necessary if the memory pool is not shared between processes and is +re-instantiated after each system reboot, or the application is using the +Berkeley DB access methods instead of calling the pool functions explicitly, or +the files in the memory pool are stored on filesystems where the default +values as described above are invariant between process and across system +reboots. +

int32_t lsn_offset;
The lsn_offset field is the zero-based byte offset in the page of +the page's log sequence number (LSN), or -1 if no LSN offset is specified. +(See the description of the DbEnv::memp_sync function for more +information.) +

u_int32_t clear_len;
The clear_len field is the number of initial bytes in a page +that should be set to zero when the page is created as a result of the +DB_MPOOL_CREATE or DB_MPOOL_NEW flags being specified to DbMpoolFile::get. +If finfop is NULL or clear_len is 0, the entire page is +cleared. +
+

The DbMpoolFile::open method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The DbMpoolFile::open method may fail and throw an exception or return a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +

The file has already been entered into the pool, and the pagesize +value is not the same as when the file was entered into the pool, or the +length of the file is not zero or a multiple of the pagesize. +

The DB_RDONLY flag was specified for an in-memory pool. +

+

+

ENOMEM
The maximum number of open files has been reached. +
+

The DbMpoolFile::open method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbMpoolFile::open method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Classes

+DbEnv, DbMpoolFile +

See Also

+DbEnv::set_mp_mmapsize, +DbMpoolFile::close, +DbMpoolFile::get, +DbMpoolFile::open, +DbMpoolFile::put, +DbMpoolFile::set, +DbMpoolFile::sync, +DbEnv::memp_register, +DbEnv::memp_stat, +DbEnv::memp_sync +and +DbEnv::memp_trickle. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/memp_fput.html b/db/docs/api_cxx/memp_fput.html new file mode 100644 index 000000000..f49c809c0 --- /dev/null +++ b/db/docs/api_cxx/memp_fput.html @@ -0,0 +1,83 @@ + + + + + +Berkeley DB: DbMpoolFile::put + + + + + + + +
+

DbMpoolFile::put

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbMpoolFile::put(void *pgaddr, u_int32_t flags); +

+

Description

+

The DbMpoolFile::put method indicates that the page referenced by +pgaddr can be evicted from the pool. The pgaddr +argument must be an address previously returned by DbMpoolFile::get. +

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +

+

DB_MPOOL_CLEAN
Clear any previously set modification information (i.e., don't bother +writing the page back to the source file). +

DB_MPOOL_DIRTY
The page has been modified and must be written to the source file +before being evicted from the pool. +

DB_MPOOL_DISCARD
The page is unlikely to be useful in the near future, +and should be discarded before other pages in the pool. +
+

The DB_MPOOL_CLEAN and DB_MPOOL_DIRTY flags are +mutually exclusive. +

The DbMpoolFile::put method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The DbMpoolFile::put method may fail and throw an exception or return a non-zero error for the following conditions: +

+

EACCES
The DB_MPOOL_DIRTY flag was set and the source file was not opened for +writing. +
+

+

EINVAL
An invalid flag value or parameter was specified. +

The pgaddr parameter does not reference a page returned by +DbMpoolFile::get. +

More than one of DB_MPOOL_CLEAN and DB_MPOOL_DIRTY flags was set. +

+

The DbMpoolFile::put method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbMpoolFile::put method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Classes

+DbEnv, DbMpoolFile +

See Also

+DbEnv::set_mp_mmapsize, +DbMpoolFile::close, +DbMpoolFile::get, +DbMpoolFile::open, +DbMpoolFile::put, +DbMpoolFile::set, +DbMpoolFile::sync, +DbEnv::memp_register, +DbEnv::memp_stat, +DbEnv::memp_sync +and +DbEnv::memp_trickle. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/memp_fset.html b/db/docs/api_cxx/memp_fset.html new file mode 100644 index 000000000..6e46d45c1 --- /dev/null +++ b/db/docs/api_cxx/memp_fset.html @@ -0,0 +1,76 @@ + + + + + +Berkeley DB: DbMpoolFile::set + + + + + + + +
+

DbMpoolFile::set

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbMpoolFile::set(void *pgaddr, u_int32_t flags); +

+

Description

+

The DbMpoolFile::set method sets the flags associated with the page referenced +by pgaddr without unpinning it from the pool. The pgaddr +argument must be an address previously returned by DbMpoolFile::get. +

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +

+

DB_MPOOL_CLEAN
Clear any previously set modification information (i.e., don't bother +writing the page back to the source file). +

DB_MPOOL_DIRTY
The page has been modified and must be written to the source file +before being evicted from the pool. +

DB_MPOOL_DISCARD
The page is unlikely to be useful in the near future, +and should be discarded before other pages in the pool. +
+

The DB_MPOOL_CLEAN and DB_MPOOL_DIRTY flags are +mutually exclusive. +

The DbMpoolFile::set method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The DbMpoolFile::set method may fail and throw an exception or return a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +
+

The DbMpoolFile::set method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbMpoolFile::set method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Classes

+DbEnv, DbMpoolFile +

See Also

+DbEnv::set_mp_mmapsize, +DbMpoolFile::close, +DbMpoolFile::get, +DbMpoolFile::open, +DbMpoolFile::put, +DbMpoolFile::set, +DbMpoolFile::sync, +DbEnv::memp_register, +DbEnv::memp_stat, +DbEnv::memp_sync +and +DbEnv::memp_trickle. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/memp_fsync.html b/db/docs/api_cxx/memp_fsync.html new file mode 100644 index 000000000..a38366f9e --- /dev/null +++ b/db/docs/api_cxx/memp_fsync.html @@ -0,0 +1,63 @@ + + + + + +Berkeley DB: DbMpoolFile::sync + + + + + + + +
+

DbMpoolFile::sync

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbMpoolFile::sync(); +

+

Description

+

The DbMpoolFile::sync method writes all pages associated with the +DbMpoolFile, that were marked as modified using DbMpoolFile::put +or DbMpoolFile::set, back to the source file. If any of the modified +pages are also pinned (i.e., currently referenced by this or +another process) DbMpoolFile::sync will ignore them. +

The DbMpoolFile::sync method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, 0 on success, and returns DB_INCOMPLETE if there were pages which were +modified but which DbMpoolFile::sync was unable to write immediately. +

Errors

+

The DbMpoolFile::sync method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbMpoolFile::sync method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Classes

+DbEnv, DbMpoolFile +

See Also

+DbEnv::set_mp_mmapsize, +DbMpoolFile::close, +DbMpoolFile::get, +DbMpoolFile::open, +DbMpoolFile::put, +DbMpoolFile::set, +DbMpoolFile::sync, +DbEnv::memp_register, +DbEnv::memp_stat, +DbEnv::memp_sync +and +DbEnv::memp_trickle. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/memp_register.html b/db/docs/api_cxx/memp_register.html new file mode 100644 index 000000000..4c5f0748e --- /dev/null +++ b/db/docs/api_cxx/memp_register.html @@ -0,0 +1,102 @@ + + + + + +Berkeley DB: DbEnv::memp_register + + + + + + + +
+

DbEnv::memp_register

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+extern "C" { + typedef int (*pgin_fcn_type)(DB_ENV *dbenv, + db_pgno_t pgno, void *pgaddr, DBT *pgcookie); + typedef int (*pgout_fcn_type)(DB_ENV *dbenv, + db_pgno_t pgno, void *pgaddr, DBT *pgcookie); +}; +int +DbEnv::memp_register(int ftype, + pgin_fcn_type pgin_fcn, pgout_fcn_type pgout_fcn); +

+

Description

+

The DbEnv::memp_register method registers page-in and page-out +functions for files of type ftype in the specified pool. +

If the pgin_fcn function is non-NULL, it is called each time +a page is read into the memory pool from a file of type ftype, or +a page is created for a file of type ftype (see the +DB_MPOOL_CREATE flag for the DbMpoolFile::get method). +

If the pgout_fcn function is non-NULL, it is called each time +a page is written to a file of type ftype. +

Both the pgin_fcn and pgout_fcn functions are called with +a reference to the current environment, the page number, a pointer to the +page being read or written, and any argument pgcookie that was +specified to the DbMpoolFile::open function when the file was opened. +The pgin_fcn and pgout_fcn functions should return 0 on +success, and an applicable non-zero errno value on failure, in +which case the shared memory pool interface routine (and, by extension, +any Berkeley DB library function) calling it will also fail, returning that +errno value. +

The purpose of the DbEnv::memp_register function is to support processing +when pages are entered into, or flushed from, the pool. A file type must +be specified to make it possible for unrelated threads or processes, that +are sharing a pool, to evict each other's pages from the pool. +Applications should call DbEnv::memp_register, during initialization, +for each type of file requiring input or output processing that will be +sharing the underlying pool. (No registry is necessary for the standard +Berkeley DB access method types, as Db::open registers them +separately.) +

If a thread or process does not call DbEnv::memp_register for a file +type, it is impossible for it to evict pages for any file requiring input +or output processing from the pool. For this reason, +DbEnv::memp_register should always be called by each application sharing +a pool for each type of file included in the pool, regardless of whether +or not the application itself uses files of that type. +

There are no standard values for ftype, pgin_fcn, +pgout_fcn and pgcookie, except that the ftype +value for a file must be a non-zero positive number, as negative numbers +are reserved for internal use by the Berkeley DB library. For this reason, +applications sharing a pool must coordinate their values amongst +themselves. +

The DbEnv::memp_register method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The DbEnv::memp_register method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv::memp_register method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Classes

+DbEnv, DbMpoolFile +

See Also

+DbEnv::set_mp_mmapsize, +DbMpoolFile::close, +DbMpoolFile::get, +DbMpoolFile::open, +DbMpoolFile::put, +DbMpoolFile::set, +DbMpoolFile::sync, +DbEnv::memp_register, +DbEnv::memp_stat, +DbEnv::memp_sync +and +DbEnv::memp_trickle. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/memp_stat.html b/db/docs/api_cxx/memp_stat.html new file mode 100644 index 000000000..1c7f16a2a --- /dev/null +++ b/db/docs/api_cxx/memp_stat.html @@ -0,0 +1,125 @@ + + + + + +Berkeley DB: DbEnv::memp_stat + + + + + + + +
+

DbEnv::memp_stat

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+extern "C" { + typedef void *(*db_malloc_fcn_type)(size_t); +}; +int +DbEnv::memp_stat(DB_MPOOL_STAT **gsp, + DB_MPOOL_FSTAT *(*fsp)[], db_malloc_fcn_type db_malloc); +

+

Description

+

The DbEnv::memp_stat method method creates statistical structures and copies +pointers to them into user-specified memory locations. The statistics +include the number of files participating in the pool, the active pages +in the pool, and information as to how effective the cache has been. +

Statistical structures are created in allocated memory. If db_malloc is non-NULL, it +is called to allocate the memory, otherwise, the library function +malloc(3) is used. The function db_malloc must match +the calling conventions of the malloc(3) library routine. +Regardless, the caller is responsible for deallocating the returned +memory. To deallocate returned memory, free the returned memory +reference, references inside the returned memory do not need to be +individually freed. +

If gsp is non-NULL, the global statistics for the memory pool +mp are copied into the memory location it references. The +global statistics are stored in a structure of type DB_MPOOL_STAT. +

The following DB_MPOOL_STAT fields will be filled in: +

+
size_t st_gbytes;
Gigabytes of cache (total cache size is st_gbytes + st_bytes) +
size_t st_bytes;
Bytes of cache (total cache size is st_gbytes + st_bytes) +
u_int32_t st_ncache;
Number of caches. +
u_int32_t st_regsize;
Individual cache size. +
u_int32_t st_cache_hit;
Requested pages found in the cache. +
u_int32_t st_cache_miss;
Requested pages not found in the cache. +
u_int32_t st_map;
Requested pages mapped into the process' address space (there is no +available information as to whether or not this request caused disk I/O, +although examining the application page fault rate may be helpful). +
u_int32_t st_page_create;
Pages created in the cache. +
u_int32_t st_page_in;
Pages read into the cache. +
u_int32_t st_page_out;
Pages written from the cache to the backing file. +
u_int32_t st_ro_evict;
Clean pages forced from the cache. +
u_int32_t st_rw_evict;
Dirty pages forced from the cache. +
u_int32_t st_hash_buckets;
Number of hash buckets in buffer hash table. +
u_int32_t st_hash_searches;
Total number of buffer hash table lookups. +
u_int32_t st_hash_longest;
The longest chain ever encountered in buffer hash table lookups. +
u_int32_t st_hash_examined;
Total number of hash elements traversed during hash table lookups. +
u_int32_t st_page_clean;
Clean pages currently in the cache. +
u_int32_t st_page_dirty;
Dirty pages currently in the cache. +
u_int32_t st_page_trickle;
Dirty pages written using the DbEnv::memp_trickle interface. +
u_int32_t st_region_wait;
The number of times that a thread of control was forced to wait before +obtaining the region lock. +
u_int32_t st_region_nowait;
The number of times that a thread of control was able to obtain +the region lock without waiting. +
+

If fsp is non-NULL, a pointer to a NULL-terminated variable +length array of statistics for individual files, in the memory pool mp, +is copied into the memory location it references. If no individual files +currently exist in the memory pool, fsp will be set to NULL. +

The per-file statistics are stored in structures of type DB_MPOOL_FSTAT. +The following DB_MPOOL_FSTAT fields will be filled in for each file in +the pool, i.e., each element of the array: +

+
char *file_name;
The name of the file. +
size_t st_pagesize;
Page size in bytes. +
u_int32_t st_cache_hit;
Requested pages found in the cache. +
u_int32_t st_cache_miss;
Requested pages not found in the cache. +
u_int32_t st_map;
Requested pages mapped into the process' address space. +
u_int32_t st_page_create;
Pages created in the cache. +
u_int32_t st_page_in;
Pages read into the cache. +
u_int32_t st_page_out;
Pages written from the cache to the backing file. +
+

The DbEnv::memp_stat method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The DbEnv::memp_stat method may fail and throw an exception or return a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +
+

The DbEnv::memp_stat method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv::memp_stat method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Classes

+DbEnv, DbMpoolFile +

See Also

+DbEnv::set_mp_mmapsize, +DbMpoolFile::close, +DbMpoolFile::get, +DbMpoolFile::open, +DbMpoolFile::put, +DbMpoolFile::set, +DbMpoolFile::sync, +DbEnv::memp_register, +DbEnv::memp_stat, +DbEnv::memp_sync +and +DbEnv::memp_trickle. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/memp_sync.html b/db/docs/api_cxx/memp_sync.html new file mode 100644 index 000000000..fe63f1dff --- /dev/null +++ b/db/docs/api_cxx/memp_sync.html @@ -0,0 +1,87 @@ + + + + + +Berkeley DB: DbEnv::memp_sync + + + + + + + +
+

DbEnv::memp_sync

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::memp_sync(DbLsn *lsn); +

+

Description

+

The DbEnv::memp_sync method ensures that any modified pages in the pool with +log sequence numbers less than the lsn argument are written to +disk. If lsn is NULL all modified pages in the pool are +flushed. +

The primary purpose of the DbEnv::memp_sync function is to enable a +transaction manager to ensure, as part of a checkpoint, that all pages +modified by a certain time have been written to disk. Pages in the pool +that cannot be written back to disk immediately (e.g., that are currently +pinned) are written to disk as soon as it is possible to do so. The +expected behavior of the Berkeley DB or other transaction subsystem is to call +the DbEnv::memp_sync function and then, if the return indicates that some +pages could not be written immediately, to wait briefly and retry again +with the same log sequence number until the DbEnv::memp_sync function +returns that all pages have been written. +

To support the DbEnv::memp_sync functionality, it is necessary that the +pool functions know the location of the log sequence number on the page +for each file type. This location should be specified when the file is +opened using the DbMpoolFile::open function. It is not required that +the log sequence number be aligned on the page in any way. +

The DbEnv::memp_sync method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, 0 on success, and returns DB_INCOMPLETE if there were pages which need to be +written but which DbEnv::memp_sync was unable to write immediately. +In addition, if DbEnv::memp_sync returns success, the value of +lsn will be overwritten with the largest log sequence number +from any page which was written by DbEnv::memp_sync to satisfy this +request. +

Errors

+

The DbEnv::memp_sync method may fail and throw an exception or return a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +

The DbEnv::memp_sync function was called without logging having been +initialized in the environment. +

+

The DbEnv::memp_sync method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv::memp_sync method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Classes

+DbEnv, DbMpoolFile +

See Also

+DbEnv::set_mp_mmapsize, +DbMpoolFile::close, +DbMpoolFile::get, +DbMpoolFile::open, +DbMpoolFile::put, +DbMpoolFile::set, +DbMpoolFile::sync, +DbEnv::memp_register, +DbEnv::memp_stat, +DbEnv::memp_sync +and +DbEnv::memp_trickle. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/memp_trickle.html b/db/docs/api_cxx/memp_trickle.html new file mode 100644 index 000000000..185bc5481 --- /dev/null +++ b/db/docs/api_cxx/memp_trickle.html @@ -0,0 +1,70 @@ + + + + + +Berkeley DB: DbEnv::memp_trickle + + + + + + + +
+

DbEnv::memp_trickle

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::memp_trickle(int pct, int *nwrotep); +

+

Description

+

The DbEnv::memp_trickle method ensures that at least pct percent of +the pages in the shared memory pool are clean by writing dirty pages to +their backing files. +If the nwrotep argument is non-NULL, the number of pages that +were written to reach the correct percentage is returned in the memory +location it references. +

The purpose of the DbEnv::memp_trickle function is to enable a memory +pool manager to ensure that a page is always available for reading in new +information without having to wait for a write. +

The DbEnv::memp_trickle method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The DbEnv::memp_trickle method may fail and throw an exception or return a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +
+

The DbEnv::memp_trickle method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv::memp_trickle method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Classes

+DbEnv, DbMpoolFile +

See Also

+DbEnv::set_mp_mmapsize, +DbMpoolFile::close, +DbMpoolFile::get, +DbMpoolFile::open, +DbMpoolFile::put, +DbMpoolFile::set, +DbMpoolFile::sync, +DbEnv::memp_register, +DbEnv::memp_stat, +DbEnv::memp_sync +and +DbEnv::memp_trickle. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/mempfile_class.html b/db/docs/api_cxx/mempfile_class.html new file mode 100644 index 000000000..ce10974d1 --- /dev/null +++ b/db/docs/api_cxx/mempfile_class.html @@ -0,0 +1,62 @@ + + + + + +Berkeley DB: DbMpoolFile + + + + + + + +
+

DbMpoolFile

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+class DbMpoolFile { ... }; +

+

Description

+

This manual page describes the specific details of the DbMpoolFile +class. +

The DbEnv memory pool methods and the DbMpoolFile class +are the library interface that provide general-purpose, page-oriented +buffer management of one or more files. While designed to work with the +other Db classes, they are also useful for more general purposes. +The memory pools are referred to in this document as simply pools. +

Pools may be shared between processes. Pools are usually filled by pages +from one or more files. Pages in the pool are replaced in LRU +(least-recently-used) order, with each new page replacing the page that +has been unused the longest. Pages retrieved from the pool using +DbMpoolFile::get are pinned in the pool until they are +returned to the control of the buffer pool using the DbMpoolFile::put +method. +

Classes

+DbEnv, DbMpoolFile +

See Also

+DbEnv::set_mp_mmapsize, +DbMpoolFile::close, +DbMpoolFile::get, +DbMpoolFile::open, +DbMpoolFile::put, +DbMpoolFile::set, +DbMpoolFile::sync, +DbEnv::memp_register, +DbEnv::memp_stat, +DbEnv::memp_sync +and +DbEnv::memp_trickle. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/pindex.src b/db/docs/api_cxx/pindex.src new file mode 100644 index 000000000..cf4a58836 --- /dev/null +++ b/db/docs/api_cxx/pindex.src @@ -0,0 +1,287 @@ +__APIREL__/api_cxx/db_class.html#2 @Db +__APIREL__/api_cxx/db_class.html#DB_CXX_NO_EXCEPTIONS Db@DB_CXX_NO_EXCEPTIONS +__APIREL__/api_cxx/db_class.html#DB_XA_CREATE Db@DB_XA_CREATE +__APIREL__/api_cxx/db_err.html#2 @DbEnv::err +__APIREL__/api_cxx/db_set_errfile.html#2 @Db::set_errfile +__APIREL__/api_cxx/db_set_malloc.html#2 @Db::set_malloc +__APIREL__/api_cxx/db_set_paniccall.html#2 @Db::set_paniccall +__APIREL__/api_cxx/db_set_realloc.html#2 @Db::set_realloc +__APIREL__/api_cxx/dbc_class.html#2 @Dbc +__APIREL__/api_cxx/dbenv_class.html#2 @DbEnv +__APIREL__/api_cxx/dbenv_class.html#DB_CLIENT DbEnv@DB_CLIENT +__APIREL__/api_cxx/dbenv_class.html#DB_CXX_NO_EXCEPTIONS DbEnv@DB_CXX_NO_EXCEPTIONS +__APIREL__/api_cxx/dbt_class.html#2 @Dbt +__APIREL__/api_cxx/dbt_class.html#3 @key/data pairs +__APIREL__/api_cxx/dbt_class.html#data Dbt@data +__APIREL__/api_cxx/dbt_class.html#DB_DBT_MALLOC Dbt@DB_DBT_MALLOC +__APIREL__/api_cxx/dbt_class.html#DB_DBT_REALLOC Dbt@DB_DBT_REALLOC +__APIREL__/api_cxx/dbt_class.html#DB_DBT_USERMEM Dbt@DB_DBT_USERMEM +__APIREL__/api_cxx/dbt_class.html#DB_DBT_PARTIAL Dbt@DB_DBT_PARTIAL +__APIREL__/api_cxx/dbt_class.html#4 retrieved key/data @permanence +__APIREL__/api_cxx/dbt_class.html#5 retrieved @key/data permanence +__APIREL__/api_cxx/dbt_class.html#6 data @alignment +__APIREL__/api_cxx/dbt_class.html#7 logical @record number format +__APIREL__/api_cxx/env_set_errfile.html#2 @DbEnv::set_errfile +__APIREL__/api_cxx/env_set_error_stream.html#2 @DbEnv::set_error_stream +__APIREL__/api_cxx/env_set_paniccall.html#2 @DbEnv::set_paniccall +__APIREL__/api_cxx/except_class.html#2 @DbException +__APIREL__/api_cxx/get_errno.html#2 @DbException::get_errno +__APIREL__/api_cxx/lock_class.html#2 @DbLock +__APIREL__/api_cxx/lsn_class.html#2 @DbLsn +__APIREL__/api_cxx/mempfile_class.html#2 @DbMpoolFile +__APIREL__/api_cxx/txn_class.html#2 @DbTxn +__APIREL__/api_cxx/what.html#2 @DbException::what +__APIREL__/api_cxx/db_close.html#2 @Db::close +__APIREL__/api_cxx/db_close.html#DB_NOSYNC Db::close@DB_NOSYNC +__APIREL__/api_cxx/db_close.html#3 Db::close @DB_INCOMPLETE +__APIREL__/api_cxx/db_cursor.html#2 @Db::cursor +__APIREL__/api_cxx/db_cursor.html#DB_WRITECURSOR Db::cursor@DB_WRITECURSOR +__APIREL__/api_cxx/db_del.html#2 @Db::del +__APIREL__/api_cxx/db_fd.html#2 @Db::fd +__APIREL__/api_cxx/db_get.html#2 @Db::get +__APIREL__/api_cxx/db_get.html#DB_CONSUME Db::get@DB_CONSUME +__APIREL__/api_cxx/db_get.html#DB_CONSUME_WAIT Db::get@DB_CONSUME_WAIT +__APIREL__/api_cxx/db_get.html#DB_GET_BOTH Db::get@DB_GET_BOTH +__APIREL__/api_cxx/db_get.html#DB_SET_RECNO Db::get@DB_SET_RECNO +__APIREL__/api_cxx/db_get.html#DB_RMW Db::get@DB_RMW +__APIREL__/api_cxx/db_get_byteswapped.html#2 @Db::get_byteswapped +__APIREL__/api_cxx/db_get_type.html#2 @Db::get_type +__APIREL__/api_cxx/db_join.html#2 @Db::join +__APIREL__/api_cxx/db_join.html#DB_JOIN_NOSORT Db::join@DB_JOIN_NOSORT +__APIREL__/api_cxx/db_join.html#DB_JOIN_ITEM Db::join@DB_JOIN_ITEM +__APIREL__/api_cxx/db_join.html#DB_RMW Db::join@DB_RMW +__APIREL__/api_cxx/db_key_range.html#2 @Db::key_range +__APIREL__/api_cxx/db_open.html#2 @Db::open +__APIREL__/api_cxx/db_open.html#DB_CREATE Db::open@DB_CREATE +__APIREL__/api_cxx/db_open.html#DB_EXCL Db::open@DB_EXCL +__APIREL__/api_cxx/db_open.html#DB_NOMMAP Db::open@DB_NOMMAP +__APIREL__/api_cxx/db_open.html#DB_RDONLY Db::open@DB_RDONLY +__APIREL__/api_cxx/db_open.html#DB_THREAD Db::open@DB_THREAD +__APIREL__/api_cxx/db_open.html#DB_TRUNCATE Db::open@DB_TRUNCATE +__APIREL__/api_cxx/db_open.html#DB_OLD_VERSION Db::open@DB_OLD_VERSION +__APIREL__/api_cxx/db_put.html#2 @Db::put +__APIREL__/api_cxx/db_put.html#DB_APPEND Db::put@DB_APPEND +__APIREL__/api_cxx/db_put.html#DB_NODUPDATA Db::put@DB_NODUPDATA +__APIREL__/api_cxx/db_put.html#DB_NOOVERWRITE Db::put@DB_NOOVERWRITE +__APIREL__/api_cxx/db_remove.html#2 @Db::remove +__APIREL__/api_cxx/db_rename.html#2 @Db::rename +__APIREL__/api_cxx/db_set_append_recno.html#2 @Db::set_append_recno +__APIREL__/api_cxx/db_set_bt_compare.html#2 @Db::set_bt_compare +__APIREL__/api_cxx/db_set_bt_minkey.html#2 @Db::set_bt_minkey +__APIREL__/api_cxx/db_set_bt_prefix.html#2 @Db::set_bt_prefix +__APIREL__/api_cxx/db_set_cachesize.html#2 @Db::set_cachesize +__APIREL__/api_cxx/db_set_dup_compare.html#2 @Db::set_dup_compare +__APIREL__/api_cxx/db_set_errcall.html#2 @Db::set_errcall +__APIREL__/api_cxx/db_set_errpfx.html#2 @Db::set_errpfx +__APIREL__/api_cxx/db_set_feedback.html#2 @Db::set_feedback +__APIREL__/api_cxx/db_set_feedback.html#DB_UPGRADE Db::set_feedback@DB_UPGRADE +__APIREL__/api_cxx/db_set_feedback.html#DB_VERIFY Db::set_feedback@DB_VERIFY +__APIREL__/api_cxx/db_set_flags.html#2 @Db::set_flags +__APIREL__/api_cxx/db_set_flags.html#DB_DUP Db::set_flags@DB_DUP +__APIREL__/api_cxx/db_set_flags.html#DB_DUPSORT Db::set_flags@DB_DUPSORT +__APIREL__/api_cxx/db_set_flags.html#DB_RECNUM Db::set_flags@DB_RECNUM +__APIREL__/api_cxx/db_set_flags.html#DB_REVSPLITOFF Db::set_flags@DB_REVSPLITOFF +__APIREL__/api_cxx/db_set_flags.html#DB_DUP Db::set_flags@DB_DUP +__APIREL__/api_cxx/db_set_flags.html#DB_DUPSORT Db::set_flags@DB_DUPSORT +__APIREL__/api_cxx/db_set_flags.html#DB_RENUMBER Db::set_flags@DB_RENUMBER +__APIREL__/api_cxx/db_set_flags.html#DB_SNAPSHOT Db::set_flags@DB_SNAPSHOT +__APIREL__/api_cxx/db_set_h_ffactor.html#2 @Db::set_h_ffactor +__APIREL__/api_cxx/db_set_h_hash.html#2 @Db::set_h_hash +__APIREL__/api_cxx/db_set_h_nelem.html#2 @Db::set_h_nelem +__APIREL__/api_cxx/db_set_lorder.html#2 @Db::set_lorder +__APIREL__/api_cxx/db_set_pagesize.html#2 @Db::set_pagesize +__APIREL__/api_cxx/db_set_q_extentsize.html#2 @Db::set_q_extentsize +__APIREL__/api_cxx/db_set_re_delim.html#2 @Db::set_re_delim +__APIREL__/api_cxx/db_set_re_len.html#2 @Db::set_re_len +__APIREL__/api_cxx/db_set_re_pad.html#2 @Db::set_re_pad +__APIREL__/api_cxx/db_set_re_source.html#2 @Db::set_re_source +__APIREL__/api_cxx/db_stat.html#2 @Db::stat +__APIREL__/api_cxx/db_stat.html#DB_CACHED_COUNTS Db::stat@DB_CACHED_COUNTS +__APIREL__/api_cxx/db_stat.html#DB_RECORDCOUNT Db::stat@DB_RECORDCOUNT +__APIREL__/api_cxx/db_sync.html#2 @Db::sync +__APIREL__/api_cxx/db_upgrade.html#2 @Db::upgrade +__APIREL__/api_cxx/db_upgrade.html#DB_DUPSORT Db::upgrade@DB_DUPSORT +__APIREL__/api_cxx/db_upgrade.html#DB_OLD_VERSION Db::upgrade@DB_OLD_VERSION +__APIREL__/api_cxx/db_verify.html#2 @Db::verify +__APIREL__/api_cxx/db_verify.html#DB_SALVAGE Db::verify@DB_SALVAGE +__APIREL__/api_cxx/db_verify.html#DB_AGGRESSIVE Db::verify@DB_AGGRESSIVE +__APIREL__/api_cxx/db_verify.html#DB_NOORDERCHK Db::verify@DB_NOORDERCHK +__APIREL__/api_cxx/db_verify.html#DB_ORDERCHKONLY Db::verify@DB_ORDERCHKONLY +__APIREL__/api_cxx/dbc_close.html#2 @Dbc::close +__APIREL__/api_cxx/dbc_count.html#2 @Dbc::count +__APIREL__/api_cxx/dbc_del.html#2 @Dbc::del +__APIREL__/api_cxx/dbc_dup.html#2 @Dbc::dup +__APIREL__/api_cxx/dbc_dup.html#DB_POSITION Dbc::dup@DB_POSITION +__APIREL__/api_cxx/dbc_get.html#2 @Dbc::get +__APIREL__/api_cxx/dbc_get.html#DB_CURRENT Dbc::get@DB_CURRENT +__APIREL__/api_cxx/dbc_get.html#DB_FIRST Dbc::get@DB_FIRST +__APIREL__/api_cxx/dbc_get.html#DB_LAST Dbc::get@DB_LAST +__APIREL__/api_cxx/dbc_get.html#DB_GET_BOTH Dbc::get@DB_GET_BOTH +__APIREL__/api_cxx/dbc_get.html#DB_GET_RECNO Dbc::get@DB_GET_RECNO +__APIREL__/api_cxx/dbc_get.html#DB_JOIN_ITEM Dbc::get@DB_JOIN_ITEM +__APIREL__/api_cxx/dbc_get.html#DB_NEXT Dbc::get@DB_NEXT +__APIREL__/api_cxx/dbc_get.html#DB_PREV Dbc::get@DB_PREV +__APIREL__/api_cxx/dbc_get.html#DB_NEXT_DUP Dbc::get@DB_NEXT_DUP +__APIREL__/api_cxx/dbc_get.html#DB_NEXT_NODUP Dbc::get@DB_NEXT_NODUP +__APIREL__/api_cxx/dbc_get.html#DB_PREV_NODUP Dbc::get@DB_PREV_NODUP +__APIREL__/api_cxx/dbc_get.html#DB_SET Dbc::get@DB_SET +__APIREL__/api_cxx/dbc_get.html#DB_SET_RANGE Dbc::get@DB_SET_RANGE +__APIREL__/api_cxx/dbc_get.html#DB_SET_RECNO Dbc::get@DB_SET_RECNO +__APIREL__/api_cxx/dbc_get.html#DB_RMW Dbc::get@DB_RMW +__APIREL__/api_cxx/dbc_put.html#2 @Dbc::put +__APIREL__/api_cxx/dbc_put.html#DB_AFTER Dbc::put@DB_AFTER +__APIREL__/api_cxx/dbc_put.html#DB_BEFORE Dbc::put@DB_BEFORE +__APIREL__/api_cxx/dbc_put.html#DB_CURRENT Dbc::put@DB_CURRENT +__APIREL__/api_cxx/dbc_put.html#DB_KEYFIRST Dbc::put@DB_KEYFIRST +__APIREL__/api_cxx/dbc_put.html#DB_KEYLAST Dbc::put@DB_KEYLAST +__APIREL__/api_cxx/dbc_put.html#DB_NODUPDATA Dbc::put@DB_NODUPDATA +__APIREL__/api_cxx/env_close.html#2 @DbEnv::close +__APIREL__/api_cxx/env_open.html#2 @DbEnv::open +__APIREL__/api_cxx/env_open.html#DB_JOINENV DbEnv::open@DB_JOINENV +__APIREL__/api_cxx/env_open.html#DB_INIT_CDB DbEnv::open@DB_INIT_CDB +__APIREL__/api_cxx/env_open.html#DB_INIT_LOCK DbEnv::open@DB_INIT_LOCK +__APIREL__/api_cxx/env_open.html#DB_INIT_LOG DbEnv::open@DB_INIT_LOG +__APIREL__/api_cxx/env_open.html#DB_INIT_MPOOL DbEnv::open@DB_INIT_MPOOL +__APIREL__/api_cxx/env_open.html#DB_INIT_TXN DbEnv::open@DB_INIT_TXN +__APIREL__/api_cxx/env_open.html#DB_RECOVER DbEnv::open@DB_RECOVER +__APIREL__/api_cxx/env_open.html#DB_RECOVER_FATAL DbEnv::open@DB_RECOVER_FATAL +__APIREL__/api_cxx/env_open.html#DB_USE_ENVIRON DbEnv::open@DB_USE_ENVIRON +__APIREL__/api_cxx/env_open.html#DB_USE_ENVIRON_ROOT DbEnv::open@DB_USE_ENVIRON_ROOT +__APIREL__/api_cxx/env_open.html#DB_CREATE DbEnv::open@DB_CREATE +__APIREL__/api_cxx/env_open.html#DB_LOCKDOWN DbEnv::open@DB_LOCKDOWN +__APIREL__/api_cxx/env_open.html#DB_PRIVATE DbEnv::open@DB_PRIVATE +__APIREL__/api_cxx/env_open.html#DB_SYSTEM_MEM DbEnv::open@DB_SYSTEM_MEM +__APIREL__/api_cxx/env_open.html#DB_THREAD DbEnv::open@DB_THREAD +__APIREL__/api_cxx/env_remove.html#2 @DbEnv::remove +__APIREL__/api_cxx/env_remove.html#DB_FORCE DbEnv::remove@DB_FORCE +__APIREL__/api_cxx/env_remove.html#DB_USE_ENVIRON DbEnv::remove@DB_USE_ENVIRON +__APIREL__/api_cxx/env_remove.html#DB_USE_ENVIRON_ROOT DbEnv::remove@DB_USE_ENVIRON_ROOT +__APIREL__/api_cxx/env_set_cachesize.html#2 @DbEnv::set_cachesize +__APIREL__/api_cxx/env_set_data_dir.html#2 @DbEnv::set_data_dir +__APIREL__/api_cxx/env_set_errcall.html#2 @DbEnv::set_errcall +__APIREL__/api_cxx/env_set_errpfx.html#2 @DbEnv::set_errpfx +__APIREL__/api_cxx/env_set_feedback.html#2 @DbEnv::set_feedback +__APIREL__/api_cxx/env_set_feedback.html#DB_RECOVER DbEnv::set_feedback@DB_RECOVER +__APIREL__/api_cxx/env_set_flags.html#2 @DbEnv::set_flags +__APIREL__/api_cxx/env_set_flags.html#DB_CDB_ALLDB DbEnv::set_flags@DB_CDB_ALLDB +__APIREL__/api_cxx/env_set_flags.html#DB_NOMMAP DbEnv::set_flags@DB_NOMMAP +__APIREL__/api_cxx/env_set_flags.html#DB_TXN_NOSYNC DbEnv::set_flags@DB_TXN_NOSYNC +__APIREL__/api_cxx/env_set_lg_bsize.html#2 @DbEnv::set_lg_bsize +__APIREL__/api_cxx/env_set_lg_dir.html#2 @DbEnv::set_lg_dir +__APIREL__/api_cxx/env_set_lg_max.html#2 @DbEnv::set_lg_max +__APIREL__/api_cxx/env_set_lk_conflicts.html#2 @DbEnv::set_lk_conflicts +__APIREL__/api_cxx/env_set_lk_detect.html#2 @DbEnv::set_lk_detect +__APIREL__/api_cxx/env_set_lk_detect.html#DB_LOCK_DEFAULT DbEnv::set_lk_detect@DB_LOCK_DEFAULT +__APIREL__/api_cxx/env_set_lk_detect.html#DB_LOCK_OLDEST DbEnv::set_lk_detect@DB_LOCK_OLDEST +__APIREL__/api_cxx/env_set_lk_detect.html#DB_LOCK_RANDOM DbEnv::set_lk_detect@DB_LOCK_RANDOM +__APIREL__/api_cxx/env_set_lk_detect.html#DB_LOCK_YOUNGEST DbEnv::set_lk_detect@DB_LOCK_YOUNGEST +__APIREL__/api_cxx/env_set_lk_max.html#2 @DbEnv::set_lk_max +__APIREL__/api_cxx/env_set_lk_max_locks.html#2 @DbEnv::set_lk_max_locks +__APIREL__/api_cxx/env_set_lk_max_lockers.html#2 @DbEnv::set_lk_max_lockers +__APIREL__/api_cxx/env_set_lk_max_objects.html#2 @DbEnv::set_lk_max_objects +__APIREL__/api_cxx/env_set_mp_mmapsize.html#2 @DbEnv::set_mp_mmapsize +__APIREL__/api_cxx/env_set_mutexlocks.html#2 @DbEnv::set_mutexlocks +__APIREL__/api_cxx/env_set_pageyield.html#2 @DbEnv::set_pageyield +__APIREL__/api_cxx/env_set_panicstate.html#2 @DbEnv::set_panicstate +__APIREL__/api_cxx/env_set_rec_init.html#2 @DbEnv::set_recovery_init +__APIREL__/api_cxx/env_set_region_init.html#2 @DbEnv::set_region_init +__APIREL__/api_cxx/env_set_server.html#2 @DbEnv::set_server +__APIREL__/api_cxx/env_set_server.html#DB_NOSERVER DbEnv::set_server@DB_NOSERVER +__APIREL__/api_cxx/env_set_server.html#DB_NOSERVER_ID DbEnv::set_server@DB_NOSERVER_ID +__APIREL__/api_cxx/env_set_shm_key.html#2 @DbEnv::set_shm_key +__APIREL__/api_cxx/env_set_tas_spins.html#2 @DbEnv::set_tas_spins +__APIREL__/api_cxx/env_set_tmp_dir.html#2 @DbEnv::set_tmp_dir +__APIREL__/api_cxx/env_set_tx_max.html#2 @DbEnv::set_tx_max +__APIREL__/api_cxx/env_set_tx_recover.html#2 @DbEnv::set_tx_recover +__APIREL__/api_cxx/env_set_tx_recover.html#DB_TXN_BACKWARD_ROLL DbEnv::set_tx_recover@DB_TXN_BACKWARD_ROLL +__APIREL__/api_cxx/env_set_tx_recover.html#DB_TXN_FORWARD_ROLL DbEnv::set_tx_recover@DB_TXN_FORWARD_ROLL +__APIREL__/api_cxx/env_set_tx_recover.html#DB_TXN_ABORT DbEnv::set_tx_recover@DB_TXN_ABORT +__APIREL__/api_cxx/env_set_tx_timestamp.html#2 @DbEnv::set_tx_timestamp +__APIREL__/api_cxx/env_set_verbose.html#2 @DbEnv::set_verbose +__APIREL__/api_cxx/env_set_verbose.html#DB_VERB_CHKPOINT DbEnv::set_verbose@DB_VERB_CHKPOINT +__APIREL__/api_cxx/env_set_verbose.html#DB_VERB_DEADLOCK DbEnv::set_verbose@DB_VERB_DEADLOCK +__APIREL__/api_cxx/env_set_verbose.html#DB_VERB_RECOVERY DbEnv::set_verbose@DB_VERB_RECOVERY +__APIREL__/api_cxx/env_set_verbose.html#DB_VERB_WAITSFOR DbEnv::set_verbose@DB_VERB_WAITSFOR +__APIREL__/api_cxx/env_strerror.html#2 @DbEnv::strerror +__APIREL__/api_cxx/env_version.html#2 @DbEnv::version +__APIREL__/api_cxx/lock_detect.html#2 @DbEnv::lock_detect +__APIREL__/api_cxx/lock_detect.html#DB_LOCK_CONFLICT DbEnv::lock_detect@DB_LOCK_CONFLICT +__APIREL__/api_cxx/lock_get.html#2 @DbEnv::lock_get +__APIREL__/api_cxx/lock_get.html#DB_LOCK_NOWAIT DbEnv::lock_get@DB_LOCK_NOWAIT +__APIREL__/api_cxx/lock_get.html#DB_LOCK_NOTGRANTED DbEnv::lock_get@DB_LOCK_NOTGRANTED +__APIREL__/api_cxx/lock_id.html#2 @DbEnv::lock_id +__APIREL__/api_cxx/lock_put.html#2 @DbLock::put +__APIREL__/api_cxx/lock_stat.html#2 @DbEnv::lock_stat +__APIREL__/api_cxx/lock_vec.html#2 @DbEnv::lock_vec +__APIREL__/api_cxx/lock_vec.html#DB_LOCK_NOWAIT DbEnv::lock_vec@DB_LOCK_NOWAIT +__APIREL__/api_cxx/lock_vec.html#op DbEnv::lock_vec@op +__APIREL__/api_cxx/lock_vec.html#DB_LOCK_GET DbEnv::lock_vec@DB_LOCK_GET +__APIREL__/api_cxx/lock_vec.html#DB_LOCK_PUT DbEnv::lock_vec@DB_LOCK_PUT +__APIREL__/api_cxx/lock_vec.html#DB_LOCK_PUT_ALL DbEnv::lock_vec@DB_LOCK_PUT_ALL +__APIREL__/api_cxx/lock_vec.html#DB_LOCK_PUT_OBJ DbEnv::lock_vec@DB_LOCK_PUT_OBJ +__APIREL__/api_cxx/lock_vec.html#obj DbEnv::lock_vec@obj +__APIREL__/api_cxx/lock_vec.html#mode DbEnv::lock_vec@mode +__APIREL__/api_cxx/lock_vec.html#lock DbEnv::lock_vec@lock +__APIREL__/api_cxx/lock_vec.html#DB_LOCK_NOTGRANTED DbEnv::lock_vec@DB_LOCK_NOTGRANTED +__APIREL__/api_cxx/log_archive.html#2 @DbEnv::log_archive +__APIREL__/api_cxx/log_archive.html#DB_ARCH_ABS DbEnv::log_archive@DB_ARCH_ABS +__APIREL__/api_cxx/log_archive.html#DB_ARCH_DATA DbEnv::log_archive@DB_ARCH_DATA +__APIREL__/api_cxx/log_archive.html#DB_ARCH_LOG DbEnv::log_archive@DB_ARCH_LOG +__APIREL__/api_cxx/log_compare.html#2 @DbEnv::log_compare +__APIREL__/api_cxx/log_file.html#2 @DbEnv::log_file +__APIREL__/api_cxx/log_flush.html#2 @DbEnv::log_flush +__APIREL__/api_cxx/log_get.html#2 @DbEnv::log_get +__APIREL__/api_cxx/log_get.html#DB_CHECKPOINT DbEnv::log_get@DB_CHECKPOINT +__APIREL__/api_cxx/log_get.html#DB_FIRST DbEnv::log_get@DB_FIRST +__APIREL__/api_cxx/log_get.html#DB_LAST DbEnv::log_get@DB_LAST +__APIREL__/api_cxx/log_get.html#DB_NEXT DbEnv::log_get@DB_NEXT +__APIREL__/api_cxx/log_get.html#DB_PREV DbEnv::log_get@DB_PREV +__APIREL__/api_cxx/log_get.html#DB_CURRENT DbEnv::log_get@DB_CURRENT +__APIREL__/api_cxx/log_get.html#DB_SET DbEnv::log_get@DB_SET +__APIREL__/api_cxx/log_put.html#2 @DbEnv::log_put +__APIREL__/api_cxx/log_put.html#DB_CHECKPOINT DbEnv::log_put@DB_CHECKPOINT +__APIREL__/api_cxx/log_put.html#DB_CURLSN DbEnv::log_put@DB_CURLSN +__APIREL__/api_cxx/log_put.html#DB_FLUSH DbEnv::log_put@DB_FLUSH +__APIREL__/api_cxx/log_register.html#2 @DbEnv::log_register +__APIREL__/api_cxx/log_stat.html#2 @DbEnv::log_stat +__APIREL__/api_cxx/log_unregister.html#2 @DbEnv::log_unregister +__APIREL__/api_cxx/memp_fclose.html#2 @DbMpoolFile::close +__APIREL__/api_cxx/memp_fget.html#2 @DbMpoolFile::get +__APIREL__/api_cxx/memp_fget.html#DB_MPOOL_CREATE DbMpoolFile::get@DB_MPOOL_CREATE +__APIREL__/api_cxx/memp_fget.html#DB_MPOOL_LAST DbMpoolFile::get@DB_MPOOL_LAST +__APIREL__/api_cxx/memp_fget.html#DB_MPOOL_NEW DbMpoolFile::get@DB_MPOOL_NEW +__APIREL__/api_cxx/memp_fopen.html#2 @DbMpoolFile::open +__APIREL__/api_cxx/memp_fopen.html#DB_CREATE DbMpoolFile::open@DB_CREATE +__APIREL__/api_cxx/memp_fopen.html#DB_NOMMAP DbMpoolFile::open@DB_NOMMAP +__APIREL__/api_cxx/memp_fopen.html#DB_RDONLY DbMpoolFile::open@DB_RDONLY +__APIREL__/api_cxx/memp_fopen.html#ftype DbMpoolFile::open@ftype +__APIREL__/api_cxx/memp_fopen.html#pgcookie DbMpoolFile::open@pgcookie +__APIREL__/api_cxx/memp_fopen.html#fileid DbMpoolFile::open@fileid +__APIREL__/api_cxx/memp_fopen.html#lsn_offset DbMpoolFile::open@lsn_offset +__APIREL__/api_cxx/memp_fopen.html#clear_len DbMpoolFile::open@clear_len +__APIREL__/api_cxx/memp_fput.html#2 @DbMpoolFile::put +__APIREL__/api_cxx/memp_fput.html#DB_MPOOL_CLEAN DbMpoolFile::put@DB_MPOOL_CLEAN +__APIREL__/api_cxx/memp_fput.html#DB_MPOOL_DIRTY DbMpoolFile::put@DB_MPOOL_DIRTY +__APIREL__/api_cxx/memp_fput.html#DB_MPOOL_DISCARD DbMpoolFile::put@DB_MPOOL_DISCARD +__APIREL__/api_cxx/memp_fset.html#2 @DbMpoolFile::set +__APIREL__/api_cxx/memp_fset.html#DB_MPOOL_CLEAN DbMpoolFile::set@DB_MPOOL_CLEAN +__APIREL__/api_cxx/memp_fset.html#DB_MPOOL_DIRTY DbMpoolFile::set@DB_MPOOL_DIRTY +__APIREL__/api_cxx/memp_fset.html#DB_MPOOL_DISCARD DbMpoolFile::set@DB_MPOOL_DISCARD +__APIREL__/api_cxx/memp_fsync.html#2 @DbMpoolFile::sync +__APIREL__/api_cxx/memp_register.html#2 @DbEnv::memp_register +__APIREL__/api_cxx/memp_stat.html#2 @DbEnv::memp_stat +__APIREL__/api_cxx/memp_sync.html#2 @DbEnv::memp_sync +__APIREL__/api_cxx/memp_trickle.html#2 @DbEnv::memp_trickle +__APIREL__/api_cxx/txn_abort.html#2 @DbTxn::abort +__APIREL__/api_cxx/txn_begin.html#2 @DbEnv::txn_begin +__APIREL__/api_cxx/txn_begin.html#DB_TXN_NOSYNC DbEnv::txn_begin@DB_TXN_NOSYNC +__APIREL__/api_cxx/txn_begin.html#DB_TXN_NOWAIT DbEnv::txn_begin@DB_TXN_NOWAIT +__APIREL__/api_cxx/txn_begin.html#DB_TXN_SYNC DbEnv::txn_begin@DB_TXN_SYNC +__APIREL__/api_cxx/txn_checkpoint.html#2 @DbEnv::txn_checkpoint +__APIREL__/api_cxx/txn_checkpoint.html#DB_FORCE DbEnv::txn_checkpoint@DB_FORCE +__APIREL__/api_cxx/txn_commit.html#2 @DbTxn::commit +__APIREL__/api_cxx/txn_commit.html#DB_TXN_NOSYNC DbTxn::commit@DB_TXN_NOSYNC +__APIREL__/api_cxx/txn_commit.html#DB_TXN_SYNC DbTxn::commit@DB_TXN_SYNC +__APIREL__/api_cxx/txn_id.html#2 @DbTxn::id +__APIREL__/api_cxx/txn_prepare.html#2 @DbTxn::prepare +__APIREL__/api_cxx/txn_stat.html#2 @DbEnv::txn_stat diff --git a/db/docs/api_cxx/txn_abort.html b/db/docs/api_cxx/txn_abort.html new file mode 100644 index 000000000..f9c863b3e --- /dev/null +++ b/db/docs/api_cxx/txn_abort.html @@ -0,0 +1,67 @@ + + + + + +Berkeley DB: DbTxn::abort + + + + + + + +
+

DbTxn::abort

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbTxn::abort(); +

+

Description

+

The DbTxn::abort method causes an abnormal termination of the +transaction. The log is played backwards and any necessary recovery +operations are initiated through the recover function specified +to DbEnv::open. After the log processing is completed, all locks +held by the transaction are released. As is the case for +DbTxn::commit, applications that require strict two-phase locking +should not explicitly release any locks. +

In the case of nested transactions, aborting a parent transaction causes +all children (unresolved or not) of the parent transaction to be aborted. +

Once the DbTxn::abort method returns, the DbTxn handle may not +be accessed again. +

The DbTxn::abort method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The DbTxn::abort method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbTxn::abort method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Classes

+DbEnv, DbTxn +

See Also

+DbEnv::set_tx_max, +DbEnv::set_tx_recover, +DbEnv::set_tx_timestamp, +DbTxn::abort, +DbEnv::txn_begin, +DbEnv::txn_checkpoint, +DbTxn::commit, +DbTxn::id, +DbTxn::prepare +and +DbEnv::txn_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/txn_begin.html b/db/docs/api_cxx/txn_begin.html new file mode 100644 index 000000000..4cacec560 --- /dev/null +++ b/db/docs/api_cxx/txn_begin.html @@ -0,0 +1,96 @@ + + + + + +Berkeley DB: DbEnv::txn_begin + + + + + + + +
+

DbEnv::txn_begin

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::txn_begin(DbTxn *parent, DbTxn **tid, u_int32_t flags); +

+

Description

+

The DbEnv::txn_begin method creates a new transaction in the environment +and copies a pointer to a DbTxn that uniquely identifies it into +the memory referenced by tid. +

If the parent argument is non-NULL, the new transaction will +be a nested transaction, with the transaction indicated by +parent as its parent. Transactions may be +nested to any level. +

The flags parameter must be set to 0 or one of the following +values: +

+

DB_TXN_NOSYNC
Do not synchronously flush the log when this transaction commits or +prepares. This means the transaction will exhibit the ACI (atomicity, +consistency and isolation) properties, but not D (durability), i.e., +database integrity will be maintained but it is possible that this +transaction may be undone during recovery instead of being redone. +

This behavior may be set for an entire Berkeley DB environment as part of the +DbEnv::set_flags interface. +

DB_TXN_NOWAIT
If a lock is unavailable for any Berkeley DB operation performed in the context +of this transaction, return immediately instead of blocking on the lock. +The error return in the case will be DB_LOCK_NOTGRANTED. +

DB_TXN_SYNC
Synchronously flush the log when this transaction commits or prepares. +This means the transaction will exhibit all of the ACID (atomicity, +consistency and isolation and durability) properties. +

This behavior is the default for Berkeley DB environments unless the +DB_TXN_NOSYNC flag was specified to the DbEnv::set_flags +interface. +

+

Note: An transaction may not span threads, +i.e., each transaction must begin and end in the same thread, and each +transaction may only be used by a single thread. +

Note: cursors may not span transactions, i.e., each cursor must be opened +and closed within a single transaction. +

Note: a parent transaction may not issue any Berkeley DB operations, except for +DbEnv::txn_begin, DbTxn::abort and DbTxn::commit, while it has +active child transactions (child transactions that have not yet been +committed or aborted). +

The DbEnv::txn_begin method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The DbEnv::txn_begin method may fail and throw an exception or return a non-zero error for the following conditions: +

+

ENOMEM
The maximum number of concurrent transactions has been reached. +
+

The DbEnv::txn_begin method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv::txn_begin method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Classes

+DbEnv, DbTxn +

See Also

+DbEnv::set_tx_max, +DbEnv::set_tx_recover, +DbEnv::set_tx_timestamp, +DbTxn::abort, +DbEnv::txn_begin, +DbEnv::txn_checkpoint, +DbTxn::commit, +DbTxn::id, +DbTxn::prepare +and +DbEnv::txn_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/txn_checkpoint.html b/db/docs/api_cxx/txn_checkpoint.html new file mode 100644 index 000000000..3bac70bcc --- /dev/null +++ b/db/docs/api_cxx/txn_checkpoint.html @@ -0,0 +1,75 @@ + + + + + +Berkeley DB: DbEnv::txn_checkpoint + + + + + + + +
+

DbEnv::txn_checkpoint

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbEnv::txn_checkpoint(u_int32_t kbyte, u_int32_t min, u_int32_t flags) const; +

+

Description

+

The DbEnv::txn_checkpoint method flushes the underlying memory pool, +writes a checkpoint record to the log and then flushes the log. +

If either kbyte or min is non-zero, the checkpoint is only +done if there has been activity since the last checkpoint and either +more than min minutes have passed since the last checkpoint, +or if more than kbyte kilobytes of log data have been written since +the last checkpoint. +

The flags parameter must be set to 0 or one of the following +values: +

+

DB_FORCE
Force a checkpoint record even if there has been no activity since the +last checkpoint. +
+

The DbEnv::txn_checkpoint method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, 0 on success, and returns DB_INCOMPLETE if there were pages that needed to be +written to complete the checkpoint but that DbEnv::memp_sync was unable +to write immediately. +

Errors

+

The DbEnv::txn_checkpoint method may fail and throw an exception or return a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +
+

The DbEnv::txn_checkpoint method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv::txn_checkpoint method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Classes

+DbEnv, DbTxn +

See Also

+DbEnv::set_tx_max, +DbEnv::set_tx_recover, +DbEnv::set_tx_timestamp, +DbTxn::abort, +DbEnv::txn_begin, +DbEnv::txn_checkpoint, +DbTxn::commit, +DbTxn::id, +DbTxn::prepare +and +DbEnv::txn_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/txn_class.html b/db/docs/api_cxx/txn_class.html new file mode 100644 index 000000000..7a335f92a --- /dev/null +++ b/db/docs/api_cxx/txn_class.html @@ -0,0 +1,59 @@ + + + + + +Berkeley DB: DbTxn + + + + + + + +
+

DbTxn

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+class DbTxn { ... }; +

+

Description

+

This manual page describes the specific details of the DbTxn class. +

The DbEnv transaction methods and the DbTxn class provide +transaction semantics. Full transaction support is provided by a +collection of modules that provide interfaces to the services required +for transaction processing. These services are recovery, concurrency +control and the management of shared data. +

Transaction semantics can be applied to the access methods described in +Db through method call parameters. +

The model intended for transactional use (and the one that is used by +the access methods) is write-ahead logging to record both before- and +after-images. Locking follows a two-phase protocol, with all locks being +released at transaction commit. +

Classes

+DbEnv, DbTxn +

See Also

+DbEnv::set_tx_max, +DbEnv::set_tx_recover, +DbEnv::set_tx_timestamp, +DbTxn::abort, +DbEnv::txn_begin, +DbEnv::txn_checkpoint, +DbTxn::commit, +DbTxn::id, +DbTxn::prepare +and +DbEnv::txn_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/txn_commit.html b/db/docs/api_cxx/txn_commit.html new file mode 100644 index 000000000..16e20c253 --- /dev/null +++ b/db/docs/api_cxx/txn_commit.html @@ -0,0 +1,87 @@ + + + + + +Berkeley DB: DbTxn::commit + + + + + + + +
+

DbTxn::commit

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbTxn::commit(u_int32_t flags); +

+

Description

+

The DbTxn::commit method ends the transaction. In the case of nested +transactions, if the transaction is a parent transaction, committing +the parent transaction causes all unresolved children of the parent to +be committed. +

In the case of nested transactions, if the transaction is a child +transaction, its locks are not released, but are acquired by its parent. +While the commit of the child transaction will succeed, the actual +resolution of the child transaction is postponed until the parent +transaction is committed or aborted, i.e., if its parent transaction +commits, it will be committed, and if its parent transaction aborts, it +will be aborted. +

The flags parameter must be set to 0 or one of the following +values: +

+

DB_TXN_NOSYNC
Do not synchronously flush the log. This means the transaction will +exhibit the ACI (atomicity, consistency and isolation) properties, but +not D (durability), i.e., database integrity will be maintained but it is +possible that this transaction may be undone during recovery instead of +being redone. +

This behavior may be set for an entire Berkeley DB environment as part of the +DbEnv::set_flags interface. +

DB_TXN_SYNC
Synchronously flush the log. This means the transaction will exhibit +all of the ACID (atomicity, consistency and isolation and durability) +properties. +

This behavior is the default for Berkeley DB environments unless the +DB_TXN_NOSYNC flag was specified to the DbEnv::set_flags +or DbEnv::txn_begin interfaces. +

+

Once the DbTxn::commit method returns, the DbTxn handle may not +be accessed again. If DbTxn::commit encounters an error, the +transaction and all child transactions of the transaction are aborted. +

The DbTxn::commit method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The DbTxn::commit method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbTxn::commit method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Classes

+DbEnv, DbTxn +

See Also

+DbEnv::set_tx_max, +DbEnv::set_tx_recover, +DbEnv::set_tx_timestamp, +DbTxn::abort, +DbEnv::txn_begin, +DbEnv::txn_checkpoint, +DbTxn::commit, +DbTxn::id, +DbTxn::prepare +and +DbEnv::txn_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/txn_id.html b/db/docs/api_cxx/txn_id.html new file mode 100644 index 000000000..9c14adf1c --- /dev/null +++ b/db/docs/api_cxx/txn_id.html @@ -0,0 +1,52 @@ + + + + + +Berkeley DB: DbTxn::id + + + + + + + +
+

DbTxn::id

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+u_int32_t +DbTxn::id(); +

+

Description

+

The DbTxn::id method returns the unique transaction id associated with the +specified transaction. Locking calls made on behalf of this transaction +should use the value returned from DbTxn::id as the locker parameter +to the DbEnv::lock_get or DbEnv::lock_vec calls. +

Classes

+DbEnv, DbTxn +

See Also

+DbEnv::set_tx_max, +DbEnv::set_tx_recover, +DbEnv::set_tx_timestamp, +DbTxn::abort, +DbEnv::txn_begin, +DbEnv::txn_checkpoint, +DbTxn::commit, +DbTxn::id, +DbTxn::prepare +and +DbEnv::txn_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/txn_prepare.html b/db/docs/api_cxx/txn_prepare.html new file mode 100644 index 000000000..de7db8e76 --- /dev/null +++ b/db/docs/api_cxx/txn_prepare.html @@ -0,0 +1,67 @@ + + + + + +Berkeley DB: DbTxn::prepare + + + + + + + +
+

DbTxn::prepare

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+int +DbTxn::prepare(); +

+

Description

+

The DbTxn::prepare method initiates the beginning of a two-phase commit. +

In a distributed transaction environment, Berkeley DB can be used as a local +transaction manager. In this case, the distributed transaction manager +must send prepare messages to each local manager. The local +manager must then issue a DbTxn::prepare and await its successful +return before responding to the distributed transaction manager. Only +after the distributed transaction manager receives successful responses +from all of its prepare messages should it issue any +commit messages. +

In the case of nested transactions, preparing a parent transaction +causes all unresolved children of the parent transaction to be prepared. +

The DbTxn::prepare method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The DbTxn::prepare method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbTxn::prepare method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Classes

+DbEnv, DbTxn +

See Also

+DbEnv::set_tx_max, +DbEnv::set_tx_recover, +DbEnv::set_tx_timestamp, +DbTxn::abort, +DbEnv::txn_begin, +DbEnv::txn_checkpoint, +DbTxn::commit, +DbTxn::id, +DbTxn::prepare +and +DbEnv::txn_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/txn_stat.html b/db/docs/api_cxx/txn_stat.html new file mode 100644 index 000000000..9644a6ae8 --- /dev/null +++ b/db/docs/api_cxx/txn_stat.html @@ -0,0 +1,100 @@ + + + + + +Berkeley DB: DbEnv::txn_stat + + + + + + + +
+

DbEnv::txn_stat

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+extern "C" { + typedef void *(*db_malloc_fcn_type)(size_t); +}; +int +DbEnv::txn_stat(DB_TXN_STAT **statp, db_malloc_fcn_type db_malloc); +

+

Description

+

The DbEnv::txn_stat method +creates a statistical structure and copies a pointer to it into a +user-specified memory location. +

Statistical structures are created in allocated memory. If db_malloc is non-NULL, it +is called to allocate the memory, otherwise, the library function +malloc(3) is used. The function db_malloc must match +the calling conventions of the malloc(3) library routine. +Regardless, the caller is responsible for deallocating the returned +memory. To deallocate returned memory, free the returned memory +reference, references inside the returned memory do not need to be +individually freed. +

The transaction region statistics are stored in a structure of type +DB_TXN_STAT. The following DB_TXN_STAT fields will be filled in: +

+
DbLsn st_last_ckp;
The LSN of the last checkpoint. +
DbLsn st_pending_ckp;
The LSN of any checkpoint that is currently in progress. If +st_pending_ckp is the same as st_last_ckp there +is no checkpoint in progress. +
time_t st_time_ckp;
The time the last completed checkpoint finished (as the number of seconds +since the Epoch, returned by the IEEE/ANSI Std 1003.1 (POSIX) time interface). +
u_int32_t st_last_txnid;
The last transaction ID allocated. +
u_int32_t st_maxtxns;
The maximum number of active transactions possible. +
u_int32_t st_nactive;
The number of transactions that are currently active. +
u_int32_t st_maxnactive;
The maximum number of active transactions at any one time. +
u_int32_t st_nbegins;
The number of transactions that have begun. +
u_int32_t st_naborts;
The number of transactions that have aborted. +
u_int32_t st_ncommits;
The number of transactions that have committed. +
u_int32_t st_regsize;
The size of the region. +
u_int32_t st_region_wait;
The number of times that a thread of control was forced to wait before +obtaining the region lock. +
u_int32_t st_region_nowait;
The number of times that a thread of control was able to obtain +the region lock without waiting. +
DB_TXN_ACTIVE * st_txnarray;
A pointer to an array of st_nactive DB_TXN_ACTIVE structures, +describing the currently active transactions. The following fields of +the DB_TXN_ACTIVE structure will be filled in: +

+

u_int32_t txnid;
The transaction ID as returned by DbEnv::txn_begin. +
u_int32_t parentid;
The transaction ID of the parent transaction (or 0, if no parent). +
DbLsn lsn;
The log sequence number of the transaction-begin record. +
+
+

The DbEnv::txn_stat method either returns a non-zero error value or throws an exception that +encapsulates a non-zero error value on failure, and returns 0 on success. +

Errors

+

The DbEnv::txn_stat method may fail and throw an exception or return a non-zero error for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv::txn_stat method may fail and either +return DB_RUNRECOVERY or throw an exception encapsulating +DB_RUNRECOVERY, in which case all subsequent Berkeley DB calls will fail +in the same way. +

Classes

+DbEnv, DbTxn +

See Also

+DbEnv::set_tx_max, +DbEnv::set_tx_recover, +DbEnv::set_tx_timestamp, +DbTxn::abort, +DbEnv::txn_begin, +DbEnv::txn_checkpoint, +DbTxn::commit, +DbTxn::id, +DbTxn::prepare +and +DbEnv::txn_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_cxx/what.html b/db/docs/api_cxx/what.html new file mode 100644 index 000000000..9e0410c76 --- /dev/null +++ b/db/docs/api_cxx/what.html @@ -0,0 +1,43 @@ + + + + + +Berkeley DB: DbException::what + + + + + + + +
+

DbException::what

+
+APIRef +
+


+ +

+#include <db_cxx.h>
+

+virtual const char * +DbException::what() const; +

+

Description

+

A DbException object contains an informational string and an errno. +The errno can be obtained by using DbException::get_errno. +The informational string can be obtained by using DbException::what. +

Class

+DbException +

See Also

+DbException::get_errno +and +DbException::what. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/db_class.html b/db/docs/api_java/db_class.html new file mode 100644 index 000000000..b03e55c1f --- /dev/null +++ b/db/docs/api_java/db_class.html @@ -0,0 +1,92 @@ + + + + + +Berkeley DB: Db + + + + + + + +
+

Db

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public class Db extends Object +{ + Db(DbEnv dbenv, int flags) + throws DbException; + ... +} +

+

Description

+

This manual page describes the specific details of the Db class, +which is the center of access method activity. +

If no dbenv value is specified, the database is standalone, i.e., +it is not part of any Berkeley DB environment. +

If a dbenv value is specified, the database is created within the +specified Berkeley DB environment. The database access methods automatically +make calls to the other subsystems in Berkeley DB based on the enclosing +environment. For example, if the environment has been configured to use +locking, then the access methods will automatically acquire the correct +locks when reading and writing pages of the database. +

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +

+

Db.DB_XA_CREATE
Instead of creating a standalone database, create a database intended to +be accessed via applications running under a X/Open conformant Transaction +Manager. The database will be opened in the environment specified by the +OPENINFO parameter of the GROUPS section of the ubbconfig file. See the +XA Resource Manager chapter in the +Reference Guide for more information. +
+

Class

+Db +

See Also

+Db.close, +Db.cursor, +Db.del, +Db.fd, +Db.get, +Db.get_byteswapped, +Db.get_type, +Db.join, +Db.key_range, +Db.open, +Db.put, +Db.remove, +Db.set_bt_minkey, +Db.set_cachesize, +Db.set_errcall, +Db.set_errpfx, +Db.set_flags, +Db.set_h_ffactor, +Db.set_h_nelem, +Db.set_lorder, +Db.set_pagesize, +Db.set_q_extentsize, +Db.set_re_delim, +Db.set_re_len, +Db.set_re_pad, +Db.set_re_source, +Db.stat, +Db.sync, +Db.upgrade +and +Db.verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/db_close.html b/db/docs/api_java/db_close.html new file mode 100644 index 000000000..fcb8fde1d --- /dev/null +++ b/db/docs/api_java/db_close.html @@ -0,0 +1,113 @@ + + + + + +Berkeley DB: Db.close + + + + + + + +
+

Db.close

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public int close(int flags) + throws DbException; +

+

Description

+

The Db.close method flushes any cached database information to disk, +closes any open cursors, frees any allocated resources, and closes any +underlying files. Since key/data pairs are cached in memory, failing to +sync the file with the Db.close or Db.sync method may result +in inconsistent or lost information. +

The flags parameter must be set to 0 or the following value: +

+

Db.DB_NOSYNC
Do not flush cached information to disk. +

The Db.DB_NOSYNC flag is a dangerous option. It should only be set +if the application is doing logging (with transactions) so that the +database is recoverable after a system or application crash, or if the +database is always generated from scratch after any system or application +crash. +

It is important to understand that flushing cached information to disk +only minimizes the window of opportunity for corrupted data. +While unlikely, it is possible for database corruption to happen if a +system or application crash occurs while writing data to the database. +To ensure that database corruption never occurs, applications must either: +use transactions and logging with automatic recovery, use logging and +application-specific recovery, or edit a copy of the database, +and, once all applications using the database have successfully called +Db.close, atomically replace the original database with the +updated copy. +

+

When multiple threads are using the Berkeley DB handle concurrently, only a single +thread may call the Db.close method. +

Once Db.close has been called, regardless of its return, the +Db handle may not be accessed again. + +

The Db.close method throws an exception that encapsulates a non-zero error value on +failure, and returns Db.DB_INCOMPLETE if the underlying database still has +dirty pages in the cache. (The only reason to return +Db.DB_INCOMPLETE is if another thread of control was writing pages +in the underlying database file at the same time as the +Db.close method was called. For this reason, a return of +Db.DB_INCOMPLETE can normally be ignored, or, in cases where it is +a possible return value, the Db.DB_NOSYNC option should probably +have been specified.) +

The Db.close method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

The Db.close method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Db.close method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Class

+Db +

See Also

+Db.close, +Db.cursor, +Db.del, +Db.fd, +Db.get, +Db.get_byteswapped, +Db.get_type, +Db.join, +Db.key_range, +Db.open, +Db.put, +Db.remove, +Db.set_bt_minkey, +Db.set_cachesize, +Db.set_errcall, +Db.set_errpfx, +Db.set_flags, +Db.set_h_ffactor, +Db.set_h_nelem, +Db.set_lorder, +Db.set_pagesize, +Db.set_q_extentsize, +Db.set_re_delim, +Db.set_re_len, +Db.set_re_pad, +Db.set_re_source, +Db.stat, +Db.sync, +Db.upgrade +and +Db.verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/db_cursor.html b/db/docs/api_java/db_cursor.html new file mode 100644 index 000000000..2494aad58 --- /dev/null +++ b/db/docs/api_java/db_cursor.html @@ -0,0 +1,94 @@ + + + + + +Berkeley DB: Db.cursor + + + + + + + +
+

Db.cursor

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public Dbc cursor(DbTxn txnid, int flags) + throws DbException; +

+

Description

+

The Db.cursor method +creates a cursor. +

If the file is being accessed under transaction protection, the +txnid parameter is a transaction ID returned from +DbEnv.txn_begin, otherwise, NULL. +

If transaction protection is enabled, cursors must be opened and closed +within the context of a transaction, and the txnid parameter +specifies the transaction context in which the cursor may be used. +

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +

+

Db.DB_WRITECURSOR
Specify that the cursor will be used to update the database. This +flag should only be set when the Db.DB_INIT_CDB flag +was specified to DbEnv.open. +
+

The Db.cursor method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

The Db.cursor method may fail and throw an exception encapsulating a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +
+

The Db.cursor method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Db.cursor method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Class

+Db +

See Also

+Db.close, +Db.cursor, +Db.del, +Db.fd, +Db.get, +Db.get_byteswapped, +Db.get_type, +Db.join, +Db.key_range, +Db.open, +Db.put, +Db.remove, +Db.set_bt_minkey, +Db.set_cachesize, +Db.set_errcall, +Db.set_errpfx, +Db.set_flags, +Db.set_h_ffactor, +Db.set_h_nelem, +Db.set_lorder, +Db.set_pagesize, +Db.set_q_extentsize, +Db.set_re_delim, +Db.set_re_len, +Db.set_re_pad, +Db.set_re_source, +Db.stat, +Db.sync, +Db.upgrade +and +Db.verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/db_del.html b/db/docs/api_java/db_del.html new file mode 100644 index 000000000..0a44190dd --- /dev/null +++ b/db/docs/api_java/db_del.html @@ -0,0 +1,94 @@ + + + + + +Berkeley DB: Db.del + + + + + + + +
+

Db.del

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public int del(DbTxn txnid, Dbt key, int flags) + throws DbException; +

+

Description

+

The Db.del method removes key/data pairs from the database. The +key/data pair associated with the specified key is discarded from +the database. In the presence of duplicate key values, all records +associated with the designated key will be discarded. +

If the file is being accessed under transaction protection, the +txnid parameter is a transaction ID returned from +DbEnv.txn_begin, otherwise, NULL. +

The flags parameter is currently unused, and must be set to 0. +

The Db.del method throws an exception that encapsulates a non-zero error value on +failure, and Db.DB_NOTFOUND if the specified key did not exist in +the file. +

Errors

+

The Db.del method may fail and throw an exception encapsulating a non-zero error for the following conditions: +

+

EACCES
An attempt was made to modify a read-only database. +
+

+

EINVAL
An invalid flag value or parameter was specified. +
+

If the operation was selected to resolve a deadlock, the +Db.del method will fail and +throw a DbDeadlockException exception. +

The Db.del method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Db.del method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Class

+Db +

See Also

+Db.close, +Db.cursor, +Db.del, +Db.fd, +Db.get, +Db.get_byteswapped, +Db.get_type, +Db.join, +Db.key_range, +Db.open, +Db.put, +Db.remove, +Db.set_bt_minkey, +Db.set_cachesize, +Db.set_errcall, +Db.set_errpfx, +Db.set_flags, +Db.set_h_ffactor, +Db.set_h_nelem, +Db.set_lorder, +Db.set_pagesize, +Db.set_q_extentsize, +Db.set_re_delim, +Db.set_re_len, +Db.set_re_pad, +Db.set_re_source, +Db.stat, +Db.sync, +Db.upgrade +and +Db.verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/db_fd.html b/db/docs/api_java/db_fd.html new file mode 100644 index 000000000..77342c2c9 --- /dev/null +++ b/db/docs/api_java/db_fd.html @@ -0,0 +1,79 @@ + + + + + +Berkeley DB: Db.fd + + + + + + + +
+

Db.fd

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public int fd() + throws DbException; +

+

Description

+

The Db.fd method +returns a file descriptor representative of the underlying database. +This method does not fit well into the Java framework and may be removed +in subsequent releases. +

The Db.fd method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

The Db.fd method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Db.fd method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Class

+Db +

See Also

+Db.close, +Db.cursor, +Db.del, +Db.fd, +Db.get, +Db.get_byteswapped, +Db.get_type, +Db.join, +Db.key_range, +Db.open, +Db.put, +Db.remove, +Db.set_bt_minkey, +Db.set_cachesize, +Db.set_errcall, +Db.set_errpfx, +Db.set_flags, +Db.set_h_ffactor, +Db.set_h_nelem, +Db.set_lorder, +Db.set_pagesize, +Db.set_q_extentsize, +Db.set_re_delim, +Db.set_re_len, +Db.set_re_pad, +Db.set_re_source, +Db.stat, +Db.sync, +Db.upgrade +and +Db.verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/db_get.html b/db/docs/api_java/db_get.html new file mode 100644 index 000000000..8fd980e92 --- /dev/null +++ b/db/docs/api_java/db_get.html @@ -0,0 +1,149 @@ + + + + + +Berkeley DB: Db.get + + + + + + + +
+

Db.get

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public int get(DbTxn txnid, Dbt key, Dbt data, int flags) + throws DbException; +

+

Description

+

The Db.get method retrieves key/data pairs from the database. The +byte array +and length of the data associated with the specified key are +returned in the structure referenced by data. +

In the presence of duplicate key values, Db.get will return the +first data item for the designated key. Duplicates are sorted by insert +order except where this order has been overridden by cursor operations. +Retrieval of duplicates requires the use of cursor operations. +See Dbc.get for details. +

If the file is being accessed under transaction protection, the +txnid parameter is a transaction ID returned from +DbEnv.txn_begin, otherwise, NULL. +

The flags parameter must be set to 0 or one of the following +values: +

+

Db.DB_CONSUME
Return the record number and data from the available record closest to +the head of the queue and delete the record. The cursor will be +positioned on the deleted record. The record number will be returned +in key as described in Dbt. The data will be returned +in the data parameter. A record is available if it is not +deleted and is not currently locked. The underlying database must be +of type Queue for Db.DB_CONSUME to be specified. +

Db.DB_CONSUME_WAIT
The Db.DB_CONSUME_WAIT flag is the same as the Db.DB_CONSUME +flag except that if the Queue database is empty, the thread of control +will wait until there is data in the queue before returning. The +underlying database must be of type Queue for Db.DB_CONSUME_WAIT +to be specified. +

Db.DB_GET_BOTH
Retrieve the key/data pair only if both the key and data match the +arguments. +

Db.DB_SET_RECNO
Retrieve the specified numbered key/data pair from a database. +Upon return, both the key and data items will have been +filled in, not just the data item as is done for all other uses of the +Db.get method. +

The data field of the specified key +must be a byte array large enough to hold a logical record +number (i.e., an int). +This record number determines the record to be retrieved. +

For Db.DB_SET_RECNO to be specified, the underlying database must be +of type Btree and it must have been created with the DB_RECNUM flag. +

+

In addition, the following flag may be set by bitwise inclusively OR'ing it into the +flags parameter: +

+

Db.DB_RMW
Acquire write locks instead of read locks when doing the retrieval. +Setting this flag may decrease the likelihood of deadlock during a +read-modify-write cycle by immediately acquiring the write lock during +the read part of the cycle so that another thread of control acquiring +a read lock for the same item, in its own read-modify-write cycle, will +not result in deadlock. +

As the Db.get interface will not hold locks across +Berkeley DB interface calls in non-transactional environments, the +Db.DB_RMW flag to the Db.get call is only meaningful in +the presence of transactions. +

+

If the database is a Queue or Recno database and the requested key exists, +but was never explicitly created by the application or was later deleted, +the Db.get method returns Db.DB_KEYEMPTY. +

Otherwise, if the requested key is not in the database, the +Db.get function returns Db.DB_NOTFOUND. +

Otherwise, the Db.get method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

The Db.get method may fail and throw an exception encapsulating a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +

A record number of 0 was specified. +

The Db.DB_THREAD flag was specified to the +Db.open method and none of the Db.DB_DBT_MALLOC, +Db.DB_DBT_REALLOC or Db.DB_DBT_USERMEM flags were set in the +Dbt. +

+

If the operation was selected to resolve a deadlock, the +Db.get method will fail and +throw a DbDeadlockException exception. +

If the requested item could not be returned due to insufficient memory, +the Db.get method will fail and +throw a DbMemoryException exception. +

The Db.get method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Db.get method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Class

+Db +

See Also

+Db.close, +Db.cursor, +Db.del, +Db.fd, +Db.get, +Db.get_byteswapped, +Db.get_type, +Db.join, +Db.key_range, +Db.open, +Db.put, +Db.remove, +Db.set_bt_minkey, +Db.set_cachesize, +Db.set_errcall, +Db.set_errpfx, +Db.set_flags, +Db.set_h_ffactor, +Db.set_h_nelem, +Db.set_lorder, +Db.set_pagesize, +Db.set_q_extentsize, +Db.set_re_delim, +Db.set_re_len, +Db.set_re_pad, +Db.set_re_source, +Db.stat, +Db.sync, +Db.upgrade +and +Db.verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/db_get_byteswapped.html b/db/docs/api_java/db_get_byteswapped.html new file mode 100644 index 000000000..1ef15479d --- /dev/null +++ b/db/docs/api_java/db_get_byteswapped.html @@ -0,0 +1,75 @@ + + + + + +Berkeley DB: Db.get_byteswapped + + + + + + + +
+

Db.get_byteswapped

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public boolean get_byteswapped(); +

+

Description

+

The Db.get_byteswapped method returns +false +if the underlying database files were created on an architecture +of the same byte order as the current one, and +true +if they were not (i.e., big-endian on a little-endian machine or +vice-versa). This field may be used to determine if application +data needs to be adjusted for this architecture or not. +

Class

+Db +

See Also

+Db.close, +Db.cursor, +Db.del, +Db.fd, +Db.get, +Db.get_byteswapped, +Db.get_type, +Db.join, +Db.key_range, +Db.open, +Db.put, +Db.remove, +Db.set_bt_minkey, +Db.set_cachesize, +Db.set_errcall, +Db.set_errpfx, +Db.set_flags, +Db.set_h_ffactor, +Db.set_h_nelem, +Db.set_lorder, +Db.set_pagesize, +Db.set_q_extentsize, +Db.set_re_delim, +Db.set_re_len, +Db.set_re_pad, +Db.set_re_source, +Db.stat, +Db.sync, +Db.upgrade +and +Db.verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/db_get_type.html b/db/docs/api_java/db_get_type.html new file mode 100644 index 000000000..cc1055619 --- /dev/null +++ b/db/docs/api_java/db_get_type.html @@ -0,0 +1,72 @@ + + + + + +Berkeley DB: Db.get_type + + + + + + + +
+

Db.get_type

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public int get_type(); +

+

Description

+

The Db.get_type method returns the type of the underlying access method +(and file format). It returns one of Db.DB_BTREE, +Db.DB_HASH or Db.DB_RECNO. This value may be used to +determine the type of the database after a return from Db.open +with the type argument set to Db.DB_UNKNOWN. +

Class

+Db +

See Also

+Db.close, +Db.cursor, +Db.del, +Db.fd, +Db.get, +Db.get_byteswapped, +Db.get_type, +Db.join, +Db.key_range, +Db.open, +Db.put, +Db.remove, +Db.set_bt_minkey, +Db.set_cachesize, +Db.set_errcall, +Db.set_errpfx, +Db.set_flags, +Db.set_h_ffactor, +Db.set_h_nelem, +Db.set_lorder, +Db.set_pagesize, +Db.set_q_extentsize, +Db.set_re_delim, +Db.set_re_len, +Db.set_re_pad, +Db.set_re_source, +Db.stat, +Db.sync, +Db.upgrade +and +Db.verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/db_join.html b/db/docs/api_java/db_join.html new file mode 100644 index 000000000..5bdd93fed --- /dev/null +++ b/db/docs/api_java/db_join.html @@ -0,0 +1,142 @@ + + + + + +Berkeley DB: Db.join + + + + + + + +
+

Db.join

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public Dbc join(Dbc curslist[], int flags) + throws DbException; +

+

Description

+

The Db.join method creates a specialized cursor for use in performing +joins on secondary indexes. For information on how to organize your data +to use this functionality, see Logical +join. +

The primary argument contains the Db handle of the primary +database, which is keyed by the data values found in entries in the +curslist. +

The curslist argument contains a null terminated array of cursors. +Each cursor must have been initialized to reference the key on which the +underlying database should be joined. Typically, this initialization is done +by a Dbc.get call with the Db.DB_SET flag specified. Once the +cursors have been passed as part of a curslist, they should not +be accessed or modified until the newly created join cursor has been closed, +or else inconsistent results may be returned. +

Joined values are retrieved by doing a sequential iteration over the first +cursor in the curslist argument, and a nested iteration over each +secondary cursor in the order they are specified in the curslist +argument. This requires database traversals to search for the current +datum in all the cursors after the first. For this reason, the best join +performance normally results from sorting the cursors from the one that +references the least number of data items to the one that references the +most. By default, Db.join does this sort on behalf of its caller. +

The flags parameter must be set to 0 or the following value: +

+

Db.DB_JOIN_NOSORT
Do not sort the cursors based on the number of data items they reference. +If the data are structured such that cursors with many data items also +share many common elements, higher performance will result from listing +those cursors before cursors with fewer data items, that is, a sort order +other than the default. The Db.DB_JOIN_NOSORT flag permits +applications to perform join optimization prior to calling Db.join. +
+

The returned cursor has the standard cursor functions: +

+

Dbc.get
Iterates over the values associated with the keys to which each item in +curslist has been initialized. Any data value which appears in +all items specified by the curslist argument is then used as a +key into the primary, and the key/data pair found in the +primary is returned. +

The flags parameter must be set to 0 or the following value: +

+

Db.DB_JOIN_ITEM
Do not use the data value found in all of the cursors as a lookup +key for the primary, but simply return it in the key parameter +instead. The data parameter is left unchanged. +
+

In addition, the following flag may be set by bitwise inclusively OR'ing it into the +flags parameter: +

+

Db.DB_RMW
Acquire write locks instead of read locks when doing the retrieval. +Setting this flag may decrease the likelihood of deadlock during a +read-modify-write cycle by immediately acquiring the write lock during +the read part of the cycle so that another thread of control acquiring +a read lock for the same item, in its own read-modify-write cycle, will +not result in deadlock. +
+

Dbc.put
Returns EINVAL. +

Dbc.del
Returns EINVAL. +

Dbc.close
Close the returned cursor and release all resources. (Closing the cursors +in curslist is the responsibility of the caller.) +
+

For the returned join cursor to be used in a transaction protected manner, +the cursors listed in curslist must have been created within the +context of the same transaction. +

The Db.join method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

The Db.join method may fail and throw an exception encapsulating a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +

The Dbc.put or Dbc.del functions were called. +

+

The Db.join method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Db.join method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Class

+Db +

See Also

+Db.close, +Db.cursor, +Db.del, +Db.fd, +Db.get, +Db.get_byteswapped, +Db.get_type, +Db.join, +Db.key_range, +Db.open, +Db.put, +Db.remove, +Db.set_bt_minkey, +Db.set_cachesize, +Db.set_errcall, +Db.set_errpfx, +Db.set_flags, +Db.set_h_ffactor, +Db.set_h_nelem, +Db.set_lorder, +Db.set_pagesize, +Db.set_q_extentsize, +Db.set_re_delim, +Db.set_re_len, +Db.set_re_pad, +Db.set_re_source, +Db.stat, +Db.sync, +Db.upgrade +and +Db.verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/db_key_range.html b/db/docs/api_java/db_key_range.html new file mode 100644 index 000000000..dd68e0e1a --- /dev/null +++ b/db/docs/api_java/db_key_range.html @@ -0,0 +1,99 @@ + + + + + +Berkeley DB: Db.key_range + + + + + + + +
+

Db.key_range

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void key_range(DbTxn txnid + Dbt key, DbKeyRange key_range, int flags) + throws DbException; +

+

Description

+

The Db.key_range method returns an estimate of the proportion of keys +that are less than, equal to and greater than the specified key. The +underlying database must be of type Btree. +

The information is returned in the key_range argument, which +contains three elements of type double, less, equal and +greater. Values are in the range of 0 to 1, e.g., if the field +less is 0.05, that indicates that 5% of the keys in the database +are less than the key argument. The value for equal will be zero +if there is no matching key and non-zero otherwise. +

If the file is being accessed under transaction protection, the +txnid parameter is a transaction ID returned from +DbEnv.txn_begin, otherwise, NULL. +The Db.key_range method does not retain the locks it acquires for the +life of the transaction, so estimates may not be repeatable. +

The flags parameter is currently unused, and must be set to 0. +

The Db.key_range method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

The Db.key_range method may fail and throw an exception encapsulating a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +

The underlying database was not of type Btree. +

+

If the operation was selected to resolve a deadlock, the +Db.key_range method will fail and +throw a DbDeadlockException exception. +

The Db.key_range method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Db.key_range method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Class

+Db +

See Also

+Db.close, +Db.cursor, +Db.del, +Db.fd, +Db.get, +Db.get_byteswapped, +Db.get_type, +Db.join, +Db.key_range, +Db.open, +Db.put, +Db.remove, +Db.set_bt_minkey, +Db.set_cachesize, +Db.set_errcall, +Db.set_errpfx, +Db.set_flags, +Db.set_h_ffactor, +Db.set_h_nelem, +Db.set_lorder, +Db.set_pagesize, +Db.set_q_extentsize, +Db.set_re_delim, +Db.set_re_len, +Db.set_re_pad, +Db.set_re_source, +Db.stat, +Db.sync, +Db.upgrade +and +Db.verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/db_open.html b/db/docs/api_java/db_open.html new file mode 100644 index 000000000..5371e10bb --- /dev/null +++ b/db/docs/api_java/db_open.html @@ -0,0 +1,179 @@ + + + + + +Berkeley DB: Db.open + + + + + + + +
+

Db.open

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+import java.io.FileNotFoundException;
+

+public void open(String file, + String database, int type, int flags, int mode) + throws DbException, FileNotFoundException; +

+

Description

+

The currently supported Berkeley DB file formats (or access methods) +are Btree, Hash, Queue and Recno. The Btree format is a representation +of a sorted, balanced tree structure. The Hash format is an extensible, +dynamic hashing scheme. The Queue format supports fast access to +fixed-length records accessed by sequentially or logical record number. +The Recno format supports fixed- or variable-length records, accessed +sequentially or by logical record number, and optionally retrieved from +a flat text file. +

Storage and retrieval for the Berkeley DB access methods are based on key/data +pairs, see Dbt for more information. +

The Db.open interface opens the database represented by the +file and database arguments for both reading and writing. +The file argument is used as the name of a physical file on disk +that will be used to back the database. The database argument is +optional and allows applications to have multiple logical databases in a +single physical file. While no database argument needs to be +specified, it is an error to attempt to open a second database in a +file that was not initially created using a database name. +In-memory databases never intended to be preserved on disk may +be created by setting both the file and database arguments +to null. Note that in-memory databases can only ever be shared by +sharing the single database handle that created them, in circumstances +where doing so is safe. +

The type argument is of type int +and must be set to one of Db.DB_BTREE, Db.DB_HASH, +Db.DB_QUEUE, Db.DB_RECNO or Db.DB_UNKNOWN, except +that databases of type Db.DB_QUEUE are restricted to one per +file. If type is Db.DB_UNKNOWN, the database must +already exist and Db.open will automatically determine its type. +The Db.get_type method may be used to determine the underlying type of +databases opened using Db.DB_UNKNOWN. +

The flags and mode arguments specify how files will be opened +and/or created if they do not already exist. +

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +

+

Db.DB_CREATE
Create any underlying files, as necessary. If the files do not already +exist and the DB_CREATE flag is not specified, the call will fail. +

Db.DB_EXCL
Return an error if the file already exists. Underlying filesystem +primitives are used to implement this flag. For this reason it is only +applicable to the physical file and cannot be used to test if a database +in a file already exists. +

The Db.DB_EXCL flag is only meaningful when specified with the +Db.DB_CREATE flag. +

Db.DB_NOMMAP
Do not map this database into process memory (see the description of the +DbEnv.set_mp_mmapsize method for further information). +

Db.DB_RDONLY
Open the database for reading only. Any attempt to modify items in the +database will fail regardless of the actual permissions of any underlying +files. +

Db.DB_THREAD
Cause the Db handle returned by Db.open to be +free-threaded, that is, useable by multiple threads within a +single address space. +

Threading is always assumed in the Java API, so no special flags are +required, and Berkeley DB functions will always behave as if the +Db.DB_THREAD flag was specified. +

Db.DB_TRUNCATE
Physically truncate the underlying file, discarding all previous databases +it might have held. Underlying filesystem primitives are used to +implement this flag. For this reason it is only applicable to the +physical file and cannot be used to discard databases within a file. +

The Db.DB_TRUNCATE flag cannot be transaction protected, and it is +an error to specify it in a transaction protected environment. +

+

On UNIX systems, or in IEEE/ANSI Std 1003.1 (POSIX) environments, all files created by the access methods +are created with mode mode (as described in chmod(2)) and +modified by the process' umask value at the time of creation (see +umask(2)). The group ownership of created files is based on +the system and directory defaults, and is not further specified by Berkeley DB. +If mode is 0, files are created readable and writeable by both +owner and group. On Windows systems, the mode argument is ignored. +

Calling Db.open is a reasonably expensive operation, and +maintaining a set of open databases will normally be preferable to +repeatedly open and closing the database for each new query. +

The Db.open method throws an exception that encapsulates a non-zero error value on +failure. +

Environment Variables

+

+

DB_HOME
If the dbenv argument to db_create was initialized using +DbEnv.open the environment variable DB_HOME may be used +as the path of the database environment home. Specifically, Db.open +is affected by the configuration value DB_DATA_DIR. +
+

+

TMPDIR
If the file and dbenv arguments to Db.open are +null, the environment variable TMPDIR may be used as a +directory in which to create a temporary backing file. +
+

Errors

+

The Db.open method may fail and throw an exception encapsulating a non-zero error for the following conditions: +

+

Db.DB_OLD_VERSION
The database cannot be opened without being first upgraded. +

EEXIST
DB_CREATE and DB_EXCL were specified and the file exists. +

EINVAL
An invalid flag value or parameter was specified (e.g., unknown database +type, page size, hash function, pad byte, byte order) or a flag value +or parameter that is incompatible with the specified database. +

+The Db.DB_THREAD flag was specified and spinlocks are not +implemented for this architecture. +

The Db.DB_THREAD flag was specified to Db.open, but was not +specified to the DbEnv.open call for the environment in which the +Db handle was created. +

A re_source file was specified with either the Db.DB_THREAD +flag or the provided database environment supports transaction +processing. +

ENOENT
A non-existent re_source file was specified. +
+

The Db.open method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Db.open method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Class

+Db +

See Also

+Db.close, +Db.cursor, +Db.del, +Db.fd, +Db.get, +Db.get_byteswapped, +Db.get_type, +Db.join, +Db.key_range, +Db.open, +Db.put, +Db.remove, +Db.set_bt_minkey, +Db.set_cachesize, +Db.set_errcall, +Db.set_errpfx, +Db.set_flags, +Db.set_h_ffactor, +Db.set_h_nelem, +Db.set_lorder, +Db.set_pagesize, +Db.set_q_extentsize, +Db.set_re_delim, +Db.set_re_len, +Db.set_re_pad, +Db.set_re_source, +Db.stat, +Db.sync, +Db.upgrade +and +Db.verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/db_put.html b/db/docs/api_java/db_put.html new file mode 100644 index 000000000..41fe6dcff --- /dev/null +++ b/db/docs/api_java/db_put.html @@ -0,0 +1,128 @@ + + + + + +Berkeley DB: Db.put + + + + + + + +
+

Db.put

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public int put(DbTxn txnid, Dbt key, Dbt data, int flags) + throws DbException; +

+

Description

+

The Db.put method stores key/data pairs in the database. The default +behavior of the Db.put function is to enter the new key/data +pair, replacing any previously existing key if duplicates are disallowed, +or adding a duplicate data item if duplicates are allowed. If the database +supports duplicates, the Db.put method adds the new data value at the +end of the duplicate set. If the database supports sorted duplicates, +the new data value is inserted at the correct sorted location. +

If the file is being accessed under transaction protection, the +txnid parameter is a transaction ID returned from +DbEnv.txn_begin, otherwise, NULL. +

The flags parameter must be set to 0 or one of the following +values: +

+

Db.DB_APPEND
Append the key/data pair to the end of the database. For the +Db.DB_APPEND flag to be specified, the underlying database must be +a Queue or Recno database. The record number allocated to the record is +returned in the specified key. +

There is a minor behavioral difference between the Recno and Queue access +methods for the Db.DB_APPEND flag. If a transaction enclosing a +Db.put operation with the Db.DB_APPEND flag aborts, the +record number may be decremented (and later re-allocated by a subsequent +Db.DB_APPEND operation) by the Recno access method, but will not be +decremented or re-allocated by the Queue access method. +

Db.DB_NODUPDATA
In the case of the Btree and Hash access methods, enter the new key/data +pair only if it does not already appear in the database. If the +key/data pair already appears in the database, Db.DB_KEYEXIST is +returned. The Db.DB_NODUPDATA flag may only be specified if the +underlying database has been configured to support sorted duplicates. +

The Db.DB_NODUPDATA flag may not be specified to the Queue or Recno +access methods. +

Db.DB_NOOVERWRITE
Enter the new key/data pair only if the key does not already appear in +the database. If the key already appears in the database, +Db.DB_KEYEXIST is returned. Even if the database allows duplicates, +a call to Db.put with the Db.DB_NOOVERWRITE flag set will +fail if the key already exists in the database. +
+

Otherwise, the Db.put method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

The Db.put method may fail and throw an exception encapsulating a non-zero error for the following conditions: +

+

EACCES
An attempt was made to modify a read-only database. +
+

+

EINVAL
An invalid flag value or parameter was specified. +

A record number of 0 was specified. +

An attempt was made to add a record to a fixed-length database that was too +large to fit. +

An attempt was made to do a partial put. +

+

+

ENOSPC
A btree exceeded the maximum btree depth (255). +
+

If the operation was selected to resolve a deadlock, the +Db.put method will fail and +throw a DbDeadlockException exception. +

The Db.put method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Db.put method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Class

+Db +

See Also

+Db.close, +Db.cursor, +Db.del, +Db.fd, +Db.get, +Db.get_byteswapped, +Db.get_type, +Db.join, +Db.key_range, +Db.open, +Db.put, +Db.remove, +Db.set_bt_minkey, +Db.set_cachesize, +Db.set_errcall, +Db.set_errpfx, +Db.set_flags, +Db.set_h_ffactor, +Db.set_h_nelem, +Db.set_lorder, +Db.set_pagesize, +Db.set_q_extentsize, +Db.set_re_delim, +Db.set_re_len, +Db.set_re_pad, +Db.set_re_source, +Db.stat, +Db.sync, +Db.upgrade +and +Db.verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/db_remove.html b/db/docs/api_java/db_remove.html new file mode 100644 index 000000000..d1238451c --- /dev/null +++ b/db/docs/api_java/db_remove.html @@ -0,0 +1,104 @@ + + + + + +Berkeley DB: Db.remove + + + + + + + +
+

Db.remove

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+import java.io.FileNotFoundException;
+

+public void remove(String file, String database, int flags) + throws DbException, FileNotFoundException; +

+

Description

+

The Db.remove interface removes the database specified by the +file and database arguments. If no database is +specified, the physical file represented by file is removed, +incidentally removing all databases that it contained. +

If a physical file is being removed and logging is currently enabled in +the database environment, no database in the file may be open when the +Db.remove method is called. Otherwise, no reference count of database +use is maintained by Berkeley DB. Applications should not remove databases that +are currently in use. In particular, some architectures do not permit +the removal of files with open handles. On these architectures, attempts +to remove databases that are currently in use will fail. +

The flags parameter is currently unused, and must be set to 0. +

Once Db.remove has been called, regardless of its return, the +Db handle may not be accessed again. +

The Db.remove method throws an exception that encapsulates a non-zero error value on +failure. +

Environment Variables

+

+

DB_HOME
If the dbenv argument to db_create was initialized using +DbEnv.open the environment variable DB_HOME may be used +as the path of the database environment home. Specifically, Db.remove +is affected by the configuration value DB_DATA_DIR. +
+

Errors

+

The Db.remove method may fail and throw an exception encapsulating a non-zero error for the following conditions: +

+

EINVAL
A database in the file is currently open. +
+

If the file or directory does not exist, the Db.remove method will +fail and +throw a FileNotFoundException exception. +

The Db.remove method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Db.remove method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Class

+Db +

See Also

+Db.close, +Db.cursor, +Db.del, +Db.fd, +Db.get, +Db.get_byteswapped, +Db.get_type, +Db.join, +Db.key_range, +Db.open, +Db.put, +Db.remove, +Db.set_bt_minkey, +Db.set_cachesize, +Db.set_errcall, +Db.set_errpfx, +Db.set_flags, +Db.set_h_ffactor, +Db.set_h_nelem, +Db.set_lorder, +Db.set_pagesize, +Db.set_q_extentsize, +Db.set_re_delim, +Db.set_re_len, +Db.set_re_pad, +Db.set_re_source, +Db.stat, +Db.sync, +Db.upgrade +and +Db.verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/db_rename.html b/db/docs/api_java/db_rename.html new file mode 100644 index 000000000..b34f20a26 --- /dev/null +++ b/db/docs/api_java/db_rename.html @@ -0,0 +1,105 @@ + + + + + +Berkeley DB: Db.rename + + + + + + + +
+

Db.rename

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+import java.io.FileNotFoundException;
+

+public void rename(String file, String database, String newname, int flags) + throws DbException, FileNotFoundException; +

+

Description

+

The Db.rename interface renames the database specified by the +file and database arguments to newname. If no +database is specified, the physical file represented by +file is renamed, incidentally renaming all databases that it +contained. +

If a physical file is being renamed and logging is currently enabled in +the database environment, no database in the file may be open when the +Db.rename method is called. Otherwise, no reference count of database +use is maintained by Berkeley DB. Applications should not rename databases that +are currently in use. In particular, some architectures do not permit +renaming files with open handles. On these architectures, attempts to +rename databases that are currently in use will fail. +

The flags parameter is currently unused, and must be set to 0. +

Once Db.rename has been called, regardless of its return, the +Db handle may not be accessed again. +

The Db.rename method throws an exception that encapsulates a non-zero error value on +failure. +

Environment Variables

+

+

DB_HOME
If the dbenv argument to db_create was initialized using +DbEnv.open the environment variable DB_HOME may be used +as the path of the database environment home. Specifically, Db.rename +is affected by the configuration value DB_DATA_DIR. +
+

Errors

+

The Db.rename method may fail and throw an exception encapsulating a non-zero error for the following conditions: +

+

EINVAL
A database in the file is currently open. +
+

If the file or directory does not exist, the Db.rename method will +fail and +throw a FileNotFoundException exception. +

The Db.rename method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Db.rename method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Class

+Db +

See Also

+Db.close, +Db.cursor, +Db.del, +Db.fd, +Db.get, +Db.get_byteswapped, +Db.get_type, +Db.join, +Db.key_range, +Db.open, +Db.put, +Db.remove, +Db.set_bt_minkey, +Db.set_cachesize, +Db.set_errcall, +Db.set_errpfx, +Db.set_flags, +Db.set_h_ffactor, +Db.set_h_nelem, +Db.set_lorder, +Db.set_pagesize, +Db.set_q_extentsize, +Db.set_re_delim, +Db.set_re_len, +Db.set_re_pad, +Db.set_re_source, +Db.stat, +Db.sync, +Db.upgrade +and +Db.verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/db_set_append_recno.html b/db/docs/api_java/db_set_append_recno.html new file mode 100644 index 000000000..8a4d4a0df --- /dev/null +++ b/db/docs/api_java/db_set_append_recno.html @@ -0,0 +1,75 @@ + + + + + +Berkeley DB: Db.set_append_recno + + + + + + + +
+

Db.set_append_recno

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public interface DbAppendRecno +{ + public abstract void db_append_recno(Db db, Dbt data, int recno); + throws DbException; +} +public class Db +{ + public void set_append_recno(DbAppendRecno db_append_recno) + throws DbException; + ... +} +

+

Description

+

When using the Db.DB_APPEND option of the Db.put method, +it may be useful to modify the stored data based on the generated key. +If a callback method is specified using the +Db.set_append_recno method, it will be called after the record number +has been selected but before the data has been stored. +The callback function must throw a DbException object to +encapsulate the error on failure. That object will be thrown to +caller of Db.put. +

The called function must take three arguments: a reference to the +enclosing database handle, the data Dbt to be stored and the +selected record number. The called function may then modify the data +Dbt. +

The Db.set_append_recno interface may only be used to configure Berkeley DB before +the Db.open interface is called. +

The Db.set_append_recno method throws an exception that encapsulates a non-zero error value on +failure. +

Class

+DbEnv +

See Also

+DbEnv.close, +DbEnv.open, +DbEnv.remove, +DbEnv.strerror, +DbEnv.get_version_string +DbEnv.set_cachesize, +DbEnv.set_errcall, +DbEnv.set_error_stream, +DbEnv.set_errpfx, +DbEnv.set_flags, +DbEnv.set_mutexlocks, +and +DbEnv.set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/db_set_bt_compare.html b/db/docs/api_java/db_set_bt_compare.html new file mode 100644 index 000000000..2a2ea869b --- /dev/null +++ b/db/docs/api_java/db_set_bt_compare.html @@ -0,0 +1,105 @@ + + + + + +Berkeley DB: Db.set_bt_compare + + + + + + + +
+

Db.set_bt_compare

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public interface DbBtreeCompare +{ + public abstract int bt_compare(Db db, Dbt dbt1, Dbt dbt2); +} +public class Db +{ + public void set_bt_compare(DbBtreeCompare bt_compare) + throws DbException; + ... +} +

+

Description

+

Set the Btree key comparison function. The comparison function is +called when it is necessary to compare a key specified by the +application with a key currently stored in the tree. The first argument +to the comparison function is the Dbt representing the +application supplied key, the second is the current tree's key. +

The comparison function must return an integer value less than, equal +to, or greater than zero if the first key argument is considered to be +respectively less than, equal to, or greater than the second key +argument. In addition, the comparison function must cause the keys in +the database to be well-ordered. The comparison function +must correctly handle any key values used by the application (possibly +including zero-length keys). In addition, when Btree key prefix +comparison is being performed (see Db.set_bt_prefix for more +information), the comparison routine may be passed a prefix of any +database key. The data and size fields of the +Dbt are the only fields that may be used for the purposes of +this comparison. +

If no comparison function is specified, the keys are compared lexically, +with shorter keys collating before longer keys. The same comparison +method must be used each time a particular Btree is opened. +

The Db.set_bt_compare interface may only be used to configure Berkeley DB before +the Db.open interface is called. +

The Db.set_bt_compare method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after Db.open was called. +

+

Class

+Db +

See Also

+Db.close, +Db.cursor, +Db.del, +Db.fd, +Db.get, +Db.get_byteswapped, +Db.get_type, +Db.join, +Db.key_range, +Db.open, +Db.put, +Db.remove, +Db.set_bt_minkey, +Db.set_cachesize, +Db.set_errcall, +Db.set_errpfx, +Db.set_flags, +Db.set_h_ffactor, +Db.set_h_nelem, +Db.set_lorder, +Db.set_pagesize, +Db.set_q_extentsize, +Db.set_re_delim, +Db.set_re_len, +Db.set_re_pad, +Db.set_re_source, +Db.stat, +Db.sync, +Db.upgrade +and +Db.verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/db_set_bt_minkey.html b/db/docs/api_java/db_set_bt_minkey.html new file mode 100644 index 000000000..dc7c17451 --- /dev/null +++ b/db/docs/api_java/db_set_bt_minkey.html @@ -0,0 +1,85 @@ + + + + + +Berkeley DB: Db.set_bt_minkey + + + + + + + +
+

Db.set_bt_minkey

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public int set_bt_minkey(int bt_minkey) + throws DbException; +

+

Description

+

Set the minimum number of keys that will be stored on any single +Btree page. +

This value is used to determine which keys will be stored on overflow +pages, i.e. if a key or data item is larger than the underlying database +page size divided by the bt_minkey value, it will be stored on +overflow pages instead of within the page itself. The bt_minkey +value specified must be at least 2; if bt_minkey is not explicitly +set, a value of 2 is used. +

The Db.set_bt_minkey interface may only be used to configure Berkeley DB before +the Db.open interface is called. +

The Db.set_bt_minkey method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after Db.open was called. +

+

Class

+Db +

See Also

+Db.close, +Db.cursor, +Db.del, +Db.fd, +Db.get, +Db.get_byteswapped, +Db.get_type, +Db.join, +Db.key_range, +Db.open, +Db.put, +Db.remove, +Db.set_bt_minkey, +Db.set_cachesize, +Db.set_errcall, +Db.set_errpfx, +Db.set_flags, +Db.set_h_ffactor, +Db.set_h_nelem, +Db.set_lorder, +Db.set_pagesize, +Db.set_q_extentsize, +Db.set_re_delim, +Db.set_re_len, +Db.set_re_pad, +Db.set_re_source, +Db.stat, +Db.sync, +Db.upgrade +and +Db.verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/db_set_bt_prefix.html b/db/docs/api_java/db_set_bt_prefix.html new file mode 100644 index 000000000..a6e823969 --- /dev/null +++ b/db/docs/api_java/db_set_bt_prefix.html @@ -0,0 +1,106 @@ + + + + + +Berkeley DB: Db.set_bt_prefix + + + + + + + +
+

Db.set_bt_prefix

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public interface DbBtreePrefix +{ + public abstract int bt_prefix(Db db, Dbt dbt1, Dbt dbt2); +} +public class Db +{ + public void set_bt_prefix(DbBtreePrefix bt_prefix) + throws DbException; + ... +} +

+

Description

+

Set the Btree prefix function. The prefix function must return the +number of bytes of the second key argument that would be required by +the Btree key comparison function to determine the second key argument's +ordering relationship with respect to the first key argument. If the +two keys are equal, the key length should be returned. The prefix +function must correctly handle any key values used by the application +(possibly including zero-length keys). The data and +size fields of the Dbt are the only fields that may be +used for the purposes of this determination. +

The prefix function is used to determine the amount by which keys stored +on the Btree internal pages can be safely truncated without losing their +uniqueness. See the Btree +prefix comparison section of the Reference Guide for more details about +how this works. The usefulness of this is data dependent, but in some +data sets can produce significantly reduced tree sizes and search times. +

If no prefix function or key comparison function is specified by the +application, a default lexical comparison function is used as the prefix +function. If no prefix function is specified and a key comparison +function is specified, no prefix function is used. It is an error to +specify a prefix function without also specifying a key comparison +function. +

The Db.set_bt_prefix interface may only be used to configure Berkeley DB before +the Db.open interface is called. +

The Db.set_bt_prefix method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after Db.open was called. +

+

Class

+Db +

See Also

+Db.close, +Db.cursor, +Db.del, +Db.fd, +Db.get, +Db.get_byteswapped, +Db.get_type, +Db.join, +Db.key_range, +Db.open, +Db.put, +Db.remove, +Db.set_bt_minkey, +Db.set_cachesize, +Db.set_errcall, +Db.set_errpfx, +Db.set_flags, +Db.set_h_ffactor, +Db.set_h_nelem, +Db.set_lorder, +Db.set_pagesize, +Db.set_q_extentsize, +Db.set_re_delim, +Db.set_re_len, +Db.set_re_pad, +Db.set_re_source, +Db.stat, +Db.sync, +Db.upgrade +and +Db.verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/db_set_cachesize.html b/db/docs/api_java/db_set_cachesize.html new file mode 100644 index 000000000..67313aa5d --- /dev/null +++ b/db/docs/api_java/db_set_cachesize.html @@ -0,0 +1,99 @@ + + + + + + +Berkeley DB: Db.set_cachesize + + + + + + + +
+

Db.set_cachesize

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public int set_cachesize(int gbytes, int bytes, int ncache) + throws DbException; +

+

Description

+

Set the size of the database's shared memory buffer pool, i.e., the cache, +to gbytes gigabytes plus bytes. The cache should be the +size of the normal working data set of the application, with some small +amount of additional memory for unusual situations. (Note, the working +set is not the same as the number of simultaneously referenced pages, and +should be quite a bit larger!) +

The default cache size is 256KB, and may not be specified as less than +20KB. Any cache size less than 500MB is automatically increased by 25% +to account for buffer pool overhead, cache sizes larger than 500MB are +used as specified. For information on tuning the Berkeley DB cache size, see +Selecting a cache size. +

It is possible to specify caches to Berkeley DB that are large enough so that +they cannot be allocated contiguously on some architectures, e.g., some +releases of Solaris limit the amount of memory that may be allocated +contiguously by a process. If ncache is 0 or 1, the cache will +be allocated contiguously in memory. If it is greater than 1, the cache +will be broken up into ncache equally sized separate pieces of +memory. +

As databases opened within Berkeley DB environments use the cache specified to +the environment, it is an error to attempt to set a cache in a database +created within an environment. +

The Db.set_cachesize interface may only be used to configure Berkeley DB before +the Db.open interface is called. +

The Db.set_cachesize method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

The specified cache size was impossibly small. +

+

Class

+Db +

See Also

+Db.close, +Db.cursor, +Db.del, +Db.fd, +Db.get, +Db.get_byteswapped, +Db.get_type, +Db.join, +Db.key_range, +Db.open, +Db.put, +Db.remove, +Db.set_bt_minkey, +Db.set_cachesize, +Db.set_errcall, +Db.set_errpfx, +Db.set_flags, +Db.set_h_ffactor, +Db.set_h_nelem, +Db.set_lorder, +Db.set_pagesize, +Db.set_q_extentsize, +Db.set_re_delim, +Db.set_re_len, +Db.set_re_pad, +Db.set_re_source, +Db.stat, +Db.sync, +Db.upgrade +and +Db.verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/db_set_dup_compare.html b/db/docs/api_java/db_set_dup_compare.html new file mode 100644 index 000000000..ea12dda35 --- /dev/null +++ b/db/docs/api_java/db_set_dup_compare.html @@ -0,0 +1,102 @@ + + + + + +Berkeley DB: Db.set_dup_compare + + + + + + + +
+

Db.set_dup_compare

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public interface DbDupCompare +{ + public abstract int dup_compare(Db db, Dbt dbt1, Dbt dbt2); +} +public class Db +{ + public void set_dup_compare(DbDupCompare dup_compare) + throws DbException; + ... +} +

+

Description

+

Set the duplicate data item comparison function. The comparison function +is called when it is necessary to compare a data item specified by the +application with a data item currently stored in the tree. The first +argument to the comparison function is the Dbt representing the +application's data item, the second is the current tree's data item. +

The comparison function must return an integer value less than, equal +to, or greater than zero if the first data item argument is considered +to be respectively less than, equal to, or greater than the second data +item argument. In addition, the comparison function must cause the data +items in the set to be well-ordered. The comparison function +must correctly handle any data item values used by the application +(possibly including zero-length data items). The data and +size fields of the Dbt are the only fields that may be +used for the purposes of this comparison. +

If no comparison function is specified, the data items are compared +lexically, with shorter data items collating before longer data items. +The same duplicate data item comparison method must be used each time +a particular Btree is opened. +

The Db.set_dup_compare interface may only be used to configure Berkeley DB before +the Db.open interface is called. +

The Db.set_dup_compare method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

Class

+Db +

See Also

+Db.close, +Db.cursor, +Db.del, +Db.fd, +Db.get, +Db.get_byteswapped, +Db.get_type, +Db.join, +Db.key_range, +Db.open, +Db.put, +Db.remove, +Db.set_bt_minkey, +Db.set_cachesize, +Db.set_errcall, +Db.set_errpfx, +Db.set_flags, +Db.set_h_ffactor, +Db.set_h_nelem, +Db.set_lorder, +Db.set_pagesize, +Db.set_q_extentsize, +Db.set_re_delim, +Db.set_re_len, +Db.set_re_pad, +Db.set_re_source, +Db.stat, +Db.sync, +Db.upgrade +and +Db.verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/db_set_errcall.html b/db/docs/api_java/db_set_errcall.html new file mode 100644 index 000000000..62f39f6b3 --- /dev/null +++ b/db/docs/api_java/db_set_errcall.html @@ -0,0 +1,81 @@ + + + + + + +Berkeley DB: Db.set_errcall + + + + + + + +
+

Db.set_errcall

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public interface DbErrcall +{ + public abstract void errcall(String errpfx, String msg); +} +public class Db +{ + public void set_errcall(DbErrcall errcall); + ... +} +

+

Description

+When an error occurs in the Berkeley DB library, an exception is thrown. In +some cases, however, the errno value may be insufficient to +completely describe the cause of the error, especially during initial +application debugging. +

The Db.set_errcall method is used to enhance the mechanism for reporting error +messages to the application. The DbEnv.set_errcall method must be +called with a single object argument. The object's class must implement +the DbErrcall interface. In some cases, when an error occurs, Berkeley DB will +invoke the object's errcall() method with two arguments; the first is the +prefix string (as previously set by Db.set_errpfx or +DbEnv.set_errpfx), the second will be an error message string. +It is up to this method to display the message in an appropriate manner. +

Alternatively, you can use the DbEnv.set_error_stream method to display +the additional information via an output stream. You should not mix these +approaches. +

This error logging enhancement does not slow performance or significantly +increase application size, and may be run during normal operation as well +as during application debugging. +

For Db handles opened inside of Berkeley DB environments, calling the +Db.set_errcall method affects the entire environment and is equivalent to calling +the DbEnv.set_errcall method. +

The Db.set_errcall interface may be used to configure Berkeley DB at any time +during the life of the application. +

Class

+DbEnv +

See Also

+DbEnv.close, +DbEnv.open, +DbEnv.remove, +DbEnv.strerror, +DbEnv.get_version_string +DbEnv.set_cachesize, +DbEnv.set_errcall, +DbEnv.set_error_stream, +DbEnv.set_errpfx, +DbEnv.set_flags, +DbEnv.set_mutexlocks, +and +DbEnv.set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/db_set_errpfx.html b/db/docs/api_java/db_set_errpfx.html new file mode 100644 index 000000000..36db5bd8a --- /dev/null +++ b/db/docs/api_java/db_set_errpfx.html @@ -0,0 +1,55 @@ + + + + + +Berkeley DB: Db.set_errpfx + + + + + + + +
+

Db.set_errpfx

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void set_errpfx(String errpfx); +

+

Description

+

Set the prefix string that appears before error messages issued by Berkeley DB. +

For Db handles opened inside of Berkeley DB environments, calling the +Db.set_errpfx method affects the entire environment and is equivalent to calling +the DbEnv.set_errpfx method. +

The Db.set_errpfx interface may be used to configure Berkeley DB at any time +during the life of the application. +

Class

+DbEnv +

See Also

+DbEnv.close, +DbEnv.open, +DbEnv.remove, +DbEnv.strerror, +DbEnv.get_version_string +DbEnv.set_cachesize, +DbEnv.set_errcall, +DbEnv.set_error_stream, +DbEnv.set_errpfx, +DbEnv.set_flags, +DbEnv.set_mutexlocks, +and +DbEnv.set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/db_set_feedback.html b/db/docs/api_java/db_set_feedback.html new file mode 100644 index 000000000..b6dc64fc2 --- /dev/null +++ b/db/docs/api_java/db_set_feedback.html @@ -0,0 +1,95 @@ + + + + + +Berkeley DB: Db.set_feedback + + + + + + + +
+

Db.set_feedback

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public interface DbFeedback +{ + public abstract void db_feedback(Db db, int opcode, int pct); +} +public class Db +{ + public void set_feedback(DbFeedback db_feedback) + throws DbException; + ... +} +

+

Description

+

Some operations performed by the Berkeley DB library can take non-trivial +amounts of time. The Db.set_feedback method can be used by +applications to monitor progress within these operations. +

When an operation is likely to take a long time, Berkeley DB will call the +specified callback method. This method must be declared with +three arguments: the first will be a reference to the enclosing database +handle, the second a flag value, and the third the percent of the +operation that has been completed, specified as an integer value between +0 and 100. It is up to the callback method to display this +information in an appropriate manner. +

The opcode argument may take on any of the following values: +

+

Db.DB_UPGRADE
The underlying database is being upgraded. +

Db.DB_VERIFY
The underlying database is being verified. +
+

The Db.set_feedback interface may be used to configure Berkeley DB at any time +during the life of the application. +

The Db.set_feedback method throws an exception that encapsulates a non-zero error value on +failure. +

Class

+Db +

See Also

+Db.close, +Db.cursor, +Db.del, +Db.fd, +Db.get, +Db.get_byteswapped, +Db.get_type, +Db.join, +Db.key_range, +Db.open, +Db.put, +Db.remove, +Db.set_bt_minkey, +Db.set_cachesize, +Db.set_errcall, +Db.set_errpfx, +Db.set_flags, +Db.set_h_ffactor, +Db.set_h_nelem, +Db.set_lorder, +Db.set_pagesize, +Db.set_q_extentsize, +Db.set_re_delim, +Db.set_re_len, +Db.set_re_pad, +Db.set_re_source, +Db.stat, +Db.sync, +Db.upgrade +and +Db.verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/db_set_flags.html b/db/docs/api_java/db_set_flags.html new file mode 100644 index 000000000..2a79213ea --- /dev/null +++ b/db/docs/api_java/db_set_flags.html @@ -0,0 +1,170 @@ + + + + + +Berkeley DB: Db.set_flags + + + + + + + +
+

Db.set_flags

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void set_flags(int flags) + throws DbException; +

+

Description

+

Calling Db.set_flags is additive, there is no way to clear flags. +

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +

Btree

+

The following flags may be specified for the Btree access method: +

+

Db.DB_DUP
Permit duplicate data items in the tree, i.e. insertion when the key of +the key/data pair being inserted already exists in the tree will be +successful. The ordering of duplicates in the tree is determined by the +order of insertion, unless the ordering is otherwise specified by use of +a cursor operation. It is an error to specify both Db.DB_DUP and +Db.DB_RECNUM. +

Db.DB_DUPSORT
Permit duplicate data items in the tree, i.e. insertion when the key of +the key/data pair being inserted already exists in the tree will be +successful. The ordering of duplicates in the tree is determined by the +duplicate comparison function. +A default, lexical comparison will be used. +It is an error to specify both Db.DB_DUPSORT and Db.DB_RECNUM. +

Db.DB_RECNUM
Support retrieval from the Btree using record numbers. For more +information, see the DB_GET_RECNO flag to the Db.get and +Dbc.get methods. +

Logical record numbers in Btree databases are mutable in the face of +record insertion or deletion. See the DB_RENUMBER flag in the Recno +access method information for further discussion. +

Maintaining record counts within a Btree introduces a serious point of +contention, namely the page locations where the record counts are stored. +In addition, the entire tree must be locked during both insertions and +deletions, effectively single-threading the tree for those operations. +Specifying DB_RECNUM can result in serious performance degradation for +some applications and data sets. +

It is an error to specify both DB_DUP and DB_RECNUM. +

Db.DB_REVSPLITOFF
Turn off reverse splitting in the Btree. As pages are emptied in a +database, the Berkeley DB Btree implementation attempts to coalesce empty pages +into higher-level pages in order to keep the tree as small as possible +and minimize tree search time. This can hurt performance in applications +with cyclical data demands, that is, applications where the database grows +and shrinks repeatedly. For example, because Berkeley DB does page-level +locking, the maximum level of concurrency in a database of 2 pages is far +smaller than that in a database of 100 pages, and so a database that has +shrunk to a minimal size can cause severe deadlocking when a new cycle of +data insertion begins. +
+

Hash

+

The following flags may be specified for the Hash access method: +

+

Db.DB_DUP
Permit duplicate data items in the tree, i.e. insertion when the key of +the key/data pair being inserted already exists in the tree will be +successful. The ordering of duplicates in the tree is determined by the +order of insertion, unless the ordering is otherwise specified by use of +a cursor operation. It is an error to specify both Db.DB_DUP and +Db.DB_RECNUM. +

Db.DB_DUPSORT
Permit duplicate data items in the tree, i.e. insertion when the key of +the key/data pair being inserted already exists in the tree will be +successful. The ordering of duplicates in the tree is determined by the +duplicate comparison function. +A default, lexical comparison will be used. +It is an error to specify both Db.DB_DUPSORT and Db.DB_RECNUM. +
+

Queue

+

There are no additional flags that may be specified for the Queue access +method. +

Recno

+

The following flags may be specified for the Recno access method: +

+

Db.DB_RENUMBER
Specifying the DB_RENUMBER flag causes the logical record numbers to be +mutable, and change as records are added to and deleted from the database. +For example, the deletion of record number 4 causes records numbered 5 +and greater to be renumbered downward by 1. If a cursor was positioned +to record number 4 before the deletion, it will reference the new record +number 4, if any such record exists, after the deletion. If a cursor was +positioned after record number 4 before the deletion, it will be shifted +downward 1 logical record, continuing to reference the same record as it +did before. +

Using the Db.put or Dbc.put interfaces to create new +records will cause the creation of multiple records if the record number +is more than one greater than the largest record currently in the +database. For example, creating record 28, when record 25 was previously +the last record in the database, will create records 26 and 27 as well as +28. Attempts to retrieve records that were created in this manner will +result in an error return of Db.DB_KEYEMPTY. +

If a created record is not at the end of the database, all records +following the new record will be automatically renumbered upward by 1. +For example, the creation of a new record numbered 8 causes records +numbered 8 and greater to be renumbered upward by 1. If a cursor was +positioned to record number 8 or greater before the insertion, it will be +shifted upward 1 logical record, continuing to reference the same record +as it did before. +

For these reasons, concurrent access to a Recno database with the +Db.DB_RENUMBER flag specified may be largely meaningless, although +it is supported. +

Db.DB_SNAPSHOT
This flag specifies that any specified re_source file be read in +its entirety when Db.open is called. If this flag is not +specified, the re_source file may be read lazily. +
+

The Db.set_flags interface may only be used to configure Berkeley DB before +the Db.open interface is called. +

The Db.set_flags method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

Class

+Db +

See Also

+Db.close, +Db.cursor, +Db.del, +Db.fd, +Db.get, +Db.get_byteswapped, +Db.get_type, +Db.join, +Db.key_range, +Db.open, +Db.put, +Db.remove, +Db.set_bt_minkey, +Db.set_cachesize, +Db.set_errcall, +Db.set_errpfx, +Db.set_flags, +Db.set_h_ffactor, +Db.set_h_nelem, +Db.set_lorder, +Db.set_pagesize, +Db.set_q_extentsize, +Db.set_re_delim, +Db.set_re_len, +Db.set_re_pad, +Db.set_re_source, +Db.stat, +Db.sync, +Db.upgrade +and +Db.verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/db_set_h_ffactor.html b/db/docs/api_java/db_set_h_ffactor.html new file mode 100644 index 000000000..c5d10aab0 --- /dev/null +++ b/db/docs/api_java/db_set_h_ffactor.html @@ -0,0 +1,86 @@ + + + + + +Berkeley DB: Db.set_h_ffactor + + + + + + + +
+

Db.set_h_ffactor

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void set_h_ffactor(int h_ffactor) + throws DbException; +

+

Description

+

Set the desired density within the hash table. +

The density is an approximation of the number of keys allowed to +accumulate in any one bucket, determining when the hash table grows or +shrinks. If you know the average sizes of the keys and data in your +dataset, setting the fill factor can enhance performance. A reasonable +rule computing fill factor is to set it to: +

(pagesize - 32) / (average_key_size + average_data_size + 8)
+

If no value is specified, the fill factor will be selected dynamically as +pages are filled. +

The Db.set_h_ffactor interface may only be used to configure Berkeley DB before +the Db.open interface is called. +

The Db.set_h_ffactor method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after Db.open was called. +

+

Class

+Db +

See Also

+Db.close, +Db.cursor, +Db.del, +Db.fd, +Db.get, +Db.get_byteswapped, +Db.get_type, +Db.join, +Db.key_range, +Db.open, +Db.put, +Db.remove, +Db.set_bt_minkey, +Db.set_cachesize, +Db.set_errcall, +Db.set_errpfx, +Db.set_flags, +Db.set_h_ffactor, +Db.set_h_nelem, +Db.set_lorder, +Db.set_pagesize, +Db.set_q_extentsize, +Db.set_re_delim, +Db.set_re_len, +Db.set_re_pad, +Db.set_re_source, +Db.stat, +Db.sync, +Db.upgrade +and +Db.verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/db_set_h_hash.html b/db/docs/api_java/db_set_h_hash.html new file mode 100644 index 000000000..89bccc1fb --- /dev/null +++ b/db/docs/api_java/db_set_h_hash.html @@ -0,0 +1,97 @@ + + + + + +Berkeley DB: Db.set_h_hash + + + + + + + +
+

Db.set_h_hash

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public interface DbHash +{ + public abstract int hash(Db db, byte[] data, int len); +} +public class Db +{ + public void set_h_hash(DbHash h_hash) + throws DbException; + ... +} +

+

Description

+

Set a user defined hash method; if no hash method is specified, a default +hash method is used. Since no hash method performs equally well on all +possible data, the user may find that the built-in hash method performs +poorly with a particular data set. User specified hash functions must +take a pointer to a byte string and a length as arguments and return a +value of type +int. +The hash function must handle any key values used by the application +(possibly including zero-length keys). +

If a hash method is specified, Db.open will attempt to determine +if the hash method specified is the same as the one with which the database +was created, and will fail if it detects that it is not. +

The Db.set_h_hash interface may only be used to configure Berkeley DB before +the Db.open interface is called. +

The Db.set_h_hash method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after Db.open was called. +

+

Class

+Db +

See Also

+Db.close, +Db.cursor, +Db.del, +Db.fd, +Db.get, +Db.get_byteswapped, +Db.get_type, +Db.join, +Db.key_range, +Db.open, +Db.put, +Db.remove, +Db.set_bt_minkey, +Db.set_cachesize, +Db.set_errcall, +Db.set_errpfx, +Db.set_flags, +Db.set_h_ffactor, +Db.set_h_nelem, +Db.set_lorder, +Db.set_pagesize, +Db.set_q_extentsize, +Db.set_re_delim, +Db.set_re_len, +Db.set_re_pad, +Db.set_re_source, +Db.stat, +Db.sync, +Db.upgrade +and +Db.verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/db_set_h_nelem.html b/db/docs/api_java/db_set_h_nelem.html new file mode 100644 index 000000000..279e109ab --- /dev/null +++ b/db/docs/api_java/db_set_h_nelem.html @@ -0,0 +1,81 @@ + + + + + +Berkeley DB: Db.set_h_nelem + + + + + + + +
+

Db.set_h_nelem

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void set_h_nelem(int h_nelem) + throws DbException; +

+

Description

+

Set an estimate of the final size of the hash table. +

If not set or set too low, hash tables will still expand gracefully +as keys are entered, although a slight performance degradation may be +noticed. +

The Db.set_h_nelem interface may only be used to configure Berkeley DB before +the Db.open interface is called. +

The Db.set_h_nelem method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after Db.open was called. +

+

Class

+Db +

See Also

+Db.close, +Db.cursor, +Db.del, +Db.fd, +Db.get, +Db.get_byteswapped, +Db.get_type, +Db.join, +Db.key_range, +Db.open, +Db.put, +Db.remove, +Db.set_bt_minkey, +Db.set_cachesize, +Db.set_errcall, +Db.set_errpfx, +Db.set_flags, +Db.set_h_ffactor, +Db.set_h_nelem, +Db.set_lorder, +Db.set_pagesize, +Db.set_q_extentsize, +Db.set_re_delim, +Db.set_re_len, +Db.set_re_pad, +Db.set_re_source, +Db.stat, +Db.sync, +Db.upgrade +and +Db.verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/db_set_lorder.html b/db/docs/api_java/db_set_lorder.html new file mode 100644 index 000000000..9f6ce37d9 --- /dev/null +++ b/db/docs/api_java/db_set_lorder.html @@ -0,0 +1,87 @@ + + + + + +Berkeley DB: Db.set_lorder + + + + + + + +
+

Db.set_lorder

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void set_lorder(int lorder) + throws DbException; +

+

Description

+

Set the byte order for integers in the stored database metadata. The +number should represent the order as an integer, for example, big endian +order is the number 4,321, and little endian order is the number 1,234. +If lorder is not explicitly set, the host order of the machine +where the Berkeley DB library was compiled is used. +

The value of lorder is ignored except when databases are being +created. If a database already exists, the byte order it uses is +determined when the database is opened. +

The access methods provide no guarantees about the byte ordering of the +application data stored in the database, and applications are responsible +for maintaining any necessary ordering. +

The Db.set_lorder interface may only be used to configure Berkeley DB before +the Db.open interface is called. +

The Db.set_lorder method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

Class

+Db +

See Also

+Db.close, +Db.cursor, +Db.del, +Db.fd, +Db.get, +Db.get_byteswapped, +Db.get_type, +Db.join, +Db.key_range, +Db.open, +Db.put, +Db.remove, +Db.set_bt_minkey, +Db.set_cachesize, +Db.set_errcall, +Db.set_errpfx, +Db.set_flags, +Db.set_h_ffactor, +Db.set_h_nelem, +Db.set_lorder, +Db.set_pagesize, +Db.set_q_extentsize, +Db.set_re_delim, +Db.set_re_len, +Db.set_re_pad, +Db.set_re_source, +Db.stat, +Db.sync, +Db.upgrade +and +Db.verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/db_set_pagesize.html b/db/docs/api_java/db_set_pagesize.html new file mode 100644 index 000000000..23c2462a0 --- /dev/null +++ b/db/docs/api_java/db_set_pagesize.html @@ -0,0 +1,83 @@ + + + + + +Berkeley DB: Db.set_pagesize + + + + + + + +
+

Db.set_pagesize

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void set_pagesize(long pagesize) + throws DbException; +

+

Description

+

Set the size of the pages used to hold items in the database, in bytes. +The minimum page size is 512 bytes and the maximum page size is 64K bytes. +If the page size is not explicitly set, one is selected based on the +underlying filesystem I/O block size. The automatically selected size +has a lower limit of 512 bytes and an upper limit of 16K bytes. +

For information on tuning the Berkeley DB page size, see +Selecting a page size. +

The Db.set_pagesize interface may only be used to configure Berkeley DB before +the Db.open interface is called. +

The Db.set_pagesize method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

Class

+Db +

See Also

+Db.close, +Db.cursor, +Db.del, +Db.fd, +Db.get, +Db.get_byteswapped, +Db.get_type, +Db.join, +Db.key_range, +Db.open, +Db.put, +Db.remove, +Db.set_bt_minkey, +Db.set_cachesize, +Db.set_errcall, +Db.set_errpfx, +Db.set_flags, +Db.set_h_ffactor, +Db.set_h_nelem, +Db.set_lorder, +Db.set_pagesize, +Db.set_q_extentsize, +Db.set_re_delim, +Db.set_re_len, +Db.set_re_pad, +Db.set_re_source, +Db.stat, +Db.sync, +Db.upgrade +and +Db.verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/db_set_q_extentsize.html b/db/docs/api_java/db_set_q_extentsize.html new file mode 100644 index 000000000..081c5b76c --- /dev/null +++ b/db/docs/api_java/db_set_q_extentsize.html @@ -0,0 +1,83 @@ + + + + + +Berkeley DB: Db.set_q_extentsize + + + + + + + +
+

Db.set_q_extentsize

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void set_q_extentsize(int extentsize) + throws DbException; +

+

Description

+

Set the size of the extents used to hold pages in a Queue database, +specified as a number of pages. Each extent is created as a separate +physical file. If no extent size is set, the default behavior is to +create only a single underlying database file. +

For information on tuning the extent size, see +Selecting a extent size. +

The Db.set_q_extentsize interface may only be used to configure Berkeley DB before +the Db.open interface is called. +

The Db.set_q_extentsize method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after Db.open was called. +

+

Class

+Db +

See Also

+Db.close, +Db.cursor, +Db.del, +Db.fd, +Db.get, +Db.get_byteswapped, +Db.get_type, +Db.join, +Db.key_range, +Db.open, +Db.put, +Db.remove, +Db.set_bt_minkey, +Db.set_cachesize, +Db.set_errcall, +Db.set_errpfx, +Db.set_flags, +Db.set_h_ffactor, +Db.set_h_nelem, +Db.set_lorder, +Db.set_pagesize, +Db.set_q_extentsize, +Db.set_re_delim, +Db.set_re_len, +Db.set_re_pad, +Db.set_re_source, +Db.stat, +Db.sync, +Db.upgrade +and +Db.verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/db_set_re_delim.html b/db/docs/api_java/db_set_re_delim.html new file mode 100644 index 000000000..dfe6bb848 --- /dev/null +++ b/db/docs/api_java/db_set_re_delim.html @@ -0,0 +1,83 @@ + + + + + +Berkeley DB: Db.set_re_delim + + + + + + + +
+

Db.set_re_delim

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void set_re_delim(int re_delim) + throws DbException; +

+

Description

+

Set the delimiting byte used to mark the end of a record in the backing +source file for the Recno access method. +

This byte is used for variable length records, if the re_source +file is specified. If the re_source file is specified and no +delimiting byte was specified, <newline> characters (i.e. +ASCII 0x0a) are interpreted as end-of-record markers. +

The Db.set_re_delim interface may only be used to configure Berkeley DB before +the Db.open interface is called. +

The Db.set_re_delim method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after Db.open was called. +

+

Class

+Db +

See Also

+Db.close, +Db.cursor, +Db.del, +Db.fd, +Db.get, +Db.get_byteswapped, +Db.get_type, +Db.join, +Db.key_range, +Db.open, +Db.put, +Db.remove, +Db.set_bt_minkey, +Db.set_cachesize, +Db.set_errcall, +Db.set_errpfx, +Db.set_flags, +Db.set_h_ffactor, +Db.set_h_nelem, +Db.set_lorder, +Db.set_pagesize, +Db.set_q_extentsize, +Db.set_re_delim, +Db.set_re_len, +Db.set_re_pad, +Db.set_re_source, +Db.stat, +Db.sync, +Db.upgrade +and +Db.verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/db_set_re_len.html b/db/docs/api_java/db_set_re_len.html new file mode 100644 index 000000000..34fa523b0 --- /dev/null +++ b/db/docs/api_java/db_set_re_len.html @@ -0,0 +1,87 @@ + + + + + +Berkeley DB: Db.set_re_len + + + + + + + +
+

Db.set_re_len

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void set_re_len(int re_len) + throws DbException; +

+

Description

+

For the Queue access method, specify that the records are of length +re_len. +

For the Recno access method, specify that the records are fixed-length, +not byte delimited, and are of length re_len. +

Any records added to the database that are less than re_len bytes +long are automatically padded (see Db.set_re_pad for more +information). +

Any attempt to insert records into the database that are greater than +re_len bytes long will cause the call to fail immediately and +return an error. +

The Db.set_re_len interface may only be used to configure Berkeley DB before +the Db.open interface is called. +

The Db.set_re_len method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after Db.open was called. +

+

Class

+Db +

See Also

+Db.close, +Db.cursor, +Db.del, +Db.fd, +Db.get, +Db.get_byteswapped, +Db.get_type, +Db.join, +Db.key_range, +Db.open, +Db.put, +Db.remove, +Db.set_bt_minkey, +Db.set_cachesize, +Db.set_errcall, +Db.set_errpfx, +Db.set_flags, +Db.set_h_ffactor, +Db.set_h_nelem, +Db.set_lorder, +Db.set_pagesize, +Db.set_q_extentsize, +Db.set_re_delim, +Db.set_re_len, +Db.set_re_pad, +Db.set_re_source, +Db.stat, +Db.sync, +Db.upgrade +and +Db.verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/db_set_re_pad.html b/db/docs/api_java/db_set_re_pad.html new file mode 100644 index 000000000..118130c54 --- /dev/null +++ b/db/docs/api_java/db_set_re_pad.html @@ -0,0 +1,81 @@ + + + + + +Berkeley DB: Db.set_re_pad + + + + + + + +
+

Db.set_re_pad

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void set_re_pad(int re_pad) + throws DbException; +

+

Description

+

Set the padding character for short, fixed-length records for the Queue +and Recno access methods. +

If no pad character is specified, <space> characters (i.e., +ASCII 0x20) are used for padding. +

The Db.set_re_pad interface may only be used to configure Berkeley DB before +the Db.open interface is called. +

The Db.set_re_pad method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after Db.open was called. +

+

Class

+Db +

See Also

+Db.close, +Db.cursor, +Db.del, +Db.fd, +Db.get, +Db.get_byteswapped, +Db.get_type, +Db.join, +Db.key_range, +Db.open, +Db.put, +Db.remove, +Db.set_bt_minkey, +Db.set_cachesize, +Db.set_errcall, +Db.set_errpfx, +Db.set_flags, +Db.set_h_ffactor, +Db.set_h_nelem, +Db.set_lorder, +Db.set_pagesize, +Db.set_q_extentsize, +Db.set_re_delim, +Db.set_re_len, +Db.set_re_pad, +Db.set_re_source, +Db.stat, +Db.sync, +Db.upgrade +and +Db.verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/db_set_re_source.html b/db/docs/api_java/db_set_re_source.html new file mode 100644 index 000000000..7ff82a204 --- /dev/null +++ b/db/docs/api_java/db_set_re_source.html @@ -0,0 +1,123 @@ + + + + + +Berkeley DB: Db.set_re_source + + + + + + + +
+

Db.set_re_source

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void set_re_source(String re_source) + throws DbException; +

+

Description

+

Set the underlying source file for the Recno access method. The purpose +of the re_source value is to provide fast access and modification +to databases that are normally stored as flat text files. +

If the re_source field is set, it specifies an underlying flat +text database file that is read to initialize a transient record number +index. In the case of variable length records, the records are separated +as specified by Db.set_re_delim. For example, standard UNIX +byte stream files can be interpreted as a sequence of variable length +records separated by <newline> characters. +

In addition, when cached data would normally be written back to the +underlying database file (e.g., the Db.close or Db.sync +methods are called), the in-memory copy of the database will be written +back to the re_source file. +

By default, the backing source file is read lazily, i.e., records are not +read from the file until they are requested by the application. +If multiple processes (not threads) are accessing a Recno database +concurrently and either inserting or deleting records, the backing source +file must be read in its entirety before more than a single process +accesses the database, and only that process should specify the backing +source file as part of the Db.open call. See the Db.DB_SNAPSHOT +flag for more information. +

Reading and writing the backing source file specified by re_source +cannot be transactionally protected because it involves filesystem +operations that are not part of the Db transaction methodology. +For this reason, if a temporary database is used to hold the records, +i.e., a null was specified as the file argument to Db.open, +it is possible to lose the contents of the re_source file, e.g., +if the system crashes at the right instant. +If a file is used to hold the database, i.e., a file name was specified +as the file argument to Db.open, normal database +recovery on that file can be used to prevent information loss, +although it is still possible that the contents of re_source +will be lost if the system crashes. +

The re_source file must already exist (but may be zero-length) when +Db.open is called. +

It is not an error to specify a read-only re_source file when +creating a database, nor is it an error to modify the resulting database. +However, any attempt to write the changes to the backing source file using +either the Db.sync or Db.close methods will fail, of course. +Specify the Db.DB_NOSYNC flag to the Db.close method to stop it +from attempting to write the changes to the backing file, instead, they +will be silently discarded. +

For all of the above reasons, the re_source field is generally +used to specify databases that are read-only for Db applications, +and that are either generated on the fly by software tools, or modified +using a different mechanism, e.g., a text editor. +

The Db.set_re_source interface may only be used to configure Berkeley DB before +the Db.open interface is called. +

The Db.set_re_source method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after Db.open was called. +

+

Class

+Db +

See Also

+Db.close, +Db.cursor, +Db.del, +Db.fd, +Db.get, +Db.get_byteswapped, +Db.get_type, +Db.join, +Db.key_range, +Db.open, +Db.put, +Db.remove, +Db.set_bt_minkey, +Db.set_cachesize, +Db.set_errcall, +Db.set_errpfx, +Db.set_flags, +Db.set_h_ffactor, +Db.set_h_nelem, +Db.set_lorder, +Db.set_pagesize, +Db.set_q_extentsize, +Db.set_re_delim, +Db.set_re_len, +Db.set_re_pad, +Db.set_re_source, +Db.stat, +Db.sync, +Db.upgrade +and +Db.verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/db_stat.html b/db/docs/api_java/db_stat.html new file mode 100644 index 000000000..197ba1913 --- /dev/null +++ b/db/docs/api_java/db_stat.html @@ -0,0 +1,185 @@ + + + + + +Berkeley DB: Db.stat + + + + + + + +
+

Db.stat

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public Object Db.stat(int flags); +

+

Description

+

The Db.stat method creates a statistical structure and +fills it with statistics for the database. +

Statistical structures are created in allocated memory. If db_malloc is non-NULL, it +is called to allocate the memory, otherwise, the library function +malloc(3) is used. The function db_malloc must match +the calling conventions of the malloc(3) library routine. +Regardless, the caller is responsible for deallocating the returned +memory. To deallocate returned memory, free the returned memory +reference, references inside the returned memory do not need to be +individually freed. +

The flags parameter must be set to 0 or the following value: +

+

Db.DB_CACHED_COUNTS
Return a cached count of the keys and records in a database. This flag +makes it possible for applications to request an possibly approximate key +and record count without incurring the performance penalty of traversing +the entire database. The statistics information described for the access +method XX_nkeys and XX_ndata fields below is filled in, +but no other information is collected. If the cached information has +never been set, the fields will be returned set to 0. +

Db.DB_RECORDCOUNT
Return a count of the records in a Btree or Recno Access Method database. +This flag makes it possible for applications to request a record count +without incurring the performance penalty of traversing the entire +database. The statistics information described for the bt_nkeys +field below is filled in, but no other information is collected. +

This option is only available for Recno databases, or Btree databases +where the underlying database was created with the Db.DB_RECNUM +flag. +

+

The Db.stat method may access all of the pages in the database, +incurring a severe performance penalty as well as possibly flushing the +underlying buffer pool. +

In the presence of multiple threads or processes accessing an active +database, the information returned by Db.stat may be out-of-date. +

If the database was not opened readonly and the Db.DB_CACHED_COUNTS +flag was not specified, the cached key and record numbers will be updated +after the statistical information has been gathered. +

The Db.stat method cannot be transaction protected. For this reason, +it should be called in a thread of control that has no open cursors or +active transactions. +

The Db.stat method throws an exception that encapsulates a non-zero error value on +failure. +

Hash Statistics

+

In the case of a Hash database, +the statistics are returned in an instance of DbHashStat. The data +fields are available from DbHashStat: +

+

public int hash_magic;
Magic number that identifies the file as a Hash file. +
public int hash_version;
The version of the Hash database. +
public int hash_nkeys;
The number of unique keys in the database. +
public int hash_ndata;
The number of key/data pairs in the database.] +
public int hash_pagesize;
The underlying Hash database page (and bucket) size. +
public int hash_nelem;
The estimated size of the hash table specified at database creation time. +
public int hash_ffactor;
The desired fill factor (number of items per bucket) specified at database +creation time. +
public int hash_buckets;
The number of hash buckets. +
public int hash_free;
The number of pages on the free list. +
public int hash_bfree;
The number of bytes free on bucket pages. +
public int hash_bigpages;
The number of big key/data pages. +
public int hash_big_bfree;
The number of bytes free on big item pages. +
public int hash_overflows;
The number of overflow pages (overflow pages are pages that contain items +that did not fit in the main bucket page). +
public int hash_ovfl_free;
The number of bytes free on overflow pages. +
public int hash_dup;
The number of duplicate pages. +
public int hash_dup_free;
The number of bytes free on duplicate pages. +
+

Btree and Recno Statistics

+

In the case of a Btree or Recno database, +the statistics are returned in an instance of DbBtreeStat. The data +fields are available from DbBtreeStat: +

+

public int bt_magic;
Magic number that identifies the file as a Btree database. +
public int bt_version;
The version of the Btree database. +
public int bt_nkeys;
For the Btree Access Method, the number of unique keys in the database. +

For the Recno Access Method, the number of records in the database. +

public int bt_ndata;
For the Btree Access Method, the number of key/data pairs in the database. +

For the Recno Access Method, the number of records in the database. If +the database has been configured to not re-number records during +deletion, the number of records will only reflect undeleted records. +

public int bt_pagesize;
Underlying database page size. +
public int bt_minkey;
The minimum keys per page. +
public int bt_re_len;
The length of fixed-length records. +
public int bt_re_pad;
The padding byte value for fixed-length records. +
public int bt_levels;
Number of levels in the database. +
public int bt_int_pg;
Number of database internal pages. +
public int bt_leaf_pg;
Number of database leaf pages. +
public int bt_dup_pg;
Number of database duplicate pages. +
public int bt_over_pg;
Number of database overflow pages. +
public int bt_free;
Number of pages on the free list. +
public int bt_int_pgfree;
Number of bytes free in database internal pages. +
public int bt_leaf_pgfree;
Number of bytes free in database leaf pages. +
public int bt_dup_pgfree;
Number of bytes free in database duplicate pages. +
public int bt_over_pgfree;
Number of bytes free in database overflow pages. +
+

Queue Statistics

+

In the case of a Queue database, +the statistics are returned in an instance of DbQueueStat. The data +fields are available from DbQueueStat: +

+

public int qs_magic;
Magic number that identifies the file as a Queue file. +
public int qs_version;
The version of the Queue file type. +
public int qs_nkeys;
The number of records in the database. +
public int qs_ndata;
The number of records in the database. +
public int qs_pagesize;
Underlying database page size. +
public int qs_pages;
Number of pages in the database. +
public int qs_re_len;
The length of the records. +
public int qs_re_pad;
The padding byte value for the records. +
public int qs_pgfree;
Number of bytes free in database pages. +
public int qs_start;
Start offset. +
public int qs_first_recno;
First undeleted record in the database. +
public int qs_cur_recno;
Last allocated record number in the database. +
+

The Db.stat method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

The Db.stat method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Db.stat method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Class

+Db +

See Also

+Db.close, +Db.cursor, +Db.del, +Db.fd, +Db.get, +Db.get_byteswapped, +Db.get_type, +Db.join, +Db.key_range, +Db.open, +Db.put, +Db.remove, +Db.set_bt_minkey, +Db.set_cachesize, +Db.set_errcall, +Db.set_errpfx, +Db.set_flags, +Db.set_h_ffactor, +Db.set_h_nelem, +Db.set_lorder, +Db.set_pagesize, +Db.set_q_extentsize, +Db.set_re_delim, +Db.set_re_len, +Db.set_re_pad, +Db.set_re_source, +Db.stat, +Db.sync, +Db.upgrade +and +Db.verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/db_sync.html b/db/docs/api_java/db_sync.html new file mode 100644 index 000000000..5162bd13d --- /dev/null +++ b/db/docs/api_java/db_sync.html @@ -0,0 +1,91 @@ + + + + + +Berkeley DB: Db.sync + + + + + + + +
+

Db.sync

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public int sync(int flags) + throws DbException; +

+

Description

+

The Db.sync method flushes any cached information to disk. +

If the database is in memory only, the Db.sync method has no effect and +will always succeed. +

The flags parameter is currently unused, and must be set to 0. +

See Db.close for a discussion of Berkeley DB and cached data. +

The Db.sync method throws an exception that encapsulates a non-zero error value on +failure, and returns Db.DB_INCOMPLETE if the underlying database still has +dirty pages in the cache. (The only reason to return +Db.DB_INCOMPLETE is if another thread of control was writing pages +in the underlying database file at the same time as the +Db.sync method was being called. For this reason, a return of +Db.DB_INCOMPLETE can normally be ignored, or, in cases where it is +a possible return value, there may be no reason to call +Db.sync.) +

Errors

+

The Db.sync method may fail and throw an exception encapsulating a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +
+

The Db.sync method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Db.sync method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Class

+Db +

See Also

+Db.close, +Db.cursor, +Db.del, +Db.fd, +Db.get, +Db.get_byteswapped, +Db.get_type, +Db.join, +Db.key_range, +Db.open, +Db.put, +Db.remove, +Db.set_bt_minkey, +Db.set_cachesize, +Db.set_errcall, +Db.set_errpfx, +Db.set_flags, +Db.set_h_ffactor, +Db.set_h_nelem, +Db.set_lorder, +Db.set_pagesize, +Db.set_q_extentsize, +Db.set_re_delim, +Db.set_re_len, +Db.set_re_pad, +Db.set_re_source, +Db.stat, +Db.sync, +Db.upgrade +and +Db.verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/db_upgrade.html b/db/docs/api_java/db_upgrade.html new file mode 100644 index 000000000..6f6da088c --- /dev/null +++ b/db/docs/api_java/db_upgrade.html @@ -0,0 +1,125 @@ + + + + + +Berkeley DB: Db.upgrade + + + + + + + +
+

Db.upgrade

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void upgrade(String file, int flags) + throws DbException; +

+

Description

+

The Db.upgrade method upgrades all of the databases included in the +file file, if necessary. If no upgrade is necessary, +Db.upgrade always returns success. +

Database upgrades are done in place and are destructive, e.g., if pages +need to be allocated and no disk space is available, the database may be +left corrupted. Backups should be made before databases are upgraded. +See Upgrading databases for more +information. +

Unlike all other database operations, Db.upgrade may only be done +on a system with the same byte-order as the database. +

The flags parameter must be set to 0 or one of the following +values: +

+

Db.DB_DUPSORT
This flag is only meaningful when upgrading databases from +releases before the Berkeley DB 3.1 release. +

As part of the upgrade from the Berkeley DB 3.0 release to the 3.1 release, the +on-disk format of duplicate data items changed. To correctly upgrade the +format requires applications specify if duplicate data items in the +database are sorted or not. Specifying the Db.DB_DUPSORT flag +informs Db.upgrade that the duplicates are sorted, otherwise they +are assumed to be unsorted. Incorrectly specifying the value of this flag +may lead to database corruption. +

Further, because the Db.upgrade method upgrades a physical file +(including all of the databases it contains), it is not possible to use +Db.upgrade to upgrade files where some of the databases it +includes have sorted duplicate data items and some of the databases it +includes have unsorted duplicate data items. If the file does not have +more than a single database, or the databases do not support duplicate +data items, or all of the databases that support duplicate data items +support the same style of duplicates (either sorted or unsorted), +Db.upgrade will work correctly as long as the Db.DB_DUPSORT +flag is correctly specified. Otherwise, the file cannot be upgraded using +Db.upgrade, and must be upgraded manually by dumping and +re-loading the databases. +

+

The Db.upgrade method throws an exception that encapsulates a non-zero error value on +failure. +

Environment Variables

+

+

DB_HOME
If the dbenv argument to db_create was initialized using +DbEnv.open the environment variable DB_HOME may be used +as the path of the database environment home. Specifically, Db.upgrade +is affected by the configuration value DB_DATA_DIR. +
+

Errors

+

The Db.upgrade method may fail and throw an exception encapsulating a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +

The database is not in the same byte-order as the system. +

+

+

Db.DB_OLD_VERSION
The database cannot be upgraded by this version of the Berkeley DB software. +
+

The Db.upgrade method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Db.upgrade method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Class

+Db +

See Also

+Db.close, +Db.cursor, +Db.del, +Db.fd, +Db.get, +Db.get_byteswapped, +Db.get_type, +Db.join, +Db.key_range, +Db.open, +Db.put, +Db.remove, +Db.set_bt_minkey, +Db.set_cachesize, +Db.set_errcall, +Db.set_errpfx, +Db.set_flags, +Db.set_h_ffactor, +Db.set_h_nelem, +Db.set_lorder, +Db.set_pagesize, +Db.set_q_extentsize, +Db.set_re_delim, +Db.set_re_len, +Db.set_re_pad, +Db.set_re_source, +Db.stat, +Db.sync, +Db.upgrade +and +Db.verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/db_verify.html b/db/docs/api_java/db_verify.html new file mode 100644 index 000000000..e27020283 --- /dev/null +++ b/db/docs/api_java/db_verify.html @@ -0,0 +1,140 @@ + + + + + +Berkeley DB: Db.verify + + + + + + + +
+

Db.verify

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void verify(String file, + String database, java.io.OutputStream outfile, int flags) + throws DbException; +

+

Description

+

The Db.verify method verifies the integrity of all databases in the +file specified by the file argument, and optionally outputs the databases' +key/data pairs to a file stream. +

The flags parameter must be set to 0 or one of the following +values: +

+

Db.DB_SALVAGE
Write the key/data pairs from all databases in the file to the file stream +named in +the outfile argument. The output format is the same as that +specified for the db_dump utility and can be used as input for +the db_load utility. +

Because the key/data pairs are output in page order as opposed to the sort +order used by db_dump, using Db.verify to dump key/data +pairs normally produces less than optimal loads for Btree databases. +

+

In addition, the following flags may be set by bitwise inclusively OR'ing them into the +flags parameter: +

+

Db.DB_AGGRESSIVE
Output all the key/data pairs in the file that can be found. +By default, Db.verify does not assume corruption. For example, +if a key/data pair on a page is marked as deleted, it is not then written +to the output file. When Db.DB_AGGRESSIVE is specified, corruption +is assumed, and any key/data pair that can be found is written. In this +case, key/data pairs that are corrupted or have been deleted may appear +in the output (even if the file being salvaged is in no way corrupt), and +the output will almost certainly require editing before being loaded into +a database. +

Db.DB_NOORDERCHK
Skip the database checks for btree and duplicate sort order and for +hashing. +

The Db.verify method normally verifies that btree keys and duplicate +items are correctly sorted and hash keys are correctly hashed. If the +file being verified contains multiple databases using differing sorting +or hashing algorithms, some of them must necessarily fail database +verification as only one sort order or hash function can be specified +before Db.verify is called. To verify files with multiple +databases having differing sorting orders or hashing functions, first +perform verification of the file as a whole by using the +Db.DB_NOORDERCHK flag, and then individually verify the sort order +and hashing function for each database in the file using the +Db.DB_ORDERCHKONLY flag. +

Db.DB_ORDERCHKONLY
Perform the database checks for btree and duplicate sort order and for +hashing, skipped by Db.DB_NOORDERCHK. +

When this flag is specified, a database argument should also be +specified, indicating the database in the physical file which is to be +checked. This flag is only safe to use on databases that have already +successfully been verified using Db.verify with the +Db.DB_NOORDERCHK flag set. +

+

The database argument must be set to null except when the +Db.DB_ORDERCHKONLY flag is set. +

The Db.verify method throws an exception that encapsulates a non-zero error value on +failure, and Db.DB_VERIFY_BAD if a database is corrupted. When the +Db.DB_SALVAGE flag is specified, the Db.DB_VERIFY_BAD return +means that all key/data pairs in the file may not have been successfully +output. +

Environment Variables

+

+

DB_HOME
If the dbenv argument to db_create was initialized using +DbEnv.open the environment variable DB_HOME may be used +as the path of the database environment home. Specifically, Db.verify +is affected by the configuration value DB_DATA_DIR. +
+

Errors

+

The Db.verify method may fail and throw an exception encapsulating a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +
+

The Db.verify method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Db.verify method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Class

+Db +

See Also

+Db.close, +Db.cursor, +Db.del, +Db.fd, +Db.get, +Db.get_byteswapped, +Db.get_type, +Db.join, +Db.key_range, +Db.open, +Db.put, +Db.remove, +Db.set_bt_minkey, +Db.set_cachesize, +Db.set_errcall, +Db.set_errpfx, +Db.set_flags, +Db.set_h_ffactor, +Db.set_h_nelem, +Db.set_lorder, +Db.set_pagesize, +Db.set_q_extentsize, +Db.set_re_delim, +Db.set_re_len, +Db.set_re_pad, +Db.set_re_source, +Db.stat, +Db.sync, +Db.upgrade +and +Db.verify. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/dbc_class.html b/db/docs/api_java/dbc_class.html new file mode 100644 index 000000000..61f6b9ec2 --- /dev/null +++ b/db/docs/api_java/dbc_class.html @@ -0,0 +1,49 @@ + + + + + +Berkeley DB: Dbc + + + + + + + +
+

Dbc

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public class Dbc extends Object { ... } +

+

Description

+

This manual page describes the specific details of the Dbc class, +which provides cursor support for the access methods in Db. +

The Dbc functions are the library interface supporting sequential +access to the records stored by the access methods of the Berkeley DB library. +Cursors are created by calling the Db.cursor method which returns a + Dbc object. +

Class

+Dbc +

See Also

+Dbc.close, +Dbc.count, +Dbc.del, +Dbc.dup, +Dbc.get +and +Dbc.put. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/dbc_close.html b/db/docs/api_java/dbc_close.html new file mode 100644 index 000000000..c8ad05702 --- /dev/null +++ b/db/docs/api_java/dbc_close.html @@ -0,0 +1,67 @@ + + + + + +Berkeley DB: Dbc.close + + + + + + + +
+

Dbc.close

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void close() + throws DbException; +

+

Description

+

The Dbc.close method discards the cursor. +

It is possible for the Dbc.close method to return +Db.DB_LOCK_DEADLOCK, signaling that any enclosing transaction should +be aborted. If the application is already intending to abort the +transaction, this error should be ignored, and the application should +proceed. +

Once Dbc.close has been called, regardless of its return, the +cursor handle may not be used again. +

The Dbc.close method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

The Dbc.close method may fail and throw an exception encapsulating a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +

The cursor was previously closed. +

+

If the operation was selected to resolve a deadlock, the +Dbc.close method will fail and +throw a DbDeadlockException exception. +

The Dbc.close method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Dbc.close method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Class

+Dbc +

See Also

+Dbc.close, +Dbc.count, +Dbc.del, +Dbc.dup, +Dbc.get +and +Dbc.put. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/dbc_count.html b/db/docs/api_java/dbc_count.html new file mode 100644 index 000000000..324ee1485 --- /dev/null +++ b/db/docs/api_java/dbc_count.html @@ -0,0 +1,58 @@ + + + + + +Berkeley DB: Dbc.count + + + + + + + +
+

Dbc.count

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public int count(int flags) + throws DbException; +

+

Description

+

The Dbc.count method returns a count of the number of duplicate data +items for the key referenced by the +cursor. +If the underlying database does not support duplicate data items the call +will still succeed and a count of 1 will be returned. +

The flags parameter is currently unused, and must be set to 0. +

If the cursor argument is not yet initialized, the Dbc.count method throws an exception that encapsulates EINVAL. +

Otherwise, the Dbc.count method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

The Dbc.count method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Dbc.count method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Class

+Dbc +

See Also

+Dbc.close, +Dbc.count, +Dbc.del, +Dbc.dup, +Dbc.get +and +Dbc.put. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/dbc_del.html b/db/docs/api_java/dbc_del.html new file mode 100644 index 000000000..eb4a32362 --- /dev/null +++ b/db/docs/api_java/dbc_del.html @@ -0,0 +1,71 @@ + + + + + +Berkeley DB: Dbc.del + + + + + + + +
+

Dbc.del

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public int del(int flags) + throws DbException; +

+

Description

+

The Dbc.del method deletes the key/data pair currently referenced by +the cursor. +

The flags parameter is currently unused, and must be set to 0. +

The cursor position is unchanged after a delete, and subsequent calls to +cursor functions expecting the cursor to reference an existing key will +fail. +

If the element has already been deleted, Dbc.del will return +Db.DB_KEYEMPTY. +

If the cursor is not yet initialized, the Dbc.del method throws an exception that encapsulates EINVAL. +

Otherwise, the Dbc.del method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

The Dbc.del method may fail and throw an exception encapsulating a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +
+

+

EPERM
Write attempted on read-only cursor when the Db.DB_INIT_CDB flag was +specified to DbEnv.open. +
+

If the operation was selected to resolve a deadlock, the +Dbc.del method will fail and +throw a DbDeadlockException exception. +

The Dbc.del method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Dbc.del method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Class

+Dbc +

See Also

+Dbc.close, +Dbc.count, +Dbc.del, +Dbc.dup, +Dbc.get +and +Dbc.put. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/dbc_dup.html b/db/docs/api_java/dbc_dup.html new file mode 100644 index 000000000..f02afbb73 --- /dev/null +++ b/db/docs/api_java/dbc_dup.html @@ -0,0 +1,75 @@ + + + + + +Berkeley DB: Dbc.dup + + + + + + + +
+

Dbc.dup

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public Dbc dup(int flags) + throws DbException; +

+

Description

+

The Dbc.dup method creates a new cursor that uses the same transaction +and locker ID as the original cursor. This is useful when an application +is using locking and requires two or more cursors in the same thread of +control. +

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +

+

Db.DB_POSITION
The newly created cursor is initialized to reference the same position +in the database as the original cursor and hold the same locks. If the +Db.DB_POSITION flag is not specified, then the created cursor is +uninitialized and will behave like a cursor newly created using +Db.cursor. +
+

When using the Berkeley DB Concurrent Data Store product, there can be only one active write cursor +at a time. For this reason, attempting to duplicate a cursor for which +the Db.DB_WRITECURSOR flag was specified during creation will return +an error. +

If the cursor argument is not yet initialized, the Dbc.dup method throws an exception that encapsulates EINVAL. +

Otherwise, the Dbc.dup method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

The Dbc.dup method may fail and throw an exception encapsulating a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +

The cursor argument was created using the +Db.DB_WRITECURSOR flag in the Berkeley DB Concurrent Data Store product. +

+

The Dbc.dup method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Dbc.dup method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Class

+Dbc +

See Also

+Dbc.close, +Dbc.count, +Dbc.del, +Dbc.dup, +Dbc.get +and +Dbc.put. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/dbc_get.html b/db/docs/api_java/dbc_get.html new file mode 100644 index 000000000..8213c5b51 --- /dev/null +++ b/db/docs/api_java/dbc_get.html @@ -0,0 +1,168 @@ + + + + + +Berkeley DB: Dbc.get + + + + + + + +
+

Dbc.get

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public int get(Dbt key, Dbt data, int flags) + throws DbException; +

+

Description

+

The Dbc.get method retrieves key/data pairs from the database. The +byte array and length of the key +are returned in the object referenced by key (except for the case +of the Db.DB_SET flag where the key object is unchanged), +and the byte array and length of +the data are returned in the object referenced by data. +

Modifications to the database during a sequential scan will be reflected +in the scan, i.e. records inserted behind a cursor will not be returned +while records inserted in front of a cursor will be returned. +

In Queue and Recno databases, missing entries (i.e., entries that were +never explicitly created or that were created and then deleted), will be +skipped during a sequential scan. +

If multiple threads or processes insert items into the same database file +without using locking, the results are undefined. +For more detail, +see Cursor stability. +

The flags parameter must be set to one of the following values: +

+

Db.DB_CURRENT
Return the key/data pair currently referenced by the cursor. +

If the cursor key/data pair was deleted, Dbc.get will return +Db.DB_KEYEMPTY. +

If the cursor is not yet initialized, the Dbc.get method throws an exception that encapsulates EINVAL. +

Db.DB_FIRST, Db.DB_LAST
The cursor is set to reference the first (last) key/data pair of the +database, and that pair is returned. In the presence of duplicate key +values, the first (last) data item in the set of duplicates is returned. +

If the database is a Queue or Recno database, Dbc.get using the +Db.DB_FIRST (Db.DB_LAST) flags will ignore any keys that exist +but were never explicitly created by the application or were created and +later deleted. +

If the database is empty, Dbc.get will return Db.DB_NOTFOUND. +

Db.DB_GET_BOTH
The Db.DB_GET_BOTH flag is identical to the Db.DB_SET flag, +except that both the key and the data arguments must be matched by the +key and data item in the database. +

Db.DB_GET_RECNO
Return the record number associated with the cursor. The record number +will be returned in data as described in Dbt. The +key parameter is ignored. +

For Db.DB_GET_RECNO to be specified, the underlying database must be +of type Btree and it must have been created with the Db.DB_RECNUM +flag. +

Db.DB_JOIN_ITEM
Do not use the data value found in all of the cursors as a lookup key for +the primary database, but simply return it in the key parameter instead. +The data parameter is left unchanged. +

For Db.DB_JOIN_ITEM to be specified, the underlying cursor must have +been returned from the Db.join method. +

Db.DB_NEXT, Db.DB_PREV
If the cursor is not yet initialized, Db.DB_NEXT (Db.DB_PREV) +is identical to Db.DB_FIRST (Db.DB_LAST). Otherwise, the cursor +is moved to the next (previous) key/data pair of the database, and that +pair is returned. In the presence of duplicate key values, the value of +the key may not change. +

If the database is a Queue or Recno database, Dbc.get using the +Db.DB_NEXT (Db.DB_PREV) flag will skip any keys that exist but +were never explicitly created by the application or were created and later +deleted. +

If the cursor is already on the last (first) record in the database, +Dbc.get will return Db.DB_NOTFOUND. +

Db.DB_NEXT_DUP
If the next key/data pair of the database is a duplicate record for the +current key/data pair, the cursor is moved to the next key/data pair of +the database, and that pair is returned. Otherwise, Dbc.get will +return Db.DB_NOTFOUND. +

If the cursor is not yet initialized, the Dbc.get method throws an exception that encapsulates EINVAL. +

Db.DB_NEXT_NODUP, Db.DB_PREV_NODUP
If the cursor is not yet initialized, Db.DB_NEXT_NODUP +(Db.DB_PREV_NODUP) is identical to Db.DB_FIRST +(Db.DB_LAST). Otherwise, the cursor is moved to the next (previous) +non-duplicate key/data pair of the database, and that pair is returned. +

If the database is a Queue or Recno database, Dbc.get using the +Db.DB_NEXT_NODUP (Db.DB_PREV_NODUP) flags will ignore any keys +that exist but were never explicitly created by the application or were +created and later deleted. +

If no non-duplicate key/data pairs occur after (before) the cursor +position in the database, Dbc.get will return Db.DB_NOTFOUND. +

Db.DB_SET
Move the cursor to the specified key/data pair of the database, and +return the datum associated with the given key. +

In the presence of duplicate key values, Dbc.get will return the +first data item for the given key. +

If the database is a Queue or Recno database and the requested key exists, +but was never explicitly created by the application or was later deleted, +Dbc.get will return Db.DB_KEYEMPTY. +

If no matching keys are found, Dbc.get will return +Db.DB_NOTFOUND. +

Db.DB_SET_RANGE
The Db.DB_SET_RANGE flag is identical to the Db.DB_SET flag, +except that the key is returned as well as the data item, and, in the case +of the Btree access method, the returned key/data pair is the smallest +key greater than or equal to the specified key (as determined by the +comparison method), permitting partial key matches and range +searches. +

Db.DB_SET_RECNO
Move the cursor to the specific numbered record of the database, and +return the associated key/data pair. The data field of the +specified key +must be a byte array containing a record number, as described in +Dbt. This determines the record to be retrieved. +

For Db.DB_SET_RECNO to be specified, the underlying database must be +of type Btree and it must have been created with the Db.DB_RECNUM +flag. +

+

In addition, the following flag may be set by bitwise inclusively OR'ing it into the +flags parameter: +

+

Db.DB_RMW
Acquire write locks instead of read locks when doing the retrieval. +Setting this flag may decrease the likelihood of deadlock during a +read-modify-write cycle by immediately acquiring the write lock during +the read part of the cycle so that another thread of control acquiring +a read lock for the same item, in its own read-modify-write cycle, will +not result in deadlock. +
+

Otherwise, the Dbc.get method throws an exception that encapsulates a non-zero error value on +failure. +

If Dbc.get fails for any reason, the state of the cursor will be +unchanged. +

Errors

+

The Dbc.get method may fail and throw an exception encapsulating a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +

The specified cursor was not currently initialized. +

+

If the operation was selected to resolve a deadlock, the +Dbc.get method will fail and +throw a DbDeadlockException exception. +

If the requested item could not be returned due to insufficient memory, +the Dbc.get method will fail and +throw a DbMemoryException exception. +

The Dbc.get method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Dbc.get method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Class

+Dbc +

See Also

+Dbc.close, +Dbc.count, +Dbc.del, +Dbc.dup, +Dbc.get +and +Dbc.put. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/dbc_put.html b/db/docs/api_java/dbc_put.html new file mode 100644 index 000000000..a2969e159 --- /dev/null +++ b/db/docs/api_java/dbc_put.html @@ -0,0 +1,157 @@ + + + + + +Berkeley DB: Dbc.put + + + + + + + +
+

Dbc.put

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void put(Dbt key, Dbt data, int flags) + throws DbException; +

+

Description

+

The Dbc.put method stores key/data pairs into the database. +

The flags parameter must be set to one of the following values: +

+

Db.DB_AFTER
In the case of the Btree and Hash access methods, insert the data +element as a duplicate element of the key referenced by the cursor. +The new element appears immediately after the current cursor position. +It is an error to specify Db.DB_AFTER if the underlying Btree or +Hash database does not support duplicate data items. The key +parameter is ignored. +

In the case of the Recno access method, it is an error to specify +Db.DB_AFTER if the underlying Recno database was not created with +the Db.DB_RENUMBER flag. If the Db.DB_RENUMBER flag was +specified, a new key is created, all records after the inserted item +are automatically renumbered, and the key of the new record is returned +in the structure referenced by the parameter key. The initial +value of the key parameter is ignored. See Db.open +for more information. +

The Db.DB_AFTER flag may not be specified to the Queue access method. +

If the current cursor record has already been deleted and the underlying +access method is Hash, Dbc.put will return Db.DB_NOTFOUND. +If the underlying access method is Btree or Recno, the operation will +succeed. +

If the cursor is not yet initialized or a duplicate sort function has been +specified, the Dbc.put function will return EINVAL. +

Db.DB_BEFORE
In the case of the Btree and Hash access methods, insert the data element +as a duplicate element of the key referenced by the cursor. The new +element appears immediately before the current cursor position. It is +an error to specify Db.DB_BEFORE if the underlying Btree or Hash +database does not support duplicate data items. The key +parameter is ignored. +

In the case of the Recno access method, it is an error to specify +Db.DB_BEFORE if the underlying Recno database was not created with +the Db.DB_RENUMBER flag. If the Db.DB_RENUMBER flag was +specified, a new key is created, the current record and all records +after it are automatically renumbered, and the key of the new record is +returned in the structure referenced by the parameter key. The +initial value of the key parameter is ignored. See +Db.open for more information. +

The Db.DB_BEFORE flag may not be specified to the Queue access method. +

If the current cursor record has already been deleted and the underlying +access method is Hash, Dbc.put will return Db.DB_NOTFOUND. +If the underlying access method is Btree or Recno, the operation will +succeed. +

If the cursor is not yet initialized or a duplicate sort function has been +specified, Dbc.put will return EINVAL. +

Db.DB_CURRENT
Overwrite the data of the key/data pair referenced by the cursor with the +specified data item. The key parameter is ignored. +

If a duplicate sort function has been specified and the data item of the +current referenced key/data pair does not compare equally to the data +parameter, Dbc.put will return EINVAL. +

If the current cursor record has already been deleted and the underlying +access method is Hash, Dbc.put will return Db.DB_NOTFOUND. +If the underlying access method is Btree, Queue or Recno, the operation +will succeed. +

If the cursor is not yet initialized, Dbc.put will return EINVAL. +

Db.DB_KEYFIRST
In the case of the Btree and Hash access methods, insert the specified +key/data pair into the database. +

If the underlying database supports duplicate data items, and if the +key already exists in the database and a duplicate sort function has +been specified, the inserted data item is added in its sorted location. +If the key already exists in the database and no duplicate sort function +has been specified, the inserted data item is added as the first of the +data items for that key. +

The Db.DB_KEYFIRST flag may not be specified to the Queue or Recno +access methods. +

Db.DB_KEYLAST
In the case of the Btree and Hash access methods, insert the specified +key/data pair into the database. +

If the underlying database supports duplicate data items, and if the +key already exists in the database and a duplicate sort function has +been specified, the inserted data item is added in its sorted location. +If the key already exists in the database, and no duplicate sort +function has been specified, the inserted data item is added as the last +of the data items for that key. +

The Db.DB_KEYLAST flag may not be specified to the Queue or Recno +access methods. +

Db.DB_NODUPDATA
In the case of the Btree and Hash access methods, insert the specified +key/data pair into the database unless it already exists in the database. +If the key/data pair already appears in the database, Db.DB_KEYEXIST +is returned. The Db.DB_NODUPDATA flag may only be specified if +the underlying database has been configured to support sorted duplicate +data items. +

The Db.DB_NODUPDATA flag may not be specified to the Queue or Recno +access methods. +

+

Otherwise, the Dbc.put method throws an exception that encapsulates a non-zero error value on +failure. +

If Dbc.put fails for any reason, the state of the cursor will be +unchanged. If Dbc.put succeeds and an item is inserted into the +database, the cursor is always positioned to reference the newly inserted +item. +

Errors

+

The Dbc.put method may fail and throw an exception encapsulating a non-zero error for the following conditions: +

+

EACCES
An attempt was made to modify a read-only database. +
+

+

EINVAL
An invalid flag value or parameter was specified. +

The Db.DB_BEFORE or Db.DB_AFTER flags were specified, and the +underlying access method is Queue. +

An attempt was made to add a record to a fixed-length database that was too +large to fit. +

+

+

EPERM
Write attempted on read-only cursor when the Db.DB_INIT_CDB flag was +specified to DbEnv.open. +
+

If the operation was selected to resolve a deadlock, the +Dbc.put method will fail and +throw a DbDeadlockException exception. +

The Dbc.put method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the Dbc.put method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Class

+Dbc +

See Also

+Dbc.close, +Dbc.count, +Dbc.del, +Dbc.dup, +Dbc.get +and +Dbc.put. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/dbenv_class.html b/db/docs/api_java/dbenv_class.html new file mode 100644 index 000000000..f610cf670 --- /dev/null +++ b/db/docs/api_java/dbenv_class.html @@ -0,0 +1,65 @@ + + + + + +Berkeley DB: DbEnv + + + + + + + +
+

DbEnv

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public class DbEnv extends Object +{ + public DbEnv(int flags); + ... +} +

+

Description

+

This manual page describes the specific details of the DbEnv +class, which is the center of the Berkeley DB environment. +

The following flags value may be specified: +

+

Db.DB_CLIENT
Create a client environment to connect to a server. +

The Db.DB_CLIENT flag indicates to the system that this environment +is remote on a server. The use of this flag causes the environment +methods to use functions that call a server instead of local functions. +Prior to making any environment or database method calls, the +application must call the DbEnv.set_server function to establish +the connection to the server. +

+

Class

+DbEnv +

See Also

+DbEnv.close, +DbEnv.open, +DbEnv.remove, +DbEnv.strerror, +DbEnv.get_version_string +DbEnv.set_cachesize, +DbEnv.set_errcall, +DbEnv.set_error_stream, +DbEnv.set_errpfx, +DbEnv.set_flags, +DbEnv.set_mutexlocks, +and +DbEnv.set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/dbt_class.html b/db/docs/api_java/dbt_class.html new file mode 100644 index 000000000..1df9cbb59 --- /dev/null +++ b/db/docs/api_java/dbt_class.html @@ -0,0 +1,227 @@ + + + + + +Berkeley DB: Dbt + + + + + + + +
+

Dbt

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public class Dbt extends Object +{ + public Dbt(byte[] data); + public Dbt(byte[] data, int off, int len); +

+ public void set_data(byte[] data); + public byte[] get_data(); +

+ public void set_offset(int off); + public int get_offset(); +

+ public int get_size(); + public void set_size(int size); +

+ public int get_ulen(); + public void set_ulen(int ulen); +

+ public int get_dlen(); + public void set_dlen(int dlen); +

+ public int get_doff(); + public void set_doff(int doff); +

+ public int get_flags(); + public void set_flags(int flags); +

+ public void set_recno_key_data(int recno); + public int get_recno_key_data(); +} +

+

Description

+

This manual page describes the specific details of the Dbt class, +used to encode keys and data items in a database. + +

Key/Data Pairs

+

Storage and retrieval for the Db access methods are based on +key/data pairs. Both key and data items are represented by Dbt +objects. Key and data byte strings may reference strings of zero length +up to strings of essentially unlimited length. See +Database limits for more +information. +

The Dbt class provides simple access to an underlying data structure, +whose elements can be examined or changed using the set_ or +get_ methods. The remainder of the manual page sometimes refers +to these accesses using the underlying name, e.g., simply ulen +instead of Dbt.get_ulen and Dbt.set_ulen. +Dbt can be subclassed, providing a way to associate +with it additional data, or references to other structures. +

The constructors set all elements of the underlying structure to zero. +The constructor with one argument has the effect of setting all elements +to zero except for the specified data and size elements. +The constructor with three arguments has has the additional effect of +only using the portion of the array specified by the size and offset. +

In the case where the flags structure element is 0, when being +provided a key or data item by the application, the Berkeley DB package expects +the data object to be set to a byte array of size bytes. +When returning a key/data item to the application, the Berkeley DB package will +store into the data object a byte array of size bytes. +During a get operation, one of the Db.DB_DBT_MALLOC, +Db.DB_DBT_REALLOC or Db.DB_DBT_USERMEM flags must be +specified. +

The elements of the structure underlying the Dbt class are defined as follows: +

+

byte[] data;
A byte array containing the data. +This element is accessed using Dbt.get_data and +Dbt.set_data, and may be initialized using one +of the constructors. +Note that the array data is not copied immediately, but only when the +Dbt is used. +

int offset;
The number of bytes offset into the data array to determine the +portion of the array actually used. +This element is accessed using Dbt.get_offset and +Dbt.set_offset. +

int size;
The length of data, in bytes. +This element is accessed using Dbt.get_size and +Dbt.set_size, and may be initialized +implicitly to the length of the data array with the constructor having +one argument. +

int ulen;
The size of the user's buffer (referenced by data), in bytes. +This location is not written by the Db methods. +

Note that applications can determine the length of a record by setting +the ulen to 0 and checking the return value found in size. +See the Db.DB_DBT_USERMEM flag for more information. +

This element is accessed using +Dbt.get_ulen and Dbt.set_ulen. +

int dlen;
The length of the partial record being read or written by the application, +in bytes. +See the Db.DB_DBT_PARTIAL flag for more information. +This element is accessed using +Dbt.get_dlen, and Dbt.set_dlen. +

int doff;
The offset of the partial record being read or written by the application, +in bytes. +See the Db.DB_DBT_PARTIAL flag for more information. +This element is accessed using +Dbt.get_doff and Dbt.set_doff. +

int flags;
This element is accessed using Dbt.get_flags and +Dbt.set_flags. +

The flags value must be set by bitwise inclusively OR'ing together one or more of the +following values. +

+

Db.DB_DBT_MALLOC
When this flag is set Berkeley DB will allocate memory for the returned key +or data item +and return a byte array containing the data in the data field of +the key or data Dbt object. +

If Db.DB_DBT_MALLOC is specified, Berkeley DB allocates a properly sized +byte array to contain the data. This can be convenient if you know little +about the nature of the data, specifically the size of data in the +database. However, if your application makes repeated calls to retrieve +keys or data, you may notice increased garbage collection due to this +allocation. If you know the maximum size of data you are retrieving, you +might decrease the memory burden and speed your application by allocating +your own byte array and using Db.DB_DBT_USERMEM. Even if you don't +know the maximum size, you can use this option and reallocate your array +whenever your retrieval API call +throws a DbMemoryException. +

It is an error to specify more than one of Db.DB_DBT_MALLOC, +Db.DB_DBT_REALLOC and Db.DB_DBT_USERMEM. +

Db.DB_DBT_REALLOC
When this flag is set Berkeley DB +will return the data in the data field of the key or data +Dbt object, reusing the existing byte array if it is large +enough, or allocating a new one of the appropriate size. +

It is an error to specify more than one of Db.DB_DBT_MALLOC, +Db.DB_DBT_REALLOC and Db.DB_DBT_USERMEM. +

Db.DB_DBT_USERMEM
The data field of the key or data object must reference memory +that is at least ulen bytes in length. If the length of the +requested item is less than or equal to that number of bytes, the item +is copied into the memory referenced by the data field. +Otherwise, the size field is set to the length needed for the +requested item, and the error ENOMEM is returned. +

If Db.DB_DBT_USERMEM is specified, the data field of the Dbt +must be set to an appropriately sized byte array. +

It is an error to specify more than one of Db.DB_DBT_MALLOC, +Db.DB_DBT_REALLOC and Db.DB_DBT_USERMEM. +

+

If Db.DB_DBT_MALLOC or Db.DB_DBT_REALLOC is specified, Berkeley DB +allocates a properly sized byte array to contain the data. This can be +convenient if you know little about the nature of the data, specifically +the size of data in the database. However, if your application makes +repeated calls to retrieve keys or data, you may notice increased garbage +collection due to this allocation. If you know the maximum size of data +you are retrieving, you might decrease the memory burden and speed your +application by allocating your own byte array and using +Db.DB_DBT_USERMEM. Even if you don't know the maximum size, you can +use this option and reallocate your array whenever your retrieval API call +throws a DbMemoryException. +

+

Db.DB_DBT_PARTIAL
Do partial retrieval or storage of an item. If the calling application +is doing a get, the dlen bytes starting doff bytes from +the beginning of the retrieved data record are returned as if they +comprised the entire record. If any or all of the specified bytes do +not exist in the record, the get is successful and the existing bytes +or nul bytes are returned. +

For example, if the data portion of a retrieved record was 100 bytes, +and a partial retrieval was done using a Dbt having a dlen +field of 20 and a doff field of 85, the get call would succeed, +the data field would reference the last 15 bytes of the record, +and the size field would be set to 15. +

If the calling application is doing a put, the dlen bytes starting +doff bytes from the beginning of the specified key's data record +are replaced by the data specified by the data and size +objects. +If dlen is smaller than size, the record will grow, and if +dlen is larger than size, the record will shrink. +If the specified bytes do not exist, the record will be extended using nul +bytes as necessary, and the put call will succeed. +

It is an error to attempt a partial put using the Db.put +method in a database that supports duplicate records. +Partial puts in databases supporting duplicate records must be done +using a Dbc method. +

It is an error to attempt a partial put with differing dlen and +size values in Queue or Recno databases with fixed-length records. +

For example, if the data portion of a retrieved record was 100 bytes, +and a partial put was done using a Dbt having a dlen +field of 20, a doff field of 85, and a size field of 30, +the resulting record would be 115 bytes in length, where the last 30 +bytes would be those specified by the put call. +

+
+

Although Java normally maintains proper alignment of byte arrays, the +set_offset method can be used to specify unaligned addresses. Unaligned +address accesses that are not supported by the underlying hardware may be +reported as an exception, or may stop the running Java program. + +

Logical Record Numbers

+

In all cases for the Queue and Recno access methods, and when calling the +Db.get and Dbc.get functions with the +Db.DB_SET_RECNO flag specified, the data +field of the key must be a four byte array, large enough to store an int. +The Dbt.set_recno_key_data method can be used to set the value of +the array. An int is a 32-bit type, +(which limits the number of logical records in a Queue or Recno database, +and the maximum logical record which may be directly retrieved from a +Btree database, to 4,294,967,296). The size field of the key +should be the size of that type, i.e., +4. +

Logical record numbers are 1-based, not 0-based, i.e., the first record +in the database is record number 1. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/deadlock_class.html b/db/docs/api_java/deadlock_class.html new file mode 100644 index 000000000..b41c5649d --- /dev/null +++ b/db/docs/api_java/deadlock_class.html @@ -0,0 +1,47 @@ + + + + + +Berkeley DB: DbDeadlockException + + + + + + + +
+

DbDeadlockException

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public class DbDeadlockException extends DbException { ... } +

+

Description

+

This manual page describes the DbDeadlockException class and +how it is used by the various Db* classes. +

A DbDeadlockException is thrown when multiple threads competing +for a lock are deadlocked. One of the threads' transactions is selected +for termination, and a DbDeadlockException is thrown to that thread. +

See DbEnv.set_lk_detect for more information. +

Class

+DbException +

See Also

+DbException.get_errno, +DbDeadlockException, +DbMemoryException +and +DbRunRecoveryException. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/env_close.html b/db/docs/api_java/env_close.html new file mode 100644 index 000000000..9650c83ed --- /dev/null +++ b/db/docs/api_java/env_close.html @@ -0,0 +1,82 @@ + + + + + +Berkeley DB: DbEnv.close + + + + + + + +
+

DbEnv.close

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void close(int flags) + throws DbException; +

+

Description

+

The DbEnv.close method closes the Berkeley DB environment, freeing any +allocated resources and closing any underlying subsystems. +

Calling DbEnv.close does not imply closing any databases that were +opened in the environment. +

The flags parameter is currently unused, and must be set to 0. +

Where the environment was initialized with the Db.DB_INIT_LOCK flag, +calling DbEnv.close does not release any locks still held by the +closing process, providing functionality for long-lived locks. +

Where the environment was initialized with the Db.DB_INIT_MPOOL +flag, calling DbEnv.close implies calls to DbMpoolFile.close for +any remaining open files in the memory pool that were returned to this +process by calls to DbMpoolFile.open. It does not imply a call to +DbMpoolFile.sync for those files. +

Where the environment was initialized with the Db.DB_INIT_TXN flag, +calling DbEnv.close aborts any uncommitted transactions. +(Applications are should not depend on this behavior. If the process' has +already closed a database handle which is necessary to abort an +uncommitted transaction, the Berkeley DB environment must then require that +recovery be run before further operations are done, since once a +transaction exists that cannot be committed or aborted, no future +checkpoint can ever succeed.) +

In multi-threaded applications, only a single thread may call +DbEnv.close. +

Once DbEnv.close has been called, regardless of its return, +the Berkeley DB environment handle may not be accessed again. +

The DbEnv.close method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

The DbEnv.close method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv.close method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Class

+DbEnv +

See Also

+DbEnv.close, +DbEnv.open, +DbEnv.remove, +DbEnv.strerror, +DbEnv.get_version_string +DbEnv.set_cachesize, +DbEnv.set_errcall, +DbEnv.set_error_stream, +DbEnv.set_errpfx, +DbEnv.set_flags, +DbEnv.set_mutexlocks, +and +DbEnv.set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/env_open.html b/db/docs/api_java/env_open.html new file mode 100644 index 000000000..3a1c25036 --- /dev/null +++ b/db/docs/api_java/env_open.html @@ -0,0 +1,212 @@ + + + + + +Berkeley DB: DbEnv.open + + + + + + + +
+

DbEnv.open

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+import java.io.FileNotFoundException;
+

+public void open(String db_home, int flags, int mode) + throws DbException, FileNotFoundException; +

+

Description

+

The DbEnv.open method is the interface for opening the Berkeley DB +environment. It provides a structure for creating a consistent +environment for processes using one or more of the features of Berkeley DB. +

The db_home argument to DbEnv.open (and file name +resolution in general) is described in +Berkeley DB File Naming. +

The flags argument specifies the subsystems that are initialized +and how the application's environment affects Berkeley DB file naming, among +other things. +

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +

As there are a large number of flags that can be specified, they have been +grouped together by functionality. The first group of flags indicate +which of the Berkeley DB subsystems should be initialized: +

+

Db.DB_JOINENV
Join an existing environment. This option allows applications to +join an existing environment without knowing which Berkeley DB subsystems +the environment supports. +

Db.DB_INIT_CDB
Initialize locking for the Berkeley DB Concurrent Data Store +product. In this mode, Berkeley DB provides multiple reader/single writer +access. The only other subsystem that should be specified with the +Db.DB_INIT_CDB flag is Db.DB_INIT_MPOOL. +

Access method calls are largely unchanged when using this flag, although +any cursors through which update operations (e.g., Dbc.put, +Dbc.del) will be made must have the Db.DB_WRITECURSOR value +set in the flags parameter to the cursor call that creates the cursor. +See Db.cursor for more information. +

Db.DB_INIT_LOCK
Initialize the locking subsystem. This subsystem should be used when +multiple processes or threads are going to be reading and writing a Berkeley DB +database, so that they do not interfere with each other. If all threads +are accessing the database(s) read-only, then locking is unnecessary. +When the DB_INIT_LOCK flag is specified, it is usually necessary to run +the deadlock detector, as well. See db_deadlock and +DbEnv.lock_detect for more information. +

Db.DB_INIT_LOG
Initialize the logging subsystem. This subsystem is used when recovery +from application or system failure is necessary. +

The log is stored in one or more files in the environment directory. +Each file is named using the format log.NNNNNNNNNN, where +NNNNNNNNNN is the sequence number of the file within the log. +For further information, see +Log File Limits. +

If the log region is being created and log files are already present, the +log files are reviewed and subsequent log writes are appended +to the end of the log, rather than overwriting current log entries. +

Db.DB_INIT_MPOOL
Initialize the shared memory buffer pool subsystem. This subsystem is +used whenever the application is using any Berkeley DB access method. +

Db.DB_INIT_TXN
Initialize the transaction subsystem. This subsystem is used when +recovery and atomicity of multiple operations and recovery are important. +The DB_INIT_TXN flag implies the DB_INIT_LOG flag. +
+

The second group of flags govern what recovery, if any, is performed when +the environment is initialized: +

+

Db.DB_RECOVER
Run normal recovery on this environment before opening it for normal use. +If this flag is set, the DB_CREATE flag must also be set since the regions +will be removed and recreated. +

Db.DB_RECOVER_FATAL
Run catastrophic recovery on this environment before opening it for normal +use. If this flag is set, the DB_CREATE flag must also be set since the +regions will be removed and recreated. +
+

A standard part of the recovery process is to remove the existing Berkeley DB +environment and create a new one in which to perform recovery. If the +thread of control performing recovery does not specify the correct region +initialization information (e.g., the correct memory pool cache size), +the result can be an application running in an environment with incorrect +cache and other subsystem sizes. For this reason, the thread of control +performing recovery should either specify correct configuration +information before calling the DbEnv.open method, or it should remove +the environment after recovery is completed, leaving creation of the +correctly sized environment to a subsequent call to DbEnv.open. +

All Berkeley DB recovery processing must be single-threaded, that is, only a +single thread of control may perform recovery or access a Berkeley DB +environment while recovery is being performed. As it is not an error to +specify Db.DB_RECOVER for an environment for which no recovery is +required, it is reasonable programming practice for the thread of control +responsible for performing recovery and creating the environment to always +specify the Db.DB_RECOVER flag during startup. +

The DbEnv.open function returns successfully if Db.DB_RECOVER +or Db.DB_RECOVER_FATAL is specified and no log files exist, so it is +necessary to ensure all necessary log files are present before running +recovery. For further information, consult db_archive and +db_recover. +

The third group of flags govern file naming extensions in the environment: +

+ +

Db.DB_USE_ENVIRON
The Berkeley DB process' environment may be permitted to specify information to +be used when naming files; see Berkeley DB +File Naming. As permitting users to specify which files are used can +create security problems, environment information will be used in file +naming for all users only if the DB_USE_ENVIRON flag is set. +

Db.DB_USE_ENVIRON_ROOT
The Berkeley DB process' environment may be permitted to specify information to +be used when naming files; see Berkeley DB +File Naming. As permitting users to specify which files are used can +create security problems, if the DB_USE_ENVIRON_ROOT flag is set, +environment information will be used for file naming only for users with +appropriate permissions (e.g., on UNIX systems, users with a user-ID of 0). +
+

Finally, there are a few additional, unrelated flags: +

+

Db.DB_CREATE
Cause Berkeley DB subsystems to create any underlying files, as necessary. +

Db.DB_LOCKDOWN
Lock shared Berkeley DB environment files and memory mapped databases into memory. +

Db.DB_PRIVATE
Specify that the environment will only be accessed by a single process +(although that process may be multi-threaded). This flag has two effects +on the Berkeley DB environment. First, all underlying data structures are +allocated from per-process memory instead of from shared memory that is +potentially accessible to more than a single process. Second, mutexes +are only configured to work between threads. +

This flag should not be specified if more than a single process is +accessing the environment, as it is likely to cause database corruption +and unpredictable behavior, e.g., if both a server application and the +Berkeley DB utility db_stat will access the environment, the +Db.DB_PRIVATE flag should not be specified. +

Db.DB_SYSTEM_MEM
Allocate memory from system shared memory instead of from memory backed +by the filesystem. See Shared Memory +Regions for more information. +

Db.DB_THREAD
Cause the DbEnv handle returned by DbEnv.open to be +free-threaded, that is, useable by multiple threads within a +single address space. +

Threading is always assumed in the Java API, so no special flags are +required and Berkeley DB functions will always behave as if the Db.DB_THREAD +flag was specified. +

+

On UNIX systems, or in IEEE/ANSI Std 1003.1 (POSIX) environments, all files created by Berkeley DB +are created with mode mode (as described in chmod(2)) and +modified by the process' umask value at the time of creation (see +umask(2)). The group ownership of created files is based on +the system and directory defaults, and is not further specified by Berkeley DB. +If mode is 0, files are created readable and writeable by both +owner and group. On Windows systems, the mode argument is ignored. +

The DbEnv.open method throws an exception that encapsulates a non-zero error value on +failure. +

Environment Variables

+

+

DB_HOME
The environment variable DB_HOME may be used as the path of +the database home as described in +Berkeley DB File Naming. +
+

Errors

+

The DbEnv.open method may fail and throw an exception encapsulating a non-zero error for the following conditions: +

+

EAGAIN
The shared memory region was locked and (repeatedly) unavailable. +
+

+

EINVAL
An invalid flag value or parameter was specified. +

+The Db.DB_THREAD flag was specified and spinlocks are not +implemented for this architecture. +

The DB_HOME or TMPDIR environment variables were set but empty. +

An incorrectly formatted NAME VALUE entry or line was found. +

+

+

ENOSPC
HP-UX only: a previously created Berkeley DB environment for this process still +exists. +
+

If the file or directory does not exist, the DbEnv.open method will +fail and +throw a FileNotFoundException exception. +

The DbEnv.open method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv.open method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Class

+DbEnv +

See Also

+DbEnv.close, +DbEnv.open, +DbEnv.remove, +DbEnv.strerror, +DbEnv.get_version_string +DbEnv.set_cachesize, +DbEnv.set_errcall, +DbEnv.set_error_stream, +DbEnv.set_errpfx, +DbEnv.set_flags, +DbEnv.set_mutexlocks, +and +DbEnv.set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/env_remove.html b/db/docs/api_java/env_remove.html new file mode 100644 index 000000000..acfaf3976 --- /dev/null +++ b/db/docs/api_java/env_remove.html @@ -0,0 +1,129 @@ + + + + + +Berkeley DB: DbEnv.remove + + + + + + + +
+

DbEnv.remove

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+import java.io.FileNotFoundException;
+

+public void remove(String db_home, int flags) + throws DbException, FileNotFoundException; +

+

Description

+

The DbEnv.remove method destroys a Berkeley DB environment, if it is not +currently in use. The environment regions, including any backing files, +are removed. Any log or database files and the environment directory are +not removed. +

The db_home argument to DbEnv.remove is described in +Berkeley DB File Naming. +

If there are processes that have called DbEnv.open without +calling DbEnv.close (i.e., there are processes currently using +the environment), DbEnv.remove will fail without further action, +unless the Db.DB_FORCE flag is set, in which case +DbEnv.remove will attempt to remove the environment regardless +of any processes still using it. +

The result of attempting to forcibly destroy the environment when it is +in use is unspecified. Processes using an environment often maintain open +file descriptors for shared regions within it. On UNIX systems, the +environment removal will usually succeed and processes that have already +joined the region will continue to run in that region without change, +however processes attempting to join the environment will either fail or +create new regions. On other systems (e.g., Windows/NT), where the +unlink(2) system call will fail if any process has an open +file descriptor for the file, the region removal will fail. +

Calling DbEnv.remove should not be necessary for most applications, +as the Berkeley DB environment is cleaned up as part of normal database recovery +procedures, however, applications may wish to call DbEnv.remove +as part of application shutdown to free up system resources. +Specifically, when the Db.DB_SYSTEM_MEM flag was specified to +DbEnv.open, it may be useful to call DbEnv.remove in order +to release system shared memory segments that have been allocated. +

In the case of catastrophic or system failure, database recovery must be +performed (see db_recover), or the Db.DB_RECOVER and +Db.DB_RECOVER_FATAL flags to DbEnv.open must be specified +when the environment is re-opened. Alternatively, if recovery is not +required because no database state is maintained across failures, and +the Db.DB_SYSTEM_MEM flag was not specified when the environment +was created, it is possible to clean up an environment by removing all +of the files in the environment directory that begin with the string +prefix "__db", as no backing files are created in any other directory. +

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +

+

Db.DB_FORCE
If the Db.DB_FORCE flag is set, the environment is removed regardless +of any processes that may still using it, and, no locks are acquired +during this process. (Generally, the Db.DB_FORCE flag is only +specified when applications were unable to shut down cleanly, and there +is a risk that an application may have died holding a Berkeley DB lock.) + +

Db.DB_USE_ENVIRON
The Berkeley DB process' environment may be permitted to specify information to +be used when naming files; see Berkeley DB +File Naming. As permitting users to specify which files are used can +create security problems, environment information will be used in file +naming for all users only if the DB_USE_ENVIRON flag is set. +

Db.DB_USE_ENVIRON_ROOT
The Berkeley DB process' environment may be permitted to specify information to +be used when naming files; see Berkeley DB +File Naming. As permitting users to specify which files are used can +create security problems, if the DB_USE_ENVIRON_ROOT flag is set, +environment information will be used for file naming only for users with +appropriate permissions (e.g., on UNIX systems, users with a user-ID of 0). +
+

In multi-threaded applications, only a single thread may call +DbEnv.remove. +

A DbEnv handle which has already been used to open an +environment should not be used to call the DbEnv.remove method, a new +DbEnv handle should be created for that purpose. +

Once DbEnv.remove has been called, regardless of its return, +the Berkeley DB environment handle may not be accessed again. +

The DbEnv.remove method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

+

EBUSY
The shared memory region was in use and the force flag was not set. +
+

If the file or directory does not exist, the DbEnv.remove method will +fail and +throw a FileNotFoundException exception. +

The DbEnv.remove method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv.remove method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Class

+DbEnv +

See Also

+DbEnv.close, +DbEnv.open, +DbEnv.remove, +DbEnv.strerror, +DbEnv.get_version_string +DbEnv.set_cachesize, +DbEnv.set_errcall, +DbEnv.set_error_stream, +DbEnv.set_errpfx, +DbEnv.set_flags, +DbEnv.set_mutexlocks, +and +DbEnv.set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/env_set_cachesize.html b/db/docs/api_java/env_set_cachesize.html new file mode 100644 index 000000000..af31e44f9 --- /dev/null +++ b/db/docs/api_java/env_set_cachesize.html @@ -0,0 +1,86 @@ + + + + + + +Berkeley DB: DbEnv.set_cachesize + + + + + + + +
+

DbEnv.set_cachesize

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public int set_cachesize(int gbytes, int bytes, in ncache) + throws DbException; +

+

Description

+

Set the size of the database's shared memory buffer pool, i.e., the cache, +to gbytes gigabytes plus bytes. The cache should be the +size of the normal working data set of the application, with some small +amount of additional memory for unusual situations. (Note, the working +set is not the same as the number of simultaneously referenced pages, and +should be quite a bit larger!) +

The default cache size is 256KB, and may not be specified as less than +20KB. Any cache size less than 500MB is automatically increased by 25% +to account for buffer pool overhead, cache sizes larger than 500MB are +used as specified. For information on tuning the Berkeley DB cache size, see +Selecting a cache size. +

It is possible to specify caches to Berkeley DB that are large enough so that +they cannot be allocated contiguously on some architectures, e.g., some +releases of Solaris limit the amount of memory that may be allocated +contiguously by a process. If ncache is 0 or 1, the cache will +be allocated contiguously in memory. If it is greater than 1, the cache +will be broken up into ncache equally sized separate pieces of +memory. +

The DbEnv.set_cachesize interface may only be used to configure Berkeley DB before +the DbEnv.open interface is called. +

The DbEnv.set_cachesize method throws an exception that encapsulates a non-zero error value on +failure. +

The database environment's cache size may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_cachesize", one or more whitespace characters, +and the three arguments specified to this interface, separated by whitespace +characters, for example, "set_cachesize 1 500 2". Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DbEnv.open was called. +

The specified cache size was impossibly small. +

+

Class

+DbEnv +

See Also

+DbEnv.close, +DbEnv.open, +DbEnv.remove, +DbEnv.strerror, +DbEnv.get_version_string +DbEnv.set_cachesize, +DbEnv.set_errcall, +DbEnv.set_error_stream, +DbEnv.set_errpfx, +DbEnv.set_flags, +DbEnv.set_mutexlocks, +and +DbEnv.set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/env_set_data_dir.html b/db/docs/api_java/env_set_data_dir.html new file mode 100644 index 000000000..52fc159e7 --- /dev/null +++ b/db/docs/api_java/env_set_data_dir.html @@ -0,0 +1,77 @@ + + + + + +Berkeley DB: DbEnv.set_data_dir + + + + + + + +
+

DbEnv.set_data_dir

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void set_data_dir(String dir) + throws DbException; +

+

Description

+

Set the path of a directory to be used as the location of the access +method database files. Paths specified to the Db.open function +will be searched relative to this path. Paths set using this interface +are additive, and specifying more than one will result in each specified +directory being searched for database files. If any directories are +specified, created database files will always be created in the first path +specified. +

If no database directories are specified, database files can only exist +in the environment home directory. See Berkeley DB File Naming for more information. +

For the greatest degree of recoverability from system or application +failure, database files and log files should be located on separate +physical devices. +

The DbEnv.set_data_dir interface may only be used to configure Berkeley DB before +the DbEnv.open interface is called. +

The DbEnv.set_data_dir method throws an exception that encapsulates a non-zero error value on +failure. +

The database environment's data directory may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_data_dir", one or more whitespace characters, +and the directory name. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DbEnv.open was called. +

+

Class

+DbEnv +

See Also

+DbEnv.close, +DbEnv.open, +DbEnv.remove, +DbEnv.strerror, +DbEnv.get_version_string +DbEnv.set_cachesize, +DbEnv.set_errcall, +DbEnv.set_error_stream, +DbEnv.set_errpfx, +DbEnv.set_flags, +DbEnv.set_mutexlocks, +and +DbEnv.set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/env_set_errcall.html b/db/docs/api_java/env_set_errcall.html new file mode 100644 index 000000000..596de4713 --- /dev/null +++ b/db/docs/api_java/env_set_errcall.html @@ -0,0 +1,78 @@ + + + + + + +Berkeley DB: DbEnv.set_errcall + + + + + + + +
+

DbEnv.set_errcall

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public interface DbErrcall +{ + public abstract void errcall(String errpfx, String msg); +} +public class DbEnv +{ + public void set_errcall(DbErrcall errcall); + ... +} +

+

Description

+When an error occurs in the Berkeley DB library, an exception is thrown. In +some cases, however, the errno value may be insufficient to +completely describe the cause of the error, especially during initial +application debugging. +

The DbEnv.set_errcall method is used to enhance the mechanism for reporting error +messages to the application. The DbEnv.set_errcall method must be +called with a single object argument. The object's class must implement +the DbErrcall interface. In some cases, when an error occurs, Berkeley DB will +invoke the object's errcall() method with two arguments; the first is the +prefix string (as previously set by Db.set_errpfx or +DbEnv.set_errpfx), the second will be an error message string. +It is up to this method to display the message in an appropriate manner. +

Alternatively, you can use the DbEnv.set_error_stream method to display +the additional information via an output stream. You should not mix these +approaches. +

This error logging enhancement does not slow performance or significantly +increase application size, and may be run during normal operation as well +as during application debugging. +

The DbEnv.set_errcall interface may be used to configure Berkeley DB at any time +during the life of the application. +

Class

+DbEnv +

See Also

+DbEnv.close, +DbEnv.open, +DbEnv.remove, +DbEnv.strerror, +DbEnv.get_version_string +DbEnv.set_cachesize, +DbEnv.set_errcall, +DbEnv.set_error_stream, +DbEnv.set_errpfx, +DbEnv.set_flags, +DbEnv.set_mutexlocks, +and +DbEnv.set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/env_set_error_stream.html b/db/docs/api_java/env_set_error_stream.html new file mode 100644 index 000000000..18f44c08d --- /dev/null +++ b/db/docs/api_java/env_set_error_stream.html @@ -0,0 +1,69 @@ + + + + + +Berkeley DB: DbEnv.set_error_stream + + + + + + + +
+

DbEnv.set_error_stream

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void Db.set_error_stream(OutputStream s) + throws DbException +

+

Description

+

When an error occurs in the Berkeley DB library, an exception is thrown. In +some cases, however, the errno value may be insufficient to +completely describe the cause of the error, especially during initial +application debugging. +

The DbEnv.set_error_stream method is used to enhance the mechanism for +reporting error messages to the application by setting a OutputStream +to be used for displaying additional Berkeley DB error messages. In some cases, +when an error occurs, Berkeley DB will output an additional error message to +the specified stream. +

The error message will consist of the prefix string and a colon +(":") (if a prefix string was previously specified using +DbEnv.set_errpfx), an error string, and a trailing +<newline> character. +

Alternatively, you can use the DbEnv.set_errcall method to capture the +additional error information in a way that does not use output streams. +You should not mix these approaches. +

This error logging enhancement does not slow performance or significantly +increase application size, and may be run during normal operation as well +as during application debugging. +

Class

+DbEnv +

See Also

+DbEnv.close, +DbEnv.open, +DbEnv.remove, +DbEnv.strerror, +DbEnv.get_version_string +DbEnv.set_cachesize, +DbEnv.set_errcall, +DbEnv.set_error_stream, +DbEnv.set_errpfx, +DbEnv.set_flags, +DbEnv.set_mutexlocks, +and +DbEnv.set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/env_set_errpfx.html b/db/docs/api_java/env_set_errpfx.html new file mode 100644 index 000000000..aca43448c --- /dev/null +++ b/db/docs/api_java/env_set_errpfx.html @@ -0,0 +1,52 @@ + + + + + +Berkeley DB: DbEnv.set_errpfx + + + + + + + +
+

DbEnv.set_errpfx

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void set_errpfx(String errpfx); +

+

Description

+

Set the prefix string that appears before error messages issued by Berkeley DB. +

The DbEnv.set_errpfx interface may be used to configure Berkeley DB at any time +during the life of the application. +

Class

+DbEnv +

See Also

+DbEnv.close, +DbEnv.open, +DbEnv.remove, +DbEnv.strerror, +DbEnv.get_version_string +DbEnv.set_cachesize, +DbEnv.set_errcall, +DbEnv.set_error_stream, +DbEnv.set_errpfx, +DbEnv.set_flags, +DbEnv.set_mutexlocks, +and +DbEnv.set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/env_set_feedback.html b/db/docs/api_java/env_set_feedback.html new file mode 100644 index 000000000..1b5310e25 --- /dev/null +++ b/db/docs/api_java/env_set_feedback.html @@ -0,0 +1,76 @@ + + + + + +Berkeley DB: DbEnv.set_feedback + + + + + + + +
+

DbEnv.set_feedback

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public interface DbEnvFeedback +{ + public abstract void db_feedback(DbEnv dbenv, int opcode, int pct); +} +public class DbEnv +{ + public void set_feedback(DbEnvFeedback db_feedback) + throws DbException; + ... +} +

+

Description

+

Some operations performed by the Berkeley DB library can take non-trivial +amounts of time. The DbEnv.set_feedback method can be used by +applications to monitor progress within these operations. +

When an operation is likely to take a long time, Berkeley DB will call the +specified callback method. This method must be declared with +three arguments: the first will be a reference to the enclosing +environment, the second a flag value, and the third the percent of the +operation that has been completed, specified as an integer value between +0 and 100. It is up to the callback method to display this +information in an appropriate manner. +

The opcode argument may take on any of the following values: +

+

Db.DB_RECOVER
The environment is being recovered. +
+

The DbEnv.set_feedback interface may be used to configure Berkeley DB at any time +during the life of the application. +

The DbEnv.set_feedback method throws an exception that encapsulates a non-zero error value on +failure. +

Class

+DbEnv +

See Also

+DbEnv.close, +DbEnv.open, +DbEnv.remove, +DbEnv.strerror, +DbEnv.get_version_string +DbEnv.set_cachesize, +DbEnv.set_errcall, +DbEnv.set_error_stream, +DbEnv.set_errpfx, +DbEnv.set_flags, +DbEnv.set_mutexlocks, +and +DbEnv.set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/env_set_flags.html b/db/docs/api_java/env_set_flags.html new file mode 100644 index 000000000..d371429e0 --- /dev/null +++ b/db/docs/api_java/env_set_flags.html @@ -0,0 +1,84 @@ + + + + + +Berkeley DB: DbEnv.set_flags + + + + + + + +
+

DbEnv.set_flags

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void set_flags(int flags, int onoff) + throws DbException; +

+

Description

+

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +If onoff is zero, the specified flags are cleared, otherwise they +are set. +

+

Db.DB_CDB_ALLDB
For Berkeley DB Concurrent Data Store applications, perform locking on an environment-wide basis +rather than per-database. This flag may only be used to configure Berkeley DB +before the DbEnv.open interface is called. +

Db.DB_NOMMAP
Copy read-only database files in this environment into the local cache +instead of potentially mapping them into process memory (see the +description of the DbEnv.set_mp_mmapsize method for further information). +

Db.DB_TXN_NOSYNC
Do not synchronously flush the log on transaction commit or prepare. +This means that transactions exhibit the ACI (atomicity, consistency and +isolation) properties, but not D (durability), i.e., database integrity +will be maintained but it is possible that some number of the most +recently committed transactions may be undone during recovery instead of +being redone. +

The number of transactions that are potentially at risk is governed by +how often the log is checkpointed (see db_checkpoint for more +information) and how many log updates can fit on a single log page. +

+

The DbEnv.set_flags method throws an exception that encapsulates a non-zero error value on +failure. +

The database environment's flag values may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_flags", one or more whitespace characters, +and the interface flag argument as a string, for example, "set_flags +DB_TXN_NOSYNC". Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

Class

+DbEnv +

See Also

+DbEnv.close, +DbEnv.open, +DbEnv.remove, +DbEnv.strerror, +DbEnv.get_version_string +DbEnv.set_cachesize, +DbEnv.set_errcall, +DbEnv.set_error_stream, +DbEnv.set_errpfx, +DbEnv.set_flags, +DbEnv.set_mutexlocks, +and +DbEnv.set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/env_set_lg_bsize.html b/db/docs/api_java/env_set_lg_bsize.html new file mode 100644 index 000000000..1f3725f6e --- /dev/null +++ b/db/docs/api_java/env_set_lg_bsize.html @@ -0,0 +1,71 @@ + + + + + +Berkeley DB: DbEnv.set_lg_bsize + + + + + + + +
+

DbEnv.set_lg_bsize

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void set_lg_bsize(int lg_bsize) + throws DbException; +

+

Description

+

Set the size of the in-memory log buffer, in bytes. By default, or if +the value is set to 0, a size of 32K is used. +

Log information is stored in-memory until the storage space fills up +or transaction commit forces the information to be flushed to stable +storage. In the presence of long-running transactions or transactions +producing large amounts of data, larger buffer sizes can increase +throughput. +

The DbEnv.set_lg_bsize interface may only be used to configure Berkeley DB before +the DbEnv.open interface is called. +

The DbEnv.set_lg_bsize method throws an exception that encapsulates a non-zero error value on +failure. +

The database environment's log buffer size may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_lg_bsize", one or more whitespace characters, +and the size in bytes. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DbEnv.open was called. +

+

Class

+DbEnv +

See Also

+DbEnv.set_lg_bsize, +DbEnv.set_lg_max, +DbEnv.log_archive, +DbEnv.log_compare, +DbEnv.log_file, +DbEnv.log_flush, +DbEnv.log_get, +DbEnv.log_put, +DbEnv.log_register, +DbEnv.log_stat +and +DbEnv.log_unregister. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/env_set_lg_dir.html b/db/docs/api_java/env_set_lg_dir.html new file mode 100644 index 000000000..6633ee5d8 --- /dev/null +++ b/db/docs/api_java/env_set_lg_dir.html @@ -0,0 +1,73 @@ + + + + + +Berkeley DB: DbEnv.set_lg_dir + + + + + + + +
+

DbEnv.set_lg_dir

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void set_lg_dir(String dir) + throws DbException; +

+

Description

+

The path of a directory to be used as the location of logging files. +Log files created by the Log Manager subsystem will be created in this +directory. +

If no logging directory is specified, log files are created in the +environment home directory. See Berkeley DB File Naming for more information. +

For the greatest degree of recoverability from system or application +failure, database files and log files should be located on separate +physical devices. +

The DbEnv.set_lg_dir interface may only be used to configure Berkeley DB before +the DbEnv.open interface is called. +

The DbEnv.set_lg_dir method throws an exception that encapsulates a non-zero error value on +failure. +

The database environment's logging directory may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_lg_dir", one or more whitespace characters, +and the directory name. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DbEnv.open was called. +

+

Class

+DbEnv +

See Also

+DbEnv.close, +DbEnv.open, +DbEnv.remove, +DbEnv.strerror, +DbEnv.get_version_string +DbEnv.set_cachesize, +DbEnv.set_errcall, +DbEnv.set_error_stream, +DbEnv.set_errpfx, +DbEnv.set_flags, +DbEnv.set_mutexlocks, +and +DbEnv.set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/env_set_lg_max.html b/db/docs/api_java/env_set_lg_max.html new file mode 100644 index 000000000..fea4163be --- /dev/null +++ b/db/docs/api_java/env_set_lg_max.html @@ -0,0 +1,71 @@ + + + + + +Berkeley DB: DbEnv.set_lg_max + + + + + + + +
+

DbEnv.set_lg_max

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void set_lg_max(int lg_max) + throws DbException; +

+

Description

+

Set the maximum size of a single file in the log, in bytes. Because +DbLsn file offsets are unsigned 4-byte values, the set value may +not be larger than the maximum unsigned 4-byte value. By default, or if +the value is set to 0, a size of 10MB is used. +

See Log File Limits +for more information. +

The DbEnv.set_lg_max interface may only be used to configure Berkeley DB before +the DbEnv.open interface is called. +

The DbEnv.set_lg_max method throws an exception that encapsulates a non-zero error value on +failure. +

The database environment's log file size may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_lg_max", one or more whitespace characters, +and the size in bytes. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DbEnv.open was called. +

The specified log file size was too large. +

+

Class

+DbEnv +

See Also

+DbEnv.set_lg_bsize, +DbEnv.set_lg_max, +DbEnv.log_archive, +DbEnv.log_compare, +DbEnv.log_file, +DbEnv.log_flush, +DbEnv.log_get, +DbEnv.log_put, +DbEnv.log_register, +DbEnv.log_stat +and +DbEnv.log_unregister. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/env_set_lk_conflicts.html b/db/docs/api_java/env_set_lk_conflicts.html new file mode 100644 index 000000000..3ad5c6173 --- /dev/null +++ b/db/docs/api_java/env_set_lk_conflicts.html @@ -0,0 +1,68 @@ + + + + + +Berkeley DB: DbEnv.set_lk_conflicts + + + + + + + +
+

DbEnv.set_lk_conflicts

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void set_lk_conflicts(byte[][] conflicts) + throws DbException; +

+

Description

+

Set the locking conflicts matrix. +A non-0 value for the array element: +

conflicts[requested_mode][held_mode]
+

indicates that requested_mode and held_mode conflict. The +not-granted mode must be represented by 0. +

If no conflicts value is specified, the conflicts array +db_rw_conflicts is used; see Standard Lock Modes for a description of that array. +

The DbEnv.set_lk_conflicts interface may only be used to configure Berkeley DB before +the DbEnv.open interface is called. +

The DbEnv.set_lk_conflicts method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DbEnv.open was called. +

+

+

ENOMEM
No memory was available to copy the conflicts array. +
+

Classes

+DbEnv, DbLock +

See Also

+DbEnv.set_lk_conflicts, +DbEnv.set_lk_detect, +DbEnv.set_lk_max_locks, +DbEnv.set_lk_max_lockers, +DbEnv.set_lk_max_objects, +DbEnv.set_lk_max, +DbEnv.lock_detect, +DbEnv.lock_get, +DbEnv.lock_id, +DbLock.put +and +DbEnv.lock_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/env_set_lk_detect.html b/db/docs/api_java/env_set_lk_detect.html new file mode 100644 index 000000000..cf3dd0871 --- /dev/null +++ b/db/docs/api_java/env_set_lk_detect.html @@ -0,0 +1,74 @@ + + + + + +Berkeley DB: DbEnv.set_lk_detect + + + + + + + +
+

DbEnv.set_lk_detect

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void set_lk_detect(int detect) + throws DbException; +

+

Description

+

Set if the deadlock detector is to be run whenever a lock conflict occurs, +and specify which transaction should be aborted in the case of a deadlock. +The specified value must be one of the following list: +

+

DB_LOCK_DEFAULT
Use the default policy as specified by db_deadlock. +
DB_LOCK_OLDEST
Abort the oldest transaction. +
DB_LOCK_RANDOM
Abort a random transaction involved in the deadlock. +
DB_LOCK_YOUNGEST
Abort the youngest transaction. +
+

The DbEnv.set_lk_detect interface may only be used to configure Berkeley DB before +the DbEnv.open interface is called. +

The DbEnv.set_lk_detect method throws an exception that encapsulates a non-zero error value on +failure. +

The database environment's deadlock detector configuration may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_lk_detect", one or more whitespace characters, +and the interface detect argument as a string, for example, +"set_lk_detect DB_LOCK_OLDEST". Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DbEnv.open was called. +

+

Classes

+DbEnv, DbLock +

See Also

+DbEnv.set_lk_conflicts, +DbEnv.set_lk_detect, +DbEnv.set_lk_max_locks, +DbEnv.set_lk_max_lockers, +DbEnv.set_lk_max_objects, +DbEnv.set_lk_max, +DbEnv.lock_detect, +DbEnv.lock_get, +DbEnv.lock_id, +DbLock.put +and +DbEnv.lock_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/env_set_lk_max.html b/db/docs/api_java/env_set_lk_max.html new file mode 100644 index 000000000..1e2a92890 --- /dev/null +++ b/db/docs/api_java/env_set_lk_max.html @@ -0,0 +1,74 @@ + + + + + +Berkeley DB: DbEnv.set_lk_max + + + + + + + +
+

DbEnv.set_lk_max

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void set_lk_max(int max) + throws DbException; +

+

Description

+

The DbEnv.set_lk_max method interface has been deprecated in favor of +the DbEnv.set_lk_max_locks, DbEnv.set_lk_max_lockers, +and DbEnv.set_lk_max_objects methods. Please update your applications. +

Set each of the maximum number of locks, lockers and lock objects +supported by the Berkeley DB lock subsystem to max. This value is +used by DbEnv.open to estimate how much space to allocate for +various lock-table data structures. For specific information on +configuring the size of the lock subsystem, see +Configuring locking: sizing the +system. +

The DbEnv.set_lk_max interface may only be used to configure Berkeley DB before +the DbEnv.open interface is called. +

The DbEnv.set_lk_max method throws an exception that encapsulates a non-zero error value on +failure. +

The database environment's maximum number of locks may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_lk_max", one or more whitespace characters, +and the number of locks. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DbEnv.open was called. +

+

Classes

+DbEnv, DbLock +

See Also

+DbEnv.set_lk_conflicts, +DbEnv.set_lk_detect, +DbEnv.set_lk_max_locks, +DbEnv.set_lk_max_lockers, +DbEnv.set_lk_max_objects, +DbEnv.set_lk_max, +DbEnv.lock_detect, +DbEnv.lock_get, +DbEnv.lock_id, +DbLock.put +and +DbEnv.lock_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/env_set_lk_max_lockers.html b/db/docs/api_java/env_set_lk_max_lockers.html new file mode 100644 index 000000000..500244bee --- /dev/null +++ b/db/docs/api_java/env_set_lk_max_lockers.html @@ -0,0 +1,70 @@ + + + + + +Berkeley DB: DbEnv.set_lk_max_lockers + + + + + + + +
+

DbEnv.set_lk_max_lockers

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void set_lk_max_lockers(int max) + throws DbException; +

+

Description

+

Set the maximum number of simultaneous locking entities supported by +the Berkeley DB lock subsystem. This value is used by DbEnv.open to +estimate how much space to allocate for various lock-table data +structures. For specific information on configuring the size of the +lock subsystem, see +Configuring locking: sizing the system. +

The DbEnv.set_lk_max_lockers interface may only be used to configure Berkeley DB before +the DbEnv.open interface is called. +

The DbEnv.set_lk_max_lockers method throws an exception that encapsulates a non-zero error value on +failure. +

The database environment's maximum number of lockers may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_lk_max_lockers", one or more whitespace characters, +and the number of lockers. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DbEnv.open was called. +

+

Classes

+DbEnv, DbLock +

See Also

+DbEnv.set_lk_conflicts, +DbEnv.set_lk_detect, +DbEnv.set_lk_max_locks, +DbEnv.set_lk_max_lockers, +DbEnv.set_lk_max_objects, +DbEnv.set_lk_max, +DbEnv.lock_detect, +DbEnv.lock_get, +DbEnv.lock_id, +DbLock.put +and +DbEnv.lock_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/env_set_lk_max_locks.html b/db/docs/api_java/env_set_lk_max_locks.html new file mode 100644 index 000000000..88a5100aa --- /dev/null +++ b/db/docs/api_java/env_set_lk_max_locks.html @@ -0,0 +1,69 @@ + + + + + +Berkeley DB: DbEnv.set_lk_max_locks + + + + + + + +
+

DbEnv.set_lk_max_locks

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void set_lk_max_locks(int max) + throws DbException; +

+

Description

+

Set the maximum number of locks supported by the Berkeley DB lock subsystem. +This value is used by DbEnv.open to estimate how much space to +allocate for various lock-table data structures. For specific +information on configuring the size of the lock subsystem, see +Configuring locking: sizing the system. +

The DbEnv.set_lk_max_locks interface may only be used to configure Berkeley DB before +the DbEnv.open interface is called. +

The DbEnv.set_lk_max_locks method throws an exception that encapsulates a non-zero error value on +failure. +

The database environment's maximum number of locks may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_lk_max_locks", one or more whitespace characters, +and the number of locks. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DbEnv.open was called. +

+

Classes

+DbEnv, DbLock +

See Also

+DbEnv.set_lk_conflicts, +DbEnv.set_lk_detect, +DbEnv.set_lk_max_locks, +DbEnv.set_lk_max_lockers, +DbEnv.set_lk_max_objects, +DbEnv.set_lk_max, +DbEnv.lock_detect, +DbEnv.lock_get, +DbEnv.lock_id, +DbLock.put +and +DbEnv.lock_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/env_set_lk_max_objects.html b/db/docs/api_java/env_set_lk_max_objects.html new file mode 100644 index 000000000..b31ebefbf --- /dev/null +++ b/db/docs/api_java/env_set_lk_max_objects.html @@ -0,0 +1,70 @@ + + + + + +Berkeley DB: DbEnv.set_lk_max_objects + + + + + + + +
+

DbEnv.set_lk_max_objects

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void set_lk_max_objects(int max) + throws DbException; +

+

Description

+

Set the maximum number of simultaneously locked objects supported by +the Berkeley DB lock subsystem. This value is used by DbEnv.open to +estimate how much space to allocate for various lock-table data +structures. For specific information on configuring the size of the +lock subsystem, see +Configuring locking: sizing the system. +

The DbEnv.set_lk_max_objects interface may only be used to configure Berkeley DB before +the DbEnv.open interface is called. +

The DbEnv.set_lk_max_objects method throws an exception that encapsulates a non-zero error value on +failure. +

The database environment's maximum number of objects may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_lk_max_objects", one or more whitespace characters, +and the number of objects. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DbEnv.open was called. +

+

Classes

+DbEnv, DbLock +

See Also

+DbEnv.set_lk_conflicts, +DbEnv.set_lk_detect, +DbEnv.set_lk_max_locks, +DbEnv.set_lk_max_lockers, +DbEnv.set_lk_max_objects, +DbEnv.set_lk_max, +DbEnv.lock_detect, +DbEnv.lock_get, +DbEnv.lock_id, +DbLock.put +and +DbEnv.lock_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/env_set_mp_mmapsize.html b/db/docs/api_java/env_set_mp_mmapsize.html new file mode 100644 index 000000000..ef1d5b14e --- /dev/null +++ b/db/docs/api_java/env_set_mp_mmapsize.html @@ -0,0 +1,66 @@ + + + + + +Berkeley DB: DbEnv.set_mp_mmapsize + + + + + + + +
+

DbEnv.set_mp_mmapsize

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void set_mp_mmapsize(long mmapsize) + throws DbException; +

+

Description

+

Files that are opened read-only in the pool (and that satisfy a few other +criteria) are, by default, mapped into the process address space instead +of being copied into the local cache. This can result in better-than-usual +performance, as available virtual memory is normally much larger than the +local cache, and page faults are faster than page copying on many systems. +However, in the presence of limited virtual memory it can cause resource +starvation, and in the presence of large databases, it can result in immense +process sizes. +

Set the maximum file size, in bytes, for a file to be mapped into the +process address space. If no value is specified, it defaults to 10MB. +

The DbEnv.set_mp_mmapsize interface may only be used to configure Berkeley DB before +the DbEnv.open interface is called. +

The DbEnv.set_mp_mmapsize method throws an exception that encapsulates a non-zero error value on +failure. +

The database environment's maximum mapped file size may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_mp_mmapsize", one or more whitespace characters, +and the size in bytes. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DbEnv.open was called. +

+

Class

+DbEnv +

See Also

+DbEnv.memp_fstat, +DbEnv.memp_stat +and +DbEnv.memp_trickle. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/env_set_mutexlocks.html b/db/docs/api_java/env_set_mutexlocks.html new file mode 100644 index 000000000..e09898770 --- /dev/null +++ b/db/docs/api_java/env_set_mutexlocks.html @@ -0,0 +1,59 @@ + + + + + +Berkeley DB: DbEnv.set_mutexlocks + + + + + + + +
+

DbEnv.set_mutexlocks

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void set_mutexlocks(int do_lock) + throws DbException; +

+

Description

+

Toggle mutex locks. Setting do_lock to a false value causes +Berkeley DB to grant all requested mutual exclusion mutexes without regard +for their availability. +

This functionality should never be used for any other purpose than +debugging. +

The DbEnv.set_mutexlocks interface may be used to configure Berkeley DB at any time +during the life of the application. +

The DbEnv.set_mutexlocks method throws an exception that encapsulates a non-zero error value on +failure. +

Class

+DbEnv +

See Also

+DbEnv.close, +DbEnv.open, +DbEnv.remove, +DbEnv.strerror, +DbEnv.get_version_string +DbEnv.set_cachesize, +DbEnv.set_errcall, +DbEnv.set_error_stream, +DbEnv.set_errpfx, +DbEnv.set_flags, +DbEnv.set_mutexlocks, +and +DbEnv.set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/env_set_pageyield.html b/db/docs/api_java/env_set_pageyield.html new file mode 100644 index 000000000..f67f3a888 --- /dev/null +++ b/db/docs/api_java/env_set_pageyield.html @@ -0,0 +1,69 @@ + + + + + +Berkeley DB: DbEnv.set_pageyield + + + + + + + +
+

DbEnv.set_pageyield

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+static int +DbEnv.set_pageyield(int pageyield); + throws DbException; +

+

Description

+

Yield the processor whenever requesting a page from the cache. Setting +pageyield to a true value causes Berkeley DB to yield the processor +any time a thread requests a page from the cache. +

The DbEnv.set_pageyield interface affects the entire application, not a single +database or database environment. +

While the DbEnv.set_pageyield interface may be used to configure Berkeley DB at any time +during the life of the application, it should normally be called before +making any calls to the db_env_create or db_create methods. +

This functionality should never be used for any other purpose than stress +testing. +

The DbEnv.set_pageyield interface may be used to configure Berkeley DB at any time +during the life of the application. +

The DbEnv.set_pageyield method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

Class

+DbEnv +

See Also

+DbEnv.close, +DbEnv.open, +DbEnv.remove, +DbEnv.strerror, +DbEnv.get_version_string +DbEnv.set_cachesize, +DbEnv.set_errcall, +DbEnv.set_error_stream, +DbEnv.set_errpfx, +DbEnv.set_flags, +DbEnv.set_mutexlocks, +and +DbEnv.set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/env_set_panicstate.html b/db/docs/api_java/env_set_panicstate.html new file mode 100644 index 000000000..d8b38ee2f --- /dev/null +++ b/db/docs/api_java/env_set_panicstate.html @@ -0,0 +1,65 @@ + + + + + +Berkeley DB: DbEnv.set_panicstate + + + + + + + +
+

DbEnv.set_panicstate

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+static int +DbEnv.set_panicstate(int panic); + throws DbException; +

+

Description

+

Toggle the Berkeley DB panic state. Setting panic to a true value +causes Berkeley DB to refuse attempts to call Berkeley DB functions with the +Db.DB_RUNRECOVERY error return. +

The DbEnv.set_panicstate interface affects the entire application, not a single +database or database environment. +

While the DbEnv.set_panicstate interface may be used to configure Berkeley DB at any time +during the life of the application, it should normally be called before +making any calls to the db_env_create or db_create methods. +

The DbEnv.set_panicstate method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

Class

+DbEnv +

See Also

+DbEnv.close, +DbEnv.open, +DbEnv.remove, +DbEnv.strerror, +DbEnv.get_version_string +DbEnv.set_cachesize, +DbEnv.set_errcall, +DbEnv.set_error_stream, +DbEnv.set_errpfx, +DbEnv.set_flags, +DbEnv.set_mutexlocks, +and +DbEnv.set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/env_set_rec_init.html b/db/docs/api_java/env_set_rec_init.html new file mode 100644 index 000000000..430c33a02 --- /dev/null +++ b/db/docs/api_java/env_set_rec_init.html @@ -0,0 +1,78 @@ + + + + + +Berkeley DB: DbEnv.set_recovery_init + + + + + + + +
+

DbEnv.set_recovery_init

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public interface DbRecoveryInit +{ + public abstract int db_recovery_init_fcn(DbEnv dbenv); +} +public class DbEnv +{ + public void set_recovery_init(DbRecoveryInit db_recovery_init_fcn) + throws DbException; + ... +} +

+

Description

+

Applications installing application-specific recovery methods need +to be called before Berkeley DB performs recovery so they may add their recovery +methods to Berkeley DB's. +

The DbEnv.set_recovery_init method supports this functionality. The +db_recovery_init_fcn method must be declared with one +argument, a reference to the enclosing Berkeley DB environment. This +method will be called after the DbEnv.open has been called, +but before recovery is started. +

If the db_recovery_init_fcn method returns a non-zero value, +no recovery will be performed and DbEnv.open will return the same +value to its caller. +

The DbEnv.set_recovery_init interface may only be used to configure Berkeley DB before +the DbEnv.open interface is called. +

The DbEnv.set_recovery_init method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DbEnv.open was called. +

+

Class

+DbEnv +

See Also

+DbEnv.close, +DbEnv.open, +DbEnv.remove, +DbEnv.strerror, +DbEnv.get_version_string +DbEnv.set_cachesize, +DbEnv.set_errcall, +DbEnv.set_error_stream, +DbEnv.set_errpfx, +DbEnv.set_flags, +DbEnv.set_mutexlocks, +and +DbEnv.set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/env_set_region_init.html b/db/docs/api_java/env_set_region_init.html new file mode 100644 index 000000000..f4f5d2562 --- /dev/null +++ b/db/docs/api_java/env_set_region_init.html @@ -0,0 +1,78 @@ + + + + + +Berkeley DB: DbEnv.set_region_init + + + + + + + +
+

DbEnv.set_region_init

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+static int +DbEnv.set_region_init(int region_init); + throws DbException; +

+

Description

+

Page-fault shared regions into memory when initially creating or joining +a Berkeley DB environment. In some applications, the expense of page-faulting +the shared memory regions can affect performance, e.g., when the +page-fault occurs while holding a lock, other lock requests can convoy +and overall throughput may decrease. Setting region_init to a +true value specifies that shared regions be read or written, as +appropriate, when the region is joined by the application. This forces +the underlying virtual memory and file systems to instantiate both the +necessary memory and the necessary disk space. This can also avoid +out-of-disk space failures later on. +

The DbEnv.set_region_init interface affects the entire application, not a single +database or database environment. +

While the DbEnv.set_region_init interface may be used to configure Berkeley DB at any time +during the life of the application, it should normally be called before +making any calls to the db_env_create or db_create methods. +

The DbEnv.set_region_init method throws an exception that encapsulates a non-zero error value on +failure. +

The database environment's initial behavior with respect to shared memory regions may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_region_init", one or more whitespace characters, +and the string "1". Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

Class

+DbEnv +

See Also

+DbEnv.close, +DbEnv.open, +DbEnv.remove, +DbEnv.strerror, +DbEnv.get_version_string +DbEnv.set_cachesize, +DbEnv.set_errcall, +DbEnv.set_error_stream, +DbEnv.set_errpfx, +DbEnv.set_flags, +DbEnv.set_mutexlocks, +and +DbEnv.set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/env_set_server.html b/db/docs/api_java/env_set_server.html new file mode 100644 index 000000000..a0ffeefe3 --- /dev/null +++ b/db/docs/api_java/env_set_server.html @@ -0,0 +1,77 @@ + + + + + +Berkeley DB: DbEnv.set_server + + + + + + + +
+

DbEnv.set_server

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void set_server(String host, + long cl_timeout, long sv_timeout, int flags) + throws DbException; +

+

Description

+

Connects to the DB server on the indicated hostname and sets up a channel +for communication. +

The cl_timeout argument specifies the number of seconds the client +should wait for results to come back from the server. Once the timeout +has expired on any communication with the server, Db.DB_NOSERVER will +be returned. If this value is zero, a default timeout is used. +

The sv_timeout argument specifies the number of seconds the server +should allow a client connection to remain idle before assuming that +client is gone. Once that timeout has been reached, the server releases +all resources associated with that client connection. Subsequent attempts +by that client to communicate with the server result in +Db.DB_NOSERVER_ID indicating that an invalid identifier has been +given to the server. This value can be considered a hint to the server. +The server may alter this value based on its own policies or allowed +values. If this value is zero, a default timeout is used. +

The flags parameter is currently unused, and must be set to 0. +

When the DbEnv.set_server method has been called, any subsequent calls +to Berkeley DB library interfaces may return either DB_NOSERVER or +DB_NOSERVER_ID. +

The DbEnv.set_server method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

dbenv_set_server +

+

Class

+DbEnv +

See Also

+DbEnv.close, +DbEnv.open, +DbEnv.remove, +DbEnv.strerror, +DbEnv.get_version_string +DbEnv.set_cachesize, +DbEnv.set_errcall, +DbEnv.set_error_stream, +DbEnv.set_errpfx, +DbEnv.set_flags, +DbEnv.set_mutexlocks, +and +DbEnv.set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/env_set_shm_key.html b/db/docs/api_java/env_set_shm_key.html new file mode 100644 index 000000000..12a65c922 --- /dev/null +++ b/db/docs/api_java/env_set_shm_key.html @@ -0,0 +1,87 @@ + + + + + +Berkeley DB: DbEnv.set_shm_key + + + + + + + +
+

DbEnv.set_shm_key

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void set_shm_key(long shm_key) + throws DbException; +

+

Description

+

Specify a base segment ID for Berkeley DB environment shared memory regions +created in system memory on VxWorks or systems supporting X/Open-style +shared memory interfaces, e.g., UNIX systems supporting +shmget(2) and related System V IPC interfaces. +

This base segment ID will be used when Berkeley DB shared memory regions are +first created. It will be incremented a small integer value each time +a new shared memory region is created, that is, if the base ID is 35, +the first shared memory region created will have a segment ID of 35 and +the next one a segment ID between 36 and 40 or so. A Berkeley DB environment +always creates a master shared memory region, plus an additional shared +memory region for each of the subsystems supported by the environment +(locking, logging, memory pool and transaction), plus an additional +shared memory region for each additional memory pool cache that is +supported. Already existing regions with the same segment IDs will be +removed. See Shared Memory Regions +for more information. +

The intent behind this interface is two-fold: without it, applications +have no way to ensure that two Berkeley DB applications don't attempt to use +the same segment IDs when creating different Berkeley DB environments. In +addition, by using the same segment IDs each time the environment is +created, previously created segments will be removed, and the set of +segments on the system will not grow without bound. +

The DbEnv.set_shm_key interface may only be used to configure Berkeley DB before +the DbEnv.open interface is called. +

The DbEnv.set_shm_key method throws an exception that encapsulates a non-zero error value on +failure. +

The database environment's base segment ID may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_shm_key", one or more whitespace characters, +and the ID. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DbEnv.open was called. +

+

Class

+DbEnv +

See Also

+DbEnv.close, +DbEnv.open, +DbEnv.remove, +DbEnv.strerror, +DbEnv.get_version_string +DbEnv.set_cachesize, +DbEnv.set_errcall, +DbEnv.set_error_stream, +DbEnv.set_errpfx, +DbEnv.set_flags, +DbEnv.set_mutexlocks, +and +DbEnv.set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/env_set_tas_spins.html b/db/docs/api_java/env_set_tas_spins.html new file mode 100644 index 000000000..64654ebc9 --- /dev/null +++ b/db/docs/api_java/env_set_tas_spins.html @@ -0,0 +1,71 @@ + + + + + +Berkeley DB: DbEnv.set_tas_spins + + + + + + + +
+

DbEnv.set_tas_spins

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+static int +DbEnv.set_tas_spins(u_int32_t tas_spins); + throws DbException; +

+

Description

+

Specify that test-and-set mutexes should spin tas_spins times +without blocking. The value defaults to 1 on uniprocessor systems and +to 50 times the number of processors on multiprocessor systems. +

The DbEnv.set_tas_spins interface affects the entire application, not a single +database or database environment. +

While the DbEnv.set_tas_spins interface may be used to configure Berkeley DB at any time +during the life of the application, it should normally be called before +making any calls to the db_env_create or db_create methods. +

The DbEnv.set_tas_spins method throws an exception that encapsulates a non-zero error value on +failure. +

The database environment's test-and-set spin count may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_tas_spins", one or more whitespace characters, +and the number of spins. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

Class

+DbEnv +

See Also

+DbEnv.close, +DbEnv.open, +DbEnv.remove, +DbEnv.strerror, +DbEnv.get_version_string +DbEnv.set_cachesize, +DbEnv.set_errcall, +DbEnv.set_error_stream, +DbEnv.set_errpfx, +DbEnv.set_flags, +DbEnv.set_mutexlocks, +and +DbEnv.set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/env_set_tmp_dir.html b/db/docs/api_java/env_set_tmp_dir.html new file mode 100644 index 000000000..8c3c4b899 --- /dev/null +++ b/db/docs/api_java/env_set_tmp_dir.html @@ -0,0 +1,89 @@ + + + + + +Berkeley DB: DbEnv.set_tmp_dir + + + + + + + +
+

DbEnv.set_tmp_dir

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void set_tmp_dir(String dir) + throws DbException; +

+

Description

+

The path of a directory to be used as the location of temporary files. +The files created to back in-memory access method databases will be +created relative to this path. These temporary files can be quite large, +depending on the size of the database. +

If no directories are specified, the following alternatives are checked +in the specified order. The first existing directory path is used for +all temporary files. +

    +

  1. The value of the environment variable TMPDIR. +
  2. The value of the environment variable TEMP. +
  3. The value of the environment variable TMP. +
  4. The value of the environment variable TempFolder. +
  5. The value returned by the GetTempPath interface. +
  6. The directory /var/tmp. +
  7. The directory /usr/tmp. +
  8. The directory /temp. +
  9. The directory /tmp. +
  10. The directory C:/temp. +
  11. The directory C:/tmp. +
+

Note: environment variables are only checked if one of the +Db.DB_USE_ENVIRON or Db.DB_USE_ENVIRON_ROOT flags were +specified. +

Note: the GetTempPath interface is only checked on Win/32 platforms. +

The DbEnv.set_tmp_dir interface may only be used to configure Berkeley DB before +the DbEnv.open interface is called. +

The DbEnv.set_tmp_dir method throws an exception that encapsulates a non-zero error value on +failure. +

The database environment's temporary file directory may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_tmp_dir", one or more whitespace characters, +and the directory name. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DbEnv.open was called. +

+

Class

+DbEnv +

See Also

+DbEnv.close, +DbEnv.open, +DbEnv.remove, +DbEnv.strerror, +DbEnv.get_version_string +DbEnv.set_cachesize, +DbEnv.set_errcall, +DbEnv.set_error_stream, +DbEnv.set_errpfx, +DbEnv.set_flags, +DbEnv.set_mutexlocks, +and +DbEnv.set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/env_set_tx_max.html b/db/docs/api_java/env_set_tx_max.html new file mode 100644 index 000000000..d1a57f5c8 --- /dev/null +++ b/db/docs/api_java/env_set_tx_max.html @@ -0,0 +1,69 @@ + + + + + +Berkeley DB: DbEnv.set_tx_max + + + + + + + +
+

DbEnv.set_tx_max

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void set_tx_max(int tx_max) + throws DbException; +

+

Description

+

Set the maximum number of active transactions that are supported by the +environment. This value bounds the size of backing shared memory regions. +Note that child transactions must be counted as active until their +ultimate parent commits or aborts. +

When there are more than the specified number of concurrent transactions, +calls to DbEnv.txn_begin will fail (until some active transactions +complete). If no value is specified, a default value of 20 is used. +

The DbEnv.set_tx_max interface may only be used to configure Berkeley DB before +the DbEnv.open interface is called. +

The DbEnv.set_tx_max method throws an exception that encapsulates a non-zero error value on +failure. +

The database environment's maximum number of active transactions may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_tx_max", one or more whitespace characters, +and the number of transactions. Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DbEnv.open was called. +

+

Classes

+DbEnv, DbTxn +

See Also

+DbEnv.set_tx_max, +DbEnv.set_tx_timestamp, +DbTxn.abort, +DbEnv.txn_begin, +DbEnv.txn_checkpoint, +DbTxn.commit, +DbTxn.id, +DbTxn.prepare +and +DbEnv.txn_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/env_set_tx_recover.html b/db/docs/api_java/env_set_tx_recover.html new file mode 100644 index 000000000..c3c71e9ba --- /dev/null +++ b/db/docs/api_java/env_set_tx_recover.html @@ -0,0 +1,84 @@ + + + + + +Berkeley DB: DbEnv.set_tx_recover + + + + + + + +
+

DbEnv.set_tx_recover

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public interface DbTxnRecover +{ + public abstract int + tx_recover(DbEnv dbenv, Dbt log_rec, DbLsn lsn, int op); +} +public class DbEnv +{ + public void set_tx_recover(DbTxnRecover tx_recover) + throws DbException; + ... +} +

+

Description

+

Set the application's method to be called during transaction abort +and recovery. This method must return 0 on success and either +errno or a value outside of the Berkeley DB error name space on +failure. It takes four arguments: +

+

dbenv
A Berkeley DB environment. +

log_rec
A log record. +

lsn
A log sequence number. +

op
One of the following values: +

+

Db.DB_TXN_BACKWARD_ROLL
The log is being read backward to determine which transactions have been +committed and to abort those operations that were not, undo the operation +described by the log record. +

Db.DB_TXN_FORWARD_ROLL
The log is being played forward, redo the operation described by the log +record. +

Db.DB_TXN_ABORT
The log is being read backwards during a transaction abort, undo the +operation described by the log record. +
+
+

The DbEnv.set_tx_recover interface may only be used to configure Berkeley DB before +the DbEnv.open interface is called. +

The DbEnv.set_tx_recover method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

Called after DbEnv.open was called. +

+

Classes

+DbEnv, DbTxn +

See Also

+DbEnv.set_tx_max, +DbEnv.set_tx_timestamp, +DbTxn.abort, +DbEnv.txn_begin, +DbEnv.txn_checkpoint, +DbTxn.commit, +DbTxn.id, +DbTxn.prepare +and +DbEnv.txn_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/env_set_tx_timestamp.html b/db/docs/api_java/env_set_tx_timestamp.html new file mode 100644 index 000000000..93ae153a7 --- /dev/null +++ b/db/docs/api_java/env_set_tx_timestamp.html @@ -0,0 +1,64 @@ + + + + + +Berkeley DB: DbEnv.set_tx_timestamp + + + + + + + +
+

DbEnv.set_tx_timestamp

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void set_tx_timestamp(java.util.Date timestamp) + throws DbException; +

+

Description

+

Recover to the time specified by timestamp rather than to the most +current possible date. +Note that only the seconds (not the milliseconds) of the timestamp +are used +

Once a database environment has been upgraded to a new version of Berkeley DB +involving a log format change (see Upgrading Berkeley DB installations, it is no longer possible to recover +to a specific time before that upgrade. +

The DbEnv.set_tx_timestamp interface may only be used to configure Berkeley DB before +the DbEnv.open interface is called. +

The DbEnv.set_tx_timestamp method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +

It is not possible to recover to the specified time using the +log files currently present in the environment. +

+

Classes

+DbEnv, DbTxn +

See Also

+DbEnv.set_tx_max, +DbEnv.set_tx_timestamp, +DbTxn.abort, +DbEnv.txn_begin, +DbEnv.txn_checkpoint, +DbTxn.commit, +DbTxn.id, +DbTxn.prepare +and +DbEnv.txn_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/env_set_verbose.html b/db/docs/api_java/env_set_verbose.html new file mode 100644 index 000000000..8fbfb32eb --- /dev/null +++ b/db/docs/api_java/env_set_verbose.html @@ -0,0 +1,77 @@ + + + + + +Berkeley DB: DbEnv.set_verbose + + + + + + + +
+

DbEnv.set_verbose

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public int set_verbose(u_int32_t which, boolean onoff); +

+

Description

+

The DbEnv.set_verbose method turns additional informational and +debugging messages in the Berkeley DB message output on and off. If +onoff is set to +true, +the additional messages are output. +

The which parameter must be set to one of the following values: +

+

Db.DB_VERB_CHKPOINT
Display checkpoint location information when searching the log for +checkpoints. +

Db.DB_VERB_DEADLOCK
Display additional information when doing deadlock detection. +

Db.DB_VERB_RECOVERY
Display additional information when performing recovery. +

Db.DB_VERB_WAITSFOR
Display the waits-for table when doing deadlock detection. +
+

The DbEnv.set_verbose interface may be used to configure Berkeley DB at any time +during the life of the application. +

The DbEnv.set_verbose method throws an exception that encapsulates a non-zero error value on +failure. +

The database environment's verbosity may also be set using the environment's +DB_CONFIG file. The syntax of the entry in that file is a +single line with the string "set_verbose", one or more whitespace characters, +and the interface which argument as a string, for example, +"set_verbose DB_VERB_CHKPOINT". Because the DB_CONFIG file is read when the database +environment is opened, it will silently overrule configuration done +before that time. +

Errors

+

+

EINVAL
An invalid flag value or parameter was specified. +
+

Class

+DbEnv +

See Also

+DbEnv.close, +DbEnv.open, +DbEnv.remove, +DbEnv.strerror, +DbEnv.get_version_string +DbEnv.set_cachesize, +DbEnv.set_errcall, +DbEnv.set_error_stream, +DbEnv.set_errpfx, +DbEnv.set_flags, +DbEnv.set_mutexlocks, +and +DbEnv.set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/env_strerror.html b/db/docs/api_java/env_strerror.html new file mode 100644 index 000000000..e63e82e5f --- /dev/null +++ b/db/docs/api_java/env_strerror.html @@ -0,0 +1,58 @@ + + + + + +Berkeley DB: DbEnv.strerror + + + + + + + +
+

DbEnv.strerror

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public static String strerror(int errcode); +

+

Description

+

The DbEnv.strerror method returns an error message string corresponding +to the error number error. This interface is a superset of the +ANSI C X3.159-1989 (ANSI C) strerror(3) interface. If the error number +error is greater than or equal to 0, then the string returned by +the system interface strerror(3) is returned. If the error +number is less than 0, an error string appropriate to the corresponding +Berkeley DB library error is returned. See +Error returns to applications +for more information. +

Class

+DbEnv +

See Also

+DbEnv.close, +DbEnv.open, +DbEnv.remove, +DbEnv.strerror, +DbEnv.get_version_string +DbEnv.set_cachesize, +DbEnv.set_errcall, +DbEnv.set_error_stream, +DbEnv.set_errpfx, +DbEnv.set_flags, +DbEnv.set_mutexlocks, +and +DbEnv.set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/env_version.html b/db/docs/api_java/env_version.html new file mode 100644 index 000000000..ba0b1a034 --- /dev/null +++ b/db/docs/api_java/env_version.html @@ -0,0 +1,58 @@ + + + + + +Berkeley DB: DbEnv.get_version_major + + + + + + + +
+

DbEnv.get_version_major

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public static int get_version_major(); +public static int get_version_minor(); +public static int get_version_patch(); +public static String get_version_string(); +

+

Description

+

These methods return version information about the underlying Berkeley DB +software. Berkeley DB is released with a major, minor and patch number, which +is returned by DbEnv.get_version_major, +DbEnv.get_version_minor and DbEnv.get_version_patch. +A verbose version of this information, suitable for display, is returned +by DbEnv.get_version_string. +

Class

+DbEnv +

See Also

+DbEnv.close, +DbEnv.open, +DbEnv.remove, +DbEnv.strerror, +DbEnv.get_version_string +DbEnv.set_cachesize, +DbEnv.set_errcall, +DbEnv.set_error_stream, +DbEnv.set_errpfx, +DbEnv.set_flags, +DbEnv.set_mutexlocks, +and +DbEnv.set_verbose. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/except_class.html b/db/docs/api_java/except_class.html new file mode 100644 index 000000000..885d161d5 --- /dev/null +++ b/db/docs/api_java/except_class.html @@ -0,0 +1,52 @@ + + + + + +Berkeley DB: DbException + + + + + + + +
+

DbException

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public class DbException extends Exception { ... } +

+

Description

+

This manual page describes the DbException class and how it is used +by the various Berkeley DB classes. +

Most methods in the Berkeley DB classes throw an exception when an error occurs. +A DbException object contains an informational string and an errno. The +errno can be obtained using DbException.get_errno. Since DbException +inherits from the java.Exception, the string portion is available using +toString(). +

Some methods may return non-zero values without issuing an exception. +This occurs in situations that are not normally considered an error, but +when some informational status is returned. For example, Db.get +returns DB_NOTFOUND when a requested key does not appear in the database. +

Class

+DbException +

See Also

+DbException.get_errno, +DbDeadlockException, +DbMemoryException +and +DbRunRecoveryException. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/get_errno.html b/db/docs/api_java/get_errno.html new file mode 100644 index 000000000..5d3850d1f --- /dev/null +++ b/db/docs/api_java/get_errno.html @@ -0,0 +1,46 @@ + + + + + +Berkeley DB: DbException.get_errno + + + + + + + +
+

DbException.get_errno

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public int get_errno(); +

+

Description

+

Most methods in the Db classes throw an exception when an error occurs. +A DbException object contains an informational string and an errno. +The errno can be obtained using DbException.get_errno. +Since DbException inherits from the java.Exception, the string +portion is available using toString(). +

Class

+DbException +

See Also

+DbException.get_errno, +DbDeadlockException, +DbMemoryException +and +DbRunRecoveryException. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/java_index.html b/db/docs/api_java/java_index.html new file mode 100644 index 000000000..c36227ede --- /dev/null +++ b/db/docs/api_java/java_index.html @@ -0,0 +1,131 @@ + + + + + +Berkeley DB: Java Interface by Class + + + + +

Java Interface by Class

+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ClassMethodDescription
DbEnv
Berkeley DB Environment Class

DbEnv.closeClose an environment

DbEnv.openOpen an environment

DbEnv.removeRemove an environment

DbEnv.set_cachesizeSet the environment cache size

DbEnv.set_data_dirSet the environment data directory

DbEnv.set_errcallSet error message callback

DbEnv.set_error_streamSet error message output stream

DbEnv.set_errpfxSet error message prefix

DbEnv.set_feedbackSet feedback callback

DbEnv.set_flagsEnvironment configuration

DbEnv.set_lg_bsizeSet log buffer size

DbEnv.set_lg_dirSet the environment logging directory

DbEnv.set_lg_maxSet log file size

DbEnv.set_lk_conflictsSet lock conflicts matrix

DbEnv.set_lk_detectSet automatic deadlock detection

DbEnv.set_lk_maxSet maximum number of locks (Deprecated)

DbEnv.set_lk_max_locksSet maximum number of locks

DbEnv.set_lk_max_lockersSet maximum number of lockers

DbEnv.set_lk_max_objectsSet maximum number of lock objects

DbEnv.set_mp_mmapsizeSet maximum mapped-in database file size

DbEnv.set_mutexlocksTurn off mutual exclusion locking

DbEnv.set_pageyieldYield the processor on each page access

DbEnv.set_panicstateReset panic state

DbEnv.set_recovery_initSet recovery initialization callback

DbEnv.set_region_initFault in shared regions on initial access

DbEnv.set_serverEstablish server connection

DbEnv.set_shm_keySet system memory shared segment ID

DbEnv.set_tas_spinsSet the number of test-and-set spins

DbEnv.set_tmp_dirSet the environment temporary file directory

DbEnv.set_tx_maxSet maximum number of transactions

DbEnv.set_tx_recoverSet transaction abort recover function

DbEnv.set_tx_timestampSet recovery timestamp

DbEnv.set_verboseSet verbose messages

DbEnv.strerrorError strings

DbEnv.lock_detectPerform deadlock detection

DbEnv.lock_getAcquire a lock

DbEnv.lock_idAcquire a locker ID

DbEnv.lock_statReturn lock subsystem statistics

DbEnv.log_archiveList log and database files

DbEnv.log_compareCompare two Log Sequence Numbers

DbEnv.log_fileMap Log Sequence Numbers to log files

DbEnv.log_flushFlush log records

DbEnv.log_getGet a log record

DbEnv.log_putWrite a log record

DbEnv.log_registerRegister a file name with the log manager

DbEnv.log_statReturn log subsystem statistics

DbEnv.log_unregisterUnregister a file name with the log manager

DbEnv.memp_fstatReturn buffer pool statistics.

DbEnv.memp_statReturn buffer pool statistics

DbEnv.memp_trickleTrickle flush pages from a buffer pool

DbEnv.txn_beginBegin a transaction

DbEnv.txn_checkpointCheckpoint the transaction subsystem

DbEnv.txn_statReturn transaction subsystem statistics

DbEnv.versionReturn version information
Db
Berkeley DB Access Method Class

Db.closeClose a database

Db.cursorOpen a cursor into a database

Db.delDelete items from a database

Db.fdReturn a file descriptor from a database

Db.getGet items from a database

Db.get_byteswappedReturn if the underlying database is in host order

Db.get_typeReturn the database type

Db.joinPerform a database join on cursors

Db.key_rangeReturn estimate of key location

Db.openOpen a database

Db.putStore items into a database

Db.removeRemove a database

Db.renameRename a database

Db.set_append_recnoSet record append callback

Db.set_bt_compareSet a Btree comparison function

Db.set_bt_minkeySet the minimum number of keys per Btree page

Db.set_bt_prefixSet a Btree prefix comparison function

Db.set_cachesizeSet the database cache size

Db.set_dup_compareSet a duplicate comparison function

Db.set_errcallSet error message callback

Db.set_errpfxSet error message prefix

Db.set_feedbackSet feedback callback

Db.set_flagsGeneral database configuration

Db.set_h_ffactorSet the Hash table density

Db.set_h_hashSet a hashing function

Db.set_h_nelemSet the Hash table size

Db.set_lorderSet the database byte order

Db.set_pagesizeSet the underlying database page size

Db.set_q_extentsizeSet Queue database extent size

Db.set_re_delimSet the variable-length record delimiter

Db.set_re_lenSet the fixed-length record length

Db.set_re_padSet the fixed-length record pad byte

Db.set_re_sourceSet the backing Recno text file

Db.statReturn database statistics

Db.syncFlush a database to stable storage

Db.upgradeUpgrade a database

Db.verifyVerify/upgrade a database
Dbc
Berkeley DB Cursor Class

Dbc.closeClose a cursor

Dbc.countReturn count of duplicates

Dbc.delDelete by cursor

Dbc.dupDuplicate a cursor

Dbc.getRetrieve by cursor

Dbc.putStore by cursor
Dbt
Key/Data Encoding Class
DbLock
Lock Class

DbLock.putRelease a lock
DbLsn
Log Sequence Number Class
DbTxn
Transaction Class

DbTxn.abortAbort a transaction

DbTxn.commitCommit a transaction

DbTxn.idReturn a transaction ID

DbTxn.preparePrepare a transaction for commit
DbException
Exception Class for Berkeley DB Activity

DbException.get_errnoGet the error value
DbDeadlockException
Exception Class for deadlocks
DbMemoryException
Exception Class for insufficient memory
DbRunRecoveryException
Exception Class for failures requiring recovery
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/java_pindex.html b/db/docs/api_java/java_pindex.html new file mode 100644 index 000000000..5ac50e479 --- /dev/null +++ b/db/docs/api_java/java_pindex.html @@ -0,0 +1,478 @@ + + +Berkeley DB: Java Interface Index + + + + +

Java Interface Index

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
configuring Berkeley DB 1.85 API compatibility
building a utility to dump Berkeley DB 1.85 databases
Upgrading to release 2.0
Upgrading to release 3.0
Upgrading to release 3.1
Upgrading to release 3.2
selecting an access method
access methods
AIX
programmatic APIs
utility to archive log files
berkeley_db_svc
building for UNIX
building for UNIX FAQ
building for VxWorks
building for VxWorks FAQ
building for Win32
building for Windows FAQ
selecting a byte order
byte ordering
configuring the C++ API
flushing the database cache
selecting a cache size
catastrophic recovery
Patches, Updates and Change logs
utility to take checkpoints
closing a cursor
closing a database
specifying a Btree comparison function
changing compile or load options
Concurrent Data Store
configuring Berkeley DB for UNIX systems
recovering corrupted databases
counting data items for a key
closing a cursor
deleting records with a cursor
duplicating a cursor
retrieving records with a cursor
storing records with a cursor
cursor stability
database cursors
Dbtdata
utility to upgrade database files
utility to verify database files
Db
db_archive
Dbc
Dbc.close
Dbc.count
Dbc.del
Dbc.dup
Dbc.get
db_checkpoint
Db.close
File namingDB_CONFIG
Dbc.put
Db.cursor
Dbc.putDb.DB_AFTER
Db.verifyDb.DB_AGGRESSIVE
Db.putDb.DB_APPEND
DbEnv.log_archiveDb.DB_ARCH_ABS
DbEnv.log_archiveDb.DB_ARCH_DATA
DbEnv.log_archiveDb.DB_ARCH_LOG
Dbc.putDb.DB_BEFORE
Db.statDb.DB_CACHED_COUNTS
DbEnv.set_flagsDb.DB_CDB_ALLDB
DbEnv.log_getDb.DB_CHECKPOINT
DbEnv.log_putDb.DB_CHECKPOINT
DbEnvDb.DB_CLIENT
Db.getDb.DB_CONSUME
Db.getDb.DB_CONSUME_WAIT
Db.openDb.DB_CREATE
DbEnv.openDb.DB_CREATE
DbEnv.log_putDb.DB_CURLSN
Dbc.getDb.DB_CURRENT
Dbc.putDb.DB_CURRENT
DbEnv.log_getDb.DB_CURRENT
DbtDb.DB_DBT_MALLOC
DbtDb.DB_DBT_PARTIAL
DbtDb.DB_DBT_REALLOC
DbtDb.DB_DBT_USERMEM
Db.set_flagsDb.DB_DUP
Db.set_flagsDb.DB_DUPSORT
Db.upgradeDb.DB_DUPSORT
Db.openDb.DB_EXCL
Dbc.getDb.DB_FIRST
DbEnv.log_getDb.DB_FIRST
DbEnv.log_putDb.DB_FLUSH
DbEnv.removeDb.DB_FORCE
DbEnv.txn_checkpointDb.DB_FORCE
Db.getDb.DB_GET_BOTH
Dbc.getDb.DB_GET_BOTH
Dbc.getDb.DB_GET_RECNO
DbEnv.openDb.DB_INIT_CDB
DbEnv.openDb.DB_INIT_LOCK
DbEnv.openDb.DB_INIT_LOG
DbEnv.openDb.DB_INIT_MPOOL
DbEnv.openDb.DB_INIT_TXN
DbEnv.openDb.DB_JOINENV
Db.joinDb.DB_JOIN_ITEM
Dbc.getDb.DB_JOIN_ITEM
Db.joinDb.DB_JOIN_NOSORT
Dbc.putDb.DB_KEYFIRST
Dbc.putDb.DB_KEYLAST
Dbc.getDb.DB_LAST
DbEnv.log_getDb.DB_LAST
DbEnv.lock_detectDb.DB_LOCK_CONFLICT
DbEnv.openDb.DB_LOCKDOWN
DbEnv.lock_getDb.DB_LOCK_NOTGRANTED
DbEnv.lock_getDb.DB_LOCK_NOWAIT
Dbc.getDb.DB_NEXT
DbEnv.log_getDb.DB_NEXT
Dbc.getDb.DB_NEXT_DUP
Dbc.getDb.DB_NEXT_NODUP
Db.putDb.DB_NODUPDATA
Dbc.putDb.DB_NODUPDATA
Db.openDb.DB_NOMMAP
DbEnv.set_flagsDb.DB_NOMMAP
Db.verifyDb.DB_NOORDERCHK
Db.putDb.DB_NOOVERWRITE
Db.closeDb.DB_NOSYNC
Db.openDb.DB_OLD_VERSION
Db.upgradeDb.DB_OLD_VERSION
Db.verifyDb.DB_ORDERCHKONLY
Dbc.dupDb.DB_POSITION
Dbc.getDb.DB_PREV
DbEnv.log_getDb.DB_PREV
Dbc.getDb.DB_PREV_NODUP
DbEnv.openDb.DB_PRIVATE
Db.openDb.DB_RDONLY
Db.set_flagsDb.DB_RECNUM
Db.statDb.DB_RECORDCOUNT
DbEnv.openDb.DB_RECOVER
DbEnv.set_feedbackDb.DB_RECOVER
DbEnv.openDb.DB_RECOVER_FATAL
Db.set_flagsDb.DB_RENUMBER
Db.set_flagsDb.DB_REVSPLITOFF
Db.getDb.DB_RMW
Db.joinDb.DB_RMW
Dbc.getDb.DB_RMW
Db.verifyDb.DB_SALVAGE
Dbc.getDb.DB_SET
DbEnv.log_getDb.DB_SET
Dbc.getDb.DB_SET_RANGE
Db.getDb.DB_SET_RECNO
Dbc.getDb.DB_SET_RECNO
Db.set_flagsDb.DB_SNAPSHOT
DbEnv.openDb.DB_SYSTEM_MEM
Db.openDb.DB_THREAD
DbEnv.openDb.DB_THREAD
Db.openDb.DB_TRUNCATE
DbEnv.set_tx_recoverDb.DB_TXN_ABORT
DbEnv.set_tx_recoverDb.DB_TXN_BACKWARD_ROLL
DbEnv.set_tx_recoverDb.DB_TXN_FORWARD_ROLL
DbEnv.set_flagsDb.DB_TXN_NOSYNC
DbEnv.txn_beginDb.DB_TXN_NOSYNC
DbTxn.commitDb.DB_TXN_NOSYNC
DbEnv.txn_beginDb.DB_TXN_NOWAIT
DbEnv.txn_beginDb.DB_TXN_SYNC
DbTxn.commitDb.DB_TXN_SYNC
Db.set_feedbackDb.DB_UPGRADE
DbEnv.openDb.DB_USE_ENVIRON
DbEnv.removeDb.DB_USE_ENVIRON
DbEnv.openDb.DB_USE_ENVIRON_ROOT
DbEnv.removeDb.DB_USE_ENVIRON_ROOT
DbEnv.set_verboseDb.DB_VERB_CHKPOINT
DbEnv.set_verboseDb.DB_VERB_DEADLOCK
DbEnv.set_verboseDb.DB_VERB_RECOVERY
DbEnv.set_verboseDb.DB_VERB_WAITSFOR
Db.set_feedbackDb.DB_VERIFY
Db.cursorDb.DB_WRITECURSOR
DbDb.DB_XA_CREATE
db_deadlock
DbDeadlockException
Db.del
db_dump
DbEnv
DbEnv.close
DbEnv.get_version_major
DbEnv.lock_detect
DbEnv.lock_get
DbEnv.lock_id
DbEnv.lock_stat
DbEnv.lock_vec
DbEnv.log_archive
DbEnv.log_compare
DbEnv.log_file
DbEnv.log_flush
DbEnv.log_get
DbEnv.log_put
DbEnv.log_register
DbEnv.log_stat
DbEnv.log_unregister
DbEnv.memp_register
DbEnv.memp_stat
DbEnv.memp_sync
DbEnv.memp_trickle
DbEnv.open
DbEnv.remove
DbEnv.set_cachesize
DbEnv.set_data_dir
DbEnv.set_errcall
DbEnv.set_error_stream
DbEnv.set_errpfx
DbEnv.set_feedback
DbEnv.set_flags
DbEnv.set_lg_bsize
DbEnv.set_lg_dir
DbEnv.set_lg_max
DbEnv.set_lk_conflicts
DbEnv.set_lk_detect
DbEnv.set_lk_max
DbEnv.set_lk_max_lockers
DbEnv.set_lk_max_locks
DbEnv.set_lk_max_objects
DbEnv.set_mp_mmapsize
DbEnv.set_mutexlocks
DbEnv.set_pageyield
DbEnv.set_panicstate
DbEnv.set_recovery_init
DbEnv.set_region_init
DbEnv.set_server
DbEnv.set_shm_key
DbEnv.set_tas_spins
DbEnv.set_tmp_dir
DbEnv.set_tx_max
DbEnv.set_tx_recover
DbEnv.set_tx_timestamp
DbEnv.set_verbose
DbEnv.strerror
DbEnv.txn_begin
DbEnv.txn_checkpoint
DbEnv.txn_stat
DbException
DbException.get_errno
Db.fd
Db.get
Db.get_byteswapped
Db.get_type
File namingDB_HOME
File namingdb_home
Db.close DB_INCOMPLETE
Db.join
Error returns to applicationsDB_KEYEMPTY
Db.key_range
db_load
DbLock
Error returns to applicationsDB_LOCK_DEADLOCK
DbEnv.set_lk_detectDB_LOCK_DEFAULT
Error returns to applicationsDB_LOCK_NOTGRANTED
DbEnv.set_lk_detectDB_LOCK_OLDEST
DbLock.put
DbEnv.set_lk_detectDB_LOCK_RANDOM
DbEnv.set_lk_detectDB_LOCK_YOUNGEST
DbLsn
DbMemoryException
DbMpoolFile.close
DbMpoolFile.get
DbMpoolFile.open
DbMpoolFile.put
DbMpoolFile.set
DbMpoolFile.sync
DbEnv.set_serverDB_NOSERVER
DbEnv.set_serverDB_NOSERVER_ID
Error returns to applicationsDB_NOTFOUND
Db.open
db_printlog
Db.put
db_recover
Db.remove
Db.rename
Error returns to applicationsDB_RUNRECOVERY
DbRunRecoveryException
Db.set_append_recno
Db.set_bt_compare
Db.set_bt_minkey
Db.set_bt_prefix
Db.set_cachesize
Db.set_dup_compare
Db.set_errcall
Db.set_errpfx
Db.set_feedback
Db.set_flags
Db.set_h_ffactor
Db.set_h_hash
Db.set_h_nelem
Db.set_lorder
Db.set_pagesize
Db.set_q_extentsize
Db.set_re_delim
Db.set_re_len
Db.set_re_pad
Db.set_re_source
Db.stat
db_stat
Db.sync
Dbt
DbTxn
DbTxn.abort
DbTxn.commit
DbTxn.id
DbTxn.prepare
Db.upgrade
db_upgrade
Db.verify
db_verify
deadlocks
utility to detect deadlocks
debugging applications
deleting records
deleting records with a cursor
Configuring Berkeley DB--disable-bigfile
disk space requirements
utility to dump databases as text files
duplicate data items
duplicating a cursor
configuring dynamic shared libraries
Configuring Berkeley DB--enable-compat185
Configuring Berkeley DB--enable-cxx
Configuring Berkeley DB--enable-debug
Configuring Berkeley DB--enable-debug_rop
Configuring Berkeley DB--enable-debug_wop
Configuring Berkeley DB--enable-diagnostic
Configuring Berkeley DB--enable-dump185
Configuring Berkeley DB--enable-dynamic
Configuring Berkeley DB--enable-java
Configuring Berkeley DB--enable-posixmutexes
Configuring Berkeley DB--enable-rpc
Configuring Berkeley DB--enable-shared
Configuring Berkeley DB--enable-tcl
Configuring Berkeley DB--enable-test
Configuring Berkeley DB--enable-uimutexes
Configuring Berkeley DB--enable-umrw
byte endian
database environment
environment variables
error handling
error name space
error returns
/etc/magic
selecting a Queue extent size
Java FAQ
Tcl FAQ
configuring without large file support
file utility
recovery and filesystem operations
remote filesystems
page fill factor
FreeBSD
Berkeley DB free-threaded handles
specifying a database hash
hash table size
HP-UX
installing Berkeley DB for UNIX systems
interface compatibility
IRIX
configuring the Java API
Java compatibility
Java configuration
Java FAQ
logical join
key/data pairs
database limits
Linux
changing compile or load options
utility to load text files into databases
standard lock modes
page-level locking
two-phase locking
locking and non-Berkeley DB applications
locking configuration
locking conventions
Berkeley DB Concurrent Data Store locking conventions
locking introduction
sizing the locking subsystem
locking without transactions
log file limits
log file removal
utility to display log files as text
logging configuration
logging introduction
memory pool configuration
Berkeley DB library name spaces
file naming
retrieving Btree records by number
opening a database
OSF/1
selecting a page size
partial record storage and retrieval
Patches, Updates and Change logs
Perl
Sleepycat Software's Berkeley DB products
QNX
logical record number format
logical record numbers
managing record-based databases
logically renumbering records
utility to recover database environments
Berkeley DB recoverability
retrieving records
retrieving records with a cursor
RPC client
configuring a RPC client/server
utility to support RPC client/server
RPC server
database salvage
SCO
Berkeley DB handle scope
security
Sendmail
configuring shared libraries
shared libraries
application signal handling
Sleepycat Software
Solaris
source code layout
cursor stability
database statistics
utility to display database and environment statistics
storing records
storing records with a cursor
SunOS
loading Berkeley DB with Tcl
using Berkeley DB with Tcl
configuring the Tcl API
Tcl API programming notes
Tcl FAQ
configuring the test suite
running the test suite
running the test suite under UNIX
running the test suite under Windows
text backing files
loading text into databases
dumping/loading text to/from databases
building threaded applications
transaction configuration
transaction limits
administering transaction protected applications
archival in transaction protected applications
checkpoints in transaction protected applications
deadlock detection in transaction protected applications
recovery in transaction protected applications
transaction throughput
Transactional Data Store
Berkeley DB and transactions
nested transactions
configuring Berkeley DB with the Tuxedo System
Ultrix
building for UNIX FAQ
configuring Berkeley DB for UNIX systems
Patches, Updates and Change logs
utility to upgrade database files
upgrading databases
utilities
database verification
utility to verify database files
building for VxWorks FAQ
VxWorks notes
running the test suite under Windows
building for Windows FAQ
Windows notes
Configuring Berkeley DB--with-tcl=DIR
XA Resource Manager
+
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/lock_class.html b/db/docs/api_java/lock_class.html new file mode 100644 index 000000000..6705e95bd --- /dev/null +++ b/db/docs/api_java/lock_class.html @@ -0,0 +1,54 @@ + + + + + +Berkeley DB: DbLock + + + + + + + +
+

DbLock

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public class DbLock extends Object { ... } +

+

Description

+

The DbEnv lock methods and the DbLock class are used +to provide general-purpose locking. While designed to work with the +other Db classes, they are also useful for more general locking +purposes. Locks can be shared between processes. +

In most cases, when multiple threads or processes are using locking, the +deadlock detector, db_deadlock should be run. +

Classes

+DbEnv, DbLock +

See Also

+DbEnv.set_lk_conflicts, +DbEnv.set_lk_detect, +DbEnv.set_lk_max_locks, +DbEnv.set_lk_max_lockers, +DbEnv.set_lk_max_objects, +DbEnv.set_lk_max, +DbEnv.lock_detect, +DbEnv.lock_get, +DbEnv.lock_id, +DbLock.put +and +DbEnv.lock_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/lock_detect.html b/db/docs/api_java/lock_detect.html new file mode 100644 index 000000000..6f453ddb8 --- /dev/null +++ b/db/docs/api_java/lock_detect.html @@ -0,0 +1,69 @@ + + + + + +Berkeley DB: DbEnv.lock_detect + + + + + + + +
+

DbEnv.lock_detect

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public int lock_detect(int flags, int atype) + throws DbException; +

+

Description

+

The DbEnv.lock_detect method runs one iteration of the deadlock detector. +The deadlock detector traverses the lock table, and for each deadlock +it finds, marks one of the participating transactions for abort. +

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +

+

Db.DB_LOCK_CONFLICT
Only run the deadlock detector if a lock conflict has occurred since +the last time that the deadlock detector was run. +
+

The atype parameter specifies which transaction to abort in the +case of deadlock. It must be set to one of possible arguments listed for +the DbEnv.set_lk_detect interface. +

The DbEnv.lock_detect method returns the number of transactions aborted. +

The DbEnv.lock_detect method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

The DbEnv.lock_detect method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv.lock_detect method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Classes

+DbEnv, DbLock +

See Also

+DbEnv.set_lk_conflicts, +DbEnv.set_lk_detect, +DbEnv.set_lk_max_locks, +DbEnv.set_lk_max_lockers, +DbEnv.set_lk_max_objects, +DbEnv.set_lk_max, +DbEnv.lock_detect, +DbEnv.lock_get, +DbEnv.lock_id, +DbLock.put +and +DbEnv.lock_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/lock_get.html b/db/docs/api_java/lock_get.html new file mode 100644 index 000000000..42604bc46 --- /dev/null +++ b/db/docs/api_java/lock_get.html @@ -0,0 +1,92 @@ + + + + + +Berkeley DB: DbEnv.lock_get + + + + + + + +
+

DbEnv.lock_get

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public DbLock lock_get(int locker, + int flags, Dbt obj, int lock_mode) + throws DbException; +

+

Description

+

The DbEnv.lock_get method acquires a lock from the lock table, returning +information about it in +a DbLock object. +

The locker argument specified to DbEnv.lock_get is an unsigned +32-bit integer quantity. It represents the entity requesting or releasing +the lock. +

The flags value must be set to 0 or the following value: +

+

Db.DB_LOCK_NOWAIT
If a lock cannot be granted because the requested lock conflicts with an +existing lock, return immediately instead of waiting for the lock to +become available. +
+

The obj argument is an untyped byte string that specifies the +object to be locked or released. +

The mode argument is an index into the environment's lock conflict +array. See DbEnv.set_lk_conflicts and +Standard Lock Modes +for a description of that array. +

The DbEnv.lock_get method may +throw an exception encapsulating +one of the following values: +

+

Db.DB_LOCK_NOTGRANTED
A lock was requested that could not be immediately granted and the +flags parameter was set to DB_LOCK_NOWAIT. +
+

Otherwise, the DbEnv.lock_get method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

The DbEnv.lock_get method may fail and throw an exception encapsulating a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +
+

+

ENOMEM
The maximum number of locks has been reached. +
+

If the operation was selected to resolve a deadlock, the +DbEnv.lock_get method will fail and +throw a DbDeadlockException exception. +

The DbEnv.lock_get method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv.lock_get method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Classes

+DbEnv, DbLock +

See Also

+DbEnv.set_lk_conflicts, +DbEnv.set_lk_detect, +DbEnv.set_lk_max_locks, +DbEnv.set_lk_max_lockers, +DbEnv.set_lk_max_objects, +DbEnv.set_lk_max, +DbEnv.lock_detect, +DbEnv.lock_get, +DbEnv.lock_id, +DbLock.put +and +DbEnv.lock_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/lock_id.html b/db/docs/api_java/lock_id.html new file mode 100644 index 000000000..2fa59317f --- /dev/null +++ b/db/docs/api_java/lock_id.html @@ -0,0 +1,59 @@ + + + + + +Berkeley DB: DbEnv.lock_id + + + + + + + +
+

DbEnv.lock_id

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public int lock_id() + throws DbException; +

+

Description

+

The DbEnv.lock_id method +returns a locker ID, which is guaranteed to be unique in the specified lock +table. +

The DbEnv.lock_id method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

The DbEnv.lock_id method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv.lock_id method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Classes

+DbEnv, DbLock +

See Also

+DbEnv.set_lk_conflicts, +DbEnv.set_lk_detect, +DbEnv.set_lk_max_locks, +DbEnv.set_lk_max_lockers, +DbEnv.set_lk_max_objects, +DbEnv.set_lk_max, +DbEnv.lock_detect, +DbEnv.lock_get, +DbEnv.lock_id, +DbLock.put +and +DbEnv.lock_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/lock_put.html b/db/docs/api_java/lock_put.html new file mode 100644 index 000000000..fe4eacc28 --- /dev/null +++ b/db/docs/api_java/lock_put.html @@ -0,0 +1,61 @@ + + + + + +Berkeley DB: DbLock.put + + + + + + + +
+

DbLock.put

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public native void put(DbEnv env) + throws DbException; +

+

Description

+

The DbLock.put method releases lock from the lock table. +

The DbLock.put method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

The DbLock.put method may fail and throw an exception encapsulating a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +
+

The DbLock.put method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbLock.put method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Classes

+DbEnv, DbLock +

See Also

+DbEnv.set_lk_conflicts, +DbEnv.set_lk_detect, +DbEnv.set_lk_max_locks, +DbEnv.set_lk_max_lockers, +DbEnv.set_lk_max_objects, +DbEnv.set_lk_max, +DbEnv.lock_detect, +DbEnv.lock_get, +DbEnv.lock_id, +DbLock.put +and +DbEnv.lock_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/lock_stat.html b/db/docs/api_java/lock_stat.html new file mode 100644 index 000000000..00c3703f5 --- /dev/null +++ b/db/docs/api_java/lock_stat.html @@ -0,0 +1,94 @@ + + + + + +Berkeley DB: DbEnv.lock_stat + + + + + + + +
+

DbEnv.lock_stat

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public DbLockStat lock_stat() + throws DbException; +

+

Description

+

The DbEnv.lock_stat method +creates a DbLockStat object encapsulating a statistical structure. +The lock region statistics are stored in a DbLockStat object. +The following data fields are available from the DbLockStat object: +

Statistical structures are created in allocated memory. If db_malloc is non-NULL, it +is called to allocate the memory, otherwise, the library function +malloc(3) is used. The function db_malloc must match +the calling conventions of the malloc(3) library routine. +Regardless, the caller is responsible for deallocating the returned +memory. To deallocate returned memory, free the returned memory +reference, references inside the returned memory do not need to be +individually freed. +

The lock region statistics are stored in a structure of type +DB_LOCK_STAT. The following DB_LOCK_STAT fields will be filled in: +

+
public int st_lastid;
The last allocated lock ID. +
public int st_nmodes;
The number of lock modes. +
public int st_maxlocks;
The maximum number of locks possible. +
public int st_maxlockers;
The maximum number of lockers possible. +
public int st_maxobjects;
The maximum number of objects possible. +
public int st_nlocks;
The number of current locks. +
public int st_maxnlocks;
The maximum number of locks at any one time. +
public int st_nlockers;
The number of current lockers. +
public int st_maxnlockers;
The maximum number of lockers at any one time. +
public int st_nobjects;
The number of current objects. +
public int st_maxnobjects;
The maximum number of objects at any one time. +
public int st_nrequests;
The total number of locks requested. +
public int st_nreleases;
The total number of locks released. +
public int st_nnowaits;
The total number of lock requests that failed because +Db.DB_LOCK_NOWAIT was set. +
public int st_nconflicts;
The total number of locks not immediately available due to conflicts. +
public int st_ndeadlocks;
The number of deadlocks detected. +
public int st_regsize;
The size of the region. +
public int st_region_wait;
The number of times that a thread of control was forced to wait before +obtaining the region lock. +
public int st_region_nowait;
The number of times that a thread of control was able to obtain +the region lock without waiting. +
+

The DbEnv.lock_stat method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

The DbEnv.lock_stat method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv.lock_stat method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Classes

+DbEnv, DbLock +

See Also

+DbEnv.set_lk_conflicts, +DbEnv.set_lk_detect, +DbEnv.set_lk_max_locks, +DbEnv.set_lk_max_lockers, +DbEnv.set_lk_max_objects, +DbEnv.set_lk_max, +DbEnv.lock_detect, +DbEnv.lock_get, +DbEnv.lock_id, +DbLock.put +and +DbEnv.lock_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/lock_vec.html b/db/docs/api_java/lock_vec.html new file mode 100644 index 000000000..233e036a3 --- /dev/null +++ b/db/docs/api_java/lock_vec.html @@ -0,0 +1,33 @@ + + + + + +Berkeley DB: DbEnv.lock_vec + + + + + + + +
+

DbEnv.lock_vec

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+

Description

+

A DbEnv.lock_vec method is not available in the Berkeley DB +Java API. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/log_archive.html b/db/docs/api_java/log_archive.html new file mode 100644 index 000000000..a84228658 --- /dev/null +++ b/db/docs/api_java/log_archive.html @@ -0,0 +1,92 @@ + + + + + +Berkeley DB: DbEnv.log_archive + + + + + + + +
+

DbEnv.log_archive

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public String[] log_archive(int flags) + throws DbException; +

+

Description

+

The DbEnv.log_archive method +returns an array of log or database file names. +

By default, DbEnv.log_archive returns the names of all of the log files +that are no longer in use (e.g., no longer involved in active transactions), +and that may safely be archived for catastrophic recovery and then removed +from the system. If there were no file names to return, the memory location +referenced by listp will be set to null. +

The flags value must be set to 0 or by bitwise inclusively OR'ing together one or more +of the following values. +

+

Db.DB_ARCH_ABS
All pathnames are returned as absolute pathnames, +instead of relative to the database home directory. +

Db.DB_ARCH_DATA
Return the database files that need to be archived in order to recover +the database from catastrophic failure. If any of the database files +have not been accessed during the lifetime of the current log files, +DbEnv.log_archive will not include them in this list. It is also +possible that some of the files referenced in the log have since been +deleted from the system. +

Db.DB_ARCH_LOG
Return all the log file names regardless of whether or not they are in +use. +
+

The Db.DB_ARCH_DATA and Db.DB_ARCH_LOG flags are mutually +exclusive. +

See the db_archive manual page for more information on database +archival procedures. +

The DbEnv.log_archive method throws an exception that encapsulates a non-zero error value on +failure. +

Bugs

+

In a threaded application (i.e., one where the environment was created +with the DB_THREAD flag specified), calling DbEnv.log_archive with the +DB_ARCH_DATA flag will fail, returning EINVAL. To work around this +problem, re-open the log explicitly without specifying DB_THREAD. This +restriction is expected to be removed in a future version of Berkeley DB. +

Errors

+

The DbEnv.log_archive method may fail and throw an exception encapsulating a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +

The log was corrupted. +

+

The DbEnv.log_archive method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv.log_archive method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Class

+DbEnv +

See Also

+DbEnv.set_lg_bsize, +DbEnv.set_lg_max, +DbEnv.log_archive, +DbEnv.log_compare, +DbEnv.log_file, +DbEnv.log_flush, +DbEnv.log_get, +DbEnv.log_put, +DbEnv.log_register, +DbEnv.log_stat +and +DbEnv.log_unregister. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/log_compare.html b/db/docs/api_java/log_compare.html new file mode 100644 index 000000000..aba583203 --- /dev/null +++ b/db/docs/api_java/log_compare.html @@ -0,0 +1,52 @@ + + + + + +Berkeley DB: DbEnv.log_compare + + + + + + + +
+

DbEnv.log_compare

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public static int log_compare(DbLsn lsn0, DbLsn lsn1); +

+

Description

+

The DbEnv.log_compare method allows the caller to compare two +DbLsn objects, +returning 0 if they are equal, 1 if lsn0 is greater than +lsn1, and -1 if lsn0 is less than lsn1. +

Class

+DbEnv +

See Also

+DbEnv.set_lg_bsize, +DbEnv.set_lg_max, +DbEnv.log_archive, +DbEnv.log_compare, +DbEnv.log_file, +DbEnv.log_flush, +DbEnv.log_get, +DbEnv.log_put, +DbEnv.log_register, +DbEnv.log_stat +and +DbEnv.log_unregister. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/log_file.html b/db/docs/api_java/log_file.html new file mode 100644 index 000000000..e85fa46df --- /dev/null +++ b/db/docs/api_java/log_file.html @@ -0,0 +1,77 @@ + + + + + +Berkeley DB: DbEnv.log_file + + + + + + + +
+

DbEnv.log_file

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public String log_file(DbLsn lsn) + throws DbException; +

+

Description

+

The DbEnv.log_file method maps +DbLsn objects +to file names, +returning the name of the file containing the record named by lsn. +

The len argument is the length of the namep buffer in bytes. +If namep is too short to hold the file name, DbEnv.log_file will +return ENOMEM. +(Log file names are normally quite short, on the order of 10 characters.) +

This mapping of +DbLsn objects +to files is needed for database administration. For example, a +transaction manager typically records the earliest +DbLsn +needed for restart, and the database administrator may want to archive +log files to tape when they contain only +DbLsn +entries before the earliest one needed for restart. +

The DbEnv.log_file method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

The DbEnv.log_file method may fail and throw an exception encapsulating a non-zero error for the following conditions: +

+

ENOMEM
The supplied buffer was too small to hold the log file name. +
+

The DbEnv.log_file method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv.log_file method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Class

+DbEnv +

See Also

+DbEnv.set_lg_bsize, +DbEnv.set_lg_max, +DbEnv.log_archive, +DbEnv.log_compare, +DbEnv.log_file, +DbEnv.log_flush, +DbEnv.log_get, +DbEnv.log_put, +DbEnv.log_register, +DbEnv.log_stat +and +DbEnv.log_unregister. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/log_flush.html b/db/docs/api_java/log_flush.html new file mode 100644 index 000000000..4396d21f7 --- /dev/null +++ b/db/docs/api_java/log_flush.html @@ -0,0 +1,65 @@ + + + + + +Berkeley DB: DbEnv.log_flush + + + + + + + +
+

DbEnv.log_flush

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void log_flush(DbLsn lsn) + throws DbException; +

+

Description

+

The DbEnv.log_flush method guarantees that all log records whose +DbLsn values +are less than or equal to the lsn argument have been +written to disk. If lsn is null, all records in the +log are flushed. +

The DbEnv.log_flush method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

The DbEnv.log_flush method may fail and throw an exception encapsulating a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +
+

The DbEnv.log_flush method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv.log_flush method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Class

+DbEnv +

See Also

+DbEnv.set_lg_bsize, +DbEnv.set_lg_max, +DbEnv.log_archive, +DbEnv.log_compare, +DbEnv.log_file, +DbEnv.log_flush, +DbEnv.log_get, +DbEnv.log_put, +DbEnv.log_register, +DbEnv.log_stat +and +DbEnv.log_unregister. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/log_get.html b/db/docs/api_java/log_get.html new file mode 100644 index 000000000..94eed0134 --- /dev/null +++ b/db/docs/api_java/log_get.html @@ -0,0 +1,117 @@ + + + + + +Berkeley DB: DbEnv.log_get + + + + + + + +
+

DbEnv.log_get

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void log_get(DbLsn lsn, Dbt data, int flags) + throws DbException; +

+

Description

+

The DbEnv.log_get method implements a cursor inside of the log, +retrieving records from the log according to the lsn and +flags arguments. +

The data field of the data structure is set to the record +retrieved and the size field indicates the number of bytes in the record. +See Dbt for a description of other fields in the data +structure. When multiple threads are using the returned log handle +concurrently, one of the Db.DB_DBT_MALLOC, Db.DB_DBT_REALLOC or +Db.DB_DBT_USERMEM flags must be specified for any Dbt used +for data retrieval. +

The flags argument must be set to exactly one of the following values: +

+

Db.DB_CHECKPOINT
The last record written with the DB_CHECKPOINT flag specified to the +DbEnv.log_put method is returned in the data argument. The +lsn argument is overwritten with the DbLsn of the record +returned. If no record has been previously written with the DB_CHECKPOINT +flag specified, the first record in the log is returned. +

If the log is empty, the DbEnv.log_get method will return Db.DB_NOTFOUND. +

Db.DB_FIRST
The first record from any of the log files found in the log directory +is returned in the data argument. +The lsn argument is overwritten with the DbLsn of the +record returned. +

If the log is empty, the DbEnv.log_get method will return Db.DB_NOTFOUND. +

Db.DB_LAST
The last record in the log is returned in the data argument. +The lsn argument is overwritten with the DbLsn of the +record returned. +

If the log is empty, the DbEnv.log_get method will return Db.DB_NOTFOUND. +

Db.DB_NEXT
The current log position is advanced to the next record in the log and that +record is returned in the data argument. +The lsn argument is overwritten with the DbLsn of the +record returned. +

If the pointer has not been initialized via DB_FIRST, DB_LAST, DB_SET, +DB_NEXT, or DB_PREV, DbEnv.log_get will return the first record in the log. +If the last log record has already been returned or the log is empty, the +DbEnv.log_get method will return Db.DB_NOTFOUND. +

If the log was opened with the DB_THREAD flag set, calls to +DbEnv.log_get with the DB_NEXT flag set will return EINVAL. +

Db.DB_PREV
The current log position is moved to the previous record in the log and that +record is returned in the data argument. +The lsn argument is overwritten with the DbLsn of the +record returned. +

If the pointer has not been initialized via DB_FIRST, DB_LAST, DB_SET, +DB_NEXT, or DB_PREV, +DbEnv.log_get will return the last record in the log. +If the first log record has already been returned or the log is empty, the +DbEnv.log_get method will return Db.DB_NOTFOUND. +

If the log was opened with the DB_THREAD flag set, calls to +DbEnv.log_get with the DB_PREV flag set will return EINVAL. +

Db.DB_CURRENT
Return the log record currently referenced by the log. +

If the log pointer has not been initialized via DB_FIRST, DB_LAST, DB_SET, +DB_NEXT, or DB_PREV, or if the log was opened with the DB_THREAD flag set, +DbEnv.log_get will return EINVAL. +

Db.DB_SET
Retrieve the record specified by the lsn argument. If the +specified DbLsn is invalid (e.g., does not appear in the log) +DbEnv.log_get will return EINVAL. +
+

Otherwise, the DbEnv.log_get method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

The DbEnv.log_get method may fail and throw an exception encapsulating a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +

The DB_FIRST flag was specified and no log files were found. +

+

The DbEnv.log_get method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv.log_get method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Class

+DbEnv +

See Also

+DbEnv.set_lg_bsize, +DbEnv.set_lg_max, +DbEnv.log_archive, +DbEnv.log_compare, +DbEnv.log_file, +DbEnv.log_flush, +DbEnv.log_get, +DbEnv.log_put, +DbEnv.log_register, +DbEnv.log_stat +and +DbEnv.log_unregister. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/log_put.html b/db/docs/api_java/log_put.html new file mode 100644 index 000000000..03749f20d --- /dev/null +++ b/db/docs/api_java/log_put.html @@ -0,0 +1,83 @@ + + + + + +Berkeley DB: DbEnv.log_put + + + + + + + +
+

DbEnv.log_put

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void log_put(DbLsn lsn, Dbt data, int flags) + throws DbException; +

+

Description

+

The DbEnv.log_put method appends records to the log. The DbLsn of +the put record is returned in the lsn argument. The flags +argument may be set to one of the following values: +

+

Db.DB_CHECKPOINT
The log should write a checkpoint record, recording any information +necessary to make the log structures recoverable after a crash. +

Db.DB_CURLSN
The DbLsn of the next record to be put is returned in the +lsn argument. +

Db.DB_FLUSH
The log is forced to disk after this record is written, guaranteeing +that all records with DbLsn values less than or equal to the +one being put are on disk before this function returns (this function +is most often used for a transaction commit, see DbTxn.commit for +more information). +

The caller is responsible for providing any necessary structure to +data. (For example, in a write-ahead logging protocol, the +application must understand what part of data is an operation +code, what part is redo information, and what part is undo information. +In addition, most transaction managers will store in data the +DbLsn of the previous log record for the same transaction, to +support chaining back through the transaction's log records during +undo.) +

+

The DbEnv.log_put method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

The DbEnv.log_flush method may fail and throw an exception encapsulating a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +

The record to be logged is larger than the maximum log record. +

+

The DbEnv.log_put method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv.log_put method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Class

+DbEnv +

See Also

+DbEnv.set_lg_bsize, +DbEnv.set_lg_max, +DbEnv.log_archive, +DbEnv.log_compare, +DbEnv.log_file, +DbEnv.log_flush, +DbEnv.log_get, +DbEnv.log_put, +DbEnv.log_register, +DbEnv.log_stat +and +DbEnv.log_unregister. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/log_register.html b/db/docs/api_java/log_register.html new file mode 100644 index 000000000..7d4833c3c --- /dev/null +++ b/db/docs/api_java/log_register.html @@ -0,0 +1,67 @@ + + + + + +Berkeley DB: DbEnv.log_register + + + + + + + +
+

DbEnv.log_register

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public int log_register(Db dbp, String name) + throws DbException; +

+

Description

+

The DbEnv.log_register method registers a file name with the specified Berkeley DB +environment's log manager. The log manager records all file name mappings +at each checkpoint so that a recovery process can identify the file to +which a record in the log refers. +

The dbp argument should be a reference to the Db object being +registered. The name argument should be a file name appropriate +for opening the file in the environment, during recovery. +

The DbEnv.log_register method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

The DbEnv.log_register method may fail and throw an exception encapsulating a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +
+

The DbEnv.log_register method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv.log_register method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Class

+DbEnv +

See Also

+DbEnv.set_lg_bsize, +DbEnv.set_lg_max, +DbEnv.log_archive, +DbEnv.log_compare, +DbEnv.log_file, +DbEnv.log_flush, +DbEnv.log_get, +DbEnv.log_put, +DbEnv.log_register, +DbEnv.log_stat +and +DbEnv.log_unregister. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/log_stat.html b/db/docs/api_java/log_stat.html new file mode 100644 index 000000000..4c51f1095 --- /dev/null +++ b/db/docs/api_java/log_stat.html @@ -0,0 +1,93 @@ + + + + + +Berkeley DB: DbEnv.log_stat + + + + + + + +
+

DbEnv.log_stat

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public DbLogStat log_stat() + throws DbException; +

+

Description

+

The DbEnv.log_stat method +creates a DbLogStat object encapsulating a statistical structure. +The log region statistics are stored in a DbLogStat object. +The following data fields are available from the DbLogStat object: +

Statistical structures are created in allocated memory. If db_malloc is non-NULL, it +is called to allocate the memory, otherwise, the library function +malloc(3) is used. The function db_malloc must match +the calling conventions of the malloc(3) library routine. +Regardless, the caller is responsible for deallocating the returned +memory. To deallocate returned memory, free the returned memory +reference, references inside the returned memory do not need to be +individually freed. +

The log region statistics are stored in a structure of type DB_LOG_STAT. +The following DB_LOG_STAT fields will be filled in: +

+
public int st_magic;
The magic number that identifies a file as a log file. +
public int st_version;
The version of the log file type. +
public int st_regsize;
The size of the region. +
public int st_mode;
The mode of any created log files. +
public int st_lg_bsize;
The in-memory log record cache size. +
public int st_lg_max;
The maximum size of any individual file comprising the log. +
public int st_w_mbytes;
The number of megabytes written to this log. +
public int st_w_bytes;
The number of bytes over and above st_w_mbytes written to this log. +
public int st_wc_mbytes;
The number of megabytes written to this log since the last checkpoint. +
public int st_wc_bytes;
The number of bytes over and above st_wc_mbytes written to this log +since the last checkpoint. +
public int st_wcount;
The number of times the log has been written to disk. +
public int st_wcount_fill;
The number of times the log has been written to disk because the +in-memory log record cache filled up. +
public int st_scount;
The number of times the log has been flushed to disk. +
public int st_cur_file;
The current log file number. +
public int st_cur_offset;
The byte offset in the current log file. +
public int st_region_wait;
The number of times that a thread of control was forced to wait before +obtaining the region lock. +
public int st_region_nowait;
The number of times that a thread of control was able to obtain +the region lock without waiting. +
+

The DbEnv.log_stat method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

The DbEnv.log_stat method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv.log_stat method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Class

+DbEnv +

See Also

+DbEnv.set_lg_bsize, +DbEnv.set_lg_max, +DbEnv.log_archive, +DbEnv.log_compare, +DbEnv.log_file, +DbEnv.log_flush, +DbEnv.log_get, +DbEnv.log_put, +DbEnv.log_register, +DbEnv.log_stat +and +DbEnv.log_unregister. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/log_unregister.html b/db/docs/api_java/log_unregister.html new file mode 100644 index 000000000..c79c324ee --- /dev/null +++ b/db/docs/api_java/log_unregister.html @@ -0,0 +1,62 @@ + + + + + +Berkeley DB: DbEnv.log_unregister + + + + + + + +
+

DbEnv.log_unregister

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void log_unregister(Db dbp) + throws DbException; +

+

Description

+

The DbEnv.log_unregister method function unregisters the file represented by +the dbp parameter from the Berkeley DB environment's log manager. +

The DbEnv.log_unregister method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

The DbEnv.log_unregister method may fail and throw an exception encapsulating a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +
+

The DbEnv.log_unregister method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv.log_unregister method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Class

+DbEnv +

See Also

+DbEnv.set_lg_bsize, +DbEnv.set_lg_max, +DbEnv.log_archive, +DbEnv.log_compare, +DbEnv.log_file, +DbEnv.log_flush, +DbEnv.log_get, +DbEnv.log_put, +DbEnv.log_register, +DbEnv.log_stat +and +DbEnv.log_unregister. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/lsn_class.html b/db/docs/api_java/lsn_class.html new file mode 100644 index 000000000..891ba8d0c --- /dev/null +++ b/db/docs/api_java/lsn_class.html @@ -0,0 +1,37 @@ + + + + + +Berkeley DB: DbLsn + + + + + + + +
+

DbLsn

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public class DbLsn extends Object { ... } +

+

Description

+

A DbLsn is a log sequence number that is fully +encapsulated. The class itself has no methods, other than a default +constructor, so there is no way for the user to manipulate its data +directly. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/mem_class.html b/db/docs/api_java/mem_class.html new file mode 100644 index 000000000..be9239def --- /dev/null +++ b/db/docs/api_java/mem_class.html @@ -0,0 +1,48 @@ + + + + + +Berkeley DB: DbMemoryException + + + + + + + +
+

DbMemoryException

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public class DbMemoryException extends DbException { ... } +

+

Description

+

This manual page describes the DbMemoryException class and +how it is used by the various Db* classes. +

A DbMemoryException is thrown when there is insufficient memory +to complete an operation. +

This may or may not be recoverable. An example of where it would be +recoverable is during a Db.get or Dbc.get operation +with the Dbt flags set to Db.DB_DBT_USERMEM. +

Class

+DbException +

See Also

+DbException.get_errno, +DbDeadlockException, +DbMemoryException +and +DbRunRecoveryException. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/memp_fclose.html b/db/docs/api_java/memp_fclose.html new file mode 100644 index 000000000..5cf196d40 --- /dev/null +++ b/db/docs/api_java/memp_fclose.html @@ -0,0 +1,33 @@ + + + + + +Berkeley DB: DbMpoolFile.close + + + + + + + +
+

DbMpoolFile.close

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+

Description

+

A DbMpoolFile.close method is not available in the Berkeley DB +Java API. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/memp_fget.html b/db/docs/api_java/memp_fget.html new file mode 100644 index 000000000..a59b4bbe8 --- /dev/null +++ b/db/docs/api_java/memp_fget.html @@ -0,0 +1,33 @@ + + + + + +Berkeley DB: DbMpoolFile.get + + + + + + + +
+

DbMpoolFile.get

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+

Description

+

A DbMpoolFile.get method is not available in the Berkeley DB +Java API. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/memp_fopen.html b/db/docs/api_java/memp_fopen.html new file mode 100644 index 000000000..e1186d505 --- /dev/null +++ b/db/docs/api_java/memp_fopen.html @@ -0,0 +1,33 @@ + + + + + +Berkeley DB: DbMpoolFile.open + + + + + + + +
+

DbMpoolFile.open

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+

Description

+

A DbMpoolFile.open method is not available in the Berkeley DB +Java API. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/memp_fput.html b/db/docs/api_java/memp_fput.html new file mode 100644 index 000000000..64cb4732a --- /dev/null +++ b/db/docs/api_java/memp_fput.html @@ -0,0 +1,33 @@ + + + + + +Berkeley DB: DbMpoolFile.put + + + + + + + +
+

DbMpoolFile.put

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+

Description

+

A DbMpoolFile.put method is not available in the Berkeley DB +Java API. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/memp_fset.html b/db/docs/api_java/memp_fset.html new file mode 100644 index 000000000..3ab3ed0ee --- /dev/null +++ b/db/docs/api_java/memp_fset.html @@ -0,0 +1,33 @@ + + + + + +Berkeley DB: DbMpoolFile.set + + + + + + + +
+

DbMpoolFile.set

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+

Description

+

A DbMpoolFile.set method is not available in the Berkeley DB +Java API. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/memp_fsync.html b/db/docs/api_java/memp_fsync.html new file mode 100644 index 000000000..b61063521 --- /dev/null +++ b/db/docs/api_java/memp_fsync.html @@ -0,0 +1,33 @@ + + + + + +Berkeley DB: DbMpoolFile.sync + + + + + + + +
+

DbMpoolFile.sync

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+

Description

+

A DbMpoolFile.sync method is not available in the Berkeley DB +Java API. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/memp_register.html b/db/docs/api_java/memp_register.html new file mode 100644 index 000000000..147b45a20 --- /dev/null +++ b/db/docs/api_java/memp_register.html @@ -0,0 +1,33 @@ + + + + + +Berkeley DB: DbEnv.memp_register + + + + + + + +
+

DbEnv.memp_register

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+

Description

+

A DbEnv.memp_register method is not available in the Berkeley DB +Java API. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/memp_stat.html b/db/docs/api_java/memp_stat.html new file mode 100644 index 000000000..1314201a5 --- /dev/null +++ b/db/docs/api_java/memp_stat.html @@ -0,0 +1,102 @@ + + + + + +Berkeley DB: DbEnv.memp_stat + + + + + + + +
+

DbEnv.memp_stat

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public DbMpoolStat memp_stat() + throws DbException; +

+public DbMpoolFStat[] memp_fstat() + throws DbException; +

+

Description

+

The DbEnv.memp_stat and DbEnv.memp_fstat method create statistical +structures and return to the caller. The statistics include the number +of files participating in the pool, the active pages in the pool, and +information as to how effective the cache has been. +

The DbEnv.memp_stat method creates a DbMpoolStat object containing global +statistics. The following data fields are available: +

+
public long st_gbytes;
Gigabytes of cache (total cache size is st_gbytes + st_bytes) +
public long st_bytes;
Bytes of cache (total cache size is st_gbytes + st_bytes) +
public int st_ncache;
Number of caches. +
public int st_regsize;
Individual cache size. +
public int st_cache_hit;
Requested pages found in the cache. +
public int st_cache_miss;
Requested pages not found in the cache. +
public int st_map;
Requested pages mapped into the process' address space (there is no +available information as to whether or not this request caused disk I/O, +although examining the application page fault rate may be helpful). +
public int st_page_create;
Pages created in the cache. +
public int st_page_in;
Pages read into the cache. +
public int st_page_out;
Pages written from the cache to the backing file. +
public int st_ro_evict;
Clean pages forced from the cache. +
public int st_rw_evict;
Dirty pages forced from the cache. +
public int st_hash_buckets;
Number of hash buckets in buffer hash table. +
public int st_hash_searches;
Total number of buffer hash table lookups. +
public int st_hash_longest;
The longest chain ever encountered in buffer hash table lookups. +
public int st_hash_examined;
Total number of hash elements traversed during hash table lookups. +
public int st_page_clean;
Clean pages currently in the cache. +
public int st_page_dirty;
Dirty pages currently in the cache. +
public int st_page_trickle;
Dirty pages written using the DbEnv.memp_trickle interface. +
public int st_region_wait;
The number of times that a thread of control was forced to wait before +obtaining the region lock. +
public int st_region_nowait;
The number of times that a thread of control was able to obtain +the region lock without waiting. +
+

The DbEnv.memp_fstat method creates an array of DbMpoolFStat objects +containing statistics for individual files in the pool. Each +DbMpoolFStat object contains statistics for an individual DbMpoolFile. +The following data fields are available for each DbMpoolFStat object: +

+
public String file_name;
The name of the file. +
public long st_pagesize;
Page size in bytes. +
public int st_cache_hit;
Requested pages found in the cache. +
public int st_cache_miss;
Requested pages not found in the cache. +
public int st_map;
Requested pages mapped into the process' address space. +
public int st_page_create;
Pages created in the cache. +
public int st_page_in;
Pages read into the cache. +
public int st_page_out;
Pages written from the cache to the backing file. +
+

The DbEnv.memp_stat method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

The DbEnv.memp_stat method may fail and throw an exception encapsulating a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +
+

The DbEnv.memp_stat method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv.memp_stat method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Class

+DbEnv +

See Also

+DbEnv.memp_fstat, +DbEnv.memp_stat +and +DbEnv.memp_trickle. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/memp_sync.html b/db/docs/api_java/memp_sync.html new file mode 100644 index 000000000..6c729b8f5 --- /dev/null +++ b/db/docs/api_java/memp_sync.html @@ -0,0 +1,33 @@ + + + + + +Berkeley DB: DbEnv.memp_sync + + + + + + + +
+

DbEnv.memp_sync

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+

Description

+

A DbEnv.memp_sync method is not available in the Berkeley DB +Java API. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/memp_trickle.html b/db/docs/api_java/memp_trickle.html new file mode 100644 index 000000000..0eeae97d5 --- /dev/null +++ b/db/docs/api_java/memp_trickle.html @@ -0,0 +1,60 @@ + + + + + +Berkeley DB: DbEnv.memp_trickle + + + + + + + +
+

DbEnv.memp_trickle

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public int memp_trickle(int pct) + throws DbException; +

+

Description

+

The DbEnv.memp_trickle method ensures that at least pct percent of +the pages in the shared memory pool are clean by writing dirty pages to +their backing files. +The number of pages that were written to reach the correct percentage is +returned. +

The purpose of the DbEnv.memp_trickle function is to enable a memory +pool manager to ensure that a page is always available for reading in new +information without having to wait for a write. +

The DbEnv.memp_trickle method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

The DbEnv.memp_trickle method may fail and throw an exception encapsulating a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +
+

The DbEnv.memp_trickle method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv.memp_trickle method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Class

+DbEnv +

See Also

+DbEnv.memp_fstat, +DbEnv.memp_stat +and +DbEnv.memp_trickle. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/pindex.src b/db/docs/api_java/pindex.src new file mode 100644 index 000000000..2dd85859d --- /dev/null +++ b/db/docs/api_java/pindex.src @@ -0,0 +1,249 @@ +__APIREL__/api_java/db_class.html#2 @Db +__APIREL__/api_java/db_class.html#Db.DB_XA_CREATE Db@Db.DB_XA_CREATE +__APIREL__/api_java/dbc_class.html#2 @Dbc +__APIREL__/api_java/dbenv_class.html#2 @DbEnv +__APIREL__/api_java/dbenv_class.html#Db.DB_CLIENT DbEnv@Db.DB_CLIENT +__APIREL__/api_java/dbt_class.html#2 @Dbt +__APIREL__/api_java/dbt_class.html#3 @key/data pairs +__APIREL__/api_java/dbt_class.html#data Dbt@data +__APIREL__/api_java/dbt_class.html#Db.DB_DBT_MALLOC Dbt@Db.DB_DBT_MALLOC +__APIREL__/api_java/dbt_class.html#Db.DB_DBT_REALLOC Dbt@Db.DB_DBT_REALLOC +__APIREL__/api_java/dbt_class.html#Db.DB_DBT_USERMEM Dbt@Db.DB_DBT_USERMEM +__APIREL__/api_java/dbt_class.html#Db.DB_DBT_PARTIAL Dbt@Db.DB_DBT_PARTIAL +__APIREL__/api_java/dbt_class.html#4 logical @record number format +__APIREL__/api_java/deadlock_class.html#2 @DbDeadlockException +__APIREL__/api_java/env_set_error_stream.html#2 @DbEnv.set_error_stream +__APIREL__/api_java/except_class.html#2 @DbException +__APIREL__/api_java/get_errno.html#2 @DbException.get_errno +__APIREL__/api_java/lock_class.html#2 @DbLock +__APIREL__/api_java/lsn_class.html#2 @DbLsn +__APIREL__/api_java/mem_class.html#2 @DbMemoryException +__APIREL__/api_java/runrec_class.html#2 @DbRunRecoveryException +__APIREL__/api_java/txn_class.html#2 @DbTxn +__APIREL__/api_java/db_close.html#2 @Db.close +__APIREL__/api_java/db_close.html#Db.DB_NOSYNC Db.close@Db.DB_NOSYNC +__APIREL__/api_java/db_close.html#3 Db.close @DB_INCOMPLETE +__APIREL__/api_java/db_cursor.html#2 @Db.cursor +__APIREL__/api_java/db_cursor.html#Db.DB_WRITECURSOR Db.cursor@Db.DB_WRITECURSOR +__APIREL__/api_java/db_del.html#2 @Db.del +__APIREL__/api_java/db_fd.html#2 @Db.fd +__APIREL__/api_java/db_get.html#2 @Db.get +__APIREL__/api_java/db_get.html#Db.DB_CONSUME Db.get@Db.DB_CONSUME +__APIREL__/api_java/db_get.html#Db.DB_CONSUME_WAIT Db.get@Db.DB_CONSUME_WAIT +__APIREL__/api_java/db_get.html#Db.DB_GET_BOTH Db.get@Db.DB_GET_BOTH +__APIREL__/api_java/db_get.html#Db.DB_SET_RECNO Db.get@Db.DB_SET_RECNO +__APIREL__/api_java/db_get.html#Db.DB_RMW Db.get@Db.DB_RMW +__APIREL__/api_java/db_get_byteswapped.html#2 @Db.get_byteswapped +__APIREL__/api_java/db_get_type.html#2 @Db.get_type +__APIREL__/api_java/db_join.html#2 @Db.join +__APIREL__/api_java/db_join.html#Db.DB_JOIN_NOSORT Db.join@Db.DB_JOIN_NOSORT +__APIREL__/api_java/db_join.html#Db.DB_JOIN_ITEM Db.join@Db.DB_JOIN_ITEM +__APIREL__/api_java/db_join.html#Db.DB_RMW Db.join@Db.DB_RMW +__APIREL__/api_java/db_key_range.html#2 @Db.key_range +__APIREL__/api_java/db_open.html#2 @Db.open +__APIREL__/api_java/db_open.html#Db.DB_CREATE Db.open@Db.DB_CREATE +__APIREL__/api_java/db_open.html#Db.DB_EXCL Db.open@Db.DB_EXCL +__APIREL__/api_java/db_open.html#Db.DB_NOMMAP Db.open@Db.DB_NOMMAP +__APIREL__/api_java/db_open.html#Db.DB_RDONLY Db.open@Db.DB_RDONLY +__APIREL__/api_java/db_open.html#Db.DB_THREAD Db.open@Db.DB_THREAD +__APIREL__/api_java/db_open.html#Db.DB_TRUNCATE Db.open@Db.DB_TRUNCATE +__APIREL__/api_java/db_open.html#Db.DB_OLD_VERSION Db.open@Db.DB_OLD_VERSION +__APIREL__/api_java/db_put.html#2 @Db.put +__APIREL__/api_java/db_put.html#Db.DB_APPEND Db.put@Db.DB_APPEND +__APIREL__/api_java/db_put.html#Db.DB_NODUPDATA Db.put@Db.DB_NODUPDATA +__APIREL__/api_java/db_put.html#Db.DB_NOOVERWRITE Db.put@Db.DB_NOOVERWRITE +__APIREL__/api_java/db_remove.html#2 @Db.remove +__APIREL__/api_java/db_rename.html#2 @Db.rename +__APIREL__/api_java/db_set_append_recno.html#2 @Db.set_append_recno +__APIREL__/api_java/db_set_bt_compare.html#2 @Db.set_bt_compare +__APIREL__/api_java/db_set_bt_minkey.html#2 @Db.set_bt_minkey +__APIREL__/api_java/db_set_bt_prefix.html#2 @Db.set_bt_prefix +__APIREL__/api_java/db_set_cachesize.html#2 @Db.set_cachesize +__APIREL__/api_java/db_set_dup_compare.html#2 @Db.set_dup_compare +__APIREL__/api_java/db_set_errcall.html#2 @Db.set_errcall +__APIREL__/api_java/db_set_errpfx.html#2 @Db.set_errpfx +__APIREL__/api_java/db_set_feedback.html#2 @Db.set_feedback +__APIREL__/api_java/db_set_feedback.html#Db.DB_UPGRADE Db.set_feedback@Db.DB_UPGRADE +__APIREL__/api_java/db_set_feedback.html#Db.DB_VERIFY Db.set_feedback@Db.DB_VERIFY +__APIREL__/api_java/db_set_flags.html#2 @Db.set_flags +__APIREL__/api_java/db_set_flags.html#Db.DB_DUP Db.set_flags@Db.DB_DUP +__APIREL__/api_java/db_set_flags.html#Db.DB_DUPSORT Db.set_flags@Db.DB_DUPSORT +__APIREL__/api_java/db_set_flags.html#Db.DB_RECNUM Db.set_flags@Db.DB_RECNUM +__APIREL__/api_java/db_set_flags.html#Db.DB_REVSPLITOFF Db.set_flags@Db.DB_REVSPLITOFF +__APIREL__/api_java/db_set_flags.html#Db.DB_DUP Db.set_flags@Db.DB_DUP +__APIREL__/api_java/db_set_flags.html#Db.DB_DUPSORT Db.set_flags@Db.DB_DUPSORT +__APIREL__/api_java/db_set_flags.html#Db.DB_RENUMBER Db.set_flags@Db.DB_RENUMBER +__APIREL__/api_java/db_set_flags.html#Db.DB_SNAPSHOT Db.set_flags@Db.DB_SNAPSHOT +__APIREL__/api_java/db_set_h_ffactor.html#2 @Db.set_h_ffactor +__APIREL__/api_java/db_set_h_hash.html#2 @Db.set_h_hash +__APIREL__/api_java/db_set_h_nelem.html#2 @Db.set_h_nelem +__APIREL__/api_java/db_set_lorder.html#2 @Db.set_lorder +__APIREL__/api_java/db_set_pagesize.html#2 @Db.set_pagesize +__APIREL__/api_java/db_set_q_extentsize.html#2 @Db.set_q_extentsize +__APIREL__/api_java/db_set_re_delim.html#2 @Db.set_re_delim +__APIREL__/api_java/db_set_re_len.html#2 @Db.set_re_len +__APIREL__/api_java/db_set_re_pad.html#2 @Db.set_re_pad +__APIREL__/api_java/db_set_re_source.html#2 @Db.set_re_source +__APIREL__/api_java/db_stat.html#2 @Db.stat +__APIREL__/api_java/db_stat.html#Db.DB_CACHED_COUNTS Db.stat@Db.DB_CACHED_COUNTS +__APIREL__/api_java/db_stat.html#Db.DB_RECORDCOUNT Db.stat@Db.DB_RECORDCOUNT +__APIREL__/api_java/db_sync.html#2 @Db.sync +__APIREL__/api_java/db_upgrade.html#2 @Db.upgrade +__APIREL__/api_java/db_upgrade.html#Db.DB_DUPSORT Db.upgrade@Db.DB_DUPSORT +__APIREL__/api_java/db_upgrade.html#Db.DB_OLD_VERSION Db.upgrade@Db.DB_OLD_VERSION +__APIREL__/api_java/db_verify.html#2 @Db.verify +__APIREL__/api_java/db_verify.html#Db.DB_SALVAGE Db.verify@Db.DB_SALVAGE +__APIREL__/api_java/db_verify.html#Db.DB_AGGRESSIVE Db.verify@Db.DB_AGGRESSIVE +__APIREL__/api_java/db_verify.html#Db.DB_NOORDERCHK Db.verify@Db.DB_NOORDERCHK +__APIREL__/api_java/db_verify.html#Db.DB_ORDERCHKONLY Db.verify@Db.DB_ORDERCHKONLY +__APIREL__/api_java/dbc_close.html#2 @Dbc.close +__APIREL__/api_java/dbc_count.html#2 @Dbc.count +__APIREL__/api_java/dbc_del.html#2 @Dbc.del +__APIREL__/api_java/dbc_dup.html#2 @Dbc.dup +__APIREL__/api_java/dbc_dup.html#Db.DB_POSITION Dbc.dup@Db.DB_POSITION +__APIREL__/api_java/dbc_get.html#2 @Dbc.get +__APIREL__/api_java/dbc_get.html#Db.DB_CURRENT Dbc.get@Db.DB_CURRENT +__APIREL__/api_java/dbc_get.html#Db.DB_FIRST Dbc.get@Db.DB_FIRST +__APIREL__/api_java/dbc_get.html#Db.DB_LAST Dbc.get@Db.DB_LAST +__APIREL__/api_java/dbc_get.html#Db.DB_GET_BOTH Dbc.get@Db.DB_GET_BOTH +__APIREL__/api_java/dbc_get.html#Db.DB_GET_RECNO Dbc.get@Db.DB_GET_RECNO +__APIREL__/api_java/dbc_get.html#Db.DB_JOIN_ITEM Dbc.get@Db.DB_JOIN_ITEM +__APIREL__/api_java/dbc_get.html#Db.DB_NEXT Dbc.get@Db.DB_NEXT +__APIREL__/api_java/dbc_get.html#Db.DB_PREV Dbc.get@Db.DB_PREV +__APIREL__/api_java/dbc_get.html#Db.DB_NEXT_DUP Dbc.get@Db.DB_NEXT_DUP +__APIREL__/api_java/dbc_get.html#Db.DB_NEXT_NODUP Dbc.get@Db.DB_NEXT_NODUP +__APIREL__/api_java/dbc_get.html#Db.DB_PREV_NODUP Dbc.get@Db.DB_PREV_NODUP +__APIREL__/api_java/dbc_get.html#Db.DB_SET Dbc.get@Db.DB_SET +__APIREL__/api_java/dbc_get.html#Db.DB_SET_RANGE Dbc.get@Db.DB_SET_RANGE +__APIREL__/api_java/dbc_get.html#Db.DB_SET_RECNO Dbc.get@Db.DB_SET_RECNO +__APIREL__/api_java/dbc_get.html#Db.DB_RMW Dbc.get@Db.DB_RMW +__APIREL__/api_java/dbc_put.html#2 @Dbc.put +__APIREL__/api_java/dbc_put.html#Db.DB_AFTER Dbc.put@Db.DB_AFTER +__APIREL__/api_java/dbc_put.html#Db.DB_BEFORE Dbc.put@Db.DB_BEFORE +__APIREL__/api_java/dbc_put.html#Db.DB_CURRENT Dbc.put@Db.DB_CURRENT +__APIREL__/api_java/dbc_put.html#Db.DB_KEYFIRST Dbc.put@Db.DB_KEYFIRST +__APIREL__/api_java/dbc_put.html#Db.DB_KEYLAST Dbc.put@Db.DB_KEYLAST +__APIREL__/api_java/dbc_put.html#Db.DB_NODUPDATA Dbc.put@Db.DB_NODUPDATA +__APIREL__/api_java/env_close.html#2 @DbEnv.close +__APIREL__/api_java/env_open.html#2 @DbEnv.open +__APIREL__/api_java/env_open.html#Db.DB_JOINENV DbEnv.open@Db.DB_JOINENV +__APIREL__/api_java/env_open.html#Db.DB_INIT_CDB DbEnv.open@Db.DB_INIT_CDB +__APIREL__/api_java/env_open.html#Db.DB_INIT_LOCK DbEnv.open@Db.DB_INIT_LOCK +__APIREL__/api_java/env_open.html#Db.DB_INIT_LOG DbEnv.open@Db.DB_INIT_LOG +__APIREL__/api_java/env_open.html#Db.DB_INIT_MPOOL DbEnv.open@Db.DB_INIT_MPOOL +__APIREL__/api_java/env_open.html#Db.DB_INIT_TXN DbEnv.open@Db.DB_INIT_TXN +__APIREL__/api_java/env_open.html#Db.DB_RECOVER DbEnv.open@Db.DB_RECOVER +__APIREL__/api_java/env_open.html#Db.DB_RECOVER_FATAL DbEnv.open@Db.DB_RECOVER_FATAL +__APIREL__/api_java/env_open.html#Db.DB_USE_ENVIRON DbEnv.open@Db.DB_USE_ENVIRON +__APIREL__/api_java/env_open.html#Db.DB_USE_ENVIRON_ROOT DbEnv.open@Db.DB_USE_ENVIRON_ROOT +__APIREL__/api_java/env_open.html#Db.DB_CREATE DbEnv.open@Db.DB_CREATE +__APIREL__/api_java/env_open.html#Db.DB_LOCKDOWN DbEnv.open@Db.DB_LOCKDOWN +__APIREL__/api_java/env_open.html#Db.DB_PRIVATE DbEnv.open@Db.DB_PRIVATE +__APIREL__/api_java/env_open.html#Db.DB_SYSTEM_MEM DbEnv.open@Db.DB_SYSTEM_MEM +__APIREL__/api_java/env_open.html#Db.DB_THREAD DbEnv.open@Db.DB_THREAD +__APIREL__/api_java/env_remove.html#2 @DbEnv.remove +__APIREL__/api_java/env_remove.html#Db.DB_FORCE DbEnv.remove@Db.DB_FORCE +__APIREL__/api_java/env_remove.html#Db.DB_USE_ENVIRON DbEnv.remove@Db.DB_USE_ENVIRON +__APIREL__/api_java/env_remove.html#Db.DB_USE_ENVIRON_ROOT DbEnv.remove@Db.DB_USE_ENVIRON_ROOT +__APIREL__/api_java/env_set_cachesize.html#2 @DbEnv.set_cachesize +__APIREL__/api_java/env_set_data_dir.html#2 @DbEnv.set_data_dir +__APIREL__/api_java/env_set_errcall.html#2 @DbEnv.set_errcall +__APIREL__/api_java/env_set_errpfx.html#2 @DbEnv.set_errpfx +__APIREL__/api_java/env_set_feedback.html#2 @DbEnv.set_feedback +__APIREL__/api_java/env_set_feedback.html#Db.DB_RECOVER DbEnv.set_feedback@Db.DB_RECOVER +__APIREL__/api_java/env_set_flags.html#2 @DbEnv.set_flags +__APIREL__/api_java/env_set_flags.html#Db.DB_CDB_ALLDB DbEnv.set_flags@Db.DB_CDB_ALLDB +__APIREL__/api_java/env_set_flags.html#Db.DB_NOMMAP DbEnv.set_flags@Db.DB_NOMMAP +__APIREL__/api_java/env_set_flags.html#Db.DB_TXN_NOSYNC DbEnv.set_flags@Db.DB_TXN_NOSYNC +__APIREL__/api_java/env_set_lg_bsize.html#2 @DbEnv.set_lg_bsize +__APIREL__/api_java/env_set_lg_dir.html#2 @DbEnv.set_lg_dir +__APIREL__/api_java/env_set_lg_max.html#2 @DbEnv.set_lg_max +__APIREL__/api_java/env_set_lk_conflicts.html#2 @DbEnv.set_lk_conflicts +__APIREL__/api_java/env_set_lk_detect.html#2 @DbEnv.set_lk_detect +__APIREL__/api_java/env_set_lk_detect.html#DB_LOCK_DEFAULT DbEnv.set_lk_detect@DB_LOCK_DEFAULT +__APIREL__/api_java/env_set_lk_detect.html#DB_LOCK_OLDEST DbEnv.set_lk_detect@DB_LOCK_OLDEST +__APIREL__/api_java/env_set_lk_detect.html#DB_LOCK_RANDOM DbEnv.set_lk_detect@DB_LOCK_RANDOM +__APIREL__/api_java/env_set_lk_detect.html#DB_LOCK_YOUNGEST DbEnv.set_lk_detect@DB_LOCK_YOUNGEST +__APIREL__/api_java/env_set_lk_max.html#2 @DbEnv.set_lk_max +__APIREL__/api_java/env_set_lk_max_locks.html#2 @DbEnv.set_lk_max_locks +__APIREL__/api_java/env_set_lk_max_lockers.html#2 @DbEnv.set_lk_max_lockers +__APIREL__/api_java/env_set_lk_max_objects.html#2 @DbEnv.set_lk_max_objects +__APIREL__/api_java/env_set_mp_mmapsize.html#2 @DbEnv.set_mp_mmapsize +__APIREL__/api_java/env_set_mutexlocks.html#2 @DbEnv.set_mutexlocks +__APIREL__/api_java/env_set_pageyield.html#2 @DbEnv.set_pageyield +__APIREL__/api_java/env_set_panicstate.html#2 @DbEnv.set_panicstate +__APIREL__/api_java/env_set_rec_init.html#2 @DbEnv.set_recovery_init +__APIREL__/api_java/env_set_region_init.html#2 @DbEnv.set_region_init +__APIREL__/api_java/env_set_server.html#2 @DbEnv.set_server +__APIREL__/api_java/env_set_server.html#DB_NOSERVER DbEnv.set_server@DB_NOSERVER +__APIREL__/api_java/env_set_server.html#DB_NOSERVER_ID DbEnv.set_server@DB_NOSERVER_ID +__APIREL__/api_java/env_set_shm_key.html#2 @DbEnv.set_shm_key +__APIREL__/api_java/env_set_tas_spins.html#2 @DbEnv.set_tas_spins +__APIREL__/api_java/env_set_tmp_dir.html#2 @DbEnv.set_tmp_dir +__APIREL__/api_java/env_set_tx_max.html#2 @DbEnv.set_tx_max +__APIREL__/api_java/env_set_tx_recover.html#2 @DbEnv.set_tx_recover +__APIREL__/api_java/env_set_tx_recover.html#Db.DB_TXN_BACKWARD_ROLL DbEnv.set_tx_recover@Db.DB_TXN_BACKWARD_ROLL +__APIREL__/api_java/env_set_tx_recover.html#Db.DB_TXN_FORWARD_ROLL DbEnv.set_tx_recover@Db.DB_TXN_FORWARD_ROLL +__APIREL__/api_java/env_set_tx_recover.html#Db.DB_TXN_ABORT DbEnv.set_tx_recover@Db.DB_TXN_ABORT +__APIREL__/api_java/env_set_tx_timestamp.html#2 @DbEnv.set_tx_timestamp +__APIREL__/api_java/env_set_verbose.html#2 @DbEnv.set_verbose +__APIREL__/api_java/env_set_verbose.html#Db.DB_VERB_CHKPOINT DbEnv.set_verbose@Db.DB_VERB_CHKPOINT +__APIREL__/api_java/env_set_verbose.html#Db.DB_VERB_DEADLOCK DbEnv.set_verbose@Db.DB_VERB_DEADLOCK +__APIREL__/api_java/env_set_verbose.html#Db.DB_VERB_RECOVERY DbEnv.set_verbose@Db.DB_VERB_RECOVERY +__APIREL__/api_java/env_set_verbose.html#Db.DB_VERB_WAITSFOR DbEnv.set_verbose@Db.DB_VERB_WAITSFOR +__APIREL__/api_java/env_strerror.html#2 @DbEnv.strerror +__APIREL__/api_java/env_version.html#2 @DbEnv.get_version_major +__APIREL__/api_java/lock_detect.html#2 @DbEnv.lock_detect +__APIREL__/api_java/lock_detect.html#Db.DB_LOCK_CONFLICT DbEnv.lock_detect@Db.DB_LOCK_CONFLICT +__APIREL__/api_java/lock_get.html#2 @DbEnv.lock_get +__APIREL__/api_java/lock_get.html#Db.DB_LOCK_NOWAIT DbEnv.lock_get@Db.DB_LOCK_NOWAIT +__APIREL__/api_java/lock_get.html#Db.DB_LOCK_NOTGRANTED DbEnv.lock_get@Db.DB_LOCK_NOTGRANTED +__APIREL__/api_java/lock_id.html#2 @DbEnv.lock_id +__APIREL__/api_java/lock_put.html#2 @DbLock.put +__APIREL__/api_java/lock_stat.html#2 @DbEnv.lock_stat +__APIREL__/api_java/lock_vec.html#2 @DbEnv.lock_vec +__APIREL__/api_java/log_archive.html#2 @DbEnv.log_archive +__APIREL__/api_java/log_archive.html#Db.DB_ARCH_ABS DbEnv.log_archive@Db.DB_ARCH_ABS +__APIREL__/api_java/log_archive.html#Db.DB_ARCH_DATA DbEnv.log_archive@Db.DB_ARCH_DATA +__APIREL__/api_java/log_archive.html#Db.DB_ARCH_LOG DbEnv.log_archive@Db.DB_ARCH_LOG +__APIREL__/api_java/log_compare.html#2 @DbEnv.log_compare +__APIREL__/api_java/log_file.html#2 @DbEnv.log_file +__APIREL__/api_java/log_flush.html#2 @DbEnv.log_flush +__APIREL__/api_java/log_get.html#2 @DbEnv.log_get +__APIREL__/api_java/log_get.html#Db.DB_CHECKPOINT DbEnv.log_get@Db.DB_CHECKPOINT +__APIREL__/api_java/log_get.html#Db.DB_FIRST DbEnv.log_get@Db.DB_FIRST +__APIREL__/api_java/log_get.html#Db.DB_LAST DbEnv.log_get@Db.DB_LAST +__APIREL__/api_java/log_get.html#Db.DB_NEXT DbEnv.log_get@Db.DB_NEXT +__APIREL__/api_java/log_get.html#Db.DB_PREV DbEnv.log_get@Db.DB_PREV +__APIREL__/api_java/log_get.html#Db.DB_CURRENT DbEnv.log_get@Db.DB_CURRENT +__APIREL__/api_java/log_get.html#Db.DB_SET DbEnv.log_get@Db.DB_SET +__APIREL__/api_java/log_put.html#2 @DbEnv.log_put +__APIREL__/api_java/log_put.html#Db.DB_CHECKPOINT DbEnv.log_put@Db.DB_CHECKPOINT +__APIREL__/api_java/log_put.html#Db.DB_CURLSN DbEnv.log_put@Db.DB_CURLSN +__APIREL__/api_java/log_put.html#Db.DB_FLUSH DbEnv.log_put@Db.DB_FLUSH +__APIREL__/api_java/log_register.html#2 @DbEnv.log_register +__APIREL__/api_java/log_stat.html#2 @DbEnv.log_stat +__APIREL__/api_java/log_unregister.html#2 @DbEnv.log_unregister +__APIREL__/api_java/memp_fclose.html#2 @DbMpoolFile.close +__APIREL__/api_java/memp_fget.html#2 @DbMpoolFile.get +__APIREL__/api_java/memp_fopen.html#2 @DbMpoolFile.open +__APIREL__/api_java/memp_fput.html#2 @DbMpoolFile.put +__APIREL__/api_java/memp_fset.html#2 @DbMpoolFile.set +__APIREL__/api_java/memp_fsync.html#2 @DbMpoolFile.sync +__APIREL__/api_java/memp_register.html#2 @DbEnv.memp_register +__APIREL__/api_java/memp_stat.html#2 @DbEnv.memp_stat +__APIREL__/api_java/memp_sync.html#2 @DbEnv.memp_sync +__APIREL__/api_java/memp_trickle.html#2 @DbEnv.memp_trickle +__APIREL__/api_java/txn_abort.html#2 @DbTxn.abort +__APIREL__/api_java/txn_begin.html#2 @DbEnv.txn_begin +__APIREL__/api_java/txn_begin.html#Db.DB_TXN_NOSYNC DbEnv.txn_begin@Db.DB_TXN_NOSYNC +__APIREL__/api_java/txn_begin.html#Db.DB_TXN_NOWAIT DbEnv.txn_begin@Db.DB_TXN_NOWAIT +__APIREL__/api_java/txn_begin.html#Db.DB_TXN_SYNC DbEnv.txn_begin@Db.DB_TXN_SYNC +__APIREL__/api_java/txn_checkpoint.html#2 @DbEnv.txn_checkpoint +__APIREL__/api_java/txn_checkpoint.html#Db.DB_FORCE DbEnv.txn_checkpoint@Db.DB_FORCE +__APIREL__/api_java/txn_commit.html#2 @DbTxn.commit +__APIREL__/api_java/txn_commit.html#Db.DB_TXN_NOSYNC DbTxn.commit@Db.DB_TXN_NOSYNC +__APIREL__/api_java/txn_commit.html#Db.DB_TXN_SYNC DbTxn.commit@Db.DB_TXN_SYNC +__APIREL__/api_java/txn_id.html#2 @DbTxn.id +__APIREL__/api_java/txn_prepare.html#2 @DbTxn.prepare +__APIREL__/api_java/txn_stat.html#2 @DbEnv.txn_stat diff --git a/db/docs/api_java/runrec_class.html b/db/docs/api_java/runrec_class.html new file mode 100644 index 000000000..31fd07b94 --- /dev/null +++ b/db/docs/api_java/runrec_class.html @@ -0,0 +1,50 @@ + + + + + +Berkeley DB: DbRunRecoveryException + + + + + + + +
+

DbRunRecoveryException

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public class DbRunRecoveryException extends DbException { ... } +

+

Description

+

This manual page describes the DbRunRecoveryException class and +how it is used by the various Db* classes. +

Errors can occur in the Berkeley DB library where the only solution is to shut +down the application and run recovery. (For example, if Berkeley DB is unable +to write log records to disk because there is insufficient disk space.) +When a fatal error occurs in Berkeley DB, methods will throw a +DbRunRecoveryException, at which point all subsequent database +calls will also fail in the same way. When this occurs, recovery should +be performed. +

Class

+DbException +

See Also

+DbException.get_errno, +DbDeadlockException, +DbMemoryException +and +DbRunRecoveryException. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/txn_abort.html b/db/docs/api_java/txn_abort.html new file mode 100644 index 000000000..48f4ddf07 --- /dev/null +++ b/db/docs/api_java/txn_abort.html @@ -0,0 +1,65 @@ + + + + + +Berkeley DB: DbTxn.abort + + + + + + + +
+

DbTxn.abort

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void abort() + throws DbException; +

+

Description

+

The DbTxn.abort method causes an abnormal termination of the +transaction. The log is played backwards and any necessary recovery +operations are initiated through the recover function specified +to DbEnv.open. After the log processing is completed, all locks +held by the transaction are released. As is the case for +DbTxn.commit, applications that require strict two-phase locking +should not explicitly release any locks. +

In the case of nested transactions, aborting a parent transaction causes +all children (unresolved or not) of the parent transaction to be aborted. +

Once the DbTxn.abort method returns, the DbTxn handle may not +be accessed again. +

The DbTxn.abort method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

The DbTxn.abort method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbTxn.abort method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Classes

+DbEnv, DbTxn +

See Also

+DbEnv.set_tx_max, +DbEnv.set_tx_timestamp, +DbTxn.abort, +DbEnv.txn_begin, +DbEnv.txn_checkpoint, +DbTxn.commit, +DbTxn.id, +DbTxn.prepare +and +DbEnv.txn_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/txn_begin.html b/db/docs/api_java/txn_begin.html new file mode 100644 index 000000000..f81e86aea --- /dev/null +++ b/db/docs/api_java/txn_begin.html @@ -0,0 +1,93 @@ + + + + + +Berkeley DB: DbEnv.txn_begin + + + + + + + +
+

DbEnv.txn_begin

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public DbTxn txn_begin(DbTxn parent, int flags) + throws DbException; +

+

Description

+

The DbEnv.txn_begin method creates a new transaction in the environment +and returns a DbTxn that uniquely identifies it. +

If the parent argument is non-null, the new transaction will +be a nested transaction, with the transaction indicated by +parent as its parent. Transactions may be +nested to any level. +

The flags parameter must be set to 0 or one of the following +values: +

+

Db.DB_TXN_NOSYNC
Do not synchronously flush the log when this transaction commits or +prepares. This means the transaction will exhibit the ACI (atomicity, +consistency and isolation) properties, but not D (durability), i.e., +database integrity will be maintained but it is possible that this +transaction may be undone during recovery instead of being redone. +

This behavior may be set for an entire Berkeley DB environment as part of the +DbEnv.set_flags interface. +

Db.DB_TXN_NOWAIT
If a lock is unavailable for any Berkeley DB operation performed in the context +of this transaction, return immediately instead of blocking on the lock. +The error return in the case will be Db.DB_LOCK_NOTGRANTED. +

Db.DB_TXN_SYNC
Synchronously flush the log when this transaction commits or prepares. +This means the transaction will exhibit all of the ACID (atomicity, +consistency and isolation and durability) properties. +

This behavior is the default for Berkeley DB environments unless the +Db.DB_TXN_NOSYNC flag was specified to the DbEnv.set_flags +interface. +

+

Note: An transaction may not span threads, +i.e., each transaction must begin and end in the same thread, and each +transaction may only be used by a single thread. +

Note: cursors may not span transactions, i.e., each cursor must be opened +and closed within a single transaction. +

Note: a parent transaction may not issue any Berkeley DB operations, except for +DbEnv.txn_begin, DbTxn.abort and DbTxn.commit, while it has +active child transactions (child transactions that have not yet been +committed or aborted). +

The DbEnv.txn_begin method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

The DbEnv.txn_begin method may fail and throw an exception encapsulating a non-zero error for the following conditions: +

+

ENOMEM
The maximum number of concurrent transactions has been reached. +
+

The DbEnv.txn_begin method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv.txn_begin method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Classes

+DbEnv, DbTxn +

See Also

+DbEnv.set_tx_max, +DbEnv.set_tx_timestamp, +DbTxn.abort, +DbEnv.txn_begin, +DbEnv.txn_checkpoint, +DbTxn.commit, +DbTxn.id, +DbTxn.prepare +and +DbEnv.txn_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/txn_checkpoint.html b/db/docs/api_java/txn_checkpoint.html new file mode 100644 index 000000000..f2bc7528a --- /dev/null +++ b/db/docs/api_java/txn_checkpoint.html @@ -0,0 +1,74 @@ + + + + + +Berkeley DB: DbEnv.txn_checkpoint + + + + + + + +
+

DbEnv.txn_checkpoint

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+int +public int txn_checkpoint(int kbyte, int min, int flags) + throws DbException; +

+

Description

+

The DbEnv.txn_checkpoint method flushes the underlying memory pool, +writes a checkpoint record to the log and then flushes the log. +

If either kbyte or min is non-zero, the checkpoint is only +done if there has been activity since the last checkpoint and either +more than min minutes have passed since the last checkpoint, +or if more than kbyte kilobytes of log data have been written since +the last checkpoint. +

The flags parameter must be set to 0 or one of the following +values: +

+

Db.DB_FORCE
Force a checkpoint record even if there has been no activity since the +last checkpoint. +
+

The DbEnv.txn_checkpoint method throws an exception that encapsulates a non-zero error value on +failure, and returns Db.DB_INCOMPLETE if there were pages that needed to be +written to complete the checkpoint but that DbEnv.memp_sync was unable +to write immediately. +

Errors

+

The DbEnv.txn_checkpoint method may fail and throw an exception encapsulating a non-zero error for the following conditions: +

+

EINVAL
An invalid flag value or parameter was specified. +
+

The DbEnv.txn_checkpoint method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv.txn_checkpoint method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Classes

+DbEnv, DbTxn +

See Also

+DbEnv.set_tx_max, +DbEnv.set_tx_timestamp, +DbTxn.abort, +DbEnv.txn_begin, +DbEnv.txn_checkpoint, +DbTxn.commit, +DbTxn.id, +DbTxn.prepare +and +DbEnv.txn_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/txn_class.html b/db/docs/api_java/txn_class.html new file mode 100644 index 000000000..ab386172b --- /dev/null +++ b/db/docs/api_java/txn_class.html @@ -0,0 +1,58 @@ + + + + + +Berkeley DB: DbTxn + + + + + + + +
+

DbTxn

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public class DbTxn extends Object { ... } +

+

Description

+

This manual page describes the specific details of the DbTxn class. +

The DbEnv transaction methods and the DbTxn class provide +transaction semantics. Full transaction support is provided by a +collection of modules that provide interfaces to the services required +for transaction processing. These services are recovery, concurrency +control and the management of shared data. +

Transaction semantics can be applied to the access methods described in +Db through method call parameters. +

The model intended for transactional use (and the one that is used by +the access methods) is write-ahead logging to record both before- and +after-images. Locking follows a two-phase protocol, with all locks being +released at transaction commit. +

Classes

+DbEnv, DbTxn +

See Also

+DbEnv.set_tx_max, +DbEnv.set_tx_timestamp, +DbTxn.abort, +DbEnv.txn_begin, +DbEnv.txn_checkpoint, +DbTxn.commit, +DbTxn.id, +DbTxn.prepare +and +DbEnv.txn_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/txn_commit.html b/db/docs/api_java/txn_commit.html new file mode 100644 index 000000000..53aa0df46 --- /dev/null +++ b/db/docs/api_java/txn_commit.html @@ -0,0 +1,85 @@ + + + + + +Berkeley DB: DbTxn.commit + + + + + + + +
+

DbTxn.commit

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void commit(u_int32_t flags) + throws DbException; +

+

Description

+

The DbTxn.commit method ends the transaction. In the case of nested +transactions, if the transaction is a parent transaction, committing +the parent transaction causes all unresolved children of the parent to +be committed. +

In the case of nested transactions, if the transaction is a child +transaction, its locks are not released, but are acquired by its parent. +While the commit of the child transaction will succeed, the actual +resolution of the child transaction is postponed until the parent +transaction is committed or aborted, i.e., if its parent transaction +commits, it will be committed, and if its parent transaction aborts, it +will be aborted. +

The flags parameter must be set to 0 or one of the following +values: +

+

Db.DB_TXN_NOSYNC
Do not synchronously flush the log. This means the transaction will +exhibit the ACI (atomicity, consistency and isolation) properties, but +not D (durability), i.e., database integrity will be maintained but it is +possible that this transaction may be undone during recovery instead of +being redone. +

This behavior may be set for an entire Berkeley DB environment as part of the +DbEnv.set_flags interface. +

Db.DB_TXN_SYNC
Synchronously flush the log. This means the transaction will exhibit +all of the ACID (atomicity, consistency and isolation and durability) +properties. +

This behavior is the default for Berkeley DB environments unless the +Db.DB_TXN_NOSYNC flag was specified to the DbEnv.set_flags +or DbEnv.txn_begin interfaces. +

+

Once the DbTxn.commit method returns, the DbTxn handle may not +be accessed again. If DbTxn.commit encounters an error, the +transaction and all child transactions of the transaction are aborted. +

The DbTxn.commit method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

The DbTxn.commit method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbTxn.commit method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Classes

+DbEnv, DbTxn +

See Also

+DbEnv.set_tx_max, +DbEnv.set_tx_timestamp, +DbTxn.abort, +DbEnv.txn_begin, +DbEnv.txn_checkpoint, +DbTxn.commit, +DbTxn.id, +DbTxn.prepare +and +DbEnv.txn_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/txn_id.html b/db/docs/api_java/txn_id.html new file mode 100644 index 000000000..89fc62a37 --- /dev/null +++ b/db/docs/api_java/txn_id.html @@ -0,0 +1,51 @@ + + + + + +Berkeley DB: DbTxn.id + + + + + + + +
+

DbTxn.id

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public int id() + throws DbException; +

+

Description

+

The DbTxn.id method returns the unique transaction id associated with the +specified transaction. Locking calls made on behalf of this transaction +should use the value returned from DbTxn.id as the locker parameter +to the DbEnv.lock_get or DbEnv.lock_vec calls. +

Classes

+DbEnv, DbTxn +

See Also

+DbEnv.set_tx_max, +DbEnv.set_tx_timestamp, +DbTxn.abort, +DbEnv.txn_begin, +DbEnv.txn_checkpoint, +DbTxn.commit, +DbTxn.id, +DbTxn.prepare +and +DbEnv.txn_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/txn_prepare.html b/db/docs/api_java/txn_prepare.html new file mode 100644 index 000000000..09feae726 --- /dev/null +++ b/db/docs/api_java/txn_prepare.html @@ -0,0 +1,65 @@ + + + + + +Berkeley DB: DbTxn.prepare + + + + + + + +
+

DbTxn.prepare

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public void prepare() + throws DbException; +

+

Description

+

The DbTxn.prepare method initiates the beginning of a two-phase commit. +

In a distributed transaction environment, Berkeley DB can be used as a local +transaction manager. In this case, the distributed transaction manager +must send prepare messages to each local manager. The local +manager must then issue a DbTxn.prepare and await its successful +return before responding to the distributed transaction manager. Only +after the distributed transaction manager receives successful responses +from all of its prepare messages should it issue any +commit messages. +

In the case of nested transactions, preparing a parent transaction +causes all unresolved children of the parent transaction to be prepared. +

The DbTxn.prepare method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

The DbTxn.prepare method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbTxn.prepare method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Classes

+DbEnv, DbTxn +

See Also

+DbEnv.set_tx_max, +DbEnv.set_tx_timestamp, +DbTxn.abort, +DbEnv.txn_begin, +DbEnv.txn_checkpoint, +DbTxn.commit, +DbTxn.id, +DbTxn.prepare +and +DbEnv.txn_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_java/txn_stat.html b/db/docs/api_java/txn_stat.html new file mode 100644 index 000000000..cb033ccde --- /dev/null +++ b/db/docs/api_java/txn_stat.html @@ -0,0 +1,95 @@ + + + + + +Berkeley DB: DbEnv.txn_stat + + + + + + + +
+

DbEnv.txn_stat

+
+APIRef +
+


+ +

+import com.sleepycat.db.*;
+

+public DbTxnStat txn_stat() + throws DbException; +

+

Description

+

The DbEnv.txn_stat method +creates a DbTxnStat object encapsulating a statistical structure. +The transaction region statistics are stored in a DbTxnStat object. +The following data fields are available from the DbTxnStat object: +

Statistical structures are created in allocated memory. If db_malloc is non-NULL, it +is called to allocate the memory, otherwise, the library function +malloc(3) is used. The function db_malloc must match +the calling conventions of the malloc(3) library routine. +Regardless, the caller is responsible for deallocating the returned +memory. To deallocate returned memory, free the returned memory +reference, references inside the returned memory do not need to be +individually freed. +

The transaction region statistics are stored in a structure of type +DB_TXN_STAT. The following DB_TXN_STAT fields will be filled in: +

+
public DbLsn st_last_ckp;
The LSN of the last checkpoint. +
public DbLsn st_pending_ckp;
The LSN of any checkpoint that is currently in progress. If +st_pending_ckp is the same as st_last_ckp there +is no checkpoint in progress. +
public long st_time_ckp;
The time the last completed checkpoint finished (as the number of seconds +since the Epoch, returned by the IEEE/ANSI Std 1003.1 (POSIX) time interface). +
public int st_last_txnid;
The last transaction ID allocated. +
public int st_maxtxns;
The maximum number of active transactions possible. +
public int st_nactive;
The number of transactions that are currently active. +
public int st_maxnactive;
The maximum number of active transactions at any one time. +
public int st_nbegins;
The number of transactions that have begun. +
public int st_naborts;
The number of transactions that have aborted. +
public int st_ncommits;
The number of transactions that have committed. +
public int st_regsize;
The size of the region. +
public int st_region_wait;
The number of times that a thread of control was forced to wait before +obtaining the region lock. +
public int st_region_nowait;
The number of times that a thread of control was able to obtain +the region lock without waiting. +
public Active st_txnarray[];
The array of active transactions. Each element of the array is an object +of type DbTxnStat.Active, a top level inner class, that has the following +fields: +

+

public int txnid;
The Transaction ID. +
public DbLsn lsn;
The Lsn of the begin record. +
+
+

The DbEnv.txn_stat method throws an exception that encapsulates a non-zero error value on +failure. +

Errors

+

The DbEnv.txn_stat method may fail and throw an exception for errors specified for other Berkeley DB and C library or system methods. +If a catastrophic error has occurred, the DbEnv.txn_stat method may fail and throw +a DbRunRecoveryException, in which case all subsequent Berkeley DB calls +will fail in the same way. +

Classes

+DbEnv, DbTxn +

See Also

+DbEnv.set_tx_max, +DbEnv.set_tx_timestamp, +DbTxn.abort, +DbEnv.txn_begin, +DbEnv.txn_checkpoint, +DbTxn.commit, +DbTxn.id, +DbTxn.prepare +and +DbEnv.txn_stat. +
+

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_tcl/db_close.html b/db/docs/api_tcl/db_close.html new file mode 100644 index 000000000..eaae31655 --- /dev/null +++ b/db/docs/api_tcl/db_close.html @@ -0,0 +1,59 @@ + + + + + + +Berkeley DB: db close + + + + + + + +
+

db close

+
+APIRef +
+


+ +

db close
+	[-nosync]
+

+

Description

+

The db close command flushes any cached database information to +disk, closes any open cursors, frees any allocated resources, and closes +any underlying files. Since key/data pairs are cached in memory, failing +to sync the file with the db close or db sync command may +result in inconsistent or lost information. +

The options are as follows: +

+

-nosync
Do not flush cached information to disk. +

The -nosync flag is a dangerous option. It should only be set if the +application is doing logging (with transactions) so that the database is +recoverable after a system or application crash, or if the database is +always generated from scratch after any system or application crash. +

It is important to understand that flushing cached information to disk +only minimizes the window of opportunity for corrupted data. While +unlikely, it is possible for database corruption to happen if a system or +application crash occurs while writing data to the database. To ensure +that database corruption never occurs, applications must either: use +transactions and logging with automatic recovery, use logging and +application-specific recovery, or edit a copy of the database, and, once +all applications using the database have successfully called +db close, atomically replace the original database with the updated +copy. +

+

Once db close has been called, regardless of its return, the DB +handle may not be accessed again. +

The db close command returns 0 on success, and in the case of error, a Tcl error +is thrown. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_tcl/db_count.html b/db/docs/api_tcl/db_count.html new file mode 100644 index 000000000..123c030cc --- /dev/null +++ b/db/docs/api_tcl/db_count.html @@ -0,0 +1,38 @@ + + + + + + +Berkeley DB: db count + + + + + + + +
+

db count

+
+APIRef +
+


+ +

db count key
+

+

Description

+

The db count command returns a count of the number +of duplicate data items for the key given. +If the key does not exist, a value of 0 is returned. +If there are no duplicates, or the database does not support +duplicates, but a key/data pair exists, a value of 1 is returned. +If an error occurs, a Berkeley DB error message is returned or a Tcl error is +thrown. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_tcl/db_cursor.html b/db/docs/api_tcl/db_cursor.html new file mode 100644 index 000000000..79187650d --- /dev/null +++ b/db/docs/api_tcl/db_cursor.html @@ -0,0 +1,42 @@ + + + + + + +Berkeley DB: db cursor + + + + + + + +
+

db cursor

+
+APIRef +
+


+ +

db cursor
+	[-txn txnid]
+

+

Description

+

The db cursor command creates a database cursor. The returned +cursor handle is bound to a Tcl command of the form dbN.cX, where +X is an integer starting at 0 (e.g., db0.c0 and db0.c1). It is through +this Tcl command that the script accesses the cursor methods. +

The options are as follows: +

+

-txn txnid
If the file is being accessed under transaction protection, the +txnid parameter is a transaction handle returned from env txn. +
+

In the case of error, a Tcl error is thrown. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_tcl/db_del.html b/db/docs/api_tcl/db_del.html new file mode 100644 index 000000000..b3340312a --- /dev/null +++ b/db/docs/api_tcl/db_del.html @@ -0,0 +1,47 @@ + + + + + + +Berkeley DB: db del + + + + + + + +
+

db del

+
+APIRef +
+


+ +

db del
+	[-glob]
+	[-txn txnid]
+	key
+

+

Description

+

The db del command removes key/data pairs from the database. +

In the presence of duplicate key values, all records associated with the +designated key will be discarded. +

The options are as follows: +

+

-glob
The specified key is a wildcard pattern, and all keys matching that +pattern are discarded from the database. The pattern is a simple +wildcard, any characters after the wildcard character are ignored. +

-txn txnid
If the file is being accessed under transaction protection, the +txnid parameter is a transaction handle returned from env txn. +
+

The db del command returns 0 on success, and in the case of error, a Tcl error +is thrown. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_tcl/db_get.html b/db/docs/api_tcl/db_get.html new file mode 100644 index 000000000..391f15652 --- /dev/null +++ b/db/docs/api_tcl/db_get.html @@ -0,0 +1,98 @@ + + + + + + +Berkeley DB: db get + + + + + + + +
+

db get

+
+APIRef +
+


+ +

db get
+	[-consume]
+	[-consume_wait]
+	[-glob]
+	[-partial {doff dlen}]
+	[-recno]
+	[-rmw]
+	[-txn txnid]
+	key
+db get
+	-get_both
+	[-partial {doff dlen}]
+	[-rmw]
+	[-txn txnid]
+	key data
+

+

Description

+

The db get command returns key/data pairs from the database. +

In the presence of duplicate key values, db get will return all +duplicate items. Duplicates are sorted by insert order except where this +order has been overridden by cursor operations. +

The options are as follows: +

+

-consume
Return the record number and data from the available record closest to +the head of the queue and delete the record. The cursor will be +positioned on the deleted record. A record is available if it is not +deleted and is not currently locked. The underlying database must be +of type Queue for -consume to be specified. +

-consume_wait
The same as the -consume flag except that if the Queue database +is empty, the thread of control will wait until there is data in the +queue before returning. The underlying database must be of type Queue +for -consume_wait to be specified. +

-get_both key data
Retrieve the key/data pair only if both the key and data match the +arguments. +

-glob
Return all keys matching the given key, where the key is a simple wildcard +pattern. Where it is used, it replaces the use of the key with the given +pattern of a set of keys. Any characters after the wildcard character +are ignored. For example, in a database of last names, the +command "db0 get Jones" will return all of the "Jones" in the database, +and the command "db0 get -glob Jo*" will return both "Jones" and "Johnson" +from the database. The command "db0 get -glob *" will return all of the +key/data pairs in the database. +

-partial {doff dlen}
The dlen bytes starting doff bytes from the beginning of +the retrieved data record are returned as if they comprised the entire +record. If any or all of the specified bytes do not exist in the record, +the command is successful and the existing bytes or 0 bytes are +returned. +

-recno
Retrieve the specified numbered key/data pair from a database. For +-recno to be specified, the specified key must be a record number +and the underlying database must be of type Recno or Queue, or of type +Btree that was created with the -recnum option. +

-rmw
Acquire write locks instead of read locks when doing the retrieval. +Setting this flag may decrease the likelihood of deadlock during a +read-modify-write cycle by immediately acquiring the write lock during +the read part of the cycle so that another thread of control acquiring a +read lock for the same item, in its own read-modify-write cycle, will not +result in deadlock. +

As the db get command will not hold locks across Berkeley DB interface +calls in non-transactional environments, the -rmw argument to the +db get call is only meaningful in the presence of transactions. +

-txn txnid
If the file is being accessed under transaction protection, the +txnid parameter is a transaction handle returned from env txn. +
+

If the underlying database is a Queue or Recno database, then the given +key will be interpreted by Tcl as an integer. For all other database +types, the key is interpreted by Tcl as a byte array unless indicated +by a given option. +

A list of key/data pairs is returned. In the error case that no matching +key exists, an empty list is returned. In all other cases, a Tcl error +is thrown. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_tcl/db_get_join.html b/db/docs/api_tcl/db_get_join.html new file mode 100644 index 000000000..e2ede7e47 --- /dev/null +++ b/db/docs/api_tcl/db_get_join.html @@ -0,0 +1,45 @@ + + + + + + +Berkeley DB: db get_join + + + + + + + +
+

db get_join

+
+APIRef +
+


+ +

db get_join
+	[-txn txnid]
+	{db key}
+	{db key}
+	...
+

+

Description

+

The db get_join command performs the cursor operations required to +join the specified keys and returns a list of joined {key data} pairs. +See Logical join for more information on +the underlying requirements for joining. +

The options are as follows: +

+

-txn txnid
If the file is being accessed under transaction protection, the +txnid parameter is a transaction handle returned from env txn. +
+

In the case of error, a Tcl error is thrown. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_tcl/db_get_type.html b/db/docs/api_tcl/db_get_type.html new file mode 100644 index 000000000..75fac1e78 --- /dev/null +++ b/db/docs/api_tcl/db_get_type.html @@ -0,0 +1,34 @@ + + + + + + +Berkeley DB: db get_type + + + + + + + +
+

db get_type

+
+APIRef +
+


+ +

db get_type
+

+

Description

+

The db get_type command returns the underlying database type, +returning one of "btree", "hash", "queue" or "recno". +

In the case of error, a Tcl error is thrown. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_tcl/db_is_byteswapped.html b/db/docs/api_tcl/db_is_byteswapped.html new file mode 100644 index 000000000..6a196eddf --- /dev/null +++ b/db/docs/api_tcl/db_is_byteswapped.html @@ -0,0 +1,37 @@ + + + + + + +Berkeley DB: db is_byteswapped + + + + + + + +
+

db is_byteswapped

+
+APIRef +
+


+ +

db is_byteswapped
+

+

Description

+

The db is_byteswapped command returns 0 if the underlying database +files were created on an architecture of the same byte order as the +current one, and 1 if they were not (i.e., big-endian on a little-endian +machine or vice-versa). This value may be used to determine if application +data needs to be adjusted for this architecture or not. +

In the case of error, a Tcl error is thrown. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_tcl/db_join.html b/db/docs/api_tcl/db_join.html new file mode 100644 index 000000000..ba3f0a2e5 --- /dev/null +++ b/db/docs/api_tcl/db_join.html @@ -0,0 +1,48 @@ + + + + + + +Berkeley DB: db join + + + + + + + +
+

db join

+
+APIRef +
+


+ +

db join
+	db.cX
+	db.cY
+	db.cZ
+	...
+

+

Description

+

The db join command joins the specified cursors and returns a +cursor handle that can be used to iterate through the joined {key data} +pairs. The returned cursor handle is bound to a Tcl command of the form +dbN.cX, where X is an integer starting at 0 (e.g., db0.c0 and +db0.c1). It is through this Tcl command that the script accesses the +cursor methods. +

The returned join cursor has limited cursor functionality and only the +dbc get and dbc close commands will succeed. +

See Logical join for more information on +the underlying requirements for joining. +

In a transaction protected environment, all of the cursors listed must +have been created within the same transaction. +

In the case of error, a Tcl error is thrown. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_tcl/db_open.html b/db/docs/api_tcl/db_open.html new file mode 100644 index 000000000..4f7b651e5 --- /dev/null +++ b/db/docs/api_tcl/db_open.html @@ -0,0 +1,300 @@ + + + + + + +Berkeley DB: berkdb open + + + + + + + +
+

berkdb open

+
+APIRef +
+


+ +

berkdb open
+	[-btree | -hash | -recno | -queue | -unknown]
+	[-cachesize {gbytes bytes ncache}]
+	[-create]
+	[-delim delim]
+	[-dup]
+	[-dupsort]
+	[-env env]
+	[-errfile filename]
+	[-excl]
+	[-extent size]
+	[-ffactor density]
+	[-len len]
+	[-mode mode]
+	[-nelem size]
+	[-pad pad]
+	[-pagesize pagesize]
+	[-rdonly]
+	[-recnum]
+	[-renumber]
+	[-snapshot]
+	[-source file]
+	[-truncate]
+	[-upgrade]
+	[--]
+	[file [database]]
+

+

Description

+

The berkdb open command opens, and optionally creates, a database. +The returned database handle is bound to a Tcl command of the form +dbN, where N is an integer starting at 0 (e.g., db0 and db1). +It is through this Tcl command that the script accesses the database +methods. +

The options are as follows: +

+

-btree
Open/create a database of type Btree. The Btree format +is a representation of a sorted, balanced tree structure. +

-hash
Open/create a database of type Hash. The Hash format is +an extensible, dynamic hashing scheme. +

-queue
Open/create a database of type Queue. The Queue format +supports fast access to fixed-length records accessed by sequentially or +logical record number. +

-recno
Open/create a database of type Recno. The Recno format +supports fixed- or variable-length records, accessed sequentially or by +logical record number, and optionally retrieved from a flat text file. +

-unknown
The database is of an unknown type, and must already exist. +

-cachesize {gbytes bytes ncache}
Set the size of the database's shared memory buffer pool, i.e., the cache, +to gbytes gigabytes plus bytes. The cache should be the +size of the normal working data set of the application, with some small +amount of additional memory for unusual situations. (Note, the working +set is not the same as the number of simultaneously referenced pages, and +should be quite a bit larger!) +

The default cache size is 256KB, and may not be specified as less than +20KB. Any cache size less than 500MB is automatically increased by 25% +to account for buffer pool overhead, cache sizes larger than 500MB are +used as specified. +

It is possible to specify caches to Berkeley DB that are large enough so that +they cannot be allocated contiguously on some architectures, e.g., some +releases of Solaris limit the amount of memory that may be allocated +contiguously by a process. If ncache is 0 or 1, the cache will +be allocated contiguously in memory. If it is greater than 1, the cache +will be broken up into ncache equally sized separate pieces of +memory. +

For information on tuning the Berkeley DB cache size, see +Selecting a cache size. +

As databases opened within Berkeley DB environments use the cache specified to +the environment, it is an error to attempt to set a cache in a database +created within an environment. +

-create
Create any underlying files, as necessary. If the files do not already +exist and the -create argument is not specified, the call will +fail. +

-delim delim
Set the delimiting byte used to mark the end of a record in the backing +source file for the Recno access method. +

This byte is used for variable length records, if the -source +argument file is specified. If the -source argument file is +specified and no delimiting byte was specified, <newline> +characters (i.e. ASCII 0x0a) are interpreted as end-of-record markers. +

-dup
Permit duplicate data items in the tree, i.e. insertion when the key of the +key/data pair being inserted already exists in the tree will be successful. +The ordering of duplicates in the tree is determined by the order of +insertion, unless the ordering is otherwise specified by use of a cursor or +a duplicate comparison function. +

It is an error to specify both -dup and -recnum. +

-dupsort
Sort duplicates within a set of data items. A default, lexical comparison +will be used. Specifying that duplicates are to be sorted changes the +behavior of the db put operation as well as the dbc put +operation when the -keyfirst, -keylast and +-current options are specified. +

-env env
If no -env argument is given, the database is standalone, i.e., +it is not part of any Berkeley DB environment. +

If a -env argument is given, the database is created within the +specified Berkeley DB environment. The database access methods automatically +make calls to the other subsystems in Berkeley DB based on the enclosing +environment. For example, if the environment has been configured to use +locking, then the access methods will automatically acquire the correct +locks when reading and writing pages of the database. +

-errfile filename
+

When an error occurs in the Berkeley DB library, a Berkeley DB error or an error +return value is returned by the function. In some cases, however, the +errno value may be insufficient to completely describe the cause of the +error especially during initial application debugging. +

The -errfile argument is used to enhance the mechanism for +reporting error messages to the application by specifying a file to be +used for displaying additional Berkeley DB error messages. In some cases, when +an error occurs, Berkeley DB will output an additional error message to the +specified file reference. +

The error message will consist of a Tcl command name and a colon (":"), +an error string, and a trailing <newline> character. If the +database was opened in an environment the Tcl command name will be the +environment name (e.g., env0), otherwise it will be the database command +name (e.g., db0). +

This error logging enhancement does not slow performance or significantly +increase application size, and may be run during normal operation as well +as during application debugging. +

For database handles opened inside of Berkeley DB environments, specifying the +-errfile argument affects the entire environment and is equivalent +to specifying the same argument to the berkdb env command. +

-excl
Return an error if the file already exists. Underlying filesystem +primitives are used to implement this flag. For this reason it is only +applicable to the physical database file and cannot be used to test if a +database in a file already exists. +

-extent size
Set the size of the extents of the Queue database, The size is specified +as the number of pages in an extent. +Each extent is created as a separate physical file. If no extent size +is set, the default behavior is to create only +a single underlying database file. +

For information on tuning the extent size, see +Selecting a extent size. +

-ffactor density
Set the desired density within the hash table. +

The density is an approximation of the number of keys allowed to +accumulate in any one bucket +

-len len
For the Queue access method, specify that the records are of length +len. +

For the Recno access method, specify that the records are fixed-length, +not byte delimited, and are of length len. +

Any records added to the database that are less than len bytes +long are automatically padded (see the -pad argument for more +information). +

Any attempt to insert records into the database that are greater than +len bytes long will cause the call to fail immediately and return +an error. +

-mode mode
+

On UNIX systems, or in IEEE/ANSI Std 1003.1 (POSIX) environments, all files created by the access methods +are created with mode mode (as described in chmod(2)) and +modified by the process' umask value at the time of creation (see +umask(2)). The group ownership of created files is based on +the system and directory defaults, and is not further specified by Berkeley DB. +If mode is 0, files are created readable and writeable by both +owner and group. On Windows systems, the mode argument is ignored. +

-nelem size
Set an estimate of the final size of the hash table. +

If not set or set too low, hash tables will still expand gracefully as +keys are entered, although a slight performance degradation may be +noticed. +

-pad pad
Set the padding character for short, fixed-length records for the Queue +and Recno access methods. +

If no pad character is specified, <space> characters (i.e., +ASCII 0x20) are used for padding. +

-pagesize pagesize
Set the size of the pages used to hold items in the database, in bytes. +The minimum page size is 512 bytes and the maximum page size is 64K bytes. +If the page size is not explicitly set, one is selected based on the +underlying filesystem I/O block size. The automatically selected size +has a lower limit of 512 bytes and an upper limit of 16K bytes. +

For information on tuning the Berkeley DB page size, see +Selecting a page size. +

-rdonly
Open the database for reading only. Any attempt to modify items in the +database will fail regardless of the actual permissions of any underlying +files. +

-recnum
Support retrieval from the Btree using record numbers. +

Logical record numbers in Btree databases are mutable in the face of +record insertion or deletion. See the -renumber argument for +further discussion. +

Maintaining record counts within a Btree introduces a serious point of +contention, namely the page locations where the record counts are stored. In +addition, the entire tree must be locked during both insertions and +deletions, effectively single-threading the tree for those operations. +Specifying -recnum can result in serious performance degradation +for some applications and data sets. +

It is an error to specify both -dup and -recnum. +

-renumber
Specifying the -renumber argument causes the logical record +numbers to be mutable, and change as records are added to and deleted from +the database. For example, the deletion of record number 4 causes records +numbered 5 and greater to be renumbered downward by 1. If a cursor was +positioned to record number 4 before the deletion, it will reference the +new record number 4, if any such record exists, after the deletion. If a +cursor was positioned after record number 4 before the deletion, it will +be shifted downward 1 logical record, continuing to reference the same +record as it did before. +

Using the db put or dbc put interfaces to create new records will +cause the creation of multiple records if the record number is more than one +greater than the largest record currently in the database. For example, +creating record 28, when record 25 was previously the last record in the +database, will create records 26 and 27 as well as 28. +

If a created record is not at the end of the database, all records following +the new record will be automatically renumbered upward by 1. For example, +the creation of a new record numbered 8 causes records numbered 8 and +greater to be renumbered upward by 1. If a cursor was positioned to record +number 8 or greater before the insertion, it will be shifted upward 1 +logical record, continuing to reference the same record as it did before. +

For these reasons, concurrent access to a Recno database with the +-renumber flag specified may be largely meaningless, although it +is supported. +

-snapshot
This argument specifies that any specified -source file be read +in its entirety when the database is opened. If this argument is not +specified, the -source file may be read lazily. +

-source file
Set the underlying source file for the Recno access method. The purpose +of the -source file is to provide fast access and modification +to databases that are normally stored as flat text files. +

If the -source argument is give, it specifies an underlying flat +text database file that is read to initialize a transient record number +index. In the case of variable length records, the records are separated +as specified by -delim. For example, standard UNIX byte stream +files can be interpreted as a sequence of variable length records +separated by <newline> characters. +

In addition, when cached data would normally be written back to the +underlying database file (e.g., the db close or db sync +commands are called), the in-memory copy of the database will be written +back to the -source file. +

By default, the backing source file is read lazily, i.e., records are not +read from the file until they are requested by the application. +If multiple processes (not threads) are accessing a Recno database +concurrently and either inserting or deleting records, the backing source +file must be read in its entirety before more than a single process +accesses the database, and only that process should specify the backing +source argument as part of the berkdb open call. See the -snapshot +argument for more information. +

Reading and writing the backing source file specified by -source +cannot be transactionally protected because it involves filesystem +operations that are not part of the Berkeley DB transaction methodology. +For this reason, if a temporary database is used to hold the records, +i.e., no file argument was specified to the berkdb open call, +it is possible to lose the contents of the -file file, e.g., if +the system crashes at the right instant. If a file is used to hold the +database, i.e., a file name was specified as the file argument +to berkdb open, normal database recovery on that file can be used to +prevent information loss, although it is still possible that the contents +of -source will be lost if the system crashes. +

The -source file must already exist (but may be zero-length) when +berkdb open is called. +

It is not an error to specify a read-only -source file when +creating a database, nor is it an error to modify the resulting database. +However, any attempt to write the changes to the backing source file using +either the db close or db sync commands will fail, of course. +Specify the -nosync argument to the db close command will +stop it from attempting to write the changes to the backing file, instead, +they will be silently discarded. +

For all of the above reasons, the -source file is generally used +to specify databases that are read-only for Berkeley DB applications, and that +are either generated on the fly by software tools, or modified using a +different mechanism, e.g., a text editor. +

-truncate
Physically truncate the underlying file, discarding all previous databases +it might have held. Underlying filesystem primitives are used to +implement this flag. For this reason it is only applicable to the +physical file and cannot be used to discard databases within a file. +

The -truncate argument cannot be transaction protected, and it is +an error to specify it in a transaction protected environment. +

-upgrade
Upgrade the database represented by file, if necessary. +

Note: Database upgrades are done in place and are +destructive, e.g., if pages need to be allocated and no disk space is +available, the database may be left corrupted. Backups should be made +before databases are upgraded. See Upgrading databases for more information. +

--
Mark the end of the command arguments. +

file
The name of a single physical file on disk that will be used to back the +database. +

database
The database argument allows applications to have multiple +databases inside of a single physical file. This is useful when the +databases are both numerous and reasonably small, in order to avoid +creating a large number of underlying files. It is an error to attempt +to open a second database file that was not initially created using a +database name. +
+

The berkdb open command returns a database handle on success. +

In the case of error, a Tcl error is thrown. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_tcl/db_put.html b/db/docs/api_tcl/db_put.html new file mode 100644 index 000000000..2311a3c97 --- /dev/null +++ b/db/docs/api_tcl/db_put.html @@ -0,0 +1,74 @@ + + + + + + +Berkeley DB: db put + + + + + + + +
+

db put

+
+APIRef +
+


+ +

db put
+	-append
+	[-partial {doff dlen}]
+	[-txn txnid]
+	data
+db put
+	[-nooverwrite]
+	[-partial {doff dlen}]
+	[-txn txnid]
+	key data
+

+

Description

+

The db put command stores the specified key/data pair into the +database. +

The options are as follows: +

+

-append
Append the data item to the end of the database. For the -append +option to be specified, the underlying database must be a Queue or Recno +database. The record number allocated to the record is returned on +success. +

-nooverwrite
Enter the new key/data pair only if the key does not already appear in +the database. +

-partial {doff dlen}
+

The dlen bytes starting doff bytes from the beginning of +the specified key's data record are replaced by the data specified by the +data and size structure elements. If dlen is smaller than the +length of the supplied data, the record will grow, and if dlen is +larger than the length of the supplied data, the record will shrink. If +the specified bytes do not exist, the record will be extended using nul +bytes as necessary, and the db put call will succeed. +

It is an error to attempt a partial put using the db put command in a database +that supports duplicate records. Partial puts in databases supporting +duplicate records must be done using a dbc put command. +

It is an error to attempt a partial put with differing dlen and +supplied data length values in Queue or Recno databases with fixed-length +records. +

-txn txnid
If the file is being accessed under transaction protection, the +txnid parameter is a transaction handle returned from env txn. +
+

The db put command returns either 0 or a record number for success +(the record number is returned if the -append option was specified). +If an error occurs, a Berkeley DB error message is returned or a Tcl error is +thrown. +

If the underlying database is a Queue or Recno database, then the given +key will be interpreted by Tcl as an integer. For all other database +types, the key is interpreted by Tcl as a byte array. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_tcl/db_remove.html b/db/docs/api_tcl/db_remove.html new file mode 100644 index 000000000..e45f3bc49 --- /dev/null +++ b/db/docs/api_tcl/db_remove.html @@ -0,0 +1,49 @@ + + + + + + +Berkeley DB: berkdb dbremove + + + + + + + +
+

berkdb dbremove

+
+APIRef +
+


+ +

berkdb dbremove
+	[-env env]
+	[--]
+	file
+	[database]
+

+

Description

+

Remove the Berkeley DB database specified by the database name file and +[database] name arguments. If no database is specified, +the physical file represented by file is removed, incidentally +removing all databases that it contained. +

No reference count of database use is maintained by Berkeley DB. Applications +should not remove databases that are currently in use. +

The options are as follows: +

+

-env env
If a -env argument is given, the database in the specified Berkeley DB +environment is removed. +

--
Mark the end of the command arguments. +
+

The berkdb dbremove command returns 0 on success, and in the case of error, a Tcl error +is thrown. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_tcl/db_rename.html b/db/docs/api_tcl/db_rename.html new file mode 100644 index 000000000..75707d92a --- /dev/null +++ b/db/docs/api_tcl/db_rename.html @@ -0,0 +1,50 @@ + + + + + + +Berkeley DB: berkdb dbrename + + + + + + + +
+

berkdb dbrename

+
+APIRef +
+


+ +

berkdb rename
+	[-env env]
+	[--]
+	file
+	[database
+	newname]
+

+

Description

+

Renames the Berkeley DB database specified by the database name file and +[database] name arguments to the new name given. +If no database is specified, +the physical file represented by file is renamed. +

No reference count of database use is maintained by Berkeley DB. Applications +should not rename databases that are currently in use. +

The options are as follows: +

+

-env env
If a -env argument is given, the database in the specified Berkeley DB +environment is renamed. +

--
Mark the end of the command arguments. +
+

The berkdb dbrename command returns 0 on success, and in the case of error, a Tcl error +is thrown. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_tcl/db_stat.html b/db/docs/api_tcl/db_stat.html new file mode 100644 index 000000000..494226dfd --- /dev/null +++ b/db/docs/api_tcl/db_stat.html @@ -0,0 +1,41 @@ + + + + + + +Berkeley DB: db stat + + + + + + + +
+

db stat

+
+APIRef +
+


+ +

db stat
+	[-recordcount]
+

+

Description

+

The db stat command returns a list of name/value pairs comprising +the statistics of the database. +

The options are as follows: +

+

-recordcount
Return the number of records in the database. The -recordcount +option may only be specified for Recno databases, or Btree databases where +the underlying database was created with the -recnum option. +
+

In the case of error, a Tcl error is thrown. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_tcl/db_sync.html b/db/docs/api_tcl/db_sync.html new file mode 100644 index 000000000..f0e61b45a --- /dev/null +++ b/db/docs/api_tcl/db_sync.html @@ -0,0 +1,36 @@ + + + + + + +Berkeley DB: db sync + + + + + + + +
+

db sync

+
+APIRef +
+


+ +

db sync
+

+

Description

+

The db sync command function flushes any database cached +information to disk. +

See db close for a discussion of Berkeley DB and cached data. +

The db sync command returns 0 on success, and in the case of error, a Tcl error +is thrown. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_tcl/dbc_close.html b/db/docs/api_tcl/dbc_close.html new file mode 100644 index 000000000..f3a63b4c5 --- /dev/null +++ b/db/docs/api_tcl/dbc_close.html @@ -0,0 +1,36 @@ + + + + + + +Berkeley DB: db close + + + + + + + +
+

dbc close

+
+APIRef +
+


+ +

dbc close
+

+

Description

+

The dbc close command discards the cursor. +

Once dbc close has been called, regardless of its return, the +cursor handle may not be used again. +

The dbc close command returns 0 on success, and in the case of error, a Tcl error +is thrown. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_tcl/dbc_del.html b/db/docs/api_tcl/dbc_del.html new file mode 100644 index 000000000..11264eeea --- /dev/null +++ b/db/docs/api_tcl/dbc_del.html @@ -0,0 +1,38 @@ + + + + + + +Berkeley DB: db del + + + + + + + +
+

dbc del

+
+APIRef +
+


+ +

dbc del
+

+

Description

+

The dbc del command deletes the key/data pair currently referenced +by the cursor. +

The cursor position is unchanged after a delete, and subsequent calls to +cursor commands expecting the cursor to reference an existing key will +fail. +

The dbc del command returns 0 on success, and in the case of error, a Tcl error +is thrown. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_tcl/dbc_dup.html b/db/docs/api_tcl/dbc_dup.html new file mode 100644 index 000000000..85b2bfb08 --- /dev/null +++ b/db/docs/api_tcl/dbc_dup.html @@ -0,0 +1,46 @@ + + + + + + +Berkeley DB: db dup + + + + + + + +
+

dbc dup

+
+APIRef +
+


+ +

dbc dup
+	[-position]
+

+

Description

+

The dbc dup command duplicates the cursor, creates a new cursor +that uses the same transaction and locker ID as the original cursor. This +is useful when an application is using locking and requires two or more +cursors in the same thread of control. +

The options are as follows: +

+

-position
The newly created cursor is initialized to reference the same position in +the database as the original cursor and hold the same locks. If the +-position flag is not specified, then the created cursor is +uninitialized and will behave like a cursor newly created using the +db cursor command. +
+

The dbc dup command returns 0 on success, and in the case of error, a Tcl error +is thrown. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_tcl/dbc_get.html b/db/docs/api_tcl/dbc_get.html new file mode 100644 index 000000000..d16e51bdf --- /dev/null +++ b/db/docs/api_tcl/dbc_get.html @@ -0,0 +1,168 @@ + + + + + + +Berkeley DB: db get + + + + + + + +
+

dbc get

+
+APIRef +
+


+ +

dbc get
+	[-current]
+	[-first]
+	[-get_recno]
+	[-join_item]
+	[-last]
+	[-next]
+	[-nextdup]
+	[-nextnodup]
+	[-partial {offset length}]
+	[-prev]
+	[-prevnodup]
+	[-rmw]
+dbc get
+	[-partial {offset length}]
+	[-rmw]
+	[-set]
+	[-set_range]
+	[-set_recno]
+	key
+dbc get
+	-get_both
+	[-partial {offset length}]
+	[-rmw]
+	key data
+

+

Description

+

The dbc get command returns a list of {key value} pairs, except in +the case of the -get_recno and -join_item options. In +the case of the -get_recno option, dbc get returns a list +of the record number. In the case of the -join_item option, +dbc get returns a list containing the joined key. +

The options are as follows: +

+

-current
Return the key/data pair currently referenced by the cursor. +

If the cursor key/data pair was deleted, dbc get will return an +empty list. +

-first
The cursor is set to reference the first key/data pair of the database, and +that pair is returned. In the presence of duplicate key values, the first +data item in the set of duplicates is returned. +

If the database is a Queue or Recno database, dbc get using the +-first option will skip any keys that exist but were never +explicitly created by the application or were created and later deleted. +

If the database is empty, dbc get will return an empty list. +

-last
The cursor is set to reference the last key/data pair of the database, and +that pair is returned. In the presence of duplicate key values, the last +data item in the set of duplicates is returned. +

If the database is a Queue or Recno database, dbc get using the +-last option will skip any keys that exist but were never +explicitly created by the application or were created and later deleted. +

If the database is empty, dbc get will return an empty list. +

-next
If the cursor is not yet initialized, the -next option is +identical to -first. +

Otherwise, the cursor is moved to the next key/data pair of the database, +and that pair is returned. In the presence of duplicate key values, the +value of the key may not change. +

If the database is a Queue or Recno database, dbc get using the +-next option will skip any keys that exist but were never +explicitly created by the application or were created and later deleted. +

If the cursor is already on the last record in the database, dbc get +will return an empty list. +

-nextdup
If the next key/data pair of the database is a duplicate record for the +current key/data pair, the cursor is moved to the next key/data pair of the +database, and that pair is returned. Otherwise, dbc get will return +an empty list. +

-nextnodup
If the cursor is not yet initialized, the -nextnodup option is +identical to -first. +

Otherwise, the cursor is moved to the next non-duplicate +key/data pair of the database, and that pair is returned. +

If no non-duplicate key/data pairs occur after the cursor +position in the database, dbc get will return an empty list. +

-prev
If the cursor is not yet initialized, -prev is identical to +-last. +

Otherwise, the cursor is moved to the previous key/data pair of the +database, and that pair is returned. In the presence of duplicate key +values, the value of the key may not change. +

If the database is a Queue or Recno database, dbc get using the +-prev flag will skip any keys that exist but were never explicitly +created by the application or were created and later deleted. +

If the cursor is already on the first record in the database, +dbc get will return an empty list. +

-prevnodup
If the cursor is not yet initialized, the -prevnodup option is +identical to -last. +

Otherwise, the cursor is moved to the previous non-duplicate +key/data pair of the database, and that pair is returned. +

If no non-duplicate key/data pairs occur before the cursor +position in the database, dbc get will return an empty list. +

-set
Move the cursor to the specified key/data pair of the database, and return +the datum associated with the given key. +

In the presence of duplicate key values, dbc get will return the +first data item for the given key. +

If the database is a Queue or Recno database and the requested key exists, +but was never explicitly created by the application or was later deleted, +dbc get will return an empty list. +

If no matching keys are found, dbc get will return an empty list. +

-set_range
The -set_range option is identical to the -set option, +except that the key is returned as well as the data item, and, in the case +of the Btree access method, the returned key/data pair is the smallest +key greater than or equal to the specified key (as determined by the +comparison function), permitting partial key matches and range searches. +

-get_both
The -get_both option is identical to the -set option, +except that both the key and the data arguments must be matched by the +key and data item in the database. +

For -get_both to be specified, the underlying database must be of +type Btree or Hash. +

-set_recno
Move the cursor to the specific numbered record of the database, and +return the associated key/data pair. The key +must be a record number. +

For the -set_recno option to be specified, the underlying database +must be of type Btree and it must have been created with the -recnum +option. +

-get_recno
Return a list of the record number associated with the current cursor +position. No key argument should be specified. +

For -get_recno to be specified, the underlying database must be +of type Btree and it must have been created with the -recnum +option. +

-join_item
Do not use the data value found in all of the cursors as a lookup key for +the primary database, but simply return it in the key parameter instead. +The data parameter is left unchanged. +

For -join_item to be specified, the cursor must have been created +by the db join command. +

-partial {offset length}
The dlen bytes starting doff bytes from the beginning of +the retrieved data record are returned as if they comprised the entire +record. If any or all of the specified bytes do not exist in the record, +the command is successful and the existing bytes or 0 bytes are +returned. +

-rmw
Acquire write locks instead of read locks when doing the retrieval. Setting +this flag may decrease the likelihood of deadlock during a read-modify-write +cycle by immediately acquiring the write lock during the read part of the +cycle so that another thread of control acquiring a read lock for the same +item, in its own read-modify-write cycle, will not result in deadlock. +
+

If a key is specified, and +if the underlying database is a Queue or Recno database, then the given +key will be interpreted by Tcl as an integer. For all other database +types, the key is interpreted by Tcl as a byte array unless indicated +by a given option. +

In the normal error case of attempting to retrieve a key that does not +exist an empty list is returned. +

In the case of error, a Tcl error is thrown. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_tcl/dbc_put.html b/db/docs/api_tcl/dbc_put.html new file mode 100644 index 000000000..bd791ab94 --- /dev/null +++ b/db/docs/api_tcl/dbc_put.html @@ -0,0 +1,133 @@ + + + + + + +Berkeley DB: dbc put + + + + + + + +
+

dbc put

+
+APIRef +
+


+ +

dbc put
+	[-after]
+	[-before]
+	[-current]
+	[-partial {doff dlen}]
+	data
+dbc put
+	[-keyfirst]
+	[-keylast]
+	[-partial {doff dlen}]
+	key data
+

+

Description

+

The dbc put command stores the specified key/data pair into the +database. +

The options are as follows: +

+

-after
In the case of the Btree and Hash access methods, insert the data element +as a duplicate element of the key referenced by the cursor. The new +element appears immediately after the current cursor position. It is an +error to specify -after if the underlying Btree or Hash database +was not created with the -dup option. No key argument should be +specified. +

In the case of the Recno access method, it is an error to specify +-after option if the underlying Recno database was not created +with the -renumber option. If the -renumber option was +specified, a new key is created, all records after the inserted item are +automatically renumbered, and the key of the new record is returned in +the structure referenced by the parameter key. The initial value of the +key parameter is ignored. See berkdb open for more information. +

In the case of the Queue access method, it is always an error to specify +-after. +

If the current cursor record has already been deleted and the underlying +access method is Hash, dbc put will throw a Tcl error. If the +underlying access method is Btree or Recno, the operation will succeed. +

-before
In the case of the Btree and Hash access methods, insert the data element +as a duplicate element of the key referenced by the cursor. The new +element appears immediately before the current cursor position. It is an +error to specify -before if the underlying Btree or Hash database +was not created with the -dup option. No key argument should be +specified. +

In the case of the Recno access method, it is an error to specify +-before if the underlying Recno database was not created with the +-before option. If the -before option was specified, a +new key is created, the current record and all records after it are +automatically renumbered, and the key of the new record is returned in +the structure referenced by the parameter key. The initial value of the +key parameter is ignored. See berkdb open for more information. +

In the case of the Queue access method, it is always an error to specify +-before. +

If the current cursor record has already been deleted and the underlying +access method is Hash, dbc put will throw a Tcl error. If the +underlying access method is Btree or Recno, the operation will succeed. +

-current
Overwrite the data of the key/data pair referenced by the cursor with the +specified data item. No key argument should be specified. +

If the -dupsort option was specified to berkdb open and the +data item of the current referenced key/data pair does not compare +equally to the data parameter, dbc put will throw a Tcl error. +

If the current cursor record has already been deleted and the underlying +access method is Hash, dbc put will throw a Tcl error. If the +underlying access method is Btree, Queue or Recno, the operation will +succeed. +

-keyfirst
In the case of the Btree and Hash access methods, insert the specified +key/data pair into the database. +

If the key already exists in the database, and the -dupsort option +was specified to berkdb open, the inserted data item is added in its +sorted location. If the key already exists in the database, and the +-dupsort option was not specified, the inserted data item is added +as the first of the data items for that key. +

The -keyfirst option may not be specified to the Queue or Recno +access methods. +

-keylast
In the case of the Btree and Hash access methods, insert the specified +key/data pair into the database. +

If the key already exists in the database, and the -dupsort option +was specified to berkdb open, the inserted data item is added in its +sorted location. If the key already exists in the database, and the +-dupsort option was not specified, the inserted data item is added +as the last of the data items for that key. +

The -keylast option may not be specified to the Queue or Recno +access methods. +

-partial {doff dlen}
+

The dlen bytes starting doff bytes from the beginning of +the specified key's data record are replaced by the data specified by the +data and size structure elements. If dlen is smaller than the +length of the supplied data, the record will grow, and if dlen is +larger than the length of the supplied data, the record will shrink. If +the specified bytes do not exist, the record will be extended using nul +bytes as necessary, and the dbc put call will succeed. +

It is an error to attempt a partial put using the dbc put command in a database +that supports duplicate records. Partial puts in databases supporting +duplicate records must be done using a dbc put command. +

It is an error to attempt a partial put with differing dlen and +supplied data length values in Queue or Recno databases with fixed-length +records. +

+

If a key is specified, and +if the underlying database is a Queue or Recno database, then the given +key will be interpreted by Tcl as an integer. For all other database +types, the key is interpreted by Tcl as a byte array. +

If dbc put fails for any reason, the state of the cursor will be +unchanged. If dbc put succeeds and an item is inserted into the +database, the cursor is always positioned to reference the newly inserted +item. +

The dbc put command returns 0 on success, and in the case of error, a Tcl error +is thrown. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_tcl/env_close.html b/db/docs/api_tcl/env_close.html new file mode 100644 index 000000000..719ad2160 --- /dev/null +++ b/db/docs/api_tcl/env_close.html @@ -0,0 +1,42 @@ + + + + + + +Berkeley DB: env close + + + + + + + +
+

env close

+
+APIRef +
+


+ +

env close
+

+

Description

+

Close the Berkeley DB environment, freeing any allocated resources and closing +any underlying subsystems. +

This does not imply closing any databases that were opened in the +environment. +

Where the environment was initialized with the -lock option, +calling env close does not release any locks still held by the +closing process, providing functionality for long-lived locks. +

Once env close has been called the env handle may not be +accessed again. +

The env close command returns 0 on success, and in the case of error, a Tcl error +is thrown. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_tcl/env_open.html b/db/docs/api_tcl/env_open.html new file mode 100644 index 000000000..1c5bafee4 --- /dev/null +++ b/db/docs/api_tcl/env_open.html @@ -0,0 +1,168 @@ + + + + + + +Berkeley DB: berkdb env + + + + + + + +
+

berkdb env

+
+APIRef +
+


+ +

berkdb env
+	[-cachesize {gbytes bytes ncache}]
+	[-create]
+	[-data_dir dirname]
+	[-errfile filename]
+	[-home directory]
+	[-log_dir dirname]
+	[-mode mode]
+	[-private]
+	[-recover]
+	[-recover_fatal]
+	[-shm_key shmid]
+	[-system_mem]
+	[-tmp_dir dirname]
+	[-txn [nosync]]
+	[-txn_max max]
+	[-use_environ]
+	[-use_environ_root]
+

+

Description

+

The berkdb env command opens, and optionally creates, a database +environment. The returned environment handle is bound to a Tcl command +of the form envN, where N is an integer starting at 0 (e.g., env0 +and env1). It is through this Tcl command that the script accesses the +environment methods. +The command automatically initializes the shared memory buffer pool subsystem. +This subsystem is used whenever the application is +using any Berkeley DB access method. +

The options are as follows: +

+

-cachesize {gbytes bytes ncache}
Set the size of the database's shared memory buffer pool, i.e., the cache, +to gbytes gigabytes plus bytes. The cache should be the +size of the normal working data set of the application, with some small +amount of additional memory for unusual situations. (Note, the working +set is not the same as the number of simultaneously referenced pages, and +should be quite a bit larger!) +

The default cache size is 256KB, and may not be specified as less than +20KB. Any cache size less than 500MB is automatically increased by 25% +to account for buffer pool overhead, cache sizes larger than 500MB are +used as specified. +

It is possible to specify caches to Berkeley DB that are large enough so that +they cannot be allocated contiguously on some architectures, e.g., some +releases of Solaris limit the amount of memory that may be allocated +contiguously by a process. If ncache is 0 or 1, the cache will +be allocated contiguously in memory. If it is greater than 1, the cache +will be broken up into ncache equally sized separate pieces of +memory. +

For information on tuning the Berkeley DB cache size, see +Selecting a cache size. +

-create
Cause Berkeley DB subsystems to create any underlying files, as necessary. +

-data_dir dirname
Specify the environment's data directory as described in +Berkeley DB File Naming. +

-errfile filename
+

When an error occurs in the Berkeley DB library, a Berkeley DB error or an error +return value is returned by the function. In some cases, however, the +errno value may be insufficient to completely describe the cause of the +error especially during initial application debugging. +

The -errfile argument is used to enhance the mechanism for +reporting error messages to the application by specifying a file to be +used for displaying additional Berkeley DB error messages. In some cases, when +an error occurs, Berkeley DB will output an additional error message to the +specified file reference. +

The error message will consist of the environment command name (e.g., env0) +and a colon (":"), an error string, and a trailing <newline> +character. +

This error logging enhancement does not slow performance or significantly +increase application size, and may be run during normal operation as well +as during application debugging. +

-home directory
The -home argument is described in +Berkeley DB File Naming. +

-log_dir dirname
Specify the environment's logging file directory as described in +Berkeley DB File Naming. +

-mode mode
+

On UNIX systems, or in IEEE/ANSI Std 1003.1 (POSIX) environments, all files created by Berkeley DB +are created with mode mode (as described in chmod(2)) and +modified by the process' umask value at the time of creation (see +umask(2)). The group ownership of created files is based on +the system and directory defaults, and is not further specified by Berkeley DB. +If mode is 0, files are created readable and writeable by both +owner and group. On Windows systems, the mode argument is ignored. +

-private
Specify that the environment will only be accessed by a single process +(although that process may be multi-threaded). This flag has two effects +on the Berkeley DB environment. First, all underlying data structures are +allocated from per-process memory instead of from shared memory that is +potentially accessible to more than a single process. Second, mutexes +are only configured to work between threads. +

This flag should not be specified if more than a single process is +accessing the environment, as it is likely to cause database corruption +and unpredictable behavior, e.g., if both a server application and the +Berkeley DB utility db_stat will access the environment, the +-private option should not be specified. +

-recover
Run normal recovery on this environment before opening it for normal use. +If this flag is set, the -create option must also be set since +the regions will be removed and recreated. +

-recover_fatal
Run catastrophic recovery on this environment before opening it for +normal use. If this flag is set, the -create option must also be +set since the regions will be removed and recreated. +

-shm_key key
Specify a base segment ID for Berkeley DB environment shared memory regions +created in system memory on systems supporting X/Open-style shared memory +interfaces, e.g., UNIX systems supporting shmget(2) and related System V +IPC interfaces. See Shared Memory +Regions for more information. +

-system_mem
Allocate memory from system shared memory instead of memory backed by the +filesystem. See Shared Memory Regions +for more information. +

-tmp_dir dirname
Specify the environment's tmp directory as described in +Berkeley DB File Naming. +

-txn [nosync]
Initialize the transaction subsystem. This subsystem is used when +recovery and atomicity of multiple operations and recovery are important. +The -txn option implies the initialization of the logging +and locking subsystems as well. +

If the optional nosync argument is specified, the log will not be +synchronously flushed on transaction commit or prepare. This means that +transactions exhibit the ACI (atomicity, consistency and isolation) +properties, but not D (durability), i.e., database integrity will be +maintained but it is possible that some number of the most recently +committed transactions may be undone during recovery instead of being +redone. +

The number of transactions that are potentially at risk is governed by +how often the log is checkpointed (see db_checkpoint for more +information) and how many log updates can fit on a single log page. +

-txn_max max
Set the maximum number of simultaneous transactions that are supported +by the environment. This bounds the size of backing files. When there +are more than the specified number of concurrent transactions, calls to +env txn will fail (until some active transactions complete). +

-use_environ
The Berkeley DB process' environment may be permitted to specify information to +be used when naming files; see Berkeley DB +File Naming. As permitting users to specify which files are used can +create security problems, environment information will be used in file +naming for all users only if the -use_environ flag is set. +

-use_environ_root
The Berkeley DB process' environment may be permitted to specify information +to be used when naming files; see Berkeley DB +File Naming. As permitting users to specify which files are used can +create security problems, if the -use_environ_root flag is set, +environment information will be used for file naming only for users with +appropriate permissions (e.g., on IEEE/ANSI Std 1003.1 (POSIX) systems, users with a +user-ID of 0). +
+

The berkdb env command returns an environment handle on success. +

In the case of error, a Tcl error is thrown. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_tcl/env_remove.html b/db/docs/api_tcl/env_remove.html new file mode 100644 index 000000000..ca90595f8 --- /dev/null +++ b/db/docs/api_tcl/env_remove.html @@ -0,0 +1,70 @@ + + + + + + +Berkeley DB: berkdb envremove + + + + + + + +
+

berkdb envremove

+
+APIRef +
+


+ +

berkdb envremove
+	[-data_dir directory]
+	[-force]
+	[-home directory]
+	[-log_dir directory]
+	[-tmp_dir directory]
+	[-use_environ]
+	[-use_environ_root]
+

+

Description

+

Remove a Berkeley DB environment. +

The options are as follows: +

+

-data_dir dirname
Specify the environment's data directory as described in +Berkeley DB File Naming. +

-force
If there are processes that have called berkdb env without calling +env close (i.e., there are processes currently using the +environment), berkdb envremove will fail without further action, unless +the -force flag is set, in which case berkdb envremove will +attempt to remove the environment regardless of any processes still using +it. +

-home directory
The -home argument is described in +Berkeley DB File Naming. +

-log_dir dirname
Specify the environment's log directory as described in +Berkeley DB File Naming. +

-tmp_dir dirname
Specify the environment's tmp directory as described in +Berkeley DB File Naming. +

-use_environ
The Berkeley DB process' environment may be permitted to specify information to +be used when naming files; see Berkeley DB +File Naming. As permitting users to specify which files are used can +create security problems, environment information will be used in file +naming for all users only if the -use_environ flag is set. +

-use_environ_root
The Berkeley DB process' environment may be permitted to specify information +to be used when naming files; see Berkeley DB +File Naming. As permitting users to specify which files are used can +create security problems, if the -use_environ_root flag is set, +environment information will be used for file naming only for users with +appropriate permissions (e.g., on IEEE/ANSI Std 1003.1 (POSIX) systems, users with a +user-ID of 0). +
+

The berkdb envremove command returns 0 on success, and in the case of error, a Tcl error +is thrown. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_tcl/pindex.src b/db/docs/api_tcl/pindex.src new file mode 100644 index 000000000..668f53d25 --- /dev/null +++ b/db/docs/api_tcl/pindex.src @@ -0,0 +1,27 @@ +__APIREL__/api_tcl/db_close.html#2 @db close +__APIREL__/api_tcl/db_count.html#2 @db count +__APIREL__/api_tcl/db_cursor.html#2 @db cursor +__APIREL__/api_tcl/db_del.html#2 @db del +__APIREL__/api_tcl/db_get.html#2 @db get +__APIREL__/api_tcl/db_get_join.html#2 @db get_join +__APIREL__/api_tcl/db_get_type.html#2 @db get_type +__APIREL__/api_tcl/db_is_byteswapped.html#2 @db is_byteswapped +__APIREL__/api_tcl/db_join.html#2 @db join +__APIREL__/api_tcl/db_open.html#2 @berkdb open +__APIREL__/api_tcl/db_put.html#2 @db put +__APIREL__/api_tcl/db_rename.html#2 @berkdb dbrename +__APIREL__/api_tcl/db_remove.html#2 @berkdb dbremove +__APIREL__/api_tcl/db_stat.html#2 @db stat +__APIREL__/api_tcl/db_sync.html#2 @db sync +__APIREL__/api_tcl/dbc_close.html#2 @db close +__APIREL__/api_tcl/dbc_del.html#2 @db del +__APIREL__/api_tcl/dbc_dup.html#2 @db dup +__APIREL__/api_tcl/dbc_get.html#2 @db get +__APIREL__/api_tcl/dbc_put.html#2 @dbc put +__APIREL__/api_tcl/env_close.html#2 @env close +__APIREL__/api_tcl/env_open.html#2 @berkdb env +__APIREL__/api_tcl/env_remove.html#2 @berkdb envremove +__APIREL__/api_tcl/txn.html#2 @env txn +__APIREL__/api_tcl/txn_abort.html#2 @txn abort +__APIREL__/api_tcl/txn_commit.html#2 @txn commit +__APIREL__/api_tcl/version.html#2 @berkdb version diff --git a/db/docs/api_tcl/tcl_index.html b/db/docs/api_tcl/tcl_index.html new file mode 100644 index 000000000..a31c6fc82 --- /dev/null +++ b/db/docs/api_tcl/tcl_index.html @@ -0,0 +1,49 @@ + + + + + +Berkeley DB: Tcl Interface + + + + +

Tcl Interface

+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Tcl CommandDescription
berkdb dbremoveRemove a database
berkdb dbrenameRename a database
berkdb envCreate an environment handle
berkdb envremoveRemove an environment
berkdb openCreate a database handle
berkdb versionReturn version information


env closeClose an environment
env txnBegin a transaction


db closeClose a database
db countReturn a count of a key's data items
db cursorOpen a cursor into a database
db delDelete items from a database
db getGet items from a database
db get_joinGet items from a database join
db get_typeReturn the database type
db is_byteswappedReturn if the underlying database is in host order
db joinPerform a database join on cursors
db putStore items into a database
db statReturn database statistics
db syncFlush a database to stable storage


dbc closeClose a cursor
dbc delDelete by cursor
dbc dupDuplicate a cursor
dbc getRetrieve by cursor
dbc putStore by cursor


txn abortAbort a transaction
txn commitCommit a transaction
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_tcl/tcl_pindex.html b/db/docs/api_tcl/tcl_pindex.html new file mode 100644 index 000000000..c82153bad --- /dev/null +++ b/db/docs/api_tcl/tcl_pindex.html @@ -0,0 +1,258 @@ + + +Berkeley DB: Tcl Interface Index + + + + +

Tcl Interface Index

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
configuring Berkeley DB 1.85 API compatibility
building a utility to dump Berkeley DB 1.85 databases
Upgrading to release 2.0
Upgrading to release 3.0
Upgrading to release 3.1
Upgrading to release 3.2
selecting an access method
access methods
AIX
programmatic APIs
utility to archive log files
berkdb dbremove
berkdb dbrename
berkdb env
berkdb envremove
berkdb open
berkdb version
berkeley_db_svc
building for UNIX
building for UNIX FAQ
building for VxWorks
building for VxWorks FAQ
building for Win32
building for Windows FAQ
selecting a byte order
byte ordering
configuring the C++ API
flushing the database cache
selecting a cache size
catastrophic recovery
Patches, Updates and Change logs
utility to take checkpoints
closing a cursor
closing a database
specifying a Btree comparison function
changing compile or load options
Concurrent Data Store
configuring Berkeley DB for UNIX systems
recovering corrupted databases
counting data items for a key
closing a cursor
deleting records with a cursor
duplicating a cursor
retrieving records with a cursor
storing records with a cursor
cursor stability
database cursors
utility to upgrade database files
utility to verify database files
db close
db close
db count
db cursor
db del
db del
db dup
db get
db get
db get_join
db get_type
db is_byteswapped
db join
db put
db stat
db sync
db_archive
dbc put
db_checkpoint
File namingDB_CONFIG
db_deadlock
db_dump
File namingDB_HOME
File namingdb_home
Error returns to applicationsDB_KEYEMPTY
db_load
Error returns to applicationsDB_LOCK_DEADLOCK
Error returns to applicationsDB_LOCK_NOTGRANTED
Error returns to applicationsDB_NOTFOUND
db_printlog
db_recover
Error returns to applicationsDB_RUNRECOVERY
db_stat
db_upgrade
db_verify
deadlocks
utility to detect deadlocks
debugging applications
deleting records
deleting records with a cursor
Configuring Berkeley DB--disable-bigfile
disk space requirements
utility to dump databases as text files
duplicate data items
duplicating a cursor
configuring dynamic shared libraries
Configuring Berkeley DB--enable-compat185
Configuring Berkeley DB--enable-cxx
Configuring Berkeley DB--enable-debug
Configuring Berkeley DB--enable-debug_rop
Configuring Berkeley DB--enable-debug_wop
Configuring Berkeley DB--enable-diagnostic
Configuring Berkeley DB--enable-dump185
Configuring Berkeley DB--enable-dynamic
Configuring Berkeley DB--enable-java
Configuring Berkeley DB--enable-posixmutexes
Configuring Berkeley DB--enable-rpc
Configuring Berkeley DB--enable-shared
Configuring Berkeley DB--enable-tcl
Configuring Berkeley DB--enable-test
Configuring Berkeley DB--enable-uimutexes
Configuring Berkeley DB--enable-umrw
byte endian
env close
env txn
database environment
environment variables
error handling
error name space
error returns
/etc/magic
selecting a Queue extent size
Java FAQ
Tcl FAQ
configuring without large file support
file utility
recovery and filesystem operations
remote filesystems
page fill factor
FreeBSD
Berkeley DB free-threaded handles
specifying a database hash
hash table size
HP-UX
installing Berkeley DB for UNIX systems
interface compatibility
IRIX
configuring the Java API
Java compatibility
Java configuration
Java FAQ
logical join
database limits
Linux
changing compile or load options
utility to load text files into databases
standard lock modes
page-level locking
two-phase locking
locking and non-Berkeley DB applications
locking configuration
locking conventions
Berkeley DB Concurrent Data Store locking conventions
locking introduction
sizing the locking subsystem
locking without transactions
log file limits
log file removal
utility to display log files as text
logging configuration
logging introduction
memory pool configuration
Berkeley DB library name spaces
file naming
retrieving Btree records by number
opening a database
OSF/1
selecting a page size
partial record storage and retrieval
Patches, Updates and Change logs
Perl
Sleepycat Software's Berkeley DB products
QNX
logical record numbers
managing record-based databases
logically renumbering records
utility to recover database environments
Berkeley DB recoverability
retrieving records
retrieving records with a cursor
RPC client
configuring a RPC client/server
utility to support RPC client/server
RPC server
database salvage
SCO
Berkeley DB handle scope
security
Sendmail
configuring shared libraries
shared libraries
application signal handling
Sleepycat Software
Solaris
source code layout
cursor stability
database statistics
utility to display database and environment statistics
storing records
storing records with a cursor
SunOS
loading Berkeley DB with Tcl
using Berkeley DB with Tcl
configuring the Tcl API
Tcl API programming notes
Tcl FAQ
configuring the test suite
running the test suite
running the test suite under UNIX
running the test suite under Windows
text backing files
loading text into databases
dumping/loading text to/from databases
building threaded applications
transaction configuration
transaction limits
administering transaction protected applications
archival in transaction protected applications
checkpoints in transaction protected applications
deadlock detection in transaction protected applications
recovery in transaction protected applications
transaction throughput
Transactional Data Store
Berkeley DB and transactions
nested transactions
configuring Berkeley DB with the Tuxedo System
txn abort
txn commit
Ultrix
building for UNIX FAQ
configuring Berkeley DB for UNIX systems
Patches, Updates and Change logs
utility to upgrade database files
upgrading databases
utilities
database verification
utility to verify database files
building for VxWorks FAQ
VxWorks notes
running the test suite under Windows
building for Windows FAQ
Windows notes
Configuring Berkeley DB--with-tcl=DIR
XA Resource Manager
+
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_tcl/txn.html b/db/docs/api_tcl/txn.html new file mode 100644 index 000000000..4e66a96a6 --- /dev/null +++ b/db/docs/api_tcl/txn.html @@ -0,0 +1,62 @@ + + + + + + +Berkeley DB: env txn + + + + + + + +
+

env txn

+
+APIRef +
+


+ +

env txn
+	[-nosync]
+	[-nowait]
+	[-parent txnid]
+	[-sync]
+

+

Description

+

The env txn command begins a transaction. The returned transaction +handle is bound to a Tcl command of the form env.txnX, where X +is an integer starting at 0 (e.g., env0.txn0 and env0.txn1). It is +through this Tcl command that the script accesses the transaction methods. +

The options are as follows: +

+

-nosync
Do not synchronously flush the log when this transaction commits or +prepares. This means the transaction will exhibit the ACI (atomicity, +consistency and isolation) properties, but not D (durability), i.e., +database integrity will be maintained but it is possible that this +transaction may be undone during recovery instead of being redone. +

This behavior may be set for an entire Berkeley DB environment as part of +the berkdb env interface. +

-nowait
If a lock is unavailable for any Berkeley DB operation performed in the context +of this transaction, throw a Tcl error immediately instead of blocking on +the lock. +

-parent txnid
Create the new transaction as a nested transaction, with the specified +transaction indicated as its parent. Transactions may be nested to any +level. +

-sync
Synchronously flush the log when this transaction commits or prepares. This +means the transaction will exhibit all of the ACID (atomicity, consistency +and isolation and durability) properties. +

This behavior is the default for Berkeley DB environments unless the +-nosync option was specified to the berkdb env interface. +

+

The env txn command returns a transaction handle on success. +

In the case of error, a Tcl error is thrown. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_tcl/txn_abort.html b/db/docs/api_tcl/txn_abort.html new file mode 100644 index 000000000..8b147883f --- /dev/null +++ b/db/docs/api_tcl/txn_abort.html @@ -0,0 +1,45 @@ + + + + + + +Berkeley DB: txn abort + + + + + + + +
+

txn abort

+
+APIRef +
+


+ +

txn abort
+

+

Description

+

The txn abort command causes an abnormal termination of the +transaction. +

The log is played backwards and any necessary recovery operations are +performed. After recovery is completed, all locks held by the +transaction are acquired by the parent transaction in the case of a +nested transaction or released in the case of a non-nested transaction. +As is the case for txn commit, applications that require strict +two-phase locking should not explicitly release any locks. +

In the case of nested transactions, aborting the parent transaction +causes all children of that transaction to be aborted. +

Once txn abort has been called, regardless of its return, the +txn handle may not be accessed again. +

The txn abort command returns 0 on success, and in the case of error, a Tcl error +is thrown. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_tcl/txn_commit.html b/db/docs/api_tcl/txn_commit.html new file mode 100644 index 000000000..acd1f2d1b --- /dev/null +++ b/db/docs/api_tcl/txn_commit.html @@ -0,0 +1,68 @@ + + + + + + +Berkeley DB: txn commit + + + + + + + +
+

txn commit

+
+APIRef +
+


+ +

txn commit
+	[-nosync]
+	[-sync]
+

+

Description

+

The txn commit command ends the transaction. +

In the case of nested transactions, if the transaction is a parent +transaction with unresolved (neither committed or aborted) child +transactions, the child transactions are aborted and the commit of the +parent will succeed. +

In the case of nested transactions, if the transaction is a child +transaction, its locks are not released, but are acquired by its parent. +While the commit of the child transaction will succeed, the actual +resolution of the child transaction is postponed until the parent +transaction is committed or aborted, i.e., if its parent transaction +commits, it will be committed, and if its parent transaction aborts, it +will be aborted. +

If the -nosync option is not specified, a commit log record is +written and flushed to disk, as are all previously written log records. +

The options are as follows: +

+

-nosync
Do not synchronously flush the log. This means the transaction will +exhibit the ACI (atomicity, consistency and isolation) properties, but +not D (durability), i.e., database integrity will be maintained but it is +possible that this transaction may be undone during recovery instead of +being redone. +

This behavior may be set for an entire Berkeley DB environment as part of +the berkdb env interface. +

-sync
Synchronously flush the log. This means the transaction will exhibit all of +the ACID (atomicity, consistency and isolation and durability) properties. +

This behavior is the default for Berkeley DB environments unless the +-nosync option was specified to the berkdb env or +env txn interfaces. +

+

Once txn commit has been called, regardless of its return, the +txn handle may not be accessed again. If txn commit +encounters an error, then this transaction and all child transactions +of this transaction are aborted. +

The txn commit command returns 0 on success, and in the case of error, a Tcl error +is thrown. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/api_tcl/version.html b/db/docs/api_tcl/version.html new file mode 100644 index 000000000..ab4b901f1 --- /dev/null +++ b/db/docs/api_tcl/version.html @@ -0,0 +1,39 @@ + + + + + + +Berkeley DB: berkdb version + + + + + + + +
+

berkdb version

+
+APIRef +
+


+ +

berkdb version
+	[-string]
+

+

Description

+

Return a list of the form {major minor patch} for the major, minor and +patch levels of the underlying Berkeley DB release. +

The options are as follows: +

+

-string
Return a string with formatted Berkeley DB version information. +
+

In the case of error, a Tcl error is thrown. + +

+APIRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/images/api.gif b/db/docs/images/api.gif new file mode 100644 index 000000000..dafd5772a Binary files /dev/null and b/db/docs/images/api.gif differ diff --git a/db/docs/images/next.gif b/db/docs/images/next.gif new file mode 100644 index 000000000..667ee061a Binary files /dev/null and b/db/docs/images/next.gif differ diff --git a/db/docs/images/prev.gif b/db/docs/images/prev.gif new file mode 100644 index 000000000..11dfc5256 Binary files /dev/null and b/db/docs/images/prev.gif differ diff --git a/db/docs/images/ps.gif b/db/docs/images/ps.gif new file mode 100644 index 000000000..0f565bc1d Binary files /dev/null and b/db/docs/images/ps.gif differ diff --git a/db/docs/images/ref.gif b/db/docs/images/ref.gif new file mode 100644 index 000000000..75be9c1f3 Binary files /dev/null and b/db/docs/images/ref.gif differ diff --git a/db/docs/images/sleepycat.gif b/db/docs/images/sleepycat.gif new file mode 100644 index 000000000..5e768f74f Binary files /dev/null and b/db/docs/images/sleepycat.gif differ diff --git a/db/docs/index.html b/db/docs/index.html new file mode 100644 index 000000000..ad638e776 --- /dev/null +++ b/db/docs/index.html @@ -0,0 +1,75 @@ + + + +Berkeley DB (Version: 3.2.9) + + + +

+Sleepycat Software Inc. +

+... the embedded database companytm + +


+


+

Berkeley DB

+ +

+ + + + + + + + + + + + + + +
Interface DocumentationBuilding Berkeley DB
+ C API
+ C API Index
+

+ C++ API
+ C++ API Index
+

+ Java API
+ Java API Index
+

+ Tcl API
+

+ Building for UNIX and QNX systems
+

+ Building for Win32 platforms
+

+ Building for VxWorks platforms
+

+ Upgrading Applications to the 3.2 release
+

Additional DocumentationCompany and Product Information
+ Supporting Utilities
+

+ Programmer's Tutorial and Reference Guide
+

+ Contacting Sleepycat Software
+ Commercial Product List
+ License
+ Release Patches and Change Logs
+ Sleepycat Software Home Page
+
+ +

+

+Version 3.2.9, January 24, 2001
+Copyright 1997-2000 Sleepycat Software, Inc. All Rights Reserved +
+ +


+


+


+

Legal Notices
+ + + diff --git a/db/docs/ref/am/close.html b/db/docs/ref/am/close.html new file mode 100644 index 000000000..04b8beacb --- /dev/null +++ b/db/docs/ref/am/close.html @@ -0,0 +1,43 @@ + + + + + +Berkeley DB Reference Guide: Closing a database + + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

Closing a database

+

The DB->close function is the standard interface for closing the database. +By default, DB->close also flushes all modified records from the +database cache to disk. +

There is one flag that you can set to customize DB->close: +

+

DB_NOSYNC
Do not flush cached information to disk. +
+It is important to understand that flushing cached information +to disk only minimizes the window of opportunity for corrupted data, it +does not eliminate the possibility. +

While unlikely, it is possible for database corruption to happen if a +system or application crash occurs while writing data to the database. To +ensure that database corruption never occurs, applications must either: +

    +
  • Use transactions and logging with automatic recovery. +
  • Use logging and application-specific recovery. +
  • Edit a copy of the database, and, once all applications +using the database have successfully called DB->close, use +system operations (e.g., the POSIX rename system call) to atomically +replace the original database with the updated copy. +
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am/count.html b/db/docs/ref/am/count.html new file mode 100644 index 000000000..92282641b --- /dev/null +++ b/db/docs/ref/am/count.html @@ -0,0 +1,28 @@ + + + + + +Berkeley DB Reference Guide: Data item count + + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

Data item count

+

Once a cursor has been initialized to reference a particular key in the +database, it can be used to determine the number of data items that are +stored for any particular key. The DBcursor->c_count method returns +this number of data items. The returned value is always one, unless +the database supports duplicate data items, in which case it may be any +number of items. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am/curclose.html b/db/docs/ref/am/curclose.html new file mode 100644 index 000000000..52ccfeb8c --- /dev/null +++ b/db/docs/ref/am/curclose.html @@ -0,0 +1,28 @@ + + + + + +Berkeley DB Reference Guide: Closing a cursor + + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

Closing a cursor

+

The DBcursor->c_close function is the standard interface for closing a cursor, +after which the cursor may no longer be used. Although cursors are +implicitly closed when the database they point to are closed, it is good +programming practice to explicitly close cursors. In addition, in +transactional systems, cursors may not exist outside of a transaction and +so must be explicitly closed. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am/curdel.html b/db/docs/ref/am/curdel.html new file mode 100644 index 000000000..b0fe8f957 --- /dev/null +++ b/db/docs/ref/am/curdel.html @@ -0,0 +1,26 @@ + + + + + +Berkeley DB Reference Guide: Deleting records with a cursor + + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

Deleting records with a cursor

+

The DBcursor->c_del function is the standard interface for deleting records from +the database using a cursor. The DBcursor->c_del function deletes the record +currently referenced by the cursor. In all cases, the cursor position is +unchanged after a delete. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am/curdup.html b/db/docs/ref/am/curdup.html new file mode 100644 index 000000000..6c609b2e5 --- /dev/null +++ b/db/docs/ref/am/curdup.html @@ -0,0 +1,34 @@ + + + + + +Berkeley DB Reference Guide: Duplicating a cursor + + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

Duplicating a cursor

+

Once a cursor has been initialized (e.g., by a call to DBcursor->c_get), +it can be thought of as identifying a particular location in a database. +The DBcursor->c_dup function permits an application to create a new cursor that +has the same locking and transactional information as the cursor from +which it is copied, and which optionally refers to the same position in +the database. +

In order to maintain a cursor position when an application is using +locking, locks are maintained on behalf of the cursor until the cursor is +closed. In cases when an application is using locking without +transactions, cursor duplication is often required to avoid +self-deadlocks. For further details, refer to +Access method locking conventions. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am/curget.html b/db/docs/ref/am/curget.html new file mode 100644 index 000000000..129fa272b --- /dev/null +++ b/db/docs/ref/am/curget.html @@ -0,0 +1,74 @@ + + + + + +Berkeley DB Reference Guide: Retrieving records with a cursor + + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

Retrieving records with a cursor

+

The DBcursor->c_get function is the standard interface for retrieving records from +the database with a cursor. The DBcursor->c_get function takes a flag which +controls how the cursor is positioned within the database and returns the +key/data item associated with that positioning. Similar to +DB->get, DBcursor->c_get may also take a supplied key and retrieve +the data associated with that key from the database. There are several +flags that you can set to customize retrieval. +

Cursor position flags

+

+

DB_FIRST, DB_LAST
Return the first (last) record in the database. +

DB_NEXT, DB_PREV
Return the next (previous) record in the database. +

DB_NEXT_DUP
Return the next record in the database, if it is a duplicate data item +for the current key. +

DB_NEXT_NODUP, DB_PREV_NODUP
Return the next (previous) record in the database that is not a +duplicate data item for the current key. +

DB_CURRENT
Return the record from the database currently referenced by the +cursor. +
+

Retrieving specific key/data pairs

+

+

DB_SET
Return the record from the database that matches the supplied key. In +the case of duplicates the first duplicate is returned and the cursor +is positioned at the beginning of the duplicate list. The user can then +traverse the duplicate entries for the key. +

DB_SET_RANGE
Return the smallest record in the database greater than or equal to the +supplied key. This functionality permits partial key matches and range +searches in the Btree access method. +

DB_GET_BOTH
Return the record from the database that matches both the supplied key +and data items. This is particularly useful when there are large +numbers of duplicate records for a key, as it allows the cursor to +easily be positioned at the correct place for traversal of some part of +a large set of duplicate records. +
+

Retrieving based on record numbers

+

+

DB_SET_RECNO
If the underlying database is a Btree, and was configured so that it is +possible to search it by logical record number, retrieve a specific +record based on a record number argument. +

DB_GET_RECNO
If the underlying database is a Btree, and was configured so that it is +possible to search it by logical record number, return the record number +for the record referenced by the cursor. +
+

Special-purpose flags

+

+

DB_CONSUME
Read-and-delete: the first record (the head) of the queue is returned and +deleted. The underlying database must be a Queue. +

DB_RMW
Read-modify-write: acquire write locks instead of read locks during +retrieval. This can enhance performance in threaded applications by +reducing the chance of deadlock. +
+

In all cases, the cursor is repositioned by a DBcursor->c_get operation +to point to the newly-returned key/data pair in the database. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am/curput.html b/db/docs/ref/am/curput.html new file mode 100644 index 000000000..0d5ef2725 --- /dev/null +++ b/db/docs/ref/am/curput.html @@ -0,0 +1,40 @@ + + + + + +Berkeley DB Reference Guide: Storing records with a cursor + + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

Storing records with a cursor

+

The DBcursor->c_put function is the standard interface for storing records into +the database with a cursor. In general, DBcursor->c_put takes a key and +inserts the associated data into the database, at a location controlled +by a specified flag. +

There are several flags that you can set to customize storage: +

+

DB_AFTER
Create a new record, immediately after the record currently referenced by +the cursor. +

DB_BEFORE
Create a new record, immediately before the record currently referenced by +the cursor. +

DB_CURRENT
Replace the data part of the record currently referenced by the cursor. +

DB_KEYFIRST
Create a new record as the first of the duplicate records for the +supplied key. +

DB_KEYLAST
Create a new record, as the last of the duplicate records for the supplied +key. +
+

In all cases, the cursor is repositioned by a DBcursor->c_put operation +to point to the newly inserted key/data pair in the database. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am/cursor.html b/db/docs/ref/am/cursor.html new file mode 100644 index 000000000..529285b4a --- /dev/null +++ b/db/docs/ref/am/cursor.html @@ -0,0 +1,41 @@ + + + + + +Berkeley DB Reference Guide: Database cursors + + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

Database cursors

+

A database cursor is a reference to a single key/data pair in the +database. It supports traversal of the database and is the only way to +access individual duplicate data items. Cursors are used for operating +on collections of records, for iterating over a database, and for saving +handles to individual records, so that they can be modified after they +have been read. +

The DB->cursor function is the standard interface for opening a cursor +into a database. Upon return the cursor is uninitialized, positioning +occurs as part of the first cursor operation. +

Once a database cursor has been opened, there are a set of access method +operations that can be performed. Each of these operations is performed +using a method referenced from the returned cursor handle. +

+
DBcursor->c_close
Close the cursor +
DBcursor->c_del
Delete a record +
DBcursor->c_dup
Duplicate a cursor +
DBcursor->c_get
Retrieve a record +
DBcursor->c_put
Store a record +
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am/delete.html b/db/docs/ref/am/delete.html new file mode 100644 index 000000000..8ab612fa4 --- /dev/null +++ b/db/docs/ref/am/delete.html @@ -0,0 +1,28 @@ + + + + + +Berkeley DB Reference Guide: Deleting records + + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

Deleting records

+

The DB->del function is the standard interface for deleting records from +the database. In general, DB->del takes a key and deletes the +data item associated with it from the database. +

If the database has been configured to support duplicate records, the +DB->del function will remove all of the duplicate records. To remove +individual duplicate records, you must use a Berkeley DB cursor interface. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am/error.html b/db/docs/ref/am/error.html new file mode 100644 index 000000000..737e6d662 --- /dev/null +++ b/db/docs/ref/am/error.html @@ -0,0 +1,61 @@ + + + + + +Berkeley DB Reference Guide: Error support + + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

Error support

+

Berkeley DB offers programmatic support for displaying error return values. +

The db_strerror interface returns a pointer to the error +message corresponding to any Berkeley DB error return, similar to the ANSI C +strerror interface, but is able to handle both system error returns and +Berkeley DB specific return values. +

For example: +

int ret;
+if ((ret = dbp->put(dbp, NULL, &key, &data, 0)) != 0) {
+	fprintf(stderr, "put failed: %s\n", db_strerror(ret));
+	return (1);
+}
+
+

There are also two additional error interfaces, DB->err and +DB->errx. These interfaces work like the ANSI C X3.159-1989 (ANSI C) printf +interface, taking a printf-style format string and argument list, and +writing a message constructed from the format string and arguments. +

The DB->err function appends the standard error string to the constructed +message, the DB->errx function does not. These interfaces provide simpler +ways of displaying Berkeley DB error messages. For example, if your application +tracks session IDs in a variable called session_id, it can include that +information in its error messages: +

Error messages can additionally be configured to always include a prefix +(e.g., the program name) using the DB->set_errpfx interface. +

#define DATABASE "access.db"
+int ret;
+dbp->errpfx(dbp, argv0);
+if ((ret =
+	dbp->open(dbp, DATABASE, DB_BTREE, DB_CREATE, 0664)) != 0) {
+	dbp->err(dbp, ret, "%s", DATABASE);
+	dbp->errx(dbp,
+		"contact your system administrator: session ID was %d",
+    		session_id);
+	return (1);
+}
+
+

For example, if the program was called my_app, and the open call returned +an EACCESS system error, the error messages shown would appear as follows: +

my_app: access.db: Permission denied.
+my_app: contact your system administrator: session ID was 14
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am/get.html b/db/docs/ref/am/get.html new file mode 100644 index 000000000..fda7a8eb2 --- /dev/null +++ b/db/docs/ref/am/get.html @@ -0,0 +1,39 @@ + + + + + +Berkeley DB Reference Guide: Retrieving records + + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

Retrieving records

+

The DB->get function is the standard interface for retrieving records from +the database. In general, DB->get takes a key and returns the +associated data from the database. +

There are a few flags that you can set to customize retrieval: +

+

DB_GET_BOTH
Search for a matching key and data item, i.e., only return success if both +the key and the data items match those stored in the database. +

DB_RMW
Read-modify-write: acquire write locks instead of read locks during +retrieval. This can enhance performance in threaded applications by +reducing the chance of deadlock. +

DB_SET_RECNO
If the underlying database is a Btree, and was configured so that it +is possible to search it by logical record number, retrieve a specific +record. +
+

If the database has been configured to support duplicate records, +DB->get will always return the first data item in the duplicate +set. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am/join.html b/db/docs/ref/am/join.html new file mode 100644 index 000000000..9d4dcdd09 --- /dev/null +++ b/db/docs/ref/am/join.html @@ -0,0 +1,184 @@ + + + + + +Berkeley DB Reference Guide: Logical join + + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

Logical join

+

A logical join is a method of retrieving data from a primary database +using criteria stored in a set of secondary indexes. A logical join +requires that your data be organized as a primary database which +contains the primary key and primary data field, and a set of secondary +indexes. Each of the secondary indexes is indexed by a different +secondary key, and, for each key in a secondary index, there is a set +of duplicate data items that match the primary keys in the primary +database. +

For example, let's assume the need for an application that will return +the names of stores in which one can buy fruit of a given color. We +would first construct a primary database that lists types of fruit as +the key item, and the store where you can buy them as the data item: +

Primary key:		Primary data:
+apple		Convenience Store
+blueberry	Farmer's Market
+peach		Shopway
+pear		Farmer's Market
+raspberry	Shopway
+strawberry	Farmer's Market
+

We would then create a secondary index with the key color, and, +as the data items, the names of fruits of different colors. +

Secondary key:		Secondary data:
+blue		blueberry
+red		apple
+red		raspberry
+red		strawberry
+yellow		peach
+yellow		pear
+

This secondary index would allow an application to look up a color, and +then use the data items to look up the stores where the colored fruit +could be purchased. For example, by first looking up blue, +the data item blueberry could be used as the lookup key in the +primary database, returning Farmer's Market. +

Your data must be organized in the following manner in order to use the +DB->join function: +

    +

  1. The actual data should be stored in the database represented by the +DB object used to invoke this function. Generally, this +DB object is called the primary. +

  2. Secondary indexes should be stored in separate databases, whose keys +are the values of the secondary indexes and whose data items are the +primary keys corresponding to the records having the designated +secondary key value. It is acceptable (and expected) that there may be +duplicate entries in the secondary indexes. +

    These duplicate entries should be sorted for performance reasons, although +it is not required. For more information see the DB_DUPSORT flag +to the DB->set_flags function. +

+

What the DB->join function does is review a list of secondary keys, and, +when it finds a data item that appears as a data item for all of the +secondary keys, it uses that data items as a lookup into the primary +database, and returns the associated data item. +

If there were a another secondary index that had as its key the +cost of the fruit, a similar lookup could be done on stores +where inexpensive fruit could be purchased: +

Secondary key:		Secondary data:
+expensive	blueberry
+expensive	peach
+expensive	pear
+expensive	strawberry
+inexpensive	apple
+inexpensive	pear
+inexpensive	raspberry
+

The DB->join function provides logical join functionality. While not +strictly cursor functionality, in that it is not a method off a cursor +handle, it is more closely related to the cursor operations than to the +standard DB operations. +

It is also possible to do lookups based on multiple criteria in a single +operation, e.g., it is possible to look up fruits that are both red and +expensive in a single operation. If the same fruit appeared as a data +item in both the color and expense indexes, then that fruit name would +be used as the key for retrieval from the primary index, and would then +return the store where expensive, red fruit could be purchased. +

Example

+

Consider the following three databases: +

+

personnel
    +
  • key = SSN +
  • data = record containing name, address, phone number, job title +
+

lastname
    +
  • key = lastname +
  • data = SSN +
+

jobs
    +
  • key = job title +
  • data = SSN +
+
+

Consider the following query: +

Return the personnel records of all people named smith with the job
+title manager.
+

This query finds are all the records in the primary database (personnel) +for whom the criteria lastname=smith and job title=manager is +true. +

Assume that all databases have been properly opened and have the handles: +pers_db, name_db, job_db. We also assume that we have an active +transaction referenced by the handle txn. +

DBC *name_curs, *job_curs, *join_curs;
+DBC *carray[3];
+DBT key, data;
+int ret, tret;
+

+name_curs = NULL; +job_curs = NULL; +memset(&key, 0, sizeof(key)); +memset(&data, 0, sizeof(data)); +

+if ((ret = + name_db->cursor(name_db, txn, &name_curs)) != 0) + goto err; +key.data = "smith"; +key.size = sizeof("smith"); +if ((ret = + name_curs->c_get(name_curs, &key, &data, DB_SET)) != 0) + goto err; +

+if ((ret = job_db->cursor(job_db, txn, &job_curs)) != 0) + goto err; +key.data = "manager"; +key.size = sizeof("manager"); +if ((ret = + job_curs->c_get(job_curs, &key, &data, DB_SET)) != 0) + goto err; +

+carray[0] = name_curs; +carray[1] = job_curs; +carray[2] = NULL; +

+if ((ret = + pers_db->join(pers_db, carray, &join_curs, 0)) != 0) + goto err; +while ((ret = + join_curs->c_get(join_curs, &key, &data, 0)) == 0) { + /* Process record returned in key/data. */ +} +

+/* + * If we exited the loop because we ran out of records, + * then it has completed successfully. + */ +if (ret == DB_NOTFOUND) + ret = 0; +

+err: +if (join_curs != NULL && + (tret = join_curs->c_close(join_curs)) != 0 && ret == 0) + ret = tret; +if (name_curs != NULL && + (tret = name_curs->c_close(name_curs)) != 0 && ret == 0) + ret = tret; +if (job_curs != NULL && + (tret = job_curs->c_close(job_curs)) != 0 && ret == 0) + ret = tret; +

+return (ret); +

+

The name cursor is positioned at the beginning of the duplicate list +for smith and the job cursor is placed at the beginning of +the duplicate list for manager. The join cursor is returned +from the logical join call. This code then loops over the join cursor +getting the personnel records of each one until there are no more. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am/open.html b/db/docs/ref/am/open.html new file mode 100644 index 000000000..01c45339e --- /dev/null +++ b/db/docs/ref/am/open.html @@ -0,0 +1,47 @@ + + + + + +Berkeley DB Reference Guide: Opening a database + + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

Opening a database

+

The DB->open function is the standard interface for opening a database, +and takes five arguments: +

+

file
The name of the file to be opened. +

database
An optional database name. +

type
The type of database to open. This value will be one of the four access +methods Berkeley DB supports: DB_BTREE, DB_HASH, DB_QUEUE or DB_RECNO, or the +special value DB_UNKNOWN, which allows you to open an existing file +without knowing its type. +

mode
The permissions to give to any created file. +
+

There are a few flags that you can set to customize open: +

+

DB_CREATE
Create the underlying database and any necessary physical files. +

DB_NOMMAP
Do not map this database into process memory. +

DB_RDONLY
Treat the data base as readonly. +

DB_THREAD
The returned handle is free-threaded, that is, it can be used +simultaneously by multiple threads within the process. +

DB_TRUNCATE
Physically truncate the underlying database file, discarding all +databases it contained. Underlying filesystem primitives are used to +implement this flag. For this reason it is only applicable to the +physical file and cannot be used to discard individual databases from +within physical files. +

DB_UPGRADE
Upgrade the database format as necessary. +
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am/opensub.html b/db/docs/ref/am/opensub.html new file mode 100644 index 000000000..066ca4b79 --- /dev/null +++ b/db/docs/ref/am/opensub.html @@ -0,0 +1,64 @@ + + + + + +Berkeley DB Reference Guide: Opening multiple databases in a single file + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

Opening multiple databases in a single file

+

Applications may create multiple databases within a single physical +file. This is useful when the databases are both numerous and +reasonably small, in order to avoid creating a large number of +underlying files, or when it is desirable to include secondary index +databases in the same file as the primary index database. Multiple +databases are an administrative convenience and using them is unlikely +to effect database performance. To open or create a file that will +include more than a single database, specify a database name when +calling the DB->open method. +

Physical files do not need to be comprised of a single type of database, +and databases in a file may be of any type (e.g., Btree, Hash or Recno), +except for Queue databases. Queue databases must be created one per file +and cannot share a file with any other database type. There is no limit +on the number of databases that may be created in a single file other than +the standard Berkeley DB file size and disk space limitations. +

It is an error to attempt to open a second database in a file that was +not initially created using a database name, that is, the file must +initially be specified as capable of containing multiple databases for a +second database to be created in it. +

It is not an error to open a file that contains multiple databases without +specifying a database name, however the database type should be specified +as DB_UNKNOWN and the database must be opened read-only. The handle that +is returned from such a call is a handle on a database whose key values +are the names of the databases stored in the database file and whose data +values are opaque objects. No keys or data values may be modified or +stored using this database handle. +

Storing multiple databases in a single file is almost identical to +storing each database in its own separate file. The one crucial +difference is how locking and the underlying memory pool services must +to be configured. As an example, consider two databases instantiated +in two different physical files. If access to each separate database +is single-threaded, there is no reason to perform any locking of any +kind, and the two databases may be read and written simultaneously. +Further, there would be no requirement to create a shared database +environment in which to open the databases. Because multiple databases +in a file exist in a single physical file, opening two databases in the +same file requires that locking be enabled, unless access to the +databases is known to be single-threaded, that is, only one of the +databases is ever accessed at a time. (As the locks for the two +databases can only conflict during page allocation, this additional +locking is unlikely to effect performance.) Further, the databases must +share an underlying memory pool so that per-physical-file information +is updated correctly. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am/ops.html b/db/docs/ref/am/ops.html new file mode 100644 index 000000000..5daaddd74 --- /dev/null +++ b/db/docs/ref/am/ops.html @@ -0,0 +1,36 @@ + + + + + +Berkeley DB Reference Guide: Access method operations + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

Access method operations

+

Once a database handle has been created using db_create, there +are several standard access method operations. Each of these operations +is performed using a method that is referenced from the returned handle. +The operations are as follows: +

+

DB->close
Close the database +
DB->cursor
Open a cursor into the database +
DB->del
Delete a record +
DB->get
Retrieve a record +
DB->open
Open a database +
DB->put
Store a record +
DB->stat
Return statistics about the database +
DB->sync
Flush the underlying cache +
DB->upgrade
Upgrade a database +
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am/partial.html b/db/docs/ref/am/partial.html new file mode 100644 index 000000000..7f3af8f68 --- /dev/null +++ b/db/docs/ref/am/partial.html @@ -0,0 +1,134 @@ + + + + + +Berkeley DB Reference Guide: Partial record storage and retrieval + + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

Partial record storage and retrieval

+

It is possible to both store and retrieve parts of data items in all +Berkeley DB access methods. This is done by setting the +DB_DBT_PARTIAL flag in the DBT structure passed to the +Berkeley DB interface. +

The DB_DBT_PARTIAL flag is based on the values of two fields +of the DBT structure, dlen and doff. The value +of dlen is the number of bytes of the record in which the +application is interested. The value of doff is the offset from +the beginning of the data item where those bytes start. +

For example, if the data item were ABCDEFGHIJKL, a doff +value of 3 would indicate that the bytes of interest started at +D, and a dlen value of 4 would indicate that the bytes +of interest were DEFG. +

When retrieving a data item from a database, the dlen bytes +starting doff bytes from the beginning of the record are +returned, as if they comprised the entire record. If any or all of the +specified bytes do not exist in the record, the retrieval is still +successful and any existing bytes (and nul bytes for any non-existent +bytes) are returned. +

When storing a data item into the database, the dlen bytes +starting doff bytes from the beginning of the specified key's +data record are replaced by the data specified by the data and +size fields. If dlen is smaller than size, the +record will grow, and if dlen is larger than size, the +record will shrink. If the specified bytes do not exist, the record will +be extended using nul bytes as necessary, and the store call will still +succeed. +

The following are various examples of the put case for the +DB_DBT_PARTIAL flag. In all examples, the initial data item is 20 +bytes in length: +

ABCDEFGHIJ0123456789 +

    +

  1. size = 20
    +doff = 0
    +dlen = 20
    +data = abcdefghijabcdefghij
    +

    +Result: The 20 bytes at offset 0 are replaced by the 20 bytes of data, +i.e., the entire record is replaced. +

    +ABCDEFGHIJ0123456789 -> abcdefghijabcdefghij +

    +

  2. size = 10
    +doff = 20
    +dlen = 0
    +data = abcdefghij
    +

    +Result: The 0 bytes at offset 20 are replaced by the 10 bytes of data, +i.e., the record is extended by 10 bytes. +

    +ABCDEFGHIJ0123456789 -> ABCDEFGHIJ0123456789abcdefghij +

    +

  3. size = 10
    +doff = 10
    +dlen = 5
    +data = abcdefghij
    +

    +Result: The 5 bytes at offset 10 are replaced by the 10 bytes of data. +

    +ABCDEFGHIJ0123456789 -> ABCDEFGHIJabcdefghij56789 +

    +

  4. size = 10
    +doff = 10
    +dlen = 0
    +data = abcdefghij
    +

    +Result: The 0 bytes at offset 10 are replaced by the 10 bytes of data, +i.e., 10 bytes are inserted into the record. +

    +ABCDEFGHIJ0123456789 -> ABCDEFGHIJabcdefghij0123456789 +

    +

  5. size = 10
    +doff = 2
    +dlen = 15
    +data = abcdefghij
    +

    +Result: The 15 bytes at offset 2 are replaced by the 10 bytes of data. +

    +ABCDEFGHIJ0123456789 -> ABabcdefghij789 +

    +

  6. size = 10
    +doff = 0
    +dlen = 0
    +data = abcdefghij
    +

    +Result: The 0 bytes at offset 0 are replaced by the 10 bytes of data, +i.e., the 10 bytes are inserted at the beginning of the record. +

    +ABCDEFGHIJ0123456789 -> abcdefghijABCDEFGHIJ0123456789 +

    +

  7. size = 0
    +doff = 0
    +dlen = 10
    +data = ""
    +

    +Result: The 10 bytes at offset 0 are replaced by the 0 bytes of data, +i.e., the first 10 bytes of the record are discarded. +

    +ABCDEFGHIJ0123456789 -> 0123456789 +

    +

  8. size = 10
    +doff = 25
    +dlen = 0
    +data = abcdefghij
    +

    +Result: The 0 bytes at offset 25 are replaced by the 10 bytes of data, +i.e., 10 bytes are inserted into the record past the end of the current +data (\0 represents a nul byte). +

    +ABCDEFGHIJ0123456789 -> ABCDEFGHIJ0123456789\0\0\0\0\0abcdefghij +

    +
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am/put.html b/db/docs/ref/am/put.html new file mode 100644 index 000000000..993dcbeb0 --- /dev/null +++ b/db/docs/ref/am/put.html @@ -0,0 +1,36 @@ + + + + + +Berkeley DB Reference Guide: Storing records + + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

Storing records

+

The DB->put function is the standard interface for storing records into +the database. In general, DB->put takes a key and stores the +associated data into the database. +

There are a few flags that you can set to customize storage: +

+

DB_APPEND
Simply append the data to the end of the database, treating the database +much like a simple log. This flag is only valid for the Queue and Recno +access methods. +

DB_NOOVERWRITE
Only store the data item if the key does not already appear in the database. +
+

If the database has been configured to support duplicate records, the +DB->put function will add the new data value at the end of the duplicate +set. If the database supports sorted duplicates, the new data value is +inserted at the correct sorted location. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am/stability.html b/db/docs/ref/am/stability.html new file mode 100644 index 000000000..b5f6d2386 --- /dev/null +++ b/db/docs/ref/am/stability.html @@ -0,0 +1,49 @@ + + + + + +Berkeley DB Reference Guide: Cursor Stability + + + + + + + +

Berkeley DB Reference Guide:
Transaction Subsystem

PrevRefNext +
+

+

Cursor Stability

+

In the absence of locking, no guarantees are made about the stability of +cursors in different processes or threads. However, the Btree, Queue +and Recno access methods guarantee that cursor operations, interspersed +with other cursor or non-cursor operations in the same thread of control +will always return keys in order and will return each non-deleted key/data +pair exactly once. Because the Hash access method uses a dynamic hashing +algorithm, it cannot guarantee any form of stability in the presence of +inserts and deletes unless locking is performed. +

If locking was specified when the Berkeley DB file was opened, but transactions +are not in effect, the access methods provide repeatable reads with +respect to the cursor. That is, a DB_CURRENT call on the cursor +is guaranteed to return the same record as was returned on the last call +to the cursor. +

With the exception of the Queue access method, in the presence of +transactions, all access method calls between a call to txn_begin +and a call to txn_abort or txn_commit provide degree 3 +consistency (serializable transactions). +

The Queue access method permits phantom records to appear between calls. +That is, deleted records are not locked, therefore another transaction may +replace a deleted record between two calls to retrieve it. The record would +not appear in the first call but would be seen by the second call. +

For all access methods, a cursor scan of the database performed within +the context of a transaction is guaranteed to return each key/data pair +once and only once, except in the following case. If, while performing +a cursor scan using the Hash access method, the transaction performing +the scan inserts a new pair into the database, it is possible that duplicate +key/data pairs will be returned. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am/stat.html b/db/docs/ref/am/stat.html new file mode 100644 index 000000000..3042ccfee --- /dev/null +++ b/db/docs/ref/am/stat.html @@ -0,0 +1,36 @@ + + + + + +Berkeley DB Reference Guide: Database statistics + + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

Database statistics

+

The DB->stat function is the standard interface for obtaining database +statistics. Generally, DB->stat returns a set of statistics +about the underlying database, e.g., the number of key/data pairs in +the database, how the database was originally configured, and so on. +

There are two flags that you can set to customize the returned statistics: +

+

DB_CACHED_COUNTS
Request an approximate key and key/data pair count. As obtaining an +exact count can be very performance intensive for large databases, +it is possible to request a previously cached count. Obviously, the +cached count is only an approximate count, and may be out-of-date. +

DB_RECORDCOUNT
If the database is a Queue or Recno database, or a Btree database that +was configured so that it is possible to search it by logical record +number, return only a count of the records in the database. +
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am/sync.html b/db/docs/ref/am/sync.html new file mode 100644 index 000000000..3d1d61e62 --- /dev/null +++ b/db/docs/ref/am/sync.html @@ -0,0 +1,38 @@ + + + + + +Berkeley DB Reference Guide: Flushing the database cache + + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

Flushing the database cache

+

The DB->sync function is the standard interface for flushing all modified +records from the database cache to disk. +

It is important to understand that flushing cached information +to disk only minimizes the window of opportunity for corrupted data, it +does not eliminate the possibility. +

While unlikely, it is possible for database corruption to happen if a +system or application crash occurs while writing data to the database. To +ensure that database corruption never occurs, applications must either: +

    +
  • Use transactions and logging with automatic recovery. +
  • Use logging and application-specific recovery. +
  • Edit a copy of the database, and, once all applications +using the database have successfully called DB->close, use +system operations (e.g., the POSIX rename system call) to atomically +replace the original database with the updated copy. +
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am/upgrade.html b/db/docs/ref/am/upgrade.html new file mode 100644 index 000000000..21fa87a1e --- /dev/null +++ b/db/docs/ref/am/upgrade.html @@ -0,0 +1,50 @@ + + + + + +Berkeley DB Reference Guide: Upgrading databases + + + + + + + +

Berkeley DB Reference Guide:
Access Method Operations

PrevRefNext +
+

+

Upgrading databases

+

When upgrading to a new release of Berkeley DB, it may be necessary to upgrade +the on-disk format of already-created database files. Berkeley DB +database upgrades are done in place, and so are potentially +destructive. This means that if the system crashes during the upgrade +procedure, or if the upgrade procedure runs out of disk space, the +databases may be left in an inconsistent and unrecoverable state. To +guard against failure, the procedures outlined in +Upgrading Berkeley DB installations +should be carefully followed. If you are not performing catastrophic +archival as part of your application upgrade process, you should at +least copy your database to archival media, verify that your archival +media is error-free and readable, and that copies of your backups are +stored off-site! +

The actual database upgrade is done using the DB->upgrade +method, or by dumping the database using the old version of the Berkeley DB +software and reloading it using the current version. +

After an upgrade, Berkeley DB applications must be recompiled to use the new +Berkeley DB library before they can access an upgraded database. +There is no guarantee that applications compiled against +previous releases of Berkeley DB will work correctly with an upgraded database +format. Nor is there any guarantee that applications compiled against +newer releases of Berkeley DB will work correctly with the previous database +format. We do guarantee that any archived database may be upgraded +using a current Berkeley DB software release and the DB->upgrade +method, and there is no need to step-wise upgrade the database using +intermediate releases of Berkeley DB. Sites should consider archiving +appropriate copies of their application or application sources if they +may need to access archived databases without first upgrading them. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am/verify.html b/db/docs/ref/am/verify.html new file mode 100644 index 000000000..5c975dd8c --- /dev/null +++ b/db/docs/ref/am/verify.html @@ -0,0 +1,50 @@ + + + + + +Berkeley DB Reference Guide: Database verification and salvage + + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

Database verification and salvage

+

The DB->verify method is the standard interface for verifying +that a file, and any databases it may contain, are uncorrupted. In +addition, the method may optionally be called with a file stream +argument to which all key/data pairs found in the database are output. +There are two modes for finding key/data pairs to be output: +

    +

  1. If the DB_SALVAGE flag is specified, the key/data pairs in the +database are output. When run in this mode, the database is assumed to +be largely uncorrupted. For example, the DB->verify method will +search for pages that are no longer linked into the database, and will +output key/data pairs from such pages. However, key/data items that +have been marked as deleted in the database will not be output, as the +page structures are generally trusted in this mode. +

  2. If both the DB_SALVAGE and DB_AGGRESSIVE flags are +specified, all possible key/data pairs are output. When run in this mode, +the database is assumed to be seriously corrupted. For example, key/data +pairs that have been deleted will re-appear in the output. In addition, +because pages may have been subsequently re-used and modified during +normal database operations after the key/data pairs were deleted, it is +not uncommon for apparently corrupted key/data pairs to be output in this +mode, even when there is no corruption in the underlying database. The +output will almost always have to be edited by hand or other means before +the data is ready for re-load into another database. We recommend that +DB_SALVAGE be tried first, and DB_AGGRESSIVE only tried +if the output from that first attempt is obviously missing data items or +the data is sufficiently valuable that human review of the output is +preferable to any kind of data loss. +
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am_conf/bt_compare.html b/db/docs/ref/am_conf/bt_compare.html new file mode 100644 index 000000000..bf824ca35 --- /dev/null +++ b/db/docs/ref/am_conf/bt_compare.html @@ -0,0 +1,85 @@ + + + + + +Berkeley DB Reference Guide: Btree comparison + + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

Btree comparison

+

The Btree data structure is a sorted, balanced tree structure storing +associated key/data pairs. By default, the sort order is lexicographical, +with shorter keys collating before longer keys. The user can specify the +sort order for the Btree by using the DB->set_bt_compare function. +

Sort routines are passed pointers to keys as arguments. The keys are +represented as DBT structures. The routine must return an integer +less than, equal to, or greater than zero if the first argument is +considered to be respectively less than, equal to, or greater than the +second argument. The only fields that the routines may examine in the +DBT structures are data and size fields. +

An example routine that might be used to sort integer keys in the database +is as follows: +

int
+compare_int(dbp, a, b)
+	DB *dbp;
+	const DBT *a, *b;
+{
+	int ai, bi;
+

+ /* + * Returns: + * < 0 if a < b + * = 0 if a = b + * > 0 if a > b + */ + memcpy(&ai, a->data, sizeof(int)); + memcpy(&bi, b->data, sizeof(int)); + return (ai - bi); +} +

+

Note that the data must first be copied into memory that is appropriately +aligned, as Berkeley DB does not guarantee any kind of alignment of the +underlying data, including for comparison routines. When writing +comparison routines, remember that databases created on machines of +different architectures may have different integer byte orders, for which +your code may need to compensate. +

An example routine that might be used to sort keys based on the first +five bytes of the key (ignoring any subsequent bytes) is as follows: +

int
+compare_dbt(dbp, a, b)
+	DB *dbp;
+	const DBT *a, *b;
+{
+	u_char *p1, *p2;
+

+ /* + * Returns: + * < 0 if a < b + * = 0 if a = b + * > 0 if a > b + */ + for (p1 = a->data, p2 = b->data, len = 5; len--; ++p1, ++p2) + if (*p1 != *p2) + return ((long)*p1 - (long)*p2); + return (0); +}

+

All comparison functions must cause the keys in the database to be +well-ordered. The most important implication of being well-ordered is +that the key relations must be transitive, that is, if key A is less +than key B, and key B is less than key C, then the comparison routine +must also return that key A is less than key C. In addition, comparisons +will only be able to return 0 when comparing full length keys; partial +key comparisons must always return a result less than or greater than 0. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am_conf/bt_minkey.html b/db/docs/ref/am_conf/bt_minkey.html new file mode 100644 index 000000000..f80ecf1df --- /dev/null +++ b/db/docs/ref/am_conf/bt_minkey.html @@ -0,0 +1,53 @@ + + + + + +Berkeley DB Reference Guide: Minimum keys per page + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

Minimum keys per page

+

The number of keys stored on each page affects the size of a Btree and +how it is maintained. Therefore, it also affects the retrieval and search +performance of the tree. For each Btree, Berkeley DB computes a maximum key +and data size. This size is a function of the page size and the fact that +at least two key/data pairs must fit on any Btree page. Whenever key or +data items exceed the calculated size, they are stored on overflow pages +instead of in the standard Btree leaf pages. +

Applications may use the DB->set_bt_minkey function to change the minimum +number of keys that must fit on a Btree page from two to another value. +Altering this value in turn alters the on-page maximum size, and can be +used to force key and data items which would normally be stored in the +Btree leaf pages onto overflow pages. +

Some data sets can benefit from this tuning. For example, consider an +application using large page sizes, with a data set almost entirely +consisting of small key and data items, but with a few large items. By +setting the minimum number of keys that must fit on a page, the +application can force the outsized items to be stored on overflow pages. +That in turn can potentially keep the tree more compact, that is, with +fewer internal levels to traverse during searches. +

The following calculation is similar to the one performed by the Btree +implementation. (The minimum_keys value is multiplied by 2 +because each key/data pair requires 2 slots on a Btree page.) +

maximum_size = page_size / (minimum_keys * 2)
+

Using this calculation, if the page size is 8KB and the default +minimum_keys value of 2 is used, then any key or data items +larger than 2KB will be forced to an overflow page. If an application +were to specify a minimum_key value of 100, then any key or data +items larger than roughly 40 bytes would be forced to overflow pages. +

It is important to remember that accesses to overflow pages do not perform +as well as accesses to the standard Btree leaf pages, and so setting the +value incorrectly can result in overusing overflow pages and decreasing +the application's overall performance. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am_conf/bt_prefix.html b/db/docs/ref/am_conf/bt_prefix.html new file mode 100644 index 000000000..621de75fa --- /dev/null +++ b/db/docs/ref/am_conf/bt_prefix.html @@ -0,0 +1,66 @@ + + + + + +Berkeley DB Reference Guide: Btree prefix comparison + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

Btree prefix comparison

+

The Berkeley DB Btree implementation maximizes the number of keys that can be +stored on an internal page by storing only as many bytes of each key as +are necessary to distinguish it from adjacent keys. The prefix comparison +routine is what determines this minimum number of bytes (i.e., the length +of the unique prefix), that must be stored. A prefix comparison function +for the Btree can be specified by calling DB->set_bt_prefix. +

The prefix comparison routine must be compatible with the overall +comparison function of the Btree, since what distinguishes any two keys +depends entirely on the function used to compare them. This means that +if a prefix comparison routine is specified by the application, a +compatible overall comparison routine must also have been specified. +

Prefix comparison routines are passed pointers to keys as arguments. The +keys are represented as DBT structures. The prefix comparison +function must return the number of bytes of the second key argument that +are necessary to determine if it is greater than the first key argument. +If the keys are equal, the length of the second key should be returned. +The only fields that the routines may examine in the DBT +structures are data and size fields. +

An example prefix comparison routine follows: +

u_int32_t
+compare_prefix(dbp, a, b)
+	DB *dbp;
+	const DBT *a, *b;
+{
+	size_t cnt, len;
+	u_int8_t *p1, *p2;
+

+ cnt = 1; + len = a->size > b->size ? b->size : a->size; + for (p1 = + a->data, p2 = b->data; len--; ++p1, ++p2, ++cnt) + if (*p1 != *p2) + return (cnt); + /* + * They match up to the smaller of the two sizes. + * Collate the longer after the shorter. + */ + if (a->size < b->size) + return (a->size + 1); + if (b->size < a->size) + return (b->size + 1); + return (b->size); +}

+

The usefulness of this functionality is data dependent, but in some data +sets can produce significantly reduced tree sizes and faster search times. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am_conf/bt_recnum.html b/db/docs/ref/am_conf/bt_recnum.html new file mode 100644 index 000000000..cdf8970e5 --- /dev/null +++ b/db/docs/ref/am_conf/bt_recnum.html @@ -0,0 +1,34 @@ + + + + + +Berkeley DB Reference Guide: Retrieving Btree records by number + + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

Retrieving Btree records by number

+

The Btree access method optionally supports retrieval by logical record +numbers). To configure a Btree to support record numbers, call the +DB->set_flags function with the DB_RECNUM flag. +

Configuring a Btree for record numbers should not be done lightly. +While often useful, it requires that storing items into the database +be single-threaded, which can severely impact application throughput. +Generally it should be avoided in trees with a need for high write +concurrency. +

To determine a key's record number, use the DB_GET_RECNO flag +to the DBcursor->c_get function. +

To retrieve by record number, use the DB_SET_RECNO flag to the +DB->get and DBcursor->c_get functions. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am_conf/byteorder.html b/db/docs/ref/am_conf/byteorder.html new file mode 100644 index 000000000..e0eef8a45 --- /dev/null +++ b/db/docs/ref/am_conf/byteorder.html @@ -0,0 +1,38 @@ + + + + + +Berkeley DB Reference Guide: Selecting a byte order + + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

Selecting a byte order

+

The database files created by Berkeley DB can be created in either little- or +big-endian formats. +

The byte order used for the underlying database can be specified by +calling the DB->set_lorder function. If no order is selected, the +native format of the machine on which the database is created will be +used. +

Berkeley DB databases are architecture independent, and any format database can +be used on a machine with a different native format. In this case, as +each page that is read into or written from the cache must be converted +to or from the host format, and databases with non-native formats will +incur a performance penalty for the run-time conversion. +

It is important to note that the Berkeley DB access methods do no data +conversion for application specified data. Key/data pairs written on a +little-endian format architecture will be returned to the application +exactly as they were written when retrieved on a big-endian format +architecture. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am_conf/cachesize.html b/db/docs/ref/am_conf/cachesize.html new file mode 100644 index 000000000..d0534767f --- /dev/null +++ b/db/docs/ref/am_conf/cachesize.html @@ -0,0 +1,86 @@ + + + + + +Berkeley DB Reference Guide: Selecting a cache size + + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

Selecting a cache size

+

The size of the cache used for the underlying database can be specified +by calling the DB->set_cachesize function. +Choosing a cache size is, unfortunately, an art. Your cache must be at +least large enough for your working set plus some overlap for unexpected +situations. +

When using the Btree access method, you must have a cache big enough for +the minimum working set for a single access. This will include a root +page, one or more internal pages (depending on the depth of your tree), +and a leaf page. If your cache is any smaller than that, each new page +will force out the least-recently-used page, and Berkeley DB will re-read the +root page of the tree anew on each database request. +

If your keys are of moderate size (a few tens of bytes) and your pages +are on the order of 4K to 8K, most Btree applications +will be only three levels. For +example, using 20 byte keys with 20 bytes of data associated with each +key, a 8KB page can hold roughly 400 keys and 200 key/data pairs, so a +fully populated three-level Btree will hold 32 million key/data pairs, +and a tree with only a 50% page-fill factor will still hold 16 million +key/data pairs. We rarely expect trees to exceed five levels, although +Berkeley DB will support trees up to 255 levels. +

The rule-of-thumb is that cache is good, and more cache is better. +Generally, applications benefit from increasing the cache size up to a +point, at which the performance will stop improving as the cache size +increases. When this point is reached, one of two things have happened: +either the cache is large enough that the application is almost never +having to retrieve information from disk, or, your application is doing +truly random accesses, and therefore increasing size of the cache doesn't +significantly increase the odds of finding the next requested information +in the cache. The latter is fairly rare -- almost all applications show +some form of locality of reference. +

That said, it is important not to increase your cache size beyond the +capabilities of your system, as that will result in reduced performance. +Under many operating systems, tying down enough virtual memory will cause +your memory and potentially your program to be swapped. This is +especially likely on systems without unified OS buffer caches and virtual +memory spaces, as the buffer cache was allocated at boot time and so +cannot be adjusted based on application requests for large amounts of +virtual memory. +

For example, even if accesses are truly random within a Btree, your +access pattern will favor internal pages to leaf pages, so your cache +should be large enough to hold all internal pages. In the steady state, +this requires at most one I/O per operation to retrieve the appropriate +leaf page. +

You can use the db_stat utility to monitor the effectiveness of +your cache. The following output is excerpted from the output of that +utility's -m option: +

prompt: db_stat -m
+131072  Cache size (128K).
+4273    Requested pages found in the cache (97%).
+134     Requested pages not found in the cache.
+18      Pages created in the cache.
+116     Pages read into the cache.
+93      Pages written from the cache to the backing file.
+5       Clean pages forced from the cache.
+13      Dirty pages forced from the cache.
+0       Dirty buffers written by trickle-sync thread.
+130     Current clean buffer count.
+4       Current dirty buffer count.
+
+

The statistics for this cache say that there have been 4,273 requests of +the cache, and only 116 of those requests required an I/O from disk. This +means that the cache is working well, yielding a 97% cache hit rate. The +db_stat utility will present these statistics both for the cache +as a whole and for each file within the cache separately. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am_conf/dup.html b/db/docs/ref/am_conf/dup.html new file mode 100644 index 000000000..eec5302cb --- /dev/null +++ b/db/docs/ref/am_conf/dup.html @@ -0,0 +1,71 @@ + + + + + +Berkeley DB Reference Guide: Duplicate data items + + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

Duplicate data items

+

The Btree and Hash access methods support the creation of multiple data +items for a single key item. By default, multiple data items are not +permitted, and each database store operation will overwrite any previous +data item for that key. To configure Berkeley DB for duplicate data items, call +the DB->set_flags function with the DB_DUP flag. +

By default, Berkeley DB stores duplicates in the order in which they were added, +that is, each new duplicate data item will be stored after any already +existing data items. This default behavior can be overridden by using +the DBcursor->c_put function and one of the DB_AFTER, DB_BEFORE +DB_KEYFIRST or DB_KEYLAST flags. Alternatively, Berkeley DB +may be configured to sort duplicate data items as described below. +

When stepping through the database sequentially, duplicate data items will +be returned individually, as a key/data pair, where the key item only +changes after the last duplicate data item has been returned. For this +reason, duplicate data items cannot be accessed using the +DB->get function, as it always returns the first of the duplicate data +items. Duplicate data items should be retrieved using the Berkeley DB cursor +interface, DBcursor->c_get. +

There is an interface flag that permits applications to request the +following data item only if it is a duplicate data item of the +current entry, see DB_NEXT_DUP for more information. There is an +interface flag that permits applications to request the following data +item only if it is not a duplicate data item of the current +entry, see DB_NEXT_NODUP and DB_PREV_NODUP for more +information. +

It is also possible to maintain duplicate records in sorted order. Sorting +duplicates will significantly increase performance when searching them +and performing logical joins, common operations when creating secondary +indexes. To configure Berkeley DB to sort duplicate data items, the application +must call the DB->set_flags function with the DB_DUPSORT flag (in +addition to the DB_DUP flag). In addition, a custom sorting +function may be specified using the DB->set_dup_compare function. If the +DB_DUPSORT flag is given, but no comparison routine is specified, +then Berkeley DB defaults to the same lexicographical sorting used for Btree +keys, with shorter items collating before longer items. +

If the duplicate data items are unsorted, applications may store identical +duplicate data items, or, for those that just like the way it sounds, +duplicate duplicates. +

In this release it is an error to attempt to store identical +duplicate data items when duplicates are being stored in a sorted order. +This restriction is expected to be lifted in a future release. There is +an interface flag that permits applications to disallow storing duplicate +data items when the database has been configured for sorted duplicates, +see DB_NODUPDATA for more information. Applications not wanting +to permit duplicate duplicates in databases configured for sorted +duplicates should begin using the DB_NODUPDATA flag immediately. +

For further information on how searching and insertion behaves in the +presence of duplicates (sorted or not), see the DB->get, +DB->put, DBcursor->c_get and DBcursor->c_put documentation. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am_conf/extentsize.html b/db/docs/ref/am_conf/extentsize.html new file mode 100644 index 000000000..15d940c15 --- /dev/null +++ b/db/docs/ref/am_conf/extentsize.html @@ -0,0 +1,38 @@ + + + + + +Berkeley DB Reference Guide: Selecting a Queue extent size + + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

Selecting a Queue extent size

+

In Queue databases, records are allocated sequentially and directly +mapped to an offset within the file storage for the database. As +records are deleted from the Queue, pages will become empty and will +not be reused in normal queue operations. To facilitate the reclamation +of disk space a Queue may be partitioned into extents. Each extent is +kept in a separate physical file. Extent files are automatically +created as needed and destroyed when they are emptied of records. +

The extent size specifies the number of pages that make up each extent. +By default, if no extent size is specified, the Queue resides in a +single file and disk space is not reclaimed. In choosing an extent size +there is a tradeoff between the amount of disk space used and the +overhead of creating and deleting files. If the extent size is too +small, the system will pay a performance penalty, creating and deleting +files frequently. In addition, if the active part of the queue spans +many files, all those files will need to be open at the same time, +consuming system and process file resources. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am_conf/h_ffactor.html b/db/docs/ref/am_conf/h_ffactor.html new file mode 100644 index 000000000..6c30f0fc3 --- /dev/null +++ b/db/docs/ref/am_conf/h_ffactor.html @@ -0,0 +1,31 @@ + + + + + +Berkeley DB Reference Guide: Page fill factor + + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

Page fill factor

+

The density, or page fill factor, is an approximation of the number of +keys allowed to accumulate in any one bucket, determining when the hash +table grows or shrinks. If you know the average sizes of the keys and +data in your dataset, setting the fill factor can enhance performance. +A reasonable rule to use to compute fill factor is: +

(pagesize - 32) / (average_key_size + average_data_size + 8)
+

The desired density within the hash table can be specified by calling +the DB->set_h_ffactor function. If no density is specified, one will +be selected dynamically as pages are filled. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am_conf/h_hash.html b/db/docs/ref/am_conf/h_hash.html new file mode 100644 index 000000000..d42edee1c --- /dev/null +++ b/db/docs/ref/am_conf/h_hash.html @@ -0,0 +1,39 @@ + + + + + +Berkeley DB Reference Guide: Specifying a database hash + + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

Specifying a database hash

+

The database hash determines in which bucket a particular key will reside. +The goal of hashing keys is to distribute keys equally across the database +pages, therefore it is important that the hash function work well with +the specified keys so that the resulting bucket usage is relatively +uniform. A hash function that does not work well can effectively turn +into a sequential list. +

No hash performs equally well on all possible data sets. It is possible +that applications may find that the default hash function performs poorly +with a particular set of keys. The distribution resulting from the hash +function can be checked using db_stat utility. By comparing the +number of hash buckets and the number of keys, one can decide if the entries +are hashing in a well-distributed manner. +

The hash function for the hash table can be specified by calling the +DB->set_h_hash function. If no hash function is specified, a default +function will be used. Any application-specified hash function must +take a reference to a DB object, a pointer to a byte string and +its length, as arguments and return an unsigned, 32-bit hash value. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am_conf/h_nelem.html b/db/docs/ref/am_conf/h_nelem.html new file mode 100644 index 000000000..8c510d6db --- /dev/null +++ b/db/docs/ref/am_conf/h_nelem.html @@ -0,0 +1,32 @@ + + + + + +Berkeley DB Reference Guide: Hash table size + + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

Hash table size

+

When setting up the hash database, knowing the expected number of elements +that will be stored in the hash table is useful. This value can be used +by the Hash access method implementation to more accurately construct the +necessary number of buckets that the database will eventually require. +

The anticipated number of elements in the hash table can be specified by +calling the DB->set_h_nelem function. If not specified, or set too low, +hash tables will expand gracefully as keys are entered, although a slight +performance degradation may be noticed. In order for the estimated number +of elements to be a useful value to Berkeley DB, the DB->set_h_ffactor function +must also be called to set the page fill factor. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am_conf/intro.html b/db/docs/ref/am_conf/intro.html new file mode 100644 index 000000000..15fed60f6 --- /dev/null +++ b/db/docs/ref/am_conf/intro.html @@ -0,0 +1,45 @@ + + + + + +Berkeley DB Reference Guide: What are the available access methods? + + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

What are the available access methods?

+

Berkeley DB currently offers four access methods: Btree, Hash, Queue and Recno. +

Btree

+

The Btree access method is an implementation of a sorted, balanced tree +structure. Searches, insertions, and deletions in the tree all take O(log +base_b N) time, where base_b is the average number of keys per page, and +N is the total number of keys stored. Often, inserting ordered data into +Btree implementations results in pages that are only half-full. Berkeley DB +makes ordered (or inverse ordered) insertion the best case, resulting in +nearly full-page space utilization. +

Hash

+

The Hash access method data structure is an implementation of Extended +Linear Hashing, as described in "Linear Hashing: A New Tool for File and +Table Addressing", Witold Litwin, Proceedings of the 6th +International Conference on Very Large Databases (VLDB), 1980. +

Queue

+

The Queue access method stores fixed-length records with logical record +numbers as keys. It is designed for fast inserts at the tail and has a +special cursor consume operation that deletes and returns a record from +the head of the queue. The Queue access method uses record level locking. +

Recno

+

The Recno access method stores both fixed and variable-length records with +logical record numbers as keys, optionally backed by a flat text (byte +stream) file. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am_conf/logrec.html b/db/docs/ref/am_conf/logrec.html new file mode 100644 index 000000000..fd9fb0141 --- /dev/null +++ b/db/docs/ref/am_conf/logrec.html @@ -0,0 +1,45 @@ + + + + + +Berkeley DB Reference Guide: Logical record numbers + + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

Logical record numbers

+

The Berkeley DB Btree, Queue and Recno access methods can operate on logical +record numbers. In all cases for the Queue and Recno access methods, +and in some cases with the Btree access method, a record number is +specified to reference a specific key/data pair. In the case of Btree +supporting duplicate data items, the logical record number refers to a +key and all of its data items. +

Record numbers are 32-bit unsigned types, which limits the number of +logical records in a database to 4,294,967,296. The first record in the +database is record number 1. +

Record numbers in Recno databases can be configured to run in either +mutable or fixed mode: mutable, where logical record numbers change as +records are deleted or inserted, and fixed, where record numbers never +change regardless of the database operation. Record numbers in Btree +databases are always mutable, and as records are deleted or inserted, the +logical record number for other records in the database can change. See +Logically renumbering records for +more information. +

Record numbers in Queue databases are always fixed, and never change +regardless of the database operation. +

Configuring Btree databases to support record numbers can severely limit +the throughput of applications with multiple concurrent threads writing +the database, because locations used to store record counts often become +hot spots that many different threads all need to update. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am_conf/malloc.html b/db/docs/ref/am_conf/malloc.html new file mode 100644 index 000000000..12e57383c --- /dev/null +++ b/db/docs/ref/am_conf/malloc.html @@ -0,0 +1,31 @@ + + + + + +Berkeley DB Reference Guide: Non-local memory allocation + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

Non-local memory allocation

+

Berkeley DB can allocate memory for returned key/data pairs which then becomes +the responsibility of the application. See DB_DBT_MALLOC or +DB_DBT_REALLOC for further information. +

On systems where there may be multiple library versions of malloc (notably +Windows NT), the Berkeley DB library could allocate memory from a different heap +than the application will use to free it. To avoid this problem, the +allocation routine to be used for allocating such key/data items can be +specified by calling the DB->set_malloc or +DB->set_realloc functions. If no allocation function is specified, the +underlying C library functions are used. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am_conf/pagesize.html b/db/docs/ref/am_conf/pagesize.html new file mode 100644 index 000000000..41cab5ec4 --- /dev/null +++ b/db/docs/ref/am_conf/pagesize.html @@ -0,0 +1,66 @@ + + + + + +Berkeley DB Reference Guide: Selecting a page size + + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

Selecting a page size

+

The size of the pages used in the underlying database can be specified by +calling the DB->set_pagesize function. The minimum page size is 512 bytes +and the maximum page size is 64K bytes, and must be a power of two. If +no page size is specified by the application, a page size is selected +based on the underlying filesystem I/O block size. (A page size selected +in this way has a lower limit of 512 bytes and an upper limit of 16K +bytes.) +

There are four issues to consider when selecting a pagesize: overflow +record sizes, locking, I/O efficiency, and recoverability. +

First, the page size implicitly sets the size of an overflow record. +Overflow records are key or data items that are too large to fit on a +normal database page because of their size, and are therefore stored in +overflow pages. Overflow pages are pages that exist outside of the normal +database structure. For this reason, there is often a significant +performance penalty associated with retrieving or modifying overflow +records. Selecting a page size that is too small, and which forces the +creation of large numbers of overflow pages, can seriously impact the +performance of an application. +

Second, in the Btree, Hash and Recno Access Methods, the finest-grained +lock that Berkeley DB acquires is for a page. (The Queue Access Method +generally acquires record-level locks rather than page-level locks.) +Selecting a page size that is too large, and which causes threads or +processes to wait because other threads of control are accessing or +modifying records on the same page, can impact the performance of your +application. +

Third, the page size specifies the granularity of I/O from the database +to the operating system. Berkeley DB will give a page-sized unit of bytes to +the operating system to be scheduled for writing to the disk. For many +operating systems, there is an internal block size which is used +as the granularity of I/O from the operating system to the disk. If the +page size is smaller than the block size, the operating system may be +forced to read a block from the disk, copy the page into the buffer it +read, and then write out the block to disk. Obviously, it will be much +more efficient for Berkeley DB to write filesystem-sized blocks to the operating +system and for the operating system to write those same blocks to the +disk. Selecting a page size that is too small, and which causes the +operating system to coalesce or otherwise manipulate Berkeley DB pages, can +impact the performance of your application. Alternatively, selecting a +page size that is too large may cause Berkeley DB and the operating system to +write more data than is strictly necessary. +

Fourth, when using the Berkeley DB Transactional Data Store product, the page size may affect the errors +from which your database can recover See +Berkeley DB Recoverability for more +information. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am_conf/re_source.html b/db/docs/ref/am_conf/re_source.html new file mode 100644 index 000000000..2095a9698 --- /dev/null +++ b/db/docs/ref/am_conf/re_source.html @@ -0,0 +1,62 @@ + + + + + +Berkeley DB Reference Guide: Flat-text backing files + + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

Flat-text backing files

+

It is possible to back any Recno database (either fixed or variable +length) with a flat-text source file. This provides fast read (and +potentially write) access to databases that are normally created and +stored as flat-text files. The backing source file may be specified by +calling the DB->set_re_source function. +

The backing source file will be read to initialize the database. In the +case of variable length records, the records are assumed to be separated +as described for the DB->set_re_delim function interface. For example, +standard UNIX byte stream files can be interpreted as a sequence of +variable length records separated by ASCII newline characters. This is +the default. +

When cached data would normally be written back to the underlying database +file (e.g., DB->close or DB->sync functions are called), the +in-memory copy of the database will be written back to the backing source +file. +

The backing source file must already exist (but may be zero-length) when +DB->open is called. By default, the backing source file is read +lazily, i.e., records are not read from the backing source file until they +are requested by the application. If multiple processes (not threads) are +accessing a Recno database concurrently and either inserting or deleting +records, the backing source file must be read in its entirety before more +than a single process accesses the database, and only that process should +specify the backing source file as part of the DB->open call. +This can be accomplished by calling the DB->set_flags function with the +DB_SNAPSHOT flag. +

Reading and writing the backing source file cannot be transactionally +protected because it involves filesystem operations that are not part of +the Berkeley DB transaction methodology. For this reason, if a temporary +database is used to hold the records (a NULL was specified as the file +argument to DB->open), it is possible to lose the +contents of the backing source file if the system crashes at the right +instant. If a permanent file is used to hold the database (a file name +was specified as the file argument to DB->open), normal database +recovery on that file can be used to prevent information loss. It is +still possible that the contents of the backing source file itself will +be corrupted or lost if the system crashes. +

For all of the above reasons, the backing source file is generally used +to specify databases that are read-only for Berkeley DB applications, and that +are either generated on the fly by software tools, or modified using a +different mechanism such as a text editor. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am_conf/recno.html b/db/docs/ref/am_conf/recno.html new file mode 100644 index 000000000..1a7128e0e --- /dev/null +++ b/db/docs/ref/am_conf/recno.html @@ -0,0 +1,69 @@ + + + + + +Berkeley DB Reference Guide: Managing record-based databases + + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

Managing record-based databases

+

When using fixed- or variable-length record-based databases, particularly +with flat-text backing files, there are several items that the user can +control. The Recno access method can be used to store either variable- +or fixed-length data items. By default, the Recno access method stores +variable-length data items. The Queue access method can only store +fixed-length data items. +

Record Delimiters

+

When using the Recno access method to store variable-length records, +records read from any backing source file are separated by a specific +byte value which marks the end of one record and the beginning of the +next. This delimiting value is ignored except when reading records from +a backing source file, that is, records may be stored into the database +that include the delimiter byte. However, if such records are written +out to the backing source file and the backing source file is +subsequently read into a database, the records will be split where +delimiting bytes were found. +

For example, UNIX text files can usually be interpreted as a sequence of +variable-length records separated by ASCII newline characters. This byte +value (ASCII 0x0a) is the default delimiter. Applications may specify a +different delimiting byte using the DB->set_re_delim interface. +If no backing source file is being used, there is no reason to set the +delimiting byte value. +

Record Length

+

When using the Recno or Queue access methods to store fixed-length +records, the record length must be specified. Since the Queue access +method always uses fixed-length records, the user must always set the +record length prior to creating the database. Setting the record length +is what causes the Recno access method to store fixed-length, not +variable-length, records. +

The length of the records is specified by calling the +DB->set_re_len function. The default length of the records is 0 bytes. +Any record read from a backing source file or otherwise stored in the +database that is shorter than the declared length will automatically be +padded as described for the DB->set_re_pad function. Any record stored +that is longer than the declared length results in an error. For +further information on backing source files, see +Flat-text backing files. +

Record Padding Byte Value

+

When storing fixed-length records in a Queue or Recno database, a pad +character may be specified by calling the DB->set_re_pad function. Any +record read from the backing source file or otherwise stored in the +database that is shorter than the expected length will automatically be +padded with this byte value. If fixed-length records are specified but +no pad value is specified, a space character (0x20 in the ASCII +character set) will be used. For further information on backing source +files, see Flat-text backing +files. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am_conf/renumber.html b/db/docs/ref/am_conf/renumber.html new file mode 100644 index 000000000..7c3594dff --- /dev/null +++ b/db/docs/ref/am_conf/renumber.html @@ -0,0 +1,80 @@ + + + + + +Berkeley DB Reference Guide: Logically renumbering records + + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

Logically renumbering records

+

Records stored in the Queue and Recno access methods are accessed by +logical record number. In all cases in Btree databases, and optionally +in Recno databases (see the DB->set_flags function and the +DB_RENUMBER flag for more information), record numbers are +mutable. This means that the record numbers may change as records are +added to and deleted from the database. The deletion of record number +4 causes any records numbered 5 and higher to be renumbered downward by +1; the addition of a new record after record number 4 causes any +records numbered 5 and higher to be renumbered upward by 1. In all +cases in Queue databases, and by default in Recno databases, record +numbers are not mutable, and the addition or deletion of records to the +database will not cause already-existing record numbers to change. For +this reason, new records cannot be inserted between already-existing +records in databases with immutable record numbers. +

Cursors pointing into a Btree database or a Recno database with mutable +record numbers maintain a reference to a specific record, rather than +a record number, that is, the record they reference does not change as +other records are added or deleted. For example, if a database contains +three records with the record numbers 1, 2, and 3, and the data items +"A", "B", and "C", respectively, the deletion of record number 2 ("B") +will cause the record "C" to be renumbered downward to record number 2. +A cursor positioned at record number 3 ("C") will be adjusted and +continue to point to "C" after the deletion. Similarly, a cursor +previously referencing the now deleted record number 2 will be +positioned between the new record numbers 1 and 2, and an insertion +using that cursor will appear between those records. In this manner +records can be added and deleted to a database without disrupting the +sequential traversal of the database by a cursor. +

Only cursors created using a single DB handle can adjust each +other's position in this way, however. If multiple DB handles +have a renumbering Recno database open simultaneously (as when multiple +processes share a single database environment), a record referred to by +one cursor could change underfoot if a cursor created using another +DB handle inserts or deletes records into the database. For +this reason, applications using Recno databases with mutable record +numbers will usually make all accesses to the database using a single +DB handle and cursors created from that handle, or will +otherwise single-thread access to the database, e.g., by using the +Berkeley DB Concurrent Data Store product. +

In any Queue or Recno databases, creating new records will cause the +creation of multiple records if the record number being created is more +than one greater than the largest record currently in the database. For +example, creating record number 28, when record 25 was previously the +last record in the database, will implicitly create records 26 and 27 +as well as 28. All first, last, next and previous cursor operations +will automatically skip over these implicitly created records. So, if +record number 5 is the only record the application has created, +implicitly creating records 1 through 4, the DBcursor->c_get interface +with the DB_FIRST flag will return record number 5, not record +number 1. Attempts to explicitly retrieve implicitly created records +by their record number will result in a special error return, +DB_KEYEMPTY. +

In any Berkeley DB database, attempting to retrieve a deleted record, using +a cursor positioned on the record, results in a special error return, +DB_KEYEMPTY. In addition, when using Queue databases or Recno +databases with immutable record numbers, attempting to retrieve a deleted +record by its record number will also result in the DB_KEYEMPTY +return. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/am_conf/select.html b/db/docs/ref/am_conf/select.html new file mode 100644 index 000000000..3838b3467 --- /dev/null +++ b/db/docs/ref/am_conf/select.html @@ -0,0 +1,116 @@ + + + + + +Berkeley DB Reference Guide: Selecting an access method + + + + + + + +

Berkeley DB Reference Guide:
Access Methods

PrevRefNext +
+

+

Selecting an access method

+

The Berkeley DB access method implementation unavoidably interacts with each +application's data set, locking requirements and data access patterns. +For this reason, one access method may result in dramatically better +performance for an application than another one. Applications whose data +could be stored in more than one access method may want to benchmark their +performance using the different candidates. +

One of the strengths of Berkeley DB is that it provides multiple access methods +with almost identical interfaces to the different access methods. This +means that it is simple to modify an application to use a different access +method. Applications can easily benchmark the different Berkeley DB access +methods against each other for their particular data set and access pattern. +

Most applications choose between using the Btree or Hash access methods +or between using the Queue and Recno access methods, because each of the +two pairs offer similar functionality. +

Hash or Btree?

+

The Hash and Btree access methods should be used when logical record +numbers are not the primary key used for data access. (If logical record +numbers are a secondary key used for data access, the Btree access method +is a possible choice, as it supports simultaneous access by a key and a +record number.) +

Keys in Btrees are stored in sorted order and the relationship between +them is defined by that sort order. For this reason, the Btree access +method should be used when there is any locality of reference among keys. +Locality of reference means that accessing one particular key in the +Btree implies that the application is more likely to access keys near to +the key being accessed, where "near" is defined by the sort order. For +example, if keys are timestamps, and it is likely that a request for an +8AM timestamp will be followed by a request for a 9AM timestamp, the +Btree access method is generally the right choice. Or, for example, if +the keys are names, and the application will want to review all entries +with the same last name, the Btree access method is again a good choice. +

There is little difference in performance between the Hash and Btree +access methods on small data sets, where all, or most of, the data set +fits into the cache. However, when a data set is large enough that +significant numbers of data pages no longer fit into the cache, then the +Btree locality of reference described above becomes important for +performance reasons. For example, there is no locality of reference for +the Hash access method, and so key "AAAAA" is as likely to be stored on +the same data page with key "ZZZZZ" as with key "AAAAB". In the Btree +access method, because items are sorted, key "AAAAA" is far more likely +to be near key "AAAAB" than key "ZZZZZ". So, if the application exhibits +locality of reference in its data requests, then the Btree page read into +the cache to satisfy a request for key "AAAAA" is much more likely to be +useful to satisfy subsequent requests from the application than the Hash +page read into the cache to satisfy the same request. This means that +for applications with locality of reference, the cache is generally much +"hotter" for the Btree access method than the Hash access method, and +the Btree access method will make many fewer I/O calls. +

However, when a data set becomes even larger, the Hash access method can +outperform the Btree access method. The reason for this is that Btrees +contain more metadata pages than Hash databases. The data set can grow +so large that metadata pages begin to dominate the cache for the Btree +access method. If this happens, the Btree can be forced to do an I/O +for each data request because the probability that any particular data +page is already in the cache becomes quite small. Because the Hash access +method has fewer metadata pages, its cache stays "hotter" longer in the +presence of large data sets. In addition, once the data set is so large +that both the Btree and Hash access methods are almost certainly doing +an I/O for each random data request, the fact that Hash does not have to +walk several internal pages as part of a key search becomes a performance +advantage for the Hash access method as well. +

Application data access patterns strongly affect all of these behaviors, +for example, accessing the data by walking a cursor through the database +will greatly mitigate the large data set behavior describe above because +each I/O into the cache will satisfy a fairly large number of subsequent +data requests. +

In the absence of information on application data and data access +patterns, for small data sets either the Btree or Hash access methods +will suffice. For data sets larger than the cache, we normally recommend +using the Btree access method. If you have truly large data, then the +Hash access method may be a better choice. The db_stat utility +is a useful tool for monitoring how well your cache is performing. +

Queue or Recno?

+

The Queue or Recno access methods should be used when logical record +numbers are the primary key used for data access. The advantage of the +Queue access method is that it performs record level locking and for this +reason supports significantly higher levels of concurrency than the Recno +access method. The advantage of the Recno access method is that it +supports a number of additional features beyond those supported by the +Queue access method, such as variable-length records and support for +backing flat-text files. +

Logical record numbers can be mutable or fixed: mutable, where logical +record numbers can change as records are deleted or inserted, and fixed, +where record numbers never change regardless of the database operation. +It is possible to store and retrieve records based on logical record +numbers in the Btree access method. However, those record numbers are +always mutable, and as records are deleted or inserted, the logical record +number for other records in the database will change. The Queue access +method always runs in fixed mode, and logical record numbers never change +regardless of the database operation. The Recno access method can be +configured to run in either mutable or fixed mode. +

In addition, the Recno access method provides support for databases whose +permanent storage is a flat text file and the database is used as a fast, +temporary storage area while the data is being read or modified. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/arch/apis.html b/db/docs/ref/arch/apis.html new file mode 100644 index 000000000..d1ae91b5a --- /dev/null +++ b/db/docs/ref/arch/apis.html @@ -0,0 +1,74 @@ + + + + + +Berkeley DB Reference Guide: Programmatic APIs + + + + + + + +

Berkeley DB Reference Guide:
Architecture

PrevRefNext +
+

+

Programmatic APIs

+

The Berkeley DB subsystems can be accessed through interfaces from multiple +languages. The standard library interface is ANSI C. Applications can +also use Berkeley DB via C++ or Java, as well as from scripting languages. +Environments can be shared among applications written using any of theses +APIs. For example, you might have a local server written in C or C++, a +script for an administrator written in Perl or Tcl, and a web based user +interface written in Java, all sharing a single database environment. +

C

+

The Berkeley DB library is written entirely in ANSI C. C applications use a +single include file: +

#include <db.h>
+

C++

+

The C++ classes provide a thin wrapper around the C API, with the major +advantages being improved encapsulation and an optional exception +mechanism for errors. C++ applications use a single include file: +

#include <db_cxx.h>
+

The classes and methods are named in a fashion that directly corresponds +to structures and functions in the C interface. Likewise, arguments to +methods appear in the same order as the C interface, except to remove the +explicit this pointer. The #defines used for flags are identical +between the C and C++ interfaces. +

As a rule, each C++ object has exactly one structure from the underlying +C API associated with it. The C structure is allocated with each +constructor call and deallocated with each destructor call. Thus, the +rules the user needs to follow in allocating and deallocating structures +are the same between the C and C++ interfaces. +

To ensure portability to many platforms, both new and old, Berkeley DB makes as +few assumptions as possible about the C++ compiler and library. For +example, it does not expect STL, templates or namespaces to be available. +The newest C++ feature used is exceptions, which are used liberally to +transmit error information. Even the use of exceptions can be disabled +at runtime. +

JAVA

+

The Java classes provide a layer around the C API that is almost identical +to the C++ layer. The classes and methods are, for the most part +identical to the C++ layer. Db constants and #defines are represented as +"static final int" values. Error conditions are communicated as Java +exceptions. +

As in C++, each Java object has exactly one structure from the underlying +C API associated with it. The Java structure is allocated with each +constructor or open call, but is deallocated only by the Java garbage +collector. Because the timing of garbage collection is not predictable, +applications should take care to do a close when finished with any object +that has a close method. +

Dbm/Ndbm, Hsearch

+

Berkeley DB supports the standard UNIX interfaces dbm (or its +ndbm variant) and hsearch. After including a new header +file and recompiling, dbm programs will run orders of magnitude +faster and their underlying databases can grow as large as necessary. +Historic dbm applications fail when some number of entries were +inserted into the database, where the number depends on the effectiveness +of the hashing function on the particular data set. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/arch/bigpic.gif b/db/docs/ref/arch/bigpic.gif new file mode 100644 index 000000000..48c52aed5 Binary files /dev/null and b/db/docs/ref/arch/bigpic.gif differ diff --git a/db/docs/ref/arch/bigpic.html b/db/docs/ref/arch/bigpic.html new file mode 100644 index 000000000..6c945744e --- /dev/null +++ b/db/docs/ref/arch/bigpic.html @@ -0,0 +1,114 @@ + + + + + +Berkeley DB Reference Guide: The big picture + + + + + + +

Berkeley DB Reference Guide:
Architecture

PrevRefNext +
+

+

The big picture

+

The previous chapters in this Reference Guide have described applications +that use the Berkeley DB Access Methods for fast data storage and retrieval. +The applications we describe here and in subsequent chapters are similar +in nature to the Access Method applications, but they are also fully +recoverable in the face of application or system failure. +

Application code that only uses the Berkeley DB Access Methods might appear as +follows: +

switch (ret = dbp->put(dbp, NULL, &key, &data, 0)) {
+case 0:
+	printf("db: %s: key stored.\n", (char *)key.data);
+	break;
+default:
+	dbp->err(dbp, ret, "dbp->put");
+	exit (1);
+}
+

The underlying Berkeley DB architecture that supports this is: +

small +

As you can see from this diagram, the application makes calls into the +Access Methods, and the Access Methods use the underlying shared memory +buffer cache to hold recently used file pages in main memory. +

When applications require recoverability, then their calls to the Access +Methods must be wrapped in calls to the transaction subsystem. The +application must inform Berkeley DB where to begin and end transactions, and +must be prepared for the possibility that an operation may fail at any +particular time, causing the transaction to abort. +

An example of transaction protected code might appear as follows: +

retry:	if ((ret = txn_begin(dbenv, NULL, &tid)) != 0) {
+		dbenv->err(dbenv, ret, "txn_begin");
+		exit (1);
+	}
+

+ switch (ret = dbp->put(dbp, tid, &key, &data, 0)) { + case DB_LOCK_DEADLOCK: + (void)txn_abort(tid); + goto retry; + case 0: + printf("db: %s: key stored.\n", (char *)key.data); + break; + default: + dbenv->err(dbenv, ret, "dbp->put"); + exit (1); + } +

+ if ((ret = txn_commit(tid)) != 0) { + dbenv->err(dbenv, ret, "txn_commit"); + exit (1); + }

+

In this example, the same operation is being done as before, however, it +is wrapped in transaction calls. The transaction is started with +txn_begin, and finished with txn_commit. If the operation +fails due to a deadlock, then the transaction is aborted using +txn_abort, after which the operation may be retried. +

There are actually five major subsystems in Berkeley DB, as follows: +

+

The Access Methods
The Access Method subsystem provides general-purpose support for creating +and accessing database files formatted as Btrees, Hashed files, and +Fixed- and Variable-length records. These modules are useful in the +absence of transactions for applications that need fast, formatted file +support. See DB->open and DB->cursor for more +information. These functions were already discussed in detail in the +previous chapters. +

The Memory Pool
The memory pool subsystem is the general-purpose shared memory buffer pool +used by Berkeley DB. This is the shared memory cache that allows multiple +processes and threads within processes to share access to databases. This +module is useful outside of the Berkeley DB package for processes that require +portable, page-oriented, cached, shared file access. +

Transactions
The transaction subsystem allows a group of database changes to be +treated as an atomic unit so that either all of the changes are done, or +none of the changes are done. The transaction subsystem implements the +Berkeley DB transaction model. This module is useful outside of the Berkeley DB +package for processes that want to transaction protect their own data +modifications. +

Locking
The locking subsystem is the general-purpose lock manager used by Berkeley DB. +This module is useful outside of the Berkeley DB package for processes that +require a portable, fast, configurable lock manager. +

Logging
The logging subsystem is the write-ahead logging used to support the Berkeley DB +transaction model. It is largely specific to the Berkeley DB package, and +unlikely to be useful elsewhere except as a supporting module for the +Berkeley DB transaction subsystem. +
+

Here is a more complete picture of the Berkeley DB library: +

large +

In this example, the application makes calls to the Access Methods and to +the transaction subsystem. The Access Methods and transaction subsystem +in turn make calls into the Buffer Pool, Locking and Logging subsystems +on behalf of the application. +

While the underlying subsystems can each be called independently. For +example, the Buffer Pool subsystem can be used apart from the rest of +Berkeley DB by applications simply wanting a shared memory buffer pool, or +the Locking subsystem may be called directly by applications that are +doing their own locking outside of Berkeley DB. However, this usage is fairly +rare, and most applications will either use only the Access Methods, or +the Access Methods wrapped in calls to the transaction interfaces. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/arch/progmodel.html b/db/docs/ref/arch/progmodel.html new file mode 100644 index 000000000..04284f4f3 --- /dev/null +++ b/db/docs/ref/arch/progmodel.html @@ -0,0 +1,41 @@ + + + + + +Berkeley DB Reference Guide: Programming model + + + + + + +

Berkeley DB Reference Guide:
Architecture

PrevRefNext +
+

+

Programming model

+

The Berkeley DB distribution is a database library, where the library is linked +into the address space of the code which uses it. The code using Berkeley DB +may be an application or it may be a server providing functionality to a +number of clients via some form of inter-process or remote-process +communication (IPC/RPC). +

In the application model, one or more applications link the Berkeley DB library +directly into their address spaces. There may be many threads of control +in this model, as Berkeley DB supports locking for both multiple processes and +for multiple threads within a process. This model provides significantly +faster access to the database functionality, but implies trust among all +threads of control sharing the database environment as they will have the +ability to read, write and potentially corrupt each other's data. +

In the client-server model, developers write a database server application +that accepts requests via some form of IPC and issues calls to the Berkeley DB +interfaces based on those requests. In this model, the database server +is the only application linking the Berkeley DB library into its address space. +The client-server model trades performance for protection, as it does not +require that the applications share a protection domain with the server, +but IPC/RPC is slower than a function call. Of course, in addition, this +model greatly simplifies the creation of network client-server applications. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/arch/script.html b/db/docs/ref/arch/script.html new file mode 100644 index 000000000..411cff460 --- /dev/null +++ b/db/docs/ref/arch/script.html @@ -0,0 +1,29 @@ + + + + + +Berkeley DB Reference Guide: Scripting languages + + + + + + +

Berkeley DB Reference Guide:
Architecture

PrevRefNext +
+

+

Scripting languages

+

Perl

+

Two Perl APIs are distributed with the Berkeley DB release. The Perl interface +to Berkeley DB version 1.85 is called DB_File. The Perl interface to Berkeley DB +version 2 is called BerkeleyDB. See Using Berkeley DB with Perl for more information. +

Tcl

+

A Tcl API is distributed with the Berkeley DB release. See +Using Berkeley DB with Tcl for more +information. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/arch/smallpic.gif b/db/docs/ref/arch/smallpic.gif new file mode 100644 index 000000000..5eb7ae8da Binary files /dev/null and b/db/docs/ref/arch/smallpic.gif differ diff --git a/db/docs/ref/arch/utilities.html b/db/docs/ref/arch/utilities.html new file mode 100644 index 000000000..72bfe52b2 --- /dev/null +++ b/db/docs/ref/arch/utilities.html @@ -0,0 +1,62 @@ + + + + + +Berkeley DB Reference Guide: Supporting utilities + + + + + + + +

Berkeley DB Reference Guide:
Architecture

PrevRefNext +
+

+

Supporting utilities

+

There are several stand-alone utilities that provide supporting +functionality for the Berkeley DB environment: +

+

berkeley_db_svc
The berkeley_db_svc utility is the Berkeley DB RPC server, providing +standard server functionality for client. applications. +

db_archive
The db_archive utility supports database backup, archival and log +file administration. It facilitates log reclamation and the creation of +database snapshots. Generally, some form of log archival must be done if +a database environment has been configured for logging or transactions. +

db_checkpoint
The db_checkpoint utility runs as a daemon process, monitoring +the database log and periodically issuing checkpoints. It facilitates +log reclamation and the creation of database snapshots. Generally, some +form of database checkpointing must be done if a database environment has +been configured for transactions. +

db_deadlock
The db_deadlock utility runs as a daemon process, periodically +traversing the database lock structures and aborting transactions when it +detects a deadlock. Generally, some form of deadlock detection must be +done if a database environment has been configured for locking. +

db_dump
The db_dump utility writes a copy of the database to a flat-text +file in a portable format. +

db_load
The db_load utility reads the flat-text file produced by +db_dump and loads it into a database file. +

db_printlog
The db_printlog utility displays the contents of Berkeley DB log files +in a human-readable and parseable format. +

db_recover
The db_recover utility runs after an unexpected Berkeley DB or system +failure to restore the database to a consistent state. Generally, some +form of database recovery must be done if databases are being modified. +

db_stat
The db_stat utility displays statistics for databases and database +environments. +

db_upgrade
The db_upgrade utility provides a command-line interface for +upgrading underlying database formats. +

db_verify
The db_verify utility provides a command-line interface for +verifying the database format. +
+

All of the functionality implemented for these utilities is also available +as part of the standard Berkeley DB API. This means that threaded applications +can easily create a thread that calls the same Berkeley DB functions as do the +utilities. This often simplifies an application environment by removing +the necessity for multiple processes to negotiate database and database +environment creation and shutdown. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/build_unix/aix.html b/db/docs/ref/build_unix/aix.html new file mode 100644 index 000000000..102e1a01f --- /dev/null +++ b/db/docs/ref/build_unix/aix.html @@ -0,0 +1,60 @@ + + + + + +Berkeley DB Reference Guide: AIX + + + + + + + +

Berkeley DB Reference Guide:
Building Berkeley DB for UNIX systems

PrevRefNext +
+

+

AIX

+

    +

  1. I can't compile and run multi-threaded applications. +

    Special compile-time flags are required when compiling threaded +applications on AIX. If you are compiling a threaded application, +you must compile with the _THREAD_SAFE flag and load with specific +libraries, e.g., "-lc_r". Specifying the compiler name with a +trailing "_r" usually performs the right actions for the system. +

    xlc_r ...
    +cc -D_THREAD_SAFE -lc_r ...
    +

    The Berkeley DB library will automatically build with the correct options. +


    +

  2. I can't run using the DB_SYSTEM_MEM option to +DBENV->open. +

    AIX 4.1 only allows applications to map 10 system shared memory segments. +In AIX 4.3 this has been raised to 256K segments, but only if you set the +environment variable "export EXTSHM=ON". +


    +

  3. I can't create database files larger than 1GB on AIX. +

    Berkeley DB does not include large-file support for AIX systems by default. +Sleepycat Software has been told that the following changes will add +large-file support on the AIX 4.2 and later releases, but we have not +tested them ourselves. +

    Add the following lines to the db_config.h file in your build +directory: +

    #ifdef	HAVE_FILE_OFFSET_BITS
    +#define	_LARGE_FILES		/* AIX specific. */
    +#endif
    +

    Change the source code for os/os_open.c to always specify the +O_LARGEFILE flag to the open(2) system call. +

    Recompile Berkeley DB from scratch. +

    Note that the documentation for the IBM Visual Age compiler states that +it does not not support the 64-bit filesystem APIs necessary for creating +large files, and that the ibmcxx product must be used instead. We have +not heard if the GNU gcc compiler supports the 64-bit APIs or not. +

    Finally, to create large files under AIX, the filesystem has to be +configured to support large files and the system wide user hard-limit for +file sizes has to be greater than 1GB. +

+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/build_unix/conf.html b/db/docs/ref/build_unix/conf.html new file mode 100644 index 000000000..289e9559e --- /dev/null +++ b/db/docs/ref/build_unix/conf.html @@ -0,0 +1,143 @@ + + + + + +Berkeley DB Reference Guide: Configuring Berkeley DB + + + + + + + +

Berkeley DB Reference Guide:
Building Berkeley DB for UNIX systems

PrevRefNext +
+

+

Configuring Berkeley DB

+

There are several options that you can specify when configuring Berkeley DB. +While only the Berkeley DB specific ones are described here, most of the +standard GNU autoconf options are available and supported. To see a +complete list of the options, specify the --help flag to the configure +program. +

The Berkeley DB specific options are as follows: +

+ +

--disable-bigfile
Some systems, notably versions of HP/UX and Solaris, require special +compile-time options in order to create files larger than 2^32 bytes. +These options are automatically enabled when Berkeley DB is compiled. For this +reason, binaries built on current versions of these systems may not run +on earlier versions of the system, as the library and system calls +necessary for large files are not available. To disable building with +these compile-time options, enter --disable-bigfile as an argument to +configure. + +

--enable-compat185
To compile or load Berkeley DB 1.85 applications against this release of the +Berkeley DB library, enter --enable-compat185 as an argument to configure. +This will include Berkeley DB 1.85 API compatibility code in the library. + +

--enable-cxx
To build the Berkeley DB C++ API, enter --enable-cxx as an argument to +configure. +

--enable-debug
To build Berkeley DB with -g as a compiler flag and with DEBUG +#defined during compilation, enter --enable-debug as an argument to +configure. This will create a Berkeley DB library with debugging symbols, as +well as load various routines that can be called from a debugger to +display pages, cursor queues and so forth. This option should not be +specified when configuring to build production binaries, although there +shouldn't be any significant performance degradation. +

--enable-debug_rop
To build Berkeley DB to output log records for read operations, enter +--enable-debug_rop as an argument to configure. This option should not +be specified when configuring to build production binaries, as you will +lose a significant amount of performance. +

--enable-debug_wop
To build Berkeley DB to output log records for write operations, enter +--enable-debug_wop as an argument to configure. This option should not +be specified when configuring to build production binaries, as you will +lose a significant amount of performance. +

--enable-diagnostic
To build Berkeley DB with debugging run-time sanity checks, enter +--enable-diagnostic as an argument to configure. This will cause a +number of special checks to be performed when Berkeley DB is running. This +option should not be specified when configuring to build production +binaries, as you will lose a significant amount of performance. + +

--enable-dump185
To convert Berkeley DB 1.85 (or earlier) databases to this release of Berkeley DB, +enter --enable-dump185 as an argument to configure. This will build the +db_dump185 utility which can dump Berkeley DB 1.85 and 1.86 databases +in a format readable by the Berkeley DB db_load utility. +

The system libraries with which you are loading the db_dump185 +utility must already contain the Berkeley DB 1.85 library routines for this to +work, as the Berkeley DB distribution does not include them. If you are using +a non-standard library for the Berkeley DB 1.85 library routines, you will have +to change the Makefile that the configuration step creates to load the +db_dump185 utility with that library. + + +

--enable-dynamic
To build a dynamic shared library version of Berkeley DB, instead of the default +static library, specify --enable-dynamic. Dynamic libraries are built +using the +GNU Project's Libtool distribution, which supports shared library builds +on many, although not all, systems. +

Berkeley DB can be configured to build either a static or a dynamic library, +but not both at once. You should not attempt to build both library +types in the same directory, as they have incompatible object file +formats. To build both static and dynamic libraries, create two +separate build directories, and configure and build them separately. + +

--enable-java
To build the Berkeley DB Java API, enter --enable-java as an argument to +configure. To build Java, you must also configure the option +--enable-dynamic. Before configuring, you must set your PATH environment +variable to include javac. Note, it is not sufficient to include a +symbolic link to javac in your PATH, because the configuration process +uses the location of javac to determine the location of the Java include +files (e.g., jni.h). On some systems additional include directories may +be needed to process jni.h, see Changing compile or load +options for more information. +

--enable-posixmutexes
To force Berkeley DB to use the POSIX pthread mutex interfaces for underlying +mutex support, enter --enable-posixmutexes as an argument to configure. +The Berkeley DB library requires that the POSIX pthread implementation support +mutexes shared between multiple processes, as described for the +pthread_condattr_setpshared and pthread_mutexattr_setpshared interfaces. +In addition, this configuration option requires that Berkeley DB be linked with +the -lpthread library. On systems where POSIX mutexes are the preferred +mutex support (e.g., HP-UX), they will be selected automatically. + +

--enable-rpc
To build the Berkeley DB RPC client code and server utility, enter --enable-rpc +as an argument to configure. The --enable-rpc option requires that RPC +libraries already be installed on your system. +

--enable-shared
The --enable-shared configure argument is an alias for --enable-dynamic. + +

--enable-tcl
To build the Berkeley DB Tcl API, enter --enable-tcl as an argument to +configure. This configuration option expects to find Tcl's tclConfig.sh +file in the /usr/local/lib directory. See the --with-tcl +option for instructions on specifying a non-standard location for the +Tcl installation. See Loading Berkeley DB +with Tcl for information on sites from which you can download Tcl and +which Tcl versions are compatible with Berkeley DB. To configure the Berkeley DB +Tcl API, you must also specify the --enable-dynamic option. + +

--enable-test
To build the Berkeley DB test suite, enter --enable-test as an argument to +configure. To run the Berkeley DB test suite, you must also specify the +--enable-dynamic and --enable-tcl options. +

--enable-uimutexes
To force Berkeley DB to use the UNIX International (UI) mutex interfaces for +underlying mutex support, enter --enable-uimutexes as an argument to +configure. This configuration option requires that Berkeley DB be linked with +the -lthread library. On systems where UI mutexes are the preferred mutex +support, (e.g., SCO's UnixWare 2), they will be selected automatically. +

--enable-umrw
Rational Software's Purify product and other run-time tools complain +about uninitialized reads/writes of structure fields whose only purpose +is padding, as well as when heap memory that was never initialized is +written to disk. Specify the --enable-umrw option during configuration +to mask these errors. This option should not be specified when +configuring to build production binaries, as you will lose a significant +amount of performance. +

--with-tcl=DIR
To build the Berkeley DB Tcl API, enter --with-tcl=DIR, replacing DIR with +the directory in which the Tcl tclConfig.sh file may be found. See +Loading Berkeley DB with Tcl for information +on sites from which you can download Tcl and which Tcl versions are +compatible with Berkeley DB. To configure the Berkeley DB Tcl API, you must also +specify the --enable-dynamic option. +
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/build_unix/flags.html b/db/docs/ref/build_unix/flags.html new file mode 100644 index 000000000..5b70b3d8d --- /dev/null +++ b/db/docs/ref/build_unix/flags.html @@ -0,0 +1,60 @@ + + + + + +Berkeley DB Reference Guide: Changing compile or load options + + + + + + + +

Berkeley DB Reference Guide:
Building Berkeley DB for UNIX systems

PrevRefNext +
+

+

Changing compile or load options

+

You can specify compiler and/or compile and load time flags by using +environment variables during Berkeley DB configuration. For example, if you +want to use a specific compiler, specify the CC environment variable +before running configure: +

prompt: env CC=gcc ../dist/configure
+

Using anything other than the native compiler will almost certainly mean +that you'll want to check the flags specified to the compiler and +loader, too. +

To specify debugging and optimization options for the C compiler, +use the CFLAGS environment variable: +

prompt: env CFLAGS=-O2 ../dist/configure
+

To specify header file search directories and other miscellaneous options +for the C preprocessor and compiler, use the CPPFLAGS environment variable: +

prompt: env CPPFLAGS=-I/usr/contrib/include ../dist/configure
+

To specify debugging and optimization options for the C++ compiler, +use the CXXFLAGS environment variable: +

prompt: env CXXFLAGS=-Woverloaded-virtual ../dist/configure
+

To specify miscellaneous options or additional library directories for +the linker, use the LDFLAGS environment variable: +

prompt: env LDFLAGS="-N32 -L/usr/local/lib" ../dist/configure
+

If you want to specify additional libraries, set the LIBS environment +variable before running configure. For example: +

prompt: env LIBS="-lposix -lsocket" ../dist/configure
+

would specify two additional libraries to load, "posix" and "socket". +

Make sure that you prepend -L to any library directory names and that you +prepend -I to any include file directory names! Also, if the arguments +you specify contain blank or tab characters, be sure to quote them as +shown above, i.e. with single or double quotes around the values you're +specifying for LIBS. +

The env command is available on most systems, and simply sets one or more +environment variables before running a command. If the env command is +not available to you, you can set the environment variables in your shell +before running configure. For example, in sh or ksh, you could do: +

prompt: LIBS="-lposix -lsocket" ../dist/configure
+

and in csh or tcsh, you could do: +

prompt: setenv LIBS "-lposix -lsocket"
+prompt: ../dist/configure
+

See your command shell's manual page for further information. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/build_unix/freebsd.html b/db/docs/ref/build_unix/freebsd.html new file mode 100644 index 000000000..3d3ff8116 --- /dev/null +++ b/db/docs/ref/build_unix/freebsd.html @@ -0,0 +1,57 @@ + + + + + +Berkeley DB Reference Guide: FreeBSD + + + + + + + +

Berkeley DB Reference Guide:
Building Berkeley DB for UNIX systems

PrevRefNext +
+

+

FreeBSD

+

    +

  1. I can't compile and run multi-threaded applications. +

    Special compile-time flags are required when compiling threaded +applications on FreeBSD. If you are compiling a threaded application, +you must compile with the _THREAD_SAFE and -pthread flags: +

    cc -D_THREAD_SAFE -pthread ...
    +

    The Berkeley DB library will automatically build with the correct options. +


    +

  2. I get occasional failures when running RPC-based programs under FreeBSD clients. +

    There is a known bug in the XDR implementation in the FreeBSD C library, +from Version 2.2 up to version 4.0-RELEASE, that causes certain sized +messages to fail and return a zero-filled reply to the client. A bug +report (#16028) has been filed with FreeBSD. The following patch is the +FreeBSD fix: +

    *** /usr/src/lib/libc/xdr/xdr_rec.c.orig	Mon Jan 10 10:20:42 2000
    +--- /usr/src/lib/libc/xdr/xdr_rec.c	Wed Jan 19 10:53:45 2000
    +***************
    +*** 558,564 ****
    +  	 * but we don't have any way to be certain that they aren't
    +  	 * what the client actually intended to send us.
    +  	 */
    +! 	if ((header & (~LAST_FRAG)) == 0)
    +  		return(FALSE);
    +  	rstrm->fbtbc = header & (~LAST_FRAG);
    +  	return (TRUE);
    +--- 558,564 ----
    +  	 * but we don't have any way to be certain that they aren't
    +  	 * what the client actually intended to send us.
    +  	 */
    +! 	if (header == 0)
    +  		return(FALSE);
    +  	rstrm->fbtbc = header & (~LAST_FRAG);
    +  	return (TRUE);
    +
    +
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/build_unix/hpux.html b/db/docs/ref/build_unix/hpux.html new file mode 100644 index 000000000..3fc50d73c --- /dev/null +++ b/db/docs/ref/build_unix/hpux.html @@ -0,0 +1,89 @@ + + + + + +Berkeley DB Reference Guide: HP-UX + + + + + + + +

Berkeley DB Reference Guide:
Building Berkeley DB for UNIX systems

PrevRefNext +
+

+

HP-UX

+

    +

  1. I can't specify the DB_SYSTEM_MEM flag to DBENV->open. +

    The shmget(2) interfaces are not always used on HP-UX, even +though they exist, as anonymous memory allocated using shmget(2) +cannot be used to store the standard HP-UX msemaphore semaphores. For +this reason, it may not be possible to specify the DB_SYSTEM_MEM +flag on some versions of HP-UX. (We have only seen this problem on HP-UX +10.XX, so the simplest workaround may be to upgrade your HP-UX release.) +


    +

  2. I can't specify both the DB_PRIVATE and DB_THREAD +flags to DBENV->open. +

    It is not possible to store the standard HP-UX msemaphore semaphores in +memory returned by malloc(3) in some versions of HP-UX. For +this reason, it may not be possible to specify both the DB_PRIVATE +and DB_THREAD flags on some versions of HP-UX. (We have only seen +this problem on HP-UX 10.XX, so the simplest workaround may be to upgrade +your HP-UX release.) +


    +

  3. During configuration I see a message that large file support has +been turned off. +

    Some HP-UX system include files redefine "open" when big-file support (the +HAVE_FILE_OFFSET_BITS and _FILE_OFFSET_BITS #defines) is enabled. This +causes problems when compiling for C++, where "open" is a legal +identifier, used in the Berkeley DB C++ API. For this reason, we automatically +turn off big-file support when Berkeley DB is configured with a C++ API. This +should not be a problem for applications unless there is a need to create +databases larger than 2GB. +


    +

  4. I can't compile and run multi-threaded applications. +

    Special compile-time flags are required when compiling threaded +applications on HP-UX. If you are compiling a threaded application, you +must compile with the _REENTRANT flag: +

    cc -D_REENTRANT ...
    +

    The Berkeley DB library will automatically build with the correct options. +


    +

  5. An ENOMEM error is returned from DBENV->open or +DBENV->remove. +

    Due to the constraints of the PA-RISC memory architecture, HP-UX does not +allow a process to map a file into its address space multiple times. +For this reason, each Berkeley DB environment may be opened only once by a +process on HP-UX, i.e., calls to DBENV->open will fail if the +specified Berkeley DB environment has been opened and not subsequently closed. +


    +

  6. When compiling with gcc, I see the following error: +

    #error "Large Files (ILP32) not supported in strict ANSI mode."
    +

    We believe this is an error in the HP-UX include files, but we don't +really understand it. The only workaround we have found is to add +-D__STDC_EXT__ to the C preprocessor defines as part of compilation. +


    +

  7. When using the Tcl or Perl APIs (including running the test suite) I +see the error "Can't shl_load() a library containing Thread Local Storage". +

    This problem happens when HP-UX has been configured to use pthread mutex +locking and an attempt is made to call Berkeley DB using the Tcl or Perl APIs. We +have never found any way to fix this problem as part of the Berkeley DB build +process. To work around the problem, rebuild tclsh or perl and modify its build +process to explicitly link it against the HP-UX pthread library (currently +/usr/lib/libpthread.a). +


    +

  8. When running an executable that has been dynamically linked +against the Berkeley DB library, I see the error "Can't find path for shared library" +even though I've correctly set the SHLIB_PATH environment variable. +

    By default, some versions of HP-UX ignore the dynamic library search path +specified by the SHLIB_PATH environment variable. To work around this, specify +the "+s" flag to ld when linking, or run +

    chatr +s enable -l /full/path/to/libdb-3.2.sl ...
    +

    on the executable that is not working. +

+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/build_unix/install.html b/db/docs/ref/build_unix/install.html new file mode 100644 index 000000000..7beb6f705 --- /dev/null +++ b/db/docs/ref/build_unix/install.html @@ -0,0 +1,60 @@ + + + + + +Berkeley DB Reference Guide: Installing Berkeley DB + + + + + + + +

Berkeley DB Reference Guide:
Building Berkeley DB for UNIX systems

PrevRefNext +
+

+

Installing Berkeley DB

+

Berkeley DB installs the following files into the following locations, with the +following default values: +

+ + + + + + + + + + + + +
Configuration VariablesDefault value
--prefix/usr/local/BerkeleyDB.Major.Minor
--exec_prefix$(prefix)
--bindir$(exec_prefix)/bin
--includedir$(prefix)/include
--libdir$(exec_prefix)/lib
docdir$(prefix)/docs
FilesDefault location
include files$(includedir)
libraries$(libdir)
utilities$(bindir)
documentation$(docdir)
+

With one exception, this follows the GNU Autoconf and GNU Coding +Standards installation guidelines, please see that documentation for +more information and rationale. +

The single exception is the Berkeley DB documentation. The Berkeley DB +documentation is provided in HTML format, not in UNIX-style man or GNU +info format. For this reason, Berkeley DB configuration does not support +--infodir or --mandir. To change the default +installation location for the Berkeley DB documentation, modify the Makefile +variable, docdir. +

To move the entire installation tree to somewhere besides +/usr/local, change the value of prefix. +

To move the binaries and libraries to a different location, change the +value of exec_prefix. The values of includedir and +libdir may be similarly changed. +

Any of these values except for docdir may be set as part +of configuration: +

prompt: ../dist/configure --bindir=/usr/local/bin
+

Any of these values, including docdir, may be changed when doing +the install itself: +

prompt: make prefix=/usr/contrib/bdb install
+

The Berkeley DB installation process will attempt to create any directories that +do not already exist on the system. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/build_unix/intro.html b/db/docs/ref/build_unix/intro.html new file mode 100644 index 000000000..b2c0d613b --- /dev/null +++ b/db/docs/ref/build_unix/intro.html @@ -0,0 +1,60 @@ + + + + + +Berkeley DB Reference Guide: Building for UNIX + + + + + + + +

Berkeley DB Reference Guide:
Building Berkeley DB for UNIX systems

PrevRefNext +
+

+

Building for UNIX

+

The Berkeley DB distribution builds up to four separate libraries: the base C +API Berkeley DB library and the optional C++, Java and Tcl API libraries. For +portability reasons each library is standalone and contains the full Berkeley DB +support necessary to build applications, that is, the C++ API Berkeley DB +library does not require any other Berkeley DB libraries to build and run C++ +applications. +

The Berkeley DB distribution uses the Free Software Foundation's +autoconf and +libtool +tools to build on UNIX platforms. In general, the standard configuration +and installation options for these tools apply to the Berkeley DB distribution. +

To perform the default UNIX build of Berkeley DB, first change to the +build_unix directory, and then enter the following two commands: +

../dist/configure
+make
+

This will build the Berkeley DB library. +

To install the Berkeley DB library, enter: +

make install
+

To rebuild Berkeley DB, enter: +

make clean
+make
+

If you change your mind about how Berkeley DB is to be configured, you must start +from scratch by entering: +

make realclean
+../dist/configure
+make
+

To build multiple UNIX versions of Berkeley DB in the same source tree, create a +new directory at the same level as the build_unix directory, and then +configure and build in that directory: +

mkdir build_bsdos3.0
+cd build_bsdos3.0
+../dist/configure
+make
+

If you have trouble with any of these commands, please send email to the +addresses found in the Sleepycat Software contact information. In that +email, please provide a complete copy of the commands that you entered +and any output, along with a copy of any config.log or +config.cache files created during configuration. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/build_unix/irix.html b/db/docs/ref/build_unix/irix.html new file mode 100644 index 000000000..af31b6e68 --- /dev/null +++ b/db/docs/ref/build_unix/irix.html @@ -0,0 +1,30 @@ + + + + + +Berkeley DB Reference Guide: IRIX + + + + + + + +

Berkeley DB Reference Guide:
Building Berkeley DB for UNIX systems

PrevRefNext +
+

+

IRIX

+

    +

  1. I can't compile and run multi-threaded applications. +

    Special compile-time flags are required when compiling threaded +applications on IRIX. If you are compiling a threaded application, you +must compile with the _SGI_MP_SOURCE flag: +

    cc -D_SGI_MP_SOURCE ...
    +

    The Berkeley DB library will automatically build with the correct options. +

+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/build_unix/linux.html b/db/docs/ref/build_unix/linux.html new file mode 100644 index 000000000..b6e2b93fb --- /dev/null +++ b/db/docs/ref/build_unix/linux.html @@ -0,0 +1,30 @@ + + + + + +Berkeley DB Reference Guide: Linux + + + + + + + +

Berkeley DB Reference Guide:
Building Berkeley DB for UNIX systems

PrevRefNext +
+

+

Linux

+

    +

  1. I can't compile and run multi-threaded applications. +

    Special compile-time flags are required when compiling threaded +applications on Linux. If you are compiling a threaded application, you +must compile with the _REENTRANT flag: +

    cc -D_REENTRANT ...
    +

    The Berkeley DB library will automatically build with the correct options. +

+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/build_unix/notes.html b/db/docs/ref/build_unix/notes.html new file mode 100644 index 000000000..dcb975e3c --- /dev/null +++ b/db/docs/ref/build_unix/notes.html @@ -0,0 +1,138 @@ + + + + + +Berkeley DB Reference Guide: Architecture independent FAQs + + + + + + + +

Berkeley DB Reference Guide:
Building Berkeley DB for UNIX systems

PrevRefNext +
+

+

Architecture independent FAQs

+

    +

  1. When compiling with gcc, I get unreferenced symbols, e.g.,: +

    symbol __muldi3: referenced symbol not found
    +symbol __cmpdi2: referenced symbol not found
    +

    On systems where they're available (e.g., HP-UX, Solaris), Berkeley DB uses +64-bit integral types. As far as we can tell, some versions of gcc +don't support these types. The simplest workaround is to reconfigure +Berkeley DB using the --disable-bigfile configuration option, and then rebuild. +


    +

  2. My C++ program traps during a failure in a DB call on my +gcc-based system. +

    We believe there are some severe bugs in the implementation of exceptions +for some gcc compilers. Exceptions require some interaction between +compiler, assembler, runtime libraries, and we're not sure exactly what +is at fault, but one failing combination is gcc 2.7.2.3 running on SuSE +Linux 6.0. The problem on this system can be seen with a rather simple +test case of an exception thrown from a shared library and caught in the +main program. +

    A variation of this problem seems to occur on AIX, although we believe it +does not necessarily involve shared libraries on that platform. +

    If you see a trap that occurs when an exception might be thrown by the DB +runtime, we suggest that you use static libraries instead of dynamic +(shared) libraries. See the documentation for configuration. If this +doesn't work, and you have a choice of compilers, try using a more recent +gcc or a non-gcc based compiler to build Berkeley DB. +

    Finally, you can disable the use of exceptions in the C++ runtime for +Berkeley DB by using the DB_CXX_NO_EXCEPTIONS flag with +db_env_create or db_create. When this flag is on, all +C++ methods fail by returning an error code rather than throwing an +exception. +


    +

  3. I get unexpected results and database corruption when running +threaded programs. +

    I get error messages that mutex (e.g., pthread_mutex_XXX or +mutex_XXX) functions are undefined when linking applications with Berkeley DB. +

    On some architectures, the Berkeley DB library uses the ISO POSIX standard +pthreads and UNIX International (UI) threads interfaces for underlying +mutex support, e.g., Solaris and HP-UX. You can specify compilers, +compiler flags or link with the appropriate thread library when loading +your application, to resolve the undefined references: +

    cc ... -lpthread ...
    +cc ... -lthread ...
    +xlc_r ...
    +cc ... -mt ...
    +

    See the appropriate architecture-specific Reference Guide pages for more +information. +

    On systems where more than one type of mutex is available, it may be +necessary for applications to use the same threads package from which +Berkeley DB draws its mutexes, e.g., if Berkeley DB was built to use the POSIX +pthreads mutex calls for mutex support, the application may need to be +written to use the POSIX pthreads interfaces for its threading model. +While this is only conjecture at this time and we know of no systems that +actually have this requirement, it's not unlikely that some exist. +

    In a few cases, Berkeley DB can be configured to use specific underlying mutex +interfaces. You can use the --enable-posixmutexes and +--enable-uimutexes configuration options to specify the POSIX and Unix +International (UI) threads packages. This should not, however, be +necessary in most cases. +

    In some cases, it is vitally important to make sure that you load +the correct library. For example, on Solaris systems, there are POSIX +pthread interfaces in the C library, and so applications can link Berkeley DB +using only C library and not see any undefined symbols. However, the C +library POSIX pthread mutex support is insufficient for Berkeley DB and Berkeley DB +cannot detect that fact. Similar errors can arise when applications +(e.g., tclsh) use dlopen to dynamically load Berkeley DB as a library. +

    If you are seeing problems in this area after you've confirmed that you're +linking with the correct libraries, there are two other things you can +try. First, if your platform supports inter-library dependencies, we +recommend that you change the Berkeley DB Makefile to specify the appropriate +threads library when creating the Berkeley DB dynamic library, as an +inter-library dependency. Second, if your application is using dlopen to +dynamically load Berkeley DB, specify the appropriate thread library on the link +line when you load the application itself. +


    +

  4. I get core dumps when running programs that fork children. +

    Berkeley DB handles should not be shared across process forks, each forked +child should acquire its own Berkeley DB handles. +


    +

  5. I get reports of uninitialized memory reads and writes when +running software analysis tools (e.g., Rational Software Corp.'s Purify +tool). +

    For performance reasons, Berkeley DB does not write the unused portions of +database pages or fill in unused structure fields. To turn off these +errors when running software analysis tools, build with the +--enable-umrw configuration option. +


    +

  6. Berkeley DB programs or the test suite fail unexpectedly. +

    The Berkeley DB architecture does not support placing the shared memory regions +on remote filesystems, e.g., the Network File System (NFS) or the Andrew +File System (AFS). For this reason, the shared memory regions (normally +located in the database home directory) must reside on a local filesystem. +See Shared Memory Regions for more +information. +

    With respect to running the test suite, always check to make sure that +TESTDIR is not on a remote mounted filesystem. +


    +

  7. The db_dump185 utility fails to build. +

    The db_dump185 utility is the utility that supports conversion +of Berkeley DB 1.85 and earlier databases to current database formats. If +the errors look something like: +

    cc -o db_dump185 db_dump185.o
    +ld:
    +Unresolved:
    +dbopen
    +

    it means that the Berkeley DB 1.85 code was not found in the standard +libraries. To build db_dump185, the Berkeley DB version 1.85 code +must have already been built and installed on the system. If the Berkeley DB +1.85 header file is not found in a standard place, or the library is +not part of the standard libraries used for loading, you will need to +edit your Makefile, and change the lines: +

    DB185INC=
    +DB185LIB=
    +

    So that the system Berkeley DB 1.85 header file and library are found, e.g., +

    DB185INC=/usr/local/include
    +DB185LIB=-ldb185
    +
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/build_unix/osf1.html b/db/docs/ref/build_unix/osf1.html new file mode 100644 index 000000000..42ac8e767 --- /dev/null +++ b/db/docs/ref/build_unix/osf1.html @@ -0,0 +1,30 @@ + + + + + +Berkeley DB Reference Guide: OSF/1 + + + + + + + +

Berkeley DB Reference Guide:
Building Berkeley DB for UNIX systems

PrevRefNext +
+

+

OSF/1

+

    +

  1. I can't compile and run multi-threaded applications. +

    Special compile-time flags are required when compiling threaded +applications on OSF/1. If you are compiling a threaded application, you +must compile with the _REENTRANT flag: +

    cc -D_REENTRANT ...
    +

    The Berkeley DB library will automatically build with the correct options. +

+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/build_unix/qnx.html b/db/docs/ref/build_unix/qnx.html new file mode 100644 index 000000000..29c90dc98 --- /dev/null +++ b/db/docs/ref/build_unix/qnx.html @@ -0,0 +1,58 @@ + + + + + +Berkeley DB Reference Guide: QNX + + + + + + + +

Berkeley DB Reference Guide:
Building Berkeley DB for UNIX systems

PrevRefNext +
+

+

QNX

+

    +

  1. To what versions of QNX has DB been ported? +

    Berkeley DB has been ported to the QNX Neutrino technology which is commonly +referred to as QNX RTP (Real-Time Platform). Berkeley DB has not been +ported to earlier versions of QNX, such as QNX 4.25. +

  2. What is the impact of QNX's use of shm_open(2) for +shared memory regions? +

    QNX requires the use of the POSIX shm_open(2) and +shm_unlink(2) calls for shared memory regions that will later +be mapped into memory using mmap(2). QNX's implementation +of the shared memory functions requires that the name given must begin +with a slash, and that no other slash may appear in the name. +

    In order to comply with those requirements and allow relative pathnames +to find the same environment, Berkeley DB uses only the last component of the +home directory path and the name of the shared memory file, separated +by a colon, as the name specified to the shared memory functions. For +example, if an application specifies a home directory of +/home/db/DB_DIR, Berkeley DB will use /DB_DIR:__db.001 as +the name for the shared memory area argument to shm_open(2). +

    The impact of this decision is that the last component of all +environment home directory pathnames on QNX must be unique with respect +to each other. Additionally, Berkeley DB requires that environments use home +directories for QNX in order to generate a reasonable entry in the +shared memory area. +

  3. What are the implications of QNX's requirement to use +shm_open(2) in order to use mmap(2)? +

    QNX requires that files mapped with mmap(2) be opened using +shm_open(2). There are other places in addition to the +environment shared memory regions, where Berkeley DB tries to memory map files +if it can. +

    The memory pool subsystem normally attempts to use mmap(2) +even when using private memory, as indicated by the DB_PRIVATE +flag to DBENV->open. In the case of QNX, if an application is +using private memory, Berkeley DB will not attempt to map the memory and will +instead use the local cache. +

+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/build_unix/sco.html b/db/docs/ref/build_unix/sco.html new file mode 100644 index 000000000..dda8e6d1d --- /dev/null +++ b/db/docs/ref/build_unix/sco.html @@ -0,0 +1,29 @@ + + + + + +Berkeley DB Reference Guide: SCO + + + + + + + +

Berkeley DB Reference Guide:
Building Berkeley DB for UNIX systems

PrevRefNext +
+

+

SCO

+

    +

  1. If I build with gcc, programs like db_dump, db_stat core dump immediately +when invoked. +

    We suspect gcc or the runtime loader may have a bug, but we haven't +tracked it down. If you want to use gcc, we suggest building static +libraries. +

+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/build_unix/shlib.html b/db/docs/ref/build_unix/shlib.html new file mode 100644 index 000000000..2819651cd --- /dev/null +++ b/db/docs/ref/build_unix/shlib.html @@ -0,0 +1,94 @@ + + + + + +Berkeley DB Reference Guide: Dynamic shared libraries + + + + + + + +

Berkeley DB Reference Guide:
Building Berkeley DB for UNIX systems

PrevRefNext +
+

+

Dynamic shared libraries

+

Warning: the following information is intended to be generic and +is likely to be correct for most UNIX systems. Unfortunately, dynamic +shared libraries are not standard between UNIX systems, so there may be +information here that is not correct for your system. If you have +problems, consult your compiler and linker manual pages or your system +administrator. +

The Berkeley DB dynamic shared libraries are created with the name +libdb-major.minor.so, where major is the major +version number and minor is the minor version number. Other +shared libraries are created if Java and Tcl support are enabled, +specifically libdb_java-major.minor.so and +libdb_tcl-major.minor.so. +

On most UNIX systems, when any shared library is created, the linker +stamps it with a "SONAME". In the case of Berkeley DB, the SONAME is +libdb-major.minor.so. It is important to realize that +applications linked against a shared library remember the SONAMEs of the +libraries they use and not the underlying names in the filesystem. +

When the Berkeley DB shared library is installed, links are created in the +install lib directory so that libdb-major.minor.so, +libdb-major.so and libdb.so all reference the same library. This +library will have an SONAME of libdb-major.minor.so. +

Any previous versions of the Berkeley DB libraries that are present in the +install directory (such as libdb-2.7.so or libdb-2.so) are left unchanged. +(Removing or moving old shared libraries is one drastic way to identify +applications that have been linked against those vintage releases.) +

Once you have installed the Berkeley DB libraries, unless they are installed in +a directory where the linker normally looks for shared libraries, you will +need to specify the installation directory as part of compiling and +linking against Berkeley DB. Consult your system manuals or system +administrator for ways to specify a shared library directory when +compiling and linking applications with the Berkeley DB libraries. Many systems +support environment variables (e.g., LD_LIBRARY_PATH, LD_RUN_PATH) ), or +system configuration files (e.g., /etc/ld.so.conf) for this purpose. +

Warning: some UNIX installations may have an already existing +/usr/lib/libdb.so, and this library may be an incompatible +version of Berkeley DB. +

We recommend that applications link against libdb.so (e.g., using -ldb). +Even though the linker uses the file named libdb.so, the executable file +for the application remembers the library's SONAME +(libdb-major.minor.so). This has the effect of marking +the applications with the versions they need at link time. Because +applications locate their needed SONAMEs when they are executed, all +previously linked applications will continue to run using the library they +were linked with, even when a new version of Berkeley DB is installed and the +file libdb.so is replaced with a new version. +

Applications that know they are using features specific to a particular +Berkeley DB release can be linked to that release. For example, an application +wanting to link to Berkeley DB major release "3" can link using -ldb-3, and +applications that know about a particular minor release number can specify +both major and minor release numbers, for example, -ldb-3.5. +

If you want to link with Berkeley DB before performing library installation, +the "make" command will have created a shared library object in the +.libs subdirectory of the build directory, such as +build_unix/.libs/libdb-major.minor.so. If you want to link a +file against this library, with, for example, a major number of "3" and +a minor number of "5", you should be able to do something like: +

cc -L BUILD_DIRECTORY/.libs -o testprog testprog.o -ldb-3.5
+env LD_LIBRARY_PATH="BUILD_DIRECTORY/.libs:$LD_LIBRARY_PATH" ./testprog
+

where BUILD_DIRECTORY is the full directory path to the directory +where you built Berkeley DB. +

The libtool program (which is configured in the build_unix directory) can +be used to set the shared library path and run a program. For example, +

libtool gdb db_dump
+

runs the gdb debugger on the db_dump utility after setting the appropriate +paths. Libtool may not know what to do with arbitrary commands (it is +hardwired to recognize "gdb" and some other commands). If it complains +the mode argument will usually resolve the problem: +

libtool --mode=execute my_debugger db_dump
+

On most systems, using libtool in this way is exactly equivalent to +setting the LD_LIBRARY_PATH environment variable and then executing the +program. On other systems, using libtool has the virtue of knowing about +any other details on systems that don't behave in this typical way. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/build_unix/solaris.html b/db/docs/ref/build_unix/solaris.html new file mode 100644 index 000000000..8239537a8 --- /dev/null +++ b/db/docs/ref/build_unix/solaris.html @@ -0,0 +1,90 @@ + + + + + +Berkeley DB Reference Guide: Solaris + + + + + + + +

Berkeley DB Reference Guide:
Building Berkeley DB for UNIX systems

PrevRefNext +
+

+

Solaris

+

    +

  1. I can't compile and run multi-threaded applications. +

    Special compile-time flags and additional libraries are required when +compiling threaded applications on Solaris. If you are compiling a +threaded application, you must compile with the D_REENTRANT flag and link +with the libpthread.a or libthread.a libraries: +

    cc -mt ...
    +cc -D_REENTRANT ... -lthread
    +cc -D_REENTRANT ... -lpthread
    +

    The Berkeley DB library will automatically build with the correct options. +


    +

  2. I've installed gcc on my Solaris system, but configuration +fails because the compiler doesn't work. +

    On some versions of Solaris, there is a cc executable in the user's path, +but all it does is display an error message and fail: +

    % which cc
    +/usr/ucb/cc
    +% cc
    +/usr/ucb/cc: language optional software package not installed
    +

    As Berkeley DB always uses the native compiler in preference to gcc, this is a +fatal error. If the error message you're seeing is: +

    checking whether the C compiler (cc -O ) works... no
    +configure: error: installation or configuration problem: C compiler cannot create executables.
    +

    then this may be the problem you're seeing. The simplest workaround is +to set your CC environment variable to the system compiler, e.g.: +

    env CC=gcc ../dist/configure
    +

    and reconfigure. +

    If you are using the --configure-cxx option, you may also want to specify +a C++ compiler, e.g.: +

    env CC=gcc CCC=g++ ../dist/configure
    +
    +

  3. I get the error +"libc internal error: _rmutex_unlock: rmutex not held", followed by a core +dump, when running threaded or JAVA programs. +

    This is a known bug in Solaris 2.5 and it is fixed by Sun patch 103187-25. +


    +

  4. I get error reports of non-existent files, corrupted metadata +pages and core dumps. +

    Solaris 7 contains a bug in the threading libraries (-lpthread, -lthread) +which causes the wrong version of the pwrite routine to be linked into +the application if the thread library is linked in after the the C +library. The result will be that the pwrite function is called rather +than the pwrite64. To work around the problem, use an explicit link order +when creating your application. +

    Sun Microsystems is tracking this problem with Bug Id's 4291109 and 4267207, +and patch 106980-09 to Solaris 7 fixes the problem. +

    Bug Id: 4291109
    +Duplicate of: 4267207
    +Category: library
    +Subcategory: libthread
    +State: closed
    +Synopsis: pwrite64 mapped to pwrite
    +Description:
    +When libthread is linked after libc, there is a table of functions in
    +libthread that gets "wired into" libc via _libc_threads_interface().
    +The table in libthread is wrong in both Solaris 7 and on28_35 for the
    +TI_PWRITE64 row (see near the end).
    +
    +

  5. During configuration I see a message that large file support has +been turned off. +

    The Solaris 8 system include files redefine "open" when big-file support (the +HAVE_FILE_OFFSET_BITS and _FILE_OFFSET_BITS #defines) is enabled. This +causes problems when compiling for C++, where "open" is a legal +identifier, used in the Berkeley DB C++ API. For this reason, we automatically +turn off big-file support when Berkeley DB is configured with a C++ API. This +should not be a problem for applications unless there is a need to create +databases larger than 2GB. +

+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/build_unix/sunos.html b/db/docs/ref/build_unix/sunos.html new file mode 100644 index 000000000..cecccaefb --- /dev/null +++ b/db/docs/ref/build_unix/sunos.html @@ -0,0 +1,30 @@ + + + + + +Berkeley DB Reference Guide: SunOS + + + + + + + +

Berkeley DB Reference Guide:
Building Berkeley DB for UNIX systems

PrevRefNext +
+

+

SunOS

+

    +

  1. I can't specify the DB_SYSTEM_MEM flag to DBENV->open. +

    The shmget(2) interfaces are not used on SunOS releases prior +to 5.0, even though they apparently exist, as the distributed include +files did not allow them to be compiled. For this reason, it will not be +possible to specify the DB_SYSTEM_MEM flag those versions of +SunOS. +

+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/build_unix/test.html b/db/docs/ref/build_unix/test.html new file mode 100644 index 000000000..9ae398980 --- /dev/null +++ b/db/docs/ref/build_unix/test.html @@ -0,0 +1,49 @@ + + + + + +Berkeley DB Reference Guide: Running the test suite under UNIX + + + + + + + +

Berkeley DB Reference Guide:
Building Berkeley DB for UNIX systems

PrevRefNext +
+

+

Running the test suite under UNIX

+

The Berkeley DB test suite is built if you specify --enable-test as an +argument when configuring Berkeley DB. +

Before running the tests for the first time, you may need to edit the +include.tcl file in your build directory. The Berkeley DB +configuration assumes you intend to use the version of the tclsh utility +included in the Tcl installation with which Berkeley DB was configured to run +the test suite, and further assumes that the test suite will be run with +the libraries pre-built in the Berkeley DB build directory. If either of these +assumptions are incorrect, you will need to edit the include.tcl +file and change the line that reads: +

set tclsh_path ...
+

to correctly specify the full path to the version of tclsh with which you +are going to run the test suite. You may also need to change the line +that reads: +

set test_path ...
+

to correctly specify the path from the directory where you are running +the test suite to the location of the Berkeley DB Tcl API library you built. +It may not be necessary that this be a full path if you have configured +your system's dynamic shared library mechanisms to search the directory +where you built or installed the Tcl library. +

All Berkeley DB tests are run from within tclsh. After starting tclsh, +you must source the file test.tcl in the test directory. For +example, if you built in the build_unix directory of the +distribution, this would be done using the command: +

% source ../test/test.tcl
+

Once you have executed that command and the "%" prompt has returned +without errors, you are ready to run tests in the test suite. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/build_unix/ultrix.html b/db/docs/ref/build_unix/ultrix.html new file mode 100644 index 000000000..e71946c88 --- /dev/null +++ b/db/docs/ref/build_unix/ultrix.html @@ -0,0 +1,27 @@ + + + + + +Berkeley DB Reference Guide: Ultrix + + + + + + + +

Berkeley DB Reference Guide:
Building Berkeley DB for UNIX systems

PrevRefNext +
+

+

Ultrix

+

    +

  1. Configuration complains that mmap(2) interfaces aren't being used. +

    The mmap(2) interfaces are not used on Ultrix, even though +they exist, as they are known to not work correctly. +

+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/build_vxworks/faq.html b/db/docs/ref/build_vxworks/faq.html new file mode 100644 index 000000000..cea733d7f --- /dev/null +++ b/db/docs/ref/build_vxworks/faq.html @@ -0,0 +1,85 @@ + + + + + +Berkeley DB Reference Guide: VxWorks FAQ + + + + + + + +

Berkeley DB Reference Guide:
Building Berkeley DB for VxWorks systems

PrevRefNext +
+

+

VxWorks FAQ

+

    +

  1. Can I run the test suite under VxWorks? +

    The test suite requires the Berkeley DB Tcl library. In turn, this library +requires Tcl 8.1 or greater. In order to run the test suite, you would +need to port Tcl 8.1 or greater to VxWorks. The Tcl shell included in +windsh is not adequate for two reasons. First, it is based on +Tcl 8.0. Second, it does not include the necessary Tcl components for +adding a Tcl extension. +

  2. Are all Berkeley DB features available for VxWorks? +

    All Berkeley DB features are available for VxWorks with the exception of the +DB_TRUNCATE flag for DB->open. The underlying mechanism +needed for that flag is not available consistently across different file +systems for VxWorks. +

  3. Are there any constraints using particular file system drivers? +

    There are constraints using the dosFs file systems with Berkeley DB. Namely, +you must configure your dosFs file system to support long file names if +you are using Berkeley DB logging in your application. The VxWorks' dosFs +1.0 file system, by default, uses the old MS-DOS 8.3 file naming +constraints, restricting to 8 character file names with a 3 character +extension. If you have configured with VxWorks' dosFs 2.0 you should +be compatible with Windows FAT32 filesystems which supports long +filenames. +

  4. Are there any dependencies on particular file system drivers? +

    There is one dependency on specifics of file system drivers in the port +of Berkeley DB to VxWorks. Berkeley DB synchronizes data using the FIOSYNC function +to ioctl() (another option would have been to use the FIOFLUSH function +instead). The FIOSYNC function was chosen because the NFS client driver, +nfsDrv, only supports it and doesn't support FIOFLUSH. All local file +systems, as of VxWorks 5.4, support FIOSYNC with the exception of +rt11fsLib, which only supports FIOFLUSH. To use rt11fsLib, you will need +to modify the os/os_fsync.c file to use the FIOFLUSH function; note that +rt11fsLib cannot work with NFS clients. +

  5. Are there any known file system problems? +

    During the course of our internal testing we came across two problems +with the dosFs 2.0 file system that warranted patches from Wind River Systems. +You should ask Wind River Systems for the patches to these +problems if you encounter them. +

    The first problem is that files will seem to disappear. You should +look at SPR 31480 in the Wind River Systems' Support pages for +a more detailed description of this problem. +

    The second problem is a semaphore deadlock within the dosFs file system +code. Looking at a stack trace via CrossWind, you will see two or more of +your application's tasks waiting in semaphore code within dosFs. The patch +for this problem is under SPR 33221 at Wind River Systems. +

  6. Are there any file systems I cannot use? +

    The Target Server File System (TSFS) uses the netDrv driver. This driver +does not support any ioctl that allows flushing to the disk and therefore +cannot be used with Berkeley DB. +

  7. Why aren't the utility programs part of the project? +

    The utility programs, in their Unix-style form, are not ported to VxWorks. +The reasoning is the utility programs are essentially wrappers for the +specific Berkeley DB interface they call. Their interface and generic model +are not the appropriate paradigm for VxWorks. It is most likely that +specific applications will want to spawn tasks that call the appropriate +Berkeley DB function to perform the actions of some utility programs, using +VxWorks native functions. For example, an application that spawns several +tasks that all may operate on the same database would also want to spawn +a task that calls lock_detect for deadlock detection, but specific +to the environment used for that application. +

  8. What VxWorks primitives are used for mutual exclusion in Berkeley DB? +

    Mutexes inside of Berkeley DB use the basic binary semaphores in VxWorks. The +mutexes are created using the FIFO queue type. +

+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/build_vxworks/intro.html b/db/docs/ref/build_vxworks/intro.html new file mode 100644 index 000000000..593b8a1e6 --- /dev/null +++ b/db/docs/ref/build_vxworks/intro.html @@ -0,0 +1,86 @@ + + + + + +Berkeley DB Reference Guide: Building for VxWorks + + + + + + + +

Berkeley DB Reference Guide:
Building Berkeley DB for VxWorks systems

PrevRefNext +
+

+

Building for VxWorks

+

The build_vxworks directory in the Berkeley DB distribution contains a workspace +and project files for Tornado 2.0. +

+ + + + +
FileDescription
Berkeley DB.wsp Berkeley DB Workspace file
Berkeley DB.wpj Berkeley DB Project file
ex_*/*.wpj Example programs project files
+

Building With Tornado 2.0

+

Open the workspace Berkeley DB.wsp. The list of projects +in this workspace will be shown. These projects were created for +the x86 BSP for VxWorks. +

The remainder of this document assumes you already have a +VxWorks target and a target server, both up and running. +

First, you'll need to set the include directories. +To do this, go to the Builds tab for the workspace. +Open up Berkeley DB Builds. You will see several different +builds, containing different configurations. All of the projects +in the Berkeley DB workspace are created to be downloadable applications. +

+ + + + + + +
BuildDescription
PENTIUM_RPCdebug x86 BSP with RPC and debugging
PENTIUM_RPCnodebug x86 BSP with RPC no debugging
PENTIUM_debug x86 BSP no RPC with debugging
PENTIUM_nodebug x86 BSP no RPC no debugging
SIMSPARCSOLARISgnu VxSim BSP no RPC with debugging
+

You will have to add a new build specification if you are using a +different BSP or wish to customize further. For instance, if you have +the Power PC (PPC) BSP, you will need to add a new build for the PPC tool +chain. To do so, select the "Builds" tab and then select the Berkeley DB +project name and right click. Choose the New Build... +selection and create the new build target. For your new build target, +you will need to decide if you want it configured to support RPC and +whether it should be built for debugging. See the properties of the +Pentium builds for how to configure for each case. After you have added +this build you still need to correctly configure the include directories +as described below. +

Select the build you are interested in and right click. Choose the +Properties... selection. At this point, a tabbed dialogue +should appear. In this new window, choose the C/C++ compiler +tab. In the edit box, you need to modify the full pathname of the +build_vxworks subdirectory of Berkeley DB, followed by the full +pathname of the include subdirectory of Berkeley DB. Then click +OK. +

If the architecture for this new build has the most significant byte +first, you will also need to edit the db_config.h file in +the build directory and define WORDS_BIGENDIAN. +

To build and download the Berkeley DB downloadable application for the first time +requires several steps: +

    +

  1. Select the build you are interested in and right click. +Choose the Set ... as Active Build selection. +

  2. Select the build you are interested in and right click. +Choose the Dependencies ... selection. +Run dependencies over all files in the Berkeley DB project. +

  3. Select the build you are interested in and right click. +Choose the Rebuild All (Berkeley DB.out) selection. +

  4. Select the Berkeley DB project name and right click. +Choose the Download 'Berkeley DB.out' selection. +
+

You will need to repeat this procedure for +all builds you are interested in building, as well as for +all of the example project builds you wish to run. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/build_vxworks/notes.html b/db/docs/ref/build_vxworks/notes.html new file mode 100644 index 000000000..83de25511 --- /dev/null +++ b/db/docs/ref/build_vxworks/notes.html @@ -0,0 +1,56 @@ + + + + + +Berkeley DB Reference Guide: VxWorks notes + + + + + + + +

Berkeley DB Reference Guide:
Building Berkeley DB for VxWorks systems

PrevRefNext +
+

+

VxWorks notes

+

Berkeley DB currently disallows the DB_TRUNC flag to DB->open. +The operations this flag represent are not fully supported under +VxWorks 5.4. +

The memory on VxWorks is always resident and fully shared among all tasks +running on the target. For this reason, the DB_SYSTEM_MEM flag +is implied for any application that does not specify the +DB_PRIVATE flag. Additionally, applications must use a +segment ID to ensure different applications do not overwrite each other's +database environments. +See the DBENV->set_shm_key function for more information. +Also, the DB_LOCKDOWN flag has no effect. +

The DB->sync function is implemented using an ioctl call into the +file system driver with the FIOSYNC command. Most, but not all, file +system drivers support this call. Berkeley DB requires the use of a file system +supporting FIOSYNC. +

Building and Running the Example Programs

+

Each example program can be downloaded and run by calling the function +equivalent to the example's name. You may have to edit the pathname to +the environments and database names in the examples' sources. The +examples included are: +

+ + + + + + + +
NameDescription
ex_access Simple access method example.
ex_btrec Example using Btree and record numbers.
ex_dbclient Example running an RPC client. Takes a hostname as an argument, e.g., +ex_dbclient "myhost".
ex_env Example using an environment.
ex_mpool Example using mpools.
ex_tpcb Example using transactions. This example requires two invocations both +taking an integer identifier as an argument. This identifier allows for +multiple sets of databases to be used within the same environment. The +first is to initialize the databases, e.g., ex_tpcb_init 1. The +second is to run the program on those databases, e.g., ex_tpcb 1.
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/build_win/faq.html b/db/docs/ref/build_win/faq.html new file mode 100644 index 000000000..2c185b6da --- /dev/null +++ b/db/docs/ref/build_win/faq.html @@ -0,0 +1,49 @@ + + + + + +Berkeley DB Reference Guide: Windows FAQ + + + + + + + +

Berkeley DB Reference Guide:
Building Berkeley DB for Windows systems

PrevRefNext +
+

+

Windows FAQ

+

    +

  1. My Win* C/C++ application crashes in the Berkeley DB library when Berkeley DB calls +fprintf (or some other standard C library function). +

    You should be using the "Debug Multithreaded DLL" compiler option in +your application when you link with the +build_win32/Debug/libdb32d.lib library (this .lib file +is actually a stub for libdb32d.DLL). To check this +setting in Visual C++, choose the "Project/Settings" menu item, and +under the tab marked "C/C++", select "Code Generation" and see the box +marked "Use runtime library". This should be set to "Debug +Multithreaded DLL". If your application is linked against the static +library, build_win32/Debug/libdb32sd.lib, then you +will want to set "Use runtime library" to "Debug Multithreaded". +

    Setting this option incorrectly can cause multiple versions of the +standard libraries to be linked into your application (one on behalf +of your application, and one on behalf of the Berkeley DB library). That +violates assumptions made by these libraries, and traps can result. +

  2. Why are the build options for DB_DLL marked as "Use MFC in a Shared DLL"? +Does Berkeley DB use MFC? +

    Berkeley DB does not use MFC at all. It does however, call malloc and free and +other facilities provided by the Microsoft C runtime library. We've found +in our work that many applications and libraries are built assuming MFC, +and specifying this for Berkeley DB solves various interoperation issues, and +guarantees that the right runtime libraries are selected. Note that since +we do not use MFC facilities, the MFC library DLL is not marked as a +dependency for libdb.dll, but the appropriate Microsoft C runtime is. +

+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/build_win/intro.html b/db/docs/ref/build_win/intro.html new file mode 100644 index 000000000..6f5e0d4bb --- /dev/null +++ b/db/docs/ref/build_win/intro.html @@ -0,0 +1,143 @@ + + + + + +Berkeley DB Reference Guide: Building for Win32 + + + + + + + +

Berkeley DB Reference Guide:
Building Berkeley DB for Win32 platforms

PrevRefNext +
+

+

Building for Win32

+

The build_win32 directory in the Berkeley DB distribution contains project files +for both MSVC 5.0 and 6.0: +

+ + + +
Project FileDescription
Berkeley_DB.dsw Visual C++ 5.0 project (compatible with 6.0)
*.dsp Visual C++ 5.0 subprojects (compatible with 6.0 +)
+

These project files can be used to build Berkeley DB for any Win32 platform: +Windows 2000, Windows NT, Windows 98 and Windows 95. +

Building With Visual C++ 6.0

+

Open the file Berkeley_DB.dsw. You will be told that the project +was generated by a previous version of Developer Studio, and asked if you +want to convert the project. Select Yes, and all projects will be +converted. Then continue on with the instructions for building with +Visual C++ 5.0. +

Note that when you build a release version, you may receive a warning +about an unknown compiler option /Ob2. This is apparently a +flaw in the project conversion for Visual C++ and can be ignored. +

Each release of Berkeley DB is built and tested with this procedure using +Microsoft Visual C++ 6.0, Standard Edition. +

Building With Visual C++ 5.0

+

Open the file Berkeley_DB.dsw. This workspace includes a number +of subprojects needed to build Berkeley DB. +

First, you'll need to set the include directories. To do this, select +Options... from the Tools pull-down menu. At this +point, a tabbed dialogue should appear. In this new window, choose the +Directories tab. For the Platform, select +Win32 and for Show directories for select +Include files. Below these options in the list of directories, +you should add two directories: the full pathname of the +build_win32 subdirectory of Berkeley DB, followed by the full +pathname of the include subdirectory of Berkeley DB. Then click OK. +

Then, select Active Project Configuration under the +Build pull-down menu. For a debug version of the libraries, +tools and examples, select db_buildall - Win32 Debug. +Results from this build are put into build_win32/Debug. +For a release version, select db_buildall - Win32 Release; +results are put into build_win32/Release. +For a debug version that has all tools and examples built with +static libraries, select db_buildall - Win32 Debug Static; +results are put into build_win32/Debug_static. +For a release version of the same, +select db_buildall - Win32 Release Static; +results are put into build_win32/Release_static. +Finally, to build, select Build db_buildall.exe under the +Build pull-down menu. +

When building your application, you should normally use compile options +"debug multithreaded dll" and link against +build_win32/Debug/libdb32d.lib. If you want +to link against a static (non-DLL) version of the library, use the +"debug multithreaded" compile options and link against +build_win32/Debug_static/libdb32sd.lib. You can +also build using a release version of the libraries and tools, which will be +placed in build_win32/Release/libdb32.lib. +The static version will be in +build_win32/Release_static/libdb32s.lib. +

Each release of Berkeley DB is maintained, built and tested using Microsoft +Visual C++ 5.0 and 6.0. +

Including the C++ API

+

C++ support is built automatically on Win32. +

Including the Java API

+

Java support is not built automatically. The following instructions +assume you have installed the Sun Java Development Kit in +d:/java. Of course, if you've installed elsewhere, or have +different Java software, you will need to adjust the pathnames +accordingly. First, use the instructions above for Visual C++ 5.0 or 6.0 +to open the Tools/Options tabbed dialog for adding include directories. +In addition to the directories specified above, add +d:/java/include and d:/java/include/win32. These are +the directories needed when including jni.h. Now, before +clicking OK, under Show directories for, choose +Executable files. Add d:/java/bin. That directory +is needed to find javac. Now select OK. +

Select Active Project Configuration under the +Build pull-down menu. Choose db_java - Win32 +Release. To build, select Build +libdb_java32.dll under the Build pull-down +menu. This builds the Java support library for Berkeley DB and compiles all +the java files, placing the class files in the java/classes +subdirectory of Berkeley DB. Set your environment variable CLASSPATH to +include this directory, your environment variable PATH to include the +build_win32/Release subdirectory, and as a test, try running +the command: +

java com.sleepycat.examples.AccessExample
+

Including the Tcl API

+

Tcl support is not built automatically. See +Loading Berkeley DB with Tcl for information +on sites from which you can download Tcl and which Tcl versions are +compatible with Berkeley DB. +

The Tcl library must be built as the same build type as the Berkeley DB +library (both Release or both Debug). We have found that the binary +release of Tcl can be used with the Release configuration of Berkeley DB, but +for the Debug configuration, you will need to need to build Tcl from +sources. Before building Tcl, you will need to modify its makefile to +make sure you are building a debug version, including thread support. +This is because the set of DLLs linked into the Tcl executable must +match the corresponding set of DLLs used by Berkeley DB. +

These notes assume Tcl is installed as d:/tcl, but you can +change that if you wish. If you run using a different version of Tcl +than the one currently being used by Sleepycat Software, you will need +to change the name of the Tcl library used in the build (e.g., +tcl83d.lib) to the appropriate name. See +Projects->Settings->Link in the db_tcl subproject. +

Use the instructions above for +Visual C++ 5.0 or 6.0 to open the Tools/Options tabbed dialog +for adding include directories. In addition to the directories specified +above, add d:/tcl/include. This is the directory that contains +tcl.h. +Then, in that same dialog, show directories for "Library Files". +Add d:/tcl/lib (or whatever directory contains +tcl83d.lib in your distribution) to the list. Now select OK. +

Select Active Project Configuration under the +Build pull-down menu. Choose db_tcl - Win32 +Release. To build, select Build +libdb_tcl32.dll under the Build pull-down +menu. This builds the Tcl support library for Berkeley DB, placing the result +into build_win32/Release/libdb_tcl32.dll. +Selecting an Active Configuration of db_tcl - Win32 Debug +will build a debug version, placing the result into +build_win32/Debug/libdb_tcl32d.dll. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/build_win/notes.html b/db/docs/ref/build_win/notes.html new file mode 100644 index 000000000..483b101ec --- /dev/null +++ b/db/docs/ref/build_win/notes.html @@ -0,0 +1,56 @@ + + + + + +Berkeley DB Reference Guide: Windows notes + + + + + + + +

Berkeley DB Reference Guide:
Building Berkeley DB for Windows systems

PrevRefNext +
+

+

Windows notes

+
    +
  • Various Berkeley DB interfaces take a mode argument, intended to specify +the underlying file permissions for created files. Berkeley DB currently ignores +this argument on Windows systems. +

    It would be possible to construct a set of security attributes to pass to +CreateFile that accurately represents the mode. In the worst +case, this would involve looking up user and all group names and creating +an entry for each. Alternatively, we could call the _chmod +(partial emulation) function after file creation, although this leaves us +with an obvious race. +

    Practically speaking, however, these efforts would be largely meaningless +on FAT, the most common file system, which only has a "readable" and +"writeable" flag, applying to all users. +

  • When using the DB_SYSTEM_MEM flag, Berkeley DB shared regions are +created without ACLs, which means that the regions are only accessible +to a single user. If wider sharing is appropriate (e.g., both user +applications and Windows/NT service applications need to access the +Berkeley DB regions), the Berkeley DB code will need to be modified to create the +shared regions with the correct ACLs. Alternatively, by not specifying +the DB_SYSTEM_MEM flag, file-system backed regions will be +created instead, and the permissions on those files may be directly +specified through the DBENV->open interface. +
  • On Windows/9X, files opened by multiple processes do not share data +correctly. For this reason, the DB_SYSTEM_MEM flag is implied +for any application that does not specify the DB_PRIVATE flag, +causing the system paging file to be used for sharing data. However, +paging file memory is freed on last close, implying that multiple +processes sharing an environment must arrange for at least one process +to always have the environment open, or, alternatively, that any process +joining the environment be prepared to re-create it. If a shared +environment is closed by all processes, a subsequent open without +specifying the DB_CREATE flag will result in the return of a +system EAGAIN error code. +
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/build_win/test.html b/db/docs/ref/build_win/test.html new file mode 100644 index 000000000..e3230ca84 --- /dev/null +++ b/db/docs/ref/build_win/test.html @@ -0,0 +1,77 @@ + + + + + +Berkeley DB Reference Guide: Running the test suite under Windows + + + + + + + +

Berkeley DB Reference Guide:
Building Berkeley DB for Windows systems

PrevRefNext +
+

+

Running the test suite under Windows

+

To build the test suite on Win32 platforms you will need to configure +Tcl support. You will also need sufficient main memory and disk. +Something around 100MB of disk will be sufficient. For memory, 32MB is +too small, we recommend at least 64MB. +

Building the software needed by the tests

+

There exist bugs in some versions of Tcl that may cause the test suite +to hang on Windows/NT 4.0. Tcl version 8.4 (currently available as an +alpha release) has fixed the problem, or there are patches available +for Tcl 8.3.2 (see bug #119188 in the Tcl SourceForge database). Note +that if you want to run the test suite against a Debug version of Berkeley DB, +you need to build a debug version of Tcl. This involves building Tcl +from its source. +

To build, perform the following steps. Note that steps #1, #4 and #5 +are part of the normal build process for building Berkeley DB; #2, #3 are part +of including the Tcl API. +

    +

  1. Open the build_win32/Berkeley_DB.dsw workspace. +

  2. Add the pathname for the Tcl include subdirectory to your +include path. To do this, under the "Tools" menu item, select "Options". +In the dialog, select the "Directories" tab, and choose directories +for "Include Files". Add d:/tcl/include (or whatever directory +contains tcl.h in your distribution) to the list. +

  3. Add the pathname for the Tcl library subdirectory to your +library path. To do this, under the "Tools" menu item, select "Options". +In the dialog, select the "Directories" tab, and choose directories for +"Library Files". Add d:/tcl/lib (or whatever directory contains +tcl83d.lib in your distribution) to the list. +

  4. Set the active configuration to db_test -- Debug. To set an +active configuration, under the "Build" menu item in the IDE, select "Set +Active Configuration". Then choose "db_test -- Debug". +

  5. Build. The IDE menu for this is called "build dbkill.exe", +even though dbkill is just one of the things that is built. +This step builds the base Berkeley DB .dll, tcl support, +and various tools that are needed by the test suite. +
+

Running the test suite under Windows

+

Before running the tests for the first time, you must edit the file +include.tcl in your build directory and change the line +that reads: +

set tclsh_path SET_YOUR_TCLSH_PATH
+

You will want to use the location of the tclsh program. For +example, if Tcl is installed as d:/tcl, this line should be: +

set tclsh_path d:/tcl/bin/tclsh83d.exe
+

Then, in a shell of your choice enter the following commands: +

    +

  1. cd build_win32 +

  2. run d:/tcl/bin/tclsh83d.exe, or the equivalent name of +the Tcl shell for your distribution. +

    You should get a "%" prompt. +

  3. % source ../test/test.tcl. +

    You should get a "%" prompt with no errors. +

+

You are now ready to run tests in the test suite, see +Running the test suite for more +information. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/cam/intro.html b/db/docs/ref/cam/intro.html new file mode 100644 index 000000000..7a02ea87f --- /dev/null +++ b/db/docs/ref/cam/intro.html @@ -0,0 +1,72 @@ + + + + + +Berkeley DB Reference Guide: Building Berkeley DB Concurrent Data Store applications + + + + + + + +

Berkeley DB Reference Guide:
Berkeley DB Concurrent Data Store Applications

PrevRefNext +
+

+

Building Berkeley DB Concurrent Data Store applications

+

It is often desirable to have concurrent read-write access to a database +when there is no need for full recoverability or transaction semantics. +For this class of applications, Berkeley DB provides an interface supporting +deadlock free, multiple-reader/single writer access to the database. +This means that, at any instant in time, there may be either multiple +readers accessing data or a single writer modifying data. The +application is entirely unaware of which is happening, and Berkeley DB +implements the necessary locking and blocking to ensure this behavior. +

In order to create Berkeley DB Concurrent Data Store applications, you must first initialize an +environment by calling DBENV->open. You must specify the +DB_INIT_CDB and DB_INIT_MPOOL flags to that interface. +It is an error to specify any of the other DBENV->open subsystem +or recovery configuration flags, e.g., DB_INIT_LOCK, +DB_INIT_TXN or DB_RECOVER. +

All databases must, of course, be created in this environment, by using +the db_create interface and specifying the correct environment +as an argument. +

The Berkeley DB access method calls used to support concurrent access are +unchanged from the normal access method calls, with one exception: the +DB->cursor interface. In Berkeley DB Concurrent Data Store, each cursor must encapsulate +the idea of being used for read-only access or for read-write access. +There may only be one read-write cursor active at any one time. When your +application creates a cursor, if that cursor will ever be used for +writing, the DB_WRITECURSOR flag must be specified when the cursor +is created. +

No deadlock detector needs to be run in a Berkeley DB Concurrent Data Store database environment. +

Only a single thread of control may write the database at a time. For +this reason care must be taken to ensure that applications do not +inadvertently block themselves causing the application to hang, unable +to proceed. Some common mistakes include: +

    +

  1. Leaving a cursor open while issuing a DB->put or DB->del +access method call. +

  2. Attempting to open a cursor for read-write access while already holding +a cursor open for read-write access. +

  3. Not testing Berkeley DB error return codes (if any cursor operation returns an +unexpected error, that cursor should be closed). +

  4. By default, Berkeley DB Concurrent Data Store does locking on a per-database basis. For this reason, +accessing multiple databases in different orders in different threads +or processes, or leaving cursors open on one database while accessing +another database, can cause an application to hang. If this behavior +is a requirement for the application, Berkeley DB can be configured to do +locking on an environment wide basis. See the DB_CDB_ALLDB flag +of the DBENV->set_flags function for more information. +
+

Note that it is correct operation for two different threads of control +(actual threads or processes) to have multiple read-write cursors open, +or for one thread to issue a DB->put call while another thread +has a read-write cursor open, and it is only a problem if these things +are done within a single thread of control. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/debug/common.html b/db/docs/ref/debug/common.html new file mode 100644 index 000000000..6374307f1 --- /dev/null +++ b/db/docs/ref/debug/common.html @@ -0,0 +1,109 @@ + + + + + +Berkeley DB Reference Guide: Common errors + + + + + + + +

Berkeley DB Reference Guide:
Debugging Applications

PrevRefNext +
+

+

Common errors

+

This page outlines some of the most common problems that people encounter +and some suggested courses of action. +

+

Symptom:
Core dumps or garbage returns from random Berkeley DB operations. +

Possible Cause:
Failure to zero out DBT structure before issuing request. +

Fix:
Before using a DBT, you must initialize all its elements +to 0 and then set the ones you are using explicitly. +

Symptom:
Random crashes and/or database corruption. +

Possible Cause:
Running multiple threads, but did not specify DB_THREAD +to DB->open or DBENV->open. +

Fix:
Any time you are sharing a handle across multiple threads, you must +specify DB_THREAD when you open that handle. +

Symptom:
DBENV->open returns EINVAL. +

Possible Cause:
The environment home directory is a remote mounted filesystem. +

Fix:
Use a locally mounted filesystem instead. +

Symptom:
DB->get calls are returning EINVAL. +

Possible Cause:
The application is running with threads, but did not specify the +DB_DBT_MALLOC, DB_DBT_REALLOC or DB_DBT_USERMEM +flags in the DBT structures used in the call. +

Fix:
When running with threaded handles (i.e., specifying DB_THREAD +to DBENV->open or DB->open), you must specify one of those +flags for all DBT structures in which Berkeley DB is returning data. +

Symptom:
Running multiple threads or processes, and the database appears to be +getting corrupted. +

Possible Cause:
Locking is not enabled. +

Fix:
Make sure that you are acquiring locks in your access methods. You +must specify DB_INIT_LOCK to your DBENV->open call and then +pass that environment to DB->open. +

Symptom:
Locks are accumulating or threads and/or processes are +deadlocking even though there is no concurrent access to the database. +

Possible Cause:
Failure to close a cursor. +

Fix:
Cursors retain locks between calls. Everywhere the application uses +a cursor, the cursor should be explicitly closed as soon as possible after +it is used. +

Symptom:
The system locks up. +

Possible Cause:
Application not checking for DB_LOCK_DEADLOCK. +

Fix:
Unless you are using the Concurrent Data Store product, whenever you +have multiple threads and/or processes and at least one of them is +writing, you have the potential for deadlock. As a result, you must +test for the DB_LOCK_DEADLOCK return on every Berkeley DB call. In +general, updates should take place in a transaction or you might leave +the database in an inconsistent state. Reads may take place outside +the context of a transaction under common conditions. +

Whenever you get a DB_LOCK_DEADLOCK return, you should: +

    +

  1. If you are running in a transaction, abort the transaction, first closing +any cursors opened in the transaction. +

  2. If you are not running in a transaction, simply close the cursor that got +the DB_LOCK_DEADLOCK (if it was a cursor operation) and retry. +
+

See Recoverability and deadlock +avoidance for further information. +

Symptom:
An inordinately high number of deadlocks. +

Possible Cause:
Read-Modify-Write pattern without using the RMW flag. +

Fix:
If you frequently read a piece of data, modify it and then write +it, you may be inadvertently causing a large number of deadlocks. Try +specifying the DB_RMW flag on your get calls. +

Or, if the application is doing a large number of updates in a small +database, turning off Btree splits may help (see DB_REVSPLITOFF +for more information.) +

Symptom:
I run recovery and it exits cleanly, but my database changes are missing. +

Possible Cause:
Failure to enable logging and transactions in the database environment, +failure to specify DB_ENV handle when creating DB handle, +transaction handle not passed to Berkeley DB interface, failure to commit +transaction. +

Fix:
Make sure that the environment and database handles are properly +created, and that the application passes the transaction handle returned +by txn_begin to the appropriate Berkeley DB interfaces, and that each +transaction is eventually committed. +

Symptom:
Recovery fails. +

Possible Cause:
A database was updated in a transactional environment both with and +without transactional handles. +

Fix:
If any database write operation is done using a transaction handle, +every write operation must be done in the context of a transaction. +

Symptom:
A database environment locks up, sometimes gradually. +

Possible Cause:
A thread of control exited unexpectedly, holding Berkeley DB resources. +

Fix:
Whenever a thread of control exits holding Berkeley DB resources, all threads +of control must exit the database environment, and recovery must be run. +

Symptom:
A database environment locks up, sometimes gradually. +

Possible Cause:
Cursors are not being closed before transaction abort. +

Fix:
Before an application aborts a transaction, any cursors opened within +the context of that transaction must be closed. +

Symptom:
Transaction abort or recovery fail, or database corruption occurs. +

Possible Cause:
Log files were removed before it was safe. +

Fix:
Do not remove any log files from a database environment until Berkeley DB +declares it safe. +
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/debug/compile.html b/db/docs/ref/debug/compile.html new file mode 100644 index 000000000..504d5d3ec --- /dev/null +++ b/db/docs/ref/debug/compile.html @@ -0,0 +1,43 @@ + + + + + +Berkeley DB Reference Guide: Compile-time configuration + + + + + + +

Berkeley DB Reference Guide:
Debugging

PrevRefNext +
+

+

Compile-time configuration

+

There are two compile-time configuration options that assist in debugging +Berkeley DB and Berkeley DB applications. +

+

--enable-debug
If you want to build Berkeley DB with -g as the C and C++ compiler +flag, enter --enable-debug as an argument to configure. This will create +Berkeley DB with debugging symbols, as well as load various Berkeley DB routines +that can be called directly from a debugger to display database page +content, cursor queues and so forth. (Note that the -O +optimization flag will still be specified. To compile with only the +-g, explicitly set the CFLAGS environment variable +before configuring.) +

--enable-diagnostic
If you want to build Berkeley DB with debugging run-time sanity checks and with +DIAGNOSTIC #defined during compilation, enter --enable-diagnostic as an +argument to configure. This will cause a number of special checks to be +performed when Berkeley DB is running. This flag should not be defined when +configuring to build production binaries, as it degrades performance. +

In addition, when compiling Berkeley DB for use in run-time memory consistency +checkers, in particular, programs that look for reads and writes of +uninitialized memory, use --enable-diagnostic as an argument to configure. +This guarantees that Berkeley DB will completely initialize allocated pages +rather than only initializing the minimum necessary amount. +

+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/debug/intro.html b/db/docs/ref/debug/intro.html new file mode 100644 index 000000000..0ea0afcfb --- /dev/null +++ b/db/docs/ref/debug/intro.html @@ -0,0 +1,58 @@ + + + + + +Berkeley DB Reference Guide: Introduction + + + + + + +

Berkeley DB Reference Guide:
Debugging Applications

PrevRefNext +
+

+

Introduction

+

As Berkeley DB is an embedded library, debugging applications that use Berkeley DB +is both harder and easier than debugging a separate server. Debugging +can be harder, because, when a problem arises, it is not always readily +apparent whether the problem is in the application, in the database +library, or is a result of an unexpected interaction between the two. +Debugging can be easier, as it is easier to track down a problem when +you can review a stack trace rather than deciphering inter-process +communication messages. This chapter is intended to assist you in +debugging applications and in reporting bugs to us in a manner such that +we can provide you with the correct answer or fix as quickly as +possible. +

When you encounter a problem, there are a few general actions you can +take: +

+

Review the Berkeley DB error output
If an error output mechanism has been configured in the Berkeley DB +environment, additional run-time error messages are made available to +the applications. If you are not using an environment, it is well worth +modifying your application to create one so that you can get more +detailed error messages. See Run-time error +information for more information on configuring Berkeley DB to output these +error messages. +

Review DBENV->set_verbose
Check the list of flags for the DBENV->set_verbose function, and +see if any of them will produce additional information that might help +understand the problem. +

Add run-time diagnostics
You can configure and build Berkeley DB to perform run-time diagnostics. +(These checks are not done by default as they can seriously impact +performance. See Compile-time configuration for more +information. +

Apply all available patches
Before reporting a problem to Sleepycat Software, please upgrade to the +latest Sleepycat Software release of Berkeley DB, if possible, or at least +make sure you have applied any updates available for your release from +the Sleepycat +Software web site. +

Run the test suite
If you are seeing repeated failures, or failures of simple test cases, +run the Berkeley DB test suite to determine if the distribution of Berkeley DB you +are using was built and configured correctly. +
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/debug/printlog.html b/db/docs/ref/debug/printlog.html new file mode 100644 index 000000000..e533a88d2 --- /dev/null +++ b/db/docs/ref/debug/printlog.html @@ -0,0 +1,160 @@ + + + + + +Berkeley DB Reference Guide: Reviewing Berkeley DB log files + + + + + + +

Berkeley DB Reference Guide:
Debugging Applications

PrevRefNext +
+

+

Reviewing Berkeley DB log files

+

If you are running with transactions and logging, the db_printlog +utility can be a useful debugging aid. The db_printlog utility +will display the contents of your log files in a human readable (and +machine-processable) format. +

The db_printlog utility will attempt to display any and all +logfiles present in a designated db_home directory. For each log record, +db_printlog will display a line of the form: +

[22][28]db_big: rec: 43 txnid 80000963 prevlsn [21][10483281]
+

The opening numbers in square brackets are the log sequence number (LSN) +of the log record being displayed. The first number indicates the log +file in which the record appears, and the second number indicates the +offset in that file of the record. +

The first character string identifies the particular log operation being +reported. The log records corresponding to particular operations are +described below. The rest of the line consists of name/value pairs. +

The rec field indicates the record type (this is used to dispatch records +in the log to appropriate recovery functions). +

The txnid field identifies the transaction for which this record was +written. A txnid of 0 means that the record was written outside the +context of any transaction. You will see these most frequently for +checkpoints. +

Finally, the prevlsn contains the LSN of the last record for this +transaction. By following prevlsn fields, you can accumulate all the +updates for a particular transaction. During normal abort processing, +this field is used to quickly access all the records for a particular +transaction. +

After the initial line identifying the record type, each field of the log +record is displayed, one item per line. There are several fields that +appear in many different records and a few fields that appear only in +some records. +

The list below presents each log record type currently produced with a brief +description of the operation they describe. + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Log Record TypeDescription
bam_adjUsed when we insert/remove an index into/from the page header of a Btree page.
bam_cadjustKeeps track of record counts in a Btree or Recno database.
bam_cdelUsed to mark a record on a page as deleted.
bam_curadjUsed to adjust a cursor location when a nearby record changes in a Btree database.
bam_pg_allocIndicates that we allocated a page to a Btree.
bam_pg_freeIndicates that we freed a page in the Btree (freed pages are added to a freelist and reused).
bam_rcuradjUsed to adjust a cursor location when a nearby record changes in a Recno database.
bam_replDescribes a replace operation on a record.
bam_rootDescribes an assignment of a root page.
bam_rsplitDescribes a reverse page split.
bam_splitDescribes a page split.
crdel_deleteDescribes the removal of a Berkeley DB file.
crdel_fileopenDescribes a Berkeley DB file create attempt.
crdel_metapageDescribes the creation of a meta-data page for a new file.
crdel_metasubDescribes the creation of a meta data page for a subdatabase.
crdel_renameDescribes a file rename operation.
db_addremAdd or remove an item from a page of duplicates.
db_bigAdd an item to an overflow page (overflow pages contain items too large to place on the main page)
db_debugLog debugging message.
db_noopThis marks an operation that did nothing but update the LSN on a page.
db_ovrefIncrement or decrement the reference count for a big item.
db_relinkFix prev/next chains on duplicate pages because a page was added or removed.
ham_chgpgUsed to adjust a cursor location when a Hash page is removed, and its elements are moved to a different Hash page.
ham_copypageUsed when we empty a bucket page, but there are overflow pages for the bucket; one needs to be copied back into the actual bucket.
ham_curadjUsed to adjust a cursor location when a nearby record changes in a Hash database.
ham_groupallocAllocate some number of contiguous pages to the Hash database.
ham_insdelInsert/Delete an item on a Hash page.
ham_metagroupUpdate the metadata page to reflect the allocation of a sequence of contiguous pages.
ham_newpageAdds or removes overflow pages from a Hash bucket.
ham_replaceHandle updates to records that are on the main page.
ham_splitdataRecord the page data for a split.
log_registerRecords an open of a file (mapping the file name to a log-id that is used in subsequent log operations).
qam_addDescribes the actual addition of a new record to a Queue.
qam_delDelete a record in a Queue.
qam_deleteRemove a Queue extent file.
qam_incIncrements the maximum record number allocated in a Queue indicating that we've allocated another space in the file.
qam_incfirstIncrements the record number that refers to the first record in the database.
qam_mvptrIndicates that we changed the reference to either or both of the first and current records in the file.
qam_renameRename a Queue extent file.
txn_childCommit a child transaction.
txn_ckpTransaction checkpoint.
txn_regopLogs a regular (non-child) transaction commit.
txn_xa_regopLogs a prepare message.
+ +

Augmenting the Log for Debugging

+

When debugging applications, it is sometimes useful to log, not only the +actual operations that modify pages, but also the underlying Berkeley DB +functions being executed. This form of logging can add significant bulk +to your log, but can permit debugging application errors that are almost +impossible to find any other way. To turn on these log messages, specify +the --enable-debug_rop and --enable-debug_wop configuration options when +configuring Berkeley DB. See Configuring +Berkeley DB for more information. +

Extracting Committed Transactions and Transaction Status

+

Sometimes it is useful to use the human-readable log output to determine +which transactions committed and aborted. The awk script, commit.awk, +found in the db_printlog directory of the Berkeley DB distribution allows you +to do just that. The command: +

awk -f commit.awk log_output
+where log_output is the output of db_printlog will display a list of +the transaction IDs of all committed transactions found in the log. +

If you need a complete list of both committed and aborted transactions, +then the script status.awk will produce that. The syntax is: +

awk -f status.awk log_output
+

Extracting Transaction Histories

+

Another useful debugging aid is to print out the complete history of a +transaction. The awk script txn.awk, allows you to do that. The +command line: +

awk -f txn.awk TXN=txnlist log_output
+where log_output is the output of db_printlog and txnlist is +a comma-separated list of transaction IDs, will display all log records +associated with the designated transaction ids. +

Extracting File Histories

+

The awk script fileid.awk, allows you to extract all log records that +affect particular files. The syntax for the fileid.awk script is: +

awk -f fileid.awk PGNO=fids log_output
+

where log_output is the output of db_printlog and fids is a +comma-separated list of fileids. The script will output all log +records that reference the designated file. +

Extracting Page Histories

+

The awk script pgno.awk, allows you to extract all log records that +affect particular pages. As currently designed, however, it will +extract records of all files with the designated page number, so this +script is most useful in conjunction with the fileid script. The syntax +for the pgno.awk script is: +

awk -f pgno.awk PGNO=pgnolist log_output
+

where log_output is the output of db_printlog and pgnolist is a +comma-separated list of page numbers. The script will output all log +records that reference the designated page numbers. +

Other log processing tools

+

The awk script count.awk will print out the number of log records +encountered that belonged to some transaction (that is the number of log +records excluding those for checkpoints and non-transaction protected +operations). +

The script range.awk will extract a subset of a log. This is useful +when the output of db_printlog is too large to be reasonably +manipulated with an editor or other tool. +

The syntax for range.awk is: +

awk -f range.awk START_FILE=sf START_OFFSET=so END_FILE=ef END_OFFSET=eo log_output
+

where the sf and so represent the log sequence number +(LSN) of the beginning of the sublog you wish to extract and ef +and eo represent the LSN of the end of the sublog you wish to +extract. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/debug/runtime.html b/db/docs/ref/debug/runtime.html new file mode 100644 index 000000000..40fec7e82 --- /dev/null +++ b/db/docs/ref/debug/runtime.html @@ -0,0 +1,47 @@ + + + + + +Berkeley DB Reference Guide: Run-time error information + + + + + + +

Berkeley DB Reference Guide:
Debugging

PrevRefNext +
+

+

Run-time error information

+

Normally, when an error occurs in the Berkeley DB library, an integer value +(either a Berkeley DB specific value, or a system errno value) is +returned by the function. In some cases, however, this value may be +insufficient to completely describe the cause of the error, especially +during initial application debugging. +

There are four interfaces intended to provide applications with +additional run-time error information. They are +DBENV->set_errcall, DBENV->set_errfile, +DBENV->set_errpfx and DBENV->set_verbose. +

If the environment is configured with these interfaces, many Berkeley DB errors +will result in additional information being written to a file or passed +as an argument to an application function. +

The Berkeley DB error reporting facilities do not slow performance or +significantly increase application size, and may be run during normal +operation as well as during debugging. Where possible, we recommend that +these options always be configured and the output saved in the filesystem. +We have found that that this often saves time when debugging installation +or other system integration problems. +

In addition, there are three routines to assist applications in +displaying their own error messages: db_strerror, +DBENV->err and DBENV->errx. The first is a superset of +the ANSI C strerror interface, and returns a descriptive string for +any error return from the Berkeley DB library. The DBENV->err and +DBENV->errx functions use the error message configuration options +described above to format and display error messages to appropriate +output devices. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/distrib/layout.html b/db/docs/ref/distrib/layout.html new file mode 100644 index 000000000..b851f62a0 --- /dev/null +++ b/db/docs/ref/distrib/layout.html @@ -0,0 +1,74 @@ + + + + + +Berkeley DB Reference Guide: Source code layout + + + + + + + +

Berkeley DB Reference Guide:
Distribution

PrevRefNext +
+

+

Source code layout

+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DirectoryDescription
LICENSEBerkeley DB Copyright
btreeBtree access method source code.
build_unixUNIX build directory.
build_vxworksVxWorks build directory.
build_win32Windows build directory.
clibC library replacement functions.
commonCommon Berkeley DB functions.
cxxC++ API.
dbBerkeley DB database interfaces.
db185Berkeley DB version 1.85 compatibility API
db_archiveThe db_archive utility.
db_checkpointThe db_checkpoint utility.
db_deadlockThe db_deadlock utility.
db_dumpThe db_dump utility.
db_dump185The db_dump185 utility.
db_loadThe db_load utility.
db_printlogThe db_printlog debugging utility.
db_recoverThe db_recover utility.
db_statThe db_stat utility.
db_upgradeThe db_upgrade utility.
db_verifyThe db_verify utility.
dbmThe dbm/ndbm compatibility APIs.
distBerkeley DB administration/distribution tools.
docsDocumentation.
envBerkeley DB environment interfaces.
examples_cC API example programs.
examples_cxxC++ API example programs.
examples_javaJava API example programs.
hashHash access method.
hsearchThe hsearch compatibility API.
includeInclude files.
javaJava API.
libdb_javaThe libdb_java shared library.
lockLock manager.
logLog manager.
mpShared memory buffer pool.
mutexMutexes.
osPOSIX 1003.1 operating-system specific functionality.
os_vxworksVxWorks operating-system specific functionality.
os_win32Windows operating-system specific functionality.
perl.BerkeleyDBBerkeleyDB Perl module.
perl.DB_FileDB_File Perl module.
qamQueue access method source code.
rpc_clientRPC client interface.
rpc_serverRPC server utility.
tclTcl API.
testTest suite.
txnTransaction manager.
xaX/Open Distributed Transaction Processing XA interface.
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/dumpload/format.html b/db/docs/ref/dumpload/format.html new file mode 100644 index 000000000..fd52e530a --- /dev/null +++ b/db/docs/ref/dumpload/format.html @@ -0,0 +1,69 @@ + + + + + +Berkeley DB Reference Guide: Dump output formats + + + + + + +

Berkeley DB Reference Guide:
Dumping and Reloading

PrevRefNext +
+

+

Dump output formats

+

There are two output formats used by db_dump and db_dump185. +

In both output formats, the first few lines of the output contain header +information describing the underlying access method, filesystem page size +and other bookkeeping information. +

The header information starts with a single line VERSION=N, where N is +the version number of the dump output format. +

The header information is then output in name=value pairs, where name may +be any of the keywords listed in the db_load manual page, and +value will be its value. While this header information can be manually +edited before the database is reloaded, there is rarely any reason to do +so, as all of this information can also be specified or overridden by +command-line arguments to db_load. +

The header information ends with single line HEADER=END. +

Following the header information are the key/data pairs from the database. +If the database being dumped is of type Btree or Hash, or if the +-k option as been specified, the output will be paired lines of +text, where the first line of the pair is the key item, and the second +line of the pair is its corresponding data item. If the database being +dumped is of type Queue or Recno and the -k has not been +specified, the output will be lines of text, where each line is the next +data item for the database. Each of these lines will be preceded by a +single space. +

If the -p option to db_dump or db_dump185 was +specified, the key/data lines will consist of single characters +representing any characters from the database that are printing +characters and backslash (\) escaped characters +for any that were not. Backslash characters appearing in the output mean +one of two things: if the backslash character precedes another backslash +character, it means that a literal backslash character occurred in the +key or data item. If the backslash character precedes any other +character, the next two characters must be interpreted as hexadecimal +specification of a single character, e.g., \0a is +a newline character in the ASCII character set. +

Although some care should be exercised, it is perfectly reasonable to use +standard text editors and tools to edit databases dumped using the +-p option before re-loading them using the db_load +utility. +

Note that the definition of a printing character may vary from system to +system, and so database representations created using the -p +option may be less portable than those created without it. +

If the -p option to db_dump or db_dump185 is +not specified, each output line will consist of paired hexadecimal values, +e.g., the line 726f6f74 is the string root in the ASCII +character set. +

In all output formats, the key and data items are ended by a single line +DATA=END. +

Where multiple databases have been dumped from a file, the overall output +will repeat, i.e., a new set of headers and a new set of data items. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/dumpload/text.html b/db/docs/ref/dumpload/text.html new file mode 100644 index 000000000..569980a19 --- /dev/null +++ b/db/docs/ref/dumpload/text.html @@ -0,0 +1,32 @@ + + + + + +Berkeley DB Reference Guide: Loading text into databases + + + + + + + +

Berkeley DB Reference Guide:
Dumping and Reloading

PrevRefNext +
+

+

Loading text into databases

+

The db_load utility can be used to load text into databases. +The -T option permits non-database applications to create +flat-text files that are then loaded into databases for fast, +highly-concurrent access. For example, the following command loads the +standard UNIX /etc/passwd file into a database, with the login +name as the key item and the entire password entry as the data item: +

awk -F: '{print $1; print $0}' < /etc/passwd |\
+	sed 's/\\/\\\\/g' | db_load -T -t hash passwd.db
+

Note that backslash characters naturally occurring in the text are escaped +to avoid interpretation as escape characters by db_load. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/dumpload/utility.html b/db/docs/ref/dumpload/utility.html new file mode 100644 index 000000000..f9cb51c11 --- /dev/null +++ b/db/docs/ref/dumpload/utility.html @@ -0,0 +1,45 @@ + + + + + +Berkeley DB Reference Guide: The db_dump and db_load utilities + + + + + + + +

Berkeley DB Reference Guide:
Dumping and Reloading

PrevRefNext +
+

+

The db_dump and db_load utilities

+

There are three utilities used for dumping and loading Berkeley DB +databases: db_dump, db_dump185 and db_load. +

The db_dump and db_dump185 utilities dump Berkeley DB +databases into a flat-text representation of the data that can +be read by db_load. The only difference between them +is that db_dump reads Berkeley DB version 2 and greater +database formats, while db_dump185 reads Berkeley DB version +1.85 and 1.86 database formats. +

The db_load utility reads either the output format used +by the dump utilities or, optionally, a flat-text representation +created using other tools, and stores it into a Berkeley DB database. +

Dumping and reloading Hash databases that use user-defined hash functions +will result in new databases that use the default hash function. While +using the default hash function may not be optimal for the new database, +it will continue to work correctly. +

Dumping and reloading Btree databases that use user-defined prefix or +comparison functions will result in new databases that use the default +prefix and comparison functions. In which case it is quite likely that +applications will be unable to retrieve records, and possible that the +load process itself will fail. +

The only available workaround for either Hash or Btree databases is to +modify the sources for the db_load utility to load the database +using the correct hash, prefix and comparison functions. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/env/create.html b/db/docs/ref/env/create.html new file mode 100644 index 000000000..374c7a6e0 --- /dev/null +++ b/db/docs/ref/env/create.html @@ -0,0 +1,73 @@ + + + + + +Berkeley DB Reference Guide: Creating an Environment + + + + + + + +

Berkeley DB Reference Guide:
Environment

PrevRefNext +
+

+

Creating an Environment

+

The DBENV->open function is the standard function for creating or +joining a database environment. Transaction-protected or multi-process +applications should call DBENV->open before making any other calls +to the Berkeley DB library. Applications must obtain an environment handle from +the db_env_create function before calling DBENV->open. +There are a large number of options that you can set to customize +DBENV->open for your environment. These options fall into four +broad categories: +

+

Subsystem Initialization:
These flags indicate which Berkeley DB subsystems will be initialized for the +environment, and, what operations will happen automatically when +databases are accessed within the environment. The flags include +DB_JOINENV, DB_INIT_CDB, DB_INIT_LOCK, +DB_INIT_LOG, DB_INIT_MPOOL and DB_INIT_TXN. +The DB_INIT_CDB flag does initialization for Berkeley DB Concurrent Data Store +applications, see Building Berkeley DB Concurrent Data Store +applications for more information. The rest of the flags initialize +a single subsystem, e.g., when DB_INIT_LOCK is specified, +applications reading and writing databases opened in this environment +will be using locking to ensure that they do not overwrite each other's +changes. +

Recovery options:
These flags indicate what recovery is to be performed on the environment +before it is opened for normal use, and include DB_RECOVER and +DB_RECOVER_FATAL. +

Naming options:
These flags modify how file naming happens in the environment, and include +DB_USE_ENVIRON and DB_USE_ENVIRON_ROOT. +

Miscellaneous:
Finally, there are a number of miscellaneous flags such as DB_CREATE +which causes underlying files to be created as necessary. See the +DBENV->open manual pages for further information. +
+

Most applications either specify only the DB_INIT_MPOOL flag or +they specify all four subsystem initialization flags +(DB_INIT_MPOOL, DB_INIT_LOCK, DB_INIT_LOG and +DB_INIT_TXN). The former configuration is for applications that +simply want to use the basic Access Method interfaces with a shared +underlying buffer pool, but don't care about recoverability after +application or system failure. The latter is for applications that need +recoverability. There are situations where other combinations of the +initialization flags make sense, but they are rare. +

The DB_RECOVER flag is specified by applications that want to +perform any necessary database recovery when they start running, i.e., if +there was a system or application failure the last time they ran, they +want the databases to be made consistent before they start running again. +It is not an error to specify this flag when no recovery needs to be +done. +

The DB_RECOVER_FATAL flag is more special-purpose. It performs +catastrophic database recovery, and normally requires that some initial +arrangements be made, i.e., archived log files be brought back into the +filesystem. Applications should not normally specify this flag. Instead, +under these rare conditions, the db_recover utility should be +used. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/env/error.html b/db/docs/ref/env/error.html new file mode 100644 index 000000000..1a79d8fe5 --- /dev/null +++ b/db/docs/ref/env/error.html @@ -0,0 +1,57 @@ + + + + + +Berkeley DB Reference Guide: Error support + + + + + + +

Berkeley DB Reference Guide:
Environment

PrevRefNext +
+

+

Error support

+

Berkeley DB offers programmatic support for displaying error return values. +The db_strerror interface returns a pointer to the error +message corresponding to any Berkeley DB error return, similar to the ANSI C +strerror interface, but able to handle both system error returns and +Berkeley DB specific return values. +

For example: +

int ret;
+if ((ret = dbenv->set_cachesize(dbenv, 0, 32 * 1024)) != 0) {
+	fprintf(stderr, "set_cachesize failed: %s\n", db_strerror(ret));
+	return (1);
+}
+

There are also two additional error functions, DBENV->err and +DBENV->errx. These functions work like the ANSI C printf +interface, taking a printf-style format string and argument list, and +writing a message constructed from the format string and arguments. +

The DBENV->err function appends the standard error string to the +constructed message and the DBENV->errx function does not. +

Error messages can be configured always to include a prefix (e.g., the +program name) using the DBENV->set_errpfx interface. +

These functions provide simpler ways of displaying Berkeley DB error messages: +

int ret;
+dbenv->set_errpfx(dbenv, argv0);
+if ((ret = dbenv->open(dbenv, home, NULL,
+    DB_CREATE | DB_INIT_LOG | DB_INIT_TXN | DB_USE_ENVIRON))
+    != 0) {
+	dbenv->err(dbenv, ret, "open: %s", home);
+	dbenv->errx(dbenv,
+	    "contact your system administrator: session ID was %d",
+	    session_id);
+	return (1);
+}
+

For example, if the program was called "my_app", attempting to open an +environment home directory in "/tmp/home", and the open call returned a +permission error, the error messages shown would look like: +

my_app: open: /tmp/home: Permission denied.
+my_app: contact your system administrator: session ID was 2
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/env/intro.html b/db/docs/ref/env/intro.html new file mode 100644 index 000000000..a555c2f0f --- /dev/null +++ b/db/docs/ref/env/intro.html @@ -0,0 +1,56 @@ + + + + + +Berkeley DB Reference Guide: Introduction + + + + + + +

Berkeley DB Reference Guide:
Environment

PrevRefNext +
+

+

Introduction

+

A Berkeley DB environment is an encapsulation of one or more databases, log +files and shared information about the database environment such as shared +memory buffer cache pages. +

The simplest way to administer a Berkeley DB application environment is to +create a single home directory that stores the files for the +applications that will share the environment. The environment home +directory must be created before any Berkeley DB applications are run. Berkeley DB +itself never creates the environment home directory. The environment can +then be identified by the name of that directory. +

An environment may be shared by any number of applications as well as by +any number of threads within the applications. It is possible for an +environment to include resources from other directories on the system, +and applications often choose to distribute resources to other directories +or disks for performance or other reasons. However, by default, the +databases, shared regions (the locking, logging, memory pool, and +transaction shared memory areas) and log files will be stored in a single +directory hierarchy. +

It is important to realize that all applications sharing a database +environment implicitly trust each other. They have access to each other's +data as it resides in the shared regions and they will share resources +such as buffer space and locks. At the same time, any applications using +the same databases must share an environment if consistency is +to be maintained between them. +

The Berkeley DB environment is created and described by the db_env_create +and DBENV->open interfaces. In situations where customization is +desired, such as storing log files on a separate disk drive, applications +must describe the customization by either creating an environment +configuration file in the environment home directory or by arguments +passed to the DBENV->open interface. See the documentation on that +function for details on this procedure. +

Once an environment has been created, database files specified using +relative pathnames will be named relative to the home directory. Using +pathnames relative to the home directory allows the entire environment +to be easily moved to facilitate restoring and recovering a database in +a different directory or on a different system. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/env/naming.html b/db/docs/ref/env/naming.html new file mode 100644 index 000000000..fd5753962 --- /dev/null +++ b/db/docs/ref/env/naming.html @@ -0,0 +1,145 @@ + + + + + +Berkeley DB Reference Guide: File naming + + + + + + + +

Berkeley DB Reference Guide:
Environment

PrevRefNext +
+

+

File naming

+

The most important task of the environment is to structure file naming +within Berkeley DB. +

Each of the locking, logging, memory pool and transaction subsystems of +Berkeley DB require shared memory regions, backed by the filesystem. Further, +cooperating applications (or multiple invocations of the same application) +must agree on the location of the shared memory regions and other files +used by the Berkeley DB subsystems, the log files used by the logging subsystem, +and, of course, the data files. Although it is possible to specify full +pathnames to all Berkeley DB functions, this is cumbersome and requires +that applications be recompiled when database files are moved. +

Applications are normally expected to specify a single directory home for +their database. This can be done easily in the call to DBENV->open +by specifying a value for the db_home argument. There are more +complex configurations where it may be desirable to override +db_home or provide supplementary path information. +

Specifying file naming to Berkeley DB

+

The following describes the possible ways in which file naming information +may be specified to the Berkeley DB library. The specific circumstances and +order in which these ways are applied are described in a subsequent +paragraph. +

+

db_home
If the db_home argument to DBENV->open is non-NULL, its +value may be used as the database home, and files named relative to its +path. +

DB_HOME
If the DB_HOME environment variable is set when DBENV->open is +called, its value may be used as the database home, and files named +relative to its path. +

The DB_HOME environment variable is intended to permit users and system +administrators to override application and installation defaults, e.g.: +

env DB_HOME=/database/my_home application
+

Application writers are encouraged to support the -h option +found in the supporting Berkeley DB utilities to let users specify a database +home. +

DB_ENV methods
There are three DB_ENV methods that affect file naming. The +DBENV->set_data_dir function specifies a directory to search for database +files. The DBENV->set_lg_dir function specifies a directory in which to +create logging files. The DBENV->set_tmp_dir function specifies a +directory in which to create backing temporary files. These methods are +intended to permit applications to customize file location for a database. +For example, an application writer can place data files and log files in +different directories, or instantiate a new log directory each time the +application runs. +

DB_CONFIG
The same information specified to the above DB_ENV methods may also +be specified using a configuration file. If an environment home directory +has been specified (either by the application specifying a non-NULL +db_home argument to DBENV->open, or by the application +setting the DB_USE_ENVIRON or DB_USE_ENVIRON_ROOT flags and the DB_HOME +environment variable being set), any file named DB_CONFIG in the +database home directory will be read for lines of the format NAME +VALUE. +

The characters delimiting the two parts of the entry may be one or more +whitespace characters, and trailing whitespace characters are discarded. +All empty lines or lines whose first character is a whitespace or hash +(#) character will be ignored. Each line must specify both +the NAME and the VALUE of the pair. The specific NAME VALUE pairs are +documented in the manual DBENV->set_data_dir, +DBENV->set_lg_dir and DBENV->set_tmp_dir pages. +

The DB_CONFIG configuration file is intended to permit systems to +customize file location for an environment independent of applications +using that database. For example, a database administrator can move the +database log and data files to a different location without application +recompilation. +

+

File name resolution in Berkeley DB

+

The following describes the specific circumstances and order in which the +different ways of specifying file naming information are applied. Berkeley DB +file name processing proceeds sequentially through the following steps: +

+

absolute pathnames
If the file name specified to a Berkeley DB function is an absolute pathname, +that file name is used without modification by Berkeley DB. +

On UNIX systems, an absolute pathname is defined as any pathname that +begins with a leading slash (/). +

On Windows systems, an absolute pathname is any pathname that begins with +a leading slash or leading backslash (\), or any +pathname beginning with a single alphabetic character, a colon and a +leading slash or backslash, e.g., C:/tmp. +

DB_ENV methods, DB_CONFIG
If a relevant configuration string (e.g., set_data_dir), is specified +either by calling a DB_ENV method or as a line in the DB_CONFIG +configuration file, the VALUE from the NAME VALUE pair is +prepended to the current file name. If the resulting file name is an +absolute pathname, the file name is used without further modification by +Berkeley DB. +

db_home
If the application specified a non-NULL db_home argument to +DBENV->open its value is prepended to the current file name. If +the resulting file name is an absolute pathname, the file name is used +without further modification by Berkeley DB. +

DB_HOME
If the db_home argument is null, the DB_HOME environment variable +was set and the application has set the appropriate DB_USE_ENVIRON or +DB_USE_ENVIRON_ROOT environment variable, its value is prepended to the +current file name. If the resulting file name is an absolute pathname, +the file name is used without further modification by Berkeley DB. +

(nothing)
Finally, all file names are interpreted relative to the current working +directory of the process. +
+

The common model for a Berkeley DB environment is one where only the DB_HOME +environment variable, or the db_home argument, is specified. In +this case, all data file names are relative to that directory, and all +files created by the Berkeley DB subsystems will be created in that directory. +

The more complex model for a transaction environment might be one where +a database home is specified, using either the DB_HOME environment +variable or the db_home argument to DBENV->open, and then +the data directory and logging directory are set to the relative path +names of directories underneath the environment home. +

Examples

+Store all files in the directory /a/database: +

DBENV->open(DBENV, "/a/database", ...);
+Create temporary backing files in /b/temporary, and all other files +in /a/database: +

DBENV->set_tmp_dir(DBENV, "/b/temporary");
+DBENV->open(DBENV, "/a/database", ...);
+Store data files in /a/database/datadir, log files in +/a/database/logdir, and all other files in the directory +/a/database: +

DBENV->set_lg_dir("logdir");
+DBENV->set_data_dir("datadir");
+DBENV->open(DBENV, "/a/database", ...);
+

Store data files in /a/database/data1 and /b/data2, and +all other files in the directory /a/database. Any data files +that are created will be created in /b/data2, because it is the +first DB_DATA_DIR directory specified: +

DBENV->set_data_dir(DBENV, "/b/data2");
+DBENV->set_data_dir(DBENV, "data1");
+DBENV->open(DBENV, "/a/database", ...);
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/env/open.html b/db/docs/ref/env/open.html new file mode 100644 index 000000000..f13675c73 --- /dev/null +++ b/db/docs/ref/env/open.html @@ -0,0 +1,30 @@ + + + + + +Berkeley DB Reference Guide: Opening databases within the environment + + + + + + +

Berkeley DB Reference Guide:
Environment

PrevRefNext +
+

+

Opening databases within the environment

+

Once the environment has been created, database handles may be created +and then opened within the environment. This is done by calling the +db_create interface and specifying the appropriate environment +as an argument. +

File naming, database operations and error handling will all be done as +specified for the environment, e.g., if the DB_INIT_LOCK or +DB_INIT_CDB flags were specified when the environment was created +or joined, database operations will automatically perform all necessary +locking operations for the application. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/env/region.html b/db/docs/ref/env/region.html new file mode 100644 index 000000000..0dfa19672 --- /dev/null +++ b/db/docs/ref/env/region.html @@ -0,0 +1,66 @@ + + + + + +Berkeley DB Reference Guide: Shared Memory Regions + + + + + + +

Berkeley DB Reference Guide:
Environment

PrevRefNext +
+

+

Shared Memory Regions

+

Each of the Berkeley DB subsystems within an environment is described by one or +more regions. The regions contain all of the per-process and per-thread +shared information, including mutexes, that comprise a Berkeley DB environment. +These regions are created in one of three areas, depending on the flags +specified to the DBENV->open function: +

    +

  1. If the DB_PRIVATE flag is specified to DBENV->open, regions +are created in per-process heap memory, i.e., memory returned by +malloc(3). In this case, the Berkeley DB environment may only be +accessed by a single process, although that process may be +multi-threaded. +

  2. If the DB_SYSTEM_MEM flag is specified to DBENV->open, +regions are created in system memory. When regions are created in system +memory, the Berkeley DB environment may be accessed by both multiple processes +and multiple threads within processes. +

    The system memory used by Berkeley DB is potentially useful past the lifetime +of any particular process. Therefore, additional cleanup may be necessary +after an application fails, as there may be no way for Berkeley DB to ensure +that system resources backing the shared memory regions are returned to +the system. +

    The system memory that is used is architecture-dependent. For example, +on systems supporting X/Open-style shared memory interfaces, e.g., UNIX +systems, the shmget(2) and related System V IPC interfaces are +used. Additionally, VxWorks systems use system memory. +In these cases, an initial segment ID must be specified by the +application to ensure that applications do not overwrite each other's +database environments, and so that the number of segments created does +not grow without bound. See the DBENV->set_shm_key function for more +information. +

  3. If no memory-related flags are specified to DBENV->open, then +memory backed by the filesystem is used to store the regions. On UNIX +systems, the Berkeley DB library will use the POSIX mmap interface. If mmap is +not available, the UNIX shmget interfaces will be used, assuming they are +available. +
+

Any files created in the filesystem to back the regions are created in +the environment home directory specified to the DBENV->open call. +These files are named __db.###, e.g., __db.001, __db.002 and so on. +When region files are backed by the filesystem, one file per region is +created. When region files are backed by system memory, a single file +will still be created, as there must be a well-known name in the +filesystem so that multiple processes can locate the system shared memory +that is being used by the environment. +

Statistics about the shared memory regions in the environment can be +displayed using the -e option to the db_stat utility. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/env/remote.html b/db/docs/ref/env/remote.html new file mode 100644 index 000000000..3cd44a539 --- /dev/null +++ b/db/docs/ref/env/remote.html @@ -0,0 +1,48 @@ + + + + + +Berkeley DB Reference Guide: Remote filesystems + + + + + + + +

Berkeley DB Reference Guide:
Environment

PrevRefNext +
+

+

Remote filesystems

+

When regions are backed by the filesystem, it is a common error to attempt +to create Berkeley DB environments backed by remote file systems such as the +Network File System (NFS) or the Andrew File System (AFS). Remote +filesystems rarely support mapping files into process memory, and even +more rarely support correct semantics for mutexes after the attempt +succeeds. For this reason, we strongly recommend that the database +environment directory reside in a local filesystem. +

For remote file systems that do allow system files to be mapped into +process memory, home directories accessed via remote file systems cannot +be used simultaneously from multiple clients. None of the commercial +remote file systems available today implement coherent, distributed shared +memory for remote-mounted files. As a result, different machines will +see different versions of these shared regions and the system behavior is +undefined. +

Databases, log files and temporary files may be placed on remote +filesystems, as long as the remote filesystem fully supports +standard POSIX filesystem semantics, although the application may incur +a performance penalty for doing so. Obviously, NFS-mounted databases +cannot be accessed from more than one Berkeley DB environment (and therefore +from more than one system), at a time since no Berkeley DB database may be +accessed from more than one Berkeley DB environment at a time. +

+

Linux note:
Some Linux releases are known to not support complete semantics for the +POSIX fsync call on NFS-mounted filesystems. No Berkeley DB files should be +placed on NFS-mounted filesystems on these systems. +
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/env/security.html b/db/docs/ref/env/security.html new file mode 100644 index 000000000..84dab59b2 --- /dev/null +++ b/db/docs/ref/env/security.html @@ -0,0 +1,54 @@ + + + + + +Berkeley DB Reference Guide: Security + + + + + + + +

Berkeley DB Reference Guide:
Environment

PrevRefNext +
+

+

Security

+

The following are security issues that should be considered when writing +Berkeley DB applications: +

+

Database environment permissions
The directory used as the Berkeley DB database environment should have its +permissions set to ensure that files in the environment are not accessible +to users without appropriate permissions. Applications which add to the +user's permissions (e.g., UNIX setuid or setgid applications), must be +carefully checked to not permit illegal use of those permissions such +as general file access in the environment directory. +

Environment variables
Setting the DB_USE_ENVIRON and DB_USE_ENVIRON_ROOT flags +and allowing the use of environment variables during file naming can be +dangerous. Setting those flags in Berkeley DB applications with additional +permissions (e.g., UNIX setuid or setgid applications) could potentially +allow users to read and write databases to which they would not normally +have access. +

File permissions
By default, Berkeley DB always creates files readable and writeable by the owner +and the group (i.e., S_IRUSR, S_IWUSR, S_IRGRP and S_IWGRP, or octal mode +0660 on historic UNIX systems). The group ownership of created files is +based on the system and directory defaults, and is not further specified +by Berkeley DB. +

Temporary backing files
If an unnamed database is created and the cache is too small to hold the +database in memory, Berkeley DB will create a temporary physical file to enable +it to page the database to disk as needed. In this case, environment +variables such as TMPDIR may be used to specify the location of +that temporary file. While temporary backing files are created readable +and writeable by the owner only (i.e., S_IRUSR and S_IWUSR, or octal mode +0600 on historic UNIX systems), some filesystems may not sufficiently +protect temporary files created in random directories from improper +access. Applications storing sensitive data in unnamed databases should +use the DBENV->set_tmp_dir method to specify a temporary directory +with known permissions, to be absolutely safe. +
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/install/file.html b/db/docs/ref/install/file.html new file mode 100644 index 000000000..2ecb240e2 --- /dev/null +++ b/db/docs/ref/install/file.html @@ -0,0 +1,37 @@ + + + + + +Berkeley DB Reference Guide: File utility /etc/magic information + + + + + + + +

Berkeley DB Reference Guide:
System Installation Notes

PrevRefNext +
+

+

File utility /etc/magic information

+

The file(1) utility is a UNIX utility that examines and +classifies files, based on information found in its database of file +types, the /etc/magic file. The following information may be added +to your system's /etc/magic file to enable file(1) to +correctly identify Berkeley DB database files. +

The file(1) utility magic(5) information for the +standard System V UNIX implementation of the file(1) utility +is included in the Berkeley DB distribution for both +big-endian (e.g., Sparc) and +little-endian (e.g., x86) architectures. +

The file(1) utility magic(5) information for +Release 3.X of Ian Darwin's implementation of the file utility (as +distributed by FreeBSD and most Linux distributions) is included in the +Berkeley DB distribution. This magic.txt information +is correct for both big-endian and little-endian architectures. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/install/magic.s5.be.txt b/db/docs/ref/install/magic.s5.be.txt new file mode 100644 index 000000000..1b8fcc108 --- /dev/null +++ b/db/docs/ref/install/magic.s5.be.txt @@ -0,0 +1,87 @@ +# Berkeley DB +# $Id: magic.s5.be.txt,v 10.4 2000/07/07 21:02:22 krinsky Exp $ +# +# System V /etc/magic files: big-endian version. +# +# Hash 1.85/1.86 databases store metadata in network byte order. +# Btree 1.85/1.86 databases store the metadata in host byte order. +# Hash and Btree 2.X and later databases store the metadata in host byte order. + +0 long 0x00053162 Berkeley DB 1.85/1.86 (Btree, +>4 long 0x00000002 version 2, +>4 long 0x00000003 version 3, +>0 long 0x00053162 native byte-order) + +0 long 0x62310500 Berkeley DB 1.85/1.86 (Btree, +>4 long 0x02000000 version 2, +>4 long 0x03000000 version 3, +>0 long 0x62310500 little-endian) + +12 long 0x00053162 Berkeley DB (Btree, +>16 long 0x00000004 version 4, +>16 long 0x00000005 version 5, +>16 long 0x00000006 version 6, +>16 long 0x00000007 version 7, +>16 long 0x00000008 version 8, +>16 long 0x00000009 version 9, +>12 long 0x00053162 native byte-order) + +12 long 0x62310500 Berkeley DB (Btree, +>16 long 0x04000000 version 4, +>16 long 0x05000000 version 5, +>16 long 0x06000000 version 6, +>16 long 0x07000000 version 7, +>16 long 0x08000000 version 8, +>16 long 0x09000000 version 9, +>12 long 0x62310500 little-endian) + +0 long 0x00061561 Berkeley DB +>4 long >2 1.86 +>4 long <3 1.85 +>0 long 0x00061561 (Hash, +>4 long 2 version 2, +>4 long 3 version 3, +>8 long 0x000004D2 little-endian) +>8 long 0x000010E1 native byte-order) + +12 long 0x00061561 Berkeley DB (Hash, +>16 long 0x00000004 version 4, +>16 long 0x00000005 version 5, +>16 long 0x00000006 version 6, +>16 long 0x00000007 version 7, +>16 long 0x00000008 version 8, +>16 long 0x00000009 version 9, +>12 long 0x00061561 native byte-order) + +12 long 0x61150600 Berkeley DB (Hash, +>16 long 0x04000000 version 4, +>16 long 0x05000000 version 5, +>16 long 0x06000000 version 6, +>16 long 0x07000000 version 7, +>16 long 0x08000000 version 8, +>16 long 0x09000000 version 9, +>12 long 0x61150600 little-endian) + +12 long 0x00042253 Berkeley DB (Queue, +>16 long 0x00000001 version 1, +>16 long 0x00000002 version 2, +>16 long 0x00000003 version 3, +>16 long 0x00000004 version 4, +>16 long 0x00000005 version 5, +>16 long 0x00000006 version 6, +>16 long 0x00000007 version 7, +>16 long 0x00000008 version 8, +>16 long 0x00000009 version 9, +>12 long 0x00042253 native byte-order) + +12 long 0x53220400 Berkeley DB (Queue, +>16 long 0x01000000 version 1, +>16 long 0x02000000 version 2, +>16 long 0x03000000 version 3, +>16 long 0x04000000 version 4, +>16 long 0x05000000 version 5, +>16 long 0x06000000 version 6, +>16 long 0x07000000 version 7, +>16 long 0x08000000 version 8, +>16 long 0x09000000 version 9, +>12 long 0x53220400 little-endian) diff --git a/db/docs/ref/install/magic.s5.le.txt b/db/docs/ref/install/magic.s5.le.txt new file mode 100644 index 000000000..c8871fedf --- /dev/null +++ b/db/docs/ref/install/magic.s5.le.txt @@ -0,0 +1,87 @@ +# Berkeley DB +# $Id: magic.s5.le.txt,v 10.4 2000/07/07 21:02:22 krinsky Exp $ +# +# System V /etc/magic files: little-endian version. +# +# Hash 1.85/1.86 databases store metadata in network byte order. +# Btree 1.85/1.86 databases store the metadata in host byte order. +# Hash and Btree 2.X and later databases store the metadata in host byte order. + +0 long 0x00053162 Berkeley DB 1.85/1.86 (Btree, +>4 long 0x00000002 version 2, +>4 long 0x00000003 version 3, +>0 long 0x00053162 native byte-order) + +0 long 0x62310500 Berkeley DB 1.85/1.86 (Btree, +>4 long 0x02000000 version 2, +>4 long 0x03000000 version 3, +>0 long 0x62310500 big-endian) + +12 long 0x00053162 Berkeley DB (Btree, +>16 long 0x00000004 version 4, +>16 long 0x00000005 version 5, +>16 long 0x00000006 version 6, +>16 long 0x00000007 version 7, +>16 long 0x00000008 version 8, +>16 long 0x00000009 version 9, +>12 long 0x00053162 native byte-order) + +12 long 0x62310500 Berkeley DB (Btree, +>16 long 0x04000000 version 4, +>16 long 0x05000000 version 5, +>16 long 0x06000000 version 6, +>16 long 0x07000000 version 7, +>16 long 0x08000000 version 8, +>16 long 0x09000000 version 9, +>12 long 0x62310500 big-endian) + +0 long 0x61150600 Berkeley DB +>4 long >0x02000000 1.86 +>4 long <0x03000000 1.85 +>0 long 0x00061561 (Hash, +>4 long 0x02000000 version 2, +>4 long 0x03000000 version 3, +>8 long 0xD2040000 native byte-order) +>8 long 0xE1100000 big-endian) + +12 long 0x00061561 Berkeley DB (Hash, +>16 long 0x00000004 version 4, +>16 long 0x00000005 version 5, +>16 long 0x00000006 version 6, +>16 long 0x00000007 version 7, +>16 long 0x00000008 version 8, +>16 long 0x00000009 version 9, +>12 long 0x00061561 native byte-order) + +12 long 0x61150600 Berkeley DB (Hash, +>16 long 0x04000000 version 4, +>16 long 0x05000000 version 5, +>16 long 0x06000000 version 6, +>16 long 0x07000000 version 7, +>16 long 0x08000000 version 8, +>16 long 0x09000000 version 9, +>12 long 0x61150600 big-endian) + +12 long 0x00042253 Berkeley DB (Queue, +>16 long 0x00000001 version 1, +>16 long 0x00000002 version 2, +>16 long 0x00000003 version 3, +>16 long 0x00000004 version 4, +>16 long 0x00000005 version 5, +>16 long 0x00000006 version 6, +>16 long 0x00000007 version 7, +>16 long 0x00000008 version 8, +>16 long 0x00000009 version 9, +>12 long 0x00042253 native byte-order) + +12 long 0x53220400 Berkeley DB (Queue, +>16 long 0x01000000 version 1, +>16 long 0x02000000 version 2, +>16 long 0x03000000 version 3, +>16 long 0x04000000 version 4, +>16 long 0x05000000 version 5, +>16 long 0x06000000 version 6, +>16 long 0x07000000 version 7, +>16 long 0x08000000 version 8, +>16 long 0x09000000 version 9, +>12 long 0x53220400 big-endian) diff --git a/db/docs/ref/install/magic.txt b/db/docs/ref/install/magic.txt new file mode 100644 index 000000000..c28329f40 --- /dev/null +++ b/db/docs/ref/install/magic.txt @@ -0,0 +1,56 @@ +# Berkeley DB +# $Id: magic.txt,v 10.10 2000/07/07 21:02:22 krinsky Exp $ +# +# Ian Darwin's file /etc/magic files: big/little-endian version. +# +# Hash 1.85/1.86 databases store metadata in network byte order. +# Btree 1.85/1.86 databases store the metadata in host byte order. +# Hash and Btree 2.X and later databases store the metadata in host byte order. + +0 long 0x00061561 Berkeley DB +>8 belong 4321 +>>4 belong >2 1.86 +>>4 belong <3 1.85 +>>4 belong >0 (Hash, version %d, native byte-order) +>8 belong 1234 +>>4 belong >2 1.86 +>>4 belong <3 1.85 +>>4 belong >0 (Hash, version %d, little-endian) + +0 belong 0x00061561 Berkeley DB +>8 belong 4321 +>>4 belong >2 1.86 +>>4 belong <3 1.85 +>>4 belong >0 (Hash, version %d, big-endian) +>8 belong 1234 +>>4 belong >2 1.86 +>>4 belong <3 1.85 +>>4 belong >0 (Hash, version %d, native byte-order) + +0 long 0x00053162 Berkeley DB 1.85/1.86 +>4 long >0 (Btree, version %d, native byte-order) +0 belong 0x00053162 Berkeley DB 1.85/1.86 +>4 belong >0 (Btree, version %d, big-endian) +0 lelong 0x00053162 Berkeley DB 1.85/1.86 +>4 lelong >0 (Btree, version %d, little-endian) + +12 long 0x00061561 Berkeley DB +>16 long >0 (Hash, version %d, native byte-order) +12 belong 0x00061561 Berkeley DB +>16 belong >0 (Hash, version %d, big-endian) +12 lelong 0x00061561 Berkeley DB +>16 lelong >0 (Hash, version %d, little-endian) + +12 long 0x00053162 Berkeley DB +>16 long >0 (Btree, version %d, native byte-order) +12 belong 0x00053162 Berkeley DB +>16 belong >0 (Btree, version %d, big-endian) +12 lelong 0x00053162 Berkeley DB +>16 lelong >0 (Btree, version %d, little-endian) + +12 long 0x00042253 Berkeley DB +>16 long >0 (Queue, version %d, native byte-order) +12 belong 0x00042253 Berkeley DB +>16 belong >0 (Queue, version %d, big-endian) +12 lelong 0x00042253 Berkeley DB +>16 lelong >0 (Queue, version %d, little-endian) diff --git a/db/docs/ref/intro/data.html b/db/docs/ref/intro/data.html new file mode 100644 index 000000000..e9d6ead06 --- /dev/null +++ b/db/docs/ref/intro/data.html @@ -0,0 +1,54 @@ + + + + + +Berkeley DB Reference Guide: An introduction to data management + + + + + + +

Berkeley DB Reference Guide:
Introduction

RefNext +
+

+

An introduction to data management

+

Cheap, powerful computing and networking have created countless new +applications that could not have existed a decade ago. The advent of +the World-Wide Web, and its influence in driving the Internet into homes +and businesses, is one obvious example. Equally important, though, is +the from large, general-purpose desktop and server computers +toward smaller, special-purpose devices with built-in processing and +communications services. +

As computer hardware has spread into virtually every corner of our +lives, of course, software has followed. Software developers today are +building applications not just for conventional desktop and server +environments, but also for handheld computers, home appliances, +networking hardware, cars and trucks, factory floor automation systems, +and more. +

While these operating environments are diverse, the problems that +software engineers must solve in them are often strikingly similar. Most +systems must deal with the outside world, whether that means +communicating with users or controlling machinery. As a result, most +need some sort of I/O system. Even a simple, single-function system +generally needs to handle multiple tasks, and so needs some kind of +operating system to schedule and manage control threads. Also, many +computer systems must store and retrieve data to track history, record +configuration settings, or manage access. +

Data management can be very simple. In some cases, just recording +configuration in a flat text file is enough. More often, though, +programs need to store and search a large amount of data, or +structurally complex data. Database management systems are tools that +programmers can use to do this work quickly and efficiently using +off-the-shelf software. +

Of course, database management systems have been around for a long time. +Data storage is a problem dating back to the earliest days of computing. +Software developers can choose from hundreds of good, +commercially-available database systems. The problem is selecting the +one that best solves the problems that their applications face. +

RefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/intro/dbis.html b/db/docs/ref/intro/dbis.html new file mode 100644 index 000000000..10c4abd95 --- /dev/null +++ b/db/docs/ref/intro/dbis.html @@ -0,0 +1,159 @@ + + + + + +Berkeley DB Reference Guide: What is Berkeley DB? + + + + + + +

Berkeley DB Reference Guide:
Introduction

PrevRefNext +
+

+

What is Berkeley DB?

+

So far, we've discussed database systems in general terms. It's time +now to consider Berkeley DB in particular and see how it fits into the +framework we have introduced. The key question is, what kinds of +applications should use Berkeley DB? +

Berkeley DB is an open source embedded database library that provides +scalable, high-performance, transaction-protected data management +services to applications. Berkeley DB provides a simple function-call API +for data access and management. +

By "open source," we mean that Berkeley DB is distributed under a license that +conforms to the Open +Source Definition. This license guarantees that Berkeley DB is freely +available for use and redistribution in other open source products. +Sleepycat Software sells +commercial licenses for redistribution in proprietary applications, but +in all cases the complete source code for Berkeley DB is freely available for +download and use. +

Berkeley DB is embedded because it links directly into the application. It +runs in the same address space as the application. As a result, no +inter-process communication, either over the network or between +processes on the same machine, is required for database operations. +Berkeley DB provides a simple function-call API for a number of programming +languages, including C, C++, Java, Perl, Tcl, Python, and PHP. All +database operations happen inside the library. Multiple processes, or +multiple threads in a single process, can all use the database at the +same time as each uses the Berkeley DB library. Low-level services like +locking, transaction logging, shared buffer management, memory +management, and so on are all handled transparently by the library. +

The library is extremely portable. It runs under almost all UNIX and +Linux variants, Windows, and a number of embedded real-time operating +systems. It runs on both 32-bit and 64-bit systems. +It has been deployed on high-end +Internet servers, desktop machines, and on palmtop computers, set-top +boxes, in network switches, and elsewhere. Once Berkeley DB is linked into +the application, the end user generally does not know that there's a +database present at all. +

Berkeley DB is scalable in a number of respects. The database library itself +is quite compact (under 300 kilobytes of text space on common +architectures), but it can manage databases up to 256 terabytes in size. +It also supports high concurrency, with thousands of users operating on +the same database at the same time. Berkeley DB is small enough to run in +tightly constrained embedded systems, but can take advantage of +gigabytes of memory and terabytes of disk on high-end server machines. +

Berkeley DB generally outperforms relational and object-oriented database +systems in embedded applications for a couple of reasons. First, because +the library runs in the same address space, no inter-process +communication is required for database operations. The cost of +communicating between processes on a single machine, or among machines +on a network, is much higher than the cost of making a function call. +Second, because Berkeley DB uses a simple function-call interface for all +operations, there is no query language to parse, and no execution plan +to produce. +

Data Access Services

+

Berkeley DB applications can choose the storage structure that best suits the +application. Berkeley DB supports hash tables, B-trees, simple +record-number-based storage, and persistent queues. Programmers can +create tables using any of these storage structures, and can mix +operations on different kinds of tables in a single application. +

Hash tables are generally good for very large databases that need +predictable search and update times for random-access records. Hash +tables allow users to ask, "Does this key exist?" or to fetch a record +with a known key. Hash tables do not allow users to ask for records +with keys that are close to a known key. +

B-trees are better for range-based searches, as when the application +needs to find all records with keys between some starting and ending +value. B-trees also do a better job of exploiting locality +of reference. If the application is likely to touch keys near each +other at the same time, the B-trees work well. The tree structure keeps +keys that are close together near one another in storage, so fetching +nearby values usually doesn't require a disk access. +

Record-number-based storage is natural for applications that need +to store and fetch records, but that do not have a simple way to +generate keys of their own. In a record number table, the record +number is the key for the record. Berkeley DB will can generate these +record numbers automatically. +

Queues are well-suited for applications that create records, and then +must deal with those records in creation order. A good example is +on-line purchasing systems. Orders can enter the system at any time, +but should generally be filled in the order in which they were placed. +

Data management services

+

Berkeley DB offers important data management services, including concurrency, +transactions, and recovery. All of these services work on all of the +storage structures. +

Many users can work on the same database concurrently. Berkeley DB handles +locking transparently, ensuring that two users working on the same +record do not interfere with one another. +

The library provides strict ACID transaction semantics. Some systems +allow the user to relax, for example, the isolation guarantees that the +database system makes. Berkeley DB ensures that all applications can see only +committed updates. +

Multiple operations can be grouped into a single transaction, and can +be committed or rolled back atomically. Berkeley DB uses a technique called +two-phase locking to be sure that concurrent transactions +are isolated from one another, and a technique called +write-ahead logging to guarantee that committed changes +survive application, system, or hardware failures. +

When an application starts up, it can ask Berkeley DB to run recovery. +Recovery restores the database to a clean state, with all committed +changes present, even after a crash. The database is guaranteed to be +consistent and all committed changes are guaranteed to be present when +recovery completes. +

An application can specify, when it starts up, which data management +services it will use. Some applications need fast, +single-user, non-transactional B-tree data storage. In that case, the +application can disable the locking and transaction systems, and will +not incur the overhead of locking or logging. If an application needs +to support multiple concurrent users, but doesn't need transactions, it +can turn on locking without transactions. Applications that need +concurrent, transaction-protected database access can enable all of the +subsystems. +

In all these cases, the application uses the same function-call API to +fetch and update records. +

Design

+

Berkeley DB was designed to provide industrial-strength database services to +application developers, without requiring them to become database +experts. It is a classic C-library style toolkit, providing +a broad base of functionality to application writers. Berkeley DB was designed +by programmers, for programmers: its modular design surfaces simple, +orthogonal interfaces to core services, and it provides mechanism (for +example, good thread support) without imposing policy (for example, the +use of threads is not required). Just as importantly, Berkeley DB allows +developers to balance performance against the need for crash recovery +and concurrent use. An application can use the storage structure that +provides the fastest access to its data and can request only the degree +of logging and locking that it needs. +

Because of the tool-based approach and separate interfaces for each +Berkeley DB subsystem, you can support a complete transaction environment for +other system operations. Berkeley DB even allows you to wrap transactions +around the standard UNIX file read and write operations! Further, Berkeley DB +was designed to interact correctly with the native system's toolset, a +feature no other database package offers. For example, Berkeley DB supports +hot backups (database backups while the database is in use), using +standard UNIX system utilities, e.g., dump, tar, cpio, pax or even cp. +

Finally, because scripting language interfaces are available for Berkeley DB +(notably Tcl and Perl), application writers can build incredibly powerful +database engines with little effort. You can build transaction-protected +database applications using your favorite scripting languages, an +increasingly important feature in a world using CGI scripts to deliver +HTML. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/intro/dbisnot.html b/db/docs/ref/intro/dbisnot.html new file mode 100644 index 000000000..a55fa7176 --- /dev/null +++ b/db/docs/ref/intro/dbisnot.html @@ -0,0 +1,146 @@ + + + + + +Berkeley DB Reference Guide: What is Berkeley DB not? + + + + + + +

Berkeley DB Reference Guide:
Introduction

PrevRefNext +
+

+

What is Berkeley DB not?

+

In contrast to most other database systems, Berkeley DB provides relatively +simple data access services. +

Records in Berkeley DB are (key, value) pairs. Berkeley DB +supports only a few logical operations on records. They are: +

    +
  • Insert a record in a table. +
  • Delete a record from a table. +
  • Find a record in a table by looking up its key. +
  • Update a record that has already been found. +
+

Notice that Berkeley DB never operates on the value part of a record. +Values are simply payload, to be +stored with keys and reliably delivered back to the application on +demand. +

Both keys and values can be arbitrary bit strings, either fixed-length +or variable-length. As a result, programmers can put native programming +language data structures into the database without converting them to +a foreign record format first. Storage and retrieval are very simple, +but the application needs to know what the structure of a key and a +value is in advance. It cannot ask Berkeley DB, because Berkeley DB doesn't know. +

This is an important feature of Berkeley DB, and one worth considering more +carefully. On the one hand, Berkeley DB cannot provide the programmer with +any information on the contents or structure of the values that it +stores. The application must understand the keys and values that it +uses. On the other hand, there is literally no limit to the data types +that can be store in a Berkeley DB database. The application never needs to +convert its own program data into the data types that Berkeley DB supports. +Berkeley DB is able to operate on any data type the application uses, no +matter how complex. +

Because both keys and values can be up to four gigabytes in length, a +single record can store images, audio streams, or other large data +values. Large values are not treated specially in Berkeley DB. They are +simply broken into page-sized chunks, and reassembled on demand when +the application needs them. Unlike some other database systems, Berkeley DB +offers no special support for binary large objects (BLOBs). +

Not a relational database

+

Berkeley DB is not a relational database. +

First, Berkeley DB does not support SQL queries. All access to data is through +the Berkeley DB API. Developers must learn a new set of interfaces in order +to work with Berkeley DB. Although the interfaces are fairly simple, they are +non-standard. +

SQL support is a double-edged sword. One big advantage of relational +databases is that they allow users to write simple declarative queries +in a high-level language. The database system knows everything about +the data and can carry out the command. This means that it's simple to +search for data in new ways, and to ask new questions of the database. +No programming is required. +

On the other hand, if a programmer can predict in advance how an +application will access data, then writing a low-level program to get +and store records can be faster. It eliminates the overhead of query +parsing, optimization, and execution. The programmer must understand +the data representation, and must write the code to do the work, but +once that's done, the application can be very fast. +

Second, Berkeley DB has no notion of schema in the way that +relational systems do. Schema is the structure of records in tables, +and the relationships among the tables in the database. For example, in +a relational system the programmer can create a record from a fixed menu +of data types. Because the record types are declared to the system, the +relational engine can reach inside records and examine individual values +in them. In addition, programmers can use SQL to declare relationships +among tables, and to create indexes on tables. Relational engines +usually maintain these relationships and indexes automatically. +

In Berkeley DB, the key and value in a record are opaque +to Berkeley DB. They may have a rich +internal structure, but the library is unaware of it. As a result, Berkeley DB +cannot decompose the value part of a record into its constituent parts, +and cannot use those parts to find values of interest. Only the +application, which knows the data structure, can do that. +

Berkeley DB does allow programmers to create indexes on tables, and to use +those indexes to speed up searches. However, the programmer has no way +to tell the library how different tables and indexes are related. The +application needs to make sure that they all stay consistent. In the +case of indexes in particular, if the application puts a new record into +a table, it must also put a new record in the index for it. It's +generally simple to write a single function to make the required +updates, but it is work that relational systems do automatically. +

Berkeley DB is not a relational system. Relational database systems are +semantically rich and offer high-level database access. Compared to such +systems, Berkeley DB is a high-performance, transactional library for record +storage. It's possible to build a relational system on top of Berkeley DB. In +fact, the popular MySQL relational system uses Berkeley DB for +transaction-protected table management, and takes care of all the SQL +parsing and execution. It uses Berkeley DB for the storage level, and provides +the semantics and access tools. +

Not an object-oriented database

+

Object-oriented databases are designed for very tight integration with +object-oriented programming languages. Berkeley DB is written entirely in the +C programming language. It includes language bindings for C++, Java, +and other languages, but the library has no information about the +objects created in any object-oriented application. Berkeley DB never makes +method calls on any application object. It has no idea what methods are +defined on user objects, and cannot see the public or private members +of any instance. The key and value part of all records are opaque to +Berkeley DB. +

Berkeley DB cannot automatically page in referenced objects, as some +object-oriented databases do. The object-oriented application programmer +must decide what records are required, and must fetch them by making +method calls on Berkeley DB objects. +

Not a network database

+

Berkeley DB does not support network-style navigation among records, as +network databases do. Records in a Berkeley DB table may move around over +time, as new records are added to the table and old ones are deleted. +Berkeley DB is able to do fast searches for records based on keys, but there +is no way to create a persistent physical pointer to a record. +Applications can only refer to records by key, not by address. +

Not a database server

+

Berkeley DB is not a standalone database server. It is a library, and runs in +the address space of the application that uses it. If more than one +application links in Berkeley DB, then all can use the same database at the +same time; the library handles coordination among the applications, and +guarantees that they do not interfere with one another. +

Recent releases of Berkeley DB allow programmers to compile the library as a +standalone process, and to use RPC stubs to connect to it and to carry +out operations. However, there are some important limitations to this +feature. The RPC stubs provide exactly the same API that the library +itself does. There is no higher-level access provided by the standalone +process. Tuning the standalone process is difficult, since Berkeley DB does +no threading in the library (applications can be threaded, but the +library never creates a thread on its own). +

It is possible to build a server application that uses Berkeley DB for data +management. For example, many commercial and open source Lightweight +Directory Access Protocol (LDAP) servers use Berkeley DB for record storage. +LDAP clients connect to these servers over the network. Individual +servers make calls through the Berkeley DB API to find records and return them +to clients. On its own, however, Berkeley DB is not a server. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/intro/distrib.html b/db/docs/ref/intro/distrib.html new file mode 100644 index 000000000..a5ff52263 --- /dev/null +++ b/db/docs/ref/intro/distrib.html @@ -0,0 +1,28 @@ + + + + + +Berkeley DB Reference Guide: What does the Berkeley DB distribution include? + + + + + + +

Berkeley DB Reference Guide:
Introduction

PrevRefNext +
+

+

What does the Berkeley DB distribution include?

+

The Berkeley DB distribution includes complete source code for the Berkeley DB +library, including all three Berkeley DB products and their supporting +utilities, as well as complete documentation in HTML format. +

The distribution does not include pre-built binaries or libraries, or +hard-copy documentation. Pre-built libraries and binaries for some +architecture/compiler combinations are available as part of Sleepycat +Software's Berkeley DB support services. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/intro/need.html b/db/docs/ref/intro/need.html new file mode 100644 index 000000000..771dd9890 --- /dev/null +++ b/db/docs/ref/intro/need.html @@ -0,0 +1,60 @@ + + + + + +Berkeley DB Reference Guide: Do you need Berkeley DB? + + + + + + +

Berkeley DB Reference Guide:
Introduction

PrevRefNext +
+

+

Do you need Berkeley DB?

+

Berkeley DB is an ideal database system for applications that need fast, +scalable, and reliable embedded database management. For applications +that need different services, however, it can be a poor choice. +

First, do you need the ability to access your data in ways you cannot +predict in advance? If your users want to be able to enter SQL +queries to perform +complicated searches that you cannot program into your application to +begin with, then you should consider a relational engine instead. Berkeley DB +requires a programmer to write code in order to run a new kind of query. +

On the other hand, if you can predict your data access patterns up front +-- and in particular if you need fairly simple key/value lookups -- then +Berkeley DB is a good choice. The queries can be coded up once, and will then +run very quickly because there is no SQL to parse and execute. +

Second, are there political arguments for or against a standalone +relational server? If you're building an application for your own use +and have a relational system installed with administrative support +already, it may be simpler to use that than to build and learn Berkeley DB. +On the other hand, if you'll be shipping many copies of your application +to customers, and don't want your customers to have to buy, install, +and manage a separate database system, then Berkeley DB may be a better +choice. +

Third, are there any technical advantages to an embedded database? If +you're building an application that will run unattended for long periods +of time, or for end users who are not sophisticated administrators, then +a separate server process may be too big a burden. It will require +separate installation and management, and if it creates new ways for +the application to fail, or new complexities to master in the field, +then Berkeley DB may be a better choice. +

The fundamental question is, how closely do your requirements match the +Berkeley DB design? Berkeley DB was conceived and built to provide fast, reliable, +transaction-protected record storage. The library itself was never +intended to provide interactive query support, graphical reporting +tools, or similar services that some other database systems provide. We +have tried always to err on the side of minimalism and simplicity. By +keeping the library small and simple, we create fewer opportunities for +bugs to creep in, and we guarantee that the database system stays fast, +because there is very little code to execute. If your application needs +that set of features, then Berkeley DB is almost certainly the best choice +for you. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/intro/products.html b/db/docs/ref/intro/products.html new file mode 100644 index 000000000..ce04135f0 --- /dev/null +++ b/db/docs/ref/intro/products.html @@ -0,0 +1,69 @@ + + + + + +Berkeley DB Reference Guide: Sleepycat Software's Berkeley DB products + + + + + + + +

Berkeley DB Reference Guide:
Introduction

PrevRefNext +
+

+

Sleepycat Software's Berkeley DB products

+

Sleepycat Software licenses three different products that use the Berkeley DB +technology. Each product offers a distinct level of database support. +It is not possible to mix-and-match products, that is, each application +or group of applications must use the same Berkeley DB product. +

All three products are included in the single Open Source distribution of +Berkeley DB from Sleepycat Software, and building that distribution +automatically builds all three products. Each product adds services, and +new interfaces, to the product that precedes it in the list. As a result, +developers can download Berkeley DB and build an application that does only +single-user, read-only database access, and later add support for more +users and more complex database access patterns. +

Users who distribute Berkeley DB must ensure that they are licensed for the +Berkeley DB interfaces they use. Information on licensing is available directly +from Sleepycat Software. +

Berkeley DB Data Store

+

The Berkeley DB Data Store product is an embeddable, high-performance data store. It +supports multiple concurrent threads of control to read information +managed by Berkeley DB. When updates are required, only a single process may +be using the database. That process may be multi-threaded, but only one +thread of control should be allowed to update the database at any time. +The Berkeley DB Data Store does no locking, and so provides no guarantees of correct +behavior if more than one thread of control is updating the database at +a time. +

The Berkeley DB Data Store product includes the db_create interface, the +DB handle methods, and the methods returned by DB->cursor. +

The Berkeley DB Data Store is intended for use in single-user or read-only applications +that can guarantee that no more than one thread of control will ever +update the database at any time. +

Berkeley DB Concurrent Data Store

+

The Berkeley DB Concurrent Data Store product adds multiple-reader, single writer capabilities to +the Berkeley DB Data Store product, supporting applications that need concurrent updates +and do not want to implement their own locking protocols. The additional +interfaces included with the Berkeley DB Concurrent Data Store product are db_env_create, the +DBENV->open method (using the DB_INIT_CDB flag), and the +DBENV->close method. +

Berkeley DB Concurrent Data Store is intended for applications that require occasional write access +to a database that is largely used for reading. +

Berkeley DB Transactional Data Store

+

The Berkeley DB Transactional Data Store product adds full transactional support and recoverability +to the Berkeley DB Data Store product. This product includes all of the interfaces +in the Berkeley DB library. +

Berkeley DB Transactional Data Store is intended for applications that require industrial-strength +database services, including good performance under high-concurrency +workloads with a mixture of readers and writers, the ability to commit +or roll back multiple changes to the database at a single instant, and +the guarantee that even in the event of a catastrophic system or hardware +failure, any committed database changes will be preserved. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/intro/terrain.html b/db/docs/ref/intro/terrain.html new file mode 100644 index 000000000..f2a708913 --- /dev/null +++ b/db/docs/ref/intro/terrain.html @@ -0,0 +1,248 @@ + + + + + +Berkeley DB Reference Guide: Mapping the terrain: theory and practice + + + + + + +

Berkeley DB Reference Guide:
Introduction

PrevRefNext +
+

+

Mapping the terrain: theory and practice

+

The first step in selecting a database system is figuring out what the +choices are. Decades of research and real-world deployment have produced +countless systems. We need to organize them somehow to reduce the number +of options. +

One obvious way to group systems is to use the common labels that +vendors apply to them. The buzzwords here include "network," +"relational," "object-oriented," and "embedded," with some +cross-fertilization like "object-relational" and "embedded network". +Understanding the buzzwords is important. Each has some grounding in +theory, but has also evolved into a practical label for categorizing +systems that work in a certain way. +

All database systems, regardless of the buzzwords that apply to them, +provide a few common services. All of them store data, for example. +We'll begin by exploring the common services that all systems provide, +and then examine the differences among the different kinds of systems. +

Data access and data management

+

Fundamentally, database systems provide two services. +

The first service is data access. Data access means adding +new data to the database (inserting), finding data of interest +(searching), changing data already stored (updating), and removing data +from the database (deleting). All databases provide these services. How +they work varies from category to category, and depends on the record +structure that the database supports. +

Each record in a database is a collection of values. For example, the +record for a Web site customer might include a name, email address, +shipping address, and payment information. Records are usually stored +in tables. Each table holds records of the same kind. For example, the +customer table at an e-commerce Web site might store the +customer records for every person who shopped at the site. Often, +database records have a different structure from the structures or +instances supported by the programming language in which an application +is written. As a result, working with records can mean: +

    +
  • using database operations like searches and updates on records; and +
  • converting between programming language structures and database record +types in the application. +
+

The second service is data management. Data management is +more complicated than data access. Providing good data management +services is the hard part of building a database system. When you +choose a database system to use in an application you build, making sure +it supports the data management services you need is critical. +

Data management services include allowing multiple users to work on the +database simultaneously (concurrency), allowing multiple records to be +changed instantaneously (transactions), and surviving application and +system crashes (recovery). Different database systems offer different +data management services. Data management services are entirely +independent of the data access services listed above. For example, +nothing about relational database theory requires that the system +support transactions, but most commercial relational systems do. +

Concurrency means that multiple users can operate on the database at +the same time. Support for concurrency ranges from none (single-user +access only) to complete (many readers and writers working +simultaneously). +

Transactions permit users to make multiple changes appear at once. For +example, a transfer of funds between bank accounts needs to be a +transaction because the balance in one account is reduced and the +balance in the other increases. If the reduction happened before the +increase, than a poorly-timed system crash could leave the customer +poorer; if the bank used the opposite order, then the same system crash +could make the customer richer. Obviously, both the customer and the +bank are best served if both operations happen at the same instant. +

Transactions have well-defined properties in database systems. They are +atomic, so that the changes happen all at once or not at all. +They are consistent, so that the database is in a legal state +when the transaction begins and when it ends. They are typically +isolated, which means that any other users in the database +cannot interfere with them while they are in progress. And they are +durable, so that if the system or application crashes after +a transaction finishes, the changes are not lost. Together, the +properties of atomicity, consistency, +isolation, and durability are known as the ACID +properties. +

As is the case for concurrency, support for transactions varies among +databases. Some offer atomicity without making guarantees about +durability. Some ignore isolatability, especially in single-user +systems; there's no need to isolate other users from the effects of +changes when there are no other users. +

Another important data management service is recovery. Strictly +speaking, recovery is a procedure that the system carries out when it +starts up. The purpose of recovery is to guarantee that the database is +complete and usable. This is most important after a system or +application crash, when the database may have been damaged. The recovery +process guarantees that the internal structure of the database is good. +Recovery usually means that any completed transactions are checked, and +any lost changes are reapplied to the database. At the end of the +recovery process, applications can use the database as if there had been +no interruption in service. +

Finally, there are a number of data management services that permit +copying of data. For example, most database systems are able to import +data from other sources, and to export it for use elsewhere. Also, most +systems provide some way to back up databases and to restore in the +event of a system failure that damages the database. Many commercial +systems allow hot backups, so that users can back up +databases while they are in use. Many applications must run without +interruption, and cannot be shut down for backups. +

A particular database system may provide other data management services. +Some provide browsers that show database structure and contents. Some +include tools that enforce data integrity rules, such as the rule that +no employee can have a negative salary. These data management services +are not common to all systems, however. Concurrency, recovery, and +transactions are the data management services that most database vendors +support. +

Deciding what kind of database to use means understanding the data +access and data management services that your application needs. Berkeley DB +is an embedded database that supports fairly simple data access with a +rich set of data management services. To highlight its strengths and +weaknesses, we can compare it to other database system categories. +

Relational databases

+

Relational databases are probably the best-known database variant, +because of the success of companies like Oracle. Relational databases +are based on the mathematical field of set theory. The term "relation" +is really just a synonym for "set" -- a relation is just a set of +records or, in our terminology, a table. One of the main innovations in +early relational systems was to insulate the programmer from the +physical organization of the database. Rather than walking through +arrays of records or traversing pointers, programmers make statements +about tables in a high-level language, and the system executes those +statements. +

Relational databases operate on tuples, or records, composed +of values of several different data types, including integers, character +strings, and others. Operations include searching for records whose +values satisfy some criteria, updating records, and so on. +

Virtually all relational databases use the Structured Query Language, +or SQL. This language permits people and computer programs to work with +the database by writing simple statements. The database engine reads +those statements and determines how to satisfy them on the tables in +the database. +

SQL is the main practical advantage of relational database systems. +Rather than writing a computer program to find records of interest, the +relational system user can just type a query in a simple syntax, and +let the engine do the work. This gives users enormous flexibility; they +do not need to decide in advance what kind of searches they want to do, +and they do not need expensive programmers to find the data they need. +Learning SQL requires some effort, but it's much simpler than a +full-blown high-level programming language for most purposes. And there +are a lot of programmers who have already learned SQL. +

Object-oriented databases

+

Object-oriented databases are less common than relational systems, but +are still fairly widespread. Most object-oriented databases were +originally conceived as persistent storage systems closely wedded to +particular high-level programming languages like C++. With the spread +of Java, most now support more than one programming language, but +object-oriented database systems fundamentally provide the same class +and method abstractions as do object-oriented programming languages. +

Many object-oriented systems allow applications to operate on objects +uniformly, whether they are in memory or on disk. These systems create +the illusion that all objects are in memory all the time. The advantage +to object-oriented programmers who simply want object storage and +retrieval is clear. They need never be aware of whether an object is in +memory or not. The application simply uses objects, and the database +system moves them between disk and memory transparently. All of the +operations on an object, and all its behavior, are determined by the +programming language. +

Object-oriented databases aren't nearly as widely deployed as relational +systems. In order to attract developers who understand relational +systems, many of the object-oriented systems have added support for +query languages very much like SQL. In practice, though, object-oriented +databases are mostly used for persistent storage of objects in C++ and +Java programs. +

Network databases

+

The "network model" is a fairly old technique for managing and +navigating application data. Network databases are designed to make +pointer traversal very fast. Every record stored in a network database +is allowed to contain pointers to other records. These pointers are +generally physical addresses, so fetching the referenced record just +means reading it from disk by its disk address. +

Network database systems generally permit records to contain integers, +floating point numbers, and character strings, as well as references to +other records. An application can search for records of interest. After +retrieving a record, the application can fetch any referenced record +quickly. +

Pointer traversal is fast because most network systems use physical disk +addresses as pointers. When the application wants to fetch a record, +the database system uses the address to fetch exactly the right string +of bytes from the disk. This requires only a single disk access in all +cases. Other systems, by contrast, often must do more than one disk read +to find a particular record. +

The key advantage of the network model is also its main drawback. The +fact that pointer traversal is so fast means that applications that do +it will run well. On the other hand, storing pointers all over the +database makes it very hard to reorganize the database. In effect, once +you store a pointer to a record, it is difficult to move that record +elsewhere. Some network databases handle this by leaving forwarding +pointers behind, but this defeats the speed advantage of doing a single +disk access in the first place. Other network databases find, and fix, +all the pointers to a record when it moves, but this makes +reorganization very expensive. Reorganization is often necessary in +databases, since adding and deleting records over time will consume +space that cannot be reclaimed without reorganizing. Without periodic +reorganization to compact network databases, they can end up with a +considerable amount of wasted space. +

Clients and servers

+

Database vendors have two choices for system architecture. They can +build a server to which remote clients connect, and do all the database +management inside the server. Alternatively, they can provide a module +that links directly into the application, and does all database +management locally. In either case, the application developer needs +some way of communicating with the database (generally, an Application +Programming Interface (API) that does work in the process or that +communicates with a server to get work done). +

Almost all commercial database products are implemented as servers, and +applications connect to them as clients. Servers have several features +that make them attractive. +

First, because all of the data is managed by a separate process, and +possibly on a separate machine, it's easy to isolate the database server +from bugs and crashes in the application. +

Second, because some database products (particularly relational engines) +are quite large, splitting them off as separate server processes keeps +applications small, which uses less disk space and memory. Relational +engines include code to parse SQL statements, to analyze them and +produce plans for execution, to optimize the plans, and to execute +them. +

Finally, by storing all the data in one place and managing it with a +single server, it's easier for organizations to back up, protect, and +set policies on their databases. The enterprise databases for large +companies often have several full-time administrators caring for them, +making certain that applications run quickly, granting and denying +access to users, and making backups. +

However, centralized administration can be a disadvantage in some cases. +In particular, if a programmer wants to build an application that uses +a database for storage of important information, then shipping and +supporting the application is much harder. The end user needs to install +and administer a separate database server, and the programmer must +support not just one product, but two. Adding a server process to the +application creates new opportunity for installation mistakes and +run-time problems. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/intro/what.html b/db/docs/ref/intro/what.html new file mode 100644 index 000000000..c8d12069a --- /dev/null +++ b/db/docs/ref/intro/what.html @@ -0,0 +1,53 @@ + + + + + +Berkeley DB Reference Guide: What other services does Berkeley DB provide? + + + + + + +

Berkeley DB Reference Guide:
Introduction

PrevRefNext +
+

+

What other services does Berkeley DB provide?

+

Berkeley DB also provides core database services to developers. These +services include: +

+

Page cache management:
The page cache provides fast access to a cache of database pages, +handling the I/O associated with the cache to ensure that dirty pages +are written back to the file system and that new pages are allocated on +demand. Applications may use the Berkeley DB shared memory buffer manager to +serve their own files and pages. +

Transactions and logging:
The transaction and logging systems provide recoverability and atomicity +for multiple database operations. The transaction system uses two-phase +locking and write-ahead logging protocols to ensure that database +operations may be undone or redone in the case of application or system +failure. Applications may use Berkeley DB transaction and logging subsystems +to protect their own data structures and operations from application or +system failure. +

Locking:
The locking system provides multiple reader or single writer access to +objects. The Berkeley DB access methods use the locking system to acquire +the right to read or write database pages. Applications may use the +Berkeley DB locking subsystem to support their own locking needs. +
+

By combining the page cache, transaction, locking, and logging systems, +Berkeley DB provides the same services found in much larger, more complex and +more expensive database systems. Berkeley DB supports multiple simultaneous +readers and writers and guarantees that all changes are recoverable, even +in the case of a catastrophic hardware failure during a database update. +

Developers may select some or all of the core database services for any +access method or database. Therefore, it is possible to choose the +appropriate storage structure and the right degrees of concurrency and +recoverability for any application. In addition, some of the systems +(e.g., the locking subsystem) can be called separately from the Berkeley DB +access method. As a result, developers can integrate non-database +objects into their transactional applications using Berkeley DB. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/intro/where.html b/db/docs/ref/intro/where.html new file mode 100644 index 000000000..45d0dc3ae --- /dev/null +++ b/db/docs/ref/intro/where.html @@ -0,0 +1,39 @@ + + + + + +Berkeley DB Reference Guide: Where does Berkeley DB run? + + + + + + +

Berkeley DB Reference Guide:
Introduction

PrevRefNext +
+

+

Where does Berkeley DB run?

+

Berkeley DB requires only underlying IEEE/ANSI Std 1003.1 (POSIX) system calls and can be +ported easily to new architectures by adding stub routines to connect +the native system interfaces to the Berkeley DB POSIX-style system calls. +

Berkeley DB will autoconfigure and run on almost any modern UNIX system, and +even on most historical UNIX platforms. See +Building for UNIX systems for +more information. +

The Berkeley DB distribution includes support for QNX Neutrino. See +Building for UNIX systems for +more information. +

The Berkeley DB distribution includes support for VxWorks, via a workspace +and project files for Tornado 2.0. See +Building for VxWorks for more +information. +

The Berkeley DB distribution includes support for Windows/95, Windows/98, +Windows/NT and Windows/2000, via the MSVC 5 and 6 development +environments. See Building for +Windows systems for more information. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/java/compat.html b/db/docs/ref/java/compat.html new file mode 100644 index 000000000..4619ec557 --- /dev/null +++ b/db/docs/ref/java/compat.html @@ -0,0 +1,34 @@ + + + + + +Berkeley DB Reference Guide: Compatibility + + + + + + + +

Berkeley DB Reference Guide:
Java API

PrevRefNext +
+

+

Compatibility

+

The Berkeley DB Java API has been tested with the +Sun Microsystems JDK 1.1.3 on SunOS +5.5, and Sun's JDK 1.1.7, JDK 1.2.2 and JDK 1.3.0 on Linux and +Windows/NT. It should work with any JDK 1.1, 1.2 or 1.3 (the latter +two are known as Java 2) compatible environment. IBM's VM 1.3.0 has +also been tested on Linux. +

The primary requirement of the Berkeley DB Java API is that the target Java +environment supports JNI (Java Native Interface), rather than another +method for allowing native C/C++ code to interface to Java. The JNI was +new in JDK 1.1, but is the most likely interface to be implemented across +multiple platforms. However, using the JNI means that Berkeley DB will not be +compatible with Microsoft Visual J++. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/java/conf.html b/db/docs/ref/java/conf.html new file mode 100644 index 000000000..b7eedcaed --- /dev/null +++ b/db/docs/ref/java/conf.html @@ -0,0 +1,82 @@ + + + + + +Berkeley DB Reference Guide: Configuration + + + + + + + +

Berkeley DB Reference Guide:
Java API

PrevRefNext +
+

+

Configuration

+

Building the Berkeley DB java classes, the examples and the native support +library is integrated into the normal build process. See +Configuring +Berkeley DB and Building for Windows +for more information. +

We expect that you've already installed the Java JDK or equivalent on +your system. For the sake of discussion, we'll assume it is in a +directory called db-VERSION, e.g., you extracted Berkeley DB version 2.3.12 +and you did not change the top-level directory name. The files related +to Java are in two subdirectories of db-VERSION: java, the java source +files, and libdb_java, the C++ files that provide the "glue" between +java and Berkeley DB. The directory tree looks like this: +

		db-VERSION
+	       /          \
+	    java        libdb_java
+	     |              |
+	    src            ...
+	     |
+	    com
+	     |
+	 sleepycat
+	/         \
+       db       examples
+       |           |
+      ...         ...
+
+

This naming conforms to the emerging standard for naming java packages. +When the java code is built, it is placed into a classes +subdirectory that is parallel to the src subdirectory. +

For your application to use Berkeley DB successfully, you must set your +CLASSPATH environment variable to include db-VERSION/java/classes as +well as the classes in your java distribution. On UNIX, CLASSPATH is +a colon separated list of directories; on Windows it is separated by +semicolons. Alternatively, you can set your CLASSPATH to include +db-VERSION/java/classes/db.jar which is created as a result of the +build. The db.jar file contains the classes in com.sleepycat.db, it +does not contain any classes in com.sleepycat.examples. +

On Windows, you will want to set your PATH variable to include: +

db-VERSION\build_win32\Release
+

On UNIX, you will want to set the LD_LIBRARY_PATH environment variable +to include the Berkeley DB library installation directory. Of course, the +standard install directory may have been changed for your site, see your +system administrator for details. Regardless, if you get a: +

java.lang.UnsatisfiedLinkError
+

exception when you run, chances are you do not have the library search +path configured correctly. Different Java interpreters provide +different error messages if the CLASSPATH value is incorrect, a typical +error is: +

java.lang.NoClassDefFoundError
+

To ensure that everything is running correctly, you may want to try a +simple test from the example programs in: +

db-VERSION/java/src/com/sleepycat/examples
+

For example, the sample program: +

% java com.sleepycat.examples.AccessExample
+

will prompt for text input lines which are then stored in a Btree +database named "access.db" in your current directory. Try giving it a +few lines of input text and then end-of-file. Before it exits, you +should see a list of the lines you entered display with data items. +This is a simple check to make sure the fundamental configuration is +working correctly. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/java/faq.html b/db/docs/ref/java/faq.html new file mode 100644 index 000000000..75b9e9f3b --- /dev/null +++ b/db/docs/ref/java/faq.html @@ -0,0 +1,31 @@ + + + + + +Berkeley DB Reference Guide: Frequently Asked Questions + + + + + + + +

Berkeley DB Reference Guide:
Java API

PrevRefNext +
+

+

Frequently Asked Questions

+

    +

  1. During one of the first calls to the Berkeley DB Java API, a +DbException is thrown with a "Bad file number" or "Bad file descriptor" +message. +

    There are known large-file support bugs under JNI in various releases +of the JDK. Please upgrade to the latest release of the JDK, and, if +that does not help, disable big file support using the --disable-bigfile +configuration option. +

+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/java/program.html b/db/docs/ref/java/program.html new file mode 100644 index 000000000..c454a0910 --- /dev/null +++ b/db/docs/ref/java/program.html @@ -0,0 +1,72 @@ + + + + + +Berkeley DB Reference Guide: Java Programming Notes + + + + + + +

Berkeley DB Reference Guide:
Programmer Notes

PrevRefNext +
+

+

Java Programming Notes

+

The Java API closely parallels the Berkeley DB C++ and C interfaces. If you +are currently using either of those APIs, there will be very little to +surprise you in the Java API. We have even taken care to make the names +of classes, constants, methods and arguments identical, where possible, +across all three APIs. +

    +

  1. The Java runtime does not automatically close Berkeley DB objects on +finalization. There are a couple reasons for this. One is that +finalization is generally run only when garbage collection occurs and +there is no guarantee that this occurs at all, even on exit. Allowing +specific Berkeley DB actions to occur in ways that cannot be replicated seems +wrong. Secondly, finalization of objects may happen in an arbitrary +order, so we would have to do extra bookkeeping to make sure everything +was closed in the proper order. The best word of advice is to always +do a close() for any matching open() call. Specifically, the Berkeley DB +package requires that you explicitly call close on each individual +Db and Dbc object that you opened. Your database +activity may not be synchronized to disk unless you do so. +

  2. Some methods in the Java API have no return type, and throw a +DbException when an severe error arises. There are some notable +methods that do have a return value, and can also throw an exception. +Db.get and Dbc.get both return 0 when a get succeeds, +Db.DB_NOTFOUND when the key is not found, and throw an error when +there is a severe error. This approach allows the programmer to check +for typical data driven errors by watching return values without special +casing exceptions. +

    An object of type DbDeadlockException is thrown when a deadlock +would occur. +

    An object of type DbMemoryException is thrown when the system +cannot provide enough memory to complete the operation (the ENOMEM +system error on UNIX). +

    An object of type DbRunRecoveryException, a subclass of +DbException, is thrown when there is an error that requires a +recovery of the database, using db_recover. +

  3. There is no class corresponding to the C++ DbMpoolFile class in the Berkeley DB +Java API. There is a subset of the memp_XXX methods in the DbEnv +class. This has been provided to allow you to perform certain +administrative actions on underlying memory pools opened as a consequence +of DbEnv.open. Direct access to other memory pool functionality +is not appropriate for the Java environment. +

  4. Berkeley DB always turns on the Db.DB_THREAD flag since threads +are expected in Java. +

  5. If there are embedded null strings in the curslist argument for +Db.join, they will be treated as the end of the list of +cursors, even though you may have allocated a longer array. Fill in +all the strings in your array unless you intend to cut it short. +

  6. The callback installed for DbEnv.set_errcall will run in the same +thread as the caller to DbEnv.set_errcall. Make sure that thread +remains running until your application exits or DbEnv.close is +called. +
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/lock/am_conv.html b/db/docs/ref/lock/am_conv.html new file mode 100644 index 000000000..7dbe3e73d --- /dev/null +++ b/db/docs/ref/lock/am_conv.html @@ -0,0 +1,129 @@ + + + + + +Berkeley DB Reference Guide: Access method locking conventions + + + + + + + +

Berkeley DB Reference Guide:
Locking Subsystem

PrevRefNext +
+

+

Access method locking conventions

+

All the Berkeley DB access methods follow the same conventions for locking +database objects. Applications that do their own locking and also do +locking via the access methods must be careful to adhere to these +conventions. +

Whenever a Berkeley DB database is opened, the DB handle is +assigned a unique locker ID. Unless transactions are specified, +that ID is used as the locker for all calls that the Berkeley DB methods +make to the lock subsystem. In order to lock a file, pages in +the file, or records in the file, we must create a unique ID that +can be used as the object to be locked in calls to the lock manager. +Under normal operation, that object is a 28-byte value, created by +the concatenation of a unique file identifier, a page or record number, +and an object type (page or record). +

In a transaction-protected environment, database create and delete +operations are recoverable and single-threaded. This single-threading is +achieved using a single lock for the entire environment that must be +acquired before beginning a create or delete operation. In this case, +the object on which Berkeley DB will lock is a 32-bit unsigned integer with a +value of 0. +

If applications are using the lock subsystem directly while they are also +using locking via the access methods, they must take care not to +inadvertently lock objects that happen to be equal to the unique file IDs +used to lock files. This is most easily accomplished by using a locker +ID of a different length than the values used by Berkeley DB. +

All of the access methods other than Queue use a simple +multiple-reader/single writer page locking scheme. The standard +read/write locks (DB_LOCK_READ and DB_LOCK_WRITE) and +conflict matrix, as described in Standard lock modes are used. An operation that returns data (e.g., +DB->get, DBcursor->c_get) obtains a read lock on all the pages +accessed while locating the requested record. When an update operation +is requested (e.g., DB->put, DBcursor->c_del), the page containing +the updated (or new) data is write locked. As read-modify-write cycles +are quite common and are deadlock prone under normal circumstances, the +Berkeley DB interfaces allow the application to specify the DB_RMW flag, +which causes operations to immediately obtain a writelock, even though +they are only reading the data. While this may reduce concurrency +somewhat, it reduces the probability of deadlock. +

The Queue access method does not hold long term page locks. +Instead, page locks are held only long enough to locate records or to change +metadata on a page, and record locks are held for the appropriate duration. +In the presence of transactions, record locks are held until transaction +commit. +For Berkeley DB operations, record locks are held until operation +completion and for DBC operations, record locks are held until +subsequent records are returned or the cursor is closed. +

Under non-transaction operation, the access methods do not normally hold +locks across calls to the Berkeley DB interfaces. The one exception to this +rule is when cursors are used. As cursors maintain a position in a file, +they must hold locks across calls and will, in fact, hold locks until the +cursor is closed. Furthermore, each cursor is assigned its own unique +locker ID when it is created, so cursor operations can conflict with one +another. (Each cursor is assigned its own locker ID because Berkeley DB handles +may be shared by multiple threads of control. The Berkeley DB library cannot +identify which operations are performed by which threads of control, and +it must ensure that two different threads of control are not +simultaneously modifying the same data structure. By assigning each +cursor its own locker, two threads of control sharing a handle cannot +inadvertently interfere with each other. +

This has important implications. If a single thread of control opens two +cursors or uses a combination of cursor and non-cursor operations, these +operations are performed on behalf of different lockers. Conflicts that +arise between these different lockers may not cause actual deadlocks, but +can, in fact, permanently block the thread of control. For example, +assume that an application creates a cursor and uses it to read record A. +Now assume a second cursor is opened and the application attempts to write +record A using the second cursor. Unfortunately, the first cursor has a +read lock so the second cursor cannot obtain its write lock. However, +that read lock is held by the same thread of control, so if we block +waiting for the write lock, the read lock can never be released. This +might appear to be a deadlock from the application's perspective, but +Berkeley DB cannot identify it as such because it has no knowledge of which +lockers belong to which threads of control. For this reason, application +designers are encouraged to close cursors as soon as they are done with +them. +

Complicated operations that require multiple cursors (or combinations of +cursor and non-cursor operations) can be performed in two ways. First, +they may be performed within a transaction, in which case all operations +lock on behalf of the designated locker ID. Alternatively, the +DBcursor->c_dup function duplicates a cursor, using the same locker ID as +the originating cursor. There is no way to achieve this duplication +functionality through the DB handle calls, but any DB call can be +implemented by one or more calls through a cursor. +

When the access methods use transactions, many of these problems disappear. +The transaction ID is used as the locker ID for all operations performed +on behalf of the transaction. This means that the application may open +multiple cursors on behalf of the same transaction and these cursors will +all share a common locker ID. This is safe because transactions cannot +span threads of control, so the library knows that two cursors in the same +transaction cannot modify the database concurrently. +

As mentioned earlier, most of the Berkeley DB access methods use page level +locking. During Btree traversal, lock-coupling is used to traverse the +tree. Note that the tree traversal that occurs during an update operation +can also use lock-coupling; it is not necessary to retain locks on +internal Btree pages even if the item finally referenced will be updated. +Even in the presence of transactions, locks obtained on internal pages of +the Btree may be safely released as the traversal proceeds. This greatly +improves concurrency. The only time internal locks become crucial is when +internal pages are split or merged. When traversing duplicate data items +for a key, the lock on the key value also acts as a lock on all duplicates +of that key. Therefore, two conflicting threads of control cannot access +the same duplicate set simultaneously. +

The Recno access method uses a Btree as its underlying data +representation and follows similar locking conventions. However, as the +Recno access method must keep track of the number of children for all +internal pages, it must obtain write locks on all internal pages during +read and write operations. In the presence of transactions, these locks +are not released until transaction commit. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/lock/cam_conv.html b/db/docs/ref/lock/cam_conv.html new file mode 100644 index 000000000..b37914890 --- /dev/null +++ b/db/docs/ref/lock/cam_conv.html @@ -0,0 +1,53 @@ + + + + + +Berkeley DB Reference Guide: Berkeley DB Concurrent Data Store locking conventions + + + + + + + +

Berkeley DB Reference Guide:
Locking Subsystem

PrevRefNext +
+

+

Berkeley DB Concurrent Data Store locking conventions

+

The Berkeley DB Concurrent Data Store product has a different set of conventions for locking. It +provides multiple reader/single writer semantics, but not per-page locking +or transaction recoverability. As such, it does its locking entirely at +the interface to the access methods. +

The object it locks is the file, identified by its unique file number. +The locking matrix is not one of the two standard lock modes, instead, +we use a four-lock set, consisting of: +

+

DB_LOCK_NG
not granted (always 0) +
DB_LOCK_READ
read (shared) +
DB_LOCK_WRITE
write (exclusive) +
DB_LOCK_IWRITE
intention-to-write (shared with NG and READ, but conflicts with WRITE and IWRITE) +
+

The IWRITE lock is used for cursors that will be used for updating (IWRITE +locks are implicitly obtained for write operations through the Berkeley DB +handles, e.g., DB->put, DB->del). While the cursor is +reading, the IWRITE lock is held, but as soon as the cursor is about to +modify the database, the IWRITE is upgraded to a WRITE lock. This upgrade +blocks until all readers have exited the database. Because only one +IWRITE lock is allowed at any one time, no two cursors can ever try to +upgrade to a WRITE lock at the same time, and therefore deadlocks are +prevented, which is essential as Berkeley DB Concurrent Data Store does not include deadlock +detection and recovery. +

Applications that need to lock compatibly with Berkeley DB Concurrent Data Store must obey the +following rules: +

    +

  1. Use only lock modes DB_LOCK_NG, DB_LOCK_READ, DB_LOCK_WRITE, +DB_LOCK_IWRITE. +

  2. Never attempt to acquire a WRITE lock on an object that is +already locked with a READ lock. +
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/lock/config.html b/db/docs/ref/lock/config.html new file mode 100644 index 000000000..cc0b52481 --- /dev/null +++ b/db/docs/ref/lock/config.html @@ -0,0 +1,46 @@ + + + + + +Berkeley DB Reference Guide: Configuring locking + + + + + + + +

Berkeley DB Reference Guide:
Locking Subsystem

PrevRefNext +
+

+

Configuring locking

+

The DBENV->set_lk_detect function specifies that the deadlock detector +should be run whenever a lock blocks. This option provides for rapid +detection of deadlocks at the expense of potentially frequent +invocations of the deadlock detector. On a fast processor with a highly +contentious application, where response time is critical, this is a good +choice. An argument to the DBENV->set_lk_detect function indicates which +transaction to abort when a deadlock is detected. It can take on any +one of the following values: +

+

DB_LOCK_YOUNGEST
Abort the most recently started transaction. +
DB_LOCK_OLDEST
Abort the longest lived transaction. +
DB_LOCK_RANDOM
Abort whatever transaction the deadlock detector happens to find first. +
DB_LOCK_DEFAULT
Use the default policy (currently DB_RANDOM). +
+

In general, DB_LOCK_DEFAULT is probably the correct choice. If +an application has long-running transactions, then +DB_LOCK_YOUNGEST will guarantee that transactions eventually +complete, but it may do so at the expense of a large number of aborts. +

The alternative to using the DBENV->set_lk_detect interface is +to run the deadlock detector manually, using the Berkeley DB +lock_detect interface. +

The DBENV->set_lk_conflicts function allows you to specify your own locking +conflicts matrix. This is an advanced configuration option, and rarely +necessary. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/lock/dead.html b/db/docs/ref/lock/dead.html new file mode 100644 index 000000000..bb77e9822 --- /dev/null +++ b/db/docs/ref/lock/dead.html @@ -0,0 +1,93 @@ + + + + + +Berkeley DB Reference Guide: Deadlocks and deadlock avoidance + + + + + + + +

Berkeley DB Reference Guide:
Locking Subsystem

PrevRefNext +
+

+

Deadlocks and deadlock avoidance

+

Practically any application that uses locking may deadlock. +In nearly all cases, in order to recover from a deadlock, transactions +must be used, so that an operation that deadlocks mid-way through can +be undone, leaving the database in a consistent state. +As the access methods may perform updates on multiple pages during a +single API call, transactions are necessary even when the application +makes only single update calls into the database. +The only exception to this rule is when all the threads accessing +the database are doing so read-only or when the Concurrent Data Store +product is used; this product guarantees deadlock-free operation at the +expense of reduced concurrency. +Since deadlocks cannot be prevented, Berkeley DB provides the ability to detect +deadlocks and recover from them gracefully. +

Deadlocks occur when two or more threads of control are blocked waiting +on each other's forward progress. Consider two transactions, each of +which wants to modify items A and B. Assume that transaction 1 modifies +first A and then B, but transaction 2 modifies B then A. Now, assume +that transaction 1 obtains its writelock on A, but before it obtains its +writelock on B, it is descheduled and transaction 2 runs. Transaction 2 +successfully acquires its writelock on B, but then blocks when it tries +to obtain its writelock on A, because transaction 1 already holds a +writelock on it. This is a deadlock. Transaction 1 cannot make forward +progress until Transaction 2 releases its lock on B, but Transaction 2 +cannot make forward progress until Transaction 1 releases its lock on A. +

The lock_detect function runs an instance of the Berkeley DB deadlock +detector. The db_deadlock utility performs deadlock detection by +calling lock_detect at regular intervals. When a deadlock exists +in the system, all of the threads of control involved in the deadlock are, +by definition, waiting on a lock. The deadlock detector examines the +state of the lock manager and identifies a deadlock, and selects one of +the participants to abort. (See Configuring locking for a discussion of how a participant is selected). +The lock on which the selected participant is waiting is identified such +that the lock_get (or lock_vec) call in which that lock +was requested will receive an error return of DB_LOCK_DEADLOCK. +In the access methods, this error return is propagated back through the +Berkeley DB interface as DB_LOCK_DEADLOCK. +

When an application receives an DB_LOCK_DEADLOCK, the correct action is +to abort the current transaction, and optionally retry it. Transaction +support is necessary for recovery from deadlocks. When a deadlock occurs, +the database may be left in an inconsistent or corrupted state, and any +database changes already accomplished must be undone before the +application can proceed further. +

The deadlock detector identifies deadlocks by looking for a cycle in what +is commonly referred to as its "waits-for" graph. More precisely, the +deadlock detector reads through the lock table, and finds each object +currently locked. Each object has a list of transactions or operations +(hereafter called lockers) that currently hold locks on the object and +possibly a list of waiting lockers, waiting on the lockers holding it. +Each object creates one or more partial orderings of lockers. That is, +for a particular object, every waiting locker comes after every holding +locker, because that holding locker must release its lock before the +waiting locker can make forward progress. Conceptually, after each object +has been examined, the partial orderings are topologically sorted (see +tsort). If this topological sort reveals any cycles, then the lockers +forming the cycle are involved in a deadlock. One of the lockers is +selected for abortion. +

It is possible that aborting a single transaction involved in a deadlock +is not enough to allow other transactions to make forward progress. +In this case, the deadlock detector will be called repeatedly. +Unfortunately, at the time a transaction is selected for abortion, +there is not enough information available to determine if aborting +that single transaction will allow forward progress or not. Since +most applications have few deadlocks, Berkeley DB takes the conservative +approach, aborting as few transactions as may be necessary to resolve +the existing deadlocks. In particular, for each unique cycle found +in the waits-for graph described in the previous paragraph, only one +transaction is selected for abortion. However, if there are multiple +cycles, then one transaction from each cycle is selected for abortion. +Only after the aborting transactions have received the deadlock return +and aborted their transactions, can it be determined if it is necessary +to abort other transactions in order to allow forward progress. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/lock/intro.html b/db/docs/ref/lock/intro.html new file mode 100644 index 000000000..b5c85af05 --- /dev/null +++ b/db/docs/ref/lock/intro.html @@ -0,0 +1,89 @@ + + + + + +Berkeley DB Reference Guide: Berkeley DB and locking + + + + + + + +

Berkeley DB Reference Guide:
Locking Subsystem

PrevRefNext +
+

+

Berkeley DB and locking

+

The lock subsystem provides interprocess and intraprocess concurrency +control mechanisms. While the locking system is used extensively by the +Berkeley DB access methods and transaction system, it may also be used as a +stand-alone subsystem to provide concurrency control to any set of +designated resources. +

The lock subsystem is created, initialized, and opened by calls to +DBENV->open with the DB_INIT_LOCK or DB_INIT_CDB +flags specified. +

The lock_detect function provides the programmatic interface to +the Berkeley DB deadlock detector. Whenever two threads of control issue lock +requests that are not carefully ordered or that require upgrading locks +(obtaining write locks on objects that are already read-locked), the +possibility for deadlock arises. A deadlock occurs when two or more +threads of control are blocked, waiting for actions that another one of +these blocked threads must take. For example, assume that threads one +and two have each obtained read locks on object A. Now suppose that both +threads wish to obtain write locks on object A. Neither thread can be +granted its writelock (because of the other thread's readlock). Both +threads block and will never unblock because the event for which they are +waiting can never happen. +

The deadlock detector examines all the locks held in the environment and +identifies situations where no thread can make forward progress. It then +selects one of the participants in the deadlock (according to the argument +that was specified to DBENV->set_lk_detect) and forces it to return +the value DB_LOCK_DEADLOCK, which indicates that a deadlock occurred. +The thread receiving such an error should abort its current transaction, +or simply release all its locks if it is not running in a transaction, +and retry the operation. +

The lock_vec interface is used to acquire and release locks. +

Two additional interfaces, lock_get and lock_put, are +provided. These interfaces are simpler front-ends to the lock_vec +functionality, where lock_get acquires a lock, and +lock_put releases a lock that was acquired using lock_get +or lock_vec. +

It is up to the application to specify lockers and objects appropriately. +When used with the Berkeley DB access methods, these lockers and objects are +handled completely internally, but an application using the lock manager +directly must either use the same conventions as the access methods or +define its own convention to which it adheres. If the application is +using the access methods with locking at the same time that it is calling +the lock manager directly, the application must follow a convention that +is compatible with the access methods' use of the locking subsystem. See +Access method locking conventions +for more information. +

The lock_id function returns a unique ID which may safely be used +as the locker parameter to the lock_vec interface. The access +methods use lock_id to generate unique lockers for the cursors +associated with a database. +

The lock_vec function performs any number of lock operations +atomically. It also provides the ability to release all locks held by a +particular locker and release all the locks on a particular object. +Performing multiple lock operations atomically is useful in performing +Btree traversals where you want to acquire a lock on a child page and once +acquired, immediately release the lock on its parent (this is +traditionally referred to as "lock-coupling"). Using lock_vec +instead of separate calls to lock_put and lock_get reduces +the synchronization overhead between multiple threads or processes. +

The three interfaces, lock_get, lock_put and lock_vec, +are fully compatible, and may be used interchangeably. +

All locks explicitly requested by an application should be released via +calls to lock_put or lock_vec. +

The lock_stat function returns information about the status of +the lock subsystem. It is the programmatic interface used by the +db_stat utility. +

The locking subsystem is closed by the call to DBENV->close. +

Finally, the entire locking subsystem may be discarded using the +DBENV->remove interface. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/lock/max.html b/db/docs/ref/lock/max.html new file mode 100644 index 000000000..236229090 --- /dev/null +++ b/db/docs/ref/lock/max.html @@ -0,0 +1,88 @@ + + + + + +Berkeley DB Reference Guide: Configuring locking: sizing the system + + + + + + + +

Berkeley DB Reference Guide:
Locking Subsystem

PrevRefNext +
+

+

Configuring locking: sizing the system

+

The lock system is sized using the following three functions: +

DBENV->set_lk_max_locks
+DBENV->set_lk_max_lockers
+DBENV->set_lk_max_objects
+

The DBENV->set_lk_max_locks, DBENV->set_lk_max_lockers +and DBENV->set_lk_max_objects functions specify, respectively, the +maximum number of locks, lockers and locked objects supported by the +lock subsystem. The maximum number of locks is the number of locks that +can be simultaneously requested in the system. The maximum number of +lockers is the number of lockers that can simultaneously request locks +in the system. The maximum number of lock objects is the number of +objects that can simultaneously be locked in the system. Selecting +appropriate values requires an understanding of your application and +its databases. If the values are too small, then requests for locks in +an application will fail. If the values are too large, then the locking +subsystem will consume more resources than is necessary. It is better +to err in the direction of allocating too many locks, lockers and +objects as increasing the number of locks does not require large amounts +of additional resources. +

The recommended algorithm for selecting the maximum number of locks, +lockers and lock objects, is to run the application under stressful +conditions and then review the lock system's statistics to determine +the maximum number of locks, lockers and lock objects that were used. +Then, double these values for safety. However, in some large +applications, finer granularity of control is necessary in order to +minimize the size of the lock subsystem. +

The maximum number of lockers can be estimated as follows: +

    +
  • If the +database environment is configured to use transactions, then the maximum +number of lockers needed is the number of simultaneously active +transactions and child transactions (where a child transaction is active +until its parent commits or aborts, not until it commits or aborts). +
  • If the database environment is not configured to use transactions, then +the maximum number of lockers needed is the number of simultaneous +non-cursor operations plus an additional locker for every simultaneously +open cursor. +
+

The maximum number of lock objects needed can be estimated as follows: +

    +
  • For Btree and Recno access methods, you will need, at a minimum, one +lock object per level of the database tree. (Unless keys are quite +large with respect to the page size, neither Recno nor Btree database +trees should ever be deeper than five levels.) Then, you will need one +lock object for each leaf page of the database tree that will be +simultaneously accessed. +
  • For the Queue access method you will need one lock object per record +that is simultaneously accessed. To this, add one lock object per page +that will be simultaneously accessed. (Since the Queue access method +uses fixed-length records, and the database page size is known, it is +possible to calculate the number of pages and therefore, lock objects, +required.) Deleted records skipped by a DB_NEXT or +DB_PREV operation do not require a separate lock object. +Further, if your application is using transactions, then no database +operation will ever use more than three lock objects at any time. +
  • For the Hash access method you only need a single lock object. +
+

For all access methods, you should then add an additional lock object +per database, for the database's metadata page. +

The maximum number of locks required by an application cannot be easily +estimated. It is possible to calculate a maximum number of locks by +multiplying the maximum number of lockers, times the maximum number of +lock objects, times two (two for the two possible lock modes for each +object, read and write). However, this is a pessimal value, and real +applications are unlikely to actually need that many locks. Review of +the lock subsystem statistics is the best way to determine this value. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/lock/nondb.html b/db/docs/ref/lock/nondb.html new file mode 100644 index 000000000..4fb37d6d7 --- /dev/null +++ b/db/docs/ref/lock/nondb.html @@ -0,0 +1,50 @@ + + + + + +Berkeley DB Reference Guide: Locking and non-Berkeley DB applications + + + + + + + +

Berkeley DB Reference Guide:
Locking Subsystem

PrevRefNext +
+

+

Locking and non-Berkeley DB applications

+

The locking subsystem is useful outside the context of Berkeley DB. It can be +used to manage concurrent access to any collection of either ephemeral or +persistent objects. That is, the lock region can persist across +invocations of an application, so it can be used to provide long-term +locking (e.g., conference room scheduling). +

In order to use the locking subsystem in such a general way, the +applications must adhere to a convention for naming objects and lockers. +Consider the conference room scheduling problem described above. Assume +there are three conference rooms and that we wish to schedule them in +half-hour intervals. +

The scheduling application must then select a way to identify each +conference room/time slot combination. In this case, we could describe +the objects being locker as bytestrings consisting of the conference room +name, the date on which it is needed, and the beginning of the appropriate +half-hour slot. +

Lockers are 32-bit numbers, so we might choose to use the User ID of the +individual running the scheduling program. To schedule half-hour slots, +all the application need do is issue a lock_get call for the +appropriate locker/object pair. To schedule a longer slot, the +application would issue a lock_vec call with one lock_get +operation per half-hour up to the total length. If the lock_vec +call fails, the application would have to release the parts of the time +slot that were obtained. +

To cancel a reservation, the application would make the appropriate +lock_put calls. To reschedule a reservation, the lock_get +and lock_put calls could all be made inside of a single +lock_vec call. The output of lock_stat could be +post-processed into a human-readable schedule of conference room use. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/lock/notxn.html b/db/docs/ref/lock/notxn.html new file mode 100644 index 000000000..16b00cf66 --- /dev/null +++ b/db/docs/ref/lock/notxn.html @@ -0,0 +1,46 @@ + + + + + +Berkeley DB Reference Guide: Locking without transactions + + + + + + + +

Berkeley DB Reference Guide:
Locking Subsystem

PrevRefNext +
+

+

Locking without transactions

+

If an application runs with locking specified, but not transactions (e.g., +DBENV->open is called with DB_INIT_LOCK or +DB_INIT_CDB specified, but not DB_INIT_TXN), locks are +normally acquired during each Berkeley DB operation and released before the +operation returns to the caller. The only exception is in the case of +cursor operations. As cursors identify a particular position in a file, +a cursor must retain a read-lock across cursor calls to make sure that +that position is uniquely identifiable during the next cursor call, +because an operation using DB_CURRENT must reference the same +record as the previous cursor call. Such cursor locks cannot be released +until either the cursor is reset using the DB_GET_BOTH, +DB_SET, DB_SET_RANGE, DB_KEYFIRST, or +DB_KEYLAST functionality, in which case a new cursor lock is +established, or the cursor is closed. As a result, application designers +are encouraged to close cursors as soon as possible. +

It is important to realize that concurrent applications that use locking +must ensure that two concurrent threads do not interfere with each other. +However, as Btree and Hash access method page splits can occur at any +time, there is virtually no way to guarantee that an application which +writes the database cannot deadlock. Applications running without the +protection of transactions may deadlock, and when they do so, can leave +the database in an inconsistent state. Applications that need concurrent +access, but not transactions, are more safely implemented using the Berkeley DB Concurrent Data Store +Product. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/lock/page.html b/db/docs/ref/lock/page.html new file mode 100644 index 000000000..a7e43b3af --- /dev/null +++ b/db/docs/ref/lock/page.html @@ -0,0 +1,62 @@ + + + + + +Berkeley DB Reference Guide: Page locks + + + + + + + +

Berkeley DB Reference Guide:
Locking Subsystem

PrevRefNext +
+

+

Page locks

+

Under normal operation, the access methods use page locking. The pagesize +of a database is set when the database is created and may be specified by +calling the DB->set_pagesize function. If not specified, the Berkeley DB +package tries to select a pagesize that will provide the best I/O +performance by setting the page size equal to the block size of the +underlying file system. +

In the Btree access method, Berkeley DB uses a technique called lock coupling +to improve concurrency. The traversal of a Btree requires reading a page, +searching that page to determine which page to search next and then +repeating this process on the next page. Once a page has been searched, +it will never be accessed again for this operation, unless a page split +is required. To improve concurrency in the tree, once the next page to +read/search has been determined, that page is locked, and then atomically +(i.e., without relinquishing control of the lock manager) the original +page lock is released. +

As the Recno access method is built upon Btree, it too uses lock coupling +for read operations. However, as the Recno access method must maintain +a count of records on its internal pages, it cannot lock couple during +write operations. Instead, it retains write locks on all internal pages +during every update operation. For this reason, it is not possible to +have high concurrency in the Recno access method in the presence of write +operations. +

The Queue access method only uses short term page locks. That is, a page +lock is released prior to requesting another page lock. Record locks are +used for transaction isolation. The provides a high degree of concurrency +for write operations. A metadata page is used to keep track of the head +and tail of the queue. This page is never locked during other locking or +I/O operations. +

The Hash access method does not have such traversal issues, but because +it implements dynamic hashing, it must always refer to its metadata while +computing a hash function. This metadata is stored on a special page in +the hash database. This page must therefore be read locked on every +operation. Fortunately, it need only be write locked when new pages are +allocated to the file, which happens in three cases: 1) a hash bucket +becomes full and needs to split, 2) a key or data item is too large to +fit on a normal page, and 3) the number of duplicate items for a fixed +key becomes sufficiently large that they are moved to an auxiliary page. +In this case, the access method must obtain a write lock on the metadata +page, thus requiring that all readers be blocked from entering the tree +until the update completes. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/lock/stdmode.html b/db/docs/ref/lock/stdmode.html new file mode 100644 index 000000000..ca1cd6b0b --- /dev/null +++ b/db/docs/ref/lock/stdmode.html @@ -0,0 +1,61 @@ + + + + + +Berkeley DB Reference Guide: Standard lock modes + + + + + + + +

Berkeley DB Reference Guide:
Locking Subsystem

PrevRefNext +
+

+

Standard lock modes

+

The Berkeley DB locking protocol is described by a conflict matrix. A conflict +matrix is an n x n array where n is the number of different lock modes +supported, and the (i, j)th entry of the array indicates whether a lock of +mode i conflicts with a lock of mode j. +

The Berkeley DB include files declare two commonly used conflict arrays: +

+

const u_int8_t db_rw_conflicts[ ];
This is a conflict matrix for a simple scheme using shared and exclusive +lock modes. +

const u_int8_t db_riw_conflicts[ ];
This is a conflict matrix that involves various intent lock modes (e.g., +intent shared) that are used for multigranularity locking. +
+

The number of modes associated with each matrix are DB_LOCK_RW_N and +DB_LOCK_RIW_N, respectively. +

In addition, the Berkeley DB include file defines the type db_lockmode_t, +which is the type of the lock modes used with the standard tables above: +

+

DB_LOCK_NG
not granted (always 0) +

DB_LOCK_READ
read (shared) +

DB_LOCK_WRITE
write (exclusive) +
+

As an example, consider the basic multiple-reader/single writer conflict +matrix described by db_rw_conflicts. In the following +example (and in the appropriate file), a 1 represents a conflict (i.e., +do not grant the lock if the indicated lock is held) and a 0 indicates +that it is OK to grant the lock. +

The rows indicate the lock that is held and the columns indicate the lock +that is requested. +

		Notheld	Read    Write
+Notheld		0	0	0
+Read*		0	0	1
+Write**		0	1	1
+
+

+

*
In this case, suppose that there is a read lock held on an object. A new +request for a read lock would be granted, but a request for a write lock +would not. +

**
In this case, suppose that there is a write lock held on an object. A +new request for either a read or write lock would be denied. +
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/lock/twopl.html b/db/docs/ref/lock/twopl.html new file mode 100644 index 000000000..6cf112c09 --- /dev/null +++ b/db/docs/ref/lock/twopl.html @@ -0,0 +1,50 @@ + + + + + +Berkeley DB Reference Guide: Locking with transactions: two-phase locking + + + + + + + +

Berkeley DB Reference Guide:
Locking Subsystem

PrevRefNext +
+

+

Locking with transactions: two-phase locking

+

Berkeley DB uses a locking protocol called two-phase locking. This is the +traditional protocol used in conjunction with lock-based transaction +systems. +

In a two-phase locking (2PL) system, transactions are broken up into two +distinct phases. During the first phase, the transaction only acquires +locks. During the second phase, the transaction only releases locks. +More formally, once a transaction releases a lock, it may not acquire any +additional locks. Practically, this translates into a system where locks +are acquired as they are needed throughout a transaction and retained +until the transaction ends, either by committing or aborting. In Berkeley DB, +locks are released during txn_abort or txn_commit. The +only exception to this protocol occurs when we use lock-coupling to +traverse a data structure. If the locks are held only for traversal +purposes, then the locks may be released before transaction commit or +abort. +

For applications, the implications of 2PL are that long-running +transactions will hold locks for a long time. When designing +applications, lock contention should be considered. In order to reduce +the probability of deadlock and achieve the best level of concurrency +possible, the following guidelines are helpful. +

    +

  1. When accessing multiple databases, design all transactions so +that they access the files in the same order. +

  2. If possible, access your most hotly contested resources last +(so that their locks are held for the shortest time possible). +

  3. If possible, use nested transactions to protect the parts of +your transaction most likely to deadlock. +
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/log/config.html b/db/docs/ref/log/config.html new file mode 100644 index 000000000..f3c948893 --- /dev/null +++ b/db/docs/ref/log/config.html @@ -0,0 +1,40 @@ + + + + + +Berkeley DB Reference Guide: Configuring logging + + + + + + + +

Berkeley DB Reference Guide:
Logging Subsystem

PrevRefNext +
+

+

Configuring logging

+

The two aspects of logging that may be configured are the size of log +files on disk and the size of the log buffer in memory. The +DBENV->set_lg_max interface specifies the individual log file +size for all of the applications sharing the Berkeley DB environment. Setting +the log file size is largely a matter of convenience, and a reflection +of the application's preferences in backup media and frequency. +However, setting the log file size too low can potentially cause +problems as it would be possible to run out of log sequence numbers, +which requires a full archival and application restart to reset. See +the Log file limits section for more +information. +

The DBENV->set_lg_bsize interface specifies the size of the +in-memory log buffer, in bytes. Log information is stored in memory +until the buffer fills up or transaction commit forces the buffer to be +written to disk. Larger buffer sizes can significantly increase +throughput in the presence of long running transactions, highly +concurrent applications, or transactions producing large amounts of +data. By default, the buffer is 32KB. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/log/intro.html b/db/docs/ref/log/intro.html new file mode 100644 index 000000000..0c41c17ef --- /dev/null +++ b/db/docs/ref/log/intro.html @@ -0,0 +1,58 @@ + + + + + +Berkeley DB Reference Guide: Berkeley DB and logging + + + + + + + +

Berkeley DB Reference Guide:
Logging Subsystem

PrevRefNext +
+

+

Berkeley DB and logging

+

The logging subsystem is the logging facility used by Berkeley DB. It is +largely Berkeley DB specific, although it is potentially useful outside of +the Berkeley DB package for applications wanting write-ahead logging support. +Applications wanting to use the log for purposes other than logging file +modifications based on a set of open file descriptors will almost +certainly need to make source code modifications to the Berkeley DB code +base. +

A log can be shared by any number of threads of control. The +DBENV->open interface is used to open a log. When the log is no +longer in use, it should be closed, using the DBENV->close +interface. +

Individual log entries are identified by log sequence numbers. Log +sequence numbers are stored in an opaque object, a DB_LSN. +

The log_put interface is used to append new log records to the +log. Optionally, the DB_CHECKPOINT flag can be used to output +a checkpoint log record (indicating that the log is consistent to that +point and recoverable after a system or application failure), as well +as open-file information. The log_get interface is used to +retrieve log records from the log. +

There are additional interfaces for integrating the log subsystem with a +transaction processing system: +

+

log_register and log_unregister
These interfaces associate files with identification numbers. These +identification numbers are logged so that transactional recovery +correctly associates log records with the appropriate files. +

log_flush
Flushes the log up to a particular log sequence number. +

log_compare
Allows applications to compare any two log sequence numbers. +

log_file
Maps a log sequence number to the specific log file which contains it. +

log_archive
Returns various sets of log file names. These interfaces are used for +database administration, e.g., to determine if log files may safely be +removed from the system. +

log_stat
The display db_stat utility uses the log_stat interface +to display statistics about the log. +

DBENV->remove
The log meta-information (but not the log files themselves) may be +removed using the DBENV->remove interface. +
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/log/limits.html b/db/docs/ref/log/limits.html new file mode 100644 index 000000000..d34e5a813 --- /dev/null +++ b/db/docs/ref/log/limits.html @@ -0,0 +1,47 @@ + + + + + +Berkeley DB Reference Guide: Log file limits + + + + + + + +

Berkeley DB Reference Guide:
Logging Subsystem

PrevRefNext +
+

+

Log file limits

+

Log file names and sizes impose a limit on how long databases may be +used in a Berkeley DB database environment. It is quite unlikely that an +application will reach this limit, however, if the limit is reached, +the Berkeley DB environment's databases must be dumped and reloaded. +

The log file name consists of log. followed by 10 digits, with +a maximum of 2,000,000,000 log files. Consider an application performing +6000 transactions per second, for 24 hours a day, logged into 10MB log +files, where each transaction is logging approximately 500 bytes of data. +The calculation: +

(10 * 2^20 * 2000000000) / (6000 * 500 * 365 * 60 * 60 * 24) = ~221
+

indicates that the system will run out of log file names in roughly 221 +years. +

There is no way to reset the log file name space in Berkeley DB. If your +application is reaching the end of its log file name space, you must: +

    +

  1. Archive your databases as if to prepare for catastrophic failure (see +db_archive for more information). +

  2. Dump and re-load all your databases (see db_dump and +db_load for more information). +

  3. Remove all of the log files from the database environment. Note, this +is the only situation where all of the log files are removed from an +environment, in all other cases at least a single log file is +retained. +

  4. Restart your application. +
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/mp/config.html b/db/docs/ref/mp/config.html new file mode 100644 index 000000000..cf311516d --- /dev/null +++ b/db/docs/ref/mp/config.html @@ -0,0 +1,55 @@ + + + + + +Berkeley DB Reference Guide: Configuring the memory pool + + + + + + + +

Berkeley DB Reference Guide:
Memory Pool Subsystem

PrevRefNext +
+

+

Configuring the memory pool

+

There are two interfaces used for configuring the memory pool. +

The most important tuning parameter for almost all applications, including +Berkeley DB applications, is the size of the pool. There are two ways to +specify the pool size. First, calling the DBENV->set_cachesize function +specifies the pool size for all of the applications sharing the Berkeley DB +environment. Second, by calling the DB->set_cachesize function. The +latter only specifies a pool size for the specific database. Note, it is +meaningless to call DB->set_cachesize for a database opened inside +of a Berkeley DB environment, since the environment pool size will override any +pool size specified for a single database. For information on tuning the +Berkeley DB cache size, see Selecting +a cache size. +

The second memory pool configuration interface specifies the maximum size +of backing files to map into the process address space instead of copying +pages through the local cache. Only read-only database files can be +mapped into process memory. Because of the requirements of the Berkeley DB +transactional implementation, log records describing database changes must +be written to disk before the actual database changes. As mapping +read-write database files into process memory would permit the underlying +operating system to write modified database changes at will, it is not +supported. +

Mapping files into the process address space can result in +better-than-usual performance, as available virtual memory is normally +much larger than the local cache, and page faults are faster than page +copying on many systems. However, in the presence of limited virtual +memory it can cause resource starvation, and in the presence of large +databases, it can result in immense process sizes. +

To specify that no files are to be mapped into the process address space, +specify the DB_NOMMAP flag to the DBENV->set_flags interface. +To specify that any individual file should not be mapped into the process +address space, specify the DB_NOMMAP flag to the +memp_fopen interface. To limit the size of files mapped into the +process address space, use the DBENV->set_mp_mmapsize function. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/mp/intro.html b/db/docs/ref/mp/intro.html new file mode 100644 index 000000000..2b52a5775 --- /dev/null +++ b/db/docs/ref/mp/intro.html @@ -0,0 +1,59 @@ + + + + + +Berkeley DB Reference Guide: Berkeley DB and the memory pool + + + + + + +

Berkeley DB Reference Guide:
Memory Pool Subsystem

PrevRefNext +
+

+

Berkeley DB and the memory pool

+

The memory pool subsystem is the general-purpose shared memory buffer pool +used by Berkeley DB. This module is useful outside of the Berkeley DB package for +processes that require page-oriented, cached, shared file access. +

A memory pool is a shared memory cache shared by any number of processes +and threads within processes. The DBENV->open interface opens, and +optionally creates, a memory pool. When that pool is no longer in use, +it should be closed, using the DBENV->close interface. +

The memp_fopen interface opens an underlying file within the +memory pool. When that file is no longer in use, it should be closed, +using the memp_fclose interface. The memp_fget interface +is used to retrieve pages from files in the pool. All retrieved pages +must be subsequently returned using the memp_fput interface. At +the time that pages are returned, they may be marked dirty, which +causes them to be written to the backing disk file before being discarded +from the pool. If there is insufficient room to bring a new page in the +pool, a page is selected to be discarded from the pool. If that page is +dirty, it is first written to the backing file. The page is selected +using a somewhat modified least-recently-used algorithm. Pages in files +may also be explicitly marked clean or dirty using the memp_fset +interface. All dirty pages in the pool from any underlying file may also +be flushed as a group using the memp_fsync interface. +

There are additional interfaces for manipulating the entire memory pool: +

    +
  • It is possible to gradually flush buffers from the pool in order to +maintain a consistent percentage of clean buffers in the pool using the +memp_trickle interface. +
  • The db_stat utility uses the memp_stat interface to +display statistics about the efficiency of the pool. +
  • As some conversion may be necessary when pages are read or written the +memp_register function allows applications to specify automatic +input and output processing in these cases. +
  • There is one additional interface that is intended for manipulating the +memory pool, but which is specific to database systems. The +memp_sync interface flushes dirty pages from all files held in +the pool up to a specified database log sequence number. +
  • Finally, the entire pool may be discarded using the DBENV->remove +interface. +
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/perl/intro.html b/db/docs/ref/perl/intro.html new file mode 100644 index 000000000..da5d93a6a --- /dev/null +++ b/db/docs/ref/perl/intro.html @@ -0,0 +1,42 @@ + + + + + +Berkeley DB Reference Guide: Using Berkeley DB with Perl + + + + + + + +

Berkeley DB Reference Guide:
Perl

PrevRefNext +
+

+

Using Berkeley DB with Perl

+

The original Perl module for Berkeley DB was DB_File, which was written to +interface to Berkeley DB version 1.85. The newer Perl module for Berkeley DB is +BerkeleyDB, which was written to interface to version 2.0 and subsequent +releases. Because Berkeley DB version 2.X has a compatibility API for version +1.85, you can (and should!) build DB_File using version 2.X of Berkeley DB, +although DB_File will still only support the 1.85 functionality. +

DB_File is distributed with the standard Perl source distribution (look +in the directory "ext/DB_File"). You can find both DB_File and BerkeleyDB +on CPAN, the Comprehensive Perl Archive Network of mirrored FTP sites. +The master CPAN site is +ftp://ftp.funet.fi/. +

Versions of both BerkeleyDB and DB_File that are known to work correctly +with each release of Berkeley DB are included in the distributed Berkeley DB source +tree, in the subdirectories perl.BerkeleyDB and +perl.DB_File. Each of those directories contains a +README file with instructions on installing and using those +modules. +

The Perl interface is not maintained by Sleepycat Software. Questions +about the DB_File and BerkeleyDB modules are best asked on the Usenet +newsgroup comp.lang.perl.modules. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/pindex.src b/db/docs/ref/pindex.src new file mode 100644 index 000000000..0e122ceb2 --- /dev/null +++ b/db/docs/ref/pindex.src @@ -0,0 +1,212 @@ +__APIREL__/ref/am/close.html#2 @closing a database +__APIREL__/ref/am/count.html#2 @counting data items for a key +__APIREL__/ref/am/curclose.html#2 @closing a cursor +__APIREL__/ref/am/curclose.html#3 closing a @cursor +__APIREL__/ref/am/curdel.html#2 @deleting records with a cursor +__APIREL__/ref/am/curdel.html#3 deleting records with a @cursor +__APIREL__/ref/am/curdup.html#2 @duplicating a cursor +__APIREL__/ref/am/curdup.html#3 duplicating a @cursor +__APIREL__/ref/am/curget.html#2 @retrieving records with a cursor +__APIREL__/ref/am/curget.html#3 retrieving records with a @cursor +__APIREL__/ref/am/curput.html#2 @storing records with a cursor +__APIREL__/ref/am/curput.html#3 storing records with a @cursor +__APIREL__/ref/am/cursor.html#2 database @cursors +__APIREL__/ref/am/delete.html#2 @deleting records +__APIREL__/ref/am/error.html#2 @error handling +__APIREL__/ref/am/get.html#2 @retrieving records +__APIREL__/ref/am/join.html#2 logical @join +__APIREL__/ref/am/open.html#2 @opening a database +__APIREL__/ref/am/partial.html#2 @partial record storage and retrieval +__APIREL__/ref/am/put.html#2 @storing records +__APIREL__/ref/am/stability.html#2 @cursor stability +__APIREL__/ref/am/stability.html#3 cursor @stability +__APIREL__/ref/am/stat.html#2 database @statistics +__APIREL__/ref/am/sync.html#2 flushing the database @cache +__APIREL__/ref/am/upgrade.html#2 @upgrading databases +__APIREL__/ref/am/verify.html#2 database @verification +__APIREL__/ref/am/verify.html#3 database @salvage +__APIREL__/ref/am/verify.html#4 recovering @corrupted databases +__APIREL__/ref/am_conf/bt_compare.html#2 specifying a Btree @comparison function +__APIREL__/ref/am_conf/bt_recnum.html#2 retrieving Btree records by @number +__APIREL__/ref/am_conf/byteorder.html#2 selecting a @byte order +__APIREL__/ref/am_conf/cachesize.html#2 selecting a @cache size +__APIREL__/ref/am_conf/dup.html#2 @duplicate data items +__APIREL__/ref/am_conf/extentsize.html#2 selecting a Queue @extent size +__APIREL__/ref/am_conf/h_ffactor.html#2 page @fill factor +__APIREL__/ref/am_conf/h_hash.html#2 specifying a database @hash +__APIREL__/ref/am_conf/h_nelem.html#2 @hash table size +__APIREL__/ref/am_conf/intro.html#2 @access methods +__APIREL__/ref/am_conf/logrec.html#2 logical @record numbers +__APIREL__/ref/am_conf/pagesize.html#2 selecting a @page size +__APIREL__/ref/am_conf/re_source.html#2 @text backing files +__APIREL__/ref/am_conf/recno.html#2 managing @record-based databases +__APIREL__/ref/am_conf/renumber.html#2 logically renumbering @records +__APIREL__/ref/am_conf/select.html#2 selecting an @access method +__APIREL__/ref/arch/apis.html#2 programmatic @APIs +__APIREL__/ref/arch/utilities.html#2 @utilities +__APIREL__/ref/build_unix/aix.html#2 @AIX +__APIREL__/ref/build_unix/conf.html#2 @configuring Berkeley DB for UNIX systems +__APIREL__/ref/build_unix/conf.html#3 configuring Berkeley DB for @UNIX systems +__APIREL__/ref/build_unix/conf.html#4 configuring without large @file support +__APIREL__/ref/build_unix/conf.html#--disable-bigfile Configuring Berkeley DB@--disable-bigfile +__APIREL__/ref/build_unix/conf.html#5 configuring Berkeley DB @1.85 API compatibility +__APIREL__/ref/build_unix/conf.html#--enable-compat185 Configuring Berkeley DB@--enable-compat185 +__APIREL__/ref/build_unix/conf.html#6 configuring the @C++ API +__APIREL__/ref/build_unix/conf.html#--enable-cxx Configuring Berkeley DB@--enable-cxx +__APIREL__/ref/build_unix/conf.html#--enable-debug Configuring Berkeley DB@--enable-debug +__APIREL__/ref/build_unix/conf.html#--enable-debug_rop Configuring Berkeley DB@--enable-debug_rop +__APIREL__/ref/build_unix/conf.html#--enable-debug_wop Configuring Berkeley DB@--enable-debug_wop +__APIREL__/ref/build_unix/conf.html#--enable-diagnostic Configuring Berkeley DB@--enable-diagnostic +__APIREL__/ref/build_unix/conf.html#7 building a utility to dump Berkeley DB @1.85 databases +__APIREL__/ref/build_unix/conf.html#--enable-dump185 Configuring Berkeley DB@--enable-dump185 +__APIREL__/ref/build_unix/conf.html#8 configuring @shared libraries +__APIREL__/ref/build_unix/conf.html#9 configuring @dynamic shared libraries +__APIREL__/ref/build_unix/conf.html#--enable-dynamic Configuring Berkeley DB@--enable-dynamic +__APIREL__/ref/build_unix/conf.html#10 configuring the @Java API +__APIREL__/ref/build_unix/conf.html#--enable-java Configuring Berkeley DB@--enable-java +__APIREL__/ref/build_unix/conf.html#--enable-posixmutexes Configuring Berkeley DB@--enable-posixmutexes +__APIREL__/ref/build_unix/conf.html#11 configuring a @RPC client/server +__APIREL__/ref/build_unix/conf.html#--enable-rpc Configuring Berkeley DB@--enable-rpc +__APIREL__/ref/build_unix/conf.html#--enable-shared Configuring Berkeley DB@--enable-shared +__APIREL__/ref/build_unix/conf.html#12 configuring the @Tcl API +__APIREL__/ref/build_unix/conf.html#--enable-tcl Configuring Berkeley DB@--enable-tcl +__APIREL__/ref/build_unix/conf.html#13 configuring the @test suite +__APIREL__/ref/build_unix/conf.html#--enable-test Configuring Berkeley DB@--enable-test +__APIREL__/ref/build_unix/conf.html#--enable-uimutexes Configuring Berkeley DB@--enable-uimutexes +__APIREL__/ref/build_unix/conf.html#--enable-umrw Configuring Berkeley DB@--enable-umrw +__APIREL__/ref/build_unix/conf.html#--with-tcl=DIR Configuring Berkeley DB@--with-tcl=DIR +__APIREL__/ref/build_unix/flags.html#2 changing @compile or load options +__APIREL__/ref/build_unix/flags.html#3 changing compile or @load options +__APIREL__/ref/build_unix/freebsd.html#2 @FreeBSD +__APIREL__/ref/build_unix/hpux.html#2 @HP-UX +__APIREL__/ref/build_unix/install.html#2 @installing Berkeley DB for UNIX systems +__APIREL__/ref/build_unix/intro.html#2 @building for UNIX +__APIREL__/ref/build_unix/irix.html#2 @IRIX +__APIREL__/ref/build_unix/linux.html#2 @Linux +__APIREL__/ref/build_unix/notes.html#2 @building for UNIX FAQ +__APIREL__/ref/build_unix/notes.html#3 building for @UNIX FAQ +__APIREL__/ref/build_unix/osf1.html#2 @OSF/1 +__APIREL__/ref/build_unix/qnx.html#2 @QNX +__APIREL__/ref/build_unix/sco.html#2 @SCO +__APIREL__/ref/build_unix/shlib.html#2 @shared libraries +__APIREL__/ref/build_unix/solaris.html#2 @Solaris +__APIREL__/ref/build_unix/sunos.html#2 @SunOS +__APIREL__/ref/build_unix/test.html#2 running the @test suite under UNIX +__APIREL__/ref/build_unix/ultrix.html#2 @Ultrix +__APIREL__/ref/build_vxworks/faq.html#2 @building for VxWorks FAQ +__APIREL__/ref/build_vxworks/faq.html#3 building for @VxWorks FAQ +__APIREL__/ref/build_vxworks/intro.html#2 @building for VxWorks +__APIREL__/ref/build_vxworks/notes.html#2 @VxWorks notes +__APIREL__/ref/build_win/faq.html#2 @building for Windows FAQ +__APIREL__/ref/build_win/faq.html#3 building for @Windows FAQ +__APIREL__/ref/build_win/intro.html#2 @building for Win32 +__APIREL__/ref/build_win/notes.html#2 @Windows notes +__APIREL__/ref/build_win/test.html#2 running the @test suite under Windows +__APIREL__/ref/build_win/test.html#3 running the test suite under @Windows +__APIREL__/ref/cam/intro.html#2 @Concurrent Data Store +__APIREL__/ref/debug/common.html#2 @debugging applications +__APIREL__/ref/distrib/layout.html#2 @source code layout +__APIREL__/ref/dumpload/text.html#2 loading @text into databases +__APIREL__/ref/dumpload/utility.html#2 dumping/loading @text to/from databases +__APIREL__/ref/env/create.html#2 database @environment +__APIREL__/ref/env/naming.html#2 file @naming +__APIREL__/ref/env/naming.html#db_home File naming@db_home +__APIREL__/ref/env/naming.html#DB_HOME File naming@DB_HOME +__APIREL__/ref/env/naming.html#DB_CONFIG File naming@DB_CONFIG +__APIREL__/ref/env/remote.html#2 remote @filesystems +__APIREL__/ref/env/security.html#2 @security +__APIREL__/ref/intro/products.html#2 Sleepycat Software's Berkeley DB @products +__APIREL__/ref/install/file.html#2 @/etc/magic +__APIREL__/ref/install/file.html#3 @file utility +__APIREL__/ref/java/compat.html#2 @Java compatibility +__APIREL__/ref/java/conf.html#2 @Java configuration +__APIREL__/ref/java/faq.html#2 Java @FAQ +__APIREL__/ref/java/faq.html#3 @Java FAQ +__APIREL__/ref/lock/am_conv.html#2 @locking conventions +__APIREL__/ref/lock/cam_conv.html#2 Berkeley DB Concurrent Data Store @locking conventions +__APIREL__/ref/lock/config.html#2 @locking configuration +__APIREL__/ref/lock/dead.html#2 @deadlocks +__APIREL__/ref/lock/intro.html#2 @locking introduction +__APIREL__/ref/lock/max.html#2 sizing the @locking subsystem +__APIREL__/ref/lock/nondb.html#2 @locking and non-Berkeley DB applications +__APIREL__/ref/lock/notxn.html#2 @locking without transactions +__APIREL__/ref/lock/page.html#2 page-level @locking +__APIREL__/ref/lock/stdmode.html#2 standard @lock modes +__APIREL__/ref/lock/twopl.html#2 two-phase @locking +__APIREL__/ref/log/config.html#2 @logging configuration +__APIREL__/ref/log/intro.html#2 @logging introduction +__APIREL__/ref/log/limits.html#2 @log file limits +__APIREL__/ref/mp/config.html#2 @memory pool configuration +__APIREL__/ref/perl/intro.html#2 @Perl +__APIREL__/ref/program/appsignals.html#2 application @signal handling +__APIREL__/ref/program/byteorder.html#2 @byte ordering +__APIREL__/ref/program/byteorder.html#3 byte @endian +__APIREL__/ref/program/compatible.html#2 @interface compatibility +__APIREL__/ref/program/dbsizes.html#2 database @limits +__APIREL__/ref/program/diskspace.html#2 @disk space requirements +__APIREL__/ref/program/environ.html#2 @environment variables +__APIREL__/ref/program/errorret.html#2 @error returns +__APIREL__/ref/program/errorret.html#3 @error name space +__APIREL__/ref/program/errorret.html#DB_NOTFOUND Error returns to applications@DB_NOTFOUND +__APIREL__/ref/program/errorret.html#DB_KEYEMPTY Error returns to applications@DB_KEYEMPTY +__APIREL__/ref/program/errorret.html#DB_LOCK_DEADLOCK Error returns to applications@DB_LOCK_DEADLOCK +__APIREL__/ref/program/errorret.html#DB_LOCK_NOTGRANTED Error returns to applications@DB_LOCK_NOTGRANTED +__APIREL__/ref/program/errorret.html#DB_RUNRECOVERY Error returns to applications@DB_RUNRECOVERY +__APIREL__/ref/program/mt.html#2 building @threaded applications +__APIREL__/ref/program/namespace.html#2 Berkeley DB library @name spaces +__APIREL__/ref/program/scope.html#2 Berkeley DB handle @scope +__APIREL__/ref/program/scope.html#3 Berkeley DB @free-threaded handles +__APIREL__/ref/rpc/client.html#2 @RPC client +__APIREL__/ref/rpc/server.html#2 @RPC server +__APIREL__/ref/sendmail/intro.html#2 @Sendmail +__APIREL__/ref/tcl/intro.html#2 loading Berkeley DB with @Tcl +__APIREL__/ref/tcl/faq.html#2 Tcl @FAQ +__APIREL__/ref/tcl/faq.html#3 @Tcl FAQ +__APIREL__/ref/tcl/program.html#2 @Tcl API programming notes +__APIREL__/ref/tcl/using.html#2 using Berkeley DB with @Tcl +__APIREL__/ref/test/run.html#2 running the @test suite +__APIREL__/ref/transapp/admin.html#2 administering @transaction protected applications +__APIREL__/ref/transapp/archival.html#2 archival in @transaction protected applications +__APIREL__/ref/transapp/archival.html#3 @catastrophic recovery +__APIREL__/ref/transapp/checkpoint.html#2 checkpoints in @transaction protected applications +__APIREL__/ref/transapp/deadlock.html#2 deadlock detection in @transaction protected applications +__APIREL__/ref/transapp/filesys.html#2 recovery and @filesystem operations +__APIREL__/ref/transapp/intro.html#2 @Transactional Data Store +__APIREL__/ref/transapp/logfile.html#2 @log file removal +__APIREL__/ref/transapp/reclimit.html#2 Berkeley DB @recoverability +__APIREL__/ref/transapp/recovery.html#2 recovery in @transaction protected applications +__APIREL__/ref/transapp/throughput.html#2 @transaction throughput +__APIREL__/ref/txn/config.html#2 @transaction configuration +__APIREL__/ref/txn/intro.html#2 Berkeley DB and @transactions +__APIREL__/ref/txn/limits.html#2 @transaction limits +__APIREL__/ref/txn/nested.html#2 nested @transactions +__APIREL__/ref/upgrade.2.0/intro.html#2 Upgrading to release @2.0 +__APIREL__/ref/upgrade.3.0/intro.html#2 Upgrading to release @3.0 +__APIREL__/ref/upgrade.3.1/intro.html#2 Upgrading to release @3.1 +__APIREL__/ref/upgrade.3.2/intro.html#2 Upgrading to release @3.2 +__APIREL__/ref/xa/config.html#2 configuring Berkeley DB with the @Tuxedo System +__APIREL__/ref/xa/intro.html#2 @XA Resource Manager +__APIREL__/utility/berkeley_db_svc.html#2 @berkeley_db_svc +__APIREL__/utility/berkeley_db_svc.html#3 utility to support @RPC client/server +__APIREL__/utility/db_archive.html#2 @db_archive +__APIREL__/utility/db_archive.html#3 utility to @archive log files +__APIREL__/utility/db_checkpoint.html#2 @db_checkpoint +__APIREL__/utility/db_checkpoint.html#3 utility to take @checkpoints +__APIREL__/utility/db_deadlock.html#2 @db_deadlock +__APIREL__/utility/db_deadlock.html#3 utility to detect @deadlocks +__APIREL__/utility/db_dump.html#2 @db_dump +__APIREL__/utility/db_dump.html#3 utility to @dump databases as text files +__APIREL__/utility/db_load.html#2 @db_load +__APIREL__/utility/db_load.html#3 utility to @load text files into databases +__APIREL__/utility/db_printlog.html#2 @db_printlog +__APIREL__/utility/db_printlog.html#3 utility to display @log files as text +__APIREL__/utility/db_recover.html#2 @db_recover +__APIREL__/utility/db_recover.html#3 utility to @recover database environments +__APIREL__/utility/db_stat.html#2 @db_stat +__APIREL__/utility/db_stat.html#3 utility to display database and environment @statistics +__APIREL__/utility/db_upgrade.html#2 @db_upgrade +__APIREL__/utility/db_upgrade.html#3 utility to upgrade @database files +__APIREL__/utility/db_upgrade.html#4 utility to @upgrade database files +__APIREL__/utility/db_verify.html#2 @db_verify +__APIREL__/utility/db_verify.html#3 utility to verify @database files +__APIREL__/utility/db_verify.html#4 utility to @verify database files diff --git a/db/docs/ref/program/appsignals.html b/db/docs/ref/program/appsignals.html new file mode 100644 index 000000000..2b1d99bd6 --- /dev/null +++ b/db/docs/ref/program/appsignals.html @@ -0,0 +1,35 @@ + + + + + +Berkeley DB Reference Guide: Application signal handling + + + + + + + +

Berkeley DB Reference Guide:
Programmer Notes

PrevRefNext +
+

+

Application signal handling

+

When applications using Berkeley DB receive signals, it is important that they +exit gracefully, discarding any Berkeley DB locks that they may hold. This is +normally done by setting a flag when a signal arrives, and then checking +for that flag periodically within the application. As Berkeley DB is not +reentrant, the signal handler should not attempt to release locks and/or +close the database handles itself. Reentering Berkeley DB is not guaranteed to +work correctly and the results are undefined. +

If an application exits holding a lock, the situation is no different +than if the application crashed, and all applications participating in +the database environment must be shutdown, and then recovery must be +performed. If this is not done, databases may be left in an +inconsistent state or locks the application held may cause unresolvable +deadlocks inside the environment, causing applications to hang. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/program/byteorder.html b/db/docs/ref/program/byteorder.html new file mode 100644 index 000000000..6569ba88b --- /dev/null +++ b/db/docs/ref/program/byteorder.html @@ -0,0 +1,31 @@ + + + + + +Berkeley DB Reference Guide: Byte ordering + + + + + + + +

Berkeley DB Reference Guide:
Programmer Notes

PrevRefNext +
+

+

Byte ordering

+

The database files created by Berkeley DB can be created in either little or +big-endian formats. By default, the native format of the machine on which +the database is created will be used. Any format database can be used on +a machine with a different native format, although it is possible that +the application will incur a performance penalty for the run-time +conversion. +

No user-specified data is converted in any way at all. Key or data items +stored on machines of one format will be returned to the application +exactly as stored on machines of another format. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/program/compatible.html b/db/docs/ref/program/compatible.html new file mode 100644 index 000000000..72db97a5c --- /dev/null +++ b/db/docs/ref/program/compatible.html @@ -0,0 +1,32 @@ + + + + + +Berkeley DB Reference Guide: Compatibility with historic interfaces + + + + + + + +

Berkeley DB Reference Guide:
Programmer Notes

PrevRefNext +
+

+

Compatibility with historic interfaces

+

The Berkeley DB version 2 library provides backward compatible interfaces for +the historic UNIX dbm, ndbm and hsearch +interfaces. It also provides a backward compatible interface for the +historic Berkeley DB 1.85 release. +

Berkeley DB version 2 does not provide database compatibility for any of the +above interfaces, and existing databases must be converted manually. To +convert existing databases from the Berkeley DB 1.85 format to the Berkeley DB version +2 format, review the db_dump185 and db_load information. +No utilities are provided to convert UNIX dbm, ndbm or +hsearch databases. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/program/copy.html b/db/docs/ref/program/copy.html new file mode 100644 index 000000000..80b6f942a --- /dev/null +++ b/db/docs/ref/program/copy.html @@ -0,0 +1,63 @@ + + + + + +Berkeley DB Reference Guide: Copying databases + + + + + + +

Berkeley DB Reference Guide:
Programmer Notes

PrevRefNext +
+

+

Copying databases

+

Because file identification cookies (e.g., file names, device and inode +numbers, volume and file IDs, etc.) are not necessarily unique or +maintained across system reboots, each Berkeley DB database file contains a +20-byte file identification bytestring that is stored in the first page +of the database at a page byte offset of 36 bytes. When multiple +processes or threads open the same database file in Berkeley DB, it is this +bytestring that is used to ensure that the same underlying pages are +updated in the shared memory buffer pool no matter which Berkeley DB handle is +used for the operation. +

It is usually a bad idea to physically copy a database to a new name. In +the few cases where copying is the best solution for your application, +you must guarantee there are never two different databases with the same +file identification bytestring in the memory pool at the same time. +Copying databases is further complicated by the fact that the shared +memory buffer pool does not discard all cached copies of pages for a +database when the database is logically closed, that is, when +DB->close is called. Nor is there a Berkeley DB interface to explicitly +discard pages from the shared memory buffer pool for any particular +database. +

Before copying a database, you must ensure that all modified pages have +been written from the memory pool cache to the backing database file. +This is done using the DB->sync or DB->close interfaces. +

Before using a copy of a database from Berkeley DB, you must ensure that all +pages from any database with the same bytestring have been removed from +the memory pool cache. If the environment in which you intend to open +the copy of the database potentially has pages from files with identical +bytestrings to the copied database (which is likely to be the case), there +are a few possible solutions: +

    +

  1. Remove the environment, either explicitly or by calling DBENV->remove. +Note, this will not allow you to access both the original and copy of the +database at the same time. +

  2. Overwrite the bytestring in the copied database with a new bytestring. +This allows you to access both the original and copy of the database at +the same time. +

  3. Create a new file that will have a new bytestring. The simplest +way to create a new file that will have a new bytestring is to call the +db_dump utility to dump out the contents of the database, and then +use the db_load utility to load the dumped output into a new file +name. This allows you to access both the original and copy of the +database at the same time. +
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/program/dbsizes.html b/db/docs/ref/program/dbsizes.html new file mode 100644 index 000000000..69b45868d --- /dev/null +++ b/db/docs/ref/program/dbsizes.html @@ -0,0 +1,45 @@ + + + + + +Berkeley DB Reference Guide: Database limits + + + + + + + +

Berkeley DB Reference Guide:
Programmer Notes

PrevRefNext +
+

+

Database limits

+

The largest database file that Berkeley DB can handle depends on the page size +selected by the application. Berkeley DB stores database file page numbers as +unsigned 32-bit numbers and database file page sizes as unsigned 16-bit +numbers. Using the maximum database page size of 65536, this results in +a maximum database file size of 248 (256 terabytes). The +minimum database page size is 512 bytes, which results in a minimum +maximum database size of 241 (2 terabytes). +

The largest database file Berkeley DB can support is potentially further limited +if the host system does not have filesystem support for files larger than +232, including the ability to seek to absolute offsets within +those files. +

The largest key or data item that Berkeley DB can support is largely limited +by available memory. Specifically, while key and data byte strings may +be of essentially unlimited length, any one of them must fit into +available memory so that it can be returned to the application. As some +of the Berkeley DB interfaces return both key and data items to the application, +those interfaces will require that any key/data pair fit simultaneously +into memory. Further, as the access methods may need to compare key and +data items with other key and data items, it may be a requirement that +any two key or two data items fit into available memory. Finally, when +writing applications supporting transactions, it may be necessary to have +an additional copy of any data item in memory for logging purposes. +

The maximum Btree depth is 255. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/program/diskspace.html b/db/docs/ref/program/diskspace.html new file mode 100644 index 000000000..fb8425d8a --- /dev/null +++ b/db/docs/ref/program/diskspace.html @@ -0,0 +1,145 @@ + + + + + +Berkeley DB Reference Guide: Disk space requirements + + + + + + + +

Berkeley DB Reference Guide:
Programmer Notes

PrevRefNext +
+

+

Disk space requirements

+

It is possible to estimate the total database size based on the size of +the data. Simply put, the following calculations attempt to figure out +how many bytes you will need to hold a set of data and then how many pages +it will take to actually store it on disk. +

Space freed by deleting key/data pairs from a Btree or Hash database is +never returned to the filesystem, although it is reused where possible. +This means that the Btree and Hash databases are grow-only. If enough +keys are deleted from a database that shrinking the underlying file is +desirable, you should create a new database and insert the records from +the old one into it. +

These are rough estimates at best. For example, they do not take into +account overflow records, filesystem metadata information, or real-life +situations where the sizes of key and data items are wildly variable, and +the page-fill factor changes over time. +

Btree

+

The formulas for the Btree access method are as follows: +

useful-bytes-per-page = (page-size - page-overhead) * page-fill-factor
+

+bytes-of-data = n-records * + (bytes-per-entry + page-overhead-for-two-entries) +

+n-pages-of-data = bytes-of-data / bytes-per-page +

+total-pages-on-disk = n-pages-of-data * page-size +

+

The useful-bytes-per-page is a measure of the bytes on each page +that will actually hold the application data. It is computed as the total +number of bytes on the page that are available to hold application data, +corrected by the percentage of the page that is likely to contain data. +The reason for this correction is that the percentage of a page that +contains application data can vary from close to 50% after a page split, +to almost 100% if the entries in the database were inserted in sorted +order. Obviously, the page-fill-factor can drastically alter +the amount of disk space required to hold any particular data set. The +page-fill factor of any existing database can be displayed using the +db_stat utility. +

As an example, using an 8K page size, with an 85% page-fill factor, there +are 6941 bytes of useful space on each page: +

6941 = (8192 - 26) * .85
+

The total bytes-of-data is an easy calculation: it is the number +of key/data pairs plus the overhead required to store each pair on a page. +The overhead to store a single item on a Btree page is 5 bytes. So, +assuming 60,000,000 key/data pairs, each of which is 8 bytes long, there +are 1440000000 bytes, or roughly 1.34GB, of total data: +

1560000000 = 60000000 * ((8 * 2) + (5 * 2))
+

The total pages of data, n-pages-of-data, is the +bytes-of-data divided by the useful-bytes-per-page. In +the example, there are 224751 pages of data. +

224751 = 1560000000 / 6941
+

The total bytes of disk space for the database is n-pages-of-data +multiplied by the page-size. In the example, the result is +1841160192 bytes, or roughly 1.71GB. +

1841160192 = 224751 * 8192
+

Hash

+

The formulas for the Hash access method are as follows: +

useful-bytes-per-page = (page-size - page-overhead)
+

+bytes-of-data = n-records * + (bytes-per-entry + page-overhead-for-two-entries) +

+n-pages-of-data = bytes-of-data / bytes-per-page +

+total-pages-on-disk = n-pages-of-data * page-size +

+

The useful-bytes-per-page is a measure of the bytes on each page +that will actually hold the application data. It is computed as the total +number of bytes on the page that are available to hold application data. +If the application has explicitly set a page fill factor, then pages will +not necessarily be kept full. For databases with a preset fill factor, +see the calculation below. The page-overhead for Hash databases is 26 +bytes and the page-overhead-for-two-entries is 6 bytes. +

As an example, using an 8K page size, there are 8166 bytes of useful space +on each page: +

8166 = (8192 - 26)
+

The total bytes-of-data is an easy calculation: it is the number +of key/data pairs plus the overhead required to store each pair on a page. +In this case that's 6 bytes per pair. So, assuming 60,000,000 key/data +pairs, each of which is 8 bytes long, there are 1320000000 bytes, or +roughly 1.23GB, of total data: +

1320000000 = 60000000 * ((16 + 6))
+

The total pages of data, n-pages-of-data, is the +bytes-of-data divided by the useful-bytes-per-page. In +this example, there are 161646 pages of data. +

161646 = 1320000000 / 8166
+

The total bytes of disk space for the database is n-pages-of-data +multiplied by the page-size. In the example, the result is +1324204032 bytes, or roughly 1.23GB. +

1324204032 = 161646 * 8192
+

Now, let's assume that the application specified a fill factor explicitly. +The fill factor indicates the target number of items to place on a single +page (a fill factor might reduce the utilization of each page, but it can +be useful in avoiding splits and preventing buckets from becoming too +large. Using our estimates above, each item is 22 bytes (16 + 6) and +there are 8166 useful bytes on a page (8192 - 26). That means that, on +average, you can fit 371 pairs per page. +

371 = 8166 / 22
+

However, let's assume that the application designer knows that while most +items are 8 bytes, they can sometimes be as large as 10 and it's very +important to avoid overflowing buckets and splitting. Then, the +application might specify a fill factor of 314. +

314 = 8166 / 26
+

With a fill factor of 314, then the formula for computing database size +is: +

npages = npairs / pairs-per-page
+

or 191082. +

191082 = 60000000 / 314
+

At 191082 pages, the total database size would be 1565343744 or 1.46GB. +

1565343744 = 191082 * 8192 
+

There are a few additional caveats with respect to Hash databases. This +discussion assumes that the hash function does a good job of evenly +distributing keys among hash buckets. If the function does not do this, +you may find your table growing significantly larger than you expected. +Secondly, in order to provide support for Hash databases co-existing with +other databases in a single file, pages within a Hash database are +allocated in power-of-2 chunks. That means that a Hash database with 65 +buckets will take up as much space as a Hash database with 128 buckets; +each time the Hash database grows beyond its current power-of-two number +of buckets, it allocates space for the next power-of-two buckets. This +space may be sparsely allocated in the file system, but the files will +appear to be their full size. Finally, because of this need for +contiguous allocation, overflow pages and duplicate pages can be allocated +only at specific points in the file, and this too can lead to sparse hash +tables. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/program/environ.html b/db/docs/ref/program/environ.html new file mode 100644 index 000000000..7f56109b5 --- /dev/null +++ b/db/docs/ref/program/environ.html @@ -0,0 +1,33 @@ + + + + + +Berkeley DB Reference Guide: Environment variables + + + + + + + +

Berkeley DB Reference Guide:
Programmer Notes

PrevRefNext +
+

+

Environment variables

+

The Berkeley DB library uses the following environment variables: +

+

DB_HOME
If the environment variable DB_HOME is set, it is used as part of +File Naming. +Note, for the DB_HOME variable to take effect, either the +DB_USE_ENVIRON or DB_USE_ENVIRON_ROOT flags must be +specified to DBENV->open. +

TMPDIR, TEMP, TMP, TempFolder
The TMPDIR, TEMP, TMP and TempFolder environment variables are all +checked as locations in which to create temporary files. See +DBENV->set_tmp_dir for more information. +
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/program/errorret.html b/db/docs/ref/program/errorret.html new file mode 100644 index 000000000..fc6ad650d --- /dev/null +++ b/db/docs/ref/program/errorret.html @@ -0,0 +1,108 @@ + + + + + +Berkeley DB Reference Guide: Error returns to applications + + + + + + + +

Berkeley DB Reference Guide:
Programmer Notes

PrevRefNext +
+

+

Error returns to applications

+

Except for the historic dbm, ndbm and hsearch +interfaces, Berkeley DB does not use the global variable errno to +return error values. The return values for all Berkeley DB functions are +grouped into three categories: +

+

0
A return value of 0 indicates that the operation was successful. +

> 0
A return value that is greater than 0 indicates that there was a system +error. The errno value returned by the system is returned by +the function, e.g., when a Berkeley DB function is unable to allocate memory, +the return value from the function will be ENOMEM. +

< 0
A return value that is less than 0 indicates a condition that was not +a system failure, but was not an unqualified success, either. For +example, a routine to retrieve a key/data pair from the database may +return DB_NOTFOUND when the key/data pair does not appear in +the database, as opposed to the value of 0, which would be returned if +the key/data pair were found in the database. +

+All values returned by Berkeley DB functions are less than 0 in order to avoid +conflict with possible values of errno. Specifically, Berkeley DB +reserves all values from -30,800 to -30,999 to itself as possible error +values. There are a few Berkeley DB interfaces where it is possible for an +application function to be called by a Berkeley DB function and subsequently +fail with an application-specific return. Such failure returns will be +passed back to the function that originally called a Berkeley DB interface. +To avoid ambiguity as to the cause of the error, error values separate +from the Berkeley DB error name space should be used. +

+While possible error returns are specified by each individual function's +manual page, there are a few error returns that deserve special mention: +

DB_NOTFOUND and DB_KEYEMPTY

+

There are two special return values that are similar in meaning, and that +are returned in similar situations, and therefore might be confused: +DB_NOTFOUND and DB_KEYEMPTY. +

The DB_NOTFOUND error return indicates that the requested key/data +pair did not exist in the database or that start- or end-of-file has been +reached. +

The DB_KEYEMPTY error return indicates that the requested key/data +pair logically exists but was never explicitly created by the application +(the Recno and Queue access methods will automatically create key/data +pairs under some circumstances; see DB->open for more +information), or that the requested key/data pair was deleted and never +re-created. In addition, the Queue access method will return +DB_KEYEMPTY for records which were created as part of a +transaction which was later aborted, and never re-created. +

DB_LOCK_DEADLOCK

+

When multiple threads of control are modifying the database, there is +normally the potential for deadlock. In Berkeley DB, deadlock is signified by +an error return from the Berkeley DB function of the value +DB_LOCK_DEADLOCK. Whenever a Berkeley DB function returns +DB_LOCK_DEADLOCK, the enclosing transaction should be aborted. +

Any Berkeley DB function that attempts to acquire locks can potentially return +DB_LOCK_DEADLOCK. Practically speaking, the safest way to deal +with applications that can deadlock is to handle an +DB_LOCK_DEADLOCK return from any Berkeley DB access method call. +

DB_LOCK_NOTGRANTED

+

When multiple threads of control are modifying the database, there is +normally the potential for deadlock. In order to avoid deadlock, +applications may specify, on a per-transaction basis, that if a lock is +unavailable, the Berkeley DB operation should return immediately instead of +waiting on the lock. The error return in this case will be +DB_LOCK_NOTGRANTED. Whenever a Berkeley DB function returns +DB_LOCK_NOTGRANTED, the enclosing transaction should be aborted. +

DB_RUNRECOVERY

+

There exists a class of errors that Berkeley DB considers fatal to an entire +Berkeley DB environment. An example of this type of error is a corrupted +database, or a log write failure because the disk is out of free space. +The only way to recover from these failures is to have all threads of +control exit the Berkeley DB environment, run recovery of the environment, and +re-enter Berkeley DB. (It is not strictly necessary that the processes exit, +although that is the only way to recover system resources, such as file +descriptors and memory, allocated by Berkeley DB.) +

When this type of error is encountered, the error value +DB_RUNRECOVERY is returned. This error can be returned by any +Berkeley DB interface. Once DB_RUNRECOVERY is returned by any +interface, it will be returned from all subsequent Berkeley DB calls made by +any threads or processes participating in the environment. +

Optionally, applications may also specify a fatal-error callback function +using the DBENV->set_paniccall function. This callback function will be +called with two arguments: a reference to the DB_ENV structure associated +with the environment, and the errno value associated with the +underlying error that caused the problem. +

Applications can handle such fatal errors in one of two ways: by checking +for DB_RUNRECOVERY as part of their normal Berkeley DB error return +checking, similarly to DB_LOCK_DEADLOCK or any other error, or, +in applications that have no cleanup processing of their own, by simply +exiting the application when the callback function is called. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/program/extending.html b/db/docs/ref/program/extending.html new file mode 100644 index 000000000..6f276d8dc --- /dev/null +++ b/db/docs/ref/program/extending.html @@ -0,0 +1,242 @@ + + + + + +Berkeley DB Reference Guide: Application-specific logging and recovery + + + + + + +

Berkeley DB Reference Guide:
Programmer Notes

PrevRefNext +
+

+

Application-specific logging and recovery

+

Berkeley DB includes tools to assist in the development of application-specific +logging and recovery. Specifically, given a description of the +information to be logged, these tools will automatically create logging +functions (functions that take the values as parameters and construct a +single record that is written to the log), read functions (functions that +read a log record and unmarshall the values into a structure that maps +onto the values you chose to log), a print function (for debugging), +templates for the recovery functions, and automatic dispatching to your +recovery functions. +

Defining Application-Specific Operations

+

Log records are described in files named XXX.src, where "XXX" is a +unique prefix. The prefixes currently used in the Berkeley DB package are +btree, crdel, db, hash, log, qam, and txn. These files contain interface +definition language descriptions for each type of log record that +is supported. +

All lines beginning with a hash character in .src files are +treated as comments. +

The first non-comment line in the file should begin with the keyword +PREFIX followed by a string that will be prepended to every function. +Frequently, the PREFIX is either identical or similar to the name of the +.src file. +

The rest of the file consists of one or more log record descriptions. +Each log record description begins with the line: +

BEGIN RECORD_NAME RECORD_NUMBER
+

and ends with the line: +

END
+

The RECORD_NAME keyword should be replaced with a unique record name for +this log record. Record names must only be unique within .src +files. +

The RECORD_NUMBER keyword should be replaced with a record number. Record +numbers must be unique for an entire application, that is, both +application-specific and Berkeley DB log records must have unique values. +Further, as record numbers are stored in log files, which often must be +portable across application releases, no record number should ever be +re-used. The record number space below 10,000 is reserved for Berkeley DB +itself, applications should choose record number values equal to or +greater than 10,000. +

Between the BEGIN and END statements, there should be one line for each +data item that will be logged in this log record. The format of these +lines is as follows: +

ARG | DBT | POINTER	variable_name	variable_type	printf_format
+

The keyword ARG indicates that the argument is a simple parameter of the +type specified. The keyword DBT indicates that the argument is a DBT +containing a length and pointer. The keyword PTR indicates that the +argument is a pointer to the data type specified and that the entire type +should be logged. +

The variable name is the field name within the structure that will be used +to reference this item. The variable type is the C type of the variable, +and the printf format should be "s", for string, "d" for signed integral +type, or "u" for unsigned integral type. +

Automatically Generated Functions

+

For each log record description found in the file, the following structure +declarations and #defines will be created in the file PREFIX_auto.h. +

+#define DB_PREFIX_RECORD_TYPE /* Integer ID number */ +

+typedef struct _PREFIX_RECORD_TYPE_args { + /* + * These three fields are generated for every record. + */ + u_int32_t type; /* Record type used for dispatch. */ +

+ /* + * Transaction id that identifies the transaction on whose + * behalf the record is being logged. + */ + DB_TXN *txnid; +

+ /* + * The LSN returned by the previous call to log for + * this transaction. + */ + DB_LSN *prev_lsn; +

+ /* + * The rest of the structure contains one field for each of + * the entries in the record statement. + */ +};

+

The DB_PREFIX_RECORD_TYPE will be described in terms of a value +DB_PREFIX_BEGIN, which should be specified by the application writer in +terms of the library provided DB_user_BEGIN macro (this is the value of +the first identifier available to users outside the access method system). +

In addition to the PREFIX_auto.h file, a file named PREFIX_auto.c is +created, containing the following functions for each record type: +

+

The log function, with the following parameters:

+

dbenv
The environment handle returned by db_env_create. +

txnid
The transaction identifier returned by txn_begin. +

lsnp
A pointer to storage for an LSN into which the LSN of the new log record +will be returned. +

syncflag
A flag indicating if the record must be written synchronously. Valid +values are 0 and DB_FLUSH. +
+

The log function marshalls the parameters into a buffer and calls +log_put on that buffer returning 0 on success and 1 on failure. +

The read function with the following parameters:
+

+

recbuf
A buffer. +

argp
A pointer to a structure of the appropriate type. +
+

The read function takes a buffer and unmarshalls its contents into a +structure of the appropriate type. It returns 0 on success and non-zero +on error. After the fields of the structure have been used, the pointer +returned from the read function should be freed. +

The recovery function with the following parameters:

+

dbenv
The handle returned from the db_env_create call which identifies +the environment in which recovery is running. +

rec
The rec parameter is the record being recovered. +

lsn
The log sequence number of the record being recovered. +

op
A parameter of type db_recops which indicates what operation is being run +(DB_TXN_OPENFILES, DB_TXN_ABORT, DB_TXN_BACKWARD_ROLL, DB_TXN_FORWARD_ROLL). +

info
A structure passed by the dispatch function. It is used to contain a list +of committed transactions and information about files that may have been +deleted. +
+

The recovery function is called on each record read from the log during +system recovery or transaction abort. +

The recovery function is created in the file PREFIX_rtemp.c since it +contains templates for recovery functions. The actual recovery functions +must be written manually, but the templates usually provide a good starting +point. +

The print function:
The print function takes the same parameters as the recover function so +that it is simple to dispatch both to simple print functions as well as +to the actual recovery functions. This is useful for debugging purposes +and is used by the db_printlog utility to produce a human-readable +version of the log. All parameters except the rec and +lsnp parameters are ignored. The rec parameter contains +the record to be printed. +
+One additional function, an initialization function, +is created for each .src file. +

+

The initialization function has the following parameters:

+

dbenv
The environment handle returned by db_env_create. +
+

The recovery initialization function registers each log record type +declared with the recovery system, so that the appropriate function is +called during recovery. +

+

Using Automatically Generated Routines

+

Applications use the automatically generated functions as follows: +

    +

  1. When the application starts, +call the DBENV->set_recovery_init with your recovery +initialization function so that the initialization function is called +at the appropriate time. +

  2. Issue a txn_begin call before any operations you wish +to be transaction protected. +

  3. Before accessing any data, issue the appropriate lock call to +lock the data (either for reading or writing). +

  4. Before modifying any data that is transaction protected, issue +a call to the appropriate log function. +

  5. Issue a txn_commit to save all of the changes or a +txn_abort to cancel all of the modifications. +
+

The recovery functions (described below) can be called in two cases: +

    +

  1. From the recovery daemon upon system failure, with op set to +DB_TXN_FORWARD_ROLL or DB_TXN_BACKWARD_ROLL. +

  2. From txn_abort, if it is called to abort a transaction, with +op set to DB_TXN_ABORT. +
+

For each log record type you declare, you must write the appropriate +function to undo and redo the modifications. The shell of these functions +will be generated for you automatically, but you must fill in the details. +

Your code should be able to detect whether the described modifications +have been applied to the data or not. The function will be called with +the "op" parameter set to DB_TXN_ABORT when a transaction that wrote the +log record aborts and with DB_TXN_FORWARD_ROLL and DB_TXN_BACKWARD_ROLL +during recovery. The actions for DB_TXN_ABORT and DB_TXN_BACKWARD_ROLL +should generally be the same. For example, in the access methods, each +page contains the log sequence number of the most recent log record that +describes a modification to the page. When the access method changes a +page it writes a log record describing the change and including the the +LSN that was on the page before the change. This LSN is referred to as +the previous LSN. The recovery functions read the page described by a +log record and compare the log sequence number (LSN) on the page to the +LSN they were passed. If the page LSN is less than the passed LSN and +the operation is undo, no action is necessary (because the modifications +have not been written to the page). If the page LSN is the same as the +previous LSN and the operation is redo, then the actions described are +reapplied to the page. If the page LSN is equal to the passed LSN and +the operation is undo, the actions are removed from the page; if the page +LSN is greater than the passed LSN and the operation is redo, no further +action is necessary. If the action is a redo and the LSN on the page is +less than the previous LSN in the log record this is an error, since this +could only happen if some previous log record was not processed. +

Please refer to the internal recovery functions in the Berkeley DB library +(found in files named XXX_rec.c) for examples of how recovery functions +should work. +

Non-conformant Logging

+

If your application cannot conform to the default logging and recovery +structure, then you will have to create your own logging and recovery +functions explicitly. +

First, you must decide how you will dispatch your records. Encapsulate +this algorithm in a dispatch function that is passed to DBENV->open. +The arguments for the dispatch function are as follows: +

+

dbenv
The environment handle returned by db_env_create. +

rec
The record being recovered. +

lsn
The log sequence number of the record to be recovered. +

op
Indicates what operation of recovery is needed (openfiles, abort, forward roll +or backward roll). +

info
An opaque value passed to your function during system recovery. +
+

When you abort a transaction, txn_abort will read the last log +record written for the aborting transaction and will then call your +dispatch function. It will continue looping, calling the dispatch +function on the record whose LSN appears in the lsn parameter of the +dispatch call (until a NULL LSN is placed in that field). The dispatch +function will be called with the op set to DB_TXN_ABORT. +

Your dispatch function can do any processing necessary. See the code +in db/db_dispatch.c for an example dispatch function (that is based on +the assumption that the transaction ID, previous LSN, and record type +appear in every log record written). +

If you do not use the default recovery system, you will need to construct +your own recovery process based on the recovery program provided in +db_recover/db_recover.c. Note that your recovery functions will need to +correctly process the log records produced by calls to txn_begin +and txn_commit. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/program/mt.html b/db/docs/ref/program/mt.html new file mode 100644 index 000000000..31110920a --- /dev/null +++ b/db/docs/ref/program/mt.html @@ -0,0 +1,95 @@ + + + + + +Berkeley DB Reference Guide: Building multi-threaded applications + + + + + + + +

Berkeley DB Reference Guide:
Programmer Notes

PrevRefNext +
+

+

Building multi-threaded applications

+

The Berkeley DB library is not itself multi-threaded. The library was +deliberately architected to not use threads internally because of the +portability problems that using threads within the library would +introduce. +

Berkeley DB supports multi-threaded applications with the caveat that it loads +and calls functions that are commonly available in C language environments. +Other than this usage, Berkeley DB has no static data and maintains no local +context between calls to Berkeley DB functions. +

Environment and database object handles returned from Berkeley DB library +functions are free-threaded. No other object handles returned from +the Berkeley DB library are free-threaded. +

The following rules should be observed when using threads to +access the Berkeley DB library: +

    +

  1. The DB_THREAD flag must be specified to the DBENV->open +and DB->open functions if the Berkeley DB handles returned by those interfaces +will be used in the context of more than one thread. Setting the +DB_THREAD flag inconsistently may result in database corruption. +

    Threading is assumed in the Java API, so no special flags are required, +and Berkeley DB functions will always behave as if the DB_THREAD flag +was specified. +

    Only a single thread may call the DBENV->close or DB->close functions +for a returned environment or database handle. +

    No other Berkeley DB handles are free-threaded, for example, cursors and +transactions may not span threads as their returned handles are not +free-threaded. +

  2. When using the non-cursor Berkeley DB calls to retrieve key/data items (e.g., +DB->get), the memory referenced by the pointer stored into the +Dbt is only valid until the next call to Berkeley DB using the DB handle +returned by DB->open. This includes any use of the returned +DB handle, including by another thread of control within the +process. +

    For this reason, if the DB_THREAD handle was specified to the +DB->open function, either DB_DBT_MALLOC, DB_DBT_REALLOC +or DB_DBT_USERMEM must be specified in the DBT when +performing any non-cursor key or data retrieval. +

  3. The DB_CURRENT, DB_NEXT and DB_PREV flags to the +log_get function may not be used by a free-threaded handle. If +such calls are necessary, a thread should explicitly create a unique +environment handle by separately calling DBENV->open without +specifying DB_THREAD. +

  4. Each database operation (i.e., any call to a function underlying the +handles returned by DB->open and DB->cursor) is normally +performed on behalf of a unique locker. If, within a single thread of +control, multiple calls on behalf of the same locker are desired, then +transactions must be used. For example, consider the case where a +cursor scan locates a record, and then based on that record, accesses +some other item in the database. If these operations are done using +the default lockers for the handle, they may conflict. If the +application wishes to guarantee that the operations do not conflict, +locks must be obtained on behalf of a transaction, instead of the +default locker ID, and a transaction must be specified to subsequent +DB->cursor and other Berkeley DB calls. +

  5. Transactions may not span threads. Each transaction must begin and end +in the same thread, and each transaction may only be used by a single +thread. +

    Cursors may not span transactions or threads. Each cursor must be +allocated and de-allocated within the same transaction and within +the same thread. +

  6. User-level synchronization mutexes must have been implemented for the +compiler/architecture combination. Attempting to specify the DB_THREAD +flag will fail if fast mutexes are not available. +

    If blocking mutexes are available, for example POSIX pthreads, they will +be used. Otherwise, the Berkeley DB library will make a system call to pause +for some amount of time when it is necessary to wait on a lock. This may +not be optimal, especially in a thread-only environment where it will be +more efficient to explicitly yield the processor to another thread. +

    It is possible to specify a yield function on an per-application basis. +See db_env_set_func_yield for more information. +

    It is possible to specify the number of attempts that will be made to +acquire the mutex before waiting. Se db_env_set_tas_spins for +more information. +

+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/program/namespace.html b/db/docs/ref/program/namespace.html new file mode 100644 index 000000000..519f5f61c --- /dev/null +++ b/db/docs/ref/program/namespace.html @@ -0,0 +1,44 @@ + + + + + +Berkeley DB Reference Guide: Name spaces + + + + + + + +

Berkeley DB Reference Guide:
Programmer Notes

PrevRefNext +
+

+

Name spaces

+

The Berkeley DB library is careful to avoid C language programmer name spaces, +but there are a few potential areas for concern, mostly in the Berkeley DB +include file db.h. The db.h include file defines a number of types and +strings. Where possible, all of these types and strings are prefixed with +"DB_" or "db_". There are a few notable exceptions. +

The Berkeley DB library uses a macro named "__P" to configure for systems that +do not provide ANSI C function prototypes. This could potentially collide +with other systems using a "__P" macro for similar or different purposes. +

The Berkeley DB library needs information about specifically sized types for +each architecture. If they are not provided by the system, they are +typedef'd in the db.h include file. The types which may be typedef'd +by db.h include the following: u_int8_t, int16_t, u_int16_t, int32_t, +u_int32_t, u_char, u_short, u_int and u_long. +

The Berkeley DB library declares a number of external routines. All of these +routines are prefixed with the strings "db_", "lock_", "log_", "memp_" +or "txn_". All internal routines are prefixed with the strings "__db_", +"__lock_," "__log_", "__memp_" or "__txn_". +

Berkeley DB environments create or use some number of files in environment home +directories. These files are named DB_CONFIG, "log.NNNNNNNNNN" +(e.g., log.0000000003), or with the string prefix "__db" (e.g., __db.001). +Database files that match these names should not be created in the +environment directory. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/program/recimp.html b/db/docs/ref/program/recimp.html new file mode 100644 index 000000000..240eccd8b --- /dev/null +++ b/db/docs/ref/program/recimp.html @@ -0,0 +1,49 @@ + + + + + +Berkeley DB Reference Guide: Recovery implementation + + + + + + +

Berkeley DB Reference Guide:
Transaction Protected Applications

PrevRefNext +
+

+

Recovery implementation

+

The physical recovery process works as follows: +

First, find the last checkpoint that completed. Since the system may +have crashed while writing a checkpoint, this implies finding the +second-to-last checkpoint in the log files. Read forward from this +checkpoint, opening any database files for which modifications are found +in the log. +

Then, read backward from the end of the log. For each commit record +encountered, record its transaction ID. For every other data update +record, find the transaction ID of the record. If that transaction ID +appears in the list of committed transactions, do nothing; if it does not +appear in the committed list, then call the appropriate recovery routine +to undo the operation. +

In the case of catastrophic recovery, this roll-backward pass continues +through all the present log files. In the case of normal recovery, this +pass continues until we find a checkpoint written before the second-to-last +checkpoint described above. +

When the roll-backward pass is complete, the roll-forward pass begins at +the point where the roll-backward pass ended. Each record is read and if +its transaction id is in the committed list, then the appropriate recovery +routine is called to redo the operation if necessary. +

In a distributed transaction environment, there may be transactions that +are prepared, but not yet committed. If these transactions are XA +transactions, then they are rolled forward to their current state, and an +active transaction corresponding to it is entered in the transaction table +so that the XA transaction manager may call either transaction abort or +commit, depending on the outcome of the overall transaction. If the +transaction is not an XA transaction, then it is aborted like any other +transactions would be. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/program/runtime.html b/db/docs/ref/program/runtime.html new file mode 100644 index 000000000..a6f860bca --- /dev/null +++ b/db/docs/ref/program/runtime.html @@ -0,0 +1,57 @@ + + + + + +Berkeley DB Reference Guide: Run-time configuration + + + + + + +

Berkeley DB Reference Guide:
Programmer Notes

PrevRefNext +
+

+

Run-time configuration

+

There are a few interfaces that support run-time configuration of Berkeley DB. +First is a group of interfaces that allow applications to intercept +Berkeley DB requests for underlying library or system call functionality: +

db_env_set_func_close
+db_env_set_func_dirfree
+db_env_set_func_dirlist
+db_env_set_func_exists
+db_env_set_func_free
+db_env_set_func_fsync
+db_env_set_func_ioinfo
+db_env_set_func_malloc
+db_env_set_func_map
+db_env_set_func_open
+db_env_set_func_read
+db_env_set_func_realloc
+db_env_set_func_seek
+db_env_set_func_sleep
+db_env_set_func_unlink
+db_env_set_func_unmap
+db_env_set_func_write
+db_env_set_func_yield
+

These interfaces are only available from the Berkeley DB C language API. +

In addition, there are a few interfaces that allow applications to +re-configure, on an application-wide basis, Berkeley DB behaviors. +

DBENV->set_mutexlocks
+db_env_set_pageyield
+db_env_set_panicstate
+db_env_set_region_init
+db_env_set_tas_spins
+

These interfaces are available from all of the Berkeley DB programmatic APIs. +

A not-uncommon problem for applications is the new API in Solaris 2.6 +for manipulating large files. As this API was not part of Solaris 2.5, +it is difficult to create a single binary that takes advantage of the +large file functionality in Solaris 2.6 but which still runs on Solaris +2.5. Example code that supports this is +included in the Berkeley DB distribution. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/program/scope.html b/db/docs/ref/program/scope.html new file mode 100644 index 000000000..198147932 --- /dev/null +++ b/db/docs/ref/program/scope.html @@ -0,0 +1,71 @@ + + + + + +Berkeley DB Reference Guide: Berkeley DB handles + + + + + + + +

Berkeley DB Reference Guide:
Programmer Notes

PrevRefNext +
+

+

Berkeley DB handles

+ +

The Berkeley DB library has a number of object handles. The following table +lists those handles, their scope, and if they are free-threaded, that +is, if multiple threads within a process can share them. +

+

DB_ENV
The DB_ENV handle is created by the db_env_create function and +references a Berkeley DB database environment, a collection of +databases and Berkeley DB subsystems. DB_ENV handles are free-threaded +if the DB_THREAD flag is specified to the DBENV->open function +when the environment is opened. The handle should not be closed while +any other handle remains open that is using it as a reference +(e.g., DB or DB_TXN). Once either the DBENV->close or +DBENV->remove functions are called, the handle may not be accessed again, +regardless of the function's return. +

DB_TXN
The DB_TXN handle is created by the txn_begin function and +references a single transaction. The handle is not free-threaded, and +transactions may not span threads nor may transactions be used by more +than a single thread. +Once the +txn_abort or txn_commit functions are called, the handle may +not be accessed again, regardless of the function's return. +In addition, parent transactions may not issue +any Berkeley DB operations, except for txn_begin, txn_abort +and txn_commit, while it has active child transactions (child +transactions that have not yet been committed or aborted). +

DB_MPOOLFILE
The DB_MPOOLFILE handle references an open file in the shared +memory buffer pool of the database environment. The handle is not +free-threaded. Once the memp_fclose function is called, the handle may +not be accessed again, regardless of the function's return. +

DB
The DB handle is created by the db_create function and +references a single Berkeley DB database, which may or may not be part of a +database environment. DB handles are free-threaded if the +DB_THREAD flag is specified to the DB->open function when the +database is opened, or if the database environment in which the database +is opened is free-threaded. The handle should not be closed while any +other handle that references the database is in use, e.g., database +handles must not be closed while cursor handles into the database remain +open, or transactions which include operations on the database have not +yet been committed or aborted. Once the DB->close, +DB->remove or DB->rename functions are called, the handle may +not be accessed again, regardless of the function's return. +

DBC
The DBC handle references a cursor into a Berkeley DB database. The +handle is not free-threaded and cursors may not span threads nor may +cursors be used by more than a single thread. If the cursor is to be +used to perform operations on behalf of a transaction, the cursor must +be opened and closed within the context of that single transaction. +Once DBcursor->c_close has been called, the handle may not be accessed +again, regardless of the function's return. +
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/program/solaris.txt b/db/docs/ref/program/solaris.txt new file mode 100644 index 000000000..d2ec31682 --- /dev/null +++ b/db/docs/ref/program/solaris.txt @@ -0,0 +1,213 @@ +#ifdef OS_solaris + * This is all for Solaris 2.6. + * + * Sun defined a new API in Solaris2.6 to be used when manipulating large + * (>2Gbyte) files. This API isn't present in 2.5.x, so we can't simply + * call it -- that would mean two binaries, one for 2.5.x and the other for + * 2.6. Not pretty. So, what we do here is determine the OS on which we're + * running at runtime, and adjust the underlying Berkeley DB calls to use + * the new API if it's there. + */ + +/* This must match the definition of stat64 in Solaris2.6 */ +struct our_stat64 { + dev_t st_dev; + long st_pad1[3]; /* reserve for dev expansion */ + u_longlong_t st_ino; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + long st_pad2[2]; + longlong_t st_size; + timestruc_t mst_atime; + timestruc_t mst_mtime; + timestruc_t mst_ctime; + long st_blksize; + longlong_t st_blocks; /* large file support */ + char st_fstype[_ST_FSTYPSZ]; + long st_pad4[8]; /* expansion area */ +}; + +#define MEGABYTE (1024 * 1024) + +typedef int (*open_fn)(const char *path, int flags, ...); +typedef longlong_t (*lseek64_fn)(int fildes, longlong_t offset, int whence); +typedef longlong_t (*fstat64_fn)(int fildes, struct our_stat64 *s); +typedef void* (*mmap64_fn)(void* addr, size_t len, int prot, int flags, +int filedes, longlong_t off); + +static fstat64_fn os_fstat64_fn = NULL; +static lseek64_fn os_lseek64_fn = NULL; +static mmap64_fn os_mmap64_fn = NULL; +static open_fn os_open64_fn = NULL; + +static int dblayer_load_largefile_fns() +{ + void *lib_handle = NULL; + void *function_found = NULL; + int ret = 0; + + lib_handle = dlopen(NULL, RTLD_NOW); + if (NULL == lib_handle) + return (-1); + + function_found = dlsym(lib_handle,"open64"); + if (NULL == function_found) + return (-1); + os_open64_fn = (open_fn)function_found; + + function_found = dlsym(lib_handle,"lseek64"); + if (NULL == function_found) + return (-1); + os_lseek64_fn = (lseek64_fn)function_found; + + function_found = dlsym(lib_handle,"fstat64"); + if (NULL == function_found) + return (-1); + os_fstat64_fn = (fstat64_fn)function_found; + + function_found = dlsym(lib_handle,"mmap64"); + if (NULL == function_found) + return (-1); + os_mmap64_fn = (mmap64_fn)function_found; + + return 0; +} + +/* Helper function for large seeks */ +static int dblayer_seek_fn_solaris(int fd, + size_t pgsize, db_pgno_t pageno, u_long relative, int whence) +{ + longlong_t offset = 0; + longlong_t ret = 0; + + if (NULL == os_lseek64_fn) { + return -1; + } + + offset = (longlong_t)pgsize * pageno + relative; + + ret = (*os_lseek64_fn)(fd,offset,whence); + + return (ret == -1) ? errno : 0; +} + +/* Helper function for large file mmap */ +static int dblayer_map_solaris(fd, len, is_private, is_rdonly, addr) + int fd, is_private, is_rdonly; + size_t len; + void **addr; +{ + void *p; + int flags, prot; + + flags = is_private ? MAP_PRIVATE : MAP_SHARED; + prot = PROT_READ | (is_rdonly ? 0 : PROT_WRITE); + + if ((p = (*os_mmap64_fn)(NULL, + len, prot, flags, fd, (longlong_t)0)) == (void *)MAP_FAILED) + return (errno); + + *addr = p; + return (0); +} + +/* Helper function for large fstat */ +static int dblayer_ioinfo_solaris(const char *path, + int fd, u_int32_t *mbytesp, u_int32_t *bytesp, u_int32_t *iosizep) +{ + struct our_stat64 sb; + + if (NULL == os_fstat64_fn) { + return -1; + } + + if ((*os_fstat64_fn)(fd, &sb) == -1) + return (errno); + + /* Return the size of the file. */ + if (mbytesp != NULL) + *mbytesp = (u_int32_t) (sb.st_size / (longlong_t)MEGABYTE); + if (bytesp != NULL) + *bytesp = (u_int32_t) (sb.st_size % (longlong_t)MEGABYTE); + + /* + * Return the underlying filesystem blocksize, if available. Default + * to 8K on the grounds that most OS's use less than 8K as their VM + * page size. + */ + if (iosizep != NULL) + *iosizep = sb.st_blksize; + return (0); +} +#endif + +#ifdef irix + * A similar mess to Solaris: a new API added in IRIX6.2 to support large + * files. We always build on 6.2 or later, so no need to do the same song + * and dance as on Solaris -- we always have the header files for the + * 64-bit API. + */ + +/* Helper function for large seeks */ +static int dblayer_seek_fn_irix(int fd, + size_t pgsize, db_pgno_t pageno, u_long relative, int whence) +{ + off64_t offset = 0; + off64_t ret = 0; + + offset = (off64_t)pgsize * pageno + relative; + + ret = lseek64(fd,offset,whence); + + return (ret == -1) ? errno : 0; +} + +/* Helper function for large fstat */ +static int dblayer_ioinfo_irix(const char *path, + int fd, u_int32_t *mbytesp, u_int32_t *bytesp, u_int32_t *iosizep) +{ + struct stat64 sb; + + if (fstat64(fd, &sb) == -1) { + return (errno); + } + + /* Return the size of the file. */ + if (mbytesp != NULL) + *mbytesp = (u_int32_t) (sb.st_size / (off64_t)MEGABYTE); + if (bytesp != NULL) + *bytesp = (u_int32_t) (sb.st_size % (off64_t)MEGABYTE); + + if (iosizep != NULL) + *iosizep = sb.st_blksize; + return (0); +} +#endif /* irix */ + +static int dblayer_override_libdb_functions(dblayer_private *priv) +{ +#if defined(OS_solaris) + int ret = 0; + + ret = dblayer_load_largefile_fns(); + if (0 != ret) { + Debug("Not Solaris2.6: no large file support enabled\n"); + } else { + /* Means we did get the XXX64 functions, so let's use them */ + db_jump_set((void*)os_open64_fn, DB_FUNC_OPEN); + db_jump_set((void*)dblayer_seek_fn_solaris, DB_FUNC_SEEK); + db_jump_set((void*)dblayer_ioinfo_solaris, DB_FUNC_IOINFO); + db_jump_set((void*)dblayer_map_solaris, DB_FUNC_MAP); + Debug("Solaris2.6: selected 64-bit file handling.\n"); + } +#else +#if defined (irix) + db_jump_set((void*)dblayer_seek_fn_irix, DB_FUNC_SEEK); + db_jump_set((void*)dblayer_ioinfo_irix, DB_FUNC_IOINFO); +#endif /* irix */ +#endif /* OS_solaris */ + return 0; +} diff --git a/db/docs/ref/program/version.html b/db/docs/ref/program/version.html new file mode 100644 index 000000000..d1b1254a1 --- /dev/null +++ b/db/docs/ref/program/version.html @@ -0,0 +1,45 @@ + + + + + +Berkeley DB Reference Guide: Library version information + + + + + + +

Berkeley DB Reference Guide:
Programmer Notes

PrevRefNext +
+

+

Library version information

+

Each release of the Berkeley DB library has a major version number, a minor +version number, and a patch number. +

The major version number changes only when major portions of the Berkeley DB +functionality have been changed. In this case, it may be necessary to +significantly modify applications in order to upgrade them to use the new +version of the library. +

The minor version number changes when Berkeley DB interfaces have changed, and +the new release is not entirely backward compatible with previous releases. +To upgrade applications to the new version, they must be recompiled, and +potentially, minor modifications made, (e.g., the order of arguments to a +function might have changed). +

The patch number changes on each release. If only the patch number +has changed in a release, applications do not need to be recompiled, +and they can be upgraded to the new version by simply installing a +new version of the shared library. +

Internal Berkeley DB interfaces may change at any time and during any release, +without warning. This means that the library must be entirely recompiled +and reinstalled when upgrading to new releases of the library, as there +is no guarantee that modules from the current version of the library will +interact correctly with modules from a previous release. +

To retrieve the Berkeley DB version information, applications should use the +db_version interface. In addition to the above information, the +db_version interface returns a string encapsulating the version +information, suitable for display to a user. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/refs/bdb_usenix.html b/db/docs/ref/refs/bdb_usenix.html new file mode 100644 index 000000000..58e82b573 --- /dev/null +++ b/db/docs/ref/refs/bdb_usenix.html @@ -0,0 +1,1120 @@ + + + +Berkeley DB + + +

+

+Berkeley DB +

+

+ +Michael A. Olson +
+Keith Bostic +
+Margo Seltzer +
  +
+Sleepycat Software, Inc. +
  +
+
+ +Abstract + +

+ +
+

+Berkeley DB is an Open Source embedded database system with a number +of key advantages over comparable systems. It is simple to use, supports +concurrent access by multiple users, and provides industrial-strength +transaction support, including surviving system and disk crashes. This +paper describes the design and technical features of Berkeley DB, the +distribution, and its license. +

+
+

+Introduction +

+

+The Berkeley Database (Berkeley DB) is an embedded database system +that can be used in applications requiring high-performance +concurrent storage and retrieval of key/value pairs. The software +is distributed as a library that can be linked directly into an +application. +It provides a variety of programmatic interfaces, +including callable APIs for C, C++, Perl, Tcl and Java. +Users may download Berkeley DB from Sleepycat Software's Web site, +at +www.sleepycat.com. +

+Sleepycat distributes Berkeley DB as an Open Source product. The company +collects license fees for certain uses of the software and sells support +and services. +

+History +

+

+Berkeley DB began as a new implementation of a hash access method +to replace both +hsearch +and the various +dbm +implementations +(dbm from AT&T, +ndbm +from Berkeley, and +gdbm +from the GNU project). +In 1990 Seltzer and Yigit produced a package called Hash to do this +[Selt91]. +

+The first general release of Berkeley DB, in 1991, +included some interface changes and a new B+tree access method. +At roughly the same time, Seltzer and Olson +developed a prototype transaction +system based on Berkeley DB, called LIBTP [Selt92], +but never released the code. +

+The 4.4BSD UNIX release included Berkeley DB 1.85 in 1992. +Seltzer and Bostic maintained the code in the early 1990s +in Berkeley and in Massachusetts. +Many users adopted the code during this period. +

+By mid-1996, +users wanted commercial support for the software. +In response, Bostic and Seltzer formed Sleepycat Software. +The company enhances, distributes, and +supports Berkeley DB and supporting software and documentation. +Sleepycat released version 2.1 of Berkeley DB in mid-1997 +with important new features, including +support for concurrent access to databases. +The company makes about three commercial releases a year, +and most recently shipped version 2.8. +

+Overview of Berkeley DB +

+

+The C interfaces in Berkeley DB permit +dbm-style +record management +for databases, +with significant extensions to handle duplicate data items elegantly, +to deal with concurrent access, and to provide transactional +support so that multiple changes can be simultaneously committed +(so that they are made permanent) or rolled back (so that the +database is restored to its state at the beginning of the transaction). +

+C++ and Java interfaces provide a small set of classes for +operating on a database. The main class in both cases is called +Db, +and provides methods that encapsulate the +dbm-style +interfaces that the C interfaces provide. +

+Tcl and Perl interfaces allow developers working in those languages +to use Berkeley DB in their applications. +Bindings for both languages are included in the distribution. +

+Developers may compile their applications and link in Berkeley DB +statically or dynamically. +

+How Berkeley DB is used +

+

+The Berkeley DB library supports concurrent access to databases. +It can be linked +into standalone applications, into a collection of cooperating applications, +or into servers that handle requests and do database operations on +behalf of clients. +

+Compared to using a standalone database management system, Berkeley +DB is easy to understand and simple to use. The +software stores and retrieves records, which consist of key/value pairs. +Keys are used to locate items and can be any data type or structure +supported by the programming language. +

+The programmer can provide the functions that Berkeley DB uses to +operate on keys. +For example, +B+trees can use a custom comparison function, +and the Hash access method can use a custom hash function. +Berkeley DB uses default functions if none are supplied. +Otherwise, Berkeley DB does not examine or interpret either keys +or values in any way. +Values may be arbitrarily long. +

+It is also important to understand what Berkeley DB is not. +It is not a database server that handles network requests. It is not an +SQL engine that executes queries. It is not a relational or object-oriented +database management system. +

+It is possible to build any of those on top of Berkeley DB, +but the package, as distributed, +is an embedded database engine. It has been designed +to be portable, small, fast, and reliable. +

+Applications that use Berkeley DB +

+

+Berkeley DB is embedded in a variety of proprietary and Open Source +software packages. +This section highlights a few of the products that use it. +

+Directory servers, which do data storage and retrieval using the +Local Directory Access Protocol (LDAP), provide naming and directory +lookup service on local-area networks. +This service is, +essentially, +database query and update, +but uses a simple protocol rather than SQL or ODBC. +Berkeley DB is the embedded data manager in the majority of deployed +directory servers today, +including LDAP servers from Netscape, +MessageDirect (formerly Isode), +and others. +

+Berkeley DB is also embedded in a large number of mail servers. +Intermail, +from Software.com, +uses Berkeley DB as a message store +and as the backing store for its directory server. +The sendmail server +(including both the commercial Sendmail Pro offering from Sendmail, +Inc. and the version distributed by sendmail.org) +uses Berkeley DB to store aliases and other information. +Similarly, +Postfix (formerly VMailer) uses Berkeley DB +to store administrative information. +

+In addition, +Berkeley DB is embedded in a wide variety of other software products. +Example applications include managing access control lists, +storing user keys in a public-key infrastructure, +recording machine-to-network-address mappings in address servers, +and storing configuration and device information in video +post-production software. +

+Finally, +Berkeley DB is a part of many other Open Source software packages +available on the Internet. +For example, +the software is embedded in the Apache Web server and the Gnome desktop. +

+Access Methods +

+

+In database terminology, an access method is the disk-based structure +used to store data and the operations available on that structure. +For example, many database systems support a B+tree access method. +B+trees allow equality-based lookups (find keys equal to some constant), +range-based lookups (find keys between two constants) and record +insertion and deletion. +

+Berkeley DB supports three access methods: B+tree, +Extended Linear Hashing (Hash), +and Fixed- or Variable-length Records (Recno). +All three operate on records composed of a key and a data value. +In the B+tree and Hash access methods, keys can have arbitrary structure. +In the Recno access method, each record is assigned a record number, which +serves as the key. +In all the access methods, the +value can have arbitrary structure. +The programmer can supply comparison or hashing functions for keys, +and Berkeley DB stores and retrieves values without +interpreting them. +

+All of the access methods use the host filesystem as a backing store. +

+Hash +

+

+Berkeley DB includes a Hash access method that implements extended +linear hashing [Litw80]. +Extended linear hashing adjusts the hash function as the hash +table grows, attempting to keep all buckets underfull in the steady +state. +

+The Hash access method supports insertion and deletion of records and +lookup by exact match only. Applications may iterate over all records +stored in a table, but the order in which they are returned is undefined. +

+B+tree +

+

+Berkeley DB includes a B+tree [Come79] access method. +B+trees store records of key/value pairs in leaf pages, +and pairs of (key, child page address) at internal nodes. +Keys in the tree are stored in sorted order, +where the order is determined by the comparison function supplied when the +database was created. +Pages at the leaf level of the tree include pointers +to their neighbors to simplify traversal. B+trees support lookup by +exact match (equality) or range (greater than or equal to a key). +Like Hash tables, B+trees support record insertion, +deletion, and iteration over all records in the tree. +

+As records are inserted and pages in the B+tree fill up, they are split, +with about half the keys going into a new peer page at the same level in +the tree. +Most B+tree implementations leave both nodes half-full after a split. +This leads to poor performance in a common case, where the caller inserts +keys in order. +To handle this case, Berkeley DB keeps track of the insertion order, +and splits pages unevenly to keep pages fuller. +This reduces tree size, yielding better search performance and smaller +databases. +

+On deletion, empty pages are coalesced by reverse splits +into single pages. +The access method does no other page balancing on insertion +or deletion. +Keys are not moved among pages at every update +to keep the tree well-balanced. While this could improve search times +in some cases, the additional code complexity leads to slower updates and +is prone to deadlocks. +

+For simplicity, Berkeley DB B+trees do no prefix compression of keys +at internal or leaf nodes. +

+Recno +

+

+Berkeley DB includes a fixed- or variable-length record access method, +called +Recno. +The Recno access method assigns logical record numbers to each +record, +and can search for and update records by record number. +Recno is able, +for example, +to load a text file into a database, +treating each line as a record. +This permits fast searches by line number for applications like +text editors [Ston82]. +

+Recno is actually built +on top of the B+tree access method and provides a simple interface +for storing sequentially-ordered data values. +The Recno access method generates keys internally. +The programmer's view of the values is that +they are numbered sequentially from one. +Developers can choose to have records automatically renumbered +when lower-numbered records are added or deleted. +In this case, new keys can be inserted between existing keys. +

+Features +

+

+This section describes important features of Berkeley DB. +In general, +developers can choose which features are useful to them, +and use only those that are required by their application. +

+For example, +when an application opens a database, it can declare the degree of +concurrency and recovery that it requires. Simple stand-alone applications, +and in particular ports of applications that used +dbm +or one of its +variants, generally do not require concurrent access or crash recovery. +Other applications, such as enterprise-class database management systems +that store sales transactions or other critical data, need full +transactional service. Single-user operation is faster than multi-user +operation, since no overhead is incurred by locking. Running with +the recovery system disabled is faster than running with it enabled, +since log records need not be written when changes are made to the +database. +

+In addition, some core subsystems, including the locking system and +the logging facility, +can be used outside the context of the access methods as well. +Although few users have chosen to do so, it is possible to +use only the lock manager in Berkeley DB to control concurrency +in an application, without using any of the standard database services. +Alternatively, the caller can integrate locking of non-database resources +with Berkeley DB's transactional two-phase locking system, to impose +transaction semantics on objects outside the database. +

+Programmatic interfaces +

+

+Berkeley DB defines a simple API for database management. +The package does not include industry-standard +programmatic interfaces such as Open Database Connectivity (ODBC), +Object Linking and Embedding for Databases (OleDB), or Structured +Query Language (SQL). These interfaces, while useful, were +designed to promote interoperability of database systems, and not +simplicity or performance. +

+In response to customer demand, +Berkeley DB 2.5 introduced support for the XA standard [Open94]. +XA permits Berkeley DB to participate in distributed transactions +under a transaction processing monitor like Tuxedo from BEA Systems. +Like XA, other standard interfaces can be built on top of the +core system. +The standards do not belong inside Berkeley DB, +since not all applications need them. +

+Working with records +

+

+A database user may need to search for particular keys in a database, +or may simply want to browse available records. +Berkeley DB supports both keyed access, +to find one or more records with a given key, +or sequential access, +to retrieve all the records in the database one at a time. +The order of the records returned during sequential scans +depends on the access method. +B+tree and Recno databases return records in sort order, +and Hash databases return them in apparently random order. +

+Similarly, +Berkeley DB defines simple interfaces for inserting, +updating, +and deleting records in a database. +

+Long keys and values +

+

+Berkeley DB manages keys and values as large as +232 bytes. +Since the time required to copy a record is proportional to its size, +Berkeley DB includes interfaces that operate on partial records. +If an application requires only part of a large record, +it requests partial record retrieval, +and receives just the bytes that it needs. +The smaller copy saves both time and memory. +

+Berkeley DB allows the programmer to define the data types of +keys and values. +Developers use any type expressible in the programming language. +

+Large databases +

+

+A single database managed by Berkeley DB can be up to 248 +bytes, +or 256 petabytes, +in size. +Berkeley DB uses the host filesystem as the backing store +for the database, +so large databases require big file support from the operating system. +Sleepycat Software has customers using Berkeley DB +to manage single databases in excess of 100 gigabytes. +

+Main memory databases +

+

+Applications that do not require persistent storage can create +databases that exist only in main memory. +These databases bypass the overhead imposed by the I/O system +altogether. +

+Some applications do need to use disk as a backing store, +but run on machines with very large memory. +Berkeley DB is able to manage very large shared memory regions +for cached data pages, +log records, +and lock management. +For example, +the cache region used for data pages may be gigabytes in size, +reducing the likelihood that any read operation will need to +visit the disk in the steady state. +The programmer declares the size of the cache region at +startup. +

+Finally, many operating systems provide memory-mapped file services +that are much faster than their general-purpose file system +interfaces. +Berkeley DB can memory-map its database files for read-only database use. +The application operates on records stored directly on the pages, +with no cache management overhead. +Because the application gets pointers directly into the +Berkeley DB pages, +writes cannot be permitted. +Otherwise, +changes could bypass the locking and logging systems, +and software errors could corrupt the database. +Read-only applications can use Berkeley DB's memory-mapped +file service to improve performance on most architectures. +

+Configurable page size +

+

+Programmers declare the size of the pages used by their access +methods when they create a database. +Although Berkeley DB provides reasonable defaults, +developers may override them to control system performance. +Small pages reduce the number of records that fit on a single page. +Fewer records on a page means that fewer records are locked when +the page is locked, +improving concurrency. +The per-page overhead is proportionally higher with smaller pages, +of course, +but developers can trade off space for time as an application requires. +

+Small footprint +

+

+Berkeley DB is a compact system. +The full package, including all access methods, recoverability, +and transaction support +is roughly 175K of text space on common architectures. +

+Cursors +

+

+In database terminology, a cursor is a pointer into an access method +that can be called iteratively to return records in sequence. Berkeley +DB includes cursor interfaces for all access methods. This permits, +for example, users to traverse a B+tree and view records in order. +Pointers to records in cursors are persistent, so that once fetched, +a record may be updated in place. Finally, cursors support access to +chains of duplicate data items in the various access methods. +

+Joins +

+

+In database terminology, +a join is an operation that spans multiple separate +tables (or in the case of Berkeley DB, multiple separate DB files). +For example, a company may store information about its customers +in one table and information about sales in another. An application +will likely want to look up sales information by customer name; this +requires matching records in the two tables that share a common +customer ID field. +This combining of records from multiple tables is called a join. +

+Berkeley DB includes interfaces for joining two or more tables. +

+Transactions +

+

+Transactions have four properties [Gray93]: +

    +
  • +They are atomic. That is, all of the changes made in a single +transaction must be applied at the same instant or not at all. +This permits, for example, the transfer of money between two +accounts to be accomplished, by making the reduction of the +balance in one account and the increase in the other into a +single, atomic action. +
  • +
  • +They must be consistent. That is, changes to the database +by any transaction cannot leave the database in an illegal +or corrupt state. +
  • +
  • +They must be isolatable. Regardless of the number of users +working in the database at the same time, every user must have +the illusion that no other activity is going on. +
  • +
  • +They must be durable. Even if the disk that stores the database +is lost, it must be possible to recover the database to its last +transaction-consistent state. +
  • +
+

+This combination of properties -- atomicity, consistency, isolation, and +durability -- is referred to as ACIDity in the literature. Berkeley DB, +like most database systems, provides ACIDity using a collection of core +services. +

+Programmers can choose to use Berkeley DB's transaction services +for applications that need them. +

+Write-ahead logging +

+

+Programmers can enable the logging system when they start up Berkeley DB. +During a transaction, +the application makes a series of changes to the database. +Each change is captured in a log entry, +which holds the state of the database record +both before and after the change. +The log record is guaranteed +to be flushed to stable storage before any of the changed data pages +are written. +This behavior -- writing the log before the data pages -- is called +write-ahead logging. +

+At any time during the transaction, +the application can +commit, +making the changes permanent, +or +roll back, +cancelling all changes and restoring the database to its +pre-transaction state. +If the application +rolls back the transaction, then the log holds the state of all +changed pages prior to the transaction, and Berkeley DB simply +restores that state. +If the application commits the transaction, +Berkeley DB writes the log records to disk. +In-memory copies of the data pages already reflect the changes, +and will be flushed as necessary during normal processing. +Since log writes are sequential, but data page +writes are random, this improves performance. +

+Crashes and recovery +

+

+Berkeley DB's write-ahead log is used by the transaction +system to commit or roll back transactions. +It also gives the recovery system the information that +it needs to protect against data loss or corruption +from crashes. +Berkeley DB is able to survive application crashes, +system crashes, +and even catastrophic failures like the loss of a hard +disk, +without losing any data. +

+Surviving crashes requires data stored in several different places. +During normal processing, +Berkeley DB has copies of active log records and recently-used +data pages in memory. +Log records are flushed to the log disk when transactions commit. +Data pages trickle out to the data disk as pages move through +the buffer cache. +Periodically, +the system administrator backs up the data disk, +creating a safe copy of the database at a particular instant. +When the database is backed up, +the log can be truncated. +For maximum robustness, +the log disk and data disk should be separate devices. +

+Different system failures can destroy memory, +the log disk, +or the data disk. +Berkeley DB is able to survive the loss of any one +of these repositories +without losing any committed transactions. +

+If the computer's memory is lost, +through an application or operating system crash, +then the log holds all committed transactions. +On restart, +the recovery system rolls the log forward against +the database, +reapplying any changes to on-disk pages that were in memory at the +time of the crash. +Since the log contains pre- and post-change state for +transactions, +the recovery system also uses the log to restore any pages to +their original state if they were modified by transactions +that never committed. +

+If the data disk is lost, +the system administrator can restore the most recent copy from backup. +The recovery system will roll the entire log forward against +the original database, +reapplying all committed changes. +When it finishes, +the database will contain every change made by every +transaction that ever committed. +

+If the log disk is lost, +then the recovery system can use the in-memory copies of +log entries to roll back any uncommitted transactions, +flush all in-memory database pages to the data disk, +and shut down gracefully. +At that point, +the system administrator can back up the database disk, +install a new log disk, +and restart the system. +

+Checkpoints +

+

+Berkeley DB includes a checkpointing service that interacts +with the recovery system. +During normal processing, +both the log and the database are changing continually. +At any given instant, +the on-disk versions of the two are not guaranteed to be consistent. +The log probably contains changes that are not yet in the database. +

+When an application makes a +checkpoint, +all committed changes in the log up to that point +are guaranteed to be present on the data disk, +too. +Checkpointing is moderately expensive during normal processing, +but limits the time spent recovering from crashes. +

+After an application or operating system crash, +the recovery system only needs to go back two checkpoints +to start rolling the log forward. +(One checkpoint is not far enough. +The recovery system cannot be sure that the most recent +checkpoint completed -- +it may have been interrupted by the crash that forced the +recovery system to run in the first place.) +Without checkpoints, +there is no way to be sure how long restarting after a crash will take. +With checkpoints, +the restart interval can be fixed by the programmer. +Recovery processing can be guaranteed to complete in a second or two. +

+Software crashes are much more common than disk failures. +Many developers want to guarantee that software bugs do not destroy data, +but are willing to restore from tape, +and to tolerate a day or two of lost work, +in the unlikley event of a disk crash. +With Berkeley DB, +programmers may truncate the log at checkpoints. +As long as the two most recent checkpoints are present, +the recovery system can guarantee that no committed transactions +are lost after a software crash. +In this case, +the recovery system does not require that the log and the +data be on separate devices, +although separating them can still improve performance +by spreading out writes. +

+Two-phase locking +

+

+Berkeley DB provides a service known as two-phase locking. +In order to reduce the likelihood of deadlocks and to guarantee ACID +properties, database systems manage locks in two phases. First, during +the operation of a transaction, they acquire locks, but never release +them. Second, at the end of the transaction, they release locks, but +never acquire them. In practice, most database systems, including Berkeley +DB, acquire locks on demand over the course of the transaction, then +flush the log, then release all locks. +

+Berkeley DB can lock entire database files, which correspond to tables, +or individual pages in them. +It does no record-level locking. +By shrinking the page size, +however, +developers can guarantee that every page holds only a small +number of records. +This reduces contention. +

+If locking is enabled, +then read and write operations on a database acquire two-phase locks, +which are held until the transaction completes. +Which objects are locked and the order of lock acquisition +depend on the workload for each transaction. +It is possible for two or more transactions to deadlock, +so that each is waiting for a lock that is held by another. +

+Berkeley DB detects deadlocks and automatically rolls back +one of the transactions. +This releases the locks that it held +and allows the other transactions to continue. +The caller is notified that its transaction did not complete, +and may restart it. +Developers can specify the deadlock detection interval +and the policy to use in choosing a transaction to roll back. +

+The two-phase locking interfaces are separately callable by applications +that link Berkeley DB, though few users have needed to use that facility +directly. +Using these interfaces, +Berkeley DB provides a fast, +platform-portable locking system for general-purpose use. +It also lets users include non-database objects in a database transaction, +by controlling access to them exactly as if they were inside the database. +

+The Berkeley DB two-phase locking facility is built on the fastest correct +locking primitives that are supported by the underlying architecture. +In the current implementation, this means that the locking system is +different on the various UNIX platforms, and is still more different +on Windows NT. In our experience, the most difficult aspect of performance +tuning is finding the fastest locking primitives that work correctly +on a particular architecture and then integrating the new +interface with the several that we already support. +

+The world would be a better place if the operating systems community +would uniformly implement POSIX locking primitives and would guarantee +that acquiring an uncontested lock was a fast operation. +Locks must work both among threads in a single process +and among processes. +

+Concurrency +

+

+Good performance under concurrent operation is a critical design point +for Berkeley DB. Although Berkeley DB is itself not multi-threaded, +it is thread-safe, and runs well in threaded applications. +Philosophically, +we view the use of threads and the choice of a threads package +as a policy decision, +and prefer to offer mechanism (the ability to run threaded or not), +allowing applications to choose their own policies. +

+The locking, logging, and buffer pool subsystems all use shared memory +or other OS-specific sharing facilities to communicate. Locks, buffer +pool fetches, and log writes behave in the same way across threads in +a single process as they do across different processes on a single +machine. +

+As a result, concurrent database applications may start up a new process +for every single user, may create a single server which spawns a new +thread for every client request, or may choose any policy in between. +

+Berkeley DB has been carefully designed to minimize contention +and maximize concurrency. +The cache manager allows all threads or processes to benefit from +I/O done by one. +Shared resources must sometimes be locked for exclusive access +by one thread of control. +We have kept critical sections small, +and are careful not to hold critical resource locks across +system calls that could deschedule the locking thread or process. +Sleepycat Software has customers with hundreds of concurrent +users working on a single database in production. +

+Engineering Philosophy +

+

+Fundamentally, Berkeley DB is a collection of access methods with +important facilities, like logging, locking, and transactional access +underlying them. In both the research and the commercial world, +the techniques for building systems like Berkeley DB have been well-known +for a long time. +

+The key advantage of Berkeley DB is the careful attention that has been +paid to engineering details throughout its life. We have carefully +designed the system so that the core facilities, like locking and I/O, +surface the right interfaces and are otherwise opaque to the caller. +As programmers, we understand the value of simplicity and have worked +hard to simplify the interfaces we surface to users of the +database system. +

+Berkeley DB avoids limits in the code. It places no practical limit +on the size of keys, values, or databases; they may grow to occupy +the available storage space. +

+The locking and logging subsystems have been carefully crafted to +reduce contention and improve throughput by shrinking or eliminating +critical sections, and reducing the sizes of locked regions and log +entries. +

+There is nothing in the design or implementation of Berkeley DB that +pushes the state of the art in database systems. Rather, we have been +very careful to get the engineering right. The result is a system that +is superior, as an embedded database system, to any other solution +available. +

+Most database systems trade off simplicity for correctness. Either the +system is easy to use, or it supports concurrent use and survives system +failures. Berkeley DB, because of its careful design and implementation, +offers both simplicity and correctness. +

+The system has a small footprint, +makes simple operations simple to carry out (inserting a new record takes +just a few lines of code), and behaves correctly in the face of heavy +concurrent use, system crashes, and even catastrophic failures like loss +of a hard disk. +

+The Berkeley DB 2.x Distribution +

+

+Berkeley DB is distributed in source code form from +www.sleepycat.com. +Users are free to download and build the software, and to use it in +their applications. +

+What is in the distribution +

+

+The distribution is a compressed archive file. +It includes the source code for the Berkeley DB library, +as well as documentation, test suites, and supporting utilities. +

+The source code includes build support for all supported platforms. +On UNIX systems Berkeley DB uses the GNU autoconfiguration tool, +autoconf, +to identify the system and to build the library +and supporting utilities. +Berkeley DB includes specific build environments for other platforms, +such as VMS and Windows. +

+Documentation +

+

+The distributed system includes documentation in HTML format. +The documentation is in two parts: +a UNIX-style reference manual for use by programmers, +and a reference guide which is tutorial in nature. +

+Test suite +

+

+The software also includes a complete test suite, written in Tcl. +We believe that the test suite is a key advantage of Berkeley DB +over comparable systems. +

+First, the test suite allows users who download and build the software +to be sure that it is operating correctly. +

+Second, the test suite allows us, like other commercial developers +of database software, to exercise the system thoroughly at every +release. When we learn of new bugs, we add them to the test suite. +We run the test suite continually during development cycles, and +always prior to release. The result is a much more reliable system +by the time it reaches beta release. +

+Binary distribution +

+

+Sleepycat makes compiled libraries and general binary distributions available +to customers for a fee. +

+Supported platforms +

+

+Berkeley DB runs on any operating system with a +POSIX 1003.1 interface [IEEE96], +which includes virtually every UNIX system. +In addition, +the software runs on VMS, +Windows/95, +Windows/98, +and Windows/NT. +Sleepycat Software no longer supports deployment on sixteen-bit +Windows systems. +

+Berkeley DB 2.x Licensing +

+

+Berkeley DB 2.x is distributed as an Open Source product. The software +is freely available from us at our Web site, and in other media. Users +are free to download the software and build applications with it. +

+The 1.x versions of Berkeley DB were covered by the UC Berkeley copyright +that covers software freely redistributable in source form. When +Sleepycat Software was formed, we needed to draft a license consistent +with the copyright governing the existing, older software. Because +of important differences between the UC Berkeley copyright and the GPL, +it was impossible for us to use the GPL. +A second copyright, with +terms contradictory to the first, simply would not have worked. +

+Sleepycat wanted to continue Open Source development of Berkeley DB +for several reasons. +We agree with Raymond [Raym98] and others that Open +Source software is typically of higher quality than proprietary, +binary-only products. +Our customers benefit from a community of developers who +know and use Berkeley DB, +and can help with application design, +debugging, +and performance tuning. +Widespread distribution and use of the source code tends to +isolate bugs early, +and to get fixes back into the distributed system quickly. +As a result, +Berkeley DB is more reliable. +Just as importantly, +individual users are able to contribute new features +and performance enhancements, +to the benefit of everyone who uses Berkeley DB. +From a business perspective, +Open Source and free distribution of the +software creates share for us, and gives us a market into which +we can sell products and services. +Finally, making the source code +freely available reduces our support load, since customers can +find and fix bugs without recourse to us, in many cases. +

+To preserve the Open Source heritage of the older Berkeley DB code, +we drafted a new license governing the distribution of Berkeley DB +2.x. We adopted terms from the GPL that make it impossible to +turn our Open Source code into proprietary code owned by someone else. +

+Briefly, the terms governing the use and distribution of Berkeley DB +are: +

    +
  • +your application must be internal to your site, or +
  • +
  • +your application must be freely redistributable in source form, or +
  • +
  • +you must get a license from us. +
  • +
+

+For customers who prefer not to distribute Open Source products, +we sell licenses to use and extend Berkeley DB at a reasonable cost. +

+We work hard to accommodate the needs of the Open Source community. +For example, +we have crafted special licensing arrangements with Gnome +to encourage its use and distribution of Berkeley DB. +

+Berkeley DB conforms to the Open Source definition [Open99]. +The license has +been carefully crafted to keep the product available as an Open Source +offering, +while providing enough of a return on our investment to fund continued +development and support of the product. The current license has +created a business capable of funding three years of development on +the software that simply would not have happened otherwise. +

+Summary +

+

+Berkeley DB offers a unique collection of features, targeted squarely +at software developers who need simple, reliable database management +services in their applications. Good design and implementation and +careful engineering throughout make the software better than many +other systems. +

+Berkeley DB is an Open Source product, available at +www.sleepycat.com. +for download. The distributed system includes everything needed to +build and deploy the software or to port it to new systems. +

+Sleepycat Software distributes Berkeley DB under a license agreement +that draws on both the UC Berkeley copyright and the GPL. The license +guarantees that Berkeley DB will remain an Open Source product and +provides Sleepycat with opportunities to make money to fund continued +development on the software. +

+References +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
[Come79] +

+Comer, D., +"The Ubiquitous B-tree," +ACM Computing Surveys +Volume 11, number 2, +June 1979. +

+[Gray93] + +

+Gray, J., and Reuter, A., +Transaction Processing: Concepts and Techniques, +Morgan-Kaufman Publishers, +1993. +

+[IEEE96] + +

+Institute for Electrical and Electronics Engineers, +IEEE/ANSI Std 1003.1, +1996 Edition. +

+[Litw80] + +

+Litwin, W., +"Linear Hashing: A New Tool for File and Table Addressing," +Proceedings of the 6th International Conference on Very Large Databases (VLDB), +Montreal, Quebec, Canada, +October 1980. +

+[Open94] + +

+The Open Group, +Distributed TP: The XA+ Specification, Version 2, +The Open Group, 1994. +

+[Open99] + +

+Opensource.org, +"Open Source Definition," +www.opensource.org/osd.html, +version 1.4, +1999. +

+[Raym98] + +

+Raymond, E.S., +"The Cathedral and the Bazaar," + +www.tuxedo.org/~esr/writings/cathedral-bazaar/cathedral-bazaar.html, +January 1998. +

+[Selt91] + +

+Seltzer, M., and Yigit, O., +"A New Hashing Package for UNIX," +Proceedings 1991 Winter USENIX Conference, +Dallas, TX, +January 1991. +

+[Selt92] + +

+Seltzer, M., and Olson, M., +"LIBTP: Portable Modular Transactions for UNIX," +Proceedings 1992 Winter Usenix Conference +San Francisco, CA, +January 1992.] +

+[Ston82] + +

+Stonebraker, M., Stettner, H., Kalash, J., Guttman, A., and Lynn, N., +"Document Processing in a Relational Database System," +Memorandum No. UCB/ERL M82/32, +University of California at Berkeley, +Berkeley, CA, +May 1982. +

+ + diff --git a/db/docs/ref/refs/bdb_usenix.ps b/db/docs/ref/refs/bdb_usenix.ps new file mode 100644 index 000000000..82e678971 --- /dev/null +++ b/db/docs/ref/refs/bdb_usenix.ps @@ -0,0 +1,1441 @@ +%!PS-Adobe-3.0 +%%Creator: groff version 1.11 +%%CreationDate: Mon Apr 26 13:38:12 1999 +%%DocumentNeededResources: font Times-Bold +%%+ font Times-Roman +%%+ font Times-Italic +%%+ font Courier +%%DocumentSuppliedResources: procset grops 1.11 0 +%%Pages: 9 +%%PageOrder: Ascend +%%Orientation: Portrait +%%EndComments +%%BeginProlog +%%BeginResource: procset grops 1.11 0 +/setpacking where{ +pop +currentpacking +true setpacking +}if +/grops 120 dict dup begin +/SC 32 def +/A/show load def +/B{0 SC 3 -1 roll widthshow}bind def +/C{0 exch ashow}bind def +/D{0 exch 0 SC 5 2 roll awidthshow}bind def +/E{0 rmoveto show}bind def +/F{0 rmoveto 0 SC 3 -1 roll widthshow}bind def +/G{0 rmoveto 0 exch ashow}bind def +/H{0 rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def +/I{0 exch rmoveto show}bind def +/J{0 exch rmoveto 0 SC 3 -1 roll widthshow}bind def +/K{0 exch rmoveto 0 exch ashow}bind def +/L{0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def +/M{rmoveto show}bind def +/N{rmoveto 0 SC 3 -1 roll widthshow}bind def +/O{rmoveto 0 exch ashow}bind def +/P{rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def +/Q{moveto show}bind def +/R{moveto 0 SC 3 -1 roll widthshow}bind def +/S{moveto 0 exch ashow}bind def +/T{moveto 0 exch 0 SC 5 2 roll awidthshow}bind def +/SF{ +findfont exch +[exch dup 0 exch 0 exch neg 0 0]makefont +dup setfont +[exch/setfont cvx]cvx bind def +}bind def +/MF{ +findfont +[5 2 roll +0 3 1 roll +neg 0 0]makefont +dup setfont +[exch/setfont cvx]cvx bind def +}bind def +/level0 0 def +/RES 0 def +/PL 0 def +/LS 0 def +/MANUAL{ +statusdict begin/manualfeed true store end +}bind def +/PLG{ +gsave newpath clippath pathbbox grestore +exch pop add exch pop +}bind def +/BP{ +/level0 save def +1 setlinecap +1 setlinejoin +72 RES div dup scale +LS{ +90 rotate +}{ +0 PL translate +}ifelse +1 -1 scale +}bind def +/EP{ +level0 restore +showpage +}bind def +/DA{ +newpath arcn stroke +}bind def +/SN{ +transform +.25 sub exch .25 sub exch +round .25 add exch round .25 add exch +itransform +}bind def +/DL{ +SN +moveto +SN +lineto stroke +}bind def +/DC{ +newpath 0 360 arc closepath +}bind def +/TM matrix def +/DE{ +TM currentmatrix pop +translate scale newpath 0 0 .5 0 360 arc closepath +TM setmatrix +}bind def +/RC/rcurveto load def +/RL/rlineto load def +/ST/stroke load def +/MT/moveto load def +/CL/closepath load def +/FL{ +currentgray exch setgray fill setgray +}bind def +/BL/fill load def +/LW/setlinewidth load def +/RE{ +findfont +dup maxlength 1 index/FontName known not{1 add}if dict begin +{ +1 index/FID ne{def}{pop pop}ifelse +}forall +/Encoding exch def +dup/FontName exch def +currentdict end definefont pop +}bind def +/DEFS 0 def +/EBEGIN{ +moveto +DEFS begin +}bind def +/EEND/end load def +/CNT 0 def +/level1 0 def +/PBEGIN{ +/level1 save def +translate +div 3 1 roll div exch scale +neg exch neg exch translate +0 setgray +0 setlinecap +1 setlinewidth +0 setlinejoin +10 setmiterlimit +[]0 setdash +/setstrokeadjust where{ +pop +false setstrokeadjust +}if +/setoverprint where{ +pop +false setoverprint +}if +newpath +/CNT countdictstack def +userdict begin +/showpage{}def +}bind def +/PEND{ +clear +countdictstack CNT sub{end}repeat +level1 restore +}bind def +end def +/setpacking where{ +pop +setpacking +}if +%%EndResource +%%IncludeResource: font Times-Bold +%%IncludeResource: font Times-Roman +%%IncludeResource: font Times-Italic +%%IncludeResource: font Courier +grops begin/DEFS 1 dict def DEFS begin/u{.001 mul}bind def end/RES 72 +def/PL 792 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron/Zcaron +/scaron/zcaron/Ydieresis/trademark/quotesingle/.notdef/.notdef/.notdef +/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef +/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef +/.notdef/.notdef/space/exclam/quotedbl/numbersign/dollar/percent +/ampersand/quoteright/parenleft/parenright/asterisk/plus/comma/hyphen +/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon +/semicolon/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O +/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright/circumflex +/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y +/z/braceleft/bar/braceright/tilde/.notdef/quotesinglbase/guillemotleft +/guillemotright/bullet/florin/fraction/perthousand/dagger/daggerdbl +/endash/emdash/ff/fi/fl/ffi/ffl/dotlessi/dotlessj/grave/hungarumlaut +/dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash +/quotedblbase/OE/Lslash/.notdef/exclamdown/cent/sterling/currency/yen +/brokenbar/section/dieresis/copyright/ordfeminine/guilsinglleft +/logicalnot/minus/registered/macron/degree/plusminus/twosuperior +/threesuperior/acute/mu/paragraph/periodcentered/cedilla/onesuperior +/ordmasculine/guilsinglright/onequarter/onehalf/threequarters +/questiondown/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE +/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex +/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis +/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn +/germandbls/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla +/egrave/eacute/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis +/eth/ntilde/ograve/oacute/ocircumflex/otilde/odieresis/divide/oslash +/ugrave/uacute/ucircumflex/udieresis/yacute/thorn/ydieresis]def +/Courier@0 ENC0/Courier RE/Times-Italic@0 ENC0/Times-Italic RE +/Times-Roman@0 ENC0/Times-Roman RE/Times-Bold@0 ENC0/Times-Bold RE +%%EndProlog +%%Page: 1 1 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 14/Times-Bold@0 SF(Berk)275.358 100.8 Q(eley DB)-.14 E/F1 12 +/Times-Roman@0 SF(Michael A. Olson)270.372 129.6 Q -.3(Ke)283.182 144 S +(ith Bostic).3 E(Mar)279.15 158.4 Q(go Seltzer)-.216 E/F2 12 +/Times-Italic@0 SF(Sleepycat Softwar)255.492 174.24 Q .24 -.12(e, I) +-.444 H(nc.).12 E/F3 12/Times-Bold@0 SF(Abstract)290.874 210.24 Q/F4 10 +/Times-Roman@0 SF(Berk)79.2 226.44 Q(ele)-.1 E 2.925(yD)-.15 G 2.925(Bi) +-2.925 G 2.924(sa)-2.925 G 2.924(nO)-2.924 G .424 +(pen Source embedded database system with a number of k)-2.924 F .724 +-.15(ey a)-.1 H(dv).15 E .424(antages o)-.25 F -.15(ve)-.15 G 2.924(rc) +.15 G .424(omparable sys-)-2.924 F 3.102(tems. It)79.2 238.44 R .602(is simple to use, supports concurrent access by multiple users, and pro) +3.102 F .602(vides industrial-strength transaction)-.15 F 1.555 +(support, including survi)79.2 250.44 R 1.555 +(ving system and disk crashes.)-.25 F 1.554 +(This paper describes the design and technical features of)6.555 F(Berk) +79.2 262.44 Q(ele)-.1 E 2.5(yD)-.15 G(B, the distrib)-2.5 E +(ution, and its license.)-.2 E F3 3(1. Intr)79.2 286.44 R(oduction)-.216 +E F4 .691(The Berk)79.2 302.64 R(ele)-.1 E 3.191(yD)-.15 G .691 +(atabase \(Berk)-3.191 F(ele)-.1 E 3.191(yD)-.15 G .692 +(B\) is an embedded)-3.191 F .253 +(database system that can be used in applications requir)79.2 314.64 R +(-)-.2 E 1.636(ing high-performance concurrent storage and retrie)79.2 +326.64 R -.25(va)-.25 G(l).25 E 2.619(of k)79.2 338.64 R -.15(ey)-.1 G +(/v).15 E 2.619(alue pairs.)-.25 F 2.619(The softw)7.619 F 2.619 +(are is distrib)-.1 F 2.618(uted as a)-.2 F .057 +(library that can be link)79.2 350.64 R .058 +(ed directly into an application.)-.1 F(It)5.058 E(pro)79.2 362.64 Q +1.454(vides a v)-.15 F 1.453(ariety of programmatic interf)-.25 F 1.453 +(aces, includ-)-.1 F .237 +(ing callable APIs for C, C++, Perl, Tcl and Ja)79.2 374.64 R -.25(va) +-.2 G 5.237(.U).25 G(sers)-5.237 E .327(may do)79.2 386.64 R .327 +(wnload Berk)-.25 F(ele)-.1 E 2.827(yD)-.15 G 2.827(Bf)-2.827 G .326 +(rom Sleep)-2.827 F .326(ycat Softw)-.1 F(are')-.1 E(s)-.55 E -.8(We) +79.2 398.64 S 2.5(bs).8 G(ite, at)-2.5 E/F5 10/Times-Italic@0 SF(www)2.5 +E(.sleepycat.com)-.74 E F4(.)A(Sleep)79.2 414.84 Q 1.33(ycat distrib)-.1 +F 1.33(utes Berk)-.2 F(ele)-.1 E 3.83(yD)-.15 G 3.83(Ba)-3.83 G 3.83(sa) +-3.83 G 3.83(nO)-3.83 G 1.33(pen Source)-3.83 F 3.3(product. The)79.2 +426.84 R(compan)3.3 E 3.3(yc)-.15 G .8(ollects license fees for certain) +-3.3 F(uses of the softw)79.2 438.84 Q +(are and sells support and services.)-.1 E F3 3(1.1. History)79.2 468.84 +R F4(Berk)79.2 485.04 Q(ele)-.1 E 3.057(yD)-.15 G 3.057(Bb)-3.057 G +-2.25 -.15(eg a)-3.057 H 3.058(na).15 G 3.058(san)-3.058 G 1.058 -.25 +(ew i)-3.058 H .558(mplementation of a hash).25 F .843 +(access method to replace both)79.2 497.04 R/F6 10/Courier@0 SF(hsearch) +3.342 E F4 .842(and the v)3.342 F(ari-)-.25 E(ous)79.2 509.04 Q F6(dbm) +5.466 E F4 2.967(implementations \()5.466 F F6(dbm)A F4 2.967(from A) +5.467 F(T&T)-1.11 E(,)-.74 E F6(ndbm)5.467 E F4 1.334(from Berk)79.2 +521.04 R(ele)-.1 E 2.634 -.65(y, a)-.15 H(nd).65 E F6(gdbm)3.834 E F4 +1.334(from the GNU project\).)3.834 F(In)6.333 E .367 +(1990 Seltzer and Y)79.2 533.04 R .368 +(igit produced a package called Hash)-.55 F(to do this [Selt91].)79.2 +545.04 Q 3.106(The \214rst general release of Berk)79.2 561.24 R(ele)-.1 +E 5.606(yD)-.15 G 3.106(B, in 1991,)-5.606 F 3.038(included some interf) +79.2 573.24 R 3.039(ace changes and a ne)-.1 F 5.539(wB)-.25 G(+tree) +-5.539 E .887(access method.)79.2 585.24 R .886 +(At roughly the same time, Seltzer and)5.887 F 1.201(Olson de)79.2 +597.24 R -.15(ve)-.25 G 1.202 +(loped a prototype transaction system based).15 F 3.356(on Berk)79.2 +609.24 R(ele)-.1 E 5.856(yD)-.15 G 3.356(B, called LIBTP [Selt92], b) +-5.856 F 3.355(ut ne)-.2 F -.15(ve)-.25 G(r).15 E(released the code.) +79.2 621.24 Q .653(The 4.4BSD UNIX release included Berk)79.2 637.44 R +(ele)-.1 E 3.153(yD)-.15 G 3.153(B1)-3.153 G(.85)-3.153 E .602(in 1992.) +79.2 649.44 R .601(Seltzer and Bostic maintained the code in the)5.601 F +1.545(early 1990s in Berk)79.2 661.44 R(ele)-.1 E 4.046(ya)-.15 G 1.546 +(nd in Massachusetts.)-4.046 F(Man)6.546 E(y)-.15 E +(users adopted the code during this period.)79.2 673.44 Q .432 +(By mid-1996, users w)79.2 689.64 R .431 +(anted commercial support for the)-.1 F(softw)79.2 701.64 Q 7.033 +(are. In)-.1 F 4.533(response, Bostic and Seltzer formed)7.033 F(Sleep) +79.2 713.64 Q 10.128(ycat Softw)-.1 F 12.628(are. The)-.1 F(compan) +12.627 E 15.127(ye)-.15 G(nhances,)-15.127 E(distrib)323.2 286.44 Q +1.623(utes, and supports Berk)-.2 F(ele)-.1 E 4.123(yD)-.15 G 4.124(Ba) +-4.123 G 1.624(nd supporting)-4.124 F(softw)323.2 298.44 Q 2.2 +(are and documentation.)-.1 F(Sleep)7.2 E 2.2(ycat released v)-.1 F(er) +-.15 E(-)-.2 E 1.677(sion 2.1 of Berk)323.2 310.44 R(ele)-.1 E 4.177(yD) +-.15 G 4.178(Bi)-4.177 G 4.178(nm)-4.178 G 1.678(id-1997 with important) +-4.178 F(ne)323.2 322.44 Q 2.56(wf)-.25 G .06 +(eatures, including support for concurrent access to)-2.56 F 4.176 +(databases. The)323.2 334.44 R(compan)4.176 E 4.177(ym)-.15 G(ak)-4.177 +E 1.677(es about three commer)-.1 F(-)-.2 E .958(cial releases a year) +323.2 346.44 R 3.458(,a)-.4 G .957(nd most recently shipped v)-3.458 F +(ersion)-.15 E(2.8.)323.2 358.44 Q F3 3(1.2. Ov)323.2 388.44 R(er)-.12 E +(view of Berk)-.12 E(eley DB)-.12 E F4 3.094(The C interf)323.2 404.64 R +3.094(aces in Berk)-.1 F(ele)-.1 E 5.594(yD)-.15 G 5.595(Bp)-5.594 G +(ermit)-5.595 E F6(dbm)5.595 E F4(-style)A 4.586 +(record management for databases, with signi\214cant)323.2 416.64 R -.15 +(ex)323.2 428.64 S 1.273(tensions to handle duplicate data items ele).15 +F -.05(ga)-.15 G(ntly).05 E 3.773(,t)-.65 G(o)-3.773 E 2.427 +(deal with concurrent access, and to pro)323.2 440.64 R 2.427 +(vide transac-)-.15 F .71 +(tional support so that multiple changes can be simulta-)323.2 452.64 R +1.273(neously committed \(so that the)323.2 464.64 R 3.773(ya)-.15 G +1.273(re made permanent\))-3.773 F 1.848 +(or rolled back \(so that the database is restored to its)323.2 476.64 R +(state at the be)323.2 488.64 Q(ginning of the transaction\).)-.15 E +1.034(C++ and Ja)323.2 504.84 R 1.534 -.25(va i)-.2 H(nterf).25 E 1.033 +(aces pro)-.1 F 1.033(vide a small set of classes)-.15 F 1.961 +(for operating on a database.)323.2 516.84 R 1.961 +(The main class in both)6.961 F .587(cases is called)323.2 528.84 R F6 +(Db)3.086 E F4 3.086(,a)C .586(nd pro)-3.086 F .586 +(vides methods that encapsu-)-.15 F 1.128(late the)323.2 540.84 R F6 +(dbm)3.628 E F4 1.129(-style interf)B 1.129(aces that the C interf)-.1 F +1.129(aces pro-)-.1 F(vide.)323.2 552.84 Q 2.565(Tcl and Perl interf) +323.2 569.04 R 2.564(aces allo)-.1 F 5.064(wd)-.25 G -2.15 -.25(ev e) +-5.064 H 2.564(lopers w).25 F 2.564(orking in)-.1 F 1.716 +(those languages to use Berk)323.2 581.04 R(ele)-.1 E 4.216(yD)-.15 G +4.216(Bi)-4.216 G 4.217(nt)-4.216 G 1.717(heir applica-)-4.217 F 3.419 +(tions. Bindings)323.2 593.04 R .919 +(for both languages are included in the)3.419 F(distrib)323.2 605.04 Q +(ution.)-.2 E(De)323.2 621.24 Q -.15(ve)-.25 G 1.069 +(lopers may compile their applications and link in).15 F(Berk)323.2 +633.24 Q(ele)-.1 E 2.5(yD)-.15 G 2.5(Bs)-2.5 G(tatically or dynamically) +-2.5 E(.)-.65 E F3 3(1.3. Ho)323.2 663.24 R 3(wB)-.12 G(erk)-3 E +(eley DB is used)-.12 E F4 .655(The Berk)323.2 679.44 R(ele)-.1 E 3.155 +(yD)-.15 G 3.154(Bl)-3.155 G .654(ibrary supports concurrent access to) +-3.154 F 5.115(databases. It)323.2 691.44 R 2.616(can be link)5.115 F +2.616(ed into standalone applica-)-.1 F 1.487 +(tions, into a collection of cooperating applications, or)323.2 703.44 R +4.21(into serv)323.2 715.44 R 4.21 +(ers that handle requests and do database)-.15 F EP +%%Page: 2 2 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF(operations on behalf of clients.)79.2 84 Q .858 +(Compared to using a standalone database management)79.2 100.2 R .846 +(system, Berk)79.2 112.2 R(ele)-.1 E 3.346(yD)-.15 G 3.346(Bi)-3.346 G +3.346(se)-3.346 G .846(asy to understand and simple)-3.346 F 3.826 +(to use.)79.2 124.2 R 3.826(The softw)8.826 F 3.826 +(are stores and retrie)-.1 F -.15(ve)-.25 G 6.325(sr).15 G(ecords,) +-6.325 E 2.77(which consist of k)79.2 136.2 R -.15(ey)-.1 G(/v).15 E +2.77(alue pairs.)-.25 F -2.15 -.25(Ke y)7.77 H 5.27(sa).25 G 2.77 +(re used to)-5.27 F .698(locate items and can be an)79.2 148.2 R 3.198 +(yd)-.15 G .698(ata type or structure sup-)-3.198 F +(ported by the programming language.)79.2 160.2 Q .813 +(The programmer can pro)79.2 176.4 R .813(vide the functions that Berk) +-.15 F(e-)-.1 E(le)79.2 188.4 Q 3.264(yD)-.15 G 3.264(Bu)-3.264 G .763 +(ses to operate on k)-3.264 F -.15(ey)-.1 G 3.263(s. F).15 F .763(or e) +-.15 F .763(xample, B+trees)-.15 F 1.72 +(can use a custom comparison function, and the Hash)79.2 200.4 R .519 +(access method can use a custom hash function.)79.2 212.4 R(Berk)5.518 E +(e-)-.1 E(le)79.2 224.4 Q 5.222(yD)-.15 G 5.222(Bu)-5.222 G 2.722 +(ses def)-5.222 F 2.723(ault functions if none are supplied.)-.1 F .873 +(Otherwise, Berk)79.2 236.4 R(ele)-.1 E 3.373(yD)-.15 G 3.373(Bd)-3.373 +G .873(oes not e)-3.373 F .873(xamine or interpret)-.15 F .934(either k) +79.2 248.4 R -.15(ey)-.1 G 3.434(so).15 G 3.434(rv)-3.434 G .934 +(alues in an)-3.684 F 3.434(yw)-.15 G(ay)-3.534 E 5.934(.V)-.65 G .934 +(alues may be arbi-)-7.044 F(trarily long.)79.2 260.4 Q .69 +(It is also important to understand what Berk)79.2 276.6 R(ele)-.1 E +3.19(yD)-.15 G 3.19(Bi)-3.19 G(s)-3.19 E 4.365(not. It)79.2 288.6 R +1.865(is not a database serv)4.365 F 1.866(er that handles netw)-.15 F +(ork)-.1 E 2.797(requests. It)79.2 300.6 R .297 +(is not an SQL engine that e)2.797 F -.15(xe)-.15 G .296(cutes queries.) +.15 F 1.547(It is not a relational or object-oriented database man-)79.2 +312.6 R(agement system.)79.2 324.6 Q 1.101(It is possible to b)79.2 +340.8 R 1.101(uild an)-.2 F 3.601(yo)-.15 G 3.601(ft)-3.601 G 1.101 +(hose on top of Berk)-3.601 F(ele)-.1 E(y)-.15 E 2.116(DB, b)79.2 352.8 +R 2.116(ut the package, as distrib)-.2 F 2.117(uted, is an embedded)-.2 +F 1.444(database engine.)79.2 364.8 R 1.444 +(It has been designed to be portable,)6.444 F(small, f)79.2 376.8 Q +(ast, and reliable.)-.1 E/F1 12/Times-Bold@0 SF 3(1.4. A)79.2 406.8 R +(pplications that use Berk)-.3 E(eley DB)-.12 E F0(Berk)79.2 423 Q(ele) +-.1 E 4.248(yD)-.15 G 4.248(Bi)-4.248 G 4.249(se)-4.248 G 1.749 +(mbedded in a v)-4.249 F 1.749(ariety of proprietary)-.25 F 3.84 +(and Open Source softw)79.2 435 R 3.84(are packages.)-.1 F 3.84 +(This section)8.84 F(highlights a fe)79.2 447 Q 2.5(wo)-.25 G 2.5(ft) +-2.5 G(he products that use it.)-2.5 E 1.467(Directory serv)79.2 463.2 R +1.467(ers, which do data storage and retrie)-.15 F -.25(va)-.25 G(l).25 +E 2.823(using the Local Directory Access Protocol \(LD)79.2 475.2 R +(AP\),)-.4 E(pro)79.2 487.2 Q .956 +(vide naming and directory lookup service on local-)-.15 F 2.837 +(area netw)79.2 499.2 R 5.337(orks. This)-.1 F 2.837 +(service is, essentially)5.337 F 5.336(,d)-.65 G(atabase)-5.336 E .039 +(query and update, b)79.2 511.2 R .039 +(ut uses a simple protocol rather than)-.2 F 2.202(SQL or ODBC.)79.2 +523.2 R(Berk)7.201 E(ele)-.1 E 4.701(yD)-.15 G 4.701(Bi)-4.701 G 4.701 +(st)-4.701 G 2.201(he embedded data)-4.701 F 1.288 +(manager in the majority of deplo)79.2 535.2 R 1.289(yed directory serv) +-.1 F(ers)-.15 E(today)79.2 547.2 Q 4.855(,i)-.65 G 2.355(ncluding LD) +-4.855 F 2.355(AP serv)-.4 F 2.355(ers from Netscape, Mes-)-.15 F +(sageDirect \(formerly Isode\), and others.)79.2 559.2 Q(Berk)79.2 575.4 +Q(ele)-.1 E 4.385(yD)-.15 G 4.385(Bi)-4.385 G 4.385(sa)-4.385 G 1.886 +(lso embedded in a lar)-4.385 F 1.886(ge number of)-.18 F 5.302 +(mail serv)79.2 587.4 R 7.802(ers. Intermail,)-.15 F 5.302(from Softw) +7.802 F 5.302(are.com, uses)-.1 F(Berk)79.2 599.4 Q(ele)-.1 E 4.613(yD) +-.15 G 4.613(Ba)-4.613 G 4.613(sam)-4.613 G 2.114 +(essage store and as the backing)-4.613 F 3.597 +(store for its directory serv)79.2 611.4 R(er)-.15 E 8.597(.T)-.55 G +3.597(he sendmail serv)-8.597 F(er)-.15 E 1.175 +(\(including both the commercial Sendmail Pro of)79.2 623.4 R(fering) +-.25 E 3.283(from Sendmail, Inc. and the v)79.2 635.4 R 3.283 +(ersion distrib)-.15 F 3.282(uted by)-.2 F(sendmail.or)79.2 647.4 Q +2.304(g\) uses Berk)-.18 F(ele)-.1 E 4.804(yD)-.15 G 4.804(Bt)-4.804 G +4.804(os)-4.804 G 2.305(tore aliases and)-4.804 F 9.01 +(other information.)79.2 659.4 R(Similarly)14.01 E 11.51(,P)-.65 G 9.01 +(ost\214x \(formerly)-11.51 F 3.465(VMailer\) uses Berk)79.2 671.4 R +(ele)-.1 E 5.965(yD)-.15 G 5.965(Bt)-5.965 G 5.965(os)-5.965 G 3.465 +(tore administrati)-5.965 F -.15(ve)-.25 G(information.)79.2 683.4 Q +.134(In addition, Berk)79.2 699.6 R(ele)-.1 E 2.634(yD)-.15 G 2.633(Bi) +-2.634 G 2.633(se)-2.633 G .133(mbedded in a wide v)-2.633 F(ariety)-.25 +E 4.994(of other softw)79.2 711.6 R 4.994(are products.)-.1 F 4.994 +(Example applications)9.994 F .373 +(include managing access control lists, storing user k)323.2 84 R -.15 +(ey)-.1 G(s).15 E 2.75(in a public-k)323.2 96 R 3.05 -.15(ey i)-.1 H +2.75(nfrastructure, recording machine-to-).15 F(netw)323.2 108 Q .519 +(ork-address mappings in address serv)-.1 F .518(ers, and stor)-.15 F(-) +-.2 E .411(ing con\214guration and de)323.2 120 R .412 +(vice information in video post-)-.25 F(production softw)323.2 132 Q +(are.)-.1 E(Finally)323.2 148.2 Q 4.978(,B)-.65 G(erk)-4.978 E(ele)-.1 E +4.978(yD)-.15 G 4.978(Bi)-4.978 G 4.978(sap)-4.978 G 2.478(art of man) +-4.978 F 4.977(yo)-.15 G 2.477(ther Open)-4.977 F .005(Source softw) +323.2 160.2 R .005(are packages a)-.1 F -.25(va)-.2 G .006 +(ilable on the Internet.).25 F -.15(Fo)5.006 G(r).15 E -.15(ex)323.2 +172.2 S .604(ample, the softw).15 F .604 +(are is embedded in the Apache W)-.1 F(eb)-.8 E(serv)323.2 184.2 Q +(er and the Gnome desktop.)-.15 E F1 3(2. Access)323.2 214.2 R(Methods)3 +E F0 .828(In database terminology)323.2 230.4 R 3.329(,a)-.65 G 3.329 +(na)-3.329 G .829(ccess method is the disk-)-3.329 F 1.964 +(based structure used to store data and the operations)323.2 242.4 R -.2 +(av)323.2 254.4 S 6.053(ailable on that structure.)-.05 F -.15(Fo)11.053 +G 8.554(re).15 G 6.054(xample, man)-8.704 F(y)-.15 E 3.853 +(database systems support a B+tree access method.)323.2 266.4 R 1.203 +(B+trees allo)323.2 278.4 R 3.703(we)-.25 G 1.203 +(quality-based lookups \(\214nd k)-3.703 F -.15(ey)-.1 G 3.704(se).15 G +(qual)-3.704 E 4(to some constant\), range-based lookups \(\214nd k) +323.2 290.4 R -.15(ey)-.1 G(s).15 E 1.188(between tw)323.2 302.4 R 3.688 +(oc)-.1 G 1.189(onstants\) and record insertion and dele-)-3.688 F +(tion.)323.2 314.4 Q(Berk)323.2 330.6 Q(ele)-.1 E 4.729(yD)-.15 G 4.729 +(Bs)-4.729 G 2.228(upports three access methods: B+tree,)-4.729 F 1.553 +(Extended Linear Hashing \(Hash\), and Fix)323.2 342.6 R 1.553(ed- or V) +-.15 F(ari-)-1.11 E 3.639(able-length Records \(Recno\).)323.2 354.6 R +3.638(All three operate on)8.638 F 1.956(records composed of a k)323.2 +366.6 R 2.256 -.15(ey a)-.1 H 1.956(nd a data v).15 F 4.456(alue. In) +-.25 F(the)4.456 E 1.301(B+tree and Hash access methods, k)323.2 378.6 R +-.15(ey)-.1 G 3.801(sc).15 G 1.301(an ha)-3.801 F 1.601 -.15(ve a)-.2 H +(rbi-).15 E 3.595(trary structure.)323.2 390.6 R 3.596 +(In the Recno access method, each)8.595 F .266 +(record is assigned a record number)323.2 402.6 R 2.765(,w)-.4 G .265 +(hich serv)-2.765 F .265(es as the)-.15 F -.1(ke)323.2 414.6 S 4.106 +-.65(y. I)-.05 H 2.806(na).65 G .306(ll the access methods, the v)-2.806 +F .306(alue can ha)-.25 F .606 -.15(ve a)-.2 H(rbi-).15 E 1.417 +(trary structure.)323.2 426.6 R 1.417 +(The programmer can supply compari-)6.417 F 2.129 +(son or hashing functions for k)323.2 438.6 R -.15(ey)-.1 G 2.129 +(s, and Berk).15 F(ele)-.1 E 4.629(yD)-.15 G(B)-4.629 E +(stores and retrie)323.2 450.6 Q -.15(ve)-.25 G 2.5(sv).15 G +(alues without interpreting them.)-2.75 E 1.069 +(All of the access methods use the host \214lesystem as a)323.2 466.8 R +(backing store.)323.2 478.8 Q F1 3(2.1. Hash)323.2 508.8 R F0(Berk)323.2 +525 Q(ele)-.1 E 6.485(yD)-.15 G 6.485(Bi)-6.485 G 3.986 +(ncludes a Hash access method that)-6.485 F 9.863(implements e)323.2 537 +R 9.862(xtended linear hashing [Litw80].)-.15 F .017 +(Extended linear hashing adjusts the hash function as the)323.2 549 R +.507(hash table gro)323.2 561 R .506(ws, attempting to k)-.25 F .506 +(eep all b)-.1 F(uck)-.2 E .506(ets under)-.1 F(-)-.2 E +(full in the steady state.)323.2 573 Q 1.649 +(The Hash access method supports insertion and dele-)323.2 589.2 R .259 +(tion of records and lookup by e)323.2 601.2 R .259(xact match only)-.15 +F 5.258(.A)-.65 G(ppli-)-5.258 E .038(cations may iterate o)323.2 613.2 +R -.15(ve)-.15 G 2.538(ra).15 G .038(ll records stored in a table, b) +-2.538 F(ut)-.2 E(the order in which the)323.2 625.2 Q 2.5(ya)-.15 G +(re returned is unde\214ned.)-2.5 E F1 3(2.2. B+tr)323.2 655.2 R(ee) +-.216 E F0(Berk)323.2 671.4 Q(ele)-.1 E 7.184(yD)-.15 G 7.184(Bi)-7.184 +G 4.683(ncludes a B+tree [Come79] access)-7.184 F 2.502(method. B+trees) +323.2 683.4 R .002(store records of k)2.502 F -.15(ey)-.1 G(/v).15 E +.003(alue pairs in leaf)-.25 F .52(pages, and pairs of \(k)323.2 695.4 R +-.15(ey)-.1 G 3.02(,c)-.5 G .52(hild page address\) at internal)-3.02 F +5.384(nodes. K)323.2 707.4 R -.15(ey)-.25 G 5.384(si).15 G 5.384(nt) +-5.384 G 2.885(he tree are stored in sorted order)-5.384 F(,)-.4 E EP +%%Page: 3 3 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF .576 +(where the order is determined by the comparison func-)79.2 84 R .815 +(tion supplied when the database w)79.2 96 R .815(as created.)-.1 F -.15 +(Pa)5.815 G .815(ges at).15 F .389(the leaf le)79.2 108 R -.15(ve)-.25 G +2.889(lo).15 G 2.889(ft)-2.889 G .389 +(he tree include pointers to their neigh-)-2.889 F 1.444 +(bors to simplify tra)79.2 120 R -.15(ve)-.2 G 3.944(rsal. B+trees).15 F +1.445(support lookup by)3.944 F -.15(ex)79.2 132 S .068 +(act match \(equality\) or range \(greater than or equal to).15 F 2.891 +(ak)79.2 144 S -.15(ey)-2.991 G 2.891(\). Lik).15 F 2.891(eH)-.1 G .391 +(ash tables, B+trees support record inser)-2.891 F(-)-.2 E +(tion, deletion, and iteration o)79.2 156 Q -.15(ve)-.15 G 2.5(ra).15 G +(ll records in the tree.)-2.5 E .646 +(As records are inserted and pages in the B+tree \214ll up,)79.2 172.2 R +(the)79.2 184.2 Q 2.722(ya)-.15 G .223(re split, with about half the k) +-2.722 F -.15(ey)-.1 G 2.723(sg).15 G .223(oing into a ne)-2.723 F(w) +-.25 E 1.603(peer page at the same le)79.2 196.2 R -.15(ve)-.25 G 4.103 +(li).15 G 4.103(nt)-4.103 G 1.603(he tree.)-4.103 F 1.603(Most B+tree) +6.603 F .387(implementations lea)79.2 208.2 R .687 -.15(ve b)-.2 H .387 +(oth nodes half-full after a split.).15 F 2.763 +(This leads to poor performance in a common case,)79.2 220.2 R 1.522 +(where the caller inserts k)79.2 232.2 R -.15(ey)-.1 G 4.022(si).15 G +4.022(no)-4.022 G(rder)-4.022 E 6.522(.T)-.55 G 4.023(oh)-7.322 G 1.523 +(andle this)-4.023 F 1.643(case, Berk)79.2 244.2 R(ele)-.1 E 4.143(yD) +-.15 G 4.143(Bk)-4.143 G 1.642(eeps track of the insertion order)-4.243 +F(,)-.4 E 2.023(and splits pages une)79.2 256.2 R -.15(ve)-.25 G 2.024 +(nly to k).15 F 2.024(eep pages fuller)-.1 F 7.024(.T)-.55 G(his)-7.024 +E 2.3(reduces tree size, yielding better search performance)79.2 268.2 R +(and smaller databases.)79.2 280.2 Q 3.177 +(On deletion, empty pages are coalesced by re)79.2 296.4 R -.15(ve)-.25 +G(rse).15 E 2.03(splits into single pages.)79.2 308.4 R 2.03 +(The access method does no)7.03 F .347 +(other page balancing on insertion or deletion.)79.2 320.4 R -2.15 -.25 +(Ke y)5.348 H 2.848(sa).25 G(re)-2.848 E 1.927(not mo)79.2 332.4 R -.15 +(ve)-.15 G 4.427(da).15 G 1.927(mong pages at e)-4.427 F -.15(ve)-.25 G +1.926(ry update to k).15 F 1.926(eep the)-.1 F 2.206 +(tree well-balanced.)79.2 344.4 R 2.207(While this could impro)7.206 F +2.507 -.15(ve s)-.15 H(earch).15 E 2.341 +(times in some cases, the additional code comple)79.2 356.4 R(xity)-.15 +E(leads to slo)79.2 368.4 Q(wer updates and is prone to deadlocks.)-.25 +E -.15(Fo)79.2 384.6 S 2.948(rs).15 G(implicity)-2.948 E 2.948(,B)-.65 G +(erk)-2.948 E(ele)-.1 E 2.949(yD)-.15 G 2.949(BB)-2.949 G .449 +(+trees do no pre\214x com-)-2.949 F(pression of k)79.2 396.6 Q -.15(ey) +-.1 G 2.5(sa).15 G 2.5(ti)-2.5 G(nternal or leaf nodes.)-2.5 E/F1 12 +/Times-Bold@0 SF 3(2.3. Recno)79.2 426.6 R F0(Berk)79.2 442.8 Q(ele)-.1 +E 2.736(yD)-.15 G 2.736(Bi)-2.736 G .236(ncludes a \214x)-2.736 F .236 +(ed- or v)-.15 F .235(ariable-length record)-.25 F 5.075 +(access method, called)79.2 454.8 R/F2 10/Times-Italic@0 SF(Recno)7.575 +E F0 10.075(.T)C 5.075(he Recno access)-10.075 F .896 +(method assigns logical record numbers to each record,)79.2 466.8 R .978 +(and can search for and update records by record num-)79.2 478.8 R(ber) +79.2 490.8 Q 5.037(.R)-.55 G .037(ecno is able, for e)-5.037 F .037 +(xample, to load a te)-.15 F .036(xt \214le into a)-.15 F 1.514 +(database, treating each line as a record.)79.2 502.8 R 1.514 +(This permits)6.514 F -.1(fa)79.2 514.8 S 1.313 +(st searches by line number for applications lik).1 F 3.812(et)-.1 G +-.15(ex)-3.812 G(t).15 E(editors [Ston82].)79.2 526.8 Q 2.59 +(Recno is actually b)79.2 543 R 2.59(uilt on top of the B+tree access) +-.2 F 3.192(method and pro)79.2 555 R 3.191(vides a simple interf)-.15 F +3.191(ace for storing)-.1 F 3.14(sequentially-ordered data v)79.2 567 R +5.64(alues. The)-.25 F 3.14(Recno access)5.64 F 2.266 +(method generates k)79.2 579 R -.15(ey)-.1 G 4.766(si).15 G(nternally) +-4.766 E 7.266(.T)-.65 G 2.266(he programmer')-7.266 F(s)-.55 E(vie)79.2 +591 Q 4.102(wo)-.25 G 4.102(ft)-4.102 G 1.602(he v)-4.102 F 1.602 +(alues is that the)-.25 F 4.102(ya)-.15 G 1.603(re numbered sequen-) +-4.102 F .254(tially from one.)79.2 603 R(De)5.254 E -.15(ve)-.25 G .254 +(lopers can choose to ha).15 F .553 -.15(ve r)-.2 H(ecords).15 E 9 +(automatically renumbered when lo)79.2 615 R(wer)-.25 E(-numbered)-.2 E +.041(records are added or deleted.)79.2 627 R .041(In this case, ne) +5.041 F 2.541(wk)-.25 G -.15(ey)-2.641 G 2.541(sc).15 G(an)-2.541 E +(be inserted between e)79.2 639 Q(xisting k)-.15 E -.15(ey)-.1 G(s.).15 +E F1 3(3. F)79.2 669 R(eatur)-.3 E(es)-.216 E F0 1.827 +(This section describes important features of Berk)79.2 685.2 R(ele)-.1 +E(y)-.15 E 3.456(DB. In)79.2 697.2 R .956(general, de)3.456 F -.15(ve) +-.25 G .956(lopers can choose which features).15 F .488 +(are useful to them, and use only those that are required)79.2 709.2 R +(by their application.)323.2 84 Q -.15(Fo)323.2 100.2 S 3.529(re).15 G +1.029(xample, when an application opens a database, it)-3.679 F .101 +(can declare the de)323.2 112.2 R .101(gree of concurrenc)-.15 F 2.601 +(ya)-.15 G .102(nd reco)-2.601 F -.15(ve)-.15 G .102(ry that).15 F .049 +(it requires.)323.2 124.2 R .048 +(Simple stand-alone applications, and in par)5.049 F(-)-.2 E .491 +(ticular ports of applications that used)323.2 136.2 R/F3 10/Courier@0 +SF(dbm)2.991 E F0 .491(or one of its)2.991 F -.25(va)323.2 148.2 S 1.093 +(riants, generally do not require concurrent access or).25 F .975 +(crash reco)323.2 160.2 R -.15(ve)-.15 G(ry).15 E 5.975(.O)-.65 G .975 +(ther applications, such as enterprise-)-5.975 F 3.08 +(class database management systems that store sales)323.2 172.2 R 2.643 +(transactions or other critical data, need full transac-)323.2 184.2 R +3.93(tional service.)323.2 196.2 R 3.93(Single-user operation is f)8.93 +F 3.93(aster than)-.1 F 1.175(multi-user operation, since no o)323.2 +208.2 R -.15(ve)-.15 G 1.176(rhead is incurred by).15 F 3.156 +(locking. Running)323.2 220.2 R .656(with the reco)3.156 F -.15(ve)-.15 +G .655(ry system disabled is).15 F -.1(fa)323.2 232.2 S 1.732 +(ster than running with it enabled, since log records).1 F 2.703 +(need not be written when changes are made to the)323.2 244.2 R +(database.)323.2 256.2 Q .851 +(In addition, some core subsystems, including the lock-)323.2 272.4 R +.345(ing system and the logging f)323.2 284.4 R(acility)-.1 E 2.844(,c) +-.65 G .344(an be used outside)-2.844 F 1.772(the conte)323.2 296.4 R +1.772(xt of the access methods as well.)-.15 F(Although)6.773 E(fe)323.2 +308.4 Q 4.284(wu)-.25 G 1.784(sers ha)-4.284 F 2.084 -.15(ve c)-.2 H +1.784(hosen to do so, it is possible to use).15 F .939 +(only the lock manager in Berk)323.2 320.4 R(ele)-.1 E 3.439(yD)-.15 G +3.439(Bt)-3.439 G 3.439(oc)-3.439 G .939(ontrol con-)-3.439 F(currenc) +323.2 332.4 Q 4.743(yi)-.15 G 4.743(na)-4.743 G 4.743(na)-4.743 G 2.242 +(pplication, without using an)-4.743 F 4.742(yo)-.15 G 4.742(ft)-4.742 G +(he)-4.742 E .158(standard database services.)323.2 344.4 R(Alternati) +5.158 E -.15(ve)-.25 G(ly).15 E 2.658(,t)-.65 G .159(he caller can) +-2.658 F(inte)323.2 356.4 Q .07 +(grate locking of non-database resources with Berk)-.15 F(e-)-.1 E(le) +323.2 368.4 Q 5.201(yD)-.15 G(B')-5.201 E 5.201(st)-.55 G 2.702 +(ransactional tw)-5.201 F 2.702(o-phase locking system, to)-.1 F 2.892 +(impose transaction semantics on objects outside the)323.2 380.4 R +(database.)323.2 392.4 Q F1 3(3.1. Pr)323.2 422.4 R +(ogrammatic interfaces)-.216 E F0(Berk)323.2 438.6 Q(ele)-.1 E 4.008(yD) +-.15 G 4.008(Bd)-4.008 G 1.509(e\214nes a simple API for database man-) +-4.008 F 3.452(agement. The)323.2 450.6 R .952 +(package does not include industry-stan-)3.452 F 1.898 +(dard programmatic interf)323.2 462.6 R 1.898 +(aces such as Open Database)-.1 F(Connecti)323.2 474.6 Q .852 +(vity \(ODBC\), Object Linking and Embedding)-.25 F .817 +(for Databases \(OleDB\), or Structured Query Language)323.2 486.6 R +4.027(\(SQL\). These)323.2 498.6 R(interf)4.027 E 1.527 +(aces, while useful, were designed)-.1 F 2.477 +(to promote interoperability of database systems, and)323.2 510.6 R +(not simplicity or performance.)323.2 522.6 Q 3.192 +(In response to customer demand, Berk)323.2 538.8 R(ele)-.1 E 5.691(yD) +-.15 G 5.691(B2)-5.691 G(.5)-5.691 E .538 +(introduced support for the XA standard [Open94].)323.2 550.8 R(XA)5.539 +E .52(permits Berk)323.2 562.8 R(ele)-.1 E 3.02(yD)-.15 G 3.02(Bt)-3.02 +G 3.02(op)-3.02 G .52(articipate in distrib)-3.02 F .52(uted trans-)-.2 +F 3.373(actions under a transaction processing monitor lik)323.2 574.8 R +(e)-.1 E -.45(Tu)323.2 586.8 S -.15(xe).45 G 1.31(do from BEA Systems.) +.15 F(Lik)6.31 E 3.81(eX)-.1 G 1.31(A, other standard)-3.81 F(interf) +323.2 598.8 Q .99(aces can be b)-.1 F .99 +(uilt on top of the core system.)-.2 F(The)5.99 E .846 +(standards do not belong inside Berk)323.2 610.8 R(ele)-.1 E 3.346(yD) +-.15 G .846(B, since not)-3.346 F(all applications need them.)323.2 +622.8 Q F1 3(3.2. W)323.2 652.8 R(orking with r)-.9 E(ecords)-.216 E F0 +3.134(Ad)323.2 669 S .634 +(atabase user may need to search for particular k)-3.134 F -.15(ey)-.1 G +(s).15 E .908(in a database, or may simply w)323.2 681 R .908 +(ant to bro)-.1 F .907(wse a)-.25 F -.25(va)-.2 G(ilable).25 E 4.101 +(records. Berk)323.2 693 R(ele)-.1 E 4.101(yD)-.15 G 4.101(Bs)-4.101 G +1.601(upports both k)-4.101 F -.15(ey)-.1 G 1.602(ed access, to).15 F +.173(\214nd one or more records with a gi)323.2 705 R -.15(ve)-.25 G +2.673(nk).15 G -.15(ey)-2.773 G 2.673(,o)-.5 G 2.673(rs)-2.673 G +(equential)-2.673 E .53(access, to retrie)323.2 717 R .83 -.15(ve a)-.25 +H .53(ll the records in the database one at).15 F EP +%%Page: 4 4 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF 6.34(at)79.2 84 S 6.34(ime. The)-6.34 F 3.84 +(order of the records returned during)6.34 F .208 +(sequential scans depends on the access method.)79.2 96 R(B+tree)5.209 E +1.495(and Recno databases return records in sort order)79.2 108 R 3.995 +(,a)-.4 G(nd)-3.995 E .023 +(Hash databases return them in apparently random order)79.2 120 R(.)-.55 +E(Similarly)79.2 136.2 Q 4.959(,B)-.65 G(erk)-4.959 E(ele)-.1 E 4.959 +(yD)-.15 G 4.958(Bd)-4.959 G 2.458(e\214nes simple interf)-4.958 F 2.458 +(aces for)-.1 F +(inserting, updating, and deleting records in a database.)79.2 148.2 Q +/F1 12/Times-Bold@0 SF 3(3.3. Long)79.2 178.2 R -.12(ke)3 G(ys and v).12 +E(alues)-.12 E F0(Berk)79.2 194.4 Q(ele)-.1 E 3.553(yD)-.15 G 3.553(Bm) +-3.553 G 1.053(anages k)-3.553 F -.15(ey)-.1 G 3.553(sa).15 G 1.053 +(nd v)-3.553 F 1.053(alues as lar)-.25 F 1.054(ge as 2)-.18 F/F2 8 +/Times-Roman@0 SF(32)-5 I F0 3.192(bytes. Since)79.2 206.4 R .692 +(the time required to cop)3.192 F 3.192(yar)-.1 G .692(ecord is pro-) +-3.192 F 1.895(portional to its size, Berk)79.2 218.4 R(ele)-.1 E 4.396 +(yD)-.15 G 4.396(Bi)-4.396 G 1.896(ncludes interf)-4.396 F(aces)-.1 E +4.507(that operate on partial records.)79.2 230.4 R 4.507 +(If an application)9.507 F 1.273(requires only part of a lar)79.2 242.4 +R 1.274(ge record, it requests partial)-.18 F .026(record retrie)79.2 +254.4 R -.25(va)-.25 G .026(l, and recei).25 F -.15(ve)-.25 G 2.526(sj) +.15 G .025(ust the bytes that it needs.)-2.526 F(The smaller cop)79.2 +266.4 Q 2.5(ys)-.1 G -2.25 -.2(av e)-2.5 H 2.5(sb).2 G +(oth time and memory)-2.5 E(.)-.65 E(Berk)79.2 282.6 Q(ele)-.1 E 3.206 +(yD)-.15 G 3.206(Ba)-3.206 G(llo)-3.206 E .706 +(ws the programmer to de\214ne the data)-.25 F 2.72(types of k)79.2 +294.6 R -.15(ey)-.1 G 5.22(sa).15 G 2.72(nd v)-5.22 F 5.22(alues. De) +-.25 F -.15(ve)-.25 G 2.72(lopers use an).15 F 5.22(yt)-.15 G(ype)-5.22 +E -.15(ex)79.2 306.6 S(pressible in the programming language.).15 E F1 3 +(3.4. Lar)79.2 336.6 R(ge databases)-.12 E F0 3.255(As)79.2 352.8 S .755 +(ingle database managed by Berk)-3.255 F(ele)-.1 E 3.256(yD)-.15 G 3.256 +(Bc)-3.256 G .756(an be up)-3.256 F 1.716(to 2)79.2 364.8 R F2(48)-5 I +F0 1.716(bytes, or 256 petabytes, in size.)4.216 5 N(Berk)6.715 E(ele) +-.1 E 4.215(yD)-.15 G(B)-4.215 E 2.144 +(uses the host \214lesystem as the backing store for the)79.2 376.8 R +2.668(database, so lar)79.2 388.8 R 2.667 +(ge databases require big \214le support)-.18 F 3.113 +(from the operating system.)79.2 400.8 R(Sleep)8.113 E 3.114(ycat Softw) +-.1 F 3.114(are has)-.1 F 5.712(customers using Berk)79.2 412.8 R(ele) +-.1 E 8.212(yD)-.15 G 8.212(Bt)-8.212 G 8.211(om)-8.212 G 5.711 +(anage single)-8.211 F(databases in e)79.2 424.8 Q(xcess of 100 gig)-.15 +E(abytes.)-.05 E F1 3(3.5. Main)79.2 454.8 R(memory databases)3 E F0 +1.171(Applications that do not require persistent storage can)79.2 471 R +.119(create databases that e)79.2 483 R .119(xist only in main memory) +-.15 F 5.118(.T)-.65 G(hese)-5.118 E .542(databases bypass the o)79.2 +495 R -.15(ve)-.15 G .543(rhead imposed by the I/O sys-).15 F +(tem altogether)79.2 507 Q(.)-.55 E 2.144 +(Some applications do need to use disk as a backing)79.2 523.2 R 2.248 +(store, b)79.2 535.2 R 2.249(ut run on machines with v)-.2 F 2.249 +(ery lar)-.15 F 2.249(ge memory)-.18 F(.)-.65 E(Berk)79.2 547.2 Q(ele) +-.1 E 2.799(yD)-.15 G 2.799(Bi)-2.799 G 2.799(sa)-2.799 G .299 +(ble to manage v)-2.799 F .299(ery lar)-.15 F .299(ge shared mem-)-.18 F +.128(ory re)79.2 559.2 R .129 +(gions for cached data pages, log records, and lock)-.15 F 3.938 +(management. F)79.2 571.2 R 1.437(or e)-.15 F 1.437 +(xample, the cache re)-.15 F 1.437(gion used for)-.15 F .033 +(data pages may be gig)79.2 583.2 R .034 +(abytes in size, reducing the lik)-.05 F(eli-)-.1 E .639(hood that an) +79.2 595.2 R 3.139(yr)-.15 G .639 +(ead operation will need to visit the disk)-3.139 F 1.201 +(in the steady state.)79.2 607.2 R 1.201 +(The programmer declares the size)6.201 F(of the cache re)79.2 619.2 Q +(gion at startup.)-.15 E(Finally)79.2 635.4 Q 7.048(,m)-.65 G(an)-7.048 +E 7.048(yo)-.15 G 4.548(perating systems pro)-7.048 F 4.548 +(vide memory-)-.15 F 2.532(mapped \214le services that are much f)79.2 +647.4 R 2.533(aster than their)-.1 F 2.602 +(general-purpose \214le system interf)79.2 659.4 R 5.102(aces. Berk)-.1 +F(ele)-.1 E 5.102(yD)-.15 G(B)-5.102 E 5.118 +(can memory-map its database \214les for read-only)79.2 671.4 R 3.917 +(database use.)79.2 683.4 R 3.917(The application operates on records) +8.917 F 2.069(stored directly on the pages, with no cache manage-)79.2 +695.4 R 1.557(ment o)79.2 707.4 R -.15(ve)-.15 G 4.057(rhead. Because) +.15 F 1.556(the application gets pointers)4.057 F 1.265 +(directly into the Berk)323.2 84 R(ele)-.1 E 3.765(yD)-.15 G 3.765(Bp) +-3.765 G 1.265(ages, writes cannot be)-3.765 F 3.775 +(permitted. Otherwise,)323.2 96 R 1.275(changes could bypass the lock-) +3.775 F .23(ing and logging systems, and softw)323.2 108 R .23 +(are errors could cor)-.1 F(-)-.2 E 4.007(rupt the database.)323.2 120 R +4.006(Read-only applications can use)9.007 F(Berk)323.2 132 Q(ele)-.1 E +2.893(yD)-.15 G(B')-2.893 E 2.893(sm)-.55 G .393 +(emory-mapped \214le service to impro)-2.893 F -.15(ve)-.15 G +(performance on most architectures.)323.2 144 Q F1 3 +(3.6. Con\214gurable)323.2 174 R(page size)3 E F0 .111 +(Programmers declare the size of the pages used by their)323.2 190.2 R +.403(access methods when the)323.2 202.2 R 2.903(yc)-.15 G .403 +(reate a database.)-2.903 F(Although)5.403 E(Berk)323.2 214.2 Q(ele)-.1 +E 4.046(yD)-.15 G 4.046(Bp)-4.046 G(ro)-4.046 E 1.546 +(vides reasonable def)-.15 F 1.546(aults, de)-.1 F -.15(ve)-.25 G +(lopers).15 E 3.64(may o)323.2 226.2 R -.15(ve)-.15 G 3.64 +(rride them to control system performance.).15 F .793 +(Small pages reduce the number of records that \214t on a)323.2 238.2 R +.353(single page.)323.2 250.2 R(Fe)5.353 E .353 +(wer records on a page means that fe)-.25 F(wer)-.25 E .724 +(records are lock)323.2 262.2 R .724(ed when the page is lock)-.1 F .723 +(ed, impro)-.1 F(ving)-.15 E(concurrenc)323.2 274.2 Q 5.262 -.65(y. T) +-.15 H 1.462(he per).65 F 1.462(-page o)-.2 F -.15(ve)-.15 G 1.462 +(rhead is proportionally).15 F 2.29 +(higher with smaller pages, of course, b)323.2 286.2 R 2.29(ut de)-.2 F +-.15(ve)-.25 G(lopers).15 E(can trade of)323.2 298.2 Q 2.5(fs)-.25 G +(pace for time as an application requires.)-2.5 E F1 3(3.7. Small)323.2 +328.2 R -.3(fo)3 G(otprint).3 E F0(Berk)323.2 344.4 Q(ele)-.1 E 3.973 +(yD)-.15 G 3.973(Bi)-3.973 G 3.974(sac)-3.973 G 1.474(ompact system.) +-3.974 F 1.474(The full package,)6.474 F .832 +(including all access methods, reco)323.2 356.4 R -.15(ve)-.15 G +(rability).15 E 3.331(,a)-.65 G .831(nd trans-)-3.331 F 1.235 +(action support is roughly 175K of te)323.2 368.4 R 1.236 +(xt space on com-)-.15 F(mon architectures.)323.2 380.4 Q F1 3 +(3.8. Cursors)323.2 410.4 R F0 1.57(In database terminology)323.2 426.6 +R 4.07(,ac)-.65 G 1.57(ursor is a pointer into an)-4.07 F 1.806 +(access method that can be called iterati)323.2 438.6 R -.15(ve)-.25 G +1.807(ly to return).15 F 3.68(records in sequence.)323.2 450.6 R(Berk) +8.68 E(ele)-.1 E 6.18(yD)-.15 G 6.18(Bi)-6.18 G 3.68(ncludes cursor) +-6.18 F(interf)323.2 462.6 Q 2.814(aces for all access methods.)-.1 F +2.815(This permits, for)7.814 F -.15(ex)323.2 474.6 S .34 +(ample, users to tra).15 F -.15(ve)-.2 G .34(rse a B+tree and vie).15 F +2.84(wr)-.25 G .34(ecords in)-2.84 F(order)323.2 486.6 Q 6.233(.P)-.55 G +1.234(ointers to records in cursors are persistent, so)-6.233 F 1.779 +(that once fetched, a record may be updated in place.)323.2 498.6 R +(Finally)323.2 510.6 Q 4.438(,c)-.65 G 1.939 +(ursors support access to chains of duplicate)-4.438 F +(data items in the v)323.2 522.6 Q(arious access methods.)-.25 E F1 3 +(3.9. J)323.2 552.6 R(oins)-.18 E F0 2.703(In database terminology)323.2 +568.8 R 5.203(,aj)-.65 G 2.702(oin is an operation that)-5.203 F .616 +(spans multiple separate tables \(or in the case of Berk)323.2 580.8 R +(e-)-.1 E(le)323.2 592.8 Q 4.518(yD)-.15 G 2.018 +(B, multiple separate DB \214les\).)-4.518 F -.15(Fo)7.017 G 4.517(re) +.15 G 2.017(xample, a)-4.667 F(compan)323.2 604.8 Q 3.372(ym)-.15 G .873 +(ay store information about its customers in)-3.372 F 1.545 +(one table and information about sales in another)323.2 616.8 R 6.545 +(.A)-.55 G(n)-6.545 E 1.498(application will lik)323.2 628.8 R 1.499 +(ely w)-.1 F 1.499(ant to look up sales informa-)-.1 F .933 +(tion by customer name; this requires matching records)323.2 640.8 R +2.28(in the tw)323.2 652.8 R 4.78(ot)-.1 G 2.28 +(ables that share a common customer ID)-4.78 F 2.515(\214eld. This)323.2 +664.8 R .015(combining of records from multiple tables is)2.515 F +(called a join.)323.2 676.8 Q(Berk)323.2 693 Q(ele)-.1 E 5.561(yD)-.15 G +5.561(Bi)-5.561 G 3.061(ncludes interf)-5.561 F 3.062 +(aces for joining tw)-.1 F 5.562(oo)-.1 G(r)-5.562 E(more tables.)323.2 +705 Q EP +%%Page: 5 5 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 12/Times-Bold@0 SF 3(3.10. T)79.2 84 R(ransactions)-.888 E/F1 10 +/Times-Roman@0 SF -.35(Tr)79.2 100.2 S(ansactions ha).35 E .3 -.15(ve f) +-.2 H(our properties [Gray93]:).15 E/F2 8/Times-Roman@0 SF<83>84.2 116.4 +Q F1(The)17.2 E 5.489(ya)-.15 G 2.989(re atomic.)-5.489 F 2.989 +(That is, all of the changes)7.989 F 1.475 +(made in a single transaction must be applied at)104.2 128.4 R 1.31 +(the same instant or not at all.)104.2 140.4 R 1.31(This permits, for) +6.31 F -.15(ex)104.2 152.4 S 3.565(ample, the transfer of mone).15 F +6.065(yb)-.15 G 3.565(etween tw)-6.065 F(o)-.1 E 3.68 +(accounts to be accomplished, by making the)104.2 164.4 R 1.27 +(reduction of the balance in one account and the)104.2 176.4 R +(increase in the other into a single, atomic action.)104.2 188.4 Q F2 +<83>84.2 204.6 Q F1(The)17.2 E 3.125(ym)-.15 G .625(ust be consistent.) +-3.125 F .625(That is, changes to the)5.625 F 3.628(database by an)104.2 +216.6 R 6.128(yt)-.15 G 3.628(ransaction cannot lea)-6.128 F 3.929 -.15 +(ve t)-.2 H(he).15 E(database in an ille)104.2 228.6 Q -.05(ga)-.15 G +2.5(lo).05 G 2.5(rc)-2.5 G(orrupt state.)-2.5 E F2<83>84.2 244.8 Q F1 +(The)17.2 E 3.006(ym)-.15 G .506(ust be isolatable.)-3.006 F(Re)5.506 E +-.05(ga)-.15 G .505(rdless of the num-).05 F .8(ber of users w)104.2 +256.8 R .8(orking in the database at the same)-.1 F 1.88(time, e)104.2 +268.8 R -.15(ve)-.25 G 1.88(ry user must ha).15 F 2.18 -.15(ve t)-.2 H +1.88(he illusion that no).15 F(other acti)104.2 280.8 Q +(vity is going on.)-.25 E F2<83>84.2 297 Q F1(The)17.2 E 5.54(ym)-.15 G +3.04(ust be durable.)-5.54 F(Ev)8.04 E 3.04(en if the disk that)-.15 F +.877(stores the database is lost, it must be possible to)104.2 309 R +(reco)104.2 321 Q -.15(ve)-.15 G 2.668(rt).15 G .168 +(he database to its last transaction-consis-)-2.668 F(tent state.)104.2 +333 Q 2.49(This combination of properties \212 atomicity)79.2 349.2 R +4.99(,c)-.65 G(onsis-)-4.99 E(tenc)79.2 361.2 Q 4.542 -.65(y, i)-.15 H +3.243(solation, and durability \212 is referred to as).65 F -.4(AC)79.2 +373.2 S 3.459(IDity in the literature.).4 F(Berk)8.459 E(ele)-.1 E 5.958 +(yD)-.15 G 3.458(B, lik)-5.958 F 5.958(em)-.1 G(ost)-5.958 E .993 +(database systems, pro)79.2 385.2 R .993(vides A)-.15 F .994 +(CIDity using a collection)-.4 F(of core services.)79.2 397.2 Q .257 +(Programmers can choose to use Berk)79.2 413.4 R(ele)-.1 E 2.757(yD)-.15 +G(B')-2.757 E 2.757(st)-.55 G(ransac-)-2.757 E +(tion services for applications that need them.)79.2 425.4 Q F0 3 +(3.10.1. Write-ahead)79.2 455.4 R(logging)3 E F1 .479 +(Programmers can enable the logging system when the)79.2 471.6 R(y)-.15 +E .918(start up Berk)79.2 483.6 R(ele)-.1 E 3.418(yD)-.15 G 3.418 +(B. During)-3.418 F 3.417(at)3.417 G .917(ransaction, the appli-)-3.417 +F .493(cation mak)79.2 495.6 R .493 +(es a series of changes to the database.)-.1 F(Each)5.494 E .552 +(change is captured in a log entry)79.2 507.6 R 3.052(,w)-.65 G .552 +(hich holds the state)-3.052 F .207 +(of the database record both before and after the change.)79.2 519.6 R +2.208(The log record is guaranteed to be \215ushed to stable)79.2 531.6 +R .871(storage before an)79.2 543.6 R 3.371(yo)-.15 G 3.371(ft)-3.371 G +.871(he changed data pages are writ-)-3.371 F 3.989(ten. This)79.2 555.6 +R(beha)3.989 E 1.489(vior \212 writing the log before the data)-.2 F +(pages \212 is called)79.2 567.6 Q/F3 10/Times-Italic@0 SF +(write-ahead lo)2.5 E -.1(gg)-.1 G(ing).1 E F1(.)A .835(At an)79.2 583.8 +R 3.335(yt)-.15 G .835(ime during the transaction, the application can) +-3.335 F F3(commit)79.2 595.8 Q F1 4.202(,m)C 1.702 +(aking the changes permanent, or)-4.202 F F3 -.45(ro)4.201 G 1.701 +(ll bac).45 F(k)-.2 E F1(,)A .852 +(cancelling all changes and restoring the database to its)79.2 607.8 R +1.57(pre-transaction state.)79.2 619.8 R 1.57 +(If the application rolls back the)6.57 F 1.003 +(transaction, then the log holds the state of all changed)79.2 631.8 R +.5(pages prior to the transaction, and Berk)79.2 643.8 R(ele)-.1 E 3(yD) +-.15 G 3(Bs)-3 G(imply)-3 E .226(restores that state.)79.2 655.8 R .226 +(If the application commits the trans-)5.226 F .538(action, Berk)79.2 +667.8 R(ele)-.1 E 3.038(yD)-.15 G 3.038(Bw)-3.038 G .538 +(rites the log records to disk.)-3.038 F(In-)5.537 E 2.312 +(memory copies of the data pages already re\215ect the)79.2 679.8 R +1.399(changes, and will be \215ushed as necessary during nor)79.2 691.8 +R(-)-.2 E 2.35(mal processing.)79.2 703.8 R 2.35 +(Since log writes are sequential, b)7.35 F(ut)-.2 E 8.732 +(data page writes are random, this impro)79.2 715.8 R -.15(ve)-.15 G(s) +.15 E(performance.)323.2 84 Q F0 3(3.10.2. Crashes)323.2 114 R(and r)3 E +(eco)-.216 E -.12(ve)-.12 G(ry).12 E F1(Berk)323.2 130.2 Q(ele)-.1 E +3.592(yD)-.15 G(B')-3.592 E 3.592(sw)-.55 G 1.093 +(rite-ahead log is used by the transac-)-3.592 F .415 +(tion system to commit or roll back transactions.)323.2 142.2 R .414 +(It also)5.414 F(gi)323.2 154.2 Q -.15(ve)-.25 G 3.23(st).15 G .73 +(he reco)-3.23 F -.15(ve)-.15 G .73 +(ry system the information that it needs).15 F .824(to protect ag)323.2 +166.2 R .824(ainst data loss or corruption from crashes.)-.05 F(Berk) +323.2 178.2 Q(ele)-.1 E 2.703(yD)-.15 G 2.703(Bi)-2.703 G 2.704(sa) +-2.703 G .204(ble to survi)-2.704 F .504 -.15(ve a)-.25 H .204 +(pplication crashes, sys-).15 F .408(tem crashes, and e)323.2 190.2 R +-.15(ve)-.25 G 2.908(nc).15 G .407(atastrophic f)-2.908 F .407 +(ailures lik)-.1 F 2.907(et)-.1 G .407(he loss)-2.907 F +(of a hard disk, without losing an)323.2 202.2 Q 2.5(yd)-.15 G(ata.)-2.5 +E(Survi)323.2 218.4 Q .538(ving crashes requires data stored in se)-.25 +F -.15(ve)-.25 G .539(ral dif).15 F(fer)-.25 E(-)-.2 E 2.52(ent places.) +323.2 230.4 R 2.52(During normal processing, Berk)7.52 F(ele)-.1 E 5.02 +(yD)-.15 G(B)-5.02 E .766(has copies of acti)323.2 242.4 R 1.066 -.15 +(ve l)-.25 H .766(og records and recently-used data).15 F 1.539 +(pages in memory)323.2 254.4 R 6.539(.L)-.65 G 1.539 +(og records are \215ushed to the log)-6.539 F .694 +(disk when transactions commit.)323.2 266.4 R .695 +(Data pages trickle out)5.694 F .008(to the data disk as pages mo)323.2 +278.4 R .308 -.15(ve t)-.15 H .008(hrough the b).15 F(uf)-.2 E .008 +(fer cache.)-.25 F(Periodically)323.2 290.4 Q 2.691(,t)-.65 G .191 +(he system administrator backs up the data)-2.691 F .278 +(disk, creating a safe cop)323.2 302.4 R 2.778(yo)-.1 G 2.778(ft)-2.778 +G .278(he database at a particular)-2.778 F 2.609(instant. When)323.2 +314.4 R .109(the database is back)2.609 F .109(ed up, the log can be)-.1 +F 3.838(truncated. F)323.2 326.4 R 1.337(or maximum rob)-.15 F 1.337 +(ustness, the log disk and)-.2 F(data disk should be separate de)323.2 +338.4 Q(vices.)-.25 E(Dif)323.2 354.6 Q 1.29(ferent system f)-.25 F 1.29 +(ailures can destro)-.1 F 3.79(ym)-.1 G(emory)-3.79 E 3.79(,t)-.65 G +1.29(he log)-3.79 F 1.106(disk, or the data disk.)323.2 366.6 R(Berk) +6.106 E(ele)-.1 E 3.606(yD)-.15 G 3.606(Bi)-3.606 G 3.606(sa)-3.606 G +1.106(ble to survi)-3.606 F -.15(ve)-.25 G .679(the loss of an)323.2 +378.6 R 3.179(yo)-.15 G .679(ne of these repositories without losing) +-3.179 F(an)323.2 390.6 Q 2.5(yc)-.15 G(ommitted transactions.)-2.5 E +1.372(If the computer')323.2 406.8 R 3.871(sm)-.55 G 1.371 +(emory is lost, through an applica-)-3.871 F 1.619 +(tion or operating system crash, then the log holds all)323.2 418.8 R +1.789(committed transactions.)323.2 430.8 R 1.788(On restart, the reco) +6.789 F -.15(ve)-.15 G 1.788(ry sys-).15 F .49(tem rolls the log forw) +323.2 442.8 R .49(ard ag)-.1 F .49(ainst the database, reapply-)-.05 F +.682(ing an)323.2 454.8 R 3.181(yc)-.15 G .681 +(hanges to on-disk pages that were in memory)-3.181 F .14 +(at the time of the crash.)323.2 466.8 R .14 +(Since the log contains pre- and)5.14 F .957 +(post-change state for transactions, the reco)323.2 478.8 R -.15(ve)-.15 +G .956(ry system).15 F 1.14(also uses the log to restore an)323.2 490.8 +R 3.64(yp)-.15 G 1.14(ages to their original)-3.64 F 1.615(state if the) +323.2 502.8 R 4.115(yw)-.15 G 1.615 +(ere modi\214ed by transactions that ne)-4.115 F -.15(ve)-.25 G(r).15 E +(committed.)323.2 514.8 Q 2.051 +(If the data disk is lost, the system administrator can)323.2 531 R .887 +(restore the most recent cop)323.2 543 R 3.386(yf)-.1 G .886 +(rom backup.)-3.386 F .886(The reco)5.886 F(v-)-.15 E 1.298 +(ery system will roll the entire log forw)323.2 555 R 1.298(ard ag)-.1 F +1.298(ainst the)-.05 F 2.64 +(original database, reapplying all committed changes.)323.2 567 R 4.363 +(When it \214nishes, the database will contain e)323.2 579 R -.15(ve) +-.25 G(ry).15 E .535(change made by e)323.2 591 R -.15(ve)-.25 G .534 +(ry transaction that e).15 F -.15(ve)-.25 G 3.034(rc).15 G(ommitted.) +-3.034 E .494(If the log disk is lost, then the reco)323.2 607.2 R -.15 +(ve)-.15 G .495(ry system can use).15 F 1.853 +(the in-memory copies of log entries to roll back an)323.2 619.2 R(y) +-.15 E .026(uncommitted transactions, \215ush all in-memory database) +323.2 631.2 R 1.659(pages to the data disk, and shut do)323.2 643.2 R +1.659(wn gracefully)-.25 F 6.658(.A)-.65 G(t)-6.658 E 2.204 +(that point, the system administrator can back up the)323.2 655.2 R .039 +(database disk, install a ne)323.2 667.2 R 2.539(wl)-.25 G .039 +(og disk, and restart the sys-)-2.539 F(tem.)323.2 679.2 Q EP +%%Page: 6 6 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 12/Times-Bold@0 SF 3(3.10.3. Checkpoints)79.2 84 R/F1 10 +/Times-Roman@0 SF(Berk)79.2 100.2 Q(ele)-.1 E 6.085(yD)-.15 G 6.085(Bi) +-6.085 G 3.585(ncludes a checkpointing service that)-6.085 F .263 +(interacts with the reco)79.2 112.2 R -.15(ve)-.15 G .263(ry system.).15 +F .263(During normal pro-)5.263 F 2.415 +(cessing, both the log and the database are changing)79.2 124.2 R +(continually)79.2 136.2 Q 5.925(.A)-.65 G 3.425(ta)-5.925 G 1.224 -.15 +(ny g)-3.425 H -2.15 -.25(iv e).15 H 3.424(ni).25 G .924 +(nstant, the on-disk v)-3.424 F(ersions)-.15 E .414(of the tw)79.2 148.2 +R 2.914(oa)-.1 G .414(re not guaranteed to be consistent.)-2.914 F .414 +(The log)5.414 F 3.838 +(probably contains changes that are not yet in the)79.2 160.2 R +(database.)79.2 172.2 Q .085(When an application mak)79.2 188.4 R .086 +(es a)-.1 F/F2 10/Times-Italic@0 SF -.15(ch)2.586 G(ec).15 E(kpoint)-.2 +E F1 2.586(,a)C .086(ll committed)-2.586 F .443 +(changes in the log up to that point are guaranteed to be)79.2 200.4 R +.631(present on the data disk, too.)79.2 212.4 R .632 +(Checkpointing is moder)5.631 F(-)-.2 E .046(ately e)79.2 224.4 R +(xpensi)-.15 E .346 -.15(ve d)-.25 H .046(uring normal processing, b).15 +F .045(ut limits the)-.2 F(time spent reco)79.2 236.4 Q -.15(ve)-.15 G +(ring from crashes.).15 E 3.117 +(After an application or operating system crash, the)79.2 252.6 R(reco) +79.2 264.6 Q -.15(ve)-.15 G 7.419(ry system only needs to go back tw).15 +F(o)-.1 E(checkpoints)79.2 278.6 Q/F3 7/Times-Roman@0 SF(1)-4 I F1 1.376 +(to start rolling the log forw)3.876 4 N 3.875(ard. W)-.1 F(ithout)-.4 E +3.264(checkpoints, there is no w)79.2 290.6 R 3.265(ay to be sure ho)-.1 +F 5.765(wl)-.25 G(ong)-5.765 E .395(restarting after a crash will tak) +79.2 302.6 R 2.895(e. W)-.1 F .395(ith checkpoints, the)-.4 F .088 +(restart interv)79.2 314.6 R .089(al can be \214x)-.25 F .089 +(ed by the programmer)-.15 F 5.089(.R)-.55 G(eco)-5.089 E(v-)-.15 E .668 +(ery processing can be guaranteed to complete in a sec-)79.2 326.6 R +(ond or tw)79.2 338.6 Q(o.)-.1 E(Softw)79.2 354.8 Q 2.457 +(are crashes are much more common than disk)-.1 F -.1(fa)79.2 366.8 S +3.385(ilures. Man).1 F 3.385(yd)-.15 G -2.15 -.25(ev e)-3.385 H .884 +(lopers w).25 F .884(ant to guarantee that soft-)-.1 F -.1(wa)79.2 378.8 +S .158(re b).1 F .158(ugs do not destro)-.2 F 2.658(yd)-.1 G .158 +(ata, b)-2.658 F .158(ut are willing to restore)-.2 F .631 +(from tape, and to tolerate a day or tw)79.2 390.8 R 3.131(oo)-.1 G +3.131(fl)-3.131 G .63(ost w)-3.131 F .63(ork, in)-.1 F .89(the unlikle) +79.2 402.8 R 3.39(ye)-.15 G -.15(ve)-3.64 G .89(nt of a disk crash.).15 +F -.4(Wi)5.89 G .89(th Berk).4 F(ele)-.1 E 3.39(yD)-.15 G(B,)-3.39 E +1.093(programmers may truncate the log at checkpoints.)79.2 414.8 R(As) +6.092 E .09(long as the tw)79.2 426.8 R 2.59(om)-.1 G .09 +(ost recent checkpoints are present, the)-2.59 F(reco)79.2 438.8 Q -.15 +(ve)-.15 G .106(ry system can guarantee that no committed trans-).15 F +.611(actions are lost after a softw)79.2 450.8 R .611(are crash.)-.1 F +.611(In this case, the)5.611 F(reco)79.2 462.8 Q -.15(ve)-.15 G 1.439 +(ry system does not require that the log and the).15 F 1.328 +(data be on separate de)79.2 474.8 R 1.329 +(vices, although separating them)-.25 F(can still impro)79.2 486.8 Q .3 +-.15(ve p)-.15 H(erformance by spreading out writes.).15 E F0 3 +(3.10.4. T)79.2 516.8 R -.12(wo)-.888 G(-phase locking).12 E F1(Berk) +79.2 533 Q(ele)-.1 E 4.416(yD)-.15 G 4.416(Bp)-4.416 G(ro)-4.416 E 1.916 +(vides a service kno)-.15 F 1.915(wn as tw)-.25 F(o-phase)-.1 E 3.017 +(locking. In)79.2 545 R .517(order to reduce the lik)3.017 F .518 +(elihood of deadlocks)-.1 F 2.547(and to guarantee A)79.2 557 R 2.546 +(CID properties, database systems)-.4 F .063(manage locks in tw)79.2 569 +R 2.564(op)-.1 G 2.564(hases. First,)-2.564 F .064(during the operation) +2.564 F 1.574(of a transaction, the)79.2 581 R 4.074(ya)-.15 G 1.574 +(cquire locks, b)-4.074 F 1.573(ut ne)-.2 F -.15(ve)-.25 G 4.073(rr).15 +G(elease)-4.073 E 6.147(them. Second,)79.2 593 R 3.648 +(at the end of the transaction, the)6.147 F(y)-.15 E .235 +(release locks, b)79.2 605 R .235(ut ne)-.2 F -.15(ve)-.25 G 2.735(ra) +.15 G .235(cquire them.)-2.735 F .235(In practice, most)5.235 F 4.69 +(database systems, including Berk)79.2 617 R(ele)-.1 E 7.19(yD)-.15 G +4.69(B, acquire)-7.19 F 2.314(locks on demand o)79.2 629 R -.15(ve)-.15 +G 4.814(rt).15 G 2.314(he course of the transaction,)-4.814 F +(then \215ush the log, then release all locks.)79.2 641 Q .32 LW 83.2 +650.6 79.2 650.6 DL 87.2 650.6 83.2 650.6 DL 91.2 650.6 87.2 650.6 DL +95.2 650.6 91.2 650.6 DL 99.2 650.6 95.2 650.6 DL 103.2 650.6 99.2 650.6 +DL 107.2 650.6 103.2 650.6 DL 111.2 650.6 107.2 650.6 DL 115.2 650.6 +111.2 650.6 DL 119.2 650.6 115.2 650.6 DL 123.2 650.6 119.2 650.6 DL +127.2 650.6 123.2 650.6 DL 131.2 650.6 127.2 650.6 DL 135.2 650.6 131.2 +650.6 DL 139.2 650.6 135.2 650.6 DL 143.2 650.6 139.2 650.6 DL 147.2 +650.6 143.2 650.6 DL 151.2 650.6 147.2 650.6 DL 155.2 650.6 151.2 650.6 +DL 159.2 650.6 155.2 650.6 DL 163.2 650.6 159.2 650.6 DL 167.2 650.6 +163.2 650.6 DL 171.2 650.6 167.2 650.6 DL 175.2 650.6 171.2 650.6 DL +179.2 650.6 175.2 650.6 DL 183.2 650.6 179.2 650.6 DL 187.2 650.6 183.2 +650.6 DL 191.2 650.6 187.2 650.6 DL 195.2 650.6 191.2 650.6 DL 199.2 +650.6 195.2 650.6 DL 203.2 650.6 199.2 650.6 DL 207.2 650.6 203.2 650.6 +DL 211.2 650.6 207.2 650.6 DL 215.2 650.6 211.2 650.6 DL 219.2 650.6 +215.2 650.6 DL 223.2 650.6 219.2 650.6 DL/F4 5/Times-Roman@0 SF(1)100.8 +661 Q/F5 8/Times-Roman@0 SF .338(One checkpoint is not f)2.338 3.2 N +.338(ar enough.)-.08 F .338(The reco)4.338 F -.12(ve)-.12 G .338 +(ry system can-).12 F .211 +(not be sure that the most recent checkpoint completed \212 it may ha) +79.2 673.8 R -.12(ve)-.16 G .734 +(been interrupted by the crash that forced the reco)79.2 683.4 R -.12 +(ve)-.12 G .734(ry system to run).12 F(in the \214rst place.)79.2 693 Q +F1(Berk)323.2 84 Q(ele)-.1 E 3.306(yD)-.15 G 3.306(Bc)-3.306 G .806 +(an lock entire database \214les, which cor)-3.306 F(-)-.2 E .845 +(respond to tables, or indi)323.2 96 R .844(vidual pages in them.)-.25 F +.844(It does)5.844 F 2.141(no record-le)323.2 108 R -.15(ve)-.25 G 4.641 +(ll).15 G 4.641(ocking. By)-4.641 F 2.142(shrinking the page size,)4.641 +F(ho)323.2 120 Q(we)-.25 E -.15(ve)-.25 G 4.427 -.4(r, d).15 H -2.15 +-.25(ev e).4 H 3.627(lopers can guarantee that e).25 F -.15(ve)-.25 G +3.626(ry page).15 F 2.101(holds only a small number of records.)323.2 +132 R 2.102(This reduces)7.102 F(contention.)323.2 144 Q .388 +(If locking is enabled, then read and write operations on)323.2 160.2 R +5.317(ad)323.2 172.2 S 2.817(atabase acquire tw)-5.317 F 2.817 +(o-phase locks, which are held)-.1 F 3.635 +(until the transaction completes.)323.2 184.2 R 3.635(Which objects are) +8.635 F(lock)323.2 196.2 Q .738 +(ed and the order of lock acquisition depend on the)-.1 F -.1(wo)323.2 +208.2 S .503(rkload for each transaction.).1 F .502 +(It is possible for tw)5.502 F 3.002(oo)-.1 G(r)-3.002 E 1.315 +(more transactions to deadlock, so that each is w)323.2 220.2 R(aiting) +-.1 E(for a lock that is held by another)323.2 232.2 Q(.)-.55 E(Berk) +323.2 248.4 Q(ele)-.1 E 3.307(yD)-.15 G 3.307(Bd)-3.307 G .807 +(etects deadlocks and automatically rolls)-3.307 F 1.825 +(back one of the transactions.)323.2 260.4 R 1.825 +(This releases the locks)6.825 F 1.926(that it held and allo)323.2 272.4 +R 1.925(ws the other transactions to con-)-.25 F 3.346(tinue. The)323.2 +284.4 R .847(caller is noti\214ed that its transaction did not)3.346 F +1.747(complete, and may restart it.)323.2 296.4 R(De)6.747 E -.15(ve) +-.25 G 1.747(lopers can specify).15 F .646 +(the deadlock detection interv)323.2 308.4 R .647(al and the polic)-.25 +F 3.147(yt)-.15 G 3.147(ou)-3.147 G .647(se in)-3.147 F +(choosing a transaction to roll back.)323.2 320.4 Q 6.686(The tw)323.2 +336.6 R 6.686(o-phase locking interf)-.1 F 6.686(aces are separately)-.1 +F .927(callable by applications that link Berk)323.2 348.6 R(ele)-.1 E +3.427(yD)-.15 G .928(B, though)-3.427 F(fe)323.2 360.6 Q 5.64(wu)-.25 G +3.14(sers ha)-5.64 F 3.44 -.15(ve n)-.2 H 3.14(eeded to use that f).15 F +3.14(acility directly)-.1 F(.)-.65 E 2.211(Using these interf)323.2 +372.6 R 2.211(aces, Berk)-.1 F(ele)-.1 E 4.711(yD)-.15 G 4.712(Bp)-4.711 +G(ro)-4.712 E 2.212(vides a f)-.15 F(ast,)-.1 E 2.4 +(platform-portable locking system for general-purpose)323.2 384.6 R +2.917(use. It)323.2 396.6 R .418 +(also lets users include non-database objects in a)2.917 F 3.497 +(database transaction, by controlling access to them)323.2 408.6 R -.15 +(ex)323.2 420.6 S(actly as if the).15 E 2.5(yw)-.15 G +(ere inside the database.)-2.5 E .583(The Berk)323.2 436.8 R(ele)-.1 E +3.083(yD)-.15 G 3.084(Bt)-3.083 G -.1(wo)-3.084 G .584(-phase locking f) +.1 F .584(acility is b)-.1 F .584(uilt on)-.2 F .609(the f)323.2 448.8 R +.609(astest correct locking primiti)-.1 F -.15(ve)-.25 G 3.108(st).15 G +.608(hat are supported)-3.108 F 1.967(by the underlying architecture.) +323.2 460.8 R 1.967(In the current imple-)6.967 F .593 +(mentation, this means that the locking system is dif)323.2 472.8 R(fer) +-.25 E(-)-.2 E 1.709(ent on the v)323.2 484.8 R 1.709 +(arious UNIX platforms, and is still more)-.25 F(dif)323.2 496.8 Q .695 +(ferent on W)-.25 F(indo)-.4 E .695(ws NT)-.25 F 5.695(.I)-.74 G 3.195 +(no)-5.695 G .695(ur e)-3.195 F .695(xperience, the most)-.15 F(dif) +323.2 508.8 Q 2.634 +(\214cult aspect of performance tuning is \214nding the)-.25 F -.1(fa) +323.2 520.8 S .883(stest locking primiti).1 F -.15(ve)-.25 G 3.383(st) +.15 G .883(hat w)-3.383 F .882(ork correctly on a par)-.1 F(-)-.2 E 1.26 +(ticular architecture and then inte)323.2 532.8 R 1.26(grating the ne) +-.15 F 3.76(wi)-.25 G(nter)-3.76 E(-)-.2 E -.1(fa)323.2 544.8 S +(ce with the se).1 E -.15(ve)-.25 G(ral that we already support.).15 E +.536(The w)323.2 561 R .536(orld w)-.1 F .536 +(ould be a better place if the operating sys-)-.1 F 2.096 +(tems community w)323.2 573 R 2.096(ould uniformly implement POSIX)-.1 F +1.31(locking primiti)323.2 585 R -.15(ve)-.25 G 3.81(sa).15 G 1.31(nd w) +-3.81 F 1.31(ould guarantee that acquiring)-.1 F 1.085 +(an uncontested lock w)323.2 597 R 1.085(as a f)-.1 F 1.085 +(ast operation.)-.1 F 1.085(Locks must)6.085 F -.1(wo)323.2 609 S 3.641 +(rk both among threads in a single process and).1 F(among processes.) +323.2 621 Q F0 3(3.11. Concurr)323.2 651 R(ency)-.216 E F1 .383 +(Good performance under concurrent operation is a crit-)323.2 667.2 R +.766(ical design point for Berk)323.2 679.2 R(ele)-.1 E 3.266(yD)-.15 G +3.265(B. Although)-3.266 F(Berk)3.265 E(ele)-.1 E(y)-.15 E 1.961 +(DB is itself not multi-threaded, it is thread-safe, and)323.2 691.2 R +.547(runs well in threaded applications.)323.2 703.2 R(Philosophically) +5.546 E 3.046(,w)-.65 G(e)-3.046 E(vie)323.2 715.2 Q 4.764(wt)-.25 G +2.264(he use of threads and the choice of a threads)-4.764 F EP +%%Page: 7 7 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF .066(package as a polic)79.2 84 R 2.566(yd)-.15 +G .065(ecision, and prefer to of)-2.566 F .065(fer mecha-)-.25 F .042 +(nism \(the ability to run threaded or not\), allo)79.2 96 R .043 +(wing appli-)-.25 F(cations to choose their o)79.2 108 Q(wn policies.) +-.25 E 1.947(The locking, logging, and b)79.2 124.2 R(uf)-.2 E 1.947 +(fer pool subsystems all)-.25 F .711 +(use shared memory or other OS-speci\214c sharing f)79.2 136.2 R(acili-) +-.1 E 1.713(ties to communicate.)79.2 148.2 R 1.713(Locks, b)6.713 F(uf) +-.2 E 1.713(fer pool fetches, and)-.25 F 1.061(log writes beha)79.2 +160.2 R 1.361 -.15(ve i)-.2 H 3.561(nt).15 G 1.061(he same w)-3.561 F +1.061(ay across threads in a)-.1 F .033(single process as the)79.2 172.2 +R 2.532(yd)-.15 G 2.532(oa)-2.532 G .032(cross dif)-2.532 F .032 +(ferent processes on a)-.25 F(single machine.)79.2 184.2 Q .896 +(As a result, concurrent database applications may start)79.2 200.4 R +1.651(up a ne)79.2 212.4 R 4.151(wp)-.25 G 1.651(rocess for e)-4.151 F +-.15(ve)-.25 G 1.651(ry single user).15 F 4.151(,m)-.4 G 1.651 +(ay create a)-4.151 F 2.848(single serv)79.2 224.4 R 2.848(er which spa) +-.15 F 2.849(wns a ne)-.15 F 5.349(wt)-.25 G 2.849(hread for e)-5.349 F +-.15(ve)-.25 G(ry).15 E(client request, or may choose an)79.2 236.4 Q +2.5(yp)-.15 G(olic)-2.5 E 2.5(yi)-.15 G 2.5(nb)-2.5 G(etween.)-2.5 E +(Berk)79.2 252.6 Q(ele)-.1 E 3.629(yD)-.15 G 3.629(Bh)-3.629 G 1.128 +(as been carefully designed to minimize)-3.629 F .07 +(contention and maximize concurrenc)79.2 264.6 R 3.87 -.65(y. T)-.15 H +.07(he cache man-).65 F .57(ager allo)79.2 276.6 R .57 +(ws all threads or processes to bene\214t from I/O)-.25 F 2.917 +(done by one.)79.2 288.6 R 2.917(Shared resources must sometimes be) +7.917 F(lock)79.2 300.6 Q 1.804(ed for e)-.1 F(xclusi)-.15 E 2.104 -.15 +(ve a)-.25 H 1.804(ccess by one thread of control.).15 F 1.757 -.8(We h) +79.2 312.6 T -2.25 -.2(av e).8 H -.1(ke)2.857 G .158 +(pt critical sections small, and are careful not).1 F 1.199 +(to hold critical resource locks across system calls that)79.2 324.6 R +.538(could deschedule the locking thread or process.)79.2 336.6 R +(Sleep-)5.539 E .979(ycat Softw)79.2 348.6 R .979 +(are has customers with hundreds of concur)-.1 F(-)-.2 E(rent users w) +79.2 360.6 Q(orking on a single database in production.)-.1 E/F1 12 +/Times-Bold@0 SF 3(4. Engineering)79.2 390.6 R(Philosoph)3 E(y)-.18 E F0 +(Fundamentally)79.2 406.8 Q 3.998(,B)-.65 G(erk)-3.998 E(ele)-.1 E 3.998 +(yD)-.15 G 3.998(Bi)-3.998 G 3.999(sac)-3.998 G 1.499 +(ollection of access)-3.999 F .19(methods with important f)79.2 418.8 R +.19(acilities, lik)-.1 F 2.69(el)-.1 G .19(ogging, locking,)-2.69 F +1.251(and transactional access underlying them.)79.2 430.8 R 1.252 +(In both the)6.252 F .992(research and the commercial w)79.2 442.8 R +.991(orld, the techniques for)-.1 F -.2(bu)79.2 454.8 S 2.727 +(ilding systems lik).2 F 5.227(eB)-.1 G(erk)-5.227 E(ele)-.1 E 5.227(yD) +-.15 G 5.227(Bh)-5.227 G -2.25 -.2(av e)-5.227 H 2.728(been well-)5.427 +F(kno)79.2 466.8 Q(wn for a long time.)-.25 E .443(The k)79.2 483 R .743 +-.15(ey a)-.1 H(dv).15 E .442(antage of Berk)-.25 F(ele)-.1 E 2.942(yD) +-.15 G 2.942(Bi)-2.942 G 2.942(st)-2.942 G .442(he careful atten-)-2.942 +F 1.059(tion that has been paid to engineering details through-)79.2 495 +R 1.039(out its life.)79.2 507 R 2.639 -.8(We h)6.039 H -2.25 -.2(av e) +.8 H 1.039(carefully designed the system so)3.739 F .452 +(that the core f)79.2 519 R .452(acilities, lik)-.1 F 2.952(el)-.1 G +.452(ocking and I/O, surf)-2.952 F .453(ace the)-.1 F .972(right interf) +79.2 531 R .971(aces and are otherwise opaque to the caller)-.1 F(.)-.55 +E .294(As programmers, we understand the v)79.2 543 R .295 +(alue of simplicity)-.25 F .206(and ha)79.2 555 R .506 -.15(ve w)-.2 H +(ork).05 E .206(ed hard to simplify the interf)-.1 F .205(aces we sur) +-.1 F(-)-.2 E -.1(fa)79.2 567 S(ce to users of the database system.).1 E +(Berk)79.2 583.2 Q(ele)-.1 E 4.531(yD)-.15 G 4.531(Ba)-4.531 G -.2(vo) +-4.731 G 2.031(ids limits in the code.).2 F 2.031(It places no)7.031 F +.474(practical limit on the size of k)79.2 595.2 R -.15(ey)-.1 G .473 +(s, v).15 F .473(alues, or databases;)-.25 F(the)79.2 607.2 Q 2.5(ym) +-.15 G(ay gro)-2.5 E 2.5(wt)-.25 G 2.5(oo)-2.5 G(ccup)-2.5 E 2.5(yt)-.1 +G(he a)-2.5 E -.25(va)-.2 G(ilable storage space.).25 E 1.857 +(The locking and logging subsystems ha)79.2 623.4 R 2.157 -.15(ve b)-.2 +H 1.858(een care-).15 F .184 +(fully crafted to reduce contention and impro)79.2 635.4 R .484 -.15 +(ve t)-.15 H(hrough-).15 E 2.16 +(put by shrinking or eliminating critical sections, and)79.2 647.4 R +(reducing the sizes of lock)79.2 659.4 Q(ed re)-.1 E +(gions and log entries.)-.15 E 2.238 +(There is nothing in the design or implementation of)79.2 675.6 R(Berk) +79.2 687.6 Q(ele)-.1 E 2.818(yD)-.15 G 2.818(Bt)-2.818 G .318 +(hat pushes the state of the art in database)-2.818 F 3.545 +(systems. Rather)79.2 699.6 R 3.545(,w)-.4 G 3.545(eh)-3.545 G -2.25 -.2 +(av e)-3.545 H 1.044(been v)3.745 F 1.044(ery careful to get the)-.15 F +4.321(engineering right.)79.2 711.6 R 4.321 +(The result is a system that is)9.321 F(superior)323.2 84 Q 2.867(,a)-.4 +G 2.867(sa)-2.867 G 2.866(ne)-2.867 G .366 +(mbedded database system, to an)-2.866 F 2.866(yo)-.15 G(ther)-2.866 E +(solution a)323.2 96 Q -.25(va)-.2 G(ilable.).25 E .811 +(Most database systems trade of)323.2 112.2 R 3.312(fs)-.25 G .812 +(implicity for correct-)-3.312 F 4.151(ness. Either)323.2 124.2 R 1.651 +(the system is easy to use, or it supports)4.151 F 1.17 +(concurrent use and survi)323.2 136.2 R -.15(ve)-.25 G 3.67(ss).15 G +1.17(ystem f)-3.67 F 3.67(ailures. Berk)-.1 F(ele)-.1 E(y)-.15 E 1.013 +(DB, because of its careful design and implementation,)323.2 148.2 R(of) +323.2 160.2 Q(fers both simplicity and correctness.)-.25 E .759 +(The system has a small footprint, mak)323.2 176.4 R .759 +(es simple opera-)-.1 F 1.012 +(tions simple to carry out \(inserting a ne)323.2 188.4 R 3.512(wr)-.25 +G 1.012(ecord tak)-3.512 F(es)-.1 E 1.16(just a fe)323.2 200.4 R 3.66 +(wl)-.25 G 1.16(ines of code\), and beha)-3.66 F -.15(ve)-.2 G 3.66(sc) +.15 G 1.16(orrectly in the)-3.66 F -.1(fa)323.2 212.4 S .528(ce of hea) +.1 F .527(vy concurrent use, system crashes, and e)-.2 F -.15(ve)-.25 G +(n).15 E(catastrophic f)323.2 224.4 Q(ailures lik)-.1 E 2.5(el)-.1 G +(oss of a hard disk.)-2.5 E F1 3(5. The)323.2 254.4 R(Berk)3 E +(eley DB 2.x Distrib)-.12 E(ution)-.24 E F0(Berk)323.2 270.6 Q(ele)-.1 E +4.171(yD)-.15 G 4.171(Bi)-4.171 G 4.171(sd)-4.171 G(istrib)-4.171 E +1.671(uted in source code form from)-.2 F/F2 10/Times-Italic@0 SF(www) +323.2 282.6 Q(.sleepycat.com)-.74 E F0 7.322(.U)C 2.322 +(sers are free to do)-7.322 F 2.321(wnload and)-.25 F -.2(bu)323.2 294.6 +S(ild the softw).2 E(are, and to use it in their applications.)-.1 E F1 +3(5.1. What)323.2 324.6 R(is in the distrib)3 E(ution)-.24 E F0 4.827 +(The distrib)323.2 340.8 R 4.827(ution is a compressed archi)-.2 F 5.127 +-.15(ve \214)-.25 H 7.328(le. It).15 F .057 +(includes the source code for the Berk)323.2 352.8 R(ele)-.1 E 2.556(yD) +-.15 G 2.556(Bl)-2.556 G(ibrary)-2.556 E 2.556(,a)-.65 G(s)-2.556 E .453 +(well as documentation, test suites, and supporting utili-)323.2 364.8 R +(ties.)323.2 376.8 Q 2.613(The source code includes b)323.2 393 R 2.612 +(uild support for all sup-)-.2 F .254(ported platforms.)323.2 405 R .254 +(On UNIX systems Berk)5.254 F(ele)-.1 E 2.755(yD)-.15 G 2.755(Bu)-2.755 +G(ses)-2.755 E 1.28(the GNU autocon\214guration tool,)323.2 417 R/F3 10 +/Courier@0 SF(autoconf)3.78 E F0 3.78(,t)C 3.78(oi)-3.78 G(den-)-3.78 E +.992(tify the system and to b)323.2 429 R .992 +(uild the library and supporting)-.2 F 3.589(utilities. Berk)323.2 441 R +(ele)-.1 E 3.589(yD)-.15 G 3.588(Bi)-3.589 G 1.088(ncludes speci\214c b) +-3.588 F 1.088(uild en)-.2 F(viron-)-.4 E .515 +(ments for other platforms, such as VMS and W)323.2 453 R(indo)-.4 E +(ws.)-.25 E F1 3(5.1.1. Documentation)323.2 483 R F0 5.008(The distrib) +323.2 499.2 R 5.008(uted system includes documentation in)-.2 F 1.626 +(HTML format.)323.2 511.2 R 1.626(The documentation is in tw)6.626 F +4.127(op)-.1 G 1.627(arts: a)-4.127 F .725 +(UNIX-style reference manual for use by programmers,)323.2 523.2 R +(and a reference guide which is tutorial in nature.)323.2 535.2 Q F1 3 +(5.1.2. T)323.2 565.2 R(est suite)-1.104 E F0 1.107(The softw)323.2 +581.4 R 1.108(are also includes a complete test suite, writ-)-.1 F .155 +(ten in Tcl.)323.2 593.4 R 1.754 -.8(We b)5.154 H(elie).8 E .454 -.15 +(ve t)-.25 H .154(hat the test suite is a k).15 F .454 -.15(ey a)-.1 H +(dv).15 E(an-)-.25 E(tage of Berk)323.2 605.4 Q(ele)-.1 E 2.5(yD)-.15 G +2.5(Bo)-2.5 G -.15(ve)-2.65 G 2.5(rc).15 G(omparable systems.)-2.5 E +2.612(First, the test suite allo)323.2 621.6 R 2.613(ws users who do) +-.25 F 2.613(wnload and)-.25 F -.2(bu)323.2 633.6 S 1.731(ild the softw) +.2 F 1.731(are to be sure that it is operating cor)-.1 F(-)-.2 E(rectly) +323.2 645.6 Q(.)-.65 E .893(Second, the test suite allo)323.2 661.8 R +.894(ws us, lik)-.25 F 3.394(eo)-.1 G .894(ther commercial)-3.394 F(de) +323.2 673.8 Q -.15(ve)-.25 G .536(lopers of database softw).15 F .536 +(are, to e)-.1 F -.15(xe)-.15 G .535(rcise the system).15 F 2.256 +(thoroughly at e)323.2 685.8 R -.15(ve)-.25 G 2.256(ry release.).15 F +2.256(When we learn of ne)7.256 F(w)-.25 E -.2(bu)323.2 697.8 S 1.719 +(gs, we add them to the test suite.).2 F 3.319 -.8(We r)6.719 H 1.719 +(un the test).8 F 5.692(suite continually during de)323.2 709.8 R -.15 +(ve)-.25 G 5.692(lopment c).15 F 5.692(ycles, and)-.15 F EP +%%Page: 8 8 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 10/Times-Roman@0 SF(al)79.2 84 Q -.1(wa)-.1 G .314 +(ys prior to release.).1 F .314(The result is a much more reli-)5.314 F +(able system by the time it reaches beta release.)79.2 96 Q/F1 12 +/Times-Bold@0 SF 3(5.2. Binary)79.2 126 R(distrib)3 E(ution)-.24 E F0 +(Sleep)79.2 142.2 Q .893(ycat mak)-.1 F .893 +(es compiled libraries and general binary)-.1 F(distrib)79.2 154.2 Q +(utions a)-.2 E -.25(va)-.2 G(ilable to customers for a fee.).25 E F1 3 +(5.3. Supported)79.2 184.2 R(platf)3 E(orms)-.3 E F0(Berk)79.2 200.4 Q +(ele)-.1 E 5.623(yD)-.15 G 5.623(Br)-5.623 G 3.123(uns on an)-5.623 F +5.622(yo)-.15 G 3.122(perating system with a)-5.622 F .816 +(POSIX 1003.1 interf)79.2 212.4 R .817(ace [IEEE96], which includes vir) +-.1 F(-)-.2 E 1.998(tually e)79.2 224.4 R -.15(ve)-.25 G 1.997 +(ry UNIX system.).15 F 1.997(In addition, the softw)6.997 F(are)-.1 E +2.85(runs on VMS, W)79.2 236.4 R(indo)-.4 E 2.85(ws/95, W)-.25 F(indo) +-.4 E 2.85(ws/98, and W)-.25 F(in-)-.4 E(do)79.2 248.4 Q(ws/NT)-.25 E +10.21(.S)-.74 G(leep)-10.21 E 5.21(ycat Softw)-.1 F 5.21 +(are no longer supports)-.1 F(deplo)79.2 260.4 Q(yment on sixteen-bit W) +-.1 E(indo)-.4 E(ws systems.)-.25 E F1 3(6. Berk)79.2 290.4 R +(eley DB 2.x Licensing)-.12 E F0(Berk)79.2 306.6 Q(ele)-.1 E 2.627(yD) +-.15 G 2.627(B2)-2.627 G .128(.x is distrib)-2.627 F .128 +(uted as an Open Source prod-)-.2 F 4.709(uct. The)79.2 318.6 R(softw) +4.709 E 2.209(are is freely a)-.1 F -.25(va)-.2 G 2.209 +(ilable from us at our).25 F -.8(We)79.2 330.6 S 3.372(bs).8 G .872 +(ite, and in other media.)-3.372 F .872(Users are free to do)5.872 F +(wn-)-.25 E(load the softw)79.2 342.6 Q(are and b)-.1 E +(uild applications with it.)-.2 E 1.023(The 1.x v)79.2 358.8 R 1.022 +(ersions of Berk)-.15 F(ele)-.1 E 3.522(yD)-.15 G 3.522(Bw)-3.522 G +1.022(ere co)-3.522 F -.15(ve)-.15 G 1.022(red by the).15 F 3.763 +(UC Berk)79.2 370.8 R(ele)-.1 E 6.263(yc)-.15 G(op)-6.263 E 3.763 +(yright that co)-.1 F -.15(ve)-.15 G 3.764(rs softw).15 F 3.764 +(are freely)-.1 F(redistrib)79.2 382.8 Q 1.742(utable in source form.) +-.2 F 1.741(When Sleep)6.742 F 1.741(ycat Soft-)-.1 F -.1(wa)79.2 394.8 +S .906(re w).1 F .907(as formed, we needed to draft a license consis-) +-.1 F 2.319(tent with the cop)79.2 406.8 R 2.319(yright go)-.1 F -.15 +(ve)-.15 G 2.318(rning the e).15 F 2.318(xisting, older)-.15 F(softw) +79.2 418.8 Q 5.328(are. Because)-.1 F 2.828(of important dif)5.328 F +2.828(ferences between)-.25 F .497(the UC Berk)79.2 430.8 R(ele)-.1 E +2.997(yc)-.15 G(op)-2.997 E .497(yright and the GPL, it w)-.1 F .496 +(as impos-)-.1 F .884(sible for us to use the GPL.)79.2 442.8 R 3.384 +(As)5.884 G .884(econd cop)-3.384 F .884(yright, with)-.1 F .87 +(terms contradictory to the \214rst, simply w)79.2 454.8 R .87 +(ould not ha)-.1 F -.15(ve)-.2 G -.1(wo)79.2 466.8 S(rk).1 E(ed.)-.1 E +(Sleep)79.2 483 Q 2.533(ycat w)-.1 F 2.533 +(anted to continue Open Source de)-.1 F -.15(ve)-.25 G(lop-).15 E 2.079 +(ment of Berk)79.2 495 R(ele)-.1 E 4.579(yD)-.15 G 4.579(Bf)-4.579 G +2.079(or se)-4.579 F -.15(ve)-.25 G 2.079(ral reasons.).15 F 3.678 -.8 +(We a)7.078 H(gree).8 E .853 +(with Raymond [Raym98] and others that Open Source)79.2 507 R(softw)79.2 +519 Q .763(are is typically of higher quality than proprietary)-.1 F(,) +-.65 E 2.616(binary-only products.)79.2 531 R 2.617 +(Our customers bene\214t from a)7.616 F .983(community of de)79.2 543 R +-.15(ve)-.25 G .983(lopers who kno).15 F 3.483(wa)-.25 G .983 +(nd use Berk)-3.483 F(ele)-.1 E(y)-.15 E 1.317 +(DB, and can help with application design, deb)79.2 555 R(ugging,)-.2 E +1.65(and performance tuning.)79.2 567 R -.4(Wi)6.65 G 1.65 +(despread distrib).4 F 1.65(ution and)-.2 F 1.017 +(use of the source code tends to isolate b)79.2 579 R 1.017(ugs early) +-.2 F 3.517(,a)-.65 G(nd)-3.517 E .032(to get \214x)79.2 591 R .031 +(es back into the distrib)-.15 F .031(uted system quickly)-.2 F 5.031 +(.A)-.65 G(s)-5.031 E 3.553(ar)79.2 603 S 1.053(esult, Berk)-3.553 F +(ele)-.1 E 3.553(yD)-.15 G 3.553(Bi)-3.553 G 3.553(sm)-3.553 G 1.053 +(ore reliable.)-3.553 F 1.054(Just as impor)6.054 F(-)-.2 E(tantly)79.2 +615 Q 3.695(,i)-.65 G(ndi)-3.695 E 1.195 +(vidual users are able to contrib)-.25 F 1.195(ute ne)-.2 F 3.695(wf) +-.25 G(ea-)-3.695 E 1.056 +(tures and performance enhancements, to the bene\214t of)79.2 627 R +-2.15 -.25(ev e)79.2 639 T .359(ryone who uses Berk).25 F(ele)-.1 E +2.859(yD)-.15 G 2.859(B. From)-2.859 F 2.858(ab)2.859 G .358 +(usiness per)-3.058 F(-)-.2 E(specti)79.2 651 Q -.15(ve)-.25 G 3.115(,O) +.15 G .615(pen Source and free distrib)-3.115 F .615(ution of the soft-) +-.2 F -.1(wa)79.2 663 S 1.605(re creates share for us, and gi).1 F -.15 +(ve)-.25 G 4.105(su).15 G 4.105(sam)-4.105 G(ark)-4.105 E 1.605(et into) +-.1 F .412(which we can sell products and services.)79.2 675 R(Finally) +5.413 E 2.913(,m)-.65 G(ak-)-2.913 E .148(ing the source code freely a) +79.2 687 R -.25(va)-.2 G .147(ilable reduces our support).25 F 2.436 +(load, since customers can \214nd and \214x b)79.2 699 R 2.437 +(ugs without)-.2 F(recourse to us, in man)79.2 711 Q 2.5(yc)-.15 G +(ases.)-2.5 E 4.727 -.8(To p)323.2 84 T(reserv).8 E 5.627(et)-.15 G +3.126(he Open Source heritage of the older)-5.627 F(Berk)323.2 96 Q(ele) +-.1 E 3.003(yD)-.15 G 3.003(Bc)-3.003 G .504(ode, we drafted a ne)-3.003 +F 3.004(wl)-.25 G .504(icense go)-3.004 F -.15(ve)-.15 G(rning).15 E +.417(the distrib)323.2 108 R .417(ution of Berk)-.2 F(ele)-.1 E 2.916 +(yD)-.15 G 2.916(B2)-2.916 G 2.916(.x. W)-2.916 F 2.916(ea)-.8 G .416 +(dopted terms)-2.916 F .411(from the GPL that mak)323.2 120 R 2.911(ei) +-.1 G 2.911(ti)-2.911 G .411(mpossible to turn our Open)-2.911 F 1.289 +(Source code into proprietary code o)323.2 132 R 1.288(wned by someone) +-.25 F(else.)323.2 144 Q(Brie\215y)323.2 160.2 Q 3.18(,t)-.65 G .68 +(he terms go)-3.18 F -.15(ve)-.15 G .68(rning the use and distrib).15 F +.68(ution of)-.2 F(Berk)323.2 172.2 Q(ele)-.1 E 2.5(yD)-.15 G 2.5(Ba) +-2.5 G(re:)-2.5 E/F2 8/Times-Roman@0 SF<83>328.2 188.4 Q F0 +(your application must be internal to your site, or)17.2 E F2<83>328.2 +204.6 Q F0 .612(your application must be freely redistrib)17.2 F .611 +(utable in)-.2 F(source form, or)348.2 216.6 Q F2<83>328.2 232.8 Q F0 +(you must get a license from us.)17.2 E -.15(Fo)323.2 249 S 2.631(rc).15 +G .131(ustomers who prefer not to distrib)-2.631 F .132(ute Open Source) +-.2 F 1.493(products, we sell licenses to use and e)323.2 261 R 1.492 +(xtend Berk)-.15 F(ele)-.1 E(y)-.15 E(DB at a reasonable cost.)323.2 273 +Q 2.675 -.8(We w)323.2 289.2 T 1.076 +(ork hard to accommodate the needs of the Open).7 F .606 +(Source community)323.2 301.2 R 5.606(.F)-.65 G .606(or e)-5.756 F .606 +(xample, we ha)-.15 F .905 -.15(ve c)-.2 H .605(rafted spe-).15 F 1.415 +(cial licensing arrangements with Gnome to encourage)323.2 313.2 R +(its use and distrib)323.2 325.2 Q(ution of Berk)-.2 E(ele)-.1 E 2.5(yD) +-.15 G(B.)-2.5 E(Berk)323.2 341.4 Q(ele)-.1 E 4.103(yD)-.15 G 4.103(Bc) +-4.103 G 1.603(onforms to the Open Source de\214nition)-4.103 F 4.867 +([Open99]. The)323.2 353.4 R 2.367 +(license has been carefully crafted to)4.867 F -.1(ke)323.2 365.4 S .643 +(ep the product a).1 F -.25(va)-.2 G .642(ilable as an Open Source of) +.25 F(fering,)-.25 E(while pro)323.2 377.4 Q +(viding enough of a return on our in)-.15 E -.15(ve)-.4 G(stment to).15 +E 1.546(fund continued de)323.2 389.4 R -.15(ve)-.25 G 1.546 +(lopment and support of the prod-).15 F 3.033(uct. The)323.2 401.4 R +.534(current license has created a b)3.033 F .534(usiness capable)-.2 F +.916(of funding three years of de)323.2 413.4 R -.15(ve)-.25 G .916 +(lopment on the softw).15 F(are)-.1 E(that simply w)323.2 425.4 Q +(ould not ha)-.1 E .3 -.15(ve h)-.2 H(appened otherwise.).15 E F1 3 +(7. Summary)323.2 455.4 R F0(Berk)323.2 471.6 Q(ele)-.1 E 2.991(yD)-.15 +G 2.991(Bo)-2.991 G -.25(ff)-2.991 G .491 +(ers a unique collection of features, tar).25 F(-)-.2 E .175 +(geted squarely at softw)323.2 483.6 R .174(are de)-.1 F -.15(ve)-.25 G +.174(lopers who need simple,).15 F .492 +(reliable database management services in their applica-)323.2 495.6 R +5.3(tions. Good)323.2 507.6 R 2.8(design and implementation and careful) +5.3 F 1.633(engineering throughout mak)323.2 519.6 R 4.133(et)-.1 G +1.633(he softw)-4.133 F 1.634(are better than)-.1 F(man)323.2 531.6 Q +2.5(yo)-.15 G(ther systems.)-2.5 E(Berk)323.2 547.8 Q(ele)-.1 E 4.1(yD) +-.15 G 4.1(Bi)-4.1 G 4.1(sa)-4.1 G 4.1(nO)-4.1 G 1.6 +(pen Source product, a)-4.1 F -.25(va)-.2 G 1.6(ilable at).25 F/F3 10 +/Times-Italic@0 SF(www)323.2 559.8 Q(.sleepycat.com)-.74 E F0 .654 +(for do)3.154 F 3.154(wnload. The)-.25 F(distrib)3.154 E .654(uted sys-) +-.2 F .383(tem includes e)323.2 571.8 R -.15(ve)-.25 G .383 +(rything needed to b).15 F .382(uild and deplo)-.2 F 2.882(yt)-.1 G(he) +-2.882 E(softw)323.2 583.8 Q(are or to port it to ne)-.1 E 2.5(ws)-.25 G +(ystems.)-2.5 E(Sleep)323.2 600 Q 2.633(ycat Softw)-.1 F 2.633 +(are distrib)-.1 F 2.633(utes Berk)-.2 F(ele)-.1 E 5.133(yD)-.15 G 5.134 +(Bu)-5.133 G 2.634(nder a)-5.134 F .764(license agreement that dra)323.2 +612 R .764(ws on both the UC Berk)-.15 F(ele)-.1 E(y)-.15 E(cop)323.2 +624 Q 2.377(yright and the GPL.)-.1 F 2.377(The license guarantees that) +7.377 F(Berk)323.2 636 Q(ele)-.1 E 3.384(yD)-.15 G 3.384(Bw)-3.384 G +.884(ill remain an Open Source product and)-3.384 F(pro)323.2 648 Q +1.493(vides Sleep)-.15 F 1.493(ycat with opportunities to mak)-.1 F +3.994(em)-.1 G(one)-3.994 E(y)-.15 E(to fund continued de)323.2 660 Q +-.15(ve)-.25 G(lopment on the softw).15 E(are.)-.1 E EP +%%Page: 9 9 +%%BeginPageSetup +BP +%%EndPageSetup +/F0 12/Times-Bold@0 SF 3(8. Refer)79.2 84 R(ences)-.216 E/F1 10 +/Times-Roman@0 SF([Come79])79.2 100.2 Q(Comer)104.2 112.2 Q 3.127(,D)-.4 +G .627(., \231The Ubiquitous B-tree,)-3.127 F<9a>-.7 E/F2 10 +/Times-Italic@0 SF -.3(AC)3.126 G 3.126(MC).3 G(om-)-3.126 E .404 +(puting Surve)104.2 124.2 R(ys)-.3 E F1 -1.29(Vo)2.904 G .404 +(lume 11, number 2, June 1979.)1.29 F([Gray93])79.2 140.4 Q(Gray)104.2 +152.4 Q 2.982(,J)-.65 G .482(., and Reuter)-2.982 F 2.982(,A)-.4 G(.,) +-2.982 E F2 -1.55 -.55(Tr a)2.981 H .481(nsaction Pr).55 F(ocessing:) +-.45 E 6.776(Concepts and T)104.2 164.4 R(ec)-.92 E(hniques)-.15 E F1 +9.277(,M)C(or)-9.277 E -.05(ga)-.18 G(n-Kaufman).05 E(Publishers, 1993.) +104.2 176.4 Q([IEEE96])79.2 192.6 Q .364 +(Institute for Electrical and Electronics Engineers,)104.2 204.6 R F2 +(IEEE/ANSI Std 1003.1)104.2 216.6 Q F1 2.5(,1)C(996 Edition.)-2.5 E +([Litw80])79.2 232.8 Q 2.365(Litwin, W)104.2 244.8 R 2.366 +(., \231Linear Hashing: A Ne)-.92 F 4.866(wT)-.25 G 2.366(ool for)-5.666 +F 1.784(File and T)104.2 256.8 R 1.783(able Addressing,)-.8 F<9a>-.7 E +F2(Pr)4.283 E 1.783(oceedings of the)-.45 F 4.804 +(6th International Confer)104.2 268.8 R 4.804(ence on V)-.37 F 4.804 +(ery Lar)-1.11 F -.1(ge)-.37 G 1.983(Databases \(VLDB\))104.2 280.8 R F1 +4.483(,M)C 1.982(ontreal, Quebec, Canada,)-4.483 F(October 1980.)104.2 +292.8 Q([Open94])79.2 309 Q 4.068(The Open Group,)104.2 321 R F2 +(Distrib)6.568 E 4.069(uted TP: The XA+)-.2 F .78(Speci\214cation, V) +104.2 333 R(er)-1.11 E .78(sion 2)-.1 F F1 3.28(,T)C .78 +(he Open Group, 1994.)-3.28 F([Open99])79.2 349.2 Q(Opensource.or)104.2 +361.2 Q 8.307(g, \231Open Source De\214nition,)-.18 F<9a>-.7 E F2(www) +104.2 373.2 Q(.opensour)-.74 E(ce)-.37 E(.or)-.15 E(g/osd.html)-.37 E F1 +3.13(,v)C .63(ersion 1.4, 1999.)-3.28 F([Raym98])79.2 389.4 Q .718 +(Raymond, E.S., \231The Cathedral and the Bazaar)104.2 401.4 R -.7<2c9a> +-.4 G F2(www)104.2 413.4 Q(.tuxedo.or)-.74 E(g/~esr/writings/cathedr) +-.37 E(al-)-.15 E(bazaar/cathedr)104.2 425.4 Q(al-bazaar)-.15 E(.html) +-1.11 E F1 2.5(,J)C(anuary 1998.)-2.5 E([Selt91])79.2 441.6 Q(Seltzer) +104.2 453.6 Q 2.578(,M)-.4 G .078(., and Y)-2.578 F .079(igit, O., \231) +-.55 F 2.579(AN)-.8 G .579 -.25(ew H)-2.579 H .079(ashing P).25 F(ack-) +-.15 E 6.704(age for UNIX,)104.2 465.6 R<9a>-.7 E F2(Pr)9.204 E 6.704 +(oceedings 1991 W)-.45 F(inter)-.55 E(USENIX Confer)104.2 477.6 Q(ence) +-.37 E F1 2.5(,D)C(allas, TX, January 1991.)-2.5 E([Selt92])79.2 493.8 Q +(Seltzer)104.2 505.8 Q 5.365(,M)-.4 G 2.865 +(., and Olson, M., \231LIBTP: Portable)-5.365 F 2.845(Modular T)104.2 +517.8 R 2.845(ransactions for UNIX,)-.35 F<9a>-.7 E F2(Pr)5.345 E +(oceedings)-.45 E 1.49(1992 W)104.2 529.8 R 1.49(inter Usenix Confer) +-.55 F(ence)-.37 E F1 3.99(,S)C 1.49(an Francisco,)-3.99 F +(CA, January 1992.)104.2 541.8 Q([Ston82])79.2 558 Q(Stonebrak)104.2 570 +Q(er)-.1 E 10.04(,M)-.4 G 7.54(., Stettner)-10.04 F 10.04(,H)-.4 G 7.54 +(., Kalash, J.,)-10.04 F .763(Guttman, A., and L)104.2 582 R .764 +(ynn, N., \231Document Process-)-.55 F .557 +(ing in a Relational Database System,)104.2 594 R 3.056<9a4d>-.7 G +(emoran-)-3.056 E .825(dum No. UCB/ERL M82/32, Uni)104.2 606 R -.15(ve) +-.25 G .825(rsity of Cali-).15 F(fornia at Berk)104.2 618 Q(ele)-.1 E +1.3 -.65(y, B)-.15 H(erk).65 E(ele)-.1 E 1.3 -.65(y, C)-.15 H +(A, May 1982.).65 E EP +%%Trailer +end +%%EOF diff --git a/db/docs/ref/refs/embedded.html b/db/docs/ref/refs/embedded.html new file mode 100644 index 000000000..b7641d931 --- /dev/null +++ b/db/docs/ref/refs/embedded.html @@ -0,0 +1,672 @@ + + +Challenges in Embedded Database System Administration + + +
+

Challenges in Embedded Database System Administration

+

Margo Seltzer, Harvard University

+

Michael Olson, Sleepycat Software, Inc.

+{margo,mao}@sleepycat.com +
+

+Database configuration and maintenance have historically been complex tasks, +often +requiring expert knowledge of database design and application +behavior. +In an embedded environment, it is not feasible to require such +expertise and ongoing database maintenance. +This paper discusses the database administration +challenges posed by embedded systems and describes how the +Berkeley DB architecture addresses these challenges. + +

1. Introduction

+ +Embedded systems provide a combination of opportunities and challenges +in application and system configuration and management. +As an embedded system is most often dedicated to a single application or +small set of tasks, the operating conditions of the system are +typically better understood than those of general purpose computing +environments. +Similarly, as embedded systems are dedicated to a small set of tasks, +one would expect that the software to manage them should be small +and simple. +On the other hand, once an embedded system is deployed, it must +continue to function without interruption and without administrator +intervention. +

+Database administration consists of two components, +initial configuration and ongoing maintenance. +Initial configuration consists of database design, manifestation, +and tuning. +The instantiation of the design includes decomposing the design +into tables, relations, or objects and designating proper indices +and their implementations (e.g., Btrees, hash tables, etc.). +Tuning a design requires selecting a location for the log and +data files, selecting appropriate database page sizes, specifying +the size of in-memory caches, and specifying the limits of +multi-threading and concurrency. +As embedded systems define a specific environment and set of tasks, +requiring expertise during the initial system +configuration process is acceptable, and we focus our efforts on +the ongoing maintenance of the system. +In this way, our emphasis differs from other projects such as +Microsoft's AutoAdmin project [3], and the "no-knobs" +administration that is identified as an area of important future +research by the Asilomar authors[1]. +

+In this paper, we focus on what the authors +of the Asilomar report call "gizmo" databases [1], +databases +that reside in devices such as smart cards, toasters, or telephones. +The key characteristics of such databases are that their +functionality is completely transparent to users, no one ever +performs explicit database operations or +database maintenance, the database may crash at any time and +must recover instantly, the device may undergo a hard reset at +any time, requiring that the database return to its initial +state, and the semantic integrity of the database must be maintained +at all times. +In Section 2, we provide more detail on the sorts of tasks +typically performed by database administrators (DBAs) that must +be automated in an embedded system. +

+The rest of this paper is structured as follows. +In Section 2, we outline the requirements for embedded database support. +In Section 3, we discuss how Berkeley DB +is conducive to the hands-off management +required in embedded systems. +In Section 4, we discuss novel features that +enhance Berkeley +DB's suitability for the embedded applications. +In Section 5, we discuss issues of footprint size. +In Section 6 we discuss related work, and we conclude +in Section 7. + +

2. Embedded Database Requirements

+Historically, much of the commercial database industry has been driven +by the requirements of high performance online transaction +processing (OLTP), complex query processing, and the industry +standard benchmarks that have emerged (e.g., TPC-C [9], +TPC-D [10]) to +allow for system comparisons. +As embedded systems typically perform fairly simple queries, +such metrics are not nearly as relevant for embedded database +systems as are ease of maintenance, robustness, and small footprint. +Of these three requirements, robustness and ease of maintenance +are the key issues. +Users must trust the data stored in their devices and must not need +to manually perform anything resembling system administration in order +to get their unit to work properly. +Fortunately, ease of use and robustness are important side +effects of simplicity and good design. +These, in turn, lead to a small size, providing the third +requirement of an embedded system. +

2.1 The User Perspective

+

+In the embedded database arena, it is the ongoing maintenance tasks +that must be automated, not necessarily the initial system configuration. +There are five tasks +that are traditionally performed by DBAs, +but must be performed automatically +in embedded database systems. +These tasks are +log archival and reclamation, +backup, +data compaction/reorganization, +automatic and rapid recovery, and +reinitialization from scratch. +

+Log archival and backup are tightly coupled. +Database backups are part of any +large database installation, and log archival is analogous to incremental +backup. +It is not clear what the implications of backup and archival are in +an embedded system. +Consumers do not back up their VCRs or refrigerators, yet they do +(or should) back up their personal computers or personal digital +assistants. +For the remainder of this paper, we assume that backups, in some form, +are required for gizmo databases (imagine having to reprogram, manually, +the television viewing access pattern learned by some set-top television +systems today). +Furthermore, we require that those backups are nearly instantaneous or +completely transparent, +as users should not be aware that their gizmos are being backed up +and should not have to explicitly initiate such backups. +

+Data compaction or reorganization has traditionally required periodic +dumping and restoration of +database tables and the recreation of indices. +In an embedded system, such reorganization must happen automatically. +

+Recovery issues are similar in embedded and traditional environments +with a few exceptions. +While a few seconds or even a minute recovery is acceptable +for a large server installation, no one is willing to wait +for their telephone or television to reboot. +As with archival, recovery must be nearly instantaneous in an embedded product. +Secondly, it is often the case that a system will be completely +reinitialized, rather than simply rebooted. +In this case, the embedded database must be restored to its initial +state, freeing all its resources. +This is not typically a requirement of large server systems. +

2.2 The Developer Perspective

+

+In addition to the maintenance-free operation required of the +embedded systems, there are a number of requirements that fall +out of the constrained resources typically found in the "gizmos" +using gizmo databases. These requirements are: +small footprint, +short code-path, +programmatic interface for tight application coupling and +to avoid the overhead (in both time and size) of +interfaces such as SQL and ODBC, +application configurability and flexibility, +support for complete memory-resident operation (e.g., these systems +must run on gizmos without file systems), and +support for multi-threading. +

+A small footprint and short code-path are self-explanatory, however +what is not as obvious is that the programmatic interface requirement +is the logical result of them. +Traditional interfaces such as ODBC and SQL add significant +size overhead and frequently add multiple context/thread switches +per operation, not to mention several IPC calls. +An embedded product is less likely to require the complex +query processing that SQL enables. +Instead, in the embedded space, the ability for an application +to configure the database for the specific tasks in question +is more important than a general query interface. +

+As some systems do not provide storage other than RAM and ROM, +it is essential that an embedded database work seemlessly +in memory-only environments. +Similarly, many of today's embedded operating systems provide a +single address space architecture, so a simple, multi-threaded +capability is essential for application requiring any concurrency. +

+In general, embedded applications run on gizmos whose native +operating system support varies tremendously. +For example, the embedded OS may or may +not support user-level processing or multi-threading. +Even if it does, a particular embedded +application may or may not need it. +Not all applications need more than one thread of control. +An embedded database must provide mechanisms to developers +without deciding policy. +For example, the threading model in an application is a matter of policy, +and depends +not on the database software, but on the hardware, operating +system, and the application's feature set. +Therefore, the data manager must provide for the use of multi-threading, +but not require it. + +

3. Berkeley DB: A Database for Embedded Systems

+Berkeley DB is the result of implementing database functionality +using the UNIX tool-based philosophy. +The current Berkeley DB package, as distributed by Sleepycat +Software, is a descendant of the hash and btree access methods +distributed with 4.4BSD and its descendents. +The original package (referred to as DB-1.85), +while intended as a public domain replacement for dbm and +its followers (e.g., ndbm, gdbm, etc), rapidly became widely +used as an efficient, easy-to-use data store. +It was incorporated into a number of Open Source packages including +Perl, Sendmail, Kerberos, and the GNU C-library. +

+Versions 2.X and higher are distributed by Sleepycat Software and +add functionality for concurrency, logging, transactions, and +recovery. +Each piece of additional functionality is implemented as an independent +module, which means that the subsystems can be used outside the +context of Berkeley DB. For example, the locking subsystem can +easily be used to implement locking for a non-DB application and +the shared memory buffer pool can be used for any application +caching data in main memory. +This subsystem design allows a designer to pick and choose +the functionality necessary for the application, minimizing +memory footprint and maximizing performance. +This addresses the small footprint and short code-path criteria +mentioned in the previous section. +

+As Berkeley DB grew out of a replacement for dbm, its primary +implementation language has always been C and its interface has +been programmatic. The C interface is the native interface, +unlike many database systems where the programmatic API is simply +a layer on top of an already-costly query interface (e.g. embedded +SQL). +Berkeley DB's heritage is also apparent in its data model; it has +none. +The database stores unstructured key/data pairs, specified as +variable length byte strings. +This leaves schema design and representation issues the responsibility +of the application, which is ideal for an embedded environment. +Applications retain full control over specification of their data +types, representation, index values, and index relationships. +In other words, Berkeley DB provides a robust, high-performance, +keyed storage system, not a particular database management system. +We have designed for simplicity and performance, trading off +complex, general purpose support that is better encapsulated in +applications. +

+Another element of Berkeley DB's programmatic interface is its +customizability; applications can specify Btree comparison and +prefix compression functions, hash functions, error routines, +and recovery models. +This means that embedded applications can tailor the underlying +database to best suit their data demands. +Similarly, the utilities traditionally bundled with a database +manager (e.g., recovery, dump/restore, archive) are implemented +as tiny wrapper programs around library routines. This means +that it is not necessary to run separate applications for the +utilities. Instead, independent threads can act as utility +daemons, or regular query threads can perform utility functions. +Many of the current products built on Berkeley DB are bundled as +a single large server with independent threads that perform functions +such as checkpoint, deadlock detection, and performance monitoring. +

+As mentioned earlier, living in an embedded environment requires +flexible management of storage. +Berkeley DB does not require any preallocation of disk space +for log or data files. +While many commercial database systems take complete control +of a raw device, Berkeley DB uses a normal file system, and +can therefore, safely and easily share a data space with other +programs. +All databases and log files are native files of the host environment, +so whatever utilities are provided by the environment can be used +to manage database files as well. +

+Berkeley DB provides three different memory models for its +management of shared information. +Applications can use the IEEE Std 1003.1b-1993 (POSIX) mmap +interface to share +data, they can use system shared memory, as frequently provided +by the shmget family of interfaces, or they can use per-process +heap memory (e.g., malloc). +Applications that require no permanent storage and do not provide +shared memory facilities can still use Berkeley DB by requesting +strictly private memory and specifying that all databases be +memory-resident. +This provides pure-memory operation. +

+Lastly, Berkeley DB is designed for rapid startup -- recovery can +happen automatically as part of system initialization. +This means that Berkeley DB works correctly in environments where +gizmos are suddenly shut down and restarted. + +

4. Extensions for Embedded Environments

+While the Berkeley DB library has been designed for use in +embedded systems, all the features described above are useful +in more conventional systems as well. +In this section, we discuss a number of features and "automatic +knobs" that are specifically geared +toward the more constrained environments found in gizmo databases. + +

4.1 Automatic compression

+Following the programmatic interface design philosophy, we +support application-specific (or default) compression routines. +These can be geared toward the particular data types present +in the application's dataset, thus providing better compression +than a general purpose routine. +Note that the application could instead specify an encryption +function and create encrypted databases instead of compressed ones. +Alternately, the application might specify a function that performs +both compression and encryption. +

+As applications are also permitted to specify comparison and hash +functions, the application can chose to organize its data based +either on uncompressed and clear-text data or compressed and encrypted +data. +If the application indicates that data should be compared in its +processed form (i.e., compressed and encrypted), then the compression +and encryption are performed on individual data items and the in-memory +representation retains these characteristics. +However, if the application indicates that data should be compared in +its original form, then entire pages are transformed upon being read +into or written out of the main memory buffer cache. +These two alternatives provide the flexibility to trade space +and security for performance. + +

4.2 In-memory logging & transactions

+One of the four key properties of transaction systems is durability. +This means that transaction systems are designed for permanent storage +(most commonly disk). However, as mentioned above, embedded systems +do not necessarily contain any such storage. +Nevertheless, transactions can be useful in this environment to +preserve the semantic integrity of the underlying storage. +Berkeley DB optionally provides logging functionality and +transaction support regardless of whether the database and logs +are on disk or in memory. + +

4.3 Remote Logs

+While we do not expect users to backup their television sets and +toasters, it is conceivable that a set-top box provided by a +cable carrier should, in fact, be backed up by that cable carrier. +The ability to store logs remotely can provide "information appliance" +functionality, and can also be used in conjunction with local logs +to enhance reliability. +Furthermore, remote logs provide for catastrophic recovery, e.g., loss +of the gizmo, destruction of the gizmo, etc. + +

4.4 Application References to Database Buffers

+ +Typically, when data is returned to the user, it must be copied +from the data manager's buffer cache (or data page) into the +application's memory. +However, in an embedded environment, the robustness of the +total software package is of paramount importance, not the +isolation between the application and the data manager. +As a result, it is possible for the data manager to avoid +copies by giving applications direct references to data items +in a shared memory cache. +This is a significant performance optimization that can be +allowed when the application and data manager are tightly +integrated. + +

4.5 Recoverable database creation/deletion

+ +In a conventional database management system, the creation of +database tables (relations) and indices are heavyweight operations +that are not recoverable. +This is not acceptable in a complex embedded environment where +instantaneous recovery and robust operation in the face of +all types of database operations is essential. +While Berkeley DB files can be removed using normal file system +utilities, we provide transaction protected utilities that +allow us to recover both database creation and deletion. + +

4.6 Adaptive concurrency control

+The Berkeley DB package uses page-level locking by default. +This trades off fine grain concurrency control for simplicity +during recovery. (Finer grain concurrency control can be +obtained by reducing the page size in the database.) +However, when multiple threads/processes perform page-locking +in the presence of writing operations, there is the +potential for deadlock. +As some environments do not need or desire the overhead of +logging and transactions, it is important to provide the +ability for concurrent access without the potential for +deadlock. +

+Berkeley DB provides an option to perform coarser grain, +deadlock-free locking. +Rather than locking on pages, locking is performed at the +interface to the database. +Multiple readers or a single writer are allowed to be +active in the database at any instant in time, with +conflicting requests queued automatically. +The presence of cursors, through which applications can both +read and write data, complicates this design. +If a cursor is currently being used for reading, but will later +be used to write, the system will be deadlock prone if no +special precautions are taken. +To handle this situation, we require that, when a cursor is +created, the application specify any future intention to write. +If there is an intention to write, the cursor is granted an +intention-to-write lock which does not conflict with readers, +but does conflict with other intention-to-write locks and write +locks. +The end result is that the application is limited to a single +potentially writing cursor accessing the database at any point +in time. +

+Under periods of low contention (but potentially high throughput), +the normal page-level locking provides the best overall throughput. +However, as contention rises, so does the potential for deadlock. +As some cross-over point, switching to the less concurrent, but +deadlock-free locking protocol will result in higher throughput +as operations must never be retried. +Given the operating conditions of an embedded database manager, +it is useful to make this change automatically as the system +itself detects high contention. + +

4.7 Adaptive synchronization

+ +In addition to the logical locks that protect the integrity of the +database pages, Berkeley DB must synchronize access to shared memory +data structures, such as the lock table, in-memory buffer pool, and +in-memory log buffer. +Each independent module uses a single mutex to protect its shared +data structures, under the assumption that operations that require +the mutex are very short and the potential for conflict is +low. +Unfortunately, in highly concurrent environments with multiple processors +present, this assumption is not always true. +When this assumption becomes invalid (that is, we observe significant +contention for the subsystem mutexes), we can switch over to a finer-grained +concurrency model for the mutexes. +Once again, there is a performance trade-off. Fine-grain mutexes +impose a penalty of approximately 25% (due to the increased number +of mutexes required for each operation), but allow for higher throughput. +Using fine-grain mutexes under low contention would cause a decrease +in performance, so it is important to monitor the system carefully, +so that the change can be executed only when it will increase system +throughput without jeopardizing latency. + +

5. Footprint of an Embedded System

+While traditional systems compete on price-performance, the +embedded players will compete on price, features, and footprint. +The earlier sections have focused on features; in this section +we focus on footprint. +

+Oracle reports that Oracle Lite 3.0 requires 350 KB to 750 KB +of memory and approximately 2.5 MB of hard disk space [7]. +This includes drivers for interfaces such as ODBC and JDBC. +In contrast, Berkeley DB ranges in size from 75 KB to under 200 KB, +foregoing heavyweight interfaces such as ODBC and JDBC and +providing a variety of deployed sizes that can be used depending +on application needs. At the low end, applications requiring +a simple single-user access method can choose from either extended +linear hashing, B+ trees, or record-number based retrieval and +pay only the 75 KB space requirement. +Applications requiring all three access methods will observe the +110 KB footprint. +At the high end, a fully recoverable, high-performance system +occupies less than a quarter megabyte of memory. +This is a system you can easily incorporate in your toaster oven. +Table 1 shows the per-module break down of the entire Berkeley DB +library. Note that this does not include memory used to cache database +pages. + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Object sizes in bytes
SubsystemTextDataBss
Btree-specific routines2881200
Recno-specific routines721100
Hash-specific routines2374200
Memory Pool1453500
Access method common code2325200
OS compatibility library4980520
Support utilities616500
All modules for Btree access method only77744520
All modules for Recno access method only84955520
All modules for Hash access method only72674520
All Access Methods108697520

Locking1253300
Recovery2694884
Logging3736700
Full Package185545604
+ +

6. Related Work

+ +Every three to five years, leading researchers in the database +community convene to identify future directions in database +research. +They produce a report of this meeting, named for the year and +location of the meeting. +The most recent of these reports, the 1998 Asilomar report, +identifies the embedded database market as one of the +high growth areas in database research [1]. +Not surprisingly, market analysts identify the embedded database +market as a high-growth area in the commercial sector as well +[5]. +

+The Asilomar report identifies a new class of database applications, which they +term "gizmo" databases, small databases embedded in tiny mobile +appliances, e.g., smart-cards, telephones, personal digital assistants. +Such databases must be self-managing, secure and reliable. +Thus, the idea is that gizmo databases require plug and play data +management with no database administrator (DBA), no human settable +parameters, and the ability to adapt to changing conditions. +More specifically, the Asilomar authors claim that the goal is +self-tuning, including defining the physical DB design, the +logical DB design, and automatic reports and utilities [1] +To date, +few researchers have accepted this challenge, and there is a dearth +of research literature on the subject. +

+Our approach to embedded database administration is fundamentally +different than that described by the Asilomar authors. +We adopt their terminology, but view the challenge in supporting +gizmo databases to be that of self-sustenance after initial +deployment. Therefore, we find it, not only acceptable, but +desirable to assume that application developers control initial +database design and configuration. To the best of our knowledge, +none of the published work in this area addresses this approach. +

+As the research community has not provided guidance in this +arena, most work in embedded database administration has fallen +to the commercial vendors. +These vendors fall into two camps, companies selling databases +specifically designed for embedding or programmatic access +and the major database vendors (e.g., Oracle, Informix, Sybase). +

+The embedded vendors all acknowledge the need for automatic +administration, but fail to identify precisely how their +products actually accomplish this. +A notable exception is Interbase whose white paper +comparison with Sybase and Microsoft's SQL servers +explicitly address features of maintenance ease. +Interbase claims that as they use no log files, there is +no need for log reclamation, checkpoint tuning, or other +tasks associated with log management. However, Interbase +uses Transaction Information Pages, and it is unclear +how these are reused or reclaimed [6]. +Additionally, with a log-free system, they must use +a FORCE policy (write all pages to disk at commit), +as defined by Haerder and Reuter [4]. This has +serious performance consequences for disk-based systems. +The approach described in this paper does use logs and +therefore requires log reclamation, +but provides hooks so the application may reclaim logs +safely and programmatically. +While Berkeley DB does require checkpoints, the goal of +tuning the checkpoint interval is to bound recovery time. +Since the checkpoint interval in Berkeley DB can be expressed +by the amount of log data written, it requires no tuning. +The application designer sets a target recovery time, and +selects the amount of log data that can be read in that interval +and specifies the checkpoint interval appropriately. Even as +load changes, the time to recover does not. +

+The backup approaches taken by Interbase and Berkeley DB +are similar in that they both allow online backup, but +rather different in their affect on transactions running +during backup. As Interbase performs backups as transactions +[6], concurrent queries can suffer potentially long +delays. Berkeley DB uses native operating system system utilities +and recovery for backups, so there is no interference with +concurrent activity, other than potential contention on disk +arms. +

+There are a number of database vendors selling in +the embedded market (e.g., Raima, +Centura, Pervasive, Faircom), but none highlight +the special requirements of embedded database +applications. +On the other end of the spectrum, the major vendors, +Oracle, Sybase, Microsoft, are all becoming convinced +of the importance of the embedded market. +As mentioned earlier, Oracle has announced its +Oracle Lite server for embedded use. +Sybase has announced its UltraLite platform for "application-optimized, +high-performance, SQL database engine for professional +application developers building solutions for mobile and embedded platforms." +[8]. +We believe that SQL is incompatible with the +gizmo database environment or truly embedded systems for which Berkeley +DB is most suitable. +Microsoft research is taking a different approach, developing +technology to assist in automating initial database design and +index specification [2][3]. +As mentioned earlier, we believe that such configuration is, not only +acceptable in the embedded market, but desirable so that applications +can tune their database management for the target environment. +

7. Conclusions

+The coming wave of embedded systems poses a new set of challenges +for data management. +The traditional server-based, big footprint systems designed for +high performance on big iron are not the right approach in this +environment. +Instead, application developers need small, fast, versatile systems +that can be tailored to a specific environment. +In this paper, we have identified several of the key issues in +providing these systems and shown how Berkeley DB provides +many of the characteristics necessary for such applications. + +

8. References

+

+[1] Bernstein, P., Brodie, M., Ceri, S., DeWitt, D., Franklin, M., +Garcia-Molina, H., Gray, J., Held, J., Hellerstein, J., +Jagadish, H., Lesk, M., Maier, D., Naughton, J., +Pirahesh, H., Stonebraker, M., Ullman, J., +"The Asilomar Report on Database Research," +SIGMOD Record 27(4): 74-80, 1998. + +

+[2] Chaudhuri, S., Narasayya, V., +"AutoAdmin 'What-If' Index Analysis Utility," +Proceedings of the ACM SIGMOD Conference, Seattle, 1998. + +

+[3] Chaudhuri, S., Narasayya, V., +"An Efficient, Cost-Driver Index Selection Tool for Microsoft SQL Server," +Proceedings of the 23rd VLDB Conference, Athens, Greece, 1997. + +

+[4] Haerder, T., Reuter, A., +"Principles of Transaction-Oriented Database Recovery," +Computing Surveys 15,4 (1983), 237-318. + +

+[5] Hostetler, M., "Cover Is Off A New Type of Database," +Embedded DB News, +http://www.theadvisors.com/embeddeddbnews.htm, +5/6/98. + +

+[6] Interbase, "A Comparison of Borland InterBase 4.0 +Sybase SQL Server and Microsoft SQL Server," +http://web.interbase.com/products/doc_info_f.html. + +

+[7] Oracle, "Oracle Delivers New Server, Application Suite +to Power the Web for Mission-Critical Business," +http://www.oracle.com.sg/partners/news/newserver.htm, +May 1998. + +

+[8] Sybase, Sybase UltraLite, http://www.sybase.com/products/ultralite/beta. + +

+[9] Transaction Processing Council, "TPC-C Benchmark Specification, +Version 3.4," San Jose, CA, August 1998. + +

+[10] Transaction Processing Council, "TPC-D Benchmark Specification, +Version 2.1," San Jose, CA, April 1999. + + + + + diff --git a/db/docs/ref/refs/hash_usenix.ps b/db/docs/ref/refs/hash_usenix.ps new file mode 100644 index 000000000..c88477883 --- /dev/null +++ b/db/docs/ref/refs/hash_usenix.ps @@ -0,0 +1,12209 @@ +%!PS-Adobe-1.0 +%%Creator: utopia:margo (& Seltzer,608-13E,8072,) +%%Title: stdin (ditroff) +%%CreationDate: Tue Dec 11 15:06:45 1990 +%%EndComments +% @(#)psdit.pro 1.3 4/15/88 +% lib/psdit.pro -- prolog for psdit (ditroff) files +% Copyright (c) 1984, 1985 Adobe Systems Incorporated. All Rights Reserved. +% last edit: shore Sat Nov 23 20:28:03 1985 +% RCSID: $Header: psdit.pro,v 2.1 85/11/24 12:19:43 shore Rel $ + +% Changed by Edward Wang (edward@ucbarpa.berkeley.edu) to handle graphics, +% 17 Feb, 87. + +/$DITroff 140 dict def $DITroff begin +/fontnum 1 def /fontsize 10 def /fontheight 10 def /fontslant 0 def +/xi{0 72 11 mul translate 72 resolution div dup neg scale 0 0 moveto + /fontnum 1 def /fontsize 10 def /fontheight 10 def /fontslant 0 def F + /pagesave save def}def +/PB{save /psv exch def currentpoint translate + resolution 72 div dup neg scale 0 0 moveto}def +/PE{psv restore}def +/arctoobig 90 def /arctoosmall .05 def +/m1 matrix def /m2 matrix def /m3 matrix def /oldmat matrix def +/tan{dup sin exch cos div}def +/point{resolution 72 div mul}def +/dround {transform round exch round exch itransform}def +/xT{/devname exch def}def +/xr{/mh exch def /my exch def /resolution exch def}def +/xp{}def +/xs{docsave restore end}def +/xt{}def +/xf{/fontname exch def /slotno exch def fontnames slotno get fontname eq not + {fonts slotno fontname findfont put fontnames slotno fontname put}if}def +/xH{/fontheight exch def F}def +/xS{/fontslant exch def F}def +/s{/fontsize exch def /fontheight fontsize def F}def +/f{/fontnum exch def F}def +/F{fontheight 0 le{/fontheight fontsize def}if + fonts fontnum get fontsize point 0 0 fontheight point neg 0 0 m1 astore + fontslant 0 ne{1 0 fontslant tan 1 0 0 m2 astore m3 concatmatrix}if + makefont setfont .04 fontsize point mul 0 dround pop setlinewidth}def +/X{exch currentpoint exch pop moveto show}def +/N{3 1 roll moveto show}def +/Y{exch currentpoint pop exch moveto show}def +/S{show}def +/ditpush{}def/ditpop{}def +/AX{3 -1 roll currentpoint exch pop moveto 0 exch ashow}def +/AN{4 2 roll moveto 0 exch ashow}def +/AY{3 -1 roll currentpoint pop exch moveto 0 exch ashow}def +/AS{0 exch ashow}def +/MX{currentpoint exch pop moveto}def +/MY{currentpoint pop exch moveto}def +/MXY{moveto}def +/cb{pop}def % action on unknown char -- nothing for now +/n{}def/w{}def +/p{pop showpage pagesave restore /pagesave save def}def +/Dt{/Dlinewidth exch def}def 1 Dt +/Ds{/Ddash exch def}def -1 Ds +/Di{/Dstipple exch def}def 1 Di +/Dsetlinewidth{2 Dlinewidth mul setlinewidth}def +/Dsetdash{Ddash 4 eq{[8 12]}{Ddash 16 eq{[32 36]} + {Ddash 20 eq{[32 12 8 12]}{[]}ifelse}ifelse}ifelse 0 setdash}def +/Dstroke{gsave Dsetlinewidth Dsetdash 1 setlinecap stroke grestore + currentpoint newpath moveto}def +/Dl{rlineto Dstroke}def +/arcellipse{/diamv exch def /diamh exch def oldmat currentmatrix pop + currentpoint translate 1 diamv diamh div scale /rad diamh 2 div def + currentpoint exch rad add exch rad -180 180 arc oldmat setmatrix}def +/Dc{dup arcellipse Dstroke}def +/De{arcellipse Dstroke}def +/Da{/endv exch def /endh exch def /centerv exch def /centerh exch def + /cradius centerv centerv mul centerh centerh mul add sqrt def + /eradius endv endv mul endh endh mul add sqrt def + /endang endv endh atan def + /startang centerv neg centerh neg atan def + /sweep startang endang sub dup 0 lt{360 add}if def + sweep arctoobig gt + {/midang startang sweep 2 div sub def /midrad cradius eradius add 2 div def + /midh midang cos midrad mul def /midv midang sin midrad mul def + midh neg midv neg endh endv centerh centerv midh midv Da + Da} + {sweep arctoosmall ge + {/controldelt 1 sweep 2 div cos sub 3 sweep 2 div sin mul div 4 mul def + centerv neg controldelt mul centerh controldelt mul + endv neg controldelt mul centerh add endh add + endh controldelt mul centerv add endv add + centerh endh add centerv endv add rcurveto Dstroke} + {centerh endh add centerv endv add rlineto Dstroke} + ifelse} + ifelse}def +/Dpatterns[ +[%cf[widthbits] +[8<0000000000000010>] +[8<0411040040114000>] +[8<0204081020408001>] +[8<0000103810000000>] +[8<6699996666999966>] +[8<0000800100001008>] +[8<81c36666c3810000>] +[8<0f0e0c0800000000>] +[8<0000000000000010>] +[8<0411040040114000>] +[8<0204081020408001>] +[8<0000001038100000>] +[8<6699996666999966>] +[8<0000800100001008>] +[8<81c36666c3810000>] +[8<0f0e0c0800000000>] +[8<0042660000246600>] +[8<0000990000990000>] +[8<0804020180402010>] +[8<2418814242811824>] +[8<6699996666999966>] +[8<8000000008000000>] +[8<00001c3e363e1c00>] +[8<0000000000000000>] +[32<00000040000000c00000004000000040000000e0000000000000000000000000>] +[32<00000000000060000000900000002000000040000000f0000000000000000000>] +[32<000000000000000000e0000000100000006000000010000000e0000000000000>] +[32<00000000000000002000000060000000a0000000f00000002000000000000000>] +[32<0000000e0000000000000000000000000000000f000000080000000e00000001>] +[32<0000090000000600000000000000000000000000000007000000080000000e00>] +[32<00010000000200000004000000040000000000000000000000000000000f0000>] +[32<0900000006000000090000000600000000000000000000000000000006000000>]] +[%ug +[8<0000020000000000>] +[8<0000020000002000>] +[8<0004020000002000>] +[8<0004020000402000>] +[8<0004060000402000>] +[8<0004060000406000>] +[8<0006060000406000>] +[8<0006060000606000>] +[8<00060e0000606000>] +[8<00060e000060e000>] +[8<00070e000060e000>] +[8<00070e000070e000>] +[8<00070e020070e000>] +[8<00070e020070e020>] +[8<04070e020070e020>] +[8<04070e024070e020>] +[8<04070e064070e020>] +[8<04070e064070e060>] +[8<06070e064070e060>] +[8<06070e066070e060>] +[8<06070f066070e060>] +[8<06070f066070f060>] +[8<060f0f066070f060>] +[8<060f0f0660f0f060>] +[8<060f0f0760f0f060>] +[8<060f0f0760f0f070>] +[8<0e0f0f0760f0f070>] +[8<0e0f0f07e0f0f070>] +[8<0e0f0f0fe0f0f070>] +[8<0e0f0f0fe0f0f0f0>] +[8<0f0f0f0fe0f0f0f0>] +[8<0f0f0f0ff0f0f0f0>] +[8<1f0f0f0ff0f0f0f0>] +[8<1f0f0f0ff1f0f0f0>] +[8<1f0f0f8ff1f0f0f0>] +[8<1f0f0f8ff1f0f0f8>] +[8<9f0f0f8ff1f0f0f8>] +[8<9f0f0f8ff9f0f0f8>] +[8<9f0f0f9ff9f0f0f8>] +[8<9f0f0f9ff9f0f0f9>] +[8<9f8f0f9ff9f0f0f9>] +[8<9f8f0f9ff9f8f0f9>] +[8<9f8f1f9ff9f8f0f9>] +[8<9f8f1f9ff9f8f1f9>] +[8] +[8] +[8] +[8] +[8] +[8] +[8] +[8] +[8] +[8] +[8] +[8] +[8] +[8] +[8] +[8] +[8] +[8] +[8] +[8]] +[%mg +[8<8000000000000000>] +[8<0822080080228000>] +[8<0204081020408001>] +[8<40e0400000000000>] +[8<66999966>] +[8<8001000010080000>] +[8<81c36666c3810000>] +[8] +[16<07c00f801f003e007c00f800f001e003c007800f001f003e007c00f801f003e0>] +[16<1f000f8007c003e001f000f8007c003e001f800fc007e003f001f8007c003e00>] +[8] +[16<0040008001000200040008001000200040008000000100020004000800100020>] +[16<0040002000100008000400020001800040002000100008000400020001000080>] +[16<1fc03fe07df0f8f8f07de03fc01f800fc01fe03ff07df8f87df03fe01fc00f80>] +[8<80>] +[8<8040201000000000>] +[8<84cc000048cc0000>] +[8<9900009900000000>] +[8<08040201804020100800020180002010>] +[8<2418814242811824>] +[8<66999966>] +[8<8000000008000000>] +[8<70f8d8f870000000>] +[8<0814224180402010>] +[8] +[8<018245aa45820100>] +[8<221c224180808041>] +[8<88000000>] +[8<0855800080550800>] +[8<2844004482440044>] +[8<0810204080412214>] +[8<00>]]]def +/Dfill{ + transform /maxy exch def /maxx exch def + transform /miny exch def /minx exch def + minx maxx gt{/minx maxx /maxx minx def def}if + miny maxy gt{/miny maxy /maxy miny def def}if + Dpatterns Dstipple 1 sub get exch 1 sub get + aload pop /stip exch def /stipw exch def /stiph 128 def + /imatrix[stipw 0 0 stiph 0 0]def + /tmatrix[stipw 0 0 stiph 0 0]def + /minx minx cvi stiph idiv stiph mul def + /miny miny cvi stipw idiv stipw mul def + gsave eoclip 0 setgray + miny stiph maxy{ + tmatrix exch 5 exch put + minx stipw maxx{ + tmatrix exch 4 exch put tmatrix setmatrix + stipw stiph true imatrix {stip} imagemask + }for + }for + grestore +}def +/Dp{Dfill Dstroke}def +/DP{Dfill currentpoint newpath moveto}def +end + +/ditstart{$DITroff begin + /nfonts 60 def % NFONTS makedev/ditroff dependent! + /fonts[nfonts{0}repeat]def + /fontnames[nfonts{()}repeat]def +/docsave save def +}def + +% character outcalls +/oc{ + /pswid exch def /cc exch def /name exch def + /ditwid pswid fontsize mul resolution mul 72000 div def + /ditsiz fontsize resolution mul 72 div def + ocprocs name known{ocprocs name get exec}{name cb}ifelse +}def +/fractm [.65 0 0 .6 0 0] def +/fraction{ + /fden exch def /fnum exch def gsave /cf currentfont def + cf fractm makefont setfont 0 .3 dm 2 copy neg rmoveto + fnum show rmoveto currentfont cf setfont(\244)show setfont fden show + grestore ditwid 0 rmoveto +}def +/oce{grestore ditwid 0 rmoveto}def +/dm{ditsiz mul}def +/ocprocs 50 dict def ocprocs begin +(14){(1)(4)fraction}def +(12){(1)(2)fraction}def +(34){(3)(4)fraction}def +(13){(1)(3)fraction}def +(23){(2)(3)fraction}def +(18){(1)(8)fraction}def +(38){(3)(8)fraction}def +(58){(5)(8)fraction}def +(78){(7)(8)fraction}def +(sr){gsave 0 .06 dm rmoveto(\326)show oce}def +(is){gsave 0 .15 dm rmoveto(\362)show oce}def +(->){gsave 0 .02 dm rmoveto(\256)show oce}def +(<-){gsave 0 .02 dm rmoveto(\254)show oce}def +(==){gsave 0 .05 dm rmoveto(\272)show oce}def +(uc){gsave currentpoint 400 .009 dm mul add translate + 8 -8 scale ucseal oce}def +end + +% an attempt at a PostScript FONT to implement ditroff special chars +% this will enable us to +% cache the little buggers +% generate faster, more compact PS out of psdit +% confuse everyone (including myself)! +50 dict dup begin +/FontType 3 def +/FontName /DIThacks def +/FontMatrix [.001 0 0 .001 0 0] def +/FontBBox [-260 -260 900 900] def% a lie but ... +/Encoding 256 array def +0 1 255{Encoding exch /.notdef put}for +Encoding + dup 8#040/space put %space + dup 8#110/rc put %right ceil + dup 8#111/lt put %left top curl + dup 8#112/bv put %bold vert + dup 8#113/lk put %left mid curl + dup 8#114/lb put %left bot curl + dup 8#115/rt put %right top curl + dup 8#116/rk put %right mid curl + dup 8#117/rb put %right bot curl + dup 8#120/rf put %right floor + dup 8#121/lf put %left floor + dup 8#122/lc put %left ceil + dup 8#140/sq put %square + dup 8#141/bx put %box + dup 8#142/ci put %circle + dup 8#143/br put %box rule + dup 8#144/rn put %root extender + dup 8#145/vr put %vertical rule + dup 8#146/ob put %outline bullet + dup 8#147/bu put %bullet + dup 8#150/ru put %rule + dup 8#151/ul put %underline + pop +/DITfd 100 dict def +/BuildChar{0 begin + /cc exch def /fd exch def + /charname fd /Encoding get cc get def + /charwid fd /Metrics get charname get def + /charproc fd /CharProcs get charname get def + charwid 0 fd /FontBBox get aload pop setcachedevice + 2 setlinejoin 40 setlinewidth + newpath 0 0 moveto gsave charproc grestore + end}def +/BuildChar load 0 DITfd put +/CharProcs 50 dict def +CharProcs begin +/space{}def +/.notdef{}def +/ru{500 0 rls}def +/rn{0 840 moveto 500 0 rls}def +/vr{0 800 moveto 0 -770 rls}def +/bv{0 800 moveto 0 -1000 rls}def +/br{0 840 moveto 0 -1000 rls}def +/ul{0 -140 moveto 500 0 rls}def +/ob{200 250 rmoveto currentpoint newpath 200 0 360 arc closepath stroke}def +/bu{200 250 rmoveto currentpoint newpath 200 0 360 arc closepath fill}def +/sq{80 0 rmoveto currentpoint dround newpath moveto + 640 0 rlineto 0 640 rlineto -640 0 rlineto closepath stroke}def +/bx{80 0 rmoveto currentpoint dround newpath moveto + 640 0 rlineto 0 640 rlineto -640 0 rlineto closepath fill}def +/ci{500 360 rmoveto currentpoint newpath 333 0 360 arc + 50 setlinewidth stroke}def + +/lt{0 -200 moveto 0 550 rlineto currx 800 2cx s4 add exch s4 a4p stroke}def +/lb{0 800 moveto 0 -550 rlineto currx -200 2cx s4 add exch s4 a4p stroke}def +/rt{0 -200 moveto 0 550 rlineto currx 800 2cx s4 sub exch s4 a4p stroke}def +/rb{0 800 moveto 0 -500 rlineto currx -200 2cx s4 sub exch s4 a4p stroke}def +/lk{0 800 moveto 0 300 -300 300 s4 arcto pop pop 1000 sub + 0 300 4 2 roll s4 a4p 0 -200 lineto stroke}def +/rk{0 800 moveto 0 300 s2 300 s4 arcto pop pop 1000 sub + 0 300 4 2 roll s4 a4p 0 -200 lineto stroke}def +/lf{0 800 moveto 0 -1000 rlineto s4 0 rls}def +/rf{0 800 moveto 0 -1000 rlineto s4 neg 0 rls}def +/lc{0 -200 moveto 0 1000 rlineto s4 0 rls}def +/rc{0 -200 moveto 0 1000 rlineto s4 neg 0 rls}def +end + +/Metrics 50 dict def Metrics begin +/.notdef 0 def +/space 500 def +/ru 500 def +/br 0 def +/lt 416 def +/lb 416 def +/rt 416 def +/rb 416 def +/lk 416 def +/rk 416 def +/rc 416 def +/lc 416 def +/rf 416 def +/lf 416 def +/bv 416 def +/ob 350 def +/bu 350 def +/ci 750 def +/bx 750 def +/sq 750 def +/rn 500 def +/ul 500 def +/vr 0 def +end + +DITfd begin +/s2 500 def /s4 250 def /s3 333 def +/a4p{arcto pop pop pop pop}def +/2cx{2 copy exch}def +/rls{rlineto stroke}def +/currx{currentpoint pop}def +/dround{transform round exch round exch itransform} def +end +end +/DIThacks exch definefont pop +ditstart +(psc)xT +576 1 1 xr +1(Times-Roman)xf 1 f +2(Times-Italic)xf 2 f +3(Times-Bold)xf 3 f +4(Times-BoldItalic)xf 4 f +5(Helvetica)xf 5 f +6(Helvetica-Bold)xf 6 f +7(Courier)xf 7 f +8(Courier-Bold)xf 8 f +9(Symbol)xf 9 f +10(DIThacks)xf 10 f +10 s +1 f +xi +%%EndProlog + +%%Page: 1 1 +10 s 10 xH 0 xS 1 f +3 f +22 s +1249 626(A)N +1420(N)X +1547(ew)X +1796(H)X +1933(ashing)X +2467(P)X +2574(ackage)X +3136(for)X +3405(U)X +3532(N)X +3659(IX)X +2 f +20 s +3855 562(1)N +1 f +12 s +1607 779(Margo)N +1887(Seltzer)X +9 f +2179(-)X +1 f +2256(University)X +2686(of)X +2790(California,)X +3229(Berkeley)X +2015 875(Ozan)N +2242(Yigit)X +9 f +2464(-)X +1 f +2541(York)X +2762(University)X +3 f +2331 1086(ABSTRACT)N +1 f +10 s +1152 1222(UNIX)N +1385(support)X +1657(of)X +1756(disk)X +1921(oriented)X +2216(hashing)X +2497(was)X +2654(originally)X +2997(provided)X +3314(by)X +2 f +3426(dbm)X +1 f +3595([ATT79])X +3916(and)X +1152 1310(subsequently)N +1595(improved)X +1927(upon)X +2112(in)X +2 f +2199(ndbm)X +1 f +2402([BSD86].)X +2735(In)X +2826(AT&T)X +3068(System)X +3327(V,)X +3429(in-memory)X +3809(hashed)X +1152 1398(storage)N +1420(and)X +1572(access)X +1814(support)X +2090(was)X +2251(added)X +2479(in)X +2577(the)X +2 f +2711(hsearch)X +1 f +3000(library)X +3249(routines)X +3542([ATT85].)X +3907(The)X +1152 1486(result)N +1367(is)X +1457(a)X +1530(system)X +1789(with)X +1968(two)X +2125(incompatible)X +2580(hashing)X +2865(schemes,)X +3193(each)X +3377(with)X +3555(its)X +3666(own)X +3840(set)X +3965(of)X +1152 1574(shortcomings.)N +1152 1688(This)N +1316(paper)X +1517(presents)X +1802(the)X +1922(design)X +2152(and)X +2289(performance)X +2717(characteristics)X +3198(of)X +3286(a)X +3343(new)X +3498(hashing)X +3768(package)X +1152 1776(providing)N +1483(a)X +1539(superset)X +1822(of)X +1909(the)X +2027(functionality)X +2456(provided)X +2761(by)X +2 f +2861(dbm)X +1 f +3019(and)X +2 f +3155(hsearch)X +1 f +3409(.)X +3469(The)X +3614(new)X +3768(package)X +1152 1864(uses)N +1322(linear)X +1537(hashing)X +1818(to)X +1912(provide)X +2189(ef\256cient)X +2484(support)X +2755(of)X +2853(both)X +3026(memory)X +3324(based)X +3538(and)X +3685(disk)X +3849(based)X +1152 1952(hash)N +1319(tables)X +1526(with)X +1688(performance)X +2115(superior)X +2398(to)X +2480(both)X +2 f +2642(dbm)X +1 f +2800(and)X +2 f +2936(hsearch)X +1 f +3210(under)X +3413(most)X +3588(conditions.)X +3 f +1380 2128(Introduction)N +1 f +892 2260(Current)N +1196(UNIX)X +1456(systems)X +1768(offer)X +1984(two)X +2163(forms)X +2409(of)X +720 2348(hashed)N +973(data)X +1137(access.)X +2 f +1413(Dbm)X +1 f +1599(and)X +1745(its)X +1850(derivatives)X +2231(provide)X +720 2436(keyed)N +939(access)X +1171(to)X +1259(disk)X +1418(resident)X +1698(data)X +1858(while)X +2 f +2062(hsearch)X +1 f +2342(pro-)X +720 2524(vides)N +929(access)X +1175(for)X +1309(memory)X +1616(resident)X +1910(data.)X +2124(These)X +2356(two)X +720 2612(access)N +979(methods)X +1302(are)X +1453(incompatible)X +1923(in)X +2037(that)X +2209(memory)X +720 2700(resident)N +1011(hash)X +1195(tables)X +1419(may)X +1593(not)X +1731(be)X +1843(stored)X +2075(on)X +2191(disk)X +2360(and)X +720 2788(disk)N +884(resident)X +1169(tables)X +1387(cannot)X +1632(be)X +1739(read)X +1909(into)X +2063(memory)X +2360(and)X +720 2876(accessed)N +1022(using)X +1215(the)X +1333(in-memory)X +1709(routines.)X +2 f +892 2990(Dbm)N +1 f +1091(has)X +1241(several)X +1512(shortcomings.)X +2026(Since)X +2247(data)X +2423(is)X +720 3078(assumed)N +1032(to)X +1130(be)X +1242(disk)X +1411(resident,)X +1721(each)X +1905(access)X +2146(requires)X +2440(a)X +720 3166(system)N +963(call,)X +1120(and)X +1257(almost)X +1491(certainly,)X +1813(a)X +1869(disk)X +2022(operation.)X +2365(For)X +720 3254(extremely)N +1072(large)X +1264(databases,)X +1623(where)X +1851(caching)X +2131(is)X +2214(unlikely)X +720 3342(to)N +810(be)X +914(effective,)X +1244(this)X +1386(is)X +1466(acceptable,)X +1853(however,)X +2177(when)X +2378(the)X +720 3430(database)N +1022(is)X +1100(small)X +1298(\(i.e.)X +1447(the)X +1569(password)X +1896(\256le\),)X +2069(performance)X +720 3518(improvements)N +1204(can)X +1342(be)X +1443(obtained)X +1744(through)X +2018(caching)X +2293(pages)X +720 3606(of)N +818(the)X +947(database)X +1255(in)X +1348(memory.)X +1685(In)X +1782(addition,)X +2 f +2094(dbm)X +1 f +2262(cannot)X +720 3694(store)N +902(data)X +1062(items)X +1261(whose)X +1492(total)X +1660(key)X +1802(and)X +1943(data)X +2102(size)X +2252(exceed)X +720 3782(the)N +850(page)X +1034(size)X +1191(of)X +1290(the)X +1420(hash)X +1599(table.)X +1827(Similarly,)X +2176(if)X +2257(two)X +2409(or)X +720 3870(more)N +907(keys)X +1076(produce)X +1357(the)X +1477(same)X +1664(hash)X +1833(value)X +2029(and)X +2166(their)X +2334(total)X +720 3958(size)N +876(exceeds)X +1162(the)X +1291(page)X +1474(size,)X +1650(the)X +1779(table)X +1966(cannot)X +2210(store)X +2396(all)X +720 4046(the)N +838(colliding)X +1142(keys.)X +892 4160(The)N +1050(in-memory)X +2 f +1439(hsearch)X +1 f +1725(routines)X +2015(have)X +2199(different)X +720 4248(shortcomings.)N +1219(First,)X +1413(the)X +1539(notion)X +1771(of)X +1865(a)X +1928(single)X +2146(hash)X +2320(table)X +720 4336(is)N +807(embedded)X +1171(in)X +1266(the)X +1397(interface,)X +1732(preventing)X +2108(an)X +2217(applica-)X +720 4424(tion)N +902(from)X +1116(accessing)X +1482(multiple)X +1806(tables)X +2050(concurrently.)X +720 4512(Secondly,)N +1063(the)X +1186(routine)X +1438(to)X +1525(create)X +1743(a)X +1804(hash)X +1976(table)X +2157(requires)X +2440(a)X +720 4600(parameter)N +1066(which)X +1286(declares)X +1573(the)X +1694(size)X +1842(of)X +1932(the)X +2053(hash)X +2223(table.)X +2422(If)X +720 4688(this)N +856(size)X +1001(is)X +1074(set)X +1183(too)X +1305(low,)X +1465(performance)X +1892(degradation)X +2291(or)X +2378(the)X +720 4776(inability)N +1008(to)X +1092(add)X +1230(items)X +1425(to)X +1509(the)X +1628(table)X +1805(may)X +1964(result.)X +2223(In)X +2311(addi-)X +720 4864(tion,)N +2 f +910(hsearch)X +1 f +1210(requires)X +1515(that)X +1681(the)X +1825(application)X +2226(allocate)X +720 4952(memory)N +1037(for)X +1181(the)X +1329(key)X +1495(and)X +1661(data)X +1845(items.)X +2108(Lastly,)X +2378(the)X +2 f +720 5040(hsearch)N +1 f +1013(routines)X +1310(provide)X +1594(no)X +1713(interface)X +2034(to)X +2135(store)X +2329(hash)X +720 5128(tables)N +927(on)X +1027(disk.)X +16 s +720 5593 MXY +864 0 Dl +2 f +8 s +760 5648(1)N +1 f +9 s +5673(UNIX)Y +990(is)X +1056(a)X +1106(registered)X +1408(trademark)X +1718(of)X +1796(AT&T.)X +10 s +2878 2128(The)N +3032(goal)X +3199(of)X +3295(our)X +3431(work)X +3625(was)X +3779(to)X +3870(design)X +4108(and)X +4253(imple-)X +2706 2216(ment)N +2900(a)X +2970(new)X +3138(package)X +3436(that)X +3590(provides)X +3899(a)X +3968(superset)X +4264(of)X +4364(the)X +2706 2304(functionality)N +3144(of)X +3240(both)X +2 f +3411(dbm)X +1 f +3578(and)X +2 f +3723(hsearch)X +1 f +3977(.)X +4045(The)X +4198(package)X +2706 2392(had)N +2871(to)X +2982(overcome)X +3348(the)X +3495(interface)X +3826(shortcomings)X +4306(cited)X +2706 2480(above)N +2930(and)X +3078(its)X +3185(implementation)X +3719(had)X +3867(to)X +3961(provide)X +4238(perfor-)X +2706 2568(mance)N +2942(equal)X +3142(or)X +3235(superior)X +3524(to)X +3612(that)X +3758(of)X +3851(the)X +3975(existing)X +4253(imple-)X +2706 2656(mentations.)N +3152(In)X +3274(order)X +3498(to)X +3614(provide)X +3913(a)X +4003(compact)X +4329(disk)X +2706 2744(representation,)N +3224(graceful)X +3531(table)X +3729(growth,)X +4018(and)X +4176(expected)X +2706 2832(constant)N +3033(time)X +3234(performance,)X +3720(we)X +3873(selected)X +4191(Litwin's)X +2706 2920(linear)N +2923(hashing)X +3206(algorithm)X +3551([LAR88,)X +3872(LIT80].)X +4178(We)X +4324(then)X +2706 3008(enhanced)N +3037(the)X +3161(algorithm)X +3498(to)X +3586(handle)X +3826(page)X +4004(over\257ows)X +4346(and)X +2706 3096(large)N +2900(key)X +3049(handling)X +3362(with)X +3537(a)X +3606(single)X +3830(mechanism,)X +4248(named)X +2706 3184(buddy-in-waiting.)N +3 f +2975 3338(Existing)N +3274(UNIX)X +3499(Hashing)X +3802(Techniques)X +1 f +2878 3470(Over)N +3076(the)X +3210(last)X +3357(decade,)X +3637(several)X +3901(dynamic)X +4213(hashing)X +2706 3558(schemes)N +3000(have)X +3174(been)X +3348(developed)X +3700(for)X +3816(the)X +3936(UNIX)X +4159(timeshar-)X +2706 3646(ing)N +2856(system,)X +3146(starting)X +3433(with)X +3622(the)X +3767(inclusion)X +4107(of)X +2 f +4221(dbm)X +1 f +4359(,)X +4426(a)X +2706 3734(minimal)N +3008(database)X +3321(library)X +3571(written)X +3834(by)X +3950(Ken)X +4120(Thompson)X +2706 3822([THOM90],)N +3141(in)X +3248(the)X +3391(Seventh)X +3694(Edition)X +3974(UNIX)X +4220(system.)X +2706 3910(Since)N +2916(then,)X +3106(an)X +3214(extended)X +3536(version)X +3804(of)X +3903(the)X +4032(same)X +4228(library,)X +2 f +2706 3998(ndbm)N +1 f +2884(,)X +2933(and)X +3078(a)X +3142(public-domain)X +3637(clone)X +3839(of)X +3934(the)X +4060(latter,)X +2 f +4273(sdbm)X +1 f +4442(,)X +2706 4086(have)N +2902(been)X +3098(developed.)X +3491(Another)X +3797 0.1645(interface-compatible)AX +2706 4174(library)N +2 f +2950(gdbm)X +1 f +3128(,)X +3178(was)X +3333(recently)X +3622(made)X +3826(available)X +4145(as)X +4241(part)X +4395(of)X +2706 4262(the)N +2829(Free)X +2997(Software)X +3312(Foundation's)X +3759(\(FSF\))X +3970(software)X +4271(distri-)X +2706 4350(bution.)N +2878 4464(All)N +3017(of)X +3121(these)X +3323(implementations)X +3893(are)X +4029(based)X +4248(on)X +4364(the)X +2706 4552(idea)N +2871(of)X +2969(revealing)X +3299(just)X +3445(enough)X +3711(bits)X +3856(of)X +3953(a)X +4019(hash)X +4196(value)X +4400(to)X +2706 4640(locate)N +2920(a)X +2978(page)X +3151(in)X +3234(a)X +3291(single)X +3503(access.)X +3770(While)X +2 f +3987(dbm/ndbm)X +1 f +4346(and)X +2 f +2706 4728(sdbm)N +1 f +2908(map)X +3079(the)X +3210(hash)X +3390(value)X +3597(directly)X +3874(to)X +3968(a)X +4036(disk)X +4201(address,)X +2 f +2706 4816(gdbm)N +1 f +2921(uses)X +3096(the)X +3231(hash)X +3414(value)X +3624(to)X +3722(index)X +3936(into)X +4096(a)X +2 f +4168(directory)X +1 f +2706 4904([ENB88])N +3020(containing)X +3378(disk)X +3531(addresses.)X +2878 5018(The)N +2 f +3033(hsearch)X +1 f +3317(routines)X +3605(in)X +3697(System)X +3962(V)X +4049(are)X +4177(designed)X +2706 5106(to)N +2804(provide)X +3085(memory-resident)X +3669(hash)X +3852(tables.)X +4115(Since)X +4328(data)X +2706 5194(access)N +2948(does)X +3131(not)X +3269(require)X +3533(disk)X +3702(access,)X +3964(simple)X +4213(hashing)X +2706 5282(schemes)N +3010(which)X +3238(may)X +3408(require)X +3667(multiple)X +3964(probes)X +4209(into)X +4364(the)X +2706 5370(table)N +2889(are)X +3015(used.)X +3209(A)X +3294(more)X +3486(interesting)X +3851(version)X +4114(of)X +2 f +4208(hsearch)X +1 f +2706 5458(is)N +2784(a)X +2845(public)X +3070(domain)X +3335(library,)X +2 f +3594(dynahash)X +1 f +3901(,)X +3945(that)X +4089(implements)X +2706 5546(Larson's)N +3036(in-memory)X +3440(adaptation)X +3822([LAR88])X +4164(of)X +4279(linear)X +2706 5634(hashing)N +2975([LIT80].)X +3 f +720 5960(USENIX)N +9 f +1042(-)X +3 f +1106(Winter)X +1371('91)X +9 f +1498(-)X +3 f +1562(Dallas,)X +1815(TX)X +1 f +4424(1)X + +2 p +%%Page: 2 2 +10 s 10 xH 0 xS 1 f +3 f +432 258(A)N +510(New)X +682(Hashing)X +985(Package)X +1290(for)X +1413(UNIX)X +3663(Seltzer)X +3920(&)X +4007(Yigit)X +2 f +1074 538(dbm)N +1 f +1232(and)X +2 f +1368(ndbm)X +1 f +604 670(The)N +2 f +760(dbm)X +1 f +928(and)X +2 f +1074(ndbm)X +1 f +1282(library)X +1526(implementations)X +2089(are)X +432 758(based)N +667(on)X +799(the)X +949(same)X +1166(algorithm)X +1529(by)X +1661(Ken)X +1846(Thompson)X +432 846([THOM90,)N +824(TOR88,)X +1113(WAL84],)X +1452(but)X +1582(differ)X +1789(in)X +1879(their)X +2054(pro-)X +432 934(grammatic)N +801(interfaces.)X +1160(The)X +1311(latter)X +1502(is)X +1581(a)X +1643(modi\256ed)X +1952(version)X +432 1022(of)N +533(the)X +665(former)X +918(which)X +1148(adds)X +1328(support)X +1601(for)X +1728(multiple)X +2027(data-)X +432 1110(bases)N +634(to)X +724(be)X +828(open)X +1011(concurrently.)X +1484(The)X +1636(discussion)X +1996(of)X +2090(the)X +432 1198(algorithm)N +774(that)X +925(follows)X +1196(is)X +1280(applicable)X +1640(to)X +1732(both)X +2 f +1904(dbm)X +1 f +2072(and)X +2 f +432 1286(ndbm)N +1 f +610(.)X +604 1400(The)N +760(basic)X +956(structure)X +1268(of)X +2 f +1366(dbm)X +1 f +1535(calls)X +1712(for)X +1836(\256xed-sized)X +432 1488(disk)N +612(blocks)X +868(\(buckets\))X +1214(and)X +1377(an)X +2 f +1499(access)X +1 f +1755(function)X +2068(that)X +432 1576(maps)N +623(a)X +681(key)X +819(to)X +902(a)X +959(bucket.)X +1234(The)X +1380(interface)X +1683(routines)X +1962(use)X +2090(the)X +2 f +432 1664(access)N +1 f +673(function)X +970(to)X +1062(obtain)X +1292(the)X +1420(appropriate)X +1816(bucket)X +2060(in)X +2152(a)X +432 1752(single)N +643(disk)X +796(access.)X +604 1866(Within)N +869(the)X +2 f +1010(access)X +1 f +1263(function,)X +1593(a)X +1672(bit-randomizing)X +432 1954(hash)N +610(function)X +2 f +8 s +877 1929(2)N +1 f +10 s +940 1954(is)N +1024(used)X +1202(to)X +1294(convert)X +1565(a)X +1631(key)X +1777(into)X +1931(a)X +1997(32-bit)X +432 2042(hash)N +605(value.)X +825(Out)X +971(of)X +1064(these)X +1254(32)X +1359(bits,)X +1519(only)X +1686(as)X +1778(many)X +1981(bits)X +2121(as)X +432 2130(necessary)N +773(are)X +900(used)X +1075(to)X +1165(determine)X +1514(the)X +1639(particular)X +1974(bucket)X +432 2218(on)N +533(which)X +750(a)X +807(key)X +944(resides.)X +1228(An)X +1347(in-memory)X +1724(bitmap)X +1967(is)X +2041(used)X +432 2306(to)N +533(determine)X +893(how)X +1070(many)X +1287(bits)X +1441(are)X +1579(required.)X +1905(Each)X +2104(bit)X +432 2394(indicates)N +746(whether)X +1033(its)X +1136(associated)X +1494(bucket)X +1736(has)X +1871(been)X +2051(split)X +432 2482(yet)N +562(\(a)X +657(0)X +728(indicating)X +1079(that)X +1230(the)X +1359(bucket)X +1604(has)X +1742(not)X +1875(yet)X +2004(split\).)X +432 2570(The)N +590(use)X +730(of)X +830(the)X +961(hash)X +1141(function)X +1441(and)X +1590(the)X +1720(bitmap)X +1974(is)X +2059(best)X +432 2658(described)N +769(by)X +878(stepping)X +1177(through)X +1454(database)X +1759(creation)X +2046(with)X +432 2746(multiple)N +718(invocations)X +1107(of)X +1194(a)X +2 f +1250(store)X +1 f +1430(operation.)X +604 2860(Initially,)N +906(the)X +1033(hash)X +1209(table)X +1394(contains)X +1690(a)X +1755(single)X +1974(bucket)X +432 2948(\(bucket)N +711(0\),)X +836(the)X +972(bit)X +1094(map)X +1270(contains)X +1575(a)X +1649(single)X +1878(bit)X +2000(\(bit)X +2148(0)X +432 3036(corresponding)N +913(to)X +997(bucket)X +1233(0\),)X +1342(and)X +1480(0)X +1542(bits)X +1699(of)X +1788(a)X +1846(hash)X +2014(value)X +432 3124(are)N +560(examined)X +901(to)X +992(determine)X +1342(where)X +1568(a)X +1633(key)X +1778(is)X +1860(placed)X +2099(\(in)X +432 3212(bucket)N +670(0\).)X +801(When)X +1017(bucket)X +1255(0)X +1319(is)X +1396(full,)X +1551(its)X +1650(bit)X +1758(in)X +1844(the)X +1966(bitmap)X +432 3300(\(bit)N +564(0\))X +652(is)X +726(set,)X +856(and)X +993(its)X +1089(contents)X +1377(are)X +1497(split)X +1655(between)X +1943(buckets)X +432 3388(0)N +499(and)X +641(1,)X +727(by)X +833(considering)X +1233(the)X +1357(0)X +2 f +7 s +3356(th)Y +10 s +1 f +1480 3388(bit)N +1590(\(the)X +1741(lowest)X +1976(bit)X +2086(not)X +432 3476(previously)N +800(examined\))X +1169(of)X +1266(the)X +1393(hash)X +1569(value)X +1772(for)X +1895(each)X +2072(key)X +432 3564(within)N +668(the)X +798(bucket.)X +1064(Given)X +1292(a)X +1359(well-designed)X +1840(hash)X +2018(func-)X +432 3652(tion,)N +613(approximately)X +1112(half)X +1273(of)X +1376(the)X +1510(keys)X +1693(will)X +1853(have)X +2041(hash)X +432 3740(values)N +666(with)X +837(the)X +964(0)X +2 f +7 s +3708(th)Y +10 s +1 f +1090 3740(bit)N +1203(set.)X +1341(All)X +1471(such)X +1646(keys)X +1821(and)X +1965(associ-)X +432 3828(ated)N +586(data)X +740(are)X +859(moved)X +1097(to)X +1179(bucket)X +1413(1,)X +1493(and)X +1629(the)X +1747(rest)X +1883(remain)X +2126(in)X +432 3916(bucket)N +666(0.)X +604 4030(After)N +804(this)X +949(split,)X +1135(the)X +1262(\256le)X +1393(now)X +1560(contains)X +1856(two)X +2005(buck-)X +432 4118(ets,)N +562(and)X +699(the)X +818(bitmap)X +1061(contains)X +1349(three)X +1530(bits:)X +1687(the)X +1805(0)X +2 f +7 s +4086(th)Y +10 s +1 f +1922 4118(bit)N +2026(is)X +2099(set)X +432 4206(to)N +525(indicate)X +810(a)X +876(bucket)X +1120(0)X +1190(split)X +1357(when)X +1561(no)X +1671(bits)X +1816(of)X +1913(the)X +2041(hash)X +432 4294(value)N +648(are)X +789(considered,)X +1199(and)X +1357(two)X +1519(more)X +1726(unset)X +1937(bits)X +2094(for)X +432 4382(buckets)N +706(0)X +775(and)X +920(1.)X +1029(The)X +1183(placement)X +1542(of)X +1638(an)X +1742(incoming)X +2072(key)X +432 4470(now)N +604(requires)X +897(examination)X +1327(of)X +1428(the)X +1560(0)X +2 f +7 s +4438(th)Y +10 s +1 f +1691 4470(bit)N +1809(of)X +1910(the)X +2041(hash)X +432 4558(value,)N +667(and)X +824(the)X +963(key)X +1119(is)X +1212(placed)X +1462(either)X +1685(in)X +1787(bucket)X +2041(0)X +2121(or)X +432 4646(bucket)N +674(1.)X +782(If)X +864(either)X +1075(bucket)X +1317(0)X +1385(or)X +1480(bucket)X +1722(1)X +1790(\256lls)X +1937(up,)X +2064(it)X +2135(is)X +432 4734(split)N +598(as)X +693(before,)X +947(its)X +1050(bit)X +1162(is)X +1243(set)X +1360(in)X +1450(the)X +1576(bitmap,)X +1846(and)X +1990(a)X +2054(new)X +432 4822(set)N +541(of)X +628(unset)X +817(bits)X +952(are)X +1071(added)X +1283(to)X +1365(the)X +1483(bitmap.)X +604 4936(Each)N +791(time)X +959(we)X +1079(consider)X +1376(a)X +1437(new)X +1596(bit)X +1705(\(bit)X +1841(n\),)X +1953(we)X +2072(add)X +432 5024(2)N +2 f +7 s +4992(n)Y +9 f +509(+)X +1 f +540(1)X +10 s +595 5024(bits)N +737(to)X +826(the)X +951(bitmap)X +1199(and)X +1341(obtain)X +1567(2)X +2 f +7 s +4992(n)Y +9 f +1644(+)X +1 f +1675(1)X +10 s +1729 5024(more)N +1920(address-)X +432 5112(able)N +595(buckets)X +869(in)X +960(the)X +1087(\256le.)X +1258(As)X +1376(a)X +1441(result,)X +1668(the)X +1795(bitmap)X +2045(con-)X +432 5200(tains)N +618(the)X +751(previous)X +1062(2)X +2 f +7 s +5168(n)Y +9 f +1139(+)X +1 f +1170(1)X +2 f +10 s +9 f +5200(-)Y +1 f +1242(1)X +1317(bits)X +1467(\(1)X +2 f +9 f +1534(+)X +1 f +1578(2)X +2 f +9 f +(+)S +1 f +1662(4)X +2 f +9 f +(+)S +1 f +1746(...)X +2 f +9 f +(+)S +1 f +1850(2)X +2 f +7 s +5168(n)Y +10 s +1 f +1931 5200(\))N +1992(which)X +432 5288(trace)N +649(the)X +807(entire)X +2 f +1050(split)X +1247(history)X +1 f +1529(of)X +1656(the)X +1813(addressable)X +16 s +432 5433 MXY +864 0 Dl +2 f +8 s +472 5488(2)N +1 f +9 s +523 5513(This)N +670(bit-randomizing)X +1153(property)X +1416(is)X +1482(important)X +1780(to)X +1854(obtain)X +2052(radi-)X +432 5593(cally)N +599(different)X +874(hash)X +1033(values)X +1244(for)X +1355(nearly)X +1562(identical)X +1836(keys,)X +2012(which)X +432 5673(in)N +506(turn)X +640(avoids)X +846(clustering)X +1148(of)X +1226(such)X +1376(keys)X +1526(in)X +1600(a)X +1650(single)X +1840(bucket.)X +10 s +2418 538(buckets.)N +2590 652(Given)N +2809(a)X +2868(key)X +3007(and)X +3146(the)X +3267(bitmap)X +3512(created)X +3768(by)X +3871(this)X +4009(algo-)X +2418 740(rithm,)N +2638(we)X +2759(\256rst)X +2910(examine)X +3209(bit)X +3320(0)X +3386(of)X +3479(the)X +3603(bitmap)X +3851(\(the)X +4002(bit)X +4112(to)X +2418 828(consult)N +2673(when)X +2871(0)X +2934(bits)X +3072(of)X +3162(the)X +3283(hash)X +3453(value)X +3650(are)X +3772(being)X +3973(exam-)X +2418 916(ined\).)N +2631(If)X +2713(it)X +2785(is)X +2866(set)X +2982(\(indicating)X +3356(that)X +3503(the)X +3628(bucket)X +3869(split\),)X +4080(we)X +2418 1004(begin)N +2617(considering)X +3012(the)X +3131(bits)X +3267(of)X +3355(the)X +3473(32-bit)X +3684(hash)X +3851(value.)X +4085(As)X +2418 1092(bit)N +2525(n)X +2587(is)X +2662(revealed,)X +2977(a)X +3035(mask)X +3226(equal)X +3422(to)X +3506(2)X +2 f +7 s +1060(n)Y +9 f +3583(+)X +1 f +3614(1)X +2 f +10 s +9 f +1092(-)Y +1 f +3686(1)X +3748(will)X +3894(yield)X +4076(the)X +2418 1180(current)N +2675(bucket)X +2918(address.)X +3228(Adding)X +3496(2)X +2 f +7 s +1148(n)Y +9 f +3573(+)X +1 f +3604(1)X +2 f +10 s +9 f +1180(-)Y +1 f +3676(1)X +3744(to)X +3834(the)X +3960(bucket)X +2418 1268(address)N +2701(identi\256es)X +3035(which)X +3272(bit)X +3397(in)X +3500(the)X +3639(bitmap)X +3902(must)X +4098(be)X +2418 1356(checked.)N +2743(We)X +2876(continue)X +3173(revealing)X +3493(bits)X +3628(of)X +3715(the)X +3833(hash)X +4000(value)X +2418 1444(until)N +2591(all)X +2698(set)X +2814(bits)X +2955(in)X +3043(the)X +3167(bitmap)X +3415(are)X +3540(exhausted.)X +3907(The)X +4058(fol-)X +2418 1532(lowing)N +2682(algorithm,)X +3055(a)X +3133(simpli\256cation)X +3614(of)X +3723(the)X +3863(algorithm)X +2418 1620(due)N +2565(to)X +2658(Ken)X +2823(Thompson)X +3196([THOM90,)X +3590(TOR88],)X +3908(uses)X +4076(the)X +2418 1708(hash)N +2625(value)X +2839(and)X +2995(the)X +3133(bitmap)X +3395(to)X +3497(calculate)X +3823(the)X +3960(bucket)X +2418 1796(address)N +2679(as)X +2766(discussed)X +3093(above.)X +0(Courier)xf 0 f +1 f +0 f +8 s +2418 2095(hash)N +2608(=)X +2684 -0.4038(calchash\(key\);)AX +2418 2183(mask)N +2608(=)X +2684(0;)X +2418 2271(while)N +2646 -0.4018(\(isbitset\(\(hash)AX +3254(&)X +3330(mask\))X +3558(+)X +3634(mask\)\))X +2706 2359(mask)N +2896(=)X +2972(\(mask)X +3200(<<)X +3314(1\))X +3428(+)X +3504(1;)X +2418 2447(bucket)N +2684(=)X +2760(hash)X +2950(&)X +3026(mask;)X +2 f +10 s +3211 2812(sdbm)N +1 f +2590 2944(The)N +2 f +2738(sdbm)X +1 f +2930(library)X +3167(is)X +3243(a)X +3302(public-domain)X +3791(clone)X +3987(of)X +4076(the)X +2 f +2418 3032(ndbm)N +1 f +2638(library,)X +2914(developed)X +3286(by)X +3408(Ozan)X +3620(Yigit)X +3826(to)X +3929(provide)X +2 f +2418 3120(ndbm)N +1 f +2596('s)X +2692(functionality)X +3139(under)X +3359(some)X +3565(versions)X +3869(of)X +3973(UNIX)X +2418 3208(that)N +2559(exclude)X +2830(it)X +2894(for)X +3008(licensing)X +3317(reasons)X +3578([YIG89].)X +3895(The)X +4040(pro-)X +2418 3296(grammer)N +2735(interface,)X +3064(and)X +3207(the)X +3332(basic)X +3524(structure)X +3832(of)X +2 f +3926(sdbm)X +1 f +4121(is)X +2418 3384(identical)N +2733(to)X +2 f +2834(ndbm)X +1 f +3051(but)X +3192(internal)X +3476(details)X +3723(of)X +3828(the)X +2 f +3964(access)X +1 f +2418 3472(function,)N +2726(such)X +2894(as)X +2982(the)X +3101(calculation)X +3474(of)X +3561(the)X +3679(bucket)X +3913(address,)X +2418 3560(and)N +2563(the)X +2690(use)X +2825(of)X +2920(different)X +3225(hash)X +3400(functions)X +3726(make)X +3928(the)X +4054(two)X +2418 3648(incompatible)N +2856(at)X +2934(the)X +3052(database)X +3349(level.)X +2590 3762(The)N +2 f +2740(sdbm)X +1 f +2934(library)X +3173(is)X +3251(based)X +3458(on)X +3562(a)X +3622(simpli\256ed)X +3965(imple-)X +2418 3850(mentation)N +2778(of)X +2885(Larson's)X +3206(1978)X +2 f +3406(dynamic)X +3717(hashing)X +1 f +4009(algo-)X +2418 3938(rithm)N +2616(including)X +2943(the)X +2 f +3066(re\256nements)X +3461(and)X +3605(variations)X +1 f +3953(of)X +4044(sec-)X +2418 4026(tion)N +2562(5)X +2622([LAR78].)X +2956(Larson's)X +3257(original)X +3526(algorithm)X +3857(calls)X +4024(for)X +4138(a)X +2418 4114(forest)N +2635(of)X +2736(binary)X +2975(hash)X +3156(trees)X +3341(that)X +3494(are)X +3626(accessed)X +3941(by)X +4054(two)X +2418 4202(hash)N +2586(functions.)X +2925(The)X +3071(\256rst)X +3216(hash)X +3384(function)X +3672(selects)X +3907(a)X +3964(partic-)X +2418 4290(ular)N +2571(tree)X +2720(within)X +2952(the)X +3078(forest.)X +3309(The)X +3462(second)X +3713(hash)X +3887(function,)X +2418 4378(which)N +2659(is)X +2757(required)X +3070(to)X +3177(be)X +3297(a)X +3377(boolean)X +3675(pseudo-random)X +2418 4466(number)N +2687(generator)X +3015(that)X +3159(is)X +3236(seeded)X +3479(by)X +3583(the)X +3705(key,)X +3865(is)X +3942(used)X +4112(to)X +2418 4554(traverse)N +2733(the)X +2890(tree)X +3070(until)X +3275(internal)X +3579(\(split\))X +3829(nodes)X +4075(are)X +2418 4642(exhausted)N +2763(and)X +2903(an)X +3003(external)X +3286(\(non-split\))X +3648(node)X +3827(is)X +3903(reached.)X +2418 4730(The)N +2571(bucket)X +2813(addresses)X +3149(are)X +3276(stored)X +3500(directly)X +3772(in)X +3861(the)X +3986(exter-)X +2418 4818(nal)N +2536(nodes.)X +2590 4932(Larson's)N +2903(re\256nements)X +3309(are)X +3440(based)X +3655(on)X +3767(the)X +3897(observa-)X +2418 5020(tion)N +2570(that)X +2718(the)X +2844(nodes)X +3059(can)X +3199(be)X +3303(represented)X +3702(by)X +3809(a)X +3872(single)X +4090(bit)X +2418 5108(that)N +2569(is)X +2653(set)X +2773(for)X +2898(internal)X +3174(nodes)X +3392(and)X +3539(not)X +3672(set)X +3791(for)X +3915(external)X +2418 5196(nodes,)N +2652(resulting)X +2959(in)X +3048(a)X +3111(radix)X +3303(search)X +3536(trie.)X +3709(Figure)X +3944(1)X +4010(illus-)X +2418 5284(trates)N +2621(this.)X +2804(Nodes)X +3037(A)X +3123(and)X +3267(B)X +3348(are)X +3475(internal)X +3748(\(split\))X +3967(nodes,)X +2418 5372(thus)N +2573(having)X +2813(no)X +2915(bucket)X +3151(addresses)X +3480(associated)X +3831(with)X +3994(them.)X +2418 5460(Instead,)N +2693(the)X +2814(external)X +3096(nodes)X +3306(\(C,)X +3429(D,)X +3530(and)X +3669(E\))X +3768(each)X +3938(need)X +4112(to)X +2418 5548(refer)N +2594(to)X +2679(a)X +2738(bucket)X +2975(address.)X +3279(These)X +3494(bucket)X +3731(addresses)X +4062(can)X +2418 5636(be)N +2529(stored)X +2760(in)X +2857(the)X +2990(trie)X +3132(itself)X +3327(where)X +3559(the)X +3691(subtries)X +3974(would)X +3 f +432 5960(2)N +2970(USENIX)X +9 f +3292(-)X +3 f +3356(Winter)X +3621('91)X +9 f +3748(-)X +3 f +3812(Dallas,)X +4065(TX)X + +3 p +%%Page: 3 3 +0(Courier)xf 0 f +10 s 10 xH 0 xS 0 f +3 f +720 258(Seltzer)N +977(&)X +1064(Yigit)X +3278(A)X +3356(New)X +3528(Hashing)X +3831(Package)X +4136(for)X +4259(UNIX)X +1 f +720 538(live)N +862(if)X +933(they)X +1092(existed)X +1340([KNU68].)X +1709(For)X +1841(example,)X +2154(if)X +2224(nodes)X +2432(F)X +720 626(and)N +858(G)X +938(were)X +1117(the)X +1237(children)X +1522(of)X +1610(node)X +1787(C,)X +1881(the)X +2000(bucket)X +2235(address)X +720 714(L00)N +886(could)X +1101(reside)X +1330(in)X +1429(the)X +1563(bits)X +1714(that)X +1870(will)X +2030(eventually)X +2400(be)X +720 802(used)N +887(to)X +969(store)X +1145(nodes)X +1352(F)X +1416(and)X +1552(G)X +1630(and)X +1766(all)X +1866(their)X +2033(children.)X +10 f +720 890 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN +3 f +1894 2247(L1)N +784 1925(A)N +1431(E)X +1106 2247(D)N +1428 1281(C)N +1109 1603(B)N +1884 1930(L01)N +1879 1286(L00)N +1221 1814(1)N +903 2131(1)N +1221 1402(0)N +903 1714(0)N +1 Dt +1397 1821 MXY +-8 -32 Dl +-5 19 Dl +-20 6 Dl +33 7 Dl +-187 -182 Dl +1397 1322 MXY +-33 7 Dl +20 6 Dl +5 19 Dl +8 -32 Dl +-187 182 Dl +1069 1639 MXY +-32 7 Dl +20 6 Dl +5 19 Dl +7 -32 Dl +-186 182 Dl +1374 1891 MXY +185 Dc +1779 2133 MXY +0 161 Dl +322 0 Dl +0 -161 Dl +-322 0 Dl +1811 MY +0 161 Dl +322 0 Dl +0 -161 Dl +-322 0 Dl +1166 MY +0 161 Dl +322 0 Dl +0 -161 Dl +-322 0 Dl +1052 2213 MXY +185 Dc +1569 MY +185 Dc +720 1881 MXY +185 Dc +1779 2213 MXY +-28 -17 Dl +10 17 Dl +-10 18 Dl +28 -18 Dl +-543 0 Dl +1769 1891 MXY +-28 -18 Dl +10 18 Dl +-10 18 Dl +28 -18 Dl +-201 0 Dl +1364 1247 MXY +185 Dc +1769 MX +-28 -18 Dl +10 18 Dl +-10 18 Dl +28 -18 Dl +-201 0 Dl +1064 2143 MXY +-7 -32 Dl +-5 19 Dl +-20 6 Dl +32 7 Dl +-181 -181 Dl +3 Dt +-1 Ds +8 s +720 2482(Figure)N +925(1:)X +1 f +1002(Radix)X +1179(search)X +1365(trie)X +1474(with)X +1612(internal)X +1831(nodes)X +2004(A)X +2074(and)X +2189(B,)X +2271(external)X +720 2570(nodes)N +891(C,)X +972(D,)X +1056(and)X +1170(E,)X +1247(and)X +1361(bucket)X +1553(addresses)X +1819(stored)X +1997(in)X +2069(the)X +2168(unused)X +2370(por-)X +720 2658(tion)N +836(of)X +905(the)X +999(trie.)X +10 s +10 f +720 2922 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN +1 f +892 3124(Further)N +1153(simpli\256cations)X +1647(of)X +1738(the)X +1860(above)X +2076([YIG89])X +2377(are)X +720 3212(possible.)N +1038(Using)X +1265(a)X +1337(single)X +1564(radix)X +1765(trie)X +1908(to)X +2006(avoid)X +2219(the)X +2352(\256rst)X +720 3300(hash)N +904(function,)X +1227(replacing)X +1562(the)X +1696(pseudo-random)X +2231(number)X +720 3388(generator)N +1052(with)X +1222(a)X +1286(well)X +1452(designed,)X +1785(bit-randomizing)X +2329(hash)X +720 3476(function,)N +1053(and)X +1215(using)X +1434(the)X +1578(portion)X +1855(of)X +1967(the)X +2110(hash)X +2302(value)X +720 3564(exposed)N +1021(during)X +1268(the)X +1404(trie)X +1549(traversal)X +1864(as)X +1969(a)X +2042(direct)X +2262(bucket)X +720 3652(address)N +990(results)X +1228(in)X +1319(an)X +2 f +1424(access)X +1 f +1663(function)X +1959(that)X +2108(works)X +2333(very)X +720 3740(similar)N +974(to)X +1068(Thompson's)X +1499(algorithm)X +1841(above.)X +2084(The)X +2240(follow-)X +720 3828(ing)N +847(algorithm)X +1183(uses)X +1346(the)X +1469(hash)X +1641(value)X +1840(to)X +1927(traverse)X +2206(a)X +2266(linear-)X +720 3916(ized)N +874(radix)X +1059(trie)X +2 f +8 s +1166 3891(3)N +1 f +10 s +1218 3916(starting)N +1478(at)X +1556(the)X +1674(0)X +2 f +7 s +3884(th)Y +10 s +1 f +1791 3916(bit.)N +0 f +8 s +720 4215(tbit)N +910(=)X +986(0;)X +1296(/*)X +1410(radix)X +1638(trie)X +1828(index)X +2056(*/)X +720 4303(hbit)N +910(=)X +986(0;)X +1296(/*)X +1410(hash)X +1600(bit)X +1752(index)X +2056(*/)X +720 4391(mask)N +910(=)X +986(0;)X +720 4479(hash)N +910(=)X +986 -0.4038(calchash\(key\);)AX +720 4655(for)N +872(\(mask)X +1100(=)X +1176(0;)X +910 4743 -0.4018(isbitset\(tbit\);)AN +910 4831(mask)N +1100(=)X +1176(\(mask)X +1404(<<)X +1518(1\))X +1632(+)X +1708(1\))X +1008 4919(if)N +1122(\(hash)X +1350(&)X +1426(\(1)X +1540(<<)X +1654 -0.4219(hbit++\)\)\))AX +1160 5007(/*)N +1274(right)X +1502(son)X +1692(*/)X +1160 5095(tbit)N +1350(=)X +1426(2)X +1502(*)X +1578(tbit)X +1768(+)X +1844(2;)X +1008 5183(else)N +1 f +16 s +720 5353 MXY +864 0 Dl +2 f +8 s +760 5408(3)N +1 f +9 s +818 5433(A)N +896(linearized)X +1206(radix)X +1380(trie)X +1502(is)X +1576(merely)X +1802(an)X +1895(array)X +2068(representation)X +720 5513(of)N +800(the)X +908(radix)X +1076(search)X +1280(trie)X +1396(described)X +1692(above.)X +1920(The)X +2052(children)X +2308(of)X +2388(the)X +720 5593(node)N +885(with)X +1038(index)X +1223(i)X +1267(can)X +1391(be)X +1483(found)X +1675(at)X +1751(the)X +1863(nodes)X +2055(indexed)X +2307(2*i+1)X +720 5673(and)N +842(2*i+2.)X +0 f +8 s +3146 538(/*)N +3260(left)X +3450(son)X +3678(*/)X +3146 626(tbit)N +3336(=)X +3412(2)X +3488(*)X +3564(tbit)X +3754(+)X +3830(1;)X +2706 802(bucket)N +2972(=)X +3048(hash)X +3238(&)X +3314(mask;)X +2 f +10 s +3495 1167(gdbm)N +1 f +2878 1299(The)N +3027(gdbm)X +3233(\(GNU)X +3458(data)X +3616(base)X +3783(manager\))X +4111(library)X +4349(is)X +4426(a)X +2706 1387(UNIX)N +2933(database)X +3236(manager)X +3539(written)X +3792(by)X +3897(Philip)X +4112(A.)X +4215(Nelson,)X +2706 1475(and)N +2848(made)X +3048(available)X +3364(as)X +3457(a)X +3518(part)X +3668(of)X +3760(the)X +3883(FSF)X +4040(software)X +4342(dis-)X +2706 1563(tribution.)N +3052(The)X +3207(gdbm)X +3419(library)X +3663(provides)X +3969(the)X +4097(same)X +4292(func-)X +2706 1651(tionality)N +3028(of)X +3151(the)X +2 f +3304(dbm)X +1 f +3442(/)X +2 f +3464(ndbm)X +1 f +3697(libraries)X +4015([NEL90])X +4360(but)X +2706 1739(attempts)N +3018(to)X +3121(avoid)X +3340(some)X +3550(of)X +3658(their)X +3846(shortcomings.)X +4337(The)X +2706 1827(gdbm)N +2918(library)X +3162(allows)X +3401(for)X +3525(arbitrary-length)X +4059(data,)X +4242(and)X +4387(its)X +2706 1915(database)N +3027(is)X +3124(a)X +3203(singular,)X +3524(non-sparse)X +2 f +8 s +3872 1890(4)N +1 f +10 s +3947 1915(\256le.)N +4112(The)X +4280(gdbm)X +2706 2003(library)N +2947(also)X +3103(includes)X +2 f +3396(dbm)X +1 f +3560(and)X +2 f +3702(ndbm)X +1 f +3906(compatible)X +4288(inter-)X +2706 2091(faces.)N +2878 2205(The)N +3025(gdbm)X +3229(library)X +3465(is)X +3540(based)X +3745(on)X +2 f +3847(extensible)X +4189(hashing)X +1 f +4442(,)X +2706 2293(a)N +2766(dynamic)X +3066(hashing)X +3339(algorithm)X +3674(by)X +3778(Fagin)X +3984(et)X +4066(al)X +4148([FAG79].)X +2706 2381(This)N +2881(algorithm)X +3225(differs)X +3467(from)X +3655(the)X +3785(previously)X +4155(discussed)X +2706 2469(algorithms)N +3069(in)X +3152(that)X +3293(it)X +3358(uses)X +3517(a)X +2 f +3574(directory)X +1 f +3889(that)X +4030(is)X +4103(a)X +4159(collapsed)X +2706 2557(representation)N +3192([ENB88])X +3517(of)X +3615(the)X +3744(radix)X +3940(search)X +4177(trie)X +4315(used)X +2706 2645(by)N +2 f +2806(sdbm)X +1 f +2975(.)X +10 f +2706 2733 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN +3 f +7 s +3572 3761(L1)N +1 Dt +3485 3738 MXY +-20 -13 Dl +7 13 Dl +-7 13 Dl +20 -13 Dl +-400 0 Dl +3180 3027 MXY +136 Dc +2706 3494 MXY +136 Dc +2950 3264 MXY +136 Dc +3738 MY +136 Dc +3485 2968 MXY +0 118 Dl +238 0 Dl +0 -118 Dl +-238 0 Dl +3442 MY +0 119 Dl +238 0 Dl +0 -119 Dl +-238 0 Dl +3679 MY +0 119 Dl +238 0 Dl +0 -119 Dl +-238 0 Dl +3187 3501 MXY +136 Dc +2963 3316 MXY +-24 5 Dl +15 4 Dl +4 15 Dl +5 -24 Dl +-137 134 Dl +3204 3083 MXY +-24 5 Dl +15 4 Dl +3 14 Dl +6 -23 Dl +-137 133 Dl +3204 3450 MXY +-6 -24 Dl +-3 14 Dl +-15 5 Dl +24 5 Dl +-137 -134 Dl +2842 3369(0)N +3075 3139(0)N +2842 3676(1)N +3075 3443(1)N +3562 3054(L00)N +3565 3528(L01)N +4197 2968 MXY +0 118 Dl +237 0 Dl +0 -118 Dl +-237 0 Dl +3205 MY +0 119 Dl +237 0 Dl +0 -119 Dl +-237 0 Dl +3561 MY +0 118 Dl +237 0 Dl +0 -118 Dl +-237 0 Dl +3960 2909 MXY +0 237 Dl +118 0 Dl +0 -237 Dl +-118 0 Dl +3146 MY +0 237 Dl +118 0 Dl +0 -237 Dl +-118 0 Dl +3383 MY +0 237 Dl +118 0 Dl +0 -237 Dl +-118 0 Dl +3620 MY +0 237 Dl +118 0 Dl +0 -237 Dl +-118 0 Dl +4197 3027 MXY +-21 -13 Dl +8 13 Dl +-8 13 Dl +21 -13 Dl +-119 0 Dl +4197 3264 MXY +-21 -13 Dl +8 13 Dl +-8 13 Dl +21 -13 Dl +-119 0 Dl +3501 MY +59 0 Dl +0 89 Dl +4078 3738 MXY +59 0 Dl +0 -88 Dl +4197 3590 MXY +-21 -13 Dl +8 13 Dl +-8 13 Dl +21 -13 Dl +-60 0 Dl +4197 3650 MXY +-21 -13 Dl +8 13 Dl +-8 13 Dl +21 -13 Dl +-60 0 Dl +3991 3050(00)N +3991 3287(01)N +3991 3524(10)N +3991 3761(11)N +4269 3050(L00)N +4269 3287(L01)N +4283 3643(L1)N +3485 3501 MXY +-20 -13 Dl +7 13 Dl +-7 13 Dl +20 -13 Dl +-155 0 Dl +3485 3027 MXY +-20 -13 Dl +7 13 Dl +-7 13 Dl +20 -13 Dl +-163 0 Dl +2967 3687 MXY +-5 -24 Dl +-4 14 Dl +-15 4 Dl +24 6 Dl +-141 -141 Dl +3 Dt +-1 Ds +8 s +2706 4033(Figure)N +2903(2:)X +1 f +2972(A)X +3034(radix)X +3181(search)X +3359(trie)X +3460(and)X +3568(a)X +3612(directory)X +3858(representing)X +4189(the)X +4283(trie.)X +10 s +10 f +2706 4209 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN +1 f +2878 4411(In)N +2968(this)X +3106(algorithm,)X +3460(a)X +3519(directory)X +3832(consists)X +4108(of)X +4198(a)X +4256(search)X +2706 4499(trie)N +2847(of)X +2947(depth)X +2 f +3158(n)X +1 f +3211(,)X +3264(containing)X +3635(2)X +2 f +7 s +4467(n)Y +10 s +1 f +3749 4499(bucket)N +3996(addresses)X +4337(\(i.e.)X +2706 4587(each)N +2897(element)X +3194(of)X +3304(the)X +3445(trie)X +3594(is)X +3689(a)X +3767(bucket)X +4023(address\).)X +4373(To)X +2706 4675(access)N +2935(the)X +3056(hash)X +3226(table,)X +3425(a)X +3483(32-bit)X +3696(hash)X +3865(value)X +4061(is)X +4136(calculated)X +2706 4763(and)N +2 f +2861(n)X +1 f +2953(bits)X +3107(of)X +3213(the)X +3350(value)X +3563(are)X +3701(used)X +3886(to)X +3986(index)X +4202(into)X +4364(the)X +2706 4851(directory)N +3018(to)X +3102(obtain)X +3324(a)X +3382(bucket)X +3618(address.)X +3921(It)X +3992(is)X +4067(important)X +4400(to)X +2706 4939(note)N +2866(that)X +3008(multiple)X +3296(entries)X +3532(of)X +3620(this)X +3756(directory)X +4067(may)X +4226(contain)X +2706 5027(the)N +2833(same)X +3026(bucket)X +3268(address)X +3537(as)X +3632(a)X +3696(result)X +3902(of)X +3997(directory)X +4315(dou-)X +2706 5115(bling)N +2903(during)X +3145(bucket)X +3392(splitting.)X +3706(Figure)X +3948(2)X +4021(illustrates)X +4364(the)X +2706 5203(relationship)N +3126(between)X +3436(a)X +3513(typical)X +3772(\(skewed\))X +4108(search)X +4355(trie)X +2706 5291(and)N +2850(its)X +2953(directory)X +3271(representation.)X +3774(The)X +3927(formation)X +4270(of)X +4364(the)X +2706 5379(directory)N +3016(shown)X +3245(in)X +3327(the)X +3445(\256gure)X +3652(is)X +3725(as)X +3812(follows.)X +16 s +2706 5593 MXY +864 0 Dl +2 f +8 s +2746 5648(4)N +1 f +9 s +2796 5673(It)N +2858(does)X +3008(not)X +3118(contain)X +3348(holes.)X +3 f +10 s +720 5960(USENIX)N +9 f +1042(-)X +3 f +1106(Winter)X +1371('91)X +9 f +1498(-)X +3 f +1562(Dallas,)X +1815(TX)X +4424(3)X + +4 p +%%Page: 4 4 +0(Courier)xf 0 f +10 s 10 xH 0 xS 0 f +3 f +432 258(A)N +510(New)X +682(Hashing)X +985(Package)X +1290(for)X +1413(UNIX)X +3663(Seltzer)X +3920(&)X +4007(Yigit)X +1 f +604 538(Initially,)N +937(there)X +1158(is)X +1271(one)X +1446(slot)X +1620(in)X +1741(the)X +1898(directory)X +432 626(addressing)N +802(a)X +865(single)X +1083(bucket.)X +1364(The)X +1515(depth)X +1719(of)X +1812(the)X +1936(trie)X +2069(is)X +2148(0)X +432 714(and)N +577(0)X +646(bits)X +790(of)X +886(each)X +1063(hash)X +1239(value)X +1442(are)X +1570(examined)X +1910(to)X +2000(deter-)X +432 802(mine)N +624(in)X +718(which)X +946(bucket)X +1192(to)X +1286(place)X +1488(a)X +1556(key;)X +1726(all)X +1837(keys)X +2015(go)X +2126(in)X +432 890(bucket)N +682(0.)X +797(When)X +1024(this)X +1174(bucket)X +1423(is)X +1511(full,)X +1677(its)X +1787(contents)X +2089(are)X +432 978(divided)N +698(between)X +992(L0)X +1107(and)X +1249(L1)X +1363(as)X +1455(was)X +1605(done)X +1786(in)X +1873(the)X +1996(previ-)X +432 1066(ously)N +664(discussed)X +1030(algorithms.)X +1471(After)X +1700(this)X +1874(split,)X +2090(the)X +432 1154(address)N +710(of)X +814(the)X +948(second)X +1207(bucket)X +1457(must)X +1648(be)X +1760(stored)X +1992(in)X +2090(the)X +432 1242(directory.)N +796(To)X +939(accommodate)X +1438(the)X +1589(new)X +1776(address,)X +2090(the)X +432 1330(directory)N +752(is)X +835(split)X +2 f +8 s +972 1305(5)N +1 f +10 s +1330(,)Y +1054(by)X +1163(doubling)X +1476(it,)X +1569(thus)X +1731(increasing)X +2090(the)X +432 1418(depth)N +630(of)X +717(the)X +835(directory)X +1145(by)X +1245(one.)X +604 1532(After)N +813(this)X +967(split,)X +1163(a)X +1237(single)X +1466(bit)X +1588(of)X +1693(the)X +1829(hash)X +2014(value)X +432 1620(needs)N +663(to)X +773(be)X +896(examined)X +1255(to)X +1364(decide)X +1621(whether)X +1927(the)X +2072(key)X +432 1708(belongs)N +711(to)X +803(L0)X +922(or)X +1019(L1.)X +1158(Once)X +1358(one)X +1504(of)X +1601(these)X +1795(buckets)X +2069(\256lls)X +432 1796(\(L0)N +578(for)X +702(example\),)X +1051(it)X +1125(is)X +1208(split)X +1375(as)X +1472(before,)X +1728(and)X +1873(the)X +2000(direc-)X +432 1884(tory)N +585(is)X +662(split)X +823(again)X +1021(to)X +1107(make)X +1305(room)X +1498(for)X +1615(the)X +1736(address)X +2000(of)X +2090(the)X +432 1972(third)N +618(bucket.)X +927(This)X +1104(splitting)X +1400(causes)X +1645(the)X +1778(addresses)X +2121(of)X +432 2060(the)N +567(non-splitting)X +1012(bucket)X +1263(\(L1\))X +1443(to)X +1541(be)X +1653(duplicated.)X +2063(The)X +432 2148(directory)N +766(now)X +948(has)X +1099(four)X +1277(entries,)X +1555(a)X +1635(depth)X +1857(of)X +1968(2,)X +2072(and)X +432 2236(indexes)N +700(the)X +821(buckets)X +1089(L00,)X +1261(L01)X +1413(and)X +1552(L1,)X +1684(as)X +1774(shown)X +2006(in)X +2090(the)X +432 2324(Figure)N +661(2.)X +604 2438(The)N +756(crucial)X +1002(part)X +1154(of)X +1247(the)X +1371(algorithm)X +1708(is)X +1787(the)X +1911(observa-)X +432 2526(tion)N +580(that)X +724(L1)X +837(is)X +914(addressed)X +1255(twice)X +1453(in)X +1539(the)X +1661(directory.)X +1995(If)X +2073(this)X +432 2614(bucket)N +679(were)X +869(to)X +964(split)X +1134(now,)X +1324(the)X +1454(directory)X +1776(already)X +2045(con-)X +432 2702(tains)N +611(room)X +808(to)X +898(hold)X +1067(the)X +1192(address)X +1460(of)X +1554(the)X +1679(new)X +1840(bucket.)X +2121(In)X +432 2790(general,)N +711(the)X +831(relationship)X +1231(between)X +1521(the)X +1641(directory)X +1953(and)X +2090(the)X +432 2878(number)N +704(of)X +798(bucket)X +1039(addresses)X +1374(contained)X +1713(therein)X +1962(is)X +2041(used)X +432 2966(to)N +517(decide)X +750(when)X +947(to)X +1031(split)X +1190(the)X +1310(directory.)X +1662(Each)X +1845(bucket)X +2081(has)X +432 3054(a)N +505(depth,)X +740(\()X +2 f +767(n)X +7 s +3070(b)Y +10 s +1 f +848 3054(\),)N +932(associated)X +1299(with)X +1478(it)X +1558(and)X +1710(appears)X +1992(in)X +2090(the)X +432 3142(directory)N +744(exactly)X +998(2)X +2 f +7 s +3106(n)Y +9 f +1075(-)X +2 f +1106(n)X +4 s +3110(b)Y +7 s +1 f +10 s +1181 3142(times.)N +1396(When)X +1610(a)X +1668(bucket)X +1904(splits,)X +2113(its)X +432 3230(depth)N +638(increases)X +961(by)X +1069(one.)X +1253(The)X +1406(directory)X +1724(must)X +1907(split)X +2072(any)X +432 3318(time)N +602(a)X +665(bucket's)X +964(depth)X +1169(exceeds)X +1451(the)X +1576(depth)X +1781(of)X +1875(the)X +2000(direc-)X +432 3406(tory.)N +630(The)X +784(following)X +1123(code)X +1303(fragment)X +1621(helps)X +1818(to)X +1908(illustrate)X +432 3494(the)N +554(extendible)X +912(hashing)X +1185(algorithm)X +1520([FAG79])X +1838(for)X +1955(access-)X +432 3582(ing)N +554(individual)X +898(buckets)X +1163(and)X +1299(maintaining)X +1701(the)X +1819(directory.)X +0 f +8 s +432 3881(hash)N +622(=)X +698 -0.4038(calchash\(key\);)AX +432 3969(mask)N +622(=)X +698 -0.4018(maskvec[depth];)AX +432 4145(bucket)N +698(=)X +774 -0.4038(directory[hash)AX +1344(&)X +1420(mask];)X +432 4321(/*)N +546(Key)X +698 -0.4219(Insertion)AX +1078(*/)X +432 4409(if)N +546 -0.4038(\(store\(bucket,)AX +1116(key,)X +1306(data\))X +1534(==)X +1648(FAIL\))X +1876({)X +720 4497(newbl)N +948(=)X +1024 -0.4167(getpage\(\);)AX +720 4585 -0.4000(bucket->depth++;)AN +720 4673 -0.4091(newbl->depth)AN +1214(=)X +1290 -0.4038(bucket->depth;)AX +720 4761(if)N +834 -0.4038(\(bucket->depth)AX +1404(>)X +1480(depth\))X +1746({)X +1008 4849(/*)N +1122(double)X +1388 -0.4219(directory)AX +1768(*/)X +1008 4937(depth++;)N +1 f +16 s +432 5033 MXY +864 0 Dl +2 f +8 s +472 5088(5)N +1 f +9 s +534 5113(This)N +692(decision)X +962(to)X +1048(split)X +1202(the)X +1319(directory)X +1608(is)X +1685(based)X +1878(on)X +1979(a)X +2040(com-)X +432 5193(parison)N +666(of)X +748(the)X +858(depth)X +1040(of)X +1121(the)X +1230(page)X +1387(being)X +1568(split)X +1713(and)X +1838(the)X +1947(depth)X +2128(of)X +432 5273(the)N +543(trie.)X +698(In)X +781(Figure)X +992(2,)X +1069(the)X +1180(depths)X +1390(of)X +1472(both)X +1622(L00)X +1760(and)X +1886(L01)X +2024(are)X +2134(2,)X +432 5353(whereas)N +689(the)X +798(depth)X +979(of)X +1060(L1)X +1161(is)X +1230(1.)X +1323(Therefore,)X +1646(if)X +1710(L1)X +1810(were)X +1970(to)X +2046(split,)X +432 5433(the)N +543(directory)X +826(would)X +1029(not)X +1144(need)X +1303(to)X +1382(split.)X +1565(In)X +1648(reality,)X +1872(a)X +1926(bucket)X +2140(is)X +432 5513(allocated)N +727(for)X +846(the)X +969(directory)X +1264(at)X +1351(the)X +1474(time)X +1637(of)X +1732(\256le)X +1858(creation)X +2124(so)X +432 5593(although)N +707(the)X +818(directory)X +1100(splits)X +1274(logically,)X +1566(physical)X +1828(splits)X +2002(do)X +2096(not)X +432 5673(occur)N +610(until)X +760(the)X +866(\256le)X +976(becomes)X +1246(quite)X +1408(large.)X +0 f +8 s +2994 538 -0.4219(directory)AN +3374(=)X +3450 -0.3971(double\(directory\);)AX +2706 626(})N +2706 714 -0.3958(splitbucket\(bucket,)AN +3466(newbl\))X +2706 802(...)N +2418 890(})N +2 f +10 s +3169 1255(hsearch)N +1 f +2590 1387(Since)N +2 f +2807(hsearch)X +1 f +3100(does)X +3286(not)X +3427(have)X +3617(to)X +3717(translate)X +4027(hash)X +2418 1475(values)N +2659(into)X +2819(disk)X +2988(addresses,)X +3352(it)X +3432(can)X +3579(use)X +3721(much)X +3934(simpler)X +2418 1563(algorithms)N +2808(than)X +2994(those)X +3211(de\256ned)X +3495(above.)X +3775(System)X +4058(V's)X +2 f +2418 1651(hsearch)N +1 f +2708(constructs)X +3069(a)X +3141(\256xed-size)X +3489(hash)X +3671(table)X +3862(\(speci\256ed)X +2418 1739(by)N +2519(the)X +2637(user)X +2791(at)X +2869(table)X +3045(creation\).)X +3391(By)X +3504(default,)X +3767(a)X +3823(multiplica-)X +2418 1827(tive)N +2570(hash)X +2748(function)X +3046(based)X +3260(on)X +3371(that)X +3522(described)X +3861(in)X +3954(Knuth,)X +2418 1915(Volume)N +2710(3,)X +2804(section)X +3065(6.4)X +3199([KNU68])X +3541(is)X +3628(used)X +3809(to)X +3905(obtain)X +4138(a)X +2418 2003(primary)N +2694(bucket)X +2930(address.)X +3233(If)X +3309(this)X +3446(bucket)X +3681(is)X +3755(full,)X +3907(a)X +3964(secon-)X +2418 2091(dary)N +2593(multiplicative)X +3069(hash)X +3248(value)X +3454(is)X +3538(computed)X +3885(to)X +3978(de\256ne)X +2418 2179(the)N +2542(probe)X +2751(interval.)X +3062(The)X +3213(probe)X +3422(interval)X +3693(is)X +3772(added)X +3989(to)X +4076(the)X +2418 2267(original)N +2712(bucket)X +2971(address)X +3257(\(modulo)X +3573(the)X +3716(table)X +3916(size\))X +4112(to)X +2418 2355(obtain)N +2658(a)X +2734(new)X +2908(bucket)X +3162(address.)X +3483(This)X +3665(process)X +3946(repeats)X +2418 2443(until)N +2588(an)X +2688(empty)X +2911(bucket)X +3148(is)X +3224(found.)X +3474(If)X +3551(no)X +3654(bucket)X +3891(is)X +3967(found,)X +2418 2531(an)N +2514(insertion)X +2814(fails)X +2972(with)X +3134(a)X +3190(``table)X +3420(full'')X +3605(condition.)X +2590 2645(The)N +2768(basic)X +2986(algorithm)X +3350(may)X +3541(be)X +3670(modi\256ed)X +4006(by)X +4138(a)X +2418 2733(number)N +2705(of)X +2813(compile)X +3112(time)X +3295(options)X +3571(available)X +3902(to)X +4005(those)X +2418 2821(users)N +2604(with)X +2767(AT&T)X +3006(source)X +3237(code.)X +3450(First,)X +3637(the)X +3756(package)X +4040(pro-)X +2418 2909(vides)N +2638(two)X +2809(options)X +3094(for)X +3238(hash)X +3435(functions.)X +3803(Users)X +4036(may)X +2418 2997(specify)N +2690(their)X +2877(own)X +3055(hash)X +3242(function)X +3549(by)X +3669(compiling)X +4032(with)X +2418 3085(``USCR'')N +2757(de\256ned)X +3016(and)X +3155(declaring)X +3477(and)X +3616(de\256ning)X +3901(the)X +4022(vari-)X +2418 3173(able)N +2 f +2578(hcompar)X +1 f +2863(,)X +2909(a)X +2971(function)X +3263(taking)X +3488(two)X +3633(string)X +3840(arguments)X +2418 3261(and)N +2560(returning)X +2880(an)X +2982(integer.)X +3271(Users)X +3480(may)X +3643(also)X +3797(request)X +4054(that)X +2418 3349(hash)N +2587(values)X +2814(be)X +2912(computed)X +3250(simply)X +3489(by)X +3590(taking)X +3811(the)X +3930(modulo)X +2418 3437(of)N +2521(key)X +2673(\(using)X +2909(division)X +3201(rather)X +3424(than)X +3597(multiplication)X +4080(for)X +2418 3525(hash)N +2589(value)X +2787(calculation\).)X +3230(If)X +3308(this)X +3447(technique)X +3783(is)X +3859(used,)X +4049(col-)X +2418 3613(lisions)N +2651(are)X +2775(resolved)X +3072(by)X +3176(scanning)X +3485(sequentially)X +3896(from)X +4076(the)X +2418 3701(selected)N +2702(bucket)X +2941(\(linear)X +3176(probing\).)X +3517(This)X +3684(option)X +3913(is)X +3991(avail-)X +2418 3789(able)N +2572(by)X +2672(de\256ning)X +2954(the)X +3072(variable)X +3351(``DIV'')X +3622(at)X +3700(compile)X +3978(time.)X +2590 3903(A)N +2720(second)X +3015(option,)X +3311(based)X +3565(on)X +3716(an)X +3863(algorithm)X +2418 3991(discovered)N +2787(by)X +2888(Richard)X +3163(P.)X +3248(Brent,)X +3466(rearranges)X +3822(the)X +3940(table)X +4116(at)X +2418 4079(the)N +2549(time)X +2724(of)X +2824(insertion)X +3137(in)X +3232(order)X +3434(to)X +3528(speed)X +3743(up)X +3855(retrievals.)X +2418 4167(The)N +2571(basic)X +2764(idea)X +2926(is)X +3007(to)X +3097(shorten)X +3361(long)X +3531(probe)X +3741(sequences)X +4094(by)X +2418 4255(lengthening)N +2833(short)X +3030(probe)X +3249(sequences.)X +3651(Once)X +3857(the)X +3991(probe)X +2418 4343(chain)N +2613(has)X +2741(exceeded)X +3062(some)X +3252(threshold)X +3571(\(Brent)X +3796(suggests)X +4087(2\),)X +2418 4431(we)N +2541(attempt)X +2809(to)X +2899(shuf\257e)X +3145(any)X +3289(colliding)X +3601(keys)X +3776(\(keys)X +3978(which)X +2418 4519(appeared)N +2734(in)X +2821(the)X +2944(probe)X +3152(sequence)X +3471(of)X +3562(the)X +3684(new)X +3842(key\).)X +4049(The)X +2418 4607(details)N +2652(of)X +2744(this)X +2884(key)X +3025(shuf\257ing)X +3333(can)X +3469(be)X +3569(found)X +3780(in)X +3866([KNU68])X +2418 4695(and)N +2576([BRE73].)X +2946(This)X +3129(algorithm)X +3481(may)X +3660(be)X +3777(obtained)X +4094(by)X +2418 4783(de\256ning)N +2700(the)X +2818(variable)X +3097(``BRENT'')X +3487(at)X +3565(compile)X +3843(time.)X +2590 4897(A)N +2698(third)X +2899(set)X +3038(of)X +3154(options,)X +3458(obtained)X +3783(by)X +3912(de\256ning)X +2418 4985(``CHAINED'',)N +2943(use)X +3086(linked)X +3321(lists)X +3484(to)X +3581(resolve)X +3848(collisions.)X +2418 5073(Either)N +2647(of)X +2747(the)X +2878(primary)X +3164(hash)X +3343(function)X +3642(described)X +3982(above)X +2418 5161(may)N +2584(be)X +2688(used,)X +2882(but)X +3011(all)X +3118(collisions)X +3451(are)X +3577(resolved)X +3876(by)X +3983(build-)X +2418 5249(ing)N +2554(a)X +2623(linked)X +2856(list)X +2986(of)X +3086(entries)X +3333(from)X +3522(the)X +3653(primary)X +3940(bucket.)X +2418 5337(By)N +2542(default,)X +2816(new)X +2981(entries)X +3226(will)X +3381(be)X +3488(added)X +3711(to)X +3804(a)X +3871(bucket)X +4116(at)X +2418 5425(the)N +2541(beginning)X +2886(of)X +2978(the)X +3101(bucket)X +3339(chain.)X +3577(However,)X +3916(compile)X +2418 5513(options)N +2706(``SORTUP'')X +3173(or)X +3293(``SORTDOWN'')X +3908(may)X +4098(be)X +2418 5601(speci\256ed)N +2723(to)X +2805(order)X +2995(the)X +3113(hash)X +3280(chains)X +3505(within)X +3729(each)X +3897(bucket.)X +3 f +432 5960(4)N +2970(USENIX)X +9 f +3292(-)X +3 f +3356(Winter)X +3621('91)X +9 f +3748(-)X +3 f +3812(Dallas,)X +4065(TX)X + +5 p +%%Page: 5 5 +0(Courier)xf 0 f +10 s 10 xH 0 xS 0 f +3 f +720 258(Seltzer)N +977(&)X +1064(Yigit)X +3278(A)X +3356(New)X +3528(Hashing)X +3831(Package)X +4136(for)X +4259(UNIX)X +2 f +1444 538(dynahash)N +1 f +892 670(The)N +2 f +1054(dynahash)X +1 f +1398(library,)X +1669(written)X +1932(by)X +2048(Esmond)X +2346(Pitt,)X +720 758(implements)N +1183(Larson's)X +1554(linear)X +1827(hashing)X +2165(algorithm)X +720 846([LAR88])N +1097(with)X +1302(an)X +2 f +1440(hsearch)X +1 f +1756(compatible)X +2174(interface.)X +720 934(Intuitively,)N +1099(a)X +1161(hash)X +1334(table)X +1516(begins)X +1751(as)X +1844(a)X +1905(single)X +2121(bucket)X +2360(and)X +720 1022(grows)N +941(in)X +1028(generations,)X +1443(where)X +1665(a)X +1725(generation)X +2088(corresponds)X +720 1110(to)N +815(a)X +884(doubling)X +1201(in)X +1296(the)X +1427(size)X +1585(of)X +1685(the)X +1815(hash)X +1994(table.)X +2222(The)X +2379(0)X +2 f +7 s +1078(th)Y +10 s +1 f +720 1198(generation)N +1085(occurs)X +1321(as)X +1414(the)X +1538(table)X +1719(grows)X +1940(from)X +2121(one)X +2262(bucket)X +720 1286(to)N +814(two.)X +1006(In)X +1105(the)X +1235(next)X +1405(generation)X +1776(the)X +1906(table)X +2093(grows)X +2320(from)X +720 1374(two)N +862(to)X +946(four.)X +1122(During)X +1371(each)X +1541(generation,)X +1921(every)X +2121(bucket)X +2356(that)X +720 1462(existed)N +967(at)X +1045(the)X +1163(beginning)X +1503(of)X +1590(the)X +1708(generation)X +2067(is)X +2140(split.)X +892 1576(The)N +1041(table)X +1221(starts)X +1414(as)X +1505(a)X +1565(single)X +1780(bucket)X +2018(\(numbered)X +2389(0\),)X +720 1664(the)N +839(current)X +1088(split)X +1245(bucket)X +1479(is)X +1552(set)X +1661(to)X +1743(bucket)X +1977(0,)X +2057(and)X +2193(the)X +2311(max-)X +720 1752(imum)N +933(split)X +1097(point)X +1288(is)X +1368(set)X +1483(to)X +1571(twice)X +1771(the)X +1895(current)X +2149(split)X +2312(point)X +720 1840(\(0\).)N +863(When)X +1084(it)X +1157(is)X +1239(time)X +1410(for)X +1532(a)X +1596(bucket)X +1838(to)X +1928(split,)X +2113(the)X +2239(keys)X +2414(in)X +720 1928(the)N +872(current)X +1154(split)X +1345(bucket)X +1612(are)X +1764(divided)X +2057(between)X +2378(the)X +720 2016(current)N +981(split)X +1151(bucket)X +1397(and)X +1545(a)X +1613(new)X +1779(bucket)X +2025(whose)X +2262(bucket)X +720 2104(number)N +1000(is)X +1088(equal)X +1297(to)X +1394(1)X +1469(+)X +1549(current)X +1812(split)X +1984(bucket)X +2232(+)X +2311(max-)X +720 2192(imum)N +927(split)X +1085(point.)X +1310(We)X +1442(can)X +1574(determine)X +1915(which)X +2131(keys)X +2298(move)X +720 2280(to)N +807(the)X +929(new)X +1087(bucket)X +1325(by)X +1429(examining)X +1791(the)X +2 f +1913(n)X +7 s +1962 2248(th)N +10 s +1 f +2043 2280(bit)N +2151(of)X +2242(a)X +2302(key's)X +720 2368(hash)N +899(value)X +1105(where)X +1334(n)X +1406(is)X +1491(the)X +1620(generation)X +1990(number.)X +2306(After)X +720 2456(the)N +846(bucket)X +1088(at)X +1174(the)X +1300(maximum)X +1651(split)X +1815(point)X +2006(has)X +2140(been)X +2319(split,)X +720 2544(the)N +839(generation)X +1198(number)X +1463(is)X +1536(incremented,)X +1973(the)X +2091(current)X +2339(split)X +720 2632(point)N +908(is)X +985(set)X +1098(back)X +1274(to)X +1360(zero,)X +1543(and)X +1683(the)X +1805(maximum)X +2152(split)X +2312(point)X +720 2720(is)N +815(set)X +946(to)X +1050(the)X +1190(number)X +1477(of)X +1586(the)X +1725(last)X +1877(bucket)X +2132(in)X +2235(the)X +2374(\256le)X +720 2808(\(which)N +971(is)X +1052(equal)X +1253(to)X +1342(twice)X +1543(the)X +1668(old)X +1797(maximum)X +2148(split)X +2312(point)X +720 2896(plus)N +873(1\).)X +892 3010(To)N +1031(facilitate)X +1361(locating)X +1668(keys,)X +1884(we)X +2027(maintain)X +2356(two)X +720 3098(masks.)N +989(The)X +1143(low)X +1291(mask)X +1488(is)X +1569(equal)X +1771(to)X +1861(the)X +1987(maximum)X +2339(split)X +720 3186(bucket)N +967(and)X +1116(the)X +1247(high)X +1422(mask)X +1624(is)X +1710(equal)X +1917(to)X +2011(the)X +2141(next)X +2311(max-)X +720 3274(imum)N +931(split)X +1093(bucket.)X +1372(To)X +1486(locate)X +1703(a)X +1764(speci\256c)X +2033(key,)X +2193(we)X +2311(com-)X +720 3362(pute)N +881(a)X +940(32-bit)X +1154(hash)X +1324(value)X +1520(using)X +1715(a)X +1773(bit-randomizing)X +2311(algo-)X +720 3450(rithm)N +932(such)X +1118(as)X +1224(the)X +1361(one)X +1516(described)X +1862(in)X +1962([LAR88].)X +2334(This)X +720 3538(hash)N +893(value)X +1093(is)X +1172(then)X +1336(masked)X +1607(with)X +1775(the)X +1898(high)X +2065(mask.)X +2299(If)X +2378(the)X +720 3626(resulting)N +1026(number)X +1297(is)X +1376(greater)X +1626(than)X +1790(the)X +1913(maximum)X +2262(bucket)X +720 3714(in)N +823(the)X +962(table)X +1159(\(current)X +1455(split)X +1633(bucket)X +1888(+)X +1974(maximum)X +2339(split)X +720 3802(point\),)N +962(the)X +1091(hash)X +1269(value)X +1474(is)X +1558(masked)X +1834(with)X +2007(the)X +2136(low)X +2287(mask.)X +720 3890(In)N +825(either)X +1046(case,)X +1242(the)X +1377(result)X +1592(of)X +1696(the)X +1831(mask)X +2037(is)X +2127(the)X +2262(bucket)X +720 3978(number)N +989(for)X +1107(the)X +1229(given)X +1431(key.)X +1611(The)X +1759(algorithm)X +2093(below)X +2312(illus-)X +720 4066(trates)N +914(this)X +1049(process.)X +0 f +8 s +720 4365(h)N +796(=)X +872 -0.4038(calchash\(key\);)AX +720 4453(bucket)N +986(=)X +1062(h)X +1138(&)X +1214 -0.4167(high_mask;)AX +720 4541(if)N +834(\()X +910(bucket)X +1176(>)X +1252 -0.4167(max_bucket)AX +1670(\))X +1008 4629(bucket)N +1274(=)X +1350(h)X +1426(&)X +1502 -0.4219(low_mask;)AX +720 4717 -0.4018(return\(bucket\);)AN +1 f +10 s +892 5042(In)N +1013(order)X +1237(to)X +1353(decide)X +1617(when)X +1845(to)X +1961(split)X +2152(a)X +2242(bucket,)X +2 f +720 5130(dynahash)N +1 f +1050(uses)X +2 f +1210(controlled)X +1561(splitting)X +1 f +1822(.)X +1884(A)X +1964(hash)X +2133(table)X +2311(has)X +2440(a)X +720 5218(\256ll)N +837(factor)X +1054(which)X +1279(is)X +1361(expressed)X +1707(in)X +1798(terms)X +2004(of)X +2099(the)X +2225(average)X +720 5306(number)N +990(of)X +1082(keys)X +1253(in)X +1339(each)X +1511(bucket.)X +1789(Each)X +1974(time)X +2140(the)X +2262(table's)X +720 5394(total)N +885(number)X +1153(of)X +1243(keys)X +1413(divided)X +1676(by)X +1778(its)X +1875(number)X +2142(of)X +2231(buckets)X +720 5482(exceeds)N +995(this)X +1130(\256ll)X +1238(factor,)X +1466(a)X +1522(bucket)X +1756(is)X +1829(split.)X +2878 538(Since)N +3079(the)X +2 f +3200(hsearch)X +1 f +3477(create)X +3693(interface)X +3998(\()X +2 f +4025(hcreate)X +1 f +4266(\))X +4315(calls)X +2706 626(for)N +2842(an)X +2960(estimate)X +3269(of)X +3378(the)X +3518(\256nal)X +3702(size)X +3869(of)X +3978(the)X +4118(hash)X +4306(table)X +2706 714(\()N +2 f +2733(nelem)X +1 f +2925(\),)X +2 f +3007(dynahash)X +1 f +3349(uses)X +3522(this)X +3672(information)X +4085(to)X +4182(initialize)X +2706 802(the)N +2848(table.)X +3088(The)X +3257(initial)X +3486(number)X +3774(of)X +3884(buckets)X +4172(is)X +4268(set)X +4400(to)X +2 f +2706 890(nelem)N +1 f +2926(rounded)X +3217(to)X +3306(the)X +3431(next)X +3596(higher)X +3828(power)X +4056(of)X +4150(two.)X +4337(The)X +2706 978(current)N +2958(split)X +3118(point)X +3305(is)X +3381(set)X +3493(to)X +3578(0)X +3641(and)X +3780(the)X +3901(maximum)X +4248(bucket)X +2706 1066(and)N +2842(maximum)X +3186(split)X +3343(point)X +3527(are)X +3646(set)X +3755(to)X +3837(this)X +3972(rounded)X +4255(value.)X +3 f +3148 1220(The)N +3301(New)X +3473(Implementation)X +1 f +2878 1352(Our)N +3042(implementation)X +3583(is)X +3675(also)X +3842(based)X +4063(on)X +4181(Larson's)X +2706 1440(linear)N +2939(hashing)X +3238([LAR88])X +3582(algorithm)X +3943(as)X +4060(well)X +4248(as)X +4364(the)X +2 f +2706 1528(dynahash)N +1 f +3047(implementation.)X +3623(The)X +2 f +3782(dbm)X +1 f +3954(family)X +4197(of)X +4297(algo-)X +2706 1616(rithms)N +2942(decide)X +3184(dynamically)X +3612(which)X +3840(bucket)X +4085(to)X +4178(split)X +4346(and)X +2706 1704(when)N +2914(to)X +3010(split)X +3180(it)X +3257(\(when)X +3491(it)X +3568(over\257ows\))X +3944(while)X +2 f +4155(dynahash)X +1 f +2706 1792(splits)N +2933(in)X +3054(a)X +3149(prede\256ned)X +3547(order)X +3776(\(linearly\))X +4134(and)X +4309(at)X +4426(a)X +2706 1880(prede\256ned)N +3116(time)X +3328(\(when)X +3599(the)X +3767(table)X +3993(\256ll)X +4151(factor)X +4409(is)X +2706 1968(exceeded\).)N +3121(We)X +3280(use)X +3434(a)X +3517(hybrid)X +3773(of)X +3887(these)X +4099(techniques.)X +2706 2056(Splits)N +2913(occur)X +3118(in)X +3206(the)X +3330(prede\256ned)X +3695(order)X +3891(of)X +3984(linear)X +4193(hashing,)X +2706 2144(but)N +2845(the)X +2980(time)X +3159(at)X +3253(which)X +3485(pages)X +3704(are)X +3839(split)X +4012(is)X +4101(determined)X +2706 2232(both)N +2869(by)X +2970(page)X +3143(over\257ows)X +3480(\()X +2 f +3507(uncontrolled)X +3937(splitting)X +1 f +4198(\))X +4246(and)X +4382(by)X +2706 2320(exceeding)N +3052(the)X +3170(\256ll)X +3278(factor)X +3486(\()X +2 f +3513(controlled)X +3862(splitting)X +1 f +4123(\))X +2878 2434(A)N +2962(hash)X +3135(table)X +3317(is)X +3395(parameterized)X +3876(by)X +3981(both)X +4148(its)X +4248(bucket)X +2706 2522(size)N +2904(\()X +2 f +2931(bsize)X +1 f +(\))S +3191(and)X +3380(\256ll)X +3541(factor)X +3801(\()X +2 f +3828(ffactor)X +1 f +4041(\).)X +4180(Whereas)X +2 f +2706 2610(dynahash's)N +1 f +3095(buckets)X +3364(can)X +3500(be)X +3599(represented)X +3993(as)X +4083(a)X +4142(linked)X +4365(list)X +2706 2698(of)N +2798(elements)X +3108(in)X +3195(memory,)X +3507(our)X +3639(package)X +3928(needs)X +4136(to)X +4222(support)X +2706 2786(disk)N +2874(access,)X +3135(and)X +3286(must)X +3476(represent)X +3806(buckets)X +4086(in)X +4183(terms)X +4395(of)X +2706 2874(pages.)N +2955(The)X +2 f +3106(bsize)X +1 f +3291(is)X +3369(the)X +3492(size)X +3642(\(in)X +3756(bytes\))X +3977(of)X +4069(these)X +4259(pages.)X +2706 2962(As)N +2833(in)X +2933(linear)X +3154(hashing,)X +3461(the)X +3597(number)X +3879(of)X +3983(buckets)X +4265(in)X +4364(the)X +2706 3050(table)N +2906(is)X +3003(equal)X +3221(to)X +3327(the)X +3469(number)X +3758(of)X +3869(keys)X +4060(in)X +4165(the)X +4306(table)X +2706 3138(divided)N +2988(by)X +2 f +3110(ffactor)X +1 f +3323(.)X +2 f +8 s +3113(6)Y +1 f +10 s +3417 3138(The)N +3584(controlled)X +3950(splitting)X +4252(occurs)X +2706 3226(each)N +2878(time)X +3044(the)X +3166(number)X +3435(of)X +3526(keys)X +3697(in)X +3783(the)X +3905(table)X +4085(exceeds)X +4364(the)X +2706 3314(\256ll)N +2814(factor)X +3022(multiplied)X +3370(by)X +3470(the)X +3588(number)X +3853(of)X +3940(buckets.)X +2878 3428(Inserting)N +3187(keys)X +3358(and)X +3498(splitting)X +3783(buckets)X +4051(is)X +4127(performed)X +2706 3516(precisely)N +3018(as)X +3107(described)X +3437(previously)X +3796(for)X +2 f +3911(dynahash)X +1 f +4218(.)X +4279(How-)X +2706 3604(ever,)N +2897(since)X +3094(buckets)X +3371(are)X +3502(now)X +3671(comprised)X +4036(of)X +4134(pages,)X +4368(we)X +2706 3692(must)N +2883(be)X +2981(prepared)X +3284(to)X +3367(handle)X +3602(cases)X +3793(where)X +4011(the)X +4130(size)X +4276(of)X +4364(the)X +2706 3780(keys)N +2873(and)X +3009(data)X +3163(in)X +3245(a)X +3301(bucket)X +3535(exceed)X +3779(the)X +3897(bucket)X +4131(size.)X +3 f +3318 3934(Over\257ow)N +3654(Pages)X +1 f +2878 4066(There)N +3095(are)X +3223(two)X +3372(cases)X +3571(where)X +3797(a)X +3862(key)X +4007(may)X +4174(not)X +4305(\256t)X +4400(in)X +2706 4154(its)N +2802(designated)X +3166(bucket.)X +3441(In)X +3529(the)X +3647(\256rst)X +3791(case,)X +3970(the)X +4088(total)X +4250(size)X +4395(of)X +2706 4242(the)N +2833(key)X +2978(and)X +3123(data)X +3286(may)X +3453(exceed)X +3706(the)X +3833(bucket)X +4076(size.)X +4269(In)X +4364(the)X +2706 4330(second,)N +3008(addition)X +3328(of)X +3453(a)X +3547(new)X +3739(key)X +3913(could)X +4149(cause)X +4386(an)X +2706 4418(over\257ow,)N +3068(but)X +3227(the)X +3382(bucket)X +3652(in)X +3770(question)X +4097(is)X +4206(not)X +4364(yet)X +2706 4506(scheduled)N +3049(to)X +3133(be)X +3230(split.)X +3428(In)X +3516(existing)X +3790(implementations,)X +4364(the)X +2706 4594(second)N +2953(case)X +3115(never)X +3317(arises)X +3523(\(since)X +3738(buckets)X +4006(are)X +4128(split)X +4288(when)X +2706 4682(they)N +2871(over\257ow\))X +3210(and)X +3352(the)X +3476(\256rst)X +3626(case)X +3791(is)X +3870(not)X +3998(handled)X +4278(at)X +4362(all.)X +2706 4770(Although)N +3036(large)X +3225(key/data)X +3525(pair)X +3678(handling)X +3986(is)X +4066(dif\256cult)X +4346(and)X +2706 4858(expensive,)N +3083(it)X +3163(is)X +3252(essential.)X +3604(In)X +3706(a)X +3777(linear)X +3995(hashed)X +4253(imple-)X +2706 4946(mentation,)N +3087(over\257ow)X +3413(pages)X +3636(are)X +3775(required)X +4083(for)X +4217(buckets)X +2706 5034(which)N +2935(over\257ow)X +3253(before)X +3492(they)X +3662(are)X +3793(split,)X +3982(so)X +4085(we)X +4211(can)X +4355(use)X +2706 5122(the)N +2833(same)X +3027(mechanism)X +3421(for)X +3544(large)X +3734(key/data)X +4035(pairs)X +4220(that)X +4368(we)X +2706 5210(use)N +2837(for)X +2955(over\257ow)X +3264(pages.)X +3511(Logically,)X +3862(we)X +3980(chain)X +4177(over\257ow)X +16 s +2706 5353 MXY +864 0 Dl +2 f +8 s +2746 5408(6)N +1 f +9 s +2801 5433(This)N +2952(is)X +3023(not)X +3138(strictly)X +3361(true.)X +3532(The)X +3667(\256le)X +3782(does)X +3937(not)X +4052(contract)X +4306(when)X +2706 5513(keys)N +2861(are)X +2972(deleted,)X +3221(so)X +3308(the)X +3419(number)X +3662(of)X +3744(buckets)X +3986(is)X +4056(actually)X +4306(equal)X +2706 5593(to)N +2782(the)X +2890(maximum)X +3202(number)X +3441(of)X +3520(keys)X +3671(ever)X +3814(present)X +4041(in)X +4116(the)X +4223(table)X +4382(di-)X +2706 5673(vided)N +2884(by)X +2974(the)X +3080(\256ll)X +3178(factor.)X +3 f +10 s +720 5960(USENIX)N +9 f +1042(-)X +3 f +1106(Winter)X +1371('91)X +9 f +1498(-)X +3 f +1562(Dallas,)X +1815(TX)X +4424(5)X + +6 p +%%Page: 6 6 +0(Courier)xf 0 f +10 s 10 xH 0 xS 0 f +3 f +432 258(A)N +510(New)X +682(Hashing)X +985(Package)X +1290(for)X +1413(UNIX)X +3663(Seltzer)X +3920(&)X +4007(Yigit)X +1 f +432 538(pages)N +639(to)X +725(the)X +847(buckets)X +1116(\(also)X +1296(called)X +1512(primary)X +1789(pages\).)X +2062(In)X +2152(a)X +432 626(memory)N +730(based)X +943(representation,)X +1448(over\257ow)X +1763(pages)X +1976(do)X +2086(not)X +432 714(pose)N +628(any)X +792(special)X +1063(problems)X +1409(because)X +1712(we)X +1854(can)X +2014(chain)X +432 802(over\257ow)N +776(pages)X +1017(to)X +1137(primary)X +1449(pages)X +1690(using)X +1921(memory)X +432 890(pointers.)N +776(However,)X +1137(mapping)X +1463(these)X +1674(over\257ow)X +2005(pages)X +432 978(into)N +584(a)X +648(disk)X +809(\256le)X +939(is)X +1019(more)X +1211(of)X +1305(a)X +1368(challenge,)X +1723(since)X +1915(we)X +2036(need)X +432 1066(to)N +547(be)X +675(able)X +861(to)X +975(address)X +1268(both)X +1462(bucket)X +1728(pages,)X +1983(whose)X +432 1154(numbers)N +729(are)X +849(growing)X +1137(linearly,)X +1422(and)X +1558(some)X +1747(indeterminate)X +432 1242(number)N +715(of)X +820(over\257ow)X +1143(pages)X +1364(without)X +1646(reorganizing)X +2090(the)X +432 1330(\256le.)N +604 1444(One)N +789(simple)X +1053(solution)X +1361(would)X +1612(be)X +1739(to)X +1852(allocate)X +2152(a)X +432 1532(separate)N +737(\256le)X +880(for)X +1015(over\257ow)X +1341(pages.)X +1604(The)X +1769(disadvantage)X +432 1620(with)N +605(such)X +783(a)X +850(technique)X +1193(is)X +1276(that)X +1426(it)X +1500(requires)X +1789(an)X +1895(extra)X +2086(\256le)X +432 1708(descriptor,)N +794(an)X +891(extra)X +1073(system)X +1316(call)X +1453(on)X +1554(open)X +1731(and)X +1867(close,)X +2072(and)X +432 1796(logically)N +739(associating)X +1122(two)X +1269(independent)X +1687(\256les.)X +1886(For)X +2023(these)X +432 1884(reasons,)N +728(we)X +857(wanted)X +1123(to)X +1219(map)X +1391(both)X +1567(primary)X +1855(pages)X +2072(and)X +432 1972(over\257ow)N +737(pages)X +940(into)X +1084(the)X +1202(same)X +1387(\256le)X +1509(space.)X +604 2086(The)N +799(buddy-in-waiting)X +1425(algorithm)X +1806(provides)X +2152(a)X +432 2174(mechanism)N +851(to)X +966(support)X +1259(multiple)X +1578(pages)X +1814(per)X +1970(logical)X +432 2262(bucket)N +685(while)X +902(retaining)X +1226(the)X +1362(simple)X +1613(split)X +1788(sequence)X +2121(of)X +432 2350(linear)N +681(hashing.)X +1015(Over\257ow)X +1383(pages)X +1631(are)X +1795(preallocated)X +432 2438(between)N +781(generations)X +1232(of)X +1379(primary)X +1713(pages.)X +1996(These)X +432 2526(over\257ow)N +759(pages)X +984(are)X +1125(used)X +1314(by)X +1436(any)X +1594(bucket)X +1850(containing)X +432 2614(more)N +646(keys)X +842(than)X +1029(\256t)X +1144(on)X +1273(the)X +1420(primary)X +1723(page)X +1924(and)X +2089(are)X +432 2702(reclaimed,)N +808(if)X +896(possible,)X +1217(when)X +1430(the)X +1567(bucket)X +1819(later)X +2000(splits.)X +432 2790(Figure)N +687(3)X +773(depicts)X +1045(the)X +1188(layout)X +1433(of)X +1545(primary)X +1844(pages)X +2072(and)X +432 2878(over\257ow)N +752(pages)X +970(within)X +1209(the)X +1342(same)X +1542(\256le.)X +1699(Over\257ow)X +2036(page)X +432 2966(use)N +586(information)X +1011(is)X +1111(recorded)X +1440(in)X +1548(bitmaps)X +1847(which)X +2089(are)X +432 3054(themselves)N +819(stored)X +1046(on)X +1157(over\257ow)X +1472(pages.)X +1725(The)X +1880(addresses)X +432 3142(of)N +520(the)X +639(bitmap)X +882(pages)X +1086(and)X +1223(the)X +1342(number)X +1608(of)X +1695(pages)X +1898(allocated)X +432 3230(at)N +515(each)X +688(split)X +850(point)X +1039(are)X +1163(stored)X +1384(in)X +1470(the)X +1592(\256le)X +1718(header.)X +1997(Using)X +432 3318(this)N +577(information,)X +1005(both)X +1177(over\257ow)X +1492(addresses)X +1829(and)X +1974(bucket)X +432 3406(addresses)N +764(can)X +900(be)X +999(mapped)X +1276(to)X +1361(disk)X +1517(addresses)X +1848(by)X +1951(the)X +2072(fol-)X +432 3494(lowing)N +674(calculation:)X +0 f +8 s +432 3793(int)N +736(bucket;)X +1192(/*)X +1306(bucket)X +1572(address)X +1876(*/)X +432 3881(u_short)N +736(oaddr;)X +1192(/*)X +1306(OVERFLOW)X +1648(address)X +1952(*/)X +432 3969(int)N +736 -0.4125(nhdr_pages;)AX +1192(/*)X +1306(npages)X +1572(in)X +1686 -112.4062(\256le)AX +1838(header)X +2104(*/)X +432 4057(int)N +736 -0.4125(spares[32];)AX +1192(/*)X +1306(npages)X +1572(at)X +1686(each)X +1876(split)X +2104(*/)X +432 4145(int)N +736(log2\(\);)X +1198(/*)X +1312(ceil\(log)X +1654(base)X +1844(2\))X +1958(*/)X +432 4321(#DEFINE)N +736 -0.3929(BUCKET_TO_PAGE\(bucket\))AX +1610(\\)X +584 4409(bucket)N +850(+)X +926 -0.4167(nhdr_pages)AX +1344(+)X +1420(\\)X +584 4497 -0.3894(\(bucket?spares[logs2\(bucket)AN +1648(+)X +1724(1\)-1]:0\))X +432 4673(#DEFINE)N +736 -0.3947(OADDR_TO_PAGE\(oaddr\))AX +1534(\\)X +584 4761 -0.3984(BUCKET_TO_PAGE\(\(1)AN +1268(<<)X +1382 -0.4091(\(oaddr>>11\)\))AX +1876(-)X +1952(1\))X +2066(+)X +2142(\\)X +584 4849(oaddr)N +812(&)X +888(0x7ff;)X +1 f +10 s +604 5262(An)N +728(over\257ow)X +1039(page)X +1217(is)X +1295(addressed)X +1637(by)X +1742(its)X +1842(split)X +2004(point,)X +432 5350(identifying)N +858(the)X +1031(generations)X +1476(between)X +1819(which)X +2090(the)X +432 5438(over\257ow)N +740(page)X +915(is)X +991(allocated,)X +1324(and)X +1463(its)X +1561(page)X +1736(number,)X +2023(iden-)X +432 5526(tifying)N +665(the)X +783(particular)X +1111(page)X +1283(within)X +1507(the)X +1625(split)X +1782(point.)X +1986(In)X +2073(this)X +432 5614(implementation,)N +983(offsets)X +1225(within)X +1457(pages)X +1668(are)X +1795(16)X +1903(bits)X +2046(long)X +432 5702(\(limiting)N +732(the)X +851(maximum)X +1196(page)X +1368(size)X +1513(to)X +1595(32K\),)X +1800(so)X +1891(we)X +2005(select)X +2418 538(an)N +2535(over\257ow)X +2860(page)X +3052(addressing)X +3435(algorithm)X +3786(that)X +3946(can)X +4098(be)X +2418 626(expressed)N +2760(in)X +2847(16)X +2952(bits)X +3091(and)X +3231(which)X +3451(allows)X +3684(quick)X +3886(retrieval.)X +2418 714(The)N +2568(top)X +2695(\256ve)X +2840(bits)X +2980(indicate)X +3258(the)X +3380(split)X +3541(point)X +3729(and)X +3869(the)X +3991(lower)X +2418 802(eleven)N +2650(indicate)X +2926(the)X +3046(page)X +3220(number)X +3487(within)X +3713(the)X +3832(split)X +3990(point.)X +2418 890(Since)N +2633(\256ve)X +2789(bits)X +2940(are)X +3075(reserved)X +3384(for)X +3514(the)X +3648(split)X +3821(point,)X +4041(\256les)X +2418 978(may)N +2578(split)X +2737(32)X +2839(times)X +3034(yielding)X +3318(a)X +3376(maximum)X +3721(\256le)X +3844(size)X +3990(of)X +4078(2)X +7 s +946(32)Y +10 s +2418 1066(buckets)N +2698(and)X +2849(32)X +2 f +(*)S +1 f +2982(2)X +7 s +1034(11)Y +10 s +3113 1066(over\257ow)N +3433(pages.)X +3691(The)X +3850(maximum)X +2418 1154(page)N +2597(size)X +2749(is)X +2829(2)X +7 s +1122(15)Y +10 s +1154(,)Y +2971(yielding)X +3259(a)X +3321(maximum)X +3671(\256le)X +3799(size)X +3950(greater)X +2418 1242(than)N +2601(131,000)X +2906(GB)X +3061(\(on)X +3212(\256le)X +3358(systems)X +3655(supporting)X +4041(\256les)X +2418 1330(larger)N +2626(than)X +2784(4GB\).)X +10 f +2418 1418 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN +1 Dt +4014 2275 MXY +0 133 Dl +3881 2275 MXY +0 133 Dl +3748 2275 MXY +0 133 Dl +3083 2275 MXY +0 133 Dl +5 s +1 f +3523 2475(2/3)N +3390(2/2)X +3257(2/1)X +2859(1/2)X +2726(1/1)X +5 Dt +3814 1743 MXY +0 133 Dl +3282 1743 MXY +0 133 Dl +3017 1743 MXY +0 133 Dl +2884 1743 MXY +0 133 Dl +1 Dt +3681 1743 MXY +0 133 Dl +133 0 Dl +0 -133 Dl +-133 0 Dl +3548 MX +0 133 Dl +133 0 Dl +0 -133 Dl +-133 0 Dl +3415 MX +0 133 Dl +133 0 Dl +0 -133 Dl +-133 0 Dl +3282 MX +0 133 Dl +133 0 Dl +0 -133 Dl +-133 0 Dl +3150 MX +0 133 Dl +132 0 Dl +0 -133 Dl +-132 0 Dl +3017 MX +0 133 Dl +133 0 Dl +0 -133 Dl +-133 0 Dl +2884 MX +0 133 Dl +133 0 Dl +0 -133 Dl +-133 0 Dl +3 f +8 s +3017 2601(Over\257ow)N +3285(Addresses)X +3515 2833(Over\257ow)N +3783(Pages)X +2850(Buckets)X +1 Di +3349 2740 MXY + 3349 2740 lineto + 3482 2740 lineto + 3482 2873 lineto + 3349 2873 lineto + 3349 2740 lineto +closepath 3 3349 2740 3482 2873 Dp +2684 MX +0 133 Dl +133 0 Dl +0 -133 Dl +-133 0 Dl +5 Dt +4146 2275 MXY +0 133 Dl +3216 2275 MXY +0 133 Dl +2684 2275 MXY +0 133 Dl +2551 2275 MXY +0 133 Dl +1 f +3798 1963(3)N +3266 1980(2)N +3001(1)X +2868(0)X +1 Dt +2751 1743 MXY +0 133 Dl +133 0 Dl +0 -133 Dl +-133 0 Dl +3548 2275 MXY +-15 -22 Dl +2 16 Dl +-13 11 Dl +26 -5 Dl +-282 -117 Dl +3432 2275 MXY +-10 -25 Dl +-2 16 Dl +-15 8 Dl +27 1 Dl +-166 -117 Dl +3282 2275 MXY +12 -25 Dl +-14 10 Dl +-15 -6 Dl +17 21 Dl +-16 -117 Dl +2884 2275 MXY +26 7 Dl +-12 -12 Dl +3 -16 Dl +-17 21 Dl +382 -117 Dl +2751 2275 MXY +25 9 Dl +-11 -12 Dl +5 -17 Dl +-19 20 Dl +515 -117 Dl +3 f +3070 2152(Over\257ow)N +3338(Pages)X +3482 2275 MXY + 3482 2275 lineto + 3615 2275 lineto + 3615 2408 lineto + 3482 2408 lineto + 3482 2275 lineto +closepath 3 3482 2275 3615 2408 Dp +3349 MX + 3349 2275 lineto + 3482 2275 lineto + 3482 2408 lineto + 3349 2408 lineto + 3349 2275 lineto +closepath 3 3349 2275 3482 2408 Dp +3216 MX + 3216 2275 lineto + 3349 2275 lineto + 3349 2408 lineto + 3216 2408 lineto + 3216 2275 lineto +closepath 3 3216 2275 3349 2408 Dp +2817 MX + 2817 2275 lineto + 2950 2275 lineto + 2950 2408 lineto + 2817 2408 lineto + 2817 2275 lineto +closepath 3 2817 2275 2950 2408 Dp +2684 MX + 2684 2275 lineto + 2817 2275 lineto + 2817 2408 lineto + 2684 2408 lineto + 2684 2275 lineto +closepath 3 2684 2275 2817 2408 Dp +3615 MX +0 133 Dl +531 0 Dl +0 -133 Dl +-531 0 Dl +2950 MX +0 133 Dl +266 0 Dl +0 -133 Dl +-266 0 Dl +2551 MX +0 133 Dl +133 0 Dl +0 -133 Dl +-133 0 Dl +3798 1726 MXY +-21 -18 Dl +6 16 Dl +-10 13 Dl +25 -11 Dl +-599 -99 Dl +3266 1726 MXY +-1 -27 Dl +-7 15 Dl +-17 1 Dl +25 11 Dl +-67 -99 Dl +3033 1726 MXY +27 1 Dl +-14 -8 Dl +-1 -17 Dl +-12 24 Dl +166 -99 Dl +2900 1726 MXY +27 7 Dl +-13 -11 Dl +3 -17 Dl +-17 21 Dl +299 -99 Dl +3058 1621(Split)N +3203(Points)X +2418 2275 MXY +0 133 Dl +133 0 Dl +0 -133 Dl +-133 0 Dl +3 Dt +-1 Ds +3137(Figure)Y +2619(3:)X +1 f +2691(Split)X +2832(points)X +3008(occur)X +3168(between)X +3399(generations)X +3712(and)X +3823(are)X +3919(numbered)X +2418 3225(from)N +2560(0.)X +2642(In)X +2713(this)X +2824(\256gure)X +2991(there)X +3136(are)X +3231(two)X +3345(over\257ow)X +3590(pages)X +3753(allocated)X +4000(at)X +4063(split)X +2418 3313(point)N +2566(1)X +2614(and)X +2722(three)X +2865(allocated)X +3111(at)X +3173(split)X +3300(point)X +3448(2.)X +10 s +10 f +2418 3489 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN +3 f +2949 3731(Buffer)N +3192(Management)X +1 f +2590 3863(The)N +2744(hash)X +2920(table)X +3105(is)X +3187(stored)X +3412(in)X +3502(memory)X +3797(as)X +3892(a)X +3956(logical)X +2418 3951(array)N +2633(of)X +2749(bucket)X +3012(pointers.)X +3359(Physically,)X +3761(the)X +3907(array)X +4121(is)X +2418 4039(arranged)N +2728(in)X +2818(segments)X +3144(of)X +3239(256)X +3387(pointers.)X +3713(Initially,)X +4013(there)X +2418 4127(is)N +2530(space)X +2767(to)X +2887(allocate)X +3195(256)X +3373(segments.)X +3769(Reallocation)X +2418 4215(occurs)N +2651(when)X +2847(the)X +2967(number)X +3234(of)X +3323(buckets)X +3590(exceeds)X +3867(32K)X +4027(\(256)X +2418 4303(*)N +2508(256\).)X +2745(Primary)X +3053(pages)X +3286(may)X +3473(be)X +3598(accessed)X +3929(directly)X +2418 4391(through)N +2711(the)X +2853(array)X +3062(by)X +3185(bucket)X +3442(number)X +3730(and)X +3889(over\257ow)X +2418 4479(pages)N +2628(are)X +2754 0.4028(referenced)AX +3122(logically)X +3429(by)X +3536(their)X +3710(over\257ow)X +4022(page)X +2418 4567(address.)N +2726(For)X +2864(small)X +3063(hash)X +3236(tables,)X +3469(it)X +3539(is)X +3618(desirable)X +3934(to)X +4022(keep)X +2418 4655(all)N +2525(pages)X +2735(in)X +2823(main)X +3009(memory)X +3302(while)X +3506(on)X +3612(larger)X +3826(tables,)X +4059(this)X +2418 4743(is)N +2523(probably)X +2860(impossible.)X +3298(To)X +3438(satisfy)X +3698(both)X +3891(of)X +4009(these)X +2418 4831(requirements,)N +2900(the)X +3041(package)X +3348(includes)X +3658(buffer)X +3897(manage-)X +2418 4919(ment)N +2598(with)X +2760(LRU)X +2940(\(least)X +3134(recently)X +3413(used\))X +3607(replacement.)X +2590 5033(By)N +2730(default,)X +3020(the)X +3165(package)X +3475(allocates)X +3802(up)X +3928(to)X +4036(64K)X +2418 5121(bytes)N +2616(of)X +2712(buffered)X +3014(pages.)X +3246(All)X +3377(pages)X +3589(in)X +3680(the)X +3807(buffer)X +4032(pool)X +2418 5209(are)N +2542(linked)X +2766(in)X +2852(LRU)X +3036(order)X +3230(to)X +3316(facilitate)X +3621(fast)X +3761(replacement.)X +2418 5297(Whereas)N +2724(ef\256cient)X +3011(access)X +3241(to)X +3327(primary)X +3605(pages)X +3812(is)X +3889(provided)X +2418 5385(by)N +2521(the)X +2642(bucket)X +2879(array,)X +3087(ef\256cient)X +3372(access)X +3600(to)X +3684(over\257ow)X +3991(pages)X +2418 5473(is)N +2501(provided)X +2816(by)X +2926(linking)X +3182(over\257ow)X +3497(page)X +3679(buffers)X +3936(to)X +4027(their)X +2418 5561(predecessor)N +2827(page)X +3008(\(either)X +3247(the)X +3374(primary)X +3657(page)X +3838(or)X +3933(another)X +2418 5649(over\257ow)N +2742(page\).)X +3000(This)X +3181(means)X +3425(that)X +3584(an)X +3699(over\257ow)X +4022(page)X +3 f +432 5960(6)N +2970(USENIX)X +9 f +3292(-)X +3 f +3356(Winter)X +3621('91)X +9 f +3748(-)X +3 f +3812(Dallas,)X +4065(TX)X + +7 p +%%Page: 7 7 +0(Courier)xf 0 f +10 s 10 xH 0 xS 0 f +3 f +720 258(Seltzer)N +977(&)X +1064(Yigit)X +3278(A)X +3356(New)X +3528(Hashing)X +3831(Package)X +4136(for)X +4259(UNIX)X +1 f +720 538(cannot)N +955(be)X +1052(present)X +1305(in)X +1388(the)X +1507(buffer)X +1724(pool)X +1886(if)X +1955(its)X +2050(primary)X +2324(page)X +720 626(is)N +804(not)X +937(present.)X +1240(This)X +1413(does)X +1591(not)X +1724(impact)X +1972(performance)X +2409(or)X +720 714(functionality,)N +1209(because)X +1524(an)X +1660(over\257ow)X +2005(page)X +2217(will)X +2400(be)X +720 802(accessed)N +1048(only)X +1236(after)X +1430(its)X +1550(predecessor)X +1975(page)X +2172(has)X +2324(been)X +720 890(accessed.)N +1068(Figure)X +1303(4)X +1369(depicts)X +1622(the)X +1746(data)X +1905(structures)X +2242(used)X +2414(to)X +720 978(manage)N +990(the)X +1108(buffer)X +1325(pool.)X +892 1092(The)N +1040(in-memory)X +1419(bucket)X +1656(array)X +1845(contains)X +2134(pointers)X +2414(to)X +720 1180(buffer)N +975(header)X +1248(structures)X +1617(which)X +1870(represent)X +2222(primary)X +720 1268(pages.)N +968(Buffer)X +1203(headers)X +1474(contain)X +1735(modi\256ed)X +2043(bits,)X +2202(the)X +2324(page)X +720 1356(address)N +995(of)X +1096(the)X +1228(buffer,)X +1479(a)X +1548(pointer)X +1808(to)X +1903(the)X +2034(actual)X +2259(buffer,)X +720 1444(and)N +875(a)X +950(pointer)X +1216(to)X +1317(the)X +1454(buffer)X +1690(header)X +1944(for)X +2077(an)X +2191(over\257ow)X +720 1532(page)N +901(if)X +979(it)X +1052(exists,)X +1283(in)X +1374(addition)X +1665(to)X +1756(the)X +1883(LRU)X +2072(links.)X +2296(If)X +2378(the)X +720 1620(buffer)N +950(corresponding)X +1442(to)X +1537(a)X +1606(particular)X +1947(bucket)X +2194(is)X +2280(not)X +2414(in)X +720 1708(memory,)N +1048(its)X +1164(pointer)X +1432(is)X +1526(NULL.)X +1801(In)X +1909(effect,)X +2154(pages)X +2377(are)X +720 1796(linked)N +950(in)X +1042(three)X +1233(ways.)X +1468(Using)X +1689(the)X +1817(buffer)X +2043(headers,)X +2338(they)X +720 1884(are)N +851(linked)X +1083(physically)X +1444(through)X +1725(the)X +1854(LRU)X +2045(links)X +2231(and)X +2378(the)X +720 1972(over\257ow)N +1036(links.)X +1241(Using)X +1462(the)X +1590(pages)X +1803(themselves,)X +2209(they)X +2377(are)X +720 2060(linked)N +943(logically)X +1246(through)X +1518(the)X +1639(over\257ow)X +1946(addresses)X +2276(on)X +2378(the)X +720 2148(page.)N +948(Since)X +1162(over\257ow)X +1482(pages)X +1700(are)X +1834(accessed)X +2151(only)X +2328(after)X +720 2236(their)N +904(predecessor)X +1321(pages,)X +1560(they)X +1734(are)X +1869(removed)X +2186(from)X +2378(the)X +720 2324(buffer)N +937(pool)X +1099(when)X +1293(their)X +1460(primary)X +1734(is)X +1807(removed.)X +10 f +720 2412 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN +1 Dt +2309 3177 MXY +24 15 Dl +-8 -15 Dl +8 -15 Dl +-24 15 Dl +52 0 Dl +789 3160 MXY +-35 0 Dl +0 -156 Dl +1607 0 Dl +0 173 Dl +789 3091 MXY +-24 -15 Dl +9 15 Dl +-9 15 Dl +24 -15 Dl +-69 0 Dl +2309 3125 MXY +104 0 Dl +0 -155 Dl +-1693 0 Dl +0 121 Dl +927 3160 MXY +24 15 Dl +-9 -15 Dl +9 -15 Dl +-24 15 Dl +553 0 Dl +1618 3177 MXY +8 27 Dl +4 -17 Dl +16 -6 Dl +-28 -4 Dl +138 121 Dl +1895 3315 MXY +28 3 Dl +-15 -9 Dl +1 -18 Dl +-14 24 Dl +276 -138 Dl +3108 MY +-28 -3 Dl +15 10 Dl +-1 17 Dl +14 -24 Dl +-276 138 Dl +1756 3229 MXY +-8 -27 Dl +-3 17 Dl +-16 6 Dl +27 4 Dl +-138 -121 Dl +1480 MX +-24 -15 Dl +9 15 Dl +-9 15 Dl +24 -15 Dl +-553 0 Dl +3 f +5 s +1083 3073(LRU)N +1178(chain)X +4 Ds +1402 3851 MXY + 1402 3851 lineto + 1471 3851 lineto + 1471 3920 lineto + 1402 3920 lineto + 1402 3851 lineto +closepath 19 1402 3851 1471 3920 Dp +1445 3747(Over\257ow)N +1613(Address)X +1549 3609 MXY +0 69 Dl +1756 MX +-23 -15 Dl +8 15 Dl +-8 15 Dl +23 -15 Dl +-207 0 Dl +-1 Ds +3 Dt +1756 3419 MXY +-6 -28 Dl +-4 17 Dl +-17 5 Dl +27 6 Dl +-138 -138 Dl +2240 3471 MXY +15 -24 Dl +-15 9 Dl +-15 -9 Dl +15 24 Dl +0 -138 Dl +1826 3609 MXY +15 -24 Dl +-15 9 Dl +-16 -9 Dl +16 24 Dl +0 -138 Dl +1549 MX +15 -24 Dl +-15 9 Dl +-15 -9 Dl +15 24 Dl +0 -138 Dl +858 3471 MXY +15 -24 Dl +-15 9 Dl +-15 -9 Dl +15 24 Dl +0 -138 Dl +2240 3056 MXY +15 -24 Dl +-15 9 Dl +-15 -9 Dl +15 24 Dl +0 -138 Dl +1549 3056 MXY +15 -24 Dl +-15 9 Dl +-15 -9 Dl +15 24 Dl +0 -138 Dl +858 3056 MXY +15 -24 Dl +-15 9 Dl +-15 -9 Dl +15 24 Dl +0 -138 Dl +1 Dt +2171 3471 MXY + 2171 3471 lineto + 2448 3471 lineto + 2448 3609 lineto + 2171 3609 lineto + 2171 3471 lineto +closepath 19 2171 3471 2448 3609 Dp +1756 3609 MXY + 1756 3609 lineto + 2033 3609 lineto + 2033 3747 lineto + 1756 3747 lineto + 1756 3609 lineto +closepath 3 1756 3609 2033 3747 Dp +1480 3471 MXY + 1480 3471 lineto + 1756 3471 lineto + 1756 3609 lineto + 1480 3609 lineto + 1480 3471 lineto +closepath 19 1480 3471 1756 3609 Dp +789 MX + 789 3471 lineto + 1065 3471 lineto + 1065 3609 lineto + 789 3609 lineto + 789 3471 lineto +closepath 19 789 3471 1065 3609 Dp +962 3903(Buffer)N +1083(Header)X +849 3851 MXY + 849 3851 lineto + 918 3851 lineto + 918 3920 lineto + 849 3920 lineto + 849 3851 lineto +closepath 14 849 3851 918 3920 Dp +1756 3194 MXY + 1756 3194 lineto + 1895 3194 lineto + 1895 3471 lineto + 1756 3471 lineto + 1756 3194 lineto +closepath 14 1756 3194 1895 3471 Dp +2171 3056 MXY + 2171 3056 lineto + 2309 3056 lineto + 2309 3333 lineto + 2171 3333 lineto + 2171 3056 lineto +closepath 14 2171 3056 2309 3333 Dp +1480 MX + 1480 3056 lineto + 1618 3056 lineto + 1618 3333 lineto + 1480 3333 lineto + 1480 3056 lineto +closepath 14 1480 3056 1618 3333 Dp +789 MX + 789 3056 lineto + 927 3056 lineto + 927 3333 lineto + 789 3333 lineto + 789 3056 lineto +closepath 14 789 3056 927 3333 Dp +2780 MY +0 138 Dl +138 0 Dl +0 -138 Dl +-138 0 Dl +927 MX +0 138 Dl +138 0 Dl +0 -138 Dl +-138 0 Dl +1065 MX +0 138 Dl +138 0 Dl +0 -138 Dl +-138 0 Dl +1203 MX +0 138 Dl +139 0 Dl +0 -138 Dl +-139 0 Dl +1342 MX +0 138 Dl +138 0 Dl +0 -138 Dl +-138 0 Dl +1480 MX +0 138 Dl +138 0 Dl +0 -138 Dl +-138 0 Dl +1618 MX +0 138 Dl +138 0 Dl +0 -138 Dl +-138 0 Dl +1756 MX +0 138 Dl +139 0 Dl +0 -138 Dl +-139 0 Dl +1895 MX +0 138 Dl +138 0 Dl +0 -138 Dl +-138 0 Dl +2033 MX +0 138 Dl +138 0 Dl +0 -138 Dl +-138 0 Dl +2171 MX +0 138 Dl +138 0 Dl +0 -138 Dl +-138 0 Dl +2309 MX +0 138 Dl +139 0 Dl +0 -138 Dl +-139 0 Dl +13 s +1048 2720(In)N +1173(Memory)X +1580(Bucket)X +1918(Array)X +867 3584(B0)N +1558(B5)X +2223(B10)X +1788 3722(O1/1)N +5 s +1515 3903(Primay)N +1651(Buffer)X +4 Ds +1990 3851 MXY + 1990 3851 lineto + 2059 3851 lineto + 2059 3920 lineto + 1990 3920 lineto + 1990 3851 lineto +closepath 3 1990 3851 2059 3920 Dp +2102 3903(Over\257ow)N +2270(Buffer)X +3 Dt +-1 Ds +8 s +720 4184(Figure)N +922(4:)X +1 f +996(Three)X +1164(primary)X +1386(pages)X +1551(\(B0,)X +1683(B5,)X +1794(B10\))X +1942(are)X +2039(accessed)X +2281(directly)X +720 4272(from)N +862(the)X +958(bucket)X +1146(array.)X +1326(The)X +1443(one)X +1553(over\257ow)X +1798(page)X +1935(\(O1/1\))X +2122(is)X +2182(linked)X +2359(phy-)X +720 4360(sically)N +915(from)X +1067(its)X +1155(primary)X +1384(page's)X +1577(buffer)X +1759(header)X +1955(as)X +2035(well)X +2172(as)X +2252(logically)X +720 4448(from)N +860(its)X +937(predecessor)X +1253(page)X +1389(buffer)X +1560(\(B5\).)X +10 s +10 f +720 4624 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN +3 f +1191 4954(Table)N +1406(Parameterization)X +1 f +892 5086(When)N +1107(a)X +1166(hash)X +1336(table)X +1515(is)X +1590(created,)X +1865(the)X +1985(bucket)X +2221(size,)X +2388(\256ll)X +720 5174(factor,)N +953(initial)X +1164(number)X +1434(of)X +1526(elements,)X +1856(number)X +2125(of)X +2216(bytes)X +2409(of)X +720 5262(main)N +919(memory)X +1225(used)X +1411(for)X +1543(caching,)X +1851(and)X +2005(a)X +2079(user-de\256ned)X +720 5350(hash)N +892(function)X +1184(may)X +1347(be)X +1448(speci\256ed.)X +1797(The)X +1946(bucket)X +2184(size)X +2333(\(and)X +720 5438(page)N +906(size)X +1064(for)X +1191(over\257ow)X +1509(pages\))X +1752(defaults)X +2039(to)X +2134(256)X +2287(bytes.)X +720 5526(For)N +858(tables)X +1072(with)X +1241(large)X +1429(data)X +1590(items,)X +1810(it)X +1881(may)X +2046(be)X +2149(preferable)X +720 5614(to)N +803(increase)X +1088(the)X +1207(page)X +1380(size,)X +1545(and,)X +1701(conversely,)X +2089(applications)X +720 5702(storing)N +1002(small)X +1235(items)X +1467(exclusively)X +1891(in)X +2012(memory)X +2338(may)X +2706 538(bene\256t)N +2966(from)X +3164(a)X +3242(smaller)X +3520(bucket)X +3776(size.)X +3983(A)X +4082(bucket)X +4337(size)X +2706 626(smaller)N +2962(than)X +3120(64)X +3220(bytes)X +3409(is)X +3482(not)X +3604(recommended.)X +2878 740(The)N +3031(\256ll)X +3147(factor)X +3363(indicates)X +3676(a)X +3740(desired)X +4000(density)X +4258(within)X +2706 828(the)N +2833(hash)X +3009(table.)X +3234(It)X +3312(is)X +3394(an)X +3499(approximation)X +3995(of)X +4091(the)X +4217(number)X +2706 916(of)N +2815(keys)X +3004(allowed)X +3300(to)X +3404(accumulate)X +3811(in)X +3914(any)X +4071(one)X +4228(bucket,)X +2706 1004(determining)N +3119(when)X +3319(the)X +3442(hash)X +3614(table)X +3795(grows.)X +4056(Its)X +4161(default)X +4409(is)X +2706 1092(eight.)N +2953(If)X +3054(the)X +3199(user)X +3380(knows)X +3636(the)X +3781(average)X +4079(size)X +4251(of)X +4364(the)X +2706 1180(key/data)N +3008(pairs)X +3194(being)X +3402(stored)X +3627(in)X +3718(the)X +3845(table,)X +4050(near)X +4218(optimal)X +2706 1268(bucket)N +2943(sizes)X +3122(and)X +3261(\256ll)X +3372(factors)X +3614(may)X +3775(be)X +3874(selected)X +4155(by)X +4257(apply-)X +2706 1356(ing)N +2828(the)X +2946(equation:)X +0 f +8 s +2706 1655(\(1\))N +2994 -0.3938(\(\(average_pair_length)AX +3830(+)X +3906(4\))X +4020(*)X +3032 1743(ffactor\))N +3374(>=)X +3488(bsize)X +1 f +10 s +2706 2042(For)N +2859(highly)X +3104(time)X +3287(critical)X +3551(applications,)X +3999(experimenting)X +2706 2130(with)N +2919(different)X +3266(bucket)X +3550(sizes)X +3776(and)X +3962(\256ll)X +4120(factors)X +4409(is)X +2706 2218(encouraged.)N +2878 2332(Figures)N +3144(5a,b,)X +3326(and)X +3468(c)X +3530(illustrate)X +3836(the)X +3960(effects)X +4200(of)X +4292(vary-)X +2706 2420(ing)N +2841(page)X +3026(sizes)X +3215(and)X +3363(\256ll)X +3483(factors)X +3734(for)X +3860(the)X +3990(same)X +4187(data)X +4353(set.)X +2706 2508(The)N +2864(data)X +3031(set)X +3152(consisted)X +3482(of)X +3581(24474)X +3813(keys)X +3992(taken)X +4198(from)X +4386(an)X +2706 2596(online)N +2931(dictionary.)X +3301(The)X +3451(data)X +3609(value)X +3807(for)X +3925(each)X +4097(key)X +4237(was)X +4386(an)X +2706 2684(ASCII)N +2938(string)X +3143(for)X +3260(an)X +3359(integer)X +3605(from)X +3784(1)X +3847(to)X +3931(24474)X +4153(inclusive.)X +2706 2772(The)N +2867(test)X +3013(run)X +3155(consisted)X +3488(of)X +3590(creating)X +3884(a)X +3955(new)X +4124(hash)X +4306(table)X +2706 2860(\(where)N +2966(the)X +3100(ultimate)X +3398(size)X +3559(of)X +3662(the)X +3796(table)X +3987(was)X +4147(known)X +4400(in)X +2706 2948(advance\),)N +3054(entering)X +3354(each)X +3539(key/data)X +3848(pair)X +4010(into)X +4171(the)X +4306(table)X +2706 3036(and)N +2849(then)X +3014(retrieving)X +3353(each)X +3528(key/data)X +3827(pair)X +3979(from)X +4162(the)X +4286(table.)X +2706 3124(Each)N +2898(of)X +2996(the)X +3125(graphs)X +3369(shows)X +3599(the)X +3727(timings)X +3996(resulting)X +4306(from)X +2706 3212(varying)N +2973(the)X +3093(pagesize)X +3392(from)X +3570(128)X +3712(bytes)X +3903(to)X +3986(1M)X +4118(and)X +4255(the)X +4374(\256ll)X +2706 3300(factor)N +2929(from)X +3120(1)X +3195(to)X +3292(128.)X +3486(For)X +3631(each)X +3813(run,)X +3974(the)X +4106(buffer)X +4337(size)X +2706 3388(was)N +2874(set)X +3006(at)X +3106(1M.)X +3299(The)X +3466(tests)X +3650(were)X +3849(all)X +3971(run)X +4120(on)X +4242(an)X +4360(HP)X +2706 3476(9000/370)N +3077(\(33.3)X +3312(Mhz)X +3527(MC68030\),)X +3966(with)X +4176(16M)X +4395(of)X +2706 3564(memory,)N +3042(64K)X +3228(physically)X +3605(addressed)X +3970(cache,)X +4222(and)X +4386(an)X +2706 3652(HP7959S)N +3055(disk)X +3231(drive,)X +3459(running)X +3751(4.3BSD-Reno)X +4244(single-)X +2706 3740(user.)N +2878 3854(Both)N +3066(system)X +3321(time)X +3496(\(Figure)X +3764(5a\))X +3899(and)X +4047(elapsed)X +4320(time)X +2706 3942(\(Figure)N +2966(5b\))X +3097(show)X +3290(that)X +3434(for)X +3552(all)X +3655(bucket)X +3892(sizes,)X +4091(the)X +4212(greatest)X +2706 4030(performance)N +3137(gains)X +3329(are)X +3451(made)X +3648(by)X +3751(increasing)X +4104(the)X +4225(\256ll)X +4336(fac-)X +2706 4118(tor)N +2822(until)X +2995(equation)X +3298(1)X +3365(is)X +3445(satis\256ed.)X +3774(The)X +3925(user)X +4085(time)X +4253(shown)X +2706 4206(in)N +2791(Figure)X +3023(5c)X +3122(gives)X +3314(a)X +3373(more)X +3561(detailed)X +3838(picture)X +4083(of)X +4172(how)X +4332(per-)X +2706 4294(formance)N +3054(varies.)X +3330(The)X +3499(smaller)X +3778(bucket)X +4035(sizes)X +4234(require)X +2706 4382(fewer)N +2921(keys)X +3099(per)X +3233(page)X +3416(to)X +3509(satisfy)X +3749(equation)X +4056(1)X +4127(and)X +4274(there-)X +2706 4470(fore)N +2860(incur)X +3049(fewer)X +3257(collisions.)X +3607(However,)X +3946(when)X +4144(the)X +4265(buffer)X +2706 4558(pool)N +2884(size)X +3045(is)X +3134(\256xed,)X +3349(smaller)X +3620(pages)X +3838(imply)X +4059(more)X +4259(pages.)X +2706 4646(An)N +2830(increased)X +3160(number)X +3430(of)X +3522(pages)X +3730(means)X +3960(more)X +2 f +4150(malloc\(3\))X +1 f +2706 4734(calls)N +2879(and)X +3021(more)X +3212(overhead)X +3533(in)X +3621(the)X +3745(hash)X +3918(package's)X +4265(buffer)X +2706 4822(manager)N +3003(to)X +3085(manage)X +3355(the)X +3473(additional)X +3813(pages.)X +2878 4936(The)N +3028(tradeoff)X +3308(works)X +3529(out)X +3655(most)X +3834(favorably)X +4166(when)X +4364(the)X +2706 5024(page)N +2886(size)X +3039(is)X +3120(256)X +3268(and)X +3412(the)X +3538(\256ll)X +3654(factor)X +3870(is)X +3950(8.)X +4057(Similar)X +4319(con-)X +2706 5112(clusions)N +3009(were)X +3207(obtained)X +3524(if)X +3614(the)X +3753(test)X +3905(was)X +4071(run)X +4218(without)X +2706 5200(knowing)N +3007(the)X +3126(\256nal)X +3289(table)X +3466(size)X +3612(in)X +3695(advance.)X +4020(If)X +4095(the)X +4214(\256le)X +4337(was)X +2706 5288(closed)N +2942(and)X +3088(written)X +3345(to)X +3437(disk,)X +3620(the)X +3748(conclusions)X +4156(were)X +4343(still)X +2706 5376(the)N +2832(same.)X +3065(However,)X +3408(rereading)X +3740(the)X +3865(\256le)X +3994(from)X +4177(disk)X +4337(was)X +2706 5464(slightly)N +2983(faster)X +3199(if)X +3285(a)X +3358(larger)X +3583(bucket)X +3834(size)X +3996(and)X +4149(\256ll)X +4274(factor)X +2706 5552(were)N +2898(used)X +3079(\(1K)X +3238(bucket)X +3486(size)X +3645(and)X +3795(32)X +3909(\256ll)X +4031(factor\).)X +4320(This)X +2706 5640(follows)N +2987(intuitively)X +3356(from)X +3553(the)X +3691(improved)X +4038(ef\256ciency)X +4395(of)X +3 f +720 5960(USENIX)N +9 f +1042(-)X +3 f +1106(Winter)X +1371('91)X +9 f +1498(-)X +3 f +1562(Dallas,)X +1815(TX)X +4424(7)X + +8 p +%%Page: 8 8 +0(Courier)xf 0 f +10 s 10 xH 0 xS 0 f +3 f +432 258(A)N +510(New)X +682(Hashing)X +985(Package)X +1290(for)X +1413(UNIX)X +3663(Seltzer)X +3920(&)X +4007(Yigit)X +1 f +432 538(performing)N +830(1K)X +965(reads)X +1172(from)X +1365(the)X +1500(disk)X +1670(rather)X +1894(than)X +2068(256)X +432 626(byte)N +609(reads.)X +857(In)X +962(general,)X +1257(performance)X +1702(for)X +1834(disk)X +2005(based)X +432 714(tables)N +639(is)X +712(best)X +861(when)X +1055(the)X +1173(page)X +1345(size)X +1490(is)X +1563(approximately)X +2046(1K.)X +10 f +432 802 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN +619 2380 MXY +-12 24 Dl +24 0 Dl +-12 -24 Dl +629 2437 MXY +-12 24 Dl +24 0 Dl +-12 -24 Dl +648 2504 MXY +-12 25 Dl +24 0 Dl +-12 -25 Dl +686 2515 MXY +-12 24 Dl +24 0 Dl +-12 -24 Dl +762 2516 MXY +-12 24 Dl +25 0 Dl +-13 -24 Dl +916 2515 MXY +-13 24 Dl +25 0 Dl +-12 -24 Dl +1222 2516 MXY +-12 24 Dl +24 0 Dl +-12 -24 Dl +1834 2515 MXY +-12 24 Dl +24 0 Dl +-12 -24 Dl +1 Dt +619 2392 MXY +10 57 Dl +19 67 Dl +38 11 Dl +76 1 Dl +154 -1 Dl +306 1 Dl +612 -1 Dl +8 s +1 f +1628 2522(128)N +3 Dt +607 2245 MXY +24 Dc +617 2375 MXY +23 Dc +635 2442 MXY +24 Dc +674 2525 MXY +23 Dc +750 2529 MXY +24 Dc +904 2527 MXY +23 Dc +1210 MX +23 Dc +1822 2528 MXY +23 Dc +20 Ds +1 Dt +619 2245 MXY +10 130 Dl +19 67 Dl +38 83 Dl +76 4 Dl +154 -2 Dl +306 0 Dl +612 1 Dl +678 2482(256)N +-1 Ds +3 Dt +619 2127 MXY +0 24 Dl +0 -12 Dl +12 0 Dl +-24 0 Dl +629 2191 MXY +0 25 Dl +0 -12 Dl +12 0 Dl +-24 0 Dl +648 2334 MXY +0 24 Dl +0 -12 Dl +12 0 Dl +-24 0 Dl +686 2409 MXY +0 25 Dl +0 -13 Dl +12 0 Dl +-24 0 Dl +762 2516 MXY +0 25 Dl +0 -12 Dl +13 0 Dl +-25 0 Dl +916 2516 MXY +0 24 Dl +0 -12 Dl +12 0 Dl +-25 0 Dl +1222 2515 MXY +0 24 Dl +0 -12 Dl +12 0 Dl +-24 0 Dl +1834 2515 MXY +0 24 Dl +0 -12 Dl +12 0 Dl +-24 0 Dl +5 Dt +619 2139 MXY +10 65 Dl +19 142 Dl +38 75 Dl +76 108 Dl +154 -1 Dl +306 -1 Dl +612 0 Dl +694 2401(512)N +3 Dt +631 2064 MXY +-24 24 Dl +12 -12 Dl +-12 -12 Dl +24 24 Dl +641 2077 MXY +-24 25 Dl +12 -12 Dl +-12 -13 Dl +24 25 Dl +660 2132 MXY +-24 24 Dl +12 -12 Dl +-12 -12 Dl +24 24 Dl +698 2292 MXY +-24 24 Dl +12 -12 Dl +-12 -12 Dl +24 24 Dl +775 2382 MXY +-25 24 Dl +12 -12 Dl +-12 -12 Dl +25 24 Dl +928 2516 MXY +-25 24 Dl +13 -12 Dl +-13 -12 Dl +25 24 Dl +1234 2516 MXY +-24 25 Dl +12 -12 Dl +-12 -13 Dl +24 25 Dl +1846 2516 MXY +-24 24 Dl +12 -12 Dl +-12 -12 Dl +24 24 Dl +16 Ds +1 Dt +619 2076 MXY +10 14 Dl +19 54 Dl +38 160 Dl +76 90 Dl +154 134 Dl +306 1 Dl +612 -1 Dl +694 2257(1024)N +-1 Ds +3 Dt +619 1877 MXY +12 -24 Dl +-24 0 Dl +12 24 Dl +629 1855 MXY +12 -24 Dl +-24 0 Dl +12 24 Dl +648 1838 MXY +12 -24 Dl +-24 0 Dl +12 24 Dl +686 1860 MXY +12 -25 Dl +-24 0 Dl +12 25 Dl +762 1923 MXY +13 -24 Dl +-25 0 Dl +12 24 Dl +916 2087 MXY +12 -24 Dl +-25 0 Dl +13 24 Dl +1222 2256 MXY +12 -24 Dl +-24 0 Dl +12 24 Dl +1834 2541 MXY +12 -25 Dl +-24 0 Dl +12 25 Dl +619 1865 MXY +10 -22 Dl +19 -17 Dl +38 21 Dl +76 64 Dl +154 164 Dl +306 169 Dl +612 285 Dl +1645 2427(4096)N +619 1243 MXY +0 24 Dl +0 -12 Dl +12 0 Dl +-24 0 Dl +629 1196 MXY +0 24 Dl +0 -12 Dl +12 0 Dl +-24 0 Dl +648 1146 MXY +0 24 Dl +0 -12 Dl +12 0 Dl +-24 0 Dl +686 1174 MXY +0 25 Dl +0 -13 Dl +12 0 Dl +-24 0 Dl +762 1249 MXY +0 24 Dl +0 -12 Dl +13 0 Dl +-25 0 Dl +916 1371 MXY +0 24 Dl +0 -12 Dl +12 0 Dl +-25 0 Dl +1222 1680 MXY +0 24 Dl +0 -12 Dl +12 0 Dl +-24 0 Dl +1834 1999 MXY +0 24 Dl +0 -12 Dl +12 0 Dl +-24 0 Dl +619 1255 MXY +10 -47 Dl +19 -50 Dl +38 28 Dl +76 75 Dl +154 122 Dl +306 309 Dl +612 319 Dl +1741 1934(8192)N +5 Dt +609 2531 MXY +1225 0 Dl +609 MX +0 -1553 Dl +2531 MY +0 16 Dl +4 Ds +1 Dt +2531 MY +0 -1553 Dl +593 2625(0)N +-1 Ds +5 Dt +916 2531 MXY +0 16 Dl +4 Ds +1 Dt +2531 MY +0 -1553 Dl +884 2625(32)N +-1 Ds +5 Dt +1222 2531 MXY +0 16 Dl +4 Ds +1 Dt +2531 MY +0 -1553 Dl +1190 2625(64)N +-1 Ds +5 Dt +1528 2531 MXY +0 16 Dl +4 Ds +1 Dt +2531 MY +0 -1553 Dl +1496 2625(96)N +-1 Ds +5 Dt +1834 2531 MXY +0 16 Dl +4 Ds +1 Dt +2531 MY +0 -1553 Dl +1786 2625(128)N +-1 Ds +5 Dt +609 2531 MXY +-16 0 Dl +4 Ds +1 Dt +609 MX +1225 0 Dl +545 2558(0)N +-1 Ds +5 Dt +609 2013 MXY +-16 0 Dl +4 Ds +1 Dt +609 MX +1225 0 Dl +481 2040(100)N +-1 Ds +5 Dt +609 1496 MXY +-16 0 Dl +4 Ds +1 Dt +609 MX +1225 0 Dl +481 1523(200)N +-1 Ds +5 Dt +609 978 MXY +-16 0 Dl +4 Ds +1 Dt +609 MX +1225 0 Dl +481 1005(300)N +1088 2724(Fill)N +1194(Factor)X +422 1611(S)N +426 1667(e)N +426 1724(c)N +424 1780(o)N +424 1837(n)N +424 1893(d)N +428 1949(s)N +3 Dt +-1 Ds +3 f +432 2882(Figure)N +636(5a:)X +1 f +744(System)X +956(Time)X +1113(for)X +1209(dictionary)X +1490(data)X +1618(set)X +1711(with)X +1847(1M)X +1958(of)X +2033(buffer)X +432 2970(space)N +594(and)X +707(varying)X +923(bucket)X +1114(sizes)X +1259(and)X +1372(\256ll)X +1465(factors.)X +1675(Each)X +1823(line)X +1940(is)X +2004(labeled)X +432 3058(with)N +562(its)X +639(bucket)X +825(size.)X +10 s +10 f +432 3234 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN +8 s +1 f +428 4381(s)N +424 4325(d)N +424 4269(n)N +424 4212(o)N +426 4156(c)N +426 4099(e)N +422 4043(S)N +1116 5156(Fill)N +1222(Factor)X +506 3437(3200)N +4 Ds +1 Dt +666 3410 MXY +1168 0 Dl +-1 Ds +5 Dt +666 MX +-16 0 Dl +506 3825(2400)N +4 Ds +1 Dt +666 3799 MXY +1168 0 Dl +-1 Ds +5 Dt +666 MX +-16 0 Dl +506 4214(1600)N +4 Ds +1 Dt +666 4186 MXY +1168 0 Dl +-1 Ds +5 Dt +666 MX +-16 0 Dl +538 4602(800)N +4 Ds +1 Dt +666 4575 MXY +1168 0 Dl +-1 Ds +5 Dt +666 MX +-16 0 Dl +602 4990(0)N +4 Ds +1 Dt +666 4963 MXY +1168 0 Dl +-1 Ds +5 Dt +666 MX +-16 0 Dl +1786 5057(128)N +4 Ds +1 Dt +1834 4963 MXY +0 -1553 Dl +-1 Ds +5 Dt +4963 MY +0 16 Dl +1510 5057(96)N +4 Ds +1 Dt +1542 4963 MXY +0 -1553 Dl +-1 Ds +5 Dt +4963 MY +0 16 Dl +1218 5057(64)N +4 Ds +1 Dt +1250 4963 MXY +0 -1553 Dl +-1 Ds +5 Dt +4963 MY +0 16 Dl +926 5057(32)N +4 Ds +1 Dt +958 4963 MXY +0 -1553 Dl +-1 Ds +5 Dt +4963 MY +0 16 Dl +650 5057(0)N +4 Ds +1 Dt +666 4963 MXY +0 -1553 Dl +-1 Ds +5 Dt +4963 MY +0 16 Dl +4963 MY +0 -1553 Dl +4963 MY +1168 0 Dl +1741 4752(8192)N +3 Dt +675 3732 MXY +9 -172 Dl +18 -118 Dl +37 128 Dl +73 -121 Dl +146 623 Dl +292 497 Dl +584 245 Dl +4802 MY +0 24 Dl +0 -12 Dl +12 0 Dl +-24 0 Dl +1250 4557 MXY +0 25 Dl +0 -13 Dl +12 0 Dl +-24 0 Dl +958 4060 MXY +0 24 Dl +0 -12 Dl +12 0 Dl +-24 0 Dl +812 3437 MXY +0 24 Dl +0 -12 Dl +12 0 Dl +-24 0 Dl +739 3558 MXY +0 24 Dl +0 -12 Dl +12 0 Dl +-24 0 Dl +702 3430 MXY +0 25 Dl +0 -13 Dl +13 0 Dl +-25 0 Dl +684 3548 MXY +0 24 Dl +0 -12 Dl +12 0 Dl +-24 0 Dl +675 3720 MXY +0 24 Dl +0 -12 Dl +12 0 Dl +-24 0 Dl +1637 4912(4096)N +675 4307 MXY +9 -58 Dl +18 30 Dl +37 89 Dl +73 144 Dl +146 235 Dl +292 122 Dl +584 89 Dl +4970 MY +12 -24 Dl +-24 0 Dl +12 24 Dl +1250 4881 MXY +12 -24 Dl +-24 0 Dl +12 24 Dl +958 4759 MXY +12 -24 Dl +-24 0 Dl +12 24 Dl +812 4524 MXY +12 -24 Dl +-24 0 Dl +12 24 Dl +739 4380 MXY +12 -24 Dl +-24 0 Dl +12 24 Dl +702 4291 MXY +13 -24 Dl +-25 0 Dl +12 24 Dl +684 4261 MXY +12 -24 Dl +-24 0 Dl +12 24 Dl +675 4319 MXY +12 -24 Dl +-24 0 Dl +12 24 Dl +734 4662(1024)N +16 Ds +1 Dt +675 4352 MXY +9 60 Dl +18 134 Dl +37 266 Dl +73 117 Dl +146 30 Dl +292 0 Dl +584 -1 Dl +-1 Ds +3 Dt +1846 4946 MXY +-24 24 Dl +12 -12 Dl +-12 -12 Dl +24 24 Dl +1262 4946 MXY +-24 25 Dl +12 -12 Dl +-12 -13 Dl +24 25 Dl +970 4947 MXY +-24 24 Dl +12 -12 Dl +-12 -12 Dl +24 24 Dl +824 4917 MXY +-24 24 Dl +12 -12 Dl +-12 -12 Dl +24 24 Dl +751 4800 MXY +-24 24 Dl +12 -12 Dl +-12 -12 Dl +24 24 Dl +715 4534 MXY +-25 25 Dl +12 -13 Dl +-12 -12 Dl +25 25 Dl +696 4400 MXY +-24 24 Dl +12 -12 Dl +-12 -12 Dl +24 24 Dl +687 4339 MXY +-24 25 Dl +12 -12 Dl +-12 -13 Dl +24 25 Dl +718 4792(512)N +5 Dt +675 4422 MXY +9 137 Dl +18 278 Dl +37 105 Dl +73 18 Dl +146 -1 Dl +292 0 Dl +584 -1 Dl +3 Dt +4946 MY +0 24 Dl +0 -12 Dl +12 0 Dl +-24 0 Dl +1250 4946 MXY +0 25 Dl +0 -12 Dl +12 0 Dl +-24 0 Dl +958 4947 MXY +0 24 Dl +0 -12 Dl +12 0 Dl +-24 0 Dl +812 4948 MXY +0 24 Dl +0 -12 Dl +12 0 Dl +-24 0 Dl +739 4930 MXY +0 24 Dl +0 -12 Dl +12 0 Dl +-24 0 Dl +702 4824 MXY +0 25 Dl +0 -12 Dl +13 0 Dl +-25 0 Dl +684 4547 MXY +0 24 Dl +0 -12 Dl +12 0 Dl +-24 0 Dl +675 4410 MXY +0 25 Dl +0 -13 Dl +12 0 Dl +-24 0 Dl +750 4921(256)N +20 Ds +1 Dt +675 4597 MXY +9 246 Dl +18 106 Dl +37 10 Dl +73 0 Dl +146 0 Dl +292 0 Dl +584 -1 Dl +-1 Ds +3 Dt +1822 MX +23 Dc +1238 4959 MXY +23 Dc +946 MX +23 Dc +800 MX +23 Dc +727 MX +23 Dc +691 4949 MXY +23 Dc +672 4843 MXY +24 Dc +663 4597 MXY +24 Dc +1395 4961(128)N +1 Dt +675 4855 MXY +9 93 Dl +18 10 Dl +37 1 Dl +73 0 Dl +146 -1 Dl +292 0 Dl +584 0 Dl +3 Dt +4946 MY +-12 24 Dl +24 0 Dl +-12 -24 Dl +1250 MX +-12 24 Dl +24 0 Dl +-12 -24 Dl +958 MX +-12 24 Dl +24 0 Dl +-12 -24 Dl +812 MX +-12 25 Dl +24 0 Dl +-12 -25 Dl +739 4947 MXY +-12 24 Dl +24 0 Dl +-12 -24 Dl +702 4946 MXY +-12 24 Dl +25 0 Dl +-13 -24 Dl +684 4936 MXY +-12 24 Dl +24 0 Dl +-12 -24 Dl +675 4843 MXY +-12 24 Dl +24 0 Dl +-12 -24 Dl +3 Dt +-1 Ds +3 f +432 5314(Figure)N +634(5b:)X +1 f +744(Elapsed)X +967(Time)X +1123(for)X +1218(dictionary)X +1498(data)X +1625(set)X +1717(with)X +1851(1M)X +1960(of)X +2033(buffer)X +432 5402(space)N +593(and)X +705(varying)X +920(bucket)X +1110(sizes)X +1254(and)X +1366(\256ll)X +1457(factors.)X +1681(Each)X +1827(line)X +1942(is)X +2004(labeled)X +432 5490(with)N +562(its)X +639(bucket)X +825(size.)X +10 s +2590 538(If)N +2677(an)X +2785(approximation)X +3284(of)X +3383(the)X +3513(number)X +3790(of)X +3889(elements)X +2418 626(ultimately)N +2773(to)X +2866(be)X +2973(stored)X +3200(in)X +3293(the)X +3422(hash)X +3599(table)X +3785(is)X +3868(known)X +4116(at)X +2418 714(the)N +2564(time)X +2754(of)X +2869(creation,)X +3196(the)X +3342(hash)X +3536(package)X +3847(takes)X +4059(this)X +2418 802(number)N +2688(as)X +2779(a)X +2839(parameter)X +3185(and)X +3325(uses)X +3487(it)X +3555(to)X +3641(hash)X +3812(entries)X +4050(into)X +2418 890(the)N +2541(full)X +2677(sized)X +2867(table)X +3048(rather)X +3261(than)X +3424(growing)X +3716(the)X +3838(table)X +4018(from)X +2418 978(a)N +2477(single)X +2691(bucket.)X +2968(If)X +3044(this)X +3181(number)X +3448(is)X +3523(not)X +3647(known,)X +3907(the)X +4027(hash)X +2418 1066(table)N +2632(starts)X +2859(with)X +3059(a)X +3153(single)X +3402(bucket)X +3674(and)X +3848(gracefully)X +2418 1154(expands)N +2707(as)X +2800(elements)X +3111(are)X +3236(added,)X +3474(although)X +3780(a)X +3842(slight)X +4044(per-)X +2418 1242(formance)N +2747(degradation)X +3151(may)X +3313(be)X +3413(noticed.)X +3713(Figure)X +3946(6)X +4010(illus-)X +2418 1330(trates)N +2625(the)X +2756(difference)X +3116(in)X +3211(performance)X +3651(between)X +3952(storing)X +2418 1418(keys)N +2588(in)X +2673(a)X +2732(\256le)X +2857(when)X +3054(the)X +3174(ultimate)X +3458(size)X +3605(is)X +3680(known)X +3920(\(the)X +4067(left)X +2418 1506(bars)N +2581(in)X +2672(each)X +2849(set\),)X +3014(compared)X +3360(to)X +3450(building)X +3744(the)X +3870(\256le)X +4000(when)X +2418 1594(the)N +2550(ultimate)X +2846(size)X +3005(is)X +3091(unknown)X +3422(\(the)X +3580(right)X +3764(bars)X +3931(in)X +4026(each)X +2418 1682(set\).)N +2609(Once)X +2814(the)X +2947(\256ll)X +3069(factor)X +3291(is)X +3378(suf\256ciently)X +3772(high)X +3948(for)X +4076(the)X +2418 1770(page)N +2596(size)X +2747(\(8\),)X +2887(growing)X +3180(the)X +3304(table)X +3486(dynamically)X +3908(does)X +4081(lit-)X +2418 1858(tle)N +2518(to)X +2600(degrade)X +2875(performance.)X +10 f +2418 1946 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN +9 s +1 f +2413 3238(s)N +2409 3173(d)N +2409 3108(n)N +2409 3043(o)N +2411 2979(c)N +2411 2914(e)N +2407 2849(S)N +3143 4129(Fill)N +3261(Factor)X +2448 2152(15)N +4 Ds +1 Dt +2557 2122 MXY +1473 0 Dl +-1 Ds +5 Dt +2557 MX +-19 0 Dl +2448 2747(10)N +4 Ds +1 Dt +2557 2717 MXY +1473 0 Dl +-1 Ds +5 Dt +2557 MX +-19 0 Dl +2484 3343(5)N +4 Ds +1 Dt +2557 3313 MXY +1473 0 Dl +-1 Ds +5 Dt +2557 MX +-19 0 Dl +2484 3938(0)N +4 Ds +1 Dt +2557 3908 MXY +1473 0 Dl +-1 Ds +5 Dt +2557 MX +-19 0 Dl +3976 4015(128)N +4 Ds +1 Dt +4030 3908 MXY +0 -1786 Dl +-1 Ds +5 Dt +3908 MY +0 19 Dl +3626 4015(96)N +4 Ds +1 Dt +3662 3908 MXY +0 -1786 Dl +-1 Ds +5 Dt +3908 MY +0 19 Dl +3258 4015(64)N +4 Ds +1 Dt +3294 3908 MXY +0 -1786 Dl +-1 Ds +5 Dt +3908 MY +0 19 Dl +2889 4015(32)N +4 Ds +1 Dt +2925 3908 MXY +0 -1786 Dl +-1 Ds +5 Dt +3908 MY +0 19 Dl +2539 4015(0)N +4 Ds +1 Dt +2557 3908 MXY +0 -1786 Dl +-1 Ds +5 Dt +3908 MY +0 19 Dl +3908 MY +0 -1786 Dl +3908 MY +1473 0 Dl +4053 2378(8192)N +3 Dt +2569 2277 MXY +11 0 Dl +23 48 Dl +46 -167 Dl +92 35 Dl +184 12 Dl +369 143 Dl +736 0 Dl +2334 MY +0 28 Dl +0 -14 Dl +14 0 Dl +-28 0 Dl +3294 2334 MXY +0 28 Dl +0 -14 Dl +13 0 Dl +-27 0 Dl +2925 2192 MXY +0 27 Dl +0 -14 Dl +14 0 Dl +-28 0 Dl +2741 2180 MXY +0 27 Dl +0 -14 Dl +14 0 Dl +-28 0 Dl +2649 2144 MXY +0 28 Dl +0 -14 Dl +14 0 Dl +-28 0 Dl +2603 2311 MXY +0 27 Dl +0 -13 Dl +14 0 Dl +-28 0 Dl +2580 2263 MXY +0 28 Dl +0 -14 Dl +14 0 Dl +-28 0 Dl +2569 2263 MXY +0 28 Dl +0 -14 Dl +13 0 Dl +-27 0 Dl +4053 2591(4096)N +2569 2348 MXY +11 -11 Dl +23 -96 Dl +46 71 Dl +92 72 Dl +184 226 Dl +369 48 Dl +736 -60 Dl +2612 MY +14 -28 Dl +-28 0 Dl +14 28 Dl +3294 2672 MXY +13 -28 Dl +-27 0 Dl +14 28 Dl +2925 2624 MXY +14 -28 Dl +-28 0 Dl +14 28 Dl +2741 2398 MXY +14 -28 Dl +-28 0 Dl +14 28 Dl +2649 2326 MXY +14 -27 Dl +-28 0 Dl +14 27 Dl +2603 2255 MXY +14 -28 Dl +-28 0 Dl +14 28 Dl +2580 2350 MXY +14 -27 Dl +-28 0 Dl +14 27 Dl +2569 2362 MXY +13 -28 Dl +-27 0 Dl +14 28 Dl +4053 2681(1024)N +16 Ds +1 Dt +2569 2300 MXY +11 48 Dl +23 96 Dl +46 95 Dl +92 274 Dl +184 202 Dl +369 -155 Dl +736 -190 Dl +-1 Ds +3 Dt +4044 2656 MXY +-28 28 Dl +14 -14 Dl +-14 -14 Dl +28 28 Dl +3307 2846 MXY +-27 28 Dl +14 -14 Dl +-14 -14 Dl +27 28 Dl +2939 3001 MXY +-28 28 Dl +14 -14 Dl +-14 -14 Dl +28 28 Dl +2755 2799 MXY +-28 28 Dl +14 -14 Dl +-14 -14 Dl +28 28 Dl +2663 2525 MXY +-28 28 Dl +14 -14 Dl +-14 -14 Dl +28 28 Dl +2617 2430 MXY +-28 28 Dl +14 -14 Dl +-14 -14 Dl +28 28 Dl +2594 2334 MXY +-28 28 Dl +14 -14 Dl +-14 -14 Dl +28 28 Dl +2582 2287 MXY +-27 27 Dl +14 -14 Dl +-14 -13 Dl +27 27 Dl +4053 2851(512)N +5 Dt +2569 2372 MXY +11 -24 Dl +23 405 Dl +46 83 Dl +92 227 Dl +184 -72 Dl +369 -119 Dl +736 -107 Dl +3 Dt +2751 MY +0 28 Dl +0 -14 Dl +14 0 Dl +-28 0 Dl +3294 2858 MXY +0 28 Dl +0 -14 Dl +13 0 Dl +-27 0 Dl +2925 2977 MXY +0 28 Dl +0 -14 Dl +14 0 Dl +-28 0 Dl +2741 3049 MXY +0 27 Dl +0 -13 Dl +14 0 Dl +-28 0 Dl +2649 2823 MXY +0 27 Dl +0 -14 Dl +14 0 Dl +-28 0 Dl +2603 2739 MXY +0 28 Dl +0 -14 Dl +14 0 Dl +-28 0 Dl +2580 2334 MXY +0 28 Dl +0 -14 Dl +14 0 Dl +-28 0 Dl +2569 2358 MXY +0 28 Dl +0 -14 Dl +13 0 Dl +-27 0 Dl +4053 2795(256)N +20 Ds +1 Dt +2569 2456 MXY +11 285 Dl +23 95 Dl +46 251 Dl +92 -60 Dl +184 -84 Dl +369 -107 Dl +736 -71 Dl +-1 Ds +3 Dt +4016 MX +27 Dc +3280 2836 MXY +27 Dc +2912 2943 MXY +27 Dc +2728 3027 MXY +27 Dc +2635 3087 MXY +28 Dc +2589 2836 MXY +28 Dc +2566 2741 MXY +27 Dc +2554 2456 MXY +28 Dc +4053 2741(128)N +1 Dt +2569 2729 MXY +11 203 Dl +23 131 Dl +46 -60 Dl +92 -119 Dl +184 -60 Dl +369 -83 Dl +736 -12 Dl +3 Dt +2716 MY +-14 27 Dl +28 0 Dl +-14 -27 Dl +3294 2727 MXY +-14 28 Dl +27 0 Dl +-13 -28 Dl +2925 2811 MXY +-14 27 Dl +28 0 Dl +-14 -27 Dl +2741 2870 MXY +-14 28 Dl +28 0 Dl +-14 -28 Dl +2649 2989 MXY +-14 28 Dl +28 0 Dl +-14 -28 Dl +2603 3049 MXY +-14 27 Dl +28 0 Dl +-14 -27 Dl +2580 2918 MXY +-14 28 Dl +28 0 Dl +-14 -28 Dl +2569 2716 MXY +-14 27 Dl +27 0 Dl +-13 -27 Dl +3 Dt +-1 Ds +3 f +8 s +2418 4286(Figure)N +2628(5c:)X +1 f +2738(User)X +2887(Time)X +3051(for)X +3154(dictionary)X +3442(data)X +3577(set)X +3677(with)X +3820(1M)X +3938(of)X +4019(buffer)X +2418 4374(space)N +2579(and)X +2691(varying)X +2906(bucket)X +3096(sizes)X +3240(and)X +3352(\256ll)X +3443(factors.)X +3667(Each)X +3813(line)X +3928(is)X +3990(labeled)X +2418 4462(with)N +2548(its)X +2625(bucket)X +2811(size.)X +10 s +10 f +2418 4638 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN +1 f +2590 4840(Since)N +2796(no)X +2904(known)X +3150(hash)X +3325(function)X +3620(performs)X +3938(equally)X +2418 4928(well)N +2589(on)X +2702(all)X +2815(possible)X +3110(data,)X +3297(the)X +3428(user)X +3595(may)X +3766(\256nd)X +3923(that)X +4076(the)X +2418 5016(built-in)N +2678(hash)X +2849(function)X +3140(does)X +3311(poorly)X +3544(on)X +3648(a)X +3708(particular)X +4040(data)X +2418 5104(set.)N +2548(In)X +2636(this)X +2771(case,)X +2950(a)X +3006(hash)X +3173(function,)X +3480(taking)X +3700(two)X +3840(arguments)X +2418 5192(\(a)N +2507(pointer)X +2760(to)X +2848(a)X +2910(byte)X +3074(string)X +3282(and)X +3424(a)X +3486(length\))X +3739(and)X +3880(returning)X +2418 5280(an)N +2517(unsigned)X +2829(long)X +2993(to)X +3077(be)X +3175(used)X +3344(as)X +3433(the)X +3553(hash)X +3722(value,)X +3938(may)X +4098(be)X +2418 5368(speci\256ed)N +2731(at)X +2817(hash)X +2992(table)X +3176(creation)X +3463(time.)X +3673(When)X +3893(an)X +3996(exist-)X +2418 5456(ing)N +2570(hash)X +2767(table)X +2973(is)X +3076(opened)X +3358(and)X +3524(a)X +3609(hash)X +3805(function)X +4121(is)X +2418 5544(speci\256ed,)N +2752(the)X +2879(hash)X +3054(package)X +3346(will)X +3498(try)X +3615(to)X +3705(determine)X +4054(that)X +2418 5632(the)N +2546(hash)X +2723(function)X +3020(supplied)X +3321(is)X +3404(the)X +3532(one)X +3678(with)X +3850(which)X +4076(the)X +2418 5720(table)N +2630(was)X +2811(created.)X +3139(There)X +3382(are)X +3536(a)X +3627(variety)X +3905(of)X +4027(hash)X +3 f +432 5960(8)N +2970(USENIX)X +9 f +3292(-)X +3 f +3356(Winter)X +3621('91)X +9 f +3748(-)X +3 f +3812(Dallas,)X +4065(TX)X + +9 p +%%Page: 9 9 +0(Courier)xf 0 f +10 s 10 xH 0 xS 0 f +3 f +720 258(Seltzer)N +977(&)X +1064(Yigit)X +3278(A)X +3356(New)X +3528(Hashing)X +3831(Package)X +4136(for)X +4259(UNIX)X +1 f +720 538(functions)N +1065(provided)X +1397(with)X +1586(the)X +1731(package.)X +2082(The)X +2253(default)X +720 626(function)N +1014(for)X +1135(the)X +1260(package)X +1551(is)X +1631(the)X +1755(one)X +1897(which)X +2119(offered)X +2378(the)X +720 714(best)N +875(performance)X +1308(in)X +1396(terms)X +1600(of)X +1693(cycles)X +1920(executed)X +2232(per)X +2360(call)X +720 802(\(it)N +827(did)X +965(not)X +1103(produce)X +1398(the)X +1531(fewest)X +1776(collisions)X +2117(although)X +2432(it)X +720 890(was)N +866(within)X +1091(a)X +1148(small)X +1341(percentage)X +1710(of)X +1797(the)X +1915(function)X +2202(that)X +2342(pro-)X +720 978(duced)N +947(the)X +1080(fewest)X +1324(collisions\).)X +1731(Again,)X +1981(in)X +2077(time)X +2253(critical)X +720 1066(applications,)N +1152(users)X +1342(are)X +1466(encouraged)X +1862(to)X +1949(experiment)X +2334(with)X +720 1154(a)N +783(variety)X +1032(of)X +1125(hash)X +1298(functions)X +1622(to)X +1710(achieve)X +1982(optimal)X +2252(perfor-)X +720 1242(mance.)N +10 f +720 1330 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN +3 f +7 s +1038 2925(Full)N +1149(size)X +1251(table)X +1384(\(left\))X +1547 2718(Fill)N +1643(Factor)X +2268 2662(64)N +1964(32)X +1674(16)X +1384(8)X +1093(4)X +4 Ds +1 Dt +900 2280 MXY +1548 0 Dl +900 1879 MXY +1548 0 Dl +900 1506 MXY +1548 0 Dl +1563 2902 MXY +111 0 Dl +-1 Ds +900 MX +110 0 Dl +1425 2828(System)N +983(User)X +1895 2778 MXY + 1895 2778 lineto + 1950 2778 lineto + 1950 2833 lineto + 1895 2833 lineto + 1895 2778 lineto +closepath 21 1895 2778 1950 2833 Dp +1342 MX + 1342 2778 lineto + 1397 2778 lineto + 1397 2833 lineto + 1342 2833 lineto + 1342 2778 lineto +closepath 14 1342 2778 1397 2833 Dp +900 MX + 900 2778 lineto + 955 2778 lineto + 955 2833 lineto + 900 2833 lineto + 900 2778 lineto +closepath 3 900 2778 955 2833 Dp +5 Dt +2283 2211 MXY +96 0 Dl +1992 MX +97 0 Dl +1702 MX +97 0 Dl +1411 2252 MXY +97 0 Dl +4 Ds +1 Dt +2283 2211 MXY + 2283 2211 lineto + 2379 2211 lineto + 2379 2252 lineto + 2283 2252 lineto + 2283 2211 lineto +closepath 14 2283 2211 2379 2252 Dp +1992 MX + 1992 2211 lineto + 2089 2211 lineto + 2089 2252 lineto + 1992 2252 lineto + 1992 2211 lineto +closepath 14 1992 2211 2089 2252 Dp +1702 MX + 1702 2211 lineto + 1799 2211 lineto + 1799 2252 lineto + 1702 2252 lineto + 1702 2211 lineto +closepath 14 1702 2211 1799 2252 Dp +1411 2252 MXY + 1411 2252 lineto + 1508 2252 lineto + 1508 2294 lineto + 1411 2294 lineto + 1411 2252 lineto +closepath 14 1411 2252 1508 2294 Dp +2283 MX + 2283 2252 lineto + 2379 2252 lineto + 2379 2612 lineto + 2283 2612 lineto + 2283 2252 lineto +closepath 3 2283 2252 2379 2612 Dp +1992 MX + 1992 2252 lineto + 2089 2252 lineto + 2089 2612 lineto + 1992 2612 lineto + 1992 2252 lineto +closepath 3 1992 2252 2089 2612 Dp +1702 MX + 1702 2252 lineto + 1799 2252 lineto + 1799 2612 lineto + 1702 2612 lineto + 1702 2252 lineto +closepath 3 1702 2252 1799 2612 Dp +1411 2294 MXY + 1411 2294 lineto + 1508 2294 lineto + 1508 2612 lineto + 1411 2612 lineto + 1411 2294 lineto +closepath 3 1411 2294 1508 2612 Dp +-1 Ds +2158 2238 MXY + 2158 2238 lineto + 2255 2238 lineto + 2255 2252 lineto + 2158 2252 lineto + 2158 2238 lineto +closepath 21 2158 2238 2255 2252 Dp +1868 MX + 1868 2238 lineto + 1965 2238 lineto + 1965 2280 lineto + 1868 2280 lineto + 1868 2238 lineto +closepath 21 1868 2238 1965 2280 Dp +1577 MX + 1577 2238 lineto + 1674 2238 lineto + 1674 2308 lineto + 1577 2308 lineto + 1577 2238 lineto +closepath 21 1577 2238 1674 2308 Dp +1287 2308 MXY + 1287 2308 lineto + 1287 2280 lineto + 1384 2280 lineto + 1384 2308 lineto + 1287 2308 lineto +closepath 21 1287 2280 1384 2308 Dp +2158 2280 MXY + 2158 2280 lineto + 2158 2252 lineto + 2255 2252 lineto + 2255 2280 lineto + 2158 2280 lineto +closepath 14 2158 2252 2255 2280 Dp +1868 2308 MXY + 1868 2308 lineto + 1868 2280 lineto + 1965 2280 lineto + 1965 2308 lineto + 1868 2308 lineto +closepath 14 1868 2280 1965 2308 Dp +1577 2335 MXY + 1577 2335 lineto + 1577 2308 lineto + 1674 2308 lineto + 1674 2335 lineto + 1577 2335 lineto +closepath 14 1577 2308 1674 2335 Dp +1287 2363 MXY + 1287 2363 lineto + 1287 2308 lineto + 1384 2308 lineto + 1384 2363 lineto + 1287 2363 lineto +closepath 14 1287 2308 1384 2363 Dp +2158 2280 MXY + 2158 2280 lineto + 2255 2280 lineto + 2255 2612 lineto + 2158 2612 lineto + 2158 2280 lineto +closepath 3 2158 2280 2255 2612 Dp +1868 2308 MXY + 1868 2308 lineto + 1965 2308 lineto + 1965 2612 lineto + 1868 2612 lineto + 1868 2308 lineto +closepath 3 1868 2308 1965 2612 Dp +1577 2335 MXY + 1577 2335 lineto + 1674 2335 lineto + 1674 2612 lineto + 1577 2612 lineto + 1577 2335 lineto +closepath 3 1577 2335 1674 2612 Dp +1287 2363 MXY + 1287 2363 lineto + 1384 2363 lineto + 1384 2612 lineto + 1287 2612 lineto + 1287 2363 lineto +closepath 3 1287 2363 1384 2612 Dp +4 Ds +1121 2066 MXY + 1121 2066 lineto + 1218 2066 lineto + 1224 2080 lineto + 1127 2080 lineto + 1121 2066 lineto +closepath 21 1121 2066 1224 2080 Dp +2080 MY + 1121 2080 lineto + 1218 2080 lineto + 1218 2273 lineto + 1121 2273 lineto + 1121 2080 lineto +closepath 14 1121 2080 1218 2273 Dp +2273 MY + 1121 2273 lineto + 1218 2273 lineto + 1218 2612 lineto + 1121 2612 lineto + 1121 2273 lineto +closepath 3 1121 2273 1218 2612 Dp +-1 Ds +997 1589 MXY + 997 1589 lineto + 1093 1589 lineto + 1093 1644 lineto + 997 1644 lineto + 997 1589 lineto +closepath 21 997 1589 1093 1644 Dp +1644 MY + 997 1644 lineto + 1093 1644 lineto + 1093 2280 lineto + 997 2280 lineto + 997 1644 lineto +closepath 14 997 1644 1093 2280 Dp +2280 MY + 997 2280 lineto + 1093 2280 lineto + 1093 2612 lineto + 997 2612 lineto + 997 2280 lineto +closepath 3 997 2280 1093 2612 Dp +10 s +719 2093(s)N +712 2037(d)N +712 1982(n)N +714 1927(o)N +716 1872(c)N +716 1816(e)N +712 1761(S)N +804 2286(10)N +804 1899(20)N +804 1540(30)N +3 Dt +900 1506 MXY +0 1106 Dl +1548 0 Dl +7 s +1978 2828(Elapsed)N +1701 2925(Dynamically)N +2018(grown)X +2184(table)X +2317(\(right\))X +3 Dt +-1 Ds +8 s +720 3180(Figure)N +934(6:)X +1 f +1020(The)X +1152(total)X +1299(regions)X +1520(indicate)X +1755(the)X +1865(difference)X +2154(between)X +2398(the)X +720 3268(elapsed)N +931(time)X +1065(and)X +1177(the)X +1275(sum)X +1402(of)X +1475(the)X +1573(system)X +1771(and)X +1883(user)X +2008(time.)X +2173(The)X +2291(left)X +2395(bar)X +720 3356(of)N +798(each)X +939(set)X +1035(depicts)X +1241(the)X +1344(timing)X +1537(of)X +1615(the)X +1718(test)X +1831(run)X +1940(when)X +2102(the)X +2204(number)X +2423(of)X +720 3444(entries)N +910(is)X +973(known)X +1167(in)X +1237(advance.)X +1496(The)X +1614(right)X +1754(bars)X +1879(depict)X +2054(the)X +2151(timing)X +2338(when)X +720 3532(the)N +814(\256le)X +912(is)X +971(grown)X +1150(from)X +1290(a)X +1334(single)X +1503(bucket.)X +10 s +10 f +720 3708 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN +1 f +892 3910(Since)N +1131(this)X +1307(hashing)X +1617(package)X +1942(provides)X +2279(buffer)X +720 3998(management,)N +1188(the)X +1323(amount)X +1600(of)X +1704(space)X +1920(allocated)X +2247(for)X +2378(the)X +720 4086(buffer)N +948(pool)X +1121(may)X +1290(be)X +1397(speci\256ed)X +1713(by)X +1824(the)X +1953(user.)X +2157(Using)X +2378(the)X +720 4174(same)N +910(data)X +1069(set)X +1183(and)X +1324(test)X +1459(procedure)X +1805(as)X +1896(used)X +2067(to)X +2153(derive)X +2378(the)X +720 4262(graphs)N +962(in)X +1052(Figures)X +1320(5a-c,)X +1507(Figure)X +1744(7)X +1812(shows)X +2039(the)X +2164(impact)X +2409(of)X +720 4350(varying)N +997(the)X +1126(size)X +1282(of)X +1380(the)X +1509(buffer)X +1737(pool.)X +1950(The)X +2106(bucket)X +2351(size)X +720 4438(was)N +873(set)X +989(to)X +1078(256)X +1225(bytes)X +1421(and)X +1564(the)X +1689(\256ll)X +1804(factor)X +2019(was)X +2171(set)X +2287(to)X +2376(16.)X +720 4526(The)N +869(buffer)X +1090(pool)X +1256(size)X +1404(was)X +1552(varied)X +1776(from)X +1955(0)X +2018(\(the)X +2166(minimum)X +720 4614(number)N +986(of)X +1074(pages)X +1277(required)X +1565(to)X +1647(be)X +1743(buffered\))X +2063(to)X +2145(1M.)X +2316(With)X +720 4702(1M)N +854(of)X +944(buffer)X +1164(space,)X +1386(the)X +1507(package)X +1794(performed)X +2151(no)X +2253(I/O)X +2382(for)X +720 4790(this)N +871(data)X +1040(set.)X +1204(As)X +1328(Figure)X +1572(7)X +1647(illustrates,)X +2013(increasing)X +2378(the)X +720 4878(buffer)N +944(pool)X +1113(size)X +1265(can)X +1404(have)X +1583(a)X +1646(dramatic)X +1954(affect)X +2165(on)X +2271(result-)X +720 4966(ing)N +842(performance.)X +2 f +8 s +1269 4941(7)N +1 f +16 s +720 5353 MXY +864 0 Dl +2 f +8 s +760 5408(7)N +1 f +9 s +826 5433(Some)N +1024(allocators)X +1338(are)X +1460(extremely)X +1782(inef\256cient)X +2107(at)X +2192(allocating)X +720 5513(memory.)N +1029(If)X +1110(you)X +1251(\256nd)X +1396(that)X +1536(applications)X +1916(are)X +2036(running)X +2292(out)X +2416(of)X +720 5593(memory)N +1005(before)X +1234(you)X +1386(think)X +1578(they)X +1746(should,)X +2000(try)X +2124(varying)X +2388(the)X +720 5673(pagesize)N +986(to)X +1060(get)X +1166(better)X +1348(utilization)X +1658(from)X +1816(the)X +1922(memory)X +2180(allocator.)X +10 s +2830 1975 MXY +0 -28 Dl +28 0 Dl +0 28 Dl +-28 0 Dl +2853 2004 MXY +0 -27 Dl +28 0 Dl +0 27 Dl +-28 0 Dl +2876 2016 MXY +0 -27 Dl +27 0 Dl +0 27 Dl +-27 0 Dl +2922 1998 MXY +0 -27 Dl +27 0 Dl +0 27 Dl +-27 0 Dl +2967 2025 MXY +0 -28 Dl +28 0 Dl +0 28 Dl +-28 0 Dl +3013 2031 MXY +0 -28 Dl +28 0 Dl +0 28 Dl +-28 0 Dl +3059 MX +0 -28 Dl +27 0 Dl +0 28 Dl +-27 0 Dl +3196 2052 MXY +0 -28 Dl +27 0 Dl +0 28 Dl +-27 0 Dl +3561 2102 MXY +0 -28 Dl +28 0 Dl +0 28 Dl +-28 0 Dl +4292 2105 MXY +0 -28 Dl +27 0 Dl +0 28 Dl +-27 0 Dl +4 Ds +1 Dt +2844 1961 MXY +23 30 Dl +23 12 Dl +45 -18 Dl +46 26 Dl +46 6 Dl +45 0 Dl +137 21 Dl +366 50 Dl +730 3 Dl +9 s +4227 2158(User)N +-1 Ds +3 Dt +2830 1211 MXY +27 Dc +2853 1261 MXY +27 Dc +2876 1267 MXY +27 Dc +2921 1341 MXY +27 Dc +2967 1385 MXY +27 Dc +3013 1450 MXY +27 Dc +3059 1497 MXY +27 Dc +3196 1686 MXY +27 Dc +3561 2109 MXY +27 Dc +4292 2295 MXY +27 Dc +20 Ds +1 Dt +2844 1211 MXY +23 50 Dl +23 6 Dl +45 74 Dl +46 44 Dl +46 65 Dl +45 47 Dl +137 189 Dl +366 423 Dl +730 186 Dl +4181 2270(System)N +-1 Ds +3 Dt +2844 583 MXY +0 28 Dl +0 -14 Dl +14 0 Dl +-28 0 Dl +2867 672 MXY +0 27 Dl +0 -14 Dl +14 0 Dl +-28 0 Dl +2890 701 MXY +0 28 Dl +0 -14 Dl +13 0 Dl +-27 0 Dl +2935 819 MXY +0 28 Dl +0 -14 Dl +14 0 Dl +-27 0 Dl +2981 849 MXY +0 28 Dl +0 -14 Dl +14 0 Dl +-28 0 Dl +3027 908 MXY +0 27 Dl +0 -13 Dl +14 0 Dl +-28 0 Dl +3072 1026 MXY +0 27 Dl +0 -13 Dl +14 0 Dl +-27 0 Dl +3209 1292 MXY +0 27 Dl +0 -14 Dl +14 0 Dl +-27 0 Dl +3575 1823 MXY +0 28 Dl +0 -14 Dl +14 0 Dl +-28 0 Dl +4305 2059 MXY +0 28 Dl +0 -14 Dl +14 0 Dl +-27 0 Dl +5 Dt +2844 597 MXY +23 88 Dl +23 30 Dl +45 118 Dl +46 30 Dl +46 59 Dl +45 118 Dl +137 265 Dl +366 532 Dl +730 236 Dl +4328 2103(Total)N +2844 2310 MXY +1461 0 Dl +2844 MX +0 -1772 Dl +2310 MY +0 18 Dl +4 Ds +1 Dt +2310 MY +0 -1772 Dl +2826 2416(0)N +-1 Ds +5 Dt +3209 2310 MXY +0 18 Dl +4 Ds +1 Dt +2310 MY +0 -1772 Dl +3155 2416(256)N +-1 Ds +5 Dt +3575 2310 MXY +0 18 Dl +4 Ds +1 Dt +2310 MY +0 -1772 Dl +3521 2416(512)N +-1 Ds +5 Dt +3940 2310 MXY +0 18 Dl +4 Ds +1 Dt +2310 MY +0 -1772 Dl +3886 2416(768)N +-1 Ds +5 Dt +4305 2310 MXY +0 18 Dl +4 Ds +1 Dt +2310 MY +0 -1772 Dl +4233 2416(1024)N +-1 Ds +5 Dt +2844 2310 MXY +-18 0 Dl +4 Ds +1 Dt +2844 MX +1461 0 Dl +2771 2340(0)N +-1 Ds +5 Dt +2844 2014 MXY +-18 0 Dl +2844 1719 MXY +-18 0 Dl +4 Ds +1 Dt +2844 MX +1461 0 Dl +2735 1749(20)N +-1 Ds +5 Dt +2844 1423 MXY +-18 0 Dl +2844 1128 MXY +-18 0 Dl +4 Ds +1 Dt +2844 MX +1461 0 Dl +2735 1158(40)N +-1 Ds +5 Dt +2844 833 MXY +-18 0 Dl +2844 538 MXY +-18 0 Dl +4 Ds +1 Dt +2844 MX +1461 0 Dl +2735 568(60)N +3239 2529(Buffer)N +3445(Pool)X +3595(Size)X +3737(\(in)X +3835(K\))X +2695 1259(S)N +2699 1324(e)N +2699 1388(c)N +2697 1452(o)N +2697 1517(n)N +2697 1581(d)N +2701 1645(s)N +3 Dt +-1 Ds +3 f +8 s +2706 2773(Figure)N +2908(7:)X +1 f +2982(User)X +3123(time)X +3258(is)X +3322(virtually)X +3560(insensitive)X +3854(to)X +3924(the)X +4022(amount)X +4234(of)X +4307(buffer)X +2706 2861(pool)N +2852(available,)X +3130(however,)X +3396(both)X +3541(system)X +3750(time)X +3895(and)X +4018(elapsed)X +4240(time)X +4385(are)X +2706 2949(inversely)N +2960(proportional)X +3296(to)X +3366(the)X +3464(size)X +3583(of)X +3656(the)X +3753(buffer)X +3927(pool.)X +4092(Even)X +4242(for)X +4335(large)X +2706 3037(data)N +2831(sets)X +2946(where)X +3120(one)X +3230(expects)X +3439(few)X +3552(collisions,)X +3832(specifying)X +4116(a)X +4162(large)X +4307(buffer)X +2706 3125(pool)N +2836(dramatically)X +3171(improves)X +3425(performance.)X +10 s +10 f +2706 3301 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN +3 f +3175 3543(Enhanced)N +3536(Functionality)X +1 f +2878 3675(This)N +3046(hashing)X +3320(package)X +3609(provides)X +3910(a)X +3971(set)X +4085(of)X +4177(compati-)X +2706 3763(bility)N +2895(routines)X +3174(to)X +3257(implement)X +3620(the)X +2 f +3739(ndbm)X +1 f +3937(interface.)X +4279(How-)X +2706 3851(ever,)N +2893(when)X +3095(the)X +3220(native)X +3443(interface)X +3752(is)X +3832(used,)X +4026(the)X +4151(following)X +2706 3939(additional)N +3046(functionality)X +3475(is)X +3548(provided:)X +10 f +2798 4071(g)N +1 f +2946(Inserts)X +3197(never)X +3413(fail)X +3556(because)X +3847(too)X +3985(many)X +4199(keys)X +2946 4159(hash)N +3113(to)X +3195(the)X +3313(same)X +3498(value.)X +10 f +2798 4247(g)N +1 f +2946(Inserts)X +3187(never)X +3393(fail)X +3527(because)X +3808(key)X +3950(and/or)X +4181(asso-)X +2946 4335(ciated)N +3158(data)X +3312(is)X +3385(too)X +3507(large)X +10 f +2798 4423(g)N +1 f +2946(Hash)X +3131(functions)X +3449(may)X +3607(be)X +3703(user-speci\256ed.)X +10 f +2798 4511(g)N +1 f +2946(Multiple)X +3268(pages)X +3498(may)X +3683(be)X +3806(cached)X +4077(in)X +4186(main)X +2946 4599(memory.)N +2706 4731(It)N +2801(also)X +2976(provides)X +3298(a)X +3380(set)X +3514(of)X +3626(compatibility)X +4097(routines)X +4400(to)X +2706 4819(implement)N +3087(the)X +2 f +3224(hsearch)X +1 f +3516(interface.)X +3876(Again,)X +4130(the)X +4266(native)X +2706 4907(interface)N +3008(offers)X +3216(enhanced)X +3540(functionality:)X +10 f +2798 5039(g)N +1 f +2946(Files)X +3121(may)X +3279(grow)X +3464(beyond)X +2 f +3720(nelem)X +1 f +3932(elements.)X +10 f +2798 5127(g)N +1 f +2946(Multiple)X +3247(hash)X +3420(tables)X +3632(may)X +3795(be)X +3896(accessed)X +4203(con-)X +2946 5215(currently.)N +10 f +2798 5303(g)N +1 f +2946(Hash)X +3134(tables)X +3344(may)X +3505(be)X +3604(stored)X +3823(and)X +3962(accessed)X +4266(on)X +2946 5391(disk.)N +10 f +2798 5479(g)N +1 f +2946(Hash)X +3155(functions)X +3497(may)X +3679(be)X +3799(user-speci\256ed)X +4288(at)X +2946 5567(runtime.)N +3 f +720 5960(USENIX)N +9 f +1042(-)X +3 f +1106(Winter)X +1371('91)X +9 f +1498(-)X +3 f +1562(Dallas,)X +1815(TX)X +4424(9)X + +10 p +%%Page: 10 10 +0(Courier)xf 0 f +10 s 10 xH 0 xS 0 f +3 f +432 258(A)N +510(New)X +682(Hashing)X +985(Package)X +1290(for)X +1413(UNIX)X +3663(Seltzer)X +3920(&)X +4007(Yigit)X +459 538(Relative)N +760(Performance)X +1227(of)X +1314(the)X +1441(New)X +1613(Implementation)X +1 f +604 670(The)N +761(performance)X +1200(testing)X +1445(of)X +1544(the)X +1674(new)X +1840(package)X +2135(is)X +432 758(divided)N +711(into)X +874(two)X +1033(test)X +1183(suites.)X +1424(The)X +1588(\256rst)X +1751(suite)X +1941(of)X +2046(tests)X +432 846(requires)N +727(that)X +882(the)X +1015(tables)X +1237(be)X +1348(read)X +1522(from)X +1713(and)X +1864(written)X +2126(to)X +432 934(disk.)N +640(In)X +742(these)X +942(tests,)X +1139(the)X +1272(basis)X +1467(for)X +1595(comparison)X +2003(is)X +2090(the)X +432 1022(4.3BSD-Reno)N +908(version)X +1169(of)X +2 f +1260(ndbm)X +1 f +1438(.)X +1502(Based)X +1722(on)X +1826(the)X +1948(designs)X +432 1110(of)N +2 f +521(sdbm)X +1 f +712(and)X +2 f +850(gdbm)X +1 f +1028(,)X +1070(they)X +1230(are)X +1351(expected)X +1659(to)X +1743(perform)X +2024(simi-)X +432 1198(larly)N +605(to)X +2 f +693(ndbm)X +1 f +871(,)X +917(and)X +1059(we)X +1179(do)X +1285(not)X +1413(show)X +1608(their)X +1781(performance)X +432 1286(numbers.)N +800(The)X +977(second)X +1252(suite)X +1454(contains)X +1772(the)X +1921(memory)X +432 1374(resident)N +712(test)X +849(which)X +1071(does)X +1243(not)X +1370(require)X +1623(that)X +1768(the)X +1891(\256les)X +2049(ever)X +432 1462(be)N +533(written)X +784(to)X +870(disk,)X +1047(only)X +1213(that)X +1357(hash)X +1528(tables)X +1739(may)X +1901(be)X +2001(mani-)X +432 1550(pulated)N +692(in)X +778(main)X +961(memory.)X +1291(In)X +1381(this)X +1519(test,)X +1673(we)X +1790(compare)X +2090(the)X +432 1638(performance)N +859(to)X +941(that)X +1081(of)X +1168(the)X +2 f +1286(hsearch)X +1 f +1560(routines.)X +604 1752(For)N +760(both)X +947(suites,)X +1194(two)X +1358(different)X +1679(databases)X +2031(were)X +432 1840(used.)N +656(The)X +818(\256rst)X +979(is)X +1069(the)X +1204(dictionary)X +1566(database)X +1880(described)X +432 1928(previously.)N +836(The)X +987(second)X +1236(was)X +1386(constructed)X +1781(from)X +1962(a)X +2023(pass-)X +432 2016(word)N +647(\256le)X +799(with)X +990(approximately)X +1502(300)X +1671(accounts.)X +2041(Two)X +432 2104(records)N +700(were)X +887(constructed)X +1287(for)X +1411(each)X +1589(account.)X +1909(The)X +2064(\256rst)X +432 2192(used)N +604(the)X +727(logname)X +1028(as)X +1120(the)X +1243(key)X +1384(and)X +1525(the)X +1648(remainder)X +1999(of)X +2090(the)X +432 2280(password)N +768(entry)X +965(for)X +1091(the)X +1221(data.)X +1427(The)X +1584(second)X +1839(was)X +1996(keyed)X +432 2368(by)N +541(uid)X +672(and)X +817(contained)X +1157(the)X +1283(entire)X +1494(password)X +1825(entry)X +2018(as)X +2113(its)X +432 2456(data)N +589(\256eld.)X +794(The)X +942(tests)X +1107(were)X +1287(all)X +1389(run)X +1518(on)X +1620(the)X +1740(HP)X +1864(9000)X +2046(with)X +432 2544(the)N +574(same)X +783(con\256guration)X +1254(previously)X +1636(described.)X +2027(Each)X +432 2632(test)N +576(was)X +734(run)X +874(\256ve)X +1027(times)X +1232(and)X +1380(the)X +1510(timing)X +1750(results)X +1991(of)X +2090(the)X +432 2720(runs)N +602(were)X +791(averaged.)X +1154(The)X +1311(variance)X +1616(across)X +1849(the)X +1979(5)X +2050(runs)X +432 2808(was)N +591(approximately)X +1088(1%)X +1229(of)X +1330(the)X +1462(average)X +1746(yielding)X +2041(95%)X +432 2896(con\256dence)N +800(intervals)X +1096(of)X +1183(approximately)X +1666(2%.)X +3 f +1021 3050(Disk)N +1196(Based)X +1420(Tests)X +1 f +604 3182(In)N +693(these)X +880(tests,)X +1064(we)X +1180(use)X +1308(a)X +1365(bucket)X +1600(size)X +1746(of)X +1834(1024)X +2015(and)X +2152(a)X +432 3270(\256ll)N +540(factor)X +748(of)X +835(32.)X +3 f +432 3384(create)N +663(test)X +1 f +547 3498(The)N +703(keys)X +881(are)X +1011(entered)X +1279(into)X +1433(the)X +1561(hash)X +1738(table,)X +1944(and)X +2090(the)X +547 3586(\256le)N +669(is)X +742(\257ushed)X +993(to)X +1075(disk.)X +3 f +432 3700(read)N +608(test)X +1 f +547 3814(A)N +640(lookup)X +897(is)X +984(performed)X +1353(for)X +1481(each)X +1663(key)X +1813(in)X +1909(the)X +2041(hash)X +547 3902(table.)N +3 f +432 4016(verify)N +653(test)X +1 f +547 4130(A)N +640(lookup)X +897(is)X +984(performed)X +1353(for)X +1481(each)X +1663(key)X +1813(in)X +1909(the)X +2041(hash)X +547 4218(table,)N +759(and)X +911(the)X +1045(data)X +1215(returned)X +1519(is)X +1608(compared)X +1961(against)X +547 4306(that)N +687(originally)X +1018(stored)X +1234(in)X +1316(the)X +1434(hash)X +1601(table.)X +3 f +432 4420(sequential)N +798(retrieve)X +1 f +547 4534(All)N +674(keys)X +846(are)X +970(retrieved)X +1281(in)X +1367(sequential)X +1716(order)X +1910(from)X +2090(the)X +547 4622(hash)N +724(table.)X +950(The)X +2 f +1105(ndbm)X +1 f +1313(interface)X +1625(allows)X +1863(sequential)X +547 4710(retrieval)N +848(of)X +948(the)X +1079(keys)X +1259(from)X +1448(the)X +1578(database,)X +1907(but)X +2041(does)X +547 4798(not)N +701(return)X +945(the)X +1094(data)X +1279(associated)X +1660(with)X +1853(each)X +2052(key.)X +547 4886(Therefore,)N +929(we)X +1067(compare)X +1388(the)X +1530(performance)X +1980(of)X +2090(the)X +547 4974(new)N +703(package)X +989(to)X +1073(two)X +1215(different)X +1514(runs)X +1674(of)X +2 f +1763(ndbm)X +1 f +1941(.)X +2002(In)X +2090(the)X +547 5062(\256rst)N +697(case,)X +2 f +882(ndbm)X +1 f +1086(returns)X +1335(only)X +1503(the)X +1627(keys)X +1800(while)X +2003(in)X +2090(the)X +547 5150(second,)N +2 f +823(ndbm)X +1 f +1034(returns)X +1290(both)X +1465(the)X +1596(keys)X +1776(and)X +1924(the)X +2054(data)X +547 5238(\(requiring)N +894(a)X +956(second)X +1204(call)X +1345(to)X +1432(the)X +1555(library\).)X +1861(There)X +2074(is)X +2152(a)X +547 5326(single)N +764(run)X +897(for)X +1017(the)X +1141(new)X +1300(library)X +1539(since)X +1729(it)X +1798(returns)X +2046(both)X +547 5414(the)N +665(key)X +801(and)X +937(the)X +1055(data.)X +3 f +3014 538(In-Memory)N +3431(Test)X +1 f +2590 670(This)N +2757(test)X +2892(uses)X +3054(a)X +3114(bucket)X +3352(size)X +3501(of)X +3592(256)X +3736(and)X +3876(a)X +3936(\256ll)X +4048(fac-)X +2418 758(tor)N +2527(of)X +2614(8.)X +3 f +2418 872(create/read)N +2827(test)X +1 f +2533 986(In)N +2627(this)X +2769(test,)X +2927(a)X +2989(hash)X +3162(table)X +3344(is)X +3423(created)X +3682(by)X +3788(inserting)X +4094(all)X +2533 1074(the)N +2660(key/data)X +2961(pairs.)X +3186(Then)X +3380(a)X +3445(keyed)X +3666(retrieval)X +3963(is)X +4044(per-)X +2533 1162(formed)N +2801(for)X +2931(each)X +3115(pair,)X +3295(and)X +3446(the)X +3579(hash)X +3761(table)X +3952(is)X +4040(des-)X +2533 1250(troyed.)N +3 f +2938 1404(Performance)N +3405(Results)X +1 f +2590 1536(Figures)N +2866(8a)X +2978(and)X +3130(8b)X +3246(show)X +3451(the)X +3585(user)X +3755(time,)X +3952(system)X +2418 1624(time,)N +2608(and)X +2752(elapsed)X +3021(time)X +3191(for)X +3312(each)X +3487(test)X +3625(for)X +3746(both)X +3915(the)X +4040(new)X +2418 1712(implementation)N +2951(and)X +3098(the)X +3227(old)X +3360(implementation)X +3893(\()X +2 f +3920(hsearch)X +1 f +2418 1800(or)N +2 f +2528(ndbm)X +1 f +2706(,)X +2769(whichever)X +3147(is)X +3243(appropriate\))X +3678(as)X +3787(well)X +3967(as)X +4076(the)X +2418 1888(improvement.)N +2929(The)X +3098(improvement)X +3569(is)X +3666(expressed)X +4027(as)X +4138(a)X +2418 1976(percentage)N +2787(of)X +2874(the)X +2992(old)X +3114(running)X +3383(time:)X +0 f +8 s +2418 2275(%)N +2494(=)X +2570(100)X +2722(*)X +2798 -0.4219(\(old_time)AX +3178(-)X +3254 -0.4219(new_time\))AX +3634(/)X +3710(old_time)X +1 f +10 s +2590 2600(In)N +2700(nearly)X +2944(all)X +3067(cases,)X +3299(the)X +3439(new)X +3615(routines)X +3915(perform)X +2418 2688(better)N +2628(than)X +2793(the)X +2918(old)X +3047(routines)X +3332(\(both)X +2 f +3527(hsearch)X +1 f +3807(and)X +2 f +3949(ndbm)X +1 f +4127(\).)X +2418 2776(Although)N +2755(the)X +3 f +2888(create)X +1 f +3134(tests)X +3311(exhibit)X +3567(superior)X +3864(user)X +4032(time)X +2418 2864(performance,)N +2869(the)X +2991(test)X +3126(time)X +3292(is)X +3369(dominated)X +3731(by)X +3834(the)X +3955(cost)X +4107(of)X +2418 2952(writing)N +2677(the)X +2803(actual)X +3023(\256le)X +3153(to)X +3243(disk.)X +3444(For)X +3583(the)X +3709(large)X +3897(database)X +2418 3040(\(the)N +2564(dictionary\),)X +2957(this)X +3093(completely)X +3470(overwhelmed)X +3927(the)X +4045(sys-)X +2418 3128(tem)N +2570(time.)X +2783(However,)X +3129(for)X +3254(the)X +3383(small)X +3587(data)X +3752(base,)X +3946(we)X +4071(see)X +2418 3216(that)N +2569(differences)X +2958(in)X +3051(both)X +3224(user)X +3389(and)X +3536(system)X +3788(time)X +3960(contri-)X +2418 3304(bute)N +2576(to)X +2658(the)X +2776(superior)X +3059(performance)X +3486(of)X +3573(the)X +3691(new)X +3845(package.)X +2590 3418(The)N +3 f +2764(read)X +1 f +2920(,)X +3 f +2989(verify)X +1 f +3190(,)X +3259(and)X +3 f +3424(sequential)X +1 f +3818(results)X +4075(are)X +2418 3506(deceptive)N +2758(for)X +2883(the)X +3012(small)X +3216(database)X +3524(since)X +3720(the)X +3849(entire)X +4063(test)X +2418 3594(ran)N +2551(in)X +2643(under)X +2856(a)X +2922(second.)X +3215(However,)X +3560(on)X +3669(the)X +3796(larger)X +4013(data-)X +2418 3682(base)N +2590(the)X +3 f +2716(read)X +1 f +2900(and)X +3 f +3044(verify)X +1 f +3273(tests)X +3443(bene\256t)X +3689(from)X +3873(the)X +3999(cach-)X +2418 3770(ing)N +2546(of)X +2639(buckets)X +2910(in)X +2998(the)X +3122(new)X +3282(package)X +3571(to)X +3658(improve)X +3950(perfor-)X +2418 3858(mance)N +2666(by)X +2784(over)X +2965(80%.)X +3169(Since)X +3384(the)X +3519(\256rst)X +3 f +3680(sequential)X +1 f +4063(test)X +2418 3946(does)N +2598(not)X +2733(require)X +2 f +2994(ndbm)X +1 f +3205(to)X +3299(return)X +3523(the)X +3653(data)X +3819(values,)X +4076(the)X +2418 4034(user)N +2573(time)X +2735(is)X +2808(lower)X +3011(than)X +3169(for)X +3283(the)X +3401(new)X +3555(package.)X +3879(However)X +2418 4122(when)N +2613(we)X +2728(require)X +2977(both)X +3139(packages)X +3454(to)X +3536(return)X +3748(data,)X +3922(the)X +4040(new)X +2418 4210(package)N +2702(excels)X +2923(in)X +3005(all)X +3105(three)X +3286(timings.)X +2590 4324(The)N +2773(small)X +3003(database)X +3337(runs)X +3532(so)X +3660(quickly)X +3957(in)X +4076(the)X +2418 4412(memory-resident)N +3000(case)X +3173(that)X +3326(the)X +3457(results)X +3699(are)X +3831(uninterest-)X +2418 4500(ing.)N +2589(However,)X +2933(for)X +3056(the)X +3183(larger)X +3400(database)X +3706(the)X +3833(new)X +3995(pack-)X +2418 4588(age)N +2567(pays)X +2751(a)X +2824(small)X +3033(penalty)X +3305(in)X +3403(system)X +3661(time)X +3839(because)X +4130(it)X +2418 4676(limits)N +2636(its)X +2748(main)X +2944(memory)X +3247(utilization)X +3607(and)X +3759(swaps)X +3991(pages)X +2418 4764(out)N +2550(to)X +2642(temporary)X +3002(storage)X +3264(in)X +3356(the)X +3484(\256le)X +3616(system)X +3868(while)X +4076(the)X +2 f +2418 4852(hsearch)N +1 f +2698(package)X +2988(requires)X +3273(that)X +3419(the)X +3543(application)X +3924(allocate)X +2418 4940(enough)N +2692(space)X +2909(for)X +3041(all)X +3159(key/data)X +3468(pair.)X +3670(However,)X +4022(even)X +2418 5028(with)N +2600(the)X +2738(system)X +3000(time)X +3182(penalty,)X +3477(the)X +3614(resulting)X +3933(elapsed)X +2418 5116(time)N +2580(improves)X +2898(by)X +2998(over)X +3161(50%.)X +3 f +432 5960(10)N +2970(USENIX)X +9 f +3292(-)X +3 f +3356(Winter)X +3621('91)X +9 f +3748(-)X +3 f +3812(Dallas,)X +4065(TX)X + +11 p +%%Page: 11 11 +0(Courier)xf 0 f +10 s 10 xH 0 xS 0 f +3 f +720 258(Seltzer)N +977(&)X +1064(Yigit)X +3278(A)X +3356(New)X +3528(Hashing)X +3831(Package)X +4136(for)X +4259(UNIX)X +1 f +10 f +908 454(i)N +927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +2 f +1379 546(hash)N +1652(ndbm)X +1950(%change)X +1 f +10 f +908 550(i)N +927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +1 f +948 642(CREATE)N +10 f +908 646(i)N +927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +1 f +1125 738(user)N +1424(6.4)X +1671(12.2)X +2073(48)X +1157 826(sys)N +1384(32.5)X +1671(34.7)X +2113(6)X +3 f +1006 914(elapsed)N +10 f +1310 922(c)N +890(c)Y +810(c)Y +730(c)Y +3 f +1384 914(90.4)N +10 f +1581 922(c)N +890(c)Y +810(c)Y +730(c)Y +3 f +1671 914(99.6)N +10 f +1883 922(c)N +890(c)Y +810(c)Y +730(c)Y +3 f +2113 914(9)N +1 f +10 f +908 910(i)N +927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +908 926(i)N +927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +1 f +948 1010(READ)N +10 f +908 1014(i)N +927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +1 f +1125 1106(user)N +1424(3.4)X +1711(6.1)X +2073(44)X +1157 1194(sys)N +1424(1.2)X +1671(15.3)X +2073(92)X +3 f +1006 1282(elapsed)N +10 f +1310 1290(c)N +1258(c)Y +1178(c)Y +1098(c)Y +3 f +1424 1282(4.0)N +10 f +1581 1290(c)N +1258(c)Y +1178(c)Y +1098(c)Y +3 f +1671 1282(21.2)N +10 f +1883 1290(c)N +1258(c)Y +1178(c)Y +1098(c)Y +3 f +2073 1282(81)N +1 f +10 f +908 1278(i)N +927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +908 1294(i)N +927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +1 f +948 1378(VERIFY)N +10 f +908 1382(i)N +927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +1 f +1125 1474(user)N +1424(3.5)X +1711(6.3)X +2073(44)X +1157 1562(sys)N +1424(1.2)X +1671(15.3)X +2073(92)X +3 f +1006 1650(elapsed)N +10 f +1310 1658(c)N +1626(c)Y +1546(c)Y +1466(c)Y +3 f +1424 1650(4.0)N +10 f +1581 1658(c)N +1626(c)Y +1546(c)Y +1466(c)Y +3 f +1671 1650(21.2)N +10 f +1883 1658(c)N +1626(c)Y +1546(c)Y +1466(c)Y +3 f +2073 1650(81)N +1 f +10 f +908 1646(i)N +927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +908 1662(i)N +927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +1 f +948 1746(SEQUENTIAL)N +10 f +908 1750(i)N +927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +1 f +1125 1842(user)N +1424(2.7)X +1711(1.9)X +2046(-42)X +1157 1930(sys)N +1424(0.7)X +1711(3.9)X +2073(82)X +3 f +1006 2018(elapsed)N +10 f +1310 2026(c)N +1994(c)Y +1914(c)Y +1834(c)Y +3 f +1424 2018(3.0)N +10 f +1581 2026(c)N +1994(c)Y +1914(c)Y +1834(c)Y +3 f +1711 2018(5.0)N +10 f +1883 2026(c)N +1994(c)Y +1914(c)Y +1834(c)Y +3 f +2073 2018(40)N +1 f +10 f +908 2014(i)N +927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +908 2030(i)N +927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +1 f +948 2114(SEQUENTIAL)N +1467(\(with)X +1656(data)X +1810(retrieval\))X +10 f +908 2118(i)N +927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +1 f +1125 2210(user)N +1424(2.7)X +1711(8.2)X +2073(67)X +1157 2298(sys)N +1424(0.7)X +1711(4.3)X +2073(84)X +3 f +1006 2386(elapsed)N +1424(3.0)X +1671(12.0)X +2073(75)X +1 f +10 f +908 2390(i)N +927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +899 2394(c)N +2378(c)Y +2298(c)Y +2218(c)Y +2138(c)Y +2058(c)Y +1978(c)Y +1898(c)Y +1818(c)Y +1738(c)Y +1658(c)Y +1578(c)Y +1498(c)Y +1418(c)Y +1338(c)Y +1258(c)Y +1178(c)Y +1098(c)Y +1018(c)Y +938(c)Y +858(c)Y +778(c)Y +698(c)Y +618(c)Y +538(c)Y +1310 2394(c)N +2362(c)Y +2282(c)Y +2202(c)Y +1581 2394(c)N +2362(c)Y +2282(c)Y +2202(c)Y +1883 2394(c)N +2362(c)Y +2282(c)Y +2202(c)Y +2278 2394(c)N +2378(c)Y +2298(c)Y +2218(c)Y +2138(c)Y +2058(c)Y +1978(c)Y +1898(c)Y +1818(c)Y +1738(c)Y +1658(c)Y +1578(c)Y +1498(c)Y +1418(c)Y +1338(c)Y +1258(c)Y +1178(c)Y +1098(c)Y +1018(c)Y +938(c)Y +858(c)Y +778(c)Y +698(c)Y +618(c)Y +538(c)Y +905 2574(i)N +930(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +2 f +1318 2666(hash)N +1585(hsearch)X +1953(%change)X +1 f +10 f +905 2670(i)N +930(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +1 f +945 2762(CREATE/READ)N +10 f +905 2766(i)N +930(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +1 f +1064 2858(user)N +1343(6.6)X +1642(17.2)X +2096(62)X +1096 2946(sys)N +1343(1.1)X +1682(0.3)X +2029(-266)X +3 f +945 3034(elapsed)N +1343(7.8)X +1642(17.0)X +2096(54)X +1 f +10 f +905 3038(i)N +930(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +896 3050(c)N +2978(c)Y +2898(c)Y +2818(c)Y +2738(c)Y +2658(c)Y +1249 3034(c)N +3010(c)Y +2930(c)Y +2850(c)Y +1520 3034(c)N +3010(c)Y +2930(c)Y +2850(c)Y +1886 3034(c)N +3010(c)Y +2930(c)Y +2850(c)Y +2281 3050(c)N +2978(c)Y +2898(c)Y +2818(c)Y +2738(c)Y +2658(c)Y +3 f +720 3174(Figure)N +967(8a:)X +1 f +1094(Timing)X +1349(results)X +1578(for)X +1692(the)X +1810(dictionary)X +2155(database.)X +10 f +720 3262 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN +3 f +1407 3504(Conclusion)N +1 f +892 3636(This)N +1063(paper)X +1271(has)X +1407(presented)X +1744(the)X +1871(design,)X +2129(implemen-)X +720 3724(tation)N +928(and)X +1070(performance)X +1503(of)X +1596(a)X +1658(new)X +1818(hashing)X +2093(package)X +2382(for)X +720 3812(UNIX.)N +993(The)X +1150(new)X +1316(package)X +1612(provides)X +1919(a)X +1986(superset)X +2280(of)X +2378(the)X +720 3900(functionality)N +1159(of)X +1255(existing)X +1537(hashing)X +1815(packages)X +2139(and)X +2284(incor-)X +720 3988(porates)N +975(additional)X +1318(features)X +1596(such)X +1766(as)X +1855(large)X +2038(key)X +2176(handling,)X +720 4076(user)N +876(de\256ned)X +1134(hash)X +1302(functions,)X +1641(multiple)X +1928(hash)X +2096(tables,)X +2324(vari-)X +720 4164(able)N +894(sized)X +1099(pages,)X +1342(and)X +1498(linear)X +1721(hashing.)X +2050(In)X +2156(nearly)X +2396(all)X +720 4252(cases,)N +954(the)X +1096(new)X +1274(package)X +1582(provides)X +1902(improved)X +2252(perfor-)X +720 4340(mance)N +974(on)X +1098(the)X +1240(order)X +1454(of)X +1565(50-80%)X +1863(for)X +2001(the)X +2142(workloads)X +720 4428(shown.)N +990(Applications)X +1420(such)X +1588(as)X +1676(the)X +1794(loader,)X +2035(compiler,)X +2360(and)X +720 4516(mail,)N +921(which)X +1156(currently)X +1485(implement)X +1866(their)X +2051(own)X +2227(hashing)X +720 4604(routines,)N +1032(should)X +1279(be)X +1389(modi\256ed)X +1706(to)X +1801(use)X +1941(the)X +2072(generic)X +2342(rou-)X +720 4692(tines.)N +892 4806(This)N +1087(hashing)X +1389(package)X +1705(is)X +1810(one)X +1978(access)X +2236(method)X +720 4894(which)N +953(is)X +1043(part)X +1205(of)X +1309(a)X +1382(generic)X +1656(database)X +1970(access)X +2212(package)X +720 4982(being)N +955(developed)X +1342(at)X +1457(the)X +1612(University)X +2007(of)X +2131(California,)X +720 5070(Berkeley.)N +1089(It)X +1177(will)X +1340(include)X +1614(a)X +1688(btree)X +1887(access)X +2131(method)X +2409(as)X +720 5158(well)N +916(as)X +1041(\256xed)X +1259(and)X +1433(variable)X +1750(length)X +2007(record)X +2270(access)X +720 5246(methods)N +1024(in)X +1119(addition)X +1414(to)X +1509(the)X +1640(hashed)X +1896(support)X +2168(presented)X +720 5334(here.)N +948(All)X +1099(of)X +1215(the)X +1361(access)X +1615(methods)X +1934(are)X +2081(based)X +2312(on)X +2440(a)X +720 5422(key/data)N +1037(pair)X +1207(interface)X +1533(and)X +1693(appear)X +1952(identical)X +2272(to)X +2378(the)X +720 5510(application)N +1121(layer,)X +1347(allowing)X +1671(application)X +2071(implementa-)X +720 5598(tions)N +906(to)X +999(be)X +1106(largely)X +1360(independent)X +1783(of)X +1881(the)X +2010(database)X +2318(type.)X +720 5686(The)N +873(package)X +1165(is)X +1246(expected)X +1560(to)X +1650(be)X +1754(an)X +1858(integral)X +2131(part)X +2284(of)X +2378(the)X +2706 538(4.4BSD)N +3006(system,)X +3293(with)X +3479(various)X +3759(standard)X +4075(applications)X +2706 626(such)N +2879(as)X +2972(more\(1\),)X +3277(sort\(1\))X +3517(and)X +3659(vi\(1\))X +3841(based)X +4050(on)X +4156(it.)X +4266(While)X +2706 714(the)N +2833(current)X +3089(design)X +3326(does)X +3501(not)X +3631(support)X +3899(multi-user)X +4256(access)X +2706 802(or)N +2804(transactions,)X +3238(they)X +3407(could)X +3616(be)X +3723(incorporated)X +4159(relatively)X +2706 890(easily.)N +10 f +2894 938(i)N +2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +2 f +3365 1030(hash)N +3638(ndbm)X +3936(%change)X +1 f +10 f +2894 1034(i)N +2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +1 f +2934 1126(CREATE)N +10 f +2894 1130(i)N +2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +1 f +3111 1222(user)N +3390(0.2)X +3677(0.4)X +4079(50)X +3143 1310(sys)N +3390(0.1)X +3677(1.0)X +4079(90)X +3 f +2992 1398(elapsed)N +10 f +3296 1406(c)N +1374(c)Y +1294(c)Y +1214(c)Y +3 f +3390 1398(0)N +10 f +3567 1406(c)N +1374(c)Y +1294(c)Y +1214(c)Y +3 f +3677 1398(3.2)N +10 f +3869 1406(c)N +1374(c)Y +1294(c)Y +1214(c)Y +3 f +4039 1398(100)N +1 f +10 f +2894 1394(i)N +2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +2894 1410(i)N +2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +1 f +2934 1494(READ)N +10 f +2894 1498(i)N +2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +1 f +3111 1590(user)N +3390(0.1)X +3677(0.1)X +4119(0)X +3143 1678(sys)N +3390(0.1)X +3677(0.4)X +4079(75)X +3 f +2992 1766(elapsed)N +10 f +3296 1774(c)N +1742(c)Y +1662(c)Y +1582(c)Y +3 f +3390 1766(0.0)N +10 f +3567 1774(c)N +1742(c)Y +1662(c)Y +1582(c)Y +3 f +3677 1766(0.0)N +10 f +3869 1774(c)N +1742(c)Y +1662(c)Y +1582(c)Y +3 f +4119 1766(0)N +1 f +10 f +2894 1762(i)N +2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +2894 1778(i)N +2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +1 f +2934 1862(VERIFY)N +10 f +2894 1866(i)N +2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +1 f +3111 1958(user)N +3390(0.1)X +3677(0.2)X +4079(50)X +3143 2046(sys)N +3390(0.1)X +3677(0.3)X +4079(67)X +3 f +2992 2134(elapsed)N +10 f +3296 2142(c)N +2110(c)Y +2030(c)Y +1950(c)Y +3 f +3390 2134(0.0)N +10 f +3567 2142(c)N +2110(c)Y +2030(c)Y +1950(c)Y +3 f +3677 2134(0.0)N +10 f +3869 2142(c)N +2110(c)Y +2030(c)Y +1950(c)Y +3 f +4119 2134(0)N +1 f +10 f +2894 2130(i)N +2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +2894 2146(i)N +2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +1 f +2934 2230(SEQUENTIAL)N +10 f +2894 2234(i)N +2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +1 f +3111 2326(user)N +3390(0.1)X +3677(0.0)X +4012(-100)X +3143 2414(sys)N +3390(0.1)X +3677(0.1)X +4119(0)X +3 f +2992 2502(elapsed)N +10 f +3296 2510(c)N +2478(c)Y +2398(c)Y +2318(c)Y +3 f +3390 2502(0.0)N +10 f +3567 2510(c)N +2478(c)Y +2398(c)Y +2318(c)Y +3 f +3677 2502(0.0)N +10 f +3869 2510(c)N +2478(c)Y +2398(c)Y +2318(c)Y +3 f +4119 2502(0)N +1 f +10 f +2894 2498(i)N +2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +2894 2514(i)N +2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +1 f +2934 2598(SEQUENTIAL)N +3453(\(with)X +3642(data)X +3796(retrieval\))X +10 f +2894 2602(i)N +2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +1 f +3111 2694(user)N +3390(0.1)X +3677(0.1)X +4119(0)X +3143 2782(sys)N +3390(0.1)X +3677(0.1)X +4119(0)X +3 f +2992 2870(elapsed)N +3390(0.0)X +3677(0.0)X +4119(0)X +1 f +10 f +2894 2874(i)N +2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +2885 2878(c)N +2862(c)Y +2782(c)Y +2702(c)Y +2622(c)Y +2542(c)Y +2462(c)Y +2382(c)Y +2302(c)Y +2222(c)Y +2142(c)Y +2062(c)Y +1982(c)Y +1902(c)Y +1822(c)Y +1742(c)Y +1662(c)Y +1582(c)Y +1502(c)Y +1422(c)Y +1342(c)Y +1262(c)Y +1182(c)Y +1102(c)Y +1022(c)Y +3296 2878(c)N +2846(c)Y +2766(c)Y +2686(c)Y +3567 2878(c)N +2846(c)Y +2766(c)Y +2686(c)Y +3869 2878(c)N +2846(c)Y +2766(c)Y +2686(c)Y +4264 2878(c)N +2862(c)Y +2782(c)Y +2702(c)Y +2622(c)Y +2542(c)Y +2462(c)Y +2382(c)Y +2302(c)Y +2222(c)Y +2142(c)Y +2062(c)Y +1982(c)Y +1902(c)Y +1822(c)Y +1742(c)Y +1662(c)Y +1582(c)Y +1502(c)Y +1422(c)Y +1342(c)Y +1262(c)Y +1182(c)Y +1102(c)Y +1022(c)Y +2891 3058(i)N +2916(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +2 f +3304 3150(hash)N +3571(hsearch)X +3939(%change)X +1 f +10 f +2891 3154(i)N +2916(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +1 f +2931 3246(CREATE/READ)N +10 f +2891 3250(i)N +2916(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +1 f +3050 3342(user)N +3329(0.3)X +3648(0.4)X +4048(25)X +3082 3430(sys)N +3329(0.0)X +3648(0.0)X +4088(0)X +3 f +2931 3518(elapsed)N +3329(0.0)X +3648(0.0)X +4088(0)X +1 f +10 f +2891 3522(i)N +2916(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +2882 3534(c)N +3462(c)Y +3382(c)Y +3302(c)Y +3222(c)Y +3142(c)Y +3235 3518(c)N +3494(c)Y +3414(c)Y +3334(c)Y +3506 3518(c)N +3494(c)Y +3414(c)Y +3334(c)Y +3872 3518(c)N +3494(c)Y +3414(c)Y +3334(c)Y +4267 3534(c)N +3462(c)Y +3382(c)Y +3302(c)Y +3222(c)Y +3142(c)Y +3 f +2706 3658(Figure)N +2953(8b:)X +1 f +3084(Timing)X +3339(results)X +3568(for)X +3682(the)X +3800(password)X +4123(database.)X +10 f +2706 3746 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN +3 f +3396 3988(References)N +1 f +2706 4120([ATT79])N +3058(AT&T,)X +3358(DBM\(3X\),)X +2 f +3773(Unix)X +3990(Programmer's)X +2878 4208(Manual,)N +3194(Seventh)X +3491(Edition,)X +3793(Volume)X +4085(1)X +1 f +(,)S +4192(January,)X +2878 4296(1979.)N +2706 4472([ATT85])N +3027(AT&T,)X +3296(HSEARCH\(BA_LIB\),)X +2 f +4053(Unix)X +4239(System)X +2878 4560(User's)N +3112(Manual,)X +3401(System)X +3644(V.3)X +1 f +3753(,)X +3793(pp.)X +3913(506-508,)X +4220(1985.)X +2706 4736([BRE73])N +3025(Brent,)X +3253(Richard)X +3537(P.,)X +3651(``Reducing)X +4041(the)X +4168(Retrieval)X +2878 4824(Time)N +3071(of)X +3162(Scatter)X +3409(Storage)X +3678(Techniques'',)X +2 f +4146(Commun-)X +2878 4912(ications)N +3175(of)X +3281(the)X +3422(ACM)X +1 f +3591(,)X +3654(Volume)X +3955(16,)X +4098(No.)X +4259(2,)X +4362(pp.)X +2878 5000(105-109,)N +3185(February,)X +3515(1973.)X +2706 5176([BSD86])N +3055(NDBM\(3\),)X +2 f +3469(4.3BSD)X +3775(Unix)X +3990(Programmer's)X +2878 5264(Manual)N +3155(Reference)X +3505(Guide)X +1 f +3701(,)X +3749(University)X +4114(of)X +4208(Califor-)X +2878 5352(nia,)N +3016(Berkeley,)X +3346(1986.)X +2706 5528([ENB88])N +3025(Enbody,)X +3319(R.)X +3417(J.,)X +3533(Du,)X +3676(H.)X +3779(C.,)X +3897(``Dynamic)X +4270(Hash-)X +2878 5616(ing)N +3034(Schemes'',)X +2 f +3427(ACM)X +3630(Computing)X +4019(Surveys)X +1 f +4269(,)X +4322(Vol.)X +2878 5704(20,)N +2998(No.)X +3136(2,)X +3216(pp.)X +3336(85-113,)X +3603(June)X +3770(1988.)X +3 f +720 5960(USENIX)N +9 f +1042(-)X +3 f +1106(Winter)X +1371('91)X +9 f +1498(-)X +3 f +1562(Dallas,)X +1815(TX)X +4384(11)X + +12 p +%%Page: 12 12 +0(Courier)xf 0 f +10 s 10 xH 0 xS 0 f +3 f +432 258(A)N +510(New)X +682(Hashing)X +985(Package)X +1290(for)X +1413(UNIX)X +3663(Seltzer)X +3920(&)X +4007(Yigit)X +1 f +432 538([FAG79])N +776(Ronald)X +1057(Fagin,)X +1308(Jurg)X +1495(Nievergelt,)X +1903(Nicholas)X +604 626(Pippenger,)N +1003(H.)X +1135(Raymond)X +1500(Strong,)X +1787(``Extendible)X +604 714(Hashing)N +901(--)X +985(A)X +1073(Fast)X +1236(Access)X +1493(Method)X +1771(for)X +1894(Dynamic)X +604 802(Files'',)N +2 f +855(ACM)X +1046(Transactions)X +1485(on)X +1586(Database)X +1914(Systems)X +1 f +2168(,)X +604 890(Volume)N +882(4,)X +962(No.)X +1100(3.,)X +1200(September)X +1563(1979,)X +1763(pp)X +1863(315-34)X +432 1066([KNU68],)N +802(Knuth,)X +1064(D.E.,)X +2 f +1273(The)X +1434(Art)X +1577(of)X +1680(Computer)X +2041(Pro-)X +604 1154(gramming)N +971(Vol.)X +1140(3:)X +1245(Sorting)X +1518(and)X +1676(Searching)X +1 f +2001(,)X +2058(sec-)X +604 1242(tions)N +779(6.3-6.4,)X +1046(pp)X +1146(481-550.)X +432 1418([LAR78])N +747(Larson,)X +1011(Per-Ake,)X +1319(``Dynamic)X +1687(Hashing'',)X +2 f +2048(BIT)X +1 f +(,)S +604 1506(Vol.)N +764(18,)X +884(1978,)X +1084(pp.)X +1204(184-201.)X +432 1682([LAR88])N +752(Larson,)X +1021(Per-Ake,)X +1335(``Dynamic)X +1709(Hash)X +1900(Tables'',)X +2 f +604 1770(Communications)N +1183(of)X +1281(the)X +1415(ACM)X +1 f +1584(,)X +1640(Volume)X +1934(31,)X +2070(No.)X +604 1858(4.,)N +704(April)X +893(1988,)X +1093(pp)X +1193(446-457.)X +432 2034([LIT80])N +731(Witold,)X +1013(Litwin,)X +1286(``Linear)X +1590(Hashing:)X +1939(A)X +2036(New)X +604 2122(Tool)N +786(for)X +911(File)X +1065(and)X +1211(Table)X +1424(Addressing'',)X +2 f +1893(Proceed-)X +604 2210(ings)N +761(of)X +847(the)X +969(6th)X +1095(International)X +1540(Conference)X +1933(on)X +2036(Very)X +604 2298(Large)N +815(Databases)X +1 f +1153(,)X +1193(1980.)X +432 2474([NEL90])N +743(Nelson,)X +1011(Philip)X +1222(A.,)X +2 f +1341(Gdbm)X +1558(1.4)X +1679(source)X +1913(distribu-)X +604 2562(tion)N +748(and)X +888(README)X +1 f +1209(,)X +1249(August)X +1500(1990.)X +432 2738([THOM90])N +840(Ken)X +1011(Thompson,)X +1410(private)X +1670(communication,)X +604 2826(Nov.)N +782(1990.)X +432 3002([TOR87])N +790(Torek,)X +1066(C.,)X +1222(``Re:)X +1470(dbm.a)X +1751(and)X +1950(ndbm.a)X +604 3090(archives'',)N +2 f +966(USENET)X +1279(newsgroup)X +1650(comp.unix)X +1 f +2002(1987.)X +432 3266([TOR88])N +760(Torek,)X +1006(C.,)X +1133(``Re:)X +1351(questions)X +1686(regarding)X +2027(data-)X +604 3354(bases)N +826(created)X +1106(with)X +1295(dbm)X +1484(and)X +1647(ndbm)X +1876(routines'')X +2 f +604 3442(USENET)N +937(newsgroup)X +1328(comp.unix.questions)X +1 f +1982(,)X +2041(June)X +604 3530(1988.)N +432 3706([WAL84])N +773(Wales,)X +1018(R.,)X +1135(``Discussion)X +1564(of)X +1655("dbm")X +1887(data)X +2045(base)X +604 3794(system'',)N +2 f +973(USENET)X +1339(newsgroup)X +1762(unix.wizards)X +1 f +2168(,)X +604 3882(January,)N +894(1984.)X +432 4058([YIG89])N +751(Ozan)X +963(S.)X +1069(Yigit,)X +1294(``How)X +1545(to)X +1648(Roll)X +1826(Your)X +2032(Own)X +604 4146(Dbm/Ndbm'',)N +2 f +1087(unpublished)X +1504(manuscript)X +1 f +(,)S +1910(Toronto,)X +604 4234(July,)N +777(1989)X +3 f +432 5960(12)N +2970(USENIX)X +9 f +3292(-)X +3 f +3356(Winter)X +3621('91)X +9 f +3748(-)X +3 f +3812(Dallas,)X +4065(TX)X + +13 p +%%Page: 13 13 +0(Courier)xf 0 f +10 s 10 xH 0 xS 0 f +3 f +720 258(Seltzer)N +977(&)X +1064(Yigit)X +3278(A)X +3356(New)X +3528(Hashing)X +3831(Package)X +4136(for)X +4259(UNIX)X +1 f +720 538(Margo)N +960(I.)X +1033(Seltzer)X +1282(is)X +1361(a)X +1423(Ph.D.)X +1631(student)X +1887(in)X +1974(the)X +2097(Department)X +720 626(of)N +823(Electrical)X +1167(Engineering)X +1595(and)X +1747(Computer)X +2102(Sciences)X +2418(at)X +720 714(the)N +850(University)X +1220(of)X +1318(California,)X +1694(Berkeley.)X +2055(Her)X +2207(research)X +720 802(interests)N +1017(include)X +1283(\256le)X +1415(systems,)X +1718(databases,)X +2076(and)X +2221(transac-)X +720 890(tion)N +896(processing)X +1291(systems.)X +1636(She)X +1807(spent)X +2027(several)X +2306(years)X +720 978(working)N +1026(at)X +1123(startup)X +1380(companies)X +1762(designing)X +2112(and)X +2267(imple-)X +720 1066(menting)N +1048(\256le)X +1216(systems)X +1535(and)X +1716(transaction)X +2133(processing)X +720 1154(software)N +1026(and)X +1170(designing)X +1509(microprocessors.)X +2103(Ms.)X +2253(Seltzer)X +720 1242(received)N +1057(her)X +1223(AB)X +1397(in)X +1522(Applied)X +1843(Mathematics)X +2320(from)X +720 1330 0.1953(Harvard/Radcliffe)AN +1325(College)X +1594(in)X +1676(1983.)X +720 1444(In)N +810(her)X +936(spare)X +1129(time,)X +1313(Margo)X +1549(can)X +1683(usually)X +1936(be)X +2034(found)X +2243(prepar-)X +720 1532(ing)N +868(massive)X +1171(quantities)X +1527(of)X +1639(food)X +1831(for)X +1970(hungry)X +2242(hoards,)X +720 1620(studying)N +1022(Japanese,)X +1355(or)X +1449(playing)X +1716(soccer)X +1948(with)X +2116(an)X +2218(exciting)X +720 1708(Bay)N +912(Area)X +1132(Women's)X +1507(Soccer)X +1788(team,)X +2026(the)X +2186(Berkeley)X +720 1796(Bruisers.)N +720 1910(Ozan)N +915(\()X +3 f +942(Oz)X +1 f +1040(\))X +1092(Yigit)X +1281(is)X +1358(currently)X +1672(a)X +1732(software)X +2033(engineer)X +2334(with)X +720 1998(the)N +886(Communications)X +1499(Research)X +1861(and)X +2044(Development)X +720 2086(group,)N +948(Computing)X +1328(Services,)X +1641(York)X +1826(University.)X +2224(His)X +2355(for-)X +720 2174(mative)N +967(years)X +1166(were)X +1352(also)X +1510(spent)X +1708(at)X +1795(York,)X +2009(where)X +2234(he)X +2338(held)X +720 2262(system)N +985(programmer)X +1425(and)X +1583(administrator)X +2052(positions)X +2382(for)X +720 2350(various)N +995(mixtures)X +1314(of)X +1420(of)X +1526(UNIX)X +1765(systems)X +2056(starting)X +2334(with)X +720 2438(Berkeley)N +1031(4.1)X +1151(in)X +1233(1982,)X +1433(while)X +1631(at)X +1709(the)X +1827(same)X +2012(time)X +2174(obtaining)X +720 2526(a)N +776(degree)X +1011(in)X +1093(Computer)X +1433(Science.)X +720 2640(In)N +813(his)X +931(copious)X +1205(free)X +1356(time,)X +1543(Oz)X +1662(enjoys)X +1896(working)X +2188(on)X +2293(what-)X +720 2728(ever)N +890(software)X +1197(looks)X +1400(interesting,)X +1788(which)X +2014(often)X +2209(includes)X +720 2816(language)N +1044(interpreters,)X +1464(preprocessors,)X +1960(and)X +2110(lately,)X +2342(pro-)X +720 2904(gram)N +905(generators)X +1260(and)X +1396(expert)X +1617(systems.)X +720 3018(Oz)N +836(has)X +964(authored)X +1266(several)X +1515(public-domain)X +2003(software)X +2301(tools,)X +720 3106(including)N +1069(an)X +1191(nroff-like)X +1545(text)X +1711(formatter)X +2 f +2056(proff)X +1 f +2257(that)X +2423(is)X +720 3194(apparently)N +1083(still)X +1226(used)X +1397(in)X +1483(some)X +1676(basement)X +2002(PCs.)X +2173(His)X +2307(latest)X +720 3282(obsessions)N +1143(include)X +1460(the)X +1639(incredible)X +2040(programming)X +720 3370(language)N +1030(Scheme,)X +1324(and)X +1460(Chinese)X +1738(Brush)X +1949(painting.)X +3 f +720 5960(USENIX)N +9 f +1042(-)X +3 f +1106(Winter)X +1371('91)X +9 f +1498(-)X +3 f +1562(Dallas,)X +1815(TX)X +4384(13)X + +14 p +%%Page: 14 14 +0(Courier)xf 0 f +10 s 10 xH 0 xS 0 f +3 f +432 5960(14)N +2970(USENIX)X +9 f +3292(-)X +3 f +3356(Winter)X +3621('91)X +9 f +3748(-)X +3 f +3812(Dallas,)X +4065(TX)X + +14 p +%%Trailer +xt + +xs diff --git a/db/docs/ref/refs/libtp_usenix.ps b/db/docs/ref/refs/libtp_usenix.ps new file mode 100644 index 000000000..ea821a914 --- /dev/null +++ b/db/docs/ref/refs/libtp_usenix.ps @@ -0,0 +1,12340 @@ +%!PS-Adobe-1.0 +%%Creator: utopia:margo (& Seltzer,608-13E,8072,) +%%Title: stdin (ditroff) +%%CreationDate: Thu Dec 12 15:32:11 1991 +%%EndComments +% @(#)psdit.pro 1.3 4/15/88 +% lib/psdit.pro -- prolog for psdit (ditroff) files +% Copyright (c) 1984, 1985 Adobe Systems Incorporated. All Rights Reserved. +% last edit: shore Sat Nov 23 20:28:03 1985 +% RCSID: $Header: psdit.pro,v 2.1 85/11/24 12:19:43 shore Rel $ + +% Changed by Edward Wang (edward@ucbarpa.berkeley.edu) to handle graphics, +% 17 Feb, 87. + +/$DITroff 140 dict def $DITroff begin +/fontnum 1 def /fontsize 10 def /fontheight 10 def /fontslant 0 def +/xi{0 72 11 mul translate 72 resolution div dup neg scale 0 0 moveto + /fontnum 1 def /fontsize 10 def /fontheight 10 def /fontslant 0 def F + /pagesave save def}def +/PB{save /psv exch def currentpoint translate + resolution 72 div dup neg scale 0 0 moveto}def +/PE{psv restore}def +/arctoobig 90 def /arctoosmall .05 def +/m1 matrix def /m2 matrix def /m3 matrix def /oldmat matrix def +/tan{dup sin exch cos div}def +/point{resolution 72 div mul}def +/dround {transform round exch round exch itransform}def +/xT{/devname exch def}def +/xr{/mh exch def /my exch def /resolution exch def}def +/xp{}def +/xs{docsave restore end}def +/xt{}def +/xf{/fontname exch def /slotno exch def fontnames slotno get fontname eq not + {fonts slotno fontname findfont put fontnames slotno fontname put}if}def +/xH{/fontheight exch def F}def +/xS{/fontslant exch def F}def +/s{/fontsize exch def /fontheight fontsize def F}def +/f{/fontnum exch def F}def +/F{fontheight 0 le{/fontheight fontsize def}if + fonts fontnum get fontsize point 0 0 fontheight point neg 0 0 m1 astore + fontslant 0 ne{1 0 fontslant tan 1 0 0 m2 astore m3 concatmatrix}if + makefont setfont .04 fontsize point mul 0 dround pop setlinewidth}def +/X{exch currentpoint exch pop moveto show}def +/N{3 1 roll moveto show}def +/Y{exch currentpoint pop exch moveto show}def +/S{show}def +/ditpush{}def/ditpop{}def +/AX{3 -1 roll currentpoint exch pop moveto 0 exch ashow}def +/AN{4 2 roll moveto 0 exch ashow}def +/AY{3 -1 roll currentpoint pop exch moveto 0 exch ashow}def +/AS{0 exch ashow}def +/MX{currentpoint exch pop moveto}def +/MY{currentpoint pop exch moveto}def +/MXY{moveto}def +/cb{pop}def % action on unknown char -- nothing for now +/n{}def/w{}def +/p{pop showpage pagesave restore /pagesave save def}def +/Dt{/Dlinewidth exch def}def 1 Dt +/Ds{/Ddash exch def}def -1 Ds +/Di{/Dstipple exch def}def 1 Di +/Dsetlinewidth{2 Dlinewidth mul setlinewidth}def +/Dsetdash{Ddash 4 eq{[8 12]}{Ddash 16 eq{[32 36]} + {Ddash 20 eq{[32 12 8 12]}{[]}ifelse}ifelse}ifelse 0 setdash}def +/Dstroke{gsave Dsetlinewidth Dsetdash 1 setlinecap stroke grestore + currentpoint newpath moveto}def +/Dl{rlineto Dstroke}def +/arcellipse{/diamv exch def /diamh exch def oldmat currentmatrix pop + currentpoint translate 1 diamv diamh div scale /rad diamh 2 div def + currentpoint exch rad add exch rad -180 180 arc oldmat setmatrix}def +/Dc{dup arcellipse Dstroke}def +/De{arcellipse Dstroke}def +/Da{/endv exch def /endh exch def /centerv exch def /centerh exch def + /cradius centerv centerv mul centerh centerh mul add sqrt def + /eradius endv endv mul endh endh mul add sqrt def + /endang endv endh atan def + /startang centerv neg centerh neg atan def + /sweep startang endang sub dup 0 lt{360 add}if def + sweep arctoobig gt + {/midang startang sweep 2 div sub def /midrad cradius eradius add 2 div def + /midh midang cos midrad mul def /midv midang sin midrad mul def + midh neg midv neg endh endv centerh centerv midh midv Da + Da} + {sweep arctoosmall ge + {/controldelt 1 sweep 2 div cos sub 3 sweep 2 div sin mul div 4 mul def + centerv neg controldelt mul centerh controldelt mul + endv neg controldelt mul centerh add endh add + endh controldelt mul centerv add endv add + centerh endh add centerv endv add rcurveto Dstroke} + {centerh endh add centerv endv add rlineto Dstroke} + ifelse} + ifelse}def +/Dpatterns[ +[%cf[widthbits] +[8<0000000000000010>] +[8<0411040040114000>] +[8<0204081020408001>] +[8<0000103810000000>] +[8<6699996666999966>] +[8<0000800100001008>] +[8<81c36666c3810000>] +[8<0f0e0c0800000000>] +[8<0000000000000010>] +[8<0411040040114000>] +[8<0204081020408001>] +[8<0000001038100000>] +[8<6699996666999966>] +[8<0000800100001008>] +[8<81c36666c3810000>] +[8<0f0e0c0800000000>] +[8<0042660000246600>] +[8<0000990000990000>] +[8<0804020180402010>] +[8<2418814242811824>] +[8<6699996666999966>] +[8<8000000008000000>] +[8<00001c3e363e1c00>] +[8<0000000000000000>] +[32<00000040000000c00000004000000040000000e0000000000000000000000000>] +[32<00000000000060000000900000002000000040000000f0000000000000000000>] +[32<000000000000000000e0000000100000006000000010000000e0000000000000>] +[32<00000000000000002000000060000000a0000000f00000002000000000000000>] +[32<0000000e0000000000000000000000000000000f000000080000000e00000001>] +[32<0000090000000600000000000000000000000000000007000000080000000e00>] +[32<00010000000200000004000000040000000000000000000000000000000f0000>] +[32<0900000006000000090000000600000000000000000000000000000006000000>]] +[%ug +[8<0000020000000000>] +[8<0000020000002000>] +[8<0004020000002000>] +[8<0004020000402000>] +[8<0004060000402000>] +[8<0004060000406000>] +[8<0006060000406000>] +[8<0006060000606000>] +[8<00060e0000606000>] +[8<00060e000060e000>] +[8<00070e000060e000>] +[8<00070e000070e000>] +[8<00070e020070e000>] +[8<00070e020070e020>] +[8<04070e020070e020>] +[8<04070e024070e020>] +[8<04070e064070e020>] +[8<04070e064070e060>] +[8<06070e064070e060>] +[8<06070e066070e060>] +[8<06070f066070e060>] +[8<06070f066070f060>] +[8<060f0f066070f060>] +[8<060f0f0660f0f060>] +[8<060f0f0760f0f060>] +[8<060f0f0760f0f070>] +[8<0e0f0f0760f0f070>] +[8<0e0f0f07e0f0f070>] +[8<0e0f0f0fe0f0f070>] +[8<0e0f0f0fe0f0f0f0>] +[8<0f0f0f0fe0f0f0f0>] +[8<0f0f0f0ff0f0f0f0>] +[8<1f0f0f0ff0f0f0f0>] +[8<1f0f0f0ff1f0f0f0>] +[8<1f0f0f8ff1f0f0f0>] +[8<1f0f0f8ff1f0f0f8>] +[8<9f0f0f8ff1f0f0f8>] +[8<9f0f0f8ff9f0f0f8>] +[8<9f0f0f9ff9f0f0f8>] +[8<9f0f0f9ff9f0f0f9>] +[8<9f8f0f9ff9f0f0f9>] +[8<9f8f0f9ff9f8f0f9>] +[8<9f8f1f9ff9f8f0f9>] +[8<9f8f1f9ff9f8f1f9>] +[8] +[8] +[8] +[8] +[8] +[8] +[8] +[8] +[8] +[8] +[8] +[8] +[8] +[8] +[8] +[8] +[8] +[8] +[8] +[8]] +[%mg +[8<8000000000000000>] +[8<0822080080228000>] +[8<0204081020408001>] +[8<40e0400000000000>] +[8<66999966>] +[8<8001000010080000>] +[8<81c36666c3810000>] +[8] +[16<07c00f801f003e007c00f800f001e003c007800f001f003e007c00f801f003e0>] +[16<1f000f8007c003e001f000f8007c003e001f800fc007e003f001f8007c003e00>] +[8] +[16<0040008001000200040008001000200040008000000100020004000800100020>] +[16<0040002000100008000400020001800040002000100008000400020001000080>] +[16<1fc03fe07df0f8f8f07de03fc01f800fc01fe03ff07df8f87df03fe01fc00f80>] +[8<80>] +[8<8040201000000000>] +[8<84cc000048cc0000>] +[8<9900009900000000>] +[8<08040201804020100800020180002010>] +[8<2418814242811824>] +[8<66999966>] +[8<8000000008000000>] +[8<70f8d8f870000000>] +[8<0814224180402010>] +[8] +[8<018245aa45820100>] +[8<221c224180808041>] +[8<88000000>] +[8<0855800080550800>] +[8<2844004482440044>] +[8<0810204080412214>] +[8<00>]]]def +/Dfill{ + transform /maxy exch def /maxx exch def + transform /miny exch def /minx exch def + minx maxx gt{/minx maxx /maxx minx def def}if + miny maxy gt{/miny maxy /maxy miny def def}if + Dpatterns Dstipple 1 sub get exch 1 sub get + aload pop /stip exch def /stipw exch def /stiph 128 def + /imatrix[stipw 0 0 stiph 0 0]def + /tmatrix[stipw 0 0 stiph 0 0]def + /minx minx cvi stiph idiv stiph mul def + /miny miny cvi stipw idiv stipw mul def + gsave eoclip 0 setgray + miny stiph maxy{ + tmatrix exch 5 exch put + minx stipw maxx{ + tmatrix exch 4 exch put tmatrix setmatrix + stipw stiph true imatrix {stip} imagemask + }for + }for + grestore +}def +/Dp{Dfill Dstroke}def +/DP{Dfill currentpoint newpath moveto}def +end + +/ditstart{$DITroff begin + /nfonts 60 def % NFONTS makedev/ditroff dependent! + /fonts[nfonts{0}repeat]def + /fontnames[nfonts{()}repeat]def +/docsave save def +}def + +% character outcalls +/oc{ + /pswid exch def /cc exch def /name exch def + /ditwid pswid fontsize mul resolution mul 72000 div def + /ditsiz fontsize resolution mul 72 div def + ocprocs name known{ocprocs name get exec}{name cb}ifelse +}def +/fractm [.65 0 0 .6 0 0] def +/fraction{ + /fden exch def /fnum exch def gsave /cf currentfont def + cf fractm makefont setfont 0 .3 dm 2 copy neg rmoveto + fnum show rmoveto currentfont cf setfont(\244)show setfont fden show + grestore ditwid 0 rmoveto +}def +/oce{grestore ditwid 0 rmoveto}def +/dm{ditsiz mul}def +/ocprocs 50 dict def ocprocs begin +(14){(1)(4)fraction}def +(12){(1)(2)fraction}def +(34){(3)(4)fraction}def +(13){(1)(3)fraction}def +(23){(2)(3)fraction}def +(18){(1)(8)fraction}def +(38){(3)(8)fraction}def +(58){(5)(8)fraction}def +(78){(7)(8)fraction}def +(sr){gsave 0 .06 dm rmoveto(\326)show oce}def +(is){gsave 0 .15 dm rmoveto(\362)show oce}def +(->){gsave 0 .02 dm rmoveto(\256)show oce}def +(<-){gsave 0 .02 dm rmoveto(\254)show oce}def +(==){gsave 0 .05 dm rmoveto(\272)show oce}def +(uc){gsave currentpoint 400 .009 dm mul add translate + 8 -8 scale ucseal oce}def +end + +% an attempt at a PostScript FONT to implement ditroff special chars +% this will enable us to +% cache the little buggers +% generate faster, more compact PS out of psdit +% confuse everyone (including myself)! +50 dict dup begin +/FontType 3 def +/FontName /DIThacks def +/FontMatrix [.001 0 0 .001 0 0] def +/FontBBox [-260 -260 900 900] def% a lie but ... +/Encoding 256 array def +0 1 255{Encoding exch /.notdef put}for +Encoding + dup 8#040/space put %space + dup 8#110/rc put %right ceil + dup 8#111/lt put %left top curl + dup 8#112/bv put %bold vert + dup 8#113/lk put %left mid curl + dup 8#114/lb put %left bot curl + dup 8#115/rt put %right top curl + dup 8#116/rk put %right mid curl + dup 8#117/rb put %right bot curl + dup 8#120/rf put %right floor + dup 8#121/lf put %left floor + dup 8#122/lc put %left ceil + dup 8#140/sq put %square + dup 8#141/bx put %box + dup 8#142/ci put %circle + dup 8#143/br put %box rule + dup 8#144/rn put %root extender + dup 8#145/vr put %vertical rule + dup 8#146/ob put %outline bullet + dup 8#147/bu put %bullet + dup 8#150/ru put %rule + dup 8#151/ul put %underline + pop +/DITfd 100 dict def +/BuildChar{0 begin + /cc exch def /fd exch def + /charname fd /Encoding get cc get def + /charwid fd /Metrics get charname get def + /charproc fd /CharProcs get charname get def + charwid 0 fd /FontBBox get aload pop setcachedevice + 2 setlinejoin 40 setlinewidth + newpath 0 0 moveto gsave charproc grestore + end}def +/BuildChar load 0 DITfd put +/CharProcs 50 dict def +CharProcs begin +/space{}def +/.notdef{}def +/ru{500 0 rls}def +/rn{0 840 moveto 500 0 rls}def +/vr{0 800 moveto 0 -770 rls}def +/bv{0 800 moveto 0 -1000 rls}def +/br{0 840 moveto 0 -1000 rls}def +/ul{0 -140 moveto 500 0 rls}def +/ob{200 250 rmoveto currentpoint newpath 200 0 360 arc closepath stroke}def +/bu{200 250 rmoveto currentpoint newpath 200 0 360 arc closepath fill}def +/sq{80 0 rmoveto currentpoint dround newpath moveto + 640 0 rlineto 0 640 rlineto -640 0 rlineto closepath stroke}def +/bx{80 0 rmoveto currentpoint dround newpath moveto + 640 0 rlineto 0 640 rlineto -640 0 rlineto closepath fill}def +/ci{500 360 rmoveto currentpoint newpath 333 0 360 arc + 50 setlinewidth stroke}def + +/lt{0 -200 moveto 0 550 rlineto currx 800 2cx s4 add exch s4 a4p stroke}def +/lb{0 800 moveto 0 -550 rlineto currx -200 2cx s4 add exch s4 a4p stroke}def +/rt{0 -200 moveto 0 550 rlineto currx 800 2cx s4 sub exch s4 a4p stroke}def +/rb{0 800 moveto 0 -500 rlineto currx -200 2cx s4 sub exch s4 a4p stroke}def +/lk{0 800 moveto 0 300 -300 300 s4 arcto pop pop 1000 sub + 0 300 4 2 roll s4 a4p 0 -200 lineto stroke}def +/rk{0 800 moveto 0 300 s2 300 s4 arcto pop pop 1000 sub + 0 300 4 2 roll s4 a4p 0 -200 lineto stroke}def +/lf{0 800 moveto 0 -1000 rlineto s4 0 rls}def +/rf{0 800 moveto 0 -1000 rlineto s4 neg 0 rls}def +/lc{0 -200 moveto 0 1000 rlineto s4 0 rls}def +/rc{0 -200 moveto 0 1000 rlineto s4 neg 0 rls}def +end + +/Metrics 50 dict def Metrics begin +/.notdef 0 def +/space 500 def +/ru 500 def +/br 0 def +/lt 416 def +/lb 416 def +/rt 416 def +/rb 416 def +/lk 416 def +/rk 416 def +/rc 416 def +/lc 416 def +/rf 416 def +/lf 416 def +/bv 416 def +/ob 350 def +/bu 350 def +/ci 750 def +/bx 750 def +/sq 750 def +/rn 500 def +/ul 500 def +/vr 0 def +end + +DITfd begin +/s2 500 def /s4 250 def /s3 333 def +/a4p{arcto pop pop pop pop}def +/2cx{2 copy exch}def +/rls{rlineto stroke}def +/currx{currentpoint pop}def +/dround{transform round exch round exch itransform} def +end +end +/DIThacks exch definefont pop +ditstart +(psc)xT +576 1 1 xr +1(Times-Roman)xf 1 f +2(Times-Italic)xf 2 f +3(Times-Bold)xf 3 f +4(Times-BoldItalic)xf 4 f +5(Helvetica)xf 5 f +6(Helvetica-Bold)xf 6 f +7(Courier)xf 7 f +8(Courier-Bold)xf 8 f +9(Symbol)xf 9 f +10(DIThacks)xf 10 f +10 s +1 f +xi +%%EndProlog + +%%Page: 1 1 +10 s 10 xH 0 xS 1 f +3 f +14 s +1205 1206(LIBTP:)N +1633(Portable,)X +2100(M)X +2206(odular)X +2551(Transactions)X +3202(for)X +3374(UNIX)X +1 f +11 s +3661 1162(1)N +2 f +12 s +2182 1398(Margo)N +2467(Seltzer)X +2171 1494(Michael)N +2511(Olson)X +1800 1590(University)N +2225(of)X +2324(California,)X +2773(Berkeley)X +3 f +2277 1878(Abstract)N +1 f +10 s +755 2001(Transactions)N +1198(provide)X +1475(a)X +1543(useful)X +1771(programming)X +2239(paradigm)X +2574(for)X +2700(maintaining)X +3114(logical)X +3364(consistency,)X +3790(arbitrating)X +4156(con-)X +555 2091(current)N +808(access,)X +1059(and)X +1200(managing)X +1540(recovery.)X +1886(In)X +1977(traditional)X +2330(UNIX)X +2555(systems,)X +2852(the)X +2974(only)X +3140(easy)X +3307(way)X +3465(of)X +3556(using)X +3753(transactions)X +4160(is)X +4237(to)X +555 2181(purchase)N +876(a)X +947(database)X +1258(system.)X +1554(Such)X +1748(systems)X +2035(are)X +2168(often)X +2367(slow,)X +2572(costly,)X +2817(and)X +2967(may)X +3139(not)X +3275(provide)X +3554(the)X +3686(exact)X +3890(functionality)X +555 2271(desired.)N +848(This)X +1011(paper)X +1210(presents)X +1493(the)X +1611(design,)X +1860(implementation,)X +2402(and)X +2538(performance)X +2965(of)X +3052(LIBTP,)X +3314(a)X +3370(simple,)X +3623(non-proprietary)X +4147(tran-)X +555 2361(saction)N +809(library)X +1050(using)X +1249(the)X +1373(4.4BSD)X +1654(database)X +1957(access)X +2189(routines)X +2473(\()X +3 f +2500(db)X +1 f +2588(\(3\)\).)X +2775(On)X +2899(a)X +2961(conventional)X +3401(transaction)X +3779(processing)X +4148(style)X +555 2451(benchmark,)N +959(its)X +1061(performance)X +1495(is)X +1575(approximately)X +2065(85%)X +2239(that)X +2386(of)X +2480(the)X +2604(database)X +2907(access)X +3139(routines)X +3423(without)X +3693(transaction)X +4071(protec-)X +555 2541(tion,)N +725(200%)X +938(that)X +1084(of)X +1177(using)X +3 f +1376(fsync)X +1 f +1554(\(2\))X +1674(to)X +1761(commit)X +2030(modi\256cations)X +2490(to)X +2577(disk,)X +2755(and)X +2896(125%)X +3108(that)X +3253(of)X +3345(a)X +3406(commercial)X +3810(relational)X +4138(data-)X +555 2631(base)N +718(system.)X +3 f +555 2817(1.)N +655(Introduction)X +1 f +755 2940(Transactions)N +1186(are)X +1306(used)X +1474(in)X +1557(database)X +1855(systems)X +2129(to)X +2212(enable)X +2443(concurrent)X +2807(users)X +2992(to)X +3074(apply)X +3272(multi-operation)X +3790(updates)X +4055(without)X +555 3030(violating)N +863(the)X +985(integrity)X +1280(of)X +1371(the)X +1493(database.)X +1814(They)X +2003(provide)X +2271(the)X +2392(properties)X +2736(of)X +2826(atomicity,)X +3171(consistency,)X +3588(isolation,)X +3906(and)X +4045(durabil-)X +555 3120(ity.)N +701(By)X +816(atomicity,)X +1160(we)X +1276(mean)X +1472(that)X +1614(the)X +1734(set)X +1845(of)X +1934(updates)X +2200(comprising)X +2581(a)X +2638(transaction)X +3011(must)X +3187(be)X +3284(applied)X +3541(as)X +3629(a)X +3686(single)X +3898(unit;)X +4085(that)X +4226(is,)X +555 3210(they)N +714(must)X +890(either)X +1094(all)X +1195(be)X +1292(applied)X +1549(to)X +1632(the)X +1751(database)X +2049(or)X +2137(all)X +2238(be)X +2335(absent.)X +2601(Consistency)X +3013(requires)X +3293(that)X +3434(a)X +3491(transaction)X +3864(take)X +4019(the)X +4138(data-)X +555 3300(base)N +725(from)X +908(one)X +1051(logically)X +1358(consistent)X +1704(state)X +1877(to)X +1965(another.)X +2272(The)X +2423(property)X +2721(of)X +2814(isolation)X +3115(requires)X +3400(that)X +3546(concurrent)X +3916(transactions)X +555 3390(yield)N +750(results)X +994(which)X +1225(are)X +1358(indistinguishable)X +1938(from)X +2128(the)X +2260(results)X +2503(which)X +2733(would)X +2967(be)X +3077(obtained)X +3387(by)X +3501(running)X +3784(the)X +3916(transactions)X +555 3480(sequentially.)N +1002(Finally,)X +1268(durability)X +1599(requires)X +1878(that)X +2018(once)X +2190(transactions)X +2593(have)X +2765(been)X +2937(committed,)X +3319(their)X +3486(results)X +3715(must)X +3890(be)X +3986(preserved)X +555 3570(across)N +776(system)X +1018(failures)X +1279([TPCB90].)X +755 3693(Although)N +1080(these)X +1268(properties)X +1612(are)X +1734(most)X +1912(frequently)X +2265(discussed)X +2595(in)X +2680(the)X +2801(context)X +3060(of)X +3150(databases,)X +3501(they)X +3661(are)X +3782(useful)X +4000(program-)X +555 3783(ming)N +750(paradigms)X +1114(for)X +1238(more)X +1433(general)X +1700(purpose)X +1984(applications.)X +2441(There)X +2659(are)X +2788(several)X +3046(different)X +3353(situations)X +3689(where)X +3916(transactions)X +555 3873(can)N +687(be)X +783(used)X +950(to)X +1032(replace)X +1285(current)X +1533(ad-hoc)X +1772(mechanisms.)X +755 3996(One)N +910(situation)X +1206(is)X +1280(when)X +1475(multiple)X +1762(\256les)X +1916(or)X +2004(parts)X +2181(of)X +2269(\256les)X +2422(need)X +2594(to)X +2676(be)X +2772(updated)X +3046(in)X +3128(an)X +3224(atomic)X +3462(fashion.)X +3758(For)X +3889(example,)X +4201(the)X +555 4086(traditional)N +907(UNIX)X +1131(\256le)X +1256(system)X +1501(uses)X +1661(ordering)X +1955(constraints)X +2324(to)X +2408(achieve)X +2676(recoverability)X +3144(in)X +3228(the)X +3348(face)X +3505(of)X +3594(crashes.)X +3893(When)X +4107(a)X +4165(new)X +555 4176(\256le)N +678(is)X +752(created,)X +1026(its)X +1122(inode)X +1321(is)X +1395(written)X +1642(to)X +1724(disk)X +1877(before)X +2103(the)X +2221(new)X +2375(\256le)X +2497(is)X +2570(added)X +2782(to)X +2864(the)X +2982(directory)X +3292(structure.)X +3633(This)X +3795(guarantees)X +4159(that,)X +555 4266(if)N +627(the)X +748(system)X +993(crashes)X +1253(between)X +1544(the)X +1665(two)X +1808(I/O's,)X +2016(the)X +2137(directory)X +2450(does)X +2620(not)X +2744(contain)X +3002(a)X +3060 0.4531(reference)AX +3383(to)X +3467(an)X +3565(invalid)X +3809(inode.)X +4049(In)X +4138(actu-)X +555 4356(ality,)N +741(the)X +863(desired)X +1119(effect)X +1326(is)X +1402(that)X +1545(these)X +1733(two)X +1876(updates)X +2144(have)X +2319(the)X +2440(transactional)X +2873(property)X +3168(of)X +3258(atomicity)X +3583(\(either)X +3816(both)X +3981(writes)X +4200(are)X +555 4446(visible)N +790(or)X +879(neither)X +1124(is\).)X +1266(Rather)X +1501(than)X +1660(building)X +1947(special)X +2191(purpose)X +2466(recovery)X +2769(mechanisms)X +3186(into)X +3331(the)X +3450(\256le)X +3573(system)X +3816(or)X +3904(related)X +4144(tools)X +555 4536(\()N +2 f +582(e.g.)X +3 f +726(fsck)X +1 f +864(\(8\)\),)X +1033(one)X +1177(could)X +1383(use)X +1518(general)X +1783(purpose)X +2064(transaction)X +2443(recovery)X +2752(protocols)X +3077(after)X +3252(system)X +3501(failure.)X +3778(Any)X +3943(application)X +555 4626(that)N +705(needs)X +918(to)X +1010(keep)X +1192(multiple,)X +1508(related)X +1757(\256les)X +1920(\(or)X +2044(directories\))X +2440(consistent)X +2790(should)X +3032(do)X +3141(so)X +3241(using)X +3443(transactions.)X +3895(Source)X +4147(code)X +555 4716(control)N +805(systems,)X +1101(such)X +1271(as)X +1361(RCS)X +1534(and)X +1673(SCCS,)X +1910(should)X +2146(use)X +2276(transaction)X +2651(semantics)X +2990(to)X +3075(allow)X +3276(the)X +3397(``checking)X +3764(in'')X +3903(of)X +3992(groups)X +4232(of)X +555 4806(related)N +801(\256les.)X +1001(In)X +1095(this)X +1237(way,)X +1418(if)X +1493(the)X +1617 0.2841(``check-in'')AX +2028(fails,)X +2212(the)X +2336(transaction)X +2714(may)X +2878(be)X +2980(aborted,)X +3267(backing)X +3547(out)X +3675(the)X +3799(partial)X +4030(``check-)X +555 4896(in'')N +691(leaving)X +947(the)X +1065(source)X +1295(repository)X +1640(in)X +1722(a)X +1778(consistent)X +2118(state.)X +755 5019(A)N +842(second)X +1094(situation)X +1398(where)X +1624(transactions)X +2036(can)X +2177(be)X +2282(used)X +2458(to)X +2549(replace)X +2811(current)X +3068(ad-hoc)X +3316(mechanisms)X +3741(is)X +3822(in)X +3912(applications)X +555 5109(where)N +776(concurrent)X +1144(updates)X +1413(to)X +1499(a)X +1559(shared)X +1793(\256le)X +1919(are)X +2042(desired,)X +2318(but)X +2444(there)X +2629(is)X +2706(logical)X +2948(consistency)X +3345(of)X +3435(the)X +3556(data)X +3713(which)X +3932(needs)X +4138(to)X +4223(be)X +555 5199(preserved.)N +928(For)X +1059(example,)X +1371(when)X +1565(the)X +1683(password)X +2006(\256le)X +2128(is)X +2201(updated,)X +2495(\256le)X +2617(locking)X +2877(is)X +2950(used)X +3117(to)X +3199(disallow)X +3490(concurrent)X +3854(access.)X +4120(Tran-)X +555 5289(saction)N +804(semantics)X +1142(on)X +1244(the)X +1364(password)X +1689(\256les)X +1844(would)X +2066(allow)X +2266(concurrent)X +2632(updates,)X +2919(while)X +3119(preserving)X +3479(the)X +3598(logical)X +3837(consistency)X +4232(of)X +555 5379(the)N +681(password)X +1012(database.)X +1357(Similarly,)X +1702(UNIX)X +1930(utilities)X +2196(which)X +2419(rewrite)X +2674(\256les)X +2834(face)X +2996(a)X +3059(potential)X +3366(race)X +3528(condition)X +3857(between)X +4152(their)X +555 5469(rewriting)N +871(a)X +929(\256le)X +1053(and)X +1191(another)X +1453(process)X +1715(reading)X +1977(the)X +2096(\256le.)X +2259(For)X +2391(example,)X +2704(the)X +2823(compiler)X +3129(\(more)X +3342(precisely,)X +3673(the)X +3792(assembler\))X +4161(may)X +8 s +10 f +555 5541(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)N +5 s +1 f +727 5619(1)N +8 s +763 5644(To)N +850(appear)X +1035(in)X +1101(the)X +2 f +1195(Proceedings)X +1530(of)X +1596(the)X +1690(1992)X +1834(Winter)X +2024(Usenix)X +1 f +2201(,)X +2233(San)X +2345(Francisco,)X +2625(CA,)X +2746(January)X +2960(1992.)X + +2 p +%%Page: 2 2 +8 s 8 xH 0 xS 1 f +10 s +3 f +1 f +555 630(have)N +737(to)X +829(rewrite)X +1087(a)X +1152(\256le)X +1283(to)X +1374(which)X +1599(it)X +1672(has)X +1808(write)X +2002(permission)X +2382(in)X +2473(a)X +2538(directory)X +2857(to)X +2948(which)X +3173(it)X +3246(does)X +3422(not)X +3553(have)X +3734(write)X +3928(permission.)X +555 720(While)N +779(the)X +904(``.o'')X +1099(\256le)X +1228(is)X +1308(being)X +1513(written,)X +1787(another)X +2055(utility)X +2272(such)X +2446(as)X +3 f +2540(nm)X +1 f +2651(\(1\))X +2772(or)X +3 f +2866(ar)X +1 f +2942(\(1\))X +3063(may)X +3228(read)X +3394(the)X +3519(\256le)X +3648(and)X +3791(produce)X +4077(invalid)X +555 810(results)N +790(since)X +981(the)X +1105(\256le)X +1233(has)X +1366(not)X +1494(been)X +1672(completely)X +2054(written.)X +2347(Currently,)X +2700(some)X +2895(utilities)X +3160(use)X +3293(special)X +3542(purpose)X +3821(code)X +3998(to)X +4085(handle)X +555 900(such)N +722(cases)X +912(while)X +1110(others)X +1326(ignore)X +1551(the)X +1669(problem)X +1956(and)X +2092(force)X +2278(users)X +2463(to)X +2545(live)X +2685(with)X +2847(the)X +2965(consequences.)X +755 1023(In)N +845(this)X +983(paper,)X +1205(we)X +1322(present)X +1577(a)X +1635(simple)X +1870(library)X +2106(which)X +2324(provides)X +2622(transaction)X +2996(semantics)X +3334(\(atomicity,)X +3705(consistency,)X +4121(isola-)X +555 1113(tion,)N +720(and)X +857(durability\).)X +1236(The)X +1382(4.4BSD)X +1658(database)X +1956(access)X +2182(methods)X +2473(have)X +2645(been)X +2817(modi\256ed)X +3121(to)X +3203(use)X +3330(this)X +3465(library,)X +3719(optionally)X +4063(provid-)X +555 1203(ing)N +682(shared)X +917(buffer)X +1139(management)X +1574(between)X +1867(applications,)X +2298(locking,)X +2582(and)X +2722(transaction)X +3098(semantics.)X +3478(Any)X +3640(UNIX)X +3865(program)X +4161(may)X +555 1293(transaction)N +930(protect)X +1176(its)X +1274(data)X +1430(by)X +1532(requesting)X +1888(transaction)X +2262(protection)X +2609(with)X +2773(the)X +3 f +2893(db)X +1 f +2981(\(3\))X +3097(library)X +3333(or)X +3422(by)X +3524(adding)X +3764(appropriate)X +4152(calls)X +555 1383(to)N +646(the)X +773(transaction)X +1154(manager,)X +1480(buffer)X +1706(manager,)X +2032(lock)X +2199(manager,)X +2525(and)X +2670(log)X +2801(manager.)X +3147(The)X +3301(library)X +3543(routines)X +3829(may)X +3995(be)X +4099(linked)X +555 1473(into)N +708(the)X +834(host)X +995(application)X +1379(and)X +1523(called)X +1743(by)X +1851(subroutine)X +2217(interface,)X +2547(or)X +2642(they)X +2808(may)X +2974(reside)X +3194(in)X +3284(a)X +3348(separate)X +3640(server)X +3865(process.)X +4174(The)X +555 1563(server)N +772(architecture)X +1172(provides)X +1468(for)X +1582(network)X +1865(access)X +2091(and)X +2227(better)X +2430(protection)X +2775(mechanisms.)X +3 f +555 1749(2.)N +655(Related)X +938(Work)X +1 f +755 1872(There)N +1000(has)X +1164(been)X +1373(much)X +1608(discussion)X +1998(in)X +2117(recent)X +2371(years)X +2597(about)X +2831(new)X +3021(transaction)X +3429(models)X +3716(and)X +3888(architectures)X +555 1962 0.1172([SPEC88][NODI90][CHEN91][MOHA91].)AN +2009(Much)X +2220(of)X +2310(this)X +2448(work)X +2636(focuses)X +2900(on)X +3003(new)X +3160(ways)X +3348(to)X +3433(model)X +3656(transactions)X +4062(and)X +4201(the)X +555 2052(interactions)N +953(between)X +1245(them,)X +1449(while)X +1651(the)X +1772(work)X +1960(presented)X +2291(here)X +2453(focuses)X +2717(on)X +2820(the)X +2941(implementation)X +3466(and)X +3605(performance)X +4035(of)X +4125(tradi-)X +555 2142(tional)N +757(transaction)X +1129(techniques)X +1492(\(write-ahead)X +1919(logging)X +2183(and)X +2319(two-phase)X +2669(locking\))X +2956(on)X +3056(a)X +3112(standard)X +3404(operating)X +3727(system)X +3969(\(UNIX\).)X +755 2265(Such)N +947(traditional)X +1308(operating)X +1643(systems)X +1928(are)X +2059(often)X +2256(criticized)X +2587(for)X +2713(their)X +2892(inability)X +3190(to)X +3283(perform)X +3573(transaction)X +3956(processing)X +555 2355(adequately.)N +971([STON81])X +1342(cites)X +1517(three)X +1706(main)X +1894(areas)X +2088(of)X +2183(inadequate)X +2559(support:)X +2849(buffer)X +3074(management,)X +3532(the)X +3658(\256le)X +3788(system,)X +4058(and)X +4201(the)X +555 2445(process)N +823(structure.)X +1191(These)X +1410(arguments)X +1771(are)X +1897(summarized)X +2316(in)X +2405(table)X +2587(one.)X +2769(Fortunately,)X +3184(much)X +3388(has)X +3521(changed)X +3815(since)X +4006(1981.)X +4232(In)X +555 2535(the)N +683(area)X +848(of)X +945(buffer)X +1172(management,)X +1632(most)X +1817(UNIX)X +2048(systems)X +2331(provide)X +2606(the)X +2734(ability)X +2968(to)X +3060(memory)X +3357(map)X +3525(\256les,)X +3708(thus)X +3870(obviating)X +4201(the)X +555 2625(need)N +734(for)X +855(a)X +918(copy)X +1101(between)X +1396(kernel)X +1624(and)X +1766(user)X +1926(space.)X +2171(If)X +2251(a)X +2313(database)X +2616(system)X +2864(is)X +2943(going)X +3151(to)X +3239(use)X +3372(the)X +3496(\256le)X +3624(system)X +3872(buffer)X +4095(cache,)X +555 2715(then)N +719(a)X +781(system)X +1029(call)X +1171(is)X +1250(required.)X +1584(However,)X +1924(if)X +1998(buffering)X +2322(is)X +2400(provided)X +2710(at)X +2793(user)X +2952(level)X +3133(using)X +3331(shared)X +3566(memory,)X +3878(as)X +3970(in)X +4057(LIBTP,)X +555 2805(buffer)N +776(management)X +1210(is)X +1287(only)X +1452(as)X +1542(slow)X +1716(as)X +1806(access)X +2035(to)X +2120(shared)X +2353(memory)X +2643(and)X +2782(any)X +2921(replacement)X +3337(algorithm)X +3671(may)X +3832(be)X +3931(used.)X +4121(Since)X +555 2895(multiple)N +849(processes)X +1185(can)X +1325(access)X +1559(the)X +1685(shared)X +1923(data,)X +2105(prefetching)X +2499(may)X +2665(be)X +2769(accomplished)X +3238(by)X +3346(separate)X +3638(processes)X +3973(or)X +4067(threads)X +555 2985(whose)N +782(sole)X +932(purpose)X +1207(is)X +1281(to)X +1364(prefetch)X +1649(pages)X +1853(and)X +1990(wait)X +2149(on)X +2250(them.)X +2471(There)X +2680(is)X +2754(still)X +2894(no)X +2995(way)X +3150(to)X +3233(enforce)X +3496(write)X +3682(ordering)X +3975(other)X +4161(than)X +555 3075(keeping)N +829(pages)X +1032(in)X +1114(user)X +1268(memory)X +1555(and)X +1691(using)X +1884(the)X +3 f +2002(fsync)X +1 f +2180(\(3\))X +2294(system)X +2536(call)X +2672(to)X +2754(perform)X +3033(synchronous)X +3458(writes.)X +755 3198(In)N +845(the)X +966(area)X +1124(of)X +1214(\256le)X +1339(systems,)X +1635(the)X +1756(fast)X +1895(\256le)X +2020(system)X +2265(\(FFS\))X +2474([MCKU84])X +2871(allows)X +3103(allocation)X +3442(in)X +3527(units)X +3704(up)X +3806(to)X +3890(64KBytes)X +4232(as)X +555 3288(opposed)N +846(to)X +932(the)X +1054(4KByte)X +1327(and)X +1466(8KByte)X +1738(\256gures)X +1979(quoted)X +2220(in)X +2305([STON81].)X +2711(The)X +2859(measurements)X +3341(in)X +3426(this)X +3564(paper)X +3766(were)X +3946(taken)X +4143(from)X +555 3378(an)N +655(8KByte)X +928(FFS,)X +1104(but)X +1230(as)X +1320(LIBTP)X +1565(runs)X +1726(exclusively)X +2114(in)X +2199(user)X +2356(space,)X +2578(there)X +2762(is)X +2838(nothing)X +3105(to)X +3190(prevent)X +3454(it)X +3521(from)X +3700(being)X +3901(run)X +4031(on)X +4134(other)X +555 3468(UNIX)N +776(compatible)X +1152(\256le)X +1274(systems)X +1547(\(e.g.)X +1710(log-structured)X +2180([ROSE91],)X +2558(extent-based,)X +3004(or)X +3091(multi-block)X +3484([SELT91]\).)X +755 3591(Finally,)N +1029(with)X +1199(regard)X +1433(to)X +1523(the)X +1648(process)X +1916(structure,)X +2244(neither)X +2494(context)X +2757(switch)X +2993(time)X +3162(nor)X +3296(scheduling)X +3670(around)X +3920(semaphores)X +555 3681(seems)N +785(to)X +881(affect)X +1099(the)X +1231(system)X +1487(performance.)X +1968(However,)X +2317(the)X +2449(implementation)X +2984(of)X +3084(semaphores)X +3496(can)X +3641(impact)X +3892(performance)X +555 3771(tremendously.)N +1051(This)X +1213(is)X +1286(discussed)X +1613(in)X +1695(more)X +1880(detail)X +2078(in)X +2160(section)X +2407(4.3.)X +755 3894(The)N +908(Tuxedo)X +1181(system)X +1431(from)X +1615(AT&T)X +1861(is)X +1941(a)X +2004(transaction)X +2383(manager)X +2687(which)X +2910(coordinates)X +3307(distributed)X +3676(transaction)X +4055(commit)X +555 3984(from)N +738(a)X +801(variety)X +1051(of)X +1145(different)X +1449(local)X +1632(transaction)X +2011(managers.)X +2386(At)X +2493(this)X +2634(time,)X +2822(LIBTP)X +3070(does)X +3243(not)X +3371(have)X +3549(its)X +3650(own)X +3814(mechanism)X +4205(for)X +555 4074(distributed)N +942(commit)X +1231(processing,)X +1639(but)X +1786(could)X +2009(be)X +2130(used)X +2322(as)X +2434(a)X +2515(local)X +2716(transaction)X +3113(agent)X +3331(by)X +3455(systems)X +3752(such)X +3943(as)X +4054(Tuxedo)X +555 4164([ANDR89].)N +10 f +863 4393(i)N +870(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +1 f +903 4483(Buffer)N +1133(Management)X +10 f +1672(g)X +1 f +1720(Data)X +1892(must)X +2067(be)X +2163(copied)X +2397(between)X +2685(kernel)X +2906(space)X +3105(and)X +3241(user)X +3395(space.)X +10 f +1672 4573(g)N +1 f +1720(Buffer)X +1950(pool)X +2112(access)X +2338(is)X +2411(too)X +2533(slow.)X +10 f +1672 4663(g)N +1 f +1720(There)X +1928(is)X +2001(no)X +2101(way)X +2255(to)X +2337(request)X +2589(prefetch.)X +10 f +1672 4753(g)N +1 f +1720(Replacement)X +2159(is)X +2232(usually)X +2483(LRU)X +2663(which)X +2879(may)X +3037(be)X +3133(suboptimal)X +3508(for)X +3622(databases.)X +10 f +1672 4843(g)N +1 f +1720(There)X +1928(is)X +2001(no)X +2101(way)X +2255(to)X +2337(guarantee)X +2670(write)X +2855(ordering.)X +10 f +863 4853(i)N +870(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +1 f +903 4943(File)N +1047(System)X +10 f +1672(g)X +1 f +1720(Allocation)X +2078(is)X +2151(done)X +2327(in)X +2409(small)X +2602(blocks)X +2831(\(usually)X +3109(4K)X +3227(or)X +3314(8K\).)X +10 f +1672 5033(g)N +1 f +1720(Logical)X +1985(organization)X +2406(of)X +2493(\256les)X +2646(is)X +2719(redundantly)X +3122(expressed.)X +10 f +863 5043(i)N +870(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +1 f +903 5133(Process)N +1168(Structure)X +10 f +1672(g)X +1 f +1720(Context)X +1993(switching)X +2324(and)X +2460(message)X +2752(passing)X +3012(are)X +3131(too)X +3253(slow.)X +10 f +1672 5223(g)N +1 f +1720(A)X +1798(process)X +2059(may)X +2217(be)X +2313(descheduled)X +2730(while)X +2928(holding)X +3192(a)X +3248(semaphore.)X +10 f +863 5233(i)N +870(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +863(c)X +5193(c)Y +5113(c)Y +5033(c)Y +4953(c)Y +4873(c)Y +4793(c)Y +4713(c)Y +4633(c)Y +4553(c)Y +4473(c)Y +3990 5233(c)N +5193(c)Y +5113(c)Y +5033(c)Y +4953(c)Y +4873(c)Y +4793(c)Y +4713(c)Y +4633(c)Y +4553(c)Y +4473(c)Y +3 f +1156 5446(Table)N +1371(One:)X +1560(Shortcomings)X +2051(of)X +2138(UNIX)X +2363(transaction)X +2770(support)X +3056(cited)X +3241(in)X +3327([STON81].)X + +3 p +%%Page: 3 3 +10 s 10 xH 0 xS 3 f +1 f +755 630(The)N +901(transaction)X +1274(architecture)X +1675(presented)X +2004(in)X +2087([YOUN91])X +2474(is)X +2548(very)X +2712(similar)X +2955(to)X +3038(that)X +3179(implemented)X +3618(in)X +3701(the)X +3820(LIBTP.)X +4103(While)X +555 720([YOUN91])N +947(presents)X +1236(a)X +1298(model)X +1524(for)X +1644(providing)X +1981(transaction)X +2359(services,)X +2663(this)X +2803(paper)X +3007(focuses)X +3273(on)X +3378(the)X +3501(implementation)X +4028(and)X +4169(per-)X +555 810(formance)N +881(of)X +970(a)X +1028(particular)X +1358(system.)X +1642(In)X +1731(addition,)X +2034(we)X +2149(provide)X +2415(detailed)X +2690(comparisons)X +3116(with)X +3279(alternative)X +3639(solutions:)X +3970(traditional)X +555 900(UNIX)N +776(services)X +1055(and)X +1191(commercial)X +1590(database)X +1887(management)X +2317(systems.)X +3 f +555 1086(3.)N +655(Architecture)X +1 f +755 1209(The)N +906(library)X +1146(is)X +1224(designed)X +1534(to)X +1621(provide)X +1891(well)X +2054(de\256ned)X +2315(interfaces)X +2653(to)X +2740(the)X +2863(services)X +3147(required)X +3440(for)X +3559(transaction)X +3936(processing.)X +555 1299(These)N +777(services)X +1066(are)X +1195(recovery,)X +1527(concurrency)X +1955(control,)X +2232(and)X +2378(the)X +2506(management)X +2946(of)X +3043(shared)X +3283(data.)X +3487(First)X +3663(we)X +3787(will)X +3941(discuss)X +4201(the)X +555 1389(design)N +795(tradeoffs)X +1112(in)X +1205(the)X +1334(selection)X +1650(of)X +1748(recovery,)X +2081(concurrency)X +2510(control,)X +2787(and)X +2933(buffer)X +3160(management)X +3600(implementations,)X +4183(and)X +555 1479(then)N +713(we)X +827(will)X +971(present)X +1223(the)X +1341(overall)X +1584(library)X +1818(architecture)X +2218(and)X +2354(module)X +2614(descriptions.)X +3 f +555 1665(3.1.)N +715(Design)X +966(Tradeoffs)X +1 f +3 f +555 1851(3.1.1.)N +775(Crash)X +1004(Recovery)X +1 f +755 1974(The)N +909(recovery)X +1220(protocol)X +1516(is)X +1598(responsible)X +1992(for)X +2115(providing)X +2455(the)X +2582(transaction)X +2963(semantics)X +3308(discussed)X +3644(earlier.)X +3919(There)X +4136(are)X +4263(a)X +555 2064(wide)N +739(range)X +946(of)X +1041(recovery)X +1351(protocols)X +1677(available)X +1995([HAER83],)X +2395(but)X +2525(we)X +2647(can)X +2786(crudely)X +3054(divide)X +3281(them)X +3468(into)X +3619(two)X +3766(main)X +3953(categories.)X +555 2154(The)N +706(\256rst)X +856(category)X +1159(records)X +1422(all)X +1528(modi\256cations)X +1989(to)X +2077(the)X +2201(database)X +2504(in)X +2592(a)X +2653(separate)X +2942(\256le,)X +3089(and)X +3230(uses)X +3393(this)X +3533(\256le)X +3660(\(log\))X +3841(to)X +3928(back)X +4105(out)X +4232(or)X +555 2244(reapply)N +825(these)X +1019(modi\256cations)X +1483(if)X +1561(a)X +1626(transaction)X +2007(aborts)X +2232(or)X +2328(the)X +2455(system)X +2706(crashes.)X +3012(We)X +3153(call)X +3298(this)X +3442(set)X +3560(the)X +3 f +3687(logging)X +3963(protocols)X +1 f +4279(.)X +555 2334(The)N +703(second)X +949(category)X +1249(avoids)X +1481(the)X +1602(use)X +1732(of)X +1822(a)X +1881(log)X +2006(by)X +2109(carefully)X +2418(controlling)X +2792(when)X +2989(data)X +3146(are)X +3268(written)X +3518(to)X +3603(disk.)X +3799(We)X +3934(call)X +4073(this)X +4210(set)X +555 2424(the)N +3 f +673(non-logging)X +1096(protocols)X +1 f +1412(.)X +755 2547(Non-logging)N +1185(protocols)X +1504(hold)X +1666(dirty)X +1837(buffers)X +2085(in)X +2167(main)X +2347(memory)X +2634(or)X +2721(temporary)X +3071(\256les)X +3224(until)X +3390(commit)X +3654(and)X +3790(then)X +3948(force)X +4134(these)X +555 2637(pages)N +769(to)X +862(disk)X +1026(at)X +1115(transaction)X +1498(commit.)X +1813(While)X +2040(we)X +2165(can)X +2308(use)X +2446(temporary)X +2807(\256les)X +2971(to)X +3064(hold)X +3237(dirty)X +3418(pages)X +3631(that)X +3781(may)X +3949(need)X +4131(to)X +4223(be)X +555 2727(evicted)N +810(from)X +988(memory)X +1277(during)X +1508(a)X +1566(long-running)X +2006(transaction,)X +2400(the)X +2520(only)X +2684(user-level)X +3023(mechanism)X +3410(to)X +3494(force)X +3682(pages)X +3887(to)X +3971(disk)X +4126(is)X +4201(the)X +3 f +555 2817(fsync)N +1 f +733(\(2\))X +850(system)X +1095(call.)X +1274(Unfortunately,)X +3 f +1767(fsync)X +1 f +1945(\(2\))X +2062(is)X +2138(an)X +2237(expensive)X +2581(system)X +2826(call)X +2965(in)X +3050(that)X +3193(it)X +3260(forces)X +3480(all)X +3583(pages)X +3789(of)X +3879(a)X +3938(\256le)X +4062(to)X +4146(disk,)X +555 2907(and)N +691(transactions)X +1094(that)X +1234(manage)X +1504(more)X +1689(than)X +1847(one)X +1983(\256le)X +2105(must)X +2280(issue)X +2460(one)X +2596(call)X +2732(per)X +2855(\256le.)X +755 3030(In)N +853(addition,)X +3 f +1166(fsync)X +1 f +1344(\(2\))X +1469(provides)X +1776(no)X +1887(way)X +2051(to)X +2143(control)X +2400(the)X +2528(order)X +2728(in)X +2820(which)X +3046(dirty)X +3227(pages)X +3440(are)X +3569(written)X +3826(to)X +3918(disk.)X +4121(Since)X +555 3120(non-logging)N +976(protocols)X +1304(must)X +1489(sometimes)X +1861(order)X +2061(writes)X +2287(carefully)X +2603([SULL92],)X +2987(they)X +3155(are)X +3284(dif\256cult)X +3567(to)X +3659(implement)X +4030(on)X +4139(Unix)X +555 3210(systems.)N +868(As)X +977(a)X +1033(result,)X +1251(we)X +1365(have)X +1537(chosen)X +1780(to)X +1862(implement)X +2224(a)X +2280(logging)X +2544(protocol.)X +755 3333(Logging)N +1050(protocols)X +1372(may)X +1534(be)X +1634(categorized)X +2029(based)X +2236(on)X +2340(how)X +2502(information)X +2904(is)X +2981(logged)X +3223(\(physically)X +3602(or)X +3692(logically\))X +4022(and)X +4161(how)X +555 3423(much)N +767(is)X +854(logged)X +1106(\(before)X +1373(images,)X +1654(after)X +1836(images)X +2097(or)X +2198(both\).)X +2441(In)X +3 f +2542(physical)X +2855(logging)X +1 f +3103(,)X +3157(images)X +3417(of)X +3517(complete)X +3844(physical)X +4144(units)X +555 3513(\(pages)N +786(or)X +874(buffers\))X +1150(are)X +1270(recorded,)X +1593(while)X +1792(in)X +3 f +1875(logical)X +2118(logging)X +1 f +2387(a)X +2444(description)X +2820(of)X +2907(the)X +3025(operation)X +3348(is)X +3421(recorded.)X +3763(Therefore,)X +4121(while)X +555 3603(we)N +675(may)X +839(record)X +1071(entire)X +1280(pages)X +1489(in)X +1577(a)X +1639(physical)X +1932(log,)X +2080(we)X +2200(need)X +2378(only)X +2546(record)X +2777(the)X +2900(records)X +3162(being)X +3365(modi\256ed)X +3674(in)X +3761(a)X +3822(logical)X +4065(log.)X +4232(In)X +555 3693(fact,)N +718(physical)X +1006(logging)X +1271(can)X +1404(be)X +1501(thought)X +1766(of)X +1854(as)X +1942(a)X +1999(special)X +2243(case)X +2403(of)X +2491(logical)X +2730(logging,)X +3015(since)X +3201(the)X +3320 0.3125(``records'')AX +3686(that)X +3827(we)X +3942(log)X +4065(in)X +4148(logi-)X +555 3783(cal)N +673(logging)X +941(might)X +1151(be)X +1251(physical)X +1542(pages.)X +1789(Since)X +1991(logical)X +2233(logging)X +2501(is)X +2578(both)X +2743(more)X +2931(space-ef\256cient)X +3423(and)X +3562(more)X +3750(general,)X +4030(we)X +4147(have)X +555 3873(chosen)N +798(it)X +862(for)X +976(our)X +1103(logging)X +1367(protocol.)X +755 3996(In)N +3 f +843(before-image)X +1315(logging)X +1 f +1563(,)X +1604(we)X +1719(log)X +1842(a)X +1899(copy)X +2076(of)X +2164(the)X +2283(data)X +2438(before)X +2665(the)X +2784(update,)X +3039(while)X +3238(in)X +3 f +3321(after-image)X +3739(logging)X +1 f +3987(,)X +4027(we)X +4141(log)X +4263(a)X +555 4086(copy)N +740(of)X +836(the)X +963(data)X +1126(after)X +1303(the)X +1429(update.)X +1711(If)X +1793(we)X +1915(log)X +2045(only)X +2215(before-images,)X +2723(then)X +2889(there)X +3078(is)X +3159(suf\256cient)X +3485(information)X +3891(in)X +3981(the)X +4107(log)X +4237(to)X +555 4176(allow)N +761(us)X +860(to)X +3 f +950(undo)X +1 f +1150(the)X +1276(transaction)X +1656(\(go)X +1791(back)X +1971(to)X +2061(the)X +2187(state)X +2361(represented)X +2759(by)X +2866(the)X +2991(before-image\).)X +3514(However,)X +3876(if)X +3952(the)X +4077(system)X +555 4266(crashes)N +814(and)X +952(a)X +1010(committed)X +1374(transaction's)X +1806(changes)X +2087(have)X +2261(not)X +2385(reached)X +2658(the)X +2778(disk,)X +2953(we)X +3068(have)X +3241(no)X +3342(means)X +3568(to)X +3 f +3651(redo)X +1 f +3828(the)X +3947(transaction)X +555 4356(\(reapply)N +849(the)X +973(updates\).)X +1311(Therefore,)X +1675(logging)X +1945(only)X +2113(before-images)X +2599(necessitates)X +3004(forcing)X +3262(dirty)X +3439(pages)X +3648(at)X +3732(commit)X +4002(time.)X +4210(As)X +555 4446(mentioned)N +913(above,)X +1145(forcing)X +1397(pages)X +1600(at)X +1678(commit)X +1942(is)X +2015(considered)X +2383(too)X +2505(costly.)X +755 4569(If)N +834(we)X +953(log)X +1080(only)X +1247(after-images,)X +1694(then)X +1857(there)X +2043(is)X +2121(suf\256cient)X +2444(information)X +2847(in)X +2934(the)X +3057(log)X +3184(to)X +3271(allow)X +3474(us)X +3570(to)X +3657(redo)X +3825(the)X +3947(transaction)X +555 4659(\(go)N +687(forward)X +967(to)X +1054(the)X +1177(state)X +1348(represented)X +1743(by)X +1847(the)X +1969(after-image\),)X +2411(but)X +2537(we)X +2655(do)X +2759(not)X +2885(have)X +3061(the)X +3183(information)X +3585(required)X +3877(to)X +3963(undo)X +4147(tran-)X +555 4749(sactions)N +845(which)X +1073(aborted)X +1346(after)X +1526(dirty)X +1709(pages)X +1924(were)X +2113(written)X +2372(to)X +2466(disk.)X +2670(Therefore,)X +3039(logging)X +3314(only)X +3487(after-images)X +3920(necessitates)X +555 4839(holding)N +819(all)X +919(dirty)X +1090(buffers)X +1338(in)X +1420(main)X +1600(memory)X +1887(until)X +2053(commit)X +2317(or)X +2404(writing)X +2655(them)X +2835(to)X +2917(a)X +2973(temporary)X +3323(\256le.)X +755 4962(Since)N +956(neither)X +1202(constraint)X +1541(\(forcing)X +1823(pages)X +2029(on)X +2132(commit)X +2399(or)X +2489(buffering)X +2811(pages)X +3016(until)X +3184(commit\))X +3477(was)X +3624(feasible,)X +3916(we)X +4032(chose)X +4237(to)X +555 5052(log)N +683(both)X +851(before)X +1083(and)X +1225(after)X +1399(images.)X +1672(The)X +1823(only)X +1991(remaining)X +2342(consideration)X +2800(is)X +2879(when)X +3079(changes)X +3363(get)X +3486(written)X +3738(to)X +3825(disk.)X +4023(Changes)X +555 5142(affect)N +764(both)X +931(data)X +1090(pages)X +1298(and)X +1438(the)X +1560(log.)X +1726(If)X +1804(the)X +1926(changed)X +2218(data)X +2376(page)X +2552(is)X +2629(written)X +2880(before)X +3110(the)X +3232(log)X +3358(page,)X +3554(and)X +3694(the)X +3816(system)X +4062(crashes)X +555 5232(before)N +787(the)X +911(log)X +1039(page)X +1217(is)X +1296(written,)X +1569(the)X +1693(log)X +1820(will)X +1969(contain)X +2230(insuf\256cient)X +2615(information)X +3018(to)X +3105(undo)X +3290(the)X +3413(change.)X +3706(This)X +3873(violates)X +4147(tran-)X +555 5322(saction)N +803(semantics,)X +1160(since)X +1346(some)X +1536(changed)X +1825(data)X +1980(pages)X +2184(may)X +2343(not)X +2466(have)X +2638(been)X +2810(written,)X +3077(and)X +3213(the)X +3331(database)X +3628(cannot)X +3862(be)X +3958(restored)X +4237(to)X +555 5412(its)N +650(pre-transaction)X +1152(state.)X +755 5535(The)N +914(log)X +1050(record)X +1290(describing)X +1658(an)X +1768(update)X +2016(must)X +2205(be)X +2315(written)X +2576(to)X +2672(stable)X +2893(storage)X +3159(before)X +3398(the)X +3529(modi\256ed)X +3846(page.)X +4071(This)X +4246(is)X +3 f +555 5625(write-ahead)N +992(logging)X +1 f +1240(.)X +1307(If)X +1388(log)X +1517(records)X +1781(are)X +1907(safely)X +2126(written)X +2380(to)X +2469(disk,)X +2649(data)X +2810(pages)X +3020(may)X +3185(be)X +3288(written)X +3542(at)X +3627(any)X +3770(time)X +3939(afterwards.)X +555 5715(This)N +721(means)X +950(that)X +1094(the)X +1216(only)X +1382(\256le)X +1508(that)X +1652(ever)X +1815(needs)X +2022(to)X +2108(be)X +2208(forced)X +2438(to)X +2524(disk)X +2681(is)X +2758(the)X +2880(log.)X +3046(Since)X +3248(the)X +3370(log)X +3495(is)X +3571(append-only,)X +4015(modi\256ed)X + +4 p +%%Page: 4 4 +10 s 10 xH 0 xS 1 f +3 f +1 f +555 630(pages)N +760(always)X +1005(appear)X +1242(at)X +1322(the)X +1442(end)X +1580(and)X +1718(may)X +1878(be)X +1976(written)X +2224(to)X +2307(disk)X +2461(ef\256ciently)X +2807(in)X +2890(any)X +3027(\256le)X +3150(system)X +3393(that)X +3534(favors)X +3756(sequential)X +4102(order-)X +555 720(ing)N +677(\()X +2 f +704(e.g.)X +1 f +820(,)X +860(FFS,)X +1032(log-structured)X +1502(\256le)X +1624(system,)X +1886(or)X +1973(an)X +2069(extent-based)X +2495(system\).)X +3 f +555 906(3.1.2.)N +775(Concurrency)X +1245(Control)X +1 f +755 1029(The)N +918(concurrency)X +1354(control)X +1619(protocol)X +1923(is)X +2013(responsible)X +2415(for)X +2546(maintaining)X +2965(consistency)X +3376(in)X +3475(the)X +3610(presence)X +3929(of)X +4033(multiple)X +555 1119(accesses.)N +897(There)X +1114(are)X +1242(several)X +1499(alternative)X +1867(solutions)X +2183(such)X +2358(as)X +2453(locking,)X +2741(optimistic)X +3088(concurrency)X +3514(control)X +3769([KUNG81],)X +4183(and)X +555 1209(timestamp)N +912(ordering)X +1208([BERN80].)X +1619(Since)X +1821(optimistic)X +2164(methods)X +2459(and)X +2599(timestamp)X +2956(ordering)X +3252(are)X +3374(generally)X +3696(more)X +3884(complex)X +4183(and)X +555 1299(restrict)N +804(concurrency)X +1228(without)X +1498(eliminating)X +1888(starvation)X +2230(or)X +2323(deadlocks,)X +2690(we)X +2810(chose)X +3018(two-phase)X +3373(locking)X +3638(\(2PL\).)X +3890(Strict)X +4088(2PL)X +4246(is)X +555 1389(suboptimal)N +935(for)X +1054(certain)X +1297(data)X +1455(structures)X +1791(such)X +1962(as)X +2053(B-trees)X +2309(because)X +2588(it)X +2656(can)X +2792(limit)X +2966(concurrency,)X +3408(so)X +3503(we)X +3621(use)X +3752(a)X +3812(special)X +4059(locking)X +555 1479(protocol)N +842(based)X +1045(on)X +1145(one)X +1281(described)X +1609(in)X +1691([LEHM81].)X +755 1602(The)N +901(B-tree)X +1123(locking)X +1384(protocol)X +1672(we)X +1787(implemented)X +2226(releases)X +2502(locks)X +2691(at)X +2769(internal)X +3034(nodes)X +3241(in)X +3323(the)X +3441(tree)X +3582(as)X +3669(it)X +3733(descends.)X +4083(A)X +4161(lock)X +555 1692(on)N +658(an)X +757(internal)X +1025(page)X +1200(is)X +1276(always)X +1522(released)X +1808(before)X +2036(a)X +2094(lock)X +2254(on)X +2356(its)X +2453(child)X +2635(is)X +2710(obtained)X +3008(\(that)X +3177(is,)X +3272(locks)X +3463(are)X +3584(not)X +3 f +3708(coupled)X +1 f +3996([BAY77])X +555 1782(during)N +786(descent\).)X +1116(When)X +1330(a)X +1388(leaf)X +1531(\(or)X +1647(internal\))X +1941(page)X +2115(is)X +2190(split,)X +2369(a)X +2427(write)X +2614(lock)X +2774(is)X +2849(acquired)X +3148(on)X +3250(the)X +3370(parent)X +3593(before)X +3821(the)X +3941(lock)X +4100(on)X +4201(the)X +555 1872(just-split)N +855(page)X +1028(is)X +1102(released)X +1387(\(locks)X +1604(are)X +3 f +1724(coupled)X +1 f +2011(during)X +2241(ascent\).)X +2530(Write)X +2734(locks)X +2924(on)X +3025(internal)X +3291(pages)X +3495(are)X +3615(released)X +3899(immediately)X +555 1962(after)N +723(the)X +841(page)X +1013(is)X +1086(updated,)X +1380(but)X +1502(locks)X +1691(on)X +1791(leaf)X +1932(pages)X +2135(are)X +2254(held)X +2412(until)X +2578(the)X +2696(end)X +2832(of)X +2919(the)X +3037(transaction.)X +755 2085(Since)N +964(locks)X +1164(are)X +1294(released)X +1589(during)X +1828(descent,)X +2119(the)X +2247(structure)X +2558(of)X +2655(the)X +2783(tree)X +2934(may)X +3102(change)X +3360(above)X +3582(a)X +3648(node)X +3834(being)X +4042(used)X +4219(by)X +555 2175(some)N +752(process.)X +1061(If)X +1143(that)X +1291(process)X +1560(must)X +1743(later)X +1914(ascend)X +2161(the)X +2287(tree)X +2435(because)X +2717(of)X +2811(a)X +2874(page)X +3053(split,)X +3237(any)X +3380(such)X +3554(change)X +3809(must)X +3991(not)X +4120(cause)X +555 2265(confusion.)N +938(We)X +1077(use)X +1211(the)X +1336(technique)X +1675(described)X +2010(in)X +2099([LEHM81])X +2487(which)X +2710(exploits)X +2989(the)X +3113(ordering)X +3411(of)X +3504(data)X +3664(on)X +3770(a)X +3832(B-tree)X +4059(page)X +4237(to)X +555 2355(guarantee)N +888(that)X +1028(no)X +1128(process)X +1389(ever)X +1548(gets)X +1697(lost)X +1832(as)X +1919(a)X +1975(result)X +2173(of)X +2260(internal)X +2525(page)X +2697(updates)X +2962(made)X +3156(by)X +3256(other)X +3441(processes.)X +755 2478(If)N +836(a)X +899(transaction)X +1278(that)X +1425(updates)X +1697(a)X +1760(B-tree)X +1988(aborts,)X +2231(the)X +2356(user-visible)X +2757(changes)X +3043(to)X +3131(the)X +3255(tree)X +3402(must)X +3583(be)X +3685(rolled)X +3898(back.)X +4116(How-)X +555 2568(ever,)N +735(changes)X +1015(to)X +1097(the)X +1215(internal)X +1480(nodes)X +1687(of)X +1774(the)X +1892(tree)X +2033(need)X +2205(not)X +2327(be)X +2423(rolled)X +2630(back,)X +2822(since)X +3007(these)X +3192(pages)X +3395(contain)X +3651(no)X +3751(user-visible)X +4145(data.)X +555 2658(When)N +771(rolling)X +1008(back)X +1184(a)X +1244(transaction,)X +1640(we)X +1758(roll)X +1893(back)X +2069(all)X +2173(leaf)X +2318(page)X +2494(updates,)X +2783(but)X +2909(no)X +3013(internal)X +3281(insertions)X +3615(or)X +3705(page)X +3880(splits.)X +4111(In)X +4201(the)X +555 2748(worst)N +759(case,)X +944(this)X +1085(will)X +1235(leave)X +1431(a)X +1493(leaf)X +1640(page)X +1818(less)X +1964(than)X +2128(half)X +2279(full.)X +2456(This)X +2624(may)X +2788(cause)X +2993(poor)X +3166(space)X +3371(utilization,)X +3741(but)X +3869(does)X +4042(not)X +4170(lose)X +555 2838(user)N +709(data.)X +755 2961(Holding)N +1038(locks)X +1228(on)X +1329(leaf)X +1471(pages)X +1675(until)X +1842(transaction)X +2215(commit)X +2480(guarantees)X +2845(that)X +2986(no)X +3087(other)X +3273(process)X +3535(can)X +3668(insert)X +3866(or)X +3953(delete)X +4165(data)X +555 3051(that)N +711(has)X +854(been)X +1042(touched)X +1332(by)X +1448(this)X +1598(process.)X +1914(Rolling)X +2188(back)X +2375(insertions)X +2721(and)X +2872(deletions)X +3196(on)X +3311(leaf)X +3467(pages)X +3685(guarantees)X +4064(that)X +4219(no)X +555 3141(aborted)N +819(updates)X +1087(are)X +1209(ever)X +1371(visible)X +1607(to)X +1692(other)X +1880(transactions.)X +2326(Leaving)X +2612(page)X +2787(splits)X +2978(intact)X +3179(permits)X +3442(us)X +3536(to)X +3621(release)X +3867(internal)X +4134(write)X +555 3231(locks)N +744(early.)X +965(Thus)X +1145(transaction)X +1517(semantics)X +1853(are)X +1972(preserved,)X +2325(and)X +2461(locks)X +2650(are)X +2769(held)X +2927(for)X +3041(shorter)X +3284(periods.)X +755 3354(The)N +901(extra)X +1083(complexity)X +1464(introduced)X +1828(by)X +1929(this)X +2065(locking)X +2326(protocol)X +2614(appears)X +2881(substantial,)X +3264(but)X +3387(it)X +3452(is)X +3525(important)X +3856(for)X +3970(multi-user)X +555 3444(execution.)N +950(The)X +1118(bene\256ts)X +1410(of)X +1520(non-two-phase)X +2040(locking)X +2323(on)X +2446(B-trees)X +2721(are)X +2863(well)X +3044(established)X +3443(in)X +3548(the)X +3689(database)X +4009(literature)X +555 3534([BAY77],)N +899([LEHM81].)X +1320(If)X +1394(a)X +1450(process)X +1711(held)X +1869(locks)X +2058(until)X +2224(it)X +2288(committed,)X +2670(then)X +2828(a)X +2884(long-running)X +3322(update)X +3556(could)X +3754(lock)X +3912(out)X +4034(all)X +4134(other)X +555 3624(transactions)N +967(by)X +1076(preventing)X +1448(any)X +1593(other)X +1787(process)X +2057(from)X +2241(locking)X +2509(the)X +2635(root)X +2792(page)X +2972(of)X +3067(the)X +3193(tree.)X +3382(The)X +3535(B-tree)X +3764(locking)X +4032(protocol)X +555 3714(described)N +884(above)X +1096(guarantees)X +1460(that)X +1600(locks)X +1789(on)X +1889(internal)X +2154(pages)X +2357(are)X +2476(held)X +2634(for)X +2748(extremely)X +3089(short)X +3269(periods,)X +3545(thereby)X +3806(increasing)X +4156(con-)X +555 3804(currency.)N +3 f +555 3990(3.1.3.)N +775(Management)X +1245(of)X +1332(Shared)X +1596(Data)X +1 f +755 4113(Database)N +1075(systems)X +1353(permit)X +1587(many)X +1790(users)X +1980(to)X +2067(examine)X +2364(and)X +2505(update)X +2744(the)X +2866(same)X +3055(data)X +3213(concurrently.)X +3683(In)X +3774(order)X +3968(to)X +4054(provide)X +555 4203(this)N +702(concurrent)X +1078(access)X +1316(and)X +1464(enforce)X +1738(the)X +1868(write-ahead)X +2280(logging)X +2556(protocol)X +2855(described)X +3195(in)X +3289(section)X +3548(3.1.1,)X +3759(we)X +3884(use)X +4022(a)X +4089(shared)X +555 4293(memory)N +848(buffer)X +1071(manager.)X +1414(Not)X +1559(only)X +1726(does)X +1898(this)X +2038(provide)X +2308(the)X +2431(guarantees)X +2800(we)X +2919(require,)X +3192(but)X +3319(a)X +3380(user-level)X +3722(buffer)X +3944(manager)X +4246(is)X +555 4383(frequently)N +916(faster)X +1126(than)X +1295(using)X +1498(the)X +1626(\256le)X +1758(system)X +2010(buffer)X +2237(cache.)X +2491(Reads)X +2717(or)X +2814(writes)X +3040(involving)X +3376(the)X +3504(\256le)X +3636(system)X +3888(buffer)X +4115(cache)X +555 4473(often)N +746(require)X +1000(copying)X +1284(data)X +1444(between)X +1738(user)X +1898(and)X +2040(kernel)X +2266(space)X +2470(while)X +2673(a)X +2734(user-level)X +3076(buffer)X +3298(manager)X +3600(can)X +3737(return)X +3954(pointers)X +4237(to)X +555 4563(data)N +709(pages)X +912(directly.)X +1217(Additionally,)X +1661(if)X +1730(more)X +1915(than)X +2073(one)X +2209(process)X +2470(uses)X +2628(the)X +2746(same)X +2931(page,)X +3123(then)X +3281(fewer)X +3485(copies)X +3710(may)X +3868(be)X +3964(required.)X +3 f +555 4749(3.2.)N +715(Module)X +997(Architecture)X +1 f +755 4872(The)N +913(preceding)X +1262(sections)X +1552(described)X +1892(modules)X +2195(for)X +2321(managing)X +2669(the)X +2799(transaction)X +3183(log,)X +3337(locks,)X +3558(and)X +3706(a)X +3774(cache)X +3990(of)X +4089(shared)X +555 4962(buffers.)N +847(In)X +938(addition,)X +1244(we)X +1362(need)X +1538(to)X +1624(provide)X +1893(functionality)X +2326(for)X +2444(transaction)X +2 f +2819(begin)X +1 f +2997(,)X +2 f +3040(commit)X +1 f +3276(,)X +3319(and)X +2 f +3458(abort)X +1 f +3654(processing,)X +4040(necessi-)X +555 5052(tating)N +769(a)X +837(transaction)X +1221(manager.)X +1570(In)X +1669(order)X +1871(to)X +1965(arbitrate)X +2265(concurrent)X +2641(access)X +2879(to)X +2973(locks)X +3173(and)X +3320(buffers,)X +3599(we)X +3724(include)X +3991(a)X +4058(process)X +555 5142(management)N +995(module)X +1264(which)X +1489(manages)X +1799(a)X +1864(collection)X +2209(of)X +2305(semaphores)X +2713(used)X +2889(to)X +2980(block)X +3187(and)X +3332(release)X +3585(processes.)X +3962(Finally,)X +4237(in)X +555 5232(order)N +752(to)X +841(provide)X +1113(a)X +1176(simple,)X +1436(standard)X +1735(interface)X +2044(we)X +2165(have)X +2344(modi\256ed)X +2655(the)X +2780(database)X +3084(access)X +3317(routines)X +3602(\()X +3 f +3629(db)X +1 f +3717(\(3\)\).)X +3904(For)X +4041(the)X +4165(pur-)X +555 5322(poses)N +758(of)X +850(this)X +990(paper)X +1194(we)X +1313(call)X +1453(the)X +1575(modi\256ed)X +1883(package)X +2171(the)X +3 f +2293(Record)X +2567(Manager)X +1 f +2879(.)X +2943(Figure)X +3176(one)X +3316(shows)X +3540(the)X +3662(main)X +3846(interfaces)X +4183(and)X +555 5412(architecture)N +955(of)X +1042(LIBTP.)X + +5 p +%%Page: 5 5 +10 s 10 xH 0 xS 1 f +3 f +1 f +11 s +1851 1520(log_commit)N +2764 2077(buf_unpin)N +2764 1987(buf_get)N +3633 1408(buf_unpin)N +3633 1319(buf_pin)N +3633 1230(buf_get)N +3 f +17 s +1163 960(Txn)N +1430(M)X +1559(anager)X +2582(Record)X +3040(M)X +3169(anager)X +1 Dt +2363 726 MXY +0 355 Dl +1426 0 Dl +0 -355 Dl +-1426 0 Dl +3255 1616 MXY +0 535 Dl +534 0 Dl +0 -535 Dl +-534 0 Dl +2185 MX +0 535 Dl +535 0 Dl +0 -535 Dl +-535 0 Dl +1116 MX +0 535 Dl +534 0 Dl +0 -535 Dl +-534 0 Dl +726 MY +0 355 Dl +891 0 Dl +0 -355 Dl +-891 0 Dl +1 f +11 s +2207 1297(lock)N +2564 1386(log)N +865(unlock_all)X +1851 1609(log_unroll)N +1650 2508 MXY +0 178 Dl +1605 0 Dl +0 -178 Dl +-1605 0 Dl +1294 1616 MXY +19 -30 Dl +-19 11 Dl +-20 -11 Dl +20 30 Dl +0 -535 Dl +2319 2508 MXY +-22 -30 Dl +4 23 Dl +-18 14 Dl +36 -7 Dl +-936 -357 Dl +3277 2455(sleep_on)N +1405 1616 MXY +36 4 Dl +-18 -13 Dl +1 -22 Dl +-19 31 Dl +1070 -535 Dl +2631 2508 MXY +36 6 Dl +-18 -14 Dl +3 -22 Dl +-21 30 Dl +891 -357 Dl +1426 2455(sleep_on)N +3255 1884 MXY +-31 -20 Dl +11 20 Dl +-11 19 Dl +31 -19 Dl +-535 0 Dl +1554 2366(wake)N +3277(wake)X +2185 1884 MXY +-31 -20 Dl +12 20 Dl +-12 19 Dl +31 -19 Dl +-356 0 Dl +0 -803 Dl +3 f +17 s +1236 1851(Lock)N +1118 2030(M)N +1247(anager)X +2339 1851(Log)N +2187 2030(M)N +2316(anager)X +3333 1851(Buffer)N +3257 2030(M)N +3386(anager)X +3522 1616 MXY +20 -30 Dl +-20 11 Dl +-20 -11 Dl +20 30 Dl +0 -535 Dl +1950 2654(Process)N +2424(M)X +2553(anager)X +2542 1616 MXY +19 -30 Dl +-19 11 Dl +-20 -11 Dl +20 30 Dl +0 -535 Dl +1 f +11 s +2207 1364(unlock)N +2452 2508 MXY +20 -31 Dl +-20 11 Dl +-19 -11 Dl +19 31 Dl +0 -357 Dl +2497 2322(sleep_on)N +2497 2233(wake)N +3 Dt +-1 Ds +3 f +10 s +1790 2830(Figure)N +2037(1:)X +2144(Library)X +2435(module)X +2708(interfaces.)X +1 f +10 f +555 3010(h)N +579(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)X +3 f +555 3286(3.2.1.)N +775(The)X +928(Log)X +1081(Manager)X +1 f +755 3409(The)N +3 f +907(Log)X +1067(Manager)X +1 f +1406(enforces)X +1706(the)X +1831(write-ahead)X +2238(logging)X +2509(protocol.)X +2843(Its)X +2949(primitive)X +3268(operations)X +3628(are)X +2 f +3753(log)X +1 f +3855(,)X +2 f +3901(log_commit)X +1 f +4279(,)X +2 f +555 3499(log_read)N +1 f +844(,)X +2 f +889(log_roll)X +1 f +1171(and)X +2 f +1312(log_unroll)X +1 f +1649(.)X +1714(The)X +2 f +1864(log)X +1 f +1991(call)X +2132(performs)X +2447(a)X +2508(buffered)X +2806(write)X +2996(of)X +3088(the)X +3211(speci\256ed)X +3520(log)X +3646(record)X +3876(and)X +4016(returns)X +4263(a)X +555 3589(unique)N +809(log)X +947(sequence)X +1278(number)X +1559(\(LSN\).)X +1840(This)X +2017(LSN)X +2203(may)X +2376(then)X +2549(be)X +2660(used)X +2842(to)X +2939(retrieve)X +3220(a)X +3291(record)X +3532(from)X +3723(the)X +3856(log)X +3993(using)X +4201(the)X +2 f +555 3679(log_read)N +1 f +865(call.)X +1042(The)X +2 f +1188(log)X +1 f +1311(interface)X +1614(knows)X +1844(very)X +2008(little)X +2175(about)X +2374(the)X +2493(internal)X +2759(format)X +2993(of)X +3080(the)X +3198(log)X +3320(records)X +3577(it)X +3641(receives.)X +3965(Rather,)X +4219(all)X +555 3769(log)N +681(records)X +942(are)X +1065 0.4028(referenced)AX +1430(by)X +1534(a)X +1594(header)X +1833(structure,)X +2158(a)X +2218(log)X +2344(record)X +2574(type,)X +2756(and)X +2896(a)X +2956(character)X +3276(buffer)X +3497(containing)X +3859(the)X +3981(data)X +4138(to)X +4223(be)X +555 3859(logged.)N +834(The)X +980(log)X +1103(record)X +1330(type)X +1489(is)X +1563(used)X +1731(to)X +1814(call)X +1951(the)X +2070(appropriate)X +2457(redo)X +2621(and)X +2758(undo)X +2939(routines)X +3217(during)X +2 f +3446(abort)X +1 f +3639(and)X +2 f +3775(commit)X +1 f +4031(process-)X +555 3949(ing.)N +721(While)X +941(we)X +1059(have)X +1235(used)X +1406(the)X +3 f +1528(Log)X +1684(Manager)X +1 f +2019(to)X +2104(provide)X +2372(before)X +2601(and)X +2740(after)X +2911(image)X +3130(logging,)X +3417(it)X +3484(may)X +3645(also)X +3797(be)X +3896(used)X +4066(for)X +4183(any)X +555 4039(of)N +642(the)X +760(logging)X +1024(algorithms)X +1386(discussed.)X +755 4162(The)N +2 f +905(log_commit)X +1 f +1308(operation)X +1636(behaves)X +1920(exactly)X +2177(like)X +2322(the)X +2 f +2445(log)X +1 f +2572(operation)X +2900(but)X +3026(guarantees)X +3394(that)X +3538(the)X +3660(log)X +3786(has)X +3917(been)X +4093(forced)X +555 4252(to)N +643(disk)X +802(before)X +1034(returning.)X +1394(A)X +1478(discussion)X +1837(of)X +1930(our)X +2063(commit)X +2333(strategy)X +2613(appears)X +2884(in)X +2971(the)X +3094(implementation)X +3621(section)X +3873(\(section)X +4152(4.2\).)X +2 f +555 4342(Log_unroll)N +1 f +935(reads)X +1126(log)X +1249(records)X +1507(from)X +1684(the)X +1803(log,)X +1946(following)X +2278(backward)X +2611(transaction)X +2983(pointers)X +3261(and)X +3397(calling)X +3635(the)X +3753(appropriate)X +4139(undo)X +555 4432(routines)N +839(to)X +927(implement)X +1295(transaction)X +1673(abort.)X +1904(In)X +1997(a)X +2059(similar)X +2307(manner,)X +2 f +2594(log_roll)X +1 f +2877(reads)X +3073(log)X +3201(records)X +3464(sequentially)X +3877(forward,)X +4178(cal-)X +555 4522(ling)N +699(the)X +817(appropriate)X +1203(redo)X +1366(routines)X +1644(to)X +1726(recover)X +1988(committed)X +2350(transactions)X +2753(after)X +2921(a)X +2977(system)X +3219(crash.)X +3 f +555 4708(3.2.2.)N +775(The)X +928(Buffer)X +1171(Manager)X +1 f +755 4831(The)N +3 f +912(Buffer)X +1167(Manager)X +1 f +1511(uses)X +1681(a)X +1749(pool)X +1923(of)X +2022(shared)X +2264(memory)X +2563(to)X +2657(provide)X +2934(a)X +3002(least-recently-used)X +3641(\(LRU\))X +3886(block)X +4095(cache.)X +555 4921(Although)N +886(the)X +1013(current)X +1270(library)X +1513(provides)X +1818(an)X +1923(LRU)X +2112(cache,)X +2345(it)X +2418(would)X +2647(be)X +2752(simple)X +2994(to)X +3085(add)X +3229(alternate)X +3534(replacement)X +3955(policies)X +4232(as)X +555 5011(suggested)N +903(by)X +1015([CHOU85])X +1408(or)X +1507(to)X +1601(provide)X +1878(multiple)X +2176(buffer)X +2405(pools)X +2610(with)X +2784(different)X +3092(policies.)X +3412(Transactions)X +3853(request)X +4116(pages)X +555 5101(from)N +736(the)X +859(buffer)X +1081(manager)X +1383(and)X +1524(keep)X +1701(them)X +3 f +1886(pinned)X +1 f +2145(to)X +2232(ensure)X +2466(that)X +2610(they)X +2772(are)X +2895(not)X +3021(written)X +3272(to)X +3358(disk)X +3515(while)X +3717(they)X +3879(are)X +4002(in)X +4088(a)X +4148(logi-)X +555 5191(cally)N +732(inconsistent)X +1135(state.)X +1343(When)X +1556(page)X +1729(replacement)X +2143(is)X +2217(necessary,)X +2571(the)X +3 f +2689(Buffer)X +2932(Manager)X +1 f +3264(\256nds)X +3439(an)X +3535(unpinned)X +3853(page)X +4025(and)X +4161(then)X +555 5281(checks)N +794(with)X +956(the)X +3 f +1074(Log)X +1227(Manager)X +1 f +1559(to)X +1641(ensure)X +1871(that)X +2011(the)X +2129(write-ahead)X +2529(protocol)X +2816(is)X +2889(enforced.)X +3 f +555 5467(3.2.3.)N +775(The)X +928(Lock)X +1121(Manager)X +1 f +755 5590(The)N +3 f +901(Lock)X +1095(Manager)X +1 f +1428(supports)X +1720(general)X +1978(purpose)X +2253(locking)X +2514(\(single)X +2753(writer,)X +2986(multiple)X +3273(readers\))X +3553(which)X +3769(is)X +3842(currently)X +4152(used)X +555 5680(to)N +638(provide)X +904(two-phase)X +1254(locking)X +1514(and)X +1650(high)X +1812(concurrency)X +2230(B-tree)X +2451(locking.)X +2751(However,)X +3086(the)X +3204(general)X +3461(purpose)X +3735(nature)X +3956(of)X +4043(the)X +4161(lock)X + +6 p +%%Page: 6 6 +10 s 10 xH 0 xS 1 f +3 f +1 f +555 630(manager)N +857(provides)X +1158(the)X +1281(ability)X +1510(to)X +1597(support)X +1862(a)X +1923(variety)X +2171(of)X +2263(locking)X +2528(protocols.)X +2890(Currently,)X +3241(all)X +3345(locks)X +3538(are)X +3661(issued)X +3885(at)X +3967(the)X +4089(granu-)X +555 720(larity)N +747(of)X +837(a)X +896(page)X +1071(\(the)X +1219(size)X +1367(of)X +1457(a)X +1516(buffer)X +1736(in)X +1821(the)X +1942(buffer)X +2161(pool\))X +2352(which)X +2570(is)X +2645(identi\256ed)X +2969(by)X +3071(two)X +3213(4-byte)X +3440(integers)X +3716(\(a)X +3801(\256le)X +3925(id)X +4009(and)X +4147(page)X +555 810(number\).)N +898(This)X +1071(provides)X +1378(the)X +1507(necessary)X +1851(information)X +2259(to)X +2351(extend)X +2595(the)X +3 f +2723(Lock)X +2926(Manager)X +1 f +3268(to)X +3360(perform)X +3649(hierarchical)X +4059(locking)X +555 900([GRAY76].)N +982(The)X +1133(current)X +1387(implementation)X +1915(does)X +2088(not)X +2216(support)X +2482(locks)X +2677(at)X +2760(other)X +2950(granularities)X +3376(and)X +3517(does)X +3689(not)X +3816(promote)X +4108(locks;)X +555 990(these)N +740(are)X +859(obvious)X +1132(future)X +1344(additions)X +1657(to)X +1739(the)X +1857(system.)X +755 1113(If)N +831(an)X +929(incoming)X +1253(lock)X +1413(request)X +1667(cannot)X +1903(be)X +2001(granted,)X +2284(the)X +2404(requesting)X +2760(process)X +3023(is)X +3098(queued)X +3352(for)X +3467(the)X +3586(lock)X +3745(and)X +3882(descheduled.)X +555 1203(When)N +769(a)X +827(lock)X +987(is)X +1062(released,)X +1368(the)X +1488(wait)X +1647(queue)X +1860(is)X +1934(traversed)X +2250(and)X +2387(any)X +2524(newly)X +2741(compatible)X +3118(locks)X +3308(are)X +3428(granted.)X +3730(Locks)X +3947(are)X +4067(located)X +555 1293(via)N +680(a)X +743(\256le)X +872(and)X +1015(page)X +1194(hash)X +1368(table)X +1551(and)X +1694(are)X +1820(chained)X +2097(both)X +2266(by)X +2373(object)X +2595(and)X +2737(by)X +2843(transaction,)X +3241(facilitating)X +3614(rapid)X +3805(traversal)X +4108(of)X +4201(the)X +555 1383(lock)N +713(table)X +889(during)X +1118(transaction)X +1490(commit)X +1754(and)X +1890(abort.)X +755 1506(The)N +907(primary)X +1188(interfaces)X +1528(to)X +1617(the)X +1742(lock)X +1907(manager)X +2211(are)X +2 f +2337(lock)X +1 f +2471(,)X +2 f +2518(unlock)X +1 f +2732(,)X +2779(and)X +2 f +2922(lock_unlock_all)X +1 f +3434(.)X +2 f +3500(Lock)X +1 f +3682(obtains)X +3939(a)X +4001(new)X +4161(lock)X +555 1596(for)N +680(a)X +747(speci\256c)X +1023(object.)X +1290(There)X +1509(are)X +1638(also)X +1797(two)X +1947(variants)X +2231(of)X +2328(the)X +2 f +2456(lock)X +1 f +2620(request,)X +2 f +2902(lock_upgrade)X +1 f +3373(and)X +2 f +3519(lock_downgrade)X +1 f +4053(,)X +4103(which)X +555 1686(allow)N +755(the)X +875(caller)X +1076(to)X +1160(atomically)X +1519(trade)X +1701(a)X +1758(lock)X +1917(of)X +2005(one)X +2142(type)X +2301(for)X +2416(a)X +2473(lock)X +2632(of)X +2720(another.)X +2 f +3022(Unlock)X +1 f +3275(releases)X +3551(a)X +3608(speci\256c)X +3874(mode)X +4073(of)X +4161(lock)X +555 1776(on)N +655(a)X +711(speci\256c)X +976(object.)X +2 f +1232(Lock_unlock_all)X +1 f +1786(releases)X +2061(all)X +2161(the)X +2279(locks)X +2468(associated)X +2818(with)X +2980(a)X +3036(speci\256c)X +3301(transaction.)X +3 f +555 1962(3.2.4.)N +775(The)X +928(Process)X +1207(Manager)X +1 f +755 2085(The)N +3 f +900(Process)X +1179(Manager)X +1 f +1511(acts)X +1656(as)X +1743(a)X +1799(user-level)X +2136(scheduler)X +2464(to)X +2546(make)X +2740(processes)X +3068(wait)X +3226(on)X +3326(unavailable)X +3716(locks)X +3905(and)X +4041(pending)X +555 2175(buffer)N +778(cache)X +988(I/O.)X +1161(For)X +1297(each)X +1470(process,)X +1756(a)X +1817(semaphore)X +2190(is)X +2268(maintained)X +2649(upon)X +2834(which)X +3055(that)X +3200(process)X +3466(waits)X +3660(when)X +3859(it)X +3928(needs)X +4136(to)X +4223(be)X +555 2265(descheduled.)N +1014(When)X +1228(a)X +1286(process)X +1549(needs)X +1754(to)X +1838(be)X +1936(run,)X +2084(its)X +2180(semaphore)X +2549(is)X +2623(cleared,)X +2897(and)X +3034(the)X +3153(operating)X +3477(system)X +3720(reschedules)X +4116(it.)X +4201(No)X +555 2355(sophisticated)N +1002(scheduling)X +1378(algorithm)X +1718(is)X +1799(applied;)X +2085(if)X +2162(the)X +2288(lock)X +2454(for)X +2576(which)X +2800(a)X +2864(process)X +3133(was)X +3286(waiting)X +3554(becomes)X +3863(available,)X +4201(the)X +555 2445(process)N +824(is)X +905(made)X +1107(runnable.)X +1456(It)X +1533(would)X +1761(have)X +1941(been)X +2121(possible)X +2411(to)X +2501(change)X +2757(the)X +2883(kernel's)X +3170(process)X +3439(scheduler)X +3775(to)X +3865(interact)X +4134(more)X +555 2535(ef\256ciently)N +900(with)X +1062(the)X +1180(lock)X +1338(manager,)X +1655(but)X +1777(doing)X +1979(so)X +2070(would)X +2290(have)X +2462(compromised)X +2918(our)X +3045(commitment)X +3469(to)X +3551(a)X +3607(user-level)X +3944(package.)X +3 f +555 2721(3.2.5.)N +775(The)X +928(Transaction)X +1361(Manager)X +1 f +755 2844(The)N +3 f +901(Transaction)X +1335(Manager)X +1 f +1668(provides)X +1965(the)X +2084(standard)X +2377(interface)X +2680(of)X +2 f +2768(txn_begin)X +1 f +3084(,)X +2 f +3125(txn_commit)X +1 f +3499(,)X +3540(and)X +2 f +3676(txn_abort)X +1 f +3987(.)X +4047(It)X +4116(keeps)X +555 2934(track)N +742(of)X +835(all)X +941(active)X +1159(transactions,)X +1588(assigns)X +1845(unique)X +2089(transaction)X +2467(identi\256ers,)X +2833(and)X +2974(directs)X +3213(the)X +3336(abort)X +3526(and)X +3667(commit)X +3936(processing.)X +555 3024(When)N +772(a)X +2 f +833(txn_begin)X +1 f +1174(is)X +1252(issued,)X +1497(the)X +3 f +1620(Transaction)X +2058(Manager)X +1 f +2395(assigns)X +2651(the)X +2773(next)X +2935(available)X +3249(transaction)X +3625(identi\256er,)X +3958(allocates)X +4263(a)X +555 3114(per-process)N +948(transaction)X +1322(structure)X +1625(in)X +1709(shared)X +1941(memory,)X +2249(increments)X +2622(the)X +2741(count)X +2940(of)X +3028(active)X +3241(transactions,)X +3665(and)X +3802(returns)X +4046(the)X +4165(new)X +555 3204(transaction)N +937(identi\256er)X +1256(to)X +1348(the)X +1476(calling)X +1724(process.)X +2034(The)X +2188(in-memory)X +2573(transaction)X +2954(structure)X +3264(contains)X +3560(a)X +3625(pointer)X +3881(into)X +4034(the)X +4161(lock)X +555 3294(table)N +734(for)X +851(locks)X +1043(held)X +1204(by)X +1307(this)X +1445(transaction,)X +1840(the)X +1961(last)X +2095(log)X +2220(sequence)X +2538(number,)X +2826(a)X +2885(transaction)X +3260(state)X +3430(\()X +2 f +3457(idle)X +1 f +(,)S +2 f +3620(running)X +1 f +3873(,)X +2 f +3915(aborting)X +1 f +4190(,)X +4232(or)X +2 f +555 3384(committing\))N +1 f +942(,)X +982(an)X +1078(error)X +1255(code,)X +1447(and)X +1583(a)X +1639(semaphore)X +2007(identi\256er.)X +755 3507(At)N +859(commit,)X +1147(the)X +3 f +1269(Transaction)X +1706(Manager)X +1 f +2042(calls)X +2 f +2213(log_commit)X +1 f +2615(to)X +2700(record)X +2929(the)X +3050(end)X +3189(of)X +3279(transaction)X +3654(and)X +3793(to)X +3878(\257ush)X +4056(the)X +4177(log.)X +555 3597(Then)N +743(it)X +810(directs)X +1047(the)X +3 f +1168(Lock)X +1364(Manager)X +1 f +1699(to)X +1784(release)X +2031(all)X +2134(locks)X +2325(associated)X +2677(with)X +2841(the)X +2961(given)X +3161(transaction.)X +3575(If)X +3651(a)X +3709(transaction)X +4083(aborts,)X +555 3687(the)N +3 f +680(Transaction)X +1120(Manager)X +1 f +1459(calls)X +1633(on)X +2 f +1739(log_unroll)X +1 f +2102(to)X +2190(read)X +2355(the)X +2479(transaction's)X +2915(log)X +3043(records)X +3306(and)X +3448(undo)X +3634(any)X +3776(modi\256cations)X +4237(to)X +555 3777(the)N +673(database.)X +1010(As)X +1119(in)X +1201(the)X +1319(commit)X +1583(case,)X +1762(it)X +1826(then)X +1984(calls)X +2 f +2151(lock_unlock_all)X +1 f +2683(to)X +2765(release)X +3009(the)X +3127(transaction's)X +3557(locks.)X +3 f +555 3963(3.2.6.)N +775(The)X +928(Record)X +1198(Manager)X +1 f +755 4086(The)N +3 f +919(Record)X +1208(Manager)X +1 f +1559(supports)X +1869(the)X +2006(abstraction)X +2397(of)X +2503(reading)X +2783(and)X +2938(writing)X +3208(records)X +3484(to)X +3585(a)X +3660(database.)X +3996(We)X +4147(have)X +555 4176(modi\256ed)N +861(the)X +981(the)X +1101(database)X +1399(access)X +1626(routines)X +3 f +1905(db)X +1 f +1993(\(3\))X +2108([BSD91])X +2418(to)X +2501(call)X +2638(the)X +2757(log,)X +2900(lock,)X +3079(and)X +3216(buffer)X +3434(managers.)X +3803(In)X +3891(order)X +4082(to)X +4165(pro-)X +555 4266(vide)N +718(functionality)X +1152(to)X +1239(perform)X +1523(undo)X +1708(and)X +1849(redo,)X +2037(the)X +3 f +2160(Record)X +2434(Manager)X +1 f +2770(de\256nes)X +3021(a)X +3081(collection)X +3421(of)X +3512(log)X +3638(record)X +3868(types)X +4061(and)X +4201(the)X +555 4356(associated)N +920(undo)X +1115(and)X +1266(redo)X +1444(routines.)X +1777(The)X +3 f +1937(Log)X +2105(Manager)X +1 f +2452(performs)X +2777(a)X +2848(table)X +3039(lookup)X +3296(on)X +3411(the)X +3543(record)X +3783(type)X +3955(to)X +4051(call)X +4201(the)X +555 4446(appropriate)N +951(routines.)X +1299(For)X +1440(example,)X +1762(the)X +1890(B-tree)X +2121(access)X +2356(method)X +2625(requires)X +2913(two)X +3062(log)X +3193(record)X +3428(types:)X +3648(insert)X +3855(and)X +4000(delete.)X +4241(A)X +555 4536(replace)N +808(operation)X +1131(is)X +1204(implemented)X +1642(as)X +1729(a)X +1785(delete)X +1997(followed)X +2302(by)X +2402(an)X +2498(insert)X +2696(and)X +2832(is)X +2905(logged)X +3143(accordingly.)X +3 f +555 4722(3.3.)N +715(Application)X +1134(Architectures)X +1 f +755 4845(The)N +907(structure)X +1215(of)X +1309(LIBTP)X +1558(allows)X +1794(application)X +2177(designers)X +2507(to)X +2596(trade)X +2784(off)X +2905(performance)X +3339(and)X +3481(protection.)X +3872(Since)X +4076(a)X +4138(large)X +555 4935(portion)N +810(of)X +901(LIBTP's)X +1205(functionality)X +1638(is)X +1715(provided)X +2024(by)X +2128(managing)X +2468(structures)X +2804(in)X +2889(shared)X +3122(memory,)X +3432(its)X +3530(structures)X +3865(are)X +3987(subject)X +4237(to)X +555 5025(corruption)N +926(by)X +1043(applications)X +1467(when)X +1678(the)X +1813(library)X +2064(is)X +2154(linked)X +2391(directly)X +2673(with)X +2852(the)X +2987(application.)X +3420(For)X +3568(this)X +3720(reason,)X +3987(LIBTP)X +4246(is)X +555 5115(designed)N +864(to)X +950(allow)X +1152(compilation)X +1558(into)X +1706(a)X +1766(separate)X +2053(server)X +2273(process)X +2537(which)X +2756(may)X +2917(be)X +3016(accessed)X +3321(via)X +3442(a)X +3501(socket)X +3729(interface.)X +4094(In)X +4184(this)X +555 5205(way)N +712(LIBTP's)X +1015(data)X +1172(structures)X +1507(are)X +1629(protected)X +1951(from)X +2130(application)X +2509(code,)X +2704(but)X +2829(communication)X +3349(overhead)X +3666(is)X +3741(increased.)X +4107(When)X +555 5295(applications)N +975(are)X +1107(trusted,)X +1377(LIBTP)X +1631(may)X +1801(be)X +1909(compiled)X +2239(directly)X +2516(into)X +2672(the)X +2802(application)X +3190(providing)X +3533(improved)X +3872(performance.)X +555 5385(Figures)N +815(two)X +955(and)X +1091(three)X +1272(show)X +1461(the)X +1579(two)X +1719(alternate)X +2016(application)X +2392(architectures.)X +755 5508(There)N +964(are)X +1084(potentially)X +1447(two)X +1588(modes)X +1818(in)X +1901(which)X +2118(one)X +2255(might)X +2462(use)X +2590(LIBTP)X +2833(in)X +2916(a)X +2972(server)X +3189(based)X +3392(architecture.)X +3832(In)X +3919(the)X +4037(\256rst,)X +4201(the)X +555 5598(server)N +778(would)X +1004(provide)X +1275(the)X +1399(capability)X +1741(to)X +1829(respond)X +2109(to)X +2197(requests)X +2486(to)X +2574(each)X +2747(of)X +2839(the)X +2962(low)X +3107(level)X +3288(modules)X +3584(\(lock,)X +3794(log,)X +3941(buffer,)X +4183(and)X +555 5688(transaction)N +944(managers\).)X +1356(Unfortunately,)X +1863(the)X +1998(performance)X +2442(of)X +2546(such)X +2730(a)X +2803(system)X +3062(is)X +3152(likely)X +3371(to)X +3470(be)X +3583(blindingly)X +3947(slow)X +4134(since)X + +7 p +%%Page: 7 7 +10 s 10 xH 0 xS 1 f +3 f +1 f +1 Dt +1864 1125 MXY +15 -26 Dl +-15 10 Dl +-14 -10 Dl +14 26 Dl +0 -266 Dl +1315 1125 MXY +15 -26 Dl +-15 10 Dl +-14 -10 Dl +14 26 Dl +0 -266 Dl +3 Dt +1133 1125 MXY +0 798 Dl +931 0 Dl +0 -798 Dl +-931 0 Dl +1 Dt +1266 1257 MXY +0 133 Dl +665 0 Dl +0 -133 Dl +-665 0 Dl +3 f +8 s +1513 1351(driver)N +1502 1617(LIBTP)N +1266 1390 MXY +0 400 Dl +665 0 Dl +0 -400 Dl +-665 0 Dl +3 Dt +1133 726 MXY +0 133 Dl +931 0 Dl +0 -133 Dl +-931 0 Dl +1 f +1029 1098(txn_abort)N +964 1015(txn_commit)N +1018 932(txn_begin)N +1910 1015(db_ops)N +3 f +1308 820(Application)N +1645(Program)X +1398 1218(Server)N +1594(Process)X +1 f +1390 986(socket)N +1569(interface)X +1 Dt +1848 967 MXY +-23 -14 Dl +8 14 Dl +-8 15 Dl +23 -15 Dl +-50 0 Dl +1324 MX +23 15 Dl +-9 -15 Dl +9 -14 Dl +-23 14 Dl +50 0 Dl +3 Dt +2862 859 MXY +0 1064 Dl +932 0 Dl +0 -1064 Dl +-932 0 Dl +1 Dt +3178 1390 MXY +24 -12 Dl +-17 0 Dl +-8 -15 Dl +1 27 Dl +150 -265 Dl +3494 1390 MXY +0 -27 Dl +-8 15 Dl +-16 1 Dl +24 11 Dl +-166 -265 Dl +3 f +3232 1617(LIBTP)N +2995 1390 MXY +0 400 Dl +666 0 Dl +0 -400 Dl +-666 0 Dl +992 MY +0 133 Dl +666 0 Dl +0 -133 Dl +-666 0 Dl +3168 1086(Application)N +1 f +2939 1201(txn_begin)N +2885 1284(txn_commit)N +2950 1368(txn_abort)N +3465 1284(db_ops)N +3 f +3155 766(Single)N +3339(Process)X +3 Dt +-1 Ds +811 2100(Figure)N +1023(2:)X +1107(Server)X +1318(Architecture.)X +1 f +1727(In)X +1811(this)X +1934(con\256guration,)X +811 2190(the)N +916(library)X +1113(is)X +1183(loaded)X +1380(into)X +1507(a)X +1562(server)X +1744(process)X +1962(which)X +2145(is)X +2214(ac-)X +811 2280(cessed)N +993(via)X +1087(a)X +1131(socket)X +1310(interface.)X +3 f +2563 2100(Figure)N +2803(3:)X +2914(Single)X +3140(Process)X +3403(Architecture.)X +1 f +3839(In)X +3950(this)X +2563 2190(con\256guration,)N +2948(the)X +3053(library)X +3250(routines)X +3483(are)X +3587(loaded)X +3784(as)X +3864(part)X +3990(of)X +2563 2280(the)N +2657(application)X +2957(and)X +3065(accessed)X +3303(via)X +3397(a)X +3441(subroutine)X +3727(interface.)X +10 s +10 f +555 2403(h)N +579(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)X +1 f +555 2679(modifying)N +909(a)X +966(piece)X +1157(of)X +1245(data)X +1400(would)X +1621(require)X +1870(three)X +2051(or)X +2138(possibly)X +2424(four)X +2578(separate)X +2862(communications:)X +3433(one)X +3569(to)X +3651(lock)X +3809(the)X +3927(data,)X +4101(one)X +4237(to)X +555 2769(obtain)N +781(the)X +905(data,)X +1085(one)X +1227(to)X +1315(log)X +1443(the)X +1567(modi\256cation,)X +2017(and)X +2159(possibly)X +2451(one)X +2593(to)X +2681(transmit)X +2969(the)X +3093(modi\256ed)X +3403(data.)X +3583(Figure)X +3817(four)X +3976(shows)X +4201(the)X +555 2859(relative)N +826(performance)X +1263(for)X +1387(retrieving)X +1728(a)X +1793(single)X +2013(record)X +2248(using)X +2450(the)X +2577(record)X +2812(level)X +2997(call)X +3142(versus)X +3376(using)X +3578(the)X +3705(lower)X +3917(level)X +4102(buffer)X +555 2949(management)N +987(and)X +1125(locking)X +1387(calls.)X +1616(The)X +1763(2:1)X +1887(ratio)X +2056(observed)X +2367(in)X +2450(the)X +2569(single)X +2781(process)X +3043(case)X +3203(re\257ects)X +3456(the)X +3575(additional)X +3916(overhead)X +4232(of)X +555 3039(parsing)N +819(eight)X +1006(commands)X +1380(rather)X +1595(than)X +1760(one)X +1903(while)X +2108(the)X +2233(3:1)X +2362(ratio)X +2536(observed)X +2853(in)X +2942(the)X +3067(client/server)X +3491(architecture)X +3898(re\257ects)X +4157(both)X +555 3129(the)N +679(parsing)X +941(and)X +1083(the)X +1207(communication)X +1731(overheard.)X +2118(Although)X +2445(there)X +2631(may)X +2794(be)X +2895(applications)X +3307(which)X +3528(could)X +3731(tolerate)X +3997(such)X +4169(per-)X +555 3219(formance,)N +904(it)X +973(seems)X +1194(far)X +1309(more)X +1499(feasible)X +1774(to)X +1861(support)X +2126(a)X +2187(higher)X +2417(level)X +2597(interface,)X +2923(such)X +3094(as)X +3185(that)X +3329(provided)X +3638(by)X +3742(a)X +3802(query)X +4009(language)X +555 3309(\()N +2 f +582(e.g.)X +1 f +718(SQL)X +889([SQL86]\).)X +755 3432(Although)N +1081(LIBTP)X +1327(does)X +1498(not)X +1624(have)X +1800(an)X +1900(SQL)X +2075(parser,)X +2316(we)X +2433(have)X +2608(built)X +2777(a)X +2836(server)X +3056(application)X +3435(using)X +3631(the)X +3752(toolkit)X +3983(command)X +555 3522(language)N +882(\(TCL\))X +1124([OUST90].)X +1544(The)X +1706(server)X +1940(supports)X +2248(a)X +2321(command)X +2674(line)X +2831(interface)X +3150(similar)X +3409(to)X +3508(the)X +3643(subroutine)X +4017(interface)X +555 3612(de\256ned)N +811(in)X +3 f +893(db)X +1 f +981(\(3\).)X +1135(Since)X +1333(it)X +1397(is)X +1470(based)X +1673(on)X +1773(TCL,)X +1964(it)X +2028(provides)X +2324(control)X +2571(structures)X +2903(as)X +2990(well.)X +3 f +555 3798(4.)N +655(Implementation)X +1 f +3 f +555 3984(4.1.)N +715(Locking)X +1014(and)X +1162(Deadlock)X +1502(Detection)X +1 f +755 4107(LIBTP)N +1007(uses)X +1175(two-phase)X +1535(locking)X +1805(for)X +1929(user)X +2093(data.)X +2297(Strictly)X +2562(speaking,)X +2897(the)X +3024(two)X +3173(phases)X +3416(in)X +3507(two-phase)X +3866(locking)X +4135(are)X +4263(a)X +3 f +555 4197(grow)N +1 f +756(phase,)X +986(during)X +1221(which)X +1443(locks)X +1638(are)X +1763(acquired,)X +2086(and)X +2228(a)X +3 f +2290(shrink)X +1 f +2537(phase,)X +2766(during)X +3001(which)X +3223(locks)X +3418(are)X +3543(released.)X +3873(No)X +3997(lock)X +4161(may)X +555 4287(ever)N +720(be)X +822(acquired)X +1124(during)X +1358(the)X +1481(shrink)X +1706(phase.)X +1954(The)X +2104(grow)X +2294(phase)X +2502(lasts)X +2669(until)X +2840(the)X +2963(\256rst)X +3112(release,)X +3381(which)X +3602(marks)X +3823(the)X +3946(start)X +4109(of)X +4201(the)X +555 4377(shrink)N +780(phase.)X +1028(In)X +1120(practice,)X +1420(the)X +1543(grow)X +1733(phase)X +1941(lasts)X +2108(for)X +2227(the)X +2350(duration)X +2642(of)X +2734(a)X +2795(transaction)X +3172(in)X +3259(LIBTP)X +3506(and)X +3647(in)X +3734(commercial)X +4138(data-)X +555 4467(base)N +721(systems.)X +1037(The)X +1184(shrink)X +1406(phase)X +1611(takes)X +1798(place)X +1990(during)X +2221(transaction)X +2595(commit)X +2861(or)X +2950(abort.)X +3177(This)X +3341(means)X +3568(that)X +3710(locks)X +3901(are)X +4022(acquired)X +555 4557(on)N +655(demand)X +929(during)X +1158(the)X +1276(lifetime)X +1545(of)X +1632(a)X +1688(transaction,)X +2080(and)X +2216(held)X +2374(until)X +2540(commit)X +2804(time,)X +2986(at)X +3064(which)X +3280(point)X +3464(all)X +3564(locks)X +3753(are)X +3872(released.)X +755 4680(If)N +832(multiple)X +1121(transactions)X +1527(are)X +1649(active)X +1864(concurrently,)X +2313(deadlocks)X +2657(can)X +2792(occur)X +2994(and)X +3133(must)X +3311(be)X +3410(detected)X +3701(and)X +3840(resolved.)X +4174(The)X +555 4770(lock)N +715(table)X +893(can)X +1027(be)X +1125(thought)X +1391(of)X +1480(as)X +1569(a)X +1627(representation)X +2104(of)X +2193(a)X +2251(directed)X +2532(graph.)X +2777(The)X +2924(nodes)X +3133(in)X +3216(the)X +3335(graph)X +3539(are)X +3659(transactions.)X +4103(Edges)X +555 4860(represent)N +878(the)X +3 f +1004(waits-for)X +1 f +1340(relation)X +1613(between)X +1909(transactions;)X +2342(if)X +2419(transaction)X +2 f +2799(A)X +1 f +2876(is)X +2957(waiting)X +3225(for)X +3347(a)X +3411(lock)X +3577(held)X +3743(by)X +3851(transaction)X +2 f +4230(B)X +1 f +4279(,)X +555 4950(then)N +716(a)X +775(directed)X +1057(edge)X +1232(exists)X +1437(from)X +2 f +1616(A)X +1 f +1687(to)X +2 f +1771(B)X +1 f +1842(in)X +1926(the)X +2046(graph.)X +2291(A)X +2371(deadlock)X +2683(exists)X +2887(if)X +2958(a)X +3016(cycle)X +3208(appears)X +3476(in)X +3560(the)X +3680(graph.)X +3925(By)X +4040(conven-)X +555 5040(tion,)N +719(no)X +819(transaction)X +1191(ever)X +1350(waits)X +1539(for)X +1653(a)X +1709(lock)X +1867(it)X +1931(already)X +2188(holds,)X +2401(so)X +2492(re\257exive)X +2793(edges)X +2996(are)X +3115(impossible.)X +755 5163(A)N +836(distinguished)X +1285(process)X +1549(monitors)X +1856(the)X +1977(lock)X +2138(table,)X +2337(searching)X +2668(for)X +2785(cycles.)X +3048(The)X +3195(frequency)X +3539(with)X +3703(which)X +3921(this)X +4058(process)X +555 5253(runs)N +716(is)X +792(user-settable;)X +1243(for)X +1360(the)X +1481(multi-user)X +1833(tests)X +1998(discussed)X +2328(in)X +2413(section)X +2663(5.1.2,)X +2866(it)X +2933(has)X +3063(been)X +3238(set)X +3350(to)X +3435(wake)X +3628(up)X +3731(every)X +3932(second,)X +4197(but)X +555 5343(more)N +742(sophisticated)X +1182(schedules)X +1516(are)X +1636(certainly)X +1938(possible.)X +2261(When)X +2474(a)X +2531(cycle)X +2722(is)X +2796(detected,)X +3105(one)X +3242(of)X +3330(the)X +3449(transactions)X +3853(in)X +3936(the)X +4055(cycle)X +4246(is)X +555 5433(nominated)N +917(and)X +1057(aborted.)X +1362(When)X +1578(the)X +1700(transaction)X +2076(aborts,)X +2315(it)X +2382(rolls)X +2547(back)X +2722(its)X +2820(changes)X +3102(and)X +3241(releases)X +3519(its)X +3617(locks,)X +3829(thereby)X +4093(break-)X +555 5523(ing)N +677(the)X +795(cycle)X +985(in)X +1067(the)X +1185(graph.)X + +8 p +%%Page: 8 8 +10 s 10 xH 0 xS 1 f +3 f +1 f +4 Ds +1 Dt +1866 865 MXY +1338 0 Dl +1866 1031 MXY +1338 0 Dl +1866 1199 MXY +1338 0 Dl +1866 1366 MXY +1338 0 Dl +1866 1533 MXY +1338 0 Dl +1866 1701 MXY +1338 0 Dl +-1 Ds +5 Dt +1866 1868 MXY +1338 0 Dl +1 Dt +1 Di +2981 MX + 2981 1868 lineto + 2981 1575 lineto + 3092 1575 lineto + 3092 1868 lineto + 2981 1868 lineto +closepath 21 2981 1575 3092 1868 Dp +2646 MX + 2646 1868 lineto + 2646 949 lineto + 2758 949 lineto + 2758 1868 lineto + 2646 1868 lineto +closepath 14 2646 949 2758 1868 Dp +2312 MX + 2312 1868 lineto + 2312 1701 lineto + 2423 1701 lineto + 2423 1868 lineto + 2312 1868 lineto +closepath 3 2312 1701 2423 1868 Dp +1977 MX + 1977 1868 lineto + 1977 1512 lineto + 2089 1512 lineto + 2089 1868 lineto + 1977 1868 lineto +closepath 19 1977 1512 2089 1868 Dp +3 f +2640 2047(Client/Server)N +1957(Single)X +2185(Process)X +7 s +2957 1957(record)N +2570(component)X +2289(record)X +1890(components)X +1733 1724(.1)N +1733 1556(.2)N +1733 1389(.3)N +1733 1222(.4)N +1733 1055(.5)N +1733 889(.6)N +1590 726(Elapsed)N +1794(Time)X +1613 782(\(in)N +1693(seconds\))X +3 Dt +-1 Ds +8 s +555 2255(Figure)N +756(4:)X +829(Comparison)X +1187(of)X +1260(High)X +1416(and)X +1540(Low)X +1681(Level)X +1850(Interfaces.)X +1 f +2174(Elapsed)X +2395(time)X +2528(in)X +2597(seconds)X +2818(to)X +2887(perform)X +3111(a)X +3158(single)X +3330(record)X +3511(retrieval)X +3742(from)X +3885(a)X +3932(command)X +4203(line)X +555 2345(\(rather)N +751(than)X +888(a)X +943(procedural)X +1241(interface\))X +1510(is)X +1579(shown)X +1772(on)X +1862(the)X +1966(y)X +2024(axis.)X +2185(The)X +2310(``component'')X +2704(numbers)X +2950(re\257ect)X +3135(the)X +3239(timings)X +3458(when)X +3622(the)X +3726(record)X +3914(is)X +3983(retrieved)X +4235(by)X +555 2435(separate)N +785(calls)X +924(to)X +996(the)X +1096(lock)X +1228(manager)X +1469(and)X +1583(buffer)X +1760(manager)X +2001(while)X +2165(the)X +2264(``record'')X +2531(timings)X +2745(were)X +2889(obtained)X +3130(by)X +3215(using)X +3375(a)X +3424(single)X +3598(call)X +3711(to)X +3782(the)X +3881(record)X +4064(manager.)X +555 2525(The)N +674(2:1)X +776(ratio)X +913(observed)X +1163(for)X +1257(the)X +1355(single)X +1528(process)X +1739(case)X +1868(is)X +1930(a)X +1977(re\257ection)X +2237(of)X +2309(the)X +2406(parsing)X +2613(overhead)X +2865(for)X +2958(executing)X +3225(eight)X +3372(separate)X +3599(commands)X +3895(rather)X +4062(than)X +4191(one.)X +555 2615(The)N +673(additional)X +948(factor)X +1115(of)X +1187(one)X +1298(re\257ected)X +1536(in)X +1605(the)X +1702(3:1)X +1803(ratio)X +1939(for)X +2031(the)X +2127(client/server)X +2460(architecture)X +2794(is)X +2855(due)X +2965(to)X +3033(the)X +3129(communication)X +3545(overhead.)X +3828(The)X +3945(true)X +4062(ratios)X +4222(are)X +555 2705(actually)N +775(worse)X +945(since)X +1094(the)X +1190(component)X +1492(timings)X +1703(do)X +1785(not)X +1884(re\257ect)X +2060(the)X +2155(search)X +2334(times)X +2490(within)X +2671(each)X +2804(page)X +2941(or)X +3011(the)X +3106(time)X +3237(required)X +3466(to)X +3533(transmit)X +3760(the)X +3855(page)X +3992(between)X +4221(the)X +555 2795(two)N +667(processes.)X +10 s +10 f +555 2885(h)N +579(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)X +3 f +555 3161(4.2.)N +715(Group)X +961(Commit)X +1 f +755 3284(Since)N +959(the)X +1083(log)X +1211(must)X +1392(be)X +1494(\257ushed)X +1751(to)X +1839(disk)X +1997(at)X +2080(commit)X +2349(time,)X +2536(disk)X +2694(bandwidth)X +3057(fundamentally)X +3545(limits)X +3751(the)X +3874(rate)X +4020(at)X +4103(which)X +555 3374(transactions)N +959(complete.)X +1314(Since)X +1513(most)X +1688(transactions)X +2091(write)X +2276(only)X +2438(a)X +2494(few)X +2635(small)X +2828(records)X +3085(to)X +3167(the)X +3285(log,)X +3427(the)X +3545(last)X +3676(page)X +3848(of)X +3935(the)X +4053(log)X +4175(will)X +555 3464(be)N +658(\257ushed)X +916(once)X +1095(by)X +1202(every)X +1408(transaction)X +1787(which)X +2010(writes)X +2233(to)X +2322(it.)X +2433(In)X +2527(the)X +2652(naive)X +2853(implementation,)X +3402(these)X +3593(\257ushes)X +3841(would)X +4067(happen)X +555 3554(serially.)N +755 3677(LIBTP)N +1008(uses)X +3 f +1177(group)X +1412(commit)X +1 f +1702([DEWI84])X +2077(in)X +2170(order)X +2371(to)X +2464(amortize)X +2775(the)X +2903(cost)X +3062(of)X +3159(one)X +3305(synchronous)X +3740(disk)X +3903(write)X +4098(across)X +555 3767(multiple)N +851(transactions.)X +1304(Group)X +1539(commit)X +1812(provides)X +2117(a)X +2182(way)X +2345(for)X +2468(a)X +2533(group)X +2749(of)X +2845(transactions)X +3257(to)X +3348(commit)X +3621(simultaneously.)X +4174(The)X +555 3857(\256rst)N +709(several)X +967(transactions)X +1380(to)X +1472(commit)X +1745(write)X +1939(their)X +2115(changes)X +2403(to)X +2494(the)X +2621(in-memory)X +3006(log)X +3137(page,)X +3338(then)X +3505(sleep)X +3699(on)X +3808(a)X +3873(distinguished)X +555 3947(semaphore.)N +966(Later,)X +1179(a)X +1238(committing)X +1629(transaction)X +2004(\257ushes)X +2249(the)X +2370(page)X +2545(to)X +2630(disk,)X +2805(and)X +2943(wakes)X +3166(up)X +3268(all)X +3370(its)X +3467(sleeping)X +3756(peers.)X +3988(The)X +4135(point)X +555 4037(at)N +635(which)X +853(changes)X +1134(are)X +1255(actually)X +1531(written)X +1780(is)X +1855(determined)X +2238(by)X +2340(three)X +2523(thresholds.)X +2914(The)X +3061(\256rst)X +3207(is)X +3281(the)X +2 f +3400(group)X +3612(threshold)X +1 f +3935(and)X +4072(de\256nes)X +555 4127(the)N +674(minimum)X +1005(number)X +1271(of)X +1359(transactions)X +1763(which)X +1979(must)X +2154(be)X +2250(active)X +2462(in)X +2544(the)X +2662(system)X +2904(before)X +3130(transactions)X +3533(are)X +3652(forced)X +3878(to)X +3960(participate)X +555 4217(in)N +646(a)X +711(group)X +927(commit.)X +1240(The)X +1394(second)X +1646(is)X +1728(the)X +2 f +1855(wait)X +2021(threshold)X +1 f +2352(which)X +2577(is)X +2658(expressed)X +3003(as)X +3098(the)X +3224(percentage)X +3601(of)X +3696(active)X +3916(transactions)X +555 4307(waiting)N +826(to)X +919(be)X +1026(committed.)X +1439(The)X +1595(last)X +1737(is)X +1821(the)X +2 f +1950(logdelay)X +2257(threshold)X +1 f +2590(which)X +2816(indicates)X +3131(how)X +3299(much)X +3507(un\257ushed)X +3848(log)X +3980(should)X +4223(be)X +555 4397(allowed)N +829(to)X +911(accumulate)X +1297(before)X +1523(a)X +1579(waiting)X +1839(transaction's)X +2289(commit)X +2553(record)X +2779(is)X +2852(\257ushed.)X +755 4520(Group)N +981(commit)X +1246(can)X +1379(substantially)X +1803(improve)X +2090(performance)X +2517(for)X +2631(high-concurrency)X +3218(environments.)X +3714(If)X +3788(only)X +3950(a)X +4006(few)X +4147(tran-)X +555 4610(sactions)N +836(are)X +957(running,)X +1248(it)X +1314(is)X +1389(unlikely)X +1673(to)X +1757(improve)X +2046(things)X +2263(at)X +2343(all.)X +2485(The)X +2632(crossover)X +2962(point)X +3148(is)X +3223(the)X +3343(point)X +3529(at)X +3609(which)X +3827(the)X +3947(transaction)X +555 4700(commit)N +823(rate)X +968(is)X +1045(limited)X +1295(by)X +1399(the)X +1521(bandwidth)X +1883(of)X +1974(the)X +2096(device)X +2330(on)X +2434(which)X +2654(the)X +2776(log)X +2902(resides.)X +3189(If)X +3267(processes)X +3599(are)X +3722(trying)X +3937(to)X +4023(\257ush)X +4201(the)X +555 4790(log)N +677(faster)X +876(than)X +1034(the)X +1152(log)X +1274(disk)X +1427(can)X +1559(accept)X +1785(data,)X +1959(then)X +2117(group)X +2324(commit)X +2588(will)X +2732(increase)X +3016(the)X +3134(commit)X +3398(rate.)X +3 f +555 4976(4.3.)N +715(Kernel)X +971(Intervention)X +1418(for)X +1541(Synchronization)X +1 f +755 5099(Since)N +954(LIBTP)X +1197(uses)X +1356(data)X +1511(in)X +1594(shared)X +1825(memory)X +2113(\()X +2 f +2140(e.g.)X +1 f +2277(the)X +2395(lock)X +2553(table)X +2729(and)X +2865(buffer)X +3082(pool\))X +3271(it)X +3335(must)X +3510(be)X +3606(possible)X +3888(for)X +4002(a)X +4058(process)X +555 5189(to)N +640(acquire)X +900(exclusive)X +1226(access)X +1454(to)X +1538(shared)X +1770(data)X +1926(in)X +2010(order)X +2202(to)X +2286(prevent)X +2549(corruption.)X +2945(In)X +3034(addition,)X +3338(the)X +3458(process)X +3721(manager)X +4020(must)X +4197(put)X +555 5279(processes)N +886(to)X +971(sleep)X +1159(when)X +1356(the)X +1477(lock)X +1638(or)X +1728(buffer)X +1948(they)X +2109(request)X +2364(is)X +2440(in)X +2525(use)X +2655(by)X +2758(some)X +2950(other)X +3138(process.)X +3441(In)X +3530(the)X +3650(LIBTP)X +3894(implementa-)X +555 5385(tion)N +705(under)X +914(Ultrix)X +1131(4.0)X +7 s +5353(2)Y +10 s +5385(,)Y +1305(we)X +1424(use)X +1556(System)X +1816(V)X +1899(semaphores)X +2303(to)X +2390(provide)X +2660(this)X +2800(synchronization.)X +3377(Semaphores)X +3794(implemented)X +4237(in)X +555 5475(this)N +701(fashion)X +968(turn)X +1128(out)X +1261(to)X +1354(be)X +1461(an)X +1568(expensive)X +1920(choice)X +2161(for)X +2285(synchronization,)X +2847(because)X +3132(each)X +3310(access)X +3546(traps)X +3732(to)X +3824(the)X +3952(kernel)X +4183(and)X +8 s +10 f +555 5547(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)N +5 s +1 f +727 5625(2)N +8 s +763 5650(Ultrix)N +932(and)X +1040(DEC)X +1184(are)X +1277(trademarks)X +1576(of)X +1645(Digital)X +1839(Equipment)X +2136(Corporation.)X + +9 p +%%Page: 9 9 +8 s 8 xH 0 xS 1 f +10 s +3 f +1 f +555 630(executes)N +852(atomically)X +1210(there.)X +755 753(On)N +878(architectures)X +1314(that)X +1459(support)X +1724(atomic)X +1967(test-and-set,)X +2382(a)X +2443(much)X +2646(better)X +2854(choice)X +3089(would)X +3314(be)X +3415(to)X +3502(attempt)X +3767(to)X +3854(obtain)X +4079(a)X +4139(spin-)X +555 843(lock)N +714(with)X +877(a)X +934(test-and-set,)X +1345(and)X +1482(issue)X +1663(a)X +1720(system)X +1963(call)X +2100(only)X +2263(if)X +2333(the)X +2452(spinlock)X +2744(is)X +2818(unavailable.)X +3249(Since)X +3447(virtually)X +3738(all)X +3838(semaphores)X +4237(in)X +555 933(LIBTP)N +801(are)X +924(uncontested)X +1330(and)X +1469(are)X +1591(held)X +1752(for)X +1869(very)X +2035(short)X +2218(periods)X +2477(of)X +2567(time,)X +2752(this)X +2890(would)X +3113(improve)X +3403(performance.)X +3873(For)X +4007(example,)X +555 1023(processes)N +885(must)X +1062(acquire)X +1321(exclusive)X +1646(access)X +1874(to)X +1958(buffer)X +2177(pool)X +2341(metadata)X +2653(in)X +2737(order)X +2929(to)X +3013(\256nd)X +3159(and)X +3297(pin)X +3421(a)X +3479(buffer)X +3698(in)X +3781(shared)X +4012(memory.)X +555 1113(This)N +721(semaphore)X +1093(is)X +1170(requested)X +1502(most)X +1681(frequently)X +2034(in)X +2119(LIBTP.)X +2404(However,)X +2742(once)X +2917(it)X +2984(is)X +3060(acquired,)X +3380(only)X +3545(a)X +3604(few)X +3748(instructions)X +4144(must)X +555 1203(be)N +656(executed)X +966(before)X +1196(it)X +1264(is)X +1341(released.)X +1669(On)X +1791(one)X +1931(architecture)X +2335(for)X +2453(which)X +2673(we)X +2791(were)X +2972(able)X +3130(to)X +3216(gather)X +3441(detailed)X +3719(pro\256ling)X +4018(informa-)X +555 1293(tion,)N +729(the)X +857(cost)X +1015(of)X +1111(the)X +1238(semaphore)X +1615(calls)X +1791(accounted)X +2146(for)X +2269(25%)X +2445(of)X +2541(the)X +2668(total)X +2839(time)X +3010(spent)X +3208(updating)X +3517(the)X +3644(metadata.)X +4003(This)X +4174(was)X +555 1383(fairly)N +749(consistent)X +1089(across)X +1310(most)X +1485(of)X +1572(the)X +1690(critical)X +1933(sections.)X +755 1506(In)N +848(an)X +950(attempt)X +1216(to)X +1304(quantify)X +1597(the)X +1720(overhead)X +2040(of)X +2132(kernel)X +2358(synchronization,)X +2915(we)X +3034(ran)X +3162(tests)X +3329(on)X +3434(a)X +3495(version)X +3756(of)X +3848(4.3BSD-Reno)X +555 1596(which)N +786(had)X +937(been)X +1123(modi\256ed)X +1441(to)X +1537(support)X +1811(binary)X +2050(semaphore)X +2432(facilities)X +2742(similar)X +2998(to)X +3094(those)X +3297(described)X +3639(in)X +3735([POSIX91].)X +4174(The)X +555 1686(hardware)N +880(platform)X +1181(consisted)X +1504(of)X +1595(an)X +1695(HP300)X +1941(\(33MHz)X +2237(MC68030\))X +2612(workstation)X +3014(with)X +3180(16MBytes)X +3537(of)X +3628(main)X +3812(memory,)X +4123(and)X +4263(a)X +555 1776(600MByte)N +920(HP7959)X +1205(SCSI)X +1396(disk)X +1552(\(17)X +1682(ms)X +1798(average)X +2072(seek)X +2237(time\).)X +2468(We)X +2602(ran)X +2727(three)X +2910(sets)X +3052(of)X +3141(comparisons)X +3568(which)X +3786(are)X +3907(summarized)X +555 1866(in)N +645(\256gure)X +860(\256ve.)X +1028(In)X +1123(each)X +1299(comparison)X +1701(we)X +1823(ran)X +1954(two)X +2102(tests,)X +2292(one)X +2436(using)X +2637(hardware)X +2965(spinlocks)X +3295(and)X +3438(the)X +3563(other)X +3755(using)X +3955(kernel)X +4183(call)X +555 1956(synchronization.)N +1135(Since)X +1341(the)X +1467(test)X +1606(was)X +1758(run)X +1892(single-user,)X +2291(none)X +2474(of)X +2568(the)X +2693(the)X +2818(locks)X +3014(were)X +3198(contested.)X +3568(In)X +3662(the)X +3787(\256rst)X +3938(two)X +4085(sets)X +4232(of)X +555 2046(tests,)N +743(we)X +863(ran)X +992(the)X +1116(full)X +1253(transaction)X +1631(processing)X +2000(benchmark)X +2383(described)X +2717(in)X +2805(section)X +3058(5.1.)X +3223(In)X +3315(one)X +3456(case)X +3620(we)X +3739(ran)X +3867(with)X +4034(both)X +4201(the)X +555 2136(database)N +854(and)X +992(log)X +1116(on)X +1218(the)X +1338(same)X +1525(disk)X +1680(\(1)X +1769(Disk\))X +1969(and)X +2107(in)X +2191(the)X +2311(second,)X +2576(we)X +2692(ran)X +2817(with)X +2981(the)X +3101(database)X +3400(and)X +3538(log)X +3661(on)X +3762(separate)X +4047(disks)X +4232(\(2)X +555 2226(Disk\).)N +800(In)X +894(the)X +1019(last)X +1157(test,)X +1315(we)X +1436(wanted)X +1695(to)X +1784(create)X +2004(a)X +2067(CPU)X +2249(bound)X +2476(environment,)X +2928(so)X +3026(we)X +3146(used)X +3319(a)X +3381(database)X +3684(small)X +3883(enough)X +4145(to)X +4233(\256t)X +555 2316(completely)N +941(in)X +1033(the)X +1161(cache)X +1375(and)X +1521(issued)X +1751(read-only)X +2089(transactions.)X +2541(The)X +2695(results)X +2933(in)X +3024(\256gure)X +3240(\256ve)X +3389(express)X +3659(the)X +3786(kernel)X +4016(call)X +4161(syn-)X +555 2406(chronization)N +980(performance)X +1411(as)X +1502(a)X +1562(percentage)X +1935(of)X +2026(the)X +2148(spinlock)X +2443(performance.)X +2914(For)X +3049(example,)X +3365(in)X +3451(the)X +3573(1)X +3637(disk)X +3794(case,)X +3977(the)X +4098(kernel)X +555 2496(call)N +697(implementation)X +1225(achieved)X +1537(4.4)X +1662(TPS)X +1824(\(transactions)X +2259(per)X +2387(second\))X +2662(while)X +2865(the)X +2988(semaphore)X +3361(implementation)X +3888(achieved)X +4199(4.6)X +555 2586(TPS,)N +735(and)X +874(the)X +995(relative)X +1259(performance)X +1689(of)X +1779(the)X +1900(kernel)X +2123(synchronization)X +2657(is)X +2732(96%)X +2901(that)X +3043(of)X +3132(the)X +3252(spinlock)X +3545(\(100)X +3714(*)X +3776(4.4)X +3898(/)X +3942(4.6\).)X +4111(There)X +555 2676(are)N +674(two)X +814(striking)X +1078(observations)X +1503(from)X +1679(these)X +1864(results:)X +10 f +635 2799(g)N +1 f +755(even)X +927(when)X +1121(the)X +1239(system)X +1481(is)X +1554(disk)X +1707(bound,)X +1947(the)X +2065(CPU)X +2240(cost)X +2389(of)X +2476(synchronization)X +3008(is)X +3081(noticeable,)X +3451(and)X +10 f +635 2922(g)N +1 f +755(when)X +949(we)X +1063(are)X +1182(CPU)X +1357(bound,)X +1597(the)X +1715(difference)X +2062(is)X +2135(dramatic)X +2436(\(67%\).)X +3 f +555 3108(4.4.)N +715(Transaction)X +1148(Protected)X +1499(Access)X +1747(Methods)X +1 f +755 3231(The)N +903(B-tree)X +1127(and)X +1266(\256xed)X +1449(length)X +1671(recno)X +1872(\(record)X +2127(number\))X +2421(access)X +2649(methods)X +2942(have)X +3116(been)X +3290(modi\256ed)X +3596(to)X +3680(provide)X +3947(transaction)X +555 3321(protection.)N +941(Whereas)X +1244(the)X +1363(previously)X +1722(published)X +2054(interface)X +2357(to)X +2440(the)X +2559(access)X +2786(routines)X +3065(had)X +3202(separate)X +3487(open)X +3664(calls)X +3832(for)X +3946(each)X +4114(of)X +4201(the)X +10 f +555 3507(h)N +579(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)X +1 Dt +2978 5036 MXY + 2978 5036 lineto + 2978 4662 lineto + 3093 4662 lineto + 3093 5036 lineto + 2978 5036 lineto +closepath 21 2978 4662 3093 5036 Dp +2518 MX + 2518 5036 lineto + 2518 3960 lineto + 2633 3960 lineto + 2633 5036 lineto + 2518 5036 lineto +closepath 3 2518 3960 2633 5036 Dp +2059 MX + 2059 5036 lineto + 2059 3946 lineto + 2174 3946 lineto + 2174 5036 lineto + 2059 5036 lineto +closepath 1 2059 3946 2174 5036 Dp +3 f +7 s +2912 5141(Read-only)N +1426 3767(of)N +1487(Spinlock)X +1710(Throughput)X +1480 3710(Throughput)N +1786(as)X +1850(a)X +1892(%)X +11 s +1670 4843(20)N +1670 4614(40)N +1670 4384(60)N +1670 4155(80)N +1648 3925(100)N +7 s +2041 5141(1)N +2083(Disk)X +2490(2)X +2532(Disks)X +5 Dt +1829 5036 MXY +1494 0 Dl +4 Ds +1 Dt +1829 4806 MXY +1494 0 Dl +1829 4577 MXY +1494 0 Dl +1829 4347 MXY +1494 0 Dl +1829 4118 MXY +1494 0 Dl +1829 3888 MXY +1494 0 Dl +3 Dt +-1 Ds +8 s +555 5360(Figure)N +753(5:)X +823(Kernel)X +1028(Overhead)X +1315(for)X +1413(System)X +1625(Call)X +1756(Synchronization.)X +1 f +2254(The)X +2370(performance)X +2708(of)X +2778(the)X +2873(kernel)X +3049(call)X +3158(synchronization)X +3583(is)X +3643(expressed)X +3911(as)X +3980(a)X +4024(percentage)X +555 5450(of)N +625(the)X +720(spinlock)X +954(synchronization)X +1379(performance.)X +1749(In)X +1819(disk)X +1943(bound)X +2120(cases)X +2271(\(1)X +2341(Disk)X +2479(and)X +2588(2)X +2637(Disks\),)X +2837(we)X +2928(see)X +3026(that)X +3139(4-6%)X +3294(of)X +3364(the)X +3459(performance)X +3797(is)X +3857(lost)X +3966(due)X +4074(to)X +4140(kernel)X +555 5540(calls)N +688(while)X +846(in)X +912(the)X +1006(CPU)X +1147(bound)X +1323(case,)X +1464(we)X +1554(have)X +1690(lost)X +1799(67%)X +1932(of)X +2001(the)X +2095(performance)X +2432(due)X +2540(to)X +2606(kernel)X +2781(calls.)X + +10 p +%%Page: 10 10 +8 s 8 xH 0 xS 1 f +10 s +3 f +1 f +555 630(access)N +781(methods,)X +1092(we)X +1206(now)X +1364(have)X +1536(an)X +1632(integrated)X +1973(open)X +2149(call)X +2285(with)X +2447(the)X +2565(following)X +2896(calling)X +3134(conventions:)X +7 f +715 753(DB)N +859(*dbopen)X +1243(\(const)X +1579(char)X +1819(*file,)X +2155(int)X +2347(flags,)X +2683(int)X +2875(mode,)X +3163(DBTYPE)X +3499(type,)X +1291 843(int)N +1483(dbflags,)X +1915(const)X +2203(void)X +2443(*openinfo\))X +1 f +555 966(where)N +2 f +774(\256le)X +1 f +894(is)X +969(the)X +1089(name)X +1285(of)X +1374(the)X +1494(\256le)X +1618(being)X +1818(opened,)X +2 f +2092(\257ags)X +1 f +2265(and)X +2 f +2402(mode)X +1 f +2597(are)X +2717(the)X +2836(standard)X +3129(arguments)X +3484(to)X +3 f +3567(open)X +1 f +3731(\(2\),)X +2 f +3866(type)X +1 f +4021(is)X +4095(one)X +4232(of)X +555 1056(the)N +680(access)X +913(method)X +1180(types,)X +2 f +1396(db\257ags)X +1 f +1654(indicates)X +1966(the)X +2091(mode)X +2296(of)X +2390(the)X +2515(buffer)X +2739(pool)X +2907(and)X +3049(transaction)X +3427(protection,)X +3798(and)X +2 f +3940(openinfo)X +1 f +4246(is)X +555 1146(the)N +681(access)X +915(method)X +1183(speci\256c)X +1456(information.)X +1902(Currently,)X +2257(the)X +2383(possible)X +2673(values)X +2906(for)X +2 f +3028(db\257ags)X +1 f +3287(are)X +3414(DB_SHARED)X +3912(and)X +4055(DB_TP)X +555 1236(indicating)N +895(that)X +1035(buffers)X +1283(should)X +1516(be)X +1612(kept)X +1770(in)X +1852(a)X +1908(shared)X +2138(buffer)X +2355(pool)X +2517(and)X +2653(that)X +2793(the)X +2911(\256le)X +3033(should)X +3266(be)X +3362(transaction)X +3734(protected.)X +755 1359(The)N +900(modi\256cations)X +1355(required)X +1643(to)X +1725(add)X +1861(transaction)X +2233(protection)X +2578(to)X +2660(an)X +2756(access)X +2982(method)X +3242(are)X +3361(quite)X +3541(simple)X +3774(and)X +3910(localized.)X +715 1482(1.)N +795(Replace)X +1074(\256le)X +2 f +1196(open)X +1 f +1372(with)X +2 f +1534(buf_open)X +1 f +1832(.)X +715 1572(2.)N +795(Replace)X +1074(\256le)X +2 f +1196(read)X +1 f +1363(and)X +2 f +1499(write)X +1 f +1683(calls)X +1850(with)X +2012(buffer)X +2229(manager)X +2526(calls)X +2693(\()X +2 f +2720(buf_get)X +1 f +(,)S +2 f +3000(buf_unpin)X +1 f +3324(\).)X +715 1662(3.)N +795(Precede)X +1070(buffer)X +1287(manager)X +1584(calls)X +1751(with)X +1913(an)X +2009(appropriate)X +2395(\(read)X +2581(or)X +2668(write\))X +2880(lock)X +3038(call.)X +715 1752(4.)N +795(Before)X +1034(updates,)X +1319(issue)X +1499(a)X +1555(logging)X +1819(operation.)X +715 1842(5.)N +795(After)X +985(data)X +1139(have)X +1311(been)X +1483(accessed,)X +1805(release)X +2049(the)X +2167(buffer)X +2384(manager)X +2681(pin.)X +715 1932(6.)N +795(Provide)X +1064(undo/redo)X +1409(code)X +1581(for)X +1695(each)X +1863(type)X +2021(of)X +2108(log)X +2230(record)X +2456(de\256ned.)X +555 2071(The)N +702(following)X +1035(code)X +1209(fragments)X +1552(show)X +1743(how)X +1903(to)X +1987(transaction)X +2361(protect)X +2606(several)X +2856(updates)X +3123(to)X +3206(a)X +3263(B-tree.)X +7 s +3484 2039(3)N +10 s +3533 2071(In)N +3621(the)X +3740(unprotected)X +4140(case,)X +555 2161(an)N +652(open)X +829(call)X +966(is)X +1040(followed)X +1346(by)X +1447(a)X +1504(read)X +1664(call)X +1801(to)X +1884(obtain)X +2105(the)X +2224(meta-data)X +2562(for)X +2677(the)X +2796(B-tree.)X +3058(Instead,)X +3331(we)X +3446(issue)X +3627(an)X +3724(open)X +3901(to)X +3984(the)X +4102(buffer)X +555 2251(manager)N +852(to)X +934(obtain)X +1154(a)X +1210(\256le)X +1332(id)X +1414(and)X +1550(a)X +1606(buffer)X +1823(request)X +2075(to)X +2157(obtain)X +2377(the)X +2495(meta-data)X +2832(as)X +2919(shown)X +3148(below.)X +7 f +715 2374(char)N +955(*path;)X +715 2464(int)N +907(fid,)X +1147(flags,)X +1483(len,)X +1723(mode;)X +715 2644(/*)N +859(Obtain)X +1195(a)X +1291(file)X +1531(id)X +1675(with)X +1915(which)X +2203(to)X +2347(access)X +2683(the)X +2875(buffer)X +3211(pool)X +3451(*/)X +715 2734(fid)N +907(=)X +1003(buf_open\(path,)X +1723(flags,)X +2059(mode\);)X +715 2914(/*)N +859(Read)X +1099(the)X +1291(meta)X +1531(data)X +1771(\(page)X +2059(0\))X +2203(for)X +2395(the)X +2587(B-tree)X +2923(*/)X +715 3004(if)N +859(\(tp_lock\(fid,)X +1531(0,)X +1675(READ_LOCK\)\))X +1003 3094(return)N +1339(error;)X +715 3184(meta_data_ptr)N +1387(=)X +1483(buf_get\(fid,)X +2107(0,)X +2251(BF_PIN,)X +2635(&len\);)X +1 f +555 3307(The)N +714(BF_PIN)X +1014(argument)X +1350(to)X +2 f +1445(buf_get)X +1 f +1718(indicates)X +2036(that)X +2189(we)X +2316(wish)X +2500(to)X +2595(leave)X +2798(this)X +2946(page)X +3131(pinned)X +3382(in)X +3477(memory)X +3777(so)X +3881(that)X +4034(it)X +4111(is)X +4197(not)X +555 3397(swapped)N +862(out)X +990(while)X +1194(we)X +1314(are)X +1439(accessing)X +1772(it.)X +1881(The)X +2031(last)X +2167(argument)X +2495(to)X +2 f +2582(buf_get)X +1 f +2847(returns)X +3095(the)X +3218(number)X +3488(of)X +3580(bytes)X +3774(on)X +3879(the)X +4002(page)X +4179(that)X +555 3487(were)N +732(valid)X +912(so)X +1003(that)X +1143(the)X +1261(access)X +1487(method)X +1747(may)X +1905(initialize)X +2205(the)X +2323(page)X +2495(if)X +2564(necessary.)X +755 3610(Next,)N +955(consider)X +1251(inserting)X +1555(a)X +1615(record)X +1845(on)X +1949(a)X +2009(particular)X +2341(page)X +2517(of)X +2608(a)X +2668(B-tree.)X +2932(In)X +3022(the)X +3143(unprotected)X +3545(case,)X +3727(we)X +3844(read)X +4006(the)X +4127(page,)X +555 3700(call)N +2 f +693(_bt_insertat)X +1 f +1079(,)X +1121(and)X +1258(write)X +1444(the)X +1563(page.)X +1776(Instead,)X +2049(we)X +2164(lock)X +2323(the)X +2442(page,)X +2635(request)X +2888(the)X +3007(buffer,)X +3245(log)X +3368(the)X +3487(change,)X +3756(modify)X +4008(the)X +4127(page,)X +555 3790(and)N +691(release)X +935(the)X +1053(buffer.)X +7 f +715 3913(int)N +907(fid,)X +1147(len,)X +1387(pageno;)X +1867(/*)X +2011(Identifies)X +2539(the)X +2731(buffer)X +3067(*/)X +715 4003(int)N +907(index;)X +1867(/*)X +2011(Location)X +2443(at)X +2587(which)X +2875(to)X +3019(insert)X +3355(the)X +3547(new)X +3739(pair)X +3979(*/)X +715 4093(DBT)N +907(*keyp,)X +1243(*datap;)X +1867(/*)X +2011(Key/Data)X +2443(pair)X +2683(to)X +2827(be)X +2971(inserted)X +3403(*/)X +715 4183(DATUM)N +1003(*d;)X +1867(/*)X +2011(Key/data)X +2443(structure)X +2923(to)X +3067(insert)X +3403(*/)X +715 4363(/*)N +859(Lock)X +1099(and)X +1291(request)X +1675(the)X +1867(buffer)X +2203(*/)X +715 4453(if)N +859(\(tp_lock\(fid,)X +1531(pageno,)X +1915(WRITE_LOCK\)\))X +1003 4543(return)N +1339(error;)X +715 4633(buffer_ptr)N +1243(=)X +1339(buf_get\(fid,)X +1963(pageno,)X +2347(BF_PIN,)X +2731(&len\);)X +715 4813(/*)N +859(Log)X +1051(and)X +1243(perform)X +1627(the)X +1819(update)X +2155(*/)X +715 4903(log_insdel\(BTREE_INSERT,)N +1915(fid,)X +2155(pageno,)X +2539(keyp,)X +2827(datap\);)X +715 4993(_bt_insertat\(buffer_ptr,)N +1915(d,)X +2059(index\);)X +715 5083(buf_unpin\(buffer_ptr\);)N +1 f +555 5206(Succinctly,)N +942(the)X +1068(algorithm)X +1407(for)X +1529(turning)X +1788(unprotected)X +2195(code)X +2375(into)X +2527(protected)X +2854(code)X +3034(is)X +3115(to)X +3205(replace)X +3466(read)X +3633(operations)X +3995(with)X +2 f +4165(lock)X +1 f +555 5296(and)N +2 f +691(buf_get)X +1 f +951(operations)X +1305(and)X +1441(write)X +1626(operations)X +1980(with)X +2 f +2142(log)X +1 f +2264(and)X +2 f +2400(buf_unpin)X +1 f +2744(operations.)X +8 s +10 f +555 5458(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)N +5 s +1 f +727 5536(3)N +8 s +766 5561(The)N +884(following)X +1152(code)X +1291(fragments)X +1565(are)X +1661(examples,)X +1937(but)X +2038(do)X +2120(not)X +2220(de\256ne)X +2394(the)X +2490(\256nal)X +2622(interface.)X +2894(The)X +3011(\256nal)X +3143(interface)X +3383(will)X +3501(be)X +3579(determined)X +3884(after)X +4018(LIBTP)X +4214(has)X +555 5633(been)N +691(fully)X +828(integrated)X +1099(with)X +1229(the)X +1323(most)X +1464(recent)X +3 f +1635(db)X +1 f +1707(\(3\))X +1797(release)X +1989(from)X +2129(the)X +2223(Computer)X +2495(Systems)X +2725(Research)X +2974(Group)X +3153(at)X +3215(University)X +3501(of)X +3570(California,)X +3861(Berkeley.)X + +11 p +%%Page: 11 11 +8 s 8 xH 0 xS 1 f +10 s +3 f +555 630(5.)N +655(Performance)X +1 f +755 753(In)N +845(this)X +983(section,)X +1253(we)X +1370(present)X +1625(the)X +1746(results)X +1978(of)X +2067(two)X +2209(very)X +2374(different)X +2673(benchmarks.)X +3103(The)X +3250(\256rst)X +3396(is)X +3471(an)X +3569(online)X +3791(transaction)X +4165(pro-)X +555 843(cessing)N +824(benchmark,)X +1234(similar)X +1489(to)X +1584(the)X +1715(standard)X +2020(TPCB,)X +2272(but)X +2407(has)X +2547(been)X +2732(adapted)X +3015(to)X +3110(run)X +3250(in)X +3345(a)X +3414(desktop)X +3696(environment.)X +4174(The)X +555 933(second)N +798(emulates)X +1103(a)X +1159(computer-aided)X +1683(design)X +1912(environment)X +2337(and)X +2473(provides)X +2769(more)X +2954(complex)X +3250(query)X +3453(processing.)X +3 f +555 1119(5.1.)N +715(Transaction)X +1148(Processing)X +1533(Benchmark)X +1 f +755 1242(For)N +887(this)X +1023(section,)X +1291(all)X +1392(performance)X +1820(numbers)X +2117(shown)X +2346(except)X +2576(for)X +2690(the)X +2808(commercial)X +3207(database)X +3504(system)X +3746(were)X +3923(obtained)X +4219(on)X +555 1332(a)N +614(DECstation)X +1009(5000/200)X +1333(with)X +1497(32MBytes)X +1852(of)X +1941(memory)X +2230(running)X +2501(Ultrix)X +2714(V4.0,)X +2914(accessing)X +3244(a)X +3302(DEC)X +3484(RZ57)X +3688(1GByte)X +3959(disk)X +4114(drive.)X +555 1422(The)N +720(commercial)X +1139(relational)X +1482(database)X +1799(system)X +2061(tests)X +2242(were)X +2438(run)X +2584(on)X +2703(a)X +2778(comparable)X +3192(machine,)X +3523(a)X +3598(Sparcstation)X +4033(1+)X +4157(with)X +555 1512(32MBytes)N +915(memory)X +1209(and)X +1352(a)X +1415(1GByte)X +1691(external)X +1976(disk)X +2135(drive.)X +2366(The)X +2517(database,)X +2840(binaries)X +3120(and)X +3262(log)X +3390(resided)X +3648(on)X +3754(the)X +3878(same)X +4069(device.)X +555 1602(Reported)N +869(times)X +1062(are)X +1181(the)X +1299(means)X +1524(of)X +1611(\256ve)X +1751(tests)X +1913(and)X +2049(have)X +2221(standard)X +2513(deviations)X +2862(within)X +3086(two)X +3226(percent)X +3483(of)X +3570(the)X +3688(mean.)X +755 1725(The)N +905(test)X +1041(database)X +1343(was)X +1493(con\256gured)X +1861(according)X +2203(to)X +2290(the)X +2413(TPCB)X +2637(scaling)X +2889(rules)X +3070(for)X +3189(a)X +3250(10)X +3355(transaction)X +3732(per)X +3860(second)X +4108(\(TPS\))X +555 1815(system)N +817(with)X +999(1,000,000)X +1359(account)X +1649(records,)X +1946(100)X +2106(teller)X +2311(records,)X +2607(and)X +2762(10)X +2881(branch)X +3139(records.)X +3455(Where)X +3709(TPS)X +3885(numbers)X +4200(are)X +555 1905(reported,)N +865(we)X +981(are)X +1102(running)X +1373(a)X +1431(modi\256ed)X +1737(version)X +1995(of)X +2084(the)X +2203(industry)X +2486(standard)X +2779(transaction)X +3152(processing)X +3516(benchmark,)X +3914(TPCB.)X +4174(The)X +555 1995(TPCB)N +780(benchmark)X +1163(simulates)X +1491(a)X +1553(withdrawal)X +1940(performed)X +2301(by)X +2407(a)X +2469(hypothetical)X +2891(teller)X +3082(at)X +3166(a)X +3228(hypothetical)X +3650(bank.)X +3872(The)X +4022(database)X +555 2085(consists)N +831(of)X +921(relations)X +1220(\(\256les\))X +1430(for)X +1547(accounts,)X +1871(branches,)X +2200(tellers,)X +2439(and)X +2578(history.)X +2863(For)X +2997(each)X +3168(transaction,)X +3563(the)X +3684(account,)X +3976(teller,)X +4183(and)X +555 2175(branch)N +795(balances)X +1093(must)X +1269(be)X +1366(updated)X +1641(to)X +1724(re\257ect)X +1946(the)X +2065(withdrawal)X +2447(and)X +2584(a)X +2640(history)X +2882(record)X +3108(is)X +3181(written)X +3428(which)X +3644(contains)X +3931(the)X +4049(account)X +555 2265(id,)N +657(branch)X +896(id,)X +998(teller)X +1183(id,)X +1285(and)X +1421(the)X +1539(amount)X +1799(of)X +1886(the)X +2004(withdrawal)X +2385([TPCB90].)X +755 2388(Our)N +914(implementation)X +1450(of)X +1551(the)X +1683(benchmark)X +2074(differs)X +2317(from)X +2506(the)X +2637(speci\256cation)X +3075(in)X +3170(several)X +3431(aspects.)X +3736(The)X +3894(speci\256cation)X +555 2478(requires)N +840(that)X +985(the)X +1108(database)X +1410(keep)X +1587(redundant)X +1933(logs)X +2091(on)X +2196(different)X +2498(devices,)X +2784(but)X +2911(we)X +3030(use)X +3162(a)X +3223(single)X +3439(log.)X +3606(Furthermore,)X +4052(all)X +4157(tests)X +555 2568(were)N +734(run)X +863(on)X +965(a)X +1023(single,)X +1256(centralized)X +1631(system)X +1875(so)X +1968(there)X +2151(is)X +2226(no)X +2328(notion)X +2553(of)X +2641(remote)X +2885(accesses.)X +3219(Finally,)X +3486(we)X +3601(calculated)X +3948(throughput)X +555 2658(by)N +662(dividing)X +955(the)X +1080(total)X +1249(elapsed)X +1517(time)X +1686(by)X +1793(the)X +1918(number)X +2190(of)X +2284(transactions)X +2694(processed)X +3038(rather)X +3253(than)X +3418(by)X +3525(computing)X +3894(the)X +4018(response)X +555 2748(time)N +717(for)X +831(each)X +999(transaction.)X +755 2871(The)N +912(performance)X +1351(comparisons)X +1788(focus)X +1993(on)X +2104(traditional)X +2464(Unix)X +2655(techniques)X +3029(\(unprotected,)X +3486(using)X +3 f +3690(\257ock)X +1 f +3854(\(2\))X +3979(and)X +4126(using)X +3 f +555 2961(fsync)N +1 f +733(\(2\)\))X +884(and)X +1030(a)X +1096(commercial)X +1504(relational)X +1836(database)X +2142(system.)X +2433(Well-behaved)X +2913(applications)X +3329(using)X +3 f +3531(\257ock)X +1 f +3695(\(2\))X +3818(are)X +3946(guaranteed)X +555 3051(that)N +704(concurrent)X +1077(processes')X +1441(updates)X +1715(do)X +1824(not)X +1955(interact)X +2225(with)X +2396(one)X +2541(another,)X +2831(but)X +2962(no)X +3070(guarantees)X +3442(about)X +3648(atomicity)X +3978(are)X +4105(made.)X +555 3141(That)N +731(is,)X +833(if)X +911(the)X +1038(system)X +1289(crashes)X +1555(in)X +1646(mid-transaction,)X +2198(only)X +2369(parts)X +2554(of)X +2649(that)X +2797(transaction)X +3177(will)X +3329(be)X +3433(re\257ected)X +3738(in)X +3828(the)X +3954 0.3125(after-crash)AX +555 3231(state)N +725(of)X +815(the)X +936(database.)X +1276(The)X +1424(use)X +1554(of)X +3 f +1643(fsync)X +1 f +1821(\(2\))X +1937(at)X +2017(transaction)X +2391(commit)X +2657(time)X +2821(provides)X +3119(guarantees)X +3485(of)X +3574(durability)X +3907(after)X +4077(system)X +555 3321(failure.)N +825(However,)X +1160(there)X +1341(is)X +1414(no)X +1514(mechanism)X +1899(to)X +1981(perform)X +2260(transaction)X +2632(abort.)X +3 f +555 3507(5.1.1.)N +775(Single-User)X +1191(Tests)X +1 f +755 3630(These)N +978(tests)X +1151(compare)X +1459(LIBTP)X +1712(in)X +1804(a)X +1870(variety)X +2123(of)X +2220(con\256gurations)X +2708(to)X +2800(traditional)X +3159(UNIX)X +3390(solutions)X +3708(and)X +3854(a)X +3920(commercial)X +555 3720(relational)N +884(database)X +1187(system)X +1435(\(RDBMS\).)X +1814(To)X +1929(demonstrate)X +2347(the)X +2471(server)X +2694(architecture)X +3100(we)X +3220(built)X +3392(a)X +3454(front)X +3636(end)X +3777(test)X +3913(process)X +4179(that)X +555 3810(uses)N +732(TCL)X +922([OUST90])X +1304(to)X +1405(parse)X +1614(database)X +1930(access)X +2175(commands)X +2561(and)X +2716(call)X +2870(the)X +3006(database)X +3321(access)X +3565(routines.)X +3901(In)X +4006(one)X +4160(case)X +555 3900(\(SERVER\),)N +956(frontend)X +1249(and)X +1386(backend)X +1675(processes)X +2004(were)X +2181(created)X +2434(which)X +2650(communicated)X +3142(via)X +3260(an)X +3356(IP)X +3447(socket.)X +3712(In)X +3799(the)X +3917(second)X +4160(case)X +555 3990(\(TCL\),)N +802(a)X +860(single)X +1073(process)X +1336(read)X +1497(queries)X +1751(from)X +1929(standard)X +2223(input,)X +2429(parsed)X +2660(them,)X +2861(and)X +2998(called)X +3211(the)X +3330(database)X +3628(access)X +3855(routines.)X +4174(The)X +555 4080(performance)N +987(difference)X +1338(between)X +1630(the)X +1752(TCL)X +1927(and)X +2067(SERVER)X +2397(tests)X +2563(quanti\256es)X +2898(the)X +3020(communication)X +3542(overhead)X +3861(of)X +3952(the)X +4074(socket.)X +555 4170(The)N +732(RDBMS)X +1063(implementation)X +1617(used)X +1816(embedded)X +2198(SQL)X +2401(in)X +2515(C)X +2620(with)X +2814(stored)X +3062(database)X +3391(procedures.)X +3835(Therefore,)X +4224(its)X +555 4260(con\256guration)N +1003(is)X +1076(a)X +1132(hybrid)X +1361(of)X +1448(the)X +1566(single)X +1777(process)X +2038(architecture)X +2438(and)X +2574(the)X +2692(server)X +2909(architecture.)X +3349(The)X +3494(graph)X +3697(in)X +3779(\256gure)X +3986(six)X +4099(shows)X +555 4350(a)N +611(comparison)X +1005(of)X +1092(the)X +1210(following)X +1541(six)X +1654(con\256gurations:)X +1126 4506(LIBTP)N +1552(Uses)X +1728(the)X +1846(LIBTP)X +2088(library)X +2322(in)X +2404(a)X +2460(single)X +2671(application.)X +1126 4596(TCL)N +1552(Uses)X +1728(the)X +1846(LIBTP)X +2088(library)X +2322(in)X +2404(a)X +2460(single)X +2671(application,)X +3067(requires)X +3346(query)X +3549(parsing.)X +1126 4686(SERVER)N +1552(Uses)X +1728(the)X +1846(LIBTP)X +2088(library)X +2322(in)X +2404(a)X +2460(server)X +2677(con\256guration,)X +3144(requires)X +3423(query)X +3626(parsing.)X +1126 4776(NOTP)N +1552(Uses)X +1728(no)X +1828(locking,)X +2108(logging,)X +2392(or)X +2479(concurrency)X +2897(control.)X +1126 4866(FLOCK)N +1552(Uses)X +3 f +1728(\257ock)X +1 f +1892(\(2\))X +2006(for)X +2120(concurrency)X +2538(control)X +2785(and)X +2921(nothing)X +3185(for)X +3299(durability.)X +1126 4956(FSYNC)N +1552(Uses)X +3 f +1728(fsync)X +1 f +1906(\(2\))X +2020(for)X +2134(durability)X +2465(and)X +2601(nothing)X +2865(for)X +2979(concurrency)X +3397(control.)X +1126 5046(RDBMS)N +1552(Uses)X +1728(a)X +1784(commercial)X +2183(relational)X +2506(database)X +2803(system.)X +755 5235(The)N +902(results)X +1133(show)X +1324(that)X +1466(LIBTP,)X +1730(both)X +1894(in)X +1978(the)X +2098(procedural)X +2464(and)X +2602(parsed)X +2834(environments,)X +3312(is)X +3387(competitive)X +3787(with)X +3951(a)X +4009(commer-)X +555 5325(cial)N +692(system)X +935(\(comparing)X +1326(LIBTP,)X +1589(TCL,)X +1781(and)X +1917(RDBMS\).)X +2263(Compared)X +2617(to)X +2699(existing)X +2972(UNIX)X +3193(solutions,)X +3521(LIBTP)X +3763(is)X +3836(approximately)X +555 5415(15%)N +738(slower)X +988(than)X +1162(using)X +3 f +1371(\257ock)X +1 f +1535(\(2\))X +1665(or)X +1768(no)X +1884(protection)X +2245(but)X +2383(over)X +2562(80%)X +2745(better)X +2964(than)X +3137(using)X +3 f +3345(fsync)X +1 f +3523(\(2\))X +3652(\(comparing)X +4057(LIBTP,)X +555 5505(FLOCK,)N +857(NOTP,)X +1106(and)X +1242(FSYNC\).)X + +12 p +%%Page: 12 12 +10 s 10 xH 0 xS 1 f +3 f +8 s +3500 2184(RDBMS)N +1 Dt +3553 2085 MXY + 3553 2085 lineto + 3676 2085 lineto + 3676 1351 lineto + 3553 1351 lineto + 3553 2085 lineto +closepath 16 3553 1351 3676 2085 Dp +2018 2184(SERVER)N +1720 1168 MXY +0 917 Dl +122 0 Dl +0 -917 Dl +-122 0 Dl +1715 2184(TCL)N +2087 1534 MXY + 2087 1534 lineto + 2209 1534 lineto + 2209 2085 lineto + 2087 2085 lineto + 2087 1534 lineto +closepath 12 2087 1534 2209 2085 Dp +3187 MX + 3187 1534 lineto + 3309 1534 lineto + 3309 2085 lineto + 3187 2085 lineto + 3187 1534 lineto +closepath 19 3187 1534 3309 2085 Dp +3142 2184(FSYNC)N +2425(NOTP)X +2453 955 MXY + 2453 955 lineto + 2576 955 lineto + 2576 2085 lineto + 2453 2085 lineto + 2453 955 lineto +closepath 21 2453 955 2576 2085 Dp +2820 1000 MXY + 2820 1000 lineto + 2942 1000 lineto + 2942 2085 lineto + 2820 2085 lineto + 2820 1000 lineto +closepath 14 2820 1000 2942 2085 Dp +5 Dt +1231 2085 MXY +2567 0 Dl +4 Ds +1 Dt +1231 1840 MXY +2567 0 Dl +1231 1596 MXY +2567 0 Dl +1231 1351 MXY +2567 0 Dl +1231 1108 MXY +2567 0 Dl +1231 863 MXY +2567 0 Dl +11 s +1087 1877(2)N +1087 1633(4)N +1087 1388(6)N +1087 1145(8)N +1065 900(10)N +1028 763(TPS)N +-1 Ds +1353 2085 MXY + 1353 2085 lineto + 1353 1151 lineto + 1476 1151 lineto + 1476 2085 lineto + 1353 2085 lineto +closepath 3 1353 1151 1476 2085 Dp +8 s +1318 2184(LIBTP)N +2767(FLOCK)X +3 Dt +-1 Ds +10 s +1597 2399(Figure)N +1844(6:)X +1931(Single-User)X +2347(Performance)X +2814(Comparison.)X +1 f +10 f +555 2579(h)N +579(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)X +3 f +555 2855(5.1.2.)N +775(Multi-User)X +1174(Tests)X +1 f +755 2978(While)N +975(the)X +1097(single-user)X +1473(tests)X +1639(form)X +1819(a)X +1878(basis)X +2061(for)X +2178(comparing)X +2544(LIBTP)X +2789(to)X +2874(other)X +3062(systems,)X +3358(our)X +3488(goal)X +3649(in)X +3734(multi-user)X +4086(testing)X +555 3068(was)N +714(to)X +810(analyze)X +1089(its)X +1197(scalability.)X +1579(To)X +1701(this)X +1849(end,)X +2018(we)X +2145(have)X +2330(run)X +2470(the)X +2601(benchmark)X +2991(in)X +3086(three)X +3280(modes,)X +3542(the)X +3673(normal)X +3933(disk)X +4099(bound)X +555 3158(con\256guration)N +1010(\(\256gure)X +1252(seven\),)X +1510(a)X +1573(CPU)X +1755(bound)X +1982(con\256guration)X +2436(\(\256gure)X +2677(eight,)X +2884(READ-ONLY\),)X +3426(and)X +3569(lock)X +3734(contention)X +4099(bound)X +555 3248(\(\256gure)N +796(eight,)X +1003(NO_FSYNC\).)X +1510(Since)X +1715(the)X +1840(normal)X +2094(con\256guration)X +2548(is)X +2628(completely)X +3011(disk)X +3171(bound)X +3398(\(each)X +3600(transaction)X +3978(requires)X +4263(a)X +555 3354(random)N +823(read,)X +1005(a)X +1064(random)X +1332(write,)X +1540(and)X +1679(a)X +1738(sequential)X +2086(write)X +7 s +2251 3322(4)N +10 s +3354(\))Y +2329(we)X +2446(expect)X +2679(to)X +2764(see)X +2890(little)X +3059(performance)X +3489(improvement)X +3939(as)X +4028(the)X +4148(mul-)X +555 3444(tiprogramming)N +1064(level)X +1249(increases.)X +1613(In)X +1709(fact,)X +1879(\256gure)X +2095(seven)X +2307(reveals)X +2564(that)X +2713(we)X +2836(are)X +2964(able)X +3127(to)X +3218(overlap)X +3487(CPU)X +3670(and)X +3814(disk)X +3975(utilization)X +555 3534(slightly)N +825(producing)X +1181(approximately)X +1674(a)X +1740(10%)X +1917(performance)X +2354(improvement)X +2811(with)X +2983(two)X +3133(processes.)X +3511(After)X +3711(that)X +3861(point,)X +4075(perfor-)X +555 3624(mance)N +785(drops)X +983(off,)X +1117(and)X +1253(at)X +1331(a)X +1387(multi-programming)X +2038(level)X +2214(of)X +2301(4,)X +2381(we)X +2495(are)X +2614(performing)X +2995(worse)X +3207(than)X +3365(in)X +3447(the)X +3565(single)X +3776(process)X +4037(case.)X +755 3747(Similar)N +1021(behavior)X +1333(was)X +1489(reported)X +1787(on)X +1897(the)X +2025(commercial)X +2434(relational)X +2767(database)X +3074(system)X +3326(using)X +3529(the)X +3657(same)X +3852(con\256guration.)X +555 3837(The)N +707(important)X +1045(conclusion)X +1419(to)X +1508(draw)X +1696(from)X +1879(this)X +2021(is)X +2101(that)X +2248(you)X +2395(cannot)X +2636(attain)X +2841(good)X +3028(multi-user)X +3384(scaling)X +3638(on)X +3745(a)X +3808(badly)X +4013(balanced)X +555 3927(system.)N +839(If)X +915(multi-user)X +1266(performance)X +1695(on)X +1797(applications)X +2205(of)X +2293(this)X +2429(sort)X +2570(is)X +2644(important,)X +2996(one)X +3133(must)X +3309(have)X +3482(a)X +3539(separate)X +3824(logging)X +4089(device)X +555 4017(and)N +697(horizontally)X +1110(partition)X +1407(the)X +1531(database)X +1834(to)X +1921(allow)X +2124(a)X +2185(suf\256ciently)X +2570(high)X +2737(degree)X +2977(of)X +3069(multiprogramming)X +3698(that)X +3843(group)X +4055(commit)X +555 4107(can)N +687(amortize)X +988(the)X +1106(cost)X +1255(of)X +1342(log)X +1464(\257ushing.)X +755 4230(By)N +871(using)X +1067(a)X +1126(very)X +1292(small)X +1488(database)X +1788(\(one)X +1954(that)X +2097(can)X +2232(be)X +2331(entirely)X +2599(cached)X +2846(in)X +2930(main)X +3112(memory\))X +3428(and)X +3566(read-only)X +3896(transactions,)X +555 4320(we)N +670(generated)X +1004(a)X +1061(CPU)X +1236(bound)X +1456(environment.)X +1921(By)X +2034(using)X +2227(the)X +2345(same)X +2530(small)X +2723(database,)X +3040(the)X +3158(complete)X +3472(TPCB)X +3691(transaction,)X +4083(and)X +4219(no)X +3 f +555 4410(fsync)N +1 f +733(\(2\))X +862(on)X +977(the)X +1110(log)X +1247(at)X +1340(commit,)X +1639(we)X +1768(created)X +2036(a)X +2107(lock)X +2280(contention)X +2652(bound)X +2886(environment.)X +3365(The)X +3524(small)X +3731(database)X +4042(used)X +4223(an)X +555 4500(account)N +828(\256le)X +953(containing)X +1314(only)X +1479(1000)X +1662(records)X +1922(rather)X +2133(than)X +2294(the)X +2415(full)X +2549(1,000,000)X +2891(records)X +3150(and)X +3288(ran)X +3413(enough)X +3671(transactions)X +4076(to)X +4160(read)X +555 4590(the)N +677(entire)X +883(database)X +1183(into)X +1330(the)X +1451(buffer)X +1671(pool)X +1836(\(2000\))X +2073(before)X +2302(beginning)X +2645(measurements.)X +3147(The)X +3295(read-only)X +3626(transaction)X +4001(consisted)X +555 4680(of)N +646(three)X +831(database)X +1132(reads)X +1326(\(from)X +1533(the)X +1655(1000)X +1839(record)X +2069(account)X +2343(\256le,)X +2489(the)X +2611(100)X +2754(record)X +2983(teller)X +3171(\256le,)X +3316(and)X +3455(the)X +3576(10)X +3679(record)X +3908(branch)X +4150(\256le\).)X +555 4770(Since)N +759(no)X +865(data)X +1025(were)X +1208(modi\256ed)X +1518(and)X +1660(no)X +1766(history)X +2014(records)X +2277(were)X +2460(written,)X +2733(no)X +2839(log)X +2966(records)X +3228(were)X +3410(written.)X +3702(For)X +3838(the)X +3961(contention)X +555 4860(bound)N +780(con\256guration,)X +1252(we)X +1371(used)X +1543(the)X +1666(normal)X +1918(TPCB)X +2142(transaction)X +2519(\(against)X +2798(the)X +2920(small)X +3117(database\))X +3445(and)X +3585(disabled)X +3876(the)X +3998(log)X +4124(\257ush.)X +555 4950(Figure)N +784(eight)X +964(shows)X +1184(both)X +1346(of)X +1433(these)X +1618(results.)X +755 5073(The)N +902(read-only)X +1231(test)X +1363(indicates)X +1669(that)X +1810(we)X +1925(barely)X +2147(scale)X +2329(at)X +2408(all)X +2509(in)X +2592(the)X +2711(CPU)X +2887(bound)X +3108(case.)X +3308(The)X +3454(explanation)X +3849(for)X +3964(that)X +4105(is)X +4179(that)X +555 5163(even)N +735(with)X +905(a)X +969(single)X +1188(process,)X +1477(we)X +1599(are)X +1726(able)X +1888(to)X +1978(drive)X +2171(the)X +2297(CPU)X +2480(utilization)X +2832(to)X +2922(96%.)X +3137(As)X +3254(a)X +3317(result,)X +3542(that)X +3689(gives)X +3885(us)X +3983(very)X +4153(little)X +555 5253(room)N +753(for)X +876(improvement,)X +1352(and)X +1497(it)X +1570(takes)X +1764(a)X +1829(multiprogramming)X +2462(level)X +2647(of)X +2743(four)X +2906(to)X +2997(approach)X +3321(100%)X +3537(CPU)X +3721(saturation.)X +4106(In)X +4201(the)X +555 5343(case)N +718(where)X +939(we)X +1057(do)X +1161(perform)X +1444(writes,)X +1684(we)X +1802(are)X +1925(interested)X +2261(in)X +2347(detecting)X +2665(when)X +2863(lock)X +3025(contention)X +3387(becomes)X +3691(a)X +3750(dominant)X +4075(perfor-)X +555 5433(mance)N +787(factor.)X +1037(Contention)X +1414(will)X +1560(cause)X +1761(two)X +1903(phenomena;)X +2317(we)X +2433(will)X +2579(see)X +2704(transactions)X +3109(queueing)X +3425(behind)X +3665(frequently)X +4017(accessed)X +555 5523(data,)N +731(and)X +869(we)X +985(will)X +1131(see)X +1256(transaction)X +1629(abort)X +1815(rates)X +1988(increasing)X +2339(due)X +2476(to)X +2559(deadlock.)X +2910(Given)X +3127(that)X +3268(the)X +3387(branch)X +3627(\256le)X +3750(contains)X +4038(only)X +4201(ten)X +8 s +10 f +555 5595(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)N +5 s +1 f +727 5673(4)N +8 s +763 5698(Although)N +1021(the)X +1115(log)X +1213(is)X +1272(written)X +1469(sequentially,)X +1810(we)X +1900(do)X +1980(not)X +2078(get)X +2172(the)X +2266(bene\256t)X +2456(of)X +2525(sequentiality)X +2868(since)X +3015(the)X +3109(log)X +3207(and)X +3315(database)X +3550(reside)X +3718(on)X +3798(the)X +3892(same)X +4039(disk.)X + +13 p +%%Page: 13 13 +8 s 8 xH 0 xS 1 f +10 s +3 f +1 f +3187 2051 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +3286 2028 MXY +0 17 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +3384 1926 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +3483 1910 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +3581 1910 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +3680 1832 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +3778 1909 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +3877 1883 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +3975 1679 MXY +0 17 Dl +0 -8 Dl +9 0 Dl +-18 0 Dl +4074 1487 MXY +0 17 Dl +0 -8 Dl +9 0 Dl +-18 0 Dl +5 Dt +3187 2060 MXY +99 -24 Dl +98 -101 Dl +99 -16 Dl +98 0 Dl +99 -78 Dl +98 77 Dl +99 -26 Dl +98 -204 Dl +99 -192 Dl +3 f +6 s +4088 1516(SMALL)N +3 Dt +3187 2051 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +3286 2051 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +3384 2041 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +3483 1990 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +3581 1843 MXY +0 17 Dl +0 -8 Dl +9 0 Dl +-18 0 Dl +3680 1578 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +3778 1496 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +3877 1430 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +3975 1269 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +4074 1070 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +1 Dt +3187 2060 MXY +99 0 Dl +98 -10 Dl +99 -51 Dl +98 -147 Dl +99 -265 Dl +98 -82 Dl +99 -66 Dl +98 -161 Dl +99 -199 Dl +4088 1099(LARGE)N +5 Dt +3089 2060 MXY +985 0 Dl +3089 MX +0 -1174 Dl +4 Ds +1 Dt +3581 2060 MXY +0 -1174 Dl +4074 2060 MXY +0 -1174 Dl +3089 1825 MXY +985 0 Dl +9 s +2993 1855(25)N +3089 1591 MXY +985 0 Dl +2993 1621(50)N +3089 1356 MXY +985 0 Dl +2993 1386(75)N +3089 1121 MXY +985 0 Dl +2957 1151(100)N +3089 886 MXY +985 0 Dl +2957 916(125)N +3281 2199(Multiprogramming)N +3071 2152(0)N +3569(5)X +4038(10)X +2859 787(Aborts)N +3089(per)X +3211(500)X +2901 847(transactions)N +-1 Ds +3 Dt +2037 1342 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +2125 1358 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +2213 1341 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +2301 1191 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +2388 1124 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-17 0 Dl +2476 1157 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +2564 1157 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +2652 1161 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +2740 1153 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +2828 1150 MXY +0 18 Dl +0 -9 Dl +8 0 Dl +-17 0 Dl +5 Dt +2037 1351 MXY +88 16 Dl +88 -17 Dl +88 -150 Dl +87 -67 Dl +88 33 Dl +88 0 Dl +88 4 Dl +88 -8 Dl +88 -3 Dl +6 s +2685 1234(READ-ONLY)N +3 Dt +2037 1464 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +2125 1640 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +2213 1854 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +2301 1872 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +2388 1871 MXY +0 17 Dl +0 -9 Dl +9 0 Dl +-17 0 Dl +2476 1933 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +2564 1914 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +2652 1903 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +2740 1980 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +2828 2004 MXY +0 18 Dl +0 -9 Dl +8 0 Dl +-17 0 Dl +1 Dt +2037 1473 MXY +88 176 Dl +88 214 Dl +88 18 Dl +87 -2 Dl +88 63 Dl +88 -19 Dl +88 -11 Dl +88 77 Dl +88 24 Dl +2759 1997(NO-FSYNC)N +5 Dt +1949 2060 MXY +879 0 Dl +1949 MX +0 -1174 Dl +4 Ds +1 Dt +2388 2060 MXY +0 -1174 Dl +2828 2060 MXY +0 -1174 Dl +1949 1825 MXY +879 0 Dl +9 s +1842 1855(40)N +1949 1591 MXY +879 0 Dl +1842 1621(80)N +1949 1356 MXY +879 0 Dl +1806 1386(120)N +1949 1121 MXY +879 0 Dl +1806 1151(160)N +1949 886 MXY +879 0 Dl +1806 916(200)N +2088 2199(Multiprogramming)N +1844 863(in)N +1922(TPS)X +1761 792(Throughput)N +1931 2121(0)N +2370 2133(5)N +2792(10)X +6 s +1679 1833(LIBTP)N +-1 Ds +3 Dt +837 1019 MXY +0 17 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +929 878 MXY +0 17 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +1021 939 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +1113 1043 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +1205 1314 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +1297 1567 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +1389 1665 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +1481 1699 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +1573 1828 MXY +0 18 Dl +0 -9 Dl +9 0 Dl +-18 0 Dl +1665 1804 MXY +0 18 Dl +0 -9 Dl +8 0 Dl +-17 0 Dl +5 Dt +837 1027 MXY +92 -141 Dl +92 62 Dl +92 104 Dl +92 271 Dl +92 253 Dl +92 98 Dl +92 34 Dl +92 129 Dl +92 -24 Dl +745 2060 MXY +920 0 Dl +745 MX +0 -1174 Dl +4 Ds +1 Dt +1205 2060 MXY +0 -1174 Dl +1665 2060 MXY +0 -1174 Dl +745 1766 MXY +920 0 Dl +9 s +673 1796(3)N +745 1473 MXY +920 0 Dl +673 1503(5)N +745 1180 MXY +920 0 Dl +673 1210(8)N +745 886 MXY +920 0 Dl +637 916(10)N +905 2199(Multiprogramming)N +622 851(in)N +700(TPS)X +575 792(Throughput)N +733 2152(0)N +1196(5)X +1629(10)X +3 Dt +-1 Ds +8 s +655 2441(Figure)N +872(7:)X +960(Multi-user)X +1286(Performance.)X +1 f +655 2531(Since)N +825(the)X +931(con\256guration)X +1300(is)X +1371(completely)X +655 2621(disk)N +790(bound,)X +994(we)X +1096(see)X +1204(only)X +1345(a)X +1400(small)X +1566(im-)X +655 2711(provement)N +964(by)X +1064(adding)X +1274(a)X +1337(second)X +1549(pro-)X +655 2801(cess.)N +849(Adding)X +1081(any)X +1213(more)X +1383(concurrent)X +655 2891(processes)N +935(causes)X +1137(performance)X +1493(degra-)X +655 2981(dation.)N +3 f +1927 2441(Figure)N +2149(8:)X +2243(Multi-user)X +2574(Performance)X +1927 2531(on)N +2021(a)X +2079(small)X +2251(database.)X +1 f +2551(With)X +2704(one)X +2821(pro-)X +1927 2621(cess,)N +2075(we)X +2174(are)X +2276(driving)X +2486(the)X +2589(CPU)X +2739(at)X +2810(96%)X +1927 2711(utilization)N +2215(leaving)X +2430(little)X +2575(room)X +2737(for)X +2838(im-)X +1927 2801(provement)N +2238(as)X +2328(the)X +2443(multiprogramming)X +1927 2891(level)N +2091(increases.)X +2396(In)X +2489(the)X +2607(NO-FSYNC)X +1927 2981(case,)N +2076(lock)X +2209(contention)X +2502(degrades)X +2751(perfor-)X +1927 3071(mance)N +2117(as)X +2194(soon)X +2339(as)X +2416(a)X +2468(second)X +2669(process)X +2884(is)X +1927 3161(added.)N +3 f +3199 2441(Figure)N +3405(9:)X +3482(Abort)X +3669(rates)X +3827(on)X +3919(the)X +4028(TPCB)X +3199 2531(Benchmark.)N +1 f +3589(The)X +3726(abort)X +3895(rate)X +4028(climbs)X +3199 2621(more)N +3366(quickly)X +3594(for)X +3704(the)X +3818(large)X +3980(database)X +3199 2711(test)N +3324(since)X +3491(processes)X +3771(are)X +3884(descheduled)X +3199 2801(more)N +3409(frequently,)X +3766(allowing)X +4068(more)X +3199 2891(processes)N +3459(to)X +3525(vie)X +3619(for)X +3709(the)X +3803(same)X +3950(locks.)X +10 s +10 f +555 3284(h)N +579(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)X +1 f +555 3560(records,)N +835(we)X +952(expect)X +1185(contention)X +1546(to)X +1631(become)X +1904(a)X +1963(factor)X +2174(quickly)X +2437(and)X +2576(the)X +2697(NO-FSYNC)X +3120(line)X +3263(in)X +3348(\256gure)X +3557(eight)X +3739(demonstrates)X +4184(this)X +555 3650(dramatically.)N +1022(Each)X +1209(additional)X +1555(process)X +1822(causes)X +2058(both)X +2226(more)X +2417(waiting)X +2682(and)X +2823(more)X +3013(deadlocking.)X +3470(Figure)X +3704(nine)X +3867(shows)X +4092(that)X +4237(in)X +555 3740(the)N +681(small)X +882(database)X +1187(case)X +1353(\(SMALL\),)X +1725(waiting)X +1992(is)X +2072(the)X +2197(dominant)X +2526(cause)X +2732(of)X +2826(declining)X +3151(performance)X +3585(\(the)X +3737(number)X +4009(of)X +4103(aborts)X +555 3830(increases)N +878(less)X +1026(steeply)X +1281(than)X +1447(the)X +1573(performance)X +2008(drops)X +2214(off)X +2336(in)X +2426(\256gure)X +2641(eight\),)X +2876(while)X +3082(in)X +3172(the)X +3298(large)X +3487(database)X +3792(case)X +3958(\(LARGE\),)X +555 3920(deadlocking)N +967(contributes)X +1343(more)X +1528(to)X +1610(the)X +1728(declining)X +2046(performance.)X +755 4043(Deadlocks)N +1116(are)X +1237(more)X +1424(likely)X +1628(to)X +1712(occur)X +1913(in)X +1997(the)X +2116(LARGE)X +2404(test)X +2536(than)X +2695(in)X +2778(the)X +2897(SMALL)X +3189(test)X +3321(because)X +3597(there)X +3779(are)X +3899(more)X +4085(oppor-)X +555 4133(tunities)N +814(to)X +900(wait.)X +1082(In)X +1173(the)X +1295(SMALL)X +1590(case,)X +1773(processes)X +2105(never)X +2307(do)X +2410(I/O)X +2540(and)X +2679(are)X +2801(less)X +2944(likely)X +3149(to)X +3234(be)X +3333(descheduled)X +3753(during)X +3985(a)X +4044(transac-)X +555 4223(tion.)N +740(In)X +828(the)X +947(LARGE)X +1235(case,)X +1415(processes)X +1744(will)X +1889(frequently)X +2240(be)X +2337(descheduled)X +2755(since)X +2941(they)X +3100(have)X +3273(to)X +3356(perform)X +3636(I/O.)X +3804(This)X +3967(provides)X +4263(a)X +555 4313(window)N +837(where)X +1058(a)X +1118(second)X +1365(process)X +1630(can)X +1766(request)X +2022(locks)X +2215(on)X +2318(already)X +2578(locked)X +2815(pages,)X +3041(thus)X +3197(increasing)X +3550(the)X +3671(likelihood)X +4018(of)X +4108(build-)X +555 4403(ing)N +677(up)X +777(long)X +939(chains)X +1164(of)X +1251(waiting)X +1511(processes.)X +1879(Eventually,)X +2266(this)X +2401(leads)X +2586(to)X +2668(deadlock.)X +3 f +555 4589(5.2.)N +715(The)X +868(OO1)X +1052(Benchmark)X +1 f +755 4712(The)N +903(TPCB)X +1125(benchmark)X +1505(described)X +1836(in)X +1921(the)X +2042(previous)X +2341(section)X +2591(measures)X +2913(performance)X +3343(under)X +3549(a)X +3608(conventional)X +4044(transac-)X +555 4802(tion)N +706(processing)X +1076(workload.)X +1446(Other)X +1656(application)X +2039(domains,)X +2357(such)X +2531(as)X +2625(computer-aided)X +3156(design,)X +3412(have)X +3591(substantially)X +4022(different)X +555 4892(access)N +786(patterns.)X +1105(In)X +1197(order)X +1392(to)X +1479(measure)X +1772(the)X +1895(performance)X +2327(of)X +2418(LIBTP)X +2664(under)X +2871(workloads)X +3229(of)X +3320(this)X +3459(type,)X +3641(we)X +3759(implemented)X +4201(the)X +555 4982(OO1)N +731(benchmark)X +1108(described)X +1436(in)X +1518([CATT91].)X +755 5105(The)N +908(database)X +1213(models)X +1472(a)X +1535(set)X +1651(of)X +1745(electronics)X +2120(components)X +2534(with)X +2703(connections)X +3113(among)X +3358(them.)X +3585(One)X +3746(table)X +3929(stores)X +4143(parts)X +555 5195(and)N +696(another)X +962(stores)X +1174(connections.)X +1622(There)X +1835(are)X +1959(three)X +2145(connections)X +2552(originating)X +2927(at)X +3009(any)X +3149(given)X +3351(part.)X +3540(Ninety)X +3782(percent)X +4043(of)X +4134(these)X +555 5285(connections)N +960(are)X +1081(to)X +1165(nearby)X +1406(parts)X +1584(\(those)X +1802(with)X +1966(nearby)X +2 f +2207(ids)X +1 f +2300(\))X +2348(to)X +2431(model)X +2652(the)X +2771(spatial)X +3001(locality)X +3262(often)X +3448(exhibited)X +3767(in)X +3850(CAD)X +4040(applica-)X +555 5375(tions.)N +779(Ten)X +933(percent)X +1198(of)X +1293(the)X +1419(connections)X +1830(are)X +1957(randomly)X +2292(distributed)X +2662(among)X +2908(all)X +3016(other)X +3209(parts)X +3393(in)X +3483(the)X +3609(database.)X +3954(Every)X +4174(part)X +555 5465(appears)N +829(exactly)X +1089(three)X +1278(times)X +1479(in)X +1569(the)X +2 f +1695(from)X +1 f +1874(\256eld)X +2043(of)X +2137(a)X +2200(connection)X +2579(record,)X +2832(and)X +2975(zero)X +3141(or)X +3235(more)X +3427(times)X +3627(in)X +3716(the)X +2 f +3841(to)X +1 f +3930(\256eld.)X +4139(Parts)X +555 5555(have)N +2 f +727(x)X +1 f +783(and)X +2 f +919(y)X +1 f +975(locations)X +1284(set)X +1393(randomly)X +1720(in)X +1802(an)X +1898(appropriate)X +2284(range.)X + +14 p +%%Page: 14 14 +10 s 10 xH 0 xS 1 f +3 f +1 f +755 630(The)N +900(intent)X +1102(of)X +1189(OO1)X +1365(is)X +1438(to)X +1520(measure)X +1808(the)X +1926(overall)X +2169(cost)X +2318(of)X +2405(a)X +2461(query)X +2664(mix)X +2808(characteristic)X +3257(of)X +3344(engineering)X +3743(database)X +4040(applica-)X +555 720(tions.)N +770(There)X +978(are)X +1097(three)X +1278(tests:)X +10 f +635 843(g)N +2 f +755(Lookup)X +1 f +1022(generates)X +1353(1,000)X +1560(random)X +1832(part)X +2 f +1984(ids)X +1 f +2077(,)X +2124(fetches)X +2378(the)X +2502(corresponding)X +2987(parts)X +3169(from)X +3351(the)X +3475(database,)X +3798(and)X +3940(calls)X +4113(a)X +4175(null)X +755 933(procedure)N +1097(in)X +1179(the)X +1297(host)X +1450(programming)X +1906(language)X +2216(with)X +2378(the)X +2496(parts')X +2 f +2699(x)X +1 f +2755(and)X +2 f +2891(y)X +1 f +2947(positions.)X +10 f +635 1056(g)N +2 f +755(Traverse)X +1 f +1067(retrieves)X +1371(a)X +1434(random)X +1706(part)X +1858(from)X +2041(the)X +2166(database)X +2470(and)X +2613(follows)X +2880(connections)X +3290(from)X +3473(it)X +3544(to)X +3632(other)X +3823(parts.)X +4045(Each)X +4232(of)X +755 1146(those)N +947(parts)X +1126(is)X +1202(retrieved,)X +1531(and)X +1670(all)X +1773(connections)X +2179(from)X +2358(it)X +2424(followed.)X +2771(This)X +2935(procedure)X +3279(is)X +3354(repeated)X +3649(depth-\256rst)X +4000(for)X +4116(seven)X +755 1236(hops)N +930(from)X +1110(the)X +1232(original)X +1505(part,)X +1674(for)X +1792(a)X +1852(total)X +2018(of)X +2109(3280)X +2293(parts.)X +2513(Backward)X +2862(traversal)X +3162(also)X +3314(exists,)X +3539(and)X +3678(follows)X +3941(all)X +4044(connec-)X +755 1326(tions)N +930(into)X +1074(a)X +1130(given)X +1328(part)X +1473(to)X +1555(their)X +1722(origin.)X +10 f +635 1449(g)N +2 f +755(Insert)X +1 f +962(adds)X +1129(100)X +1269(new)X +1423(parts)X +1599(and)X +1735(their)X +1902(connections.)X +755 1572(The)N +913(benchmark)X +1303(is)X +1389(single-user,)X +1794(but)X +1929(multi-user)X +2291(access)X +2530(controls)X +2821(\(locking)X +3120(and)X +3268(transaction)X +3652(protection\))X +4036(must)X +4223(be)X +555 1662(enforced.)N +898(It)X +968(is)X +1042(designed)X +1348(to)X +1431(be)X +1528(run)X +1656(on)X +1757(a)X +1814(database)X +2112(with)X +2275(20,000)X +2516(parts,)X +2713(and)X +2850(on)X +2951(one)X +3087(with)X +3249(200,000)X +3529(parts.)X +3745(Because)X +4033(we)X +4147(have)X +555 1752(insuf\256cient)N +935(disk)X +1088(space)X +1287(for)X +1401(the)X +1519(larger)X +1727(database,)X +2044(we)X +2158(report)X +2370(results)X +2599(only)X +2761(for)X +2875(the)X +2993(20,000)X +3233(part)X +3378(database.)X +3 f +555 1938(5.2.1.)N +775(Implementation)X +1 f +755 2061(The)N +920(LIBTP)X +1182(implementation)X +1724(of)X +1831(OO1)X +2027(uses)X +2205(the)X +2342(TCL)X +2532([OUST90])X +2914(interface)X +3235(described)X +3582(earlier.)X +3867(The)X +4031(backend)X +555 2151(accepts)N +813(commands)X +1181(over)X +1345(an)X +1442(IP)X +1534(socket)X +1760(and)X +1897(performs)X +2208(the)X +2327(requested)X +2656(database)X +2954(actions.)X +3242(The)X +3387(frontend)X +3679(opens)X +3886(and)X +4022(executes)X +555 2241(a)N +618(TCL)X +796(script.)X +1041(This)X +1210(script)X +1415(contains)X +1709(database)X +2013(accesses)X +2313(interleaved)X +2697(with)X +2866(ordinary)X +3165(program)X +3463(control)X +3716(statements.)X +4120(Data-)X +555 2331(base)N +718(commands)X +1085(are)X +1204(submitted)X +1539(to)X +1621(the)X +1739(backend)X +2027(and)X +2163(results)X +2392(are)X +2511(bound)X +2731(to)X +2813(program)X +3105(variables.)X +755 2454(The)N +903(parts)X +1082(table)X +1261(was)X +1409(stored)X +1628(as)X +1718(a)X +1776(B-tree)X +1999(indexed)X +2275(by)X +2 f +2377(id)X +1 f +2439(.)X +2501(The)X +2648(connection)X +3022(table)X +3200(was)X +3347(stored)X +3565(as)X +3654(a)X +3712(set)X +3823(of)X +3912(\256xed-length)X +555 2544(records)N +824(using)X +1029(the)X +1159(4.4BSD)X +1446(recno)X +1657(access)X +1895(method.)X +2207(In)X +2306(addition,)X +2620(two)X +2771(B-tree)X +3003(indices)X +3261(were)X +3449(maintained)X +3836(on)X +3947(connection)X +555 2634(table)N +732(entries.)X +1007(One)X +1162(index)X +1360(mapped)X +1634(the)X +2 f +1752(from)X +1 f +1923(\256eld)X +2085(to)X +2167(a)X +2223(connection)X +2595(record)X +2821(number,)X +3106(and)X +3242(the)X +3360(other)X +3545(mapped)X +3819(the)X +2 f +3937(to)X +1 f +4019(\256eld)X +4181(to)X +4263(a)X +555 2724(connection)N +932(record)X +1163(number.)X +1473(These)X +1690(indices)X +1941(support)X +2205(fast)X +2345(lookups)X +2622(on)X +2726(connections)X +3133(in)X +3219(both)X +3385(directions.)X +3765(For)X +3900(the)X +4022(traversal)X +555 2814(tests,)N +743(the)X +867(frontend)X +1165(does)X +1338(an)X +1439(index)X +1642(lookup)X +1889(to)X +1976(discover)X +2273(the)X +2396(connected)X +2747(part's)X +2 f +2955(id)X +1 f +3017(,)X +3062(and)X +3203(then)X +3366(does)X +3538(another)X +3804(lookup)X +4051(to)X +4138(fetch)X +555 2904(the)N +673(part)X +818(itself.)X +3 f +555 3090(5.2.2.)N +775(Performance)X +1242(Measurements)X +1766(for)X +1889(OO1)X +1 f +755 3213(We)N +888(compare)X +1186(LIBTP's)X +1487(OO1)X +1664(performance)X +2092(to)X +2174(that)X +2314(reported)X +2602(in)X +2684([CATT91].)X +3087(Those)X +3303(results)X +3532(were)X +3709(collected)X +4019(on)X +4119(a)X +4175(Sun)X +555 3303(3/280)N +759(\(25)X +888(MHz)X +1075(MC68020\))X +1448(with)X +1612(16)X +1714(MBytes)X +1989(of)X +2078(memory)X +2367(and)X +2505(two)X +2647(Hitachi)X +2904(892MByte)X +3267(disks)X +3452(\(15)X +3580(ms)X +3694(average)X +3966(seek)X +4130(time\))X +555 3393(behind)N +793(an)X +889(SMD-4)X +1149(controller.)X +1521(Frontends)X +1861(ran)X +1984(on)X +2084(an)X +2180(8MByte)X +2462(Sun)X +2606(3/260.)X +755 3516(In)N +844(order)X +1036(to)X +1120(measure)X +1410(performance)X +1839(on)X +1941(a)X +1999(machine)X +2293(of)X +2382(roughly)X +2653(equivalent)X +3009(processor)X +3339(power,)X +3582(we)X +3698(ran)X +3822(one)X +3959(set)X +4069(of)X +4157(tests)X +555 3606(on)N +666(a)X +733(standalone)X +1107(MC68030-based)X +1671(HP300)X +1923(\(33MHz)X +2225(MC68030\).)X +2646(The)X +2801(database)X +3108(was)X +3263(stored)X +3489(on)X +3599(a)X +3665(300MByte)X +4037(HP7959)X +555 3696(SCSI)N +744(disk)X +898(\(17)X +1026(ms)X +1139(average)X +1410(seek)X +1573(time\).)X +1802(Since)X +2000(this)X +2135(machine)X +2427(is)X +2500(not)X +2622(connected)X +2968(to)X +3050(a)X +3106(network,)X +3409(we)X +3523(ran)X +3646(local)X +3822(tests)X +3984(where)X +4201(the)X +555 3786(frontend)N +855(and)X +999(backend)X +1295(run)X +1430(on)X +1538(the)X +1664(same)X +1856(machine.)X +2195(We)X +2334(compare)X +2638(these)X +2830(measurements)X +3316(with)X +3485(Cattell's)X +3783(local)X +3966(Sun)X +4117(3/280)X +555 3876(numbers.)N +755 3999(Because)N +1051(the)X +1177(benchmark)X +1562(requires)X +1849(remote)X +2100(access,)X +2354(we)X +2476(ran)X +2607(another)X +2876(set)X +2993(of)X +3088(tests)X +3258(on)X +3365(a)X +3428(DECstation)X +3828(5000/200)X +4157(with)X +555 4089(32M)N +732(of)X +825(memory)X +1118(running)X +1393(Ultrix)X +1610(V4.0)X +1794(and)X +1936(a)X +1998(DEC)X +2184(1GByte)X +2459(RZ57)X +2666(SCSI)X +2859(disk.)X +3057(We)X +3194(compare)X +3496(the)X +3619(local)X +3800(performance)X +4232(of)X +555 4179(OO1)N +734(on)X +837(the)X +958(DECstation)X +1354(to)X +1439(its)X +1536(remote)X +1781(performance.)X +2250(For)X +2383(the)X +2503(remote)X +2748(case,)X +2929(we)X +3045(ran)X +3170(the)X +3290(frontend)X +3584(on)X +3686(a)X +3744(DECstation)X +4139(3100)X +555 4269(with)N +717(16)X +817(MBytes)X +1090(of)X +1177(main)X +1357(memory.)X +755 4392(The)N +900(databases)X +1228(tested)X +1435(in)X +1517([CATT91])X +1880(are)X +10 f +635 4515(g)N +1 f +755(INDEX,)X +1045(a)X +1101(highly-optimized)X +1672(access)X +1898(method)X +2158(package)X +2442(developed)X +2792(at)X +2870(Sun)X +3014(Microsystems.)X +10 f +635 4638(g)N +1 f +755(OODBMS,)X +1137(a)X +1193(beta)X +1347(release)X +1591(of)X +1678(a)X +1734(commercial)X +2133(object-oriented)X +2639(database)X +2936(management)X +3366(system.)X +10 f +635 4761(g)N +1 f +755(RDBMS,)X +1076(a)X +1133(UNIX-based)X +1565(commercial)X +1965(relational)X +2289(data)X +2444(manager)X +2742(at)X +2821(production)X +3189(release.)X +3474(The)X +3620(OO1)X +3797(implementation)X +755 4851(used)N +922(embedded)X +1272(SQL)X +1443(in)X +1525(C.)X +1638(Stored)X +1867(procedures)X +2240(were)X +2417(de\256ned)X +2673(to)X +2755(reduce)X +2990(client-server)X +3412(traf\256c.)X +755 4974(Table)N +974(two)X +1130(shows)X +1366(the)X +1500(measurements)X +1995(from)X +2187([CATT91])X +2566(and)X +2718(LIBTP)X +2976(for)X +3106(a)X +3178(local)X +3370(test)X +3517(on)X +3632(the)X +3765(MC680x0-based)X +555 5064(hardware.)N +915(All)X +1037(caches)X +1272(are)X +1391(cleared)X +1644(before)X +1870(each)X +2038(test.)X +2209(All)X +2331(times)X +2524(are)X +2643(in)X +2725(seconds.)X +755 5187(Table)N +960(two)X +1102(shows)X +1324(that)X +1466(LIBTP)X +1710(outperforms)X +2123(the)X +2242(commercial)X +2642(relational)X +2966(system,)X +3229(but)X +3352(is)X +3426(slower)X +3661(than)X +3820(OODBMS)X +4183(and)X +555 5277(INDEX.)N +872(Since)X +1077(the)X +1202(caches)X +1444(were)X +1628(cleared)X +1888(at)X +1973(the)X +2098(start)X +2263(of)X +2356(each)X +2530(test,)X +2687(disk)X +2846(throughput)X +3223(is)X +3302(critical)X +3551(in)X +3639(this)X +3780(test.)X +3957(The)X +4108(single)X +555 5367(SCSI)N +749(HP)X +877(drive)X +1068(used)X +1241(by)X +1347(LIBTP)X +1595(is)X +1674(approximately)X +2163(13%)X +2336(slower)X +2576(than)X +2739(the)X +2862(disks)X +3051(used)X +3223(in)X +3310([CATT91])X +3678(which)X +3899(accounts)X +4205(for)X +555 5457(part)N +700(of)X +787(the)X +905(difference.)X +755 5580(OODBMS)N +1118(and)X +1255(INDEX)X +1525(outperform)X +1906(LIBTP)X +2148(most)X +2323(dramatically)X +2744(on)X +2844(traversal.)X +3181(This)X +3343(is)X +3416(because)X +3691(we)X +3805(use)X +3932(index)X +4130(look-)X +555 5670(ups)N +689(to)X +774(\256nd)X +921(connections,)X +1347(whereas)X +1634(the)X +1755(other)X +1942(two)X +2084(systems)X +2359(use)X +2488(a)X +2546(link)X +2692(access)X +2920(method.)X +3222(The)X +3369(index)X +3569(requires)X +3850(us)X +3943(to)X +4027(examine)X + +15 p +%%Page: 15 15 +10 s 10 xH 0 xS 1 f +3 f +1 f +10 f +555 679(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)N +2 f +606 769(Measure)N +1 f +1019(INDEX)X +1389(OODBMS)X +1851(RDBMS)X +2250(LIBTP)X +10 f +555 771(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)N +555 787(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)N +1 f +595 869(Lookup)N +1114(5.4)X +1490(12.9)X +1950(27)X +2291(27.2)X +595 959(Traversal)N +1074(13)X +1530(9.8)X +1950(90)X +2291(47.3)X +595 1049(Insert)N +1114(7.4)X +1530(1.5)X +1950(22)X +2331(9.7)X +10 f +555 1059(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)N +555(c)X +999(c)Y +919(c)Y +839(c)Y +759(c)Y +959 1059(c)N +999(c)Y +919(c)Y +839(c)Y +759(c)Y +1329 1059(c)N +999(c)Y +919(c)Y +839(c)Y +759(c)Y +1791 1059(c)N +999(c)Y +919(c)Y +839(c)Y +759(c)Y +2190 1059(c)N +999(c)Y +919(c)Y +839(c)Y +759(c)Y +2512 1059(c)N +999(c)Y +919(c)Y +839(c)Y +759(c)Y +2618 679(i)N +2629(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +2 f +2829 769(Measure)N +3401(Cache)X +3726(Local)X +4028(Remote)X +1 f +10 f +2618 771(i)N +2629(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +2618 787(i)N +2629(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +1 f +2658 869(Lookup)N +3401(cold)X +3747(15.7)X +4078(20.6)X +3401 959(warm)N +3787(7.8)X +4078(12.4)X +10 f +2618 969(i)N +2629(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +1 f +2658 1059(Forward)N +2950(traversal)X +3401(cold)X +3747(28.4)X +4078(52.6)X +3401 1149(warm)N +3747(23.5)X +4078(47.4)X +10 f +2618 1159(i)N +2629(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +1 f +2658 1249(Backward)N +3004(traversal)X +3401(cold)X +3747(24.2)X +4078(47.4)X +3401 1339(warm)N +3747(24.3)X +4078(47.6)X +10 f +2618 1349(i)N +2629(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +1 f +2658 1439(Insert)N +3401(cold)X +3787(7.5)X +4078(10.3)X +3401 1529(warm)N +3787(6.7)X +4078(10.9)X +10 f +2618 1539(i)N +2629(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X +2618(c)X +1479(c)Y +1399(c)Y +1319(c)Y +1239(c)Y +1159(c)Y +1079(c)Y +999(c)Y +919(c)Y +839(c)Y +759(c)Y +3341 1539(c)N +1479(c)Y +1399(c)Y +1319(c)Y +1239(c)Y +1159(c)Y +1079(c)Y +999(c)Y +919(c)Y +839(c)Y +759(c)Y +3666 1539(c)N +1479(c)Y +1399(c)Y +1319(c)Y +1239(c)Y +1159(c)Y +1079(c)Y +999(c)Y +919(c)Y +839(c)Y +759(c)Y +3968 1539(c)N +1479(c)Y +1399(c)Y +1319(c)Y +1239(c)Y +1159(c)Y +1079(c)Y +999(c)Y +919(c)Y +839(c)Y +759(c)Y +4309 1539(c)N +1479(c)Y +1399(c)Y +1319(c)Y +1239(c)Y +1159(c)Y +1079(c)Y +999(c)Y +919(c)Y +839(c)Y +759(c)Y +3 f +587 1785(Table)N +823(2:)X +931(Local)X +1163(MC680x0)X +1538(Performance)X +2026(of)X +2133(Several)X +587 1875(Systems)N +883(on)X +987(OO1.)X +2667 1785(Table)N +2909(3:)X +3023(Local)X +3260(vs.)X +3397(Remote)X +3707(Performance)X +4200(of)X +2667 1875(LIBTP)N +2926(on)X +3030(OO1.)X +1 f +10 f +555 1998(h)N +579(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)X +1 f +555 2274(two)N +696(disk)X +850(pages,)X +1074(but)X +1197(the)X +1316(links)X +1492(require)X +1741(only)X +1904(one,)X +2061(regardless)X +2408(of)X +2496(database)X +2794(size.)X +2980(Cattell)X +3214(reports)X +3458(that)X +3599(lookups)X +3873(using)X +4067(B-trees)X +555 2364(instead)N +808(of)X +901(links)X +1082(makes)X +1313(traversal)X +1616(take)X +1776(twice)X +1976(as)X +2069(long)X +2237(in)X +2325(INDEX.)X +2641(Adding)X +2907(a)X +2969(link)X +3119(access)X +3351(method)X +3617(to)X +3 f +3704(db)X +1 f +3792(\(3\))X +3911(or)X +4003(using)X +4201(the)X +555 2454(existing)N +828(hash)X +995(method)X +1255(would)X +1475(apparently)X +1834(be)X +1930(a)X +1986(good)X +2166(idea.)X +755 2577(Both)N +936(OODBMS)X +1304(and)X +1446(INDEX)X +1722(issue)X +1908 0.1944(coarser-granularity)AX +2545(locks)X +2739(than)X +2902(LIBTP.)X +3189(This)X +3356(limits)X +3562(concurrency)X +3985(for)X +4104(multi-)X +555 2667(user)N +711(applications,)X +1140(but)X +1264(helps)X +1455(single-user)X +1829(applications.)X +2278(In)X +2367(addition,)X +2671(the)X +2791(fact)X +2934(that)X +3076(LIBTP)X +3319(releases)X +3595(B-tree)X +3817(locks)X +4007(early)X +4189(is)X +4263(a)X +555 2757(drawback)N +896(in)X +986(OO1.)X +1210(Since)X +1416(there)X +1605(is)X +1686(no)X +1793(concurrency)X +2218(in)X +2307(the)X +2432(benchmark,)X +2836(high-concurrency)X +3430(strategies)X +3760(only)X +3929(show)X +4125(up)X +4232(as)X +555 2847(increased)N +882(locking)X +1145(overhead.)X +1503(Finally,)X +1772(the)X +1892(architecture)X +2294(of)X +2383(the)X +2503(LIBTP)X +2747(implementation)X +3271(was)X +3418(substantially)X +3844(different)X +4143(from)X +555 2937(that)N +702(of)X +796(either)X +1006(OODBMS)X +1375(or)X +1469(INDEX.)X +1786(Both)X +1968(of)X +2062(those)X +2258(systems)X +2538(do)X +2645(the)X +2770(searches)X +3070(in)X +3159(the)X +3284(user's)X +3503(address)X +3771(space,)X +3997(and)X +4139(issue)X +555 3027(requests)N +844(for)X +964(pages)X +1173(to)X +1260(the)X +1383(server)X +1605(process.)X +1911(Pages)X +2123(are)X +2247(cached)X +2496(in)X +2583(the)X +2706(client,)X +2929(and)X +3070(many)X +3273(queries)X +3530(can)X +3667(be)X +3768(satis\256ed)X +4055(without)X +555 3117(contacting)N +910(the)X +1029(server)X +1247(at)X +1326(all.)X +1467(LIBTP)X +1710(submits)X +1979(all)X +2080(the)X +2199(queries)X +2452(to)X +2535(the)X +2653(server)X +2870(process,)X +3151(and)X +3287(receives)X +3571(database)X +3868(records)X +4125(back;)X +555 3207(it)N +619(does)X +786(no)X +886(client)X +1084(caching.)X +755 3330(The)N +911(RDBMS)X +1221(architecture)X +1632(is)X +1716(much)X +1925(closer)X +2148(to)X +2241(that)X +2392(of)X +2490(LIBTP.)X +2783(A)X +2872(server)X +3100(process)X +3372(receives)X +3667(queries)X +3930(and)X +4076(returns)X +555 3420(results)N +786(to)X +870(a)X +928(client.)X +1168(The)X +1315(timing)X +1545(results)X +1776(in)X +1860(table)X +2038(two)X +2180(clearly)X +2421(show)X +2612(that)X +2754(the)X +2874(conventional)X +3309(database)X +3607(client/server)X +4025(model)X +4246(is)X +555 3510(expensive.)N +941(LIBTP)X +1188(outperforms)X +1605(the)X +1728(RDBMS)X +2032(on)X +2136(traversal)X +2437(and)X +2577(insertion.)X +2921(We)X +3057(speculate)X +3380(that)X +3524(this)X +3663(is)X +3740(due)X +3880(in)X +3966(part)X +4115(to)X +4201(the)X +555 3600(overhead)N +870(of)X +957(query)X +1160(parsing,)X +1436(optimization,)X +1880(and)X +2016(repeated)X +2309(interpretation)X +2761(of)X +2848(the)X +2966(plan)X +3124(tree)X +3265(in)X +3347(the)X +3465(RDBMS')X +3791(query)X +3994(executor.)X +755 3723(Table)N +962(three)X +1147(shows)X +1371(the)X +1492(differences)X +1873(between)X +2164(local)X +2343(and)X +2482(remote)X +2728(execution)X +3063(of)X +3153(LIBTP's)X +3456(OO1)X +3635(implementation)X +4160(on)X +4263(a)X +555 3813(DECstation.)N +989(We)X +1122(measured)X +1451(performance)X +1879(with)X +2042(a)X +2099(populated)X +2436(\(warm\))X +2694(cache)X +2899(and)X +3036(an)X +3133(empty)X +3354(\(cold\))X +3567(cache.)X +3812(Reported)X +4126(times)X +555 3903(are)N +681(the)X +806(means)X +1037(of)X +1130(twenty)X +1374(tests,)X +1562(and)X +1704(are)X +1829(in)X +1917(seconds.)X +2237(Standard)X +2548(deviations)X +2903(were)X +3086(within)X +3316(seven)X +3525(percent)X +3788(of)X +3881(the)X +4005(mean)X +4205(for)X +555 3993(remote,)N +818(and)X +954(two)X +1094(percent)X +1351(of)X +1438(the)X +1556(mean)X +1750(for)X +1864(local.)X +755 4116(The)N +914(20ms)X +1121(overhead)X +1450(of)X +1551(TCP/IP)X +1824(on)X +1938(an)X +2048(Ethernet)X +2354(entirely)X +2633(accounts)X +2948(for)X +3076(the)X +3207(difference)X +3567(in)X +3662(speed.)X +3918(The)X +4076(remote)X +555 4206(traversal)N +857(times)X +1055(are)X +1179(nearly)X +1405(double)X +1648(the)X +1771(local)X +1952(times)X +2150(because)X +2430(we)X +2549(do)X +2653(index)X +2855(lookups)X +3132(and)X +3272(part)X +3421(fetches)X +3673(in)X +3759(separate)X +4047(queries.)X +555 4296(It)N +629(would)X +854(make)X +1053(sense)X +1252(to)X +1339(do)X +1444(indexed)X +1723(searches)X +2021(on)X +2126(the)X +2248(server,)X +2489(but)X +2615(we)X +2733(were)X +2914(unwilling)X +3244(to)X +3330(hard-code)X +3676(knowledge)X +4052(of)X +4143(OO1)X +555 4386(indices)N +803(into)X +948(our)X +1075(LIBTP)X +1317(TCL)X +1488(server.)X +1745(Cold)X +1920(and)X +2056(warm)X +2259(insertion)X +2559(times)X +2752(are)X +2871(identical)X +3167(since)X +3352(insertions)X +3683(do)X +3783(not)X +3905(bene\256t)X +4143(from)X +555 4476(caching.)N +755 4599(One)N +915(interesting)X +1279(difference)X +1632(shown)X +1867(by)X +1973(table)X +2155(three)X +2342(is)X +2421(the)X +2545(cost)X +2700(of)X +2793(forward)X +3074(versus)X +3305(backward)X +3644(traversal.)X +3987(When)X +4205(we)X +555 4689(built)N +725(the)X +847(database,)X +1168(we)X +1285(inserted)X +1562(parts)X +1741(in)X +1826(part)X +2 f +1974(id)X +1 f +2059(order.)X +2292(We)X +2427(built)X +2596(the)X +2717(indices)X +2967(at)X +3048(the)X +3169(same)X +3357(time.)X +3562(Therefore,)X +3923(the)X +4044(forward)X +555 4779(index)N +757(had)X +897(keys)X +1068(inserted)X +1346(in)X +1432(order,)X +1646(while)X +1848(the)X +1970(backward)X +2307(index)X +2509(had)X +2649(keys)X +2820(inserted)X +3098(more)X +3286(randomly.)X +3656(In-order)X +3943(insertion)X +4246(is)X +555 4885(pessimal)N +858(for)X +975(B-tree)X +1199(indices,)X +1469(so)X +1563(the)X +1684(forward)X +1962(index)X +2163(is)X +2239(much)X +2440(larger)X +2651(than)X +2812(the)X +2933(backward)X +3269(one)X +7 s +3385 4853(5)N +10 s +4885(.)Y +3476(This)X +3640(larger)X +3850(size)X +3997(shows)X +4219(up)X +555 4975(as)N +642(extra)X +823(disk)X +976(reads)X +1166(in)X +1248(the)X +1366(cold)X +1524(benchmark.)X +3 f +555 5161(6.)N +655(Conclusions)X +1 f +755 5284(LIBTP)N +1006(provides)X +1311(the)X +1438(basic)X +1632(building)X +1927(blocks)X +2165(to)X +2256(support)X +2525(transaction)X +2906(protection.)X +3300(In)X +3396(comparison)X +3799(with)X +3970(traditional)X +555 5374(Unix)N +746(libraries)X +1040(and)X +1187(commercial)X +1597(systems,)X +1900(it)X +1974(offers)X +2192(a)X +2258(variety)X +2511(of)X +2608(tradeoffs.)X +2964(Using)X +3185(complete)X +3509(transaction)X +3891(protection)X +4246(is)X +555 5464(more)N +747(complicated)X +1166(than)X +1331(simply)X +1575(adding)X +3 f +1820(fsync)X +1 f +1998(\(2\))X +2119(and)X +3 f +2262(\257ock)X +1 f +2426(\(2\))X +2547(calls)X +2721(to)X +2810(code,)X +3008(but)X +3136(it)X +3206(is)X +3285(faster)X +3490(in)X +3578(some)X +3773(cases)X +3969(and)X +4111(offers)X +8 s +10 f +555 5536(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)N +5 s +1 f +727 5614(5)N +8 s +763 5639(The)N +878(next)X +1004(release)X +1196(of)X +1265(the)X +1359(4.4BSD)X +1580(access)X +1758(method)X +1966(will)X +2082(automatically)X +2446(detect)X +2614(and)X +2722(compensate)X +3039(for)X +3129(in-order)X +3350(insertion,)X +3606(eliminating)X +3914(this)X +4023(problem.)X + +16 p +%%Page: 16 16 +8 s 8 xH 0 xS 1 f +10 s +3 f +1 f +555 630(stricter)N +801(guarantees)X +1168(\(atomicity,)X +1540(consistency,)X +1957(isolation,)X +2275(and)X +2414(durability\).)X +2815(If)X +2892(the)X +3013(data)X +3170(to)X +3255(be)X +3354(protected)X +3676(are)X +3798(already)X +4058(format-)X +555 720(ted)N +675(\()X +2 f +702(i.e.)X +1 f +821(use)X +949(one)X +1086(of)X +1174(the)X +1293(database)X +1591(access)X +1818(methods\),)X +2157(then)X +2316(adding)X +2555(transaction)X +2928(protection)X +3274(requires)X +3554(no)X +3655(additional)X +3996(complex-)X +555 810(ity,)N +679(but)X +801(incurs)X +1017(a)X +1073(performance)X +1500(penalty)X +1756(of)X +1843(approximately)X +2326(15%.)X +755 933(In)N +844(comparison)X +1240(with)X +1404(commercial)X +1805(database)X +2104(systems,)X +2399(the)X +2519(tradeoffs)X +2827(are)X +2948(more)X +3135(complex.)X +3473(LIBTP)X +3717(does)X +3886(not)X +4009(currently)X +555 1023(support)N +825(a)X +891(standard)X +1193(query)X +1406(language.)X +1766(The)X +1921(TCL-based)X +2312(server)X +2539(process)X +2810(allows)X +3049(a)X +3115(certain)X +3364(ease)X +3533(of)X +3630(use)X +3767(which)X +3993(would)X +4223(be)X +555 1113(enhanced)N +882(with)X +1047(a)X +1106(more)X +1294(user-friendly)X +1732(interface)X +2037(\()X +2 f +2064(e.g.)X +1 f +2203(a)X +2261(windows)X +2572(based)X +2777(query-by-form)X +3272(application\),)X +3697(for)X +3813(which)X +4031(we)X +4147(have)X +555 1203(a)N +620(working)X +916(prototype.)X +1292(When)X +1513(accesses)X +1815(do)X +1924(not)X +2055(require)X +2312(sophisticated)X +2758(query)X +2969(processing,)X +3360(the)X +3486(TCL)X +3665(interface)X +3975(is)X +4056(an)X +4160(ade-)X +555 1293(quate)N +756(solution.)X +1080(What)X +1281(LIBTP)X +1529(fails)X +1693(to)X +1781(provide)X +2052(in)X +2140(functionality,)X +2595(it)X +2665(makes)X +2896(up)X +3002(for)X +3122(in)X +3210(performance)X +3643(and)X +3785(\257exibility.)X +4161(Any)X +555 1383(application)N +931(may)X +1089(make)X +1283(use)X +1410(of)X +1497(its)X +1592(record)X +1818(interface)X +2120(or)X +2207(the)X +2325(more)X +2510(primitive)X +2823(log,)X +2965(lock,)X +3143(and)X +3279(buffer)X +3496(calls.)X +755 1506(Future)N +987(work)X +1175(will)X +1322(focus)X +1519(on)X +1621(overcoming)X +2026(some)X +2217(of)X +2306(the)X +2426(areas)X +2614(in)X +2698(which)X +2916(LIBTP)X +3160(is)X +3235(currently)X +3547(de\256cient)X +3845(and)X +3983(extending)X +555 1596(its)N +652(transaction)X +1026(model.)X +1288(The)X +1435(addition)X +1719(of)X +1808(an)X +1905(SQL)X +2077(parser)X +2295(and)X +2432(forms)X +2640(front)X +2817(end)X +2954(will)X +3099(improve)X +3387(the)X +3506(system's)X +3807(ease)X +3967(of)X +4055(use)X +4183(and)X +555 1686(make)N +750(it)X +815(more)X +1001(competitive)X +1400(with)X +1563(commercial)X +1963(systems.)X +2277(In)X +2365(the)X +2484(long)X +2647(term,)X +2835(we)X +2950(would)X +3170(like)X +3310(to)X +3392(add)X +3528(generalized)X +3919(hierarchical)X +555 1776(locking,)N +836(nested)X +1062(transactions,)X +1486(parallel)X +1748(transactions,)X +2171(passing)X +2431(of)X +2518(transactions)X +2921(between)X +3209(processes,)X +3557(and)X +3693(distributed)X +4055(commit)X +555 1866(handling.)N +900(In)X +992(the)X +1115(short)X +1300(term,)X +1492(the)X +1614(next)X +1776(step)X +1929(is)X +2006(to)X +2092(integrate)X +2397(LIBTP)X +2643(with)X +2809(the)X +2931(most)X +3110(recent)X +3331(release)X +3579(of)X +3670(the)X +3792(database)X +4093(access)X +555 1956(routines)N +833(and)X +969(make)X +1163(it)X +1227(freely)X +1435(available)X +1745(via)X +1863(anonymous)X +2252(ftp.)X +3 f +555 2142(7.)N +655(Acknowledgements)X +1 f +755 2265(We)N +888(would)X +1109(like)X +1250(to)X +1332(thank)X +1530(John)X +1701(Wilkes)X +1948(and)X +2084(Carl)X +2242(Staelin)X +2484(of)X +2571(Hewlett-Packard)X +3131(Laboratories)X +3557(and)X +3693(Jon)X +3824(Krueger.)X +4148(John)X +555 2355(and)N +694(Carl)X +855(provided)X +1162(us)X +1255(with)X +1419(an)X +1517(extra)X +1700(disk)X +1855(for)X +1971(the)X +2091(HP)X +2215(testbed)X +2464(less)X +2606(than)X +2766(24)X +2868(hours)X +3068(after)X +3238(we)X +3354(requested)X +3684(it.)X +3770(Jon)X +3903(spent)X +4094(count-)X +555 2445(less)N +699(hours)X +901(helping)X +1164(us)X +1258(understand)X +1633(the)X +1754(intricacies)X +2107(of)X +2197(commercial)X +2599(database)X +2899(products)X +3198(and)X +3337(their)X +3507(behavior)X +3811(under)X +4017(a)X +4076(variety)X +555 2535(of)N +642(system)X +884(con\256gurations.)X +3 f +555 2721(8.)N +655(References)X +1 f +555 2901([ANDR89])N +942(Andrade,)X +1265(J.,)X +1361(Carges,)X +1629(M.,)X +1765(Kovach,)X +2060(K.,)X +2183(``Building)X +2541(an)X +2642(On-Line)X +2939(Transaction)X +3343(Processing)X +3715(System)X +3975(On)X +4098(UNIX)X +727 2991(System)N +982(V'',)X +2 f +1134(CommUNIXations)X +1 f +1725(,)X +1765 0.2188(November/December)AX +2477(1989.)X +555 3171([BAY77])N +878(Bayer,)X +1110(R.,)X +1223(Schkolnick,)X +1623(M.,)X +1754(``Concurrency)X +2243(of)X +2330(Operations)X +2702(on)X +2802(B-Trees'',)X +2 f +3155(Acta)X +3322(Informatica)X +1 f +3700(,)X +3740(1977.)X +555 3351([BERN80])N +936(Bernstein,)X +1297(P.,)X +1415(Goodman,)X +1785(N.,)X +1917(``Timestamp)X +2365(Based)X +2595(Algorithms)X +2992(for)X +3119(Concurrency)X +3567(Control)X +3844(in)X +3939(Distributed)X +727 3441(Database)N +1042(Systems'',)X +2 f +1402(Proceedings)X +1823(6th)X +1945(International)X +2387(Conference)X +2777(on)X +2877(Very)X +3049(Large)X +3260(Data)X +3440(Bases)X +1 f +3627(,)X +3667(October)X +3946(1980.)X +555 3621([BSD91])N +864(DB\(3\),)X +2 f +1109(4.4BSD)X +1376(Unix)X +1552(Programmer's)X +2044(Manual)X +2313(Reference)X +2655(Guide)X +1 f +2851(,)X +2891(University)X +3249(of)X +3336(California,)X +3701(Berkeley,)X +4031(1991.)X +555 3801([CATT91])N +923(Cattell,)X +1181(R.G.G.,)X +1455(``An)X +1632(Engineering)X +2049(Database)X +2369(Benchmark'',)X +2 f +2838(The)X +2983(Benchmark)X +3373(Handbook)X +3731(for)X +3848(Database)X +4179(and)X +727 3891(Transaction)N +1133(Processing)X +1509(Systems)X +1 f +1763(,)X +1803(J.)X +1874(Gray,)X +2075(editor,)X +2302(Morgan)X +2576(Kaufman)X +2895(1991.)X +555 4071([CHEN91])N +929(Cheng,)X +1180(E.,)X +1291(Chang,)X +1542(E.,)X +1653(Klein,)X +1872(J.,)X +1964(Lee,)X +2126(D.,)X +2245(Lu,)X +2375(E.,)X +2485(Lutgardo,)X +2820(A.,)X +2939(Obermarck,)X +3342(R.,)X +3456(``An)X +3629(Open)X +3824(and)X +3961(Extensible)X +727 4161(Event-Based)N +1157(Transaction)X +1556(Manager'',)X +2 f +1936(Proceedings)X +2357(1991)X +2537(Summer)X +2820(Usenix)X +1 f +3043(,)X +3083(Nashville,)X +3430(TN,)X +3577(June)X +3744(1991.)X +555 4341([CHOU85])N +943(Chou,)X +1163(H.,)X +1288(DeWitt,)X +1570(D.,)X +1694(``An)X +1872(Evaluation)X +2245(of)X +2338(Buffer)X +2574(Management)X +3019(Strategies)X +3361(for)X +3481(Relational)X +3836(Database)X +4157(Sys-)X +727 4431(tems'',)N +2 f +972(Proceedings)X +1393(of)X +1475(the)X +1593(11th)X +1755(International)X +2197(Conference)X +2587(on)X +2687(Very)X +2859(Large)X +3070(Databases)X +1 f +3408(,)X +3448(1985.)X +555 4611([DEWI84])N +925(DeWitt,)X +1207(D.,)X +1331(Katz,)X +1529(R.,)X +1648(Olken,)X +1890(F.,)X +2000(Shapiro,)X +2295(L.,)X +2410(Stonebraker,)X +2843(M.,)X +2979(Wood,)X +3220(D.,)X +3343(``Implementation)X +3929(Techniques)X +727 4701(for)N +841(Main)X +1030(Memory)X +1326(Database)X +1641(Systems'',)X +2 f +2001(Proceedings)X +2422(of)X +2504(SIGMOD)X +1 f +2812(,)X +2852(pp.)X +2972(1-8,)X +3119(June)X +3286(1984.)X +555 4881([GRAY76])N +944(Gray,)X +1153(J.,)X +1252(Lorie,)X +1474(R.,)X +1595(Putzolu,)X +1887(F.,)X +1999(and)X +2143(Traiger,)X +2428(I.,)X +2522(``Granularity)X +2973(of)X +3067(locks)X +3263(and)X +3406(degrees)X +3679(of)X +3773(consistency)X +4174(in)X +4263(a)X +727 4971(large)N +909(shared)X +1140(data)X +1295(base'',)X +2 f +1533(Modeling)X +1861(in)X +1944(Data)X +2125(Base)X +2301(Management)X +2740(Systems)X +1 f +2994(,)X +3034(Elsevier)X +3317(North)X +3524(Holland,)X +3822(New)X +3994(York,)X +4199(pp.)X +727 5061(365-394.)N +555 5241([HAER83])N +931(Haerder,)X +1235(T.)X +1348(Reuter,)X +1606(A.)X +1728(``Principles)X +2126(of)X +2217(Transaction-Oriented)X +2928(Database)X +3246(Recovery'',)X +2 f +3651(Computing)X +4029(Surveys)X +1 f +4279(,)X +727 5331(15\(4\);)N +943(237-318,)X +1250(1983.)X +555 5511([KUNG81])N +943(Kung,)X +1162(H.)X +1261(T.,)X +1371(Richardson,)X +1777(J.,)X +1869(``On)X +2042(Optimistic)X +2400(Methods)X +2701(for)X +2816(Concurrency)X +3252(Control'',)X +2 f +3591(ACM)X +3781(Transactions)X +4219(on)X +727 5601(Database)N +1054(Systems)X +1 f +1328(6\(2\);)X +1504(213-226,)X +1811(1981.)X + +17 p +%%Page: 17 17 +10 s 10 xH 0 xS 1 f +3 f +1 f +555 630([LEHM81])N +939(Lehman,)X +1245(P.,)X +1352(Yao,)X +1529(S.,)X +1636(``Ef\256cient)X +1989(Locking)X +2279(for)X +2396(Concurrent)X +2780(Operations)X +3155(on)X +3258(B-trees'',)X +2 f +3587(ACM)X +3779(Transactions)X +4219(on)X +727 720(Database)N +1054(Systems)X +1 f +1308(,)X +1348(6\(4\),)X +1522(December)X +1873(1981.)X +555 900([MOHA91])N +964(Mohan,)X +1241(C.,)X +1364(Pirahesh,)X +1690(H.,)X +1818(``ARIES-RRH:)X +2366(Restricted)X +2721(Repeating)X +3076(of)X +3173(History)X +3442(in)X +3533(the)X +3660(ARIES)X +3920(Transaction)X +727 990(Recovery)N +1055(Method'',)X +2 f +1398(Proceedings)X +1819(7th)X +1941(International)X +2383(Conference)X +2773(on)X +2873(Data)X +3053(Engineering)X +1 f +3449(,)X +3489(Kobe,)X +3703(Japan,)X +3926(April)X +4115(1991.)X +555 1170([NODI90])N +914(Nodine,)X +1194(M.,)X +1328(Zdonik,)X +1602(S.,)X +1709(``Cooperative)X +2178(Transaction)X +2580(Hierarchies:)X +2996(A)X +3077(Transaction)X +3479(Model)X +3711(to)X +3796(Support)X +4072(Design)X +727 1260(Applications'',)N +2 f +1242(Proceedings)X +1675(16th)X +1849(International)X +2303(Conference)X +2704(on)X +2815(Very)X +2998(Large)X +3220(Data)X +3411(Bases)X +1 f +3598(,)X +3649(Brisbane,)X +3985(Australia,)X +727 1350(August)N +978(1990.)X +555 1530([OUST90])N +923(Ousterhout,)X +1324(J.,)X +1420(``Tcl:)X +1648(An)X +1771(Embeddable)X +2197(Command)X +2555(Language'',)X +2 f +2971(Proceedings)X +3396(1990)X +3580(Winter)X +3822(Usenix)X +1 f +4045(,)X +4089(Wash-)X +727 1620(ington,)N +971(D.C.,)X +1162(January)X +1432(1990.)X +555 1800([POSIX91])N +955(``Unapproved)X +1441(Draft)X +1645(for)X +1773(Realtime)X +2096(Extension)X +2450(for)X +2578(Portable)X +2879(Operating)X +3234(Systems'',)X +3608(Draft)X +3812(11,)X +3946(October)X +4239(7,)X +727 1890(1991,)N +927(IEEE)X +1121(Computer)X +1461(Society.)X +555 2070([ROSE91])N +925(Rosenblum,)X +1341(M.,)X +1484(Ousterhout,)X +1892(J.,)X +1995(``The)X +2206(Design)X +2464(and)X +2611(Implementation)X +3149(of)X +3247(a)X +3314(Log-Structured)X +3835(File)X +3990(System'',)X +2 f +727 2160(Proceedings)N +1148(of)X +1230(the)X +1348(13th)X +1510(Symposium)X +1895(on)X +1995(Operating)X +2344(Systems)X +2618(Principles)X +1 f +2947(,)X +2987(1991.)X +555 2340([SELT91])N +904(Seltzer,)X +1171(M.,)X +1306(Stonebraker,)X +1738(M.,)X +1873(``Read)X +2116(Optimized)X +2478(File)X +2626(Systems:)X +2938(A)X +3020(Performance)X +3454(Evaluation'',)X +2 f +3898(Proceedings)X +727 2430(7th)N +849(Annual)X +1100(International)X +1542(Conference)X +1932(on)X +2032(Data)X +2212(Engineering)X +1 f +2608(,)X +2648(Kobe,)X +2862(Japan,)X +3085(April)X +3274(1991.)X +555 2610([SPEC88])N +907(Spector,)X +1200(Rausch,)X +1484(Bruell,)X +1732(``Camelot:)X +2107(A)X +2192(Flexible,)X +2501(Distributed)X +2888(Transaction)X +3294(Processing)X +3668(System'',)X +2 f +4004(Proceed-)X +727 2700(ings)N +880(of)X +962(Spring)X +1195(COMPCON)X +1606(1988)X +1 f +(,)S +1806(February)X +2116(1988.)X +555 2880([SQL86])N +862(American)X +1201(National)X +1499(Standards)X +1836(Institute,)X +2139(``Database)X +2509(Language)X +2847(SQL'',)X +3093(ANSI)X +3301(X3.135-1986)X +3747(\(ISO)X +3924(9075\),)X +4152(May)X +727 2970(1986.)N +555 3150([STON81])N +919(Stonebraker,)X +1348(M.,)X +1480(``Operating)X +1876(System)X +2132(Support)X +2406(for)X +2520(Database)X +2835(Management'',)X +2 f +3348(Communications)X +3910(of)X +3992(the)X +4110(ACM)X +1 f +4279(,)X +727 3240(1981.)N +555 3420([SULL92])N +925(Sullivan,)X +1247(M.,)X +1394(Olson,)X +1641(M.,)X +1788(``An)X +1976(Index)X +2195(Implementation)X +2737(Supporting)X +3127(Fast)X +3295(Recovery)X +3638(for)X +3767(the)X +3900(POSTGRES)X +727 3510(Storage)N +1014(System'',)X +1365(to)X +1469(appear)X +1726(in)X +2 f +1830(Proceedings)X +2272(8th)X +2415(Annual)X +2687(International)X +3150(Conference)X +3561(on)X +3682(Data)X +3883(Engineering)X +1 f +4279(,)X +727 3600(Tempe,)N +990(Arizona,)X +1289(February)X +1599(1992.)X +555 3780([TPCB90])N +914(Transaction)X +1319(Processing)X +1692(Performance)X +2129(Council,)X +2428(``TPC)X +2653(Benchmark)X +3048(B'',)X +3200(Standard)X +3510(Speci\256cation,)X +3973(Waterside)X +727 3870(Associates,)N +1110(Fremont,)X +1421(CA.,)X +1592(1990.)X +555 4050([YOUN91])N +947(Young,)X +1211(M.)X +1328(W.,)X +1470(Thompson,)X +1858(D.)X +1962(S.,)X +2072(Jaffe,)X +2274(E.,)X +2388(``A)X +2525(Modular)X +2826(Architecture)X +3253(for)X +3372(Distributed)X +3757(Transaction)X +4161(Pro-)X +727 4140(cessing'',)N +2 f +1057(Proceedings)X +1478(1991)X +1658(Winter)X +1896(Usenix)X +1 f +2119(,)X +2159(Dallas,)X +2404(TX,)X +2551(January)X +2821(1991.)X +3 f +755 4263(Margo)N +1008(I.)X +1080(Seltzer)X +1 f +1338(is)X +1411(a)X +1467(Ph.D.)X +1669(student)X +1920(in)X +2002(the)X +2120(Department)X +2519(of)X +2606(Electrical)X +2934(Engineering)X +3346(and)X +3482(Computer)X +3822(Sciences)X +4123(at)X +4201(the)X +555 4353(University)N +919(of)X +1012(California,)X +1383(Berkeley.)X +1739(Her)X +1886(research)X +2181(interests)X +2474(include)X +2735(\256le)X +2862(systems,)X +3160(databases,)X +3513(and)X +3654(transaction)X +4031(process-)X +555 4443(ing)N +686(systems.)X +1008(She)X +1157(spent)X +1355(several)X +1612(years)X +1811(working)X +2107(at)X +2194(startup)X +2441(companies)X +2813(designing)X +3153(and)X +3298(implementing)X +3771(\256le)X +3902(systems)X +4183(and)X +555 4533(transaction)N +929(processing)X +1294(software)X +1592(and)X +1729(designing)X +2061(microprocessors.)X +2648(Ms.)X +2791(Seltzer)X +3035(received)X +3329(her)X +3453(AB)X +3585(in)X +3668(Applied)X +3947(Mathemat-)X +555 4623(ics)N +664(from)X +840 0.1953(Harvard/Radcliffe)AX +1445(College)X +1714(in)X +1796(1983.)X +755 4746(In)N +845(her)X +971(spare)X +1163(time,)X +1347(Margo)X +1583(can)X +1717(usually)X +1970(be)X +2068(found)X +2277(preparing)X +2607(massive)X +2887(quantities)X +3220(of)X +3309(food)X +3478(for)X +3594(hungry)X +3843(hordes,)X +4099(study-)X +555 4836(ing)N +677(Japanese,)X +1003(or)X +1090(playing)X +1350(soccer)X +1576(with)X +1738(an)X +1834(exciting)X +2112(Bay)X +2261(Area)X +2438(Women's)X +2770(Soccer)X +3009(team,)X +3205(the)X +3323(Berkeley)X +3633(Bruisers.)X +3 f +755 5049(Michael)N +1056(A.)X +1159(Olson)X +1 f +1383(is)X +1461(a)X +1522(Master's)X +1828(student)X +2084(in)X +2170(the)X +2292(Department)X +2695(of)X +2786(Electrical)X +3118(Engineering)X +3534(and)X +3674(Computer)X +4018(Sciences)X +555 5139(at)N +645(the)X +774(University)X +1143(of)X +1241(California,)X +1617(Berkeley.)X +1978(His)X +2120(primary)X +2405(interests)X +2703(are)X +2833(database)X +3141(systems)X +3425(and)X +3572(mass)X +3763(storage)X +4026(systems.)X +555 5229(Mike)N +759(spent)X +963(two)X +1118(years)X +1323(working)X +1625(for)X +1754(a)X +1825(commercial)X +2239(database)X +2551(system)X +2808(vendor)X +3066(before)X +3307(joining)X +3567(the)X +3699(Postgres)X +4004(Research)X +555 5319(Group)N +780(at)X +858(Berkeley)X +1168(in)X +1250(1988.)X +1470(He)X +1584(received)X +1877(his)X +1990(B.A.)X +2161(in)X +2243(Computer)X +2583(Science)X +2853(from)X +3029(Berkeley)X +3339(in)X +3421(May)X +3588(1991.)X +755 5442(Mike)N +945(only)X +1108(recently)X +1388(transferred)X +1758(into)X +1903(Sin)X +2030(City,)X +2208(but)X +2330(is)X +2403(rapidly)X +2650(adopting)X +2950(local)X +3126(customs)X +3408(and)X +3544(coloration.)X +3929(In)X +4016(his)X +4129(spare)X +555 5532(time,)N +742(he)X +843(organizes)X +1176(informal)X +1477(Friday)X +1711(afternoon)X +2043(study)X +2240(groups)X +2482(to)X +2568(discuss)X +2823(recent)X +3044(technical)X +3358(and)X +3498(economic)X +3834(developments.)X +555 5622(Among)N +815(his)X +928(hobbies)X +1197(are)X +1316(Charles)X +1581(Dickens,)X +1884(Red)X +2033(Rock,)X +2242(and)X +2378(speaking)X +2683(Dutch)X +2899(to)X +2981(anyone)X +3233(who)X +3391(will)X +3535(permit)X +3764(it.)X + +17 p +%%Trailer +xt + +xs + diff --git a/db/docs/ref/refs/refs.html b/db/docs/ref/refs/refs.html new file mode 100644 index 000000000..9e321b938 --- /dev/null +++ b/db/docs/ref/refs/refs.html @@ -0,0 +1,75 @@ + + + + + +Berkeley DB Reference Guide: Additional references + + + + + + +

Berkeley DB Reference Guide:
Additional References

PrevRef +
+

+

Additional references

+

For more information on Berkeley DB, or on database systems theory in general, +we recommend the sources listed below. +

Technical Papers on Berkeley DB

+

These papers have appeared in refereed conference proceedings, and are +subject to copyrights held by the conference organizers and the authors +of the papers. Sleepycat Software makes them available here as a courtesy +with the permission of the copyright holders. +

+

Berkeley DB (HTML, Postscript)
Michael Olson, Keith Bostic, and Margo Seltzer, Proceedings of the 1999 +Summer Usenix Technical Conference, Monterey, California, June 1999. This +paper describes recent commercial releases of Berkeley DB, its most important +features, the history of the software, and Sleepycat's Open Source +licensing policies. +

Challenges in Embedded Database System Administration +(HTML)
Margo Seltzer and Michael Olson, First Workshop on Embedded Systems, +Cambridge, Massachusetts, March 1999. This paper describes the challenges +that face embedded systems developers, and how Berkeley DB has been designed to +address them. +

LIBTP: Portable Modular Transactions for UNIX +(Postscript)
Margo Seltzer and Michael Olson, USENIX Conference Proceedings, Winter +1992. This paper describes an early prototype of the transactional system +for Berkeley DB. +

A New Hashing Package for UNIX +(Postscript)
Margo Seltzer and Oz Yigit, USENIX Conference Proceedings, Winter 1991. +This paper describes the Extended Linear Hashing techniques used by Berkeley DB. +
+

Background on Berkeley DB Features

+

These papers, while not specific to Berkeley DB, give a good overview of how +different Berkeley DB features were implemented. +

+

Operating System Support for Database Management
Michael Stonebraker, Communications of the ACM 24(7), 1981, pp. 412-418. +

Dynamic Hash Tables
Per-Ake Larson, Communications of the ACM, April 1988. +

Linear Hashing: A New Tool for File and Table Addressing
Witold Litwin, Proceedings of the 6th International +Conference on Very Large Databases (VLDB), 1980 +

The Ubiquitous B-tree
Douglas Comer, ACM Comput. Surv. 11, 2 (June 1979), pp. 121-138. +

Prefix B-trees
Bayer and Unterauer, ACM Transactions on Database Systems, Vol. 2, 1 +(March 1977), pp. 11-26. +

The Art of Computer Programming Vol. 3: Sorting and Searching
D.E. Knuth, 1968, pp. 471-480. +

Document Processing in a Relational Database System
Michael Stonebraker, Heidi Stettner, Joseph Kalash, Antonin Guttman, +Nadene Lynn, Memorandum No. UCB/ERL M82/32, May 1982. +
+

Database Systems Theory

+

These publications are standard reference works on the design and +implementation of database systems. Berkeley DB uses many of the ideas they +describe. +

+

Transaction Processing Concepts and Techniques
by Jim Gray and Andreas Reuter, Morgan Kaufmann Publishers. +We recommend chapters 1, 4 (skip 4.6, 4.7, 4.9, 4.10 and 4.11), +7, 9, 10.3, and 10.4. +

An Introduction to Database Systems, Volume 1
by C.J. Date, Addison Wesley Longman Publishers. +In the 5th Edition, we recommend chapters 1, 2, 3, 16 and 17. +

Concurrency Control and Recovery in Database Systems
by Bernstein, Goodman, Hadzilaco. Currently out of print, but available +from http://research.microsoft.com/pubs/ccontrol/. +
+

PrevRef +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/refs/witold.html b/db/docs/ref/refs/witold.html new file mode 100644 index 000000000..d81065e66 --- /dev/null +++ b/db/docs/ref/refs/witold.html @@ -0,0 +1,16 @@ + + + + + +Berkeley DB: Witold Litwin + + + + +

Witold Litwin

+Witold is a hell of a guy to take you on a late-night high-speed car +chase up the mountains of Austria in search of very green wine. +

Copyright Sleepycat Software + + diff --git a/db/docs/ref/rpc/client.html b/db/docs/ref/rpc/client.html new file mode 100644 index 000000000..e8eb90dcf --- /dev/null +++ b/db/docs/ref/rpc/client.html @@ -0,0 +1,75 @@ + + + + + +Berkeley DB Reference Guide: Client program + + + + + + + +

Berkeley DB Reference Guide:
RPC Client/Server

PrevRefNext +
+

+

Client program

+

Changing a Berkeley DB application to remotely call a server program requires +only a few changes on the client side: +

    +

  1. The client application must create and use a Berkeley DB environment, +that is, it cannot simply call the db_create interface, but must +first call the db_env_create interface to create an environment in +which the database will live. +

  2. The client application must call db_env_create using the +DB_CLIENT flag. +

  3. The client application must call the additional DB_ENV +method DBENV->set_server to specify the database server. This call +must be made before opening the environment with the DBENV->open +call. +
+

The client application provides three pieces of information to Berkeley DB as +part of the DBENV->set_server call: +

    +

  1. The hostname of the server. The hostname format is not +specified by Berkeley DB, but must be in a format acceptable to the local +network support, specifically, the RPC clnt_create interface. +

  2. The client timeout. This is the number of seconds the client +will wait for the server to respond to its requests. A default is used +if this value is zero. +

  3. The server timeout. This is the number of seconds the server +will allow client resources to remain idle before releasing those +resources. The resources this applies to are transactions and cursors, +as those objects hold locks and if a client dies, the server needs to +release those resources in a timely manner. This value +is really a hint to the server, as the server may choose to override this +value with its own. +
+

The only other item of interest to the client is the home directory +that is given to the DBENV->open call. +The server is started with a list of allowed home directories. +The client must use one of those names (where a name is the last +component of the home directory). This allows the pathname structure +on the server to change without client applications needing to be +aware of it. +

Once the DBENV->set_server call has been made, the client is +connected to the server and all subsequent Berkeley DB +operations will be forwarded to the server. The client does not need to +be otherwise aware that it is using a database server rather than +accessing the database locally. +

It is important to realize that the client portion of the Berkeley DB library +acts as a simple conduit, forwarding Berkeley DB interface arguments to the +server without interpretation. This has two important implications. +First, all pathnames must be specified relative to the server. For +example, the home directory and other configuration information passed by +the application when creating its environment or databases must be +pathnames for the server, not the client system. In addition, as there +is no logical bundling of operations at the server, performance is usually +significantly less than when Berkeley DB is embedded within the client's address +space, even if the RPC is to a local address. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/rpc/intro.html b/db/docs/ref/rpc/intro.html new file mode 100644 index 000000000..25e4f4aea --- /dev/null +++ b/db/docs/ref/rpc/intro.html @@ -0,0 +1,62 @@ + + + + + +Berkeley DB Reference Guide: Introduction + + + + + + +

Berkeley DB Reference Guide:
RPC Client/Server

PrevRefNext +
+

+

Introduction

+

Berkeley DB includes a basic implementation of a client-server protocol, using +Sun Microsystem's Remote Procedure Call Protocol. RPC support is only +available for UNIX systems, and is not included in the Berkeley DB library by +default, but must be enabled during configuration. See +Configuring Berkeley DB for more +information. For more information on RPC itself, see your UNIX system +documentation or RPC: Remote Procedure Call Protocol +Specification, RFC1832, Sun Microsystems, Inc., USC-ISI. +

Only some of the complete Berkeley DB functionality is available when using RPC. +The following functionality is available: +

    +
  1. The db_env_create interface and the DB_ENV +handle methods. +
  2. The db_create interface and the DB handle +methods. +
  3. The txn_begin, txn_commit and +txn_abort interfaces. +
+

The RPC client/server code does not support any of the user-defined +comparison or allocation functions, e.g., an application using the RPC +support may not specify its own Btree comparison function. If your +application only requires those portions of Berkeley DB, then using RPC is +fairly simple. If your application requires other Berkeley DB functionality, +such as direct access to locking, logging or shared memory buffer memory +pools, then your application cannot use the RPC support. +

The Berkeley DB RPC support does not provide any security or authentication of +any kind. Sites needing any kind of data security measures must modify +the client and server code to provide whatever level of security they +require. +

One particularly interesting use of the RPC support is for debugging Berkeley DB +applications. The seamless nature of the interface means that with very +minor application code changes, an application can run outside of the +Berkeley DB address space, making it far easier to track down many types of +errors such as memory misuse. +

Using the RPC mechanisms in Berkeley DB involves two basic steps: +

    +

  1. Modify your Berkeley DB application to act as a client and call the +RPC server. +
  2. Run the berkeley_db_svc server program on the system +where the database resides. +
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/rpc/server.html b/db/docs/ref/rpc/server.html new file mode 100644 index 000000000..64572a90d --- /dev/null +++ b/db/docs/ref/rpc/server.html @@ -0,0 +1,54 @@ + + + + + +Berkeley DB Reference Guide: Server program + + + + + + + +

Berkeley DB Reference Guide:
RPC Client/Server

PrevRefNext +
+

+

Server program

+

The Berkeley DB server utility, berkeley_db_svc, handles all of the +client application requests. +

Currently, the berkeley_db_svc utility is single-threaded, +limiting the number of requests that it can handle. Modifying the server +implementation to run in multi-thread or multi-process mode will require +modification of the server code automatically generated by the rpcgen +program. +

There are two different types of timeouts used by berkeley_db_svc. +The first timeout (which can be modified within some constraints by the +client application), is the resource timeout. When clients use +transactions or cursors, those resources hold locks in Berkeley DB across calls +to the server. If a client application dies or loses its connection to +the server while holding those resources, it prevents any other client +from acquiring them. Therefore, it is important to detect that a client +has not used a resource for some period of time and release them. In the +case of transactions, the server aborts the transaction. In the case of +cursors, the server closes the cursor. +

The second timeout is an idle timeout. A client application may remain +idle with an open handle to an environment and a database. Doing so +simply consumes some memory, it does not hold locks. However, the Berkeley DB +server may want to eventually reclaim resources if a client dies or +remains disconnected for a long period of time, so there is a separate +idle timeout for open Berkeley DB handles. +

The list of home directories specified to berkeley_db_svc are the +only ones client applications are allowed to use. When +berkeley_db_svc is started, it is given a list of pathnames. +Clients are expected to specify the name of the home directory (defined +as the last component in the directory pathname) as the database +environment they are opening. In this manner, clients need only know the +name of their home environment, and not its full pathname on the server +machine. This means, of course, that only one environment of a particular +name is allowed on the server at any given time. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/sendmail/intro.html b/db/docs/ref/sendmail/intro.html new file mode 100644 index 000000000..9dc1b4a14 --- /dev/null +++ b/db/docs/ref/sendmail/intro.html @@ -0,0 +1,51 @@ + + + + + +Berkeley DB Reference Guide: Using Berkeley DB with Sendmail + + + + + + + +

Berkeley DB Reference Guide:
Sendmail

PrevRefNext +
+

+

Using Berkeley DB with Sendmail

+

If you are attempting to use Berkeley DB with Sendmail 8.8.X, you must use +Berkeley DB version 1.85 (see the Sleepycat Software web site's +historic releases +of Berkeley DB page for more information. +

Berkeley DB versions 2.0 and later are only supported by Sendmail versions 8.9.X +and later. +

Berkeley DB versions 3.0 and later are only supported by Sendmail versions +8.10.X and later. +

We strongly recommend that you not use Berkeley DB version 1.85. It is no longer +maintained or supported and has known bugs that can cause Sendmail to +fail. Instead, please upgrade to Sendmail version 8.9.X or later and use +a later version of Berkeley DB. For more information on using Berkeley DB with +Sendmail, please review the README and src/README files in the Sendmail +distribution. +

To load sendmail against Berkeley DB, add the following lines to +BuildTools/Site/site.config.m4: +

APPENDDEF(`confINCDIRS', `-I/usr/local/BerkeleyDB/include')
+APPENDDEF(`confLIBDIRS', `-L/usr/local/BerkeleyDB/lib')
+

where those are the paths to #include <db.h> and libdb.a respectively. +Then, run "Build -c" from the src directory. +

Note that this Build script will use -DNEWDB on the compiles +and -L/path/to/libdb/directory -ldb on the link if it can find libdb.a; +the search path is $LIBDIRS:/lib:/usr/lib:/usr/shlib. $LIBDIRS is +NULL by default for most systems, but some set it in BuildTools/OS/foo. +Anyone can append to it as above (confLIBDIRS is the m4 variable name; +LIBDIRS is the shell-script variable name). +

To download Sendmail, or to obtain more information on Sendmail, see the +Sendmail home page, which includes +FAQ pages and problem addresses. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/simple_tut/close.html b/db/docs/ref/simple_tut/close.html new file mode 100644 index 000000000..a268a591c --- /dev/null +++ b/db/docs/ref/simple_tut/close.html @@ -0,0 +1,102 @@ + + + + + +Berkeley DB Reference Guide: Closing a database + + + + + + +

Berkeley DB Reference Guide:
Simple Tutorial

PrevRefNext +
+

+

Closing a database

+

The only other operation that we need for our simple example is closing +the database, and cleaning up the DB handle. +

It is necessary that the database be closed. The most important reason +for this is that Berkeley DB runs on top of an underlying buffer cache. If +the modified database pages are never explicitly flushed to disk and +the database is never closed, changes made to the database may never +make it out to disk, because they are held in the Berkeley DB cache. As the +default behavior of the close function is to flush the Berkeley DB cache, +closing the database will update the on-disk information. +

The DB->close interface takes two arguments: +

+

db
The database handle returned by db_create. +

flags
Optional flags modifying the underlying behavior of the DB->close +interface. +
+

Here's what the code to call DB->close looks like: +

#include <sys/types.h>
+#include <stdio.h>
+#include <db.h>
+

+#define DATABASE "access.db" +

+int +main() +{ + DB *dbp; + DBT key, data; + int ret, t_ret; +

+ if ((ret = db_create(&dbp, NULL, 0)) != 0) { + fprintf(stderr, "db_create: %s\n", db_strerror(ret)); + exit (1); + } + if ((ret = dbp->open( + dbp, DATABASE, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) { + dbp->err(dbp, ret, "%s", DATABASE); + goto err; + } +

+ memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = "fruit"; + key.size = sizeof("fruit"); + data.data = "apple"; + data.size = sizeof("apple"); +

+ if ((ret = dbp->put(dbp, NULL, &key, &data, 0)) == 0) + printf("db: %s: key stored.\n", (char *)key.data); + else { + dbp->err(dbp, ret, "DB->put"); + goto err; + } +

+ if ((ret = dbp->get(dbp, NULL, &key, &data, 0)) == 0) + printf("db: %s: key retrieved: data was %s.\n", + (char *)key.data, (char *)data.data); + else { + dbp->err(dbp, ret, "DB->get"); + goto err; + } +

+ if ((ret = dbp->del(dbp, NULL, &key, 0)) == 0) + printf("db: %s: key was deleted.\n", (char *)key.data); + else { + dbp->err(dbp, ret, "DB->del"); + goto err; + } +

+ if ((ret = dbp->get(dbp, NULL, &key, &data, 0)) == 0) + printf("db: %s: key retrieved: data was %s.\n", + (char *)key.data, (char *)data.data); + else + dbp->err(dbp, ret, "DB->get"); +

err: if ((t_ret = dbp->close(dbp, 0)) != 0 && ret == 0) + ret = t_ret; +

+ exit(ret); +} +

+

Note that we do not necessarily overwrite the ret variable, as it +may contain error return information from a previous Berkeley DB call. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/simple_tut/del.html b/db/docs/ref/simple_tut/del.html new file mode 100644 index 000000000..ac4d41260 --- /dev/null +++ b/db/docs/ref/simple_tut/del.html @@ -0,0 +1,93 @@ + + + + + +Berkeley DB Reference Guide: Removing elements from a database + + + + + + +

Berkeley DB Reference Guide:
Simple Tutorial

PrevRefNext +
+

+

Removing elements from a database

+

The simplest way to remove elements from a database is the DB->del +interface. +

The DB->del interface takes four of the same five arguments that +the DB->get and DB->put interfaces take. The difference +is that there is no need to specify a data item, as the delete operation +is only interested in the key that you want to remove. +

+

db
The database handle returned by db_create. +

txnid
A transaction ID. +In our simple case, we aren't expecting to recover the database after +application or system crash, so we aren't using transactions, and will +leave this argument unspecified. +

key
The key item for the key/data pair that we want to delete from the +database. +

flags
Optional flags modifying the underlying behavior of the DB->del +interface. There are currently no available flags for this interface, +so the flags argument should always be set to 0. +
+

Here's what the code to call DB->del looks like: +

#include <sys/types.h>
+#include <stdio.h>
+#include <db.h>
+

+#define DATABASE "access.db" +

+int +main() +{ + DB *dbp; + DBT key, data; + int ret; +

+ if ((ret = db_create(&dbp, NULL, 0)) != 0) { + fprintf(stderr, "db_create: %s\n", db_strerror(ret)); + exit (1); + } + if ((ret = dbp->open( + dbp, DATABASE, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) { + dbp->err(dbp, ret, "%s", DATABASE); + goto err; + } +

+ memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = "fruit"; + key.size = sizeof("fruit"); + data.data = "apple"; + data.size = sizeof("apple"); +

+ if ((ret = dbp->put(dbp, NULL, &key, &data, 0)) == 0) + printf("db: %s: key stored.\n", (char *)key.data); + else { + dbp->err(dbp, ret, "DB->put"); + goto err; + } +

+ if ((ret = dbp->get(dbp, NULL, &key, &data, 0)) == 0) + printf("db: %s: key retrieved: data was %s.\n", + (char *)key.data, (char *)data.data); + else { + dbp->err(dbp, ret, "DB->get"); + goto err; + } +

if ((ret = dbp->del(dbp, NULL, &key, 0)) == 0) + printf("db: %s: key was deleted.\n", (char *)key.data); + else { + dbp->err(dbp, ret, "DB->del"); + goto err; + } +

+

After the DB->del call returns, the entry referenced by the key +fruit has been removed from the database. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/simple_tut/errors.html b/db/docs/ref/simple_tut/errors.html new file mode 100644 index 000000000..bb7e8a671 --- /dev/null +++ b/db/docs/ref/simple_tut/errors.html @@ -0,0 +1,46 @@ + + + + + +Berkeley DB Reference Guide: Error returns + + + + + + +

Berkeley DB Reference Guide:
Simple Tutorial

PrevRefNext +
+

+

Error returns

+

The Berkeley DB interfaces always return a value of 0 on success. If the +operation does not succeed for any reason, the return value will be +non-zero. +

If a system error occurred (e.g., Berkeley DB ran out of disk space, or +permission to access a file was denied, or an illegal argument was +specified to one of the interfaces), Berkeley DB returns an errno +value. All of the possible values of errno are greater than +0. +

If the operation didn't fail due to a system error, but wasn't +successful either, Berkeley DB returns a special error value. For example, +if you tried to retrieve the data item associated with the key +fruit, and there was no such key/data pair in the database, +Berkeley DB would return DB_NOTFOUND, a special error value that means +the requested key does not appear in the database. All of the possible +special error values are less than 0. +

Berkeley DB also offers programmatic support for displaying error return values. +First, the db_strerror interface returns a pointer to the error +message corresponding to any Berkeley DB error return, similar to the ANSI C +strerror interface, but is able to handle both system error returns and +Berkeley DB-specific return values. +

Second, there are two error functions, DB->err and DB->errx. +These functions work like the ANSI C printf interface, taking a +printf-style format string and argument list, and optionally appending +the standard error string to a message constructed from the format string +and other arguments. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/simple_tut/example.txt b/db/docs/ref/simple_tut/example.txt new file mode 100644 index 000000000..e610648d1 --- /dev/null +++ b/db/docs/ref/simple_tut/example.txt @@ -0,0 +1,73 @@ +#include + +#include +#include +#include + +#include "db.h" + +#define DATABASE "access.db" + +int +main() +{ + DB *dbp; + DBT key, data; + int ret, t_ret; + + /* Create the database handle and open the underlying database. */ + if ((ret = db_create(&dbp, NULL, 0)) != 0) { + fprintf(stderr, "db_create: %s\n", db_strerror(ret)); + exit (1); + } + if ((ret = + dbp->open(dbp, DATABASE, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) { + dbp->err(dbp, ret, "%s", DATABASE); + goto err; + } + + /* Initialize key/data structures. */ + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = "fruit"; + key.size = sizeof("fruit"); + data.data = "apple"; + data.size = sizeof("apple"); + + /* Store a key/data pair. */ + if ((ret = dbp->put(dbp, NULL, &key, &data, 0)) == 0) + printf("db: %s: key stored.\n", (char *)key.data); + else { + dbp->err(dbp, ret, "DB->put"); + goto err; + } + + /* Retrieve a key/data pair. */ + if ((ret = dbp->get(dbp, NULL, &key, &data, 0)) == 0) + printf("db: %s: key retrieved: data was %s.\n", + (char *)key.data, (char *)data.data); + else { + dbp->err(dbp, ret, "DB->get"); + goto err; + } + + /* Delete a key/data pair. */ + if ((ret = dbp->del(dbp, NULL, &key, 0)) == 0) + printf("db: %s: key was deleted.\n", (char *)key.data); + else { + dbp->err(dbp, ret, "DB->del"); + goto err; + } + + /* Retrieve a key/data pair. */ + if ((ret = dbp->get(dbp, NULL, &key, &data, 0)) == 0) + printf("db: %s: key retrieved: data was %s.\n", + (char *)key.data, (char *)data.data); + else + dbp->err(dbp, ret, "DB->get"); + +err: if ((t_ret = dbp->close(dbp, 0)) != 0 && ret == 0) + ret = t_ret; + + exit(ret); +} diff --git a/db/docs/ref/simple_tut/get.html b/db/docs/ref/simple_tut/get.html new file mode 100644 index 000000000..697aa8f51 --- /dev/null +++ b/db/docs/ref/simple_tut/get.html @@ -0,0 +1,97 @@ + + + + + +Berkeley DB Reference Guide: Retrieving elements from a database + + + + + + +

Berkeley DB Reference Guide:
Simple Tutorial

PrevRefNext +
+

+

Retrieving elements from a database

+

The simplest way to retrieve elements from a database is the +DB->get interface. +

The DB->get interface takes the same five arguments that the +DB->put interface takes: +

+

db
The database handle returned by db_create. +

txnid
A transaction ID. In our simple case, we aren't expecting to recover +the database after application or system crash, so we aren't using +transactions, and will leave this argument NULL. +

key
The key item for the key/data pair that we want to retrieve from the +database. +

data
The data item for the key/data pair that we want to retrieve from the +database. +

flags
Optional flags modifying the underlying behavior of the DB->get +interface. +
+

Here's what the code to call DB->get looks like: +

#include <sys/types.h>
+#include <stdio.h>
+#include <db.h>
+

+#define DATABASE "access.db" +

+int +main() +{ + DB *dbp; + DBT key, data; + int ret; +

+ if ((ret = db_create(&dbp, NULL, 0)) != 0) { + fprintf(stderr, "db_create: %s\n", db_strerror(ret)); + exit (1); + } + if ((ret = dbp->open( + dbp, DATABASE, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) { + dbp->err(dbp, ret, "%s", DATABASE); + goto err; + } +

+ memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = "fruit"; + key.size = sizeof("fruit"); + data.data = "apple"; + data.size = sizeof("apple"); +

+ if ((ret = dbp->put(dbp, NULL, &key, &data, 0)) == 0) + printf("db: %s: key stored.\n", (char *)key.data); + else { + dbp->err(dbp, ret, "DB->put"); + goto err; + } +

if ((ret = dbp->get(dbp, NULL, &key, &data, 0)) == 0) + printf("db: %s: key retrieved: data was %s.\n", + (char *)key.data, (char *)data.data); + else { + dbp->err(dbp, ret, "DB->get"); + goto err; + } +

+

It is not usually necessary to clear the DBT structures passed +to the Berkeley DB functions between calls. This is not always true, when +some of the less commonly used flags for DBT structures are +used. The DBT manual page specified the details of those cases. +

It is possible, of course, to distinguish between system errors and the +key/data pair simply not existing in the database. There are three +standard returns from DB->get: +

    +

  1. The call might be successful and the key found, in which case the return +value will be 0. +
  2. The call might be successful, but the key not found, in which case the +return value will be DB_NOTFOUND. +
  3. The call might not be successful, in which case the return value will +be a system error. +
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/simple_tut/handles.html b/db/docs/ref/simple_tut/handles.html new file mode 100644 index 000000000..2396a224e --- /dev/null +++ b/db/docs/ref/simple_tut/handles.html @@ -0,0 +1,29 @@ + + + + + +Berkeley DB Reference Guide: Handles + + + + + + +

Berkeley DB Reference Guide:
Simple Tutorial

PrevRefNext +
+

+

Handles

+

With a few minor exceptions, Berkeley DB functionality is accessed by creating +a structure and then calling functions that are fields in that structure. +This is, of course, similar to object-oriented concepts, of instances and +methods on them. For simplicity, we will often refer to these structure +fields as methods of the handle. +

The manual pages will show these methods as C structure references. For +example, the open-a-database method for a database handle is represented +as DB->open. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/simple_tut/intro.html b/db/docs/ref/simple_tut/intro.html new file mode 100644 index 000000000..a9b6f648c --- /dev/null +++ b/db/docs/ref/simple_tut/intro.html @@ -0,0 +1,40 @@ + + + + + +Berkeley DB Reference Guide: Introduction + + + + + + +

Berkeley DB Reference Guide:
Simple Tutorial

PrevRefNext +
+

+

Introduction

+

As an introduction to Berkeley DB, we will present a few Berkeley DB programming +concepts, and then a simple database application. +

The programming concepts are: +

+

This database application will: +

+

The introduction will be presented using the programming language C. The +complete source of the final version of the +example program is included in the Berkeley DB distribution. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/simple_tut/keydata.html b/db/docs/ref/simple_tut/keydata.html new file mode 100644 index 000000000..38d34aebc --- /dev/null +++ b/db/docs/ref/simple_tut/keydata.html @@ -0,0 +1,48 @@ + + + + + +Berkeley DB Reference Guide: Key/data pairs + + + + + + +

Berkeley DB Reference Guide:
Simple Tutorial

PrevRefNext +
+

+

Key/data pairs

+

Berkeley DB uses key/data pairs to identify elements in the database. +That is, in the general case, whenever you call a Berkeley DB interface, +you present a key to identify the key/data pair on which you intend +to operate. +

For example, you might store some key/data pairs as follows: +

+ + + + +
Key:Data:
fruitapple
sportcricket
drinkwater
+

In each case, the first element of the pair is the key, and the second is +the data. To store the first of these key/data pairs into the database, +you would call the Berkeley DB interface to store items, with fruit as +the key, and apple as the data. At some future time, you could +then retrieve the data item associated with fruit, and the Berkeley DB +retrieval interface would return apple to you. While there are +many variations and some subtleties, all accesses to data in Berkeley DB come +down to key/data pairs. +

Both key and data items are stored in simple structures (called +DBTs) that contain a reference to memory and a length, counted +in bytes. (The name DBT is an acronym for database +thang, chosen because nobody could think of a sensible name that wasn't +already in use somewhere else.) Key and data items can be arbitrary +binary data of practically any length, including 0 bytes. There is a +single data item for each key item, by default, but databases can be +configured to support multiple data items for each key item. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/simple_tut/open.html b/db/docs/ref/simple_tut/open.html new file mode 100644 index 000000000..24df8a8e1 --- /dev/null +++ b/db/docs/ref/simple_tut/open.html @@ -0,0 +1,90 @@ + + + + + +Berkeley DB Reference Guide: Opening a database + + + + + + +

Berkeley DB Reference Guide:
Simple Tutorial

PrevRefNext +
+

+

Opening a database

+

Opening a database is done in two steps: first, a DB handle is +created using the Berkeley DB db_create interface, and then the +actual database is opened using the DB->open function. +

The db_create interface takes three arguments: +

+

dbp
A location to store a reference to the created structure. +

environment
A location to specify an enclosing Berkeley DB environment, not used in our +example. +

flags
A placeholder for flags, not used in our example. +
+

The DB->open interface takes five arguments: +

+

file
The name of the database file to be opened. +

database
The optional database name, not used in this example. +

type
The type of database to open. This value will be one of the four access +methods Berkeley DB supports: DB_BTREE, DB_HASH, DB_QUEUE or DB_RECNO, or the +special value DB_UNKNOWN, which allows you to open an existing file +without knowing its type. +

flags
Various flags that modify the behavior of DB->open. In our +simple case, the only interesting flag is DB_CREATE. This flag +behaves similarly to the IEEE/ANSI Std 1003.1 (POSIX) O_CREATE flag to the open system +call, causing Berkeley DB to create the underlying database if it does not +yet exist. +

mode
The file mode of any underlying files that DB->open will create. +The mode behaves as does the IEEE/ANSI Std 1003.1 (POSIX) mode argument to the open +system call, and specifies file read, write and execute permissions. +Of course, only the read and write permissions are relevant to Berkeley DB. +
+

Here's what the code to create the handle and then call DB->open +looks like: +

#include <sys/types.h>
+#include <stdio.h>
+#include <db.h>
+

+#define DATABASE "access.db" +

+int +main() +{ + DB *dbp; + int ret; +

+ if ((ret = db_create(&dbp, NULL, 0)) != 0) { + fprintf(stderr, "db_create: %s\n", db_strerror(ret)); + exit (1); + } + if ((ret = dbp->open( + dbp, DATABASE, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) { + dbp->err(dbp, ret, "%s", DATABASE); + goto err; + } +

+

If the call to db_create is successful, the variable dbp +will contain a database handle that will be used to configure and access +an underlying database. +

As you see, the program opens a database named access.db. The +underlying database is a Btree. Because the DB_CREATE flag was +specified, the file will be created if it does not already exist. The +mode of any created files will be 0664 (i.e., readable and writeable by +the owner and the group, and readable by everyone else). +

One additional function call is used in this code sample, DB->err. +This method works like the ANSI C printf interface. The second argument +is the error return from a Berkeley DB function, and the rest of the arguments +are a printf-style format string and argument list. The error message +associated with the error return will be appended to a message constructed +from the format string and other arguments. In the above code, if the +DB->open call were to fail, the message it would display would be +something like +

access.db: Operation not permitted
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/simple_tut/put.html b/db/docs/ref/simple_tut/put.html new file mode 100644 index 000000000..8ecdfa6ca --- /dev/null +++ b/db/docs/ref/simple_tut/put.html @@ -0,0 +1,127 @@ + + + + + +Berkeley DB Reference Guide: Adding elements to a database + + + + + + +

Berkeley DB Reference Guide:
Simple Tutorial

PrevRefNext +
+

+

Adding elements to a database

+

The simplest way to add elements to a database is the DB->put +interface. +

The DB->put interface takes five arguments: +

+

db
The database handle returned by db_create. +

txnid
A transaction handle. In our simple case, we aren't expecting to +recover the database after application or system crash, so we aren't +using transactions, and will leave this argument NULL. +

key
The key item for the key/data pair that we want to add to the database. +

data
The data item for the key/data pair that we want to add to the database. +

flags
Optional flags modifying the underlying behavior of the DB->put +interface. +
+

Here's what the code to call DB->put looks like: +

#include <sys/types.h>
+#include <stdio.h>
+#include <db.h>
+

+#define DATABASE "access.db" +

+int +main() +{ + DB *dbp; + DBT key, data; + int ret; +

+ if ((ret = db_create(&dbp, NULL, 0)) != 0) { + fprintf(stderr, "db_create: %s\n", db_strerror(ret)); + exit (1); + } + if ((ret = dbp->open( + dbp, DATABASE, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) { + dbp->err(dbp, ret, "%s", DATABASE); + goto err; + } +

memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = "fruit"; + key.size = sizeof("fruit"); + data.data = "apple"; + data.size = sizeof("apple"); +

+ if ((ret = dbp->put(dbp, NULL, &key, &data, 0)) == 0) + printf("db: %s: key stored.\n", (char *)key.data); + else { + dbp->err(dbp, ret, "DB->put"); + goto err; + } +

+

The first thing to notice about this new code is that we clear the +DBT structures that we're about to pass as arguments to Berkeley DB +functions. This is very important, and being careful to do so will +result in fewer errors in your programs. All Berkeley DB structures +instantiated in the application and handed to Berkeley DB should be cleared +before use, without exception. This is necessary so that future +versions of Berkeley DB may add additional fields to the structures. If +applications clear the structures before use, it will be possible for +Berkeley DB to change those structures without requiring that the applications +be rewritten to be aware of the changes. +

Notice also that we're storing the trailing nul byte found in the C +strings "fruit" and "apple" in both the key and data +items, that is, the trailing nul byte is part of the stored key, and +therefore has to be specified in order to access the data item. There is +no requirement to store the trailing nul byte, it simply makes it easier +for us to display strings that we've stored in programming languages that +use nul bytes to terminate strings. +

In many applications, it is important not to overwrite existing +data. For example, we might not want to store the key/data pair +fruit/apple if it already existed, e.g., if someone had +previously stored the key/data pair fruit/cherry into the +database. +

This is easily accomplished by adding the DB_NOOVERWRITE flag to +the DB->put call: +

if ((ret =
+	dbp->put(dbp, NULL, &key, &data, DB_NOOVERWRITE)) == 0)
+		printf("db: %s: key stored.\n", (char *)key.data);
+else {
+	dbp->err(dbp, ret, "DB->put");
+	goto err;
+}
+

This flag causes the underlying database functions to not overwrite any +previously existing key/data pair. (Note that the value of the previously +existing data doesn't matter in this case. The only question is if a +key/data pair already exists where the key matches the key that we are +trying to store.) +

Specifying DB_NOOVERWRITE opens up the possibility of a new +Berkeley DB return value from the DB->put function, DB_KEYEXIST, +which means we were unable to add the key/data pair to the database +because the key already existed in the database. While the above sample +code simply displays a message in this case: +

DB->put: DB_KEYEXIST: Key/data pair already exists
+

The following code shows an explicit check for this possibility: +

switch (ret =
+	dbp->put(dbp, NULL, &key, &data, DB_NOOVERWRITE)) {
+case 0:
+	printf("db: %s: key stored.\n", (char *)key.data);
+	break;
+case DB_KEYEXIST:
+	printf("db: %s: key previously stored.\n",
+	(char *)key.data);
+	break;
+default:
+	dbp->err(dbp, ret, "DB->put");
+	goto err;
+}
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/tcl/error.html b/db/docs/ref/tcl/error.html new file mode 100644 index 000000000..3d1de037d --- /dev/null +++ b/db/docs/ref/tcl/error.html @@ -0,0 +1,69 @@ + + + + + +Berkeley DB Reference Guide: Tcl error handling + + + + + + +

Berkeley DB Reference Guide:
Tcl

PrevRefNext +
+

+

Tcl error handling

+

The Tcl interfaces to Berkeley DB generally return TCL_OK on success and throw +a Tcl error on failure, using the appropriate Tcl interfaces to provide +the user with an informative error message. There are some "expected" +failures, however, for which no Tcl error will be thrown and for which +Tcl commands will return TCL_OK. These failures include when a +searched-for key is not found, a requested key/data pair was previously +deleted, or a key/data pair cannot be written because the key already +exists. +

These failures can be detected by searching the Berkeley DB error message that +is returned. For example, to detect that an attempt to put a record into +the database failed because the key already existed: +

% berkdb open -create -btree a.db
+db0
+% db0 put dog cat
+0
+% set ret [db0 put -nooverwrite dog newcat]
+DB_KEYEXIST: Key/data pair already exists
+% if { [string first DB_KEYEXIST $ret] != -1 } {
+	puts "This was an error; the key existed"
+}
+This was an error; the key existed
+% db0 close
+0
+% exit
+

To simplify parsing, it is recommended that the initial Berkeley DB error name +be checked, e.g., DB_KEYEXIST in the above example. These values will +not change in future releases of Berkeley DB to ensure that Tcl scripts are not +broken by upgrading to new releases of Berkeley DB. There are currently only +three such "expected" error returns. They are: +

DB_NOTFOUND: No matching key/data pair found
+DB_KEYEMPTY: Non-existent key/data pair
+DB_KEYEXIST: Key/data pair already exists
+

Finally, in some cases, when a Berkeley DB error occurs Berkeley DB will output +additional error information. By default, all Berkeley DB error messages will +be prefixed with the created command in whose context the error occurred +(e.g., "env0", "db2", etc.). There are several ways to capture and +access this information. +

First, if Berkeley DB invokes the error callback function, the additional +information will be placed in the error result returned from the +command and in the errorInfo backtrace variable in Tcl. +

Also the two calls to open an environment and +open a database take an option, -errfile filename, which sets an +output file to which these additional error messages should be written. +

Additionally the two calls to open an environment and +open a database take an option, -errpfx string, which sets the +error prefix to the given string. This option may be useful +in circumstances where a more descriptive prefix is desired or +where a constant prefix indicating an error is desired. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/tcl/faq.html b/db/docs/ref/tcl/faq.html new file mode 100644 index 000000000..29f63b423 --- /dev/null +++ b/db/docs/ref/tcl/faq.html @@ -0,0 +1,60 @@ + + + + + +Berkeley DB Reference Guide: Frequently Asked Questions + + + + + + + +

Berkeley DB Reference Guide:
Tcl API

PrevRefNext +
+

+

Frequently Asked Questions

+

    +

  1. I have several versions of Tcl installed. How do I configure +Berkeley DB to use a particular version? +

    To compile the Tcl interface with a particular version of Tcl, use the +--with-tcl option to specify the Tcl installation directory that contains +the tclConfig.sh file. +

    See Changing compile or load options +for more information. +


    +

  2. Berkeley DB was configured using --enable-tcl or --with-tcl and fails +to build. +

    The Berkeley DB Tcl interface requires Tcl version 8.1 or greater. You can +download a copy of Tcl from the +Ajuba Solutions +corporate web site. +


    +

  3. Berkeley DB was configured using --enable-tcl or --with-tcl and fails +to build. +

    If the Tcl installation was moved after it was configured and installed, +try re-configuring and re-installing Tcl. +

    Also, some systems do not search for shared libraries by default, or do +not search for shared libraries named the way the Tcl installation names +them, or are searching for a different kind of library than those in +your Tcl installation. For example, Linux systems often require linking +"libtcl.a" to "libtcl#.#.a", while AIX systems often require adding the +"-brtl" flag to the linker. A simpler solution that almost always works +on all systems is to create a link from "libtcl.#.#.a" or "libtcl.so" +(or whatever you happen to have) to "libtcl.a" and reconfigure. +


    +

  4. Loading the Berkeley DB library into Tcl on AIX causes a core dump. +

    In some versions of Tcl, the "tclConfig.sh" autoconfiguration script +created by the Tcl installation does not work properly under AIX. To +build a working Berkeley DB Tcl API when this happens, use the "--enable-tcl" +flag to configure Berkeley DB (rather than "--with-tcl"). In addition, you +will have to specify any necessary include and library paths and linker +flags needed to build with Tcl by setting the CPPFLAGS, LIBS and LDFLAGS +environment variables before running configure. +

+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/tcl/intro.html b/db/docs/ref/tcl/intro.html new file mode 100644 index 000000000..6484eaac6 --- /dev/null +++ b/db/docs/ref/tcl/intro.html @@ -0,0 +1,70 @@ + + + + + +Berkeley DB Reference Guide: Loading Berkeley DB with Tcl + + + + + + + +

Berkeley DB Reference Guide:
Tcl

PrevRefNext +
+

+

Loading Berkeley DB with Tcl

+

Berkeley DB includes a dynamically loadable Tcl API. The Tcl API requires that +Tcl/Tk 8.1 or later already be installed on your system. We recommend +that you install later releases of Tcl/Tk than 8.1, if possible, +especially on Windows platforms, as we found that we had to make local +fixes to the 8.1 release in a few cases. You can download a copy of +Tcl from the Ajuba +Solutions corporate web site. +

This document assumes that you have already configured Berkeley DB for Tcl +support and you have built and installed everything where you want it +to be. If you have not done so, see +Configuring Berkeley DB or +Building for Win32 for more +information. +

Installing as a Tcl Package

+

Once enabled, the Berkeley DB shared library for Tcl is automatically installed +as part of the standard installation process. However, if you wish to be +able to dynamically load it as a Tcl package into your script there are +several steps that must be performed: +

    +

  1. Run the Tcl shell in the install directory +
  2. Append this directory to your auto_path variable +
  3. Run the pkg_mkIndex proc giving the name of the Berkeley DB Tcl library +
+

For example: +

# tclsh8.1
+% lappend auto_path /usr/local/BerkeleyDB/lib
+% pkg_mkIndex /usr/local/BerkeleyDB/lib libdb_tcl-3.2.so libdb-3.2.so
+

Note that your Tcl and Berkeley DB version numbers may differ from the example, +and so your tclsh and and library names may be different. +

Loading Berkeley DB with Tcl

+

The Berkeley DB package may be loaded into the user's interactive Tcl script +(or wish session) via the "load" command. For example: +

load /usr/local/BerkeleyDB/lib/libdb_tcl-3.2.so
+

Note that your Berkeley DB version numbers may differ from the example, and so +the library name may be different. +

If you installed your library to run as a Tcl package, Tcl application +scripts should use the "package" command to indicate to the Tcl +interpreter that it needs the Berkeley DB package and where to find it. For +example: +

lappend auto_path "/usr/local/BerkeleyDB/lib"
+package require Db_tcl
+

No matter which way the library gets loaded, it creates a command named +berkdb. All of the Berkeley DB functionality is accessed via this +command and additional commands it creates on behalf of the application. +A simple test to determine if everything is loaded and ready is to ask +for the version: +

berkdb version -string
+

This should return you the Berkeley DB version in a string format. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/tcl/program.html b/db/docs/ref/tcl/program.html new file mode 100644 index 000000000..881c8848b --- /dev/null +++ b/db/docs/ref/tcl/program.html @@ -0,0 +1,33 @@ + + + + + +Berkeley DB Reference Guide: Tcl API programming notes + + + + + + + +

Berkeley DB Reference Guide:
Tcl

PrevRefNext +
+

+

Tcl API programming notes

+

The Tcl API closely parallels the Berkeley DB programmatic interfaces. If you +are already familiar with one of those interfaces there will not be many +surprises in the Tcl API. +

Several pieces of Berkeley DB functionality are not available in the Tcl API. +Any of the functions that require a user-provided function are not +supported via the Tcl API. For example, there is no equivalent to the +DB->set_dup_compare or the DBENV->set_errcall +methods. +

The Berkeley DB Tcl API always turns on the DB_THREAD flag for environments and +databases making no assumptions about the existence or lack thereof of +threads support in current or future releases of Tcl. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/tcl/using.html b/db/docs/ref/tcl/using.html new file mode 100644 index 000000000..6c927477c --- /dev/null +++ b/db/docs/ref/tcl/using.html @@ -0,0 +1,53 @@ + + + + + +Berkeley DB Reference Guide: Using Berkeley DB with Tcl + + + + + + + +

Berkeley DB Reference Guide:
Tcl

PrevRefNext +
+

+

Using Berkeley DB with Tcl

+

All commands in the Berkeley DB Tcl interface are of the form: +

command_handle operation options
+

The command handle is berkdb or one of the additional +commands that may be created. The operation is what you want +to do to that handle and the options apply to the operation. +Commands that get created on behalf of the application have their own sets +of operations. Generally any calls in DB that result in new object +handles will translate into a new command handle in Tcl. Then the user +can access the operations of the handle via the new Tcl command handle. +

Newly created commands are named with an abbreviated form of their objects +followed by a number. Some created commands are subcommands of other +created commands and will be the first command, followed by a period, '.' +followed by the new subcommand. For example, suppose you have a database +already existing called my_data.db. The following example shows the +commands created when you open the database, and when you open a cursor: +

# First open the database and get a database command handle
+% berkdb open my_data.db
+db0
+#Get some data from that database
+% db0 get my_key
+{{my_key my_data0}{my_key my_data1}}
+#Open a cursor in this database, get a new cursor handle
+% db0 cursor
+db0.c0
+#Get the first data from the cursor
+% db0.c0 get -first
+{{first_key first_data}}
+

All commands in the library support a special option -? that will +list the correct operations for a command or the correct options. +

A list of commands and operations can be found in the +Tcl Interface documentation. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/test/faq.html b/db/docs/ref/test/faq.html new file mode 100644 index 000000000..ec5d2d3f0 --- /dev/null +++ b/db/docs/ref/test/faq.html @@ -0,0 +1,32 @@ + + + + + +Berkeley DB Reference Guide: Test suite FAQ + + + + + + +

Berkeley DB Reference Guide:
Test Suite

PrevRefNext +
+

+

Test suite FAQ

+

    +

  1. The test suite has been running for over a day. What's wrong? +

    The test suite an take anywhere from some number of hours to several +days to run, depending on your hardware configuration. As long as the +run is making forward progress and new lines are being written to the +ALL.OUT file, everything is probably fine. +

  2. The test suite hangs. +

    The test suite requires Tcl 8.1 or greater, preferably at least Tcl 8.3. +If you are using an earlier version of Tcl, the test suite may simply +hang at some point. +

+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/test/run.html b/db/docs/ref/test/run.html new file mode 100644 index 000000000..078951a05 --- /dev/null +++ b/db/docs/ref/test/run.html @@ -0,0 +1,78 @@ + + + + + +Berkeley DB Reference Guide: Running the test suite + + + + + + + +

Berkeley DB Reference Guide:
Test Suite

PrevRefNext +
+

+

Running the test suite

+

Once you have started tclsh and have loaded the test.tcl source file (see +Running the test suite under UNIX +and Running the test suite under +Windows for more information), you are ready to run the test suite. At +the tclsh prompt, to run the entire test suite, enter: +

% run_all
+

Running all the tests can take from several hours to a few days to +complete, depending on your hardware. For this reason, the output from +this command is re-directed to a file in the current directory named +ALL.OUT. Periodically, a line will be written to the standard +output indicating what test is being run. When the suite has finished, +a single message indicating that the test suite completed successfully or +that it failed will be written. If the run failed, you should review the +file ALL.OUT to determine which tests failed. Any errors will appear in +that file as output lines beginning with the string: FAIL. +

It is also possible to run specific tests or tests for a particular +subsystem: +

% r archive
+% r btree
+% r env
+% r frecno
+% r hash
+% r join
+% r join
+% r lock
+% r log
+% r mpool
+% r mutex
+% r queue
+% r rbtree
+% r recno
+% r rrecno
+% r subdb
+% r txn
+

Or to run a single, individual test: +

% test001 btree
+

It is also possible to modify the test run based on arguments on the +command line. For example, the command: +

% test001 btree 10
+

will run a greatly abbreviated form of test001, doing 10 operations +instead of 10,000. +

In all cases, when not running the entire test suite as described above, +a successful test run will return you to the tclsh prompt (%). On +failure, a message is displayed indicating what failed. +

Tests are run, by default, in the directory TESTDIR. However, +the test files are often very large. To use a different directory for +the test directory, edit the file include.tcl in your build directory, +and change the line: +

set testdir ./TESTDIR
+

to a more appropriate value for your system, e.g.: +

set testdir /var/tmp/db.test
+

Alternatively, you can create a symbolic link named TESTDIR in your build +directory to an appropriate location for running the tests. Regardless +of where you run the tests, the TESTDIR directory should be on a local +filesystem, using a remote filesystem (e.g., NFS) will almost certainly +cause spurious test failures. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/toc.html b/db/docs/ref/toc.html new file mode 100644 index 000000000..e56ee5d48 --- /dev/null +++ b/db/docs/ref/toc.html @@ -0,0 +1,310 @@ + + + + + +Berkeley DB: Reference Guide Table of Contents + + + + +

Reference Guide Table of Contents

+
    +
  1. Introduction +
      +
    1. An introduction to data management +
    2. Mapping the terrain: theory and practice +
    3. What is Berkeley DB? +
    4. What is Berkeley DB not? +
    5. Do you need Berkeley DB? +
    6. What other services does Berkeley DB provide? +
    7. What does the Berkeley DB distribution include? +
    8. Where does Berkeley DB run? +
    9. Sleepycat Software's Berkeley DB products +
    +
  2. Getting Started: A Simple Tutorial +
      +
    1. Introduction +
    2. Key/data pairs +
    3. Object handles +
    4. Error returns +
    5. Opening a database +
    6. Adding elements to a database +
    7. Retrieving elements from a database +
    8. Removing elements from a database +
    9. Closing a database +
    +
  3. Access Method Configuration +
      +
    1. What are the available access methods? +
    2. Selecting an access method +
    3. Logical record numbers +
    4. General access method configuration +
        +
      1. Selecting a page size +
      2. Selecting a cache size +
      3. Selecting a byte order +
      4. Duplicate data items +
      5. Non-local memory allocation +
      +
    5. Btree access method specific configuration +
        +
      1. Btree comparison +
      2. Btree prefix comparison +
      3. Minimum keys per page +
      4. Retrieving Btree records by logical record number +
      +
    6. Hash access method specific configuration +
        +
      1. Page fill factor +
      2. Specifying a database hash +
      3. Hash table size +
      +
    7. Queue and Recno access method specific configuration +
        +
      1. Managing record-based databases +
      2. Selecting a Queue extent size +
      3. Flat-text backing files +
      4. Logically renumbering records +
      +
    +
  4. Access Method Operations +
      +
    1. Access method operations +
    2. Opening a database +
    3. Opening multiple databases in a single file +
    4. Upgrading databases +
    5. Retrieving records +
    6. Storing records +
    7. Deleting records +
    8. Flushing the database cache +
    9. Database statistics +
    10. Closing a database +
    11. Database cursors +
        +
      1. Retrieving records with a cursor +
      2. Storing records with a cursor +
      3. Deleting records with a cursor +
      4. Duplicating a cursor +
      5. Logical join +
      6. Data item count +
      7. Closing a cursor +
      8. Cursor stability +
      +
    12. Partial record storage and retrieval +
    13. Database verification and salvage +
    14. Error support +
    +
  5. Berkeley DB Architecture +
      +
    1. The big picture +
    2. Programming model +
    3. Programmatic APIs +
    4. Scripting languages +
    5. Supporting utilities +
    +
  6. The Berkeley DB Environment +
      +
    1. Introduction +
    2. Creating an environment +
    3. File naming +
    4. Security +
    5. Shared memory regions +
    6. Remote filesystems +
    7. Opening databases within the environment +
    8. Error support +
    +
  7. Berkeley DB Concurrent Data Store Applications +
      +
    1. Building Berkeley DB Concurrent Data Store applications +
    +
  8. Berkeley DB Transactional Data Store Applications +
      +
    1. Building Berkeley DB Transactional Data Store applications +
    2. Why transactions? +
    3. Terminology +
    4. Application structure +
    5. Opening the environment +
    6. Opening the databases +
    7. Recoverability and deadlock avoidance +
    8. Atomicity +
    9. Repeatable reads +
    10. Transactional cursors +
    11. Environment infrastructure +
    12. Deadlock detection +
    13. Checkpoints +
    14. Database and log file archival +
    15. Log file removal +
    16. Recovery procedures +
    17. Recovery and filesystem operations +
    18. Berkeley DB recoverability +
    19. Transaction throughput +
    +
  9. XA Resource Manager +
      +
    1. Introduction +
    2. Configuring Berkeley DB with The Tuxedo System +
    3. Frequently Asked Questions +
    +
  10. Programmer Notes +
      +
    1. Application signal handling +
    2. Error returns to applications +
    3. Environmental variables +
    4. Building multi-threaded applications +
    5. Berkeley DB handles +
    6. Name spaces +
    7. Copying databases +
    8. Library version information +
    9. Database limits +
    10. Byte ordering +
    11. Disk space requirements +
    12. Compatibility with historic interfaces +
    13. Recovery implementation +
    14. Application-specific logging and recovery +
    15. Run-time configuration +
    +
  11. The Locking Subsystem +
      +
    1. Berkeley DB and locking +
    2. Page locks +
        +
      1. Standard lock modes +
      2. Locking without transactions +
      3. Locking with transactions: two-phase locking +
      +
    3. Access method locking conventions +
    4. Berkeley DB Concurrent Data Store locking conventions +
    5. Deadlocks and deadlock avoidance +
    6. Configuring locking +
    7. Configuring locking: sizing the system +
    8. Locking and non-Berkeley DB applications +
    +
  12. The Logging Subsystem +
      +
    1. Berkeley DB and logging +
    2. Configuring logging +
    3. Log file limits +
    +
  13. The Memory Pool Subsystem +
      +
    1. Berkeley DB and the memory pool +
    2. Configuring the memory pool +
    +
  14. The Transaction Subsystem +
      +
    1. Berkeley DB and transactions +
    2. Nested transactions +
    3. Transaction limits +
    4. Configuring transactions +
    5. Transactions and non-Berkeley DB applications +
    +
  15. RPC Client/Server +
      +
    1. Introduction +
    2. Client program +
    3. Server program +
    +
  16. Java API +
      +
    1. Configuration +
    2. Compatibility +
    3. Programming notes +
    4. Java FAQ +
    +
  17. Perl API +
      +
    1. Using Berkeley DB with Perl +
    +
  18. Tcl API +
      +
    1. Loading Berkeley DB with Tcl +
    2. Using Berkeley DB with Tcl +
    3. Tcl API programming notes +
    4. Tcl error handling +
    5. Tcl FAQ +
    +
  19. Sendmail +
      +
    1. Using Berkeley DB with Sendmail +
    +
  20. Dumping and Reloading Databases +
      +
    1. The db_dump and db_load utilities +
    2. Dump output formats +
    3. Loading text into databases +
    +
  21. System Installation Notes +
      +
    1. File utility /etc/magic information +
    +
  22. Debugging Applications +
      +
    1. Introduction +
    2. Compile-time configuration +
    3. Run-time error information +
    4. Reviewing Berkeley DB log files +
    5. Common errors +
    +
  23. Building Berkeley DB for UNIX and QNX systems +
      +
    1. Building for UNIX +
    2. Configuring Berkeley DB +
    3. Changing compile or load options +
    4. Installing Berkeley DB +
    5. Dynamic shared libraries +
    6. Running the test suite under UNIX +
    7. Architecture independent FAQ +
    8. Architecture specific FAQs +
        +
      1. AIX +
      2. FreeBSD +
      3. HP-UX +
      4. IRIX +
      5. Linux +
      6. OSF/1 +
      7. QNX +
      8. SCO +
      9. Solaris +
      10. SunOS +
      11. Ultrix +
      +
    +
  24. Building Berkeley DB for Win32 platforms +
      +
    1. Building for Win32 +
    2. Running the test suite under Windows +
    3. Windows notes +
    4. Windows FAQ +
    +
  25. Building Berkeley DB for VxWorks systems +
      +
    1. Building for VxWorks +
    2. VxWorks notes +
    3. VxWorks FAQ +
    +
  26. Upgrading Berkeley DB Applications +
      +
    1. Upgrading Berkeley DB installations +
    2. Upgrading Berkeley DB 1.XX applications to Berkeley DB 2.0 +
    3. Upgrading Berkeley DB 2.X.X applications to Berkeley DB 3.0 +
    4. Upgrading Berkeley DB 3.0.X applications to Berkeley DB 3.1 +
    5. Upgrading Berkeley DB 3.1.X applications to Berkeley DB 3.2 +
    +
  27. Test Suite +
      +
    1. Running the test suite +
    2. Test suite FAQ +
    +
  28. Distribution +
      +
    1. Source code layout +
    +
  29. Additional References +
      +
    1. Additional references +
    +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/transapp/admin.html b/db/docs/ref/transapp/admin.html new file mode 100644 index 000000000..c908a7a33 --- /dev/null +++ b/db/docs/ref/transapp/admin.html @@ -0,0 +1,47 @@ + + + + + +Berkeley DB Reference Guide: Environment infrastructure + + + + + + + +

Berkeley DB Reference Guide:
Transaction Protected Applications

PrevRefNext +
+

+

Environment infrastructure

+

When building transactional applications, it is usually necessary to +build an administrative infrastructure around the database environment. +There are five components to this infrastructure, and each is +supported by the Berkeley DB package in two different ways: a standalone +utility and one or more library interfaces. +

+

When writing multi-threaded server applications and/or applications +intended for download from the web, it is usually simpler to create +local threads that are responsible for administration of the database +environment as scheduling is often simpler in a single-process model, +and only a single binary need be installed and run. However, the +supplied utilities can be generally useful tools even when the +application is responsible for doing its own administration, as +applications rarely offer external interfaces to database +administration. The utilities are required when programming to a Berkeley DB +scripting interface, as the scripting APIs do not always offer +interfaces to the administrative functionality. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/transapp/app.html b/db/docs/ref/transapp/app.html new file mode 100644 index 000000000..3c946989b --- /dev/null +++ b/db/docs/ref/transapp/app.html @@ -0,0 +1,117 @@ + + + + + +Berkeley DB Reference Guide: Application structure + + + + + + +

Berkeley DB Reference Guide:
Transaction Protected Applications

PrevRefNext +
+

+

Application structure

+

When building transactionally protected applications, there are some +special issues that must be considered. The most important one is that, +if any thread of control exits for any reason while holding Berkeley DB +resources, recovery must be performed to: +

    +
  • recover the Berkeley DB resources, +
  • release any locks or mutexes that may have been held to avoid starvation +as the remaining threads of control convoy behind the failed thread's +locks, and +
  • clean up any partially completed operations that may have left a +database in an inconsistent or corrupted state. +
+

Complicating this problem is the fact that the Berkeley DB library itself +cannot determine if recovery is required, the application itself +must make that decision. A further complication is that +recovery must be single-threaded, that is, one thread of control or +process must perform recovery before any other thread of control or +processes attempts to create or join the Berkeley DB environment. +

There are two approaches to handling this problem: +

+

The hard way:
An application can track its own state carefully enough that it knows +when recovery needs to be performed. Specifically, the rule to use is +that recovery must be performed before using a Berkeley DB environment any +time the threads of control previously using the Berkeley DB environment did +not shut the environment down cleanly before exiting the environment +for any reason (including application or system failure). +

Requirements for shutting down the environment cleanly differ depending +on the type of environment created. If the environment is public and +persistent (i.e., the DB_PRIVATE flag was not specified to the +DBENV->open function), recovery must be performed if any transaction was +not committed or aborted, or DBENV->close function was not called for +any open DB_ENV handle. +

If the environment is private and temporary (i.e., the DB_PRIVATE +flag was specified to the DBENV->open function), recovery must be performed +if any transaction was not committed or aborted, or DBENV->close function +was not called for any open DB_ENV handle. In addition, at least +one transaction checkpoint must be performed after all existing +transactions have been committed or aborted. +

The easy way:
It greatly simplifies matters that recovery may be performed regardless +of whether recovery strictly needs to be performed, that is, it is not +an error to run recovery on a database where no recovery is necessary. +Because of this fact, it is almost invariably simpler to ignore the +above rules about shutting an application down cleanly, and simply run +recovery each time a thread of control accessing a database environment +fails for any reason, as well as before accessing any database +environment after system reboot. +
+

There are two common ways to build transactionally protected Berkeley DB +applications. The most common way is as a single, usually +multi-threaded, process. This architecture is simplest because it +requires no monitoring of other threads of control. When the +application starts, it opens and potentially creates the environment, +runs recovery (whether it was needed or not), and then opens its +databases. From then on, the application can create new threads of +control as it chooses. All threads of control share the open Berkeley DB +DB_ENV and DB handles. In this model, databases are +rarely opened or closed when more than a single thread of control is +running, that is, they are opened when only a single thread is running, +and closed after all threads but one have exited. The last thread of +control to exit closes the databases and the environment. +

An alternative way to build Berkeley DB applications is as a set of +cooperating processes, which may or may not be multi-threaded. This +architecture is more complicated. +

First, this architecture requires that the order in which threads of +control are created and subsequently access the Berkeley DB environment be +controlled, because recovery must be single-threaded. The first thread +of control to access the environment must run recovery, and no other +thread should attempt to access the environment until recovery is +complete. (Note that this ordering requirement does not apply to +environment creation without recovery. If multiple threads attempt to +create a Berkeley DB environment, only one will perform the creation and the +others will join the already existing environment.) +

Second, this architecture requires that threads of control be monitored. +If any thread of control that owns Berkeley DB resources exits, without first +cleanly discarding those resources, recovery is usually necessary. +Before running recovery, all threads using the Berkeley DB environment must +relinquish all of their Berkeley DB resources (it does not matter if they do +so gracefully or because they are forced to exit). Then recovery can +be run and the threads of control continued or re-started. +

We have found that the safest way to structure groups of cooperating +processes is to first create a single process (often a shell script) +that opens/creates the Berkeley DB environment and runs recovery, and which +then creates the processes or threads that will actually perform work. +The initial thread has no further responsibilities other than to monitor +the threads of control it has created, to ensure that none of them +unexpectedly exits. If one exits, the initial process then forces all +of the threads of control using the Berkeley DB environment to exit, runs +recovery, and restarts the working threads of control. +

If it is not practical to have a single parent for the processes sharing +a Berkeley DB environment, each process sharing the environment should log +their connection to and exit from the environment in some fashion that +permits a monitoring process to detect if a thread of control may have +potentially acquired Berkeley DB resources and never released them. +

Obviously, it is important that the monitoring process in either case +be as simple and well-tested as possible as there is no recourse should +it fail. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/transapp/archival.html b/db/docs/ref/transapp/archival.html new file mode 100644 index 000000000..2e8815850 --- /dev/null +++ b/db/docs/ref/transapp/archival.html @@ -0,0 +1,149 @@ + + + + + +Berkeley DB Reference Guide: Database and log file archival + + + + + + + +

Berkeley DB Reference Guide:
Transaction Protected Applications

PrevRefNext +
+

+

Database and log file archival

+ +

The third component of the administrative infrastructure, archival for +catastrophic recovery, concerns the recoverability of the database in +the face of catastrophic failure. Recovery after catastrophic failure +is intended to minimize data loss when physical hardware has been +destroyed, for example, loss of a disk that contains databases or log +files. While the application may still experience data loss in this +case, it is possible to minimize it. +

First, you may want to periodically create snapshots (i.e., backups) of +your databases to make it possible to recover from catastrophic failure. +These snapshots are either a standard backup which creates a consistent +picture of the databases as of a single instant in time, or an on-line +backup (also known as a hot backup), which creates a +consistent picture of the databases as of an unspecified instant during +the period of time when the snapshot was made. The advantage of a hot +backup is that applications may continue to read and write the databases +while the snapshot is being taken. The disadvantage of a hot backup is +that more information must be archived, and recovery based on a hot +backup is to an unspecified time between the start of the backup and +when the backup is completed. +

Second, after taking a snapshot, you should periodically archive the +log files being created in the environment. It is often helpful to +think of database archival in terms of full and incremental filesystem +backups. A snapshot is a full backup, while the periodic archival of +the current log files is an incremental. For example, it might be +reasonable to take a full snapshot of a database environment weekly or +monthly, and then archive additional log files daily. Using both the +snapshot and the log files, a catastrophic crash at any time can be +recovered to the time of the most recent log archival, a time long after +the original snapshot. +

To create a standard backup of your database that can be used to recover +from catastrophic failure, take the following steps: +

    +

  1. Commit or abort all on-going transactions. +

  2. Force an environment checkpoint (see db_checkpoint for more +information). +

  3. Stop writing your databases until the backup has completed. Read-only +operations are permitted, but no write operations and no filesystem +operations may be performed, e.g., the DBENV->remove and +DB->open functions may not be called). +

  4. Run db_archive -s to identify all of the database data +files, and copy them to a backup device, such as CDROM, alternate disk, +or tape. Obviously, the reliability of your archive media will affect +the safety of your data. +

    If the database files are stored in a separate directory from the other +Berkeley DB files, it may be simpler to archive the directory itself instead +of the individual files (see DBENV->set_data_dir for additional +information). If you are performing a hot backup, the utility you use +to copy the files must read database pages atomically (as described by +Berkeley DB recoverability). +

    Note: if any of the database files did not have an open DB +handle during the lifetime of the current log files, db_archive +will not list them in its output! For this reason, it may be simpler +to use a separate database file directory, and archive the entire +directory instead of only the files listed by db_archive. +

+

To create a hot backup of your database that can be used to +recover from catastrophic failure, take the following steps: +

    +

  1. Archive your databases as described in Step #4 above. You +do not have to halt on-going transactions or force a checkpoint. +

  2. When performing a hot backup, you must additionally archive the active +log files. Note that the order of these two operations is required, +and the database files must be archived before the log files. This +means that if the database files and log files are in the same +directory, you cannot simply archive the directory, you must make sure +that the correct order of archival is maintained. +

    To archive your log files, run the db_archive utility, using +the -l option, to identify all of the database log files, and +copy them to your backup media. If the database log files are stored +in a separate directory from the other database files, it may be simpler +to archive the directory itself instead of the individual files (see +the DBENV->set_lg_dir function for more information). +

+

Once these steps are completed, your database can be recovered from +catastrophic failure (see Recovery procedures for +more information). +

To update your snapshot so that recovery from catastrophic failure is +possible up to a new point in time, repeat step #2 under the hot backup +instructions, copying all existing log files to a backup device. This +is applicable to both standard and hot backups, that is, you can update +snapshots made in either way. Each time both the database and log files +are copied to backup media, you may discard all previous database +snapshots and saved log files. Archiving additional log files does not +allow you to discard either previous database snapshots or log files. +

The time to restore from catastrophic failure is a function of the +number of log records that have been written since the snapshot was +originally created. Perhaps more importantly, the more separate pieces +of backup media you use, the more likely that you will have a problem +reading from one of them. For these reasons, it is often best to make +snapshots on a regular basis. +

For archival safety, ensure that you have multiple copies of your +database backups, verify that your archival media is error-free and +readable, and that copies of your backups are stored off-site! +

The functionality provided by the db_archive utility is also +available directly from the Berkeley DB library. The following code fragment +prints out a list of log and database files that need to be archived. +

void
+log_archlist(DB_ENV *dbenv)
+{
+	int ret;
+	char **begin, **list;
+

+ /* Get the list of database files. */ + if ((ret = log_archive(dbenv, + &list, DB_ARCH_ABS | DB_ARCH_DATA, NULL)) != 0) { + dbenv->err(dbenv, ret, "log_archive: DB_ARCH_DATA"); + exit (1); + } + if (list != NULL) { + for (begin = list; *list != NULL; ++list) + printf("database file: %s\n", *list); + free (begin); + } +

+ /* Get the list of log files. */ + if ((ret = log_archive(dbenv, + &list, DB_ARCH_ABS | DB_ARCH_LOG, NULL)) != 0) { + dbenv->err(dbenv, ret, "log_archive: DB_ARCH_LOG"); + exit (1); + } + if (list != NULL) { + for (begin = list; *list != NULL; ++list) + printf("log file: %s\n", *list); + free (begin); + } +}

+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/transapp/checkpoint.html b/db/docs/ref/transapp/checkpoint.html new file mode 100644 index 000000000..b9bd81a3e --- /dev/null +++ b/db/docs/ref/transapp/checkpoint.html @@ -0,0 +1,127 @@ + + + + + +Berkeley DB Reference Guide: Checkpoints + + + + + + + +

Berkeley DB Reference Guide:
Transaction Protected Applications

PrevRefNext +
+

+

Checkpoints

+

The second component of the infrastructure is performing checkpoints of +the log files. As transactions commit, change records are written into +the log files, but the actual changes to the database are not +necessarily written to disk. When a checkpoint is performed, the +changes to the database that are part of committed transactions are +written into the backing database file. +

Performing checkpoints is necessary for two reasons. First, you can +only remove the Berkeley DB log files from your system after a checkpoint. +Second, the frequency of your checkpoints is inversely proportional to +the amount of time it takes to run database recovery after a system or +application failure. +

Once the database pages are written, log files can be archived and removed +from the system because they will never be needed for anything other than +catastrophic failure. In addition, recovery after system or application +failure only has to redo or undo changes since the last checkpoint, since +changes before the checkpoint have all been flushed to the filesystem. +

Berkeley DB provides a separate utility, db_checkpoint, which can be +used to perform checkpoints. Alternatively, applications can write +their own checkpoint utility using the underlying txn_checkpoint +function. The following code fragment checkpoints the database +environment every 60 seconds: +

int
+main(int argc, char *argv)
+{
+	extern char *optarg;
+	extern int optind;
+	DB *db_cats, *db_color, *db_fruit;
+	DB_ENV *dbenv;
+	pthread_t ptid;
+	int ch;
+

+ while ((ch = getopt(argc, argv, "")) != EOF) + switch (ch) { + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; +

+ env_dir_create(); + env_open(&dbenv); +

+ /* Start a checkpoint thread. */ + if ((errno = pthread_create( + &ptid, NULL, checkpoint_thread, (void *)dbenv)) != 0) { + fprintf(stderr, + "txnapp: failed spawning checkpoint thread: %s\n", + strerror(errno)); + exit (1); + } +

+ /* Open database: Key is fruit class; Data is specific type. */ + db_open(dbenv, &db_fruit, "fruit", 0); +

+ /* Open database: Key is a color; Data is an integer. */ + db_open(dbenv, &db_color, "color", 0); +

+ /* + * Open database: + * Key is a name; Data is: company name, address, cat breeds. + */ + db_open(dbenv, &db_cats, "cats", 1); +

+ add_fruit(dbenv, db_fruit, "apple", "yellow delicious"); +

+ add_color(dbenv, db_color, "blue", 0); + add_color(dbenv, db_color, "blue", 3); +

+ add_cat(dbenv, db_cats, + "Amy Adams", + "Sleepycat Software", + "394 E. Riding Dr., Carlisle, MA 01741, USA", + "abyssinian", + "bengal", + "chartreaux", + NULL); +

+ return (0); +} +

+void * +checkpoint_thread(void *arg) +{ + DB_ENV *dbenv; + int ret; +

+ dbenv = arg; + dbenv->errx(dbenv, "Checkpoint thread: %lu", (u_long)pthread_self()); +

+ /* Checkpoint once a minute. */ + for (;; sleep(60)) + switch (ret = txn_checkpoint(dbenv, 0, 0, 0)) { + case 0: + case DB_INCOMPLETE: + break; + default: + dbenv->err(dbenv, ret, "checkpoint thread"); + exit (1); + } +

+ /* NOTREACHED */ +}

+

As checkpoints can be quite expensive, choosing how often to perform a +checkpoint is a common tuning parameter for Berkeley DB applications. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/transapp/cursor.html b/db/docs/ref/transapp/cursor.html new file mode 100644 index 000000000..bb1aff98a --- /dev/null +++ b/db/docs/ref/transapp/cursor.html @@ -0,0 +1,169 @@ + + + + + +Berkeley DB Reference Guide: Transactional cursors + + + + + + +

Berkeley DB Reference Guide:
Transaction Protected Applications

PrevRefNext +
+

+

Transactional cursors

+

Berkeley DB cursors may be used inside a transaction, exactly like any other +DB method. The enclosing transaction ID must be specified when +the cursor is created, but it does not then need to be further specified +on operations performed using the cursor. One important point to +remember is that a cursor must be closed before the enclosing +transaction is committed or aborted. +

The following code fragment uses a cursor to store a new key in the cats +database with four associated data items. The key is a name. The data +items are a company name, an address, and a list of the breeds of cat +owned. Each of the data entries is stored as a duplicate data item. +In this example, transactions are necessary to ensure that either all or none +of the data items appear in case of system or application failure. +

int
+main(int argc, char *argv)
+{
+	extern char *optarg;
+	extern int optind;
+	DB *db_cats, *db_color, *db_fruit;
+	DB_ENV *dbenv;
+	pthread_t ptid;
+	int ch;
+

+ while ((ch = getopt(argc, argv, "")) != EOF) + switch (ch) { + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; +

+ env_dir_create(); + env_open(&dbenv); +

+ /* Open database: Key is fruit class; Data is specific type. */ + db_open(dbenv, &db_fruit, "fruit", 0); +

+ /* Open database: Key is a color; Data is an integer. */ + db_open(dbenv, &db_color, "color", 0); +

+ /* + * Open database: + * Key is a name; Data is: company name, address, cat breeds. + */ + db_open(dbenv, &db_cats, "cats", 1); +

+ add_fruit(dbenv, db_fruit, "apple", "yellow delicious"); +

+ add_color(dbenv, db_color, "blue", 0); + add_color(dbenv, db_color, "blue", 3); +

+ add_cat(dbenv, db_cats, + "Amy Adams", + "Sleepycat Software", + "394 E. Riding Dr., Carlisle, MA 01741, USA", + "abyssinian", + "bengal", + "chartreaux", + NULL); +

+ return (0); +} +

+void +add_cat(DB_ENV *dbenv, DB *db, char *name, ...) +{ + va_list ap; + DBC *dbc; + DBT key, data; + DB_TXN *tid; + int ret; + char *s; +

+ /* Initialization. */ + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = name; + key.size = strlen(name); +

+retry: /* Begin the transaction. */ + if ((ret = txn_begin(dbenv, NULL, &tid, 0)) != 0) { + dbenv->err(dbenv, ret, "txn_begin"); + exit (1); + } +

+ /* Delete any previously existing item. */ + switch (ret = db->del(db, tid, &key, 0)) { + case 0: + case DB_NOTFOUND: + break; + case DB_LOCK_DEADLOCK: + /* Deadlock: retry the operation. */ + if ((ret = txn_abort(tid)) != 0) { + dbenv->err(dbenv, ret, "txn_abort"); + exit (1); + } + goto retry; + default: + dbenv->err(dbenv, ret, "db->del: %s", name); + exit (1); + } +

+ /* Create a cursor. */ + if ((ret = db->cursor(db, tid, &dbc, 0)) != 0) { + dbenv->err(dbenv, ret, "db->cursor"); + exit (1); + } +

+ /* Append the items, in order. */ + va_start(ap, name); + while ((s = va_arg(ap, char *)) != NULL) { + data.data = s; + data.size = strlen(s); + switch (ret = dbc->c_put(dbc, &key, &data, DB_KEYLAST)) { + case 0: + break; + case DB_LOCK_DEADLOCK: + va_end(ap); +

+ /* Deadlock: retry the operation. */ + if ((ret = dbc->c_close(dbc)) != 0) { + dbenv->err( + dbenv, ret, "dbc->c_close"); + exit (1); + } + if ((ret = txn_abort(tid)) != 0) { + dbenv->err(dbenv, ret, "txn_abort"); + exit (1); + } + goto retry; + default: + /* Error: run recovery. */ + dbenv->err(dbenv, ret, "dbc->put: %s/%s", name, s); + exit (1); + } + } + va_end(ap); +

+ /* Success: commit the change. */ + if ((ret = dbc->c_close(dbc)) != 0) { + dbenv->err(dbenv, ret, "dbc->c_close"); + exit (1); + } + if ((ret = txn_commit(tid, 0)) != 0) { + dbenv->err(dbenv, ret, "txn_commit"); + exit (1); + } +}

+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/transapp/data_open.html b/db/docs/ref/transapp/data_open.html new file mode 100644 index 000000000..904778c35 --- /dev/null +++ b/db/docs/ref/transapp/data_open.html @@ -0,0 +1,119 @@ + + + + + +Berkeley DB Reference Guide: Opening the databases + + + + + + +

Berkeley DB Reference Guide:
Transaction Protected Applications

PrevRefNext +
+

+

Opening the databases

+

Next, we open three databases ("color" and "fruit" and "cats"), in the +database environment. Again, our DB database handles are +declared to be free-threaded using the DB_THREAD flag, and so +may be used by any number of threads we subsequently create. +

int
+main(int argc, char *argv)
+{
+	extern char *optarg;
+	extern int optind;
+	DB *db_cats, *db_color, *db_fruit;
+	DB_ENV *dbenv;
+	pthread_t ptid;
+	int ch;
+

+ while ((ch = getopt(argc, argv, "")) != EOF) + switch (ch) { + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; +

+ env_dir_create(); + env_open(&dbenv); +

+ /* Open database: Key is fruit class; Data is specific type. */ + db_open(dbenv, &db_fruit, "fruit", 0); +

+ /* Open database: Key is a color; Data is an integer. */ + db_open(dbenv, &db_color, "color", 0); +

+ /* + * Open database: + * Key is a name; Data is: company name, address, cat breeds. + */ + db_open(dbenv, &db_cats, "cats", 1); +

+ return (0); +} +

+void +db_open(DB_ENV *dbenv, DB **dbp, char *name, int dups) +{ + DB *db; + int ret; +

+ /* Create the database handle. */ + if ((ret = db_create(&db, dbenv, 0)) != 0) { + dbenv->err(dbenv, ret, "db_create"); + exit (1); + } +

+ /* Optionally, turn on duplicate data items. */ + if (dups && (ret = db->set_flags(db, DB_DUP)) != 0) { + dbenv->err(dbenv, ret, "db->set_flags: DB_DUP"); + exit (1); + } +

+ /* + * Open a database in the environment: + * create if it doesn't exist + * free-threaded handle + * read/write owner only + */ + if ((ret = db->open(db, name, NULL, + DB_BTREE, DB_CREATE | DB_THREAD, S_IRUSR | S_IWUSR)) != 0) { + dbenv->err(dbenv, ret, "db->open: %s", name); + exit (1); + } +

+ *dbp = db; +}

+

There is no reason to wrap database opens inside of transactions. All +database opens are transaction protected internally to Berkeley DB, and +applications using transaction-protected environments can simply rely on +files either being successfully re-created in a recovered environment, +or not appearing at all. +

After running this initial code, we can use the db_stat utility +to display information about a database we have created: +

prompt> db_stat -h TXNAPP -d color
+53162   Btree magic number.
+8       Btree version number.
+Flags:
+2       Minimum keys per-page.
+8192    Underlying database page size.
+1       Number of levels in the tree.
+0       Number of unique keys in the tree.
+0       Number of data items in the tree.
+0       Number of tree internal pages.
+0       Number of bytes free in tree internal pages (0% ff).
+1       Number of tree leaf pages.
+8166    Number of bytes free in tree leaf pages (0.% ff).
+0       Number of tree duplicate pages.
+0       Number of bytes free in tree duplicate pages (0% ff).
+0       Number of tree overflow pages.
+0       Number of bytes free in tree overflow pages (0% ff).
+0       Number of pages on the free list.
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/transapp/deadlock.html b/db/docs/ref/transapp/deadlock.html new file mode 100644 index 000000000..65765ec59 --- /dev/null +++ b/db/docs/ref/transapp/deadlock.html @@ -0,0 +1,92 @@ + + + + + +Berkeley DB Reference Guide: Deadlock detection + + + + + + + +

Berkeley DB Reference Guide:
Transaction Protected Applications

PrevRefNext +
+

+

Deadlock detection

+

The first component of the infrastructure, deadlock detection, is not +so much a requirement specific to transaction protected applications, +but rather is necessary for almost all applications where more than a +single thread of control will be accessing the database at one time. +While Berkeley DB automatically handles database locking, it is normally +possible for deadlock to occur. It is not required by all transactional +applications, but exceptions are rare. +

When the deadlock occurs, two (or more) threads of control each request +additional locks which can never be granted because one of the threads +of control waiting holds the requested resource. +

For example, consider two processes A and B. Let's say that A obtains +an exclusive lock on item X, and B obtains an exclusive lock on item Y. +Then, A requests a lock on Y and B requests a lock on X. A will wait +until resource Y becomes available and B will wait until resource X +becomes available. Unfortunately, since both A and B are waiting, +neither will release the locks they hold and neither will ever obtain +the resource on which it is waiting. In order to detect that deadlock +has happened, a separate process or thread must review the locks +currently held in the database. If deadlock has occurred, a victim must +be selected, and that victim will then return the error +DB_LOCK_DEADLOCK from whatever Berkeley DB call it was making. +

Berkeley DB provides a separate UNIX-style utility which can be used to +perform this deadlock detection, named db_deadlock. +Alternatively, applications can create their own deadlock utility or +thread using the underlying lock_detect function, or specify +that Berkeley DB run the deadlock detector internally whenever there is a +conflict over a lock (see DBENV->set_lk_detect for more +information). The following code fragment does the latter: +

void
+env_open(DB_ENV **dbenvp)
+{
+	DB_ENV *dbenv;
+	int ret;
+

+ /* Create the environment handle. */ + if ((ret = db_env_create(&dbenv, 0)) != 0) { + fprintf(stderr, + "txnapp: db_env_create: %s\n", db_strerror(ret)); + exit (1); + } +

+ /* Set up error handling. */ + dbenv->set_errpfx(dbenv, "txnapp"); +

+ /* Do deadlock detection internally. */ + if ((ret = dbenv->set_lk_detect(dbenv, DB_LOCK_DEFAULT)) != 0) { + dbenv->err(dbenv, ret, "set_lk_detect: DB_LOCK_DEFAULT"); + exit (1); + } +

+ /* + * Open a transactional environment: + * create if it doesn't exist + * free-threaded handle + * run recovery + * read/write owner only + */ + if ((ret = dbenv->open(dbenv, ENV_DIRECTORY, + DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | + DB_INIT_MPOOL | DB_INIT_TXN | DB_RECOVER | DB_THREAD, + S_IRUSR | S_IWUSR)) != 0) { + dbenv->err(dbenv, ret, "dbenv->open: %s", ENV_DIRECTORY); + exit (1); + } +

+ *dbenvp = dbenv; +}

+

Deciding how often to run the deadlock detector and which of the +deadlocked transactions will be forced to abort when the deadlock is +detected is a common tuning parameter for Berkeley DB applications. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/transapp/env_open.html b/db/docs/ref/transapp/env_open.html new file mode 100644 index 000000000..7209a3fef --- /dev/null +++ b/db/docs/ref/transapp/env_open.html @@ -0,0 +1,174 @@ + + + + + +Berkeley DB Reference Guide: Opening the environment + + + + + + +

Berkeley DB Reference Guide:
Transaction Protected Applications

PrevRefNext +
+

+

Opening the environment

+

Creating transaction-protected applications using the Berkeley DB library is +quite easy. Applications first use DBENV->open to initialize +the database environment. Transaction-protected applications normally +require all four Berkeley DB subsystems, so the DB_INIT_MPOOL, +DB_INIT_LOCK, DB_INIT_LOG and DB_INIT_TXN flags +should be specified. +

Once the application has called DBENV->open, it opens its +databases within the environment. Once the databases are opened, the +application makes changes to the databases inside of transactions. Each +set of changes that entail a unit of work should be surrounded by the +appropriate txn_begin, txn_commit and txn_abort +calls. The Berkeley DB access methods will make the appropriate calls into +the lock, log and memory pool subsystems in order to guarantee +transaction semantics. When the application is ready to exit, all +outstanding transactions should have been committed or aborted. +

Databases accessed by a transaction must not be closed during the +transaction. Once all outstanding transactions are finished, all open +Berkeley DB files should be closed. When the Berkeley DB database files have been +closed, the environment should be closed by calling DBENV->close. +

The following code fragment creates the database environment directory, +then opens the environment, running recovery. Our DB_ENV +database environment handle is declared to be free-threaded using the +DB_THREAD flag, and so may be used by any number of threads that +we may subsequently create. +

#include <sys/types.h>
+#include <sys/stat.h>
+

+#include <errno.h> +#include <pthread.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +

+#include <db.h> +

+#define ENV_DIRECTORY "TXNAPP" +

+void env_dir_create(void); +void env_open(DB_ENV **); +

+int +main(int argc, char *argv) +{ + extern char *optarg; + extern int optind; + DB *db_cats, *db_color, *db_fruit; + DB_ENV *dbenv; + pthread_t ptid; + int ch; +

+ while ((ch = getopt(argc, argv, "")) != EOF) + switch (ch) { + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; +

+ env_dir_create(); + env_open(&dbenv); +

+ return (0); +} +

+void +env_dir_create() +{ + struct stat sb; +

+ /* + * If the directory exists, we're done. We do not further check + * the type of the file, DB will fail appropriately if it's the + * wrong type. + */ + if (stat(ENV_DIRECTORY, &sb) == 0) + return; +

+ /* Create the directory, read/write/access owner only. */ + if (mkdir(ENV_DIRECTORY, S_IRWXU) != 0) { + fprintf(stderr, + "txnapp: mkdir: %s: %s\n", ENV_DIRECTORY, strerror(errno)); + exit (1); + } +} +

+void +env_open(DB_ENV **dbenvp) +{ + DB_ENV *dbenv; + int ret; +

+ /* Create the environment handle. */ + if ((ret = db_env_create(&dbenv, 0)) != 0) { + fprintf(stderr, + "txnapp: db_env_create: %s\n", db_strerror(ret)); + exit (1); + } +

+ /* Set up error handling. */ + dbenv->set_errpfx(dbenv, "txnapp"); +

+ /* + * Open a transactional environment: + * create if it doesn't exist + * free-threaded handle + * run recovery + * read/write owner only + */ + if ((ret = dbenv->open(dbenv, ENV_DIRECTORY, + DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | + DB_INIT_MPOOL | DB_INIT_TXN | DB_RECOVER | DB_THREAD, + S_IRUSR | S_IWUSR)) != 0) { + dbenv->err(dbenv, ret, "dbenv->open: %s", ENV_DIRECTORY); + exit (1); + } +

+ *dbenvp = dbenv; +}

+

After running this initial program, we can use the db_stat +utility to display the contents of the environment directory: +

prompt> db_stat -e -h TXNAPP
+3.2.1   Environment version.
+120897  Magic number.
+0       Panic value.
+1       References.
+6       Locks granted without waiting.
+0       Locks granted after waiting.
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+Mpool Region: 4.
+264KB   Size (270336 bytes).
+-1      Segment ID.
+1       Locks granted without waiting.
+0       Locks granted after waiting.
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+Log Region: 3.
+96KB    Size (98304 bytes).
+-1      Segment ID.
+3       Locks granted without waiting.
+0       Locks granted after waiting.
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+Lock Region: 2.
+240KB   Size (245760 bytes).
+-1      Segment ID.
+1       Locks granted without waiting.
+0       Locks granted after waiting.
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+Txn Region: 5.
+8KB     Size (8192 bytes).
+-1      Segment ID.
+1       Locks granted without waiting.
+0       Locks granted after waiting.
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/transapp/filesys.html b/db/docs/ref/transapp/filesys.html new file mode 100644 index 000000000..fc68089e9 --- /dev/null +++ b/db/docs/ref/transapp/filesys.html @@ -0,0 +1,62 @@ + + + + + +Berkeley DB Reference Guide: Recovery and filesystem operations + + + + + + + +

Berkeley DB Reference Guide:
Transaction Protected Applications

PrevRefNext +
+

+

Recovery and filesystem operations

+

When running in a transaction-protected environment, database creation +and deletion are logged as stand-alone transactions internal to Berkeley DB. +That is, for each such operation a new transaction is begun and aborted +or committed internally, so that they will be recovered during recovery. +

The Berkeley DB API supports removing and renaming files. Renaming files is +supported by the DB->rename method, and removing files by the +DB->remove method. Berkeley DB does not permit specifying the +DB_TRUNCATE flag when opening a file in a transaction protected +environment. This is an implicit file deletion, but one that does not +always require the same operating system file permissions as does deleting +and creating a file. +

If you have changed the name of a file or deleted it outside of the Berkeley DB +library (e.g., you explicitly removed a file using your normal operating +system utilities), then it is possible that recovery will not be able to +find a database referenced in the log. In this case, db_recover +will produce a warning message saying it was unable to locate a file it +expected to find. This message is only a warning, as the file may have +been subsequently deleted as part of normal database operations before +the failure occurred, and so is not necessarily a problem. +

Generally, any filesystem operations that are performed outside the Berkeley DB +interface should be performed at the same time as making a snapshot of +the database. To perform filesystem operations correctly: +

    +

  1. Cleanly shutdown database operations. +

    To shutdown database operations cleanly, all applications accessing the +database environment must be shutdown and a transaction checkpoint must +be taken. If the applications are not implemented such that they can be +shutdown gracefully (i.e., closing all references to the database +environment), recovery must be performed after all applications have been +killed to ensure that the underlying databases are consistent on disk. +

  2. Perform the filesystem operations, e.g., remove or rename one +or more files. +

  3. Make an archival snapshot of the database. +

    While this step is not strictly necessary, it is strongly recommended. +If this step is not performed, recovery from catastrophic failure will +require that recovery first be performed up to the time of the +filesystem operations, the filesystem operations be redone, and then +recovery be performed from the filesystem operations forward. +

  4. Restart the database applications. +
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/transapp/inc.html b/db/docs/ref/transapp/inc.html new file mode 100644 index 000000000..35cf67d7e --- /dev/null +++ b/db/docs/ref/transapp/inc.html @@ -0,0 +1,201 @@ + + + + + +Berkeley DB Reference Guide: Atomicity + + + + + + +

Berkeley DB Reference Guide:
Transaction Protected Applications

PrevRefNext +
+

+

Atomicity

+

The third reason listed for using transactions was atomicity. Consider +an application suite where multiple threads of control (multiple +processes or threads in one or more processes) are changing the values +associated with a key in one or more databases. Specifically, they are +taking the current value, incrementing it, and then storing it back into +the database. +

Such an application requires atomicity. Since we want to change a value +in the database, we must make sure that once we read it, no other thread +of control modifies it. For example, assume that both thread #1 and +thread #2 are doing similar operations in the database, where thread #1 +is incrementing records by 3, and thread #2 is incrementing records by +5. We want to increment the record by a total of 8. If the operations +interleave in the right (well, wrong) order, that is not what will +happen: +

thread #1  read record: the value is 2
+thread #2  read record: the value is 2
+thread #2  write record + 5 back into the database (new value 7)
+thread #1  write record + 3 back into the database (new value 5)
+

As you can see, instead of incrementing the record by a total of 8, +we've only incremented it by 3, because thread #1 overwrote thread #2's +change. By wrapping the operations in transactions, we ensure that this +cannot happen. In a transaction, when the first thread reads the +record, locks are acquired that will not be released until the +transaction finishes, guaranteeing that all other readers and writers +will block, waiting for the first thread's transaction to complete (or +to be aborted). +

Here is an example function that does transaction-protected increments +on database records to ensure atomicity. +

int
+main(int argc, char *argv)
+{
+	extern char *optarg;
+	extern int optind;
+	DB *db_cats, *db_color, *db_fruit;
+	DB_ENV *dbenv;
+	pthread_t ptid;
+	int ch;
+

+ while ((ch = getopt(argc, argv, "")) != EOF) + switch (ch) { + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; +

+ env_dir_create(); + env_open(&dbenv); +

+ /* Open database: Key is fruit class; Data is specific type. */ + db_open(dbenv, &db_fruit, "fruit", 0); +

+ /* Open database: Key is a color; Data is an integer. */ + db_open(dbenv, &db_color, "color", 0); +

+ /* + * Open database: + * Key is a name; Data is: company name, address, cat breeds. + */ + db_open(dbenv, &db_cats, "cats", 1); +

+ add_fruit(dbenv, db_fruit, "apple", "yellow delicious"); +

+ add_color(dbenv, db_color, "blue", 0); + add_color(dbenv, db_color, "blue", 3); +

+ return (0); +} +

+void +add_color(DB_ENV *dbenv, DB *dbp, char *color, int increment) +{ + DBT key, data; + DB_TXN *tid; + int original, ret; + char buf64; +

+ /* Initialization. */ + memset(&key, 0, sizeof(key)); + key.data = color; + key.size = strlen(color); + memset(&data, 0, sizeof(data)); + data.flags = DB_DBT_MALLOC; +

+ for (;;) { + /* Begin the transaction. */ + if ((ret = txn_begin(dbenv, NULL, &tid, 0)) != 0) { + dbenv->err(dbenv, ret, "txn_begin"); + exit (1); + } +

+ /* + * Get the key. If it exists, we increment the value. If it + * doesn't exist, we create it. + */ + switch (ret = dbp->get(dbp, tid, &key, &data, 0)) { + case 0: + original = atoi(data.data); + break; + case DB_LOCK_DEADLOCK: + /* Deadlock: retry the operation. */ + if ((ret = txn_abort(tid)) != 0) { + dbenv->err(dbenv, ret, "txn_abort"); + exit (1); + } + continue; + case DB_NOTFOUND: + original = 0; + break; + default: + /* Error: run recovery. */ + dbenv->err( + dbenv, ret, "dbc->get: %s/%d", color, increment); + exit (1); + } + if (data.data != NULL) + free(data.data); +

+ /* Create the new data item. */ + (void)snprintf(buf, sizeof(buf), "%d", original + increment); + data.data = buf; + data.size = strlen(buf) + 1; +

+ /* Store the new value. */ + switch (ret = dbp->put(dbp, tid, &key, &data, 0)) { + case 0: + /* Success: commit the change. */ + if ((ret = txn_commit(tid, 0)) != 0) { + dbenv->err(dbenv, ret, "txn_commit"); + exit (1); + } + return; + case DB_LOCK_DEADLOCK: + /* Deadlock: retry the operation. */ + if ((ret = txn_abort(tid)) != 0) { + dbenv->err(dbenv, ret, "txn_abort"); + exit (1); + } + break; + default: + /* Error: run recovery. */ + dbenv->err( + dbenv, ret, "dbc->put: %s/%d", color, increment); + exit (1); + } + } +}

+

Any number of operations, on any number of databases, can be included +in a single transaction to ensure atomicity of the operations. There +is, however, a trade-off between the number of operations included in +a single transaction and both throughput and the possibility of +deadlock. The reason for this is because transactions acquire locks +throughout their lifetime, and do not release them until transaction +commit or abort. So, the more operations included in a transaction, +the more likely that a transaction will block other operations and that +deadlock will occur. However, each transaction commit requires a +synchronous disk I/O, so grouping multiple operations into a transaction +can increase overall throughput. (There is one exception to this. The +DB_TXN_NOSYNC option causes transactions to exhibit the ACI +(atomicity, consistency and isolation) properties, but not D +(durability), avoiding the synchronous disk I/O on transaction commit +and greatly increasing transaction throughput for some applications. +

When applications do create complex transactions, they often avoid +having more than one complex transaction at a time, as simple operations +like a single DB->put are unlikely to deadlock with each other +or the complex transaction, while multiple complex transactions are +likely to deadlock with each other as they will both acquire many locks +over their lifetime. Alternatively, complex transactions can be broken +up into smaller sets of operations, and each of those sets may be +encapsulated in a nested transaction. Because nested transactions may +be individually aborted and retried without causing the entire +transaction to be aborted, this allows complex transactions to proceed +even in the face of heavy contention, repeatedly trying the +sub-operations until they succeed. +

It is also helpful to order operations within a transaction, that is, +access the databases and items within the databases in the same order, +to the extent possible, in all transactions. Accessing databases and +items in different orders greatly increases the likelihood of operations +being blocked and failing due to deadlocks. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/transapp/intro.html b/db/docs/ref/transapp/intro.html new file mode 100644 index 000000000..758169e85 --- /dev/null +++ b/db/docs/ref/transapp/intro.html @@ -0,0 +1,42 @@ + + + + + +Berkeley DB Reference Guide: Building transaction protected applications + + + + + + + +

Berkeley DB Reference Guide:
Transaction Protected Applications

PrevRefNext +
+

+

Building transaction protected applications

+

It is difficult to write a useful transactional tutorial and still keep +within reasonable bounds of documentation, that is, without writing a +book on transactional programming. We have two goals in this section: +to familiarize readers with the transactional interfaces of Berkeley DB and +to provide code building blocks that will be useful in creating +applications. +

We have not attempted to present this information using a real-world +application. First, transactional applications are often complex and +time consuming to explain. Also, one of our goals is to give you an +understanding of the wide variety of tools Berkeley DB makes available to you, +and no single application would use most of the interfaces included in +the Berkeley DB library. For these reasons, we have chosen to simply present +the Berkeley DB data structures and programming solutions, using examples that +differ from page to page. All of the examples are included in a +standalone program you can examine, modify and run, and from which you +will be able to extract code blocks for your own applications. +Fragments of the program will be presented throughout this chapter, and +the complete text of the example program +for IEEE/ANSI Std 1003.1 (POSIX) standard systems is included in the Berkeley DB +distribution. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/transapp/logfile.html b/db/docs/ref/transapp/logfile.html new file mode 100644 index 000000000..64d8a9647 --- /dev/null +++ b/db/docs/ref/transapp/logfile.html @@ -0,0 +1,104 @@ + + + + + +Berkeley DB Reference Guide: Log file removal + + + + + + + +

Berkeley DB Reference Guide:
Transaction Protected Applications

PrevRefNext +
+

+

Log file removal

+

The fourth component of the infrastructure, log file removal, concerns +the ongoing disk consumption of the database log files. Depending on +the rate at which the application writes to the databases and the +available disk space, the number of log files may increase quickly +enough that disk space will be a resource problem. For this reason, +you will periodically want to remove log files in order to conserve disk +space. This procedure is distinct from database and log file archival +for catastrophic recovery, and you cannot remove the current log files +simply because you have created a database snapshot or copied log files +to archival media. +

Log files may be removed at any time, as long as: +

    +
  • the log file is not involved in an active transaction +
  • at least two checkpoints have been written subsequent to the +log file's creation, and +
  • the log file is not the only log file in the environment. +
+

Obviously, if you are preparing for catastrophic failure, you will want +to copy the log files to archival media before you remove them. +

To remove log files, take the following steps: +

    +

  1. If you are concerned with catastrophic failure, first copy the log files +to backup media as described in Archival for +catastrophic recovery. +

  2. Run db_archive without options to identify all of the log files +that are no longer in use (e.g., no longer involved in an active +transaction). +

  3. Remove those log files from the system. +
+

The functionality provided by the db_archive utility is also +available directly from the Berkeley DB library. The following code fragment +removes log files that are no longer needed by the database +environment. +

int
+main(int argc, char *argv)
+{
+	...
+

+ /* Start a logfile removal thread. */ + if ((errno = pthread_create( + &ptid, NULL, logfile_thread, (void *)dbenv)) != 0) { + fprintf(stderr, + "txnapp: failed spawning log file removal thread: %s\n", + strerror(errno)); + exit (1); + } +

+ ... +} +

+void * +logfile_thread(void *arg) +{ + DB_ENV *dbenv; + int ret; + char **begin, **list; +

+ dbenv = arg; + dbenv->errx(dbenv, + "Log file removal thread: %lu", (u_long)pthread_self()); +

+ /* Check once every 5 minutes. */ + for (;; sleep(300)) { + /* Get the list of log files. */ + if ((ret = log_archive(dbenv, &list, DB_ARCH_ABS, NULL)) != 0) { + dbenv->err(dbenv, ret, "log_archive"); + exit (1); + } +

+ /* Remove the log files. */ + if (list != NULL) { + for (begin = list; *list != NULL; ++list) + if ((ret = remove(*list)) != 0) { + dbenv->err(dbenv, + ret, "remove %s", *list); + exit (1); + } + free (begin); + } + } + /* NOTREACHED */ +}

+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/transapp/put.html b/db/docs/ref/transapp/put.html new file mode 100644 index 000000000..e04a04f70 --- /dev/null +++ b/db/docs/ref/transapp/put.html @@ -0,0 +1,151 @@ + + + + + +Berkeley DB Reference Guide: Recoverability and deadlock avoidance + + + + + + +

Berkeley DB Reference Guide:
Transaction Protected Applications

PrevRefNext +
+

+

Recoverability and deadlock avoidance

+

The first reason listed for using transactions was recoverability. Any +logical change to a database may require multiple changes to underlying +data structures. For example, modifying a record in a Btree may require +leaf and internal pages to split, and so a single DB->put method +call can potentially require that multiple physical database pages be +written. If only some of those pages are written and then the system +or application fails, the database is left inconsistent and cannot be +used until it has been recovered, that is, until the partially completed +changes have been undone. +

Write-ahead-logging is the term that describes the underlying +implementation that Berkeley DB uses to ensure recoverability. What it means +is that before any change is made to a database, information about the +change is written to a database log. During recovery, the log is read, +and databases are checked to ensure that changes described in the log +for committed transactions appear in the database. Changes that appear +in the database but are related to aborted or unfinished transactions +in the log are undone from the database. +

For recoverability after application or system failure, operations that +modify the database must be protected by transactions. More +specifically, operations are not recoverable unless a transaction is +begun and each operation is associated with the transaction via the +Berkeley DB interfaces, and then the transaction successfully committed. This +is true even if logging is turned on in the database environment. +

Here is an example function that updates a record in a database in a +transactionally protected manner. The function takes a key and data +items as arguments, and then attempts to store them into the database. +

int
+main(int argc, char *argv)
+{
+	extern char *optarg;
+	extern int optind;
+	DB *db_cats, *db_color, *db_fruit;
+	DB_ENV *dbenv;
+	pthread_t ptid;
+	int ch;
+

+ while ((ch = getopt(argc, argv, "")) != EOF) + switch (ch) { + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; +

+ env_dir_create(); + env_open(&dbenv); +

+ /* Open database: Key is fruit class; Data is specific type. */ + db_open(dbenv, &db_fruit, "fruit", 0); +

+ /* Open database: Key is a color; Data is an integer. */ + db_open(dbenv, &db_color, "color", 0); +

+ /* + * Open database: + * Key is a name; Data is: company name, address, cat breeds. + */ + db_open(dbenv, &db_cats, "cats", 1); +

+ add_fruit(dbenv, db_fruit, "apple", "yellow delicious"); +

+ return (0); +} +

+void +add_fruit(DB_ENV *dbenv, DB *db, char *fruit, char *name) +{ + DBT key, data; + DB_TXN *tid; + int ret; +

+ /* Initialization. */ + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = fruit; + key.size = strlen(fruit); + data.data = name; + data.size = strlen(name); +

+ for (;;) { + /* Begin the transaction. */ + if ((ret = txn_begin(dbenv, NULL, &tid, 0)) != 0) { + dbenv->err(dbenv, ret, "txn_begin"); + exit (1); + } +

+ /* Store the value. */ + switch (ret = db->put(db, tid, &key, &data, 0)) { + case 0: + /* Success: commit the change. */ + if ((ret = txn_commit(tid, 0)) != 0) { + dbenv->err(dbenv, ret, "txn_commit"); + exit (1); + } + return; + case DB_LOCK_DEADLOCK: + /* Deadlock: retry the operation. */ + if ((ret = txn_abort(tid)) != 0) { + dbenv->err(dbenv, ret, "txn_abort"); + exit (1); + } + break; + default: + /* Error: run recovery. */ + dbenv->err(dbenv, ret, "dbc->put: %s/%s", fruit, name); + exit (1); + } + } +}

+

The second reason listed for using transactions was deadlock avoidance. +There is a new error return in this function that you may not have seen +before. In transactional (not Concurrent Data Store) applications +supporting both readers and writers or just multiple writers, Berkeley DB +functions have an additional possible error return: +DB_LOCK_DEADLOCK. This return means that our thread of control +deadlocked with another thread of control, and our thread was selected +to discard all of its Berkeley DB resources in order to resolve the problem. +In the sample code, any time the DB->put function returns +DB_LOCK_DEADLOCK, the transaction is aborted (by calling +txn_abort, which releases the transaction's Berkeley DB resources and +undoes any partial changes to the databases), and then the transaction +is retried from the beginning. +

There is no requirement that the transaction be attempted again, but +that is a common course of action for applications. Applications may +want to set an upper boundary on the number of times an operation will +be retried, as some operations on some data sets may simply be unable +to succeed. For example, updating all of the pages on a large web site +during prime business hours may simply be impossible because of the high +access rate to the database. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/transapp/read.html b/db/docs/ref/transapp/read.html new file mode 100644 index 000000000..912401e87 --- /dev/null +++ b/db/docs/ref/transapp/read.html @@ -0,0 +1,40 @@ + + + + + +Berkeley DB Reference Guide: Repeatable reads + + + + + + +

Berkeley DB Reference Guide:
Transaction Protected Applications

PrevRefNext +
+

+

Repeatable reads

+

The fourth reason listed for using transactions was repeatable reads. +Generally, most applications do not need to place reads inside a +transaction for performance reasons. The problem is that a +transactionally protected cursor, reading each key/data pair in a +database, will acquire a read lock on most of the pages in the database +and so will gradually block all write operations on the databases until +the transaction commits or aborts. Note, however, if there are update +transactions present in the application, the reading transactions must +still use locking, and should be prepared to repeat any operation +(possibly closing and reopening a cursor) which fails with a return +value of DB_LOCK_DEADLOCK. +

The exceptions to this rule are when the application is doing a +read-modify-write operation and so requires atomicity, and when an +application requires the ability to repeatedly access a data item +knowing that it will not have changed. A repeatable read simply means +that, for the life of the transaction, every time a request is made by +any thread of control to read a data item, it will be unchanged from +its previous value, that is, that the value will not change until the +transaction commits or aborts. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/transapp/reclimit.html b/db/docs/ref/transapp/reclimit.html new file mode 100644 index 000000000..559f8ed11 --- /dev/null +++ b/db/docs/ref/transapp/reclimit.html @@ -0,0 +1,106 @@ + + + + + +Berkeley DB Reference Guide: Berkeley DB recoverability + + + + + + + +

Berkeley DB Reference Guide:
Transaction Protected Applications

PrevRefNext +
+

+

Berkeley DB recoverability

+

Berkeley DB recovery is based on write-ahead logging. What this means is that, +when a change is made to a database page, a description of the change is +written into a log file. This description in the log file is guaranteed +to be written to stable storage before the database pages that were +changed are written to stable storage. This is the fundamental feature +of the logging system that makes durability and rollback work. +

If the application or system crashes, the log is reviewed during recovery. +Any database changes described in the log that were part of committed +transactions, and that were never written to the actual database itself, +are written to the database as part of recovery. Any database changes +described in the log that were never committed, and that were written to +the actual database itself, are backed-out of the the database as part of +recovery. This design allows the database to be written lazily, and only +blocks from the log file have to be forced to disk as part of transaction +commit. +

There are two interfaces that are a concern when considering Berkeley DB +recoverability: +

    +

  1. The interface between Berkeley DB and the operating system/filesystem. +
  2. The interface between the operating system/filesystem and the +underlying stable storage hardware. +
+

Berkeley DB uses the operating system interfaces and its underlying filesystem +when writing its files. This means that Berkeley DB can fail if the underlying +filesystem fails in some unrecoverable way. Otherwise, the interface +requirements here are simple: the system call that Berkeley DB uses to flush +data to disk (normally fsync(2)), must guarantee that all the +information necessary for a file's recoverability has been written to +stable storage before it returns to Berkeley DB, and that no possible +application or system crash can cause that file to be unrecoverable. +

In addition, Berkeley DB implicitly uses the interface between the operating +system and the underlying hardware. The interface requirements here are +not as simple. +

First, it is necessary to consider the underlying page size of the Berkeley DB +databases. The Berkeley DB library performs all database writes using the page +size specified by the application. These pages are not checksummed and +Berkeley DB assumes that they are written atomically. This means that if the +operating system performs filesystem I/O in different sized blocks than +the database page size, it may increase the possibility for database +corruption. For example, assume that Berkeley DB is writing 32KB pages for a +database and the operating system does filesystem I/O in 16KB blocks. If +the operating system writes the first 16KB of the database page +successfully, but crashes before being able to write the second 16KB of +the database, the database has been corrupted and this corruption will +not be detected during recovery. For this reason, it may be important +to select database page sizes that will be written as single block +transfers by the underlying operating system. +

Second, it is necessary to consider the behavior of the system's underlying +stable storage hardware. For example, consider a SCSI controller that +has been configured to cache data and return to the operating system that +the data has been written to stable storage, when, in fact, it has only +been written into the controller RAM cache. If power is lost before the +controller is able to flush its cache to disk, and the controller cache +is not stable (i.e., the writes will not be flushed to disk when power +returns), the writes will be lost. If the writes include database blocks, +there is no loss as recovery will correctly update the database. If the +writes include log file blocks, it is possible that transactions that were +already committed may not appear in the recovered database, although the +recovered database will be coherent after a crash. +

If the underlying hardware can fail in any way such that only part of the +block was written, the failure conditions are the same as those described +above for an operating system failure that only writes part of a logical +database block. +

For these reasons, it is important to select hardware that does not do +partial writes and does not cache data writes (or does not return that +the data has been written to stable storage until it either has been +written to stable storage or the actual writing of all of the data is +guaranteed barring catastrophic hardware failure, e.g., your disk drive +exploding). You should also be aware that Berkeley DB does not protect against +all cases of stable storage hardware failure, nor does it protect against +hardware misbehavior. +

If the disk drive on which you are storing your databases explodes, you +can perform normal Berkeley DB catastrophic recovery, as that requires only a +snapshot of your databases plus all of the log files you have archived +since those snapshots were taken. In this case, you will lose no database +changes at all. If the disk drive on which you are storing your log files +explodes, you can still perform catastrophic recovery, but you will lose +any database changes that were part of transactions committed since your +last archival of the log files. For this reason, storing your databases +and log files on different disks should be considered a safety measure as +well as a performance enhancement. +

Finally, if your hardware misbehaves, for example, a SCSI controller +writes incorrect data to the disk, Berkeley DB will not detect this and your +data may be corrupted. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/transapp/recovery.html b/db/docs/ref/transapp/recovery.html new file mode 100644 index 000000000..5be94bf41 --- /dev/null +++ b/db/docs/ref/transapp/recovery.html @@ -0,0 +1,91 @@ + + + + + +Berkeley DB Reference Guide: Recovery procedures + + + + + + + +

Berkeley DB Reference Guide:
Transaction Protected Applications

PrevRefNext +
+

+

Recovery procedures

+

The fifth component of the infrastructure, recovery procedures, concerns +the recoverability of the database. After any application or system +failure, there are two possible approaches to database recovery: +

    +

  1. There is no need for recoverability and all databases can be recreated +from scratch. While these applications may still need transaction +protection for other reasons, recovery usually consists of removing the +Berkeley DB environment home directory and all files it contains, and then +restarting the application. +

  2. It is necessary to recover information after system or application +failure. In this case, recovery processing must be performed on any +database environments that were active at the time of the failure. +Recovery processing involves running the db_recover utility or +calling the DBENV->open function with the DB_RECOVER or +DB_RECOVER_FATAL flags. +

    During recovery processing, all database changes made by aborted or +unfinished transactions are undone and all database changes made by +committed transactions are redone, as necessary. Database applications +must not be restarted until recovery completes. After recovery +finishes, the environment is properly initialized so that applications +may be restarted. +

+

If you intend to do recovery, there are two possible types of recovery +processing: +

    +

  1. catastrophic recovery. A failure that requires catastrophic +recovery is a failure where either the database or log files have been +destroyed or corrupted. For example, catastrophic failure includes the +case where the disk drive on which either the database or logs are +stored has been physically destroyed, or when the system's normal +filesystem recovery on startup is unable to bring the database and log +files to a consistent state. This is often difficult to detect, and +perhaps the most common sign of the need for catastrophic recovery is +when the normal recovery procedures fail. +

    To restore your database environment after catastrophic failure, take +the following steps: +

      +

    1. Restore the most recent snapshots of the database and log files from +the backup media into the system directory where recovery will be +performed. +

    2. If any log files were archived since the last snapshot was made, they +should be restored into the Berkeley DB environment directory where recovery +will be performed. Make sure you restore them in the order in which +they were written. The order is important because it's possible that +the same log file appears on multiple backups and you want to run +recovery using the most recent version of each log file. +

    3. Run the db_recover utility, specifying its -c option, +or call the DBENV->open function specifying the DB_RECOVER_FATAL +flag. The catastrophic recovery process will review the logs and +database files to bring the environment databases to a consistent state +as of the time of the last uncorrupted log file that is found. It is +important to realize that only transactions committed before that date +will appear in the databases. +

      It is possible to recreate the database in a location different than +the original, by specifying appropriate pathnames to the -h +option of the db_recover utility. In order for this to work +properly, it is important that your application reference files by +names relative to the database home directory or the pathname(s) specified +in calls to DBENV->set_data_dir, instead of using full path names. +

    +

  2. non-catastrophic or normal recovery. If the +failure is non-catastrophic and the database files and log are both +accessible on a stable filesystem, run the db_recover utility +without the -c option or call the DBENV->open function +specifying the DB_RECOVER flag. The normal recovery process +will review the logs and database files to ensure that all changes +associated with committed transactions appear in the databases and that +all uncommitted transactions do not. +
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/transapp/term.html b/db/docs/ref/transapp/term.html new file mode 100644 index 000000000..d6d54a44d --- /dev/null +++ b/db/docs/ref/transapp/term.html @@ -0,0 +1,60 @@ + + + + + +Berkeley DB Reference Guide: Terminology + + + + + + +

Berkeley DB Reference Guide:
Transaction Protected Applications

PrevRefNext +
+

+

Terminology

+

Here are some definitions that will be helpful in understanding +transactions: +

+

Thread of control
Berkeley DB is indifferent to the type or style of threads being used by the +application, or, for that matter, if threads are being used at all, as +Berkeley DB supports multi-process access. In the Berkeley DB documentation, any +time we refer to a "thread of control", that can be read as a true +thread (one of many in an application's address space), or, a process. +

Free-threaded
A Berkeley DB handle that can be used by multiple threads simultaneously +without any application-level synchronization is called free-threaded. +

Transaction
A transaction is a one or more operations on one or more databases, that +should be treated as a single unit of work. For example, changes to a +set of databases, where either all of the changes must be applied to +the database(s) or none of them should. Applications specify when each +transaction starts, what database operations are included in it, and +when it ends. +

Transaction abort/commit
Every transaction ends by committing or aborting. +If a transaction commits, then Berkeley DB guarantees that any database +changes included in the transaction will never be lost, even after +system or application failure. If a transaction aborts, or is +uncommitted when the system or application fails, then the changes +involved will never appear in the database. +

System or application failure
This is the phrase that we will use to describe when something bad +happens near your data. It can be an application dumping core, being +interrupted by a signal, the disk filling up, or the entire system +crashing. In any case, for whatever reason, the application can no +longer make forward progress, and its databases were left in an unknown +state. +

Recovery
Whenever system or application failure occurs, the application must run +recovery. Recovery is what makes the database consistent, that is, the +recovery process includes review of log files and databases to ensure +that the changes from each committed transaction appear in the database, +and that no changes from an unfinished (or aborted) transaction do. +

Deadlock
Deadlock, in its simplest form, happens when one thread of control owns +resource A, but needs resource B, while another thread of control owns +resource B, but needs resource A. Neither thread of control can make +progress, and so one has to give up and release all of its resources, +at which time the remaining thread of control can make forward progress. +
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/transapp/throughput.html b/db/docs/ref/transapp/throughput.html new file mode 100644 index 000000000..734f3c7f9 --- /dev/null +++ b/db/docs/ref/transapp/throughput.html @@ -0,0 +1,117 @@ + + + + + +Berkeley DB Reference Guide: Transaction throughput + + + + + + + +

Berkeley DB Reference Guide:
Transaction Protected Applications

PrevRefNext +
+

+

Transaction throughput

+

Generally, the speed of a database system is measured by the transaction +throughput, expressed as the number of transactions per second. The two +gating factors for Berkeley DB performance in a transactional system are usually +the underlying database files and the log file. Both are factors because +they require disk I/O, which is slow relative to other system resources +like CPU. +

In the worst case scenario: +

    +
  • Database access is truly random and the database is too large to fit into +the cache, resulting in a single I/O per requested key/data pair. +
  • Both the database and the log are on a single disk. +
+

This means that for each transaction, Berkeley DB is potentially performing +several filesystem operations: +

    +
  • Disk seek to database file. +
  • Database file read. +
  • Disk seek to log file. +
  • Log file write. +
  • Flush log file information to disk. +
  • Disk seek to update log file metadata (e.g., inode). +
  • Log metadata write. +
  • Flush log file metadata to disk. +
+

There are a number of ways to increase transactional throughput, all of +which attempt to decrease the number of filesystem operations per +transaction: +

    +
  • Tune the size of the database cache. If the Berkeley DB key/data pairs used +during the transaction are found in the database cache, the seek and read +from the database are no longer necessary, resulting in two fewer +filesystem operations per transaction. To determine if your cache size +is too small, see Selecting a +cache size. +
  • Put the database and the log files on different disks. This allows reads +and writes to the log files and the database files to be performed +concurrently. +
  • Set the filesystem configuration so that file access and modification +times are not updated. Note, although the file access and modification +times are not used by Berkeley DB, this may affect other programs, so be +careful. +
  • Upgrade your hardware. When considering the hardware on which to run your +application, however, it is important to consider the entire system. The +controller and bus can have as much to do with the disk performance as +the disk itself. It is also important to remember that throughput is +rarely the limiting factor, and that disk seek times are normally the true +performance issue for Berkeley DB. +
  • Turn on the DB_TXN_NOSYNC flag. This changes the Berkeley DB behavior +so that the log files are not flushed when transactions are committed. +While this change will greatly increase your transaction throughput, it +means that transactions will exhibit the ACI (atomicity, consistency and +isolation) properties, but not D (durability). Database integrity will +be maintained but it is possible that some number of the most recently +committed transactions may be undone during recovery instead of being +redone. +
+

If you are bottlenecked on logging, the following test will help you +confirm that the number of transactions per second that your application +does is reasonable for the hardware on which you're running. Your test +program should repeatedly perform the following operations: +

    +
  • Seek to the beginning of a file. +
  • Write to the file. +
  • Flush the file write to disk. +
+

The number of times that you can perform these three operations per second +is a rough measure of the number of transactions per second of which the +hardware is capable. This test simulates the operations applied to the +log file. (As a simplifying assumption in this experiment, we assume that +the database files are either on a separate disk, or that they fit, with +some few exceptions, into the database cache.) We do not have to directly +simulate updating the log file directory information, as it will normally +be updated and flushed to disk as a result of flushing the log file write +to disk. +

Running this test program, where we write 256 bytes, for 1000 operations, +on reasonably standard commodity hardware (Pentium II CPU, SCSI disk), +returned the following results: +

% testfile -b256 -o1000
+running: 1000 ops
+Elapsed time: 16.641934 seconds
+1000 ops:   60.09 ops per second
+

Note that the number of bytes being written to the log as part of each +transaction can dramatically affect the transaction throughput. The +above test run used 256, which is a reasonable size log write. Your +log writes may be different. To determine your average log write size, +use the db_stat utility to display your log statistics. +

As a quick sanity check, for this particular disk, the average seek time +is 9.4 msec, and the average latency is 4.17 msec. That results in a +minimum requirement for a data transfer to the disk of 13.57 msec, or a +maximum of 74 transfers per second. This is close enough to the above 60 +operations per second (which wasn't done on a quiescent disk) that the +number is believable. +

An implementation of the above example test +program for IEEE/ANSI Std 1003.1 (POSIX) standard systems is included in the Berkeley DB +distribution. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/transapp/transapp.txt b/db/docs/ref/transapp/transapp.txt new file mode 100644 index 000000000..afd441c59 --- /dev/null +++ b/db/docs/ref/transapp/transapp.txt @@ -0,0 +1,492 @@ +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#define ENV_DIRECTORY "TXNAPP" + +void add_cat(DB_ENV *, DB *, char *, ...); +void add_color(DB_ENV *, DB *, char *, int); +void add_fruit(DB_ENV *, DB *, char *, char *); +void *checkpoint_thread(void *); +void log_archlist(DB_ENV *); +void *logfile_thread(void *); +void db_open(DB_ENV *, DB **, char *, int); +void env_dir_create(void); +void env_open(DB_ENV **); +void usage(void); + +int +main(int argc, char *argv[]) +{ + extern char *optarg; + extern int optind; + DB *db_cats, *db_color, *db_fruit; + DB_ENV *dbenv; + pthread_t ptid; + int ch; + + while ((ch = getopt(argc, argv, "")) != EOF) + switch (ch) { + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + env_dir_create(); + env_open(&dbenv); + + /* Start a checkpoint thread. */ + if ((errno = pthread_create( + &ptid, NULL, checkpoint_thread, (void *)dbenv)) != 0) { + fprintf(stderr, + "txnapp: failed spawning checkpoint thread: %s\n", + strerror(errno)); + exit (1); + } + + /* Start a logfile removal thread. */ + if ((errno = pthread_create( + &ptid, NULL, logfile_thread, (void *)dbenv)) != 0) { + fprintf(stderr, + "txnapp: failed spawning log file removal thread: %s\n", + strerror(errno)); + exit (1); + } + + /* Open database: Key is fruit class; Data is specific type. */ + db_open(dbenv, &db_fruit, "fruit", 0); + + /* Open database: Key is a color; Data is an integer. */ + db_open(dbenv, &db_color, "color", 0); + + /* + * Open database: + * Key is a name; Data is: company name, address, cat breeds. + */ + db_open(dbenv, &db_cats, "cats", 1); + + add_fruit(dbenv, db_fruit, "apple", "yellow delicious"); + + add_color(dbenv, db_color, "blue", 0); + add_color(dbenv, db_color, "blue", 3); + + add_cat(dbenv, db_cats, + "Amy Adams", + "Sleepycat Software", + "394 E. Riding Dr., Carlisle, MA 01741, USA", + "abyssinian", + "bengal", + "chartreaux", + NULL); + + return (0); +} + +void +env_dir_create() +{ + struct stat sb; + + /* + * If the directory exists, we're done. We do not further check + * the type of the file, DB will fail appropriately if it's the + * wrong type. + */ + if (stat(ENV_DIRECTORY, &sb) == 0) + return; + + /* Create the directory, read/write/access owner only. */ + if (mkdir(ENV_DIRECTORY, S_IRWXU) != 0) { + fprintf(stderr, + "txnapp: mkdir: %s: %s\n", ENV_DIRECTORY, strerror(errno)); + exit (1); + } +} + +void +env_open(DB_ENV **dbenvp) +{ + DB_ENV *dbenv; + int ret; + + /* Create the environment handle. */ + if ((ret = db_env_create(&dbenv, 0)) != 0) { + fprintf(stderr, + "txnapp: db_env_create: %s\n", db_strerror(ret)); + exit (1); + } + + /* Set up error handling. */ + dbenv->set_errpfx(dbenv, "txnapp"); + + /* Do deadlock detection internally. */ + if ((ret = dbenv->set_lk_detect(dbenv, DB_LOCK_DEFAULT)) != 0) { + dbenv->err(dbenv, ret, "set_lk_detect: DB_LOCK_DEFAULT"); + exit (1); + } + + /* + * Open a transactional environment: + * create if it doesn't exist + * free-threaded handle + * run recovery + * read/write owner only + */ + if ((ret = dbenv->open(dbenv, ENV_DIRECTORY, + DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | + DB_INIT_MPOOL | DB_INIT_TXN | DB_RECOVER | DB_THREAD, + S_IRUSR | S_IWUSR)) != 0) { + dbenv->err(dbenv, ret, "dbenv->open: %s", ENV_DIRECTORY); + exit (1); + } + + *dbenvp = dbenv; +} + +void * +checkpoint_thread(void *arg) +{ + DB_ENV *dbenv; + int ret; + + dbenv = arg; + dbenv->errx(dbenv, "Checkpoint thread: %lu", (u_long)pthread_self()); + + /* Checkpoint once a minute. */ + for (;; sleep(60)) + switch (ret = txn_checkpoint(dbenv, 0, 0, 0)) { + case 0: + case DB_INCOMPLETE: + break; + default: + dbenv->err(dbenv, ret, "checkpoint thread"); + exit (1); + } + + /* NOTREACHED */ +} + +void * +logfile_thread(void *arg) +{ + DB_ENV *dbenv; + int ret; + char **begin, **list; + + dbenv = arg; + dbenv->errx(dbenv, + "Log file removal thread: %lu", (u_long)pthread_self()); + + /* Check once every 5 minutes. */ + for (;; sleep(300)) { + /* Get the list of log files. */ + if ((ret = log_archive(dbenv, &list, DB_ARCH_ABS, NULL)) != 0) { + dbenv->err(dbenv, ret, "log_archive"); + exit (1); + } + + /* Remove the log files. */ + if (list != NULL) { + for (begin = list; *list != NULL; ++list) + if ((ret = remove(*list)) != 0) { + dbenv->err(dbenv, + ret, "remove %s", *list); + exit (1); + } + free (begin); + } + } + /* NOTREACHED */ +} + +void +log_archlist(DB_ENV *dbenv) +{ + int ret; + char **begin, **list; + + /* Get the list of database files. */ + if ((ret = log_archive(dbenv, + &list, DB_ARCH_ABS | DB_ARCH_DATA, NULL)) != 0) { + dbenv->err(dbenv, ret, "log_archive: DB_ARCH_DATA"); + exit (1); + } + if (list != NULL) { + for (begin = list; *list != NULL; ++list) + printf("database file: %s\n", *list); + free (begin); + } + + /* Get the list of log files. */ + if ((ret = log_archive(dbenv, + &list, DB_ARCH_ABS | DB_ARCH_LOG, NULL)) != 0) { + dbenv->err(dbenv, ret, "log_archive: DB_ARCH_LOG"); + exit (1); + } + if (list != NULL) { + for (begin = list; *list != NULL; ++list) + printf("log file: %s\n", *list); + free (begin); + } +} + +void +db_open(DB_ENV *dbenv, DB **dbp, char *name, int dups) +{ + DB *db; + int ret; + + /* Create the database handle. */ + if ((ret = db_create(&db, dbenv, 0)) != 0) { + dbenv->err(dbenv, ret, "db_create"); + exit (1); + } + + /* Optionally, turn on duplicate data items. */ + if (dups && (ret = db->set_flags(db, DB_DUP)) != 0) { + dbenv->err(dbenv, ret, "db->set_flags: DB_DUP"); + exit (1); + } + + /* + * Open a database in the environment: + * create if it doesn't exist + * free-threaded handle + * read/write owner only + */ + if ((ret = db->open(db, name, NULL, + DB_BTREE, DB_CREATE | DB_THREAD, S_IRUSR | S_IWUSR)) != 0) { + dbenv->err(dbenv, ret, "db->open: %s", name); + exit (1); + } + + *dbp = db; +} + +void +add_fruit(DB_ENV *dbenv, DB *db, char *fruit, char *name) +{ + DBT key, data; + DB_TXN *tid; + int ret; + + /* Initialization. */ + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = fruit; + key.size = strlen(fruit); + data.data = name; + data.size = strlen(name); + + for (;;) { + /* Begin the transaction. */ + if ((ret = txn_begin(dbenv, NULL, &tid, 0)) != 0) { + dbenv->err(dbenv, ret, "txn_begin"); + exit (1); + } + + /* Store the value. */ + switch (ret = db->put(db, tid, &key, &data, 0)) { + case 0: + /* Success: commit the change. */ + if ((ret = txn_commit(tid, 0)) != 0) { + dbenv->err(dbenv, ret, "txn_commit"); + exit (1); + } + return; + case DB_LOCK_DEADLOCK: + /* Deadlock: retry the operation. */ + if ((ret = txn_abort(tid)) != 0) { + dbenv->err(dbenv, ret, "txn_abort"); + exit (1); + } + break; + default: + /* Error: run recovery. */ + dbenv->err(dbenv, ret, "dbc->put: %s/%s", fruit, name); + exit (1); + } + } +} + +void +add_color(DB_ENV *dbenv, DB *dbp, char *color, int increment) +{ + DBT key, data; + DB_TXN *tid; + int original, ret; + char buf[64]; + + /* Initialization. */ + memset(&key, 0, sizeof(key)); + key.data = color; + key.size = strlen(color); + memset(&data, 0, sizeof(data)); + data.flags = DB_DBT_MALLOC; + + for (;;) { + /* Begin the transaction. */ + if ((ret = txn_begin(dbenv, NULL, &tid, 0)) != 0) { + dbenv->err(dbenv, ret, "txn_begin"); + exit (1); + } + + /* + * Get the key. If it exists, we increment the value. If it + * doesn't exist, we create it. + */ + switch (ret = dbp->get(dbp, tid, &key, &data, 0)) { + case 0: + original = atoi(data.data); + break; + case DB_LOCK_DEADLOCK: + /* Deadlock: retry the operation. */ + if ((ret = txn_abort(tid)) != 0) { + dbenv->err(dbenv, ret, "txn_abort"); + exit (1); + } + continue; + case DB_NOTFOUND: + original = 0; + break; + default: + /* Error: run recovery. */ + dbenv->err( + dbenv, ret, "dbc->get: %s/%d", color, increment); + exit (1); + } + if (data.data != NULL) + free(data.data); + + /* Create the new data item. */ + (void)snprintf(buf, sizeof(buf), "%d", original + increment); + data.data = buf; + data.size = strlen(buf) + 1; + + /* Store the new value. */ + switch (ret = dbp->put(dbp, tid, &key, &data, 0)) { + case 0: + /* Success: commit the change. */ + if ((ret = txn_commit(tid, 0)) != 0) { + dbenv->err(dbenv, ret, "txn_commit"); + exit (1); + } + return; + case DB_LOCK_DEADLOCK: + /* Deadlock: retry the operation. */ + if ((ret = txn_abort(tid)) != 0) { + dbenv->err(dbenv, ret, "txn_abort"); + exit (1); + } + break; + default: + /* Error: run recovery. */ + dbenv->err( + dbenv, ret, "dbc->put: %s/%d", color, increment); + exit (1); + } + } +} + +void +add_cat(DB_ENV *dbenv, DB *db, char *name, ...) +{ + va_list ap; + DBC *dbc; + DBT key, data; + DB_TXN *tid; + int ret; + char *s; + + /* Initialization. */ + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = name; + key.size = strlen(name); + +retry: /* Begin the transaction. */ + if ((ret = txn_begin(dbenv, NULL, &tid, 0)) != 0) { + dbenv->err(dbenv, ret, "txn_begin"); + exit (1); + } + + /* Delete any previously existing item. */ + switch (ret = db->del(db, tid, &key, 0)) { + case 0: + case DB_NOTFOUND: + break; + case DB_LOCK_DEADLOCK: + /* Deadlock: retry the operation. */ + if ((ret = txn_abort(tid)) != 0) { + dbenv->err(dbenv, ret, "txn_abort"); + exit (1); + } + goto retry; + default: + dbenv->err(dbenv, ret, "db->del: %s", name); + exit (1); + } + + /* Create a cursor. */ + if ((ret = db->cursor(db, tid, &dbc, 0)) != 0) { + dbenv->err(dbenv, ret, "db->cursor"); + exit (1); + } + + /* Append the items, in order. */ + va_start(ap, name); + while ((s = va_arg(ap, char *)) != NULL) { + data.data = s; + data.size = strlen(s); + switch (ret = dbc->c_put(dbc, &key, &data, DB_KEYLAST)) { + case 0: + break; + case DB_LOCK_DEADLOCK: + va_end(ap); + + /* Deadlock: retry the operation. */ + if ((ret = dbc->c_close(dbc)) != 0) { + dbenv->err( + dbenv, ret, "dbc->c_close"); + exit (1); + } + if ((ret = txn_abort(tid)) != 0) { + dbenv->err(dbenv, ret, "txn_abort"); + exit (1); + } + goto retry; + default: + /* Error: run recovery. */ + dbenv->err(dbenv, ret, "dbc->put: %s/%s", name, s); + exit (1); + } + } + va_end(ap); + + /* Success: commit the change. */ + if ((ret = dbc->c_close(dbc)) != 0) { + dbenv->err(dbenv, ret, "dbc->c_close"); + exit (1); + } + if ((ret = txn_commit(tid, 0)) != 0) { + dbenv->err(dbenv, ret, "txn_commit"); + exit (1); + } +} + +void +usage() +{ + (void)fprintf(stderr, "usage: txnapp\n"); + exit(1); +} diff --git a/db/docs/ref/transapp/why.html b/db/docs/ref/transapp/why.html new file mode 100644 index 000000000..8fee13082 --- /dev/null +++ b/db/docs/ref/transapp/why.html @@ -0,0 +1,49 @@ + + + + + +Berkeley DB Reference Guide: Why transactions? + + + + + + +

Berkeley DB Reference Guide:
Transaction Protected Applications

PrevRefNext +
+

+

Why transactions?

+

Perhaps the first question to answer is "Why transactions?" There are +a number of reasons for including transactional support in your +applications. The most common ones are: +

+

Recoverability
Applications often need to ensure that, no matter how the system or +application fails, previously saved data is available the next time the +application runs. +

Deadlock avoidance
When multiple threads of control change the database at the same time, +there is usually the possibility of deadlock, that is, where each of +the threads of control owns a resource another thread wants, and so no +thread is able to make forward progress, all waiting for a resource. +Deadlocks are resolved by having one of the operations involved release +the resources it controls so the other operations can proceed. (The +operation releasing its resources usually just tries again later.) +Transactions are necessary so that any changes that were already made +to the database can be undone as part of releasing the held resources. +

Atomicity
Applications often need to make multiple changes to one or more +databases, but want to ensure that either all of the changes happen, or +none of them happen. Transactions guarantee that a group of changes +are atomic, that is, if the application or system fails, either all of +the changes to the databases will appear when the application next runs, +or none of them. +

Repeatable reads
Applications sometimes need to ensure that, while doing a group of +operations on a database, the value returned as a result of a database +retrieval doesn't change, that is, if you retrieve the same key more +than once, the data item will be the same each time. Transactions +guarantee this behavior. +
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/transapp/writetest.txt b/db/docs/ref/transapp/writetest.txt new file mode 100644 index 000000000..b86c1b6ce --- /dev/null +++ b/db/docs/ref/transapp/writetest.txt @@ -0,0 +1,100 @@ +/* + * writetest -- + * + * $Id: writetest.txt,v 10.3 1999/11/19 17:21:06 bostic Exp $ + */ +#include + +#include +#include +#include +#include +#include +#include +#include + +void usage __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + struct timeval start_time, end_time; + long usecs; + int bytes, ch, cnt, fd, ops; + char *fname, buf[100 * 1024]; + + bytes = 256; + fname = "testfile"; + ops = 1000; + while ((ch = getopt(argc, argv, "b:f:o:")) != EOF) + switch (ch) { + case 'b': + if ((bytes = atoi(optarg)) > sizeof(buf)) { + fprintf(stderr, + "max -b option %d\n", sizeof(buf)); + exit (1); + } + break; + case 'f': + fname = optarg; + break; + case 'o': + if ((ops = atoi(optarg)) <= 0) { + fprintf(stderr, "illegal -o option value\n"); + exit (1); + } + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + (void)unlink(fname); + if ((fd = open(fname, O_RDWR | O_CREAT, 0666)) == -1) { + perror(fname); + exit (1); + } + + memset(buf, 0, bytes); + + printf("running: %d ops\n", ops); + + (void)gettimeofday(&start_time, NULL); + for (cnt = 0; cnt < ops; ++cnt) { + if (write(fd, buf, bytes) != bytes) { + fprintf(stderr, "write: %s\n", strerror(errno)); + exit (1); + } + if (lseek(fd, (off_t)0, SEEK_SET) == -1) { + fprintf(stderr, "lseek: %s\n", strerror(errno)); + exit (1); + } + if (fsync(fd) != 0) { + fprintf(stderr, "fsync: %s\n", strerror(errno)); + exit (1); + } + } + (void)gettimeofday(&end_time, NULL); + + usecs = (end_time.tv_sec - start_time.tv_sec) * 1000000 + + end_time.tv_usec - start_time.tv_usec; + printf("Elapsed time: %ld.%06ld seconds\n", + usecs / 1000000, usecs % 1000000); + printf("%d ops: %7.2f ops per second\n", + ops, (float)1000000 * ops/usecs); + + (void)unlink(fname); + exit (0); +} + +void +usage() +{ + (void)fprintf(stderr, + "usage: testfile [-b bytes] [-f file] [-o ops]\n"); + exit(1); +} diff --git a/db/docs/ref/txn/config.html b/db/docs/ref/txn/config.html new file mode 100644 index 000000000..beb73859f --- /dev/null +++ b/db/docs/ref/txn/config.html @@ -0,0 +1,37 @@ + + + + + +Berkeley DB Reference Guide: Configuring transactions + + + + + + + +

Berkeley DB Reference Guide:
Transaction Subsystem

PrevRefNext +
+

+

Configuring transactions

+

There is only a single parameter used in configuring transactions, the +DB_TXN_NOSYNC flag. Setting the DB_TXN_NOSYNC flag to +DBENV->set_flags when opening a transaction region changes the +behavior of transactions not to synchronously flush the log during +transaction commit. +

This change will significantly increase application transactional +throughput. However, it means that while transactions will continue to +exhibit the ACI (atomicity, consistency and isolation) properties, they +will not have D (durability). Database integrity will be maintained but +it is possible that some number of the most recently committed +transactions may be undone during recovery instead of being redone. +

The application may also limit the number of simultaneous outstanding +transactions supported by the environment by calling the +DBENV->set_tx_max function. When this number is met, additional calls to +txn_begin will fail until some active transactions complete. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/txn/intro.html b/db/docs/ref/txn/intro.html new file mode 100644 index 000000000..557481509 --- /dev/null +++ b/db/docs/ref/txn/intro.html @@ -0,0 +1,86 @@ + + + + + +Berkeley DB Reference Guide: Berkeley DB and transactions + + + + + + + +

Berkeley DB Reference Guide:
Transaction Subsystem

PrevRefNext +
+

+

Berkeley DB and transactions

+

The transaction subsystem makes operations atomic, consistent, isolated, +and durable in the face of system and application failures. The subsystem +requires that the data be properly logged and locked in order to attain +these properties. Berkeley DB contains all the components necessary to +transaction-protect the Berkeley DB access methods and other forms of data may +be protected if they are logged and locked appropriately. +

The transaction subsystem is created, initialized, and opened by calls to +DBENV->open with the DB_INIT_TXN flag specified. Note that +enabling transactions automatically enables logging, but does not enable +locking, as a single thread of control that needed atomicity and +recoverability would not require it. +

The txn_begin function starts a transaction, returning an opaque +handle to a transaction. If the parent parameter to txn_begin is +non-NULL, then the new transaction is a child of the designated parent +transaction. +

The txn_abort function ends the designated transaction and causes +all updates performed by the transaction to be undone. The end result is +that the database is left in a state identical to the state that existed +prior to the txn_begin. If the aborting transaction has any child +transactions associated with it (even ones that have already been +committed), they are also aborted. Any transactions that are unresolved +(i.e., neither committed nor aborted) when the application or system fails +are aborted during recovery. +

The txn_commit function ends the designated transaction and makes +all the updates performed by the transaction permanent, even in the face +of application or system failure. If this is a parent transaction +committing, then all child transactions that individually committed or +had not been resolved are also committed. +

Transactions are identified by 32-bit unsigned integers. The ID +associated with any transaction can be obtained using the txn_id +function. If an application is maintaining information outside of Berkeley DB +that it wishes to transaction-protect, it should use this transaction ID +as the locking ID. +

The txn_checkpoint function causes a transaction checkpoint. A +checkpoint is performed relative to a specific log sequence number (LSN), +referred to as the checkpoint LSN. When a checkpoint completes +successfully, it means that all data buffers whose updates are described +by LSNs less than the checkpoint LSN have been written to disk. This, in +turn, means that the log records less than the checkpoint LSN are no +longer necessary for normal recovery (although they would be required for +catastrophic recovery should the database files be lost) and all log files +containing only records prior to the checkpoint LSN may be safely archived +and removed. +

It is possible that in order to complete a transaction checkpoint, it will +be necessary to write a buffer that is currently in use (i.e., is actively +being read or written by some transaction). In this case, +txn_checkpoint will not be able to write the buffer, as doing so +might cause an inconsistent version of the page to be written to disk, +and instead of completing successfully will return with an error code of +DB_INCOMPLETE. In such cases, the checkpoint can simply be +retried after a short delay. +

The interval between successive checkpoints is directly proportional to +the length of time required to run normal recovery. If the interval +between checkpoints is long, then a large number of updates that are +recorded in the log may not yet be written to disk and recovery may take +longer to run. If the interval is short, then data is being written to +disk more frequently, but the recovery time will be shorter. Often, the +checkpoint interval will be tuned for each specific application. +

The txn_stat function returns information about the status of +the transaction subsystem. It is the programmatic interface used by the +db_stat utility. +

The transaction system is closed by a call to DBENV->close. +

Finally, the entire transaction system may be removed using the +DBENV->remove interface. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/txn/limits.html b/db/docs/ref/txn/limits.html new file mode 100644 index 000000000..0ed978066 --- /dev/null +++ b/db/docs/ref/txn/limits.html @@ -0,0 +1,66 @@ + + + + + +Berkeley DB Reference Guide: Transaction limits + + + + + + + +

Berkeley DB Reference Guide:
Transaction Subsystem

PrevRefNext +
+

+

Transaction limits

+

Transaction IDs

+

Transactions are identified uniquely by 32-bit unsigned integers. The +high-order bit of the transaction ID is reserved (and defined to be 1) +resulting in just over two billion unique transaction IDs. Each time +that recovery is run, the beginning transaction ID is reset with new +transactions being numbered starting from 1. This means that recovery +must be run at least once every two billion transactions. +

It is possible that some environments may need to be aware of this +limitation. Consider an application performing 600 transactions a second +for 15 hours a day. The transaction ID space will run out in roughly 66 +days: +

2^31 / (600 * 15 * 60 * 60) = 66
+

Doing only 100 transactions a second exhausts the transaction ID space +in roughly one year. +

The transaction ID name space is initialized each time +a database environment is created or recovered. If you +reach the end of the transaction ID name space, it must +be handled as if an application or system failure had +occurred. The most recently allocated transaction ID +is the st_last_txnid value in the transaction +statistics information, and is displayed by the +db_stat utility. +

Cursors

+

When using transactions, cursors are localized to a single transaction. +That is, a cursor may not span transactions and must be opened and +closed within a single transaction. In addition, intermingling +transaction-protected cursor operations and non-transaction-protected +cursor operations on the same database in a single thread of control is +practically guaranteed to deadlock as the locks obtained for transactions +and non-transactions can conflict. +

Multiple Threads of Control

+

Since transactions must hold all their locks until commit, a single +transaction may accumulate a large number of long-term locks during its +lifetime. As a result, when two concurrently running transactions access +the same database, there is strong potential for conflict. While Berkeley +DB allows an application to have multiple outstanding transactions active +within a single thread of control, great care must be taken to ensure that +the transactions do not interfere with each other (e.g., attempt to obtain +conflicting locks on the same data). If two concurrently active +transactions in the same thread of control do encounter a lock conflict, +the thread of control will deadlock in such a manner that the deadlock +detector will be unable to resolve the problem. In this case, there is +no true deadlock, but because the transaction on which a transaction is +waiting is in the same thread of control, no forward progress can be made. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/txn/nested.html b/db/docs/ref/txn/nested.html new file mode 100644 index 000000000..a635abf52 --- /dev/null +++ b/db/docs/ref/txn/nested.html @@ -0,0 +1,66 @@ + + + + + +Berkeley DB Reference Guide: Nested transactions + + + + + + + +

Berkeley DB Reference Guide:
Transaction Subsystem

PrevRefNext +
+

+

Nested transactions

+

Berkeley DB provides support for nested transactions. Nested transactions +allow an application to decompose a large or long-running transaction +into smaller units that may be independently aborted. +

Normally, when beginning a transaction, the application will pass a NULL +value for the parent argument to txn_begin. If, however, the +parent argument is a DB_TXN handle, then the newly created +transaction will be treated as a nested transaction within the parent. +Transactions may nest arbitrarily deeply. For the purposes of this +discussion, transactions created with a parent identifier will be called +child transactions. +

Once a transaction becomes a parent, as long as any of its child +transactions are unresolved (i.e., they have neither committed nor +aborted), the parent may not issue any Berkeley DB calls except to begin more +child transactions or to commit or abort. That is, it may not issue +any access method or cursor calls. Once all of a parent's children have +committed or aborted, the parent may again request operations on its +own behalf. +

The semantics of nested transactions are as follows. When a child +transaction is begun, it inherits all the locks of its parent. This +means that the child will never block waiting on a lock held by its +parent. However, if a parent attempts to obtain locks after they have +begun a child, the parental locks can conflict with those held by a +child. Furthermore, locks held by two different children will also +conflict. To make this concrete, consider the following set of +transactions and lock acquisitions. +

Transaction T1 is the parent transaction. It acquires an exclusive lock +on item A and then begins two child transactions, C1 and C2. C1 also +wishes to acquire a write lock on A; this succeeds. Now, let's say that +C1 acquires a write lock on B. If C2 now attempts to obtain a lock on +B, it will block. However, let's now assume that C1 commits. Its locks +are anti-inherited, which means they are now given to T1. At this +point, either T1 or C2 is allowed to acquire a lock on B. If, however, +transaction T1 aborts, then its locks are released. Future requests by +T1 or C2 will also succeed, but they will be obtaining new locks as +opposed to piggy-backing off a lock already held by T1. +

Child transactions are entirely subservient to their parent transaction. +They may abort, undoing their operations regardless of the eventual fate +of the parent. However, even if a child transaction commits, if its +parent transaction is eventually aborted, the child's changes are undone +and the child's transaction is effectively aborted. Any child +transactions that are not yet resolved when the parent commits or aborts +are resolved based on the parent's resolution, committing if the parent +commits and aborting if the parent aborts. Any child transactions that +are not yet resolved when the parent prepares are also prepared. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/txn/other.html b/db/docs/ref/txn/other.html new file mode 100644 index 000000000..e4678c2cb --- /dev/null +++ b/db/docs/ref/txn/other.html @@ -0,0 +1,67 @@ + + + + + +Berkeley DB Reference Guide: Transactions and non-Berkeley DB applications + + + + + + +

Berkeley DB Reference Guide:
Transaction Subsystem

PrevRefNext +
+

+

Transactions and non-Berkeley DB applications

+

It is possible to use the locking, logging and transaction subsystems +of Berkeley DB to provide transaction semantics on objects other than those +described by the Berkeley DB access methods. In these cases, the application +will need more explicit customization of the subsystems as well as the +development of appropriate data-structure-specific recovery functions. +

For example, consider an application that provides transaction semantics +on data stored in plain UNIX files accessed using the POSIX read and write +system calls. The operations for which transaction protection is desired +are bracketed by calls to txn_begin and txn_commit. +

Before data are referenced, the application must make a call to the lock +manager, lock_get, for a lock of the appropriate type (e.g., +read) on the object being locked. The object might be a page in the file, +a byte, a range of bytes, or some key. It is up to the application to +ensure that appropriate locks are acquired. Before a write is performed, +the application should acquire a write lock on the object, by making an +appropriate call to the lock manager, lock_get. Then, the +application should make a call to the log manager, log_put, to +record enough information to redo the operation in case of failure after +commit and to undo the operation in case of abort. +

It is important, when designing applications that will use the log +subsystem, to remember that the application is responsible for providing +any necessary structure to the log record. For example, the application +must understand what part of the log record is an operation code, what +part identifies the file being modified, what part is redo information, +and what part is undo information. +

After the log message is written, the application may issue the write +system call. After all requests are issued, the application may call +txn_commit. When txn_commit returns, the caller is +guaranteed that all necessary log writes have been written to disk. +

At any time, the application may call txn_abort, which will result +in restoration of the database to a consistent pre-transaction state. +(The application may specify its own recovery function for this purpose +using the DBENV->set_tx_recover function. The recovery function must be +able to either re-apply or undo the update depending on the context, for +each different type of log record.) +

If the application should crash, the recovery process uses the log to +restore the database to a consistent state. +

The txn_prepare function provides the core functionality to +implement distributed transactions, but it does not manage the +notification of distributed transaction managers. The caller is +responsible for issuing txn_prepare calls to all sites +participating in the transaction. If all responses are positive, the +caller can issue a txn_commit. If any of the responses are +negative, the caller should issue a txn_abort. In general, the +txn_prepare call requires that the transaction log be flushed to +disk. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.2.0/convert.html b/db/docs/ref/upgrade.2.0/convert.html new file mode 100644 index 000000000..ad5685368 --- /dev/null +++ b/db/docs/ref/upgrade.2.0/convert.html @@ -0,0 +1,74 @@ + + + + + +Berkeley DB Reference Guide: Release 2.0: converting applications + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 2.0: converting applications

+

Mapping the Berkeley DB 1.85 functionality into Berkeley DB version 2 is almost always +simple. The manual page DB->open replaces the Berkeley DB 1.85 manual +pages dbopen(3), btree(3), hash(3) and +recno(3). You should be able to convert each 1.85 function +call into a Berkeley DB version 2 function call using just the DB->open +documentation. +

Some guidelines and things to watch out for: +

    +

  1. Most access method functions have exactly the same semantics as in Berkeley DB +1.85, although the arguments to the functions have changed in some cases. +To get your code to compile, the most common change is to add the +transaction ID as an argument (NULL, since Berkeley DB 1.85 did not support +transactions.) +

  2. You must always initialize DBT structures to zero before using them with +any Berkeley DB version 2 function. (They do not normally have to be +reinitialized each time, only when they are first allocated. Do this by +declaring the DBT structure external or static, or by calling the C +library routine bzero(3) or memset(3).) +

  3. The error returns are completely different in the two versions. In Berkeley DB +1.85, < 0 meant an error, and > 0 meant a minor Berkeley DB exception. +In Berkeley DB 2.0, > 0 means an error (the Berkeley DB version 2 functions +return errno on error) and < 0 means a Berkeley DB exception. +See Error Returns to Applications +for more information. +

  4. The Berkeley DB 1.85 DB->seq function has been replaced by cursors in Berkeley DB +version 2. The semantics are approximately the same, but cursors require +the creation of an extra object (the DBC object), which is then used to +access the database. +

    Specifically, the partial key match and range search functionality of the +R_CURSOR flag in DB->seq has been replaced by the +DB_SET_RANGE flag in DBcursor->c_get. +

  5. In version 2 of the Berkeley DB library, additions or deletions into Recno +(fixed and variable-length record) databases no longer automatically +logically renumber all records after the add/delete point, by default. +The default behavior is that deleting records does not cause subsequent +records to be renumbered, and it is an error to attempt to add new records +between records already in the database. Applications wanting the +historic Recno access method semantics should call the +DB->set_flags function with the DB_RENUMBER flag. +

  6. Opening a database in Berkeley DB version 2 is a much heavier-weight operation +than it was in Berkeley DB 1.85. Therefore, if your historic applications were +written to open a database, perform a single operation, and close the +database, you may observe performance degradation. In most cases, this +is due to the expense of creating the environment upon each open. While +we encourage restructuring your application to avoid repeated opens and +closes, you can probably recover most of the lost performance by simply +using a persistent environment across invocations. +
+

While simply converting Berkeley DB 1.85 function calls to Berkeley DB version 2 +function calls will work, we recommend that you eventually reconsider your +application's interface to the Berkeley DB database library in light of the +additional functionality supplied by Berkeley DB version 2, as it is likely to +result in enhanced application performance. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.2.0/disk.html b/db/docs/ref/upgrade.2.0/disk.html new file mode 100644 index 000000000..8e7aeabc7 --- /dev/null +++ b/db/docs/ref/upgrade.2.0/disk.html @@ -0,0 +1,27 @@ + + + + + +Berkeley DB Reference Guide: Release 2.0: upgrade requirements + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 2.0: upgrade requirements

+

You will need to upgrade your on-disk databases, as all access method +database formats changed in the Berkeley DB 2.0 release. For information on +converting databases from Berkeley DB 1.85 to Berkeley DB 2.0, see the +db_dump185 and db_load documentation. As database +environments did not exist prior to the 2.0 release, there is no +question of upgrading existing database environments. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.2.0/intro.html b/db/docs/ref/upgrade.2.0/intro.html new file mode 100644 index 000000000..1bebc81cb --- /dev/null +++ b/db/docs/ref/upgrade.2.0/intro.html @@ -0,0 +1,32 @@ + + + + + +Berkeley DB Reference Guide: Release 2.0: introduction + + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 2.0: introduction

+

The following pages describe how to upgrade applications coded against +the Berkeley DB 1.85 and 1.86 release interfaces to the Berkeley DB 2.0 release +interfaces. They do not describe how to upgrade to the current Berkeley DB +release interfaces. +

It is not difficult to upgrade Berkeley DB 1.85 applications to use the Berkeley DB +version 2 library. The Berkeley DB version 2 library has a Berkeley DB 1.85 +compatibility API, which you can use by either recompiling your +application's source code or by relinking its object files against the +version 2 library. The underlying databases must be converted, however, +as the Berkeley DB version 2 library has a different underlying database format. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.2.0/system.html b/db/docs/ref/upgrade.2.0/system.html new file mode 100644 index 000000000..60a11c9bd --- /dev/null +++ b/db/docs/ref/upgrade.2.0/system.html @@ -0,0 +1,84 @@ + + + + + +Berkeley DB Reference Guide: Release 2.0: system integration + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 2.0: system integration

+

    +

  1. It is possible to maintain both the Berkeley DB 1.85 and Berkeley DB version 2 +libraries on your system. However, the db.h include file that +was distributed with Berkeley DB 1.85 is not compatible with the db.h +file distributed with Berkeley DB version 2, so you will have to install them +in different locations. In addition, both the Berkeley DB 1.85 and Berkeley DB +version 2 libraries are named libdb.a. +

    As the Berkeley DB 1.85 library did not have an installation target in the +Makefile, there's no way to know exactly where it was installed on the +system. In addition, many vendors included it in the C library instead +of as a separate library, and so it may actually be part of libc and the +db.h include file may be installed in /usr/include. +

    For these reasons, the simplest way to maintain both libraries is to +install Berkeley DB version 2 in a completely separate area of your system. +The Berkeley DB version 2 installation process allows you to install into a +standalone directory hierarchy on your system. See the +Building for UNIX systems +documentation for more information and instructions on how to install the +Berkeley DB version 2 library, include files and documentation into specific +locations. +

  2. Alternatively, you can replace Berkeley DB 1.85 on your system with Berkeley DB +version 2. In this case, you'll probably want to install Berkeley DB version +2 in the normal place on your system, wherever that may be, and delete +the Berkeley DB 1.85 include files, manual pages and libraries. +

    To replace 1.85 with version 2, you must either convert your 1.85 +applications to use the version 2 API or build the Berkeley DB version 2 library +to include Berkeley DB 1.85 interface compatibility code. Whether converting +your applications to use the version 2 interface or using the version 1.85 +compatibility API, you will need to recompile or relink your 1.85 +applications, and you must convert any persistent application databases +to the Berkeley DB version 2 database formats. +

    If you want to recompile your Berkeley DB 1.85 applications, you will have to +change them to include the file db_185.h instead of +db.h. (The db_185.h file is automatically installed +during the Berkeley DB version 2 installation process.) You can then recompile +the applications, linking them against the Berkeley DB version 2 library. +

    For more information on compiling the Berkeley DB 1.85 compatibility code into +the Berkeley DB version 2 library, see Building for UNIX platforms. +

    For more information on converting databases from the Berkeley DB 1.85 formats +to the Berkeley DB version 2 formats, see the db_dump185 and +db_load documentation. +

  3. Finally, although we certainly do not recommend it, it is possible to +load both Berkeley DB 1.85 and Berkeley DB version 2 into the same library. +Similarly, it is possible to use both Berkeley DB 1.85 and Berkeley DB version 2 +within a single application, although it is not possible to use them from +within the same file. +

    The name space in Berkeley DB version 2 has been changed from that of previous +Berkeley DB versions, notably version 1.85, for portability and consistency +reasons. The only name collisions in the two libraries are the names used +by the historic dbm, ndbm and hsearch interfaces, +and the Berkeley DB 1.85 compatibility interfaces in the Berkeley DB version 2 +library. +

    If you are loading both Berkeley DB 1.85 and Berkeley DB version 2 into a single +library, remove the historic interfaces from one of the two library +builds, and configure the Berkeley DB version 2 build to not include the Berkeley DB +1.85 compatibility API, otherwise you could have collisions and undefined +behavior. This can be done by editing the library Makefiles and +reconfiguring and rebuilding the Berkeley DB version 2 library. Obviously, if +you use the historic interfaces, you will get the version in the library +from which you did not remove them. Similarly, you will not be able to +access Berkeley DB version 2 files using the Berkeley DB 1.85 compatibility interface, +since you have removed that from the library as well. +

+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.2.0/toc.html b/db/docs/ref/upgrade.2.0/toc.html new file mode 100644 index 000000000..68502be59 --- /dev/null +++ b/db/docs/ref/upgrade.2.0/toc.html @@ -0,0 +1,20 @@ + + + + + +Berkeley DB: Upgrading Berkeley DB 1.XX applications to Berkeley DB 2.0 + + + + +

Upgrading Berkeley DB 1.XX applications to Berkeley DB 2.0

+
    +
  1. Release 2.0: introduction +
  2. Release 2.0: system integration +
  3. Release 2.0: converting applications +
  4. Release 2.0: upgrade requirements +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.0/close.html b/db/docs/ref/upgrade.3.0/close.html new file mode 100644 index 000000000..620e4babb --- /dev/null +++ b/db/docs/ref/upgrade.3.0/close.html @@ -0,0 +1,34 @@ + + + + + +Berkeley DB Reference Guide: Release 3.0: DB->sync and DB->close + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.0: DB->sync and DB->close

+

In previous Berkeley DB releases, the DB->close and DB->sync functions +discarded any return of DB_INCOMPLETE from the underlying buffer +pool interfaces, and returned success to its caller. (The +DB_INCOMPLETE error will be returned if the buffer pool functions +are unable to flush all of the database's dirty blocks from the pool. +This often happens if another thread is reading or writing the database's +pages in the pool.) +

In the 3.X release, DB->sync and DB->close will return +DB_INCOMPLETE to the application. The best solution is to not +call DB->sync and specify the DB_NOSYNC flag to the +DB->close function when multiple threads are expected to be accessing the +database. Alternatively, the caller can ignore any error return of +DB_INCOMPLETE. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.0/cxx.html b/db/docs/ref/upgrade.3.0/cxx.html new file mode 100644 index 000000000..7f6c1ab7e --- /dev/null +++ b/db/docs/ref/upgrade.3.0/cxx.html @@ -0,0 +1,31 @@ + + + + + +Berkeley DB Reference Guide: Release 3.0: additional C++ changes + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.0: additional C++ changes

+

The Db::set_error_model method is gone. The way to change the C++ API to +return errors rather than throw exceptions is via a flag on the DbEnv or +Db constructor. For example: +

int dberr;
+DbEnv *dbenv = new DbEnv(DB_CXX_NO_EXCEPTIONS);
+

creates an environment that will never throw exceptions, and method +returns should be checked instead. +

There are a number of smaller changes to the API that bring the C, C++ +and Java APIs much closer in terms of functionality and usage. Please +refer to the pages for upgrading C applications for further details. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.0/db.html b/db/docs/ref/upgrade.3.0/db.html new file mode 100644 index 000000000..a086b589e --- /dev/null +++ b/db/docs/ref/upgrade.3.0/db.html @@ -0,0 +1,48 @@ + + + + + +Berkeley DB Reference Guide: Release 3.0: the DB structure + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.0: the DB structure

+

The DB structure is now opaque for applications in the Berkeley DB 3.0 +release. Accesses to any fields within that structure by the application +should be replaced with method calls. The following example illustrates +this using the historic type structure field. In the Berkeley DB 2.X releases, +applications could find the type of an underlying database using code +similar to the following: +

DB *db;
+DB_TYPE type;
+

+ type = db->type;

+

in the Berkeley DB 3.X releases, this should be done using the +DB->get_type method, as follows: +

DB *db;
+DB_TYPE type;
+

+ type = db->get_type(db);

+

The following table lists the DB fields previously used by +applications and the methods that should now be used to get or set them. +

+ + + + + + + +
DB fieldBerkeley DB 3.X method
byteswappedDB->get_byteswapped
db_errcallDB->set_errcall
db_errfileDB->set_errfile
db_errpfxDB->set_errpfx
db_paniccallDB->set_paniccall
typeDB->get_type
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.0/db_cxx.html b/db/docs/ref/upgrade.3.0/db_cxx.html new file mode 100644 index 000000000..e3a794e38 --- /dev/null +++ b/db/docs/ref/upgrade.3.0/db_cxx.html @@ -0,0 +1,47 @@ + + + + + +Berkeley DB Reference Guide: Release 3.0: the Db class for C++ and Java + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.0: the Db class for C++ and Java

+

The static Db::open method and the DbInfo class have been removed in the +Berkeley DB 3.0 release. The way to open a database file is to use the new Db +constructor with two arguments, followed by set_XXX methods to configure +the Db object, and finally a call to the new (nonstatic) Db::open(). In +comparing the Berkeley DB 3.0 release open method with the 2.X static open +method, the second argument is new. It is a database name, which can +be null. The DbEnv argument has been removed, as the environment is now +specified in the constructor. The open method no longer returns a Db, +since it operates on one. +

Here's a C++ example opening a Berkeley DB database using the 2.X interface: +

// Note: by default, errors are thrown as exceptions
+Db *table;
+Db::open("lookup.db", DB_BTREE, DB_CREATE, 0644, dbenv, 0, &table);
+

In the Berkeley DB 3.0 release, this code would be written as: +

// Note: by default, errors are thrown as exceptions
+Db *table = new Db(dbenv, 0);
+table->open("lookup.db", NULL, DB_BTREE, DB_CREATE, 0644);
+

Here's a Java example opening a Berkeley DB database using the 2.X interface: +

// Note: errors are thrown as exceptions
+Db table = Db.open("lookup.db", Db.DB_BTREE, Db.DB_CREATE, 0644, dbenv, 0);
+

In the Berkeley DB 3.0 release, this code would be written as: +

// Note: errors are thrown as exceptions
+Db table = new Db(dbenv, 0);
+table.open("lookup.db", null, Db.DB_BTREE, Db.DB_CREATE, 0644);
+

Note that if the dbenv argument is null, the database will not exist +within an environment. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.0/dbenv.html b/db/docs/ref/upgrade.3.0/dbenv.html new file mode 100644 index 000000000..08b6ec149 --- /dev/null +++ b/db/docs/ref/upgrade.3.0/dbenv.html @@ -0,0 +1,68 @@ + + + + + +Berkeley DB Reference Guide: Release 3.0: the DB_ENV structure + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.0: the DB_ENV structure

+

The DB_ENV structure is now opaque for applications in the Berkeley DB +3.0 release. Accesses to any fields within that structure by the +application should be replaced with method calls. The following example +illustrates this using the historic errpfx structure field. In the Berkeley DB +2.X releases, applications set error prefixes using code similar to the +following: +

DB_ENV *dbenv;
+

+ dbenv->errpfx = "my prefix";

+

in the Berkeley DB 3.X releases, this should be done using the +DBENV->set_errpfx method, as follows: +

DB_ENV *dbenv;
+

+ dbenv->set_errpfx(dbenv, "my prefix");

+

The following table lists the DB_ENV fields previously used by +applications and the methods that should now be used to set them. +

+ + + + + + + + + + + + + + + + + +
DB_ENV fieldBerkeley DB 3.X method
db_errcallDBENV->set_errcall
db_errfileDBENV->set_errfile
db_errpfxDBENV->set_errpfx
db_lorderThis field was removed from the DB_ENV structure in the Berkeley DB +3.0 release as no application should have ever used it. Any code using +it should be evaluated for potential bugs.
db_paniccallDBENV->set_paniccall
db_verboseDBENV->set_verbose +

Note: the db_verbose field was a simple boolean toggle, the +DBENV->set_verbose method takes arguments that specify exactly +which verbose messages are desired.

lg_maxDBENV->set_lg_max
lk_conflictsDBENV->set_lk_conflicts
lk_detectDBENV->set_lk_detect
lk_maxDBENV->set_lk_max
lk_modesDBENV->set_lk_conflicts
mp_mmapsizeDBENV->set_mp_mmapsize
mp_sizeDBENV->set_cachesize +

Note: the DBENV->set_cachesize function takes additional arguments. +Setting both the second argument (the number of GB in the pool) and the +last argument (the number of memory pools to create) to 0 will result in +behavior that is backward compatible with previous Berkeley DB releases.

tx_infoThis field was used by applications as an argument to the transaction +subsystem functions. As those functions take references to a +DB_ENV structure as arguments in the Berkeley DB 3.0 release, it should +no longer be used by any application.
tx_maxDBENV->set_tx_max
tx_recoverDBENV->set_tx_recover
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.0/dbenv_cxx.html b/db/docs/ref/upgrade.3.0/dbenv_cxx.html new file mode 100644 index 000000000..8839d6408 --- /dev/null +++ b/db/docs/ref/upgrade.3.0/dbenv_cxx.html @@ -0,0 +1,72 @@ + + + + + +Berkeley DB Reference Guide: Release 3.0: the DbEnv class for C++ and Java + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.0: the DbEnv class for C++ and Java

+

The DbEnv::appinit() method and two constructors for the DbEnv class are +gone. There is now a single way to create and initialize the environment. +The way to create an environment is to use the new DbEnv constructor with +one argument. After this call, the DbEnv can be configured with various +set_XXX methods. Finally, a call to DbEnv::open is made to initialize +the environment. +

Here's a C++ example creating a Berkeley DB environment using the 2.X interface +

int dberr;
+DbEnv *dbenv = new DbEnv();
+

+dbenv->set_error_stream(&cerr); +dbenv->set_errpfx("myprog"); +

+if ((dberr = dbenv->appinit("/database/home", + NULL, DB_CREATE | DB_INIT_LOCK | DB_INIT_MPOOL)) != 0) { + cerr << "failure: " << strerror(dberr); + exit (1); +}

+

In the Berkeley DB 3.0 release, this code would be written as: +

int dberr;
+DbEnv *dbenv = new DbEnv(0);
+

+dbenv->set_error_stream(&cerr); +dbenv->set_errpfx("myprog"); +

+if ((dberr = dbenv->open("/database/home", + NULL, DB_CREATE | DB_INIT_LOCK | DB_INIT_MPOOL, 0)) != 0) { + cerr << "failure: " << dbenv->strerror(dberr); + exit (1); +}

+

Here's a Java example creating a Berkeley DB environment using the 2.X interface: +

int dberr;
+DbEnv dbenv = new DbEnv();
+

+dbenv.set_error_stream(System.err); +dbenv.set_errpfx("myprog"); +

+dbenv.appinit("/database/home", + null, Db.DB_CREATE | Db.DB_INIT_LOCK | Db.DB_INIT_MPOOL);

+

In the Berkeley DB 3.0 release, this code would be written as: +

int dberr;
+DbEnv dbenv = new DbEnv(0);
+

+dbenv.set_error_stream(System.err); +dbenv.set_errpfx("myprog"); +

+dbenv.open("/database/home", + null, Db.DB_CREATE | Db.DB_INIT_LOCK | Db.DB_INIT_MPOOL, 0);

+

In the Berkeley DB 2.X release, DbEnv had accessors to obtain "managers" of type +DbTxnMgr, DbMpool, DbLog, DbTxnMgr. If you used any of these managers, +all their methods are now found directly in the DbEnv class. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.0/dbinfo.html b/db/docs/ref/upgrade.3.0/dbinfo.html new file mode 100644 index 000000000..da1f8460d --- /dev/null +++ b/db/docs/ref/upgrade.3.0/dbinfo.html @@ -0,0 +1,72 @@ + + + + + +Berkeley DB Reference Guide: Release 3.0: the DBINFO structure + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.0: the DBINFO structure

+

The DB_INFO structure has been removed from the Berkeley DB 3.0 release. +Accesses to any fields within that structure by the application should be +replaced with method calls on the DB handle. The following +example illustrates this using the historic db_cachesize structure field. +In the Berkeley DB 2.X releases, applications could set the size of an +underlying database cache using code similar to the following: +

DB_INFO dbinfo;
+

+ memset(dbinfo, 0, sizeof(dbinfo)); + dbinfo.db_cachesize = 1024 * 1024;

+

in the Berkeley DB 3.X releases, this should be done using the +DB->set_cachesize method, as follows: +

DB *db;
+int ret;
+

+ ret = db->set_cachesize(db, 0, 1024 * 1024, 0);

+

The DB_INFO structure is no longer used in any way by the Berkeley DB 3.0 +release, and should be removed from the application. +

The following table lists the DB_INFO fields previously used by +applications and the methods that should now be used to set +them. Because these calls provide configuration for the +database open, they must precede the call to DB->open. +Calling them after the call to DB->open will return an +error. +

+ + + + + + + + + + + + + + + + + +
DB_INFO fieldBerkeley DB 3.X method
bt_compareDB->set_bt_compare
bt_minkeyDB->set_bt_minkey
bt_prefixDB->set_bt_prefix
db_cachesizeDB->set_cachesize +

Note: the DB->set_cachesize function takes additional arguments. +Setting both the second argument (the number of GB in the pool) and the +last argument (the number of memory pools to create) to 0 will result in +behavior that is backward compatible with previous Berkeley DB releases.

db_lorderDB->set_lorder
db_mallocDB->set_malloc
db_pagesizeDB->set_pagesize
dup_compareDB->set_dup_compare
flagsDB->set_flags +

Note: the DB_DELIMITER, DB_FIXEDLEN and DB_PAD flags no longer need to be +set as there are specific methods off the DB handle that set the +file delimiter, the length of fixed-length records and the fixed-length +record pad character. They should simply be discarded from the application.

h_ffactorDB->set_h_ffactor
h_hashDB->set_h_hash
h_nelemDB->set_h_nelem
re_delimDB->set_re_delim
re_lenDB->set_re_len
re_padDB->set_re_pad
re_sourceDB->set_re_source
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.0/disk.html b/db/docs/ref/upgrade.3.0/disk.html new file mode 100644 index 000000000..f6ea2799b --- /dev/null +++ b/db/docs/ref/upgrade.3.0/disk.html @@ -0,0 +1,30 @@ + + + + + +Berkeley DB Reference Guide: Release 3.0: upgrade requirements + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.0: upgrade requirements

+

Log file formats and the Btree, Recno and Hash Access Method database +formats changed in the Berkeley DB 3.0 release. (The on-disk Btree/Recno +format changed from version 6 to version 7. The on-disk Hash format +changed from version 5 to version 6.) Until the underlying databases +are upgraded, the DB->open function will return a DB_OLD_VERSION +error. +

For further information on upgrading Berkeley DB installations, see +Upgrading Berkeley DB +installations. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.0/eacces.html b/db/docs/ref/upgrade.3.0/eacces.html new file mode 100644 index 000000000..b7fb3e859 --- /dev/null +++ b/db/docs/ref/upgrade.3.0/eacces.html @@ -0,0 +1,28 @@ + + + + + +Berkeley DB Reference Guide: Release 3.0: EACCES + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.0: EACCES

+

There was an error in previous releases of the Berkeley DB documentation that +said that the lock_put and lock_vec interfaces could +return EACCES as an error to indicate that a lock could not be released +because it was held by another locker. The application should be +searched for any occurrences of EACCES. For each of these, any that are +checking for an error return from lock_put or lock_vec +should have the test and any error handling removed. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.0/eagain.html b/db/docs/ref/upgrade.3.0/eagain.html new file mode 100644 index 000000000..e998c1b43 --- /dev/null +++ b/db/docs/ref/upgrade.3.0/eagain.html @@ -0,0 +1,34 @@ + + + + + +Berkeley DB Reference Guide: Release 3.0: EAGAIN + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.0: EAGAIN

+

Historically, the Berkeley DB interfaces have returned the POSIX error value +EAGAIN to indicate a deadlock. This has been removed from the Berkeley DB 3.0 +release in order to make it possible for applications to distinguish +between EAGAIN errors returned by the system and returns from Berkeley DB +indicating deadlock. +

The application should be searched for any occurrences of EAGAIN. For +each of these, any that are checking for a deadlock return from Berkeley DB +should be changed to check for the DB_LOCK_DEADLOCK return value. +

If, for any reason, this is a difficult change for the application to +make, the include/db.src distribution file should be modified to +translate all returns of DB_LOCK_DEADLOCK to EAGAIN. Search for the +string EAGAIN in that file, there is a comment that describes how to make +the change. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.0/envopen.html b/db/docs/ref/upgrade.3.0/envopen.html new file mode 100644 index 000000000..3c20a0e9e --- /dev/null +++ b/db/docs/ref/upgrade.3.0/envopen.html @@ -0,0 +1,156 @@ + + + + + +Berkeley DB Reference Guide: Release 3.0: environment open/close/unlink + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.0: environment open/close/unlink

+

The hardest part of upgrading your application from a 2.X code base to +the 3.0 release is translating the Berkeley DB environment open, close and +remove calls. +

There were two logical changes in this part of the Berkeley DB interface. +First, in Berkeley DB 3.0, there are no longer separate structures that +represent each subsystem (e.g., DB_LOCKTAB or DB_TXNMGR) and an overall +DB_ENV environment structure. Instead there is only the +DB_ENV structure. This means that DB_ENV references should +be passed around by your application instead of passing around DB_LOCKTAB +or DB_TXNMGR references. This is likely to be a simple change for most +applications as few applications use the lock_XXX, log_XXX, +memp_XXX or txn_XXX interfaces to create Berkeley DB environments. +

The second change is that there are no longer separate open, close, and +unlink interfaces to the +Berkeley DB subsystems, e.g., in previous releases, it was possible to open a +lock subsystem either using db_appinit or using the lock_open call. In +the 3.0 release the XXX_open interfaces to the subsystems have been +removed, and subsystems must now be opened using the 3.0 replacement for the +db_appinit call. +

To upgrade your application, first find each place your application opens, +closes and/or removes a Berkeley DB environment. This will be code of the form: +

db_appinit, db_appexit
+lock_open, lock_close, lock_unlink
+log_open, log_close, log_unlink
+memp_open, memp_close, memp_unlink
+txn_open, txn_close, txn_unlink
+

Each of these groups of calls should be replaced with calls to: +

db_env_create, DBENV->open, DBENV->close,
+DBENV->remove
+

The db_env_create call and the call to the DBENV->open +method replace the db_appinit, lock_open, log_open, memp_open and txn_open +calls. The DBENV->close method replaces the db_appexit, +lock_close, log_close, memp_close and txn_close calls. The +DBENV->remove call replaces the lock_unlink, log_unlink, +memp_unlink and txn_unlink calls. +

Here's an example creating a Berkeley DB environment using the 2.X interface: +

/*
+ * db_init --
+ *	Initialize the environment.
+ */
+DB_ENV *
+db_init(home)
+	char *home;
+{
+	DB_ENV *dbenv;
+

+ if ((dbenv = (DB_ENV *)calloc(sizeof(DB_ENV), 1)) == NULL) + return (errno); +

+ if ((errno = db_appinit(home, NULL, dbenv, + DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN | + DB_USE_ENVIRON)) == 0) + return (dbenv); +

+ free(dbenv); + return (NULL); +}

+

In the Berkeley DB 3.0 release, this code would be written as: +

/*
+ * db_init --
+ *	Initialize the environment.
+ */
+int
+db_init(home, dbenvp)
+	char *home;
+	DB_ENV **dbenvp;
+{
+	int ret;
+	DB_ENV *dbenv;
+

+ if ((ret = db_env_create(&dbenv, 0)) != 0) + return (ret); +

+ if ((ret = dbenv->open(dbenv, home, NULL, + DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN | + DB_USE_ENVIRON, 0)) == 0) { + *dbenvp = dbenv; + return (0); + } +

+ (void)dbenv->close(dbenv, 0); + return (ret); +}

+

As you can see, the arguments to db_appinit and to DBENV->open are +largely the same. There is some minor re-organization: the mapping is +that arguments #1, 2, 3, and 4 to db_appinit become arguments #2, 3, 1 +and 4 to DBENV->open. There is one additional argument to +DBENV->open, argument #5. For backward compatibility with the 2.X +Berkeley DB releases, simply set that argument to 0. +

It is only slightly more complex to translate calls to XXX_open to the +DBENV->open method. Here's an example of creating a lock region +using the 2.X interface: +

lock_open(dir, DB_CREATE, 0664, dbenv, ®ionp);
+

In the Berkeley DB 3.0 release, this code would be written as: +

if ((ret = db_env_create(&dbenv, 0)) != 0)
+	return (ret);
+

+if ((ret = dbenv->open(dbenv, + dir, NULL, DB_CREATE | DB_INIT_LOCK, 0664)) == 0) { + *dbenvp = dbenv; + return (0); +}

+

Note that in this example, you no longer need the DB_LOCKTAB structure +reference that was required in Berkeley DB 2.X releases. +

The final issue with upgrading the db_appinit call is the DB_MPOOL_PRIVATE +option previously provided for the db_appinit interface. If your +application is using this flag, it should almost certainly use the new +DB_PRIVATE flag to the DBENV->open interface. Regardless, +you should carefully consider this change before converting to use the +DB_PRIVATE flag. +

Translating db_appexit or XXX_close calls to DBENV->close is equally +simple. Instead of taking a reference to a per-subsystem structure such +as DB_LOCKTAB or DB_TXNMGR, all calls take a reference to a DB_ENV +structure. The calling sequence is otherwise unchanged. Note that as +the application no longer allocates the memory for the DB_ENV structure, +application code to discard it after the call to db_appexit() is no longer +needed. +

Translating XXX_unlink calls to DBENV->remove is slightly more complex. +As with DBENV->close, the call takes a reference to a DB_ENV +structure instead of a per-subsystem structure. The calling sequence is +slightly different, however. Here is an example of removing a lock region +using the 2.X interface: +

DB_ENV *dbenv;
+

+ret = lock_unlink(dir, 1, dbenv);

+

In the Berkeley DB 3.0 release, this code fragment would be written as: +

DB_ENV *dbenv;
+

+ret = dbenv->remove(dbenv, dir, NULL, DB_FORCE);

+

The additional argument to the DBENV->remove function is a +configuration argument similar to that previously taken by db_appinit and +now taken by the DBENV->open method. For backward compatibility +this new argument should simply be set to NULL. The force argument to +XXX_unlink is now a flag value that is set by bitwise inclusively OR'ing it the +DBENV->remove flag argument. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.0/func.html b/db/docs/ref/upgrade.3.0/func.html new file mode 100644 index 000000000..b6f7d816b --- /dev/null +++ b/db/docs/ref/upgrade.3.0/func.html @@ -0,0 +1,69 @@ + + + + + +Berkeley DB Reference Guide: Release 3.0: function arguments + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.0: function arguments

+

In Berkeley DB 3.0, there are no longer separate structures that +represent each subsystem (e.g., DB_LOCKTAB or DB_TXNMGR), and an overall +DB_ENV environment structure. Instead there is only the +DB_ENV structure. This means that DB_ENV references should +be passed around by your application instead of passing around DB_LOCKTAB +or DB_TXNMGR references. +

Each of the following functions: +

lock_detect
+lock_get
+lock_id
+lock_put
+lock_stat
+lock_vec
+

should have its first argument, a reference to the DB_LOCKTAB structure, +replaced with a reference to the enclosing DB_ENV structure. For +example, the following line of code from a Berkeley DB 2.X application: +

DB_LOCKTAB *lt;
+DB_LOCK lock;
+	ret = lock_put(lt, lock);
+

should now be written as follows: +

DB_ENV *dbenv;
+DB_LOCK *lock;
+	ret = lock_put(dbenv, lock);
+

Similarly, all of the functions: +

log_archive
+log_compare
+log_file
+log_flush
+log_get
+log_put
+log_register
+log_stat
+log_unregister
+

should have their DB_LOG argument replaced with a reference to a +DB_ENV structure, and the functions: +

memp_fopen
+memp_register
+memp_stat
+memp_sync
+memp_trickle
+

should have their DB_MPOOL argument replaced with a reference to a +DB_ENV structure. +

You should remove all references to DB_LOCKTAB, DB_LOG, DB_MPOOL, and +DB_TXNMGR structures from your application, they are no longer useful +in any way. In fact, a simple way to identify all of the places that +need to be upgraded is to remove all such structures and variables +they declare, and then compile. You will see a warning message from +your compiler in each case that needs to be upgraded. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.0/intro.html b/db/docs/ref/upgrade.3.0/intro.html new file mode 100644 index 000000000..a74e40f4e --- /dev/null +++ b/db/docs/ref/upgrade.3.0/intro.html @@ -0,0 +1,26 @@ + + + + + +Berkeley DB Reference Guide: Release 3.0: introduction + + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.0: introduction

+

The following pages describe how to upgrade applications coded against +the Berkeley DB 2.X release interfaces to the Berkeley DB 3.0 release interfaces. +This information does not describe how to upgrade Berkeley DB 1.85 release +applications. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.0/java.html b/db/docs/ref/upgrade.3.0/java.html new file mode 100644 index 000000000..3997095bc --- /dev/null +++ b/db/docs/ref/upgrade.3.0/java.html @@ -0,0 +1,34 @@ + + + + + +Berkeley DB Reference Guide: Release 3.0: additional Java changes + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.0: additional Java changes

+

There are several additional types of exceptions thrown in the Berkeley DB 3.0 +Java API. +

DbMemoryException and DbDeadlockException can be caught independently of +DbException if you want to do special handling for these kinds of errors. +Since they are subclassed from DbException, a try block that catches +DbException will catch these also, so code is not required to change. +The catch clause for these new exceptions should appear before the catch +clause for DbException. +

You will need to add a catch clause for java.io.FileNotFoundException, +since that can be thrown by the Db.open and DbEnv.open functions. +

There are a number of smaller changes to the API that bring the C, C++ +and Java APIs much closer in terms of functionality and usage. Please +refer to the pages for upgrading C applications for further details. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.0/join.html b/db/docs/ref/upgrade.3.0/join.html new file mode 100644 index 000000000..82c9019fa --- /dev/null +++ b/db/docs/ref/upgrade.3.0/join.html @@ -0,0 +1,28 @@ + + + + + +Berkeley DB Reference Guide: Release 3.0: DB->join + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.0: DB->join

+

Historically, the last two arguments to the Berkeley DB DB->join +interface were a flags value followed by a reference to a memory location +to store the returned cursor object. In the Berkeley DB 3.0 release, the +order of those two arguments has been swapped for consistency with other +Berkeley DB interfaces. +

The application should be searched for any occurrences of DB->join. +For each of these, the order of the last two arguments should be swapped. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.0/jump_set.html b/db/docs/ref/upgrade.3.0/jump_set.html new file mode 100644 index 000000000..c93e7270e --- /dev/null +++ b/db/docs/ref/upgrade.3.0/jump_set.html @@ -0,0 +1,48 @@ + + + + + +Berkeley DB Reference Guide: Release 3.0: db_jump_set + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.0: db_jump_set

+

The db_jump_set interface has been removed from the Berkeley DB 3.0 release, +replaced by method calls on the DB_ENV handle. +

The following table lists the db_jump_set arguments previously used by +applications and the methods that should now be used instead. +

+ + + + + + + + + + + + + + + + + + + + +
db_jump_set argumentBerkeley DB 3.X method
DB_FUNC_CLOSEdb_env_set_func_close
DB_FUNC_DIRFREEdb_env_set_func_dirfree
DB_FUNC_DIRLISTdb_env_set_func_dirlist
DB_FUNC_EXISTSdb_env_set_func_exists
DB_FUNC_FREEdb_env_set_func_free
DB_FUNC_FSYNCdb_env_set_func_fsync
DB_FUNC_IOINFOdb_env_set_func_ioinfo
DB_FUNC_MALLOCdb_env_set_func_malloc
DB_FUNC_MAPdb_env_set_func_map
DB_FUNC_OPENdb_env_set_func_open
DB_FUNC_READdb_env_set_func_read
DB_FUNC_REALLOCdb_env_set_func_realloc
DB_FUNC_RUNLINKThe DB_FUNC_RUNLINK functionality has been removed from the Berkeley DB +3.0 release, and should be removed from the application.
DB_FUNC_SEEKdb_env_set_func_seek
DB_FUNC_SLEEPdb_env_set_func_sleep
DB_FUNC_UNLINKdb_env_set_func_unlink
DB_FUNC_UNMAPdb_env_set_func_unmap
DB_FUNC_WRITEdb_env_set_func_write
DB_FUNC_YIELDdb_env_set_func_yield
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.0/lock_detect.html b/db/docs/ref/upgrade.3.0/lock_detect.html new file mode 100644 index 000000000..4ff00a8a6 --- /dev/null +++ b/db/docs/ref/upgrade.3.0/lock_detect.html @@ -0,0 +1,24 @@ + + + + + +Berkeley DB Reference Guide: Release 3.0: lock_detect + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.0: lock_detect

+

An additional argument has been added to the lock_detect interface. +

The application should be searched for any occurrences of lock_detect. +For each one, a NULL argument should be appended to the current arguments. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.0/lock_notheld.html b/db/docs/ref/upgrade.3.0/lock_notheld.html new file mode 100644 index 000000000..3f1173856 --- /dev/null +++ b/db/docs/ref/upgrade.3.0/lock_notheld.html @@ -0,0 +1,27 @@ + + + + + +Berkeley DB Reference Guide: Release 3.0: DB_LOCK_NOTHELD + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.0: DB_LOCK_NOTHELD

+

Historically, the Berkeley DB lock_put and lock_vec interfaces +could return the DB_LOCK_NOTHELD error to indicate that a lock could +not be released as it was held by another locker. This error can no +longer be returned under any circumstances. The application should be +searched for any occurrences of DB_LOCK_NOTHELD. For each of these, +the test and any error processing should be removed. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.0/lock_put.html b/db/docs/ref/upgrade.3.0/lock_put.html new file mode 100644 index 000000000..d6057f8e2 --- /dev/null +++ b/db/docs/ref/upgrade.3.0/lock_put.html @@ -0,0 +1,25 @@ + + + + + +Berkeley DB Reference Guide: Release 3.0: lock_put + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.0: lock_put

+

An argument change has been made in the lock_put interface. +

The application should be searched for any occurrences of lock_put. +For each one, instead of passing a DB_LOCK variable as the last argument +to the function, the address of the DB_LOCK variable should be passed. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.0/lock_stat.html b/db/docs/ref/upgrade.3.0/lock_stat.html new file mode 100644 index 000000000..80504db3b --- /dev/null +++ b/db/docs/ref/upgrade.3.0/lock_stat.html @@ -0,0 +1,24 @@ + + + + + +Berkeley DB Reference Guide: Release 3.0: lock_stat + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.0: lock_stat

+

The st_magic, st_version, st_numobjs and +st_refcnt fields returned from the lock_stat interface +have been removed, and this information is no longer available. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.0/log_register.html b/db/docs/ref/upgrade.3.0/log_register.html new file mode 100644 index 000000000..3a856275f --- /dev/null +++ b/db/docs/ref/upgrade.3.0/log_register.html @@ -0,0 +1,25 @@ + + + + + +Berkeley DB Reference Guide: Release 3.0: log_register + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.0: log_register

+

An argument has been removed from the log_register interface. +The application should be searched for any occurrences of +log_register. In each of these, the DBTYPE argument (it is the +fourth argument) should be removed. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.0/log_stat.html b/db/docs/ref/upgrade.3.0/log_stat.html new file mode 100644 index 000000000..8c023bfe2 --- /dev/null +++ b/db/docs/ref/upgrade.3.0/log_stat.html @@ -0,0 +1,23 @@ + + + + + +Berkeley DB Reference Guide: Release 3.0: log_stat + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.0: log_stat

+

The st_refcnt field returned from the log_stat interface +has been removed, and this information is no longer available. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.0/memp_stat.html b/db/docs/ref/upgrade.3.0/memp_stat.html new file mode 100644 index 000000000..ff61fa745 --- /dev/null +++ b/db/docs/ref/upgrade.3.0/memp_stat.html @@ -0,0 +1,26 @@ + + + + + +Berkeley DB Reference Guide: Release 3.0: memp_stat + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.0: memp_stat

+

The st_refcnt field returned from the memp_stat interface +has been removed, and this information is no longer available. +

The st_cachesize field returned from the memp_stat +interface has been replaced with two new fields, st_gbytes and +st_bytes. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.0/open.html b/db/docs/ref/upgrade.3.0/open.html new file mode 100644 index 000000000..3730ab474 --- /dev/null +++ b/db/docs/ref/upgrade.3.0/open.html @@ -0,0 +1,65 @@ + + + + + +Berkeley DB Reference Guide: Release 3.0: database open/close + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.0: database open/close

+

Database opens were changed in the Berkeley DB 3.0 release in a similar way to +environment opens. +

To upgrade your application, first find each place your application opens +a database, that is, calls the db_open function. Each of these calls +should be replaced with calls to db_create and DB->open. +

Here's an example creating a Berkeley DB database using the 2.X interface: +

DB *dbp;
+DB_ENV *dbenv;
+int ret;
+

+if ((ret = db_open(DATABASE, + DB_BTREE, DB_CREATE, 0664, dbenv, NULL, &dbp)) != 0) + return (ret);

+

In the Berkeley DB 3.0 release, this code would be written as: +

DB *dbp;
+DB_ENV *dbenv;
+int ret;
+

+if ((ret = db_create(&dbp, dbenv, 0)) != 0) + return (ret); +

+if ((ret = dbp->open(dbp, + DATABASE, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) { + (void)dbp->close(dbp, 0); + return (ret); +}

+

As you can see, the arguments to db_open and to DB->open are +largely the same. There is some re-organization, and note that the +enclosing DB_ENV structure is specified when the DB object +is created using the db_create interface. There is one +additional argument to DB->open, argument #3. For backward +compatibility with the 2.X Berkeley DB releases, simply set that argument to +NULL. +

There are two additional issues with the db_open call. +

First, it was possible in the 2.X releases for an application to provide +an environment that did not contain a shared memory buffer pool as the +database environment, and Berkeley DB would create a private one automatically. +This functionality is no longer available, applications must specify the +DB_INIT_MPOOL flag if databases are going to be opened in the +environment. +

The final issue with upgrading the db_open call is that the DB_INFO +structure is no longer used, having been replaced by individual methods +on the DB handle. That change is discussed in detail later in +this chapter. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.0/rmw.html b/db/docs/ref/upgrade.3.0/rmw.html new file mode 100644 index 000000000..a1a30da5e --- /dev/null +++ b/db/docs/ref/upgrade.3.0/rmw.html @@ -0,0 +1,31 @@ + + + + + +Berkeley DB Reference Guide: Release 3.0: DB_RMW + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.0: DB_RMW

+

The following change applies only to applications using the +Berkeley DB Concurrent Data Store product. If your application is not using that product, +you can ignore this change. +

Historically, the Berkeley DB DB->cursor interface took the DB_RMW flag +to indicate that the created cursor would be used for write operations on +the database. This flag has been renamed to the DB_WRITECURSOR +flag. +

The application should be searched for any occurrences of DB_RMW. For +each of these, any that are arguments to the DB->cursor function +should be changed to pass in the DB_WRITECURSOR flag instead. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.0/stat.html b/db/docs/ref/upgrade.3.0/stat.html new file mode 100644 index 000000000..735e235d9 --- /dev/null +++ b/db/docs/ref/upgrade.3.0/stat.html @@ -0,0 +1,24 @@ + + + + + +Berkeley DB Reference Guide: Release 3.0: DB->stat + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.0: DB->stat

+

The bt_flags field returned from the DB->stat interface +for Btree and Recno databases has been removed, and this information is +no longer available. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.0/toc.html b/db/docs/ref/upgrade.3.0/toc.html new file mode 100644 index 000000000..189d7c0a6 --- /dev/null +++ b/db/docs/ref/upgrade.3.0/toc.html @@ -0,0 +1,47 @@ + + + + + +Berkeley DB: Upgrading Berkeley DB 2.X.X applications to Berkeley DB 3.0 + + + + +

Upgrading Berkeley DB 2.X.X applications to Berkeley DB 3.0

+
    +
  1. Release 3.0: introduction +
  2. Release 3.0: environment open/close/unlink +
  3. Release 3.0: function arguments +
  4. Release 3.0: the DB_ENV structure +
  5. Release 3.0: database open/close +
  6. Release 3.0: db_xa_open +
  7. Release 3.0: the DB structure +
  8. Release 3.0: the DBINFO structure +
  9. Release 3.0: DB->join +
  10. Release 3.0: DB->stat +
  11. Release 3.0: DB->sync and DB->close +
  12. Release 3.0: lock_put +
  13. Release 3.0: lock_detect +
  14. Release 3.0: lock_stat +
  15. Release 3.0: log_register +
  16. Release 3.0: log_stat +
  17. Release 3.0: memp_stat +
  18. Release 3.0: txn_begin +
  19. Release 3.0: txn_commit +
  20. Release 3.0: txn_stat +
  21. Release 3.0: DB_RMW +
  22. Release 3.0: DB_LOCK_NOTHELD +
  23. Release 3.0: EAGAIN +
  24. Release 3.0: EACCES +
  25. Release 3.0: db_jump_set +
  26. Release 3.0: db_value_set +
  27. Release 3.0: the DbEnv class for C++ and Java +
  28. Release 3.0: the Db class for C++ and Java +
  29. Release 3.0: additional C++ changes +
  30. Release 3.0: additional Java changes +
  31. Release 3.0: upgrade requirements +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.0/txn_begin.html b/db/docs/ref/upgrade.3.0/txn_begin.html new file mode 100644 index 000000000..3fb9a6527 --- /dev/null +++ b/db/docs/ref/upgrade.3.0/txn_begin.html @@ -0,0 +1,25 @@ + + + + + +Berkeley DB Reference Guide: Release 3.0: txn_begin + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.0: txn_begin

+

An additional argument has been added to the txn_begin interface. +

The application should be searched for any occurrences of +txn_begin. For each one, an argument of 0 should be appended to +the current arguments. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.0/txn_commit.html b/db/docs/ref/upgrade.3.0/txn_commit.html new file mode 100644 index 000000000..8090b1e3b --- /dev/null +++ b/db/docs/ref/upgrade.3.0/txn_commit.html @@ -0,0 +1,25 @@ + + + + + +Berkeley DB Reference Guide: Release 3.0: txn_commit + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.0: txn_commit

+

An additional argument has been added to the txn_commit interface. +

The application should be searched for any occurrences of +txn_commit. For each one, an argument of 0 should be appended to +the current arguments. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.0/txn_stat.html b/db/docs/ref/upgrade.3.0/txn_stat.html new file mode 100644 index 000000000..d965494d5 --- /dev/null +++ b/db/docs/ref/upgrade.3.0/txn_stat.html @@ -0,0 +1,23 @@ + + + + + +Berkeley DB Reference Guide: Release 3.0: txn_stat + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.0: txn_stat

+

The st_refcnt field returned from the txn_stat interface +has been removed, and this information is no longer available. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.0/value_set.html b/db/docs/ref/upgrade.3.0/value_set.html new file mode 100644 index 000000000..66070b09f --- /dev/null +++ b/db/docs/ref/upgrade.3.0/value_set.html @@ -0,0 +1,41 @@ + + + + + +Berkeley DB Reference Guide: Release 3.0: db_value_set + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.0: db_value_set

+

The db_value_set interface has been removed from the Berkeley DB 3.0 release, +replaced by method calls on the DB_ENV handle. +

The following table lists the db_value_set arguments previously used by +applications and the methods that should now be used instead. +

+ + + + + + +
db_value_set argumentBerkeley DB 3.X method
DB_MUTEX_LOCKSDBENV->set_mutexlocks
DB_REGION_ANONThe DB_REGION_ANON functionality has +been replaced by the DB_SYSTEM_MEM and DB_PRIVATE flags +to the DBENV->open function. A direct translation is not +available, please review the DBENV->open manual page for more +information.
DB_REGION_INITdb_env_set_region_init
DB_REGION_NAMEThe DB_REGION_NAME functionality has +been replaced by the DB_SYSTEM_MEM and DB_PRIVATE flags +to the DBENV->open function. A direct translation is not +available, please review the DBENV->open manual page for more +information.
DB_TSL_SPINSdb_env_set_tas_spins
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.0/xa.html b/db/docs/ref/upgrade.3.0/xa.html new file mode 100644 index 000000000..41f5a993d --- /dev/null +++ b/db/docs/ref/upgrade.3.0/xa.html @@ -0,0 +1,33 @@ + + + + + +Berkeley DB Reference Guide: Release 3.0: db_xa_open + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.0: db_xa_open

+

The following change applies only to applications using Berkeley DB as an XA +Resource Manager. If your application is not using Berkeley DB in this way, +you can ignore this change. +

The db_xa_open function has been replaced with the DB_XA_CREATE +flag to the db_create function. All calls to db_xa_open should +be replaced with calls to db_create with the DB_XA_CREATE +flag set, followed by a call to the DB->open function. +

A similar change has been made for the C++ API, where the +DB_XA_CREATE flag should be specified to the Db constructor. All +calls to the Db::xa_open method should be replaced with the +DB_XA_CREATE flag to the Db constructor, followed by a call to +the DB::open method. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.1/btstat.html b/db/docs/ref/upgrade.3.1/btstat.html new file mode 100644 index 000000000..e5d7c4bb5 --- /dev/null +++ b/db/docs/ref/upgrade.3.1/btstat.html @@ -0,0 +1,50 @@ + + + + + +Berkeley DB Reference Guide: Release 3.1: DB->stat + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.1: DB->stat

+

For Btree database statistics, the DB->stat interface field +bt_nrecs has been removed, replaced by two fields: +bt_nkeys and bt_ndata. The bt_nkeys field returns +a count of the unique keys in the database. The bt_ndata field +returns a count of the key/data pairs in the database. Neither exactly +matches the previous value of the bt_nrecs field, which returned +a count of keys in the database, but, in the case of Btree databases, +could overcount as it sometimes counted duplicate data items as unique +keys. The application should be searched for any uses of the +bt_nrecs field and the field should be changed to be either +bt_nkeys or bt_ndata, whichever is more appropriate. +

For Hash database statistics, the DB->stat interface field +hash_nrecs has been removed, replaced by two fields: +hash_nkeys and hash_ndata. The hash_nkeys field +returns a count of the unique keys in the database. The +hash_ndata field returns a count of the key/data pairs in the +database. The new hash_nkeys field exactly matches the previous +value of the hash_nrecs field. The application should be searched +for any uses of the hash_nrecs field, and the field should be +changed to be hash_nkeys. +

For Queue database statistics, the DB->stat interface field +qs_nrecs has been removed, replaced by two fields: +qs_nkeys and qs_ndata. The qs_nkeys field returns +a count of the unique keys in the database. The qs_ndata field +returns a count of the key/data pairs in the database. The new +qs_nkeys field exactly matches the previous value of the +qs_nrecs field. The application should be searched for any uses +of the qs_nrecs field, and the field should be changed to be +qs_nkeys. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.1/config.html b/db/docs/ref/upgrade.3.1/config.html new file mode 100644 index 000000000..29a53363e --- /dev/null +++ b/db/docs/ref/upgrade.3.1/config.html @@ -0,0 +1,35 @@ + + + + + +Berkeley DB Reference Guide: Release 3.1: DBENV->open, DBENV->remove + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.1: DBENV->open, DBENV->remove

+

In the Berkeley DB 3.1 release, the config argument to the +DBENV->open, DBENV->remove methods has been removed, +replaced by additional methods on the DB_ENV handle. If your +application calls DBENV->open or DBENV->remove with a NULL +config argument, find those functions and remove the config +argument from the call. If your application has non-NULL config +argument, the strings values in that argument are replaced with calls to +DB_ENV methods as follows: +

+ + + + +
Previous config stringBerkeley DB 3.1 version method
DB_DATA_DIRDBENV->set_data_dir
DB_LOG_DIRDBENV->set_lg_dir
DB_TMP_DIRDBENV->set_tmp_dir
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.1/disk.html b/db/docs/ref/upgrade.3.1/disk.html new file mode 100644 index 000000000..cbaa3342b --- /dev/null +++ b/db/docs/ref/upgrade.3.1/disk.html @@ -0,0 +1,34 @@ + + + + + +Berkeley DB Reference Guide: Release 3.1: upgrade requirements + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.1: upgrade requirements

+

Log file formats and the Btree, Queue, Recno and Hash Access Method +database formats changed in the Berkeley DB 3.1 release. (The on-disk +Btree/Recno format changed from version 7 to version 8. The on-disk +Hash format changed from version 6 to version 7. The on-disk Queue +format changed from version 1 to version 2.) Until the underlying +databases are upgraded, the DB->open function will return a +DB_OLD_VERSION error. +

An additional flag, DB_DUPSORT, has been added to the +DB->upgrade function for this upgrade. Please review the +DB->upgrade documentation for further information. +

For further information on upgrading Berkeley DB installations, see +Upgrading Berkeley DB +installations. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.1/dup.html b/db/docs/ref/upgrade.3.1/dup.html new file mode 100644 index 000000000..33f71ebb4 --- /dev/null +++ b/db/docs/ref/upgrade.3.1/dup.html @@ -0,0 +1,31 @@ + + + + + +Berkeley DB Reference Guide: Release 3.1: identical duplicate data items + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.1: identical duplicate data items

+

In previous releases of Berkeley DB, it was not an error to store identical +duplicate data items, or, for those that just like the way it sounds, +duplicate duplicates. However, there were implementation bugs where +storing duplicate duplicates could cause database corruption. +

In this release, applications may store identical duplicate data items +as long as the data items are unsorted. It is an error to attempt to +store identical duplicate data items when duplicates are being stored +in a sorted order. This restriction is expected to be lifted in a future +release. See Duplicate data items +for more information. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.1/env.html b/db/docs/ref/upgrade.3.1/env.html new file mode 100644 index 000000000..6e1b8ccde --- /dev/null +++ b/db/docs/ref/upgrade.3.1/env.html @@ -0,0 +1,53 @@ + + + + + +Berkeley DB Reference Guide: Release 3.1: environment configuration + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.1: environment configuration

+

A set of DB_ENV configuration methods which were not environment +specific, but which instead affected the entire application space, have +been removed from the DB_ENV object and replaced by static +functions. The following table lists the DB_ENV methods previously +available to applications and the static functions that should now be used +instead. +

+ + + + + + + + + + + + + + + + + + + + + + + + +
DB_ENV methodBerkeley DB 3.1 function
DBENV->set_func_closedb_env_set_func_close
DBENV->set_func_dirfreedb_env_set_func_dirfree
DBENV->set_func_dirlistdb_env_set_func_dirlist
DBENV->set_func_existsdb_env_set_func_exists
DBENV->set_func_freedb_env_set_func_free
DBENV->set_func_fsyncdb_env_set_func_fsync
DBENV->set_func_ioinfodb_env_set_func_ioinfo
DBENV->set_func_mallocdb_env_set_func_malloc
DBENV->set_func_mapdb_env_set_func_map
DBENV->set_func_opendb_env_set_func_open
DBENV->set_func_readdb_env_set_func_read
DBENV->set_func_reallocdb_env_set_func_realloc
DBENV->set_func_renamedb_env_set_func_rename
DBENV->set_func_seekdb_env_set_func_seek
DBENV->set_func_sleepdb_env_set_func_sleep
DBENV->set_func_unlinkdb_env_set_func_unlink
DBENV->set_func_unmapdb_env_set_func_unmap
DBENV->set_func_writedb_env_set_func_write
DBENV->set_func_yielddb_env_set_func_yield
DBENV->set_pageyielddb_env_set_pageyield
DBENV->set_region_initdb_env_set_region_init
DBENV->set_mutexlocksDBENV->set_mutexlocks
DBENV->set_tas_spinsdb_env_set_tas_spins
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.1/intro.html b/db/docs/ref/upgrade.3.1/intro.html new file mode 100644 index 000000000..9c5d95291 --- /dev/null +++ b/db/docs/ref/upgrade.3.1/intro.html @@ -0,0 +1,26 @@ + + + + + +Berkeley DB Reference Guide: Release 3.1: introduction + + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.1: introduction

+

The following pages describe how to upgrade applications coded against +the Berkeley DB 3.0 release interfaces to the Berkeley DB 3.1 release interfaces. +This information does not describe how to upgrade Berkeley DB 1.85 release +applications. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.1/log_register.html b/db/docs/ref/upgrade.3.1/log_register.html new file mode 100644 index 000000000..8823d6439 --- /dev/null +++ b/db/docs/ref/upgrade.3.1/log_register.html @@ -0,0 +1,28 @@ + + + + + +Berkeley DB Reference Guide: Release 3.1: log_register + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.1: log_register

+

The arguments to the log_register and log_unregister +interfaces have changed. Instead of returning (and passing in) a logging +file ID, a reference to the DB structure being registered (or +unregistered) is passed. The application should be searched for any +occurrences of log_register and log_unregister. For each +one, change the arguments to be a reference to the DB structure +being registered or unregistered. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.1/logalloc.html b/db/docs/ref/upgrade.3.1/logalloc.html new file mode 100644 index 000000000..acafbf6ee --- /dev/null +++ b/db/docs/ref/upgrade.3.1/logalloc.html @@ -0,0 +1,27 @@ + + + + + +Berkeley DB Reference Guide: Release 3.1: log file pre-allocation + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.1: log file pre-allocation

+

This change only affects Win/32 applications. +

On Win/32 platforms Berkeley DB no longer pre-allocates log files. The problem +was a noticeable performance spike as each log file was created. To turn +this feature back on, search for the flag DB_OSO_LOG in the source file +log/log_put.c and make the change described there, or contact +Sleepycat Software for assistance. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.1/memp_register.html b/db/docs/ref/upgrade.3.1/memp_register.html new file mode 100644 index 000000000..e8a667031 --- /dev/null +++ b/db/docs/ref/upgrade.3.1/memp_register.html @@ -0,0 +1,30 @@ + + + + + +Berkeley DB Reference Guide: Release 3.1: memp_register + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.1: memp_register

+

An additional argument has been added to the pgin and +pgout functions provided to the memp_register interface. +The application should be searched for any occurrences of +memp_register. For each one, if pgin or pgout +functions are specified, the pgin and pgout functions +should be modified to take an initial argument of a DB_ENV *. +This argument is intended to support better error reporting for +applications, and may be entirely ignored by the pgin and +pgout functions themselves. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.1/put.html b/db/docs/ref/upgrade.3.1/put.html new file mode 100644 index 000000000..5252b3ac0 --- /dev/null +++ b/db/docs/ref/upgrade.3.1/put.html @@ -0,0 +1,63 @@ + + + + + +Berkeley DB Reference Guide: Release 3.1: DB->put + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.1: DB->put

+

For the Queue and Recno access methods, when the DB_APPEND flag +is specified to the DB->put interface, the allocated record number +is returned to the application in the key DBT argument. +In previous releases of Berkeley DB, this DBT structure did not follow +the usual DBT conventions, e.g., it was not possible to cause +Berkeley DB to allocate space for the returned record number. Rather, it was +always assumed that the data field of the key structure +referenced memory that could be used as storage for a db_recno_t type. +

As of the Berkeley DB 3.1.0 release, the key structure behaves as +described in the DBT C++/Java class or C structure documentation. +

Applications which are using the DB_APPEND flag for Queue and +Recno access method databases will require a change to upgrade to the +Berkeley DB 3.1 releases. The simplest change is likely to be to add the +DB_DBT_USERMEM flag to the key structure. For example, +code that appears as follows: +

DBT key;
+db_recno_t recno;
+

+memset(&key, 0, sizeof(DBT)); +key.data = &recno; +key.size = sizeof(recno); +DB->put(DB, NULL, &key, &data, DB_APPEND); +printf("new record number is %lu\n", (u_long)recno);

+

would be changed to: +

DBT key;
+db_recno_t recno;
+

+memset(&key, 0, sizeof(DBT)); +key.data = &recno; +key.ulen = sizeof(recno); +key.flags = DB_DBT_USERMEM; +DB->put(DB, NULL, &key, &data, DB_APPEND); +printf("new record number is %lu\n", (u_long)recno);

+

Note that the ulen field is now set as well as the flag value. +An alternative change would be: +

DBT key;
+db_recno_t recno;
+

+memset(&key, 0, sizeof(DBT)); +DB->put(DB, NULL, &key, &data, DB_APPEND); +recno = *(db_recno_t *)key->data; +printf("new record number is %lu\n", (u_long)recno);

+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.1/set_feedback.html b/db/docs/ref/upgrade.3.1/set_feedback.html new file mode 100644 index 000000000..c7b7864b9 --- /dev/null +++ b/db/docs/ref/upgrade.3.1/set_feedback.html @@ -0,0 +1,27 @@ + + + + + +Berkeley DB Reference Guide: Release 3.1: DBENV->set_feedback, DB->set_feedback + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.1: DBENV->set_feedback, DB->set_feedback

+

Starting with the 3.1 release of Berkeley DB, the DBENV->set_feedback +and DB->set_feedback functions may return an error value, that is, they +are no longer declared as returning no value, instead they return an int +or throw an exception as appropriate when an error occurs. +

If your application calls these functions, you may want to check for a +possible error on return. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.1/set_paniccall.html b/db/docs/ref/upgrade.3.1/set_paniccall.html new file mode 100644 index 000000000..8aa554cf0 --- /dev/null +++ b/db/docs/ref/upgrade.3.1/set_paniccall.html @@ -0,0 +1,27 @@ + + + + + +Berkeley DB Reference Guide: Release 3.1: DBENV->set_paniccall, DB->set_paniccall + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.1: DBENV->set_paniccall, DB->set_paniccall

+

Starting with the 3.1 release of Berkeley DB, the DBENV->set_paniccall +and DB->set_paniccall functions may return an error value, that is, they +are no longer declared as returning no value, instead they return an int +or throw an exception as appropriate when an error occurs. +

If your application calls these functions, you may want to check for a +possible error on return. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.1/set_tx_recover.html b/db/docs/ref/upgrade.3.1/set_tx_recover.html new file mode 100644 index 000000000..9943845e8 --- /dev/null +++ b/db/docs/ref/upgrade.3.1/set_tx_recover.html @@ -0,0 +1,36 @@ + + + + + +Berkeley DB Reference Guide: Release 3.1: DBENV->set_tx_recover + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.1: DBENV->set_tx_recover

+

The redo parameter of the function passed to DBENV->set_tx_recover +used to be an integer set to any one of a number of #defined values. In +the 3.1 release of Berkeley DB, the redo parameter has been replaced by the op +parameter which is an enumerated type of type db_recops. +

If your application calls DBENV->set_tx_recover, then find the +function referenced in the call. Replace the flag values in that function +as follows: +

+ + + + + + +
Previous flagBerkeley DB 3.1 version flag
TXN_BACKWARD_ROLLDB_TXN_BACKWARD_ROLL
TXN_FORWARD_ROLLDB_TXN_FORWARD_ROLL
TXN_OPENFILESDB_TXN_OPENFILES
TXN_REDODB_TXN_FORWARD_ROLL
TXN_UNDODB_TXN_ABORT
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.1/sysmem.html b/db/docs/ref/upgrade.3.1/sysmem.html new file mode 100644 index 000000000..7e21a565e --- /dev/null +++ b/db/docs/ref/upgrade.3.1/sysmem.html @@ -0,0 +1,25 @@ + + + + + +Berkeley DB Reference Guide: Release 3.1: DB_SYSTEM_MEM + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.1: DB_SYSTEM_MEM

+

Using the DB_SYSTEM_MEM option on UNIX systems now requires the +specification of a base system memory segment ID, using the +DBENV->set_shm_key function. Any valid segment ID may be specified, for +example, one returned by the UNIX ftok(3) interface. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.1/tcl.html b/db/docs/ref/upgrade.3.1/tcl.html new file mode 100644 index 000000000..0f964abb3 --- /dev/null +++ b/db/docs/ref/upgrade.3.1/tcl.html @@ -0,0 +1,30 @@ + + + + + +Berkeley DB Reference Guide: Release 3.1: Tcl API + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.1: Tcl API

+

The Berkeley DB Tcl API has been modified so that the -mpool option to +the berkdb env command is now the default behavior. The Tcl API +has also been modified so that the -txn option to the +berkdb env command implies the -lock and -log +options. Tcl scripts should be updated to remove the -mpool, +-lock and -log options. +

The Berkeley DB Tcl API has been modified to follow the Tcl standard rules for +integer conversion, e.g., if the first two characters of a record number +are "0x", the record number is expected to be in hexadecimal form. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.1/tmp.html b/db/docs/ref/upgrade.3.1/tmp.html new file mode 100644 index 000000000..72034803b --- /dev/null +++ b/db/docs/ref/upgrade.3.1/tmp.html @@ -0,0 +1,34 @@ + + + + + +Berkeley DB Reference Guide: Release 3.1: DB_TMP_DIR + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.1: DB_TMP_DIR

+

This change only affects Win/32 applications that create in-memory +databases. +

On Win/32 platforms an additional test has been added when searching for +the appropriate directory in which to create the temporary files that are +used to back in-memory databases. Berkeley DB now uses any return value from +the GetTempPath interface as the temporary file directory name before +resorting to the static list of compiled-in pathnames. +

If the system registry does not return the same directory as Berkeley DB has +been using previously, this change could cause temporary backing files to +move to a new directory when applications are upgraded to the 3.1 release. +In extreme cases, this could create (or fix) security problems if the file +protection modes for the system registry directory are different from +those on the directory previously used by Berkeley DB. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.1/toc.html b/db/docs/ref/upgrade.3.1/toc.html new file mode 100644 index 000000000..091318810 --- /dev/null +++ b/db/docs/ref/upgrade.3.1/toc.html @@ -0,0 +1,33 @@ + + + + + +Berkeley DB: Upgrading Berkeley DB 3.0.X applications to Berkeley DB 3.1 + + + + +

Upgrading Berkeley DB 3.0.X applications to Berkeley DB 3.1

+
    +
  1. Release 3.1: introduction +
  2. Release 3.1: DBENV->open, DBENV->remove +
  3. Release 3.1: DBENV->set_tx_recover +
  4. Release 3.1: DBENV->set_feedback, DB->set_feedback +
  5. Release 3.1: DBENV->set_paniccall, DB->set_paniccall +
  6. Release 3.1: DB->put +
  7. Release 3.1: identical duplicate data items +
  8. Release 3.1: DB->stat +
  9. Release 3.1: DB_SYSTEM_MEM +
  10. Release 3.1: log_register +
  11. Release 3.1: memp_register +
  12. Release 3.1: txn_checkpoint +
  13. Release 3.1: environment configuration +
  14. Release 3.1: Tcl API +
  15. Release 3.1: DB_TMP_DIR +
  16. Release 3.1: log file pre-allocation +
  17. Release 3.1: upgrade requirements +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.1/txn_check.html b/db/docs/ref/upgrade.3.1/txn_check.html new file mode 100644 index 000000000..27dc3851f --- /dev/null +++ b/db/docs/ref/upgrade.3.1/txn_check.html @@ -0,0 +1,26 @@ + + + + + +Berkeley DB Reference Guide: Release 3.1: txn_checkpoint + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.1: txn_checkpoint

+

An additional argument has been added to the txn_checkpoint +interface. +

The application should be searched for any occurrences of +txn_checkpoint. For each one, an argument of 0 should be appended +to the current arguments. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.2/callback.html b/db/docs/ref/upgrade.3.2/callback.html new file mode 100644 index 000000000..f60a81d5c --- /dev/null +++ b/db/docs/ref/upgrade.3.2/callback.html @@ -0,0 +1,39 @@ + + + + + +Berkeley DB Reference Guide: Release 3.2: DB callback functions, app_private field + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.2: DB callback functions, app_private field

+

In the Berkeley DB 3.2 release, four application callback functions (the +callback functions set by DB->set_bt_compare, +DB->set_bt_prefix, DB->set_dup_compare and +DB->set_h_hash) were modified to take a reference to a +DB object as their first argument. This change allows the Berkeley DB +Java API to reasonably support these interfaces. There is currently no +need for the callback functions to do anything with this additional +argument. +

C and C++ applications that specify their own Btree key comparison, +Btree prefix comparison, duplicate data item comparison or Hash +functions should modify these functions to take a reference to a +DB structure as their first argument. No further change is +required. +

The app_private field of the DBT structure (accessible only from +the Berkeley DB C API) has been removed in the 3.2 release. It was replaced +with app_private fields in the DB_ENV and DB handles. +Applications using this field will have to convert to using one of the +replacement fields. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.2/db_dump.html b/db/docs/ref/upgrade.3.2/db_dump.html new file mode 100644 index 000000000..87d909086 --- /dev/null +++ b/db/docs/ref/upgrade.3.2/db_dump.html @@ -0,0 +1,29 @@ + + + + + +Berkeley DB Reference Guide: Release 3.2: db_dump + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.2: db_dump

+

In previous releases of Berkeley DB, the db_dump utility dumped Recno +access method database keys as numeric strings. For consistency, the +db_dump utility has been changed in the 3.2 release to dump +record numbers as hex pairs when the data items are being dumped as hex +pairs. (See the -k and -p options to the +db_dump utility for more information.) Any applications or +scripts post-processing the db_dump output of Recno databases +under these conditions may require modification. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.2/disk.html b/db/docs/ref/upgrade.3.2/disk.html new file mode 100644 index 000000000..8cebb9319 --- /dev/null +++ b/db/docs/ref/upgrade.3.2/disk.html @@ -0,0 +1,28 @@ + + + + + +Berkeley DB Reference Guide: Release 3.2: upgrade requirements + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.2: upgrade requirements

+

Log file formats and the Queue Access Method database formats changed +in the Berkeley DB 3.2 release. (The on-disk Queue format changed from +version 2 to version 3.) Until the underlying databases are upgraded, +the DB->open function will return a DB_OLD_VERSION error. +

For further information on upgrading Berkeley DB installations, see +Upgrading Berkeley DB +installations. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.2/handle.html b/db/docs/ref/upgrade.3.2/handle.html new file mode 100644 index 000000000..86f86a03a --- /dev/null +++ b/db/docs/ref/upgrade.3.2/handle.html @@ -0,0 +1,27 @@ + + + + + +Berkeley DB Reference Guide: Release 3.2: Java and C++ object re-use + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.2: Java and C++ object re-use

+

In previous releases of Berkeley DB, Java DbEnv and Db +objects, and C++ DbEnv and Db objects could be +re-used after they were closed, by calling open on them again. This is +no longer permitted, and these objects no longer allow any operations +after a close. Applications re-using these objects should be modified +to create new objects instead. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.2/incomplete.html b/db/docs/ref/upgrade.3.2/incomplete.html new file mode 100644 index 000000000..5aeb77559 --- /dev/null +++ b/db/docs/ref/upgrade.3.2/incomplete.html @@ -0,0 +1,39 @@ + + + + + +Berkeley DB Reference Guide: Release 3.2: DB_INCOMPLETE + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.2: DB_INCOMPLETE

+

There are a number of functions that flush pages from the Berkeley DB shared +memory buffer pool to disk. Most of those functions can potentially +fail because a page that needs to be flushed is not currently available. +However, this is not a hard failure and is rarely cause for concern. +In the Berkeley DB 3.2 release, the C++ API (if that API is configured to +throw exceptions) and the Java API have been changed so that this +failure does not throw an exception, but rather returns a non-zero error +code of DB_INCOMPLETE. +

The following C++ methods will return DB_INCOMPLETE rather than throw +an exception: Db::close, Db::sync, DbEnv::memp_sync, +DbEnv::txn_checkpoint, DbMpoolFile::sync. +

The following Java methods are now declared "public int" rather than +"public void", and will return Db.DB_INCOMPLETE rather than +throw an exception: Db.close, Db.sync, +DbEnv.txn_checkpoint. +

It is likely that the only change required by any application will be +those currently checking for a DB_INCOMPLETE return that has +been encapsulated in an exception. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.2/intro.html b/db/docs/ref/upgrade.3.2/intro.html new file mode 100644 index 000000000..df4d573a0 --- /dev/null +++ b/db/docs/ref/upgrade.3.2/intro.html @@ -0,0 +1,26 @@ + + + + + +Berkeley DB Reference Guide: Release 3.2: introduction + + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.2: introduction

+

The following pages describe how to upgrade applications coded against +the Berkeley DB 3.1 release interfaces to the Berkeley DB 3.2 release interfaces. +This information does not describe how to upgrade Berkeley DB 1.85 release +applications. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.2/mutexlock.html b/db/docs/ref/upgrade.3.2/mutexlock.html new file mode 100644 index 000000000..fb1b87ca9 --- /dev/null +++ b/db/docs/ref/upgrade.3.2/mutexlock.html @@ -0,0 +1,28 @@ + + + + + +Berkeley DB Reference Guide: Release 3.2: DBENV->set_mutexlocks + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.2: DBENV->set_mutexlocks

+

Previous Berkeley DB releases included the db_env_set_mutexlocks interface, +intended for debugging, that allows applications to always obtain +requested mutual exclusion mutexes without regard for their +availability. This interface has been replaced with +DBENV->set_mutexlocks, which provides the same functionality on +a per-database environment basis. Applications using the old interface +should be updated to use the new one. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.2/notfound.html b/db/docs/ref/upgrade.3.2/notfound.html new file mode 100644 index 000000000..cb40beaae --- /dev/null +++ b/db/docs/ref/upgrade.3.2/notfound.html @@ -0,0 +1,25 @@ + + + + + +Berkeley DB Reference Guide: Release 3.2: Java java.io.FileNotFoundException + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.2: Java java.io.FileNotFoundException

+

The Java DbEnv.remove, Db.remove and +Db.rename methods now throw java.io.FileNotFoundException +in the case where the named file does not exist. Applications should +be modified to catch this exception where appropriate. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.2/renumber.html b/db/docs/ref/upgrade.3.2/renumber.html new file mode 100644 index 000000000..619fa07ff --- /dev/null +++ b/db/docs/ref/upgrade.3.2/renumber.html @@ -0,0 +1,39 @@ + + + + + +Berkeley DB Reference Guide: Release 3.2: Logically renumbering records + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.2: Logically renumbering records

+

In the Berkeley DB 3.2 release, cursor adjustment semantics changed for Recno +databases with mutable record numbers. Before the 3.2 release, cursors +were adjusted to point to the previous or next record at the time the +record referenced by the cursor was deleted. This could lead to +unexpected behaviors. For example, two cursors referencing sequential +records that were both deleted would lose their relationship to each +other and would reference the same position in the database instead of +their original sequential relationship. There were also command +sequences that would have unexpected results. For example, DB_AFTER +and DB_BEFORE cursor put operations, using a cursor previously used to +delete an item, would perform the put relative to the cursor's adjusted +position and not its original position. +

In the Berkeley DB 3.2 release, cursors maintain their position in the tree +regardless of deletion operations using the cursor. Applications that +perform database operations, using cursors previously used to delete +entries in Recno databases with mutable record numbers, should be +evaluated to ensure that the new semantics do not cause application +failure. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.2/set_flags.html b/db/docs/ref/upgrade.3.2/set_flags.html new file mode 100644 index 000000000..b1bbe906b --- /dev/null +++ b/db/docs/ref/upgrade.3.2/set_flags.html @@ -0,0 +1,35 @@ + + + + + +Berkeley DB Reference Guide: Release 3.2: DBENV->set_flags + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.2: DBENV->set_flags

+

A new method has been added to the Berkeley DB environment handle, +DBENV->set_flags. This interface currently takes three flags: +DB_CDB_ALLDB, DB_NOMMAP and DB_TXN_NOSYNC. The +first of these flags, DB_CDB_ALLDB, provides new functionality, +allowing Berkeley DB Concurrent Data Store applications to do locking across multiple databases. +

The other two flags, DB_NOMMAP and DB_TXN_NOSYNC, were +specified to the DBENV->open method in previous releases. In +the 3.2 release, they have been moved to the DBENV->set_flags function +because this allows the database environment's value to be toggled +during the life of the application as well as because it is a more +appropriate place for them. Applications specifying either the +DB_NOMMAP or DB_TXN_NOSYNC flags to the +DBENV->open function should replace those flags with calls to the +DBENV->set_flags function. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.2/toc.html b/db/docs/ref/upgrade.3.2/toc.html new file mode 100644 index 000000000..8a466d1b4 --- /dev/null +++ b/db/docs/ref/upgrade.3.2/toc.html @@ -0,0 +1,27 @@ + + + + + +Berkeley DB: Upgrading Berkeley DB 3.1.X applications to Berkeley DB 3.2 + + + + +

Upgrading Berkeley DB 3.1.X applications to Berkeley DB 3.2

+
    +
  1. Release 3.2: introduction +
  2. Release 3.2: DBENV->set_flags +
  3. Release 3.2: DB callback functions, app_private field +
  4. Release 3.2: logically renumbering records +
  5. Release 3.2: DB_INCOMPLETE +
  6. Release 3.2: DBENV->set_tx_recover +
  7. Release 3.2: DBENV->set_mutexlocks +
  8. Release 3.2: Java and C++ object re-use +
  9. Release 3.2: Java java.io.FileNotFoundException +
  10. Release 3.2: db_dump +
  11. Release 3.2: upgrade requirements +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade.3.2/tx_recover.html b/db/docs/ref/upgrade.3.2/tx_recover.html new file mode 100644 index 000000000..c5cf18ebc --- /dev/null +++ b/db/docs/ref/upgrade.3.2/tx_recover.html @@ -0,0 +1,32 @@ + + + + + +Berkeley DB Reference Guide: Release 3.2: DBENV->set_tx_recover + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Release 3.2: DBENV->set_tx_recover

+

The info parameter of the function passed to +DBENV->set_tx_recover is no longer needed. If your application +calls DBENV->set_tx_recover, find the callback function referenced +in that call and remove the info parameter. +

In addition, the called function no longer needs to handle Berkeley DB log +records, Berkeley DB will handle them internally as well as call the +application-specified function. Any handling of Berkeley DB log records in the +application's callback function may be removed. +

In addition, the callback function will no longer be called with the +DB_TXN_FORWARD_ROLL flag specified unless the transaction +enclosing the operation successfully committed. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/upgrade/process.html b/db/docs/ref/upgrade/process.html new file mode 100644 index 000000000..40be3c8e8 --- /dev/null +++ b/db/docs/ref/upgrade/process.html @@ -0,0 +1,108 @@ + + + + + +Berkeley DB Reference Guide: Upgrading Berkeley DB installations + + + + + + +

Berkeley DB Reference Guide:
Upgrading Berkeley DB Applications

PrevRefNext +
+

+

Upgrading Berkeley DB installations

+

The following information describes the general process of upgrading +Berkeley DB installations. There are three issues to be considered when +upgrading Berkeley DB applications and database environments. They are the +application API, the underlying database formats, and, in the case of +transactional database environments, the log files. +

An application must always be re-compiled to use a new Berkeley DB release. +Internal Berkeley DB interfaces may change at any time and in any release, +without warning. This means the application and library must be entirely +recompiled and reinstalled when upgrading to new releases of the +library, as there is no guarantee that modules from one version of the +library will interact correctly with modules from another release. +

A Berkeley DB patch release will never modify the Berkeley DB API, log file or +database formats in non-backward compatible ways. Berkeley DB minor and major +releases may optionally include changes to the Berkeley DB application API, +log files and database formats that are not backward compatible. Note, +that there are several underlying Berkeley DB database formats. As all of +them do not necessarily change at the same time, changes to one database +format in a release may not affect any particular application. +

Each Berkeley DB minor or major release has an upgrading section in this +chapter of the Berkeley DB Reference Guide. The section describes any API +changes that were made in the release. Application maintainers must +review the API changes, update their applications as necessary, and then +re-compile using the new release. In addition, each section includes +a page specifying if the log file format or database formats changed in +non-backward compatible ways as part of the release. +

If the application does not have a Berkeley DB transactional environment, the +re-compiled application may be installed in the field using the +following steps: +

    +

  1. Shut down the old version of the application. +

  2. Remove any Berkeley DB environment, using the DBENV->remove function or an +appropriate system utility. +

  3. Install the new version of the application. +

  4. If the database format has changed, upgrade the application's databases. +See Upgrading databases for more +information. +

  5. Re-start the application. +
+

If the application has a Berkeley DB transactional environment, but neither +the log file or database formats have changed, the re-compiled +application may be installed in the field using the following steps: +

    +

  1. Shut down the old version of the application. +

  2. Run recovery on the database environment, using the DBENV->open function +or the db_recover utility. +

  3. Install the new version of the application. +

  4. Re-start the application. +
+

If the application has a Berkeley DB transactional environment, and the log +file format has changed but the database formats have not, the +re-compiled application may be installed in the field using the +following steps: +

    +

  1. Shut down the old version of the application. +

  2. Run recovery on the database environment, using the DBENV->open function +or the db_recover utility. +

  3. Archive the database environment for catastrophic recovery. See +Archival procedures for more +information. +

  4. Install the new version of the application. +

  5. Re-start the application. +
+

If the application has a Berkeley DB transactional environment and the +database format has changed, the re-compiled application may be +installed in the field using the following steps: +

    +

  1. Shut down the old version of the application. +

  2. Run recovery on the database environment, using the DBENV->open function +or the db_recover utility. +

  3. Archive the database environment for catastrophic recovery. See +Archival procedures for more +information. +

  4. Install the new version of the application. +

  5. Upgrade the application's databases. See +Upgrading databases for more +information. +

  6. Archive the database for catastrophic recovery again (using different +media than before, of course). +

    This archival is not strictly necessary. However, if you have to perform +catastrophic recovery after restarting your applications, that recovery +must be done based on the last archive you have made. If you make this +archive, you can use it as the basis of your catastrophic recovery. If +you do not make this archive, you will have to use the archive you made +in step #2 as the basis of your recovery, and you will have to upgrade it +as described in step #3 before you can apply your log files to it. +

  7. Re-start the application. +
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/xa/config.html b/db/docs/ref/xa/config.html new file mode 100644 index 000000000..cfe31f372 --- /dev/null +++ b/db/docs/ref/xa/config.html @@ -0,0 +1,79 @@ + + + + + +Berkeley DB Reference Guide: Configuring Berkeley DB with the Tuxedo System + + + + + + + +

Berkeley DB Reference Guide:
XA Resource Manager

PrevRefNext +
+

+

Configuring Berkeley DB with the Tuxedo System

+

This information assumes that you have already installed the Berkeley DB +library. +

First, you must update the resource manager file in Tuxedo. For the +purposes of this discussion, assume the Tuxedo home directory is in: +

/home/tuxedo
+In that case, the resource manager file will be located in: +

/home/tuxedo/udataobj/RM
+Edit the resource manager file, adding the following line: +

BERKELEY-DB:db_xa_switch:-L${DB_INSTALL}/lib -ldb \
+	-lsocket -ldl -lm
+

where ${DB_INSTALLHOME} is the directory into which you installed the Berkeley DB +library. +

Note, the above load options are for a Sun Microsystems Solaris +5.6 Sparc installation of Tuxedo, and may not be correct for your system. +

Next, you must build the transaction manager server. To do this, use the +Tuxedo buildtms(1) utility. The buildtms utility will create +the Berkeley-DB resource manager in the directory from which it was run. +The parameters to buildtms should be: +

buildtms -v -o DBRM -r BERKELEY-DB
+

This will create an executable transaction manager server, DBRM, that is +called by Tuxedo to process begins, commits, and aborts. +

Finally, you must make sure that your TUXCONFIG environment variable +identifies a ubbconfig file that properly identifies your resource +managers. In the GROUPS section of the ubb file, you should identify the +group's LMID and GRPNO as well as the transaction manager server name +"TMSNAME=DBRM." You must also specify the OPENINFO parameter, setting it +equal to the string: +

rm_name:dir
+

where rm_name is the resource name specified in the RM file (i.e., +BERKELEY-DB) and dir is the directory for the Berkeley DB home environment +(see DBENV->open for a discussion of Berkeley DB environments). +

As Tuxedo resource manager startup accepts only a single string for +configuration, any environment customization that might have been done +via the config parameter to DBENV->open must instead be done by +placing a DB_CONFIG file in the Berkeley DB environment directory. See +Berkeley DB File Naming for further +information. +

Consider the following configuration. We have built a transaction +manager server as described above. We want the Berkeley DB environment +to be /home/dbhome, our database files to be maintained +in /home/datafiles, our log files to be maintained in +/home/log, and we want a duplexed server. +

The GROUPS section of the ubb file might look like: +

group_tm LMID=myname GRPNO=1 TMSNAME=DBRM TMSCOUNT=2 \
+	OPENINFO="BERKELEY-DB:/home/dbhome"
+

There would be a DB_CONFIG configuration file in the directory +/home/dbhome that contained the following two lines: +

DB_DATA_DIR	/home/datafiles
+DB_LOG_DIR	/home/log
+
+

Finally, the ubb file must be translated into a binary version, using +Tuxedo's tmloadcf(1) utility, and then the pathname of that +binary file must be specified as your TUXCONFIG environment variable. +

At this point, your system is properly initialized to use the Berkeley DB +resource manager. +

See db_create for further information on accessing data files +using XA. +

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/xa/faq.html b/db/docs/ref/xa/faq.html new file mode 100644 index 000000000..db1e26a0b --- /dev/null +++ b/db/docs/ref/xa/faq.html @@ -0,0 +1,55 @@ + + + + + +Berkeley DB Reference Guide: Frequently Asked Questions + + + + + + +

Berkeley DB Reference Guide:
XA Resource Manager

PrevRefNext +
+

+

Frequently Asked Questions

+

    +

  1. Does converting an application to run within XA change any of +the already existing C/C++ API calls it does? +

    When converting an application to run under XA, the application's Berkeley DB +calls are unchanged, with two exceptions: +

      +

    1. The application must use specify the DB_XA_CREATE flag +to the db_create interface. +

    2. The application should never explicitly call txn_commit, +txn_abort or txn_begin, as those calls are replaced by +calls into the Tuxedo transaction manager. For the same reason, the +application will always specify a transaction argument of NULL to the +Berkeley DB functions that take transaction arguments (e.g., DB->put or +DB->cursor). +
    +

    Otherwise, your application should be unchanged. +


    +

  2. Is it possible to mix XA and non-XA transactions? +

    Yes. It is also possible for XA and non-XA transactions to co-exist in +the same Berkeley DB environment. To do this, specify the same environment to +the non-XA DBENV->open calls as was specified in the Tuxedo +configuration file. +


    +

  3. How does Berkeley DB recovery interact with recovery by the transaction +manager? +

    When the Tuxedo recovery calls the Berkeley DB recovery functions, the standard +Berkeley DB recovery procedures occur, for all operations that are represented +in the Berkeley DB log files. This includes any non-XA transactions that were +performed in the environment. Of course, this means that you can't use +the standard Berkeley DB utilities (e.g., db_recover) to perform +recovery. +

    Also, standard log file archival and catastrophic recovery procedures +should occur independently of XA operation. +

+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/ref/xa/intro.html b/db/docs/ref/xa/intro.html new file mode 100644 index 000000000..7643ee420 --- /dev/null +++ b/db/docs/ref/xa/intro.html @@ -0,0 +1,61 @@ + + + + + +Berkeley DB Reference Guide: Introduction + + + + + + + +

Berkeley DB Reference Guide:
XA Resource Manager

PrevRefNext +
+

+

Introduction

+

Berkeley DB can be used as an XA-compliant resource manager. The XA +implementation is known to work with the Tuxedo(tm) transaction +manager. +

The XA support is encapsulated in the resource manager switch +db_xa_switch, which defines the following functions: +

__db_xa_close     Close the resource manager.
+__db_xa_commit    Commit the specified transaction.
+__db_xa_complete  Wait for asynchronous operations to
+                  complete.
+__db_xa_end       Disassociate the application from a
+                  transaction.
+__db_xa_forget    Forget about a transaction that was heuristically
+                  completed. (Berkeley DB does not support heuristic
+                  completion.)
+__db_xa_open      Open the resource manager.
+__db_xa_prepare   Prepare the specified transaction.
+__db_xa_recover   Return a list of prepared, but not yet
+                  committed transactions.
+__db_xa_rollback  Abort the specified transaction.
+__db_xa_start     Associate the application with a
+                  transaction.
+
+

The Berkeley DB resource manager does not support the following optional +XA features: +

    +
  • Asynchronous operations. +
  • Transaction migration. +
+

The Tuxedo System is available from BEA Systems, Inc. +

For additional information on Tuxedo, see: +

Building Client/Server Applications Using Tuxedo, +by Hall, John Wiley & Sons, Inc. Publishers.
+

For additional information on XA Resource Managers, see: +

X/Open CAE Specification +Distributed Transaction Processing: The XA Specification, +X/Open Document Number: XO/CAE/91/300.
+

For additional information on The Tuxedo System, see: +

The Tuxedo System, +by Andrade, Carges, Dwyer and Felts, Addison Wesley Longman Publishers.
+

PrevRefNext +
+

Copyright Sleepycat Software + + diff --git a/db/docs/sleepycat/contact.html b/db/docs/sleepycat/contact.html new file mode 100644 index 000000000..c2d1e7f0a --- /dev/null +++ b/db/docs/sleepycat/contact.html @@ -0,0 +1,107 @@ + + + +The Sleepycat Software Contact Page + + + + + +

+Sleepycat Software Inc. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +General: + + +db@sleepycat.com +

+ +Sales and Marketing: + + +sales@sleepycat.com
++1-510-526-3972
++1-877-SLEEPYCAT (USA only, toll-free)
+

+ +Technical Support: + + +support@sleepycat.com +

+ +Web Site: + + +webmaster@sleepycat.com +

+ +Press Inquiries: + + +Michael Olson, VP Marketing
+Sleepycat Software, Inc.
+mao@sleepycat.com +

+ +Postal Mail: + + +Massachussetts Corporate Office
+
+Sleepycat Software Inc.
+394 E. Riding Dr.
+Carlisle, MA 01741-1601
+
+ +West Coast Sales Office
+
+Sleepycat Software Inc.
+1509 McGee St.
+Berkeley CA 94703
+
+ + + diff --git a/db/docs/sleepycat/legal.html b/db/docs/sleepycat/legal.html new file mode 100644 index 000000000..1945b3976 --- /dev/null +++ b/db/docs/sleepycat/legal.html @@ -0,0 +1,56 @@ + + + + + +Berkeley DB: Sleepycat Software Legal Notices + + + + +

Sleepycat Software Legal Notices

+

Copyright (c) 1990-2000 Sleepycat Software, Inc., 394 E. Riding Dr., +Carlisle, MA 01741-1601 U.S.A. All Rights Reserved. +

This product and publication is protected by copyright and distributed +under licenses restricting its use, copying and distribution. Permission +to use this publication or portions of this publication is granted by +Sleepycat Software provided that the above copyright notice appears in +all copies and that use of such publications is for non-commercial use +only and no modifications of the publication is made. +

RESTRICTED RIGHTS: Use, duplication, or disclosure by the U.S. Government +is subject to restrictions of FAR 52.227-14(g)(2)(6/87) and FAR +52.227-19(6/87), or DFAR 252.227-7015(b)(6/95) and DFAR 227.7202-3(a). +

Sleepycat and the names of Sleepycat Software products referenced herein +are either trademarks and/or service marks or registered trademarks and/or +service marks of Sleepycat Software Inc. +

Sun Microsystems, SunOS and Solaris are trademarks or registered +trademarks of Sun Microsystems, Inc. +

Hewlett-Packard and HP-UX are trademarks or registered trademarks of +Hewlett-Packard Company. +

DIGITAL and ULTRIX are trademarks or registered trademarks of Digital +Equipment Corporation. +

Microsoft, Windows and Windows NT are trademarks or registered trademarks +of Microsoft Corporation. +

TUXEDO is a trademark or registered trademark of BEA Systems, Inc. +

All other brand, company and product names referenced in this publication +may be trademarks, registered trademarks or service marks of their +respective holders and are used here for informational purposes only. +

WARNING: There is a non-zero chance that, through a process know as +"tunneling," this product may spontaneously disappear from its present +location and reappear at any random place in the universe. Sleepycat +Software will not be responsible for damages or inconvenience that may +result. +

THIS PRODUCT IS PROVIDED BY SLEEPYCAT SOFTWARE "AS IS" AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, +ARE DISCLAIMED. IN NO EVENT SHALL SLEEPYCAT SOFTWARE BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. +

Copyright Sleepycat Software + + diff --git a/db/docs/sleepycat/license.html b/db/docs/sleepycat/license.html new file mode 100644 index 000000000..1407eed05 --- /dev/null +++ b/db/docs/sleepycat/license.html @@ -0,0 +1,109 @@ + + + + + +Berkeley DB: Sleepycat Software Product License + + + + +

Sleepycat Software Product License

+

The following is the license that applies to this copy of the Berkeley DB +software. For a license to use the Berkeley DB software under conditions +other than those described here, or to purchase support for this software, +please contact Sleepycat Software. +

/*
+ * Copyright (c) 1990-2000
+ *	Sleepycat Software.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Redistributions in any form must be accompanied by information on
+ *    how to obtain complete source code for the DB software and any
+ *    accompanying software that uses the DB software.  The source code
+ *    must either be included in the distribution or be available for no
+ *    more than the cost of distribution plus a nominal fee, and must be
+ *    freely redistributable under reasonable conditions.  For an
+ *    executable file, complete source code means the source code for all
+ *    modules it contains.  It does not include source code for modules or
+ *    files that typically accompany the major components of the operating
+ *    system on which the executable file runs.
+ *
+ * THIS SOFTWARE IS PROVIDED BY SLEEPYCAT SOFTWARE ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ * NON-INFRINGEMENT, ARE DISCLAIMED.  IN NO EVENT SHALL SLEEPYCAT SOFTWARE
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 1990, 1993, 1994, 1995
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 1995, 1996
+ *	The President and Fellows of Harvard University.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY HARVARD AND ITS CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL HARVARD OR ITS CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+

Copyright Sleepycat Software + + diff --git a/db/docs/utility/berkeley_db_svc.html b/db/docs/utility/berkeley_db_svc.html new file mode 100644 index 000000000..9e9c7bb4e --- /dev/null +++ b/db/docs/utility/berkeley_db_svc.html @@ -0,0 +1,88 @@ + + + + + +Berkeley DB: berkeley_db_svc + + + + + + + +
+

berkeley_db_svc

+
+APIRef +
+


+ +

berkeley_db_svc [-Vv] [-h home]
+    [-I seconds] [-L file] [-t seconds] [-T seconds]

+

Description

+ +

The berkeley_db_svc utility is the Berkeley DB RPC server. +

The options are as follows: +

+

-h
Add the specified home directory to the list of allowed home directories +that can be specified by the client. The home directory should be an +absolute pathname. The last component of each home directory specified +must be unique, as that is how clients specify which database environment +they wish to join. +

Recovery will be run on each specified environment before the server +begins accepting requests from clients. For this reason, only one copy +of the server program should ever be run at any time, as recovery must +always be single-threaded. +

-I
Set the default idle timeout for client environments to the specified +number of seconds. The default timeout is 24 hours. +

-L
Log the execution of the berkeley_db_svc utility to the specified file in the +following format, where ### is the process ID, and the date +is the time the utility was started. +

berkeley_db_svc: ### Wed Jun 15 01:23:45 EDT 1995
+This file will be removed if the berkeley_db_svc utility exits gracefully. +

-t
Set the default timeout for client resources (idle transactions and +cursors) to the +specified number of seconds. When the timeout expires, if the +resource is a transaction, it is aborted, if the resource is +a cursor, it is closed. +The default timeout is 5 minutes. +

-T
Set the maximum timeout allowed for client resources. +The default timeout is 20 minutes. +If a client application requests a server timeout +greater than the maximum timeout set for this server, then the client's +timeout will be capped at the maximum timeout value. +

-V
Write the version number to the standard output and exit. +

-v
Run in verbose mode. +
+

The berkeley_db_svc utility uses a Berkeley DB environment (as described for the +-h option, the environment variable DB_HOME, or, +because the utility was run in a directory containing a Berkeley DB +environment). In order to avoid environment corruption when using a Berkeley DB +environment, berkeley_db_svc should always be given the chance to detach from +the environment and exit gracefully. To cause berkeley_db_svc to release all +environment resources and exit cleanly, send it an interrupt signal +(SIGINT). +

The berkeley_db_svc utility exits 0 on success, and >0 if an error occurs. +

Environment Variables

+

+

DB_HOME
If the -h option is not specified and the environment variable +DB_HOME is set, it is used as the path of the database home, as described +in DBENV->open. +
+

See Also

+berkeley_db_svc, +db_archive, +db_checkpoint, +db_deadlock, +db_dump, +db_load, +db_recover, +db_stat, +db_upgrade, +and +db_verify. +
+

Copyright Sleepycat Software + + diff --git a/db/docs/utility/db_archive.html b/db/docs/utility/db_archive.html new file mode 100644 index 000000000..5cc56a428 --- /dev/null +++ b/db/docs/utility/db_archive.html @@ -0,0 +1,85 @@ + + + + + +Berkeley DB: db_archive + + + + + + + +
+

db_archive

+
+APIRef +
+


+ +

db_archive [-alsVv] [-h home]

+

Description

+ +

The db_archive utility writes the pathnames of log files that are +no longer in use (e.g., no longer involved in active transactions), to +the standard output, one pathname per line. These log files should be +written to backup media to provide for recovery in the case of +catastrophic failure (which also requires a snapshot of the database +files), but they may then be deleted from the system to reclaim disk +space. +

The options are as follows: +

+

-a
Write all pathnames as absolute pathnames, +instead of relative to the database home directories. +

-h
Specify a home directory for the database environment; by +default, the current working directory is used. +

-l
Write out the pathnames of all of the database log files, +whether or not they are involved in active transactions. +

-s
Write the pathnames of all of the database files that need to be archived +in order to recover the database from catastrophic failure. +If any of the database files have not been accessed during the lifetime of +the current log files, db_archive will +not include them in this +output. +

It is possible that some of the files referenced in the log have since +been deleted from the system. +In this case, db_archive will ignore them. +When db_recover is run, any files referenced in the log that +are not present during recovery are assumed to have been deleted and will +not be recovered. +

-V
Write the version number to the standard output and exit. +

-v
Run in verbose mode, listing the checkpoints in the log files as they +are reviewed. +
+

The db_archive utility uses a Berkeley DB environment (as described for the +-h option, the environment variable DB_HOME, or, +because the utility was run in a directory containing a Berkeley DB +environment). In order to avoid environment corruption when using a Berkeley DB +environment, db_archive should always be given the chance to detach from +the environment and exit gracefully. To cause db_archive to release all +environment resources and exit cleanly, send it an interrupt signal +(SIGINT). +

The db_archive utility exits 0 on success, and >0 if an error occurs. +

Environment Variables

+

+

DB_HOME
If the -h option is not specified and the environment variable +DB_HOME is set, it is used as the path of the database home, as described +in DBENV->open. +
+

See Also

+berkeley_db_svc, +db_archive, +db_checkpoint, +db_deadlock, +db_dump, +db_load, +db_recover, +db_stat, +db_upgrade, +and +db_verify. +
+

Copyright Sleepycat Software + + diff --git a/db/docs/utility/db_checkpoint.html b/db/docs/utility/db_checkpoint.html new file mode 100644 index 000000000..dc49d03d8 --- /dev/null +++ b/db/docs/utility/db_checkpoint.html @@ -0,0 +1,82 @@ + + + + + +Berkeley DB: db_checkpoint + + + + + + + +
+

db_checkpoint

+
+APIRef +
+


+ +

db_checkpoint [-1Vv]
+    [-h home] [-k kbytes] [-L file] [-p min]

+

Description

+ +

The db_checkpoint utility is a daemon process that monitors the +database log and periodically calls txn_checkpoint to checkpoint it. +

The options are as follows: +

+

-1
Checkpoint the log once, regardless of whether or not there has +been activity since the last checkpoint, and then exit. +

-h
Specify a home directory for the database environment; by +default, the current working directory is used. +

-k
Checkpoint the database at least as often as every kbytes of log +file are written. +

-L
Log the execution of the db_checkpoint utility to the specified file in the +following format, where ### is the process ID, and the date +is the time the utility was started. +

db_checkpoint: ### Wed Jun 15 01:23:45 EDT 1995
+This file will be removed if the db_checkpoint utility exits gracefully. +

-p
Checkpoint the database at least every min minutes if +there has been any activity since the last checkpoint. +

-V
Write the version number to the standard output and exit. +

-v
Write the time of each checkpoint attempt to the standard +output. +
+

At least one of the -1, -k and -p options must +be specified. +

The db_checkpoint utility uses a Berkeley DB environment (as described for the +-h option, the environment variable DB_HOME, or, +because the utility was run in a directory containing a Berkeley DB +environment). In order to avoid environment corruption when using a Berkeley DB +environment, db_checkpoint should always be given the chance to detach from +the environment and exit gracefully. To cause db_checkpoint to release all +environment resources and exit cleanly, send it an interrupt signal +(SIGINT). +

The db_checkpoint utility does not attempt to create the Berkeley DB +shared memory regions if they do not already exist. The application +which creates the region should be started first, and then, once the +region is created, the db_checkpoint utility should be started. +

The db_checkpoint utility exits 0 on success, and >0 if an error occurs. +

Environment Variables

+

+

DB_HOME
If the -h option is not specified and the environment variable +DB_HOME is set, it is used as the path of the database home, as described +in DBENV->open. +
+

See Also

+berkeley_db_svc, +db_archive, +db_checkpoint, +db_deadlock, +db_dump, +db_load, +db_recover, +db_stat, +db_upgrade, +and +db_verify. +
+

Copyright Sleepycat Software + + diff --git a/db/docs/utility/db_deadlock.html b/db/docs/utility/db_deadlock.html new file mode 100644 index 000000000..dfd23a903 --- /dev/null +++ b/db/docs/utility/db_deadlock.html @@ -0,0 +1,85 @@ + + + + + +Berkeley DB: db_deadlock + + + + + + + +
+

db_deadlock

+
+APIRef +
+


+ +

db_deadlock [-Vvw]
+    [-a o | y] [-h home] [-L file] [-t sec]

+

Description

+ +

The db_deadlock utility traverses the database lock structures +and aborts a lock request each time it detects a deadlock. By default, +a random lock request is chosen to be aborted. This utility should be +run as a background daemon, or the underlying Berkeley DB deadlock detection +interfaces should be called in some other way, whenever there are +multiple threads or processes accessing a database and at least one of +them is modifying it. +

The options are as follows: +

+

-a
When a deadlock is detected, abort the oldest (o) lock request or the +youngest (y) lock request. +

-h
Specify a home directory for the database environment; by +default, the current working directory is used. +

-L
Log the execution of the db_deadlock utility to the specified file in the +following format, where ### is the process ID, and the date +is the time the utility was started. +

db_deadlock: ### Wed Jun 15 01:23:45 EDT 1995
+This file will be removed if the db_deadlock utility exits gracefully. +

-t
Initiate a pass over the database locks at least every sec +seconds. +

-V
Write the version number to the standard output and exit. +

-v
Run in verbose mode, generating messages each time the detector runs. +

-w
Make a single pass over the database locks every time a process is +forced to wait for a lock. +
+

At least one of the -t and -w options must be specified. +

The db_deadlock utility uses a Berkeley DB environment (as described for the +-h option, the environment variable DB_HOME, or, +because the utility was run in a directory containing a Berkeley DB +environment). In order to avoid environment corruption when using a Berkeley DB +environment, db_deadlock should always be given the chance to detach from +the environment and exit gracefully. To cause db_deadlock to release all +environment resources and exit cleanly, send it an interrupt signal +(SIGINT). +

The db_deadlock utility does not attempt to create the Berkeley DB +shared memory regions if they do not already exist. The application +which creates the region should be started first, and then, once the +region is created, the db_deadlock utility should be started. +

The db_deadlock utility exits 0 on success, and >0 if an error occurs. +

Environment Variables

+

+

DB_HOME
If the -h option is not specified and the environment variable +DB_HOME is set, it is used as the path of the database home, as described +in DBENV->open. +
+

See Also

+berkeley_db_svc, +db_archive, +db_checkpoint, +db_deadlock, +db_dump, +db_load, +db_recover, +db_stat, +db_upgrade, +and +db_verify. +
+

Copyright Sleepycat Software + + diff --git a/db/docs/utility/db_dump.html b/db/docs/utility/db_dump.html new file mode 100644 index 000000000..bd97b307c --- /dev/null +++ b/db/docs/utility/db_dump.html @@ -0,0 +1,128 @@ + + + + + +Berkeley DB: db_dump + + + + + + + +
+

db_dump

+
+APIRef +
+


+ +

db_dump [-klNpRrV] [-d ahr]
+	[-f output] [-h home] [-s database] file
+db_dump185 [-p] [-f output] file

+

Description

+ +

The db_dump utility reads the database file file and +writes it to the standard output using a portable flat-text format +understood by the db_load utility. The argument file +must be a file produced using the Berkeley DB library functions. +

The db_dump185 utility is similar to the db_dump utility +except that it reads databases in the format used by Berkeley DB versions 1.85 +and 1.86. +

The options are as follows: +

+

-d
Dump the specified database in a format helpful for debugging the Berkeley DB +library routines. +

+

a
Display all information. +
h
Display only page headers. +
r
Do not display the free-list or pages on the free list. This +mode is used by the recovery tests. +
+

The output format of the -d option is not standard and may change, +without notice, between releases of the Berkeley DB library. +

-f
Write to the specified file instead of to the standard output. +

-h
Specify a home directory for the database environment; by +default, the current working directory is used. +

-k
Dump record numbers from Queue and Recno databases as keys. +

-l
List the databases stored in the file. +

-N
Do not acquire shared region locks while running. Other problems such as +potentially fatal errors in Berkeley DB will be ignored as well. This option +is intended only for debugging errors and should not be used under any +other circumstances. +

-p
If characters in either the key or data items are printing characters (as +defined by isprint(3)), use printing characters in file +to represent them. This option permits users to use standard text editors +and tools to modify the contents of databases. +

Note, different systems may have different notions as to what characters +are considered printing characters, and databases dumped in +this manner may be less portable to external systems. +

-R
Aggressively salvage data from a possibly corrupt file. The -R +flag differs from the -r option in that it will return all +possible data from the file at the risk of also returning already deleted +or otherwise nonsensical items. Data dumped in this fashion will almost +certainly have to be edited by hand or other means before the data is +ready for re-load into another database +

-r
Salvage data from a possibly corrupt file. When used on a uncorrupted +database, this option should return equivalent data to a normal dump, but +most likely in a different order. +

-s
Specify a single database to dump. If no database is specified, all +databases in the database file are dumped. +

-V
Write the version number to the standard output and exit. +
+

Dumping and reloading Hash databases that use user-defined hash functions +will result in new databases that use the default hash function. +While using the default hash function may not be optimal for the new database, +it will continue to work correctly. +

Dumping and reloading Btree databases that use user-defined prefix or +comparison functions will result in new databases that use the default +prefix and comparison functions. +In this case, it is quite likely that the database will be damaged +beyond repair permitting neither record storage or retrieval. +

The only available workaround for either case is to modify the sources +for the db_load utility to load the database using the correct +hash, prefix and comparison functions. +

The db_dump185 utility may not be available on your system as it +is not always built when the Berkeley DB libraries and utilities are installed. +If you are unable to find it, see your system administrator for further +information. +

The db_dump and db_dump185 utility output formats are +documented in the Dump Output +Formats section of the Reference Guide. +

The db_dump utility may be used with a Berkeley DB environment (as described for the +-h option, the environment variable DB_HOME, or, +because the utility was run in a directory containing a Berkeley DB +environment). In order to avoid environment corruption when using a Berkeley DB +environment, db_dump should always be given the chance to detach from +the environment and exit gracefully. To cause db_dump to release all +environment resources and exit cleanly, send it an interrupt signal +(SIGINT). +

When using an Berkeley DB database environment, the db_dump utility +does not configure for any kind of database locking and so should not +be used with active Berkeley DB environments. If db_dump is used in +an active database environment, corruption may result. +

The db_dump utility exits 0 on success, and >0 if an error occurs. +

The db_dump185 utility exits 0 on success, and >0 if an error occurs. +

Environment Variables

+

+

DB_HOME
If the -h option is not specified and the environment variable +DB_HOME is set, it is used as the path of the database home, as described +in DBENV->open. +
+

See Also

+berkeley_db_svc, +db_archive, +db_checkpoint, +db_deadlock, +db_dump, +db_load, +db_recover, +db_stat, +db_upgrade, +and +db_verify. +
+

Copyright Sleepycat Software + + diff --git a/db/docs/utility/db_load.html b/db/docs/utility/db_load.html new file mode 100644 index 000000000..41084f09c --- /dev/null +++ b/db/docs/utility/db_load.html @@ -0,0 +1,151 @@ + + + + + +Berkeley DB: db_load + + + + + + + +
+

db_load

+
+APIRef +
+


+ +

db_load [-nTV] [-c name=value] [-f file]
+    [-h home] [-t btree | hash | queue | recno] file

+

Description

+ +

The db_load utility reads from the standard input and loads it +into the database file. The database file is created if +it does not already exist. +

The input to db_load must be in the output format specified by the +db_dump utility, utilities, or as specified for the -T +below. +

The options are as follows: +

+

-c
Specify configuration options ignoring any value they may have based on +the input. The command-line format is name=value. See +Supported Keywords for a +list of supported words for the -c option. +

-f
Read from the specified input file instead of from the standard +input. +

-h
Specify a home directory for the database environment. +

If a home directory is specified, the database environment is opened using +the DB_INIT_LOCK, DB_INIT_LOG, DB_INIT_MPOOL, +DB_INIT_TXN and DB_USE_ENVIRON flags to +DBENV->open. (This means that db_load can be used to load +data into databases while they are in use by other processes.) If the +DBENV->open call fails, or if no home directory is specified, the +database is still updated, but the environment is ignored, e.g., no +locking is done. +

-n
Do not overwrite existing keys in the database when loading into an +already existing database. If a key/data pair cannot be loaded into the +database for this reason, a warning message is displayed on the standard +error output and the key/data pair are skipped. +

-T
The -T option allows non-Berkeley DB applications to easily load text +files into databases. +

If the database to be created is of type Btree or Hash, or the keyword +keys is specified as set, the input must be paired lines of text, +where the first line of the pair is the key item, and the second line of +the pair is its corresponding data item. If the database to be created +is of type Queue or Recno and the keywork keys is not set, the +input must be lines of text, where each line is a new data item for the +database. +

A simple escape mechanism, where newline and backslash (\) +characters are special, is applied to the text input. Newline characters +are interpreted as record separators. Backslash characters in the text +will be interpreted in one of two ways: if the backslash character +precedes another backslash character, the pair will be interpreted as a +literal backslash. If the backslash character precedes any other +character, the two characters following the backslash will be interpreted +as hexadecimal specification of a single character, e.g., \0a +is a newline character in the ASCII character set. +

For this reason, any backslash or newline characters that naturally +occur in the text input must be escaped to avoid misinterpretation by +db_load. +

If the -T option is specified, the underlying access method type +must be specified using the -t option. +

-t
Specify the underlying access method. If no -t option is +specified, the database will be loaded into a database of the same type +as was dumped, e.g., a Hash database will be created if a Hash database +was dumped. +

Btree and Hash databases may be converted from one to the other. Queue +and Recno databases may be converted from one to the other. If the +-k option was specified on the call to db_dump then Queue +and Recno databases may be converted to Btree or Hash, with the key being +the integer record number. +

-V
Write the version number to the standard output and exit. +
+

The db_load utility may be used with a Berkeley DB environment (as described for the +-h option, the environment variable DB_HOME, or, +because the utility was run in a directory containing a Berkeley DB +environment). In order to avoid environment corruption when using a Berkeley DB +environment, db_load should always be given the chance to detach from +the environment and exit gracefully. To cause db_load to release all +environment resources and exit cleanly, send it an interrupt signal +(SIGINT). +

The db_load utility exits 0 on success, 1 if one or more key/data +pairs were not loaded into the database because the key already existed, +and >1 if an error occurs. +

Examples

+

The db_load utility can be used to load text files into databases. +For example, the following command loads the standard UNIX +/etc/passwd file into a database, with the login name as the +key item and the entire password entry as the data item: +

awk -F: '{print $1; print $0}' < /etc/passwd |
+    sed 's/\\/\\\\/g' | db_load -T -t hash passwd.db
+

Note that backslash characters naturally occurring in the text are escaped +to avoid interpretation as escape characters by db_load. +

Environment Variables

+

+

DB_HOME
If the -h option is not specified and the environment variable +DB_HOME is set, it is used as the path of the database home, as described +in DBENV->open. +
+

Supported Keywords

+The following keywords are supported for the -c command-line +option to the db_load utility. See DB->open for further +discussion of these keywords and what values should be specified. +

The parenthetical listing specifies how the value part of the +name=value pair is interpreted. Items listed as (boolean) expect +value to be 1 (set) or 0 (unset). Items listed as +(number) convert value to a number. Items listed as (string) use the +string value without modification. +

+
bt_minkey (number)
The minimum number of keys per page. +
database (string)
The database to load. +
db_lorder (number)
The byte order for integers in the stored database metadata. +
db_pagesize (number)
The size of pages used for nodes in the tree, in bytes. +
duplicates (boolean)
The value of the DB_DUP flag. +
dupsort (boolean)
The value of the DB_DUPSORT flag. +
h_ffactor (number)
The density within the Hash database. +
h_nelem (number)
The size of the Hash database. +
keys (boolean)
Specify if keys are present for Queue or Recno databases. +
re_len (number)
Specify fixed-length records of the specified length. +
re_pad (string)
Specify the fixed-length record pad character. +
recnum (boolean)
The value of the DB_RECNUM flag. +
renumber (boolean)
The value of the DB_RENUMBER flag. +
+

See Also

+berkeley_db_svc, +db_archive, +db_checkpoint, +db_deadlock, +db_dump, +db_load, +db_recover, +db_stat, +db_upgrade, +and +db_verify. +
+

Copyright Sleepycat Software + + diff --git a/db/docs/utility/db_printlog.html b/db/docs/utility/db_printlog.html new file mode 100644 index 000000000..10033e094 --- /dev/null +++ b/db/docs/utility/db_printlog.html @@ -0,0 +1,69 @@ + + + + + +Berkeley DB: db_printlog + + + + + + + +
+

db_printlog

+
+APIRef +
+


+ +

db_printlog [-NV] [-h home]

+

Description

+ +

The db_printlog utility is a debugging utility that dumps Berkeley DB +log files in a human-readable format. +

The options are as follows: +

+

-h
Specify a home directory for the database environment; by +default, the current working directory is used. +

-N
Do not acquire shared region locks while running. Other problems such as +potentially fatal errors in Berkeley DB will be ignored as well. This option +is intended only for debugging errors and should not be used under any +other circumstances. +

-V
Write the version number to the standard output and exit. +
+

For more information on the db_printlog output and using it to +debug applications, see Reviewing +Berkeley DB log files. +

The db_printlog utility uses a Berkeley DB environment (as described for the +-h option, the environment variable DB_HOME, or, +because the utility was run in a directory containing a Berkeley DB +environment). In order to avoid environment corruption when using a Berkeley DB +environment, db_printlog should always be given the chance to detach from +the environment and exit gracefully. To cause db_printlog to release all +environment resources and exit cleanly, send it an interrupt signal +(SIGINT). +

The db_printlog utility exits 0 on success, and >0 if an error occurs. +

Environment Variables

+

+

DB_HOME
If the -h option is not specified and the environment variable +DB_HOME is set, it is used as the path of the database home, as described +in DBENV->open. +
+

See Also

+berkeley_db_svc, +db_archive, +db_checkpoint, +db_deadlock, +db_dump, +db_load, +db_recover, +db_stat, +db_upgrade, +and +db_verify. +
+

Copyright Sleepycat Software + + diff --git a/db/docs/utility/db_recover.html b/db/docs/utility/db_recover.html new file mode 100644 index 000000000..80341597c --- /dev/null +++ b/db/docs/utility/db_recover.html @@ -0,0 +1,97 @@ + + + + + +Berkeley DB: db_recover + + + + + + + +
+

db_recover

+
+APIRef +
+


+ +

db_recover [-cVv] [-h home] [-t [[CC]YY]MMDDhhmm[.SS]]]

+

Description

+ +

The db_recover utility must be run after an unexpected application, +Berkeley DB, or system failure to restore the database to a consistent state. +All committed transactions are guaranteed to appear after db_recover +has run, and all uncommitted transactions will be completely undone. +

The options are as follows: +

+

-c
Perform catastrophic recovery instead of normal recovery. +

-h
Specify a home directory for the database environment; by +default, the current working directory is used. +

-t
Recover to the time specified rather than to the most current possible +date. The timestamp argument should be in the form +[[CC]YY]MMDDhhmm[.SS] where each pair of +letters represents the following: +

+

CC
The first two digits of the year (the century). +
YY
The second two digits of the year. If "YY" is specified, but "CC" is not, +a value for "YY" between 69 and 99 results in a "YY" value of 19. Otherwise, +a "YY" value of 20 is used. +
MM
The month of the year, from 1 to 12. +
DD
The day of the month, from 1 to 31. +
hh
The hour of the day, from 0 to 23. +
mm
The minute of the hour, from 0 to 59. +
SS
The second of the minute, from 0 to 61. +
+

If the "CC" and "YY" letter pairs are not specified, the values default +to the current year. If the "SS" letter pair is not specified, the value +defaults to 0. +

-V
Write the version number to the standard output and exit. +

-v
Run in verbose mode. +
+

In the case of catastrophic recovery, an archival copy, or +snapshot of all database files must be restored along with all +of the log files written since the database file snapshot was made. (If +disk space is a problem, log files may be referenced by symbolic links). +For further information on creating a database snapshot, see +Archival Procedures. +For further information on performing recovery, see +Recovery Procedures. +

If the failure was not catastrophic, the files present on the system at the +time of failure are sufficient to perform recovery. +

If log files are missing, db_recover will identify the missing +log file(s) and fail, in which case the missing log files need to be +restored and recovery performed again. +

The db_recover utility uses a Berkeley DB environment (as described for the +-h option, the environment variable DB_HOME, or, +because the utility was run in a directory containing a Berkeley DB +environment). In order to avoid environment corruption when using a Berkeley DB +environment, db_recover should always be given the chance to detach from +the environment and exit gracefully. To cause db_recover to release all +environment resources and exit cleanly, send it an interrupt signal +(SIGINT). +

The db_recover utility exits 0 on success, and >0 if an error occurs. +

Environment Variables

+

+

DB_HOME
If the -h option is not specified and the environment variable +DB_HOME is set, it is used as the path of the database home, as described +in DBENV->open. +
+

See Also

+berkeley_db_svc, +db_archive, +db_checkpoint, +db_deadlock, +db_dump, +db_load, +db_recover, +db_stat, +db_upgrade, +and +db_verify. +
+

Copyright Sleepycat Software + + diff --git a/db/docs/utility/db_stat.html b/db/docs/utility/db_stat.html new file mode 100644 index 000000000..ba9263e32 --- /dev/null +++ b/db/docs/utility/db_stat.html @@ -0,0 +1,104 @@ + + + + + +Berkeley DB: db_stat + + + + + + + +
+

db_stat

+
+APIRef +
+


+ +

db_stat [-celmNtV]
+    [-C Acfhlmo] [-d file [-s database]] [-h home] [-M Ahlm]

+

Description

+ +

The db_stat utility displays statistics for Berkeley DB environments. +

The options are as follows: +

+

-C
Display internal information about the lock region. (The output from this +option is often both voluminous and meaningless, and is intended only for +debugging.) +

+

A
Display all information. +
c
Display lock conflict matrix. +
f
Display lock and object free lists. +
l
Display lockers within hash chains. +
m
Display region memory information. +
o
Display objects within hash chains. +
+

-c
Display lock region statistics as described in lock_stat. +

-d
Display database statistics for the specified file, as described in +DB->stat. +

If the database contains multiple databases and the -s flag is +not specified, the statistics are for the internal database that describes +the other databases the file contains, and not for the file as a whole. +

-e
Display current environment statistics. +

-h
Specify a home directory for the database environment; by +default, the current working directory is used. +

-l
Display log region statistics as described in log_stat. +

-M
Display internal information about the shared memory buffer pool. (The +output from this option is often both voluminous and meaningless, and is +intended only for debugging.) +

+

A
Display all information. +
h
Display buffers within hash chains. +
l
Display buffers within LRU chains. +
m
Display region memory information. +
+

-m
Display shared memory buffer pool statistics as described in +memp_stat. +

-N
Do not acquire shared region locks while running. Other problems such as +potentially fatal errors in Berkeley DB will be ignored as well. This option +is intended only for debugging errors and should not be used under any +other circumstances. +

-s
Display statistics for the specified database contained in the file +specified with the -d flag. +

-t
Display transaction region statistics as described in txn_stat. +

-V
Write the version number to the standard output and exit. +
+

Only one set of statistics is displayed for each run, and the last option +specifying a set of statistics takes precedence. +

Values smaller than 10 million are generally displayed without any special +notation. Values larger than 10 million are normally displayed as +<number>M. +

The db_stat utility may be used with a Berkeley DB environment (as described for the +-h option, the environment variable DB_HOME, or, +because the utility was run in a directory containing a Berkeley DB +environment). In order to avoid environment corruption when using a Berkeley DB +environment, db_stat should always be given the chance to detach from +the environment and exit gracefully. To cause db_stat to release all +environment resources and exit cleanly, send it an interrupt signal +(SIGINT). +

The db_stat utility exits 0 on success, and >0 if an error occurs. +

Environment Variables

+

+

DB_HOME
If the -h option is not specified and the environment variable +DB_HOME is set, it is used as the path of the database home, as described +in DBENV->open. +
+

See Also

+berkeley_db_svc, +db_archive, +db_checkpoint, +db_deadlock, +db_dump, +db_load, +db_recover, +db_stat, +db_upgrade, +and +db_verify. +
+

Copyright Sleepycat Software + + diff --git a/db/docs/utility/db_upgrade.html b/db/docs/utility/db_upgrade.html new file mode 100644 index 000000000..6375f380e --- /dev/null +++ b/db/docs/utility/db_upgrade.html @@ -0,0 +1,93 @@ + + + + + +Berkeley DB: db_upgrade + + + + + + + +
+

db_upgrade

+
+APIRef +
+


+ +

db_upgrade [-NsV] [-h home] file ...

+

Description

+ +

The db_upgrade utility upgrades the Berkeley DB version of one or more +files and the databases they contain to the current release version. +

The options are as follows: +

+

-h
Specify a home directory for the database environment; by +default, the current working directory is used. +

-N
Do not acquire shared region locks while running. Other problems such as +potentially fatal errors in Berkeley DB will be ignored as well. This option +is intended only for debugging errors and should not be used under any +other circumstances. +

-s
This flag is only meaningful when upgrading databases from releases before the +Berkeley DB 3.1 release. +

As part of the upgrade from the Berkeley DB 3.0 release to the 3.1 release, the +on-disk format of duplicate data items changed. To correctly upgrade the +format requires applications specify if duplicate data items in the +database are sorted or not. Specifying the -s flag means that +the duplicates are sorted, otherwise they are assumed to be unsorted. +Incorrectly specifying the value of this flag may lead to database +corruption. +

Because the db_upgrade utility upgrades a physical file (including +all of the databases it contains), it is not possible to use +db_upgrade to upgrade files where some of the databases it +includes have sorted duplicate data items and some of the databases it +includes have unsorted duplicate data items. If the file does not have +more than a single database, or the databases do not support duplicate +data items, or all of the databases that support duplicate data items +support the same style of duplicates (either sorted or unsorted), +db_upgrade will work correctly as long as the -s flag is +correctly specified. Otherwise, the file cannot be upgraded using +db_upgrade, and must be upgraded manually using the db_dump +and db_load utilities. +

-V
Write the version number to the standard output and exit. +
+

It is important to realize that Berkeley DB database upgrades are done +in place, and so are potentially destructive. This means that if the +system crashes during the upgrade procedure, or if the upgrade procedure +runs out of disk space, the databases may be left in an inconsistent and +unrecoverable state. See Upgrading +databases for more information. +

The db_upgrade utility may be used with a Berkeley DB environment (as described for the +-h option, the environment variable DB_HOME, or, +because the utility was run in a directory containing a Berkeley DB +environment). In order to avoid environment corruption when using a Berkeley DB +environment, db_upgrade should always be given the chance to detach from +the environment and exit gracefully. To cause db_upgrade to release all +environment resources and exit cleanly, send it an interrupt signal +(SIGINT). +

The db_upgrade utility exits 0 on success, and >0 if an error occurs. +

Environment Variables

+

+

DB_HOME
If the -h option is not specified and the environment variable +DB_HOME is set, it is used as the path of the database home, as described +in DBENV->open. +
+

See Also

+berkeley_db_svc, +db_archive, +db_checkpoint, +db_deadlock, +db_dump, +db_load, +db_recover, +db_stat, +db_upgrade, +and +db_verify. +
+

Copyright Sleepycat Software + + diff --git a/db/docs/utility/db_verify.html b/db/docs/utility/db_verify.html new file mode 100644 index 000000000..610e857a9 --- /dev/null +++ b/db/docs/utility/db_verify.html @@ -0,0 +1,73 @@ + + + + + +Berkeley DB: db_verify + + + + + + + +
+

db_verify

+
+APIRef +
+


+ +

db_verify [-NqV] [-h home] file ...

+

Description

+ +

The db_verify utility verifies the structure of one or more +files and the databases they contain. +

The options are as follows: +

+

-h
Specify a home directory for the database environment; by +default, the current working directory is used. +

-N
Do not acquire shared region locks while running. Other problems such as +potentially fatal errors in Berkeley DB will be ignored as well. This option +is intended only for debugging errors and should not be used under any +other circumstances. +

-q
Suppress the printing of any error descriptions, simply exit success or +failure. +

-V
Write the version number to the standard output and exit. +
+

If the file being verified contains databases using non-default +comparison or hashing functions, the db_verify utility may +not be used for verification, as it will likely always return failure. +Such files must be verified explicitly, using the DB->verify function, +after setting the correct comparison or hashing functions. +

The db_verify utility may be used with a Berkeley DB environment (as described for the +-h option, the environment variable DB_HOME, or, +because the utility was run in a directory containing a Berkeley DB +environment). In order to avoid environment corruption when using a Berkeley DB +environment, db_verify should always be given the chance to detach from +the environment and exit gracefully. To cause db_verify to release all +environment resources and exit cleanly, send it an interrupt signal +(SIGINT). +

The db_verify utility exits 0 on success, and >0 if an error occurs. +

Environment Variables

+

+

DB_HOME
If the -h option is not specified and the environment variable +DB_HOME is set, it is used as the path of the database home, as described +in DBENV->open. +
+

See Also

+berkeley_db_svc, +db_archive, +db_checkpoint, +db_deadlock, +db_dump, +db_load, +db_recover, +db_stat, +db_upgrade, +and +db_verify. +
+

Copyright Sleepycat Software + + diff --git a/db/docs/utility/index.html b/db/docs/utility/index.html new file mode 100644 index 000000000..3f0c430ab --- /dev/null +++ b/db/docs/utility/index.html @@ -0,0 +1,28 @@ + + + + + +Berkeley DB: Berkeley DB Supporting Utilities + + + + +

Berkeley DB Supporting Utilities

+

+ + + + + + + + + + + + +
UtilityDescription
berkeley_db_svcRPC server utility
db_archiveArchival utility
db_checkpointTransaction checkpoint utility
db_deadlockDeadlock detection utility
db_dumpDatabase dump utility
db_loadDatabase load utility
db_printlogTransaction log display utility
db_recoverRecovery utility
db_statStatistics utility
db_upgradeDatabase upgrade utility
db_verifyVerification utility
+

Copyright Sleepycat Software + + diff --git a/db/env/db_salloc.c b/db/env/db_salloc.c new file mode 100644 index 000000000..4780107c5 --- /dev/null +++ b/db/env/db_salloc.c @@ -0,0 +1,360 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: db_salloc.c,v 11.10 2000/12/06 19:55:44 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#endif + +#include "db_int.h" + +/* + * Implement shared memory region allocation, using simple first-fit algorithm. + * The model is that we take a "chunk" of shared memory store and begin carving + * it up into areas, similarly to how malloc works. We do coalescing on free. + * + * The "len" field in the __data struct contains the length of the free region + * (less the size_t bytes that holds the length). We use the address provided + * by the caller to find this length, which allows us to free a chunk without + * requiring that the caller pass in the length of the chunk they're freeing. + */ +SH_LIST_HEAD(__head); +struct __data { + size_t len; + SH_LIST_ENTRY links; +}; + +/* + * __db_shalloc_init -- + * Initialize the area as one large chunk. + * + * PUBLIC: void __db_shalloc_init __P((void *, size_t)); + */ +void +__db_shalloc_init(area, size) + void *area; + size_t size; +{ + struct __data *elp; + struct __head *hp; + + hp = area; + SH_LIST_INIT(hp); + + elp = (struct __data *)(hp + 1); + elp->len = size - sizeof(struct __head) - sizeof(elp->len); + SH_LIST_INSERT_HEAD(hp, elp, links, __data); +} + +/* + * __db_shalloc -- + * Allocate some space from the shared region. + * + * PUBLIC: int __db_shalloc_size __P((size_t, size_t)); + */ +int +__db_shalloc_size(len, align) + size_t len, align; +{ + /* Never allocate less than the size of a struct __data. */ + if (len < sizeof(struct __data)) + len = sizeof(struct __data); + +#ifdef DIAGNOSTIC + /* Add room for a guard byte. */ + ++len; +#endif + + /* Never align to less than a db_align_t boundary. */ + if (align <= sizeof(db_align_t)) + align = sizeof(db_align_t); + + return (ALIGN(len, align) + sizeof (struct __data)); +} + +/* + * __db_shalloc -- + * Allocate some space from the shared region. + * + * PUBLIC: int __db_shalloc __P((void *, size_t, size_t, void *)); + */ +int +__db_shalloc(p, len, align, retp) + void *p, *retp; + size_t len, align; +{ + struct __data *elp; + size_t *sp; + void *rp; + + /* Never allocate less than the size of a struct __data. */ + if (len < sizeof(struct __data)) + len = sizeof(struct __data); + +#ifdef DIAGNOSTIC + /* Add room for a guard byte. */ + ++len; +#endif + + /* Never align to less than a db_align_t boundary. */ + if (align <= sizeof(db_align_t)) + align = sizeof(db_align_t); + + /* Walk the list, looking for a slot. */ + for (elp = SH_LIST_FIRST((struct __head *)p, __data); + elp != NULL; + elp = SH_LIST_NEXT(elp, links, __data)) { + /* + * Calculate the value of the returned pointer if we were to + * use this chunk. + * + Find the end of the chunk. + * + Subtract the memory the user wants. + * + Find the closest previous correctly-aligned address. + */ + rp = (u_int8_t *)elp + sizeof(size_t) + elp->len; + rp = (u_int8_t *)rp - len; + rp = (u_int8_t *)((db_alignp_t)rp & ~(align - 1)); + + /* + * Rp may now point before elp->links, in which case the chunk + * was too small, and we have to try again. + */ + if ((u_int8_t *)rp < (u_int8_t *)&elp->links) + continue; + + *(void **)retp = rp; +#ifdef DIAGNOSTIC + /* + * At this point, whether or not we still need to split up a + * chunk, retp is the address of the region we are returning, + * and (u_int8_t *)elp + sizeof(size_t) + elp->len gives us + * the address of the first byte after the end of the chunk. + * Make the byte immediately before that the guard byte. + */ + *((u_int8_t *)elp + sizeof(size_t) + elp->len - 1) = GUARD_BYTE; +#endif + +#define SHALLOC_FRAGMENT 32 + /* + * If there are at least SHALLOC_FRAGMENT additional bytes of + * memory, divide the chunk into two chunks. + */ + if ((u_int8_t *)rp >= + (u_int8_t *)&elp->links + SHALLOC_FRAGMENT) { + sp = rp; + *--sp = elp->len - + ((u_int8_t *)rp - (u_int8_t *)&elp->links); + elp->len -= *sp + sizeof(size_t); + return (0); + } + + /* + * Otherwise, we return the entire chunk, wasting some amount + * of space to keep the list compact. However, because the + * address we're returning to the user may not be the address + * of the start of the region for alignment reasons, set the + * size_t length fields back to the "real" length field to a + * flag value, so that we can find the real length during free. + */ +#define ILLEGAL_SIZE 1 + SH_LIST_REMOVE(elp, links, __data); + for (sp = rp; (u_int8_t *)--sp >= (u_int8_t *)&elp->links;) + *sp = ILLEGAL_SIZE; + return (0); + } + + return (ENOMEM); +} + +/* + * __db_shalloc_free -- + * Free a shared memory allocation. + * + * PUBLIC: void __db_shalloc_free __P((void *, void *)); + */ +void +__db_shalloc_free(regionp, ptr) + void *regionp, *ptr; +{ + struct __data *elp, *lastp, *newp; + struct __head *hp; + size_t free_size, *sp; + int merged; + + /* + * Step back over flagged length fields to find the beginning of + * the object and its real size. + */ + for (sp = (size_t *)ptr; sp[-1] == ILLEGAL_SIZE; --sp) + ; + ptr = sp; + + newp = (struct __data *)((u_int8_t *)ptr - sizeof(size_t)); + free_size = newp->len; + +#ifdef DIAGNOSTIC + /* + * The "real size" includes the guard byte; it's just the last + * byte in the chunk, and the caller never knew it existed. + * + * Check it to make sure it hasn't been stomped. + */ + if (*((u_int8_t *)ptr + free_size - 1) != GUARD_BYTE) { + /* + * Eventually, once we push a DB_ENV handle down to these + * routines, we should use the standard output channels. + */ + fprintf(stderr, + "Guard byte incorrect during shared memory free.\n"); + abort(); + /* NOTREACHED */ + } + + /* Trash the returned memory (including guard byte). */ + memset(ptr, CLEAR_BYTE, free_size); +#endif + + /* + * Walk the list, looking for where this entry goes. + * + * We keep the free list sorted by address so that coalescing is + * trivial. + * + * XXX + * Probably worth profiling this to see how expensive it is. + */ + hp = (struct __head *)regionp; + for (elp = SH_LIST_FIRST(hp, __data), lastp = NULL; + elp != NULL && (void *)elp < (void *)ptr; + lastp = elp, elp = SH_LIST_NEXT(elp, links, __data)) + ; + + /* + * Elp is either NULL (we reached the end of the list), or the slot + * after the one that's being returned. Lastp is either NULL (we're + * returning the first element of the list) or the element before the + * one being returned. + * + * Check for coalescing with the next element. + */ + merged = 0; + if ((u_int8_t *)ptr + free_size == (u_int8_t *)elp) { + newp->len += elp->len + sizeof(size_t); + SH_LIST_REMOVE(elp, links, __data); + if (lastp != NULL) + SH_LIST_INSERT_AFTER(lastp, newp, links, __data); + else + SH_LIST_INSERT_HEAD(hp, newp, links, __data); + merged = 1; + } + + /* Check for coalescing with the previous element. */ + if (lastp != NULL && (u_int8_t *)lastp + + lastp->len + sizeof(size_t) == (u_int8_t *)newp) { + lastp->len += newp->len + sizeof(size_t); + + /* + * If we have already put the new element into the list take + * it back off again because it's just been merged with the + * previous element. + */ + if (merged) + SH_LIST_REMOVE(newp, links, __data); + merged = 1; + } + + if (!merged) { + if (lastp == NULL) + SH_LIST_INSERT_HEAD(hp, newp, links, __data); + else + SH_LIST_INSERT_AFTER(lastp, newp, links, __data); + } +} + +/* + * __db_shalloc_count -- + * Return the amount of memory on the free list. + * + * PUBLIC: size_t __db_shalloc_count __P((void *)); + */ +size_t +__db_shalloc_count(addr) + void *addr; +{ + struct __data *elp; + size_t count; + + count = 0; + for (elp = SH_LIST_FIRST((struct __head *)addr, __data); + elp != NULL; + elp = SH_LIST_NEXT(elp, links, __data)) + count += elp->len; + + return (count); +} + +/* + * __db_shsizeof -- + * Return the size of a shalloc'd piece of memory. + * + * !!! + * Note that this is from an internal standpoint -- it includes not only + * the size of the memory being used, but also the extra alignment bytes + * in front and, #ifdef DIAGNOSTIC, the guard byte at the end. + * + * PUBLIC: size_t __db_shsizeof __P((void *)); + */ +size_t +__db_shsizeof(ptr) + void *ptr; +{ + struct __data *elp; + size_t *sp; + + /* + * Step back over flagged length fields to find the beginning of + * the object and its real size. + */ + for (sp = (size_t *)ptr; sp[-1] == ILLEGAL_SIZE; --sp) + ; + + elp = (struct __data *)((u_int8_t *)sp - sizeof(size_t)); + return (elp->len); +} + +/* + * __db_shalloc_dump -- + * + * PUBLIC: void __db_shalloc_dump __P((void *, FILE *)); + */ +void +__db_shalloc_dump(addr, fp) + void *addr; + FILE *fp; +{ + struct __data *elp; + + /* Make it easy to call from the debugger. */ + if (fp == NULL) + fp = stderr; + + fprintf(fp, "%s\nMemory free list\n", DB_LINE); + + for (elp = SH_LIST_FIRST((struct __head *)addr, __data); + elp != NULL; + elp = SH_LIST_NEXT(elp, links, __data)) + fprintf(fp, "%#lx: %lu\t", (u_long)elp, (u_long)elp->len); + fprintf(fp, "\n"); +} diff --git a/db/env/db_shash.c b/db/env/db_shash.c new file mode 100644 index 000000000..1c33b3830 --- /dev/null +++ b/db/env/db_shash.c @@ -0,0 +1,124 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: db_shash.c,v 11.3 2000/02/14 02:59:49 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include +#endif + +#include "db_int.h" + +/* + * Table of good hash values. Up to ~250,000 buckets, we use powers of 2. + * After that, we slow the rate of increase by half. For each choice, we + * then use a nearby prime number as the hash value. + * + * If a terabyte is the maximum cache we'll see, and we assume there are + * 10 1K buckets on each hash chain, then 107374182 is the maximum number + * of buckets we'll ever need. + */ +static const struct { + u_int32_t power; + u_int32_t prime; +} list[] = { + { 64, 67}, /* 2^6 */ + { 128, 131}, /* 2^7 */ + { 256, 257}, /* 2^8 */ + { 512, 521}, /* 2^9 */ + { 1024, 1031}, /* 2^10 */ + { 2048, 2053}, /* 2^11 */ + { 4096, 4099}, /* 2^12 */ + { 8192, 8191}, /* 2^13 */ + { 16384, 16381}, /* 2^14 */ + { 32768, 32771}, /* 2^15 */ + { 65536, 65537}, /* 2^16 */ + { 131072, 131071}, /* 2^17 */ + { 262144, 262147}, /* 2^18 */ + { 393216, 393209}, /* 2^18 + 2^18/2 */ + { 524288, 524287}, /* 2^19 */ + { 786432, 786431}, /* 2^19 + 2^19/2 */ + { 1048576, 1048573}, /* 2^20 */ + { 1572864, 1572869}, /* 2^20 + 2^20/2 */ + { 2097152, 2097169}, /* 2^21 */ + { 3145728, 3145721}, /* 2^21 + 2^21/2 */ + { 4194304, 4194301}, /* 2^22 */ + { 6291456, 6291449}, /* 2^22 + 2^22/2 */ + { 8388608, 8388617}, /* 2^23 */ + { 12582912, 12582917}, /* 2^23 + 2^23/2 */ + { 16777216, 16777213}, /* 2^24 */ + { 25165824, 25165813}, /* 2^24 + 2^24/2 */ + { 33554432, 33554393}, /* 2^25 */ + { 50331648, 50331653}, /* 2^25 + 2^25/2 */ + { 67108864, 67108859}, /* 2^26 */ + { 100663296, 100663291}, /* 2^26 + 2^26/2 */ + { 134217728, 134217757}, /* 2^27 */ + { 201326592, 201326611}, /* 2^27 + 2^27/2 */ + { 268435456, 268435459}, /* 2^28 */ + { 402653184, 402653189}, /* 2^28 + 2^28/2 */ + { 536870912, 536870909}, /* 2^29 */ + { 805306368, 805306357}, /* 2^29 + 2^29/2 */ + {1073741824, 1073741827}, /* 2^30 */ + {0, 0} +}; + +/* + * __db_tablesize -- + * Choose a size for the hash table. + * + * PUBLIC: int __db_tablesize __P((u_int32_t)); + */ +int +__db_tablesize(n_buckets) + u_int32_t n_buckets; +{ + int i; + + /* + * We try to be clever about how big we make the hash tables. Use a + * prime number close to the "suggested" number of elements that will + * be in the hash table. Use 64 as the minimum hash table size. + * + * Ref: Sedgewick, Algorithms in C, "Hash Functions" + */ + if (n_buckets < 64) + n_buckets = 64; + + for (i = 0;; ++i) { + if (list[i].power == 0) { + --i; + break; + } + if (list[i].power >= n_buckets) + break; + } + return (list[i].prime); +} + +/* + * __db_hashinit -- + * Initialize a hash table that resides in shared memory. + * + * PUBLIC: void __db_hashinit __P((void *, u_int32_t)); + */ +void +__db_hashinit(begin, nelements) + void *begin; + u_int32_t nelements; +{ + u_int32_t i; + SH_TAILQ_HEAD(hash_head) *headp; + + headp = (struct hash_head *)begin; + + for (i = 0; i < nelements; i++, headp++) + SH_TAILQ_INIT(headp); +} diff --git a/db/env/env_method.c b/db/env/env_method.c new file mode 100644 index 000000000..c5f45df71 --- /dev/null +++ b/db/env/env_method.c @@ -0,0 +1,461 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: env_method.c,v 11.31 2000/11/30 00:58:35 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#ifdef HAVE_RPC +#include "db_server.h" +#endif + +/* + * This is the file that initializes the global array. Do it this way because + * people keep changing one without changing the other. Having declaration and + * initialization in one file will hopefully fix that. + */ +#define DB_INITIALIZE_DB_GLOBALS 1 + +#include "db_int.h" +#include "db_shash.h" +#include "db_page.h" +#include "db_am.h" +#include "lock.h" +#include "log.h" +#include "mp.h" +#include "txn.h" + +#ifdef HAVE_RPC +#include "gen_client_ext.h" +#include "rpc_client_ext.h" +#endif + +static void __dbenv_err __P((const DB_ENV *, int, const char *, ...)); +static void __dbenv_errx __P((const DB_ENV *, const char *, ...)); +static int __dbenv_set_data_dir __P((DB_ENV *, const char *)); +static void __dbenv_set_errcall __P((DB_ENV *, void (*)(const char *, char *))); +static void __dbenv_set_errfile __P((DB_ENV *, FILE *)); +static void __dbenv_set_errpfx __P((DB_ENV *, const char *)); +static int __dbenv_set_feedback __P((DB_ENV *, void (*)(DB_ENV *, int, int))); +static int __dbenv_set_flags __P((DB_ENV *, u_int32_t, int)); +static int __dbenv_set_mutexlocks __P((DB_ENV *, int)); +static int __dbenv_set_paniccall __P((DB_ENV *, void (*)(DB_ENV *, int))); +static int __dbenv_set_recovery_init __P((DB_ENV *, int (*)(DB_ENV *))); +static int __dbenv_set_server_noclnt + __P((DB_ENV *, char *, long, long, u_int32_t)); +static int __dbenv_set_shm_key __P((DB_ENV *, long)); +static int __dbenv_set_tmp_dir __P((DB_ENV *, const char *)); +static int __dbenv_set_verbose __P((DB_ENV *, u_int32_t, int)); + +/* + * db_env_create -- + * DB_ENV constructor. + */ +int +db_env_create(dbenvpp, flags) + DB_ENV **dbenvpp; + u_int32_t flags; +{ + DB_ENV *dbenv; + int ret; + + /* + * !!! + * We can't call the flags-checking routines, we don't have an + * environment yet. + */ + if (flags != 0 && flags != DB_CLIENT) + return (EINVAL); + + if ((ret = __os_calloc(NULL, 1, sizeof(*dbenv), &dbenv)) != 0) + return (ret); + +#ifdef HAVE_RPC + if (LF_ISSET(DB_CLIENT)) + F_SET(dbenv, DB_ENV_RPCCLIENT); +#endif + ret = __dbenv_init(dbenv); + + if (ret != 0) { + __os_free(dbenv, sizeof(*dbenv)); + return (ret); + } + + *dbenvpp = dbenv; + return (0); +} + +/* + * __dbenv_init -- + * Initialize a DB_ENV structure. + * + * PUBLIC: int __dbenv_init __P((DB_ENV *)); + */ +int +__dbenv_init(dbenv) + DB_ENV *dbenv; +{ + /* + * Set up methods that are the same in both normal and RPC + */ + dbenv->err = __dbenv_err; + dbenv->errx = __dbenv_errx; + dbenv->set_errcall = __dbenv_set_errcall; + dbenv->set_errfile = __dbenv_set_errfile; + dbenv->set_errpfx = __dbenv_set_errpfx; + +#ifdef HAVE_RPC + if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) { + dbenv->close = __dbcl_env_close; + dbenv->open = __dbcl_env_open; + dbenv->remove = __dbcl_env_remove; + dbenv->set_data_dir = __dbcl_set_data_dir; + dbenv->set_feedback = __dbcl_env_set_feedback; + dbenv->set_flags = __dbcl_env_flags; + dbenv->set_mutexlocks = __dbcl_set_mutex_locks; + dbenv->set_paniccall = __dbcl_env_paniccall; + dbenv->set_recovery_init = __dbcl_set_recovery_init; + dbenv->set_server = __dbcl_envserver; + dbenv->set_shm_key = __dbcl_set_shm_key; + dbenv->set_tmp_dir = __dbcl_set_tmp_dir; + dbenv->set_verbose = __dbcl_set_verbose; + } else { +#endif + dbenv->close = __dbenv_close; + dbenv->open = __dbenv_open; + dbenv->remove = __dbenv_remove; + dbenv->set_data_dir = __dbenv_set_data_dir; + dbenv->set_feedback = __dbenv_set_feedback; + dbenv->set_flags = __dbenv_set_flags; + dbenv->set_mutexlocks = __dbenv_set_mutexlocks; + dbenv->set_paniccall = __dbenv_set_paniccall; + dbenv->set_recovery_init = __dbenv_set_recovery_init; + dbenv->set_server = __dbenv_set_server_noclnt; + dbenv->set_shm_key = __dbenv_set_shm_key; + dbenv->set_tmp_dir = __dbenv_set_tmp_dir; + dbenv->set_verbose = __dbenv_set_verbose; +#ifdef HAVE_RPC + } +#endif + dbenv->shm_key = INVALID_REGION_SEGID; + dbenv->db_mutexlocks = 1; + + __log_dbenv_create(dbenv); /* Subsystem specific. */ + __lock_dbenv_create(dbenv); + __memp_dbenv_create(dbenv); + __txn_dbenv_create(dbenv); + + return (0); +} + +/* + * __dbenv_err -- + * Error message, including the standard error string. + */ +static void +#ifdef __STDC__ +__dbenv_err(const DB_ENV *dbenv, int error, const char *fmt, ...) +#else +__dbenv_err(dbenv, error, fmt, va_alist) + const DB_ENV *dbenv; + int error; + const char *fmt; + va_dcl +#endif +{ + va_list ap; + +#ifdef __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + __db_real_err(dbenv, error, 1, 1, fmt, ap); + + va_end(ap); +} + +/* + * __dbenv_errx -- + * Error message. + */ +static void +#ifdef __STDC__ +__dbenv_errx(const DB_ENV *dbenv, const char *fmt, ...) +#else +__dbenv_errx(dbenv, fmt, va_alist) + const DB_ENV *dbenv; + const char *fmt; + va_dcl +#endif +{ + va_list ap; + +#ifdef __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + __db_real_err(dbenv, 0, 0, 1, fmt, ap); + + va_end(ap); +} + +static int +__dbenv_set_flags(dbenv, flags, onoff) + DB_ENV *dbenv; + u_int32_t flags; + int onoff; +{ +#define OK_FLAGS (DB_CDB_ALLDB | DB_NOMMAP | DB_TXN_NOSYNC) + + if (LF_ISSET(~OK_FLAGS)) + return (__db_ferr(dbenv, "DBENV->set_flags", 0)); + + if (LF_ISSET(DB_CDB_ALLDB)) { + ENV_ILLEGAL_AFTER_OPEN(dbenv, "set_flags: DB_CDB_ALLDB"); + if (onoff) + F_SET(dbenv, DB_ENV_CDB_ALLDB); + else + F_CLR(dbenv, DB_ENV_CDB_ALLDB); + } + if (LF_ISSET(DB_NOMMAP)) { + if (onoff) + F_SET(dbenv, DB_ENV_NOMMAP); + else + F_CLR(dbenv, DB_ENV_NOMMAP); + } + if (LF_ISSET(DB_TXN_NOSYNC)) { + if (onoff) + F_SET(dbenv, DB_ENV_TXN_NOSYNC); + else + F_CLR(dbenv, DB_ENV_TXN_NOSYNC); + } + return (0); +} + +static int +__dbenv_set_data_dir(dbenv, dir) + DB_ENV *dbenv; + const char *dir; +{ + int ret; + +#define DATA_INIT_CNT 20 /* Start with 20 data slots. */ + if (dbenv->db_data_dir == NULL) { + if ((ret = __os_calloc(dbenv, DATA_INIT_CNT, + sizeof(char **), &dbenv->db_data_dir)) != 0) + return (ret); + dbenv->data_cnt = DATA_INIT_CNT; + } else if (dbenv->data_next == dbenv->data_cnt - 1) { + dbenv->data_cnt *= 2; + if ((ret = __os_realloc(dbenv, + dbenv->data_cnt * sizeof(char **), + NULL, &dbenv->db_data_dir)) != 0) + return (ret); + } + return (__os_strdup(dbenv, + dir, &dbenv->db_data_dir[dbenv->data_next++])); +} + +static void +__dbenv_set_errcall(dbenv, errcall) + DB_ENV *dbenv; + void (*errcall) __P((const char *, char *)); +{ + dbenv->db_errcall = errcall; +} + +static void +__dbenv_set_errfile(dbenv, errfile) + DB_ENV *dbenv; + FILE *errfile; +{ + dbenv->db_errfile = errfile; +} + +static void +__dbenv_set_errpfx(dbenv, errpfx) + DB_ENV *dbenv; + const char *errpfx; +{ + dbenv->db_errpfx = errpfx; +} + +static int +__dbenv_set_feedback(dbenv, feedback) + DB_ENV *dbenv; + void (*feedback) __P((DB_ENV *, int, int)); +{ + dbenv->db_feedback = feedback; + return (0); +} + +static int +__dbenv_set_mutexlocks(dbenv, onoff) + DB_ENV *dbenv; + int onoff; +{ + dbenv->db_mutexlocks = onoff; + return (0); +} + +static int +__dbenv_set_paniccall(dbenv, paniccall) + DB_ENV *dbenv; + void (*paniccall) __P((DB_ENV *, int)); +{ + dbenv->db_paniccall = paniccall; + return (0); +} + +static int +__dbenv_set_recovery_init(dbenv, recovery_init) + DB_ENV *dbenv; + int (*recovery_init) __P((DB_ENV *)); +{ + ENV_ILLEGAL_AFTER_OPEN(dbenv, "set_recovery_init"); + + dbenv->db_recovery_init = recovery_init; + + return (0); +} + +static int +__dbenv_set_shm_key(dbenv, shm_key) + DB_ENV *dbenv; + long shm_key; /* !!!: really a key_t. */ +{ + ENV_ILLEGAL_AFTER_OPEN(dbenv, "set_shm_key"); + + dbenv->shm_key = shm_key; + return (0); +} + +static int +__dbenv_set_tmp_dir(dbenv, dir) + DB_ENV *dbenv; + const char *dir; +{ + if (dbenv->db_tmp_dir != NULL) + __os_freestr(dbenv->db_tmp_dir); + return (__os_strdup(dbenv, dir, &dbenv->db_tmp_dir)); +} + +static int +__dbenv_set_verbose(dbenv, which, onoff) + DB_ENV *dbenv; + u_int32_t which; + int onoff; +{ + switch (which) { + case DB_VERB_CHKPOINT: + case DB_VERB_DEADLOCK: + case DB_VERB_RECOVERY: + case DB_VERB_WAITSFOR: + if (onoff) + FLD_SET(dbenv->verbose, which); + else + FLD_CLR(dbenv->verbose, which); + break; + default: + return (EINVAL); + } + return (0); +} + +/* + * __db_mi_env -- + * Method illegally called with public environment. + * + * PUBLIC: int __db_mi_env __P((DB_ENV *, const char *)); + */ +int +__db_mi_env(dbenv, name) + DB_ENV *dbenv; + const char *name; +{ + __db_err(dbenv, "%s: method meaningless in shared environment", name); + return (EINVAL); +} + +/* + * __db_mi_open -- + * Method illegally called after open. + * + * PUBLIC: int __db_mi_open __P((DB_ENV *, const char *, int)); + */ +int +__db_mi_open(dbenv, name, after) + DB_ENV *dbenv; + const char *name; + int after; +{ + __db_err(dbenv, + "%s: method meaningless %s open", name, after ? "after" : "before"); + return (EINVAL); +} + +/* + * __db_env_config -- + * Method or function called without subsystem being configured. + * + * PUBLIC: int __db_env_config __P((DB_ENV *, int)); + */ +int +__db_env_config(dbenv, subsystem) + DB_ENV *dbenv; + int subsystem; +{ + const char *name; + + switch (subsystem) { + case DB_INIT_LOCK: + name = "lock"; + break; + case DB_INIT_LOG: + name = "log"; + break; + case DB_INIT_MPOOL: + name = "mpool"; + break; + case DB_INIT_TXN: + name = "txn"; + break; + default: + name = "unknown"; + break; + } + __db_err(dbenv, + "%s interface called with environment not configured for that subsystem", + name); + return (EINVAL); +} + +static int +__dbenv_set_server_noclnt(dbenv, host, tsec, ssec, flags) + DB_ENV *dbenv; + char *host; + long tsec, ssec; + u_int32_t flags; +{ + COMPQUIET(host, NULL); + COMPQUIET(tsec, 0); + COMPQUIET(ssec, 0); + COMPQUIET(flags, 0); + + __db_err(dbenv, "set_server method meaningless in non-RPC enviroment"); + return (__db_eopnotsup(dbenv)); +} diff --git a/db/env/env_open.c b/db/env/env_open.c new file mode 100644 index 000000000..2007b4266 --- /dev/null +++ b/db/env/env_open.c @@ -0,0 +1,1064 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: env_open.c,v 11.34 2000/12/21 19:20:00 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_shash.h" +#include "btree.h" +#include "hash.h" +#include "qam.h" +#include "lock.h" +#include "log.h" +#include "mp.h" +#include "txn.h" +#include "clib_ext.h" + +static int __dbenv_config __P((DB_ENV *, const char *, u_int32_t)); +static int __dbenv_refresh __P((DB_ENV *)); +static int __db_home __P((DB_ENV *, const char *, u_int32_t)); +static int __db_parse __P((DB_ENV *, char *)); +static int __db_tmp_open __P((DB_ENV *, u_int32_t, char *, DB_FH *)); + +/* + * db_version -- + * Return version information. + */ +char * +db_version(majverp, minverp, patchp) + int *majverp, *minverp, *patchp; +{ + if (majverp != NULL) + *majverp = DB_VERSION_MAJOR; + if (minverp != NULL) + *minverp = DB_VERSION_MINOR; + if (patchp != NULL) + *patchp = DB_VERSION_PATCH; + return ((char *)DB_VERSION_STRING); +} + +/* + * __dbenv_open -- + * Initialize an environment. + * + * PUBLIC: int __dbenv_open __P((DB_ENV *, const char *, u_int32_t, int)); + */ +int +__dbenv_open(dbenv, db_home, flags, mode) + DB_ENV *dbenv; + const char *db_home; + u_int32_t flags; + int mode; +{ + DB_ENV *rm_dbenv; + int ret; + u_int32_t init_flags; + +#undef OKFLAGS +#define OKFLAGS \ + DB_CREATE | DB_INIT_CDB | DB_INIT_LOCK | DB_INIT_LOG | \ + DB_INIT_MPOOL | DB_INIT_TXN | DB_JOINENV | DB_LOCKDOWN | \ + DB_PRIVATE | DB_RECOVER | DB_RECOVER_FATAL | DB_SYSTEM_MEM | \ + DB_THREAD | DB_USE_ENVIRON | DB_USE_ENVIRON_ROOT +#undef OKFLAGS_CDB +#define OKFLAGS_CDB \ + DB_CREATE | DB_INIT_CDB | DB_INIT_MPOOL | DB_LOCKDOWN | \ + DB_PRIVATE | DB_SYSTEM_MEM | DB_THREAD | \ + DB_USE_ENVIRON | DB_USE_ENVIRON_ROOT + + /* + * Flags saved in the init_flags field of the environment, representing + * flags to DBENV->set_flags and DBENV->open that need to be set. + */ +#define DB_INITENV_CDB 0x0001 /* DB_INIT_CDB */ +#define DB_INITENV_CDB_ALLDB 0x0002 /* DB_INIT_CDB_ALLDB */ +#define DB_INITENV_LOCK 0x0004 /* DB_INIT_LOCK */ +#define DB_INITENV_LOG 0x0008 /* DB_INIT_LOG */ +#define DB_INITENV_MPOOL 0x0010 /* DB_INIT_MPOOL */ +#define DB_INITENV_TXN 0x0020 /* DB_INIT_TXN */ + + if ((ret = __db_fchk(dbenv, "DBENV->open", flags, OKFLAGS)) != 0) + return (ret); + if (LF_ISSET(DB_INIT_CDB) && + (ret = __db_fchk(dbenv, "DBENV->open", flags, OKFLAGS_CDB)) != 0) + return (ret); + if ((ret = __db_fcchk(dbenv, + "DBENV->open", flags, DB_PRIVATE, DB_SYSTEM_MEM)) != 0) + return (ret); + if ((ret = __db_fcchk(dbenv, "DBENV->open", flags, DB_JOINENV, + DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | + DB_INIT_TXN | DB_PRIVATE)) != 0) + return (ret); + + /* + * If we're doing recovery, destroy the environment so that we create + * all the regions from scratch. I'd like to reuse already created + * regions, but that's hard. We would have to create the environment + * region from scratch, at least, as we have no way of knowing if its + * linked lists are corrupted. + * + * I suppose we could set flags while modifying those links, but that + * is going to be difficult to get right. The major concern I have + * is if the application stomps the environment with a rogue pointer. + * We have no way of detecting that, and we could be forced into a + * situation where we start up and then crash, repeatedly. + * + * Note that we do not check any flags like DB_PRIVATE before calling + * remove. We don't care if the current environment was private or + * not, we just want to nail any files that are left-over for whatever + * reason, from whatever session. + */ + if (LF_ISSET(DB_RECOVER | DB_RECOVER_FATAL)) { + if ((ret = db_env_create(&rm_dbenv, 0)) != 0) + return (ret); + if ((ret = dbenv->remove(rm_dbenv, db_home, DB_FORCE)) != 0) + return (ret); + } + + /* Initialize the DB_ENV structure. */ + if ((ret = __dbenv_config(dbenv, db_home, flags)) != 0) + goto err; + + /* Convert the DBENV->open flags to internal flags. */ + if (LF_ISSET(DB_CREATE)) + F_SET(dbenv, DB_ENV_CREATE); + if (LF_ISSET(DB_LOCKDOWN)) + F_SET(dbenv, DB_ENV_LOCKDOWN); + if (LF_ISSET(DB_PRIVATE)) + F_SET(dbenv, DB_ENV_PRIVATE); + if (LF_ISSET(DB_SYSTEM_MEM)) + F_SET(dbenv, DB_ENV_SYSTEM_MEM); + if (LF_ISSET(DB_THREAD)) + F_SET(dbenv, DB_ENV_THREAD); + + /* Default permissions are read-write for both owner and group. */ + dbenv->db_mode = mode == 0 ? __db_omode("rwrw--") : mode; + + /* + * Create/join the environment. We pass in the flags that + * will be of interest to an environment joining later; if + * we're not the ones to do the create, we + * pull out whatever has been stored, if we don't do a create. + */ + init_flags = 0; + init_flags |= (LF_ISSET(DB_INIT_CDB) ? DB_INITENV_CDB : 0); + init_flags |= (LF_ISSET(DB_INIT_LOCK) ? DB_INITENV_LOCK : 0); + init_flags |= (LF_ISSET(DB_INIT_LOG) ? DB_INITENV_LOG : 0); + init_flags |= (LF_ISSET(DB_INIT_MPOOL) ? DB_INITENV_MPOOL : 0); + init_flags |= (LF_ISSET(DB_INIT_TXN) ? DB_INITENV_TXN : 0); + init_flags |= + (F_ISSET(dbenv, DB_ENV_CDB_ALLDB) ? DB_INITENV_CDB_ALLDB : 0); + + if ((ret = __db_e_attach(dbenv, &init_flags)) != 0) + goto err; + + /* + * __db_e_attach will return the saved init_flags field, which + * contains the DB_INIT_* flags used when we were created. + */ + if (LF_ISSET(DB_JOINENV)) { + LF_CLR(DB_JOINENV); + + LF_SET((init_flags & DB_INITENV_CDB) ? DB_INIT_CDB : 0); + LF_SET((init_flags & DB_INITENV_LOCK) ? DB_INIT_LOCK : 0); + LF_SET((init_flags & DB_INITENV_LOG) ? DB_INIT_LOG : 0); + LF_SET((init_flags & DB_INITENV_MPOOL) ? DB_INIT_MPOOL : 0); + LF_SET((init_flags & DB_INITENV_TXN) ? DB_INIT_TXN : 0); + + if (LF_ISSET(DB_INITENV_CDB_ALLDB) && + (ret = dbenv->set_flags(dbenv, DB_CDB_ALLDB, 1)) != 0) + goto err; + } + + /* Initialize for CDB product. */ + if (LF_ISSET(DB_INIT_CDB)) { + LF_SET(DB_INIT_LOCK); + F_SET(dbenv, DB_ENV_CDB); + } + + /* Initialize the DB list, and its mutex if appropriate. */ + LIST_INIT(&dbenv->dblist); + if (F_ISSET(dbenv, DB_ENV_THREAD)) { + if ((ret = __db_mutex_alloc(dbenv, + dbenv->reginfo, (MUTEX **)&dbenv->dblist_mutexp)) != 0) + return (ret); + if ((ret = __db_mutex_init(dbenv, + dbenv->dblist_mutexp, 0, MUTEX_THREAD)) != 0) { + __db_mutex_free(dbenv, dbenv->reginfo, + dbenv->dblist_mutexp); + return (ret); + } + } + + /* + * Initialize the subsystems. Transactions imply logging but do not + * imply locking. While almost all applications want both locking + * and logging, it would not be unreasonable for a single threaded + * process to want transactions for atomicity guarantees, but not + * necessarily need concurrency. + */ + if (LF_ISSET(DB_INIT_MPOOL)) + if ((ret = __memp_open(dbenv)) != 0) + goto err; + if (LF_ISSET(DB_INIT_LOG | DB_INIT_TXN)) + if ((ret = __log_open(dbenv)) != 0) + goto err; + if (LF_ISSET(DB_INIT_LOCK)) + if ((ret = __lock_open(dbenv)) != 0) + goto err; + if (LF_ISSET(DB_INIT_TXN)) { + if ((ret = __txn_open(dbenv)) != 0) + goto err; + + /* + * If the application is running with transactions, initialize + * the function tables. + */ + if ((ret = __bam_init_recover(dbenv)) != 0) + goto err; + if ((ret = __crdel_init_recover(dbenv)) != 0) + goto err; + if ((ret = __db_init_recover(dbenv)) != 0) + goto err; + if ((ret = __ham_init_recover(dbenv)) != 0) + goto err; + if ((ret = __log_init_recover(dbenv)) != 0) + goto err; + if ((ret = __qam_init_recover(dbenv)) != 0) + goto err; + if ((ret = __txn_init_recover(dbenv)) != 0) + goto err; + + /* + * If the application specified their own recovery + * initialization function, call it. + */ + if (dbenv->db_recovery_init != NULL && + (ret = dbenv->db_recovery_init(dbenv)) != 0) + goto err; + + /* Perform recovery for any previous run. */ + if (LF_ISSET(DB_RECOVER | DB_RECOVER_FATAL) && + (ret = __db_apprec(dbenv, + LF_ISSET(DB_RECOVER | DB_RECOVER_FATAL))) != 0) + goto err; + } + return (0); + +err: (void)__dbenv_refresh(dbenv); + return (ret); +} + +/* + * __dbenv_remove -- + * Discard an environment. + * + * PUBLIC: int __dbenv_remove __P((DB_ENV *, const char *, u_int32_t)); + */ +int +__dbenv_remove(dbenv, db_home, flags) + DB_ENV *dbenv; + const char *db_home; + u_int32_t flags; +{ + int ret, t_ret; + +#undef OKFLAGS +#define OKFLAGS \ + DB_FORCE | DB_USE_ENVIRON | DB_USE_ENVIRON_ROOT + + /* Validate arguments. */ + if ((ret = __db_fchk(dbenv, "DBENV->remove", flags, OKFLAGS)) != 0) + goto err; + + /* + * A hard-to-debug error is calling DBENV->remove after open. That's + * not legal. You have to close the original, already opened handle + * and then allocate a new DBENV handle to use for DBENV->remove. + */ + if (F_ISSET(dbenv, DB_ENV_OPEN_CALLED)) { + __db_err(dbenv, + "DBENV handle opened, not usable for remove method."); + return (EINVAL); + } + + /* Initialize the DB_ENV structure. */ + if ((ret = __dbenv_config(dbenv, db_home, flags)) != 0) + goto err; + + /* Remove the environment. */ + ret = __db_e_remove(dbenv, LF_ISSET(DB_FORCE) ? 1 : 0); + + /* Discard any resources we've acquired. */ +err: if ((t_ret = __dbenv_refresh(dbenv)) != 0 && ret == 0) + ret = t_ret; + + memset(dbenv, CLEAR_BYTE, sizeof(DB_ENV)); + __os_free(dbenv, sizeof(DB_ENV)); + + return (ret); +} + +/* + * __dbenv_config -- + * Initialize the DB_ENV structure. + */ +static int +__dbenv_config(dbenv, db_home, flags) + DB_ENV *dbenv; + const char *db_home; + u_int32_t flags; +{ + FILE *fp; + int ret; + char *lp, buf[MAXPATHLEN * 2]; + + /* Set the database home. */ + if ((ret = __db_home(dbenv, db_home, flags)) != 0) + return (ret); + + /* + * Parse the config file. + * + * !!! + * Don't use sprintf(3)/snprintf(3) -- the former is dangerous, and + * the latter isn't standard, and we're manipulating strings handed + * us by the application. + */ + if (dbenv->db_home != NULL) { +#define CONFIG_NAME "/DB_CONFIG" + if (strlen(dbenv->db_home) + + strlen(CONFIG_NAME) + 1 > sizeof(buf)) { + ret = ENAMETOOLONG; + return (ret); + } + (void)strcpy(buf, dbenv->db_home); + (void)strcat(buf, CONFIG_NAME); + if ((fp = fopen(buf, "r")) != NULL) { + while (fgets(buf, sizeof(buf), fp) != NULL) { + if ((lp = strchr(buf, '\n')) == NULL) { + __db_err(dbenv, + "%s: line too long", CONFIG_NAME); + (void)fclose(fp); + ret = EINVAL; + return (ret); + } + *lp = '\0'; + if (buf[0] == '\0' || + buf[0] == '#' || isspace((int)buf[0])) + continue; + + if ((ret = __db_parse(dbenv, buf)) != 0) { + (void)fclose(fp); + return (ret); + } + } + (void)fclose(fp); + } + } + + /* Set up the tmp directory path. */ + if (dbenv->db_tmp_dir == NULL && (ret = __os_tmpdir(dbenv, flags)) != 0) + return (ret); + + /* + * The locking file descriptor is rarely on. Set the fd to -1, not + * because it's ever tested, but to make sure we catch mistakes. + */ + if ((ret = + __os_calloc(dbenv, + 1, sizeof(*dbenv->lockfhp), &dbenv->lockfhp)) != 0) + return (ret); + dbenv->lockfhp->fd = -1; + + /* + * Flag that the DB_ENV structure has been initialized. Note, this + * must be set before calling into the subsystems as it's used during + * file naming. + */ + F_SET(dbenv, DB_ENV_OPEN_CALLED); + + return (0); +} + +/* + * __dbenv_close -- + * DB_ENV destructor. + * + * PUBLIC: int __dbenv_close __P((DB_ENV *, u_int32_t)); + */ +int +__dbenv_close(dbenv, flags) + DB_ENV *dbenv; + u_int32_t flags; +{ + int ret; + + COMPQUIET(flags, 0); + + PANIC_CHECK(dbenv); + + ret = __dbenv_refresh(dbenv); + + /* Discard the structure if we allocated it. */ + if (!F_ISSET(dbenv, DB_ENV_USER_ALLOC)) { + memset(dbenv, CLEAR_BYTE, sizeof(DB_ENV)); + __os_free(dbenv, sizeof(DB_ENV)); + } + + return (ret); +} + +/* + * __dbenv_refresh -- + * Refresh the DB_ENV structure, releasing any allocated resources. + */ +static int +__dbenv_refresh(dbenv) + DB_ENV *dbenv; +{ + int ret, t_ret; + char **p; + + ret = 0; + + /* + * Close subsystems, in the reverse order they were opened (txn + * must be first, it may want to discard locks and flush the log). + */ + if (TXN_ON(dbenv)) { + if ((t_ret = __txn_close(dbenv)) != 0 && ret == 0) + ret = t_ret; + } + + if (LOCKING_ON(dbenv)) { + if ((t_ret = __lock_close(dbenv)) != 0 && ret == 0) + ret = t_ret; + } + __lock_dbenv_close(dbenv); + + if (LOGGING_ON(dbenv)) { + if ((t_ret = __log_close(dbenv)) != 0 && ret == 0) + ret = t_ret; + } + + if (MPOOL_ON(dbenv)) { + if ((t_ret = __memp_close(dbenv)) != 0 && ret == 0) + ret = t_ret; + } + + /* Discard DB list and its mutex. */ + LIST_INIT(&dbenv->dblist); + if (dbenv->dblist_mutexp != NULL) + __db_mutex_free(dbenv, dbenv->reginfo, dbenv->dblist_mutexp); + + /* Detach from the region. */ + if (dbenv->reginfo != NULL) { + if ((t_ret = __db_e_detach(dbenv, 0)) != 0 && ret == 0) + ret = t_ret; + /* + * !!! + * Don't free dbenv->reginfo or set the reference to NULL, + * that was done by __db_e_detach(). + */ + } + + /* Clean up the structure. */ + dbenv->db_panic = 0; + + if (dbenv->db_home != NULL) { + __os_freestr(dbenv->db_home); + dbenv->db_home = NULL; + } + if (dbenv->db_log_dir != NULL) { + __os_freestr(dbenv->db_log_dir); + dbenv->db_log_dir = NULL; + } + if (dbenv->db_tmp_dir != NULL) { + __os_freestr(dbenv->db_tmp_dir); + dbenv->db_tmp_dir = NULL; + } + if (dbenv->db_data_dir != NULL) { + for (p = dbenv->db_data_dir; *p != NULL; ++p) + __os_freestr(*p); + __os_free(dbenv->db_data_dir, + dbenv->data_cnt * sizeof(char **)); + dbenv->db_data_dir = NULL; + } + dbenv->data_cnt = dbenv->data_next = 0; + + dbenv->db_mode = 0; + + if (dbenv->lockfhp != NULL) { + __os_free(dbenv->lockfhp, sizeof(*dbenv->lockfhp)); + dbenv->lockfhp = NULL; + } + + if (dbenv->dtab != NULL) { + __os_free(dbenv->dtab, + dbenv->dtab_size * sizeof(dbenv->dtab[0])); + dbenv->dtab = NULL; + dbenv->dtab_size = 0; + } + + dbenv->mp_mmapsize = 0; + dbenv->links.tqe_next = NULL; + dbenv->links.tqe_prev = NULL; + dbenv->xa_rmid = 0; + dbenv->xa_txn = 0; + + F_CLR(dbenv, ~(DB_ENV_STANDALONE | DB_ENV_USER_ALLOC)); + + return (ret); +} + +#define DB_ADDSTR(add) { \ + if ((add) != NULL) { \ + /* If leading slash, start over. */ \ + if (__os_abspath(add)) { \ + p = str; \ + slash = 0; \ + } \ + /* Append to the current string. */ \ + len = strlen(add); \ + if (slash) \ + *p++ = PATH_SEPARATOR[0]; \ + memcpy(p, add, len); \ + p += len; \ + slash = strchr(PATH_SEPARATOR, p[-1]) == NULL; \ + } \ +} + +/* + * __db_appname -- + * Given an optional DB environment, directory and file name and type + * of call, build a path based on the DBENV->open rules, and return + * it in allocated space. + * + * PUBLIC: int __db_appname __P((DB_ENV *, APPNAME, + * PUBLIC: const char *, const char *, u_int32_t, DB_FH *, char **)); + */ +int +__db_appname(dbenv, appname, dir, file, tmp_oflags, fhp, namep) + DB_ENV *dbenv; + APPNAME appname; + const char *dir, *file; + u_int32_t tmp_oflags; + DB_FH *fhp; + char **namep; +{ + DB_ENV etmp; + size_t len, str_len; + int data_entry, ret, slash, tmp_create, tmp_free; + const char *a, *b, *c; + char *p, *str; + + a = b = c = NULL; + data_entry = -1; + tmp_create = tmp_free = 0; + + /* + * We don't return a name when creating temporary files, just a + * file handle. Default to an error now. + */ + if (fhp != NULL) + F_CLR(fhp, DB_FH_VALID); + if (namep != NULL) + *namep = NULL; + + /* + * Absolute path names are never modified. If the file is an absolute + * path, we're done. If the directory is, simply append the file and + * return. + */ + if (file != NULL && __os_abspath(file)) + return (__os_strdup(dbenv, file, namep)); + if (dir != NULL && __os_abspath(dir)) { + a = dir; + goto done; + } + + /* + * DB_ENV DIR APPNAME RESULT + * ------------------------------------------- + * null null none /file + * null set none DIR/file + * set null none DB_HOME/file + * set set none DB_HOME/DIR/file + * + * DB_ENV FILE APPNAME RESULT + * ------------------------------------------- + * null null DB_APP_DATA / + * null set DB_APP_DATA ./file + * set null DB_APP_DATA / + * set set DB_APP_DATA DB_HOME/DB_DATA_DIR/file + * + * DB_ENV DIR APPNAME RESULT + * ------------------------------------------- + * null null DB_APP_LOG /file + * null set DB_APP_LOG DIR/file + * set null DB_APP_LOG DB_HOME/DB_LOG_DIR/file + * set set DB_APP_LOG DB_HOME/DB_LOG_DIR/DIR/file + * + * DB_ENV APPNAME RESULT + * ------------------------------------------- + * null DB_APP_TMP* / + * set DB_APP_TMP* DB_HOME/DB_TMP_DIR/ + */ +retry: switch (appname) { + case DB_APP_NONE: + if (dbenv == NULL || !F_ISSET(dbenv, DB_ENV_OPEN_CALLED)) { + if (dir == NULL) + goto tmp; + a = dir; + } else { + a = dbenv->db_home; + b = dir; + } + break; + case DB_APP_DATA: + if (dir != NULL) { + __db_err(dbenv, + "DB_APP_DATA: illegal directory specification"); + return (EINVAL); + } + + if (file == NULL) { + tmp_create = 1; + goto tmp; + } + if (dbenv != NULL && F_ISSET(dbenv, DB_ENV_OPEN_CALLED)) { + a = dbenv->db_home; + if (dbenv->db_data_dir != NULL && + (b = dbenv->db_data_dir[++data_entry]) == NULL) { + data_entry = -1; + b = dbenv->db_data_dir[0]; + } + } + break; + case DB_APP_LOG: + if (dbenv == NULL || !F_ISSET(dbenv, DB_ENV_OPEN_CALLED)) { + if (dir == NULL) + goto tmp; + a = dir; + } else { + a = dbenv->db_home; + b = dbenv->db_log_dir; + c = dir; + } + break; + case DB_APP_TMP: + if (dir != NULL || file != NULL) { + __db_err(dbenv, + "DB_APP_TMP: illegal directory or file specification"); + return (EINVAL); + } + + tmp_create = 1; + if (dbenv == NULL || !F_ISSET(dbenv, DB_ENV_OPEN_CALLED)) + goto tmp; + else { + a = dbenv->db_home; + b = dbenv->db_tmp_dir; + } + break; + } + + /* Reference a file from the appropriate temporary directory. */ + if (0) { +tmp: if (dbenv == NULL || !F_ISSET(dbenv, DB_ENV_OPEN_CALLED)) { + memset(&etmp, 0, sizeof(etmp)); + if ((ret = __os_tmpdir(&etmp, DB_USE_ENVIRON)) != 0) + return (ret); + tmp_free = 1; + a = etmp.db_tmp_dir; + } else + a = dbenv->db_tmp_dir; + } + +done: len = + (a == NULL ? 0 : strlen(a) + 1) + + (b == NULL ? 0 : strlen(b) + 1) + + (c == NULL ? 0 : strlen(c) + 1) + + (file == NULL ? 0 : strlen(file) + 1); + + /* + * Allocate space to hold the current path information, as well as any + * temporary space that we're going to need to create a temporary file + * name. + */ +#define DB_TRAIL "BDBXXXXXX" + str_len = len + sizeof(DB_TRAIL) + 10; + if ((ret = __os_malloc(dbenv, str_len, NULL, &str)) != 0) { + if (tmp_free) + __os_freestr(etmp.db_tmp_dir); + return (ret); + } + + slash = 0; + p = str; + DB_ADDSTR(a); + DB_ADDSTR(b); + DB_ADDSTR(file); + *p = '\0'; + + /* Discard any space allocated to find the temp directory. */ + if (tmp_free) { + __os_freestr(etmp.db_tmp_dir); + tmp_free = 0; + } + + /* + * If we're opening a data file, see if it exists. If it does, + * return it, otherwise, try and find another one to open. + */ + if (data_entry != -1 && __os_exists(str, NULL) != 0) { + __os_free(str, str_len); + a = b = c = NULL; + goto retry; + } + + /* Create the file if so requested. */ + if (tmp_create && + (ret = __db_tmp_open(dbenv, tmp_oflags, str, fhp)) != 0) { + __os_free(str, str_len); + return (ret); + } + + if (namep == NULL) + __os_free(str, str_len); + else + *namep = str; + return (0); +} + +/* + * __db_home -- + * Find the database home. + */ +static int +__db_home(dbenv, db_home, flags) + DB_ENV *dbenv; + const char *db_home; + u_int32_t flags; +{ + const char *p; + + /* + * Use db_home by default, this allows utilities to reasonably + * override the environment either explicitly or by using a -h + * option. Otherwise, use the environment if it's permitted + * and initialized. + */ + if ((p = db_home) == NULL && + (LF_ISSET(DB_USE_ENVIRON) || + (LF_ISSET(DB_USE_ENVIRON_ROOT) && __os_isroot())) && + (p = getenv("DB_HOME")) != NULL && p[0] == '\0') { + __db_err(dbenv, "illegal DB_HOME environment variable"); + return (EINVAL); + } + + return (p == NULL ? 0 : __os_strdup(dbenv, p, &dbenv->db_home)); +} + +/* + * __db_parse -- + * Parse a single NAME VALUE pair. + */ +static int +__db_parse(dbenv, s) + DB_ENV *dbenv; + char *s; +{ + u_long v1, v2, v3; + u_int32_t flags; + char *name, *p, *value, v4; + + /* + * !!! + * The value of 40 is hard-coded into format arguments to sscanf + * below, it can't be changed here without changing it there, too. + */ + char arg[40]; + + /* + * Name/value pairs are parsed as two white-space separated strings. + * Leading and trailing white-space is trimmed from the value, but + * it may contain embedded white-space. Note: we use the isspace(3) + * macro because it's more portable, but that means that you can use + * characters like form-feed to separate the strings. + */ + name = s; + for (p = name; *p != '\0' && !isspace((int)*p); ++p) + ; + if (*p == '\0' || p == name) + goto illegal; + *p = '\0'; + for (++p; isspace((int)*p); ++p) + ; + if (*p == '\0') + goto illegal; + value = p; + for (++p; *p != '\0'; ++p) + ; + for (--p; isspace((int)*p); --p) + ; + ++p; + if (p == value) { +illegal: __db_err(dbenv, "mis-formatted name-value pair: %s", s); + return (EINVAL); + } + *p = '\0'; + + if (!strcasecmp(name, "set_cachesize")) { + if (sscanf(value, "%lu %lu %lu %c", &v1, &v2, &v3, &v4) != 3) + goto badarg; + return (dbenv->set_cachesize(dbenv, v1, v2, v3)); + } + + if (!strcasecmp(name, "set_data_dir") || + !strcasecmp(name, "db_data_dir")) /* Compatibility. */ + return (dbenv->set_data_dir(dbenv, value)); + + if (!strcasecmp(name, "set_flags")) { + if (sscanf(value, "%40s %c", arg, &v4) != 1) + goto badarg; + + if (!strcasecmp(value, "db_cdb_alldb")) + return (dbenv->set_flags(dbenv, DB_CDB_ALLDB, 1)); + if (!strcasecmp(value, "db_nommap")) + return (dbenv->set_flags(dbenv, DB_NOMMAP, 1)); + if (!strcasecmp(value, "db_txn_nosync")) + return (dbenv->set_flags(dbenv, DB_TXN_NOSYNC, 1)); + goto badarg; + } + + if (!strcasecmp(name, "set_lg_bsize")) { + if (sscanf(value, "%lu %c", &v1, &v4) != 1) + goto badarg; + return (dbenv->set_lg_bsize(dbenv, v1)); + } + + if (!strcasecmp(name, "set_lg_max")) { + if (sscanf(value, "%lu %c", &v1, &v4) != 1) + goto badarg; + return (dbenv->set_lg_max(dbenv, v1)); + } + + if (!strcasecmp(name, "set_lg_dir") || + !strcasecmp(name, "db_log_dir")) /* Compatibility. */ + return (dbenv->set_lg_dir(dbenv, value)); + + if (!strcasecmp(name, "set_lk_detect")) { + if (sscanf(value, "%40s %c", arg, &v4) != 1) + goto badarg; + if (!strcasecmp(value, "db_lock_default")) + flags = DB_LOCK_DEFAULT; + else if (!strcasecmp(value, "db_lock_oldest")) + flags = DB_LOCK_OLDEST; + else if (!strcasecmp(value, "db_lock_random")) + flags = DB_LOCK_RANDOM; + else if (!strcasecmp(value, "db_lock_youngest")) + flags = DB_LOCK_YOUNGEST; + else + goto badarg; + return (dbenv->set_lk_detect(dbenv, flags)); + } + + if (!strcasecmp(name, "set_lk_max")) { + if (sscanf(value, "%lu %c", &v1, &v4) != 1) + goto badarg; + return (dbenv->set_lk_max(dbenv, v1)); + } + + if (!strcasecmp(name, "set_lk_max_locks")) { + if (sscanf(value, "%lu %c", &v1, &v4) != 1) + goto badarg; + return (dbenv->set_lk_max_locks(dbenv, v1)); + } + + if (!strcasecmp(name, "set_lk_max_lockers")) { + if (sscanf(value, "%lu %c", &v1, &v4) != 1) + goto badarg; + return (dbenv->set_lk_max_lockers(dbenv, v1)); + } + + if (!strcasecmp(name, "set_lk_max_objects")) { + if (sscanf(value, "%lu %c", &v1, &v4) != 1) + goto badarg; + return (dbenv->set_lk_max_objects(dbenv, v1)); + } + + if (!strcasecmp(name, "set_mp_mmapsize")) { + if (sscanf(value, "%lu %c", &v1, &v4) != 1) + goto badarg; + return (dbenv->set_mp_mmapsize(dbenv, v1)); + } + + if (!strcasecmp(name, "set_region_init")) { + if (sscanf(value, "%lu %c", &v1, &v4) != 1 || v1 != 1) + goto badarg; + return (db_env_set_region_init(v1)); + } + + if (!strcasecmp(name, "set_shm_key")) { + if (sscanf(value, "%lu %c", &v1, &v4) != 1) + goto badarg; + return (dbenv->set_shm_key(dbenv, (long)v1)); + } + + if (!strcasecmp(name, "set_tas_spins")) { + if (sscanf(value, "%lu %c", &v1, &v4) != 1) + goto badarg; + return (db_env_set_tas_spins(v1)); + } + + if (!strcasecmp(name, "set_tmp_dir") || + !strcasecmp(name, "db_tmp_dir")) /* Compatibility.*/ + return (dbenv->set_tmp_dir(dbenv, value)); + + if (!strcasecmp(name, "set_tx_max")) { + if (sscanf(value, "%lu %c", &v1, &v4) != 1) + goto badarg; + return (dbenv->set_tx_max(dbenv, v1)); + } + + if (!strcasecmp(name, "set_verbose")) { + if (sscanf(value, "%40s %c", arg, &v4) != 1) + goto badarg; + + if (!strcasecmp(value, "db_verb_chkpoint")) + flags = DB_VERB_CHKPOINT; + else if (!strcasecmp(value, "db_verb_deadlock")) + flags = DB_VERB_DEADLOCK; + else if (!strcasecmp(value, "db_verb_recovery")) + flags = DB_VERB_RECOVERY; + else if (!strcasecmp(value, "db_verb_waitsfor")) + flags = DB_VERB_WAITSFOR; + else + goto badarg; + return (dbenv->set_verbose(dbenv, flags, 1)); + } + + __db_err(dbenv, "unrecognized name-value pair: %s", s); + return (EINVAL); + +badarg: __db_err(dbenv, "incorrect arguments for name-value pair: %s", s); + return (EINVAL); +} + +/* + * __db_tmp_open -- + * Create a temporary file. + */ +static int +__db_tmp_open(dbenv, tmp_oflags, path, fhp) + DB_ENV *dbenv; + u_int32_t tmp_oflags; + char *path; + DB_FH *fhp; +{ + u_long pid; + int mode, isdir, ret; + const char *p; + char *trv; + + /* + * Check the target directory; if you have six X's and it doesn't + * exist, this runs for a *very* long time. + */ + if ((ret = __os_exists(path, &isdir)) != 0) { + __db_err(dbenv, "%s: %s", path, db_strerror(ret)); + return (ret); + } + if (!isdir) { + __db_err(dbenv, "%s: %s", path, db_strerror(EINVAL)); + return (EINVAL); + } + + /* Build the path. */ + for (trv = path; *trv != '\0'; ++trv) + ; + *trv = PATH_SEPARATOR[0]; + for (p = DB_TRAIL; (*++trv = *p) != '\0'; ++p) + ; + + /* + * Replace the X's with the process ID. Pid should be a pid_t, + * but we use unsigned long for portability. + */ + for (pid = getpid(); *--trv == 'X'; pid /= 10) + switch (pid % 10) { + case 0: *trv = '0'; break; + case 1: *trv = '1'; break; + case 2: *trv = '2'; break; + case 3: *trv = '3'; break; + case 4: *trv = '4'; break; + case 5: *trv = '5'; break; + case 6: *trv = '6'; break; + case 7: *trv = '7'; break; + case 8: *trv = '8'; break; + case 9: *trv = '9'; break; + } + ++trv; + + /* Set up open flags and mode. */ + mode = __db_omode("rw----"); + + /* Loop, trying to open a file. */ + for (;;) { + if ((ret = __os_open(dbenv, path, + tmp_oflags | DB_OSO_CREATE | DB_OSO_EXCL, mode, fhp)) == 0) + return (0); + + /* + * !!!: + * If we don't get an EEXIST error, then there's something + * seriously wrong. Unfortunately, if the implementation + * doesn't return EEXIST for O_CREAT and O_EXCL regardless + * of other possible errors, we've lost. + */ + if (ret != EEXIST) { + __db_err(dbenv, + "tmp_open: %s: %s", path, db_strerror(ret)); + return (ret); + } + + /* + * Tricky little algorithm for backward compatibility. + * Assumes sequential ordering of lower-case characters. + */ + for (;;) { + if (*trv == '\0') + return (EINVAL); + if (*trv == 'z') + *trv++ = 'a'; + else { + if (isdigit((int)*trv)) + *trv = 'a'; + else + ++*trv; + break; + } + } + } + /* NOTREACHED */ +} diff --git a/db/env/env_recover.c b/db/env/env_recover.c new file mode 100644 index 000000000..bc5e47605 --- /dev/null +++ b/db/env/env_recover.c @@ -0,0 +1,449 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char copyright[] = + "Copyright (c) 1996-2000\nSleepycat Software Inc. All rights reserved.\n"; +static const char revid[] = + "$Id: env_recover.c,v 11.33 2001/01/04 22:38:42 ubell Exp $"; +#endif + +#ifndef NO_SYSTEM_INCLUDES +#include + +#if TIME_WITH_SYS_TIME +#include +#include +#else +#if HAVE_SYS_TIME_H +#include +#else +#include +#endif +#endif + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_dispatch.h" +#include "db_am.h" +#include "log.h" +#include "txn.h" + +static float __lsn_diff __P((DB_LSN *, DB_LSN *, DB_LSN *, u_int32_t, int)); +static int __log_earliest __P((DB_ENV *, int32_t *, DB_LSN *)); + +/* + * __db_apprec -- + * Perform recovery. + * + * PUBLIC: int __db_apprec __P((DB_ENV *, u_int32_t)); + */ +int +__db_apprec(dbenv, flags) + DB_ENV *dbenv; + u_int32_t flags; +{ + DBT data; + DB_LSN ckp_lsn, first_lsn, last_lsn, lowlsn, lsn, open_lsn; + DB_TXNREGION *region; + __txn_ckp_args *ckp_args; + time_t now, tlow; + float nfiles; + int32_t low; + int is_thread, progress, ret; + void *txninfo; + + COMPQUIET(nfiles, (float)0); + + /* + * Save the state of the thread flag -- we don't need it on at the + * moment because we're single-threaded until recovery is complete. + */ + is_thread = F_ISSET(dbenv, DB_ENV_THREAD) ? 1 : 0; + F_CLR(dbenv, DB_ENV_THREAD); + F_SET((DB_LOG *)dbenv->lg_handle, DBLOG_RECOVER); + + /* + * If the user is specifying recover to a particular point in time, + * verify that the logs present are sufficient to do this. + */ + ZERO_LSN(lowlsn); + if (dbenv->tx_timestamp != 0) { + if ((ret = __log_earliest(dbenv, &low, &lowlsn)) != 0) + return (ret); + if ((int32_t)dbenv->tx_timestamp < low) { + char t1[30], t2[30]; + + strcpy(t1, ctime(&dbenv->tx_timestamp)); + tlow = (time_t)low; + strcpy(t2, ctime(&tlow)); + __db_err(dbenv, + "Invalid recovery timestamp %.*s; earliest time is %.*s", + 24, t1, 24, t2); + return (EINVAL); + } + } + + /* Initialize the transaction list. */ + if ((ret = __db_txnlist_init(dbenv, &txninfo)) != 0) + return (ret); + + /* + * Recovery is done in three passes: + * Pass #0: + * We need to find the position from which we will open files + * We need to open files beginning with the last to next + * checkpoint because we might have crashed after writing the + * last checkpoint record, but before having written out all + * the open file information. + * + * Pass #1: + * Read forward through the log from the second to last checkpoint + * opening and closing files so that at the end of the log we have + * the "current" set of files open. + * + * Pass #2: + * Read backward through the log undoing any uncompleted TXNs. + * There are three cases: + * 1. If doing catastrophic recovery, we read to the beginning + * of the log + * 2. If we are doing normal reovery, then we have to roll + * back to the most recent checkpoint that occurs + * before the most recent checkpoint LSN, which is + * returned by __log_findckp(). + * 3. If we are recovering to a point in time, then we have + * to roll back to the checkpoint whose ckp_lsn is earlier + * than the specified time. __log_earliest will figure + * this out for us. + * In case 2, "uncompleted TXNs" include all those who commited + * after the user's specified timestamp. + * + * Pass #3: + * Read forward through the log from the LSN found in pass #2, + * redoing any committed TXNs (which commited after any user- + * specified rollback point). During this pass, checkpoint + * file information is ignored, and file openings and closings + * are redone. + */ + + /* + * Find out the last lsn, so that we can estimate how far along we + * are in recovery. This will help us determine how much log there + * is between the first LSN that we're going to be working with and + * the last one. We assume that each of the three phases takes the + * same amount of time (a false assumption) and then use the %-age + * of the amount of log traversed to figure out how much of the + * pass we've accomplished. + */ + memset(&data, 0, sizeof(data)); + if (dbenv->db_feedback != NULL && + (ret = log_get(dbenv, &last_lsn, &data, DB_LAST)) != 0) + goto out; + + /* + * Pass #0 + * Find the second to last checkpoint in the log. This is the point + * from which we want to begin pass #1 (the open files pass). + */ + ckp_args = NULL; + + if (LF_ISSET(DB_RECOVER_FATAL)) { + if ((ret = log_get(dbenv, &ckp_lsn, &data, DB_FIRST)) != 0) { + if (ret == DB_NOTFOUND) + ret = 0; + else + __db_err(dbenv, "First log record not found"); + goto out; + } + open_lsn = ckp_lsn; + } else if ((ret = + log_get(dbenv, &ckp_lsn, &data, DB_CHECKPOINT)) != 0) { + /* + * If we don't find a checkpoint, start from the beginning. + * If that fails, we're done. Note, we do not require that + * there be log records if we're performing recovery. + */ +first: if ((ret = log_get(dbenv, &ckp_lsn, &data, DB_FIRST)) != 0) { + if (ret == DB_NOTFOUND) + ret = 0; + else + __db_err(dbenv, "First log record not found"); + goto out; + } + open_lsn = ckp_lsn; + } else if ((ret = __txn_ckp_read(dbenv, data.data, &ckp_args)) != 0) { + __db_err(dbenv, "Invalid checkpoint record at [%ld][%ld]\n", + (u_long)ckp_lsn.file, (u_long)ckp_lsn.offset); + goto out; + } else if (IS_ZERO_LSN(ckp_args->last_ckp) || + (ret = log_get(dbenv, &ckp_args->last_ckp, &data, DB_SET)) != 0) + goto first; + else + open_lsn = ckp_args->last_ckp; + + if (dbenv->db_feedback != NULL) { + if (last_lsn.file == open_lsn.file) + nfiles = (float)(last_lsn.offset - open_lsn.offset) / + dbenv->lg_max; + else + nfiles = (float)(last_lsn.file - open_lsn.file) + + (float)(dbenv->lg_max - open_lsn.offset + + last_lsn.offset) / dbenv->lg_max; + /* We are going to divide by nfiles; make sure it isn't 0. */ + if (nfiles == 0) + nfiles = (float)0.001; + } + + /* + * Pass #1 + * Now, ckp_lsn is either the lsn of the last checkpoint + * or the lsn of the first record in the log. Open_lsn is + * the second to last checkpoint or the beinning of the log; + * begin the open files pass from that lsn, and proceed to + * the end of the log. + */ + lsn = open_lsn; + for (;;) { + if (dbenv->db_feedback != NULL) { + progress = (int)(33 * (__lsn_diff(&open_lsn, + &last_lsn, &lsn, dbenv->lg_max, 1) / nfiles)); + dbenv->db_feedback(dbenv, DB_RECOVER, progress); + } + ret = __db_dispatch(dbenv, + &data, &lsn, DB_TXN_OPENFILES, txninfo); + if (ret != 0 && ret != DB_TXN_CKP) + goto msgerr; + if ((ret = log_get(dbenv, &lsn, &data, DB_NEXT)) != 0) { + if (ret == DB_NOTFOUND) + break; + goto out; + } + } + + /* + * Pass #2. + * + * Before we can begin pass #2, backward roll phase, we determine how + * far back in the log to recover. If we are doing catastrophic + * recovery, then we go as far back as we have files. If we are + * doing normal recovery, we go as back to the most recent checkpoint + * that occurs before the most recent checkpoint LSN. If we are + * recovering to a point in time, then rollback to the checkpoint whose + * ckp_lsn precedes the first log record (and then roll forward to + * the appropriate timestamp in Pass #3). + */ + if (LF_ISSET(DB_RECOVER_FATAL)) { + ZERO_LSN(first_lsn); + } else if (dbenv->tx_timestamp != 0) + first_lsn = lowlsn; + else + if ((ret = __log_findckp(dbenv, &first_lsn)) == DB_NOTFOUND) { + /* + * We don't require that log files exist if recovery + * was specified. + */ + ret = 0; + goto out; + } + + if (FLD_ISSET(dbenv->verbose, DB_VERB_RECOVERY)) + __db_err(dbenv, "Recovery starting from [%lu][%lu]", + (u_long)first_lsn.file, (u_long)first_lsn.offset); + + for (ret = log_get(dbenv, &lsn, &data, DB_LAST); + ret == 0 && log_compare(&lsn, &first_lsn) > 0; + ret = log_get(dbenv, &lsn, &data, DB_PREV)) { + if (dbenv->db_feedback != NULL) { + progress = 34 + (int)(33 * (__lsn_diff(&open_lsn, + &last_lsn, &lsn, dbenv->lg_max, 0) / nfiles)); + dbenv->db_feedback(dbenv, DB_RECOVER, progress); + } + ret = __db_dispatch(dbenv, + &data, &lsn, DB_TXN_BACKWARD_ROLL, txninfo); + if (ret != 0) { + if (ret != DB_TXN_CKP) + goto msgerr; + else + ret = 0; + } + } + if (ret != 0 && ret != DB_NOTFOUND) + goto out; + + /* + * Pass #3. + */ + for (ret = log_get(dbenv, &lsn, &data, DB_NEXT); + ret == 0; ret = log_get(dbenv, &lsn, &data, DB_NEXT)) { + if (dbenv->db_feedback != NULL) { + progress = 67 + (int)(33 * (__lsn_diff(&open_lsn, + &last_lsn, &lsn, dbenv->lg_max, 1) / nfiles)); + dbenv->db_feedback(dbenv, DB_RECOVER, progress); + } + ret = __db_dispatch(dbenv, + &data, &lsn, DB_TXN_FORWARD_ROLL, txninfo); + if (ret != 0) { + if (ret != DB_TXN_CKP) + goto msgerr; + else + ret = 0; + } + } + if (ret != DB_NOTFOUND) + goto out; + + /* + * Process any pages that were on the limbo list + * and move them to the free list. Do this + * before checkpointing the database. + */ + if ((ret = __db_do_the_limbo(dbenv, txninfo)) != 0) + goto out; + + /* + * Now set the last checkpoint lsn and the current time, + * take a checkpoint, and reset the txnid. + */ + (void)time(&now); + region = ((DB_TXNMGR *)dbenv->tx_handle)->reginfo.primary; + region->last_txnid = ((DB_TXNHEAD *)txninfo)->maxid; + region->last_ckp = ckp_lsn; + region->time_ckp = (u_int32_t)now; + + /* + * Take two checkpoints so that we don't re-recover any of the + * work we've already done. + */ + if ((ret = txn_checkpoint(dbenv, 0, 0, DB_FORCE)) != 0) + goto out; + + /* Now close all the db files that are open. */ + __log_close_files(dbenv); + + if ((ret = txn_checkpoint(dbenv, 0, 0, DB_FORCE)) != 0) + goto out; + region->last_txnid = TXN_MINIMUM; + + if (FLD_ISSET(dbenv->verbose, DB_VERB_RECOVERY)) { + __db_err(dbenv, "Recovery complete at %.24s", ctime(&now)); + __db_err(dbenv, "%s %lx %s [%lu][%lu]", + "Maximum transaction ID", + ((DB_TXNHEAD *)txninfo)->maxid, + "Recovery checkpoint", + (u_long)region->last_ckp.file, + (u_long)region->last_ckp.offset); + } + + if (0) { +msgerr: __db_err(dbenv, "Recovery function for LSN %lu %lu failed", + (u_long)lsn.file, (u_long)lsn.offset); + } + +out: if (is_thread) + F_SET(dbenv, DB_ENV_THREAD); + __db_txnlist_end(dbenv, txninfo); + if (ckp_args != NULL) + __os_free(ckp_args, sizeof(*ckp_args)); + F_CLR((DB_LOG *)dbenv->lg_handle, DBLOG_RECOVER); + + dbenv->tx_timestamp = 0; + return (ret); +} + +/* + * Figure out how many logfiles we have processed. If we are moving + * forward (is_forward != 0), then we're computing current - low. If + * we are moving backward, we are computing high - current. max is + * the number of bytes per logfile. + */ +static float +__lsn_diff(low, high, current, max, is_forward) + DB_LSN *low, *high, *current; + u_int32_t max; + int is_forward; +{ + float nf; + + /* + * There are three cases in each direction. If you are in the + * same file, then all you need worry about is the difference in + * offsets. If you are in different files, then either your offsets + * put you either more or less than the integral difference in the + * number of files -- we need to handle both of these. + */ + if (is_forward) { + if (current->file == low->file) + nf = (float)(current->offset - low->offset) / max; + else if (current->offset < low->offset) + nf = (float)(current->file - low->file - 1) + + (float)(max - low->offset + current->offset) / max; + else + nf = (float)(current->file - low->file) + + (float)(current->offset - low->offset) / max; + } else { + if (current->file == high->file) + nf = (float)(high->offset - current->offset) / max; + else if (current->offset > high->offset) + nf = (float)(high->file - current->file - 1) + + (float)(max - current->offset + high->offset) / max; + else + nf = (float)(high->file - current->file) + + (float)(high->offset - current->offset) / max; + } + return (nf); +} + +/* + * __log_earliest -- + * + * Return the earliest recovery point for the log files present. The + * earliest recovery time is the time stamp of the first checkpoint record + * whose checkpoint LSN is greater than the first LSN we process. + */ +static int +__log_earliest(dbenv, lowtime, lowlsn) + DB_ENV *dbenv; + int32_t *lowtime; + DB_LSN *lowlsn; +{ + DB_LSN first_lsn, lsn; + DBT data; + __txn_ckp_args *ckpargs; + u_int32_t rectype; + int cmp, ret; + + memset(&data, 0, sizeof(data)); + /* + * Read forward through the log looking for the first checkpoint + * record whose ckp_lsn is greater than first_lsn. + */ + + for (ret = log_get(dbenv, &first_lsn, &data, DB_FIRST); + ret == 0; ret = log_get(dbenv, &lsn, &data, DB_NEXT)) { + if (ret != 0) + break; + memcpy(&rectype, data.data, sizeof(rectype)); + if (rectype != DB_txn_ckp) + continue; + if ((ret = __txn_ckp_read(dbenv, data.data, &ckpargs)) == 0) { + cmp = log_compare(&ckpargs->ckp_lsn, &first_lsn); + *lowlsn = ckpargs->ckp_lsn; + *lowtime = ckpargs->timestamp; + + __os_free(ckpargs, 0); + if (cmp >= 0) + break; + } + } + + return (ret); +} diff --git a/db/env/env_region.c b/db/env/env_region.c new file mode 100644 index 000000000..f3df4bac1 --- /dev/null +++ b/db/env/env_region.c @@ -0,0 +1,1205 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: env_region.c,v 11.28 2000/12/12 17:36:10 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#endif + +#include "db_int.h" +#include "db_shash.h" +#include "lock.h" +#include "lock_ext.h" +#include "log.h" +#include "log_ext.h" +#include "mp.h" +#include "mp_ext.h" +#include "txn.h" +#include "txn_ext.h" + +static int __db_des_destroy __P((DB_ENV *, REGION *)); +static int __db_des_get __P((DB_ENV *, REGINFO *, REGINFO *, REGION **)); +static int __db_e_remfile __P((DB_ENV *)); +static int __db_faultmem __P((void *, size_t, int)); +static void __db_region_destroy __P((DB_ENV *, REGINFO *)); + +/* + * __db_e_attach + * Join/create the environment + * + * PUBLIC: int __db_e_attach __P((DB_ENV *, u_int32_t *)); + */ +int +__db_e_attach(dbenv, init_flagsp) + DB_ENV *dbenv; + u_int32_t *init_flagsp; +{ + REGENV *renv; + REGENV_REF ref; + REGINFO *infop; + REGION *rp, tregion; + size_t size; + size_t nrw; + u_int32_t mbytes, bytes; + int retry_cnt, ret, segid; + char buf[sizeof(DB_REGION_FMT) + 20]; + +#if !defined(HAVE_MUTEX_THREADS) + /* + * !!! + * If we don't have spinlocks, we need a file descriptor for fcntl(2) + * locking. We use the file handle from the REGENV file for this + * purpose. + * + * Since we may be using shared memory regions, e.g., shmget(2), and + * not a mapped-in regular file, the backing file may be only a few + * bytes in length. So, this depends on the ability to call fcntl to + * lock file offsets much larger than the actual physical file. I + * think that's safe -- besides, very few systems actually need this + * kind of support, SunOS is the only one still in wide use of which + * I'm aware. + * + * The error case is if an application lacks spinlocks and wants to be + * threaded. That doesn't work because fcntl may lock the underlying + * process, including all its threads. + */ + if (F_ISSET(dbenv, DB_ENV_THREAD)) { + __db_err(dbenv, +"architecture lacks fast mutexes: applications cannot be threaded"); + return (EINVAL); + } +#endif + + /* Initialization */ + retry_cnt = 0; + + /* Repeated initialization. */ +loop: renv = NULL; + + /* Set up the DB_ENV's REG_INFO structure. */ + if ((ret = __os_calloc(dbenv, 1, sizeof(REGINFO), &infop)) != 0) + return (ret); + infop->type = REGION_TYPE_ENV; + infop->id = REGION_ID_ENV; + infop->mode = dbenv->db_mode; + infop->flags = REGION_JOIN_OK; + if (F_ISSET(dbenv, DB_ENV_CREATE)) + F_SET(infop, REGION_CREATE_OK); + + /* + * We have to single-thread the creation of the REGENV region. Once + * it exists, we can do locking using locks in the region, but until + * then we have to be the only player in the game. + * + * If this is a private environment, we are only called once and there + * are no possible race conditions. + * + * If this is a public environment, we use the filesystem to ensure + * the creation of the environment file is single-threaded. + */ + if (F_ISSET(dbenv, DB_ENV_PRIVATE)) + goto creation; + + /* Build the region name. */ + (void)snprintf(buf, sizeof(buf), "%s", DB_REGION_ENV); + if ((ret = __db_appname(dbenv, + DB_APP_NONE, NULL, buf, 0, NULL, &infop->name)) != 0) + goto err; + + /* + * Try to create the file, if we have the authority. We have to ensure + * that multiple threads/processes attempting to simultaneously create + * the file are properly ordered. Open using the O_CREAT and O_EXCL + * flags so that multiple attempts to create the region will return + * failure in all but one. POSIX 1003.1 requires that EEXIST be the + * errno return value -- I sure hope they're right. + */ + if (F_ISSET(dbenv, DB_ENV_CREATE)) { + if ((ret = __os_open(dbenv, + infop->name, DB_OSO_REGION | DB_OSO_CREATE | DB_OSO_EXCL, + dbenv->db_mode, dbenv->lockfhp)) == 0) + goto creation; + if (ret != EEXIST) { + __db_err(dbenv, + "%s: %s", infop->name, db_strerror(ret)); + goto err; + } + } + + /* + * If we couldn't create the file, try and open it. (If that fails, + * we're done.) + */ + if ((ret = __os_open(dbenv, infop->name, + DB_OSO_REGION, dbenv->db_mode, dbenv->lockfhp)) != 0) + goto err; + + /* + * !!! + * The region may be in system memory not backed by the filesystem + * (more specifically, not backed by this file), and we're joining + * it. In that case, the process that created it will have written + * out a REGENV_REF structure as its only contents. We read that + * structure before we do anything further, e.g., we can't just map + * that file in and then figure out what's going on. + * + * All of this noise is because some systems don't have a coherent VM + * and buffer cache, and what's worse, when you mix operations on the + * VM and buffer cache, half the time you hang the system. + * + * If the file is the size of an REGENV_REF structure, then we know + * the real region is in some other memory. (The only way you get a + * file that size is to deliberately write it, as it's smaller than + * any possible disk sector created by writing a file or mapping the + * file into memory.) In which case, retrieve the structure from the + * file and use it to acquire the referenced memory. + * + * If the structure is larger than a REGENV_REF structure, then this + * file is backing the shared memory region, and we just map it into + * memory. + * + * And yes, this makes me want to take somebody and kill them. (I + * digress -- but you have no freakin' idea. This is unbelievably + * stupid and gross, and I've probably spent six months of my life, + * now, trying to make different versions of it work.) + */ + if ((ret = __os_ioinfo(dbenv, infop->name, + dbenv->lockfhp, &mbytes, &bytes, NULL)) != 0) { + __db_err(dbenv, "%s: %s", infop->name, db_strerror(ret)); + goto err; + } + + /* + * !!! + * A size_t is OK -- regions get mapped into memory, and so can't + * be larger than a size_t. + */ + size = mbytes * MEGABYTE + bytes; + + /* + * If the size is less than the size of a REGENV_REF structure, the + * region (or, possibly, the REGENV_REF structure) has not yet been + * completely written. Wait awhile and try again. + * + * Otherwise, if the size is the size of a REGENV_REF structure, + * read it into memory and use it as a reference to the real region. + */ + if (size <= sizeof(ref)) { + if (size != sizeof(ref)) + goto retry; + + if ((ret = __os_read(dbenv, dbenv->lockfhp, &ref, + sizeof(ref), &nrw)) != 0 || nrw < (size_t)sizeof(ref)) { + if (ret == 0) + ret = EIO; + __db_err(dbenv, + "%s: unable to read system-memory information from: %s", + infop->name, db_strerror(ret)); + goto err; + } + size = ref.size; + segid = ref.segid; + + F_SET(dbenv, DB_ENV_SYSTEM_MEM); + } else if (F_ISSET(dbenv, DB_ENV_SYSTEM_MEM)) { + ret = EINVAL; + __db_err(dbenv, + "%s: existing environment not created in system memory: %s", + infop->name, db_strerror(ret)); + goto err; + } else + segid = INVALID_REGION_SEGID; + + /* + * If not doing thread locking, we need to save the file handle for + * fcntl(2) locking. Otherwise, discard the handle, we no longer + * need it, and the less contact between the buffer cache and the VM, + * the better. + */ +#ifdef HAVE_MUTEX_THREADS + __os_closehandle(dbenv->lockfhp); +#endif + + /* Call the region join routine to acquire the region. */ + memset(&tregion, 0, sizeof(tregion)); + tregion.size = size; + tregion.segid = segid; + if ((ret = __os_r_attach(dbenv, infop, &tregion)) != 0) + goto err; + + /* + * The environment's REGENV structure has to live at offset 0 instead + * of the usual shalloc information. Set the primary reference and + * correct the "addr" value to reference the shalloc region. Note, + * this means that all of our offsets (R_ADDR/R_OFFSET) get shifted + * as well, but that should be fine. + */ + infop->primary = R_ADDR(infop, 0); + infop->addr = (u_int8_t *)infop->addr + sizeof(REGENV); + + /* + * Check if the environment has had a catastrophic failure. + * + * Check the magic number to ensure the region is initialized. If the + * magic number isn't set, the lock may not have been initialized, and + * an attempt to use it could lead to random behavior. + * + * The panic and magic values aren't protected by any lock, so we never + * use them in any check that's more complex than set/not-set. + * + * !!! + * I'd rather play permissions games using the underlying file, but I + * can't because Windows/NT filesystems won't open files mode 0. + */ + renv = infop->primary; + if (renv->panic) { + ret = __db_panic_msg(dbenv); + goto err; + } + if (renv->magic != DB_REGION_MAGIC) + goto retry; + + /* Make sure the region matches our build. */ + if (renv->majver != DB_VERSION_MAJOR || + renv->minver != DB_VERSION_MINOR || + renv->patch != DB_VERSION_PATCH) { + __db_err(dbenv, + "Program version %d.%d.%d doesn't match environment version %d.%d.%d", + DB_VERSION_MAJOR, DB_VERSION_MINOR, DB_VERSION_PATCH, + renv->majver, renv->minver, renv->patch); +#ifndef DIAGNOSTIC + ret = EINVAL; + goto err; +#endif + } + + /* Lock the environment. */ + MUTEX_LOCK(dbenv, &renv->mutex, dbenv->lockfhp); + + /* + * Finally! We own the environment now. Repeat the panic check, it's + * possible that it was set while we waited for the lock. + */ + if (renv->panic) { + ret = __db_panic_msg(dbenv); + goto err_unlock; + } + + /* + * Get a reference to the underlying REGION information for this + * environment. + */ + if ((ret = __db_des_get(dbenv, infop, infop, &rp)) != 0 || rp == NULL) { + MUTEX_UNLOCK(dbenv, &renv->mutex); + goto find_err; + } + infop->rp = rp; + + /* + * There's still a possibility for inconsistent data. When we acquired + * the size of the region and attached to it, it might have still been + * growing as part of its creation. We can detect this by checking the + * size we originally found against the region's current size. (The + * region's current size has to be final, the creator finished growing + * it before releasing the environment for us to lock.) + */ + if (rp->size != size) { +err_unlock: MUTEX_UNLOCK(dbenv, &renv->mutex); + goto retry; + } + + /* Increment the reference count. */ + ++renv->refcnt; + + /* + * If our caller wants them, return the flags this environment was + * initialized with. + */ + if (init_flagsp != NULL) + *init_flagsp = renv->init_flags; + + /* Discard our lock. */ + MUTEX_UNLOCK(dbenv, &renv->mutex); + + /* + * Fault the pages into memory. Note, do this AFTER releasing the + * lock, because we're only reading the pages, not writing them. + */ + (void)__db_faultmem(infop->primary, rp->size, 0); + + /* Everything looks good, we're done. */ + dbenv->reginfo = infop; + return (0); + +creation: + /* Create the environment region. */ + F_SET(infop, REGION_CREATE); + + /* + * Allocate room for 50 REGION structures plus overhead (we're going + * to use this space for last-ditch allocation requests), although we + * should never need anything close to that. + */ + memset(&tregion, 0, sizeof(tregion)); + tregion.size = 50 * sizeof(REGION) + 50 * sizeof(MUTEX) + 2048; + tregion.segid = INVALID_REGION_SEGID; + if ((ret = __os_r_attach(dbenv, infop, &tregion)) != 0) + goto err; + + /* + * Fault the pages into memory. Note, do this BEFORE we initialize + * anything, because we're writing the pages, not just reading them. + */ + (void)__db_faultmem(infop->addr, tregion.size, 1); + + /* + * The first object in the region is the REGENV structure. This is + * different from the other regions, and, from everything else in + * this region, where all objects are allocated from the pool, i.e., + * there aren't any fixed locations. The remaining space is made + * available for later allocation. + * + * The allocation space must be size_t aligned, because that's what + * the initialization routine is going to store there. To make sure + * that happens, the REGENV structure was padded with a final size_t. + * No other region needs to worry about it because all of them treat + * the entire region as allocation space. + * + * Set the primary reference and correct the "addr" value to reference + * the shalloc region. Note, this requires that we "uncorrect" it at + * region detach, and that all of our offsets (R_ADDR/R_OFFSET) will be + * shifted as well, but that should be fine. + */ + infop->primary = R_ADDR(infop, 0); + infop->addr = (u_int8_t *)infop->addr + sizeof(REGENV); + __db_shalloc_init(infop->addr, tregion.size - sizeof(REGENV)); + + /* + * Initialize the rest of the REGENV structure, except for the magic + * number which validates the file/environment. + */ + renv = infop->primary; + renv->panic = 0; + db_version(&renv->majver, &renv->minver, &renv->patch); + SH_LIST_INIT(&renv->regionq); + renv->refcnt = 1; + + /* + * Initialize init_flags to store the flags that any other environment + * handle that uses DB_JOINENV to join this environment will need. + */ + renv->init_flags = (init_flagsp == NULL) ? 0 : *init_flagsp; + + /* + * Lock the environment. + * + * Check the lock call return. This is the first lock we initialize + * and acquire, and we have to know if it fails. (It CAN fail, e.g., + * SunOS, when using fcntl(2) for locking and using an in-memory + * filesystem as the database home. But you knew that, I'm sure -- it + * probably wasn't even worth mentioning.) + */ + if ((ret = + __db_mutex_init(dbenv, &renv->mutex, DB_FCNTL_OFF_GEN, 0)) != 0) { + __db_err(dbenv, "%s: unable to initialize environment lock: %s", + infop->name, db_strerror(ret)); + goto err; + } + + if (!F_ISSET(&renv->mutex, MUTEX_IGNORE) && + (ret = __db_mutex_lock(dbenv, &renv->mutex, dbenv->lockfhp)) != 0) { + __db_err(dbenv, "%s: unable to acquire environment lock: %s", + infop->name, db_strerror(ret)); + goto err; + } + + /* + * Get the underlying REGION structure for this environment. Note, + * we created the underlying OS region before we acquired the REGION + * structure, which is backwards from the normal procedure. Update + * the REGION structure. + */ + if ((ret = __db_des_get(dbenv, infop, infop, &rp)) != 0) { +find_err: __db_err(dbenv, + "%s: unable to find environment", infop->name); + if (ret == 0) + ret = EINVAL; + goto err; + } + infop->rp = rp; + rp->size = tregion.size; + rp->segid = tregion.segid; + + /* + * !!! + * If we create an environment where regions are public and in system + * memory, we have to inform processes joining the environment how to + * attach to the shared memory segment. So, we write the shared memory + * identifier into the file, to be read by those other processes. + * + * XXX + * This is really OS-layer information, but I can't see any easy way + * to move it down there without passing down information that it has + * no right to know, e.g., that this is the one-and-only REGENV region + * and not some other random region. + */ + if (tregion.segid != INVALID_REGION_SEGID) { + ref.size = tregion.size; + ref.segid = tregion.segid; + if ((ret = __os_write(dbenv, dbenv->lockfhp, + &ref, sizeof(ref), &nrw)) != 0 || nrw != sizeof(ref)) { + __db_err(dbenv, + "%s: unable to write out public environment ID: %s", + infop->name, db_strerror(ret)); + goto err; + } + } + + /* + * If not doing thread locking, we need to save the file handle for + * fcntl(2) locking. Otherwise, discard the handle, we no longer + * need it, and the less contact between the buffer cache and the VM, + * the better. + */ +#if defined(HAVE_MUTEX_THREADS) + if (F_ISSET(dbenv->lockfhp, DB_FH_VALID)) + __os_closehandle(dbenv->lockfhp); +#endif + + /* Validate the file. */ + renv->magic = DB_REGION_MAGIC; + + /* Discard our lock. */ + MUTEX_UNLOCK(dbenv, &renv->mutex); + + /* Everything looks good, we're done. */ + dbenv->reginfo = infop; + return (0); + +err: +retry: /* Close any open file handle. */ + if (F_ISSET(dbenv->lockfhp, DB_FH_VALID)) + (void)__os_closehandle(dbenv->lockfhp); + + /* + * If we joined or created the region, detach from it. If we created + * it, destroy it. Note, there's a path in the above code where we're + * using a temporary REGION structure because we haven't yet allocated + * the real one. In that case the region address (addr) will be filled + * in, but the REGION pointer (rp) won't. Fix it. + */ + if (infop->addr != NULL) { + if (infop->rp == NULL) + infop->rp = &tregion; + + /* Reset the addr value that we "corrected" above. */ + infop->addr = infop->primary; + (void)__os_r_detach(dbenv, + infop, F_ISSET(infop, REGION_CREATE)); + } + + /* Free the allocated name and/or REGINFO structure. */ + if (infop->name != NULL) + __os_freestr(infop->name); + __os_free(infop, sizeof(REGINFO)); + + /* If we had a temporary error, wait awhile and try again. */ + if (ret == 0) { + if (++retry_cnt > 3) { + __db_err(dbenv, "unable to join the environment"); + ret = EAGAIN; + } else { + __os_sleep(dbenv, retry_cnt * 3, 0); + goto loop; + } + } + + return (ret); +} + +/* + * __db_e_detach -- + * Detach from the environment. + * + * PUBLIC: int __db_e_detach __P((DB_ENV *, int)); + */ +int +__db_e_detach(dbenv, destroy) + DB_ENV *dbenv; + int destroy; +{ + REGENV *renv; + REGINFO *infop; + + infop = dbenv->reginfo; + renv = infop->primary; + + /* Lock the environment. */ + MUTEX_LOCK(dbenv, &renv->mutex, dbenv->lockfhp); + + /* Decrement the reference count. */ + if (renv->refcnt == 0) { + __db_err(dbenv, + "region %lu (environment): reference count went negative", + infop->rp->id); + } else + --renv->refcnt; + + /* Release the lock. */ + MUTEX_UNLOCK(dbenv, &renv->mutex); + + /* Close the locking file handle. */ + if (F_ISSET(dbenv->lockfhp, DB_FH_VALID)) + (void)__os_closehandle(dbenv->lockfhp); + + /* Reset the addr value that we "corrected" above. */ + infop->addr = infop->primary; + + /* + * If we are destroying the environment, we need to + * destroy any system resources backing the mutex. + * Do that now before we free the memory in __os_r_detach. + */ + if (destroy) + __db_mutex_destroy(&renv->mutex); + + /* + * Release the region, and kill our reference. + * + * We set the DBENV->reginfo field to NULL here and discard its memory. + * DBENV->remove calls __dbenv_remove to do the region remove, and + * __dbenv_remove attached and then detaches from the region. We don't + * want to return to DBENV->remove with a non-NULL DBENV->reginfo field + * because it will attempt to detach again as part of its cleanup. + */ + (void)__os_r_detach(dbenv, infop, destroy); + + if (infop->name != NULL) + __os_free(infop->name, 0); + __os_free(dbenv->reginfo, sizeof(REGINFO)); + dbenv->reginfo = NULL; + + return (0); +} + +/* + * __db_e_remove -- + * Discard an environment if it's not in use. + * + * PUBLIC: int __db_e_remove __P((DB_ENV *, int)); + */ +int +__db_e_remove(dbenv, force) + DB_ENV *dbenv; + int force; +{ + REGENV *renv; + REGINFO *infop, reginfo; + REGION *rp; + int ret; + + /* + * This routine has to walk a nasty line between not looking into + * the environment (which may be corrupted after an app or system + * crash), and removing everything that needs removing. What we + * do is: + * 1. Connect to the environment (so it better be OK). + * 2. If the environment is in use (reference count is non-zero), + * return EBUSY. + * 3. Overwrite the magic number so that any threads of control + * attempting to connect will backoff and retry. + * 4. Walk the list of regions. Connect to each region and then + * disconnect with the destroy flag set. This shouldn't cause + * any problems, even if the region is corrupted, because we + * should never be looking inside the region. + * 5. Walk the list of files in the directory, unlinking any + * files that match a region name. Unlink the environment + * file last. + * + * If the force flag is set, we do not acquire any locks during this + * process. + */ + if (force) + dbenv->db_mutexlocks = 0; + + /* Join the environment. */ + if ((ret = __db_e_attach(dbenv, NULL)) != 0) { + /* + * If we can't join it, we assume that's because it doesn't + * exist. It would be better to know why we failed, but it + * probably isn't important. + */ + ret = 0; + if (force) + goto remfiles; + goto err; + } + + infop = dbenv->reginfo; + renv = infop->primary; + + /* Lock the environment. */ + MUTEX_LOCK(dbenv, &renv->mutex, dbenv->lockfhp); + + /* If it's in use, we're done. */ + if (renv->refcnt == 1 || force) { + /* + * Set the panic flag and overwrite the magic number. + * + * !!! + * From this point on, there's no going back, we pretty + * much ignore errors, and just whack on whatever we can. + */ + renv->panic = 1; + renv->magic = 0; + + /* + * Unlock the environment. We should no longer need the lock + * because we've poisoned the pool, but we can't continue to + * hold it either, because other routines may want it. + */ + MUTEX_UNLOCK(dbenv, &renv->mutex); + + /* + * Attach to each sub-region and destroy it. + * + * !!! + * The REGION_CREATE_OK flag is set for Windows/95 -- regions + * are zero'd out when the last reference to the region goes + * away, in which case the underlying OS region code requires + * callers be prepared to create the region in order to join it. + */ + memset(®info, 0, sizeof(reginfo)); +restart: for (rp = SH_LIST_FIRST(&renv->regionq, __db_region); + rp != NULL; rp = SH_LIST_NEXT(rp, q, __db_region)) { + if (rp->type == REGION_TYPE_ENV) + continue; + + reginfo.id = rp->id; + reginfo.flags = REGION_CREATE_OK; + if ((ret = __db_r_attach(dbenv, ®info, 0)) != 0) { + __db_err(dbenv, + "region %s attach: %s", db_strerror(ret)); + continue; + } + R_UNLOCK(dbenv, ®info); + if ((ret = __db_r_detach(dbenv, ®info, 1)) != 0) { + __db_err(dbenv, + "region detach: %s", db_strerror(ret)); + continue; + } + /* + * If we have an error, we continue so we eventually + * reach the end of the list. If we succeed, restart + * the list because it was relinked when we destroyed + * the entry. + */ + goto restart; + } + + /* Destroy the environment's region. */ + (void)__db_e_detach(dbenv, 1); + + /* Discard the physical files. */ +remfiles: (void)__db_e_remfile(dbenv); + } else { + /* Unlock the environment. */ + MUTEX_UNLOCK(dbenv, &renv->mutex); + + /* Discard the environment. */ + (void)__db_e_detach(dbenv, 0); + + ret = EBUSY; + } + +err: + return (ret); +} + +/* + * __db_e_remfile -- + * Discard any region files in the filesystem. + */ +static int +__db_e_remfile(dbenv) + DB_ENV *dbenv; +{ + static char *old_region_names[] = { + "__db_lock.share", + "__db_log.share", + "__db_mpool.share", + "__db_txn.share", + NULL, + }; + int cnt, fcnt, lastrm, ret; + u_int8_t saved_byte; + const char *dir; + char *p, **names, *path, buf[sizeof(DB_REGION_FMT) + 20]; + + /* Get the full path of a file in the environment. */ + (void)snprintf(buf, sizeof(buf), "%s", DB_REGION_ENV); + if ((ret = + __db_appname(dbenv, DB_APP_NONE, NULL, buf, 0, NULL, &path)) != 0) + return (ret); + + /* Get the parent directory for the environment. */ + if ((p = __db_rpath(path)) == NULL) { + p = path; + saved_byte = *p; + + dir = PATH_DOT; + } else { + saved_byte = *p; + *p = '\0'; + + dir = path; + } + + /* Get the list of file names. */ + ret = __os_dirlist(dbenv, dir, &names, &fcnt); + + /* Restore the path, and free it. */ + *p = saved_byte; + __os_freestr(path); + + if (ret != 0) { + __db_err(dbenv, "%s: %s", dir, db_strerror(ret)); + return (ret); + } + + /* + * Search for valid region names, and remove them. We remove the + * environment region last, because it's the key to this whole mess. + */ + for (lastrm = -1, cnt = fcnt; --cnt >= 0;) { + if (strlen(names[cnt]) != DB_REGION_NAME_LENGTH || + memcmp(names[cnt], DB_REGION_FMT, DB_REGION_NAME_NUM) != 0) + continue; + if (strcmp(names[cnt], DB_REGION_ENV) == 0) { + lastrm = cnt; + continue; + } + for (p = names[cnt] + DB_REGION_NAME_NUM; + *p != '\0' && isdigit((int)*p); ++p) + ; + if (*p != '\0') + continue; + + if (__db_appname(dbenv, + DB_APP_NONE, NULL, names[cnt], 0, NULL, &path) == 0) { + (void)__os_unlink(dbenv, path); + __os_freestr(path); + } + } + + if (lastrm != -1) + if (__db_appname(dbenv, + DB_APP_NONE, NULL, names[lastrm], 0, NULL, &path) == 0) { + (void)__os_unlink(dbenv, path); + __os_freestr(path); + } + __os_dirfree(names, fcnt); + + /* + * !!! + * Backward compatibility -- remove region files from releases + * before 2.8.XX. + */ + for (names = (char **)old_region_names; *names != NULL; ++names) + if (__db_appname(dbenv, + DB_APP_NONE, NULL, *names, 0, NULL, &path) == 0) { + (void)__os_unlink(dbenv, path); + __os_freestr(path); + } + + return (0); +} + +/* + * __db_e_stat + * Statistics for the environment. + * + * PUBLIC: int __db_e_stat __P((DB_ENV *, REGENV *, REGION *, int *)); + */ +int +__db_e_stat(dbenv, arg_renv, arg_regions, arg_regions_cnt) + DB_ENV *dbenv; + REGENV *arg_renv; + REGION *arg_regions; + int *arg_regions_cnt; +{ + REGENV *renv; + REGINFO *infop; + REGION *rp; + int n; + + infop = dbenv->reginfo; + renv = infop->primary; + rp = infop->rp; + + /* Lock the environment. */ + MUTEX_LOCK(dbenv, &rp->mutex, dbenv->lockfhp); + + *arg_renv = *renv; + + for (n = 0, rp = SH_LIST_FIRST(&renv->regionq, __db_region); + n < *arg_regions_cnt && rp != NULL; + ++n, rp = SH_LIST_NEXT(rp, q, __db_region)) + arg_regions[n] = *rp; + + /* Release the lock. */ + rp = infop->rp; + MUTEX_UNLOCK(dbenv, &rp->mutex); + + *arg_regions_cnt = n == 0 ? n : n - 1; + + return (0); +} + +/* + * __db_r_attach + * Join/create a region. + * + * PUBLIC: int __db_r_attach __P((DB_ENV *, REGINFO *, size_t)); + */ +int +__db_r_attach(dbenv, infop, size) + DB_ENV *dbenv; + REGINFO *infop; + size_t size; +{ + REGENV *renv; + REGION *rp; + int ret; + char buf[sizeof(DB_REGION_FMT) + 20]; + + renv = ((REGINFO *)dbenv->reginfo)->primary; + F_CLR(infop, REGION_CREATE); + + /* Lock the environment. */ + MUTEX_LOCK(dbenv, &renv->mutex, dbenv->lockfhp); + + /* Find or create a REGION structure for this region. */ + if ((ret = __db_des_get(dbenv, dbenv->reginfo, infop, &rp)) != 0) { + MUTEX_UNLOCK(dbenv, &renv->mutex); + return (ret); + } + infop->rp = rp; + infop->type = rp->type; + infop->id = rp->id; + + /* If we're creating the region, set the desired size. */ + if (F_ISSET(infop, REGION_CREATE)) + rp->size = size; + + /* Join/create the underlying region. */ + (void)snprintf(buf, sizeof(buf), DB_REGION_FMT, infop->id); + if ((ret = __db_appname(dbenv, + DB_APP_NONE, NULL, buf, 0, NULL, &infop->name)) != 0) + goto err; + if ((ret = __os_r_attach(dbenv, infop, rp)) != 0) + goto err; + + /* + * Fault the pages into memory. Note, do this BEFORE we initialize + * anything because we're writing pages in created regions, not just + * reading them. + */ + (void)__db_faultmem(infop->addr, + rp->size, F_ISSET(infop, REGION_CREATE)); + + /* + * !!! + * The underlying layer may have just decided that we are going + * to create the region. There are various system issues that + * can result in a useless region that requires re-initialization. + * + * If we created the region, initialize it for allocation. + */ + if (F_ISSET(infop, REGION_CREATE)) { + ((REGION *)(infop->addr))->magic = DB_REGION_MAGIC; + + (void)__db_shalloc_init(infop->addr, rp->size); + } + + /* + * If the underlying REGION isn't the environment, acquire a lock + * for it and release our lock on the environment. + */ + if (infop->type != REGION_TYPE_ENV) { + MUTEX_LOCK(dbenv, &rp->mutex, dbenv->lockfhp); + MUTEX_UNLOCK(dbenv, &renv->mutex); + } + + return (0); + + /* Discard the underlying region. */ +err: if (infop->addr != NULL) + (void)__os_r_detach(dbenv, + infop, F_ISSET(infop, REGION_CREATE)); + infop->rp = NULL; + infop->id = INVALID_REGION_ID; + + /* Discard the REGION structure if we created it. */ + if (F_ISSET(infop, REGION_CREATE)) + (void)__db_des_destroy(dbenv, rp); + + /* Release the environment lock. */ + MUTEX_UNLOCK(dbenv, &renv->mutex); + + return (ret); +} + +/* + * __db_r_detach -- + * Detach from a region. + * + * PUBLIC: int __db_r_detach __P((DB_ENV *, REGINFO *, int)); + */ +int +__db_r_detach(dbenv, infop, destroy) + DB_ENV *dbenv; + REGINFO *infop; + int destroy; +{ + REGENV *renv; + REGION *rp; + int ret, t_ret; + + renv = ((REGINFO *)dbenv->reginfo)->primary; + rp = infop->rp; + + /* Lock the environment. */ + MUTEX_LOCK(dbenv, &renv->mutex, dbenv->lockfhp); + + /* Acquire the lock for the REGION. */ + MUTEX_LOCK(dbenv, &rp->mutex, dbenv->lockfhp); + + /* + * We need to call destroy on per-subsystem info before + * we free the memory associated with the region. + */ + if (destroy) + __db_region_destroy(dbenv, infop); + + /* Detach from the underlying OS region. */ + ret = __os_r_detach(dbenv, infop, destroy); + + /* Release the REGION lock. */ + MUTEX_UNLOCK(dbenv, &rp->mutex); + + /* If we destroyed the region, discard the REGION structure. */ + if (destroy && + ((t_ret = __db_des_destroy(dbenv, rp)) != 0) && ret == 0) + ret = t_ret; + + /* Release the environment lock. */ + MUTEX_UNLOCK(dbenv, &renv->mutex); + + /* Destroy the structure. */ + if (infop->name != NULL) + __os_freestr(infop->name); + + return (ret); +} + +/* + * __db_des_get -- + * Return a reference to the shared information for a REGION, + * optionally creating a new entry. + */ +static int +__db_des_get(dbenv, env_infop, infop, rpp) + DB_ENV *dbenv; + REGINFO *env_infop, *infop; + REGION **rpp; +{ + REGENV *renv; + REGION *rp, *first_type; + u_int32_t maxid; + int ret; + + /* + * !!! + * Called with the environment already locked. + */ + *rpp = NULL; + renv = env_infop->primary; + + /* + * If the caller wants to join a region, walk through the existing + * regions looking for a matching ID (if ID specified) or matching + * type (if type specified). If we return based on a matching type + * return the "primary" region, that is, the first region that was + * created of this type. + * + * Track the maximum region ID so we can allocate a new region, + * note that we have to start at 1 because the primary environment + * uses ID == 1. + */ + maxid = REGION_ID_ENV; + for (first_type = NULL, + rp = SH_LIST_FIRST(&renv->regionq, __db_region); + rp != NULL; rp = SH_LIST_NEXT(rp, q, __db_region)) { + if (infop->id != INVALID_REGION_ID) { + if (infop->id == rp->id) + break; + continue; + } + if (infop->type == rp->type && + F_ISSET(infop, REGION_JOIN_OK) && + (first_type == NULL || first_type->id > rp->id)) + first_type = rp; + + if (rp->id > maxid) + maxid = rp->id; + } + if (rp == NULL) + rp = first_type; + + /* + * If we didn't find a region and we can't create the region, fail. + * The caller generates any error message. + */ + if (rp == NULL && !F_ISSET(infop, REGION_CREATE_OK)) + return (ENOENT); + + /* + * If we didn't find a region, create and initialize a REGION structure + * for the caller. If id was set, use that value, otherwise we use the + * next available ID. + */ + if (rp == NULL) { + if ((ret = __db_shalloc(env_infop->addr, + sizeof(REGION), MUTEX_ALIGN, &rp)) != 0) + return (ret); + + /* Initialize the region. */ + memset(rp, 0, sizeof(*rp)); + if ((ret = __db_mutex_init(dbenv, &rp->mutex, + R_OFFSET(env_infop, &rp->mutex) + DB_FCNTL_OFF_GEN, + 0)) != 0) { + __db_shalloc_free(env_infop->addr, rp); + return (ret); + } + rp->segid = INVALID_REGION_SEGID; + + /* + * Set the type and ID; if no region ID was specified, + * allocate one. + */ + rp->type = infop->type; + rp->id = infop->id == INVALID_REGION_ID ? maxid + 1 : infop->id; + + SH_LIST_INSERT_HEAD(&renv->regionq, rp, q, __db_region); + F_SET(infop, REGION_CREATE); + } + + *rpp = rp; + return (0); +} + +/* + * __db_des_destroy -- + * Destroy a reference to a REGION. + */ +static int +__db_des_destroy(dbenv, rp) + DB_ENV *dbenv; + REGION *rp; +{ + REGINFO *infop; + + /* + * !!! + * Called with the environment already locked. + */ + infop = dbenv->reginfo; + + SH_LIST_REMOVE(rp, q, __db_region); + __db_mutex_destroy(&rp->mutex); + __db_shalloc_free(infop->addr, rp); + + return (0); +} + +/* + * __db_faultmem -- + * Fault the region into memory. + */ +static int +__db_faultmem(addr, size, created) + void *addr; + size_t size; + int created; +{ + int ret; + u_int8_t *p, *t; + + /* + * It's sometimes significantly faster to page-fault in all of the + * region's pages before we run the application, as we see nasty + * side-effects when we page-fault while holding various locks, i.e., + * the lock takes a long time to acquire because of the underlying + * page fault, and the other threads convoy behind the lock holder. + * + * If we created the region, we write a non-zero value so that the + * system can't cheat. If we're just joining the region, we can + * only read the value and try to confuse the compiler sufficiently + * that it doesn't figure out that we're never really using it. + */ + ret = 0; + if (DB_GLOBAL(db_region_init)) { + if (created) + for (p = addr, t = (u_int8_t *)addr + size; + p < t; p += OS_VMPAGESIZE) + p[0] = 0xdb; + else + for (p = addr, t = (u_int8_t *)addr + size; + p < t; p += OS_VMPAGESIZE) + ret |= p[0]; + } + + return (ret); +} + +/* + * __db_region_destroy -- + * Destroy per-subsystem region information. + * Called with the region already locked. + */ +static void +__db_region_destroy(dbenv, infop) + DB_ENV *dbenv; + REGINFO *infop; +{ + switch (infop->type) { + case REGION_TYPE_LOCK: + __lock_region_destroy(dbenv, infop); + break; + case REGION_TYPE_MPOOL: + __mpool_region_destroy(dbenv, infop); + break; + case REGION_TYPE_ENV: + case REGION_TYPE_LOG: + case REGION_TYPE_MUTEX: + case REGION_TYPE_TXN: + break; + default: + DB_ASSERT(0); + break; + } +} diff --git a/db/examples_c/README b/db/examples_c/README new file mode 100644 index 000000000..f59ae00a6 --- /dev/null +++ b/db/examples_c/README @@ -0,0 +1,23 @@ +# $Id: README,v 11.3 2000/12/13 06:32:29 krinsky Exp $ + +ex_access.c Using just the DB access methods. + +ex_btrec.c Using the BTREE access method with record numbers. + +ex_env.c Setting up the DB environment. + +ex_lock.c Locking. + +ex_mpool.c Shared memory buffer pools. + +ex_tpcb.c TPC/B. + Ex_tpcb sets up a framework in which to run a TPC/B test. + Database initialization (the -i flag) and running the + benchmark (-n flag) must take place separately (i.e., + first create the database, then run 1 or more copies of + the benchmark). Furthermore, when running more than one + TPCB process, it is necessary to run the deadlock detector + (db_deadlock), since it is possible for concurrent tpcb + processes to deadlock. For performance measurement, it + will also be beneficial to run the db_checkpoint process + as well. diff --git a/db/examples_c/ex_access.c b/db/examples_c/ex_access.c new file mode 100644 index 000000000..3448daf43 --- /dev/null +++ b/db/examples_c/ex_access.c @@ -0,0 +1,171 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: ex_access.c,v 11.7 2000/05/22 15:17:03 sue Exp $ + */ + +#include "db_config.h" + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#endif + +#include + +#ifdef HAVE_VXWORKS +#include "stdio.h" +#define DATABASE "/vxtmp/vxtmp/access.db" +#define ERROR_RETURN ERROR +#else +#define DATABASE "access.db" +#define ERROR_RETURN 1 +int main __P((int, char *[])); +void usage __P((char *)); +#endif + +int ex_access __P((void)); + +#ifndef HAVE_VXWORKS +int +main(argc, argv) + int argc; + char *argv[]; +{ + extern char *optarg; + extern int optind; + int ch; + + while ((ch = getopt(argc, argv, "")) != EOF) + switch (ch) { + case '?': + default: + usage(argv[0]); + } + argc -= optind; + argv += optind; + + return (ex_access()); +} + +void +usage(progname) + char *progname; +{ + (void)fprintf(stderr, "usage: %s\n", progname); + exit(1); +} +#endif + +int +ex_access() +{ + DB *dbp; + DBC *dbcp; + DBT key, data; + u_int32_t len; + int ret; + char *p, *t, buf[1024], rbuf[1024]; + const char *progname = "ex_access"; /* Program name. */ + + /* Remove the previous database. */ + (void)unlink(DATABASE); + + /* Create and initialize database object, open the database. */ + if ((ret = db_create(&dbp, NULL, 0)) != 0) { + fprintf(stderr, + "%s: db_create: %s\n", progname, db_strerror(ret)); + return (ERROR_RETURN); + } + dbp->set_errfile(dbp, stderr); + dbp->set_errpfx(dbp, progname); + if ((ret = dbp->set_pagesize(dbp, 1024)) != 0) { + dbp->err(dbp, ret, "set_pagesize"); + goto err1; + } + if ((ret = dbp->set_cachesize(dbp, 0, 32 * 1024, 0)) != 0) { + dbp->err(dbp, ret, "set_cachesize"); + goto err1; + } + if ((ret = + dbp->open(dbp, DATABASE, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) { + dbp->err(dbp, ret, "%s: open", DATABASE); + goto err1; + } + + /* + * Insert records into the database, where the key is the user + * input and the data is the user input in reverse order. + */ + memset(&key, 0, sizeof(DBT)); + memset(&data, 0, sizeof(DBT)); + for (;;) { + printf("input> "); + fflush(stdout); + if (fgets(buf, sizeof(buf), stdin) == NULL) + break; + if ((len = strlen(buf)) <= 1) + continue; + for (t = rbuf, p = buf + (len - 2); p >= buf;) + *t++ = *p--; + *t++ = '\0'; + + key.data = buf; + data.data = rbuf; + data.size = key.size = len - 1; + + switch (ret = + dbp->put(dbp, NULL, &key, &data, DB_NOOVERWRITE)) { + case 0: + break; + default: + dbp->err(dbp, ret, "DB->put"); + if (ret != DB_KEYEXIST) + goto err1; + break; + } + } + printf("\n"); + + /* Acquire a cursor for the database. */ + if ((ret = dbp->cursor(dbp, NULL, &dbcp, 0)) != 0) { + dbp->err(dbp, ret, "DB->cursor"); + goto err1; + } + + /* Initialize the key/data pair so the flags aren't set. */ + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + + /* Walk through the database and print out the key/data pairs. */ + while ((ret = dbcp->c_get(dbcp, &key, &data, DB_NEXT)) == 0) + printf("%.*s : %.*s\n", + (int)key.size, (char *)key.data, + (int)data.size, (char *)data.data); + if (ret != DB_NOTFOUND) { + dbp->err(dbp, ret, "DBcursor->get"); + goto err2; + } + + /* Close everything down. */ + if ((ret = dbcp->c_close(dbcp)) != 0) { + dbp->err(dbp, ret, "DBcursor->close"); + goto err1; + } + if ((ret = dbp->close(dbp, 0)) != 0) { + fprintf(stderr, + "%s: DB->close: %s\n", progname, db_strerror(ret)); + return (ERROR_RETURN); + } + return (0); + +err2: (void)dbcp->c_close(dbcp); +err1: (void)dbp->close(dbp, 0); + return (ERROR_RETURN); +} diff --git a/db/examples_c/ex_btrec.c b/db/examples_c/ex_btrec.c new file mode 100644 index 000000000..b74f16b83 --- /dev/null +++ b/db/examples_c/ex_btrec.c @@ -0,0 +1,241 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: ex_btrec.c,v 11.8 2000/05/22 15:17:03 sue Exp $ + */ + +#include "db_config.h" + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#include +#endif + +#include + +#ifdef HAVE_VXWORKS +#define DATABASE "/vxtmp/vxtmp/access.db" +#define WORDLIST "/vxtmp/vxtmp/wordlist" +#define ERROR_RETURN ERROR +#else +#define DATABASE "access.db" +#define WORDLIST "../test/wordlist" +#define ERROR_RETURN 1 +int main __P((int, char *[])); +void usage __P((char *)); +#endif + +int ex_btrec __P((void)); +void show __P((char *, DBT *, DBT *)); + +#ifndef HAVE_VXWORKS +int +main(argc, argv) + int argc; + char *argv[]; +{ + extern char *optarg; + extern int optind; + int ch; + + while ((ch = getopt(argc, argv, "")) != EOF) + switch (ch) { + case '?': + default: + usage(argv[0]); + } + argc -= optind; + argv += optind; + + return (ex_btrec()); +} + +void +usage(progname) + char *progname; +{ + (void)fprintf(stderr, "usage: %s\n", progname); + exit(1); +} +#endif + +int +ex_btrec() +{ + DB *dbp; + DBC *dbcp; + DBT key, data; + DB_BTREE_STAT *statp; + FILE *fp; + db_recno_t recno; + u_int32_t len; + int cnt, ret; + char *p, *t, buf[1024], rbuf[1024]; + const char *progname = "ex_btrec"; /* Program name. */ + + /* Open the word database. */ + if ((fp = fopen(WORDLIST, "r")) == NULL) { + fprintf(stderr, "%s: open %s: %s\n", + progname, WORDLIST, db_strerror(errno)); + return (ERROR_RETURN); + } + + /* Remove the previous database. */ + (void)unlink(DATABASE); + + /* Create and initialize database object, open the database. */ + if ((ret = db_create(&dbp, NULL, 0)) != 0) { + fprintf(stderr, + "%s: db_create: %s\n", progname, db_strerror(ret)); + return (ERROR_RETURN); + } + dbp->set_errfile(dbp, stderr); + dbp->set_errpfx(dbp, progname); /* 1K page sizes. */ + if ((ret = dbp->set_pagesize(dbp, 1024)) != 0) { + dbp->err(dbp, ret, "set_pagesize"); + return (ERROR_RETURN); + } /* Record numbers. */ + if ((ret = dbp->set_flags(dbp, DB_RECNUM)) != 0) { + dbp->err(dbp, ret, "set_flags: DB_RECNUM"); + return (ERROR_RETURN); + } + if ((ret = + dbp->open(dbp, DATABASE, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) { + dbp->err(dbp, ret, "open: %s", DATABASE); + return (ERROR_RETURN); + } + + /* + * Insert records into the database, where the key is the word + * preceded by its record number, and the data is the same, but + * in reverse order. + */ + memset(&key, 0, sizeof(DBT)); + memset(&data, 0, sizeof(DBT)); + for (cnt = 1; cnt <= 1000; ++cnt) { + (void)sprintf(buf, "%04d_", cnt); + if (fgets(buf + 4, sizeof(buf) - 4, fp) == NULL) + break; + len = strlen(buf); + for (t = rbuf, p = buf + (len - 2); p >= buf;) + *t++ = *p--; + *t++ = '\0'; + + key.data = buf; + data.data = rbuf; + data.size = key.size = len - 1; + + if ((ret = + dbp->put(dbp, NULL, &key, &data, DB_NOOVERWRITE)) != 0) { + dbp->err(dbp, ret, "DB->put"); + if (ret != DB_KEYEXIST) + goto err1; + } + } + + /* Close the word database. */ + (void)fclose(fp); + + /* Print out the number of records in the database. */ + if ((ret = dbp->stat(dbp, &statp, NULL, 0)) != 0) { + dbp->err(dbp, ret, "DB->stat"); + goto err1; + } + printf("%s: database contains %lu records\n", + progname, (u_long)statp->bt_ndata); + free(statp); + + /* Acquire a cursor for the database. */ + if ((ret = dbp->cursor(dbp, NULL, &dbcp, 0)) != 0) { + dbp->err(dbp, ret, "DB->cursor"); + goto err1; + } + + /* + * Prompt the user for a record number, then retrieve and display + * that record. + */ + for (;;) { + /* Get a record number. */ + printf("recno #> "); + fflush(stdout); + if (fgets(buf, sizeof(buf), stdin) == NULL) + break; + recno = atoi(buf); + + /* + * Reset the key each time, the dbp->c_get() routine returns + * the key and data pair, not just the key! + */ + key.data = &recno; + key.size = sizeof(recno); + if ((ret = dbcp->c_get(dbcp, &key, &data, DB_SET_RECNO)) != 0) + goto get_err; + + /* Display the key and data. */ + show("k/d\t", &key, &data); + + /* Move the cursor a record forward. */ + if ((ret = dbcp->c_get(dbcp, &key, &data, DB_NEXT)) != 0) + goto get_err; + + /* Display the key and data. */ + show("next\t", &key, &data); + + /* + * Retrieve the record number for the following record into + * local memory. + */ + data.data = &recno; + data.size = sizeof(recno); + data.ulen = sizeof(recno); + data.flags |= DB_DBT_USERMEM; + if ((ret = dbcp->c_get(dbcp, &key, &data, DB_GET_RECNO)) != 0) { +get_err: dbp->err(dbp, ret, "DBcursor->get"); + if (ret != DB_NOTFOUND && ret != DB_KEYEMPTY) + goto err2; + } else + printf("retrieved recno: %lu\n", (u_long)recno); + + /* Reset the data DBT. */ + memset(&data, 0, sizeof(data)); + } + + if ((ret = dbcp->c_close(dbcp)) != 0) { + dbp->err(dbp, ret, "DBcursor->close"); + goto err1; + } + if ((ret = dbp->close(dbp, 0)) != 0) { + fprintf(stderr, + "%s: DB->close: %s\n", progname, db_strerror(ret)); + return (ERROR_RETURN); + } + + return (0); + +err2: (void)dbcp->c_close(dbcp); +err1: (void)dbp->close(dbp, 0); + return (ret); + +} + +/* + * show -- + * Display a key/data pair. + */ +void +show(msg, key, data) + DBT *key, *data; + char *msg; +{ + printf("%s%.*s : %.*s\n", msg, + (int)key->size, (char *)key->data, + (int)data->size, (char *)data->data); +} diff --git a/db/examples_c/ex_dbclient.c b/db/examples_c/ex_dbclient.c new file mode 100644 index 000000000..27461a892 --- /dev/null +++ b/db/examples_c/ex_dbclient.c @@ -0,0 +1,248 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: ex_dbclient.c,v 1.12 2000/10/26 14:13:05 bostic Exp $ + */ + +#include "db_config.h" + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#include +#endif + +#include + +#define DATABASE_HOME "database" + +#define DATABASE "access.db" + +int db_clientrun __P((DB_ENV *, char *)); +int ex_dbclient_run __P((char *, FILE *, char *, char *)); +#ifdef HAVE_VXWORKS +int ex_dbclient __P((char *)); +#define ERROR_RETURN ERROR +#define VXSHM_KEY 10 +#else +int main __P((int, char *[])); +#define ERROR_RETURN 1 +#endif + +/* + * An example of a program creating/configuring a Berkeley DB environment. + */ +#ifndef HAVE_VXWORKS +int +main(argc, argv) + int argc; + char *argv[]; +{ + char *home; + int ret; + + if (argc != 2) { + fprintf(stderr, "Usage: %s hostname\n",argv[0]); + exit(1); + } + /* + * All of the shared database files live in DATABASE_HOME, but + * data files will live in CONFIG_DATA_DIR. + */ + home = DATABASE_HOME; + + if ((ret = ex_dbclient_run(home, stderr, argv[1], argv[0])) != 0) + return (ret); + + return (0); +} +#endif + +int +ex_dbclient(host) + char *host; +{ + char *home; + char *progname = "ex_dbclient"; /* Program name. */ + int ret; + + /* + * All of the shared database files live in DATABASE_HOME, but + * data files will live in CONFIG_DATA_DIR. + */ + home = DATABASE_HOME; + + if ((ret = ex_dbclient_run(home, stderr, host, progname)) != 0) + return (ret); + + return (0); +} + +int +ex_dbclient_run(home, errfp, host, progname) + char *home, *host, *progname; + FILE *errfp; +{ + DB_ENV *dbenv; + int ret, retry; + + /* + * Create an environment object and initialize it for error + * reporting. + */ + if ((ret = db_env_create(&dbenv, DB_CLIENT)) != 0) { + fprintf(errfp, "%s: %s\n", progname, db_strerror(ret)); + return (ERROR_RETURN); + } +#ifdef HAVE_VXWORKS + if ((ret = dbenv->set_shm_key(dbenv, VXSHM_KEY)) != 0) { + fprintf(errfp, "%s: %s\n", progname, db_strerror(ret)); + return (ERROR_RETURN); + } +#endif + retry = 0; +retry: + while (retry < 5) { + /* + * Set the server host we are talking to. + */ + if ((ret = + dbenv->set_server(dbenv, host, 10000, 10000, 0)) != 0) { + fprintf(stderr, "Try %d: DBENV->set_server: %s\n", + retry, db_strerror(ret)); + retry++; + if ((ret = __os_sleep(dbenv, 15, 0)) != 0) + return (ret); + } else + break; + } + + if (retry >= 5) { + fprintf(stderr, "DBENV->set_server: %s\n", db_strerror(ret)); + dbenv->close(dbenv, 0); + return (ERROR_RETURN); + } + /* + * We want to specify the shared memory buffer pool cachesize, + * but everything else is the default. + */ + if ((ret = dbenv->set_cachesize(dbenv, 0, 64 * 1024, 0)) != 0) { + dbenv->err(dbenv, ret, "set_cachesize"); + dbenv->close(dbenv, 0); + return (ERROR_RETURN); + } + /* + * We have multiple processes reading/writing these files, so + * we need concurrency control and a shared buffer pool, but + * not logging or transactions. + */ + if ((ret = dbenv->open(dbenv, home, + DB_CREATE | DB_INIT_LOCK | DB_INIT_MPOOL | DB_INIT_TXN, 0)) != 0) { + dbenv->err(dbenv, ret, "environment open: %s", home); + dbenv->close(dbenv, 0); + if (ret == DB_NOSERVER) + goto retry; + return (ERROR_RETURN); + } + + ret = db_clientrun(dbenv, progname); + printf("db_clientrun returned %d\n", ret); + if (ret == DB_NOSERVER) + goto retry; + + /* Close the handle. */ + if ((ret = dbenv->close(dbenv, 0)) != 0) { + fprintf(stderr, "DBENV->close: %s\n", db_strerror(ret)); + return (ERROR_RETURN); + } + return (0); +} + +int +db_clientrun(dbenv, progname) + DB_ENV *dbenv; + char *progname; +{ + DB *dbp; + DBT key, data; + u_int32_t len; + int ret; + char *p, *t, buf[1024], rbuf[1024]; + + /* Remove the previous database. */ + + /* Create and initialize database object, open the database. */ + if ((ret = db_create(&dbp, dbenv, 0)) != 0) { + fprintf(stderr, + "%s: db_create: %s\n", progname, db_strerror(ret)); + return (ret); + } + if ((ret = dbp->set_pagesize(dbp, 1024)) != 0) { + dbp->err(dbp, ret, "set_pagesize"); + goto err1; + } + if ((ret = + dbp->open(dbp, DATABASE, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) { + dbp->err(dbp, ret, "%s: open", DATABASE); + goto err1; + } + + /* + * Insert records into the database, where the key is the user + * input and the data is the user input in reverse order. + */ + memset(&key, 0, sizeof(DBT)); + memset(&data, 0, sizeof(DBT)); + for (;;) { + printf("input> "); + fflush(stdout); + if (fgets(buf, sizeof(buf), stdin) == NULL) + break; + if ((len = strlen(buf)) <= 1) + continue; + for (t = rbuf, p = buf + (len - 2); p >= buf;) + *t++ = *p--; + *t++ = '\0'; + + key.data = buf; + data.data = rbuf; + data.size = key.size = len - 1; + + switch (ret = + dbp->put(dbp, NULL, &key, &data, DB_NOOVERWRITE)) { + case 0: + break; + default: + dbp->err(dbp, ret, "DB->put"); + if (ret != DB_KEYEXIST) + goto err1; + break; + } + memset(&data, 0, sizeof(DBT)); + switch (ret = dbp->get(dbp, NULL, &key, &data, 0)) { + case 0: + printf("%.*s : %.*s\n", + (int)key.size, (char *)key.data, + (int)data.size, (char *)data.data); + break; + default: + dbp->err(dbp, ret, "DB->get"); + break; + } + } + if ((ret = dbp->close(dbp, 0)) != 0) { + fprintf(stderr, + "%s: DB->close: %s\n", progname, db_strerror(ret)); + return (1); + } + return (0); + +err1: (void)dbp->close(dbp, 0); + return (ret); +} diff --git a/db/examples_c/ex_env.c b/db/examples_c/ex_env.c new file mode 100644 index 000000000..5490723a3 --- /dev/null +++ b/db/examples_c/ex_env.c @@ -0,0 +1,170 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: ex_env.c,v 11.18 2000/10/27 20:32:00 dda Exp $ + */ + +#include "db_config.h" + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#endif + +#include + +#ifdef macintosh +#define DATABASE_HOME ":database" +#define CONFIG_DATA_DIR ":database" +#else +#ifdef DB_WIN32 +#define DATABASE_HOME "\\tmp\\database" +#define CONFIG_DATA_DIR "\\database\\files" +#else +#ifdef HAVE_VXWORKS +#define DATABASE_HOME "/ata0/vxtmp/database" +#define CONFIG_DATA_DIR "/vxtmp/vxtmp/database/files" +#else +#define DATABASE_HOME "/tmp/database" +#define CONFIG_DATA_DIR "/database/files" +#endif +#endif +#endif + +int db_setup __P((char *, char *, FILE *, char *)); +int db_teardown __P((char *, char *, FILE *, char *)); +#ifdef HAVE_VXWORKS +int ex_env __P((void)); +#define ERROR_RETURN ERROR +#define VXSHM_KEY 11 +#else +int main __P((void)); +#define ERROR_RETURN 1 +#endif + +/* + * An example of a program creating/configuring a Berkeley DB environment. + */ +int +#ifdef HAVE_VXWORKS +ex_env() +#else +main() +#endif +{ + int ret; + char *data_dir, *home; + char *progname = "ex_env"; /* Program name. */ + + /* + * All of the shared database files live in DATABASE_HOME, but + * data files will live in CONFIG_DATA_DIR. + */ + home = DATABASE_HOME; + data_dir = CONFIG_DATA_DIR; + + printf("Setup env\n"); + if ((ret = db_setup(home, data_dir, stderr, progname)) != 0) + return (ret); + + printf("Teardown env\n"); + if ((ret = db_teardown(home, data_dir, stderr, progname)) != 0) + return (ret); + + return (0); +} + +int +db_setup(home, data_dir, errfp, progname) + char *home, *data_dir, *progname; + FILE *errfp; +{ + DB_ENV *dbenv; + int ret; + + /* + * Create an environment object and initialize it for error + * reporting. + */ + if ((ret = db_env_create(&dbenv, 0)) != 0) { + fprintf(errfp, "%s: %s\n", progname, db_strerror(ret)); + return (ERROR_RETURN); + } + dbenv->set_errfile(dbenv, errfp); + dbenv->set_errpfx(dbenv, progname); + +#ifdef HAVE_VXWORKS + /* VxWorks needs to specify a base segment ID. */ + if ((ret = dbenv->set_shm_key(dbenv, VXSHM_KEY)) != 0) { + fprintf(errfp, "%s: %s\n", progname, db_strerror(ret)); + return (ERROR_RETURN); + } +#endif + + /* + * We want to specify the shared memory buffer pool cachesize, + * but everything else is the default. + */ + if ((ret = dbenv->set_cachesize(dbenv, 0, 64 * 1024, 0)) != 0) { + dbenv->err(dbenv, ret, "set_cachesize"); + dbenv->close(dbenv, 0); + return (ERROR_RETURN); + } + + /* Databases are in a subdirectory. */ + (void)dbenv->set_data_dir(dbenv, data_dir); + + /* Open the environment with full transactional support. */ + if ((ret = dbenv->open(dbenv, home, + DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN, + 0)) != 0) { + dbenv->err(dbenv, ret, "environment open: %s", home); + dbenv->close(dbenv, 0); + return (ERROR_RETURN); + } + + /* Do something interesting... */ + + /* Close the handle. */ + if ((ret = dbenv->close(dbenv, 0)) != 0) { + fprintf(stderr, "DBENV->close: %s\n", db_strerror(ret)); + return (ERROR_RETURN); + } + return (0); +} + +int +db_teardown(home, data_dir, errfp, progname) + char *home, *data_dir, *progname; + FILE *errfp; +{ + DB_ENV *dbenv; + int ret; + + /* Remove the shared database regions. */ + if ((ret = db_env_create(&dbenv, 0)) != 0) { + fprintf(errfp, "%s: %s\n", progname, db_strerror(ret)); + return (ERROR_RETURN); + } + dbenv->set_errfile(dbenv, errfp); + dbenv->set_errpfx(dbenv, progname); +#ifdef HAVE_VXWORKS + if ((ret = dbenv->set_shm_key(dbenv, VXSHM_KEY)) != 0) { + fprintf(errfp, "%s: %s\n", progname, db_strerror(ret)); + return (ERROR_RETURN); + } +#endif + + (void)dbenv->set_data_dir(dbenv, data_dir); + if ((ret = dbenv->remove(dbenv, home, 0)) != 0) { + fprintf(stderr, "DBENV->remove: %s\n", db_strerror(ret)); + return (ERROR_RETURN); + } + return (0); +} diff --git a/db/examples_c/ex_lock.c b/db/examples_c/ex_lock.c new file mode 100644 index 000000000..e858be6b3 --- /dev/null +++ b/db/examples_c/ex_lock.c @@ -0,0 +1,235 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: ex_lock.c,v 11.6 2001/01/04 14:23:29 dda Exp $ + */ + +#include "db_config.h" + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#endif + +#include + +void db_init __P((char *, u_int32_t, int)); +int main __P((int, char *[])); +void usage __P((void)); + +DB_ENV *dbenv; +const char + *progname = "ex_lock"; /* Program name. */ + +int +main(argc, argv) + int argc; + char *argv[]; +{ + extern char *optarg; + extern int optind; + DBT lock_dbt; + DB_LOCK lock; + DB_LOCK *locks; + db_lockmode_t lock_type; + long held; + u_int32_t len, locker, maxlocks; + int ch, do_unlink, did_get, i, lockid, lockcount, ret; + char *home, opbuf[16], objbuf[1024], lockbuf[16]; + + home = "TESTDIR"; + maxlocks = 0; + do_unlink = 0; + while ((ch = getopt(argc, argv, "h:m:u")) != EOF) + switch (ch) { + case 'h': + home = optarg; + break; + case 'm': + if ((i = atoi(optarg)) <= 0) + usage(); + maxlocks = (u_int32_t)i; /* XXX: possible overflow. */ + break; + case 'u': + do_unlink = 1; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (argc != 0) + usage(); + + /* Initialize the database environment. */ + db_init(home, maxlocks, do_unlink); + + locks = 0; + lockcount = 0; + + /* + * Accept lock requests. + */ + if ((ret = lock_id(dbenv, &locker)) != 0) { + dbenv->err(dbenv, ret, "unable to get locker id"); + (void)dbenv->close(dbenv, 0); + exit (1); + } + lockid = -1; + + memset(&lock_dbt, 0, sizeof(lock_dbt)); + for (held = 0, did_get = 0;;) { + printf("Operation get/release [get]> "); + fflush(stdout); + if (fgets(opbuf, sizeof(opbuf), stdin) == NULL) + break; + if ((len = strlen(opbuf)) <= 1 || strcmp(opbuf, "get\n") == 0) { + /* Acquire a lock. */ + printf("input object (text string) to lock> "); + fflush(stdout); + if (fgets(objbuf, sizeof(objbuf), stdin) == NULL) + break; + if ((len = strlen(objbuf)) <= 1) + continue; + + do { + printf("lock type read/write [read]> "); + fflush(stdout); + if (fgets(lockbuf, + sizeof(lockbuf), stdin) == NULL) + break; + len = strlen(lockbuf); + } while (len > 1 && + strcmp(lockbuf, "read\n") != 0 && + strcmp(lockbuf, "write\n") != 0); + if (len == 1 || strcmp(lockbuf, "read\n") == 0) + lock_type = DB_LOCK_READ; + else + lock_type = DB_LOCK_WRITE; + + lock_dbt.data = objbuf; + lock_dbt.size = strlen(objbuf); + ret = lock_get(dbenv, locker, + DB_LOCK_NOWAIT, &lock_dbt, lock_type, &lock); + if (ret == 0) { + did_get = 1; + lockid = lockcount++; + if (locks == NULL) + locks = + (DB_LOCK *)malloc(sizeof(DB_LOCK)); + else + locks = (DB_LOCK *)realloc(locks, + lockcount * sizeof(DB_LOCK)); + locks[lockid] = lock; + } + } else { + /* Release a lock. */ + do { + printf("input lock to release> "); + fflush(stdout); + if (fgets(objbuf, + sizeof(objbuf), stdin) == NULL) + break; + } while ((len = strlen(objbuf)) <= 1); + lockid = strtol(objbuf, NULL, 16); + if (lockid < 0 || lockid >= lockcount) { + printf("Lock #%d out of range\n", lockid); + continue; + } + lock = locks[lockid]; + ret = lock_put(dbenv, &lock); + did_get = 0; + } + switch (ret) { + case 0: + printf("Lock #%d %s\n", lockid, + did_get ? "granted" : "released"); + held += did_get ? 1 : -1; + break; + case DB_LOCK_NOTGRANTED: + dbenv->err(dbenv, ret, NULL); + break; + case DB_LOCK_DEADLOCK: + dbenv->err(dbenv, ret, + "lock_%s", did_get ? "get" : "put"); + break; + default: + dbenv->err(dbenv, ret, + "lock_%s", did_get ? "get" : "put"); + (void)dbenv->close(dbenv, 0); + exit (1); + } + } + + printf("\nClosing lock region %ld locks held\n", held); + + if (locks != NULL) + free(locks); + + if ((ret = dbenv->close(dbenv, 0)) != 0) { + fprintf(stderr, + "%s: dbenv->close: %s\n", progname, db_strerror(ret)); + return (1); + } + return (0); +} + +/* + * db_init -- + * Initialize the environment. + */ +void +db_init(home, maxlocks, do_unlink) + char *home; + u_int32_t maxlocks; + int do_unlink; +{ + int ret; + + if ((ret = db_env_create(&dbenv, 0)) != 0) { + fprintf(stderr, "%s: db_env_create: %s\n", + progname, db_strerror(ret)); + exit (1); + } + + if (do_unlink) { + if ((ret = dbenv->remove(dbenv, home, DB_FORCE)) != 0) { + fprintf(stderr, "%s: dbenv->remove: %s\n", + progname, db_strerror(ret)); + exit (1); + } + if ((ret = db_env_create(&dbenv, 0)) != 0) { + fprintf(stderr, "%s: db_env_create: %s\n", + progname, db_strerror(ret)); + exit (1); + } + } + + dbenv->set_errfile(dbenv, stderr); + dbenv->set_errpfx(dbenv, progname); + if (maxlocks != 0) + dbenv->set_lk_max_locks(dbenv, maxlocks); + + if ((ret = + dbenv->open(dbenv, home, DB_CREATE | DB_INIT_LOCK, 0)) != 0) { + dbenv->err(dbenv, ret, NULL); + (void)dbenv->close(dbenv, 0); + exit(1); + } +} + +void +usage() +{ + (void)fprintf(stderr, + "usage: %s [-u] [-h home] [-m maxlocks]\n", progname); + exit(1); +} diff --git a/db/examples_c/ex_mpool.c b/db/examples_c/ex_mpool.c new file mode 100644 index 000000000..376c66478 --- /dev/null +++ b/db/examples_c/ex_mpool.c @@ -0,0 +1,280 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: ex_mpool.c,v 11.13 2000/10/27 20:32:00 dda Exp $ + */ + +#include "db_config.h" + +#ifndef NO_SYSTEM_INCLUDES +#include + +#if TIME_WITH_SYS_TIME +#include +#include +#else +#if HAVE_SYS_TIME_H +#include +#else +#include +#endif +#endif + +#include +#include +#include +#include +#include +#endif + +#include + +int init __P((char *, int, int, char *)); +int run __P((int, int, int, int, char *)); +int run_mpool __P((int, int, int, int, char *)); +#ifdef HAVE_VXWORKS +int ex_mpool __P((void)); +#define MPOOL "/vxtmp/vxtmp/mpool" /* File. */ +#define ERROR_RETURN ERROR +#define VXSHM_KEY 12 +#else +int main __P((int, char *[])); +void usage __P((char *)); +#define MPOOL "mpool" /* File. */ +#define ERROR_RETURN 1 +#endif + +#ifndef HAVE_VXWORKS +int +main(argc, argv) + int argc; + char *argv[]; +{ + extern char *optarg; + extern int optind; + int cachesize, ch, hits, npages, pagesize; + char *progname; + + cachesize = 20 * 1024; + hits = 1000; + npages = 50; + pagesize = 1024; + progname = argv[0]; + while ((ch = getopt(argc, argv, "c:h:n:p:")) != EOF) + switch (ch) { + case 'c': + if ((cachesize = atoi(optarg)) < 20 * 1024) + usage(progname); + break; + case 'h': + if ((hits = atoi(optarg)) <= 0) + usage(progname); + break; + case 'n': + if ((npages = atoi(optarg)) <= 0) + usage(progname); + break; + case 'p': + if ((pagesize = atoi(optarg)) <= 0) + usage(progname); + break; + case '?': + default: + usage(progname); + } + argc -= optind; + argv += optind; + + return (run_mpool(pagesize, cachesize, hits, npages, progname)); +} + +void +usage(progname) + char *progname; +{ + (void)fprintf(stderr, + "usage: %s [-c cachesize] [-h hits] [-n npages] [-p pagesize]\n", + progname); + exit(1); +} +#else +int +ex_mpool() +{ + char *progname = "ex_mpool"; /* Program name. */ + int cachesize, ch, hits, npages, pagesize; + + cachesize = 20 * 1024; + hits = 1000; + npages = 50; + pagesize = 1024; + + return (run_mpool(pagesize, cachesize, hits, npages, progname)); +} +#endif + +int +run_mpool(pagesize, cachesize, hits, npages, progname) + int pagesize, cachesize, hits, npages; + char *progname; +{ + int ret; + + /* Initialize the file. */ + if ((ret = init(MPOOL, pagesize, npages, progname)) != 0) + return (ret); + + /* Get the pages. */ + if ((ret = run(hits, cachesize, pagesize, npages, progname)) != 0) + return (ret); + + return (0); +} + +/* + * init -- + * Create a backing file. + */ +int +init(file, pagesize, npages, progname) + char *file, *progname; + int pagesize, npages; +{ + int cnt, flags, fd; + char *p; + + /* + * Create a file with the right number of pages, and store a page + * number on each page. + */ + flags = O_CREAT | O_RDWR | O_TRUNC; +#ifdef DB_WIN32 + flags |= O_BINARY; +#endif + if ((fd = open(file, flags, 0666)) < 0) { + fprintf(stderr, + "%s: %s: %s\n", progname, file, strerror(errno)); + return (ERROR_RETURN); + } + if ((p = (char *)malloc(pagesize)) == NULL) { + fprintf(stderr, "%s: %s\n", progname, strerror(ENOMEM)); + return (ERROR_RETURN); + } + + /* The pages are numbered from 0. */ + for (cnt = 0; cnt <= npages; ++cnt) { + *(int *)p = cnt; + if (write(fd, p, pagesize) != pagesize) { + fprintf(stderr, + "%s: %s: %s\n", progname, file, strerror(errno)); + return (ERROR_RETURN); + } + } + + (void)close(fd); + free(p); + return (0); +} + +/* + * run -- + * Get a set of pages. + */ +int +run(hits, cachesize, pagesize, npages, progname) + int hits, cachesize, pagesize, npages; + char *progname; +{ + DB_ENV *dbenv; + DB_MPOOLFILE *dbmfp; + db_pgno_t pageno; + int cnt, ret; + void *p; + + printf("%s: cachesize: %d; pagesize: %d; N pages: %d\n", + progname, cachesize, pagesize, npages); + + /* + * Open a memory pool, specify a cachesize, output error messages + * to stderr. + */ + if ((ret = db_env_create(&dbenv, 0)) != 0) { + fprintf(stderr, + "%s: db_env_create: %s\n", progname, db_strerror(ret)); + return (ERROR_RETURN); + } + dbenv->set_errfile(dbenv, stderr); + dbenv->set_errpfx(dbenv, progname); +#ifdef HAVE_VXWORKS + if ((ret = dbenv->set_shm_key(dbenv, VXSHM_KEY)) != 0) { + dbenv->err(dbenv, ret, "set_shm_key"); + return (ERROR_RETURN); + } +#endif + + /* Set the cachesize. */ + if ((ret = dbenv->set_cachesize(dbenv, 0, cachesize, 0)) != 0) { + dbenv->err(dbenv, ret, "set_cachesize"); + goto err1; + } + + /* Open the environment. */ + if ((ret = dbenv->open( + dbenv, NULL, DB_CREATE | DB_INIT_MPOOL, 0)) != 0) { + dbenv->err(dbenv, ret, "open"); + goto err1; + } + + /* Open the file in the environment. */ + if ((ret = + memp_fopen(dbenv, MPOOL, 0, 0, pagesize, NULL, &dbmfp)) != 0) { + dbenv->err(dbenv, ret, "memp_fopen: %s", MPOOL); + goto err1; + } + + printf("retrieve %d random pages... ", hits); + + srand((u_int)time(NULL)); + for (cnt = 0; cnt < hits; ++cnt) { + pageno = (rand() % npages) + 1; + if ((ret = memp_fget(dbmfp, &pageno, 0, &p)) != 0) { + dbenv->err(dbenv, ret, + "unable to retrieve page %lu", (u_long)pageno); + goto err2; + } + if (*(db_pgno_t *)p != pageno) { + dbenv->errx(dbenv, + "wrong page retrieved (%lu != %d)", + (u_long)pageno, *(int *)p); + goto err2; + } + if ((ret = memp_fput(dbmfp, p, 0)) != 0) { + dbenv->err(dbenv, ret, + "unable to return page %lu", (u_long)pageno); + goto err2; + } + } + + printf("successful.\n"); + + /* Close the file. */ + if ((ret = memp_fclose(dbmfp)) != 0) { + dbenv->err(dbenv, ret, "memp_fclose"); + goto err1; + } + + /* Close the pool. */ + if ((ret = dbenv->close(dbenv, 0)) != 0) { + fprintf(stderr, + "%s: db_env_create: %s\n", progname, db_strerror(ret)); + return (ERROR_RETURN); + } + return (0); + +err2: (void)memp_fclose(dbmfp); +err1: (void)dbenv->close(dbenv, 0); + return (ERROR_RETURN); +} diff --git a/db/examples_c/ex_thread.c b/db/examples_c/ex_thread.c new file mode 100644 index 000000000..93812ade7 --- /dev/null +++ b/db/examples_c/ex_thread.c @@ -0,0 +1,604 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: ex_thread.c,v 11.9 2000/05/31 15:10:04 bostic Exp $ + */ + +#include "db_config.h" + +#ifndef NO_SYSTEM_INCLUDES +#include + +#if TIME_WITH_SYS_TIME +#include +#include +#else +#if HAVE_SYS_TIME_H +#include +#else +#include +#endif +#endif + +#include +#include +#include +#include +#include +#include +#endif + +#include + +/* + * NB: This application is written using POSIX 1003.1b-1993 pthreads + * interfaces, which may not be portable to your system. + */ +extern int sched_yield __P((void)); /* Pthread yield function. */ + +DB_ENV *db_init __P((char *)); +void *deadlock __P((void *)); +void fatal __P((char *, int, int)); +int main __P((int, char *[])); +int reader __P((int)); +void stats __P((void)); +void *trickle __P((void *)); +void *tstart __P((void *)); +void usage __P((void)); +void word __P((void)); +int writer __P((int)); + +struct _statistics { + int aborted; /* Write. */ + int aborts; /* Read/write. */ + int adds; /* Write. */ + int deletes; /* Write. */ + int txns; /* Write. */ + int found; /* Read. */ + int notfound; /* Read. */ +} *perf; + +const char + *progname = "ex_thread"; /* Program name. */ + +#define DATABASE "access.db" /* Database name. */ +#define WORDLIST "../test/wordlist" /* Dictionary. */ + +/* + * We can seriously increase the number of collisions and transaction + * aborts by yielding the scheduler after every DB call. Specify the + * -p option to do this. + */ +int punish; /* -p */ +int nlist; /* -n */ +int nreaders; /* -r */ +int verbose; /* -v */ +int nwriters; /* -w */ + +DB *dbp; /* Database handle. */ +DB_ENV *dbenv; /* Database environment. */ +int nthreads; /* Total threads. */ +char **list; /* Word list. */ + +/* + * ex_thread -- + * Run a simple threaded application of some numbers of readers and + * writers competing for a set of words. + * + * Example UNIX shell script to run this program: + * % rm -rf TESTDIR + * % mkdir TESTDIR + * % ex_thread -h TESTDIR + */ +int +main(argc, argv) + int argc; + char *argv[]; +{ + extern char *optarg; + extern int errno, optind; + pthread_t *tids; + int ch, i, ret; + char *home; + void *retp; + + nlist = 1000; + nreaders = nwriters = 4; + home = "TESTDIR"; + while ((ch = getopt(argc, argv, "h:pn:r:vw:")) != EOF) + switch (ch) { + case 'h': + home = optarg; + break; + case 'p': + punish = 1; + break; + case 'n': + nlist = atoi(optarg); + break; + case 'r': + nreaders = atoi(optarg); + break; + case 'v': + verbose = 1; + break; + case 'w': + nwriters = atoi(optarg); + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + /* Initialize the random number generator. */ + srand(getpid() | time(NULL)); + + /* Build the key list. */ + word(); + + /* Remove the previous database. */ + (void)unlink(DATABASE); + + /* Initialize the database environment. */ + dbenv = db_init(home); + + /* Initialize the database. */ + if ((ret = db_create(&dbp, dbenv, 0)) != 0) { + dbenv->err(dbenv, ret, "db_create"); + (void)dbenv->close(dbenv, 0); + return (1); + } + if ((ret = dbp->set_pagesize(dbp, 1024)) != 0) { + dbp->err(dbp, ret, "set_pagesize"); + goto err; + } + if ((ret = dbp->open(dbp, + DATABASE, NULL, DB_BTREE, DB_CREATE | DB_THREAD, 0664)) != 0) { + dbp->err(dbp, ret, "%s: open", DATABASE); + goto err; + } + + nthreads = nreaders + nwriters + 2; + printf("Running: readers %d, writers %d\n", nreaders, nwriters); + fflush(stdout); + + /* Create statistics structures, offset by 1. */ + if ((perf = calloc(nreaders + nwriters + 1, sizeof(*perf))) == NULL) + fatal(NULL, errno, 1); + + /* Create thread ID structures. */ + if ((tids = malloc(nthreads * sizeof(pthread_t))) == NULL) + fatal(NULL, errno, 1); + + /* Create reader/writer threads. */ + for (i = 0; i < nreaders + nwriters; ++i) + if (pthread_create(&tids[i], NULL, tstart, (void *)i)) + fatal("pthread_create", errno, 1); + + /* Create buffer pool trickle thread. */ + if (pthread_create(&tids[i], NULL, trickle, &i)) + fatal("pthread_create", errno, 1); + ++i; + + /* Create deadlock detector thread. */ + if (pthread_create(&tids[i], NULL, deadlock, &i)) + fatal("pthread_create", errno, 1); + + /* Wait for the threads. */ + for (i = 0; i < nthreads; ++i) + (void)pthread_join(tids[i], &retp); + +err: (void)dbp->close(dbp, 0); + (void)dbenv->close(dbenv, 0); + + return (0); +} + +int +reader(id) + int id; +{ + DBT key, data; + int n, ret; + char buf[64]; + + /* + * DBT's must use local memory or malloc'd memory if the DB handle + * is accessed in a threaded fashion. + */ + memset(&key, 0, sizeof(DBT)); + memset(&data, 0, sizeof(DBT)); + data.flags = DB_DBT_MALLOC; + + /* + * Read-only threads do not require transaction protection, unless + * there's a need for repeatable reads. + */ + for (;;) { + /* Pick a key at random, and look it up. */ + n = rand() % nlist; + key.data = list[n]; + key.size = strlen(key.data); + + if (verbose) { + sprintf(buf, "reader: %d: list entry %d\n", id, n); + write(STDOUT_FILENO, buf, strlen(buf)); + } + + switch (ret = dbp->get(dbp, NULL, &key, &data, 0)) { + case DB_LOCK_DEADLOCK: /* Deadlock. */ + ++perf[id].aborts; + break; + case 0: /* Success. */ + ++perf[id].found; + free(data.data); + break; + case DB_NOTFOUND: /* Not found. */ + ++perf[id].notfound; + break; + default: + sprintf(buf, + "reader %d: dbp->get: %s", id, (char *)key.data); + fatal(buf, ret, 0); + } + } + return (0); +} + +int +writer(id) + int id; +{ + DBT key, data; + DB_TXN *tid; + time_t now, then; + int n, ret; + char buf[256], dbuf[10000]; + + time(&now); + then = now; + + /* + * DBT's must use local memory or malloc'd memory if the DB handle + * is accessed in a threaded fashion. + */ + memset(&key, 0, sizeof(DBT)); + memset(&data, 0, sizeof(DBT)); + data.data = dbuf; + data.ulen = sizeof(dbuf); + data.flags = DB_DBT_USERMEM; + + for (;;) { + /* Pick a random key. */ + n = rand() % nlist; + key.data = list[n]; + key.size = strlen(key.data); + + if (verbose) { + sprintf(buf, "writer: %d: list entry %d\n", id, n); + write(STDOUT_FILENO, buf, strlen(buf)); + } + + /* Abort and retry. */ + if (0) { +retry: if ((ret = txn_abort(tid)) != 0) + fatal("txn_abort", ret, 1); + ++perf[id].aborts; + ++perf[id].aborted; + } + + /* Thread #1 prints out the stats every 20 seconds. */ + if (id == 1) { + time(&now); + if (now - then >= 20) { + stats(); + then = now; + } + } + + /* Begin the transaction. */ + if ((ret = txn_begin(dbenv, NULL, &tid, 0)) != 0) + fatal("txn_begin", ret, 1); + + /* + * Get the key. If it doesn't exist, add it. If it does + * exist, delete it. + */ + switch (ret = dbp->get(dbp, tid, &key, &data, 0)) { + case DB_LOCK_DEADLOCK: + goto retry; + case 0: + goto delete; + case DB_NOTFOUND: + goto add; + } + + sprintf(buf, "writer: %d: dbp->get", id); + fatal(buf, ret, 1); + /* NOTREACHED */ + +delete: /* Delete the key. */ + switch (ret = dbp->del(dbp, tid, &key, 0)) { + case DB_LOCK_DEADLOCK: + goto retry; + case 0: + ++perf[id].deletes; + goto commit; + } + + sprintf(buf, "writer: %d: dbp->del", id); + fatal(buf, ret, 1); + /* NOTREACHED */ + +add: /* Add the key. 1 data item in 30 is an overflow item. */ + data.size = 20 + rand() % 128; + if (rand() % 30 == 0) + data.size += 8192; + + switch (ret = dbp->put(dbp, tid, &key, &data, 0)) { + case DB_LOCK_DEADLOCK: + goto retry; + case 0: + ++perf[id].adds; + goto commit; + default: + sprintf(buf, "writer: %d: dbp->put", id); + fatal(buf, ret, 1); + } + +commit: /* The transaction finished, commit it. */ + if ((ret = txn_commit(tid, 0)) != 0) + fatal("txn_commit", ret, 1); + + /* + * Every time the thread completes 20 transactions, show + * our progress. + */ + if (++perf[id].txns % 20 == 0) { + sprintf(buf, +"writer: %2d: adds: %4d: deletes: %4d: aborts: %4d: txns: %4d\n", + id, perf[id].adds, perf[id].deletes, + perf[id].aborts, perf[id].txns); + write(STDOUT_FILENO, buf, strlen(buf)); + } + + /* + * If this thread was aborted more than 5 times before + * the transaction finished, complain. + */ + if (perf[id].aborted > 5) { + sprintf(buf, +"writer: %2d: adds: %4d: deletes: %4d: aborts: %4d: txns: %4d: ABORTED: %2d\n", + id, perf[id].adds, perf[id].deletes, + perf[id].aborts, perf[id].txns, perf[id].aborted); + write(STDOUT_FILENO, buf, strlen(buf)); + } + perf[id].aborted = 0; + } + return (0); +} + +/* + * stats -- + * Display reader/writer thread statistics. To display the statistics + * for the mpool trickle or deadlock threads, use db_stat(1). + */ +void +stats() +{ + int id; + char *p, buf[8192]; + + p = buf + sprintf(buf, "-------------\n"); + for (id = 0; id < nreaders + nwriters;) + if (id++ < nwriters) + p += sprintf(p, + "writer: %2d: adds: %4d: deletes: %4d: aborts: %4d: txns: %4d\n", + id, perf[id].adds, + perf[id].deletes, perf[id].aborts, perf[id].txns); + else + p += sprintf(p, + "reader: %2d: found: %5d: notfound: %5d: aborts: %4d\n", + id, perf[id].found, + perf[id].notfound, perf[id].aborts); + p += sprintf(p, "-------------\n"); + + write(STDOUT_FILENO, buf, p - buf); +} + +/* + * db_init -- + * Initialize the environment. + */ +DB_ENV * +db_init(home) + char *home; +{ + DB_ENV *dbenv; + int ret; + + if (punish) { + (void)db_env_set_pageyield(1); + (void)db_env_set_func_yield(sched_yield); + } + + if ((ret = db_env_create(&dbenv, 0)) != 0) { + fprintf(stderr, + "%s: db_env_create: %s\n", progname, db_strerror(ret)); + exit (1); + } + dbenv->set_errfile(dbenv, stderr); + dbenv->set_errpfx(dbenv, progname); + (void)dbenv->set_cachesize(dbenv, 0, 100 * 1024, 0); + (void)dbenv->set_lg_max(dbenv, 200000); + + if ((ret = dbenv->open(dbenv, home, + DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | + DB_INIT_MPOOL | DB_INIT_TXN | DB_THREAD, 0)) != 0) { + dbenv->err(dbenv, ret, NULL); + (void)dbenv->close(dbenv, 0); + exit (1); + } + return (dbenv); +} + +/* + * tstart -- + * Thread start function for readers and writers. + */ +void * +tstart(arg) + void *arg; +{ + pthread_t tid; + u_int id; + + id = (u_int)arg + 1; + + tid = pthread_self(); + + if (id <= (u_int)nwriters) { + printf("write thread %d starting: tid: %lu\n", id, (u_long)tid); + fflush(stdout); + writer(id); + } else { + printf("read thread %d starting: tid: %lu\n", id, (u_long)tid); + fflush(stdout); + reader(id); + } + + /* NOTREACHED */ + return (NULL); +} + +/* + * deadlock -- + * Thread start function for lock_detect(). + */ +void * +deadlock(arg) + void *arg; +{ + struct timeval t; + pthread_t tid; + + arg = arg; /* XXX: shut the compiler up. */ + tid = pthread_self(); + + printf("deadlock thread starting: tid: %lu\n", (u_long)tid); + fflush(stdout); + + t.tv_sec = 0; + t.tv_usec = 100000; + for (;;) { + (void)lock_detect(dbenv, + DB_LOCK_CONFLICT, DB_LOCK_YOUNGEST, NULL); + + /* Check every 100ms. */ + (void)select(0, NULL, NULL, NULL, &t); + } + + /* NOTREACHED */ + return (NULL); +} + +/* + * trickle -- + * Thread start function for memp_trickle(). + */ +void * +trickle(arg) + void *arg; +{ + pthread_t tid; + int wrote; + char buf[64]; + + arg = arg; /* XXX: shut the compiler up. */ + tid = pthread_self(); + + printf("trickle thread starting: tid: %lu\n", (u_long)tid); + fflush(stdout); + + for (;;) { + (void)memp_trickle(dbenv, 10, &wrote); + if (verbose) { + sprintf(buf, "trickle: wrote %d\n", wrote); + write(STDOUT_FILENO, buf, strlen(buf)); + } + if (wrote == 0) { + sleep(1); + sched_yield(); + } + } + + /* NOTREACHED */ + return (NULL); +} + +/* + * word -- + * Build the dictionary word list. + */ +void +word() +{ + FILE *fp; + int cnt; + char buf[256]; + + if ((fp = fopen(WORDLIST, "r")) == NULL) + fatal(WORDLIST, errno, 1); + + if ((list = malloc(nlist * sizeof(char *))) == NULL) + fatal(NULL, errno, 1); + + for (cnt = 0; cnt < nlist; ++cnt) { + if (fgets(buf, sizeof(buf), fp) == NULL) + break; + if ((list[cnt] = strdup(buf)) == NULL) + fatal(NULL, errno, 1); + } + nlist = cnt; /* In case nlist was larger than possible. */ +} + +/* + * fatal -- + * Report a fatal error and quit. + */ +void +fatal(msg, err, syserr) + char *msg; + int err, syserr; +{ + fprintf(stderr, "%s: ", progname); + if (msg != NULL) { + fprintf(stderr, "%s", msg); + if (syserr) + fprintf(stderr, ": "); + } + if (syserr) + fprintf(stderr, "%s", strerror(err)); + fprintf(stderr, "\n"); + exit (1); + + /* NOTREACHED */ +} + +/* + * usage -- + * Usage message. + */ +void +usage() +{ + (void)fprintf(stderr, + "usage: %s [-pv] [-h home] [-n words] [-r readers] [-w writers]\n", + progname); + exit(1); +} diff --git a/db/examples_c/ex_tpcb.c b/db/examples_c/ex_tpcb.c new file mode 100644 index 000000000..2fd11510a --- /dev/null +++ b/db/examples_c/ex_tpcb.c @@ -0,0 +1,811 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: ex_tpcb.c,v 11.21 2000/10/27 20:32:00 dda Exp $ + */ + +#include "db_config.h" + +#ifndef NO_SYSTEM_INCLUDES +#include + +#if TIME_WITH_SYS_TIME +#include +#include +#else +#if HAVE_SYS_TIME_H +#include +#else +#include +#endif +#endif + +#include +#include +#include +#include +#endif + +#ifdef DB_WIN32 +#include +#include +#endif + +#include + +typedef enum { ACCOUNT, BRANCH, TELLER } FTYPE; + +DB_ENV *db_init __P((char *, char *, int, int, int)); +int hpopulate __P((DB *, int, int, int, int)); +int populate __P((DB *, u_int32_t, u_int32_t, int, char *)); +u_int32_t random_id __P((FTYPE, int, int, int)); +u_int32_t random_int __P((u_int32_t, u_int32_t)); +int tp_populate __P((DB_ENV *, int, int, int, int, int)); +int tp_run __P((DB_ENV *, int, int, int, int, int)); +int tp_txn __P((DB_ENV *, DB *, DB *, DB *, DB *, int, int, int, int)); + +#ifdef HAVE_VXWORKS +#define ERROR_RETURN ERROR +#define HOME "/vxtmp/vxtmp/TESTDIR" +#define VXSHM_KEY 13 +int ex_tpcb_init __P(()); +int ex_tpcb __P(()); +#else +#define ERROR_RETURN 1 +void invarg __P((char *, int, char *)); +int main __P((int, char *[])); +void usage __P((char *)); +#endif + +/* + * This program implements a basic TPC/B driver program. To create the + * TPC/B database, run with the -i (init) flag. The number of records + * with which to populate the account, history, branch, and teller tables + * is specified by the a, s, b, and t flags respectively. To run a TPC/B + * test, use the n flag to indicate a number of transactions to run (note + * that you can run many of these processes in parallel to simulate a + * multiuser test run). + */ +#define TELLERS_PER_BRANCH 10 +#define ACCOUNTS_PER_TELLER 10000 +#define HISTORY_PER_BRANCH 2592000 + +/* + * The default configuration that adheres to TPCB scaling rules requires + * nearly 3 GB of space. To avoid requiring that much space for testing, + * we set the parameters much lower. If you want to run a valid 10 TPS + * configuration, define VALID_SCALING. + */ +#ifdef VALID_SCALING +#define ACCOUNTS 1000000 +#define BRANCHES 10 +#define TELLERS 100 +#define HISTORY 25920000 +#endif + +#ifdef TINY +#define ACCOUNTS 1000 +#define BRANCHES 10 +#define TELLERS 100 +#define HISTORY 10000 +#endif + +#ifdef VERY_TINY +#define ACCOUNTS 500 +#define BRANCHES 10 +#define TELLERS 50 +#define HISTORY 5000 +#endif + +#if !defined(VALID_SCALING) && !defined(TINY) && !defined(VERY_TINY) +#define ACCOUNTS 100000 +#define BRANCHES 10 +#define TELLERS 100 +#define HISTORY 259200 +#endif + +#define HISTORY_LEN 100 +#define RECLEN 100 +#define BEGID 1000000 + +typedef struct _defrec { + u_int32_t id; + u_int32_t balance; + u_int8_t pad[RECLEN - sizeof(u_int32_t) - sizeof(u_int32_t)]; +} defrec; + +typedef struct _histrec { + u_int32_t aid; + u_int32_t bid; + u_int32_t tid; + u_int32_t amount; + u_int8_t pad[RECLEN - 4 * sizeof(u_int32_t)]; +} histrec; + +#ifdef HAVE_VXWORKS +int +ex_tpcb_init() +{ + DB_ENV *dbenv; + int accounts, branches, ret, seed, t_ret, tellers, history, verbose; + char *home; + char *progname = "ex_tpcb_init"; /* Program name. */ + + verbose = 1; + if ((dbenv = db_init(HOME, progname, 0, 1, 0)) == NULL) + return (ERROR_RETURN); + + accounts = ACCOUNTS; + branches = BRANCHES; + tellers = TELLERS; + history = HISTORY; + + if ((ret = tp_populate(dbenv, accounts, branches, history, tellers, + verbose)) != OK) + fprintf(stderr, "%s: %s\n", progname, db_strerror(ret)); + if ((t_ret = dbenv->close(dbenv, 0)) != 0) { + fprintf(stderr, "%s: %s\n", progname, db_strerror(ret)); + return (ERROR_RETURN); + } + + return (ret == 0 ? t_ret : ret); +} + +int +ex_tpcb() +{ + DB_ENV *dbenv; + int accounts, branches, seed, tellers, history; + int ch, mpool, ntxns, ret, t_ret, txn_no_sync, verbose; + char *progname = "ex_tpcb"; /* Program name. */ + + accounts = ACCOUNTS; + branches = BRANCHES; + tellers = TELLERS; + history = HISTORY; + + txn_no_sync = 0; + mpool = 0; + ntxns = 20; + verbose = 1; + seed = (int)((u_int)getpid() | time(NULL)); + + srand((u_int)seed); + + /* Initialize the database environment. */ + if ((dbenv = db_init(HOME, progname, mpool, 0, + txn_no_sync ? DB_TXN_NOSYNC : 0)) == NULL) + return (ERROR_RETURN); + + if (verbose) + printf("%ld Accounts, %ld Branches, %ld Tellers, %ld History\n", + (long)accounts, (long)branches, + (long)tellers, (long)history); + + if ((ret = tp_run(dbenv, ntxns, accounts, branches, tellers, verbose)) + != OK) + fprintf(stderr, "tp_run failed\n"); + + if ((t_ret = dbenv->close(dbenv, 0)) != 0) { + fprintf(stderr, "%s: %s\n", progname, db_strerror(ret)); + return (ERROR_RETURN); + } + return (ret == 0 ? t_ret : ret); +} +#else +int +main(argc, argv) + int argc; + char *argv[]; +{ + extern char *optarg; + extern int optind; + DB_ENV *dbenv; + int accounts, branches, seed, tellers, history; + int ch, iflag, mpool, ntxns, ret, txn_no_sync, verbose; + char *home, *progname; + + home = "TESTDIR"; + progname = "ex_tpcb"; + accounts = branches = history = tellers = 0; + txn_no_sync = 0; + mpool = ntxns = 0; + verbose = 0; + iflag = 0; + seed = (int)((u_int)getpid() | time(NULL)); + while ((ch = getopt(argc, argv, "a:b:c:fh:in:S:s:t:v")) != EOF) + switch (ch) { + case 'a': /* Number of account records */ + if ((accounts = atoi(optarg)) <= 0) + invarg(progname, ch, optarg); + break; + case 'b': /* Number of branch records */ + if ((branches = atoi(optarg)) <= 0) + invarg(progname, ch, optarg); + break; + case 'c': /* Cachesize in bytes */ + if ((mpool = atoi(optarg)) <= 0) + invarg(progname, ch, optarg); + break; + case 'f': /* Fast mode: no txn sync. */ + txn_no_sync = 1; + break; + case 'h': /* DB home. */ + home = optarg; + break; + case 'i': /* Initialize the test. */ + iflag = 1; + break; + case 'n': /* Number of transactions */ + if ((ntxns = atoi(optarg)) <= 0) + invarg(progname, ch, optarg); + break; + case 'S': /* Random number seed. */ + if ((seed = atoi(optarg)) <= 0) + invarg(progname, ch, optarg); + break; + case 's': /* Number of history records */ + if ((history = atoi(optarg)) <= 0) + invarg(progname, ch, optarg); + break; + case 't': /* Number of teller records */ + if ((tellers = atoi(optarg)) <= 0) + invarg(progname, ch, optarg); + break; + case 'v': /* Verbose option. */ + verbose = 1; + break; + case '?': + default: + usage(progname); + } + argc -= optind; + argv += optind; + + srand((u_int)seed); + + /* Initialize the database environment. */ + if ((dbenv = db_init(home, + progname, mpool, iflag, txn_no_sync ? DB_TXN_NOSYNC : 0)) == NULL) + return (1); + + accounts = accounts == 0 ? ACCOUNTS : accounts; + branches = branches == 0 ? BRANCHES : branches; + tellers = tellers == 0 ? TELLERS : tellers; + history = history == 0 ? HISTORY : history; + + if (verbose) + printf("%ld Accounts, %ld Branches, %ld Tellers, %ld History\n", + (long)accounts, (long)branches, + (long)tellers, (long)history); + + if (iflag) { + if (ntxns != 0) + usage(progname); + tp_populate(dbenv, + accounts, branches, history, tellers, verbose); + } else { + if (ntxns == 0) + usage(progname); + tp_run(dbenv, ntxns, accounts, branches, tellers, verbose); + } + + if ((ret = dbenv->close(dbenv, 0)) != 0) { + fprintf(stderr, "%s: dbenv->close failed: %s\n", + progname, db_strerror(ret)); + return (1); + } + + return (0); +} + +void +invarg(progname, arg, str) + char *progname; + int arg; + char *str; +{ + (void)fprintf(stderr, + "%s: invalid argument for -%c: %s\n", progname, arg, str); + exit (1); +} + +void +usage(progname) + char *progname; +{ + char *a1, *a2; + + a1 = "[-fv] [-a accounts] [-b branches]\n"; + a2 = "\t[-c cache_size] [-h home] [-S seed] [-s history] [-t tellers]"; + (void)fprintf(stderr, "usage: %s -i %s %s\n", progname, a1, a2); + (void)fprintf(stderr, + " %s -n transactions %s %s\n", progname, a1, a2); + exit(1); +} +#endif + +/* + * db_init -- + * Initialize the environment. + */ +DB_ENV * +db_init(home, prefix, cachesize, initializing, flags) + char *home, *prefix; + int cachesize, initializing, flags; +{ + DB_ENV *dbenv; + u_int32_t local_flags; + int ret; + + if ((ret = db_env_create(&dbenv, 0)) != 0) { + dbenv->err(dbenv, ret, "db_env_create"); + return (NULL); + } + dbenv->set_errfile(dbenv, stderr); + dbenv->set_errpfx(dbenv, prefix); +#ifdef HAVE_VXWORKS + if ((ret = dbenv->set_shm_key(dbenv, VXSHM_KEY)) != 0) { + dbenv->err(dbenv, ret, "set_shm_key"); + return (NULL); + } +#endif + (void)dbenv->set_cachesize(dbenv, 0, + cachesize == 0 ? 4 * 1024 * 1024 : (u_int32_t)cachesize, 0); + + local_flags = flags | DB_CREATE | (initializing ? DB_INIT_MPOOL : + DB_INIT_TXN | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL); + if ((ret = dbenv->open(dbenv, home, local_flags, 0)) != 0) { + dbenv->err(dbenv, ret, "DBENV->open: %s", home); + (void)dbenv->close(dbenv, 0); + return (NULL); + } + return (dbenv); +} + +/* + * Initialize the database to the specified number of accounts, branches, + * history records, and tellers. + */ +int +tp_populate(env, accounts, branches, history, tellers, verbose) + DB_ENV *env; + int accounts, branches, history, tellers, verbose; +{ + DB *dbp; + char dbname[100]; + u_int32_t balance, idnum, oflags; + u_int32_t end_anum, end_bnum, end_tnum; + u_int32_t start_anum, start_bnum, start_tnum; + int ret; + + idnum = BEGID; + balance = 500000; +#ifdef HAVE_VXWORKS + oflags = DB_CREATE; +#else + oflags = DB_CREATE | DB_TRUNCATE; +#endif + + if ((ret = db_create(&dbp, env, 0)) != 0) { + env->err(env, ret, "db_create"); + return (ERROR_RETURN); + } + (void)dbp->set_h_nelem(dbp, (u_int32_t)accounts); + + snprintf(dbname, sizeof(dbname), "account"); + if ((ret = dbp->open(dbp, dbname, NULL, + DB_HASH, oflags, 0644)) != 0) { + env->err(env, ret, "DB->open: account"); + return (ERROR_RETURN); + } + + start_anum = idnum; + populate(dbp, idnum, balance, accounts, "account"); + idnum += accounts; + end_anum = idnum - 1; + if ((ret = dbp->close(dbp, 0)) != 0) { + env->err(env, ret, "DB->close: account"); + return (ERROR_RETURN); + } + if (verbose) + printf("Populated accounts: %ld - %ld\n", + (long)start_anum, (long)end_anum); + + /* + * Since the number of branches is very small, we want to use very + * small pages and only 1 key per page, i.e., key-locking instead + * of page locking. + */ + if ((ret = db_create(&dbp, env, 0)) != 0) { + env->err(env, ret, "db_create"); + return (ERROR_RETURN); + } + (void)dbp->set_h_ffactor(dbp, 1); + (void)dbp->set_h_nelem(dbp, (u_int32_t)branches); + (void)dbp->set_pagesize(dbp, 512); + snprintf(dbname, sizeof(dbname), "branch"); + if ((ret = dbp->open(dbp, dbname, NULL, + DB_HASH, oflags, 0644)) != 0) { + env->err(env, ret, "DB->open: branch"); + return (ERROR_RETURN); + } + start_bnum = idnum; + populate(dbp, idnum, balance, branches, "branch"); + idnum += branches; + end_bnum = idnum - 1; + if ((ret = dbp->close(dbp, 0)) != 0) { + env->err(env, ret, "DB->close: branch"); + return (ERROR_RETURN); + } + if (verbose) + printf("Populated branches: %ld - %ld\n", + (long)start_bnum, (long)end_bnum); + + /* + * In the case of tellers, we also want small pages, but we'll let + * the fill factor dynamically adjust itself. + */ + if ((ret = db_create(&dbp, env, 0)) != 0) { + env->err(env, ret, "db_create"); + return (ERROR_RETURN); + } + (void)dbp->set_h_ffactor(dbp, 0); + (void)dbp->set_h_nelem(dbp, (u_int32_t)tellers); + (void)dbp->set_pagesize(dbp, 512); + snprintf(dbname, sizeof(dbname), "teller"); + if ((ret = dbp->open(dbp, dbname, NULL, + DB_HASH, oflags, 0644)) != 0) { + env->err(env, ret, "DB->open: teller"); + return (ERROR_RETURN); + } + + start_tnum = idnum; + populate(dbp, idnum, balance, tellers, "teller"); + idnum += tellers; + end_tnum = idnum - 1; + if ((ret = dbp->close(dbp, 0)) != 0) { + env->err(env, ret, "DB->close: teller"); + return (ERROR_RETURN); + } + if (verbose) + printf("Populated tellers: %ld - %ld\n", + (long)start_tnum, (long)end_tnum); + + if ((ret = db_create(&dbp, env, 0)) != 0) { + env->err(env, ret, "db_create"); + return (ERROR_RETURN); + } + (void)dbp->set_re_len(dbp, HISTORY_LEN); + snprintf(dbname, sizeof(dbname), "history"); + if ((ret = dbp->open(dbp, dbname, NULL, + DB_RECNO, oflags, 0644)) != 0) { + env->err(env, ret, "DB->open: history"); + return (ERROR_RETURN); + } + + hpopulate(dbp, history, accounts, branches, tellers); + if ((ret = dbp->close(dbp, 0)) != 0) { + env->err(env, ret, "DB->close: history"); + return (ERROR_RETURN); + } + return (0); +} + +int +populate(dbp, start_id, balance, nrecs, msg) + DB *dbp; + u_int32_t start_id, balance; + int nrecs; + char *msg; +{ + DBT kdbt, ddbt; + defrec drec; + int i, ret; + + kdbt.flags = 0; + kdbt.data = &drec.id; + kdbt.size = sizeof(u_int32_t); + ddbt.flags = 0; + ddbt.data = &drec; + ddbt.size = sizeof(drec); + memset(&drec.pad[0], 1, sizeof(drec.pad)); + + for (i = 0; i < nrecs; i++) { + drec.id = start_id + (u_int32_t)i; + drec.balance = balance; + if ((ret = + (dbp->put)(dbp, NULL, &kdbt, &ddbt, DB_NOOVERWRITE)) != 0) { + dbp->err(dbp, + ret, "Failure initializing %s file\n", msg); + return (ERROR_RETURN); + } + } + return (0); +} + +int +hpopulate(dbp, history, accounts, branches, tellers) + DB *dbp; + int history, accounts, branches, tellers; +{ + DBT kdbt, ddbt; + histrec hrec; + db_recno_t key; + int i, ret; + + memset(&kdbt, 0, sizeof(kdbt)); + memset(&ddbt, 0, sizeof(ddbt)); + ddbt.data = &hrec; + ddbt.size = sizeof(hrec); + kdbt.data = &key; + kdbt.size = sizeof(key); + memset(&hrec.pad[0], 1, sizeof(hrec.pad)); + hrec.amount = 10; + + for (i = 1; i <= history; i++) { + hrec.aid = random_id(ACCOUNT, accounts, branches, tellers); + hrec.bid = random_id(BRANCH, accounts, branches, tellers); + hrec.tid = random_id(TELLER, accounts, branches, tellers); + if ((ret = dbp->put(dbp, NULL, &kdbt, &ddbt, DB_APPEND)) != 0) { + dbp->err(dbp, ret, "dbp->put"); + return (ERROR_RETURN); + } + } + return (0); +} + +u_int32_t +random_int(lo, hi) + u_int32_t lo, hi; +{ + u_int32_t ret; + int t; + +#ifndef RAND_MAX +#define RAND_MAX 0x7fffffff +#endif + t = rand(); + ret = (u_int32_t)(((double)t / ((double)(RAND_MAX) + 1)) * + (hi - lo + 1)); + ret += lo; + return (ret); +} + +u_int32_t +random_id(type, accounts, branches, tellers) + FTYPE type; + int accounts, branches, tellers; +{ + u_int32_t min, max, num; + + max = min = BEGID; + num = accounts; + switch(type) { + case TELLER: + min += branches; + num = tellers; + /* FALLTHROUGH */ + case BRANCH: + if (type == BRANCH) + num = branches; + min += accounts; + /* FALLTHROUGH */ + case ACCOUNT: + max = min + num - 1; + } + return (random_int(min, max)); +} + +int +tp_run(dbenv, n, accounts, branches, tellers, verbose) + DB_ENV *dbenv; + int n, accounts, branches, tellers, verbose; +{ + DB *adb, *bdb, *hdb, *tdb; + char dbname[100]; + double gtps, itps; + int failed, ifailed, ret, txns; + time_t starttime, curtime, lasttime; +#ifndef DB_WIN32 + pid_t pid; + + pid = getpid(); +#else + int pid; + + pid = 0; +#endif + + /* + * Open the database files. + */ + if ((ret = db_create(&adb, dbenv, 0)) != 0) { + dbenv->err(dbenv, ret, "db_create"); + return (ERROR_RETURN); + } + snprintf(dbname, sizeof(dbname), "account"); + if ((ret = adb->open(adb, dbname, NULL, DB_UNKNOWN, 0, 0)) != 0) { + dbenv->err(dbenv, ret, "DB->open: account"); + return (ERROR_RETURN); + } + + if ((ret = db_create(&bdb, dbenv, 0)) != 0) { + dbenv->err(dbenv, ret, "db_create"); + return (ERROR_RETURN); + } + snprintf(dbname, sizeof(dbname), "branch"); + if ((ret = bdb->open(bdb, dbname, NULL, DB_UNKNOWN, 0, 0)) != 0) { + dbenv->err(dbenv, ret, "DB->open: branch"); + return (ERROR_RETURN); + } + + if ((ret = db_create(&tdb, dbenv, 0)) != 0) { + dbenv->err(dbenv, ret, "db_create"); + return (ERROR_RETURN); + } + snprintf(dbname, sizeof(dbname), "teller"); + if ((ret = tdb->open(tdb, dbname, NULL, DB_UNKNOWN, 0, 0)) != 0) { + dbenv->err(dbenv, ret, "DB->open: teller"); + return (ERROR_RETURN); + } + + if ((ret = db_create(&hdb, dbenv, 0)) != 0) { + dbenv->err(dbenv, ret, "db_create"); + return (ERROR_RETURN); + } + snprintf(dbname, sizeof(dbname), "history"); + if ((ret = hdb->open(hdb, dbname, NULL, DB_UNKNOWN, 0, 0)) != 0) { + dbenv->err(dbenv, ret, "DB->open: history"); + return (ERROR_RETURN); + } + + txns = failed = ifailed = 0; + starttime = time(NULL); + lasttime = starttime; + while (n-- > 0) { + txns++; + ret = tp_txn(dbenv, adb, bdb, tdb, hdb, + accounts, branches, tellers, verbose); + if (ret != 0) { + failed++; + ifailed++; + } + if (n % 5000 == 0) { + curtime = time(NULL); + gtps = (double)(txns - failed) / (curtime - starttime); + itps = (double)(5000 - ifailed) / (curtime - lasttime); + printf("[%d] %d txns %d failed ", (int)pid, + txns, failed); + printf("%6.2f TPS (gross) %6.2f TPS (interval)\n", + gtps, itps); + lasttime = curtime; + ifailed = 0; + } + } + + (void)adb->close(adb, 0); + (void)bdb->close(bdb, 0); + (void)tdb->close(tdb, 0); + (void)hdb->close(hdb, 0); + + printf("%ld transactions begun %ld failed\n", (long)txns, (long)failed); + return (0); +} + +/* + * XXX Figure out the appropriate way to pick out IDs. + */ +int +tp_txn(dbenv, adb, bdb, tdb, hdb, accounts, branches, tellers, verbose) + DB_ENV *dbenv; + DB *adb, *bdb, *tdb, *hdb; + int accounts, branches, tellers, verbose; +{ + DBC *acurs, *bcurs, *tcurs; + DBT d_dbt, d_histdbt, k_dbt, k_histdbt; + DB_TXN *t; + db_recno_t key; + defrec rec; + histrec hrec; + int account, branch, teller; + + t = NULL; + acurs = bcurs = tcurs = NULL; + + /* + * XXX We could move a lot of this into the driver to make this + * faster. + */ + account = random_id(ACCOUNT, accounts, branches, tellers); + branch = random_id(BRANCH, accounts, branches, tellers); + teller = random_id(TELLER, accounts, branches, tellers); + + memset(&d_histdbt, 0, sizeof(d_histdbt)); + + memset(&k_histdbt, 0, sizeof(k_histdbt)); + k_histdbt.data = &key; + k_histdbt.size = sizeof(key); + + memset(&k_dbt, 0, sizeof(k_dbt)); + k_dbt.size = sizeof(int); + + memset(&d_dbt, 0, sizeof(d_dbt)); + d_dbt.flags = DB_DBT_USERMEM; + d_dbt.data = &rec; + d_dbt.ulen = sizeof(rec); + + hrec.aid = account; + hrec.bid = branch; + hrec.tid = teller; + hrec.amount = 10; + /* Request 0 bytes since we're just positioning. */ + d_histdbt.flags = DB_DBT_PARTIAL; + + /* START TIMING */ + if (txn_begin(dbenv, NULL, &t, 0) != 0) + goto err; + + if (adb->cursor(adb, t, &acurs, 0) != 0 || + bdb->cursor(bdb, t, &bcurs, 0) != 0 || + tdb->cursor(tdb, t, &tcurs, 0) != 0) + goto err; + + /* Account record */ + k_dbt.data = &account; + if (acurs->c_get(acurs, &k_dbt, &d_dbt, DB_SET) != 0) + goto err; + rec.balance += 10; + if (acurs->c_put(acurs, &k_dbt, &d_dbt, DB_CURRENT) != 0) + goto err; + + /* Branch record */ + k_dbt.data = &branch; + if (bcurs->c_get(bcurs, &k_dbt, &d_dbt, DB_SET) != 0) + goto err; + rec.balance += 10; + if (bcurs->c_put(bcurs, &k_dbt, &d_dbt, DB_CURRENT) != 0) + goto err; + + /* Teller record */ + k_dbt.data = &teller; + if (tcurs->c_get(tcurs, &k_dbt, &d_dbt, DB_SET) != 0) + goto err; + rec.balance += 10; + if (tcurs->c_put(tcurs, &k_dbt, &d_dbt, DB_CURRENT) != 0) + goto err; + + /* History record */ + d_histdbt.flags = 0; + d_histdbt.data = &hrec; + d_histdbt.ulen = sizeof(hrec); + if (hdb->put(hdb, t, &k_histdbt, &d_histdbt, DB_APPEND) != 0) + goto err; + + if (acurs->c_close(acurs) != 0 || bcurs->c_close(bcurs) != 0 || + tcurs->c_close(tcurs) != 0) + goto err; + + if (txn_commit(t, 0) != 0) + goto err; + + /* END TIMING */ + return (0); + +err: if (acurs != NULL) + (void)acurs->c_close(acurs); + if (bcurs != NULL) + (void)bcurs->c_close(bcurs); + if (tcurs != NULL) + (void)tcurs->c_close(tcurs); + if (t != NULL) + (void)txn_abort(t); + + if (verbose) + printf("Transaction A=%ld B=%ld T=%ld failed\n", + (long)account, (long)branch, (long)teller); + return (-1); +} diff --git a/db/examples_c/ex_tpcb.h b/db/examples_c/ex_tpcb.h new file mode 100644 index 000000000..ef90bc532 --- /dev/null +++ b/db/examples_c/ex_tpcb.h @@ -0,0 +1,39 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: ex_tpcb.h,v 11.4 2000/05/17 19:21:02 bostic Exp $ + */ + +#ifndef _TPCB_H_ +#define _TPCB_H_ + +typedef enum { ACCOUNT, BRANCH, TELLER } FTYPE; + +#define TELLERS_PER_BRANCH 100 +#define ACCOUNTS_PER_TELLER 1000 + +#define ACCOUNTS 1000000 +#define BRANCHES 10 +#define TELLERS 1000 +#define HISTORY 1000000 +#define HISTORY_LEN 100 +#define RECLEN 100 +#define BEGID 1000000 + +typedef struct _defrec { + u_int32_t id; + u_int32_t balance; + u_int8_t pad[RECLEN - sizeof(u_int32_t) - sizeof(u_int32_t)]; +} defrec; + +typedef struct _histrec { + u_int32_t aid; + u_int32_t bid; + u_int32_t tid; + u_int32_t amount; + u_int8_t pad[RECLEN - 4 * sizeof(u_int32_t)]; +} histrec; +#endif /* _TPCB_H_ */ diff --git a/db/examples_cxx/AccessExample.cpp b/db/examples_cxx/AccessExample.cpp new file mode 100644 index 000000000..ae885aa83 --- /dev/null +++ b/db/examples_cxx/AccessExample.cpp @@ -0,0 +1,151 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: AccessExample.cpp,v 11.7 2000/12/06 18:58:23 bostic Exp $ + */ + +#include "db_config.h" + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#include +#ifndef _MSC_VER +#include +#endif +#endif + +#include +#include + +class AccessExample +{ +public: + AccessExample(); + void run(); + +private: + static const char FileName[]; + + // no need for copy and assignment + AccessExample(const AccessExample &); + void operator = (const AccessExample &); +}; + +static void usage(); // forward + +int main(int argc, char *argv[]) +{ + if (argc > 1) { + usage(); + } + + // Use a try block just to report any errors. + // An alternate approach to using exceptions is to + // use error models (see DbEnv::set_error_model()) so + // that error codes are returned for all Berkeley DB methods. + // + try { + AccessExample app; + app.run(); + return 0; + } + catch (DbException &dbe) { + cerr << "AccessExample: " << dbe.what() << "\n"; + return 1; + } +} + +static void usage() +{ + cerr << "usage: AccessExample\n"; + exit(1); +} + +const char AccessExample::FileName[] = "access.db"; + +AccessExample::AccessExample() +{ +} + +void AccessExample::run() +{ + // Remove the previous database. + (void)unlink(FileName); + + // Create the database object. + // There is no environment for this simple example. + Db db(0, 0); + + db.set_error_stream(&cerr); + db.set_errpfx("AccessExample"); + db.set_pagesize(1024); /* Page size: 1K. */ + db.set_cachesize(0, 32 * 1024, 0); + db.open(FileName, NULL, DB_BTREE, DB_CREATE, 0664); + + // + // Insert records into the database, where the key is the user + // input and the data is the user input in reverse order. + // + char buf[1024]; + char rbuf[1024]; + char *t; + char *p; + int ret; + int len; + + for (;;) { + cout << "input> "; + cout.flush(); + + cin.getline(buf, sizeof(buf)); + if (cin.eof()) + break; + + if ((len = strlen(buf)) <= 0) + continue; + for (t = rbuf, p = buf + (len - 1); p >= buf;) + *t++ = *p--; + *t++ = '\0'; + + Dbt key(buf, len + 1); + Dbt data(rbuf, len + 1); + + ret = db.put(0, &key, &data, DB_NOOVERWRITE); + if (ret == DB_KEYEXIST) { + cout << "Key " << buf << " already exists.\n"; + } + } + cout << "\n"; + + // We put a try block around this section of code + // to ensure that our database is properly closed + // in the event of an error. + // + try { + // Acquire a cursor for the table. + Dbc *dbcp; + db.cursor(NULL, &dbcp, 0); + + // Walk through the table, printing the key/data pairs. + Dbt key; + Dbt data; + while (dbcp->get(&key, &data, DB_NEXT) == 0) { + char *key_string = (char *)key.get_data(); + char *data_string = (char *)data.get_data(); + cout << key_string << " : " << data_string << "\n"; + } + dbcp->close(); + } + catch (DbException &dbe) { + cerr << "AccessExample: " << dbe.what() << "\n"; + } + + db.close(0); +} diff --git a/db/examples_cxx/BtRecExample.cpp b/db/examples_cxx/BtRecExample.cpp new file mode 100644 index 000000000..98d9626b9 --- /dev/null +++ b/db/examples_cxx/BtRecExample.cpp @@ -0,0 +1,247 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: BtRecExample.cpp,v 11.6 2000/02/19 20:57:59 bostic Exp $ + */ + +#include "db_config.h" + +#ifndef NO_SYSTEM_INCLUDES +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#include +#include + +#define DATABASE "access.db" +#define WORDLIST "../test/wordlist" + +void usage(); +extern "C" int getopt(int, char * const *, const char *); + +char *progname = "BtRecExample"; // Program name. + +class BtRecExample +{ +public: + BtRecExample(FILE *fp); + ~BtRecExample(); + void run(); + void stats(); + void show(char *msg, Dbt *key, Dbt *data); + +private: + Db *dbp; + Dbc *dbcp; +}; + +BtRecExample::BtRecExample(FILE *fp) +{ + char *p, *t, buf[1024], rbuf[1024]; + int ret; + + // Remove the previous database. + (void)unlink(DATABASE); + + dbp = new Db(NULL, 0); + + dbp->set_error_stream(&cerr); + dbp->set_errpfx(progname); + dbp->set_pagesize(1024); // 1K page sizes. + + dbp->set_flags(DB_RECNUM); // Record numbers. + dbp->open(DATABASE, NULL, DB_BTREE, DB_CREATE, 0664); + + // + // Insert records into the database, where the key is the word + // preceded by its record number, and the data is the same, but + // in reverse order. + // + + for (int cnt = 1; cnt <= 1000; ++cnt) { + (void)sprintf(buf, "%04d_", cnt); + if (fgets(buf + 4, sizeof(buf) - 4, fp) == NULL) + break; + u_int32_t len = strlen(buf); + buf[len - 1] = '\0'; + for (t = rbuf, p = buf + (len - 2); p >= buf;) + *t++ = *p--; + *t++ = '\0'; + + // As a convenience for printing, we include the null terminator + // in the stored data. + // + Dbt key(buf, len); + Dbt data(rbuf, len); + + if ((ret = dbp->put(NULL, &key, &data, DB_NOOVERWRITE)) != 0) { + dbp->err(ret, "Db::put"); + if (ret != DB_KEYEXIST) + throw DbException(ret); + } + } +} + +BtRecExample::~BtRecExample() +{ + if (dbcp != 0) + dbcp->close(); + dbp->close(0); + delete dbp; +} + +// +// Print out the number of records in the database. +// +void BtRecExample::stats() +{ + DB_BTREE_STAT *statp; + + dbp->stat(&statp, NULL, 0); + cout << progname << ": database contains " + << (u_long)statp->bt_ndata << " records\n"; + + // Note: must use free, not delete. + // This struct is allocated by C. + // + free(statp); +} + +void BtRecExample::run() +{ + db_recno_t recno; + int ret; + char buf[1024]; + + // Acquire a cursor for the database. + dbp->cursor(NULL, &dbcp, 0); + + // + // Prompt the user for a record number, then retrieve and display + // that record. + // + for (;;) { + // Get a record number. + cout << "recno #> "; + cout.flush(); + if (fgets(buf, sizeof(buf), stdin) == NULL) + break; + recno = atoi(buf); + + // + // Start with a fresh key each time, + // the dbp->get() routine returns + // the key and data pair, not just the key! + // + Dbt key(&recno, sizeof(recno)); + Dbt data; + + if ((ret = dbcp->get(&key, &data, DB_SET_RECNO)) != 0) { + dbp->err(ret, "DBcursor->get"); + throw DbException(ret); + } + + // Display the key and data. + show("k/d\t", &key, &data); + + // Move the cursor a record forward. + if ((ret = dbcp->get(&key, &data, DB_NEXT)) != 0) { + dbp->err(ret, "DBcursor->get"); + throw DbException(ret); + } + + // Display the key and data. + show("next\t", &key, &data); + + // + // Retrieve the record number for the following record into + // local memory. + // + data.set_data(&recno); + data.set_size(sizeof(recno)); + data.set_ulen(sizeof(recno)); + data.set_flags(data.get_flags() | DB_DBT_USERMEM); + + if ((ret = dbcp->get(&key, &data, DB_GET_RECNO)) != 0) { + if (ret != DB_NOTFOUND && ret != DB_KEYEMPTY) { + dbp->err(ret, "DBcursor->get"); + throw DbException(ret); + } + } + else { + cout << "retrieved recno: " << (u_long)recno << "\n"; + } + } + + dbcp->close(); + dbcp = NULL; +} + +// +// show -- +// Display a key/data pair. +// +void BtRecExample::show(char *msg, Dbt *key, Dbt *data) +{ + cout << msg << (char *)key->get_data() + << " : " << (char *)data->get_data() << "\n"; +} + +int +main(int argc, char *argv[]) +{ + extern char *optarg; + extern int optind; + FILE *fp; + int ch; + + while ((ch = getopt(argc, argv, "")) != EOF) + switch (ch) { + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + // Open the word database. + if ((fp = fopen(WORDLIST, "r")) == NULL) { + fprintf(stderr, "%s: open %s: %s\n", + progname, WORDLIST, db_strerror(errno)); + exit (1); + } + + try { + BtRecExample app(fp); + + // Close the word database. + (void)fclose(fp); + fp = NULL; + + app.stats(); + app.run(); + } + catch (DbException &dbe) { + cerr << "Exception: " << dbe.what() << "\n"; + return dbe.get_errno(); + } + + return (0); +} + +void +usage() +{ + (void)fprintf(stderr, "usage: %s\n", progname); + exit(1); +} diff --git a/db/examples_cxx/EnvExample.cpp b/db/examples_cxx/EnvExample.cpp new file mode 100644 index 000000000..bef1f3d1a --- /dev/null +++ b/db/examples_cxx/EnvExample.cpp @@ -0,0 +1,122 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: EnvExample.cpp,v 11.12 2000/10/27 20:32:00 dda Exp $ + */ + +#include "db_config.h" + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#include +#include +#include +#include +#endif + +#include + +#ifdef macintosh +#define DATABASE_HOME ":database" +#define CONFIG_DATA_DIR ":database" +#else +#ifdef DB_WIN32 +#define DATABASE_HOME "\\tmp\\database" +#define CONFIG_DATA_DIR "\\database\\files" +#else +#define DATABASE_HOME "/tmp/database" +#define CONFIG_DATA_DIR "/database/files" +#endif +#endif + +void db_setup(char *, char *, ostream&); +void db_teardown(char *, char *, ostream&); + +char *progname = "EnvExample"; /* Program name. */ + +// +// An example of a program creating/configuring a Berkeley DB environment. +// +int +main(int, char **) +{ + // + // Note: it may be easiest to put all Berkeley DB operations in a + // try block, as seen here. Alternatively, you can change the + // ErrorModel in the DbEnv so that exceptions are never thrown + // and check error returns from all methods. + // + try { + char *data_dir, *home; + + // + // All of the shared database files live in /home/database, + // but data files live in /database. + // + home = DATABASE_HOME; + data_dir = CONFIG_DATA_DIR; + + cout << "Setup env\n"; + db_setup(DATABASE_HOME, data_dir, cerr); + + cout << "Teardown env\n"; + db_teardown(DATABASE_HOME, data_dir, cerr); + return 0; + } + catch (DbException &dbe) { + cerr << "AccessExample: " << dbe.what() << "\n"; + return 1; + } +} + +// Note that any of the db calls can throw DbException +void +db_setup(char *home, char *data_dir, ostream& err_stream) +{ + // + // Create an environment object and initialize it for error + // reporting. + // + DbEnv *dbenv = new DbEnv(0); + dbenv->set_error_stream(&err_stream); + dbenv->set_errpfx(progname); + + // + // We want to specify the shared memory buffer pool cachesize, + // but everything else is the default. + // + dbenv->set_cachesize(0, 64 * 1024, 0); + + // Databases are in a subdirectory. + (void)dbenv->set_data_dir(data_dir); + + // Open the environment with full transactional support. + dbenv->open(DATABASE_HOME, + DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN, 0); + + // Do something interesting... + + // Close the handle. + dbenv->close(0); +} + +void +db_teardown(char *home, char *data_dir, ostream& err_stream) +{ + // Remove the shared database regions. + DbEnv *dbenv = new DbEnv(0); + + dbenv->set_error_stream(&err_stream); + dbenv->set_errpfx(progname); + + (void)dbenv->set_data_dir(data_dir); + dbenv->remove(home, 0); + delete dbenv; +} diff --git a/db/examples_cxx/LockExample.cpp b/db/examples_cxx/LockExample.cpp new file mode 100644 index 000000000..cfab28680 --- /dev/null +++ b/db/examples_cxx/LockExample.cpp @@ -0,0 +1,236 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: LockExample.cpp,v 11.8 2001/01/04 14:23:30 dda Exp $ + */ + +#include "db_config.h" + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#include +#include +#endif + +#include + +char *progname = "LockExample"; // Program name. + +// +// An example of a program using DBLock and related classes. +// +class LockExample : public DbEnv +{ +public: + void run(); + + LockExample(const char *home, u_int32_t maxlocks, int do_unlink); + +private: + static const char FileName[]; + + // no need for copy and assignment + LockExample(const LockExample &); + void operator = (const LockExample &); +}; + +static void usage(); // forward + +int +main(int argc, char *argv[]) +{ + const char *home; + int do_unlink; + u_int32_t maxlocks; + int i; + + home = "TESTDIR"; + maxlocks = 0; + do_unlink = 0; + for (int argnum = 1; argnum < argc; ++argnum) { + if (strcmp(argv[argnum], "-h") == 0) { + if (++argnum >= argc) + usage(); + home = argv[argnum]; + } + else if (strcmp(argv[argnum], "-m") == 0) { + if (++argnum >= argc) + usage(); + if ((i = atoi(argv[argnum])) <= 0) + usage(); + maxlocks = (u_int32_t)i; /* XXX: possible overflow. */ + } + else if (strcmp(argv[argnum], "-u") == 0) { + do_unlink = 1; + } + else { + usage(); + } + } + + try { + if (do_unlink) { + // Create an environment that immediately + // removes all files. + LockExample tmp(home, maxlocks, do_unlink); + } + + LockExample app(home, maxlocks, do_unlink); + app.run(); + app.close(0); + return 0; + } + catch (DbException &dbe) { + cerr << "LockExample: " << dbe.what() << "\n"; + return 1; + } +} + +LockExample::LockExample(const char *home, u_int32_t maxlocks, int do_unlink) +: DbEnv(0) +{ + int ret; + + if (do_unlink) { + if ((ret = remove(home, DB_FORCE)) != 0) { + cerr << progname << ": DbEnv::remove: " + << strerror(errno) << "\n"; + exit (1); + } + } + else { + set_error_stream(&cerr); + set_errpfx("LockExample"); + if (maxlocks != 0) + set_lk_max_locks(maxlocks); + open(home, DB_CREATE | DB_INIT_LOCK, 0); + } +} + +void LockExample::run() +{ + long held; + u_int32_t len, locker; + int did_get, ret; + DbLock *locks = 0; + int lockcount = 0; + char objbuf[1024]; + int lockid = 0; + + // + // Accept lock requests. + // + lock_id(&locker); + for (held = 0;;) { + cout << "Operation get/release [get]> "; + cout.flush(); + + char opbuf[16]; + cin.getline(opbuf, sizeof(opbuf)); + if (cin.eof()) + break; + if ((len = strlen(opbuf)) <= 1 || strcmp(opbuf, "get") == 0) { + // Acquire a lock. + cout << "input object (text string) to lock> "; + cout.flush(); + cin.getline(objbuf, sizeof(objbuf)); + if (cin.eof()) + break; + if ((len = strlen(objbuf)) <= 0) + continue; + + char lockbuf[16]; + do { + cout << "lock type read/write [read]> "; + cout.flush(); + cin.getline(lockbuf, sizeof(lockbuf)); + if (cin.eof()) + break; + len = strlen(lockbuf); + } while (len >= 1 && + strcmp(lockbuf, "read") != 0 && + strcmp(lockbuf, "write") != 0); + + db_lockmode_t lock_type; + if (len <= 1 || strcmp(lockbuf, "read") == 0) + lock_type = DB_LOCK_READ; + else + lock_type = DB_LOCK_WRITE; + + Dbt dbt(objbuf, strlen(objbuf)); + + DbLock lock; + ret = lock_get(locker, DB_LOCK_NOWAIT, &dbt, + lock_type, &lock); + did_get = 1; + lockid = lockcount++; + if (locks == NULL) { + locks = new DbLock[1]; + } + else { + DbLock *newlocks = new DbLock[lockcount]; + for (int lockno = 0; lockno < lockid; lockno++) { + newlocks[lockno] = locks[lockno]; + } + delete locks; + locks = newlocks; + } + locks[lockid] = lock; + } else { + // Release a lock. + do { + cout << "input lock to release> "; + cout.flush(); + cin.getline(objbuf, sizeof(objbuf)); + if (cin.eof()) + break; + } while ((len = strlen(objbuf)) <= 0); + lockid = strtol(objbuf, NULL, 16); + if (lockid < 0 || lockid >= lockcount) { + cout << "Lock #" << lockid << " out of range\n"; + continue; + } + DbLock lock = locks[lockid]; + ret = lock.put(this); + did_get = 0; + } + + switch (ret) { + case 0: + cout << "Lock #" << lockid << " " + << (did_get ? "granted" : "released") + << "\n"; + held += did_get ? 1 : -1; + break; + case DB_LOCK_NOTGRANTED: + cout << "Lock not granted\n"; + break; + case DB_LOCK_DEADLOCK: + cerr << "LockExample: lock_" + << (did_get ? "get" : "put") + << ": " << "returned DEADLOCK"; + break; + default: + cerr << "LockExample: lock_get: %s", + strerror(errno); + } + } + cout << "\n"; + cout << "Closing lock region " << held << " locks held\n"; + if (locks != 0) + delete locks; +} + +static void +usage() +{ + cerr << "usage: LockExample [-u] [-h home] [-m maxlocks]\n"; + exit(1); +} diff --git a/db/examples_cxx/MpoolExample.cpp b/db/examples_cxx/MpoolExample.cpp new file mode 100644 index 000000000..cf0f5f7e6 --- /dev/null +++ b/db/examples_cxx/MpoolExample.cpp @@ -0,0 +1,210 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: MpoolExample.cpp,v 11.9 2000/10/27 20:32:01 dda Exp $ + */ + +#include "db_config.h" + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#include +#include +#include +#include +#endif + +#include + +#define MPOOL "mpool" + +void init(char *, int, int); +void run(DB_ENV *, int, int, int); + +static void usage(); + +char *progname = "MpoolExample"; // Program name. + +class MpoolExample : public DbEnv +{ +public: + MpoolExample(); + void initdb(const char *home, int cachesize); + void run(int hits, int pagesize, int npages); + +private: + static const char FileName[]; + + // no need for copy and assignment + MpoolExample(const MpoolExample &); + void operator = (const MpoolExample &); +}; + +int main(int argc, char *argv[]) +{ + int cachesize = 20 * 1024; + int hits = 1000; + int npages = 50; + int pagesize = 1024; + + for (int i = 1; i < argc; ++i) { + if (strcmp(argv[i], "-c") == 0) { + if ((cachesize = atoi(argv[++i])) < 20 * 1024) + usage(); + } + else if (strcmp(argv[i], "-h") == 0) { + if ((hits = atoi(argv[++i])) <= 0) + usage(); + } + else if (strcmp(argv[i], "-n") == 0) { + if ((npages = atoi(argv[++i])) <= 0) + usage(); + } + else if (strcmp(argv[i], "-p") == 0) { + if ((pagesize = atoi(argv[++i])) <= 0) + usage(); + } + else { + usage(); + } + } + + // Initialize the file. + init(MPOOL, pagesize, npages); + + try { + MpoolExample app; + + cout << progname + << ": cachesize: " << cachesize + << "; pagesize: " << pagesize + << "; N pages: " << npages << "\n"; + + app.initdb(NULL, cachesize); + app.run(hits, pagesize, npages); + cout << "MpoolExample: completed\n"; + return 0; + } + catch (DbException &dbe) { + cerr << "MpoolExample: " << dbe.what() << "\n"; + return 1; + } +} + +// +// init -- +// Create a backing file. +// +void +init(char *file, int pagesize, int npages) +{ + // + // Create a file with the right number of pages, and store a page + // number on each page. + // + int fd; + int flags = O_CREAT | O_RDWR | O_TRUNC; +#ifdef DB_WIN32 + flags |= O_BINARY; +#endif + if ((fd = open(file, flags, 0666)) < 0) { + cerr << "MpoolExample: " << file << ": " << strerror(errno) << "\n"; + exit(1); + } + char *p = new char[pagesize]; + memset(p, 0, pagesize); + + // The pages are numbered from 0. + for (int cnt = 0; cnt <= npages; ++cnt) { + *(db_pgno_t *)p = cnt; + if (write(fd, p, pagesize) != pagesize) { + cerr << "MpoolExample: " << file + << ": " << strerror(errno) << "\n"; + exit(1); + } + } + delete [] p; +} + +static void +usage() +{ + cerr << "usage: MpoolExample [-c cachesize] " + << "[-h hits] [-n npages] [-p pagesize]\n"; + exit(1); +} + +// Note: by using DB_CXX_NO_EXCEPTIONS, we get explicit error returns +// from various methods rather than exceptions so we can report more +// information with each error. +// +MpoolExample::MpoolExample() +: DbEnv(DB_CXX_NO_EXCEPTIONS) +{ +} + +void MpoolExample::initdb(const char *home, int cachesize) +{ + set_error_stream(&cerr); + set_errpfx("MpoolExample"); + set_cachesize(0, cachesize, 0); + + open(home, DB_CREATE | DB_INIT_MPOOL, 0); +} + +// +// run -- +// Get a set of pages. +// +void +MpoolExample::run(int hits, int pagesize, int npages) +{ + db_pgno_t pageno; + int cnt; + void *p; + + // Open the file in the pool. + DbMpoolFile *dbmfp; + + DbMpoolFile::open(this, MPOOL, 0, 0, pagesize, NULL, &dbmfp); + + cout << "retrieve " << hits << " random pages... "; + + srand((unsigned int)time(NULL)); + for (cnt = 0; cnt < hits; ++cnt) { + pageno = (rand() % npages) + 1; + if ((errno = dbmfp->get(&pageno, 0, &p)) != 0) { + cerr << "MpoolExample: unable to retrieve page " + << (unsigned long)pageno << ": " + << strerror(errno) << "\n"; + exit(1); + } + if (*(db_pgno_t *)p != pageno) { + cerr << "MpoolExample: wrong page retrieved (" + << (unsigned long)pageno << " != " + << *(int *)p << ")\n"; + exit(1); + } + if ((errno = dbmfp->put(p, 0)) != 0) { + cerr << "MpoolExample: unable to return page " + << (unsigned long)pageno << ": " + << strerror(errno) << "\n"; + exit(1); + } + } + + cout << "successful.\n"; + + // Close the pool. + if ((errno = close(0)) != 0) { + cerr << "MpoolExample: " << strerror(errno) << "\n"; + exit(1); + } +} diff --git a/db/examples_cxx/TpcbExample.cpp b/db/examples_cxx/TpcbExample.cpp new file mode 100644 index 000000000..f4ca72df8 --- /dev/null +++ b/db/examples_cxx/TpcbExample.cpp @@ -0,0 +1,666 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: TpcbExample.cpp,v 11.14 2000/10/27 20:32:01 dda Exp $ + */ + +#include "db_config.h" + +#ifndef NO_SYSTEM_INCLUDES +#include + +#if TIME_WITH_SYS_TIME +#include +#include +#else +#if HAVE_SYS_TIME_H +#include +#else +#include +#endif +#endif + +#include +#include +#include +#include +#endif + +#ifdef DB_WIN32 +#include +#include +#endif + +#include +#include +#include + +typedef enum { ACCOUNT, BRANCH, TELLER } FTYPE; + +void errExit(int err, const char *); // show err as errno and exit + +void invarg(int, char *); +u_int32_t random_id(FTYPE, u_int32_t, u_int32_t, u_int32_t); +u_int32_t random_int(u_int32_t, u_int32_t); +static void usage(void); + +int verbose; +char *progname = "TpcbExample"; // Program name. + +class TpcbExample : public DbEnv +{ +public: + void populate(int, int, int, int); + void run(int, int, int, int); + int txn(Db *, Db *, Db *, Db *, + int, int, int); + void populateHistory(Db *, int, u_int32_t, u_int32_t, u_int32_t); + void populateTable(Db *, u_int32_t, u_int32_t, int, char *); + + // Note: the constructor creates a DbEnv(), which is + // not fully initialized until the DbEnv::open() method + // is called. + // + TpcbExample(const char *home, int cachesize, + int initializing, int flags); + +private: + static const char FileName[]; + + // no need for copy and assignment + TpcbExample(const TpcbExample &); + void operator = (const TpcbExample &); +}; + +// +// This program implements a basic TPC/B driver program. To create the +// TPC/B database, run with the -i (init) flag. The number of records +// with which to populate the account, history, branch, and teller tables +// is specified by the a, s, b, and t flags respectively. To run a TPC/B +// test, use the n flag to indicate a number of transactions to run (note +// that you can run many of these processes in parallel to simulate a +// multiuser test run). +// +#define TELLERS_PER_BRANCH 100 +#define ACCOUNTS_PER_TELLER 1000 +#define HISTORY_PER_BRANCH 2592000 + +/* + * The default configuration that adheres to TPCB scaling rules requires + * nearly 3 GB of space. To avoid requiring that much space for testing, + * we set the parameters much lower. If you want to run a valid 10 TPS + * configuration, define VALID_SCALING. + */ +#ifdef VALID_SCALING +#define ACCOUNTS 1000000 +#define BRANCHES 10 +#define TELLERS 100 +#define HISTORY 25920000 +#endif + +#ifdef TINY +#define ACCOUNTS 1000 +#define BRANCHES 10 +#define TELLERS 100 +#define HISTORY 10000 +#endif + +#if !defined(VALID_SCALING) && !defined(TINY) +#define ACCOUNTS 100000 +#define BRANCHES 10 +#define TELLERS 100 +#define HISTORY 259200 +#endif + +#define HISTORY_LEN 100 +#define RECLEN 100 +#define BEGID 1000000 + +struct Defrec { + u_int32_t id; + u_int32_t balance; + u_int8_t pad[RECLEN - sizeof(u_int32_t) - sizeof(u_int32_t)]; +}; + +struct Histrec { + u_int32_t aid; + u_int32_t bid; + u_int32_t tid; + u_int32_t amount; + u_int8_t pad[RECLEN - 4 * sizeof(u_int32_t)]; +}; + +int +main(int argc, char *argv[]) +{ + unsigned long seed; + int accounts, branches, tellers, history; + int iflag, mpool, ntxns, txn_no_sync; + char *home, *endarg; + + home = "TESTDIR"; + accounts = branches = history = tellers = 0; + txn_no_sync = 0; + mpool = ntxns = 0; + verbose = 0; + iflag = 0; + seed = (unsigned long)getpid(); + + for (int i = 1; i < argc; ++i) { + + if (strcmp(argv[i], "-a") == 0) { + // Number of account records + if ((accounts = atoi(argv[++i])) <= 0) + invarg('a', argv[i]); + } + else if (strcmp(argv[i], "-b") == 0) { + // Number of branch records + if ((branches = atoi(argv[++i])) <= 0) + invarg('b', argv[i]); + } + else if (strcmp(argv[i], "-c") == 0) { + // Cachesize in bytes + if ((mpool = atoi(argv[++i])) <= 0) + invarg('c', argv[i]); + } + else if (strcmp(argv[i], "-f") == 0) { + // Fast mode: no txn sync. + txn_no_sync = 1; + } + else if (strcmp(argv[i], "-h") == 0) { + // DB home. + home = argv[++i]; + } + else if (strcmp(argv[i], "-i") == 0) { + // Initialize the test. + iflag = 1; + } + else if (strcmp(argv[i], "-n") == 0) { + // Number of transactions + if ((ntxns = atoi(argv[++i])) <= 0) + invarg('n', argv[i]); + } + else if (strcmp(argv[i], "-S") == 0) { + // Random number seed. + seed = strtoul(argv[++i], &endarg, 0); + if (*endarg != '\0') + invarg('S', argv[i]); + } + else if (strcmp(argv[i], "-s") == 0) { + // Number of history records + if ((history = atoi(argv[++i])) <= 0) + invarg('s', argv[i]); + } + else if (strcmp(argv[i], "-t") == 0) { + // Number of teller records + if ((tellers = atoi(argv[++i])) <= 0) + invarg('t', argv[i]); + } + else if (strcmp(argv[i], "-v") == 0) { + // Verbose option. + verbose = 1; + } + else { + usage(); + } + } + + srand((unsigned int)seed); + + accounts = accounts == 0 ? ACCOUNTS : accounts; + branches = branches == 0 ? BRANCHES : branches; + tellers = tellers == 0 ? TELLERS : tellers; + history = history == 0 ? HISTORY : history; + + if (verbose) + cout << (long)accounts << " Accounts " + << (long)branches << " Branches " + << (long)tellers << " Tellers " + << (long)history << " History\n"; + + try { + // Initialize the database environment. + // Must be done in within a try block, unless you + // change the error model in the environment options. + // + TpcbExample app(home, mpool, iflag, txn_no_sync ? DB_TXN_NOSYNC : 0); + + if (iflag) { + if (ntxns != 0) + usage(); + app.populate(accounts, branches, history, tellers); + } + else { + if (ntxns == 0) + usage(); + app.run(ntxns, accounts, branches, tellers); + } + + app.close(0); + return 0; + } + catch (DbException &dbe) { + cerr << "TpcbExample: " << dbe.what() << "\n"; + return 1; + } +} + +void +invarg(int arg, char *str) +{ + cerr << "TpcbExample: invalid argument for -" + << (char)arg << ": " << str << "\n"; + exit(1); +} + +static void +usage() +{ + cerr << "usage: TpcbExample [-fiv] [-a accounts] [-b branches]\n" + << " [-c cachesize] [-h home] [-n transactions ]\n" + << " [-S seed] [-s history] [-t tellers]\n"; + exit(1); +} + +TpcbExample::TpcbExample(const char *home, int cachesize, + int initializing, int flags) +: DbEnv(0) +{ + u_int32_t local_flags; + + set_error_stream(&cerr); + set_errpfx("TpcbExample"); + (void)set_cachesize(0, cachesize == 0 ? + 4 * 1024 * 1024 : (u_int32_t)cachesize, 0); + + local_flags = flags | DB_CREATE | DB_INIT_MPOOL; + if (!initializing) + local_flags |= DB_INIT_TXN | DB_INIT_LOCK | DB_INIT_LOG; + open(home, local_flags, 0); +} + +// +// Initialize the database to the specified number of accounts, branches, +// history records, and tellers. +// +void +TpcbExample::populate(int accounts, int branches, int history, int tellers) +{ + Db *dbp; + + int err; + u_int32_t balance, idnum; + u_int32_t end_anum, end_bnum, end_tnum; + u_int32_t start_anum, start_bnum, start_tnum; + + idnum = BEGID; + balance = 500000; + + dbp = new Db(this, 0); + dbp->set_h_nelem((unsigned int)accounts); + + if ((err = dbp->open("account", NULL, DB_HASH, + DB_CREATE | DB_TRUNCATE, 0644)) != 0) { + errExit(err, "Open of account file failed"); + } + + start_anum = idnum; + populateTable(dbp, idnum, balance, accounts, "account"); + idnum += accounts; + end_anum = idnum - 1; + if ((err = dbp->close(0)) != 0) { + errExit(err, "Account file close failed"); + } + delete dbp; + if (verbose) + cout << "Populated accounts: " + << (long)start_anum << " - " << (long)end_anum << "\n"; + + dbp = new Db(this, 0); + // + // Since the number of branches is very small, we want to use very + // small pages and only 1 key per page. This is the poor-man's way + // of getting key locking instead of page locking. + // + dbp->set_h_ffactor(1); + dbp->set_h_nelem((unsigned int)branches); + dbp->set_pagesize(512); + + if ((err = dbp->open("branch", NULL, DB_HASH, + DB_CREATE | DB_TRUNCATE, 0644)) != 0) { + errExit(err, "Branch file create failed"); + } + start_bnum = idnum; + populateTable(dbp, idnum, balance, branches, "branch"); + idnum += branches; + end_bnum = idnum - 1; + if ((err = dbp->close(0)) != 0) { + errExit(err, "Close of branch file failed"); + } + delete dbp; + + if (verbose) + cout << "Populated branches: " + << (long)start_bnum << " - " << (long)end_bnum << "\n"; + + dbp = new Db(this, 0); + // + // In the case of tellers, we also want small pages, but we'll let + // the fill factor dynamically adjust itself. + // + dbp->set_h_ffactor(0); + dbp->set_h_nelem((unsigned int)tellers); + dbp->set_pagesize(512); + + if ((err = dbp->open("teller", NULL, DB_HASH, + DB_CREATE | DB_TRUNCATE, 0644)) != 0) { + errExit(err, "Teller file create failed"); + } + + start_tnum = idnum; + populateTable(dbp, idnum, balance, tellers, "teller"); + idnum += tellers; + end_tnum = idnum - 1; + if ((err = dbp->close(0)) != 0) { + errExit(err, "Close of teller file failed"); + } + delete dbp; + if (verbose) + cout << "Populated tellers: " + << (long)start_tnum << " - " << (long)end_tnum << "\n"; + + dbp = new Db(this, 0); + dbp->set_re_len(HISTORY_LEN); + if ((err = dbp->open("history", NULL, DB_RECNO, + DB_CREATE | DB_TRUNCATE, 0644)) != 0) { + errExit(err, "Create of history file failed"); + } + + populateHistory(dbp, history, accounts, branches, tellers); + if ((err = dbp->close(0)) != 0) { + errExit(err, "Close of history file failed"); + } + delete dbp; +} + +void +TpcbExample::populateTable(Db *dbp, + u_int32_t start_id, u_int32_t balance, + int nrecs, char *msg) +{ + Defrec drec; + memset(&drec.pad[0], 1, sizeof(drec.pad)); + + Dbt kdbt(&drec.id, sizeof(u_int32_t)); + Dbt ddbt(&drec, sizeof(drec)); + + for (int i = 0; i < nrecs; i++) { + drec.id = start_id + (u_int32_t)i; + drec.balance = balance; + int err; + if ((err = + dbp->put(NULL, &kdbt, &ddbt, DB_NOOVERWRITE)) != 0) { + cerr << "Failure initializing " << msg << " file: " + << strerror(err) << "\n"; + exit(1); + } + } +} + +void +TpcbExample::populateHistory(Db *dbp, int nrecs, + u_int32_t accounts, u_int32_t branches, u_int32_t tellers) +{ + Histrec hrec; + memset(&hrec.pad[0], 1, sizeof(hrec.pad)); + hrec.amount = 10; + db_recno_t key; + + Dbt kdbt(&key, sizeof(u_int32_t)); + Dbt ddbt(&hrec, sizeof(hrec)); + + for (int i = 1; i <= nrecs; i++) { + hrec.aid = random_id(ACCOUNT, accounts, branches, tellers); + hrec.bid = random_id(BRANCH, accounts, branches, tellers); + hrec.tid = random_id(TELLER, accounts, branches, tellers); + + int err; + key = (db_recno_t)i; + if ((err = dbp->put(NULL, &kdbt, &ddbt, DB_APPEND)) != 0) { + errExit(err, "Failure initializing history file"); + } + } +} + +u_int32_t +random_int(u_int32_t lo, u_int32_t hi) +{ + u_int32_t ret; + int t; + + t = rand(); + ret = (u_int32_t)(((double)t / ((double)(RAND_MAX) + 1)) * + (hi - lo + 1)); + ret += lo; + return (ret); +} + +u_int32_t +random_id(FTYPE type, u_int32_t accounts, u_int32_t branches, u_int32_t tellers) +{ + u_int32_t min, max, num; + + max = min = BEGID; + num = accounts; + switch(type) { + case TELLER: + min += branches; + num = tellers; + // Fallthrough + case BRANCH: + if (type == BRANCH) + num = branches; + min += accounts; + // Fallthrough + case ACCOUNT: + max = min + num - 1; + } + return (random_int(min, max)); +} + +void +TpcbExample::run(int n, int accounts, int branches, int tellers) +{ + Db *adb, *bdb, *hdb, *tdb; + double gtps, itps; + int failed, ifailed, ret, txns; + time_t starttime, curtime, lasttime; +#ifndef DB_WIN32 + pid_t pid; + + pid = getpid(); +#else + int pid; + + pid = 0; +#endif + + // + // Open the database files. + // + + int err; + adb = new Db(this, 0); + if ((err = adb->open("account", NULL, DB_UNKNOWN, 0, 0)) != 0) + errExit(err, "Open of account file failed"); + + bdb = new Db(this, 0); + if ((err = bdb->open("branch", NULL, DB_UNKNOWN, 0, 0)) != 0) + errExit(err, "Open of branch file failed"); + + tdb = new Db(this, 0); + if ((err = tdb->open("teller", NULL, DB_UNKNOWN, 0, 0)) != 0) + errExit(err, "Open of teller file failed"); + + hdb = new Db(this, 0); + if ((err = hdb->open("history", NULL, DB_UNKNOWN, 0, 0)) != 0) + errExit(err, "Open of history file failed"); + + txns = failed = ifailed = 0; + starttime = time(NULL); + lasttime = starttime; + while (n-- > 0) { + txns++; + ret = txn(adb, bdb, tdb, hdb, accounts, branches, tellers); + if (ret != 0) { + failed++; + ifailed++; + } + if (n % 5000 == 0) { + curtime = time(NULL); + gtps = (double)(txns - failed) / (curtime - starttime); + itps = (double)(5000 - ifailed) / (curtime - lasttime); + + // We use printf because it provides much simpler + // formatting than iostreams. + // + printf("[%d] %d txns %d failed ", (int)pid, + txns, failed); + printf("%6.2f TPS (gross) %6.2f TPS (interval)\n", + gtps, itps); + lasttime = curtime; + ifailed = 0; + } + } + + (void)adb->close(0); + (void)bdb->close(0); + (void)tdb->close(0); + (void)hdb->close(0); + + cout << (long)txns << " transactions begun " + << (long)failed << " failed\n"; +} + +// +// XXX Figure out the appropriate way to pick out IDs. +// +int +TpcbExample::txn(Db *adb, Db *bdb, Db *tdb, Db *hdb, + int accounts, int branches, int tellers) +{ + Dbc *acurs = NULL; + Dbc *bcurs = NULL; + Dbc *tcurs = NULL; + DbTxn *t = NULL; + + db_recno_t key; + Defrec rec; + Histrec hrec; + int account, branch, teller; + + Dbt d_dbt; + Dbt d_histdbt; + Dbt k_dbt; + Dbt k_histdbt(&key, sizeof(key)); + + // + // XXX We could move a lot of this into the driver to make this + // faster. + // + account = random_id(ACCOUNT, accounts, branches, tellers); + branch = random_id(BRANCH, accounts, branches, tellers); + teller = random_id(TELLER, accounts, branches, tellers); + + k_dbt.set_size(sizeof(int)); + + d_dbt.set_flags(DB_DBT_USERMEM); + d_dbt.set_data(&rec); + d_dbt.set_ulen(sizeof(rec)); + + hrec.aid = account; + hrec.bid = branch; + hrec.tid = teller; + hrec.amount = 10; + // Request 0 bytes since we're just positioning. + d_histdbt.set_flags(DB_DBT_PARTIAL); + + // START TIMING + if (txn_begin(NULL, &t, 0) != 0) + goto err; + + if (adb->cursor(t, &acurs, 0) != 0 || + bdb->cursor(t, &bcurs, 0) != 0 || + tdb->cursor(t, &tcurs, 0) != 0) + goto err; + + // Account record + k_dbt.set_data(&account); + if (acurs->get(&k_dbt, &d_dbt, DB_SET) != 0) + goto err; + rec.balance += 10; + if (acurs->put(&k_dbt, &d_dbt, DB_CURRENT) != 0) + goto err; + + // Branch record + k_dbt.set_data(&branch); + if (bcurs->get(&k_dbt, &d_dbt, DB_SET) != 0) + goto err; + rec.balance += 10; + if (bcurs->put(&k_dbt, &d_dbt, DB_CURRENT) != 0) + goto err; + + // Teller record + k_dbt.set_data(&teller); + if (tcurs->get(&k_dbt, &d_dbt, DB_SET) != 0) + goto err; + rec.balance += 10; + if (tcurs->put(&k_dbt, &d_dbt, DB_CURRENT) != 0) + goto err; + + // History record + d_histdbt.set_flags(0); + d_histdbt.set_data(&hrec); + d_histdbt.set_ulen(sizeof(hrec)); + if (hdb->put(t, &k_histdbt, &d_histdbt, DB_APPEND) != 0) + goto err; + + if (acurs->close() != 0 || bcurs->close() != 0 || + tcurs->close() != 0) + goto err; + + if (t->commit(0) != 0) + goto err; + + // END TIMING + return (0); + +err: + if (acurs != NULL) + (void)acurs->close(); + if (bcurs != NULL) + (void)bcurs->close(); + if (tcurs != NULL) + (void)tcurs->close(); + if (t != NULL) + (void)t->abort(); + + if (verbose) + cout << "Transaction A=" << (long)account + << " B=" << (long)branch + << " T=" << (long)teller << " failed\n"; + return (-1); +} + +void errExit(int err, const char *s) +{ + cerr << progname << ": "; + if (s != NULL) { + cerr << s << ": "; + } + cerr << strerror(err) << "\n"; + exit(1); +} diff --git a/db/hash/hash.c b/db/hash/hash.c new file mode 100644 index 000000000..e96fd4898 --- /dev/null +++ b/db/hash/hash.c @@ -0,0 +1,2096 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994 + * Margo Seltzer. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Margo Seltzer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: hash.c,v 11.94 2001/01/03 16:42:26 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_am.h" +#include "db_ext.h" +#include "db_shash.h" +#include "db_swap.h" +#include "hash.h" +#include "btree.h" +#include "log.h" +#include "lock.h" +#include "txn.h" + +static int __ham_c_close __P((DBC *, db_pgno_t, int *)); +static int __ham_c_del __P((DBC *)); +static int __ham_c_destroy __P((DBC *)); +static int __ham_c_get __P((DBC *, DBT *, DBT *, u_int32_t, db_pgno_t *)); +static int __ham_c_put __P((DBC *, DBT *, DBT *, u_int32_t, db_pgno_t *)); +static int __ham_c_writelock __P((DBC *)); +static int __ham_del_dups __P((DBC *, DBT *)); +static int __ham_delete __P((DB *, DB_TXN *, DBT *, u_int32_t)); +static int __ham_dup_return __P((DBC *, DBT *, u_int32_t)); +static int __ham_expand_table __P((DBC *)); +static int __ham_init_htab __P((DBC *, + const char *, db_pgno_t, u_int32_t, u_int32_t)); +static int __ham_lookup __P((DBC *, + const DBT *, u_int32_t, db_lockmode_t, db_pgno_t *)); +static int __ham_overwrite __P((DBC *, DBT *, u_int32_t)); + +/* + * __ham_metachk -- + * + * PUBLIC: int __ham_metachk __P((DB *, const char *, HMETA *)); + */ +int +__ham_metachk(dbp, name, hashm) + DB *dbp; + const char *name; + HMETA *hashm; +{ + DB_ENV *dbenv; + u_int32_t vers; + int ret; + + dbenv = dbp->dbenv; + + /* + * At this point, all we know is that the magic number is for a Hash. + * Check the version, the database may be out of date. + */ + vers = hashm->dbmeta.version; + if (F_ISSET(dbp, DB_AM_SWAP)) + M_32_SWAP(vers); + switch (vers) { + case 4: + case 5: + case 6: + __db_err(dbenv, + "%s: hash version %lu requires a version upgrade", + name, (u_long)vers); + return (DB_OLD_VERSION); + case 7: + break; + default: + __db_err(dbenv, + "%s: unsupported hash version: %lu", name, (u_long)vers); + return (EINVAL); + } + + /* Swap the page if we need to. */ + if (F_ISSET(dbp, DB_AM_SWAP) && (ret = __ham_mswap((PAGE *)hashm)) != 0) + return (ret); + + /* Check the type. */ + if (dbp->type != DB_HASH && dbp->type != DB_UNKNOWN) + return (EINVAL); + dbp->type = DB_HASH; + DB_ILLEGAL_METHOD(dbp, DB_OK_HASH); + + /* + * Check application info against metadata info, and set info, flags, + * and type based on metadata info. + */ + if ((ret = __db_fchk(dbenv, + "DB->open", hashm->dbmeta.flags, + DB_HASH_DUP | DB_HASH_SUBDB | DB_HASH_DUPSORT)) != 0) + return (ret); + + if (F_ISSET(&hashm->dbmeta, DB_HASH_DUP)) + F_SET(dbp, DB_AM_DUP); + else + if (F_ISSET(dbp, DB_AM_DUP)) { + __db_err(dbenv, + "%s: DB_DUP specified to open method but not set in database", + name); + return (EINVAL); + } + + if (F_ISSET(&hashm->dbmeta, DB_HASH_SUBDB)) + F_SET(dbp, DB_AM_SUBDB); + else + if (F_ISSET(dbp, DB_AM_SUBDB)) { + __db_err(dbenv, + "%s: multiple databases specified but not supported in file", + name); + return (EINVAL); + } + + if (F_ISSET(&hashm->dbmeta, DB_HASH_DUPSORT)) { + if (dbp->dup_compare == NULL) + dbp->dup_compare = __bam_defcmp; + } else + if (dbp->dup_compare != NULL) { + __db_err(dbenv, + "%s: duplicate sort function specified but not set in database", + name); + return (EINVAL); + } + + /* Set the page size. */ + dbp->pgsize = hashm->dbmeta.pagesize; + + /* Copy the file's ID. */ + memcpy(dbp->fileid, hashm->dbmeta.uid, DB_FILE_ID_LEN); + + return (0); +} + +/* + * __ham_open -- + * + * PUBLIC: int __ham_open __P((DB *, const char *, db_pgno_t, u_int32_t)); + */ +int +__ham_open(dbp, name, base_pgno, flags) + DB *dbp; + const char *name; + db_pgno_t base_pgno; + u_int32_t flags; +{ + DB_ENV *dbenv; + DBC *dbc; + HASH_CURSOR *hcp; + HASH *hashp; + int need_sync, ret, t_ret; + + dbc = NULL; + dbenv = dbp->dbenv; + need_sync = 0; + + /* Initialize the remaining fields/methods of the DB. */ + dbp->del = __ham_delete; + dbp->stat = __ham_stat; + + /* + * Get a cursor. If DB_CREATE is specified, we may be creating + * pages, and to do that safely in CDB we need a write cursor. + * In STD_LOCKING mode, we'll synchronize using the meta page + * lock instead. + */ + if ((ret = dbp->cursor(dbp, + dbp->open_txn, &dbc, LF_ISSET(DB_CREATE) && CDB_LOCKING(dbenv) ? + DB_WRITECURSOR : 0)) != 0) + return (ret); + + hcp = (HASH_CURSOR *)dbc->internal; + hashp = dbp->h_internal; + hashp->meta_pgno = base_pgno; + if ((ret = __ham_get_meta(dbc)) != 0) + goto err1; + + /* + * If this is a new file, initialize it, and put it back dirty. + * + * Initialize the hdr structure. + */ + if (hcp->hdr->dbmeta.magic == DB_HASHMAGIC) { + /* File exists, verify the data in the header. */ + if (hashp->h_hash == NULL) + hashp->h_hash = hcp->hdr->dbmeta.version < 5 + ? __ham_func4 : __ham_func5; + if (!F_ISSET(dbp, DB_RDONLY) && + hashp->h_hash(dbp, + CHARKEY, sizeof(CHARKEY)) != hcp->hdr->h_charkey) { + __db_err(dbp->dbenv, + "hash: incompatible hash function"); + ret = EINVAL; + goto err2; + } + if (F_ISSET(&hcp->hdr->dbmeta, DB_HASH_DUP)) + F_SET(dbp, DB_AM_DUP); + if (F_ISSET(&hcp->hdr->dbmeta, DB_HASH_DUPSORT)) + F_SET(dbp, DB_AM_DUPSORT); + if (F_ISSET(&hcp->hdr->dbmeta, DB_HASH_SUBDB)) + F_SET(dbp, DB_AM_SUBDB); + } else if (!IS_RECOVERING(dbenv)) { + /* + * File does not exist, we must initialize the header. If + * locking is enabled that means getting a write lock first. + * During recovery the meta page will be in the log. + */ + dbc->lock.pgno = base_pgno; + + if (STD_LOCKING(dbc) && + ((ret = lock_put(dbenv, &hcp->hlock)) != 0 || + (ret = lock_get(dbenv, dbc->locker, + DB_NONBLOCK(dbc) ? DB_LOCK_NOWAIT : 0, + &dbc->lock_dbt, DB_LOCK_WRITE, &hcp->hlock)) != 0)) + goto err2; + else if (CDB_LOCKING(dbp->dbenv)) { + DB_ASSERT(LF_ISSET(DB_CREATE)); + if ((ret = lock_get(dbenv, dbc->locker, + DB_LOCK_UPGRADE, &dbc->lock_dbt, DB_LOCK_WRITE, + &dbc->mylock)) != 0) + goto err2; + } + if ((ret = __ham_init_htab(dbc, name, + base_pgno, hashp->h_nelem, hashp->h_ffactor)) != 0) + goto err2; + + need_sync = 1; + } + +err2: /* Release the meta data page */ + if ((t_ret = __ham_release_meta(dbc)) != 0 && ret == 0) + ret = t_ret; +err1: if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0) + ret = t_ret; + + /* Sync the file so that we know that the meta data goes to disk. */ + if (ret == 0 && need_sync) + ret = dbp->sync(dbp, 0); +#if CONFIG_TEST + if (ret == 0) + DB_TEST_RECOVERY(dbp, DB_TEST_POSTSYNC, ret, name); + +DB_TEST_RECOVERY_LABEL +#endif + if (ret != 0) + (void)__ham_db_close(dbp); + + return (ret); +} + +/************************** LOCAL CREATION ROUTINES **********************/ +/* + * Returns 0 on No Error + */ +static int +__ham_init_htab(dbc, name, pgno, nelem, ffactor) + DBC *dbc; + const char *name; + db_pgno_t pgno; + u_int32_t nelem, ffactor; +{ + DB *dbp; + DB_LOCK metalock; + DB_LSN orig_lsn; + DBMETA *mmeta; + HASH_CURSOR *hcp; + HASH *hashp; + PAGE *h; + db_pgno_t mpgno; + int32_t l2, nbuckets; + int dirty_mmeta, i, ret, t_ret; + + hcp = (HASH_CURSOR *)dbc->internal; + dbp = dbc->dbp; + hashp = dbp->h_internal; + mmeta = NULL; + h = NULL; + ret = 0; + dirty_mmeta = 0; + metalock.off = LOCK_INVALID; + + if (hashp->h_hash == NULL) + hashp->h_hash = DB_HASHVERSION < 5 ? __ham_func4 : __ham_func5; + + if (nelem != 0 && ffactor != 0) { + nelem = (nelem - 1) / ffactor + 1; + l2 = __db_log2(nelem > 2 ? nelem : 2); + } else + l2 = 1; + nbuckets = 1 << l2; + + orig_lsn = hcp->hdr->dbmeta.lsn; + memset(hcp->hdr, 0, sizeof(HMETA)); + ZERO_LSN(hcp->hdr->dbmeta.lsn); + hcp->hdr->dbmeta.pgno = pgno; + hcp->hdr->dbmeta.magic = DB_HASHMAGIC; + hcp->hdr->dbmeta.version = DB_HASHVERSION; + hcp->hdr->dbmeta.pagesize = dbp->pgsize; + hcp->hdr->dbmeta.type = P_HASHMETA; + hcp->hdr->dbmeta.free = PGNO_INVALID; + hcp->hdr->max_bucket = hcp->hdr->high_mask = nbuckets - 1; + hcp->hdr->low_mask = (nbuckets >> 1) - 1; + hcp->hdr->ffactor = ffactor; + hcp->hdr->h_charkey = hashp->h_hash(dbp, CHARKEY, sizeof(CHARKEY)); + memcpy(hcp->hdr->dbmeta.uid, dbp->fileid, DB_FILE_ID_LEN); + + if (F_ISSET(dbp, DB_AM_DUP)) + F_SET(&hcp->hdr->dbmeta, DB_HASH_DUP); + if (F_ISSET(dbp, DB_AM_SUBDB)) + F_SET(&hcp->hdr->dbmeta, DB_HASH_SUBDB); + if (dbp->dup_compare != NULL) + F_SET(&hcp->hdr->dbmeta, DB_HASH_DUPSORT); + + if ((ret = memp_fset(dbp->mpf, hcp->hdr, DB_MPOOL_DIRTY)) != 0) + goto err; + + /* + * Create the first and second buckets pages so that we have the + * page numbers for them and we can store that page number + * in the meta-data header (spares[0]). + */ + hcp->hdr->spares[0] = nbuckets; + if ((ret = memp_fget(dbp->mpf, + &hcp->hdr->spares[0], DB_MPOOL_NEW_GROUP, &h)) != 0) + goto err; + + P_INIT(h, dbp->pgsize, hcp->hdr->spares[0], PGNO_INVALID, + PGNO_INVALID, 0, P_HASH); + + /* Fill in the last fields of the meta data page. */ + hcp->hdr->spares[0] -= (nbuckets - 1); + for (i = 1; i <= l2; i++) + hcp->hdr->spares[i] = hcp->hdr->spares[0]; + for (; i < NCACHED; i++) + hcp->hdr->spares[i] = PGNO_INVALID; + + /* + * Before we are about to put any dirty pages, we need to log + * the meta-data page create. + */ + ret = __db_log_page(dbp, name, &orig_lsn, pgno, (PAGE *)hcp->hdr); + + if (dbp->open_txn != NULL) { + mmeta = (DBMETA *) hcp->hdr; + if (F_ISSET(dbp, DB_AM_SUBDB)) { + + /* + * If this is a subdatabase, then we need to + * get the LSN off the master meta data page + * because that's where free pages are linked + * and during recovery we need to access + * that page and roll it backward/forward + * correctly with respect to LSN. + */ + mpgno = PGNO_BASE_MD; + if ((ret = __db_lget(dbc, + 0, mpgno, DB_LOCK_WRITE, 0, &metalock)) != 0) + goto err; + if ((ret = memp_fget(dbp->mpf, + &mpgno, 0, (PAGE **)&mmeta)) != 0) + goto err; + } + if ((t_ret = __ham_groupalloc_log(dbp->dbenv, + dbp->open_txn, &LSN(mmeta), 0, dbp->log_fileid, + &LSN(mmeta), hcp->hdr->spares[0], + hcp->hdr->max_bucket + 1, mmeta->free)) != 0 && ret == 0) + ret = t_ret; + if (ret == 0) { + /* need to update real LSN for buffer manager */ + dirty_mmeta = 1; + } + + } + + DB_TEST_RECOVERY(dbp, DB_TEST_POSTLOG, ret, name); + +DB_TEST_RECOVERY_LABEL +err: if (h != NULL && + (t_ret = memp_fput(dbp->mpf, h, DB_MPOOL_DIRTY)) != 0 && ret == 0) + ret = t_ret; + + if (F_ISSET(dbp, DB_AM_SUBDB) && mmeta != NULL) + if ((t_ret = memp_fput(dbp->mpf, mmeta, + dirty_mmeta ? DB_MPOOL_DIRTY : 0)) != 0 && ret == 0) + ret = t_ret; + if (metalock.off != LOCK_INVALID) + (void)__TLPUT(dbc, metalock); + + return (ret); +} + +static int +__ham_delete(dbp, txn, key, flags) + DB *dbp; + DB_TXN *txn; + DBT *key; + u_int32_t flags; +{ + DBC *dbc; + HASH_CURSOR *hcp; + db_pgno_t pgno; + int ret, t_ret; + + /* + * This is the only access method routine called directly from + * the dbp, so we have to do error checking. + */ + + PANIC_CHECK(dbp->dbenv); + DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->del"); + DB_CHECK_TXN(dbp, txn); + + if ((ret = + __db_delchk(dbp, key, flags, F_ISSET(dbp, DB_AM_RDONLY))) != 0) + return (ret); + + if ((ret = dbp->cursor(dbp, txn, &dbc, DB_WRITELOCK)) != 0) + return (ret); + + DEBUG_LWRITE(dbc, txn, "ham_delete", key, NULL, flags); + + hcp = (HASH_CURSOR *)dbc->internal; + if ((ret = __ham_get_meta(dbc)) != 0) + goto out; + + pgno = PGNO_INVALID; + if ((ret = __ham_lookup(dbc, key, 0, DB_LOCK_WRITE, &pgno)) == 0) { + if (F_ISSET(hcp, H_OK)) { + if (pgno == PGNO_INVALID) + ret = __ham_del_pair(dbc, 1); + else { + /* When we close the cursor in __ham_del_dups, + * that will make the off-page dup tree go + * go away as well as our current entry. When + * it updates cursors, ours should get marked + * as H_DELETED. + */ + ret = __ham_del_dups(dbc, key); + } + } else + ret = DB_NOTFOUND; + } + + if ((t_ret = __ham_release_meta(dbc)) != 0 && ret == 0) + ret = t_ret; + +out: if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0) + ret = t_ret; + return (ret); +} + +/* ****************** CURSORS ********************************** */ +/* + * __ham_c_init -- + * Initialize the hash-specific portion of a cursor. + * + * PUBLIC: int __ham_c_init __P((DBC *)); + */ +int +__ham_c_init(dbc) + DBC *dbc; +{ + DB_ENV *dbenv; + HASH_CURSOR *new_curs; + int ret; + + dbenv = dbc->dbp->dbenv; + if ((ret = __os_calloc(dbenv, + 1, sizeof(struct cursor_t), &new_curs)) != 0) + return (ret); + if ((ret = __os_malloc(dbenv, + dbc->dbp->pgsize, NULL, &new_curs->split_buf)) != 0) { + __os_free(new_curs, sizeof(*new_curs)); + return (ret); + } + + dbc->internal = (DBC_INTERNAL *) new_curs; + dbc->c_close = __db_c_close; + dbc->c_count = __db_c_count; + dbc->c_del = __db_c_del; + dbc->c_dup = __db_c_dup; + dbc->c_get = __db_c_get; + dbc->c_put = __db_c_put; + dbc->c_am_close = __ham_c_close; + dbc->c_am_del = __ham_c_del; + dbc->c_am_destroy = __ham_c_destroy; + dbc->c_am_get = __ham_c_get; + dbc->c_am_put = __ham_c_put; + dbc->c_am_writelock = __ham_c_writelock; + + __ham_item_init(dbc); + + return (0); +} + +/* + * __ham_c_close -- + * Close down the cursor from a single use. + */ +static int +__ham_c_close(dbc, root_pgno, rmroot) + DBC *dbc; + db_pgno_t root_pgno; + int *rmroot; +{ + HASH_CURSOR *hcp; + HKEYDATA *dp; + int doroot, gotmeta, ret, t_ret; + u_int32_t dirty; + + COMPQUIET(rmroot, 0); + dirty = 0; + doroot = gotmeta = ret = 0; + hcp = (HASH_CURSOR *) dbc->internal; + + /* Check for off page dups. */ + if (dbc->internal->opd != NULL) { + if ((ret = __ham_get_meta(dbc)) != 0) + goto done; + gotmeta = 1; + if ((ret = __ham_get_cpage(dbc, DB_LOCK_READ)) != 0) + goto out; + dp = (HKEYDATA *)H_PAIRDATA(hcp->page, hcp->indx); + DB_ASSERT(HPAGE_PTYPE(dp) == H_OFFDUP); + memcpy(&root_pgno, HOFFPAGE_PGNO(dp), sizeof(db_pgno_t)); + + if ((ret = + hcp->opd->c_am_close(hcp->opd, root_pgno, &doroot)) != 0) + goto out; + if (doroot != 0) { + if ((ret = __ham_del_pair(dbc, 1)) != 0) + goto out; + dirty = DB_MPOOL_DIRTY; + } + } + +out: if (hcp->page != NULL && (t_ret = + memp_fput(dbc->dbp->mpf, hcp->page, dirty)) != 0 && ret == 0) + ret = t_ret; + if (gotmeta != 0 && (t_ret = __ham_release_meta(dbc)) != 0 && ret == 0) + ret = t_ret; + +done: + __ham_item_init(dbc); + return (ret); +} + +/* + * __ham_c_destroy -- + * Cleanup the access method private part of a cursor. + */ +static int +__ham_c_destroy(dbc) + DBC *dbc; +{ + HASH_CURSOR *hcp; + + hcp = (HASH_CURSOR *)dbc->internal; + if (hcp->split_buf != NULL) + __os_free(hcp->split_buf, dbc->dbp->pgsize); + __os_free(hcp, sizeof(HASH_CURSOR)); + + return (0); +} + +/* + * __ham_c_count -- + * Return a count of on-page duplicates. + * + * PUBLIC: int __ham_c_count __P((DBC *, db_recno_t *)); + */ +int +__ham_c_count(dbc, recnop) + DBC *dbc; + db_recno_t *recnop; +{ + DB *dbp; + HASH_CURSOR *hcp; + db_indx_t len; + db_recno_t recno; + int ret, t_ret; + u_int8_t *p, *pend; + + dbp = dbc->dbp; + hcp = (HASH_CURSOR *) dbc->internal; + + recno = 0; + + if ((ret = __ham_get_cpage(dbc, DB_LOCK_READ)) != 0) + return (ret); + + switch (HPAGE_PTYPE(H_PAIRDATA(hcp->page, hcp->indx))) { + case H_KEYDATA: + case H_OFFPAGE: + recno = 1; + break; + case H_DUPLICATE: + p = HKEYDATA_DATA(H_PAIRDATA(hcp->page, hcp->indx)); + pend = p + + LEN_HDATA(hcp->page, dbp->pgsize, hcp->indx); + for (; p < pend; recno++) { + /* p may be odd, so copy rather than just dereffing */ + memcpy(&len, p, sizeof(db_indx_t)); + p += 2 * sizeof(db_indx_t) + len; + } + + break; + default: + ret = __db_unknown_type(dbp->dbenv, "__ham_c_count", + HPAGE_PTYPE(H_PAIRDATA(hcp->page, hcp->indx))); + goto err; + } + + *recnop = recno; + +err: if ((t_ret = memp_fput(dbc->dbp->mpf, hcp->page, 0)) != 0 && ret == 0) + ret = t_ret; + hcp->page = NULL; + return (ret); +} + +static int +__ham_c_del(dbc) + DBC *dbc; +{ + DB *dbp; + DBT repldbt; + HASH_CURSOR *hcp; + int ret, t_ret; + + dbp = dbc->dbp; + hcp = (HASH_CURSOR *)dbc->internal; + + if (F_ISSET(hcp, H_DELETED)) + return (DB_NOTFOUND); + + if ((ret = __ham_get_meta(dbc)) != 0) + goto out; + + if ((ret = __ham_get_cpage(dbc, DB_LOCK_WRITE)) != 0) + goto out; + + /* Off-page duplicates. */ + if (HPAGE_TYPE(hcp->page, H_DATAINDEX(hcp->indx)) == H_OFFDUP) + goto out; + + if (F_ISSET(hcp, H_ISDUP)) { /* On-page duplicate. */ + if (hcp->dup_off == 0 && + DUP_SIZE(hcp->dup_len) == LEN_HDATA(hcp->page, + hcp->hdr->dbmeta.pagesize, hcp->indx)) + ret = __ham_del_pair(dbc, 1); + else { + repldbt.flags = 0; + F_SET(&repldbt, DB_DBT_PARTIAL); + repldbt.doff = hcp->dup_off; + repldbt.dlen = DUP_SIZE(hcp->dup_len); + repldbt.size = 0; + repldbt.data = HKEYDATA_DATA(H_PAIRDATA(hcp->page, + hcp->indx)); + ret = __ham_replpair(dbc, &repldbt, 0); + hcp->dup_tlen -= DUP_SIZE(hcp->dup_len); + F_SET(hcp, H_DELETED); + ret = __ham_c_update(dbc, DUP_SIZE(hcp->dup_len), 0, 1); + } + + } else /* Not a duplicate */ + ret = __ham_del_pair(dbc, 1); + +out: if (ret == 0 && hcp->page != NULL && + (t_ret = memp_fput(dbp->mpf, hcp->page, DB_MPOOL_DIRTY)) != 0) + ret = t_ret; + hcp->page = NULL; + if ((t_ret = __ham_release_meta(dbc)) != 0 && ret == 0) + ret = t_ret; + return (ret); +} + +/* + * __ham_c_dup -- + * Duplicate a hash cursor, such that the new one holds appropriate + * locks for the position of the original. + * + * PUBLIC: int __ham_c_dup __P((DBC *, DBC *)); + */ +int +__ham_c_dup(orig_dbc, new_dbc) + DBC *orig_dbc, *new_dbc; +{ + HASH_CURSOR *orig, *new; + + orig = (HASH_CURSOR *)orig_dbc->internal; + new = (HASH_CURSOR *)new_dbc->internal; + + new->bucket = orig->bucket; + new->lbucket = orig->lbucket; + new->dup_off = orig->dup_off; + new->dup_len = orig->dup_len; + new->dup_tlen = orig->dup_tlen; + + if (F_ISSET(orig, H_DELETED)) + F_SET(new, H_DELETED); + if (F_ISSET(orig, H_ISDUP)) + F_SET(new, H_ISDUP); + + /* + * If the old cursor held a lock and we're not in transactions, get one + * for the new one. The reason that we don't need a new lock if we're + * in a transaction is because we already hold a lock and will continue + * to do so until commit, so there is no point in reaquiring it. We + * don't know if the old lock was a read or write lock, but it doesn't + * matter. We'll get a read lock. We know that this locker already + * holds a lock of the correct type, so if we need a write lock and + * request it, we know that we'll get it. + */ + if (orig->lock.off == LOCK_INVALID || orig_dbc->txn != NULL) + return (0); + + return (__ham_lock_bucket(new_dbc, DB_LOCK_READ)); +} + +static int +__ham_c_get(dbc, key, data, flags, pgnop) + DBC *dbc; + DBT *key; + DBT *data; + u_int32_t flags; + db_pgno_t *pgnop; +{ + DB *dbp; + HASH_CURSOR *hcp; + db_lockmode_t lock_type; + int get_key, ret, t_ret; + + hcp = (HASH_CURSOR *)dbc->internal; + dbp = dbc->dbp; + + /* Clear OR'd in additional bits so we can check for flag equality. */ + if (F_ISSET(dbc, DBC_RMW)) + lock_type = DB_LOCK_WRITE; + else + lock_type = DB_LOCK_READ; + + if ((ret = __ham_get_meta(dbc)) != 0) + return (ret); + hcp->seek_size = 0; + + ret = 0; + get_key = 1; + switch (flags) { + case DB_PREV_NODUP: + F_SET(hcp, H_NEXT_NODUP); + /* FALLTHROUGH */ + case DB_PREV: + if (IS_INITIALIZED(dbc)) { + ret = __ham_item_prev(dbc, lock_type, pgnop); + break; + } + /* FALLTHROUGH */ + case DB_LAST: + ret = __ham_item_last(dbc, lock_type, pgnop); + break; + case DB_NEXT_NODUP: + F_SET(hcp, H_NEXT_NODUP); + /* FALLTHROUGH */ + case DB_NEXT: + if (IS_INITIALIZED(dbc)) { + ret = __ham_item_next(dbc, lock_type, pgnop); + break; + } + /* FALLTHROUGH */ + case DB_FIRST: + ret = __ham_item_first(dbc, lock_type, pgnop); + break; + case DB_NEXT_DUP: + /* cgetchk has already determined that the cursor is set. */ + F_SET(hcp, H_DUPONLY); + ret = __ham_item_next(dbc, lock_type, pgnop); + break; + case DB_SET: + case DB_SET_RANGE: + case DB_GET_BOTH: + ret = __ham_lookup(dbc, key, 0, lock_type, pgnop); + get_key = 0; + break; + case DB_GET_BOTHC: + F_SET(hcp, H_DUPONLY); + + ret = __ham_item_next(dbc, lock_type, pgnop); + get_key = 0; + break; + case DB_CURRENT: + /* cgetchk has already determined that the cursor is set. */ + if (F_ISSET(hcp, H_DELETED)) { + ret = DB_KEYEMPTY; + goto err; + } + + ret = __ham_item(dbc, lock_type, pgnop); + break; + } + + /* + * Must always enter this loop to do error handling and + * check for big key/data pair. + */ + for (;;) { + if (ret != 0 && ret != DB_NOTFOUND) + goto err; + else if (F_ISSET(hcp, H_OK)) { + if (*pgnop == PGNO_INVALID) + ret = __ham_dup_return (dbc, data, flags); + break; + } else if (!F_ISSET(hcp, H_NOMORE)) { + __db_err(dbp->dbenv, + "H_NOMORE returned to __ham_c_get"); + ret = EINVAL; + break; + } + + /* + * Ran out of entries in a bucket; change buckets. + */ + switch (flags) { + case DB_LAST: + case DB_PREV: + case DB_PREV_NODUP: + ret = memp_fput(dbp->mpf, hcp->page, 0); + hcp->page = NULL; + if (hcp->bucket == 0) { + ret = DB_NOTFOUND; + hcp->pgno = PGNO_INVALID; + goto err; + } + F_CLR(hcp, H_ISDUP); + hcp->bucket--; + hcp->indx = NDX_INVALID; + hcp->pgno = BUCKET_TO_PAGE(hcp, hcp->bucket); + if (ret == 0) + ret = __ham_item_prev(dbc, + lock_type, pgnop); + break; + case DB_FIRST: + case DB_NEXT: + case DB_NEXT_NODUP: + ret = memp_fput(dbp->mpf, hcp->page, 0); + hcp->page = NULL; + hcp->indx = NDX_INVALID; + hcp->bucket++; + F_CLR(hcp, H_ISDUP); + hcp->pgno = BUCKET_TO_PAGE(hcp, hcp->bucket); + if (hcp->bucket > hcp->hdr->max_bucket) { + ret = DB_NOTFOUND; + hcp->pgno = PGNO_INVALID; + goto err; + } + if (ret == 0) + ret = __ham_item_next(dbc, + lock_type, pgnop); + break; + case DB_GET_BOTH: + case DB_GET_BOTHC: + case DB_NEXT_DUP: + case DB_SET: + case DB_SET_RANGE: + /* Key not found. */ + ret = DB_NOTFOUND; + goto err; + case DB_CURRENT: + /* + * This should only happen if you are doing + * deletes and reading with concurrent threads + * and not doing proper locking. We return + * the same error code as we would if the + * cursor were deleted. + */ + ret = DB_KEYEMPTY; + goto err; + default: + DB_ASSERT(0); + } + } + + if (get_key == 0) + F_SET(key, DB_DBT_ISSET); + +err: if ((t_ret = __ham_release_meta(dbc)) != 0 && ret == 0) + ret = t_ret; + + F_CLR(hcp, H_DUPONLY); + F_CLR(hcp, H_NEXT_NODUP); + + return (ret); +} + +static int +__ham_c_put(dbc, key, data, flags, pgnop) + DBC *dbc; + DBT *key; + DBT *data; + u_int32_t flags; + db_pgno_t *pgnop; +{ + DB *dbp; + DBT tmp_val, *myval; + HASH_CURSOR *hcp; + u_int32_t nbytes; + int ret, t_ret; + + /* + * The compiler doesn't realize that we only use this when ret is + * equal to 0 and that if ret is equal to 0, that we must have set + * myval. So, we initialize it here to shut the compiler up. + */ + COMPQUIET(myval, NULL); + + dbp = dbc->dbp; + hcp = (HASH_CURSOR *)dbc->internal; + + if (F_ISSET(hcp, H_DELETED) && + flags != DB_KEYFIRST && flags != DB_KEYLAST) + return (DB_NOTFOUND); + + if ((ret = __ham_get_meta(dbc)) != 0) + goto err1; + + switch (flags) { + case DB_KEYLAST: + case DB_KEYFIRST: + case DB_NODUPDATA: + nbytes = (ISBIG(hcp, key->size) ? HOFFPAGE_PSIZE : + HKEYDATA_PSIZE(key->size)) + + (ISBIG(hcp, data->size) ? HOFFPAGE_PSIZE : + HKEYDATA_PSIZE(data->size)); + if ((ret = __ham_lookup(dbc, + key, nbytes, DB_LOCK_WRITE, pgnop)) == DB_NOTFOUND) { + ret = 0; + if (hcp->seek_found_page != PGNO_INVALID && + hcp->seek_found_page != hcp->pgno) { + if ((ret = memp_fput(dbp->mpf, hcp->page, 0)) + != 0) + goto err2; + hcp->page = NULL; + hcp->pgno = hcp->seek_found_page; + hcp->indx = NDX_INVALID; + } + + if (F_ISSET(data, DB_DBT_PARTIAL) && data->doff != 0) { + /* + * A partial put, but the key does not exist + * and we are not beginning the write at 0. + * We must create a data item padded up to doff + * and then write the new bytes represented by + * val. + */ + if ((ret = __ham_init_dbt(dbp->dbenv, + &tmp_val, data->size + data->doff, + &dbc->rdata.data, &dbc->rdata.ulen)) == 0) { + memset(tmp_val.data, 0, data->doff); + memcpy((u_int8_t *)tmp_val.data + + data->doff, data->data, data->size); + myval = &tmp_val; + } + } else + myval = (DBT *)data; + + if (ret == 0) + ret = __ham_add_el(dbc, key, myval, H_KEYDATA); + goto done; + } + break; + case DB_BEFORE: + case DB_AFTER: + case DB_CURRENT: + ret = __ham_item(dbc, DB_LOCK_WRITE, pgnop); + break; + } + + if (*pgnop == PGNO_INVALID && ret == 0) { + if (flags == DB_CURRENT || + ((flags == DB_KEYFIRST || + flags == DB_KEYLAST || flags == DB_NODUPDATA) && + !(F_ISSET(dbp, DB_AM_DUP) || F_ISSET(key, DB_DBT_DUPOK)))) + ret = __ham_overwrite(dbc, data, flags); + else + ret = __ham_add_dup(dbc, data, flags, pgnop); + } + +done: if (ret == 0 && F_ISSET(hcp, H_EXPAND)) { + ret = __ham_expand_table(dbc); + F_CLR(hcp, H_EXPAND); + } + + if (ret == 0 && + (t_ret = memp_fset(dbp->mpf, hcp->page, DB_MPOOL_DIRTY)) != 0) + ret = t_ret; + +err2: if ((t_ret = __ham_release_meta(dbc)) != 0 && ret == 0) + ret = t_ret; + +err1: return (ret); +} + +/********************************* UTILITIES ************************/ + +/* + * __ham_expand_table -- + */ +static int +__ham_expand_table(dbc) + DBC *dbc; +{ + DB *dbp; + PAGE *h; + HASH_CURSOR *hcp; + db_pgno_t pgno; + u_int32_t old_bucket, new_bucket; + int ret; + + dbp = dbc->dbp; + hcp = (HASH_CURSOR *)dbc->internal; + if ((ret = __ham_dirty_meta(dbc)) != 0) + return (ret); + + /* + * If the split point is about to increase, make sure that we + * have enough extra pages. The calculation here is weird. + * We'd like to do this after we've upped max_bucket, but it's + * too late then because we've logged the meta-data split. What + * we'll do between then and now is increment max bucket and then + * see what the log of one greater than that is; here we have to + * look at the log of max + 2. VERY NASTY STUFF. + * + * It just got even nastier. With subdatabases, we have to request + * a chunk of contiguous pages, so we do that here using an + * undocumented feature of mpool (the MPOOL_NEW_GROUP flag) to + * give us a number of contiguous pages. Ouch. + */ + if (hcp->hdr->max_bucket == hcp->hdr->high_mask) { + /* + * Ask mpool to give us a set of contiguous page numbers + * large enough to contain the next doubling. + * + * Figure out how many new pages we need. This will return + * us the last page. We calculate its page number, initialize + * the page and then write it back to reserve all the pages + * in between. It is possible that the allocation of new pages + * has already been done, but the tranaction aborted. Since + * we don't undo the allocation, check for a valid pgno before + * doing the allocation. + */ + pgno = hcp->hdr->max_bucket + 1; + if (hcp->hdr->spares[__db_log2(pgno) + 1] == PGNO_INVALID) + /* Allocate a group of pages. */ + ret = memp_fget(dbp->mpf, + &pgno, DB_MPOOL_NEW_GROUP, &h); + else { + /* Just read in the last page of the batch */ + pgno = hcp->hdr->spares[__db_log2(pgno) + 1] + + hcp->hdr->max_bucket + 1; + /* Move to the last page of the group. */ + pgno += hcp->hdr->max_bucket; + ret = memp_fget(dbp->mpf, + &pgno, DB_MPOOL_CREATE, &h); + } + if (ret != 0) + return (ret); + + P_INIT(h, dbp->pgsize, pgno, + PGNO_INVALID, PGNO_INVALID, 0, P_HASH); + pgno -= hcp->hdr->max_bucket; + } else { + pgno = BUCKET_TO_PAGE(hcp, hcp->hdr->max_bucket + 1); + if ((ret = + memp_fget(dbp->mpf, &pgno, DB_MPOOL_CREATE, &h)) != 0) + return (ret); + } + + /* Now we can log the meta-data split. */ + if (DB_LOGGING(dbc)) { + if ((ret = __ham_metagroup_log(dbp->dbenv, + dbc->txn, &h->lsn, 0, dbp->log_fileid, + hcp->hdr->max_bucket, pgno, &hcp->hdr->dbmeta.lsn, + &h->lsn)) != 0) { + (void)memp_fput(dbp->mpf, h, DB_MPOOL_DIRTY); + return (ret); + } + + hcp->hdr->dbmeta.lsn = h->lsn; + } + + /* If we allocated some new pages, write out the last page. */ + if ((ret = memp_fput(dbp->mpf, h, DB_MPOOL_DIRTY)) != 0) + return (ret); + + new_bucket = ++hcp->hdr->max_bucket; + old_bucket = (hcp->hdr->max_bucket & hcp->hdr->low_mask); + + /* + * If we started a new doubling, fill in the spares array with + * the starting page number negatively offset by the bucket number. + */ + if (new_bucket > hcp->hdr->high_mask) { + /* Starting a new doubling */ + hcp->hdr->low_mask = hcp->hdr->high_mask; + hcp->hdr->high_mask = new_bucket | hcp->hdr->low_mask; + if (hcp->hdr->spares[__db_log2(new_bucket) + 1] == PGNO_INVALID) + hcp->hdr->spares[__db_log2(new_bucket) + 1] = + pgno - new_bucket; + } + + /* Relocate records to the new bucket */ + return (__ham_split_page(dbc, old_bucket, new_bucket)); +} + +/* + * PUBLIC: u_int32_t __ham_call_hash __P((DBC *, u_int8_t *, int32_t)); + */ +u_int32_t +__ham_call_hash(dbc, k, len) + DBC *dbc; + u_int8_t *k; + int32_t len; +{ + DB *dbp; + u_int32_t n, bucket; + HASH_CURSOR *hcp; + HASH *hashp; + + dbp = dbc->dbp; + hcp = (HASH_CURSOR *)dbc->internal; + hashp = dbp->h_internal; + + n = (u_int32_t)(hashp->h_hash(dbp, k, len)); + + bucket = n & hcp->hdr->high_mask; + if (bucket > hcp->hdr->max_bucket) + bucket = bucket & hcp->hdr->low_mask; + return (bucket); +} + +/* + * Check for duplicates, and call __db_ret appropriately. Release + * everything held by the cursor. + */ +static int +__ham_dup_return (dbc, val, flags) + DBC *dbc; + DBT *val; + u_int32_t flags; +{ + DB *dbp; + HASH_CURSOR *hcp; + PAGE *pp; + DBT *myval, tmp_val; + db_indx_t ndx; + db_pgno_t pgno; + u_int32_t off, tlen; + u_int8_t *hk, type; + int cmp, ret; + db_indx_t len; + + /* Check for duplicate and return the first one. */ + dbp = dbc->dbp; + hcp = (HASH_CURSOR *)dbc->internal; + ndx = H_DATAINDEX(hcp->indx); + type = HPAGE_TYPE(hcp->page, ndx); + pp = hcp->page; + myval = val; + + /* + * There are 4 cases: + * 1. We are not in duplicate, simply return; the upper layer + * will do the right thing. + * 2. We are looking at keys and stumbled onto a duplicate. + * 3. We are in the middle of a duplicate set. (ISDUP set) + * 4. We need to check for particular data match. + */ + + /* We should never get here with off-page dups. */ + DB_ASSERT(type != H_OFFDUP); + + /* Case 1 */ + if (type != H_DUPLICATE && + flags != DB_GET_BOTH && flags != DB_GET_BOTHC) + return (0); + + /* + * Here we check for the case where we just stumbled onto a + * duplicate. In this case, we do initialization and then + * let the normal duplicate code handle it. (Case 2) + */ + if (!F_ISSET(hcp, H_ISDUP) && type == H_DUPLICATE) { + F_SET(hcp, H_ISDUP); + hcp->dup_tlen = LEN_HDATA(hcp->page, + hcp->hdr->dbmeta.pagesize, hcp->indx); + hk = H_PAIRDATA(hcp->page, hcp->indx); + if (flags == DB_LAST + || flags == DB_PREV || flags == DB_PREV_NODUP) { + hcp->dup_off = 0; + do { + memcpy(&len, + HKEYDATA_DATA(hk) + hcp->dup_off, + sizeof(db_indx_t)); + hcp->dup_off += DUP_SIZE(len); + } while (hcp->dup_off < hcp->dup_tlen); + hcp->dup_off -= DUP_SIZE(len); + } else { + memcpy(&len, + HKEYDATA_DATA(hk), sizeof(db_indx_t)); + hcp->dup_off = 0; + } + hcp->dup_len = len; + } + + /* + * If we are retrieving a specific key/data pair, then we + * may need to adjust the cursor before returning data. + * Case 4 + */ + if (flags == DB_GET_BOTH || flags == DB_GET_BOTHC) { + if (F_ISSET(hcp, H_ISDUP)) { + /* + * If we're doing a join, search forward from the + * current position, not the beginning of the dup set. + */ + if (flags == DB_GET_BOTHC) + F_SET(hcp, H_CONTINUE); + + __ham_dsearch(dbc, val, &off, &cmp); + + /* + * This flag is set nowhere else and is safe to + * clear unconditionally. + */ + F_CLR(hcp, H_CONTINUE); + hcp->dup_off = off; + } else { + hk = H_PAIRDATA(hcp->page, hcp->indx); + if (((HKEYDATA *)hk)->type == H_OFFPAGE) { + memcpy(&tlen, + HOFFPAGE_TLEN(hk), sizeof(u_int32_t)); + memcpy(&pgno, + HOFFPAGE_PGNO(hk), sizeof(db_pgno_t)); + if ((ret = __db_moff(dbp, val, + pgno, tlen, dbp->dup_compare, &cmp)) != 0) + return (ret); + } else { + /* + * We do not zero tmp_val since the comparison + * routines may only look at data and size. + */ + tmp_val.data = HKEYDATA_DATA(hk); + tmp_val.size = LEN_HDATA(hcp->page, + dbp->pgsize, hcp->indx); + cmp = dbp->dup_compare == NULL ? + __bam_defcmp(dbp, &tmp_val, val) : + dbp->dup_compare(dbp, &tmp_val, val); + } + } + + if (cmp != 0) + return (DB_NOTFOUND); + } + + /* + * Now, everything is initialized, grab a duplicate if + * necessary. + */ + if (F_ISSET(hcp, H_ISDUP)) { /* Case 3 */ + /* + * Copy the DBT in case we are retrieving into user + * memory and we need the parameters for it. If the + * user requested a partial, then we need to adjust + * the user's parameters to get the partial of the + * duplicate which is itself a partial. + */ + memcpy(&tmp_val, val, sizeof(*val)); + if (F_ISSET(&tmp_val, DB_DBT_PARTIAL)) { + /* + * Take the user's length unless it would go + * beyond the end of the duplicate. + */ + if (tmp_val.doff + hcp->dup_off > hcp->dup_len) + tmp_val.dlen = 0; + else if (tmp_val.dlen + tmp_val.doff > + hcp->dup_len) + tmp_val.dlen = + hcp->dup_len - tmp_val.doff; + + /* + * Calculate the new offset. + */ + tmp_val.doff += hcp->dup_off; + } else { + F_SET(&tmp_val, DB_DBT_PARTIAL); + tmp_val.dlen = hcp->dup_len; + tmp_val.doff = hcp->dup_off + sizeof(db_indx_t); + } + myval = &tmp_val; + } + + /* + * Finally, if we had a duplicate, pp, ndx, and myval should be + * set appropriately. + */ + if ((ret = __db_ret(dbp, pp, ndx, myval, &dbc->rdata.data, + &dbc->rdata.ulen)) != 0) + return (ret); + + /* + * In case we sent a temporary off to db_ret, set the real + * return values. + */ + val->data = myval->data; + val->size = myval->size; + + F_SET(val, DB_DBT_ISSET); + + return (0); +} + +static int +__ham_overwrite(dbc, nval, flags) + DBC *dbc; + DBT *nval; + u_int32_t flags; +{ + DB *dbp; + HASH_CURSOR *hcp; + DBT *myval, tmp_val, tmp_val2; + void *newrec; + u_int8_t *hk, *p; + u_int32_t len, nondup_size; + db_indx_t newsize; + int ret; + + dbp = dbc->dbp; + hcp = (HASH_CURSOR *)dbc->internal; + if (F_ISSET(hcp, H_ISDUP)) { + /* + * This is an overwrite of a duplicate. We should never + * be off-page at this point. + */ + DB_ASSERT(hcp->opd == NULL); + /* On page dups */ + if (F_ISSET(nval, DB_DBT_PARTIAL)) { + /* + * We're going to have to get the current item, then + * construct the record, do any padding and do a + * replace. + */ + memset(&tmp_val, 0, sizeof(tmp_val)); + if ((ret = + __ham_dup_return (dbc, &tmp_val, DB_CURRENT)) != 0) + return (ret); + + /* Figure out new size. */ + nondup_size = tmp_val.size; + newsize = nondup_size; + + /* + * Three cases: + * 1. strictly append (may need to allocate space + * for pad bytes; really gross). + * 2. overwrite some and append. + * 3. strictly overwrite. + */ + if (nval->doff > nondup_size) + newsize += + (nval->doff - nondup_size + nval->size); + else if (nval->doff + nval->dlen > nondup_size) + newsize += nval->size - + (nondup_size - nval->doff); + else + newsize += nval->size - nval->dlen; + + /* + * Make sure that the new size doesn't put us over + * the onpage duplicate size in which case we need + * to convert to off-page duplicates. + */ + if (ISBIG(hcp, hcp->dup_tlen - nondup_size + newsize)) { + if ((ret = __ham_dup_convert(dbc)) != 0) + return (ret); + return (hcp->opd->c_am_put(hcp->opd, + NULL, nval, flags, NULL)); + } + + if ((ret = __os_malloc(dbp->dbenv, + DUP_SIZE(newsize), NULL, &newrec)) != 0) + return (ret); + memset(&tmp_val2, 0, sizeof(tmp_val2)); + F_SET(&tmp_val2, DB_DBT_PARTIAL); + + /* Construct the record. */ + p = newrec; + /* Initial size. */ + memcpy(p, &newsize, sizeof(db_indx_t)); + p += sizeof(db_indx_t); + + /* First part of original record. */ + len = nval->doff > tmp_val.size + ? tmp_val.size : nval->doff; + memcpy(p, tmp_val.data, len); + p += len; + + if (nval->doff > tmp_val.size) { + /* Padding */ + memset(p, 0, nval->doff - tmp_val.size); + p += nval->doff - tmp_val.size; + } + + /* New bytes */ + memcpy(p, nval->data, nval->size); + p += nval->size; + + /* End of original record (if there is any) */ + if (nval->doff + nval->dlen < tmp_val.size) { + len = tmp_val.size - nval->doff - nval->dlen; + memcpy(p, (u_int8_t *)tmp_val.data + + nval->doff + nval->dlen, len); + p += len; + } + + /* Final size. */ + memcpy(p, &newsize, sizeof(db_indx_t)); + + /* + * Make sure that the caller isn't corrupting + * the sort order. + */ + if (dbp->dup_compare != NULL) { + tmp_val2.data = + (u_int8_t *)newrec + sizeof(db_indx_t); + tmp_val2.size = newsize; + if (dbp->dup_compare( + dbp, &tmp_val, &tmp_val2) != 0) { + (void)__os_free(newrec, + DUP_SIZE(newsize)); + return (__db_duperr(dbp, flags)); + } + } + + tmp_val2.data = newrec; + tmp_val2.size = DUP_SIZE(newsize); + tmp_val2.doff = hcp->dup_off; + tmp_val2.dlen = DUP_SIZE(hcp->dup_len); + + ret = __ham_replpair(dbc, &tmp_val2, 0); + (void)__os_free(newrec, DUP_SIZE(newsize)); + + /* Update cursor */ + if (ret != 0) + return (ret); + + if (newsize > nondup_size) + hcp->dup_tlen += (newsize - nondup_size); + else + hcp->dup_tlen -= (nondup_size - newsize); + hcp->dup_len = DUP_SIZE(newsize); + return (0); + } else { + /* Check whether we need to convert to off page. */ + if (ISBIG(hcp, + hcp->dup_tlen - hcp->dup_len + nval->size)) { + if ((ret = __ham_dup_convert(dbc)) != 0) + return (ret); + return (hcp->opd->c_am_put(hcp->opd, + NULL, nval, flags, NULL)); + } + + /* Make sure we maintain sort order. */ + if (dbp->dup_compare != NULL) { + tmp_val2.data = + HKEYDATA_DATA(H_PAIRDATA(hcp->page, + hcp->indx)) + hcp->dup_off + + sizeof(db_indx_t); + tmp_val2.size = hcp->dup_len; + if (dbp->dup_compare(dbp, nval, &tmp_val2) != 0) + return (EINVAL); + } + /* Overwriting a complete duplicate. */ + if ((ret = + __ham_make_dup(dbp->dbenv, nval, + &tmp_val, &dbc->rdata.data, &dbc->rdata.ulen)) != 0) + return (ret); + /* Now fix what we are replacing. */ + tmp_val.doff = hcp->dup_off; + tmp_val.dlen = DUP_SIZE(hcp->dup_len); + + /* Update cursor */ + if (nval->size > hcp->dup_len) + hcp->dup_tlen += (nval->size - hcp->dup_len); + else + hcp->dup_tlen -= (hcp->dup_len - nval->size); + hcp->dup_len = DUP_SIZE(nval->size); + } + myval = &tmp_val; + } else if (!F_ISSET(nval, DB_DBT_PARTIAL)) { + /* Put/overwrite */ + memcpy(&tmp_val, nval, sizeof(*nval)); + F_SET(&tmp_val, DB_DBT_PARTIAL); + tmp_val.doff = 0; + hk = H_PAIRDATA(hcp->page, hcp->indx); + if (HPAGE_PTYPE(hk) == H_OFFPAGE) + memcpy(&tmp_val.dlen, + HOFFPAGE_TLEN(hk), sizeof(u_int32_t)); + else + tmp_val.dlen = LEN_HDATA(hcp->page, + hcp->hdr->dbmeta.pagesize, hcp->indx); + myval = &tmp_val; + } else + /* Regular partial put */ + myval = nval; + + return (__ham_replpair(dbc, myval, 0)); +} + +/* + * Given a key and a cursor, sets the cursor to the page/ndx on which + * the key resides. If the key is found, the cursor H_OK flag is set + * and the pagep, bndx, pgno (dpagep, dndx, dpgno) fields are set. + * If the key is not found, the H_OK flag is not set. If the sought + * field is non-0, the pagep, bndx, pgno (dpagep, dndx, dpgno) fields + * are set indicating where an add might take place. If it is 0, + * non of the cursor pointer field are valid. + */ +static int +__ham_lookup(dbc, key, sought, mode, pgnop) + DBC *dbc; + const DBT *key; + u_int32_t sought; + db_lockmode_t mode; + db_pgno_t *pgnop; +{ + DB *dbp; + HASH_CURSOR *hcp; + db_pgno_t pgno; + u_int32_t tlen; + int match, ret; + u_int8_t *hk, *dk; + + dbp = dbc->dbp; + hcp = (HASH_CURSOR *)dbc->internal; + /* + * Set up cursor so that we're looking for space to add an item + * as we cycle through the pages looking for the key. + */ + if ((ret = __ham_item_reset(dbc)) != 0) + return (ret); + hcp->seek_size = sought; + + hcp->bucket = __ham_call_hash(dbc, (u_int8_t *)key->data, key->size); + hcp->pgno = BUCKET_TO_PAGE(hcp, hcp->bucket); + + while (1) { + *pgnop = PGNO_INVALID; + if ((ret = __ham_item_next(dbc, mode, pgnop)) != 0) + return (ret); + + if (F_ISSET(hcp, H_NOMORE)) + break; + + hk = H_PAIRKEY(hcp->page, hcp->indx); + switch (HPAGE_PTYPE(hk)) { + case H_OFFPAGE: + memcpy(&tlen, HOFFPAGE_TLEN(hk), sizeof(u_int32_t)); + if (tlen == key->size) { + memcpy(&pgno, + HOFFPAGE_PGNO(hk), sizeof(db_pgno_t)); + if ((ret = __db_moff(dbp, + key, pgno, tlen, NULL, &match)) != 0) + return (ret); + if (match == 0) + goto found_key; + } + break; + case H_KEYDATA: + if (key->size == + LEN_HKEY(hcp->page, dbp->pgsize, hcp->indx) && + memcmp(key->data, + HKEYDATA_DATA(hk), key->size) == 0) { + /* Found the key, check for data type. */ +found_key: F_SET(hcp, H_OK); + dk = H_PAIRDATA(hcp->page, hcp->indx); + if (HPAGE_PTYPE(dk) == H_OFFDUP) + memcpy(pgnop, HOFFDUP_PGNO(dk), + sizeof(db_pgno_t)); + return (0); + } + break; + case H_DUPLICATE: + case H_OFFDUP: + /* + * These are errors because keys are never + * duplicated, only data items are. + */ + return (__db_pgfmt(dbp, PGNO(hcp->page))); + } + } + + /* + * Item was not found. + */ + + if (sought != 0) + return (ret); + + return (ret); +} + +/* + * __ham_init_dbt -- + * Initialize a dbt using some possibly already allocated storage + * for items. + * + * PUBLIC: int __ham_init_dbt __P((DB_ENV *, + * PUBLIC: DBT *, u_int32_t, void **, u_int32_t *)); + */ +int +__ham_init_dbt(dbenv, dbt, size, bufp, sizep) + DB_ENV *dbenv; + DBT *dbt; + u_int32_t size; + void **bufp; + u_int32_t *sizep; +{ + int ret; + + memset(dbt, 0, sizeof(*dbt)); + if (*sizep < size) { + if ((ret = __os_realloc(dbenv, size, NULL, bufp)) != 0) { + *sizep = 0; + return (ret); + } + *sizep = size; + } + dbt->data = *bufp; + dbt->size = size; + return (0); +} + +/* + * Adjust the cursor after an insert or delete. The cursor passed is + * the one that was operated upon; we just need to check any of the + * others. + * + * len indicates the length of the item added/deleted + * add indicates if the item indicated by the cursor has just been + * added (add == 1) or deleted (add == 0). + * dup indicates if the addition occurred into a duplicate set. + * + * PUBLIC: int __ham_c_update + * PUBLIC: __P((DBC *, u_int32_t, int, int)); + */ +int +__ham_c_update(dbc, len, add, is_dup) + DBC *dbc; + u_int32_t len; + int add, is_dup; +{ + DB *dbp, *ldbp; + DBC *cp; + DB_ENV *dbenv; + DB_LSN lsn; + DB_TXN *my_txn; + HASH_CURSOR *hcp, *lcp; + int found, ret; + u_int32_t order; + + dbp = dbc->dbp; + dbenv = dbp->dbenv; + hcp = (HASH_CURSOR *)dbc->internal; + + /* + * Adjustment will only be logged if this is a subtransaction. + * Only subtransactions can abort and effect their parent + * transactions cursors. + */ + + my_txn = IS_SUBTRANSACTION(dbc->txn) ? dbc->txn : NULL; + found = 0; + + MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp); + + /* + * Calcuate the order of this deleted record. + * This will be one grater than any cursor that is pointing + * at this record and already marked as deleted. + */ + order = 0; + if (!add) { + order = 1; + for (ldbp = __dblist_get(dbenv, dbp->adj_fileid); + ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid; + ldbp = LIST_NEXT(ldbp, dblistlinks)) { + MUTEX_THREAD_LOCK(dbenv, dbp->mutexp); + for (cp = TAILQ_FIRST(&ldbp->active_queue); cp != NULL; + cp = TAILQ_NEXT(cp, links)) { + if (cp == dbc || cp->dbtype != DB_HASH) + continue; + lcp = (HASH_CURSOR *)cp->internal; + if (F_ISSET(lcp, H_DELETED) && + hcp->pgno == lcp->pgno && + hcp->indx == lcp->indx && + order <= lcp->order && + (!is_dup || hcp->dup_off == lcp->dup_off)) + order = lcp->order +1; + } + MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp); + } + hcp->order = order; + } + + for (ldbp = __dblist_get(dbenv, dbp->adj_fileid); + ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid; + ldbp = LIST_NEXT(ldbp, dblistlinks)) { + MUTEX_THREAD_LOCK(dbenv, dbp->mutexp); + for (cp = TAILQ_FIRST(&ldbp->active_queue); cp != NULL; + cp = TAILQ_NEXT(cp, links)) { + if (cp == dbc || cp->dbtype != DB_HASH) + continue; + + lcp = (HASH_CURSOR *)cp->internal; + + if (lcp->pgno != hcp->pgno || lcp->indx == NDX_INVALID) + continue; + + if (my_txn != NULL && cp->txn != my_txn) + found = 1; + + if (!is_dup) { + if (add) { + /* + * This routine is not called to add + * non-dup records which are always put + * at the end. It is only called from + * recovery in this case and the + * cursor will be marked deleted. + * We are "undeleting" so unmark all + * cursors with the same order. + */ + if (lcp->indx == hcp->indx + && F_ISSET(lcp, H_DELETED)) { + if (lcp->order == hcp->order) + F_CLR(lcp, H_DELETED); + else if (lcp->order > + hcp->order) { + + /* + * If we've moved this cursor's + * index, split its order + * number--i.e., decrement it by + * enough so that the lowest + * cursor moved has order 1. + * cp_arg->order is the split + * point, so decrement by one + * less than that. + */ + lcp->order -= + (hcp->order - 1); + lcp->indx += 2; + } + } else if (lcp->indx >= hcp->indx) + lcp->indx += 2; + + } else { + if (lcp->indx > hcp->indx) { + lcp->indx -= 2; + if (lcp->indx == hcp->indx + && F_ISSET(lcp, H_DELETED)) + lcp->order += order; + } else if (lcp->indx == hcp->indx + && !F_ISSET(lcp, H_DELETED)) { + F_SET(lcp, H_DELETED); + lcp->order = order; + } + } + } else if (lcp->indx == hcp->indx) { + /* + * Handle duplicates. This routine is + * only called for on page dups. + * Off page dups are handled by btree/rtree + * code. + */ + if (add) { + lcp->dup_tlen += len; + if (lcp->dup_off == hcp->dup_off + && F_ISSET(hcp, H_DELETED) + && F_ISSET(lcp, H_DELETED)) { + /* Abort of a delete. */ + if (lcp->order == hcp->order) + F_CLR(lcp, H_DELETED); + else if (lcp->order > + hcp->order) { + lcp->order -= + (hcp->order -1); + lcp->dup_off += len; + } + } else if (lcp->dup_off >= hcp->dup_off) + lcp->dup_off += len; + } else { + lcp->dup_tlen -= len; + if (lcp->dup_off > hcp->dup_off) { + lcp->dup_off -= len; + if (lcp->dup_off == hcp->dup_off + && F_ISSET(lcp, H_DELETED)) + lcp->order += order; + } else if (lcp->dup_off == + hcp->dup_off && + !F_ISSET(lcp, H_DELETED)) { + F_SET(lcp, H_DELETED); + lcp->order = order; + } + } + } + } + MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp); + } + MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp); + + if (found != 0 && DB_LOGGING(dbc)) { + if ((ret = __ham_curadj_log(dbenv, + my_txn, &lsn, 0, dbp->log_fileid, hcp->pgno, + hcp->indx, len, hcp->dup_off, add, is_dup, order)) != 0) + return (ret); + } + + return (0); +} + +/* + * __ham_get_clist -- + * + * Get a list of cursors either on a particular bucket or on a particular + * page and index combination. The former is so that we can update + * cursors on a split. The latter is so we can update cursors when we + * move items off page. + * + * PUBLIC: int __ham_get_clist __P((DB *, + * PUBLIC: db_pgno_t, u_int32_t, DBC ***)); + */ +int +__ham_get_clist(dbp, bucket, indx, listp) + DB *dbp; + db_pgno_t bucket; + u_int32_t indx; + DBC ***listp; +{ + DB *ldbp; + DBC *cp; + DB_ENV *dbenv; + int nalloc, nused, ret; + + /* + * Assume that finding anything is the exception, so optimize for + * the case where there aren't any. + */ + nalloc = nused = 0; + *listp = NULL; + dbenv = dbp->dbenv; + + MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp); + for (ldbp = __dblist_get(dbenv, dbp->adj_fileid); + ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid; + ldbp = LIST_NEXT(ldbp, dblistlinks)) { + MUTEX_THREAD_LOCK(dbenv, dbp->mutexp); + for (cp = TAILQ_FIRST(&ldbp->active_queue); cp != NULL; + cp = TAILQ_NEXT(cp, links)) + if (cp->dbtype == DB_HASH && + ((indx == NDX_INVALID && + ((HASH_CURSOR *)(cp->internal))->bucket + == bucket) || (indx != NDX_INVALID && + cp->internal->pgno == bucket && + cp->internal->indx == indx))) { + if (nused >= nalloc) { + nalloc += 10; + if ((ret = __os_realloc(dbp->dbenv, + nalloc * sizeof(HASH_CURSOR *), + NULL, listp)) != 0) + return (ret); + } + (*listp)[nused++] = cp; + } + + MUTEX_THREAD_UNLOCK(dbp->dbenv, dbp->mutexp); + } + MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp); + + if (listp != NULL) { + if (nused >= nalloc) { + nalloc++; + if ((ret = __os_realloc(dbp->dbenv, + nalloc * sizeof(HASH_CURSOR *), NULL, listp)) != 0) + return (ret); + } + (*listp)[nused] = NULL; + } + return (0); +} + +static int +__ham_del_dups(orig_dbc, key) + DBC *orig_dbc; + DBT *key; +{ + DBC *dbc; + DBT data, lkey; + int ret, t_ret; + + /* Allocate a cursor. */ + if ((ret = orig_dbc->c_dup(orig_dbc, &dbc, 0)) != 0) + return (ret); + + /* + * Walk a cursor through the key/data pairs, deleting as we go. Set + * the DB_DBT_USERMEM flag, as this might be a threaded application + * and the flags checking will catch us. We don't actually want the + * keys or data, so request a partial of length 0. + */ + memset(&lkey, 0, sizeof(lkey)); + F_SET(&lkey, DB_DBT_USERMEM | DB_DBT_PARTIAL); + memset(&data, 0, sizeof(data)); + F_SET(&data, DB_DBT_USERMEM | DB_DBT_PARTIAL); + + /* Walk through the set of key/data pairs, deleting as we go. */ + if ((ret = dbc->c_get(dbc, key, &data, DB_SET)) != 0) { + if (ret == DB_NOTFOUND) + ret = 0; + goto err; + } + + for (;;) { + if ((ret = dbc->c_del(dbc, 0)) != 0) + goto err; + if ((ret = dbc->c_get(dbc, &lkey, &data, DB_NEXT_DUP)) != 0) { + if (ret == DB_NOTFOUND) { + ret = 0; + break; + } + goto err; + } + } + +err: /* + * Discard the cursor. This will cause the underlying off-page dup + * tree to go away as well as the actual entry on the page. + */ + if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0) + ret = t_ret; + + return (ret); + +} + +static int +__ham_c_writelock(dbc) + DBC *dbc; +{ + HASH_CURSOR *hcp; + DB_LOCK tmp_lock; + int ret; + + /* + * All we need do is acquire the lock and let the off-page + * dup tree do its thing. + */ + if (!STD_LOCKING(dbc)) + return (0); + + hcp = (HASH_CURSOR *)dbc->internal; + if ((hcp->lock.off == LOCK_INVALID || hcp->lock_mode == DB_LOCK_READ)) { + tmp_lock = hcp->lock; + if ((ret = __ham_lock_bucket(dbc, DB_LOCK_WRITE)) != 0) + return (ret); + if (tmp_lock.off != LOCK_INVALID && + (ret = lock_put(dbc->dbp->dbenv, &tmp_lock)) != 0) + return (ret); + } + return (0); +} + +/* + * __ham_c_chgpg -- + * + * Adjust the cursors after moving an item from one page to another. + * If the old_index is NDX_INVALID, that means that we copied the + * page wholesale and we're leaving indices intact and just changing + * the page number. + * + * PUBLIC: int __ham_c_chgpg + * PUBLIC: __P((DBC *, db_pgno_t, u_int32_t, db_pgno_t, u_int32_t)); + */ +int +__ham_c_chgpg(dbc, old_pgno, old_index, new_pgno, new_index) + DBC *dbc; + db_pgno_t old_pgno, new_pgno; + u_int32_t old_index, new_index; +{ + DB *dbp, *ldbp; + DB_ENV *dbenv; + DB_LSN lsn; + DB_TXN *my_txn; + DBC *cp; + HASH_CURSOR *hcp; + int found, ret; + + dbp = dbc->dbp; + dbenv = dbp->dbenv; + + my_txn = IS_SUBTRANSACTION(dbc->txn) ? dbc->txn : NULL; + found = 0; + + MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp); + for (ldbp = __dblist_get(dbenv, dbp->adj_fileid); + ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid; + ldbp = LIST_NEXT(ldbp, dblistlinks)) { + MUTEX_THREAD_LOCK(dbenv, dbp->mutexp); + for (cp = TAILQ_FIRST(&ldbp->active_queue); cp != NULL; + cp = TAILQ_NEXT(cp, links)) { + if (cp == dbc || cp->dbtype != DB_HASH) + continue; + + hcp = (HASH_CURSOR *)cp->internal; + if (hcp->pgno == old_pgno) { + if (old_index == NDX_INVALID) { + hcp->pgno = new_pgno; + } else if (hcp->indx == old_index) { + hcp->pgno = new_pgno; + hcp->indx = new_index; + } else + continue; + if (my_txn != NULL && cp->txn != my_txn) + found = 1; + } + } + MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp); + } + MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp); + + if (found != 0 && DB_LOGGING(dbc)) { + if ((ret = __ham_chgpg_log(dbenv, + my_txn, &lsn, 0, dbp->log_fileid, DB_HAM_CHGPG, + old_pgno, new_pgno, old_index, new_index)) != 0) + return (ret); + } + return (0); +} diff --git a/db/hash/hash.src b/db/hash/hash.src new file mode 100644 index 000000000..e6ecd11c9 --- /dev/null +++ b/db/hash/hash.src @@ -0,0 +1,361 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1995, 1996 + * Margo Seltzer. All rights reserved. + */ +/* + * Copyright (c) 1995, 1996 + * The President and Fellows of Harvard University. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Margo Seltzer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: hash.src,v 10.24 2000/12/12 17:41:48 bostic Exp $ + */ + +/* + * This is the source file used to create the logging functions for the + * hash package. Each access method (or set of routines wishing to register + * record types with the transaction system) should have a file like this. + * Each type of log record and its parameters is defined. The basic + * format of a record definition is: + * + * BEGIN + * ARG|STRING|POINTER + * ... + * END + * ARG the argument is a simple parameter of the type * specified. + * DBT the argument is a DBT (db.h) containing a length and pointer. + * PTR the argument is a pointer to the data type specified; the entire + * type should be logged. + * + * There are a set of shell scripts of the form xxx.sh that generate c + * code and or h files to process these. (This is probably better done + * in a single PERL script, but for now, this works.) + * + * The DB recovery system requires the following three fields appear in + * every record, and will assign them to the per-record-type structures + * as well as making them the first parameters to the appropriate logging + * call. + * rectype: record-type, identifies the structure and log/read call + * txnid: transaction id, a DBT in this implementation + * prev: the last LSN for this transaction + */ + +/* + * Use the argument of PREFIX as the prefix for all record types, + * routines, id numbers, etc. + */ +PREFIX ham + +INCLUDE #include "db_config.h" +INCLUDE +INCLUDE #ifndef NO_SYSTEM_INCLUDES +INCLUDE #include +INCLUDE +INCLUDE #include +INCLUDE #include +INCLUDE #include +INCLUDE #endif +INCLUDE +INCLUDE #include "db_int.h" +INCLUDE #include "db_page.h" +INCLUDE #include "db_dispatch.h" +INCLUDE #include "db_am.h" +INCLUDE #include "hash.h" +INCLUDE #include "txn.h" +INCLUDE + +/* + * HASH-insdel: used for hash to insert/delete a pair of entries onto a master + * page. The pair might be regular key/data pairs or they might be the + * structures that refer to off page items, duplicates or offpage duplicates. + * opcode - PUTPAIR/DELPAIR + big masks + * fileid - identifies the file referenced + * pgno - page within file + * ndx - index on the page of the item being added (item index) + * pagelsn - lsn on the page before the update + * key - the key being inserted + * data - the data being inserted + */ +BEGIN insdel 21 +ARG opcode u_int32_t lu +ARG fileid int32_t ld +ARG pgno db_pgno_t lu +ARG ndx u_int32_t lu +POINTER pagelsn DB_LSN * lu +DBT key DBT s +DBT data DBT s +END + +/* + * Used to add and remove overflow pages. + * prev_pgno is the previous page that is going to get modified to + * point to this one. If this is the first page in a chain + * then prev_pgno should be PGNO_INVALID. + * new_pgno is the page being allocated. + * next_pgno is the page that follows this one. On allocation, + * this should be PGNO_INVALID. For deletes, it may exist. + * pagelsn is the old lsn on the page. + */ +BEGIN newpage 22 +ARG opcode u_int32_t lu +ARG fileid int32_t ld +ARG prev_pgno db_pgno_t lu +POINTER prevlsn DB_LSN * lu +ARG new_pgno db_pgno_t lu +POINTER pagelsn DB_LSN * lu +ARG next_pgno db_pgno_t lu +POINTER nextlsn DB_LSN * lu +END + +/* + * DEPRECATED in 3.0. + * Superceded by metagroup which allocates a group of new pages. + * + * Splitting requires two types of log messages. The first logs the + * meta-data of the split. + * + * For the meta-data split + * bucket: max_bucket in table before split + * ovflpoint: overflow point before split. + * spares: spares[ovflpoint] before split. + */ +DEPRECATED splitmeta 23 +ARG fileid int32_t ld +ARG bucket u_int32_t lu +ARG ovflpoint u_int32_t lu +ARG spares u_int32_t lu +POINTER metalsn DB_LSN * lu +END + +/* + * Splitting requires two types of log messages. The second logs the + * data on the original page. To redo the split, we have to visit the + * new page (pages) and add the items back on the page if they are not + * yet there. + */ +BEGIN splitdata 24 +ARG fileid int32_t ld +ARG opcode u_int32_t lu +ARG pgno db_pgno_t lu +DBT pageimage DBT s +POINTER pagelsn DB_LSN * lu +END + +/* + * HASH-replace: is used for hash to handle partial puts that only + * affect a single master page. + * fileid - identifies the file referenced + * pgno - page within file + * ndx - index on the page of the item being modified (item index) + * pagelsn - lsn on the page before the update + * off - offset in the old item where the new item is going. + * olditem - DBT that describes the part of the item being replaced. + * newitem - DBT of the new item. + * makedup - this was a replacement that made an item a duplicate. + */ +BEGIN replace 25 +ARG fileid int32_t ld +ARG pgno db_pgno_t lu +ARG ndx u_int32_t lu +POINTER pagelsn DB_LSN * lu +ARG off int32_t ld +DBT olditem DBT s +DBT newitem DBT s +ARG makedup u_int32_t lu +END + +/* + * DEPRECATED in 3.0. + * Hash now uses the btree allocation and deletion page routines. + * + * HASH-newpgno: is used to record getting/deleting a new page number. + * This doesn't require much data modification, just modifying the + * meta-data. + * pgno is the page being allocated/freed. + * free_pgno is the next_pgno on the free list. + * old_type was the type of a page being deallocated. + * old_pgno was the next page number before the deallocation. + */ +DEPRECATED newpgno 26 +ARG opcode u_int32_t lu +ARG fileid int32_t ld +ARG pgno db_pgno_t lu +ARG free_pgno db_pgno_t lu +ARG old_type u_int32_t lu +ARG old_pgno db_pgno_t lu +ARG new_type u_int32_t lu +POINTER pagelsn DB_LSN * lu +POINTER metalsn DB_LSN * lu +END + +/* + * DEPRECATED in 3.0. + * Since we now pre-allocate the contiguous chunk of pages for a doubling, + * there is no big benefit to pre-allocating a few extra pages. It used + * to be that the file was only physically as large as the current bucket, + * so if you were on a doubling of 16K, but were only on the first bucket + * of that 16K, the file was much shorter than it would be at the end of + * the doubling, so we didn't want to force overflow pages at the end of the + * 16K pages. Since we now must allocate the 16K pages (because of sub + * databases), it's not a big deal to tack extra pages on at the end. + * + * ovfl: initialize a set of overflow pages. + */ +DEPRECATED ovfl 27 +ARG fileid int32_t ld +ARG start_pgno db_pgno_t lu +ARG npages u_int32_t lu +ARG free_pgno db_pgno_t lu +ARG ovflpoint u_int32_t lu +POINTER metalsn DB_LSN * lu +END + +/* + * Used when we empty the first page in a bucket and there are pages after + * it. The page after it gets copied into the bucket page (since bucket + * pages have to be in fixed locations). + * pgno: the bucket page + * pagelsn: the old LSN on the bucket page + * next_pgno: the page number of the next page + * nnext_pgno: page after next_pgno (may need to change its prev) + * nnextlsn: the LSN of nnext_pgno. + */ +BEGIN copypage 28 +ARG fileid int32_t ld +ARG pgno db_pgno_t lu +POINTER pagelsn DB_LSN * lu +ARG next_pgno db_pgno_t lu +POINTER nextlsn DB_LSN * lu +ARG nnext_pgno db_pgno_t lu +POINTER nnextlsn DB_LSN * lu +DBT page DBT s +END + +/* + * This replaces the old splitmeta operation. It behaves largely the same + * way, but it has enough information so that we can record a group allocation + * which we do now because of sub databases. The number of pages allocated is + * always bucket + 1 pgno is the page number of the first newly allocated + * bucket. + * bucket: Old maximum bucket number. + * pgno: Page allocated to bucket + 1 (first newly allocated page) + * metalsn: Lsn of the meta-data page. + * pagelsn: Lsn of the maximum page allocated. + */ +BEGIN metagroup 29 +ARG fileid int32_t ld +ARG bucket u_int32_t lu +ARG pgno db_pgno_t lu +POINTER metalsn DB_LSN * lu +POINTER pagelsn DB_LSN * lu +END + +/* + * groupalloc + * + * This is used in conjunction with MPOOL_NEW_GROUP when we are creating + * a new database to make sure that we recreate or reclaim free pages + * when we allocate a chunk of contiguous ones during database creation. + * + * pgno: meta-data page number + * metalsn: meta-data lsn + * start_pgno: starting page number + * num: number of allocated pages + */ +DEPRECATED groupalloc1 30 +ARG fileid int32_t ld +ARG pgno db_pgno_t lu +POINTER metalsn DB_LSN * lu +POINTER mmetalsn DB_LSN * lu +ARG start_pgno db_pgno_t lu +ARG num u_int32_t lu +END + +DEPRECATED groupalloc2 31 +ARG fileid int32_t ld +POINTER meta_lsn DB_LSN * lu +POINTER alloc_lsn DB_LSN * lu +ARG start_pgno db_pgno_t lu +ARG num u_int32_t lu +ARG free db_pgno_t lu +END + +BEGIN groupalloc 32 +ARG fileid int32_t ld +POINTER meta_lsn DB_LSN * lu +ARG start_pgno db_pgno_t lu +ARG num u_int32_t lu +ARG free db_pgno_t lu +END + +/* + * Records for backing out cursor adjustment. + * curadj - added or deleted a record or a dup + * within a record. + * pgno - page that was effected + * indx - indx of recrod effected. + * len - if a dup its length. + * dup_off - if a dup its offset + * add - 1 if add 0 if delete + * is_dup - 1 if dup 0 otherwise. + * order - order assinged to this deleted record or dup. + * + * chgpg - rmoved a page, move the records to a new page + * mode - CHGPG page was deleted or records move to new page. + * - SPLIT we split a bucket + * - DUP we convered to off page duplicates. + * old_pgno, new_pgno - old and new page numbers. + * old_index, new_index - old and new index numbers, NDX_INVALID if + * it effects all records on the page. + */ +BEGIN curadj 33 +ARG fileid int32_t ld +ARG pgno db_pgno_t lu +ARG indx u_int32_t lu +ARG len u_int32_t lu +ARG dup_off u_int32_t lu +ARG add int ld +ARG is_dup int ld +ARG order u_int32_t lu +END + +BEGIN chgpg 34 +ARG fileid int32_t ld +ARG mode db_ham_mode ld +ARG old_pgno db_pgno_t lu +ARG new_pgno db_pgno_t lu +ARG old_indx u_int32_t lu +ARG new_indx u_int32_t lu +END + diff --git a/db/hash/hash_auto.c b/db/hash/hash_auto.c new file mode 100644 index 000000000..b6faf4f56 --- /dev/null +++ b/db/hash/hash_auto.c @@ -0,0 +1,2023 @@ +/* Do not edit: automatically built by gen_rec.awk. */ +#include "db_config.h" + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_dispatch.h" +#include "db_am.h" +#include "hash.h" +#include "txn.h" + +int +__ham_insdel_log(dbenv, txnid, ret_lsnp, flags, + opcode, fileid, pgno, ndx, pagelsn, key, + data) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + u_int32_t opcode; + int32_t fileid; + db_pgno_t pgno; + u_int32_t ndx; + DB_LSN * pagelsn; + const DBT *key; + const DBT *data; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t zero; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_ham_insdel; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(opcode) + + sizeof(fileid) + + sizeof(pgno) + + sizeof(ndx) + + sizeof(*pagelsn) + + sizeof(u_int32_t) + (key == NULL ? 0 : key->size) + + sizeof(u_int32_t) + (data == NULL ? 0 : data->size); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &opcode, sizeof(opcode)); + bp += sizeof(opcode); + memcpy(bp, &fileid, sizeof(fileid)); + bp += sizeof(fileid); + memcpy(bp, &pgno, sizeof(pgno)); + bp += sizeof(pgno); + memcpy(bp, &ndx, sizeof(ndx)); + bp += sizeof(ndx); + if (pagelsn != NULL) + memcpy(bp, pagelsn, sizeof(*pagelsn)); + else + memset(bp, 0, sizeof(*pagelsn)); + bp += sizeof(*pagelsn); + if (key == NULL) { + zero = 0; + memcpy(bp, &zero, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + } else { + memcpy(bp, &key->size, sizeof(key->size)); + bp += sizeof(key->size); + memcpy(bp, key->data, key->size); + bp += key->size; + } + if (data == NULL) { + zero = 0; + memcpy(bp, &zero, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + } else { + memcpy(bp, &data->size, sizeof(data->size)); + bp += sizeof(data->size); + memcpy(bp, data->data, data->size); + bp += data->size; + } + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__ham_insdel_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __ham_insdel_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __ham_insdel_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]ham_insdel: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\topcode: %lu\n", (u_long)argp->opcode); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tpgno: %lu\n", (u_long)argp->pgno); + printf("\tndx: %lu\n", (u_long)argp->ndx); + printf("\tpagelsn: [%lu][%lu]\n", + (u_long)argp->pagelsn.file, (u_long)argp->pagelsn.offset); + printf("\tkey: "); + for (i = 0; i < argp->key.size; i++) { + ch = ((u_int8_t *)argp->key.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\tdata: "); + for (i = 0; i < argp->data.size; i++) { + ch = ((u_int8_t *)argp->data.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__ham_insdel_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __ham_insdel_args **argpp; +{ + __ham_insdel_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__ham_insdel_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->opcode, bp, sizeof(argp->opcode)); + bp += sizeof(argp->opcode); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->pgno, bp, sizeof(argp->pgno)); + bp += sizeof(argp->pgno); + memcpy(&argp->ndx, bp, sizeof(argp->ndx)); + bp += sizeof(argp->ndx); + memcpy(&argp->pagelsn, bp, sizeof(argp->pagelsn)); + bp += sizeof(argp->pagelsn); + memset(&argp->key, 0, sizeof(argp->key)); + memcpy(&argp->key.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->key.data = bp; + bp += argp->key.size; + memset(&argp->data, 0, sizeof(argp->data)); + memcpy(&argp->data.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->data.data = bp; + bp += argp->data.size; + *argpp = argp; + return (0); +} + +int +__ham_newpage_log(dbenv, txnid, ret_lsnp, flags, + opcode, fileid, prev_pgno, prevlsn, new_pgno, pagelsn, + next_pgno, nextlsn) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + u_int32_t opcode; + int32_t fileid; + db_pgno_t prev_pgno; + DB_LSN * prevlsn; + db_pgno_t new_pgno; + DB_LSN * pagelsn; + db_pgno_t next_pgno; + DB_LSN * nextlsn; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_ham_newpage; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(opcode) + + sizeof(fileid) + + sizeof(prev_pgno) + + sizeof(*prevlsn) + + sizeof(new_pgno) + + sizeof(*pagelsn) + + sizeof(next_pgno) + + sizeof(*nextlsn); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &opcode, sizeof(opcode)); + bp += sizeof(opcode); + memcpy(bp, &fileid, sizeof(fileid)); + bp += sizeof(fileid); + memcpy(bp, &prev_pgno, sizeof(prev_pgno)); + bp += sizeof(prev_pgno); + if (prevlsn != NULL) + memcpy(bp, prevlsn, sizeof(*prevlsn)); + else + memset(bp, 0, sizeof(*prevlsn)); + bp += sizeof(*prevlsn); + memcpy(bp, &new_pgno, sizeof(new_pgno)); + bp += sizeof(new_pgno); + if (pagelsn != NULL) + memcpy(bp, pagelsn, sizeof(*pagelsn)); + else + memset(bp, 0, sizeof(*pagelsn)); + bp += sizeof(*pagelsn); + memcpy(bp, &next_pgno, sizeof(next_pgno)); + bp += sizeof(next_pgno); + if (nextlsn != NULL) + memcpy(bp, nextlsn, sizeof(*nextlsn)); + else + memset(bp, 0, sizeof(*nextlsn)); + bp += sizeof(*nextlsn); + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__ham_newpage_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __ham_newpage_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __ham_newpage_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]ham_newpage: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\topcode: %lu\n", (u_long)argp->opcode); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tprev_pgno: %lu\n", (u_long)argp->prev_pgno); + printf("\tprevlsn: [%lu][%lu]\n", + (u_long)argp->prevlsn.file, (u_long)argp->prevlsn.offset); + printf("\tnew_pgno: %lu\n", (u_long)argp->new_pgno); + printf("\tpagelsn: [%lu][%lu]\n", + (u_long)argp->pagelsn.file, (u_long)argp->pagelsn.offset); + printf("\tnext_pgno: %lu\n", (u_long)argp->next_pgno); + printf("\tnextlsn: [%lu][%lu]\n", + (u_long)argp->nextlsn.file, (u_long)argp->nextlsn.offset); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__ham_newpage_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __ham_newpage_args **argpp; +{ + __ham_newpage_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__ham_newpage_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->opcode, bp, sizeof(argp->opcode)); + bp += sizeof(argp->opcode); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->prev_pgno, bp, sizeof(argp->prev_pgno)); + bp += sizeof(argp->prev_pgno); + memcpy(&argp->prevlsn, bp, sizeof(argp->prevlsn)); + bp += sizeof(argp->prevlsn); + memcpy(&argp->new_pgno, bp, sizeof(argp->new_pgno)); + bp += sizeof(argp->new_pgno); + memcpy(&argp->pagelsn, bp, sizeof(argp->pagelsn)); + bp += sizeof(argp->pagelsn); + memcpy(&argp->next_pgno, bp, sizeof(argp->next_pgno)); + bp += sizeof(argp->next_pgno); + memcpy(&argp->nextlsn, bp, sizeof(argp->nextlsn)); + bp += sizeof(argp->nextlsn); + *argpp = argp; + return (0); +} + +int +__ham_splitmeta_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __ham_splitmeta_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __ham_splitmeta_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]ham_splitmeta: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tbucket: %lu\n", (u_long)argp->bucket); + printf("\tovflpoint: %lu\n", (u_long)argp->ovflpoint); + printf("\tspares: %lu\n", (u_long)argp->spares); + printf("\tmetalsn: [%lu][%lu]\n", + (u_long)argp->metalsn.file, (u_long)argp->metalsn.offset); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__ham_splitmeta_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __ham_splitmeta_args **argpp; +{ + __ham_splitmeta_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__ham_splitmeta_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->bucket, bp, sizeof(argp->bucket)); + bp += sizeof(argp->bucket); + memcpy(&argp->ovflpoint, bp, sizeof(argp->ovflpoint)); + bp += sizeof(argp->ovflpoint); + memcpy(&argp->spares, bp, sizeof(argp->spares)); + bp += sizeof(argp->spares); + memcpy(&argp->metalsn, bp, sizeof(argp->metalsn)); + bp += sizeof(argp->metalsn); + *argpp = argp; + return (0); +} + +int +__ham_splitdata_log(dbenv, txnid, ret_lsnp, flags, + fileid, opcode, pgno, pageimage, pagelsn) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + int32_t fileid; + u_int32_t opcode; + db_pgno_t pgno; + const DBT *pageimage; + DB_LSN * pagelsn; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t zero; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_ham_splitdata; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(fileid) + + sizeof(opcode) + + sizeof(pgno) + + sizeof(u_int32_t) + (pageimage == NULL ? 0 : pageimage->size) + + sizeof(*pagelsn); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &fileid, sizeof(fileid)); + bp += sizeof(fileid); + memcpy(bp, &opcode, sizeof(opcode)); + bp += sizeof(opcode); + memcpy(bp, &pgno, sizeof(pgno)); + bp += sizeof(pgno); + if (pageimage == NULL) { + zero = 0; + memcpy(bp, &zero, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + } else { + memcpy(bp, &pageimage->size, sizeof(pageimage->size)); + bp += sizeof(pageimage->size); + memcpy(bp, pageimage->data, pageimage->size); + bp += pageimage->size; + } + if (pagelsn != NULL) + memcpy(bp, pagelsn, sizeof(*pagelsn)); + else + memset(bp, 0, sizeof(*pagelsn)); + bp += sizeof(*pagelsn); + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__ham_splitdata_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __ham_splitdata_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __ham_splitdata_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]ham_splitdata: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\topcode: %lu\n", (u_long)argp->opcode); + printf("\tpgno: %lu\n", (u_long)argp->pgno); + printf("\tpageimage: "); + for (i = 0; i < argp->pageimage.size; i++) { + ch = ((u_int8_t *)argp->pageimage.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\tpagelsn: [%lu][%lu]\n", + (u_long)argp->pagelsn.file, (u_long)argp->pagelsn.offset); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__ham_splitdata_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __ham_splitdata_args **argpp; +{ + __ham_splitdata_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__ham_splitdata_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->opcode, bp, sizeof(argp->opcode)); + bp += sizeof(argp->opcode); + memcpy(&argp->pgno, bp, sizeof(argp->pgno)); + bp += sizeof(argp->pgno); + memset(&argp->pageimage, 0, sizeof(argp->pageimage)); + memcpy(&argp->pageimage.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->pageimage.data = bp; + bp += argp->pageimage.size; + memcpy(&argp->pagelsn, bp, sizeof(argp->pagelsn)); + bp += sizeof(argp->pagelsn); + *argpp = argp; + return (0); +} + +int +__ham_replace_log(dbenv, txnid, ret_lsnp, flags, + fileid, pgno, ndx, pagelsn, off, olditem, + newitem, makedup) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + int32_t fileid; + db_pgno_t pgno; + u_int32_t ndx; + DB_LSN * pagelsn; + int32_t off; + const DBT *olditem; + const DBT *newitem; + u_int32_t makedup; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t zero; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_ham_replace; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(fileid) + + sizeof(pgno) + + sizeof(ndx) + + sizeof(*pagelsn) + + sizeof(off) + + sizeof(u_int32_t) + (olditem == NULL ? 0 : olditem->size) + + sizeof(u_int32_t) + (newitem == NULL ? 0 : newitem->size) + + sizeof(makedup); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &fileid, sizeof(fileid)); + bp += sizeof(fileid); + memcpy(bp, &pgno, sizeof(pgno)); + bp += sizeof(pgno); + memcpy(bp, &ndx, sizeof(ndx)); + bp += sizeof(ndx); + if (pagelsn != NULL) + memcpy(bp, pagelsn, sizeof(*pagelsn)); + else + memset(bp, 0, sizeof(*pagelsn)); + bp += sizeof(*pagelsn); + memcpy(bp, &off, sizeof(off)); + bp += sizeof(off); + if (olditem == NULL) { + zero = 0; + memcpy(bp, &zero, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + } else { + memcpy(bp, &olditem->size, sizeof(olditem->size)); + bp += sizeof(olditem->size); + memcpy(bp, olditem->data, olditem->size); + bp += olditem->size; + } + if (newitem == NULL) { + zero = 0; + memcpy(bp, &zero, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + } else { + memcpy(bp, &newitem->size, sizeof(newitem->size)); + bp += sizeof(newitem->size); + memcpy(bp, newitem->data, newitem->size); + bp += newitem->size; + } + memcpy(bp, &makedup, sizeof(makedup)); + bp += sizeof(makedup); + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__ham_replace_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __ham_replace_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __ham_replace_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]ham_replace: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tpgno: %lu\n", (u_long)argp->pgno); + printf("\tndx: %lu\n", (u_long)argp->ndx); + printf("\tpagelsn: [%lu][%lu]\n", + (u_long)argp->pagelsn.file, (u_long)argp->pagelsn.offset); + printf("\toff: %ld\n", (long)argp->off); + printf("\tolditem: "); + for (i = 0; i < argp->olditem.size; i++) { + ch = ((u_int8_t *)argp->olditem.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\tnewitem: "); + for (i = 0; i < argp->newitem.size; i++) { + ch = ((u_int8_t *)argp->newitem.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\tmakedup: %lu\n", (u_long)argp->makedup); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__ham_replace_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __ham_replace_args **argpp; +{ + __ham_replace_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__ham_replace_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->pgno, bp, sizeof(argp->pgno)); + bp += sizeof(argp->pgno); + memcpy(&argp->ndx, bp, sizeof(argp->ndx)); + bp += sizeof(argp->ndx); + memcpy(&argp->pagelsn, bp, sizeof(argp->pagelsn)); + bp += sizeof(argp->pagelsn); + memcpy(&argp->off, bp, sizeof(argp->off)); + bp += sizeof(argp->off); + memset(&argp->olditem, 0, sizeof(argp->olditem)); + memcpy(&argp->olditem.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->olditem.data = bp; + bp += argp->olditem.size; + memset(&argp->newitem, 0, sizeof(argp->newitem)); + memcpy(&argp->newitem.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->newitem.data = bp; + bp += argp->newitem.size; + memcpy(&argp->makedup, bp, sizeof(argp->makedup)); + bp += sizeof(argp->makedup); + *argpp = argp; + return (0); +} + +int +__ham_newpgno_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __ham_newpgno_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __ham_newpgno_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]ham_newpgno: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\topcode: %lu\n", (u_long)argp->opcode); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tpgno: %lu\n", (u_long)argp->pgno); + printf("\tfree_pgno: %lu\n", (u_long)argp->free_pgno); + printf("\told_type: %lu\n", (u_long)argp->old_type); + printf("\told_pgno: %lu\n", (u_long)argp->old_pgno); + printf("\tnew_type: %lu\n", (u_long)argp->new_type); + printf("\tpagelsn: [%lu][%lu]\n", + (u_long)argp->pagelsn.file, (u_long)argp->pagelsn.offset); + printf("\tmetalsn: [%lu][%lu]\n", + (u_long)argp->metalsn.file, (u_long)argp->metalsn.offset); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__ham_newpgno_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __ham_newpgno_args **argpp; +{ + __ham_newpgno_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__ham_newpgno_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->opcode, bp, sizeof(argp->opcode)); + bp += sizeof(argp->opcode); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->pgno, bp, sizeof(argp->pgno)); + bp += sizeof(argp->pgno); + memcpy(&argp->free_pgno, bp, sizeof(argp->free_pgno)); + bp += sizeof(argp->free_pgno); + memcpy(&argp->old_type, bp, sizeof(argp->old_type)); + bp += sizeof(argp->old_type); + memcpy(&argp->old_pgno, bp, sizeof(argp->old_pgno)); + bp += sizeof(argp->old_pgno); + memcpy(&argp->new_type, bp, sizeof(argp->new_type)); + bp += sizeof(argp->new_type); + memcpy(&argp->pagelsn, bp, sizeof(argp->pagelsn)); + bp += sizeof(argp->pagelsn); + memcpy(&argp->metalsn, bp, sizeof(argp->metalsn)); + bp += sizeof(argp->metalsn); + *argpp = argp; + return (0); +} + +int +__ham_ovfl_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __ham_ovfl_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __ham_ovfl_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]ham_ovfl: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tstart_pgno: %lu\n", (u_long)argp->start_pgno); + printf("\tnpages: %lu\n", (u_long)argp->npages); + printf("\tfree_pgno: %lu\n", (u_long)argp->free_pgno); + printf("\tovflpoint: %lu\n", (u_long)argp->ovflpoint); + printf("\tmetalsn: [%lu][%lu]\n", + (u_long)argp->metalsn.file, (u_long)argp->metalsn.offset); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__ham_ovfl_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __ham_ovfl_args **argpp; +{ + __ham_ovfl_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__ham_ovfl_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->start_pgno, bp, sizeof(argp->start_pgno)); + bp += sizeof(argp->start_pgno); + memcpy(&argp->npages, bp, sizeof(argp->npages)); + bp += sizeof(argp->npages); + memcpy(&argp->free_pgno, bp, sizeof(argp->free_pgno)); + bp += sizeof(argp->free_pgno); + memcpy(&argp->ovflpoint, bp, sizeof(argp->ovflpoint)); + bp += sizeof(argp->ovflpoint); + memcpy(&argp->metalsn, bp, sizeof(argp->metalsn)); + bp += sizeof(argp->metalsn); + *argpp = argp; + return (0); +} + +int +__ham_copypage_log(dbenv, txnid, ret_lsnp, flags, + fileid, pgno, pagelsn, next_pgno, nextlsn, nnext_pgno, + nnextlsn, page) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + int32_t fileid; + db_pgno_t pgno; + DB_LSN * pagelsn; + db_pgno_t next_pgno; + DB_LSN * nextlsn; + db_pgno_t nnext_pgno; + DB_LSN * nnextlsn; + const DBT *page; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t zero; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_ham_copypage; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(fileid) + + sizeof(pgno) + + sizeof(*pagelsn) + + sizeof(next_pgno) + + sizeof(*nextlsn) + + sizeof(nnext_pgno) + + sizeof(*nnextlsn) + + sizeof(u_int32_t) + (page == NULL ? 0 : page->size); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &fileid, sizeof(fileid)); + bp += sizeof(fileid); + memcpy(bp, &pgno, sizeof(pgno)); + bp += sizeof(pgno); + if (pagelsn != NULL) + memcpy(bp, pagelsn, sizeof(*pagelsn)); + else + memset(bp, 0, sizeof(*pagelsn)); + bp += sizeof(*pagelsn); + memcpy(bp, &next_pgno, sizeof(next_pgno)); + bp += sizeof(next_pgno); + if (nextlsn != NULL) + memcpy(bp, nextlsn, sizeof(*nextlsn)); + else + memset(bp, 0, sizeof(*nextlsn)); + bp += sizeof(*nextlsn); + memcpy(bp, &nnext_pgno, sizeof(nnext_pgno)); + bp += sizeof(nnext_pgno); + if (nnextlsn != NULL) + memcpy(bp, nnextlsn, sizeof(*nnextlsn)); + else + memset(bp, 0, sizeof(*nnextlsn)); + bp += sizeof(*nnextlsn); + if (page == NULL) { + zero = 0; + memcpy(bp, &zero, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + } else { + memcpy(bp, &page->size, sizeof(page->size)); + bp += sizeof(page->size); + memcpy(bp, page->data, page->size); + bp += page->size; + } + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__ham_copypage_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __ham_copypage_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __ham_copypage_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]ham_copypage: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tpgno: %lu\n", (u_long)argp->pgno); + printf("\tpagelsn: [%lu][%lu]\n", + (u_long)argp->pagelsn.file, (u_long)argp->pagelsn.offset); + printf("\tnext_pgno: %lu\n", (u_long)argp->next_pgno); + printf("\tnextlsn: [%lu][%lu]\n", + (u_long)argp->nextlsn.file, (u_long)argp->nextlsn.offset); + printf("\tnnext_pgno: %lu\n", (u_long)argp->nnext_pgno); + printf("\tnnextlsn: [%lu][%lu]\n", + (u_long)argp->nnextlsn.file, (u_long)argp->nnextlsn.offset); + printf("\tpage: "); + for (i = 0; i < argp->page.size; i++) { + ch = ((u_int8_t *)argp->page.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__ham_copypage_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __ham_copypage_args **argpp; +{ + __ham_copypage_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__ham_copypage_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->pgno, bp, sizeof(argp->pgno)); + bp += sizeof(argp->pgno); + memcpy(&argp->pagelsn, bp, sizeof(argp->pagelsn)); + bp += sizeof(argp->pagelsn); + memcpy(&argp->next_pgno, bp, sizeof(argp->next_pgno)); + bp += sizeof(argp->next_pgno); + memcpy(&argp->nextlsn, bp, sizeof(argp->nextlsn)); + bp += sizeof(argp->nextlsn); + memcpy(&argp->nnext_pgno, bp, sizeof(argp->nnext_pgno)); + bp += sizeof(argp->nnext_pgno); + memcpy(&argp->nnextlsn, bp, sizeof(argp->nnextlsn)); + bp += sizeof(argp->nnextlsn); + memset(&argp->page, 0, sizeof(argp->page)); + memcpy(&argp->page.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->page.data = bp; + bp += argp->page.size; + *argpp = argp; + return (0); +} + +int +__ham_metagroup_log(dbenv, txnid, ret_lsnp, flags, + fileid, bucket, pgno, metalsn, pagelsn) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + int32_t fileid; + u_int32_t bucket; + db_pgno_t pgno; + DB_LSN * metalsn; + DB_LSN * pagelsn; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_ham_metagroup; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(fileid) + + sizeof(bucket) + + sizeof(pgno) + + sizeof(*metalsn) + + sizeof(*pagelsn); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &fileid, sizeof(fileid)); + bp += sizeof(fileid); + memcpy(bp, &bucket, sizeof(bucket)); + bp += sizeof(bucket); + memcpy(bp, &pgno, sizeof(pgno)); + bp += sizeof(pgno); + if (metalsn != NULL) + memcpy(bp, metalsn, sizeof(*metalsn)); + else + memset(bp, 0, sizeof(*metalsn)); + bp += sizeof(*metalsn); + if (pagelsn != NULL) + memcpy(bp, pagelsn, sizeof(*pagelsn)); + else + memset(bp, 0, sizeof(*pagelsn)); + bp += sizeof(*pagelsn); + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__ham_metagroup_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __ham_metagroup_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __ham_metagroup_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]ham_metagroup: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tbucket: %lu\n", (u_long)argp->bucket); + printf("\tpgno: %lu\n", (u_long)argp->pgno); + printf("\tmetalsn: [%lu][%lu]\n", + (u_long)argp->metalsn.file, (u_long)argp->metalsn.offset); + printf("\tpagelsn: [%lu][%lu]\n", + (u_long)argp->pagelsn.file, (u_long)argp->pagelsn.offset); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__ham_metagroup_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __ham_metagroup_args **argpp; +{ + __ham_metagroup_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__ham_metagroup_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->bucket, bp, sizeof(argp->bucket)); + bp += sizeof(argp->bucket); + memcpy(&argp->pgno, bp, sizeof(argp->pgno)); + bp += sizeof(argp->pgno); + memcpy(&argp->metalsn, bp, sizeof(argp->metalsn)); + bp += sizeof(argp->metalsn); + memcpy(&argp->pagelsn, bp, sizeof(argp->pagelsn)); + bp += sizeof(argp->pagelsn); + *argpp = argp; + return (0); +} + +int +__ham_groupalloc1_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __ham_groupalloc1_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __ham_groupalloc1_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]ham_groupalloc1: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tpgno: %lu\n", (u_long)argp->pgno); + printf("\tmetalsn: [%lu][%lu]\n", + (u_long)argp->metalsn.file, (u_long)argp->metalsn.offset); + printf("\tmmetalsn: [%lu][%lu]\n", + (u_long)argp->mmetalsn.file, (u_long)argp->mmetalsn.offset); + printf("\tstart_pgno: %lu\n", (u_long)argp->start_pgno); + printf("\tnum: %lu\n", (u_long)argp->num); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__ham_groupalloc1_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __ham_groupalloc1_args **argpp; +{ + __ham_groupalloc1_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__ham_groupalloc1_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->pgno, bp, sizeof(argp->pgno)); + bp += sizeof(argp->pgno); + memcpy(&argp->metalsn, bp, sizeof(argp->metalsn)); + bp += sizeof(argp->metalsn); + memcpy(&argp->mmetalsn, bp, sizeof(argp->mmetalsn)); + bp += sizeof(argp->mmetalsn); + memcpy(&argp->start_pgno, bp, sizeof(argp->start_pgno)); + bp += sizeof(argp->start_pgno); + memcpy(&argp->num, bp, sizeof(argp->num)); + bp += sizeof(argp->num); + *argpp = argp; + return (0); +} + +int +__ham_groupalloc2_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __ham_groupalloc2_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __ham_groupalloc2_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]ham_groupalloc2: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tmeta_lsn: [%lu][%lu]\n", + (u_long)argp->meta_lsn.file, (u_long)argp->meta_lsn.offset); + printf("\talloc_lsn: [%lu][%lu]\n", + (u_long)argp->alloc_lsn.file, (u_long)argp->alloc_lsn.offset); + printf("\tstart_pgno: %lu\n", (u_long)argp->start_pgno); + printf("\tnum: %lu\n", (u_long)argp->num); + printf("\tfree: %lu\n", (u_long)argp->free); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__ham_groupalloc2_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __ham_groupalloc2_args **argpp; +{ + __ham_groupalloc2_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__ham_groupalloc2_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->meta_lsn, bp, sizeof(argp->meta_lsn)); + bp += sizeof(argp->meta_lsn); + memcpy(&argp->alloc_lsn, bp, sizeof(argp->alloc_lsn)); + bp += sizeof(argp->alloc_lsn); + memcpy(&argp->start_pgno, bp, sizeof(argp->start_pgno)); + bp += sizeof(argp->start_pgno); + memcpy(&argp->num, bp, sizeof(argp->num)); + bp += sizeof(argp->num); + memcpy(&argp->free, bp, sizeof(argp->free)); + bp += sizeof(argp->free); + *argpp = argp; + return (0); +} + +int +__ham_groupalloc_log(dbenv, txnid, ret_lsnp, flags, + fileid, meta_lsn, start_pgno, num, free) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + int32_t fileid; + DB_LSN * meta_lsn; + db_pgno_t start_pgno; + u_int32_t num; + db_pgno_t free; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_ham_groupalloc; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(fileid) + + sizeof(*meta_lsn) + + sizeof(start_pgno) + + sizeof(num) + + sizeof(free); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &fileid, sizeof(fileid)); + bp += sizeof(fileid); + if (meta_lsn != NULL) + memcpy(bp, meta_lsn, sizeof(*meta_lsn)); + else + memset(bp, 0, sizeof(*meta_lsn)); + bp += sizeof(*meta_lsn); + memcpy(bp, &start_pgno, sizeof(start_pgno)); + bp += sizeof(start_pgno); + memcpy(bp, &num, sizeof(num)); + bp += sizeof(num); + memcpy(bp, &free, sizeof(free)); + bp += sizeof(free); + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__ham_groupalloc_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __ham_groupalloc_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __ham_groupalloc_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]ham_groupalloc: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tmeta_lsn: [%lu][%lu]\n", + (u_long)argp->meta_lsn.file, (u_long)argp->meta_lsn.offset); + printf("\tstart_pgno: %lu\n", (u_long)argp->start_pgno); + printf("\tnum: %lu\n", (u_long)argp->num); + printf("\tfree: %lu\n", (u_long)argp->free); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__ham_groupalloc_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __ham_groupalloc_args **argpp; +{ + __ham_groupalloc_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__ham_groupalloc_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->meta_lsn, bp, sizeof(argp->meta_lsn)); + bp += sizeof(argp->meta_lsn); + memcpy(&argp->start_pgno, bp, sizeof(argp->start_pgno)); + bp += sizeof(argp->start_pgno); + memcpy(&argp->num, bp, sizeof(argp->num)); + bp += sizeof(argp->num); + memcpy(&argp->free, bp, sizeof(argp->free)); + bp += sizeof(argp->free); + *argpp = argp; + return (0); +} + +int +__ham_curadj_log(dbenv, txnid, ret_lsnp, flags, + fileid, pgno, indx, len, dup_off, add, + is_dup, order) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + int32_t fileid; + db_pgno_t pgno; + u_int32_t indx; + u_int32_t len; + u_int32_t dup_off; + int add; + int is_dup; + u_int32_t order; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_ham_curadj; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(fileid) + + sizeof(pgno) + + sizeof(indx) + + sizeof(len) + + sizeof(dup_off) + + sizeof(add) + + sizeof(is_dup) + + sizeof(order); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &fileid, sizeof(fileid)); + bp += sizeof(fileid); + memcpy(bp, &pgno, sizeof(pgno)); + bp += sizeof(pgno); + memcpy(bp, &indx, sizeof(indx)); + bp += sizeof(indx); + memcpy(bp, &len, sizeof(len)); + bp += sizeof(len); + memcpy(bp, &dup_off, sizeof(dup_off)); + bp += sizeof(dup_off); + memcpy(bp, &add, sizeof(add)); + bp += sizeof(add); + memcpy(bp, &is_dup, sizeof(is_dup)); + bp += sizeof(is_dup); + memcpy(bp, &order, sizeof(order)); + bp += sizeof(order); + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__ham_curadj_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __ham_curadj_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __ham_curadj_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]ham_curadj: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tpgno: %lu\n", (u_long)argp->pgno); + printf("\tindx: %lu\n", (u_long)argp->indx); + printf("\tlen: %lu\n", (u_long)argp->len); + printf("\tdup_off: %lu\n", (u_long)argp->dup_off); + printf("\tadd: %ld\n", (long)argp->add); + printf("\tis_dup: %ld\n", (long)argp->is_dup); + printf("\torder: %lu\n", (u_long)argp->order); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__ham_curadj_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __ham_curadj_args **argpp; +{ + __ham_curadj_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__ham_curadj_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->pgno, bp, sizeof(argp->pgno)); + bp += sizeof(argp->pgno); + memcpy(&argp->indx, bp, sizeof(argp->indx)); + bp += sizeof(argp->indx); + memcpy(&argp->len, bp, sizeof(argp->len)); + bp += sizeof(argp->len); + memcpy(&argp->dup_off, bp, sizeof(argp->dup_off)); + bp += sizeof(argp->dup_off); + memcpy(&argp->add, bp, sizeof(argp->add)); + bp += sizeof(argp->add); + memcpy(&argp->is_dup, bp, sizeof(argp->is_dup)); + bp += sizeof(argp->is_dup); + memcpy(&argp->order, bp, sizeof(argp->order)); + bp += sizeof(argp->order); + *argpp = argp; + return (0); +} + +int +__ham_chgpg_log(dbenv, txnid, ret_lsnp, flags, + fileid, mode, old_pgno, new_pgno, old_indx, new_indx) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + int32_t fileid; + db_ham_mode mode; + db_pgno_t old_pgno; + db_pgno_t new_pgno; + u_int32_t old_indx; + u_int32_t new_indx; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_ham_chgpg; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(fileid) + + sizeof(mode) + + sizeof(old_pgno) + + sizeof(new_pgno) + + sizeof(old_indx) + + sizeof(new_indx); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &fileid, sizeof(fileid)); + bp += sizeof(fileid); + memcpy(bp, &mode, sizeof(mode)); + bp += sizeof(mode); + memcpy(bp, &old_pgno, sizeof(old_pgno)); + bp += sizeof(old_pgno); + memcpy(bp, &new_pgno, sizeof(new_pgno)); + bp += sizeof(new_pgno); + memcpy(bp, &old_indx, sizeof(old_indx)); + bp += sizeof(old_indx); + memcpy(bp, &new_indx, sizeof(new_indx)); + bp += sizeof(new_indx); + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__ham_chgpg_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __ham_chgpg_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __ham_chgpg_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]ham_chgpg: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tmode: %ld\n", (long)argp->mode); + printf("\told_pgno: %lu\n", (u_long)argp->old_pgno); + printf("\tnew_pgno: %lu\n", (u_long)argp->new_pgno); + printf("\told_indx: %lu\n", (u_long)argp->old_indx); + printf("\tnew_indx: %lu\n", (u_long)argp->new_indx); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__ham_chgpg_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __ham_chgpg_args **argpp; +{ + __ham_chgpg_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__ham_chgpg_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->mode, bp, sizeof(argp->mode)); + bp += sizeof(argp->mode); + memcpy(&argp->old_pgno, bp, sizeof(argp->old_pgno)); + bp += sizeof(argp->old_pgno); + memcpy(&argp->new_pgno, bp, sizeof(argp->new_pgno)); + bp += sizeof(argp->new_pgno); + memcpy(&argp->old_indx, bp, sizeof(argp->old_indx)); + bp += sizeof(argp->old_indx); + memcpy(&argp->new_indx, bp, sizeof(argp->new_indx)); + bp += sizeof(argp->new_indx); + *argpp = argp; + return (0); +} + +int +__ham_init_print(dbenv) + DB_ENV *dbenv; +{ + int ret; + + if ((ret = __db_add_recovery(dbenv, + __ham_insdel_print, DB_ham_insdel)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __ham_newpage_print, DB_ham_newpage)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __ham_splitmeta_print, DB_ham_splitmeta)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __ham_splitdata_print, DB_ham_splitdata)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __ham_replace_print, DB_ham_replace)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __ham_newpgno_print, DB_ham_newpgno)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __ham_ovfl_print, DB_ham_ovfl)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __ham_copypage_print, DB_ham_copypage)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __ham_metagroup_print, DB_ham_metagroup)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __ham_groupalloc1_print, DB_ham_groupalloc1)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __ham_groupalloc2_print, DB_ham_groupalloc2)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __ham_groupalloc_print, DB_ham_groupalloc)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __ham_curadj_print, DB_ham_curadj)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __ham_chgpg_print, DB_ham_chgpg)) != 0) + return (ret); + return (0); +} + +int +__ham_init_recover(dbenv) + DB_ENV *dbenv; +{ + int ret; + + if ((ret = __db_add_recovery(dbenv, + __ham_insdel_recover, DB_ham_insdel)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __ham_newpage_recover, DB_ham_newpage)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __deprecated_recover, DB_ham_splitmeta)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __ham_splitdata_recover, DB_ham_splitdata)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __ham_replace_recover, DB_ham_replace)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __deprecated_recover, DB_ham_newpgno)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __deprecated_recover, DB_ham_ovfl)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __ham_copypage_recover, DB_ham_copypage)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __ham_metagroup_recover, DB_ham_metagroup)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __deprecated_recover, DB_ham_groupalloc1)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __deprecated_recover, DB_ham_groupalloc2)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __ham_groupalloc_recover, DB_ham_groupalloc)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __ham_curadj_recover, DB_ham_curadj)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __ham_chgpg_recover, DB_ham_chgpg)) != 0) + return (ret); + return (0); +} + diff --git a/db/hash/hash_conv.c b/db/hash/hash_conv.c new file mode 100644 index 000000000..30d17a616 --- /dev/null +++ b/db/hash/hash_conv.c @@ -0,0 +1,112 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: hash_conv.c,v 11.5 2000/03/31 00:30:32 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_swap.h" +#include "hash.h" + +/* + * __ham_pgin -- + * Convert host-specific page layout from the host-independent format + * stored on disk. + * + * PUBLIC: int __ham_pgin __P((DB_ENV *, db_pgno_t, void *, DBT *)); + */ +int +__ham_pgin(dbenv, pg, pp, cookie) + DB_ENV *dbenv; + db_pgno_t pg; + void *pp; + DBT *cookie; +{ + DB_PGINFO *pginfo; + PAGE *h; + + h = pp; + pginfo = (DB_PGINFO *)cookie->data; + + /* + * The hash access method does blind reads of pages, causing them + * to be created. If the type field isn't set it's one of them, + * initialize the rest of the page and return. + */ + if (h->type != P_HASHMETA && h->pgno == PGNO_INVALID) { + P_INIT(pp, pginfo->db_pagesize, + pg, PGNO_INVALID, PGNO_INVALID, 0, P_HASH); + return (0); + } + + if (!pginfo->needswap) + return (0); + + return (h->type == P_HASHMETA ? __ham_mswap(pp) : + __db_byteswap(dbenv, pg, pp, pginfo->db_pagesize, 1)); +} + +/* + * __ham_pgout -- + * Convert host-specific page layout to the host-independent format + * stored on disk. + * + * PUBLIC: int __ham_pgout __P((DB_ENV *, db_pgno_t, void *, DBT *)); + */ +int +__ham_pgout(dbenv, pg, pp, cookie) + DB_ENV *dbenv; + db_pgno_t pg; + void *pp; + DBT *cookie; +{ + DB_PGINFO *pginfo; + PAGE *h; + + pginfo = (DB_PGINFO *)cookie->data; + if (!pginfo->needswap) + return (0); + + h = pp; + return (h->type == P_HASHMETA ? __ham_mswap(pp) : + __db_byteswap(dbenv, pg, pp, pginfo->db_pagesize, 0)); +} + +/* + * __ham_mswap -- + * Swap the bytes on the hash metadata page. + * + * PUBLIC: int __ham_mswap __P((void *)); + */ +int +__ham_mswap(pg) + void *pg; +{ + u_int8_t *p; + int i; + + __db_metaswap(pg); + + p = (u_int8_t *)pg + sizeof(DBMETA); + + SWAP32(p); /* max_bucket */ + SWAP32(p); /* high_mask */ + SWAP32(p); /* low_mask */ + SWAP32(p); /* ffactor */ + SWAP32(p); /* nelem */ + SWAP32(p); /* h_charkey */ + for (i = 0; i < NCACHED; ++i) + SWAP32(p); /* spares */ + return (0); +} diff --git a/db/hash/hash_dup.c b/db/hash/hash_dup.c new file mode 100644 index 000000000..f5fbf4f47 --- /dev/null +++ b/db/hash/hash_dup.c @@ -0,0 +1,805 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Margo Seltzer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: hash_dup.c,v 11.49 2000/12/21 21:54:35 margo Exp $"; +#endif /* not lint */ + +/* + * PACKAGE: hashing + * + * DESCRIPTION: + * Manipulation of duplicates for the hash package. + * + * ROUTINES: + * + * External + * __add_dup + * Internal + */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "hash.h" +#include "btree.h" +#include "txn.h" + +static int __ham_check_move __P((DBC *, u_int32_t)); +static int __ham_dcursor __P((DBC *, db_pgno_t, u_int32_t)); + +/* + * Called from hash_access to add a duplicate key. nval is the new + * value that we want to add. The flags correspond to the flag values + * to cursor_put indicating where to add the new element. + * There are 4 cases. + * Case 1: The existing duplicate set already resides on a separate page. + * We return and let the common code handle this. + * Case 2: The element is small enough to just be added to the existing set. + * Case 3: The element is large enough to be a big item, so we're going to + * have to push the set onto a new page. + * Case 4: The element is large enough to push the duplicate set onto a + * separate page. + * + * PUBLIC: int __ham_add_dup __P((DBC *, DBT *, u_int32_t, db_pgno_t *)); + */ +int +__ham_add_dup(dbc, nval, flags, pgnop) + DBC *dbc; + DBT *nval; + u_int32_t flags; + db_pgno_t *pgnop; +{ + DB *dbp; + HASH_CURSOR *hcp; + DBT pval, tmp_val; + u_int32_t add_bytes, new_size; + int cmp, ret; + u_int8_t *hk; + + dbp = dbc->dbp; + hcp = (HASH_CURSOR *)dbc->internal; + + DB_ASSERT(flags != DB_CURRENT); + + add_bytes = nval->size + + (F_ISSET(nval, DB_DBT_PARTIAL) ? nval->doff : 0); + add_bytes = DUP_SIZE(add_bytes); + + if ((ret = __ham_check_move(dbc, add_bytes)) != 0) + return (ret); + + /* + * Check if resulting duplicate set is going to need to go + * onto a separate duplicate page. If so, convert the + * duplicate set and add the new one. After conversion, + * hcp->dndx is the first free ndx or the index of the + * current pointer into the duplicate set. + */ + hk = H_PAIRDATA(hcp->page, hcp->indx); + /* Add the len bytes to the current singleton. */ + if (HPAGE_PTYPE(hk) != H_DUPLICATE) + add_bytes += DUP_SIZE(0); + new_size = + LEN_HKEYDATA(hcp->page, dbp->pgsize, H_DATAINDEX(hcp->indx)) + + add_bytes; + + /* + * We convert to off-page duplicates if the item is a big item, + * the addition of the new item will make the set large, or + * if there isn't enough room on this page to add the next item. + */ + if (HPAGE_PTYPE(hk) != H_OFFDUP && + (HPAGE_PTYPE(hk) == H_OFFPAGE || ISBIG(hcp, new_size) || + add_bytes > P_FREESPACE(hcp->page))) { + + if ((ret = __ham_dup_convert(dbc)) != 0) + return (ret); + return (hcp->opd->c_am_put(hcp->opd, + NULL, nval, flags, NULL)); + } + + /* There are two separate cases here: on page and off page. */ + if (HPAGE_PTYPE(hk) != H_OFFDUP) { + if (HPAGE_PTYPE(hk) != H_DUPLICATE) { + pval.flags = 0; + pval.data = HKEYDATA_DATA(hk); + pval.size = LEN_HDATA(hcp->page, dbp->pgsize, + hcp->indx); + if ((ret = __ham_make_dup(dbp->dbenv, + &pval, &tmp_val, &dbc->rdata.data, + &dbc->rdata.ulen)) != 0 || (ret = + __ham_replpair(dbc, &tmp_val, 1)) != 0) + return (ret); + hk = H_PAIRDATA(hcp->page, hcp->indx); + HPAGE_PTYPE(hk) = H_DUPLICATE; + + /* + * Update the cursor position since we now are in + * duplicates. + */ + F_SET(hcp, H_ISDUP); + hcp->dup_off = 0; + hcp->dup_len = pval.size; + hcp->dup_tlen = DUP_SIZE(hcp->dup_len); + } + + /* Now make the new entry a duplicate. */ + if ((ret = __ham_make_dup(dbp->dbenv, nval, + &tmp_val, &dbc->rdata.data, &dbc->rdata.ulen)) != 0) + return (ret); + + tmp_val.dlen = 0; + switch (flags) { /* On page. */ + case DB_KEYFIRST: + case DB_KEYLAST: + case DB_NODUPDATA: + if (dbp->dup_compare != NULL) { + __ham_dsearch(dbc, nval, &tmp_val.doff, &cmp); + + /* dup dups are not supported w/ sorted dups */ + if (cmp == 0) + return (__db_duperr(dbp, flags)); + } else { + hcp->dup_tlen = LEN_HDATA(hcp->page, + dbp->pgsize, hcp->indx); + hcp->dup_len = nval->size; + F_SET(hcp, H_ISDUP); + if (flags == DB_KEYFIRST) + hcp->dup_off = tmp_val.doff = 0; + else + hcp->dup_off = + tmp_val.doff = hcp->dup_tlen; + } + break; + case DB_BEFORE: + tmp_val.doff = hcp->dup_off; + break; + case DB_AFTER: + tmp_val.doff = hcp->dup_off + DUP_SIZE(hcp->dup_len); + break; + } + /* Add the duplicate. */ + ret = __ham_replpair(dbc, &tmp_val, 0); + if (ret == 0) + ret = memp_fset(dbp->mpf, hcp->page, DB_MPOOL_DIRTY); + + if (ret != 0) + return (ret); + + /* Now, update the cursor if necessary. */ + switch (flags) { + case DB_AFTER: + hcp->dup_off += DUP_SIZE(hcp->dup_len); + hcp->dup_len = nval->size; + hcp->dup_tlen += DUP_SIZE(nval->size); + break; + case DB_KEYFIRST: + case DB_KEYLAST: + case DB_BEFORE: + hcp->dup_tlen += DUP_SIZE(nval->size); + hcp->dup_len = nval->size; + break; + } + ret = __ham_c_update(dbc, tmp_val.size, 1, 1); + return (ret); + } + + /* + * If we get here, then we're on duplicate pages; set pgnop and + * return so the common code can handle it. + */ + memcpy(pgnop, + HOFFDUP_PGNO(H_PAIRDATA(hcp->page, hcp->indx)), sizeof(db_pgno_t)); + + return (ret); +} + +/* + * Convert an on-page set of duplicates to an offpage set of duplicates. + * + * PUBLIC: int __ham_dup_convert __P((DBC *)); + */ +int +__ham_dup_convert(dbc) + DBC *dbc; +{ + DB *dbp; + DBC **hcs; + DB_LSN lsn; + PAGE *dp; + HASH_CURSOR *hcp; + BOVERFLOW bo; + DBT dbt; + HOFFPAGE ho; + db_indx_t i, len, off; + int c, ret, t_ret; + u_int8_t *p, *pend; + + dbp = dbc->dbp; + hcp = (HASH_CURSOR *)dbc->internal; + + /* + * Create a new page for the duplicates. + */ + if ((ret = __db_new(dbc, + dbp->dup_compare == NULL ? P_LRECNO : P_LDUP, &dp)) != 0) + return (ret); + P_INIT(dp, dbp->pgsize, + dp->pgno, PGNO_INVALID, PGNO_INVALID, LEAFLEVEL, TYPE(dp)); + + /* + * Get the list of cursors that may need to be updated. + */ + if ((ret = __ham_get_clist(dbp, + PGNO(hcp->page), (u_int32_t)hcp->indx, &hcs)) != 0) + return (ret); + + /* + * Now put the duplicates onto the new page. + */ + dbt.flags = 0; + switch (HPAGE_PTYPE(H_PAIRDATA(hcp->page, hcp->indx))) { + case H_KEYDATA: + /* Simple case, one key on page; move it to dup page. */ + dbt.size = LEN_HDATA(hcp->page, dbp->pgsize, hcp->indx); + dbt.data = HKEYDATA_DATA(H_PAIRDATA(hcp->page, hcp->indx)); + ret = __db_pitem(dbc, + dp, 0, BKEYDATA_SIZE(dbt.size), NULL, &dbt); + goto finish; + case H_OFFPAGE: + /* Simple case, one key on page; move it to dup page. */ + memcpy(&ho, + P_ENTRY(hcp->page, H_DATAINDEX(hcp->indx)), HOFFPAGE_SIZE); + UMRW_SET(bo.unused1); + B_TSET(bo.type, ho.type, 0); + UMRW_SET(bo.unused2); + bo.pgno = ho.pgno; + bo.tlen = ho.tlen; + dbt.size = BOVERFLOW_SIZE; + dbt.data = &bo; + + ret = __db_pitem(dbc, dp, 0, dbt.size, &dbt, NULL); + +finish: if (ret == 0) { + memp_fset(dbp->mpf, dp, DB_MPOOL_DIRTY); + /* + * Update any other cursors + */ + if (hcs != NULL && DB_LOGGING(dbc) + && IS_SUBTRANSACTION(dbc->txn)) { + if ((ret = __ham_chgpg_log(dbp->dbenv, + dbc->txn, &lsn, 0, dbp->log_fileid, + DB_HAM_DUP, PGNO(hcp->page), + PGNO(dp), hcp->indx, 0)) != 0) + break; + } + for (c = 0; hcs != NULL && hcs[c] != NULL; c++) + if ((ret = __ham_dcursor(hcs[c], + PGNO(dp), 0)) != 0) + break; + + } + break; + + case H_DUPLICATE: + p = HKEYDATA_DATA(H_PAIRDATA(hcp->page, hcp->indx)); + pend = p + + LEN_HDATA(hcp->page, dbp->pgsize, hcp->indx); + + /* + * We need to maintain the duplicate cursor position. + * Keep track of where we are in the duplicate set via + * the offset, and when it matches the one in the cursor, + * set the off-page duplicate cursor index to the current + * index. + */ + for (off = 0, i = 0; p < pend; i++) { + memcpy(&len, p, sizeof(db_indx_t)); + dbt.size = len; + p += sizeof(db_indx_t); + dbt.data = p; + p += len + sizeof(db_indx_t); + if ((ret = __db_pitem(dbc, dp, + i, BKEYDATA_SIZE(dbt.size), NULL, &dbt)) != 0) + break; + /* + * Update any other cursors + */ + for (c = 0; hcs != NULL && hcs[c] != NULL; c++) + if (((HASH_CURSOR *)(hcs[c]->internal))->dup_off + == off && (ret = __ham_dcursor(hcs[c], + PGNO(dp), i)) != 0) + goto out; + off += len + 2 * sizeof(db_indx_t); + } +out: break; + + default: + ret = __db_pgfmt(dbp, (u_long)hcp->pgno); + break; + } + if (ret == 0) { + /* + * Now attach this to the source page in place of + * the old duplicate item. + */ + __ham_move_offpage(dbc, hcp->page, + (u_int32_t)H_DATAINDEX(hcp->indx), PGNO(dp)); + + ret = memp_fset(dbp->mpf, hcp->page, DB_MPOOL_DIRTY); + if ((t_ret = memp_fput(dbp->mpf, dp, DB_MPOOL_DIRTY)) != 0) + ret = t_ret; + hcp->dup_tlen = hcp->dup_off = hcp->dup_len = 0; + } else + (void)__db_free(dbc, dp); + + if (hcs != NULL) + __os_free(hcs, 0); + + return (ret); +} + +/* + * __ham_make_dup + * + * Take a regular dbt and make it into a duplicate item with all the partial + * information set appropriately. If the incoming dbt is a partial, assume + * we are creating a new entry and make sure that we do any initial padding. + * + * PUBLIC: int __ham_make_dup __P((DB_ENV *, + * PUBLIC: const DBT *, DBT *d, void **, u_int32_t *)); + */ +int +__ham_make_dup(dbenv, notdup, duplicate, bufp, sizep) + DB_ENV *dbenv; + const DBT *notdup; + DBT *duplicate; + void **bufp; + u_int32_t *sizep; +{ + db_indx_t tsize, item_size; + int ret; + u_int8_t *p; + + item_size = (db_indx_t)notdup->size; + if (F_ISSET(notdup, DB_DBT_PARTIAL)) + item_size += notdup->doff; + + tsize = DUP_SIZE(item_size); + if ((ret = __ham_init_dbt(dbenv, duplicate, tsize, bufp, sizep)) != 0) + return (ret); + + duplicate->dlen = 0; + duplicate->flags = notdup->flags; + F_SET(duplicate, DB_DBT_PARTIAL); + + p = duplicate->data; + memcpy(p, &item_size, sizeof(db_indx_t)); + p += sizeof(db_indx_t); + if (F_ISSET(notdup, DB_DBT_PARTIAL)) { + memset(p, 0, notdup->doff); + p += notdup->doff; + } + memcpy(p, notdup->data, notdup->size); + p += notdup->size; + memcpy(p, &item_size, sizeof(db_indx_t)); + + duplicate->doff = 0; + duplicate->dlen = notdup->size; + + return (0); +} + +/* + * __ham_check_move -- + * + * Check if we can do whatever we need to on this page. If not, + * then we'll have to move the current element to a new page. + */ +static int +__ham_check_move(dbc, add_len) + DBC *dbc; + u_int32_t add_len; +{ + DB *dbp; + HASH_CURSOR *hcp; + DBT k, d; + DB_LSN new_lsn; + PAGE *next_pagep; + db_pgno_t next_pgno; + u_int32_t new_datalen, old_len, rectype; + u_int8_t *hk; + int ret; + + dbp = dbc->dbp; + hcp = (HASH_CURSOR *)dbc->internal; + + hk = H_PAIRDATA(hcp->page, hcp->indx); + + /* + * If the item is already off page duplicates or an offpage item, + * then we know we can do whatever we need to do in-place + */ + if (HPAGE_PTYPE(hk) == H_OFFDUP || HPAGE_PTYPE(hk) == H_OFFPAGE) + return (0); + + old_len = LEN_HITEM(hcp->page, dbp->pgsize, H_DATAINDEX(hcp->indx)); + new_datalen = old_len - HKEYDATA_SIZE(0) + add_len; + if (HPAGE_PTYPE(hk) != H_DUPLICATE) + new_datalen += DUP_SIZE(0); + + /* + * We need to add a new page under two conditions: + * 1. The addition makes the total data length cross the BIG + * threshold and the OFFDUP structure won't fit on this page. + * 2. The addition does not make the total data cross the + * threshold, but the new data won't fit on the page. + * If neither of these is true, then we can return. + */ + if (ISBIG(hcp, new_datalen) && (old_len > HOFFDUP_SIZE || + HOFFDUP_SIZE - old_len <= P_FREESPACE(hcp->page))) + return (0); + + if (!ISBIG(hcp, new_datalen) && add_len <= P_FREESPACE(hcp->page)) + return (0); + + /* + * If we get here, then we need to move the item to a new page. + * Check if there are more pages in the chain. We now need to + * update new_datalen to include the size of both the key and + * the data that we need to move. + */ + + new_datalen = ISBIG(hcp, new_datalen) ? + HOFFDUP_SIZE : HKEYDATA_SIZE(new_datalen); + new_datalen += LEN_HITEM(hcp->page, dbp->pgsize, H_KEYINDEX(hcp->indx)); + + next_pagep = NULL; + for (next_pgno = NEXT_PGNO(hcp->page); next_pgno != PGNO_INVALID; + next_pgno = NEXT_PGNO(next_pagep)) { + if (next_pagep != NULL && + (ret = memp_fput(dbp->mpf, next_pagep, 0)) != 0) + return (ret); + + if ((ret = memp_fget(dbp->mpf, + &next_pgno, DB_MPOOL_CREATE, &next_pagep)) != 0) + return (ret); + + if (P_FREESPACE(next_pagep) >= new_datalen) + break; + } + + /* No more pages, add one. */ + if (next_pagep == NULL && (ret = __ham_add_ovflpage(dbc, + hcp->page, 0, &next_pagep)) != 0) + return (ret); + + /* Add new page at the end of the chain. */ + if (P_FREESPACE(next_pagep) < new_datalen && (ret = + __ham_add_ovflpage(dbc, next_pagep, 1, &next_pagep)) != 0) { + (void)memp_fput(dbp->mpf, next_pagep, 0); + return (ret); + } + + /* Copy the item to the new page. */ + if (DB_LOGGING(dbc)) { + rectype = PUTPAIR; + k.flags = 0; + d.flags = 0; + if (HPAGE_PTYPE( + H_PAIRKEY(hcp->page, hcp->indx)) == H_OFFPAGE) { + rectype |= PAIR_KEYMASK; + k.data = H_PAIRKEY(hcp->page, hcp->indx); + k.size = HOFFPAGE_SIZE; + } else { + k.data = + HKEYDATA_DATA(H_PAIRKEY(hcp->page, hcp->indx)); + k.size = LEN_HKEY(hcp->page, dbp->pgsize, hcp->indx); + } + + if (HPAGE_PTYPE(hk) == H_OFFPAGE) { + rectype |= PAIR_DATAMASK; + d.data = H_PAIRDATA(hcp->page, hcp->indx); + d.size = HOFFPAGE_SIZE; + } else { + if (HPAGE_PTYPE(H_PAIRDATA(hcp->page, hcp->indx)) + == H_DUPLICATE) + rectype |= PAIR_DUPMASK; + d.data = + HKEYDATA_DATA(H_PAIRDATA(hcp->page, hcp->indx)); + d.size = LEN_HDATA(hcp->page, dbp->pgsize, hcp->indx); + } + + if ((ret = __ham_insdel_log(dbp->dbenv, + dbc->txn, &new_lsn, 0, rectype, + dbp->log_fileid, PGNO(next_pagep), + (u_int32_t)NUM_ENT(next_pagep), &LSN(next_pagep), + &k, &d)) != 0) { + (void)memp_fput(dbp->mpf, next_pagep, 0); + return (ret); + } + + /* Move lsn onto page. */ + LSN(next_pagep) = new_lsn; /* Structure assignment. */ + } + + __ham_copy_item(dbp->pgsize, + hcp->page, H_KEYINDEX(hcp->indx), next_pagep); + __ham_copy_item(dbp->pgsize, + hcp->page, H_DATAINDEX(hcp->indx), next_pagep); + + /* + * We've just manually inserted a key and set of data onto + * next_pagep; however, it's possible that our caller will + * return without further modifying the new page, for instance + * if DB_NODUPDATA is set and our new item is a duplicate duplicate. + * Thus, to be on the safe side, we need to mark the page dirty + * here. [#2996] + * + * Note that __ham_del_pair should dirty the page we're moving + * the items from, so we need only dirty the new page ourselves. + */ + if ((ret = memp_fset(dbp->mpf, next_pagep, DB_MPOOL_DIRTY)) != 0) + goto out; + + /* Update all cursors that used to point to this item. */ + if ((ret = __ham_c_chgpg(dbc, PGNO(hcp->page), H_KEYINDEX(hcp->indx), + PGNO(next_pagep), NUM_ENT(next_pagep) - 2)) != 0) + goto out; + + /* Now delete the pair from the current page. */ + ret = __ham_del_pair(dbc, 0); + + /* + * __ham_del_pair decremented nelem. This is incorrect; we + * manually copied the element elsewhere, so the total number + * of elements hasn't changed. Increment it again. + */ + if (!STD_LOCKING(dbc)) + hcp->hdr->nelem++; + +out: + (void)memp_fput(dbp->mpf, hcp->page, DB_MPOOL_DIRTY); + hcp->page = next_pagep; + hcp->pgno = PGNO(hcp->page); + hcp->indx = NUM_ENT(hcp->page) - 2; + F_SET(hcp, H_EXPAND); + F_CLR(hcp, H_DELETED); + + return (ret); +} + +/* + * __ham_move_offpage -- + * Replace an onpage set of duplicates with the OFFDUP structure + * that references the duplicate page. + * + * XXX + * This is really just a special case of __onpage_replace; we should + * probably combine them. + * + * PUBLIC: void __ham_move_offpage __P((DBC *, PAGE *, u_int32_t, db_pgno_t)); + */ +void +__ham_move_offpage(dbc, pagep, ndx, pgno) + DBC *dbc; + PAGE *pagep; + u_int32_t ndx; + db_pgno_t pgno; +{ + DB *dbp; + HASH_CURSOR *hcp; + DBT new_dbt; + DBT old_dbt; + HOFFDUP od; + db_indx_t i; + int32_t shrink; + u_int8_t *src; + + dbp = dbc->dbp; + hcp = (HASH_CURSOR *)dbc->internal; + od.type = H_OFFDUP; + UMRW_SET(od.unused[0]); + UMRW_SET(od.unused[1]); + UMRW_SET(od.unused[2]); + od.pgno = pgno; + + if (DB_LOGGING(dbc)) { + new_dbt.data = &od; + new_dbt.size = HOFFDUP_SIZE; + old_dbt.data = P_ENTRY(pagep, ndx); + old_dbt.size = LEN_HITEM(pagep, dbp->pgsize, ndx); + (void)__ham_replace_log(dbp->dbenv, + dbc->txn, &LSN(pagep), 0, dbp->log_fileid, + PGNO(pagep), (u_int32_t)ndx, &LSN(pagep), -1, + &old_dbt, &new_dbt, 0); + } + + shrink = LEN_HITEM(pagep, dbp->pgsize, ndx) - HOFFDUP_SIZE; + + if (shrink != 0) { + /* Copy data. */ + src = (u_int8_t *)(pagep) + HOFFSET(pagep); + memmove(src + shrink, src, pagep->inp[ndx] - HOFFSET(pagep)); + HOFFSET(pagep) += shrink; + + /* Update index table. */ + for (i = ndx; i < NUM_ENT(pagep); i++) + pagep->inp[i] += shrink; + } + + /* Now copy the offdup entry onto the page. */ + memcpy(P_ENTRY(pagep, ndx), &od, HOFFDUP_SIZE); +} + +/* + * __ham_dsearch: + * Locate a particular duplicate in a duplicate set. Make sure that + * we exit with the cursor set appropriately. + * + * PUBLIC: void __ham_dsearch __P((DBC *, DBT *, u_int32_t *, int *)); + */ +void +__ham_dsearch(dbc, dbt, offp, cmpp) + DBC *dbc; + DBT *dbt; + u_int32_t *offp; + int *cmpp; +{ + DB *dbp; + HASH_CURSOR *hcp; + DBT cur; + db_indx_t i, len; + int (*func) __P((DB *, const DBT *, const DBT *)); + u_int8_t *data; + + dbp = dbc->dbp; + hcp = (HASH_CURSOR *)dbc->internal; + if (dbp->dup_compare == NULL) + func = __bam_defcmp; + else + func = dbp->dup_compare; + + i = F_ISSET(hcp, H_CONTINUE) ? hcp->dup_off: 0; + data = HKEYDATA_DATA(H_PAIRDATA(hcp->page, hcp->indx)) + i; + hcp->dup_tlen = LEN_HDATA(hcp->page, dbp->pgsize, hcp->indx); + while (i < hcp->dup_tlen) { + memcpy(&len, data, sizeof(db_indx_t)); + data += sizeof(db_indx_t); + cur.data = data; + cur.size = (u_int32_t)len; + *cmpp = func(dbp, dbt, &cur); + if (*cmpp == 0 || (*cmpp < 0 && dbp->dup_compare != NULL)) + break; + i += len + 2 * sizeof(db_indx_t); + data += len + sizeof(db_indx_t); + } + *offp = i; + hcp->dup_off = i; + hcp->dup_len = len; + F_SET(hcp, H_ISDUP); +} + +#ifdef DEBUG +/* + * __ham_cprint -- + * Display the current cursor list. + * + * PUBLIC: int __ham_cprint __P((DB *)); + */ +int +__ham_cprint(dbp) + DB *dbp; +{ + HASH_CURSOR *cp; + DBC *dbc; + + MUTEX_THREAD_LOCK(dbp->dbenv, dbp->mutexp); + for (dbc = TAILQ_FIRST(&dbp->active_queue); + dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) { + cp = (HASH_CURSOR *)dbc->internal; + fprintf(stderr, "%#0lx->%#0lx: page: %lu index: %lu", + P_TO_ULONG(dbc), P_TO_ULONG(cp), (u_long)cp->pgno, + (u_long)cp->indx); + if (F_ISSET(cp, H_DELETED)) + fprintf(stderr, " (deleted)"); + fprintf(stderr, "\n"); + } + MUTEX_THREAD_UNLOCK(dbp->dbenv, dbp->mutexp); + + return (0); +} +#endif /* DEBUG */ + +/* + * __ham_dcursor -- + * + * Create an off page duplicate cursor for this cursor. + */ +static int +__ham_dcursor(dbc, pgno, indx) + DBC *dbc; + db_pgno_t pgno; + u_int32_t indx; +{ + DB *dbp; + DBC *dbc_nopd; + HASH_CURSOR *hcp; + BTREE_CURSOR *dcp; + int ret; + + dbp = dbc->dbp; + + if ((ret = __db_c_newopd(dbc, pgno, &dbc_nopd)) != 0) + return (ret); + + dcp = (BTREE_CURSOR *)dbc_nopd->internal; + dcp->pgno = pgno; + dcp->indx = indx; + + if (dbp->dup_compare == NULL) { + /* + * Converting to off-page Recno trees is tricky. The + * record number for the cursor is the index + 1 (to + * convert to 1-based record numbers). + */ + dcp->recno = indx + 1; + } + + /* + * Transfer the deleted flag from the top-level cursor to the + * created one. + */ + hcp = (HASH_CURSOR *)dbc->internal; + if (F_ISSET(hcp, H_DELETED)) { + F_SET(dcp, C_DELETED); + F_CLR(hcp, H_DELETED); + } + + /* Stack the cursors and reset the initial cursor's index. */ + hcp->opd = dbc_nopd; + + return (0); +} diff --git a/db/hash/hash_func.c b/db/hash/hash_func.c new file mode 100644 index 000000000..22b4f08ee --- /dev/null +++ b/db/hash/hash_func.c @@ -0,0 +1,242 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993 + * Margo Seltzer. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Margo Seltzer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: hash_func.c,v 11.7 2000/08/16 18:26:19 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "hash.h" + +/* + * __ham_func2 -- + * Phong Vo's linear congruential hash. + * + * PUBLIC: u_int32_t __ham_func2 __P((DB *, const void *, u_int32_t)); + */ +#define DCHARHASH(h, c) ((h) = 0x63c63cd9*(h) + 0x9c39c33d + (c)) + +u_int32_t +__ham_func2(dbp, key, len) + DB *dbp; + const void *key; + u_int32_t len; +{ + const u_int8_t *e, *k; + u_int32_t h; + u_int8_t c; + + if (dbp != NULL) + COMPQUIET(dbp, NULL); + + k = key; + e = k + len; + for (h = 0; k != e;) { + c = *k++; + if (!c && k > e) + break; + DCHARHASH(h, c); + } + return (h); +} + +/* + * __ham_func3 -- + * Ozan Yigit's original sdbm hash. + * + * Ugly, but fast. Break the string up into 8 byte units. On the first time + * through the loop get the "leftover bytes" (strlen % 8). On every other + * iteration, perform 8 HASHC's so we handle all 8 bytes. Essentially, this + * saves us 7 cmp & branch instructions. + * + * PUBLIC: u_int32_t __ham_func3 __P((DB *, const void *, u_int32_t)); + */ +u_int32_t +__ham_func3(dbp, key, len) + DB *dbp; + const void *key; + u_int32_t len; +{ + const u_int8_t *k; + u_int32_t n, loop; + + if (dbp != NULL) + COMPQUIET(dbp, NULL); + + if (len == 0) + return (0); + +#define HASHC n = *k++ + 65599 * n + n = 0; + k = key; + + loop = (len + 8 - 1) >> 3; + switch (len & (8 - 1)) { + case 0: + do { + HASHC; + case 7: + HASHC; + case 6: + HASHC; + case 5: + HASHC; + case 4: + HASHC; + case 3: + HASHC; + case 2: + HASHC; + case 1: + HASHC; + } while (--loop); + } + return (n); +} + +/* + * __ham_func4 -- + * Chris Torek's hash function. Although this function performs only + * slightly worse than __ham_func5 on strings, it performs horribly on + * numbers. + * + * PUBLIC: u_int32_t __ham_func4 __P((DB *, const void *, u_int32_t)); + */ +u_int32_t +__ham_func4(dbp, key, len) + DB *dbp; + const void *key; + u_int32_t len; +{ + const u_int8_t *k; + u_int32_t h, loop; + + if (dbp != NULL) + COMPQUIET(dbp, NULL); + + if (len == 0) + return (0); + +#define HASH4a h = (h << 5) - h + *k++; +#define HASH4b h = (h << 5) + h + *k++; +#define HASH4 HASH4b + h = 0; + k = key; + + loop = (len + 8 - 1) >> 3; + switch (len & (8 - 1)) { + case 0: + do { + HASH4; + case 7: + HASH4; + case 6: + HASH4; + case 5: + HASH4; + case 4: + HASH4; + case 3: + HASH4; + case 2: + HASH4; + case 1: + HASH4; + } while (--loop); + } + return (h); +} + +/* + * Fowler/Noll/Vo hash + * + * The basis of the hash algorithm was taken from an idea sent by email to the + * IEEE Posix P1003.2 mailing list from Phong Vo (kpv@research.att.com) and + * Glenn Fowler (gsf@research.att.com). Landon Curt Noll (chongo@toad.com) + * later improved on their algorithm. + * + * The magic is in the interesting relationship between the special prime + * 16777619 (2^24 + 403) and 2^32 and 2^8. + * + * This hash produces the fewest collisions of any function that we've seen so + * far, and works well on both numbers and strings. + * + * PUBLIC: u_int32_t __ham_func5 __P((DB *, const void *, u_int32_t)); + */ +u_int32_t +__ham_func5(dbp, key, len) + DB *dbp; + const void *key; + u_int32_t len; +{ + const u_int8_t *k, *e; + u_int32_t h; + + if (dbp != NULL) + COMPQUIET(dbp, NULL); + + k = key; + e = k + len; + for (h = 0; k < e; ++k) { + h *= 16777619; + h ^= *k; + } + return (h); +} + +u_int32_t +__ham_test(dbp, key, len) + DB *dbp; + const void *key; + u_int32_t len; +{ + COMPQUIET(dbp, NULL); + COMPQUIET(len, 0); + return ((u_int32_t)*(char *)key); +} diff --git a/db/hash/hash_meta.c b/db/hash/hash_meta.c new file mode 100644 index 000000000..d96a6db32 --- /dev/null +++ b/db/hash/hash_meta.c @@ -0,0 +1,121 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: hash_meta.c,v 11.10 2000/12/21 21:54:35 margo Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "hash.h" +#include "db_shash.h" +#include "lock.h" +#include "txn.h" + +/* + * Acquire the meta-data page. + * + * PUBLIC: int __ham_get_meta __P((DBC *)); + */ +int +__ham_get_meta(dbc) + DBC *dbc; +{ + HASH_CURSOR *hcp; + HASH *hashp; + DB *dbp; + int ret; + + hcp = (HASH_CURSOR *)dbc->internal; + dbp = dbc->dbp; + hashp = dbp->h_internal; + + if (dbp->dbenv != NULL && + STD_LOCKING(dbc) && !F_ISSET(dbc, DBC_RECOVER)) { + dbc->lock.pgno = hashp->meta_pgno; + if ((ret = lock_get(dbp->dbenv, dbc->locker, + DB_NONBLOCK(dbc) ? DB_LOCK_NOWAIT : 0, + &dbc->lock_dbt, DB_LOCK_READ, &hcp->hlock)) != 0) + return (ret); + } + + if ((ret = memp_fget(dbc->dbp->mpf, + &hashp->meta_pgno, DB_MPOOL_CREATE, &(hcp->hdr))) != 0 && + hcp->hlock.off != LOCK_INVALID) { + (void)lock_put(dbc->dbp->dbenv, &hcp->hlock); + hcp->hlock.off = LOCK_INVALID; + } + + return (ret); +} + +/* + * Release the meta-data page. + * + * PUBLIC: int __ham_release_meta __P((DBC *)); + */ +int +__ham_release_meta(dbc) + DBC *dbc; +{ + HASH_CURSOR *hcp; + + hcp = (HASH_CURSOR *)dbc->internal; + + if (hcp->hdr) + (void)memp_fput(dbc->dbp->mpf, hcp->hdr, + F_ISSET(hcp, H_DIRTY) ? DB_MPOOL_DIRTY : 0); + hcp->hdr = NULL; + if (!F_ISSET(dbc, DBC_RECOVER) && + dbc->txn == NULL && hcp->hlock.off != LOCK_INVALID) + (void)lock_put(dbc->dbp->dbenv, &hcp->hlock); + hcp->hlock.off = LOCK_INVALID; + F_CLR(hcp, H_DIRTY); + + return (0); +} + +/* + * Mark the meta-data page dirty. + * + * PUBLIC: int __ham_dirty_meta __P((DBC *)); + */ +int +__ham_dirty_meta(dbc) + DBC *dbc; +{ + DB *dbp; + DB_LOCK _tmp; + HASH *hashp; + HASH_CURSOR *hcp; + int ret; + + dbp = dbc->dbp; + hashp = dbp->h_internal; + hcp = (HASH_CURSOR *)dbc->internal; + + ret = 0; + if (STD_LOCKING(dbc) && !F_ISSET(dbc, DBC_RECOVER)) { + dbc->lock.pgno = hashp->meta_pgno; + if ((ret = lock_get(dbp->dbenv, dbc->locker, + DB_NONBLOCK(dbc) ? DB_LOCK_NOWAIT : 0, + &dbc->lock_dbt, DB_LOCK_WRITE, &_tmp)) == 0) { + ret = lock_put(dbp->dbenv, &hcp->hlock); + hcp->hlock = _tmp; + } + } + + if (ret == 0) + F_SET(hcp, H_DIRTY); + return (ret); +} diff --git a/db/hash/hash_method.c b/db/hash/hash_method.c new file mode 100644 index 000000000..f8239993d --- /dev/null +++ b/db/hash/hash_method.c @@ -0,0 +1,126 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: hash_method.c,v 11.7 2000/07/04 18:28:23 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "hash.h" + +static int __ham_set_h_ffactor __P((DB *, u_int32_t)); +static int __ham_set_h_hash + __P((DB *, u_int32_t(*)(DB *, const void *, u_int32_t))); +static int __ham_set_h_nelem __P((DB *, u_int32_t)); + +/* + * __ham_db_create -- + * Hash specific initialization of the DB structure. + * + * PUBLIC: int __ham_db_create __P((DB *)); + */ +int +__ham_db_create(dbp) + DB *dbp; +{ + HASH *hashp; + int ret; + + if ((ret = __os_malloc(dbp->dbenv, + sizeof(HASH), NULL, &dbp->h_internal)) != 0) + return (ret); + + hashp = dbp->h_internal; + + hashp->h_nelem = 0; /* Defaults. */ + hashp->h_ffactor = 0; + hashp->h_hash = NULL; + + dbp->set_h_ffactor = __ham_set_h_ffactor; + dbp->set_h_hash = __ham_set_h_hash; + dbp->set_h_nelem = __ham_set_h_nelem; + + return (0); +} + +/* + * PUBLIC: int __ham_db_close __P((DB *)); + */ +int +__ham_db_close(dbp) + DB *dbp; +{ + if (dbp->h_internal == NULL) + return (0); + __os_free(dbp->h_internal, sizeof(HASH)); + dbp->h_internal = NULL; + return (0); +} + +/* + * __ham_set_h_ffactor -- + * Set the fill factor. + */ +static int +__ham_set_h_ffactor(dbp, h_ffactor) + DB *dbp; + u_int32_t h_ffactor; +{ + HASH *hashp; + + DB_ILLEGAL_AFTER_OPEN(dbp, "set_h_ffactor"); + DB_ILLEGAL_METHOD(dbp, DB_OK_HASH); + + hashp = dbp->h_internal; + hashp->h_ffactor = h_ffactor; + return (0); +} + +/* + * __ham_set_h_hash -- + * Set the hash function. + */ +static int +__ham_set_h_hash(dbp, func) + DB *dbp; + u_int32_t (*func) __P((DB *, const void *, u_int32_t)); +{ + HASH *hashp; + + DB_ILLEGAL_AFTER_OPEN(dbp, "set_h_hash"); + DB_ILLEGAL_METHOD(dbp, DB_OK_HASH); + + hashp = dbp->h_internal; + hashp->h_hash = func; + return (0); +} + +/* + * __ham_set_h_nelem -- + * Set the table size. + */ +static int +__ham_set_h_nelem(dbp, h_nelem) + DB *dbp; + u_int32_t h_nelem; +{ + HASH *hashp; + + DB_ILLEGAL_AFTER_OPEN(dbp, "set_h_nelem"); + DB_ILLEGAL_METHOD(dbp, DB_OK_HASH); + + hashp = dbp->h_internal; + hashp->h_nelem = h_nelem; + return (0); +} diff --git a/db/hash/hash_page.c b/db/hash/hash_page.c new file mode 100644 index 000000000..64f388532 --- /dev/null +++ b/db/hash/hash_page.c @@ -0,0 +1,1655 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994 + * Margo Seltzer. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Margo Seltzer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: hash_page.c,v 11.46 2001/01/11 18:19:51 bostic Exp $"; +#endif /* not lint */ + +/* + * PACKAGE: hashing + * + * DESCRIPTION: + * Page manipulation for hashing package. + * + * ROUTINES: + * + * External + * __get_page + * __add_ovflpage + * __overflow_page + * Internal + * open_temp + */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_shash.h" +#include "hash.h" +#include "lock.h" +#include "txn.h" + +/* + * PUBLIC: int __ham_item __P((DBC *, db_lockmode_t, db_pgno_t *)); + */ +int +__ham_item(dbc, mode, pgnop) + DBC *dbc; + db_lockmode_t mode; + db_pgno_t *pgnop; +{ + DB *dbp; + HASH_CURSOR *hcp; + db_pgno_t next_pgno; + int ret; + + dbp = dbc->dbp; + hcp = (HASH_CURSOR *)dbc->internal; + + if (F_ISSET(hcp, H_DELETED)) { + __db_err(dbp->dbenv, "Attempt to return a deleted item"); + return (EINVAL); + } + F_CLR(hcp, H_OK | H_NOMORE); + + /* Check if we need to get a page for this cursor. */ + if ((ret = __ham_get_cpage(dbc, mode)) != 0) + return (ret); + +recheck: + /* Check if we are looking for space in which to insert an item. */ + if (hcp->seek_size && hcp->seek_found_page == PGNO_INVALID + && hcp->seek_size < P_FREESPACE(hcp->page)) + hcp->seek_found_page = hcp->pgno; + + /* Check for off-page duplicates. */ + if (hcp->indx < NUM_ENT(hcp->page) && + HPAGE_TYPE(hcp->page, H_DATAINDEX(hcp->indx)) == H_OFFDUP) { + memcpy(pgnop, + HOFFDUP_PGNO(H_PAIRDATA(hcp->page, hcp->indx)), + sizeof(db_pgno_t)); + F_SET(hcp, H_OK); + return (0); + } + + /* Check if we need to go on to the next page. */ + if (F_ISSET(hcp, H_ISDUP)) + /* + * ISDUP is set, and offset is at the beginning of the datum. + * We need to grab the length of the datum, then set the datum + * pointer to be the beginning of the datum. + */ + memcpy(&hcp->dup_len, + HKEYDATA_DATA(H_PAIRDATA(hcp->page, hcp->indx)) + + hcp->dup_off, sizeof(db_indx_t)); + + if (hcp->indx >= (db_indx_t)NUM_ENT(hcp->page)) { + /* Fetch next page. */ + if (NEXT_PGNO(hcp->page) == PGNO_INVALID) { + F_SET(hcp, H_NOMORE); + return (DB_NOTFOUND); + } + next_pgno = NEXT_PGNO(hcp->page); + hcp->indx = 0; + if ((ret = __ham_next_cpage(dbc, next_pgno, 0)) != 0) + return (ret); + goto recheck; + } + + F_SET(hcp, H_OK); + return (0); +} + +/* + * PUBLIC: int __ham_item_reset __P((DBC *)); + */ +int +__ham_item_reset(dbc) + DBC *dbc; +{ + HASH_CURSOR *hcp; + DB *dbp; + int ret; + + ret = 0; + dbp = dbc->dbp; + hcp = (HASH_CURSOR *)dbc->internal; + if (hcp->page != NULL) + ret = memp_fput(dbp->mpf, hcp->page, 0); + + __ham_item_init(dbc); + return (ret); +} + +/* + * PUBLIC: void __ham_item_init __P((DBC *)); + */ +void +__ham_item_init(dbc) + DBC *dbc; +{ + HASH_CURSOR *hcp; + + hcp = (HASH_CURSOR *)dbc->internal; + /* + * If this cursor still holds any locks, we must + * release them if we are not running with transactions. + */ + if (hcp->lock.off != LOCK_INVALID && dbc->txn == NULL) + (void)lock_put(dbc->dbp->dbenv, &hcp->lock); + + /* + * The following fields must *not* be initialized here + * because they may have meaning across inits. + * hlock, hdr, split_buf, stats + */ + hcp->bucket = BUCKET_INVALID; + hcp->lbucket = BUCKET_INVALID; + hcp->lock.off = LOCK_INVALID; + hcp->lock_mode = DB_LOCK_NG; + hcp->dup_off = 0; + hcp->dup_len = 0; + hcp->dup_tlen = 0; + hcp->seek_size = 0; + hcp->seek_found_page = PGNO_INVALID; + hcp->flags = 0; + + hcp->pgno = PGNO_INVALID; + hcp->indx = NDX_INVALID; + hcp->page = NULL; +} + +/* + * Returns the last item in a bucket. + * + * PUBLIC: int __ham_item_last __P((DBC *, db_lockmode_t, db_pgno_t *)); + */ +int +__ham_item_last(dbc, mode, pgnop) + DBC *dbc; + db_lockmode_t mode; + db_pgno_t *pgnop; +{ + HASH_CURSOR *hcp; + int ret; + + hcp = (HASH_CURSOR *)dbc->internal; + if ((ret = __ham_item_reset(dbc)) != 0) + return (ret); + + hcp->bucket = hcp->hdr->max_bucket; + hcp->pgno = BUCKET_TO_PAGE(hcp, hcp->bucket); + F_SET(hcp, H_OK); + return (__ham_item_prev(dbc, mode, pgnop)); +} + +/* + * PUBLIC: int __ham_item_first __P((DBC *, db_lockmode_t, db_pgno_t *)); + */ +int +__ham_item_first(dbc, mode, pgnop) + DBC *dbc; + db_lockmode_t mode; + db_pgno_t *pgnop; +{ + HASH_CURSOR *hcp; + int ret; + + hcp = (HASH_CURSOR *)dbc->internal; + if ((ret = __ham_item_reset(dbc)) != 0) + return (ret); + F_SET(hcp, H_OK); + hcp->bucket = 0; + hcp->pgno = BUCKET_TO_PAGE(hcp, hcp->bucket); + return (__ham_item_next(dbc, mode, pgnop)); +} + +/* + * __ham_item_prev -- + * Returns a pointer to key/data pair on a page. In the case of + * bigkeys, just returns the page number and index of the bigkey + * pointer pair. + * + * PUBLIC: int __ham_item_prev __P((DBC *, db_lockmode_t, db_pgno_t *)); + */ +int +__ham_item_prev(dbc, mode, pgnop) + DBC *dbc; + db_lockmode_t mode; + db_pgno_t *pgnop; +{ + DB *dbp; + HASH_CURSOR *hcp; + db_pgno_t next_pgno; + int ret; + + dbp = dbc->dbp; + hcp = (HASH_CURSOR *)dbc->internal; + /* + * There are 5 cases for backing up in a hash file. + * Case 1: In the middle of a page, no duplicates, just dec the index. + * Case 2: In the middle of a duplicate set, back up one. + * Case 3: At the beginning of a duplicate set, get out of set and + * back up to next key. + * Case 4: At the beginning of a page; go to previous page. + * Case 5: At the beginning of a bucket; go to prev bucket. + */ + F_CLR(hcp, H_OK | H_NOMORE | H_DELETED); + + if ((ret = __ham_get_cpage(dbc, mode)) != 0) + return (ret); + + /* + * First handle the duplicates. Either you'll get the key here + * or you'll exit the duplicate set and drop into the code below + * to handle backing up through keys. + */ + if (!F_ISSET(hcp, H_NEXT_NODUP) && F_ISSET(hcp, H_ISDUP)) { + if (HPAGE_TYPE(hcp->page, H_DATAINDEX(hcp->indx)) == H_OFFDUP) { + memcpy(pgnop, + HOFFDUP_PGNO(H_PAIRDATA(hcp->page, hcp->indx)), + sizeof(db_pgno_t)); + F_SET(hcp, H_OK); + return (0); + } + + /* Duplicates are on-page. */ + if (hcp->dup_off != 0) { + memcpy(&hcp->dup_len, HKEYDATA_DATA( + H_PAIRDATA(hcp->page, hcp->indx)) + + hcp->dup_off - sizeof(db_indx_t), + sizeof(db_indx_t)); + hcp->dup_off -= + DUP_SIZE(hcp->dup_len); + return (__ham_item(dbc, mode, pgnop)); + } + } + + /* + * If we get here, we are not in a duplicate set, and just need + * to back up the cursor. There are still three cases: + * midpage, beginning of page, beginning of bucket. + */ + + if (F_ISSET(hcp, H_DUPONLY)) { + F_CLR(hcp, H_OK); + F_SET(hcp, H_NOMORE); + return (0); + } else + /* + * We are no longer in a dup set; flag this so the dup code + * will reinitialize should we stumble upon another one. + */ + F_CLR(hcp, H_ISDUP); + + if (hcp->indx == 0) { /* Beginning of page. */ + hcp->pgno = PREV_PGNO(hcp->page); + if (hcp->pgno == PGNO_INVALID) { + /* Beginning of bucket. */ + F_SET(hcp, H_NOMORE); + return (DB_NOTFOUND); + } else if ((ret = + __ham_next_cpage(dbc, hcp->pgno, 0)) != 0) + return (ret); + else + hcp->indx = NUM_ENT(hcp->page); + } + + /* + * Either we've got the cursor set up to be decremented, or we + * have to find the end of a bucket. + */ + if (hcp->indx == NDX_INVALID) { + DB_ASSERT(hcp->page != NULL); + + hcp->indx = NUM_ENT(hcp->page); + for (next_pgno = NEXT_PGNO(hcp->page); + next_pgno != PGNO_INVALID; + next_pgno = NEXT_PGNO(hcp->page)) { + if ((ret = __ham_next_cpage(dbc, next_pgno, 0)) != 0) + return (ret); + hcp->indx = NUM_ENT(hcp->page); + } + + if (hcp->indx == 0) { + /* Bucket was empty. */ + F_SET(hcp, H_NOMORE); + return (DB_NOTFOUND); + } + } + + hcp->indx -= 2; + + return (__ham_item(dbc, mode, pgnop)); +} + +/* + * Sets the cursor to the next key/data pair on a page. + * + * PUBLIC: int __ham_item_next __P((DBC *, db_lockmode_t, db_pgno_t *)); + */ +int +__ham_item_next(dbc, mode, pgnop) + DBC *dbc; + db_lockmode_t mode; + db_pgno_t *pgnop; +{ + HASH_CURSOR *hcp; + int ret; + + hcp = (HASH_CURSOR *)dbc->internal; + + if ((ret = __ham_get_cpage(dbc, mode)) != 0) + return (ret); + + /* + * Deleted on-page duplicates are a weird case. If we delete the last + * one, then our cursor is at the very end of a duplicate set and + * we actually need to go on to the next key. + */ + if (F_ISSET(hcp, H_DELETED)) { + if (hcp->indx != NDX_INVALID && + F_ISSET(hcp, H_ISDUP) && + HPAGE_TYPE(hcp->page, H_DATAINDEX(hcp->indx)) + == H_DUPLICATE && hcp->dup_tlen == hcp->dup_off) { + if (F_ISSET(hcp, H_DUPONLY)) { + F_CLR(hcp, H_OK); + F_SET(hcp, H_NOMORE); + return (0); + } else { + F_CLR(hcp, H_ISDUP); + hcp->indx += 2; + } + } else if (!F_ISSET(hcp, H_ISDUP) && F_ISSET(hcp, H_DUPONLY)) { + F_CLR(hcp, H_OK); + F_SET(hcp, H_NOMORE); + return (0); + } else if (F_ISSET(hcp, H_ISDUP) && + F_ISSET(hcp, H_NEXT_NODUP)) { + F_CLR(hcp, H_ISDUP); + hcp->indx += 2; + } + F_CLR(hcp, H_DELETED); + } else if (hcp->indx == NDX_INVALID) { + hcp->indx = 0; + F_CLR(hcp, H_ISDUP); + } else if (F_ISSET(hcp, H_NEXT_NODUP)) { + hcp->indx += 2; + F_CLR(hcp, H_ISDUP); + } else if (F_ISSET(hcp, H_ISDUP) && hcp->dup_tlen != 0) { + if (hcp->dup_off + DUP_SIZE(hcp->dup_len) >= + hcp->dup_tlen && F_ISSET(hcp, H_DUPONLY)) { + F_CLR(hcp, H_OK); + F_SET(hcp, H_NOMORE); + return (0); + } + hcp->dup_off += DUP_SIZE(hcp->dup_len); + if (hcp->dup_off >= hcp->dup_tlen) { + F_CLR(hcp, H_ISDUP); + hcp->indx += 2; + } + } else if (F_ISSET(hcp, H_DUPONLY)) { + F_CLR(hcp, H_OK); + F_SET(hcp, H_NOMORE); + return (0); + } else { + hcp->indx += 2; + F_CLR(hcp, H_ISDUP); + } + + return (__ham_item(dbc, mode, pgnop)); +} + +/* + * PUBLIC: void __ham_putitem __P((PAGE *p, const DBT *, int)); + * + * This is a little bit sleazy in that we're overloading the meaning + * of the H_OFFPAGE type here. When we recover deletes, we have the + * entire entry instead of having only the DBT, so we'll pass type + * H_OFFPAGE to mean, "copy the whole entry" as opposed to constructing + * an H_KEYDATA around it. + */ +void +__ham_putitem(p, dbt, type) + PAGE *p; + const DBT *dbt; + int type; +{ + u_int16_t n, off; + + n = NUM_ENT(p); + + /* Put the item element on the page. */ + if (type == H_OFFPAGE) { + off = HOFFSET(p) - dbt->size; + HOFFSET(p) = p->inp[n] = off; + memcpy(P_ENTRY(p, n), dbt->data, dbt->size); + } else { + off = HOFFSET(p) - HKEYDATA_SIZE(dbt->size); + HOFFSET(p) = p->inp[n] = off; + PUT_HKEYDATA(P_ENTRY(p, n), dbt->data, dbt->size, type); + } + + /* Adjust page info. */ + NUM_ENT(p) += 1; +} + +/* + * PUBLIC: void __ham_reputpair + * PUBLIC: __P((PAGE *p, u_int32_t, u_int32_t, const DBT *, const DBT *)); + * + * This is a special case to restore a key/data pair to its original + * location during recovery. We are guaranteed that the pair fits + * on the page and is not the last pair on the page (because if it's + * the last pair, the normal insert works). + */ +void +__ham_reputpair(p, psize, ndx, key, data) + PAGE *p; + u_int32_t psize, ndx; + const DBT *key, *data; +{ + db_indx_t i, movebytes, newbytes; + u_int8_t *from; + + /* First shuffle the existing items up on the page. */ + movebytes = + (ndx == 0 ? psize : p->inp[H_DATAINDEX(ndx - 2)]) - HOFFSET(p); + newbytes = key->size + data->size; + from = (u_int8_t *)p + HOFFSET(p); + memmove(from - newbytes, from, movebytes); + + /* + * Adjust the indices and move them up 2 spaces. Note that we + * have to check the exit condition inside the loop just in case + * we are dealing with index 0 (db_indx_t's are unsigned). + */ + for (i = NUM_ENT(p) - 1; ; i-- ) { + p->inp[i + 2] = p->inp[i] - newbytes; + if (i == H_KEYINDEX(ndx)) + break; + } + + /* Put the key and data on the page. */ + p->inp[H_KEYINDEX(ndx)] = + (ndx == 0 ? psize : p->inp[H_DATAINDEX(ndx - 2)]) - key->size; + p->inp[H_DATAINDEX(ndx)] = p->inp[H_KEYINDEX(ndx)] - data->size; + memcpy(P_ENTRY(p, H_KEYINDEX(ndx)), key->data, key->size); + memcpy(P_ENTRY(p, H_DATAINDEX(ndx)), data->data, data->size); + + /* Adjust page info. */ + HOFFSET(p) -= newbytes; + NUM_ENT(p) += 2; +} + +/* + * PUBLIC: int __ham_del_pair __P((DBC *, int)); + */ +int +__ham_del_pair(dbc, reclaim_page) + DBC *dbc; + int reclaim_page; +{ + DB *dbp; + HASH_CURSOR *hcp; + DBT data_dbt, key_dbt; + DB_ENV *dbenv; + DB_LSN new_lsn, *n_lsn, tmp_lsn; + PAGE *n_pagep, *nn_pagep, *p, *p_pagep; + db_indx_t ndx; + db_pgno_t chg_pgno, pgno, tmp_pgno; + int ret, t_ret; + + dbp = dbc->dbp; + hcp = (HASH_CURSOR *)dbc->internal; + + dbenv = dbp->dbenv; + ndx = hcp->indx; + + n_pagep = p_pagep = nn_pagep = NULL; + + if (hcp->page == NULL && (ret = memp_fget(dbp->mpf, + &hcp->pgno, DB_MPOOL_CREATE, &hcp->page)) != 0) + return (ret); + p = hcp->page; + + /* + * We optimize for the normal case which is when neither the key nor + * the data are large. In this case, we write a single log record + * and do the delete. If either is large, we'll call __big_delete + * to remove the big item and then update the page to remove the + * entry referring to the big item. + */ + ret = 0; + if (HPAGE_PTYPE(H_PAIRKEY(p, ndx)) == H_OFFPAGE) { + memcpy(&pgno, HOFFPAGE_PGNO(P_ENTRY(p, H_KEYINDEX(ndx))), + sizeof(db_pgno_t)); + ret = __db_doff(dbc, pgno); + } + + if (ret == 0) + switch (HPAGE_PTYPE(H_PAIRDATA(p, ndx))) { + case H_OFFPAGE: + memcpy(&pgno, + HOFFPAGE_PGNO(P_ENTRY(p, H_DATAINDEX(ndx))), + sizeof(db_pgno_t)); + ret = __db_doff(dbc, pgno); + break; + case H_OFFDUP: + case H_DUPLICATE: + /* + * If we delete a pair that is/was a duplicate, then + * we had better clear the flag so that we update the + * cursor appropriately. + */ + F_CLR(hcp, H_ISDUP); + break; + } + + if (ret) + return (ret); + + /* Now log the delete off this page. */ + if (DB_LOGGING(dbc)) { + key_dbt.data = P_ENTRY(p, H_KEYINDEX(ndx)); + key_dbt.size = LEN_HITEM(p, dbp->pgsize, H_KEYINDEX(ndx)); + data_dbt.data = P_ENTRY(p, H_DATAINDEX(ndx)); + data_dbt.size = LEN_HITEM(p, dbp->pgsize, H_DATAINDEX(ndx)); + + if ((ret = __ham_insdel_log(dbenv, + dbc->txn, &new_lsn, 0, DELPAIR, + dbp->log_fileid, PGNO(p), (u_int32_t)ndx, + &LSN(p), &key_dbt, &data_dbt)) != 0) + return (ret); + + /* Move lsn onto page. */ + LSN(p) = new_lsn; + } + + /* Do the delete. */ + __ham_dpair(dbp, p, ndx); + + /* + * Mark item deleted so that we don't try to return it, and + * so that we update the cursor correctly on the next call + * to next. + */ + F_SET(hcp, H_DELETED); + F_CLR(hcp, H_OK); + + /* + * Update cursors that are on the page where the delete happend. + */ + if ((ret = __ham_c_update(dbc, 0, 0, 0)) != 0) + return (ret); + + /* + * If we are locking, we will not maintain this, because it is + * a hot spot. + * + * XXX + * Perhaps we can retain incremental numbers and apply them later. + */ + if (!STD_LOCKING(dbc)) + --hcp->hdr->nelem; + + /* + * If we need to reclaim the page, then check if the page is empty. + * There are two cases. If it's empty and it's not the first page + * in the bucket (i.e., the bucket page) then we can simply remove + * it. If it is the first chain in the bucket, then we need to copy + * the second page into it and remove the second page. + * If its the only page in the bucket we leave it alone. + */ + if (!reclaim_page || + NUM_ENT(p) != 0 || + (PREV_PGNO(p) == PGNO_INVALID && NEXT_PGNO(p) == PGNO_INVALID)) + return (memp_fset(dbp->mpf, p, DB_MPOOL_DIRTY)); + + if (PREV_PGNO(p) == PGNO_INVALID) { + /* + * First page in chain is empty and we know that there + * are more pages in the chain. + */ + if ((ret = + memp_fget(dbp->mpf, &NEXT_PGNO(p), 0, &n_pagep)) != 0) + return (ret); + + if (NEXT_PGNO(n_pagep) != PGNO_INVALID && + (ret = memp_fget(dbp->mpf, &NEXT_PGNO(n_pagep), 0, + &nn_pagep)) != 0) + goto err; + + if (DB_LOGGING(dbc)) { + key_dbt.data = n_pagep; + key_dbt.size = dbp->pgsize; + if ((ret = __ham_copypage_log(dbenv, + dbc->txn, &new_lsn, 0, dbp->log_fileid, PGNO(p), + &LSN(p), PGNO(n_pagep), &LSN(n_pagep), + NEXT_PGNO(n_pagep), + nn_pagep == NULL ? NULL : &LSN(nn_pagep), + &key_dbt)) != 0) + goto err; + + /* Move lsn onto page. */ + LSN(p) = new_lsn; /* Structure assignment. */ + LSN(n_pagep) = new_lsn; + if (NEXT_PGNO(n_pagep) != PGNO_INVALID) + LSN(nn_pagep) = new_lsn; + } + if (nn_pagep != NULL) { + PREV_PGNO(nn_pagep) = PGNO(p); + if ((ret = memp_fput(dbp->mpf, + nn_pagep, DB_MPOOL_DIRTY)) != 0) { + nn_pagep = NULL; + goto err; + } + } + + tmp_pgno = PGNO(p); + tmp_lsn = LSN(p); + memcpy(p, n_pagep, dbp->pgsize); + PGNO(p) = tmp_pgno; + LSN(p) = tmp_lsn; + PREV_PGNO(p) = PGNO_INVALID; + + /* + * Update cursors to reflect the fact that records + * on the second page have moved to the first page. + */ + if ((ret = __ham_c_chgpg(dbc, + PGNO(n_pagep), NDX_INVALID, PGNO(p), NDX_INVALID)) != 0) + return (ret); + + /* + * Update the cursor to reflect its new position. + */ + hcp->indx = 0; + hcp->pgno = PGNO(p); + if ((ret = memp_fset(dbp->mpf, p, DB_MPOOL_DIRTY)) != 0 || + (ret = __db_free(dbc, n_pagep)) != 0) + return (ret); + } else { + if ((ret = + memp_fget(dbp->mpf, &PREV_PGNO(p), 0, &p_pagep)) != 0) + goto err; + + if (NEXT_PGNO(p) != PGNO_INVALID) { + if ((ret = memp_fget(dbp->mpf, + &NEXT_PGNO(p), 0, &n_pagep)) != 0) + goto err; + n_lsn = &LSN(n_pagep); + } else { + n_pagep = NULL; + n_lsn = NULL; + } + + NEXT_PGNO(p_pagep) = NEXT_PGNO(p); + if (n_pagep != NULL) + PREV_PGNO(n_pagep) = PGNO(p_pagep); + + if (DB_LOGGING(dbc)) { + if ((ret = __ham_newpage_log(dbenv, + dbc->txn, &new_lsn, 0, DELOVFL, + dbp->log_fileid, PREV_PGNO(p), &LSN(p_pagep), + PGNO(p), &LSN(p), NEXT_PGNO(p), n_lsn)) != 0) + goto err; + + /* Move lsn onto page. */ + LSN(p_pagep) = new_lsn; /* Structure assignment. */ + if (n_pagep) + LSN(n_pagep) = new_lsn; + LSN(p) = new_lsn; + } + if (NEXT_PGNO(p) == PGNO_INVALID) { + /* + * There is no next page; put the cursor on the + * previous page as if we'd deleted the last item + * on that page; index greater than number of + * valid entries and H_DELETED set. + */ + hcp->pgno = PGNO(p_pagep); + hcp->indx = NUM_ENT(p_pagep); + F_SET(hcp, H_DELETED); + } else { + hcp->pgno = NEXT_PGNO(p); + hcp->indx = 0; + } + + /* + * Since we are about to delete the cursor page and we have + * just moved the cursor, we need to make sure that the + * old page pointer isn't left hanging around in the cursor. + */ + hcp->page = NULL; + chg_pgno = PGNO(p); + ret = __db_free(dbc, p); + if ((t_ret = memp_fput(dbp->mpf, p_pagep, DB_MPOOL_DIRTY)) != 0 + && ret == 0) + ret = t_ret; + if (n_pagep != NULL && (t_ret = memp_fput(dbp->mpf, + n_pagep, DB_MPOOL_DIRTY)) != 0 && ret == 0) + ret = t_ret; + if (ret != 0) + return (ret); + ret = __ham_c_chgpg(dbc, + chg_pgno, 0, hcp->pgno, hcp->indx); + } + return (ret); + +err: /* Clean up any pages. */ + if (n_pagep != NULL) + (void)memp_fput(dbp->mpf, n_pagep, 0); + if (nn_pagep != NULL) + (void)memp_fput(dbp->mpf, nn_pagep, 0); + if (p_pagep != NULL) + (void)memp_fput(dbp->mpf, p_pagep, 0); + return (ret); +} + +/* + * __ham_replpair -- + * Given the key data indicated by the cursor, replace part/all of it + * according to the fields in the dbt. + * + * PUBLIC: int __ham_replpair __P((DBC *, DBT *, u_int32_t)); + */ +int +__ham_replpair(dbc, dbt, make_dup) + DBC *dbc; + DBT *dbt; + u_int32_t make_dup; +{ + DB *dbp; + HASH_CURSOR *hcp; + DBT old_dbt, tdata, tmp; + DB_LSN new_lsn; + int32_t change; /* XXX: Possible overflow. */ + u_int32_t dup, len, memsize; + int is_big, ret, type; + u_int8_t *beg, *dest, *end, *hk, *src; + void *memp; + + /* + * Big item replacements are handled in generic code. + * Items that fit on the current page fall into 4 classes. + * 1. On-page element, same size + * 2. On-page element, new is bigger (fits) + * 3. On-page element, new is bigger (does not fit) + * 4. On-page element, old is bigger + * Numbers 1, 2, and 4 are essentially the same (and should + * be the common case). We handle case 3 as a delete and + * add. + */ + dbp = dbc->dbp; + hcp = (HASH_CURSOR *)dbc->internal; + + /* + * We need to compute the number of bytes that we are adding or + * removing from the entry. Normally, we can simply substract + * the number of bytes we are replacing (dbt->dlen) from the + * number of bytes we are inserting (dbt->size). However, if + * we are doing a partial put off the end of a record, then this + * formula doesn't work, because we are essentially adding + * new bytes. + */ + change = dbt->size - dbt->dlen; + + hk = H_PAIRDATA(hcp->page, hcp->indx); + is_big = HPAGE_PTYPE(hk) == H_OFFPAGE; + + if (is_big) + memcpy(&len, HOFFPAGE_TLEN(hk), sizeof(u_int32_t)); + else + len = LEN_HKEYDATA(hcp->page, + dbp->pgsize, H_DATAINDEX(hcp->indx)); + + if (dbt->doff + dbt->dlen > len) + change += dbt->doff + dbt->dlen - len; + + if (change > (int32_t)P_FREESPACE(hcp->page) || is_big) { + /* + * Case 3 -- two subcases. + * A. This is not really a partial operation, but an overwrite. + * Simple del and add works. + * B. This is a partial and we need to construct the data that + * we are really inserting (yuck). + * In both cases, we need to grab the key off the page (in + * some cases we could do this outside of this routine; for + * cleanliness we do it here. If you happen to be on a big + * key, this could be a performance hit). + */ + memset(&tmp, 0, sizeof(tmp)); + if ((ret = + __db_ret(dbp, hcp->page, H_KEYINDEX(hcp->indx), + &tmp, &dbc->rkey.data, &dbc->rkey.ulen)) != 0) + return (ret); + + /* Preserve duplicate info. */ + dup = F_ISSET(hcp, H_ISDUP); + if (dbt->doff == 0 && dbt->dlen == len) { + ret = __ham_del_pair(dbc, 0); + if (ret == 0) + ret = __ham_add_el(dbc, + &tmp, dbt, dup ? H_DUPLICATE : H_KEYDATA); + } else { /* Case B */ + type = HPAGE_PTYPE(hk) != H_OFFPAGE ? + HPAGE_PTYPE(hk) : H_KEYDATA; + memset(&tdata, 0, sizeof(tdata)); + memp = NULL; + memsize = 0; + if ((ret = __db_ret(dbp, hcp->page, + H_DATAINDEX(hcp->indx), &tdata, &memp, &memsize)) + != 0) + goto err; + + /* Now we can delete the item. */ + if ((ret = __ham_del_pair(dbc, 0)) != 0) { + __os_free(memp, memsize); + goto err; + } + + /* Now shift old data around to make room for new. */ + if (change > 0) { + if ((ret = __os_realloc(dbp->dbenv, + tdata.size + change, + NULL, &tdata.data)) != 0) + return (ret); + memp = tdata.data; + memsize = tdata.size + change; + memset((u_int8_t *)tdata.data + tdata.size, + 0, change); + } + end = (u_int8_t *)tdata.data + tdata.size; + + src = (u_int8_t *)tdata.data + dbt->doff + dbt->dlen; + if (src < end && tdata.size > dbt->doff + dbt->dlen) { + len = tdata.size - dbt->doff - dbt->dlen; + dest = src + change; + memmove(dest, src, len); + } + memcpy((u_int8_t *)tdata.data + dbt->doff, + dbt->data, dbt->size); + tdata.size += change; + + /* Now add the pair. */ + ret = __ham_add_el(dbc, &tmp, &tdata, type); + __os_free(memp, memsize); + } + F_SET(hcp, dup); +err: return (ret); + } + + /* + * Set up pointer into existing data. Do it before the log + * message so we can use it inside of the log setup. + */ + beg = HKEYDATA_DATA(H_PAIRDATA(hcp->page, hcp->indx)); + beg += dbt->doff; + + /* + * If we are going to have to move bytes at all, figure out + * all the parameters here. Then log the call before moving + * anything around. + */ + if (DB_LOGGING(dbc)) { + old_dbt.data = beg; + old_dbt.size = dbt->dlen; + if ((ret = __ham_replace_log(dbp->dbenv, + dbc->txn, &new_lsn, 0, dbp->log_fileid, PGNO(hcp->page), + (u_int32_t)H_DATAINDEX(hcp->indx), &LSN(hcp->page), + (u_int32_t)dbt->doff, &old_dbt, dbt, make_dup)) != 0) + return (ret); + + LSN(hcp->page) = new_lsn; /* Structure assignment. */ + } + + __ham_onpage_replace(hcp->page, dbp->pgsize, + (u_int32_t)H_DATAINDEX(hcp->indx), (int32_t)dbt->doff, change, dbt); + + return (0); +} + +/* + * Replace data on a page with new data, possibly growing or shrinking what's + * there. This is called on two different occasions. On one (from replpair) + * we are interested in changing only the data. On the other (from recovery) + * we are replacing the entire data (header and all) with a new element. In + * the latter case, the off argument is negative. + * pagep: the page that we're changing + * ndx: page index of the element that is growing/shrinking. + * off: Offset at which we are beginning the replacement. + * change: the number of bytes (+ or -) that the element is growing/shrinking. + * dbt: the new data that gets written at beg. + * PUBLIC: void __ham_onpage_replace __P((PAGE *, size_t, u_int32_t, int32_t, + * PUBLIC: int32_t, DBT *)); + */ +void +__ham_onpage_replace(pagep, pgsize, ndx, off, change, dbt) + PAGE *pagep; + size_t pgsize; + u_int32_t ndx; + int32_t off; + int32_t change; + DBT *dbt; +{ + db_indx_t i; + int32_t len; + u_int8_t *src, *dest; + int zero_me; + + if (change != 0) { + zero_me = 0; + src = (u_int8_t *)(pagep) + HOFFSET(pagep); + if (off < 0) + len = pagep->inp[ndx] - HOFFSET(pagep); + else if ((u_int32_t)off >= LEN_HKEYDATA(pagep, pgsize, ndx)) { + len = HKEYDATA_DATA(P_ENTRY(pagep, ndx)) + + LEN_HKEYDATA(pagep, pgsize, ndx) - src; + zero_me = 1; + } else + len = (HKEYDATA_DATA(P_ENTRY(pagep, ndx)) + off) - src; + dest = src - change; + memmove(dest, src, len); + if (zero_me) + memset(dest + len, 0, change); + + /* Now update the indices. */ + for (i = ndx; i < NUM_ENT(pagep); i++) + pagep->inp[i] -= change; + HOFFSET(pagep) -= change; + } + if (off >= 0) + memcpy(HKEYDATA_DATA(P_ENTRY(pagep, ndx)) + off, + dbt->data, dbt->size); + else + memcpy(P_ENTRY(pagep, ndx), dbt->data, dbt->size); +} + +/* + * PUBLIC: int __ham_split_page __P((DBC *, u_int32_t, u_int32_t)); + */ +int +__ham_split_page(dbc, obucket, nbucket) + DBC *dbc; + u_int32_t obucket, nbucket; +{ + DB *dbp; + DBC **carray; + HASH_CURSOR *hcp, *cp; + DBT key, page_dbt; + DB_ENV *dbenv; + DB_LSN new_lsn; + PAGE **pp, *old_pagep, *temp_pagep, *new_pagep; + db_indx_t n; + db_pgno_t bucket_pgno, npgno, next_pgno; + u_int32_t big_len, len; + int found, i, ret, t_ret; + void *big_buf; + + dbp = dbc->dbp; + hcp = (HASH_CURSOR *)dbc->internal; + dbenv = dbp->dbenv; + temp_pagep = old_pagep = new_pagep = NULL; + + if ((ret = __ham_get_clist(dbp, obucket, NDX_INVALID, &carray)) != 0) + return (ret); + + bucket_pgno = BUCKET_TO_PAGE(hcp, obucket); + if ((ret = memp_fget(dbp->mpf, + &bucket_pgno, DB_MPOOL_CREATE, &old_pagep)) != 0) + goto err; + + /* Properly initialize the new bucket page. */ + npgno = BUCKET_TO_PAGE(hcp, nbucket); + if ((ret = memp_fget(dbp->mpf, + &npgno, DB_MPOOL_CREATE, &new_pagep)) != 0) + goto err; + P_INIT(new_pagep, + dbp->pgsize, npgno, PGNO_INVALID, PGNO_INVALID, 0, P_HASH); + + temp_pagep = hcp->split_buf; + memcpy(temp_pagep, old_pagep, dbp->pgsize); + + if (DB_LOGGING(dbc)) { + page_dbt.size = dbp->pgsize; + page_dbt.data = old_pagep; + if ((ret = __ham_splitdata_log(dbenv, + dbc->txn, &new_lsn, 0, dbp->log_fileid, SPLITOLD, + PGNO(old_pagep), &page_dbt, &LSN(old_pagep))) != 0) + goto err; + } + + P_INIT(old_pagep, dbp->pgsize, PGNO(old_pagep), PGNO_INVALID, + PGNO_INVALID, 0, P_HASH); + + if (DB_LOGGING(dbc)) + LSN(old_pagep) = new_lsn; /* Structure assignment. */ + + big_len = 0; + big_buf = NULL; + key.flags = 0; + while (temp_pagep != NULL) { + for (n = 0; n < (db_indx_t)NUM_ENT(temp_pagep); n += 2) { + if ((ret = + __db_ret(dbp, temp_pagep, H_KEYINDEX(n), + &key, &big_buf, &big_len)) != 0) + goto err; + + if (__ham_call_hash(dbc, key.data, key.size) + == obucket) + pp = &old_pagep; + else + pp = &new_pagep; + + /* + * Figure out how many bytes we need on the new + * page to store the key/data pair. + */ + + len = LEN_HITEM(temp_pagep, dbp->pgsize, + H_DATAINDEX(n)) + + LEN_HITEM(temp_pagep, dbp->pgsize, + H_KEYINDEX(n)) + + 2 * sizeof(db_indx_t); + + if (P_FREESPACE(*pp) < len) { + if (DB_LOGGING(dbc)) { + page_dbt.size = dbp->pgsize; + page_dbt.data = *pp; + if ((ret = __ham_splitdata_log( + dbenv, dbc->txn, + &new_lsn, 0, dbp->log_fileid, + SPLITNEW, PGNO(*pp), &page_dbt, + &LSN(*pp))) != 0) + goto err; + LSN(*pp) = new_lsn; + } + if ((ret = + __ham_add_ovflpage(dbc, *pp, 1, pp)) != 0) + goto err; + } + + /* Check if we need to update a cursor. */ + if (carray != NULL) { + found = 0; + for (i = 0; carray[i] != NULL; i++) { + cp = + (HASH_CURSOR *)carray[i]->internal; + if (cp->pgno == PGNO(temp_pagep) + && cp->indx == n) { + cp->pgno = PGNO(*pp); + cp->indx = NUM_ENT(*pp); + found = 1; + } + } + if (found && DB_LOGGING(dbc) + && IS_SUBTRANSACTION(dbc->txn)) { + if ((ret = + __ham_chgpg_log(dbp->dbenv, + dbc->txn, &new_lsn, 0, + dbp->log_fileid, + DB_HAM_SPLIT, PGNO(temp_pagep), + PGNO(*pp), n, NUM_ENT(*pp))) != 0) + goto err; + } + } + __ham_copy_item(dbp->pgsize, + temp_pagep, H_KEYINDEX(n), *pp); + __ham_copy_item(dbp->pgsize, + temp_pagep, H_DATAINDEX(n), *pp); + } + next_pgno = NEXT_PGNO(temp_pagep); + + /* Clear temp_page; if it's a link overflow page, free it. */ + if (PGNO(temp_pagep) != bucket_pgno && (ret = + __db_free(dbc, temp_pagep)) != 0) { + temp_pagep = NULL; + goto err; + } + + if (next_pgno == PGNO_INVALID) + temp_pagep = NULL; + else if ((ret = memp_fget(dbp->mpf, + &next_pgno, DB_MPOOL_CREATE, &temp_pagep)) != 0) + goto err; + + if (temp_pagep != NULL && DB_LOGGING(dbc)) { + page_dbt.size = dbp->pgsize; + page_dbt.data = temp_pagep; + if ((ret = __ham_splitdata_log(dbenv, + dbc->txn, &new_lsn, 0, dbp->log_fileid, + SPLITOLD, PGNO(temp_pagep), + &page_dbt, &LSN(temp_pagep))) != 0) + goto err; + LSN(temp_pagep) = new_lsn; + } + } + if (big_buf != NULL) + __os_free(big_buf, big_len); + + /* + * If the original bucket spanned multiple pages, then we've got + * a pointer to a page that used to be on the bucket chain. It + * should be deleted. + */ + if (temp_pagep != NULL && PGNO(temp_pagep) != bucket_pgno && + (ret = __db_free(dbc, temp_pagep)) != 0) { + temp_pagep = NULL; + goto err; + } + + /* + * Write new buckets out. + */ + if (DB_LOGGING(dbc)) { + page_dbt.size = dbp->pgsize; + page_dbt.data = old_pagep; + if ((ret = __ham_splitdata_log(dbenv, dbc->txn, &new_lsn, 0, + dbp->log_fileid, SPLITNEW, PGNO(old_pagep), &page_dbt, + &LSN(old_pagep))) != 0) + goto err; + LSN(old_pagep) = new_lsn; + + page_dbt.data = new_pagep; + if ((ret = __ham_splitdata_log(dbenv, dbc->txn, &new_lsn, 0, + dbp->log_fileid, SPLITNEW, PGNO(new_pagep), &page_dbt, + &LSN(new_pagep))) != 0) + goto err; + LSN(new_pagep) = new_lsn; + } + ret = memp_fput(dbp->mpf, old_pagep, DB_MPOOL_DIRTY); + if ((t_ret = memp_fput(dbp->mpf, new_pagep, DB_MPOOL_DIRTY)) != 0 + && ret == 0) + ret = t_ret; + + if (0) { +err: if (old_pagep != NULL) + (void)memp_fput(dbp->mpf, old_pagep, DB_MPOOL_DIRTY); + if (new_pagep != NULL) + (void)memp_fput(dbp->mpf, new_pagep, DB_MPOOL_DIRTY); + if (temp_pagep != NULL && PGNO(temp_pagep) != bucket_pgno) + (void)memp_fput(dbp->mpf, temp_pagep, DB_MPOOL_DIRTY); + } + if (carray != NULL) /* We never knew its size. */ + __os_free(carray, 0); + return (ret); +} + +/* + * Add the given pair to the page. The page in question may already be + * held (i.e. it was already gotten). If it is, then the page is passed + * in via the pagep parameter. On return, pagep will contain the page + * to which we just added something. This allows us to link overflow + * pages and return the new page having correctly put the last page. + * + * PUBLIC: int __ham_add_el __P((DBC *, const DBT *, const DBT *, int)); + */ +int +__ham_add_el(dbc, key, val, type) + DBC *dbc; + const DBT *key, *val; + int type; +{ + DB *dbp; + HASH_CURSOR *hcp; + const DBT *pkey, *pdata; + DBT key_dbt, data_dbt; + DB_LSN new_lsn; + HOFFPAGE doff, koff; + db_pgno_t next_pgno, pgno; + u_int32_t data_size, key_size, pairsize, rectype; + int do_expand, is_keybig, is_databig, ret; + int key_type, data_type; + + dbp = dbc->dbp; + hcp = (HASH_CURSOR *)dbc->internal; + do_expand = 0; + + pgno = hcp->seek_found_page != PGNO_INVALID ? hcp->seek_found_page : + hcp->pgno; + if (hcp->page == NULL && (ret = memp_fget(dbp->mpf, &pgno, + DB_MPOOL_CREATE, &hcp->page)) != 0) + return (ret); + + key_size = HKEYDATA_PSIZE(key->size); + data_size = HKEYDATA_PSIZE(val->size); + is_keybig = ISBIG(hcp, key->size); + is_databig = ISBIG(hcp, val->size); + if (is_keybig) + key_size = HOFFPAGE_PSIZE; + if (is_databig) + data_size = HOFFPAGE_PSIZE; + + pairsize = key_size + data_size; + + /* Advance to first page in chain with room for item. */ + while (H_NUMPAIRS(hcp->page) && NEXT_PGNO(hcp->page) != PGNO_INVALID) { + /* + * This may not be the end of the chain, but the pair may fit + * anyway. Check if it's a bigpair that fits or a regular + * pair that fits. + */ + if (P_FREESPACE(hcp->page) >= pairsize) + break; + next_pgno = NEXT_PGNO(hcp->page); + if ((ret = + __ham_next_cpage(dbc, next_pgno, 0)) != 0) + return (ret); + } + + /* + * Check if we need to allocate a new page. + */ + if (P_FREESPACE(hcp->page) < pairsize) { + do_expand = 1; + if ((ret = __ham_add_ovflpage(dbc, + (PAGE *)hcp->page, 1, (PAGE **)&hcp->page)) != 0) + return (ret); + hcp->pgno = PGNO(hcp->page); + } + + /* + * Update cursor. + */ + hcp->indx = NUM_ENT(hcp->page); + F_CLR(hcp, H_DELETED); + if (is_keybig) { + koff.type = H_OFFPAGE; + UMRW_SET(koff.unused[0]); + UMRW_SET(koff.unused[1]); + UMRW_SET(koff.unused[2]); + if ((ret = __db_poff(dbc, key, &koff.pgno)) != 0) + return (ret); + koff.tlen = key->size; + key_dbt.data = &koff; + key_dbt.size = sizeof(koff); + pkey = &key_dbt; + key_type = H_OFFPAGE; + } else { + pkey = key; + key_type = H_KEYDATA; + } + + if (is_databig) { + doff.type = H_OFFPAGE; + UMRW_SET(doff.unused[0]); + UMRW_SET(doff.unused[1]); + UMRW_SET(doff.unused[2]); + if ((ret = __db_poff(dbc, val, &doff.pgno)) != 0) + return (ret); + doff.tlen = val->size; + data_dbt.data = &doff; + data_dbt.size = sizeof(doff); + pdata = &data_dbt; + data_type = H_OFFPAGE; + } else { + pdata = val; + data_type = type; + } + + if (DB_LOGGING(dbc)) { + rectype = PUTPAIR; + if (is_databig) + rectype |= PAIR_DATAMASK; + if (is_keybig) + rectype |= PAIR_KEYMASK; + if (type == H_DUPLICATE) + rectype |= PAIR_DUPMASK; + + if ((ret = __ham_insdel_log(dbp->dbenv, dbc->txn, &new_lsn, 0, + rectype, dbp->log_fileid, PGNO(hcp->page), + (u_int32_t)NUM_ENT(hcp->page), &LSN(hcp->page), pkey, + pdata)) != 0) + return (ret); + + /* Move lsn onto page. */ + LSN(hcp->page) = new_lsn; /* Structure assignment. */ + } + + __ham_putitem(hcp->page, pkey, key_type); + __ham_putitem(hcp->page, pdata, data_type); + + /* + * For splits, we are going to update item_info's page number + * field, so that we can easily return to the same page the + * next time we come in here. For other operations, this shouldn't + * matter, since odds are this is the last thing that happens before + * we return to the user program. + */ + hcp->pgno = PGNO(hcp->page); + + /* + * XXX + * Maybe keep incremental numbers here. + */ + if (!STD_LOCKING(dbc)) + hcp->hdr->nelem++; + + if (do_expand || (hcp->hdr->ffactor != 0 && + (u_int32_t)H_NUMPAIRS(hcp->page) > hcp->hdr->ffactor)) + F_SET(hcp, H_EXPAND); + return (0); +} + +/* + * Special __putitem call used in splitting -- copies one entry to + * another. Works for all types of hash entries (H_OFFPAGE, H_KEYDATA, + * H_DUPLICATE, H_OFFDUP). Since we log splits at a high level, we + * do not need to do any logging here. + * + * PUBLIC: void __ham_copy_item __P((size_t, PAGE *, u_int32_t, PAGE *)); + */ +void +__ham_copy_item(pgsize, src_page, src_ndx, dest_page) + size_t pgsize; + PAGE *src_page; + u_int32_t src_ndx; + PAGE *dest_page; +{ + u_int32_t len; + void *src, *dest; + + /* + * Copy the key and data entries onto this new page. + */ + src = P_ENTRY(src_page, src_ndx); + + /* Set up space on dest. */ + len = LEN_HITEM(src_page, pgsize, src_ndx); + HOFFSET(dest_page) -= len; + dest_page->inp[NUM_ENT(dest_page)] = HOFFSET(dest_page); + dest = P_ENTRY(dest_page, NUM_ENT(dest_page)); + NUM_ENT(dest_page)++; + + memcpy(dest, src, len); +} + +/* + * + * Returns: + * pointer on success + * NULL on error + * + * PUBLIC: int __ham_add_ovflpage __P((DBC *, PAGE *, int, PAGE **)); + */ +int +__ham_add_ovflpage(dbc, pagep, release, pp) + DBC *dbc; + PAGE *pagep; + int release; + PAGE **pp; +{ + DB *dbp; + HASH_CURSOR *hcp; + DB_LSN new_lsn; + PAGE *new_pagep; + int ret; + + dbp = dbc->dbp; + hcp = (HASH_CURSOR *)dbc->internal; + + if ((ret = __db_new(dbc, P_HASH, &new_pagep)) != 0) + return (ret); + + if (DB_LOGGING(dbc)) { + if ((ret = __ham_newpage_log(dbp->dbenv, dbc->txn, &new_lsn, 0, + PUTOVFL, dbp->log_fileid, PGNO(pagep), &LSN(pagep), + PGNO(new_pagep), &LSN(new_pagep), PGNO_INVALID, NULL)) != 0) + return (ret); + + /* Move lsn onto page. */ + LSN(pagep) = LSN(new_pagep) = new_lsn; + } + NEXT_PGNO(pagep) = PGNO(new_pagep); + PREV_PGNO(new_pagep) = PGNO(pagep); + + if (release) + ret = memp_fput(dbp->mpf, pagep, DB_MPOOL_DIRTY); + + *pp = new_pagep; + return (ret); +} + +/* + * PUBLIC: int __ham_get_cpage __P((DBC *, db_lockmode_t)); + */ +int +__ham_get_cpage(dbc, mode) + DBC *dbc; + db_lockmode_t mode; +{ + DB *dbp; + DB_LOCK tmp_lock; + HASH_CURSOR *hcp; + int ret; + + dbp = dbc->dbp; + hcp = (HASH_CURSOR *)dbc->internal; + ret = 0; + + /* + * There are four cases with respect to buckets and locks. + * 1. If there is no lock held, then if we are locking, we should + * get the lock. + * 2. If there is a lock held, it's for the current bucket, and it's + * for the right mode, we don't need to do anything. + * 3. If there is a lock held for the current bucket but it's not + * strong enough, we need to upgrade. + * 4. If there is a lock, but it's for a different bucket, then we need + * to release the existing lock and get a new lock. + */ + tmp_lock.off = LOCK_INVALID; + if (STD_LOCKING(dbc)) { + if (hcp->lock.off != LOCK_INVALID && + hcp->lbucket != hcp->bucket) { /* Case 4 */ + if (dbc->txn == NULL && + (ret = lock_put(dbp->dbenv, &hcp->lock)) != 0) + return (ret); + hcp->lock.off = LOCK_INVALID; + } + if ((hcp->lock.off != LOCK_INVALID && + (hcp->lock_mode == DB_LOCK_READ && + mode == DB_LOCK_WRITE))) { + /* Case 3. */ + tmp_lock = hcp->lock; + hcp->lock.off = LOCK_INVALID; + } + + /* Acquire the lock. */ + if (hcp->lock.off == LOCK_INVALID) + /* Cases 1, 3, and 4. */ + if ((ret = __ham_lock_bucket(dbc, mode)) != 0) + return (ret); + + if (ret == 0) { + hcp->lock_mode = mode; + hcp->lbucket = hcp->bucket; + if (tmp_lock.off != LOCK_INVALID) + /* Case 3: release the original lock. */ + ret = lock_put(dbp->dbenv, &tmp_lock); + } else if (tmp_lock.off != LOCK_INVALID) + hcp->lock = tmp_lock; + } + + if (ret == 0 && hcp->page == NULL) { + if (hcp->pgno == PGNO_INVALID) + hcp->pgno = BUCKET_TO_PAGE(hcp, hcp->bucket); + if ((ret = memp_fget(dbp->mpf, + &hcp->pgno, DB_MPOOL_CREATE, &hcp->page)) != 0) + return (ret); + } + + return (0); +} + +/* + * Get a new page at the cursor, putting the last page if necessary. + * If the flag is set to H_ISDUP, then we are talking about the + * duplicate page, not the main page. + * + * PUBLIC: int __ham_next_cpage __P((DBC *, db_pgno_t, int)); + */ +int +__ham_next_cpage(dbc, pgno, dirty) + DBC *dbc; + db_pgno_t pgno; + int dirty; +{ + DB *dbp; + HASH_CURSOR *hcp; + PAGE *p; + int ret; + + dbp = dbc->dbp; + hcp = (HASH_CURSOR *)dbc->internal; + + if (hcp->page != NULL && (ret = memp_fput(dbp->mpf, + hcp->page, dirty ? DB_MPOOL_DIRTY : 0)) != 0) + return (ret); + + if ((ret = memp_fget(dbp->mpf, &pgno, DB_MPOOL_CREATE, &p)) != 0) + return (ret); + + hcp->page = p; + hcp->pgno = pgno; + hcp->indx = 0; + + return (0); +} + +/* + * __ham_lock_bucket -- + * Get the lock on a particular bucket. + * + * PUBLIC: int __ham_lock_bucket __P((DBC *, db_lockmode_t)); + */ +int +__ham_lock_bucket(dbc, mode) + DBC *dbc; + db_lockmode_t mode; +{ + HASH_CURSOR *hcp; + u_int32_t flags; + int gotmeta, ret; + + hcp = (HASH_CURSOR *)dbc->internal; + gotmeta = hcp->hdr == NULL ? 1 : 0; + if (gotmeta) + if ((ret = __ham_get_meta(dbc)) != 0) + return (ret); + dbc->lock.pgno = BUCKET_TO_PAGE(hcp, hcp->bucket); + if (gotmeta) + if ((ret = __ham_release_meta(dbc)) != 0) + return (ret); + + flags = 0; + if (DB_NONBLOCK(dbc)) + LF_SET(DB_LOCK_NOWAIT); + + ret = lock_get(dbc->dbp->dbenv, + dbc->locker, flags, &dbc->lock_dbt, mode, &hcp->lock); + + hcp->lock_mode = mode; + return (ret); +} + +/* + * __ham_dpair -- + * Delete a pair on a page, paying no attention to what the pair + * represents. The caller is responsible for freeing up duplicates + * or offpage entries that might be referenced by this pair. + * + * PUBLIC: void __ham_dpair __P((DB *, PAGE *, u_int32_t)); + */ +void +__ham_dpair(dbp, p, indx) + DB *dbp; + PAGE *p; + u_int32_t indx; +{ + db_indx_t delta, n; + u_int8_t *dest, *src; + + /* + * Compute "delta", the amount we have to shift all of the + * offsets. To find the delta, we just need to calculate + * the size of the pair of elements we are removing. + */ + delta = H_PAIRSIZE(p, dbp->pgsize, indx); + + /* + * The hard case: we want to remove something other than + * the last item on the page. We need to shift data and + * offsets down. + */ + if ((db_indx_t)indx != NUM_ENT(p) - 2) { + /* + * Move the data: src is the first occupied byte on + * the page. (Length is delta.) + */ + src = (u_int8_t *)p + HOFFSET(p); + + /* + * Destination is delta bytes beyond src. This might + * be an overlapping copy, so we have to use memmove. + */ + dest = src + delta; + memmove(dest, src, p->inp[H_DATAINDEX(indx)] - HOFFSET(p)); + } + + /* Adjust page metadata. */ + HOFFSET(p) = HOFFSET(p) + delta; + NUM_ENT(p) = NUM_ENT(p) - 2; + + /* Adjust the offsets. */ + for (n = (db_indx_t)indx; n < (db_indx_t)(NUM_ENT(p)); n++) + p->inp[n] = p->inp[n + 2] + delta; + +} diff --git a/db/hash/hash_rec.c b/db/hash/hash_rec.c new file mode 100644 index 000000000..ded58c281 --- /dev/null +++ b/db/hash/hash_rec.c @@ -0,0 +1,1078 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1995, 1996 + * Margo Seltzer. All rights reserved. + */ +/* + * Copyright (c) 1995, 1996 + * The President and Fellows of Harvard University. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Margo Seltzer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: hash_rec.c,v 11.34 2001/01/11 18:19:52 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_shash.h" +#include "btree.h" +#include "hash.h" +#include "lock.h" +#include "log.h" +#include "mp.h" + +static int __ham_alloc_pages __P((DB *, __ham_groupalloc_args *)); + +/* + * __ham_insdel_recover -- + * + * PUBLIC: int __ham_insdel_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__ham_insdel_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __ham_insdel_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + u_int32_t opcode; + int cmp_n, cmp_p, flags, getmeta, ret, type; + + COMPQUIET(info, NULL); + + getmeta = 0; + REC_PRINT(__ham_insdel_print); + REC_INTRO(__ham_insdel_read, 1); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) { + if (DB_UNDO(op)) { + /* + * We are undoing and the page doesn't exist. That + * is equivalent to having a pagelsn of 0, so we + * would not have to undo anything. In this case, + * don't bother creating a page. + */ + goto done; + } else if ((ret = memp_fget(mpf, &argp->pgno, + DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } + + if ((ret = __ham_get_meta(dbc)) != 0) + goto out; + getmeta = 1; + + cmp_n = log_compare(lsnp, &LSN(pagep)); + cmp_p = log_compare(&LSN(pagep), &argp->pagelsn); + CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->pagelsn); + /* + * Two possible things going on: + * redo a delete/undo a put: delete the item from the page. + * redo a put/undo a delete: add the item to the page. + * If we are undoing a delete, then the information logged is the + * entire entry off the page, not just the data of a dbt. In + * this case, we want to copy it back onto the page verbatim. + * We do this by calling __putitem with the type H_OFFPAGE instead + * of H_KEYDATA. + */ + opcode = OPCODE_OF(argp->opcode); + + flags = 0; + if ((opcode == DELPAIR && cmp_n == 0 && DB_UNDO(op)) || + (opcode == PUTPAIR && cmp_p == 0 && DB_REDO(op))) { + /* + * Need to redo a PUT or undo a delete. If we are undoing a + * delete, we've got to restore the item back to its original + * position. That's a royal pain in the butt (because we do + * not store item lengths on the page), but there's no choice. + */ + if (opcode != DELPAIR || + argp->ndx == (u_int32_t)NUM_ENT(pagep)) { + __ham_putitem(pagep, &argp->key, + DB_UNDO(op) || PAIR_ISKEYBIG(argp->opcode) ? + H_OFFPAGE : H_KEYDATA); + + if (PAIR_ISDATADUP(argp->opcode)) + type = H_DUPLICATE; + else if (DB_UNDO(op) || PAIR_ISDATABIG(argp->opcode)) + type = H_OFFPAGE; + else + type = H_KEYDATA; + __ham_putitem(pagep, &argp->data, type); + } else + (void)__ham_reputpair(pagep, file_dbp->pgsize, + argp->ndx, &argp->key, &argp->data); + + LSN(pagep) = DB_REDO(op) ? *lsnp : argp->pagelsn; + flags = DB_MPOOL_DIRTY; + + } else if ((opcode == DELPAIR && cmp_p == 0 && DB_REDO(op)) + || (opcode == PUTPAIR && cmp_n == 0 && DB_UNDO(op))) { + /* Need to undo a put or redo a delete. */ + __ham_dpair(file_dbp, pagep, argp->ndx); + LSN(pagep) = DB_REDO(op) ? *lsnp : argp->pagelsn; + flags = DB_MPOOL_DIRTY; + } + + if ((ret = memp_fput(file_dbp->mpf, pagep, flags)) != 0) + goto out; + + /* Return the previous LSN. */ +done: *lsnp = argp->prev_lsn; + ret = 0; + +out: if (getmeta) + (void)__ham_release_meta(dbc); + REC_CLOSE; +} + +/* + * __ham_newpage_recover -- + * This log message is used when we add/remove overflow pages. This + * message takes care of the pointer chains, not the data on the pages. + * + * PUBLIC: int __ham_newpage_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__ham_newpage_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __ham_newpage_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, flags, getmeta, ret; + + COMPQUIET(info, NULL); + + getmeta = 0; + REC_PRINT(__ham_newpage_print); + REC_INTRO(__ham_newpage_read, 1); + + if ((ret = memp_fget(mpf, &argp->new_pgno, 0, &pagep)) != 0) { + if (DB_UNDO(op)) { + /* + * We are undoing and the page doesn't exist. That + * is equivalent to having a pagelsn of 0, so we + * would not have to undo anything. In this case, + * don't bother creating a page. + */ + ret = 0; + goto ppage; + } else if ((ret = memp_fget(mpf, &argp->new_pgno, + DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } + + if ((ret = __ham_get_meta(dbc)) != 0) + goto out; + getmeta = 1; + + /* + * There are potentially three pages we need to check: the one + * that we created/deleted, the one before it and the one after + * it. + */ + + cmp_n = log_compare(lsnp, &LSN(pagep)); + cmp_p = log_compare(&LSN(pagep), &argp->pagelsn); + CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->pagelsn); + + flags = 0; + if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == PUTOVFL) || + (cmp_n == 0 && DB_UNDO(op) && argp->opcode == DELOVFL)) { + /* Redo a create new page or undo a delete new page. */ + P_INIT(pagep, file_dbp->pgsize, argp->new_pgno, + argp->prev_pgno, argp->next_pgno, 0, P_HASH); + flags = DB_MPOOL_DIRTY; + } else if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == DELOVFL) || + (cmp_n == 0 && DB_UNDO(op) && argp->opcode == PUTOVFL)) { + /* + * Redo a delete or undo a create new page. All we + * really need to do is change the LSN. + */ + flags = DB_MPOOL_DIRTY; + } + + if (flags) + LSN(pagep) = DB_REDO(op) ? *lsnp : argp->pagelsn; + + if ((ret = memp_fput(file_dbp->mpf, pagep, flags)) != 0) + goto out; + + /* Now do the prev page. */ +ppage: if (argp->prev_pgno != PGNO_INVALID) { + if ((ret = memp_fget(mpf, &argp->prev_pgno, 0, &pagep)) != 0) { + if (DB_UNDO(op)) { + /* + * We are undoing and the page doesn't exist. + * That is equivalent to having a pagelsn of 0, + * so we would not have to undo anything. In + * this case, don't bother creating a page. + */ + ret = 0; + goto npage; + } else if ((ret = + memp_fget(mpf, &argp->prev_pgno, + DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } + + cmp_n = log_compare(lsnp, &LSN(pagep)); + cmp_p = log_compare(&LSN(pagep), &argp->prevlsn); + CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->prevlsn); + flags = 0; + + if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == PUTOVFL) || + (cmp_n == 0 && DB_UNDO(op) && argp->opcode == DELOVFL)) { + /* Redo a create new page or undo a delete new page. */ + pagep->next_pgno = argp->new_pgno; + flags = DB_MPOOL_DIRTY; + } else if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == DELOVFL) || + (cmp_n == 0 && DB_UNDO(op) && argp->opcode == PUTOVFL)) { + /* Redo a delete or undo a create new page. */ + pagep->next_pgno = argp->next_pgno; + flags = DB_MPOOL_DIRTY; + } + + if (flags) + LSN(pagep) = DB_REDO(op) ? *lsnp : argp->prevlsn; + + if ((ret = memp_fput(file_dbp->mpf, pagep, flags)) != 0) + goto out; + } + + /* Now time to do the next page */ +npage: if (argp->next_pgno != PGNO_INVALID) { + if ((ret = memp_fget(mpf, &argp->next_pgno, 0, &pagep)) != 0) { + if (DB_UNDO(op)) { + /* + * We are undoing and the page doesn't exist. + * That is equivalent to having a pagelsn of 0, + * so we would not have to undo anything. In + * this case, don't bother creating a page. + */ + goto done; + } else if ((ret = + memp_fget(mpf, &argp->next_pgno, + DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } + + cmp_n = log_compare(lsnp, &LSN(pagep)); + cmp_p = log_compare(&LSN(pagep), &argp->nextlsn); + CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->nextlsn); + flags = 0; + + if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == PUTOVFL) || + (cmp_n == 0 && DB_UNDO(op) && argp->opcode == DELOVFL)) { + /* Redo a create new page or undo a delete new page. */ + pagep->prev_pgno = argp->new_pgno; + flags = DB_MPOOL_DIRTY; + } else if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == DELOVFL) || + (cmp_n == 0 && DB_UNDO(op) && argp->opcode == PUTOVFL)) { + /* Redo a delete or undo a create new page. */ + pagep->prev_pgno = argp->prev_pgno; + flags = DB_MPOOL_DIRTY; + } + + if (flags) + LSN(pagep) = DB_REDO(op) ? *lsnp : argp->nextlsn; + + if ((ret = memp_fput(file_dbp->mpf, pagep, flags)) != 0) + goto out; + } +done: *lsnp = argp->prev_lsn; + ret = 0; + +out: if (getmeta) + (void)__ham_release_meta(dbc); + REC_CLOSE; +} + +/* + * __ham_replace_recover -- + * This log message refers to partial puts that are local to a single + * page. You can think of them as special cases of the more general + * insdel log message. + * + * PUBLIC: int __ham_replace_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__ham_replace_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __ham_replace_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + DBT dbt; + PAGE *pagep; + int32_t grow; + int cmp_n, cmp_p, flags, getmeta, ret; + u_int8_t *hk; + + COMPQUIET(info, NULL); + + getmeta = 0; + REC_PRINT(__ham_replace_print); + REC_INTRO(__ham_replace_read, 1); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) { + if (DB_UNDO(op)) { + /* + * We are undoing and the page doesn't exist. That + * is equivalent to having a pagelsn of 0, so we + * would not have to undo anything. In this case, + * don't bother creating a page. + */ + goto done; + } else if ((ret = memp_fget(mpf, &argp->pgno, + DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } + + if ((ret = __ham_get_meta(dbc)) != 0) + goto out; + getmeta = 1; + + cmp_n = log_compare(lsnp, &LSN(pagep)); + cmp_p = log_compare(&LSN(pagep), &argp->pagelsn); + CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->pagelsn); + + memset(&dbt, 0, sizeof(dbt)); + flags = 0; + grow = 1; + + if (cmp_p == 0 && DB_REDO(op)) { + /* Reapply the change as specified. */ + dbt.data = argp->newitem.data; + dbt.size = argp->newitem.size; + grow = argp->newitem.size - argp->olditem.size; + LSN(pagep) = *lsnp; + flags = DB_MPOOL_DIRTY; + } else if (cmp_n == 0 && DB_UNDO(op)) { + /* Undo the already applied change. */ + dbt.data = argp->olditem.data; + dbt.size = argp->olditem.size; + grow = argp->olditem.size - argp->newitem.size; + LSN(pagep) = argp->pagelsn; + flags = DB_MPOOL_DIRTY; + } + + if (flags) { + __ham_onpage_replace(pagep, + file_dbp->pgsize, argp->ndx, argp->off, grow, &dbt); + if (argp->makedup) { + hk = P_ENTRY(pagep, argp->ndx); + if (DB_REDO(op)) + HPAGE_PTYPE(hk) = H_DUPLICATE; + else + HPAGE_PTYPE(hk) = H_KEYDATA; + } + } + + if ((ret = memp_fput(file_dbp->mpf, pagep, flags)) != 0) + goto out; + +done: *lsnp = argp->prev_lsn; + ret = 0; + +out: if (getmeta) + (void)__ham_release_meta(dbc); + REC_CLOSE; +} + +/* + * __ham_splitdata_recover -- + * + * PUBLIC: int __ham_splitdata_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__ham_splitdata_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __ham_splitdata_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, flags, getmeta, ret; + + COMPQUIET(info, NULL); + + getmeta = 0; + REC_PRINT(__ham_splitdata_print); + REC_INTRO(__ham_splitdata_read, 1); + + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) { + if (DB_UNDO(op)) { + /* + * We are undoing and the page doesn't exist. That + * is equivalent to having a pagelsn of 0, so we + * would not have to undo anything. In this case, + * don't bother creating a page. + */ + goto done; + } else if ((ret = memp_fget(mpf, &argp->pgno, + DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } + + if ((ret = __ham_get_meta(dbc)) != 0) + goto out; + getmeta = 1; + + cmp_n = log_compare(lsnp, &LSN(pagep)); + cmp_p = log_compare(&LSN(pagep), &argp->pagelsn); + CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->pagelsn); + + /* + * There are two types of log messages here, one for the old page + * and one for the new pages created. The original image in the + * SPLITOLD record is used for undo. The image in the SPLITNEW + * is used for redo. We should never have a case where there is + * a redo operation and the SPLITOLD record is on disk, but not + * the SPLITNEW record. Therefore, we only have work to do when + * redo NEW messages and undo OLD messages, but we have to update + * LSNs in both cases. + */ + flags = 0; + if (cmp_p == 0 && DB_REDO(op)) { + if (argp->opcode == SPLITNEW) + /* Need to redo the split described. */ + memcpy(pagep, argp->pageimage.data, + argp->pageimage.size); + LSN(pagep) = *lsnp; + flags = DB_MPOOL_DIRTY; + } else if (cmp_n == 0 && DB_UNDO(op)) { + if (argp->opcode == SPLITOLD) { + /* Put back the old image. */ + memcpy(pagep, argp->pageimage.data, + argp->pageimage.size); + } else + P_INIT(pagep, file_dbp->pgsize, argp->pgno, + PGNO_INVALID, PGNO_INVALID, 0, P_HASH); + LSN(pagep) = argp->pagelsn; + flags = DB_MPOOL_DIRTY; + } + if ((ret = memp_fput(file_dbp->mpf, pagep, flags)) != 0) + goto out; + +done: *lsnp = argp->prev_lsn; + ret = 0; + +out: if (getmeta) + (void)__ham_release_meta(dbc); + REC_CLOSE; +} + +/* + * __ham_copypage_recover -- + * Recovery function for copypage. + * + * PUBLIC: int __ham_copypage_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__ham_copypage_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __ham_copypage_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + int cmp_n, cmp_p, flags, getmeta, ret; + + COMPQUIET(info, NULL); + + getmeta = 0; + REC_PRINT(__ham_copypage_print); + REC_INTRO(__ham_copypage_read, 1); + + if ((ret = __ham_get_meta(dbc)) != 0) + goto out; + getmeta = 1; + flags = 0; + + /* This is the bucket page. */ + if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) { + if (DB_UNDO(op)) { + /* + * We are undoing and the page doesn't exist. That + * is equivalent to having a pagelsn of 0, so we + * would not have to undo anything. In this case, + * don't bother creating a page. + */ + ret = 0; + goto donext; + } else if ((ret = memp_fget(mpf, &argp->pgno, + DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } + + cmp_n = log_compare(lsnp, &LSN(pagep)); + cmp_p = log_compare(&LSN(pagep), &argp->pagelsn); + CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->pagelsn); + + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + memcpy(pagep, argp->page.data, argp->page.size); + PGNO(pagep) = argp->pgno; + PREV_PGNO(pagep) = PGNO_INVALID; + LSN(pagep) = *lsnp; + flags = DB_MPOOL_DIRTY; + } else if (cmp_n == 0 && DB_UNDO(op)) { + /* Need to undo update described. */ + P_INIT(pagep, file_dbp->pgsize, argp->pgno, PGNO_INVALID, + argp->next_pgno, 0, P_HASH); + LSN(pagep) = argp->pagelsn; + flags = DB_MPOOL_DIRTY; + } + if ((ret = memp_fput(mpf, pagep, flags)) != 0) + goto out; + +donext: /* Now fix up the "next" page. */ + if ((ret = memp_fget(mpf, &argp->next_pgno, 0, &pagep)) != 0) { + if (DB_UNDO(op)) { + /* + * We are undoing and the page doesn't exist. That + * is equivalent to having a pagelsn of 0, so we + * would not have to undo anything. In this case, + * don't bother creating a page. + */ + ret = 0; + goto do_nn; + } else if ((ret = memp_fget(mpf, &argp->next_pgno, + DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } + + /* For REDO just update the LSN. For UNDO copy page back. */ + cmp_n = log_compare(lsnp, &LSN(pagep)); + cmp_p = log_compare(&LSN(pagep), &argp->nextlsn); + CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->nextlsn); + flags = 0; + if (cmp_p == 0 && DB_REDO(op)) { + LSN(pagep) = *lsnp; + flags = DB_MPOOL_DIRTY; + } else if (cmp_n == 0 && DB_UNDO(op)) { + /* Need to undo update described. */ + memcpy(pagep, argp->page.data, argp->page.size); + flags = DB_MPOOL_DIRTY; + } + if ((ret = memp_fput(mpf, pagep, flags)) != 0) + goto out; + + /* Now fix up the next's next page. */ +do_nn: if (argp->nnext_pgno == PGNO_INVALID) + goto done; + + if ((ret = memp_fget(mpf, &argp->nnext_pgno, 0, &pagep)) != 0) { + if (DB_UNDO(op)) { + /* + * We are undoing and the page doesn't exist. That + * is equivalent to having a pagelsn of 0, so we + * would not have to undo anything. In this case, + * don't bother creating a page. + */ + goto done; + } else if ((ret = memp_fget(mpf, &argp->nnext_pgno, + DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + } + + cmp_n = log_compare(lsnp, &LSN(pagep)); + cmp_p = log_compare(&LSN(pagep), &argp->nnextlsn); + CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->nnextlsn); + + flags = 0; + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + PREV_PGNO(pagep) = argp->pgno; + LSN(pagep) = *lsnp; + flags = DB_MPOOL_DIRTY; + } else if (cmp_n == 0 && DB_UNDO(op)) { + /* Need to undo update described. */ + PREV_PGNO(pagep) = argp->next_pgno; + LSN(pagep) = argp->nnextlsn; + flags = DB_MPOOL_DIRTY; + } + if ((ret = memp_fput(mpf, pagep, flags)) != 0) + goto out; + +done: *lsnp = argp->prev_lsn; + ret = 0; + +out: if (getmeta) + (void)__ham_release_meta(dbc); + REC_CLOSE; +} + +/* + * __ham_metagroup_recover -- + * Recovery function for metagroup. + * + * PUBLIC: int __ham_metagroup_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__ham_metagroup_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __ham_metagroup_args *argp; + HASH_CURSOR *hcp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + PAGE *pagep; + db_pgno_t last_pgno; + int cmp_n, cmp_p, flags, groupgrow, ret; + + COMPQUIET(info, NULL); + REC_PRINT(__ham_metagroup_print); + REC_INTRO(__ham_metagroup_read, 1); + + /* + * This logs the virtual create of pages pgno to pgno + bucket + * Since the mpool page-allocation is not really able to be + * transaction protected, we can never undo it. Even in an abort, + * we have to allocate these pages to the hash table. + * The log record contains: + * bucket: new bucket being allocated. + * pgno: page number of the new bucket. + * if bucket is a power of 2, then we allocated a whole batch of + * pages; if it's not, then we simply allocated one new page. + */ + groupgrow = + (u_int32_t)(1 << __db_log2(argp->bucket + 1)) == argp->bucket + 1; + + last_pgno = argp->pgno; + if (groupgrow) + /* Read the last page. */ + last_pgno += argp->bucket; + + if ((ret = memp_fget(mpf, &last_pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + + cmp_n = log_compare(lsnp, &LSN(pagep)); + cmp_p = log_compare(&LSN(pagep), &argp->pagelsn); + CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->pagelsn); + + flags = 0; + if ((cmp_p == 0 && DB_REDO(op)) || (cmp_n == 0 && DB_UNDO(op))) { + /* + * We need to make sure that we redo the allocation of the + * pages. + */ + if (DB_REDO(op)) + pagep->lsn = *lsnp; + else + pagep->lsn = argp->pagelsn; + flags = DB_MPOOL_DIRTY; + } + if ((ret = memp_fput(mpf, pagep, flags)) != 0) + goto out; + + /* Now we have to update the meta-data page. */ + hcp = (HASH_CURSOR *)dbc->internal; + if ((ret = __ham_get_meta(dbc)) != 0) + goto out; + cmp_n = log_compare(lsnp, &hcp->hdr->dbmeta.lsn); + cmp_p = log_compare(&hcp->hdr->dbmeta.lsn, &argp->metalsn); + CHECK_LSN(op, cmp_p, &hcp->hdr->dbmeta.lsn, &argp->metalsn); + if ((cmp_p == 0 && DB_REDO(op)) || (cmp_n == 0 && DB_UNDO(op))) { + if (DB_REDO(op)) { + /* Redo the actual updating of bucket counts. */ + ++hcp->hdr->max_bucket; + if (groupgrow) { + hcp->hdr->low_mask = hcp->hdr->high_mask; + hcp->hdr->high_mask = + (argp->bucket + 1) | hcp->hdr->low_mask; + } + hcp->hdr->dbmeta.lsn = *lsnp; + } else { + /* Undo the actual updating of bucket counts. */ + --hcp->hdr->max_bucket; + if (groupgrow) { + hcp->hdr->high_mask = hcp->hdr->low_mask; + hcp->hdr->low_mask = hcp->hdr->high_mask >> 1; + } + hcp->hdr->dbmeta.lsn = argp->metalsn; + } + if (groupgrow && + hcp->hdr->spares[__db_log2(argp->bucket + 1) + 1] == + PGNO_INVALID) + hcp->hdr->spares[__db_log2(argp->bucket + 1) + 1] = + argp->pgno - argp->bucket - 1; + F_SET(hcp, H_DIRTY); + } + if ((ret = __ham_release_meta(dbc)) != 0) + goto out; + +done: *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __ham_groupalloc_recover -- + * Recover the batch creation of a set of pages for a new database. + * + * PUBLIC: int __ham_groupalloc_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__ham_groupalloc_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __ham_groupalloc_args *argp; + DBMETA *mmeta; + DB_MPOOLFILE *mpf; + DB *file_dbp; + DBC *dbc; + db_pgno_t pgno; + int cmp_n, cmp_p, flags, ret; + + REC_PRINT(__ham_groupalloc_print); + REC_INTRO(__ham_groupalloc_read, 0); + + pgno = PGNO_BASE_MD; + if ((ret = memp_fget(mpf, &pgno, 0, &mmeta)) != 0) { + if (DB_REDO(op)) { + /* Page should have existed. */ + (void)__db_pgerr(file_dbp, pgno); + goto out; + } else { + ret = 0; + goto done; + } + } + + cmp_n = log_compare(lsnp, &LSN(mmeta)); + cmp_p = log_compare(&LSN(mmeta), &argp->meta_lsn); + CHECK_LSN(op, cmp_p, &LSN(mmeta), &argp->meta_lsn); + + /* + * Basically, we used mpool to allocate a chunk of pages. + * We need to either add those to a free list (in the undo + * case) or initialize them (in the redo case). + * + * If we are redoing and this is a hash subdatabase, it's possible + * that the pages were never allocated, so we'd better check for + * that and handle it here. + */ + + flags = 0; + if (DB_REDO(op)) { + if ((ret = __ham_alloc_pages(file_dbp, argp)) != 0) + goto out1; + if (cmp_p == 0) { + LSN(mmeta) = *lsnp; + flags = DB_MPOOL_DIRTY; + } + } + + /* + * Always put the pages into the limbo list and free them later. + */ + else if (DB_UNDO(op)) { + if ((ret = __db_add_limbo(dbenv, + info, argp->fileid, argp->start_pgno, argp->num)) != 0) + goto out; + if (cmp_n == 0) { + LSN(mmeta) = argp->meta_lsn; + flags = DB_MPOOL_DIRTY; + } + } + +out1: if ((ret = memp_fput(mpf, mmeta, flags)) != 0) + goto out; + +done: if (ret == 0) + *lsnp = argp->prev_lsn; + +out: REC_CLOSE; +} + +/* + * __ham_alloc_pages -- + * + * Called during redo of a file create. We create new pages in the file + * using the MPOOL_NEW_GROUP flag. We then log the meta-data page with a + * __crdel_metasub message. If we manage to crash without the newly written + * pages getting to disk (I'm not sure this can happen anywhere except our + * test suite?!), then we need to go through a recreate the final pages. + * Hash normally has holes in its files and handles them appropriately. + */ +static int +__ham_alloc_pages(dbp, argp) + DB *dbp; + __ham_groupalloc_args *argp; +{ + DB_MPOOLFILE *mpf; + PAGE *pagep; + db_pgno_t pgno; + int ret; + + mpf = dbp->mpf; + + /* Read the last page of the allocation. */ + pgno = argp->start_pgno + argp->num - 1; + + /* If the page exists, and it has been initialized, then we're done. */ + if ((ret = memp_fget(mpf, &pgno, 0, &pagep)) == 0) { + if ((pagep->type == P_INVALID) && IS_ZERO_LSN(pagep->lsn)) + goto reinit_page; + if ((ret = memp_fput(mpf, pagep, 0)) != 0) + return (ret); + return (0); + } + + /* + * Had to create the page. On some systems (read "Windows"), + * you can find random garbage on pages to which you haven't + * yet written. So, we have an os layer that will do the + * right thing for group allocations. We call that directly + * to make sure all the pages are allocated and then continue + * merrily on our way with normal recovery. + */ + if ((ret = __os_fpinit(dbp->dbenv, &mpf->fh, + argp->start_pgno, argp->num, dbp->pgsize)) != 0) + return (ret); + + if ((ret = memp_fget(mpf, &pgno, DB_MPOOL_CREATE, &pagep)) != 0) { + (void)__db_pgerr(dbp, pgno); + return (ret); + } + +reinit_page: + /* Initialize the newly allocated page. */ + P_INIT(pagep, + dbp->pgsize, pgno, PGNO_INVALID, PGNO_INVALID, 0, P_HASH); + ZERO_LSN(pagep->lsn); + + if ((ret = memp_fput(mpf, pagep, DB_MPOOL_DIRTY)) != 0) + return (ret); + + return (0); +} + +/* + * __ham_curadj_recover -- + * Undo cursor adjustments if a subtransaction fails. + * + * PUBLIC: int __ham_curadj_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ + +int +__ham_curadj_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __ham_curadj_args *argp; + DB_MPOOLFILE *mpf; + DB *file_dbp; + DBC *dbc; + int ret; + HASH_CURSOR *hcp; + + REC_PRINT(__ham_groupalloc_print); + + ret = 0; + if (op != DB_TXN_ABORT) + goto done; + REC_INTRO(__ham_curadj_read, 0); + + COMPQUIET(info, NULL); + /* + * Undo the adjustment by reinitializing the the cursor + * to look like the one that was used to do the adustment, + * then we invert the add so that undo the adjustment. + */ + hcp = (HASH_CURSOR *)dbc->internal; + hcp->pgno = argp->pgno; + hcp->indx = argp->indx; + hcp->dup_off = argp->dup_off; + hcp->order = argp->order; + if (!argp->add) + F_SET(hcp, H_DELETED); + (void)__ham_c_update(dbc, argp->len, !argp->add, argp->is_dup); + +done: *lsnp = argp->prev_lsn; +out: REC_CLOSE; +} + +/* + * __ham_chgpg_recover -- + * Undo cursor adjustments if a subtransaction fails. + * + * PUBLIC: int __ham_chgpg_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ + +int +__ham_chgpg_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __ham_chgpg_args *argp; + BTREE_CURSOR *opdcp; + DB_MPOOLFILE *mpf; + DB *file_dbp, *ldbp; + DBC *dbc; + int ret; + DBC *cp; + HASH_CURSOR *lcp; + + REC_PRINT(__ham_chgpg_print); + + ret = 0; + if (op != DB_TXN_ABORT) + goto out; + REC_INTRO(__ham_chgpg_read, 0); + + COMPQUIET(info, NULL); + + MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp); + for (ldbp = __dblist_get(dbenv, file_dbp->adj_fileid); + ldbp != NULL && ldbp->adj_fileid == file_dbp->adj_fileid; + ldbp = LIST_NEXT(ldbp, dblistlinks)) { + MUTEX_THREAD_LOCK(dbenv, file_dbp->mutexp); + + for (cp = TAILQ_FIRST(&ldbp->active_queue); cp != NULL; + cp = TAILQ_NEXT(cp, links)) { + lcp = (HASH_CURSOR *)cp->internal; + + switch (argp->mode) { + case DB_HAM_CHGPG: + if (lcp->pgno != argp->new_pgno) + break; + + if (argp->old_indx == NDX_INVALID) + lcp->pgno = argp->old_pgno; + else if (lcp->indx == argp->new_indx) { + lcp->indx = argp->old_indx; + lcp->pgno = argp->old_pgno; + } + break; + + case DB_HAM_SPLIT: + if (lcp->pgno == argp->new_pgno + && lcp->indx == argp->new_indx) { + lcp->indx = argp->old_indx; + lcp->pgno = argp->old_pgno; + } + break; + + case DB_HAM_DUP: + if (lcp->opd != NULL) { + opdcp = + (BTREE_CURSOR *)lcp->opd->internal; + if (opdcp->pgno == argp->new_pgno && + opdcp->indx == argp->new_indx) { + if (F_ISSET(opdcp, C_DELETED)) + F_SET(lcp, H_DELETED); + if ((ret = + lcp->opd->c_close( + lcp->opd)) != 0) + goto out; + lcp->opd = NULL; + } + } + break; + } + } + + MUTEX_THREAD_UNLOCK(dbenv, file_dbp->mutexp); + } + MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp); + +done: *lsnp = argp->prev_lsn; + ret = 0; +out: REC_CLOSE; +} diff --git a/db/hash/hash_reclaim.c b/db/hash/hash_reclaim.c new file mode 100644 index 000000000..8857c5406 --- /dev/null +++ b/db/hash/hash_reclaim.c @@ -0,0 +1,68 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: hash_reclaim.c,v 11.4 2000/11/30 00:58:37 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_shash.h" +#include "hash.h" +#include "lock.h" + +/* + * __ham_reclaim -- + * Reclaim the pages from a subdatabase and return them to the + * parent free list. For now, we link each freed page on the list + * separately. If people really store hash databases in subdatabases + * and do a lot of creates and deletes, this is going to be a problem, + * because hash needs chunks of contiguous storage. We may eventually + * need to go to a model where we maintain the free list with chunks of + * contiguous pages as well. + * + * PUBLIC: int __ham_reclaim __P((DB *, DB_TXN *txn)); + */ +int +__ham_reclaim(dbp, txn) + DB *dbp; + DB_TXN *txn; +{ + DBC *dbc; + HASH_CURSOR *hcp; + int ret; + + /* Open up a cursor that we'll use for traversing. */ + if ((ret = dbp->cursor(dbp, txn, &dbc, 0)) != 0) + return (ret); + hcp = (HASH_CURSOR *)dbc->internal; + + if ((ret = __ham_get_meta(dbc)) != 0) + goto err; + + if ((ret = __ham_traverse(dbp, + dbc, DB_LOCK_WRITE, __db_reclaim_callback, dbc)) != 0) + goto err; + if ((ret = dbc->c_close(dbc)) != 0) + goto err; + if ((ret = __ham_release_meta(dbc)) != 0) + goto err; + return (0); + +err: if (hcp->hdr != NULL) + (void)__ham_release_meta(dbc); + (void)dbc->c_close(dbc); + return (ret); +} diff --git a/db/hash/hash_stat.c b/db/hash/hash_stat.c new file mode 100644 index 000000000..ed64bbc68 --- /dev/null +++ b/db/hash/hash_stat.c @@ -0,0 +1,329 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: hash_stat.c,v 11.24 2000/12/21 21:54:35 margo Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_shash.h" +#include "btree.h" +#include "hash.h" +#include "lock.h" + +static int __ham_stat_callback __P((DB *, PAGE *, void *, int *)); + +/* + * __ham_stat -- + * Gather/print the hash statistics + * + * PUBLIC: int __ham_stat __P((DB *, void *, void *(*)(size_t), u_int32_t)); + */ +int +__ham_stat(dbp, spp, db_malloc, flags) + DB *dbp; + void *spp, *(*db_malloc) __P((size_t)); + u_int32_t flags; +{ + DB_HASH_STAT *sp; + HASH_CURSOR *hcp; + DBC *dbc; + PAGE *h; + db_pgno_t pgno; + int ret; + + PANIC_CHECK(dbp->dbenv); + DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->stat"); + + sp = NULL; + + /* Check for invalid flags. */ + if ((ret = __db_statchk(dbp, flags)) != 0) + return (ret); + + if ((ret = dbp->cursor(dbp, NULL, &dbc, 0)) != 0) + return (ret); + hcp = (HASH_CURSOR *)dbc->internal; + + if ((ret = __ham_get_meta(dbc)) != 0) + goto err; + + /* Allocate and clear the structure. */ + if ((ret = __os_malloc(dbp->dbenv, sizeof(*sp), db_malloc, &sp)) != 0) + goto err; + memset(sp, 0, sizeof(*sp)); + if (flags == DB_CACHED_COUNTS) { + sp->hash_nkeys = hcp->hdr->dbmeta.key_count; + sp->hash_ndata = hcp->hdr->dbmeta.record_count; + goto done; + } + + /* Copy the fields that we have. */ + sp->hash_pagesize = dbp->pgsize; + sp->hash_buckets = hcp->hdr->max_bucket + 1; + sp->hash_magic = hcp->hdr->dbmeta.magic; + sp->hash_version = hcp->hdr->dbmeta.version; + sp->hash_metaflags = hcp->hdr->dbmeta.flags; + sp->hash_nelem = hcp->hdr->nelem; + sp->hash_ffactor = hcp->hdr->ffactor; + + /* Walk the free list, counting pages. */ + for (sp->hash_free = 0, pgno = hcp->hdr->dbmeta.free; + pgno != PGNO_INVALID;) { + ++sp->hash_free; + + if ((ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) + goto err; + + pgno = h->next_pgno; + (void)memp_fput(dbp->mpf, h, 0); + } + + /* Now traverse the rest of the table. */ + if ((ret = __ham_traverse(dbp, + dbc, DB_LOCK_READ, __ham_stat_callback, sp)) != 0) + goto err; + + if (!F_ISSET(dbp, DB_AM_RDONLY)) { + if ((ret = __ham_dirty_meta(dbc)) != 0) + goto err; + hcp->hdr->dbmeta.key_count = sp->hash_nkeys; + hcp->hdr->dbmeta.record_count = sp->hash_ndata; + } + +done: + if ((ret = __ham_release_meta(dbc)) != 0) + goto err; + if ((ret = dbc->c_close(dbc)) != 0) + goto err; + + *(DB_HASH_STAT **)spp = sp; + return (0); + +err: if (sp != NULL) + __os_free(sp, sizeof(*sp)); + if (hcp->hdr != NULL) + (void)__ham_release_meta(dbc); + (void)dbc->c_close(dbc); + return (ret); + +} + +/* + * __ham_traverse + * Traverse an entire hash table. We use the callback so that we + * can use this both for stat collection and for deallocation. + * + * PUBLIC: int __ham_traverse __P((DB *, DBC *, db_lockmode_t, + * PUBLIC: int (*)(DB *, PAGE *, void *, int *), void *)); + */ +int +__ham_traverse(dbp, dbc, mode, callback, cookie) + DB *dbp; + DBC *dbc; + db_lockmode_t mode; + int (*callback) __P((DB *, PAGE *, void *, int *)); + void *cookie; +{ + HASH_CURSOR *hcp; + HKEYDATA *hk; + DBC *opd; + db_pgno_t pgno, opgno; + u_int32_t bucket; + int did_put, i, ret, t_ret; + + hcp = (HASH_CURSOR *)dbc->internal; + opd = NULL; + ret = 0; + + /* + * In a perfect world, we could simply read each page in the file + * and look at its page type to tally the information necessary. + * Unfortunately, the bucket locking that hash tables do to make + * locking easy, makes this a pain in the butt. We have to traverse + * duplicate, overflow and big pages from the bucket so that we + * don't access anything that isn't properly locked. + */ + for (bucket = 0; bucket <= hcp->hdr->max_bucket; bucket++) { + hcp->bucket = bucket; + hcp->pgno = pgno = BUCKET_TO_PAGE(hcp, bucket); + for (ret = __ham_get_cpage(dbc, mode); ret == 0; + ret = __ham_next_cpage(dbc, pgno, 0)) { + pgno = NEXT_PGNO(hcp->page); + + /* + * Go through each item on the page checking for + * duplicates (in which case we have to count the + * duplicate pages) or big key/data items (in which + * case we have to count those pages). + */ + for (i = 0; i < NUM_ENT(hcp->page); i++) { + hk = (HKEYDATA *)P_ENTRY(hcp->page, i); + switch (HPAGE_PTYPE(hk)) { + case H_OFFDUP: + memcpy(&opgno, HOFFDUP_PGNO(hk), + sizeof(db_pgno_t)); + if ((ret = __db_c_newopd(dbc, + opgno, &opd)) != 0) + return (ret); + if ((ret = __bam_traverse(opd, + DB_LOCK_READ, opgno, + __ham_stat_callback, cookie)) + != 0) + goto err; + if ((ret = opd->c_close(opd)) != 0) + return (ret); + opd = NULL; + break; + case H_OFFPAGE: + /* + * We are about to get a big page + * which will use the same spot that + * the current page uses, so we need + * to restore the current page before + * looking at it again. + */ + memcpy(&opgno, HOFFPAGE_PGNO(hk), + sizeof(db_pgno_t)); + if ((ret = __db_traverse_big(dbp, + opgno, callback, cookie)) != 0) + goto err; + break; + case H_KEYDATA: + break; + } + } + + /* Call the callback on main pages. */ + if ((ret = callback(dbp, + hcp->page, cookie, &did_put)) != 0) + goto err; + + if (did_put) + hcp->page = NULL; + if (pgno == PGNO_INVALID) + break; + } + if (ret != 0) + goto err; + + if (STD_LOCKING(dbc)) + (void)lock_put(dbp->dbenv, &hcp->lock); + + if (hcp->page != NULL) { + if ((ret = memp_fput(dbc->dbp->mpf, hcp->page, 0)) != 0) + return (ret); + hcp->page = NULL; + } + + } +err: if (opd != NULL && + (t_ret = opd->c_close(opd)) != 0 && ret == 0) + ret = t_ret; + return (ret); +} + +static int +__ham_stat_callback(dbp, pagep, cookie, putp) + DB *dbp; + PAGE *pagep; + void *cookie; + int *putp; +{ + DB_HASH_STAT *sp; + DB_BTREE_STAT bstat; + db_indx_t indx, len, off, tlen, top; + u_int8_t *hk; + + *putp = 0; + sp = cookie; + + switch (pagep->type) { + case P_INVALID: + /* + * Hash pages may be wholly zeroed; this is not a bug. + * Obviously such pages have no data, so we can just proceed. + */ + break; + case P_HASH: + /* + * We count the buckets and the overflow pages + * separately and tally their bytes separately + * as well. We need to figure out if this page + * is a bucket. + */ + if (PREV_PGNO(pagep) == PGNO_INVALID) + sp->hash_bfree += P_FREESPACE(pagep); + else { + sp->hash_overflows++; + sp->hash_ovfl_free += P_FREESPACE(pagep); + } + top = NUM_ENT(pagep); + /* Correct for on-page duplicates and deleted items. */ + for (indx = 0; indx < top; indx += P_INDX) { + switch (*H_PAIRDATA(pagep, indx)) { + case H_OFFDUP: + case H_OFFPAGE: + break; + case H_KEYDATA: + sp->hash_ndata++; + break; + case H_DUPLICATE: + tlen = LEN_HDATA(pagep, 0, indx); + hk = H_PAIRDATA(pagep, indx); + for (off = 0; off < tlen; + off += len + 2 * sizeof (db_indx_t)) { + sp->hash_ndata++; + memcpy(&len, + HKEYDATA_DATA(hk) + + off, sizeof(db_indx_t)); + } + } + } + sp->hash_nkeys += H_NUMPAIRS(pagep); + break; + case P_IBTREE: + case P_IRECNO: + case P_LBTREE: + case P_LRECNO: + case P_LDUP: + /* + * These are all btree pages; get a correct + * cookie and call them. Then add appropriate + * fields into our stat structure. + */ + memset(&bstat, 0, sizeof(bstat)); + bstat.bt_dup_pgfree = 0; + bstat.bt_int_pgfree = 0; + bstat.bt_leaf_pgfree = 0; + bstat.bt_ndata = 0; + __bam_stat_callback(dbp, pagep, &bstat, putp); + sp->hash_dup++; + sp->hash_dup_free += bstat.bt_leaf_pgfree + + bstat.bt_dup_pgfree + bstat.bt_int_pgfree; + sp->hash_ndata += bstat.bt_ndata; + break; + case P_OVERFLOW: + sp->hash_bigpages++; + sp->hash_big_bfree += P_OVFLSPACE(dbp->pgsize, pagep); + break; + default: + return (__db_unknown_type(dbp->dbenv, + "__ham_stat_callback", pagep->type)); + } + + return (0); +} diff --git a/db/hash/hash_upgrade.c b/db/hash/hash_upgrade.c new file mode 100644 index 000000000..c34381276 --- /dev/null +++ b/db/hash/hash_upgrade.c @@ -0,0 +1,271 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: hash_upgrade.c,v 11.25 2000/12/14 19:18:32 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_swap.h" +#include "hash.h" +#include "db_upgrade.h" + +/* + * __ham_30_hashmeta -- + * Upgrade the database from version 4/5 to version 6. + * + * PUBLIC: int __ham_30_hashmeta __P((DB *, char *, u_int8_t *)); + */ +int +__ham_30_hashmeta(dbp, real_name, obuf) + DB *dbp; + char *real_name; + u_int8_t *obuf; +{ + DB_ENV *dbenv; + HASHHDR *oldmeta; + HMETA30 newmeta; + u_int32_t *o_spares, *n_spares; + u_int32_t fillf, maxb, nelem; + int i, max_entry, ret; + + dbenv = dbp->dbenv; + memset(&newmeta, 0, sizeof(newmeta)); + + oldmeta = (HASHHDR *)obuf; + + /* + * The first 32 bytes are similar. The only change is the version + * and that we removed the ovfl_point and have the page type now. + */ + + newmeta.dbmeta.lsn = oldmeta->lsn; + newmeta.dbmeta.pgno = oldmeta->pgno; + newmeta.dbmeta.magic = oldmeta->magic; + newmeta.dbmeta.version = 6; + newmeta.dbmeta.pagesize = oldmeta->pagesize; + newmeta.dbmeta.type = P_HASHMETA; + + /* Move flags */ + newmeta.dbmeta.flags = oldmeta->flags; + + /* Copy the free list, which has changed its name but works the same. */ + newmeta.dbmeta.free = oldmeta->last_freed; + + /* Copy: max_bucket, high_mask, low-mask, ffactor, nelem, h_charkey */ + newmeta.max_bucket = oldmeta->max_bucket; + newmeta.high_mask = oldmeta->high_mask; + newmeta.low_mask = oldmeta->low_mask; + newmeta.ffactor = oldmeta->ffactor; + newmeta.nelem = oldmeta->nelem; + newmeta.h_charkey = oldmeta->h_charkey; + + /* + * There was a bug in 2.X versions where the nelem could go negative. + * In general, this is considered "bad." If it does go negative + * (that is, very large and positive), we'll die trying to dump and + * load this database. So, let's see if we can fix it here. + */ + nelem = newmeta.nelem; + fillf = newmeta.ffactor; + maxb = newmeta.max_bucket; + + if ((fillf != 0 && fillf * maxb < 2 * nelem) || + (fillf == 0 && nelem > 0x8000000)) + newmeta.nelem = 0; + + /* + * We now have to convert the spares array. The old spares array + * contained the total number of extra pages allocated prior to + * the bucket that begins the next doubling. The new spares array + * contains the page number of the first bucket in the next doubling + * MINUS the bucket number of that bucket. + */ + o_spares = oldmeta->spares; + n_spares = newmeta.spares; + max_entry = __db_log2(maxb + 1); /* highest spares entry in use */ + n_spares[0] = 1; + for (i = 1; i < NCACHED && i <= max_entry; i++) + n_spares[i] = 1 + o_spares[i - 1]; + + /* Replace the unique ID. */ + if ((ret = __os_fileid(dbenv, real_name, 1, newmeta.dbmeta.uid)) != 0) + return (ret); + + /* Overwrite the original. */ + memcpy(oldmeta, &newmeta, sizeof(newmeta)); + + return (0); +} + +/* + * __ham_30_sizefix -- + * Make sure that all hash pages belonging to the current + * hash doubling are within the bounds of the file. + * + * PUBLIC: int __ham_30_sizefix __P((DB *, DB_FH *, char *, u_int8_t *)); + */ +int +__ham_30_sizefix(dbp, fhp, realname, metabuf) + DB *dbp; + DB_FH *fhp; + char *realname; + u_int8_t *metabuf; +{ + u_int8_t buf[DB_MAX_PGSIZE]; + DB_ENV *dbenv; + HMETA30 *meta; + db_pgno_t last_actual, last_desired; + int ret; + size_t nw; + u_int32_t pagesize; + + dbenv = dbp->dbenv; + memset(buf, 0, DB_MAX_PGSIZE); + + meta = (HMETA30 *)metabuf; + pagesize = meta->dbmeta.pagesize; + + /* + * Get the last page number. To do this, we'll need dbp->pgsize + * to be set right, so slam it into place. + */ + dbp->pgsize = pagesize; + if ((ret = __db_lastpgno(dbp, realname, fhp, &last_actual)) != 0) + return (ret); + + /* + * The last bucket in the doubling is equal to high_mask; calculate + * the page number that implies. + */ + last_desired = BS_TO_PAGE(meta->high_mask, meta->spares); + + /* + * If last_desired > last_actual, we need to grow the file. Write + * a zeroed page where last_desired would go. + */ + if (last_desired > last_actual) { + if ((ret = __os_seek(dbenv, + fhp, pagesize, last_desired, 0, 0, DB_OS_SEEK_SET)) != 0) + return (ret); + if ((ret = __os_write(dbenv, fhp, buf, pagesize, &nw)) != 0) + return (ret); + if (nw != pagesize) { + __db_err(dbenv, "Short write during upgrade"); + return (EIO); + } + } + + return (0); +} + +/* + * __ham_31_hashmeta -- + * Upgrade the database from version 6 to version 7. + * + * PUBLIC: int __ham_31_hashmeta + * PUBLIC: __P((DB *, char *, u_int32_t, DB_FH *, PAGE *, int *)); + */ +int +__ham_31_hashmeta(dbp, real_name, flags, fhp, h, dirtyp) + DB *dbp; + char *real_name; + u_int32_t flags; + DB_FH *fhp; + PAGE *h; + int *dirtyp; +{ + HMETA31 *newmeta; + HMETA30 *oldmeta; + + COMPQUIET(dbp, NULL); + COMPQUIET(real_name, NULL); + COMPQUIET(fhp, NULL); + + newmeta = (HMETA31 *)h; + oldmeta = (HMETA30 *)h; + + /* + * Copy the fields down the page. + * The fields may overlap so start at the bottom and use memmove(). + */ + memmove(newmeta->spares, oldmeta->spares, sizeof(oldmeta->spares)); + newmeta->h_charkey = oldmeta->h_charkey; + newmeta->nelem = oldmeta->nelem; + newmeta->ffactor = oldmeta->ffactor; + newmeta->low_mask = oldmeta->low_mask; + newmeta->high_mask = oldmeta->high_mask; + newmeta->max_bucket = oldmeta->max_bucket; + memmove(newmeta->dbmeta.uid, + oldmeta->dbmeta.uid, sizeof(oldmeta->dbmeta.uid)); + newmeta->dbmeta.flags = oldmeta->dbmeta.flags; + newmeta->dbmeta.record_count = 0; + newmeta->dbmeta.key_count = 0; + ZERO_LSN(newmeta->dbmeta.unused3); + + /* Update the version. */ + newmeta->dbmeta.version = 7; + + /* Upgrade the flags. */ + if (LF_ISSET(DB_DUPSORT)) + F_SET(&newmeta->dbmeta, DB_HASH_DUPSORT); + + *dirtyp = 1; + return (0); +} + +/* + * __ham_31_hash -- + * Upgrade the database hash leaf pages. + * + * PUBLIC: int __ham_31_hash + * PUBLIC: __P((DB *, char *, u_int32_t, DB_FH *, PAGE *, int *)); + */ +int +__ham_31_hash(dbp, real_name, flags, fhp, h, dirtyp) + DB *dbp; + char *real_name; + u_int32_t flags; + DB_FH *fhp; + PAGE *h; + int *dirtyp; +{ + HKEYDATA *hk; + db_pgno_t pgno, tpgno; + db_indx_t indx; + int ret; + + COMPQUIET(flags, 0); + + ret = 0; + for (indx = 0; indx < NUM_ENT(h); indx += 2) { + hk = (HKEYDATA *)H_PAIRDATA(h, indx); + if (HPAGE_PTYPE(hk) == H_OFFDUP) { + memcpy(&pgno, HOFFDUP_PGNO(hk), sizeof(db_pgno_t)); + tpgno = pgno; + if ((ret = __db_31_offdup(dbp, real_name, fhp, + LF_ISSET(DB_DUPSORT) ? 1 : 0, &tpgno)) != 0) + break; + if (pgno != tpgno) { + *dirtyp = 1; + memcpy(HOFFDUP_PGNO(hk), + &tpgno, sizeof(db_pgno_t)); + } + } + } + + return (ret); +} diff --git a/db/hash/hash_verify.c b/db/hash/hash_verify.c new file mode 100644 index 000000000..31dd7cc22 --- /dev/null +++ b/db/hash/hash_verify.c @@ -0,0 +1,1051 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: hash_verify.c,v 1.31 2000/11/30 00:58:37 ubell Exp $ + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: hash_verify.c,v 1.31 2000/11/30 00:58:37 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_verify.h" +#include "btree.h" +#include "hash.h" + +static int __ham_dups_unsorted __P((DB *, u_int8_t *, u_int32_t)); +static int __ham_vrfy_bucket __P((DB *, VRFY_DBINFO *, HMETA *, u_int32_t, + u_int32_t)); +static int __ham_vrfy_item __P((DB *, + VRFY_DBINFO *, db_pgno_t, PAGE *, u_int32_t, u_int32_t)); + +/* + * __ham_vrfy_meta -- + * Verify the hash-specific part of a metadata page. + * + * Note that unlike btree, we don't save things off, because we + * will need most everything again to verify each page and the + * amount of state here is significant. + * + * PUBLIC: int __ham_vrfy_meta __P((DB *, VRFY_DBINFO *, HMETA *, + * PUBLIC: db_pgno_t, u_int32_t)); + */ +int +__ham_vrfy_meta(dbp, vdp, m, pgno, flags) + DB *dbp; + VRFY_DBINFO *vdp; + HMETA *m; + db_pgno_t pgno; + u_int32_t flags; +{ + HASH *hashp; + VRFY_PAGEINFO *pip; + int i, ret, t_ret, isbad; + u_int32_t pwr, mbucket; + u_int32_t (*hfunc) __P((DB *, const void *, u_int32_t)); + + if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) + return (ret); + isbad = 0; + + hashp = dbp->h_internal; + + if (hashp != NULL && hashp->h_hash != NULL) + hfunc = hashp->h_hash; + else + hfunc = __ham_func5; + + /* + * If we haven't already checked the common fields in pagezero, + * check them. + */ + if (!F_ISSET(pip, VRFY_INCOMPLETE) && + (ret = __db_vrfy_meta(dbp, vdp, &m->dbmeta, pgno, flags)) != 0) { + if (ret == DB_VERIFY_BAD) + isbad = 1; + else + goto err; + } + + /* h_charkey */ + if (!LF_ISSET(DB_NOORDERCHK)) + if (m->h_charkey != hfunc(dbp, CHARKEY, sizeof(CHARKEY))) { + EPRINT((dbp->dbenv, +"Database has different custom hash function; reverify with DB_NOORDERCHK set" + )); + /* + * Return immediately; this is probably a sign + * of user error rather than database corruption, so + * we want to avoid extraneous errors. + */ + isbad = 1; + goto err; + } + + /* max_bucket must be less than the last pgno. */ + if (m->max_bucket > vdp->last_pgno) { + EPRINT((dbp->dbenv, + "Impossible max_bucket %lu on meta page %lu", + m->max_bucket, pgno)); + /* + * Most other fields depend somehow on max_bucket, so + * we just return--there will be lots of extraneous + * errors. + */ + isbad = 1; + goto err; + } + + /* + * max_bucket, high_mask and low_mask: high_mask must be one + * less than the next power of two above max_bucket, and + * low_mask must be one less than the power of two below it. + * + * + */ + pwr = (m->max_bucket == 0) ? 1 : 1 << __db_log2(m->max_bucket + 1); + if (m->high_mask != pwr - 1) { + EPRINT((dbp->dbenv, + "Incorrect high_mask %lu on page %lu, should be %lu", + m->high_mask, pgno, pwr - 1)); + isbad = 1; + } + pwr >>= 1; + if (m->low_mask != pwr - 1) { + EPRINT((dbp->dbenv, + "Incorrect low_mask %lu on page %lu, should be %lu", + m->low_mask, pgno, pwr - 1)); + isbad = 1; + } + + /* ffactor: no check possible. */ + pip->h_ffactor = m->ffactor; + + /* + * nelem: just make sure it's not astronomical for now. This is the + * same check that hash_upgrade does, since there was a bug in 2.X + * which could make nelem go "negative". + */ + if (m->nelem > 0x80000000) { + EPRINT((dbp->dbenv, + "Suspiciously high nelem of %lu on page %lu", + m->nelem, pgno)); + isbad = 1; + pip->h_nelem = 0; + } else + pip->h_nelem = m->nelem; + + /* flags */ + if (F_ISSET(&m->dbmeta, DB_HASH_DUP)) + F_SET(pip, VRFY_HAS_DUPS); + if (F_ISSET(&m->dbmeta, DB_HASH_DUPSORT)) + F_SET(pip, VRFY_HAS_DUPSORT); + /* XXX: Why is the DB_HASH_SUBDB flag necessary? */ + + /* spares array */ + for (i = 0; m->spares[i] != 0 && i < NCACHED; i++) { + /* + * We set mbucket to the maximum bucket that would use a given + * spares entry; we want to ensure that it's always less + * than last_pgno. + */ + mbucket = (1 << i) - 1; + if (BS_TO_PAGE(mbucket, m->spares) > vdp->last_pgno) { + EPRINT((dbp->dbenv, + "Spares array entry %lu, page %lu is invalid", + i, pgno)); + isbad = 1; + } + } + +err: if ((t_ret = __db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0) + ret = t_ret; + return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret); +} + +/* + * __ham_vrfy -- + * Verify hash page. + * + * PUBLIC: int __ham_vrfy __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, + * PUBLIC: u_int32_t)); + */ +int +__ham_vrfy(dbp, vdp, h, pgno, flags) + DB *dbp; + VRFY_DBINFO *vdp; + PAGE *h; + db_pgno_t pgno; + u_int32_t flags; +{ + VRFY_PAGEINFO *pip; + u_int32_t ent, himark, inpend; + int isbad, ret, t_ret; + + isbad = 0; + if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) + return (ret); + + /* Sanity check our flags and page type. */ + if ((ret = __db_fchk(dbp->dbenv, "__ham_vrfy", + flags, DB_AGGRESSIVE | DB_NOORDERCHK | DB_SALVAGE)) != 0) + goto err; + + if (TYPE(h) != P_HASH) { + TYPE_ERR_PRINT(dbp->dbenv, "__ham_vrfy", pgno, TYPE(h)); + DB_ASSERT(0); + ret = EINVAL; + goto err; + } + + /* Verify and save off fields common to all PAGEs. */ + if ((ret = __db_vrfy_datapage(dbp, vdp, h, pgno, flags)) != 0) { + if (ret == DB_VERIFY_BAD) + isbad = 1; + else + goto err; + } + + /* + * Verify inp[]. Each offset from 0 to NUM_ENT(h) must be lower + * than the previous one, higher than the current end of the inp array, + * and lower than the page size. + * + * In any case, we return immediately if things are bad, as it would + * be unsafe to proceed. + */ + for (ent = 0, himark = dbp->pgsize, + inpend = (u_int8_t *)h->inp - (u_int8_t *)h; + ent < NUM_ENT(h); ent++) + if (h->inp[ent] >= himark) { + EPRINT((dbp->dbenv, + "Item %lu on page %lu out of order or nonsensical", + ent, pgno)); + isbad = 1; + goto err; + } else if (inpend >= himark) { + EPRINT((dbp->dbenv, + "inp array collided with data on page %lu", + pgno)); + isbad = 1; + goto err; + + } else { + himark = h->inp[ent]; + inpend += sizeof(db_indx_t); + if ((ret = __ham_vrfy_item( + dbp, vdp, pgno, h, ent, flags)) != 0) + goto err; + } + +err: if ((t_ret = __db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0) + ret = t_ret; + return (ret == 0 && isbad == 1 ? DB_VERIFY_BAD : ret); +} + +/* + * __ham_vrfy_item -- + * Given a hash page and an offset, sanity-check the item itself, + * and save off any overflow items or off-page dup children as necessary. + */ +static int +__ham_vrfy_item(dbp, vdp, pgno, h, i, flags) + DB *dbp; + VRFY_DBINFO *vdp; + db_pgno_t pgno; + PAGE *h; + u_int32_t i, flags; +{ + HOFFPAGE hop; + HOFFDUP hod; + VRFY_CHILDINFO child; + VRFY_PAGEINFO *pip; + db_indx_t offset, len, dlen, elen; + int ret, t_ret; + u_int8_t *databuf; + + if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) + return (ret); + + switch (HPAGE_TYPE(h, i)) { + case H_KEYDATA: + /* Nothing to do here--everything but the type field is data */ + break; + case H_DUPLICATE: + /* Are we a datum or a key? Better be the former. */ + if (i % 2 == 0) { + EPRINT((dbp->dbenv, + "Hash key stored as duplicate at page %lu item %lu", + pip->pgno, i)); + } + /* + * Dups are encoded as a series within a single HKEYDATA, + * in which each dup is surrounded by a copy of its length + * on either side (so that the series can be walked in either + * direction. We loop through this series and make sure + * each dup is reasonable. + * + * Note that at this point, we've verified item i-1, so + * it's safe to use LEN_HKEYDATA (which looks at inp[i-1]). + */ + len = LEN_HKEYDATA(h, dbp->pgsize, i); + databuf = HKEYDATA_DATA(P_ENTRY(h, i)); + for (offset = 0; offset < len; offset += DUP_SIZE(dlen)) { + memcpy(&dlen, databuf + offset, sizeof(db_indx_t)); + + /* Make sure the length is plausible. */ + if (offset + DUP_SIZE(dlen) > len) { + EPRINT((dbp->dbenv, + "Duplicate item %lu, page %lu has bad length", + i, pip->pgno)); + ret = DB_VERIFY_BAD; + goto err; + } + + /* + * Make sure the second copy of the length is the + * same as the first. + */ + memcpy(&elen, + databuf + offset + dlen + sizeof(db_indx_t), + sizeof(db_indx_t)); + if (elen != dlen) { + EPRINT((dbp->dbenv, + "Duplicate item %lu, page %lu has two different lengths", + i, pip->pgno)); + ret = DB_VERIFY_BAD; + goto err; + } + } + F_SET(pip, VRFY_HAS_DUPS); + if (!LF_ISSET(DB_NOORDERCHK) && + __ham_dups_unsorted(dbp, databuf, len)) + F_SET(pip, VRFY_DUPS_UNSORTED); + break; + case H_OFFPAGE: + /* Offpage item. Make sure pgno is sane, save off. */ + memcpy(&hop, P_ENTRY(h, i), HOFFPAGE_SIZE); + if (!IS_VALID_PGNO(hop.pgno) || hop.pgno == pip->pgno || + hop.pgno == PGNO_INVALID) { + EPRINT((dbp->dbenv, + "Offpage item %lu, page %lu has bad page number", + i, pip->pgno)); + ret = DB_VERIFY_BAD; + goto err; + } + memset(&child, 0, sizeof(VRFY_CHILDINFO)); + child.pgno = hop.pgno; + child.type = V_OVERFLOW; + child.tlen = hop.tlen; /* This will get checked later. */ + if ((ret = __db_vrfy_childput(vdp, pip->pgno, &child)) != 0) + goto err; + break; + case H_OFFDUP: + /* Offpage duplicate item. Same drill. */ + memcpy(&hod, P_ENTRY(h, i), HOFFDUP_SIZE); + if (!IS_VALID_PGNO(hod.pgno) || hod.pgno == pip->pgno || + hod.pgno == PGNO_INVALID) { + EPRINT((dbp->dbenv, + "Offpage item %lu, page %lu has bad page number", + i, pip->pgno)); + ret = DB_VERIFY_BAD; + goto err; + } + memset(&child, 0, sizeof(VRFY_CHILDINFO)); + child.pgno = hod.pgno; + child.type = V_DUPLICATE; + if ((ret = __db_vrfy_childput(vdp, pip->pgno, &child)) != 0) + goto err; + F_SET(pip, VRFY_HAS_DUPS); + break; + default: + EPRINT((dbp->dbenv, + "Item %i, page %lu has bad type", i, pip->pgno)); + ret = DB_VERIFY_BAD; + break; + } + +err: if ((t_ret = __db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0) + ret = t_ret; + return (ret); +} + +/* + * __ham_vrfy_structure -- + * Verify the structure of a hash database. + * + * PUBLIC: int __ham_vrfy_structure __P((DB *, VRFY_DBINFO *, db_pgno_t, + * PUBLIC: u_int32_t)); + */ +int +__ham_vrfy_structure(dbp, vdp, meta_pgno, flags) + DB *dbp; + VRFY_DBINFO *vdp; + db_pgno_t meta_pgno; + u_int32_t flags; +{ + DB *pgset; + HMETA *m; + PAGE *h; + VRFY_PAGEINFO *pip; + int isbad, p, ret, t_ret; + db_pgno_t pgno; + u_int32_t bucket; + + ret = isbad = 0; + h = NULL; + pgset = vdp->pgset; + + if ((ret = __db_vrfy_pgset_get(pgset, meta_pgno, &p)) != 0) + return (ret); + if (p != 0) { + EPRINT((dbp->dbenv, + "Hash meta page %lu referenced twice", meta_pgno)); + return (DB_VERIFY_BAD); + } + if ((ret = __db_vrfy_pgset_inc(pgset, meta_pgno)) != 0) + return (ret); + + /* Get the meta page; we'll need it frequently. */ + if ((ret = memp_fget(dbp->mpf, &meta_pgno, 0, &m)) != 0) + return (ret); + + /* Loop through bucket by bucket. */ + for (bucket = 0; bucket <= m->max_bucket; bucket++) + if ((ret = + __ham_vrfy_bucket(dbp, vdp, m, bucket, flags)) != 0) { + if (ret == DB_VERIFY_BAD) + isbad = 1; + else + goto err; + } + + /* + * There may be unused hash pages corresponding to buckets + * that have been allocated but not yet used. These may be + * part of the current doubling above max_bucket, or they may + * correspond to buckets that were used in a transaction + * that then aborted. + * + * Loop through them, as far as the spares array defines them, + * and make sure they're all empty. + * + * Note that this should be safe, since we've already verified + * that the spares array is sane. + */ + for (bucket = m->max_bucket + 1; + m->spares[__db_log2(bucket + 1)] != 0; bucket++) { + pgno = BS_TO_PAGE(bucket, m->spares); + if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) + goto err; + + /* It's okay if these pages are totally zeroed; unmark it. */ + F_CLR(pip, VRFY_IS_ALLZEROES); + + if (pip->type != P_HASH) { + EPRINT((dbp->dbenv, + "Hash bucket %lu maps to non-hash page %lu", + bucket, pgno)); + isbad = 1; + } else if (pip->entries != 0) { + EPRINT((dbp->dbenv, + "Non-empty page %lu in unused hash bucket %lu", + pgno, bucket)); + isbad = 1; + } else { + if ((ret = __db_vrfy_pgset_get(pgset, pgno, &p)) != 0) + goto err; + if (p != 0) { + EPRINT((dbp->dbenv, + "Hash page %lu above max_bucket referenced", + pgno)); + isbad = 1; + } else { + if ((ret = + __db_vrfy_pgset_inc(pgset, pgno)) != 0) + goto err; + if ((ret = + __db_vrfy_putpageinfo(vdp, pip)) != 0) + goto err; + continue; + } + } + + /* If we got here, it's an error. */ + (void)__db_vrfy_putpageinfo(vdp, pip); + goto err; + } + +err: if ((t_ret = memp_fput(dbp->mpf, m, 0)) != 0) + return (t_ret); + if (h != NULL && (t_ret = memp_fput(dbp->mpf, h, 0)) != 0) + return (t_ret); + return ((isbad == 1 && ret == 0) ? DB_VERIFY_BAD: ret); +} + +/* + * __ham_vrfy_bucket -- + * Verify a given bucket. + */ +static int +__ham_vrfy_bucket(dbp, vdp, m, bucket, flags) + DB *dbp; + VRFY_DBINFO *vdp; + HMETA *m; + u_int32_t bucket, flags; +{ + HASH *hashp; + VRFY_CHILDINFO *child; + VRFY_PAGEINFO *mip, *pip; + int ret, t_ret, isbad, p; + db_pgno_t pgno, next_pgno; + DBC *cc; + u_int32_t (*hfunc) __P((DB *, const void *, u_int32_t)); + + isbad = 0; + pip = NULL; + cc = NULL; + + hashp = dbp->h_internal; + if (hashp != NULL && hashp->h_hash != NULL) + hfunc = hashp->h_hash; + else + hfunc = __ham_func5; + + if ((ret = __db_vrfy_getpageinfo(vdp, PGNO(m), &mip)) != 0) + return (ret); + + /* Calculate the first pgno for this bucket. */ + pgno = BS_TO_PAGE(bucket, m->spares); + + if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) + goto err; + + /* Make sure we got a plausible page number. */ + if (pgno > vdp->last_pgno || pip->type != P_HASH) { + EPRINT((dbp->dbenv, "Bucket %lu has impossible first page %lu", + bucket, pgno)); + /* Unsafe to continue. */ + isbad = 1; + goto err; + } + + if (pip->prev_pgno != PGNO_INVALID) { + EPRINT((dbp->dbenv, + "First hash page %lu in bucket %lu has a prev_pgno", pgno)); + isbad = 1; + } + + /* + * Set flags for dups and sorted dups. + */ + flags |= F_ISSET(mip, VRFY_HAS_DUPS) ? ST_DUPOK : 0; + flags |= F_ISSET(mip, VRFY_HAS_DUPSORT) ? ST_DUPSORT : 0; + + /* Loop until we find a fatal bug, or until we run out of pages. */ + for (;;) { + /* Provide feedback on our progress to the application. */ + if (!LF_ISSET(DB_SALVAGE)) + __db_vrfy_struct_feedback(dbp, vdp); + + if ((ret = __db_vrfy_pgset_get(vdp->pgset, pgno, &p)) != 0) + goto err; + if (p != 0) { + EPRINT((dbp->dbenv, + "Hash page %lu referenced twice", pgno)); + isbad = 1; + /* Unsafe to continue. */ + goto err; + } else if ((ret = __db_vrfy_pgset_inc(vdp->pgset, pgno)) != 0) + goto err; + + /* + * Hash pages that nothing has ever hashed to may never + * have actually come into existence, and may appear to be + * entirely zeroed. This is acceptable, and since there's + * no real way for us to know whether this has actually + * occurred, we clear the "wholly zeroed" flag on every + * hash page. A wholly zeroed page, by nature, will appear + * to have no flags set and zero entries, so should + * otherwise verify correctly. + */ + F_CLR(pip, VRFY_IS_ALLZEROES); + + /* If we have dups, our meta page had better know about it. */ + if (F_ISSET(pip, VRFY_HAS_DUPS) + && !F_ISSET(mip, VRFY_HAS_DUPS)) { + EPRINT((dbp->dbenv, + "Duplicates present in non-duplicate database, page %lu", + pgno)); + isbad = 1; + } + + /* + * If the database has sorted dups, this page had better + * not have unsorted ones. + */ + if (F_ISSET(mip, VRFY_HAS_DUPSORT) && + F_ISSET(pip, VRFY_DUPS_UNSORTED)) { + EPRINT((dbp->dbenv, + "Unsorted dups in sorted-dup database, page %lu", + pgno)); + isbad = 1; + } + + /* Walk overflow chains and offpage dup trees. */ + if ((ret = __db_vrfy_childcursor(vdp, &cc)) != 0) + goto err; + for (ret = __db_vrfy_ccset(cc, pip->pgno, &child); ret == 0; + ret = __db_vrfy_ccnext(cc, &child)) + if (child->type == V_OVERFLOW) { + if ((ret = __db_vrfy_ovfl_structure(dbp, vdp, + child->pgno, child->tlen, flags)) != 0) { + if (ret == DB_VERIFY_BAD) + isbad = 1; + else + goto err; + } + } else if (child->type == V_DUPLICATE) { + if ((ret = __db_vrfy_duptype(dbp, + vdp, child->pgno, flags)) != 0) { + isbad = 1; + continue; + } + if ((ret = __bam_vrfy_subtree(dbp, vdp, + child->pgno, NULL, NULL, + flags | ST_RECNUM | ST_DUPSET, NULL, + NULL, NULL)) != 0) { + if (ret == DB_VERIFY_BAD) + isbad = 1; + else + goto err; + } + } + if ((ret = __db_vrfy_ccclose(cc)) != 0) + goto err; + cc = NULL; + + /* If it's safe to check that things hash properly, do so. */ + if (isbad == 0 && !LF_ISSET(DB_NOORDERCHK) && + (ret = __ham_vrfy_hashing(dbp, pip->entries, + m, bucket, pgno, flags, hfunc)) != 0) { + if (ret == DB_VERIFY_BAD) + isbad = 1; + else + goto err; + } + + next_pgno = pip->next_pgno; + ret = __db_vrfy_putpageinfo(vdp, pip); + + pip = NULL; + if (ret != 0) + goto err; + + if (next_pgno == PGNO_INVALID) + break; /* End of the bucket. */ + + /* We already checked this, but just in case... */ + if (!IS_VALID_PGNO(next_pgno)) { + DB_ASSERT(0); + EPRINT((dbp->dbenv, + "Hash page %lu has bad next_pgno", pgno)); + isbad = 1; + goto err; + } + + if ((ret = __db_vrfy_getpageinfo(vdp, next_pgno, &pip)) != 0) + goto err; + + if (pip->prev_pgno != pgno) { + EPRINT((dbp->dbenv, "Hash page %lu has bad prev_pgno", + next_pgno)); + isbad = 1; + } + pgno = next_pgno; + } + +err: if (cc != NULL && ((t_ret = __db_vrfy_ccclose(cc)) != 0) && ret == 0) + ret = t_ret; + if (mip != NULL && ((t_ret = __db_vrfy_putpageinfo(vdp, mip)) != 0) && + ret == 0) + ret = t_ret; + if (pip != NULL && ((t_ret = __db_vrfy_putpageinfo(vdp, pip)) != 0) && + ret == 0) + ret = t_ret; + return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret); +} + +/* + * __ham_vrfy_hashing -- + * Verify that all items on a given hash page hash correctly. + * + * PUBLIC: int __ham_vrfy_hashing __P((DB *, + * PUBLIC: u_int32_t, HMETA *, u_int32_t, db_pgno_t, u_int32_t, + * PUBLIC: u_int32_t (*) __P((DB *, const void *, u_int32_t)))); + */ +int +__ham_vrfy_hashing(dbp, nentries, m, thisbucket, pgno, flags, hfunc) + DB *dbp; + u_int32_t nentries; + HMETA *m; + u_int32_t thisbucket; + db_pgno_t pgno; + u_int32_t flags; + u_int32_t (*hfunc) __P((DB *, const void *, u_int32_t)); +{ + DBT dbt; + PAGE *h; + db_indx_t i; + int ret, t_ret, isbad; + u_int32_t hval, bucket; + + ret = isbad = 0; + memset(&dbt, 0, sizeof(DBT)); + F_SET(&dbt, DB_DBT_REALLOC); + + if ((ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) + return (ret); + + for (i = 0; i < nentries; i += 2) { + /* + * We've already verified the page integrity and that of any + * overflow chains linked off it; it is therefore safe to use + * __db_ret. It's also not all that much slower, since we have + * to copy every hash item to deal with alignment anyway; we + * can tweak this a bit if this proves to be a bottleneck, + * but for now, take the easy route. + */ + if ((ret = __db_ret(dbp, h, i, &dbt, NULL, NULL)) != 0) + goto err; + hval = hfunc(dbp, dbt.data, dbt.size); + + bucket = hval & m->high_mask; + if (bucket > m->max_bucket) + bucket = bucket & m->low_mask; + + if (bucket != thisbucket) { + EPRINT((dbp->dbenv, + "Item %lu on page %lu hashes incorrectly", + i, pgno)); + isbad = 1; + } + } + +err: if (dbt.data != NULL) + __os_free(dbt.data, 0); + if ((t_ret = memp_fput(dbp->mpf, h, 0)) != 0) + return (t_ret); + + return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret); +} + +/* + * __ham_salvage -- + * Safely dump out anything that looks like a key on an alleged + * hash page. + * + * PUBLIC: int __ham_salvage __P((DB *, VRFY_DBINFO *, db_pgno_t, PAGE *, + * PUBLIC: void *, int (*)(void *, const void *), u_int32_t)); + */ +int +__ham_salvage(dbp, vdp, pgno, h, handle, callback, flags) + DB *dbp; + VRFY_DBINFO *vdp; + db_pgno_t pgno; + PAGE *h; + void *handle; + int (*callback) __P((void *, const void *)); + u_int32_t flags; +{ + DBT dbt, unkdbt; + db_pgno_t dpgno; + int ret, err_ret, t_ret; + u_int32_t himark, tlen; + u_int8_t *hk; + void *buf; + u_int32_t dlen, len, i; + + memset(&dbt, 0, sizeof(DBT)); + dbt.flags = DB_DBT_REALLOC; + + memset(&unkdbt, 0, sizeof(DBT)); + unkdbt.size = strlen("UNKNOWN") + 1; + unkdbt.data = "UNKNOWN"; + + err_ret = 0; + + /* + * Allocate a buffer for overflow items. Start at one page; + * __db_safe_goff will realloc as needed. + */ + if ((ret = __os_malloc(dbp->dbenv, dbp->pgsize, NULL, &buf)) != 0) + return (ret); + + himark = dbp->pgsize; + for (i = 0;; i++) { + /* If we're not aggressive, break when we hit NUM_ENT(h). */ + if (!LF_ISSET(DB_AGGRESSIVE) && i >= NUM_ENT(h)) + break; + + /* Verify the current item. */ + ret = __db_vrfy_inpitem(dbp, + h, pgno, i, 0, flags, &himark, NULL); + /* If this returned a fatality, it's time to break. */ + if (ret == DB_VERIFY_FATAL) + break; + + if (ret == 0) { + hk = P_ENTRY(h, i); + len = LEN_HKEYDATA(h, dbp->pgsize, i); + if ((u_int32_t)(hk + len - (u_int8_t *)h) > + dbp->pgsize) { + /* + * Item is unsafely large; either continue + * or set it to the whole page, depending on + * aggressiveness. + */ + if (!LF_ISSET(DB_AGGRESSIVE)) + continue; + len = dbp->pgsize - + (u_int32_t)(hk - (u_int8_t *)h); + err_ret = DB_VERIFY_BAD; + } + switch (HPAGE_PTYPE(hk)) { + default: + if (!LF_ISSET(DB_AGGRESSIVE)) + break; + err_ret = DB_VERIFY_BAD; + /* FALLTHROUGH */ + case H_KEYDATA: +keydata: memcpy(buf, HKEYDATA_DATA(hk), len); + dbt.size = len; + dbt.data = buf; + if ((ret = __db_prdbt(&dbt, + 0, " ", handle, callback, 0, NULL)) != 0) + err_ret = ret; + break; + case H_OFFPAGE: + if (len < HOFFPAGE_SIZE) { + err_ret = DB_VERIFY_BAD; + continue; + } + memcpy(&dpgno, + HOFFPAGE_PGNO(hk), sizeof(dpgno)); + if ((ret = __db_safe_goff(dbp, vdp, + dpgno, &dbt, &buf, flags)) != 0) { + err_ret = ret; + (void)__db_prdbt(&unkdbt, 0, " ", + handle, callback, 0, NULL); + break; + } + if ((ret = __db_prdbt(&dbt, + 0, " ", handle, callback, 0, NULL)) != 0) + err_ret = ret; + break; + case H_OFFDUP: + if (len < HOFFPAGE_SIZE) { + err_ret = DB_VERIFY_BAD; + continue; + } + memcpy(&dpgno, + HOFFPAGE_PGNO(hk), sizeof(dpgno)); + /* UNKNOWN iff pgno is bad or we're a key. */ + if (!IS_VALID_PGNO(dpgno) || (i % 2 == 0)) { + if ((ret = __db_prdbt(&unkdbt, 0, " ", + handle, callback, 0, NULL)) != 0) + err_ret = ret; + } else if ((ret = __db_salvage_duptree(dbp, + vdp, dpgno, &dbt, handle, callback, + flags | SA_SKIPFIRSTKEY)) != 0) + err_ret = ret; + break; + case H_DUPLICATE: + /* + * We're a key; printing dups will seriously + * foul the output. If we're being aggressive, + * pretend this is a key and let the app. + * programmer sort out the mess. + */ + if (i % 2 == 0) { + err_ret = ret; + if (LF_ISSET(DB_AGGRESSIVE)) + goto keydata; + break; + } + + /* Too small to have any data. */ + if (len < + HKEYDATA_SIZE(2 * sizeof(db_indx_t))) { + err_ret = DB_VERIFY_BAD; + continue; + } + + /* Loop until we hit the total length. */ + for (tlen = 0; tlen + sizeof(db_indx_t) < len; + tlen += dlen) { + tlen += sizeof(db_indx_t); + memcpy(&dlen, hk, sizeof(db_indx_t)); + /* + * If dlen is too long, print all the + * rest of the dup set in a chunk. + */ + if (dlen + tlen > len) + dlen = len - tlen; + memcpy(buf, hk + tlen, dlen); + dbt.size = dlen; + dbt.data = buf; + if ((ret = __db_prdbt(&dbt, 0, " ", + handle, callback, 0, NULL)) != 0) + err_ret = ret; + tlen += sizeof(db_indx_t); + } + break; + } + } + } + + __os_free(buf, 0); + if ((t_ret = __db_salvage_markdone(vdp, pgno)) != 0) + return (t_ret); + return ((ret == 0 && err_ret != 0) ? err_ret : ret); +} + +/* + * __ham_meta2pgset -- + * Return the set of hash pages corresponding to the given + * known-good meta page. + * + * PUBLIC: int __ham_meta2pgset __P((DB *, VRFY_DBINFO *, HMETA *, u_int32_t, + * PUBLIC: DB *)); + */ +int __ham_meta2pgset(dbp, vdp, hmeta, flags, pgset) + DB *dbp; + VRFY_DBINFO *vdp; + HMETA *hmeta; + u_int32_t flags; + DB *pgset; +{ + PAGE *h; + db_pgno_t pgno; + u_int32_t bucket, totpgs; + int ret, val; + + /* + * We don't really need flags, but leave them for consistency with + * __bam_meta2pgset. + */ + COMPQUIET(flags, 0); + + DB_ASSERT(pgset != NULL); + + totpgs = 0; + + /* + * Loop through all the buckets, pushing onto pgset the corresponding + * page(s) for each one. + */ + for (bucket = 0; bucket <= hmeta->max_bucket; bucket++) { + pgno = BS_TO_PAGE(bucket, hmeta->spares); + + /* + * We know the initial pgno is safe because the spares array has + * been verified. + * + * Safely walk the list of pages in this bucket. + */ + for (;;) { + if ((ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) + return (ret); + if (TYPE(h) == P_HASH) { + + /* + * Make sure we don't go past the end of + * pgset. + */ + if (++totpgs > vdp->last_pgno) { + (void)memp_fput(dbp->mpf, h, 0); + return (DB_VERIFY_BAD); + } + if ((ret = + __db_vrfy_pgset_inc(pgset, pgno)) != 0) + return (ret); + + pgno = NEXT_PGNO(h); + } else + pgno = PGNO_INVALID; + + if ((ret = memp_fput(dbp->mpf, h, 0)) != 0) + return (ret); + + /* If the new pgno is wonky, go onto the next bucket. */ + if (!IS_VALID_PGNO(pgno) || + pgno == PGNO_INVALID) + goto nextbucket; + + /* + * If we've touched this page before, we have a cycle; + * go on to the next bucket. + */ + if ((ret = __db_vrfy_pgset_get(pgset, pgno, &val)) != 0) + return (ret); + if (val != 0) + goto nextbucket; + } +nextbucket: ; + } + return (0); +} + +/* + * __ham_dups_unsorted -- + * Takes a known-safe hash duplicate set and its total length. + * Returns 1 if there are out-of-order duplicates in this set, + * 0 if there are not. + */ +static int +__ham_dups_unsorted(dbp, buf, len) + DB *dbp; + u_int8_t *buf; + u_int32_t len; +{ + DBT a, b; + db_indx_t offset, dlen; + int (*func) __P((DB *, const DBT *, const DBT *)); + + memset(&a, 0, sizeof(DBT)); + memset(&b, 0, sizeof(DBT)); + + func = (dbp->dup_compare == NULL) ? __bam_defcmp : dbp->dup_compare; + + /* + * Loop through the dup set until we hit the end or we find + * a pair of dups that's out of order. b is always the current + * dup, a the one before it. + */ + for (offset = 0; offset < len; offset += DUP_SIZE(dlen)) { + memcpy(&dlen, buf + offset, sizeof(db_indx_t)); + b.data = buf + offset + sizeof(db_indx_t); + b.size = dlen; + + if (a.data != NULL && func(dbp, &a, &b) > 0) + return (1); + + a.data = b.data; + a.size = b.size; + } + + return (0); +} diff --git a/db/hsearch/hsearch.c b/db/hsearch/hsearch.c new file mode 100644 index 000000000..c2869c4c4 --- /dev/null +++ b/db/hsearch/hsearch.c @@ -0,0 +1,148 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993 + * Margo Seltzer. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Margo Seltzer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: hsearch.c,v 11.5 2000/11/30 00:58:37 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#define DB_DBM_HSEARCH 1 +#include "db_int.h" + +static DB *dbp; +static ENTRY retval; + +int +__db_hcreate(nel) + size_t nel; +{ + int ret; + + if ((ret = db_create(&dbp, NULL, 0)) != 0) { + __os_set_errno(ret); + return (1); + } + + if ((ret = dbp->set_pagesize(dbp, 512)) != 0 || + (ret = dbp->set_h_ffactor(dbp, 16)) != 0 || + (ret = dbp->set_h_nelem(dbp, nel)) != 0 || + (ret = dbp->open(dbp, + NULL, NULL, DB_HASH, DB_CREATE, __db_omode("rw----"))) != 0) + __os_set_errno(ret); + + /* + * !!! + * Hsearch returns 0 on error, not 1. + */ + return (ret == 0 ? 1 : 0); +} + +ENTRY * +__db_hsearch(item, action) + ENTRY item; + ACTION action; +{ + DBT key, val; + int ret; + + if (dbp == NULL) { + __os_set_errno(EINVAL); + return (NULL); + } + memset(&key, 0, sizeof(key)); + memset(&val, 0, sizeof(val)); + key.data = item.key; + key.size = strlen(item.key) + 1; + + switch (action) { + case ENTER: + val.data = item.data; + val.size = strlen(item.data) + 1; + + /* + * Try and add the key to the database. If we fail because + * the key already exists, return the existing key. + */ + if ((ret = + dbp->put(dbp, NULL, &key, &val, DB_NOOVERWRITE)) == 0) + break; + if (ret == DB_KEYEXIST && + (ret = dbp->get(dbp, NULL, &key, &val, 0)) == 0) + break; + /* + * The only possible DB error is DB_NOTFOUND, and it can't + * happen. Check for a DB error, and lie if we find one. + */ + __os_set_errno(ret > 0 ? ret : EINVAL); + return (NULL); + case FIND: + if ((ret = dbp->get(dbp, NULL, &key, &val, 0)) != 0) { + if (ret != DB_NOTFOUND) + __os_set_errno(ret); + return (NULL); + } + item.data = (char *)val.data; + break; + default: + __os_set_errno(EINVAL); + return (NULL); + } + retval.key = item.key; + retval.data = item.data; + return (&retval); +} + +void +__db_hdestroy() +{ + if (dbp != NULL) { + (void)dbp->close(dbp, 0); + dbp = NULL; + } +} diff --git a/db/include/btree.h b/db/include/btree.h new file mode 100644 index 000000000..395f645f0 --- /dev/null +++ b/db/include/btree.h @@ -0,0 +1,317 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994, 1995 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Mike Olson. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: btree.h,v 11.37 2001/01/17 17:09:52 bostic Exp $ + */ + +/* Forward structure declarations. */ +struct __btree; typedef struct __btree BTREE; +struct __cursor; typedef struct __cursor BTREE_CURSOR; +struct __epg; typedef struct __epg EPG; +struct __recno; typedef struct __recno RECNO; + +#define DEFMINKEYPAGE (2) + +/* + * A recno order of 0 indicates that we don't have an order, not that we've + * an order less than 1. + */ +#define INVALID_ORDER 0 + +#define ISINTERNAL(p) (TYPE(p) == P_IBTREE || TYPE(p) == P_IRECNO) +#define ISLEAF(p) (TYPE(p) == P_LBTREE || \ + TYPE(p) == P_LRECNO || TYPE(p) == P_LDUP) + +/* Flags for __bam_cadjust_log(). */ +#define CAD_UPDATEROOT 0x01 /* Root page count was updated. */ + +/* Flags for __bam_split_log(). */ +#define SPL_NRECS 0x01 /* Split tree has record count. */ + +/* Flags for __bam_iitem(). */ +#define BI_DELETED 0x01 /* Key/data pair only placeholder. */ + +/* Flags for __bam_stkrel(). */ +#define STK_CLRDBC 0x01 /* Clear dbc->page reference. */ +#define STK_NOLOCK 0x02 /* Don't retain locks. */ + +/* Flags for __ram_ca(). These get logged, so make the values explicit. */ +typedef enum { + CA_DELETE = 0, /* Delete the current record. */ + CA_IAFTER = 1, /* Insert before the current record. */ + CA_IBEFORE = 2, /* Insert after the current record. */ + CA_ICURRENT = 3 /* Overwrite the current record. */ +} ca_recno_arg; + +/* + * Flags for __bam_search() and __bam_rsearch(). + * + * Note, internal page searches must find the largest record less than key in + * the tree so that descents work. Leaf page searches must find the smallest + * record greater than key so that the returned index is the record's correct + * position for insertion. + * + * The flags parameter to the search routines describes three aspects of the + * search: the type of locking required (including if we're locking a pair of + * pages), the item to return in the presence of duplicates and whether or not + * to return deleted entries. To simplify both the mnemonic representation + * and the code that checks for various cases, we construct a set of bitmasks. + */ +#define S_READ 0x00001 /* Read locks. */ +#define S_WRITE 0x00002 /* Write locks. */ + +#define S_APPEND 0x00040 /* Append to the tree. */ +#define S_DELNO 0x00080 /* Don't return deleted items. */ +#define S_DUPFIRST 0x00100 /* Return first duplicate. */ +#define S_DUPLAST 0x00200 /* Return last duplicate. */ +#define S_EXACT 0x00400 /* Exact items only. */ +#define S_PARENT 0x00800 /* Lock page pair. */ +#define S_STACK 0x01000 /* Need a complete stack. */ +#define S_PAST_EOF 0x02000 /* If doing insert search (or keyfirst + * or keylast operations), or a split + * on behalf of an insert, it's okay to + * return an entry one past end-of-page. + */ +#define S_STK_ONLY 0x04000 /* Just return info in the stack */ + +#define S_DELETE (S_WRITE | S_DUPFIRST | S_DELNO | S_EXACT | S_STACK) +#define S_FIND (S_READ | S_DUPFIRST | S_DELNO) +#define S_FIND_WR (S_WRITE | S_DUPFIRST | S_DELNO) +#define S_INSERT (S_WRITE | S_DUPLAST | S_PAST_EOF | S_STACK) +#define S_KEYFIRST (S_WRITE | S_DUPFIRST | S_PAST_EOF | S_STACK) +#define S_KEYLAST (S_WRITE | S_DUPLAST | S_PAST_EOF | S_STACK) +#define S_WRPAIR (S_WRITE | S_DUPLAST | S_PAST_EOF | S_PARENT) + +/* + * Various routines pass around page references. A page reference is + * a pointer to the page, and the indx indicates an item on the page. + * Each page reference may include a lock. + */ +struct __epg { + PAGE *page; /* The page. */ + db_indx_t indx; /* The index on the page. */ + db_indx_t entries; /* The number of entries on page */ + DB_LOCK lock; /* The page's lock. */ + db_lockmode_t lock_mode; /* The lock mode. */ +}; + +/* + * We maintain a stack of the pages that we're locking in the tree. Grow + * the stack as necessary. + * + * XXX + * Temporary fix for #3243 -- clear the page and lock from the stack entry. + * The correct fix is to never release a stack that doesn't hold items. + */ +#define BT_STK_CLR(c) do { \ + (c)->csp = (c)->sp; \ + (c)->csp->page = NULL; \ + (c)->csp->lock.off = LOCK_INVALID; \ +} while (0) + +#define BT_STK_ENTER(dbenv, c, pagep, page_indx, l, mode, ret) do { \ + if ((ret = \ + (c)->csp == (c)->esp ? __bam_stkgrow(dbenv, c) : 0) == 0) { \ + (c)->csp->page = pagep; \ + (c)->csp->indx = page_indx; \ + (c)->csp->entries = NUM_ENT(pagep); \ + (c)->csp->lock = l; \ + (c)->csp->lock_mode = mode; \ + } \ +} while (0) + +#define BT_STK_PUSH(dbenv, c, pagep, page_indx, lock, mode, ret) do { \ + BT_STK_ENTER(dbenv, c, pagep, page_indx, lock, mode, ret); \ + ++(c)->csp; \ +} while (0) + +#define BT_STK_NUM(dbenv, c, pagep, page_indx, ret) do { \ + if ((ret = \ + (c)->csp == (c)->esp ? __bam_stkgrow(dbenv, c) : 0) == 0) { \ + (c)->csp->page = NULL; \ + (c)->csp->indx = page_indx; \ + (c)->csp->entries = NUM_ENT(pagep); \ + (c)->csp->lock.off = LOCK_INVALID; \ + (c)->csp->lock_mode = DB_LOCK_NG; \ + } \ +} while (0) + +#define BT_STK_NUMPUSH(dbenv, c, pagep, page_indx,ret) do { \ + BT_STK_NUM(dbenv, cp, pagep, page_indx, ret); \ + ++(c)->csp; \ +} while (0) + +#define BT_STK_POP(c) \ + ((c)->csp == (c)->sp ? NULL : --(c)->csp) + +/* Btree/Recno cursor. */ +struct __cursor { + /* struct __dbc_internal */ + __DBC_INTERNAL + + /* btree private part */ + EPG *sp; /* Stack pointer. */ + EPG *csp; /* Current stack entry. */ + EPG *esp; /* End stack pointer. */ + EPG stack[5]; + + db_indx_t ovflsize; /* Maximum key/data on-page size. */ + + db_recno_t recno; /* Current record number. */ + u_int32_t order; /* Relative order among deleted curs. */ + + /* + * Btree: + * We set a flag in the cursor structure if the underlying object has + * been deleted. It's not strictly necessary, we could get the same + * information by looking at the page itself, but this method doesn't + * require us to retrieve the page on cursor delete. + * + * Recno: + * When renumbering recno databases during deletes, cursors referencing + * "deleted" records end up positioned between two records, and so must + * be specially adjusted on the next operation. + */ +#define C_DELETED 0x0001 /* Record was deleted. */ + /* + * There are three tree types that require maintaining record numbers. + * Recno AM trees, Btree AM trees for which the DB_RECNUM flag was set, + * and Btree off-page duplicate trees. + */ +#define C_RECNUM 0x0002 /* Tree requires record counts. */ + /* + * Recno trees have immutable record numbers by default, but optionally + * support mutable record numbers. Off-page duplicate Recno trees have + * mutable record numbers. All Btrees with record numbers (including + * off-page duplicate trees) are mutable by design, no flag is needed. + */ +#define C_RENUMBER 0x0004 /* Tree records are mutable. */ + u_int32_t flags; +}; + +/* + * Threshhold value, as a function of bt_minkey, of the number of + * bytes a key/data pair can use before being placed on an overflow + * page. Assume every item requires the maximum alignment for + * padding, out of sheer paranoia. + */ +#define B_MINKEY_TO_OVFLSIZE(minkey, pgsize) \ + ((u_int16_t)(((pgsize) - P_OVERHEAD) / ((minkey) * P_INDX) - \ + (BKEYDATA_PSIZE(0) + ALIGN(1, sizeof(int32_t))))) + +/* + * The maximum space that a single item can ever take up on one page. + * Used by __bam_split to determine whether a split is still necessary. + */ +#define B_MAX(a,b) (((a) > (b)) ? (a) : (b)) +#define B_MAXSIZEONPAGE(ovflsize) \ + (B_MAX(BOVERFLOW_PSIZE, BKEYDATA_PSIZE(ovflsize))) + +/* + * The in-memory, per-tree btree/recno data structure. + */ +struct __btree { /* Btree access method. */ + /* + * !!! + * These fields are write-once (when the structure is created) and + * so are ignored as far as multi-threading is concerned. + */ + db_pgno_t bt_meta; /* Database meta-data page. */ + db_pgno_t bt_root; /* Database root page. */ + + u_int32_t bt_maxkey; /* Maximum keys per page. */ + u_int32_t bt_minkey; /* Minimum keys per page. */ + + /* Btree comparison function. */ + int (*bt_compare) __P((DB *, const DBT *, const DBT *)); + /* Btree prefix function. */ + size_t (*bt_prefix) __P((DB *, const DBT *, const DBT *)); + + /* Recno access method. */ + int re_pad; /* Fixed-length padding byte. */ + int re_delim; /* Variable-length delimiting byte. */ + u_int32_t re_len; /* Length for fixed-length records. */ + char *re_source; /* Source file name. */ + + /* + * !!! + * The bt_lpgno field is NOT protected by any mutex, and for this + * reason must be advisory only, so, while it is read/written by + * multiple threads, DB is completely indifferent to the quality + * of its information. + */ + db_pgno_t bt_lpgno; /* Last insert location. */ + + /* + * !!! + * The re_modified field is NOT protected by any mutex, and for this + * reason cannot be anything more complicated than a zero/non-zero + * value. The actual writing of the backing source file cannot be + * threaded, so clearing the flag isn't a problem. + */ + int re_modified; /* If the tree was modified. */ + + /* + * !!! + * These fields are ignored as far as multi-threading is concerned. + * There are no transaction semantics associated with backing files, + * nor is there any thread protection. + */ + FILE *re_fp; /* Source file handle. */ + int re_eof; /* Backing source file EOF reached. */ + db_recno_t re_last; /* Last record number read. */ +}; + +/* + * Modes for the __bam_curadj recovery records (btree_curadj). + * These appear in log records, so we wire the values and + * do not leave it up to the compiler. + */ +typedef enum { + DB_CA_DI = 1, + DB_CA_DUP = 2, + DB_CA_RSPLIT = 3, + DB_CA_SPLIT = 4 +} db_ca_mode; + +#include "btree_auto.h" +#include "btree_ext.h" +#include "db_am.h" diff --git a/db/include/btree_auto.h b/db/include/btree_auto.h new file mode 100644 index 000000000..214f84332 --- /dev/null +++ b/db/include/btree_auto.h @@ -0,0 +1,267 @@ +/* Do not edit: automatically built by gen_rec.awk. */ + +#ifndef bam_AUTO_H +#define bam_AUTO_H + +#define DB_bam_pg_alloc 51 +typedef struct _bam_pg_alloc_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + DB_LSN meta_lsn; + DB_LSN page_lsn; + db_pgno_t pgno; + u_int32_t ptype; + db_pgno_t next; +} __bam_pg_alloc_args; + +int __bam_pg_alloc_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, int32_t, DB_LSN *, DB_LSN *, db_pgno_t, u_int32_t, db_pgno_t)); +int __bam_pg_alloc_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_pg_alloc_read __P((DB_ENV *, void *, __bam_pg_alloc_args **)); + +#define DB_bam_pg_alloc1 60 +typedef struct _bam_pg_alloc1_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + DB_LSN meta_lsn; + DB_LSN alloc_lsn; + DB_LSN page_lsn; + db_pgno_t pgno; + u_int32_t ptype; + db_pgno_t next; +} __bam_pg_alloc1_args; + +int __bam_pg_alloc1_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_pg_alloc1_read __P((DB_ENV *, void *, __bam_pg_alloc1_args **)); + +#define DB_bam_pg_free 52 +typedef struct _bam_pg_free_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t pgno; + DB_LSN meta_lsn; + DBT header; + db_pgno_t next; +} __bam_pg_free_args; + +int __bam_pg_free_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, int32_t, db_pgno_t, DB_LSN *, const DBT *, db_pgno_t)); +int __bam_pg_free_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_pg_free_read __P((DB_ENV *, void *, __bam_pg_free_args **)); + +#define DB_bam_pg_free1 61 +typedef struct _bam_pg_free1_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t pgno; + DB_LSN meta_lsn; + DB_LSN alloc_lsn; + DBT header; + db_pgno_t next; +} __bam_pg_free1_args; + +int __bam_pg_free1_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_pg_free1_read __P((DB_ENV *, void *, __bam_pg_free1_args **)); + +#define DB_bam_split1 53 +typedef struct _bam_split1_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t left; + DB_LSN llsn; + db_pgno_t right; + DB_LSN rlsn; + u_int32_t indx; + db_pgno_t npgno; + DB_LSN nlsn; + DBT pg; +} __bam_split1_args; + +int __bam_split1_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_split1_read __P((DB_ENV *, void *, __bam_split1_args **)); + +#define DB_bam_split 62 +typedef struct _bam_split_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t left; + DB_LSN llsn; + db_pgno_t right; + DB_LSN rlsn; + u_int32_t indx; + db_pgno_t npgno; + DB_LSN nlsn; + db_pgno_t root_pgno; + DBT pg; + u_int32_t opflags; +} __bam_split_args; + +int __bam_split_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, int32_t, db_pgno_t, DB_LSN *, db_pgno_t, DB_LSN *, u_int32_t, db_pgno_t, DB_LSN *, db_pgno_t, const DBT *, u_int32_t)); +int __bam_split_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_split_read __P((DB_ENV *, void *, __bam_split_args **)); + +#define DB_bam_rsplit1 54 +typedef struct _bam_rsplit1_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t pgno; + DBT pgdbt; + db_pgno_t nrec; + DBT rootent; + DB_LSN rootlsn; +} __bam_rsplit1_args; + +int __bam_rsplit1_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_rsplit1_read __P((DB_ENV *, void *, __bam_rsplit1_args **)); + +#define DB_bam_rsplit 63 +typedef struct _bam_rsplit_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t pgno; + DBT pgdbt; + db_pgno_t root_pgno; + db_pgno_t nrec; + DBT rootent; + DB_LSN rootlsn; +} __bam_rsplit_args; + +int __bam_rsplit_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, int32_t, db_pgno_t, const DBT *, db_pgno_t, db_pgno_t, const DBT *, DB_LSN *)); +int __bam_rsplit_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_rsplit_read __P((DB_ENV *, void *, __bam_rsplit_args **)); + +#define DB_bam_adj 55 +typedef struct _bam_adj_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t pgno; + DB_LSN lsn; + u_int32_t indx; + u_int32_t indx_copy; + u_int32_t is_insert; +} __bam_adj_args; + +int __bam_adj_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, int32_t, db_pgno_t, DB_LSN *, u_int32_t, u_int32_t, u_int32_t)); +int __bam_adj_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_adj_read __P((DB_ENV *, void *, __bam_adj_args **)); + +#define DB_bam_cadjust 56 +typedef struct _bam_cadjust_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t pgno; + DB_LSN lsn; + u_int32_t indx; + int32_t adjust; + u_int32_t opflags; +} __bam_cadjust_args; + +int __bam_cadjust_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, int32_t, db_pgno_t, DB_LSN *, u_int32_t, int32_t, u_int32_t)); +int __bam_cadjust_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_cadjust_read __P((DB_ENV *, void *, __bam_cadjust_args **)); + +#define DB_bam_cdel 57 +typedef struct _bam_cdel_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t pgno; + DB_LSN lsn; + u_int32_t indx; +} __bam_cdel_args; + +int __bam_cdel_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, int32_t, db_pgno_t, DB_LSN *, u_int32_t)); +int __bam_cdel_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_cdel_read __P((DB_ENV *, void *, __bam_cdel_args **)); + +#define DB_bam_repl 58 +typedef struct _bam_repl_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t pgno; + DB_LSN lsn; + u_int32_t indx; + u_int32_t isdeleted; + DBT orig; + DBT repl; + u_int32_t prefix; + u_int32_t suffix; +} __bam_repl_args; + +int __bam_repl_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, int32_t, db_pgno_t, DB_LSN *, u_int32_t, u_int32_t, const DBT *, const DBT *, u_int32_t, u_int32_t)); +int __bam_repl_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_repl_read __P((DB_ENV *, void *, __bam_repl_args **)); + +#define DB_bam_root 59 +typedef struct _bam_root_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t meta_pgno; + db_pgno_t root_pgno; + DB_LSN meta_lsn; +} __bam_root_args; + +int __bam_root_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, int32_t, db_pgno_t, db_pgno_t, DB_LSN *)); +int __bam_root_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_root_read __P((DB_ENV *, void *, __bam_root_args **)); + +#define DB_bam_curadj 64 +typedef struct _bam_curadj_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_ca_mode mode; + db_pgno_t from_pgno; + db_pgno_t to_pgno; + db_pgno_t left_pgno; + u_int32_t first_indx; + u_int32_t from_indx; + u_int32_t to_indx; +} __bam_curadj_args; + +int __bam_curadj_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, int32_t, db_ca_mode, db_pgno_t, db_pgno_t, db_pgno_t, u_int32_t, u_int32_t, u_int32_t)); +int __bam_curadj_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_curadj_read __P((DB_ENV *, void *, __bam_curadj_args **)); + +#define DB_bam_rcuradj 65 +typedef struct _bam_rcuradj_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + ca_recno_arg mode; + db_pgno_t root; + db_recno_t recno; + u_int32_t order; +} __bam_rcuradj_args; + +int __bam_rcuradj_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, int32_t, ca_recno_arg, db_pgno_t, db_recno_t, u_int32_t)); +int __bam_rcuradj_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_rcuradj_read __P((DB_ENV *, void *, __bam_rcuradj_args **)); +int __bam_init_print __P((DB_ENV *)); +int __bam_init_recover __P((DB_ENV *)); +#endif diff --git a/db/include/btree_ext.h b/db/include/btree_ext.h new file mode 100644 index 000000000..8a9866e0b --- /dev/null +++ b/db/include/btree_ext.h @@ -0,0 +1,122 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _btree_ext_h_ +#define _btree_ext_h_ +#if defined(__cplusplus) +extern "C" { +#endif +int __bam_cmp __P((DB *, const DBT *, PAGE *, + u_int32_t, int (*)(DB *, const DBT *, const DBT *), int *)); +int __bam_defcmp __P((DB *, const DBT *, const DBT *)); +size_t __bam_defpfx __P((DB *, const DBT *, const DBT *)); +int __bam_pgin __P((DB_ENV *, db_pgno_t, void *, DBT *)); +int __bam_pgout __P((DB_ENV *, db_pgno_t, void *, DBT *)); +int __bam_mswap __P((PAGE *)); +void __bam_cprint __P((DBC *)); +int __bam_ca_delete __P((DB *, db_pgno_t, u_int32_t, int)); +int __ram_ca_delete __P((DB *, db_pgno_t)); +int __bam_ca_di __P((DBC *, db_pgno_t, u_int32_t, int)); +int __bam_ca_dup __P((DBC *, + u_int32_t, db_pgno_t, u_int32_t, db_pgno_t, u_int32_t)); +int __bam_ca_undodup __P((DB *, + u_int32_t, db_pgno_t, u_int32_t, u_int32_t)); +int __bam_ca_rsplit __P((DBC *, db_pgno_t, db_pgno_t)); +int __bam_ca_split __P((DBC *, + db_pgno_t, db_pgno_t, db_pgno_t, u_int32_t, int)); +void __bam_ca_undosplit __P((DB *, + db_pgno_t, db_pgno_t, db_pgno_t, u_int32_t)); +int __bam_c_init __P((DBC *, DBTYPE)); +int __bam_c_refresh __P((DBC *)); +int __bam_c_count __P((DBC *, db_recno_t *)); +int __bam_c_dup __P((DBC *, DBC *)); +int __bam_c_rget __P((DBC *, DBT *, u_int32_t)); +int __bam_delete __P((DB *, DB_TXN *, DBT *, u_int32_t)); +int __bam_ditem __P((DBC *, PAGE *, u_int32_t)); +int __bam_adjindx __P((DBC *, PAGE *, u_int32_t, u_int32_t, int)); +int __bam_dpages __P((DBC *, EPG *)); +int __bam_db_create __P((DB *)); +int __bam_db_close __P((DB *)); +int __bam_set_flags __P((DB *, u_int32_t *flagsp)); +int __ram_set_flags __P((DB *, u_int32_t *flagsp)); +int __bam_open __P((DB *, const char *, db_pgno_t, u_int32_t)); +int __bam_metachk __P((DB *, const char *, BTMETA *)); +int __bam_read_root __P((DB *, const char *, db_pgno_t, u_int32_t)); +int __bam_iitem __P((DBC *, DBT *, DBT *, u_int32_t, u_int32_t)); +u_int32_t __bam_partsize __P((u_int32_t, DBT *, PAGE *, u_int32_t)); +int __bam_build __P((DBC *, u_int32_t, + DBT *, PAGE *, u_int32_t, u_int32_t)); +int __bam_ritem __P((DBC *, PAGE *, u_int32_t, DBT *)); +int __bam_pg_alloc_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_pg_free_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_split_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_rsplit_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_adj_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_cadjust_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_cdel_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_repl_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_root_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_curadj_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_rcuradj_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_reclaim __P((DB *, DB_TXN *)); +int __ram_open __P((DB *, const char *, db_pgno_t, u_int32_t)); +int __ram_c_del __P((DBC *)); +int __ram_c_get + __P((DBC *, DBT *, DBT *, u_int32_t, db_pgno_t *)); +int __ram_c_put __P((DBC *, DBT *, DBT *, u_int32_t, db_pgno_t *)); +int __ram_ca __P((DBC *, ca_recno_arg)); +int __ram_getno __P((DBC *, const DBT *, db_recno_t *, int)); +int __ram_writeback __P((DB *)); +int __bam_rsearch __P((DBC *, db_recno_t *, u_int32_t, int, int *)); +int __bam_adjust __P((DBC *, int32_t)); +int __bam_nrecs __P((DBC *, db_recno_t *)); +db_recno_t __bam_total __P((PAGE *)); +int __bam_search __P((DBC *, + const DBT *, u_int32_t, int, db_recno_t *, int *)); +int __bam_stkrel __P((DBC *, u_int32_t)); +int __bam_stkgrow __P((DB_ENV *, BTREE_CURSOR *)); +int __bam_split __P((DBC *, void *)); +int __bam_copy __P((DB *, PAGE *, PAGE *, u_int32_t, u_int32_t)); +int __bam_stat __P((DB *, void *, void *(*)(size_t), u_int32_t)); +int __bam_traverse __P((DBC *, db_lockmode_t, + db_pgno_t, int (*)(DB *, PAGE *, void *, int *), void *)); +int __bam_stat_callback __P((DB *, PAGE *, void *, int *)); +int __bam_key_range __P((DB *, + DB_TXN *, DBT *, DB_KEY_RANGE *, u_int32_t)); +int __bam_30_btreemeta __P((DB *, char *, u_int8_t *)); +int __bam_31_btreemeta + __P((DB *, char *, u_int32_t, DB_FH *, PAGE *, int *)); +int __bam_31_lbtree + __P((DB *, char *, u_int32_t, DB_FH *, PAGE *, int *)); +int __bam_vrfy_meta __P((DB *, VRFY_DBINFO *, BTMETA *, + db_pgno_t, u_int32_t)); +int __ram_vrfy_leaf __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, + u_int32_t)); +int __bam_vrfy __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, + u_int32_t)); +int __bam_vrfy_itemorder __P((DB *, VRFY_DBINFO *, PAGE *, + db_pgno_t, u_int32_t, int, int, u_int32_t)); +int __bam_vrfy_structure __P((DB *, VRFY_DBINFO *, db_pgno_t, + u_int32_t)); +int __bam_vrfy_subtree __P((DB *, VRFY_DBINFO *, db_pgno_t, void *, + void *, u_int32_t, u_int32_t *, u_int32_t *, u_int32_t *)); +int __bam_salvage __P((DB *, VRFY_DBINFO *, db_pgno_t, u_int32_t, + PAGE *, void *, int (*)(void *, const void *), DBT *, + u_int32_t)); +int __bam_salvage_walkdupint __P((DB *, VRFY_DBINFO *, PAGE *, + DBT *, void *, int (*)(void *, const void *), u_int32_t)); +int __bam_meta2pgset __P((DB *, VRFY_DBINFO *, BTMETA *, + u_int32_t, DB *)); +#if defined(__cplusplus) +} +#endif +#endif /* _btree_ext_h_ */ diff --git a/db/include/clib_ext.h b/db/include/clib_ext.h new file mode 100644 index 000000000..efd0796af --- /dev/null +++ b/db/include/clib_ext.h @@ -0,0 +1,38 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _clib_ext_h_ +#define _clib_ext_h_ +#if defined(__cplusplus) +extern "C" { +#endif +#ifndef HAVE_GETCWD +char *getcwd __P((char *, size_t)); +#endif +#ifndef HAVE_GETOPT +int getopt __P((int, char * const *, const char *)); +#endif +#ifndef HAVE_MEMCMP +int memcmp __P((const void *, const void *, size_t)); +#endif +#ifndef HAVE_MEMCPY +void *memcpy __P((void *, const void *, size_t)); +#endif +#ifndef HAVE_MEMMOVE +void *memmove __P((void *, const void *, size_t)); +#endif +#ifndef HAVE_RAISE +int raise __P((int)); +#endif +#ifndef HAVE_SNPRINTF +int snprintf __P((char *, size_t, const char *, ...)); +#endif +int strcasecmp __P((const char *, const char *)); +#ifndef HAVE_STRERROR +char *strerror __P((int)); +#endif +#ifndef HAVE_VSNPRINTF +int vsnprintf(); +#endif +#if defined(__cplusplus) +} +#endif +#endif /* _clib_ext_h_ */ diff --git a/db/include/common_ext.h b/db/include/common_ext.h new file mode 100644 index 000000000..a36d62cac --- /dev/null +++ b/db/include/common_ext.h @@ -0,0 +1,44 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _common_ext_h_ +#define _common_ext_h_ +#if defined(__cplusplus) +extern "C" { +#endif +int __db_byteorder __P((DB_ENV *, int)); +int __db_fchk __P((DB_ENV *, const char *, u_int32_t, u_int32_t)); +int __db_fcchk + __P((DB_ENV *, const char *, u_int32_t, u_int32_t, u_int32_t)); +int __db_ferr __P((const DB_ENV *, const char *, int)); +int __db_pgerr __P((DB *, db_pgno_t)); +int __db_pgfmt __P((DB *, db_pgno_t)); +int __db_eopnotsup __P((const DB_ENV *)); +#ifdef DIAGNOSTIC +void __db_assert __P((const char *, const char *, int)); +#endif +int __db_panic_msg __P((DB_ENV *)); +int __db_panic __P((DB_ENV *, int)); +void __db_err __P((const DB_ENV *, const char *, ...)); +void __db_real_err + __P((const DB_ENV *, int, int, int, const char *, va_list)); +void __db_logmsg __P((const DB_ENV *, + DB_TXN *, const char *, u_int32_t, const char *, ...)); +void __db_real_log __P((const DB_ENV *, + DB_TXN *, const char *, u_int32_t, const char *, va_list ap)); +int __db_unknown_flag __P((DB_ENV *, char *, u_int32_t)); +int __db_unknown_type __P((DB_ENV *, char *, u_int32_t)); +#ifdef DIAGNOSTIC +int __db_missing_txn_err __P((DB_ENV *)); +#endif +int __db_getlong + __P((DB *, const char *, char *, long, long, long *)); +int __db_getulong + __P((DB *, const char *, char *, u_long, u_long, u_long *)); +u_int32_t __db_log2 __P((u_int32_t)); +int __db_util_logset __P((const char *, char *)); +void __db_util_siginit __P((void)); +int __db_util_interrupted __P((void)); +void __db_util_sigresend __P((void)); +#if defined(__cplusplus) +} +#endif +#endif /* _common_ext_h_ */ diff --git a/db/include/crdel_auto.h b/db/include/crdel_auto.h new file mode 100644 index 000000000..409c25681 --- /dev/null +++ b/db/include/crdel_auto.h @@ -0,0 +1,88 @@ +/* Do not edit: automatically built by gen_rec.awk. */ + +#ifndef crdel_AUTO_H +#define crdel_AUTO_H + +#define DB_crdel_fileopen 141 +typedef struct _crdel_fileopen_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + DBT name; + u_int32_t mode; +} __crdel_fileopen_args; + +int __crdel_fileopen_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, const DBT *, u_int32_t)); +int __crdel_fileopen_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __crdel_fileopen_read __P((DB_ENV *, void *, __crdel_fileopen_args **)); + +#define DB_crdel_metasub 142 +typedef struct _crdel_metasub_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t pgno; + DBT page; + DB_LSN lsn; +} __crdel_metasub_args; + +int __crdel_metasub_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, int32_t, db_pgno_t, const DBT *, DB_LSN *)); +int __crdel_metasub_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __crdel_metasub_read __P((DB_ENV *, void *, __crdel_metasub_args **)); + +#define DB_crdel_metapage 143 +typedef struct _crdel_metapage_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + DBT name; + db_pgno_t pgno; + DBT page; +} __crdel_metapage_args; + +int __crdel_metapage_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, int32_t, const DBT *, db_pgno_t, const DBT *)); +int __crdel_metapage_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __crdel_metapage_read __P((DB_ENV *, void *, __crdel_metapage_args **)); + +#define DB_crdel_old_delete 144 +typedef struct _crdel_old_delete_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + DBT name; +} __crdel_old_delete_args; + +int __crdel_old_delete_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __crdel_old_delete_read __P((DB_ENV *, void *, __crdel_old_delete_args **)); + +#define DB_crdel_rename 145 +typedef struct _crdel_rename_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + DBT name; + DBT newname; +} __crdel_rename_args; + +int __crdel_rename_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, int32_t, const DBT *, const DBT *)); +int __crdel_rename_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __crdel_rename_read __P((DB_ENV *, void *, __crdel_rename_args **)); + +#define DB_crdel_delete 146 +typedef struct _crdel_delete_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + DBT name; +} __crdel_delete_args; + +int __crdel_delete_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, int32_t, const DBT *)); +int __crdel_delete_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __crdel_delete_read __P((DB_ENV *, void *, __crdel_delete_args **)); +int __crdel_init_print __P((DB_ENV *)); +int __crdel_init_recover __P((DB_ENV *)); +#endif diff --git a/db/include/cxx_int.h b/db/include/cxx_int.h new file mode 100644 index 000000000..4a9a40ceb --- /dev/null +++ b/db/include/cxx_int.h @@ -0,0 +1,96 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: cxx_int.h,v 11.13 2000/11/21 22:56:36 dda Exp $ + */ + +#ifndef _CXX_INT_H_ +#define _CXX_INT_H_ + +// private data structures known to the implementation only + +// +// Using FooImp classes will allow the implementation to change in the +// future without any modification to user code or even to header files +// that the user includes. FooImp * is just like void * except that it +// provides a little extra protection, since you cannot randomly assign +// any old pointer to a FooImp* as you can with void *. Currently, a +// pointer to such an opaque class is always just a pointer to the +// appropriate underlying implementation struct. These are converted +// back and forth using the various overloaded wrap()/unwrap() methods. +// This is essentially a use of the "Bridge" Design Pattern. +// +// WRAPPED_CLASS implements the appropriate wrap() and unwrap() methods +// for a wrapper class that has an underlying pointer representation. +// +#define WRAPPED_CLASS(_WRAPPER_CLASS, _IMP_CLASS, _WRAPPED_TYPE) \ + \ + class _IMP_CLASS {}; \ + \ + inline _WRAPPED_TYPE unwrap(_WRAPPER_CLASS *val) \ + { \ + if (!val) return (0); \ + return ((_WRAPPED_TYPE)((void *)(val->imp()))); \ + } \ + \ + inline const _WRAPPED_TYPE unwrapConst(const _WRAPPER_CLASS *val) \ + { \ + if (!val) return (0); \ + return ((const _WRAPPED_TYPE)((void *)(val->constimp()))); \ + } \ + \ + inline _IMP_CLASS *wrap(_WRAPPED_TYPE val) \ + { \ + return ((_IMP_CLASS*)((void *)val)); \ + } + +WRAPPED_CLASS(DbMpoolFile, DbMpoolFileImp, DB_MPOOLFILE*) +WRAPPED_CLASS(Db, DbImp, DB*) +WRAPPED_CLASS(DbEnv, DbEnvImp, DB_ENV*) +WRAPPED_CLASS(DbTxn, DbTxnImp, DB_TXN*) + +// A tristate integer value used by the DB_ERROR macro below. +// We chose not to make this an enumerated type so it can +// be kept private, even though methods that return the +// tristate int can be declared in db_cxx.h . +// +#define ON_ERROR_THROW 1 +#define ON_ERROR_RETURN 0 +#define ON_ERROR_UNKNOWN (-1) + +// Macros that handle detected errors, in case we want to +// change the default behavior. The 'policy' is one of +// the tristate values given above. If UNKNOWN is specified, +// the behavior is taken from the last initialized DbEnv. +// +#define DB_ERROR(caller, ecode, policy) \ + DbEnv::runtime_error(caller, ecode, policy) + +// These defines are for tedious field set/get access methods. +// + +#define DB_RO_ACCESS(_class, _type, _cxx_name, _field) \ + \ +_type _class::get_##_cxx_name() const \ +{ \ + return (_field); \ +} + +#define DB_WO_ACCESS(_class, _type, _cxx_name, _field) \ + \ +void _class::set_##_cxx_name(_type value) \ +{ \ + _field = value; \ +} \ + +#define DB_RW_ACCESS(_class, _type, _cxx_name, _field) \ + DB_RO_ACCESS(_class, _type, _cxx_name, _field) \ + DB_WO_ACCESS(_class, _type, _cxx_name, _field) + +/* values for Db::flags_ */ +#define DB_CXX_PRIVATE_ENV 0x00000001 + +#endif /* !_CXX_INT_H_ */ diff --git a/db/include/db.src b/db/include/db.src new file mode 100644 index 000000000..6dc0071ef --- /dev/null +++ b/db/include/db.src @@ -0,0 +1,1375 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: db.src,v 11.121 2001/01/10 15:43:08 sue Exp $ + */ + +#ifndef _DB_H_ +#define _DB_H_ + +#ifndef __NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +/* + * XXX + * Handle function prototypes and the keyword "const". This steps on name + * space that DB doesn't control, but all of the other solutions are worse. + * + * XXX + * While Microsoft's compiler is ANSI C compliant, it doesn't have _STDC_ + * defined by default, you specify a command line flag or #pragma to turn + * it on. Don't do that, however, because some of Microsoft's own header + * files won't compile. + */ +#undef __P +#if defined(__STDC__) || defined(__cplusplus) || defined(_MSC_VER) +#define __P(protos) protos /* ANSI C prototypes */ +#else +#define const +#define __P(protos) () /* K&R C preprocessor */ +#endif + +/* + * !!! + * DB needs basic information about specifically sized types. If they're + * not provided by the system, typedef them here. + * + * We protect them against multiple inclusion using __BIT_TYPES_DEFINED__, + * as does BIND and Kerberos, since we don't know for sure what #include + * files the user is using. + * + * !!! + * We also provide the standard u_int, u_long etc., if they're not provided + * by the system. + */ +#ifndef __BIT_TYPES_DEFINED__ +#define __BIT_TYPES_DEFINED__ +@u_int8_decl@ +@int16_decl@ +@u_int16_decl@ +@int32_decl@ +@u_int32_decl@ +#endif + +@u_char_decl@ +@u_short_decl@ +@u_int_decl@ +@u_long_decl@ +@ssize_t_decl@ + +#define DB_VERSION_MAJOR @DB_VERSION_MAJOR@ +#define DB_VERSION_MINOR @DB_VERSION_MINOR@ +#define DB_VERSION_PATCH @DB_VERSION_PATCH@ +#define DB_VERSION_STRING @DB_VERSION_STRING@ + +typedef u_int32_t db_pgno_t; /* Page number type. */ +typedef u_int16_t db_indx_t; /* Page offset type. */ +#define DB_MAX_PAGES 0xffffffff /* >= # of pages in a file */ + +typedef u_int32_t db_recno_t; /* Record number type. */ +#define DB_MAX_RECORDS 0xffffffff /* >= # of records in a tree */ + +/* Forward structure declarations, so applications get type checking. */ +struct __db; typedef struct __db DB; +#ifdef DB_DBM_HSEARCH + typedef struct __db DBM; +#endif +struct __db_bt_stat; typedef struct __db_bt_stat DB_BTREE_STAT; +struct __db_dbt; typedef struct __db_dbt DBT; +struct __db_env; typedef struct __db_env DB_ENV; +struct __db_h_stat; typedef struct __db_h_stat DB_HASH_STAT; +struct __db_ilock; typedef struct __db_ilock DB_LOCK_ILOCK; +struct __db_lock_stat; typedef struct __db_lock_stat DB_LOCK_STAT; +struct __db_lock_u; typedef struct __db_lock_u DB_LOCK; +struct __db_lockreq; typedef struct __db_lockreq DB_LOCKREQ; +struct __db_log_stat; typedef struct __db_log_stat DB_LOG_STAT; +struct __db_lsn; typedef struct __db_lsn DB_LSN; +struct __db_mpool_finfo;typedef struct __db_mpool_finfo DB_MPOOL_FINFO; +struct __db_mpool_fstat;typedef struct __db_mpool_fstat DB_MPOOL_FSTAT; +struct __db_mpool_stat; typedef struct __db_mpool_stat DB_MPOOL_STAT; +struct __db_mpoolfile; typedef struct __db_mpoolfile DB_MPOOLFILE; +struct __db_qam_stat; typedef struct __db_qam_stat DB_QUEUE_STAT; +struct __db_txn; typedef struct __db_txn DB_TXN; +struct __db_txn_active; typedef struct __db_txn_active DB_TXN_ACTIVE; +struct __db_txn_stat; typedef struct __db_txn_stat DB_TXN_STAT; +struct __dbc; typedef struct __dbc DBC; +struct __dbc_internal; typedef struct __dbc_internal DBC_INTERNAL; +struct __fh_t; typedef struct __fh_t DB_FH; +struct __key_range; typedef struct __key_range DB_KEY_RANGE; + +/* Key/data structure -- a Data-Base Thang. */ +struct __db_dbt { + /* + * data/size must be fields 1 and 2 for DB 1.85 compatibility. + */ + void *data; /* Key/data */ + u_int32_t size; /* key/data length */ + + u_int32_t ulen; /* RO: length of user buffer. */ + u_int32_t dlen; /* RO: get/put record length. */ + u_int32_t doff; /* RO: get/put record offset. */ + +#define DB_DBT_ISSET 0x001 /* Lower level calls set value. */ +#define DB_DBT_MALLOC 0x002 /* Return in malloc'd memory. */ +#define DB_DBT_PARTIAL 0x004 /* Partial put/get. */ +#define DB_DBT_REALLOC 0x008 /* Return in realloc'd memory. */ +#define DB_DBT_USERMEM 0x010 /* Return in user's memory. */ +#define DB_DBT_DUPOK 0x020 /* Insert if duplicate. */ + u_int32_t flags; +}; + +/* + * Common flags -- + * Interfaces which use any of these common flags should never have + * interface specific flags in this range. + */ +#define DB_CREATE 0x000001 /* Create file as necessary. */ +#define DB_CXX_NO_EXCEPTIONS 0x000002 /* C++: return error values. */ +#define DB_FORCE 0x000004 /* Force (anything). */ +#define DB_NOMMAP 0x000008 /* Don't mmap underlying file. */ +#define DB_RDONLY 0x000010 /* Read-only (O_RDONLY). */ +#define DB_RECOVER 0x000020 /* Run normal recovery. */ +#define DB_THREAD 0x000040 /* Applications are threaded. */ +#define DB_TXN_NOSYNC 0x000080 /* Do not sync log on commit. */ +#define DB_USE_ENVIRON 0x000100 /* Use the environment. */ +#define DB_USE_ENVIRON_ROOT 0x000200 /* Use the environment if root. */ + +/* + * Flags private to db_env_create. + */ +#define DB_CLIENT 0x000400 /* Open for a client environment. */ + +/* + * Flags private to db_create. + */ +#define DB_XA_CREATE 0x000400 /* Open in an XA environment. */ + +/* + * Flags private to DBENV->open. + */ +#define DB_INIT_CDB 0x000400 /* Concurrent Access Methods. */ +#define DB_INIT_LOCK 0x000800 /* Initialize locking. */ +#define DB_INIT_LOG 0x001000 /* Initialize logging. */ +#define DB_INIT_MPOOL 0x002000 /* Initialize mpool. */ +#define DB_INIT_TXN 0x004000 /* Initialize transactions. */ +#define DB_JOINENV 0x008000 /* Initialize all subsystems present. */ +#define DB_LOCKDOWN 0x010000 /* Lock memory into physical core. */ +#define DB_PRIVATE 0x020000 /* DB_ENV is process local. */ +#define DB_RECOVER_FATAL 0x040000 /* Run catastrophic recovery. */ +#define DB_SYSTEM_MEM 0x080000 /* Use system-backed memory. */ + +/* + * Flags private to DB->open. + */ +#define DB_EXCL 0x000400 /* Exclusive open (O_EXCL). */ +#define DB_FCNTL_LOCKING 0x000800 /* UNDOC: fcntl(2) locking. */ +#define DB_ODDFILESIZE 0x001000 /* UNDOC: truncate to N * pgsize. */ +#define DB_RDWRMASTER 0x002000 /* UNDOC: allow subdb master open R/W */ +#define DB_TRUNCATE 0x004000 /* Discard existing DB (O_TRUNC). */ +#define DB_EXTENT 0x008000 /* UNDOC: dealing with an extent. */ + +/* + * Flags private to DBENV->txn_begin. + */ +#define DB_TXN_NOWAIT 0x000400 /* Do not wait for locks in this TXN. */ +#define DB_TXN_SYNC 0x000800 /* Always sync log on commit. */ + +/* + * Flags private to DBENV->set_flags. + */ +#define DB_CDB_ALLDB 0x000400 /* In CDB, lock across environment. */ + +/* + * Flags private to DB->set_feedback's callback. + */ +#define DB_UPGRADE 0x000400 /* Upgrading. */ +#define DB_VERIFY 0x000800 /* Verifying. */ + +/* + * Flags private to DB->set_flags. + * + * DB->set_flags does not share common flags and so values start at 0x01. + */ +#define DB_DUP 0x0001 /* Btree, Hash: duplicate keys. */ +#define DB_DUPSORT 0x0002 /* Btree, Hash: duplicate keys. */ +#define DB_RECNUM 0x0004 /* Btree: record numbers. */ +#define DB_RENUMBER 0x0008 /* Recno: renumber on insert/delete. */ +#define DB_REVSPLITOFF 0x0010 /* Btree: turn off reverse splits. */ +#define DB_SNAPSHOT 0x0020 /* Recno: snapshot the input. */ + +/* + * Flags private to DB->join. + * + * DB->join does not share common flags and so values start at 0x01. + */ +#define DB_JOIN_NOSORT 0x0001 /* Don't try to optimize join. */ + +/* + * Flags private to DB->verify. + * + * DB->verify does not share common flags and so values start at 0x01. + */ +#define DB_AGGRESSIVE 0x0001 /* Salvage anything which might be data.*/ +#define DB_NOORDERCHK 0x0002 /* Skip order check; subdb w/ user func */ +#define DB_ORDERCHKONLY 0x0004 /* Only perform an order check on subdb */ +#define DB_PR_PAGE 0x0008 /* Show page contents (-da). */ +#define DB_PR_HEADERS 0x0010 /* Show only page headers (-dh). */ +#define DB_PR_RECOVERYTEST 0x0020 /* Recovery test (-dr). */ +#define DB_SALVAGE 0x0040 /* Salvage what looks like data. */ +/* + * !!! + * These must not go over 0x8000, or they will collide with the flags + * used by __bam_vrfy_subtree. + */ +#define DB_VRFY_FLAGMASK 0xffff /* For masking above flags. */ + +/* + * Deadlock detector modes; used in the DBENV structure to configure the + * locking subsystem. + */ +#define DB_LOCK_NORUN 0 +#define DB_LOCK_DEFAULT 1 /* Default policy. */ +#define DB_LOCK_OLDEST 2 /* Abort oldest transaction. */ +#define DB_LOCK_RANDOM 3 /* Abort random transaction. */ +#define DB_LOCK_YOUNGEST 4 /* Abort youngest transaction. */ + +/******************************************************* + * Environment. + *******************************************************/ +#define DB_REGION_MAGIC 0x120897 /* Environment magic number. */ + +typedef enum { + DB_TXN_ABORT, + DB_TXN_BACKWARD_ROLL, + DB_TXN_FORWARD_ROLL, + DB_TXN_OPENFILES +} db_recops; + +#define DB_UNDO(op) ((op) == DB_TXN_ABORT || (op) == DB_TXN_BACKWARD_ROLL) +#define DB_REDO(op) ((op) == DB_TXN_FORWARD_ROLL) + +struct __db_env { + /******************************************************* + * Public: owned by the application. + *******************************************************/ + FILE *db_errfile; /* Error message file stream. */ + const char *db_errpfx; /* Error message prefix. */ + /* Callbacks. */ + void (*db_errcall) __P((const char *, char *)); + void (*db_feedback) __P((DB_ENV *, int, int)); + void (*db_paniccall) __P((DB_ENV *, int)); + int (*db_recovery_init) __P((DB_ENV *)); + + /* + * Currently, the verbose list is a bit field with room for 32 + * entries. There's no reason that it needs to be limited, if + * there are ever more than 32 entries, convert to a bit array. + */ +#define DB_VERB_CHKPOINT 0x0001 /* List checkpoints. */ +#define DB_VERB_DEADLOCK 0x0002 /* Deadlock detection information. */ +#define DB_VERB_RECOVERY 0x0004 /* Recovery information. */ +#define DB_VERB_WAITSFOR 0x0008 /* Dump waits-for table. */ + u_int32_t verbose; /* Verbose output. */ + + void *app_private; /* Application-private handle. */ + + /* Locking. */ + u_int8_t *lk_conflicts; /* Two dimensional conflict matrix. */ + u_int32_t lk_modes; /* Number of lock modes in table. */ + u_int32_t lk_max; /* Maximum number of locks. */ + u_int32_t lk_max_lockers;/* Maximum number of lockers. */ + u_int32_t lk_max_objects;/* Maximum number of locked objects. */ + u_int32_t lk_detect; /* Deadlock detect on all conflicts. */ + + /* Logging. */ + u_int32_t lg_bsize; /* Buffer size. */ + u_int32_t lg_max; /* Maximum file size. */ + + /* Memory pool. */ + u_int32_t mp_gbytes; /* Cachesize: GB. */ + u_int32_t mp_bytes; /* Cachesize: Bytes. */ + size_t mp_size; /* DEPRECATED: Cachesize: bytes. */ + int mp_ncache; /* Number of cache regions. */ + size_t mp_mmapsize; /* Maximum file size for mmap. */ + + /* Transactions. */ + u_int32_t tx_max; /* Maximum number of transactions. */ + time_t tx_timestamp; /* Recover to specific timestamp. */ + int (*tx_recover) /* Dispatch function for recovery. */ + __P((DB_ENV *, DBT *, DB_LSN *, db_recops)); + + /******************************************************* + * Private: owned by DB. + *******************************************************/ + int db_panic; /* Panic causing errno. */ + + /* User files, paths. */ + char *db_home; /* Database home. */ + char *db_log_dir; /* Database log file directory. */ + char *db_tmp_dir; /* Database tmp file directory. */ + + char **db_data_dir; /* Database data file directories. */ + int data_cnt; /* Database data file slots. */ + int data_next; /* Next Database data file slot. */ + + int db_mode; /* Default open permissions. */ + + void *reginfo; /* REGINFO structure reference. */ + DB_FH *lockfhp; /* fcntl(2) locking file handle. */ + long shm_key; /* shmget(2) key. */ + + void *lg_handle; /* Log handle. */ + + void *lk_handle; /* Lock handle. */ + + void *mp_handle; /* Mpool handle. */ + + void *tx_handle; /* Txn handle. */ + + int (**dtab) /* Dispatch table */ + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + size_t dtab_size; /* Slots in the dispatch table. */ + + void *cl_handle; /* RPC: remote client handle. */ + long cl_id; /* RPC: Remote client env id. */ + + int dblocal_ref; /* DB_ENV_DBLOCAL: reference count. */ + u_int32_t db_mutexlocks; /* db_set_mutexlocks */ + + /* + * List of open DB handles for this DB_ENV, used for cursor + * adjustment. Must be protected for multi-threaded support. + * + * !!! + * As this structure is allocated in per-process memory, the + * mutex may need to be stored elsewhere on architectures unable + * to support mutexes in heap memory, e.g. HP/UX 9. + */ + void *dblist_mutexp; /* Mutex. */ + /* + * !!! + * Explicit representation of structure in queue.h. + * LIST_HEAD(dblist, __db); + */ + struct { + struct __db *lh_first; + } dblist; + + /* + * XA support. + * + * !!! + * Explicit representations of structures in queue.h. + * + * TAILQ_ENTRY(__db_env); + */ + struct { + struct __db_env *tqe_next; + struct __db_env **tqe_prev; + } links; + int xa_rmid; /* XA Resource Manager ID. */ + DB_TXN *xa_txn; /* XA Current transaction. */ + + void *cj_internal; /* C++/Java private. */ + + /* Methods. */ + int (*close) __P((DB_ENV *, u_int32_t)); + void (*err) __P((const DB_ENV *, int, const char *, ...)); + void (*errx) __P((const DB_ENV *, const char *, ...)); + int (*open) __P((DB_ENV *, const char *, u_int32_t, int)); + int (*remove) __P((DB_ENV *, const char *, u_int32_t)); + int (*set_data_dir) __P((DB_ENV *, const char *)); + void (*set_errcall) __P((DB_ENV *, void (*)(const char *, char *))); + void (*set_errfile) __P((DB_ENV *, FILE *)); + void (*set_errpfx) __P((DB_ENV *, const char *)); + int (*set_feedback) __P((DB_ENV *, void (*)(DB_ENV *, int, int))); + int (*set_flags) __P((DB_ENV *, u_int32_t, int)); + int (*set_mutexlocks) __P((DB_ENV *, int)); + int (*set_paniccall) __P((DB_ENV *, void (*)(DB_ENV *, int))); + int (*set_recovery_init) __P((DB_ENV *, int (*)(DB_ENV *))); + int (*set_server) __P((DB_ENV *, char *, long, long, u_int32_t)); + int (*set_shm_key) __P((DB_ENV *, long)); + int (*set_tmp_dir) __P((DB_ENV *, const char *)); + int (*set_verbose) __P((DB_ENV *, u_int32_t, int)); + + int (*set_lg_bsize) __P((DB_ENV *, u_int32_t)); + int (*set_lg_dir) __P((DB_ENV *, const char *)); + int (*set_lg_max) __P((DB_ENV *, u_int32_t)); + + int (*set_lk_conflicts) __P((DB_ENV *, u_int8_t *, int)); + int (*set_lk_detect) __P((DB_ENV *, u_int32_t)); + int (*set_lk_max) __P((DB_ENV *, u_int32_t)); + int (*set_lk_max_locks) __P((DB_ENV *, u_int32_t)); + int (*set_lk_max_lockers) __P((DB_ENV *, u_int32_t)); + int (*set_lk_max_objects) __P((DB_ENV *, u_int32_t)); + + int (*set_mp_mmapsize) __P((DB_ENV *, size_t)); + int (*set_cachesize) __P((DB_ENV *, u_int32_t, u_int32_t, int)); + + int (*set_tx_max) __P((DB_ENV *, u_int32_t)); + int (*set_tx_recover) __P((DB_ENV *, + int (*)(DB_ENV *, DBT *, DB_LSN *, db_recops))); + int (*set_tx_timestamp) __P((DB_ENV *, time_t *)); + +#ifdef CONFIG_TEST +#define DB_TEST_PREOPEN 1 /* before __os_open */ +#define DB_TEST_POSTOPEN 2 /* after __os_open */ +#define DB_TEST_POSTLOGMETA 3 /* after logging meta in btree */ +#define DB_TEST_POSTLOG 4 /* after logging all pages */ +#define DB_TEST_POSTSYNC 5 /* after syncing the log */ +#define DB_TEST_PRERENAME 6 /* before __os_rename */ +#define DB_TEST_POSTRENAME 7 /* after __os_rename */ + int test_abort; /* Abort value for testing. */ + int test_copy; /* Copy value for testing. */ +#endif + +#define DB_ENV_CDB 0x00001 /* DB_INIT_CDB. */ +#define DB_ENV_CDB_ALLDB 0x00002 /* CDB environment wide locking. */ +#define DB_ENV_CREATE 0x00004 /* DB_CREATE set. */ +#define DB_ENV_DBLOCAL 0x00008 /* DB_ENV allocated for private DB. */ +#define DB_ENV_LOCKDOWN 0x00010 /* DB_LOCKDOWN set. */ +#define DB_ENV_NOMMAP 0x00020 /* DB_NOMMAP set. */ +#define DB_ENV_OPEN_CALLED 0x00040 /* DBENV->open called (paths valid). */ +#define DB_ENV_PRIVATE 0x00080 /* DB_PRIVATE set. */ +#define DB_ENV_RPCCLIENT 0x00100 /* DB_CLIENT set. */ +#define DB_ENV_STANDALONE 0x00200 /* Test: freestanding environment. */ +#define DB_ENV_SYSTEM_MEM 0x00400 /* DB_SYSTEM_MEM set. */ +#define DB_ENV_THREAD 0x00800 /* DB_THREAD set. */ +#define DB_ENV_TXN_NOSYNC 0x01000 /* DB_TXN_NOSYNC set. */ +#define DB_ENV_USER_ALLOC 0x02000 /* User allocated the structure. */ + u_int32_t flags; /* Flags. */ +}; + +/******************************************************* + * Access methods. + *******************************************************/ +/* + * !!! + * Changes here must be reflected in java/src/com/sleepycat/db/Db.java. + */ +typedef enum { + DB_BTREE=1, + DB_HASH, + DB_RECNO, + DB_QUEUE, + DB_UNKNOWN /* Figure it out on open. */ +} DBTYPE; + +#define DB_BTREEVERSION 8 /* Current btree version. */ +#define DB_BTREEOLDVER 6 /* Oldest btree version supported. */ +#define DB_BTREEMAGIC 0x053162 + +#define DB_HASHVERSION 7 /* Current hash version. */ +#define DB_HASHOLDVER 4 /* Oldest hash version supported. */ +#define DB_HASHMAGIC 0x061561 + +#define DB_QAMVERSION 3 /* Current queue version. */ +#define DB_QAMOLDVER 1 /* Oldest queue version supported. */ +#define DB_QAMMAGIC 0x042253 + +#define DB_LOGVERSION 3 /* Current log version. */ +#define DB_LOGOLDVER 3 /* Oldest log version supported. */ +#define DB_LOGMAGIC 0x040988 + +/* + * DB access method and cursor operation values. Each value is an operation + * code to which additional bit flags are added. + */ +#define DB_AFTER 1 /* c_put() */ +#define DB_APPEND 2 /* put() */ +#define DB_BEFORE 3 /* c_put() */ +#define DB_CACHED_COUNTS 4 /* stat() */ +#define DB_CHECKPOINT 5 /* log_put(), log_get() */ +#define DB_CONSUME 6 /* get() */ +#define DB_CONSUME_WAIT 7 /* get() */ +#define DB_CURLSN 8 /* log_put() */ +#define DB_CURRENT 9 /* c_get(), c_put(), log_get() */ +#define DB_FIRST 10 /* c_get(), log_get() */ +#define DB_FLUSH 11 /* log_put() */ +#define DB_GET_BOTH 12 /* get(), c_get() */ +#define DB_GET_BOTHC 13 /* c_get() (internal) */ +#define DB_GET_RECNO 14 /* c_get() */ +#define DB_JOIN_ITEM 15 /* c_get(); do not do primary lookup */ +#define DB_KEYFIRST 16 /* c_put() */ +#define DB_KEYLAST 17 /* c_put() */ +#define DB_LAST 18 /* c_get(), log_get() */ +#define DB_NEXT 19 /* c_get(), log_get() */ +#define DB_NEXT_DUP 20 /* c_get() */ +#define DB_NEXT_NODUP 21 /* c_get() */ +#define DB_NODUPDATA 22 /* put(), c_put() */ +#define DB_NOOVERWRITE 23 /* put() */ +#define DB_NOSYNC 24 /* close() */ +#define DB_POSITION 25 /* c_dup() */ +#define DB_POSITIONI 26 /* c_dup() (internal) */ +#define DB_PREV 27 /* c_get(), log_get() */ +#define DB_PREV_NODUP 28 /* c_get(), log_get() */ +#define DB_RECORDCOUNT 29 /* stat() */ +#define DB_SET 30 /* c_get(), log_get() */ +#define DB_SET_RANGE 31 /* c_get() */ +#define DB_SET_RECNO 32 /* get(), c_get() */ +#define DB_WRITECURSOR 33 /* cursor() */ +#define DB_WRITELOCK 34 /* cursor() (internal) */ + +/* This has to change when the max opcode hits 255. */ +#define DB_OPFLAGS_MASK 0x000000ff /* Mask for operations flags. */ +#define DB_RMW 0x80000000 /* Acquire write flag immediately. */ + +/* + * DB (user visible) error return codes. + * + * !!! + * Changes to any of the user visible error return codes must be reflected + * in java/src/com/sleepycat/db/Db.java. + * + * !!! + * For source compatibility with DB 2.X deadlock return (EAGAIN), use the + * following: + * #include + * #define DB_LOCK_DEADLOCK EAGAIN + * + * !!! + * We don't want our error returns to conflict with other packages where + * possible, so pick a base error value that's hopefully not common. We + * document that we own the error name space from -30,800 to -30,999. + */ +/* Public error return codes. */ +#define DB_INCOMPLETE (-30999)/* Sync didn't finish. */ +#define DB_KEYEMPTY (-30998)/* Key/data deleted or never created. */ +#define DB_KEYEXIST (-30997)/* The key/data pair already exists. */ +#define DB_LOCK_DEADLOCK (-30996)/* Deadlock. */ +#define DB_LOCK_NOTGRANTED (-30995)/* Lock unavailable. */ +#define DB_NOSERVER (-30994)/* Server panic return. */ +#define DB_NOSERVER_HOME (-30993)/* Bad home sent to server. */ +#define DB_NOSERVER_ID (-30992)/* Bad ID sent to server. */ +#define DB_NOTFOUND (-30991)/* Key/data pair not found (EOF). */ +#define DB_OLD_VERSION (-30990)/* Out-of-date version. */ +#define DB_RUNRECOVERY (-30989)/* Panic return. */ +#define DB_VERIFY_BAD (-30988)/* Verify failed; bad format. */ + +/* DB (private) error return codes. */ +#define DB_ALREADY_ABORTED (-30899) +#define DB_DELETED (-30898)/* Recovery file marked deleted. */ +#define DB_JAVA_CALLBACK (-30897)/* Exception during a java callback. */ +#define DB_NEEDSPLIT (-30896)/* Page needs to be split. */ +#define DB_SWAPBYTES (-30895)/* Database needs byte swapping. */ +#define DB_TXN_CKP (-30894)/* Encountered ckp record in log. */ +#define DB_VERIFY_FATAL (-30893)/* Fatal: DB->verify cannot proceed. */ + +#define DB_FILE_ID_LEN 20 /* DB file ID length. */ + +/* DB access method description structure. */ +struct __db { + /******************************************************* + * Public: owned by the application. + *******************************************************/ + u_int32_t pgsize; /* Database logical page size. */ + + /* Callbacks. */ + int (*db_append_recno) __P((DB *, DBT *, db_recno_t)); + void (*db_feedback) __P((DB *, int, int)); + void *(*db_malloc) __P((size_t)); + void *(*db_realloc) __P((void *, size_t)); + int (*dup_compare) __P((DB *, const DBT *, const DBT *)); + + void *app_private; /* Application-private handle. */ + + /******************************************************* + * Private: owned by DB. + *******************************************************/ + DB_ENV *dbenv; /* Backing environment. */ + + DBTYPE type; /* DB access method type. */ + + DB_MPOOLFILE *mpf; /* Backing buffer pool. */ + + void *mutexp; /* Synchronization for free threading */ + + u_int8_t fileid[DB_FILE_ID_LEN];/* File's unique ID for locking. */ + + u_int32_t adj_fileid; /* File's unique ID for curs. adj. */ + +#define DB_LOGFILEID_INVALID -1 + int32_t log_fileid; /* File's unique ID for logging. */ + db_pgno_t meta_pgno; /* Meta page number */ + DB_TXN *open_txn; /* Transaction to protect creates. */ + + long cl_id; /* RPC: remote client id. */ + + /* + * !!! + * Some applications use DB but implement their own locking outside of + * DB. If they're using fcntl(2) locking on the underlying database + * file, and we open and close a file descriptor for that file, we will + * discard their locks. The DB_FCNTL_LOCKING flag to DB->open is an + * undocumented interface to support this usage which leaves any file + * descriptors we open until DB->close. This will only work with the + * DB->open interface and simple caches, e.g., creating a transaction + * thread may open/close file descriptors this flag doesn't protect. + * Locking with fcntl(2) on a file that you don't own is a very, very + * unsafe thing to do. 'Nuff said. + */ + DB_FH *saved_open_fhp; /* Saved file handle. */ + + /* + * Linked list of DBP's, used in the log's dbentry table + * to keep track of all open db handles for a given log id. + * !!! + * Explicit representations of structures in queue.h. + * + * TAILQ_ENTRY(__db) links; + */ + struct { + struct __db *tqe_next; + struct __db **tqe_prev; + } links; + + /* + * Linked list of DBP's, linked from the DB_ENV, used to + * keep track of all open db handles for cursor adjustment. + * + * XXX + * Eventually, this should be merged with "links" above. + * + * !!! + * Explicit representations of structures in queue.h. + * + * LIST_ENTRY(__db) dblistlinks; + */ + struct { + struct __db *le_next; + struct __db **le_prev; + } dblistlinks; + + /* + * Cursor queues. + * + * !!! + * Explicit representations of structures in queue.h. + * + * TAILQ_HEAD(free_queue, __dbc); + * TAILQ_HEAD(active_queue, __dbc); + * TAILQ_HEAD(join_queue, __dbc); + */ + struct { + struct __dbc *tqh_first; + struct __dbc **tqh_last; + } free_queue; + struct { + struct __dbc *tqh_first; + struct __dbc **tqh_last; + } active_queue; + struct { + struct __dbc *tqh_first; + struct __dbc **tqh_last; + } join_queue; + + void *bt_internal; /* Btree/Recno access method private. */ + void *cj_internal; /* C++/Java private. */ + void *h_internal; /* Hash access method private. */ + void *q_internal; /* Queue access method private. */ + void *xa_internal; /* XA private. */ + + /* Methods. */ + int (*close) __P((DB *, u_int32_t)); + int (*cursor) __P((DB *, DB_TXN *, DBC **, u_int32_t)); + int (*del) __P((DB *, DB_TXN *, DBT *, u_int32_t)); + void (*err) __P((DB *, int, const char *, ...)); + void (*errx) __P((DB *, const char *, ...)); + int (*fd) __P((DB *, int *)); + int (*get) __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t)); + int (*get_byteswapped) __P((DB *)); + DBTYPE + (*get_type) __P((DB *)); + int (*join) __P((DB *, DBC **, DBC **, u_int32_t)); + int (*key_range) __P((DB *, + DB_TXN *, DBT *, DB_KEY_RANGE *, u_int32_t)); + int (*open) __P((DB *, + const char *, const char *, DBTYPE, u_int32_t, int)); + int (*put) __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t)); + int (*remove) __P((DB *, const char *, const char *, u_int32_t)); + int (*rename) __P((DB *, + const char *, const char *, const char *, u_int32_t)); + int (*set_append_recno) __P((DB *, int (*)(DB *, DBT *, db_recno_t))); + int (*set_cachesize) __P((DB *, u_int32_t, u_int32_t, int)); + int (*set_dup_compare) __P((DB *, + int (*)(DB *, const DBT *, const DBT *))); + void (*set_errcall) __P((DB *, void (*)(const char *, char *))); + void (*set_errfile) __P((DB *, FILE *)); + void (*set_errpfx) __P((DB *, const char *)); + int (*set_feedback) __P((DB *, void (*)(DB *, int, int))); + int (*set_flags) __P((DB *, u_int32_t)); + int (*set_lorder) __P((DB *, int)); + int (*set_malloc) __P((DB *, void *(*)(size_t))); + int (*set_pagesize) __P((DB *, u_int32_t)); + int (*set_paniccall) __P((DB *, void (*)(DB_ENV *, int))); + int (*set_realloc) __P((DB *, void *(*)(void *, size_t))); + int (*stat) __P((DB *, void *, void *(*)(size_t), u_int32_t)); + int (*sync) __P((DB *, u_int32_t)); + int (*upgrade) __P((DB *, const char *, u_int32_t)); + int (*verify) __P((DB *, + const char *, const char *, FILE *, u_int32_t)); + + int (*set_bt_compare) __P((DB *, + int (*)(DB *, const DBT *, const DBT *))); + int (*set_bt_maxkey) __P((DB *, u_int32_t)); + int (*set_bt_minkey) __P((DB *, u_int32_t)); + int (*set_bt_prefix) __P((DB *, + size_t (*)(DB *, const DBT *, const DBT *))); + + int (*set_h_ffactor) __P((DB *, u_int32_t)); + int (*set_h_hash) __P((DB *, + u_int32_t (*)(DB *, const void *, u_int32_t))); + int (*set_h_nelem) __P((DB *, u_int32_t)); + + int (*set_re_delim) __P((DB *, int)); + int (*set_re_len) __P((DB *, u_int32_t)); + int (*set_re_pad) __P((DB *, int)); + int (*set_re_source) __P((DB *, const char *)); + int (*set_q_extentsize) __P((DB *, u_int32_t)); + + int (*db_am_remove) __P((DB *, const char *, + const char *, DB_LSN *, int (**)(DB *, void*), void **)); + int (*db_am_rename) __P((DB *, + const char *, const char *, const char *)); + +#define DB_OK_BTREE 0x01 +#define DB_OK_HASH 0x02 +#define DB_OK_QUEUE 0x04 +#define DB_OK_RECNO 0x08 + u_int32_t am_ok; /* Legal AM choices. */ + +#define DB_AM_DISCARD 0x00001 /* Discard any cached pages. */ +#define DB_AM_DUP 0x00002 /* DB_DUP. */ +#define DB_AM_DUPSORT 0x00004 /* DB_DUPSORT. */ +#define DB_AM_INMEM 0x00008 /* In-memory; no sync on close. */ +#define DB_AM_PGDEF 0x00010 /* Page size was defaulted. */ +#define DB_AM_RDONLY 0x00020 /* Database is readonly. */ +#define DB_AM_RECOVER 0x00040 /* DBP opened by recovery routine. */ +#define DB_AM_SUBDB 0x00080 /* Subdatabases supported. */ +#define DB_AM_SWAP 0x00100 /* Pages need to be byte-swapped. */ +#define DB_AM_TXN 0x00200 /* DBP was in a transaction. */ +#define DB_AM_VERIFYING 0x00400 /* DB handle is in the verifier. */ +#define DB_BT_RECNUM 0x00800 /* DB_RECNUM. */ +#define DB_BT_REVSPLIT 0x01000 /* DB_REVSPLITOFF. */ +#define DB_DBM_ERROR 0x02000 /* Error in DBM/NDBM database. */ +#define DB_OPEN_CALLED 0x04000 /* DB->open called. */ +#define DB_RE_DELIMITER 0x08000 /* Variablen length delimiter set. */ +#define DB_RE_FIXEDLEN 0x10000 /* Fixed-length records. */ +#define DB_RE_PAD 0x20000 /* Fixed-length record pad. */ +#define DB_RE_RENUMBER 0x40000 /* DB_RENUMBER. */ +#define DB_RE_SNAPSHOT 0x80000 /* DB_SNAPSHOT. */ + u_int32_t flags; +}; + +/* + * DB_LOCK_ILOCK -- + * Internal DB access method lock. + */ +struct __db_ilock { + db_pgno_t pgno; /* Page being locked. */ + u_int8_t fileid[DB_FILE_ID_LEN];/* File id. */ +#define DB_RECORD_LOCK 1 +#define DB_PAGE_LOCK 2 + u_int8_t type; /* Record or Page lock */ +}; + +/* + * DB_LOCK -- + * The structure is allocated by the caller and filled in during a + * lock_get request (or a lock_vec/DB_LOCK_GET). + */ +struct __db_lock_u { + size_t off; /* Offset of the lock in the region */ + u_int32_t ndx; /* Index of the object referenced by + * this lock; used for locking. */ + u_int32_t gen; /* Generation number of this lock. */ +}; + +/* Cursor description structure. */ +struct __dbc { + DB *dbp; /* Related DB access method. */ + DB_TXN *txn; /* Associated transaction. */ + + /* + * !!! + * Explicit representations of structures in queue.h. + * + * TAILQ_ENTRY(__dbc) links; Active/free cursor queues. + */ + struct { + DBC *tqe_next; + DBC **tqe_prev; + } links; + + DBT rkey; /* Returned key. */ + DBT rdata; /* Returned data. */ + + u_int32_t lid; /* Default process' locker id. */ + u_int32_t locker; /* Locker for this operation. */ + DBT lock_dbt; /* DBT referencing lock. */ + DB_LOCK_ILOCK lock; /* Object to be locked. */ + DB_LOCK mylock; /* Lock held on this cursor. */ + + long cl_id; /* Remote client id. */ + + DBTYPE dbtype; /* Cursor type. */ + + DBC_INTERNAL *internal; /* Access method private. */ + + int (*c_close) __P((DBC *)); /* Methods: public. */ + int (*c_count) __P((DBC *, db_recno_t *, u_int32_t)); + int (*c_del) __P((DBC *, u_int32_t)); + int (*c_dup) __P((DBC *, DBC **, u_int32_t)); + int (*c_get) __P((DBC *, DBT *, DBT *, u_int32_t)); + int (*c_put) __P((DBC *, DBT *, DBT *, u_int32_t)); + + /* Methods: private. */ + int (*c_am_close) __P((DBC *, db_pgno_t, int *)); + int (*c_am_del) __P((DBC *)); + int (*c_am_destroy) __P((DBC *)); + int (*c_am_get) __P((DBC *, DBT *, DBT *, u_int32_t, db_pgno_t *)); + int (*c_am_put) __P((DBC *, DBT *, DBT *, u_int32_t, db_pgno_t *)); + int (*c_am_writelock) __P((DBC *)); + +#define DBC_ACTIVE 0x001 /* Cursor is being used. */ +#define DBC_OPD 0x002 /* Cursor references off-page dups. */ +#define DBC_RECOVER 0x004 /* Cursor created by recovery routine + * (do not log or lock). + */ +#define DBC_RMW 0x008 /* Acquire write flag in read op. */ +#define DBC_WRITECURSOR 0x010 /* Cursor may be used to write (CDB). */ +#define DBC_WRITEDUP 0x020 /* idup'ed DBC_WRITECURSOR (CDB). */ +#define DBC_WRITER 0x040 /* Cursor immediately writing (CDB). */ +#define DBC_TRANSIENT 0x080 /* Cursor is transient. */ +#define DBC_COMPENSATE 0x100 /* Cursor is doing compensation + * do not lock. + */ + u_int32_t flags; +}; + +/* Key range statistics structure */ +struct __key_range { + double less; + double equal; + double greater; +}; + +/* Btree/Recno statistics structure. */ +struct __db_bt_stat { + u_int32_t bt_magic; /* Magic number. */ + u_int32_t bt_version; /* Version number. */ + u_int32_t bt_metaflags; /* Metadata flags. */ + u_int32_t bt_nkeys; /* Number of unique keys. */ + u_int32_t bt_ndata; /* Number of data items. */ + u_int32_t bt_pagesize; /* Page size. */ + u_int32_t bt_maxkey; /* Maxkey value. */ + u_int32_t bt_minkey; /* Minkey value. */ + u_int32_t bt_re_len; /* Fixed-length record length. */ + u_int32_t bt_re_pad; /* Fixed-length record pad. */ + u_int32_t bt_levels; /* Tree levels. */ + u_int32_t bt_int_pg; /* Internal pages. */ + u_int32_t bt_leaf_pg; /* Leaf pages. */ + u_int32_t bt_dup_pg; /* Duplicate pages. */ + u_int32_t bt_over_pg; /* Overflow pages. */ + u_int32_t bt_free; /* Pages on the free list. */ + u_int32_t bt_int_pgfree; /* Bytes free in internal pages. */ + u_int32_t bt_leaf_pgfree; /* Bytes free in leaf pages. */ + u_int32_t bt_dup_pgfree; /* Bytes free in duplicate pages. */ + u_int32_t bt_over_pgfree; /* Bytes free in overflow pages. */ +}; + +/* Queue statistics structure. */ +struct __db_qam_stat { + u_int32_t qs_magic; /* Magic number. */ + u_int32_t qs_version; /* Version number. */ + u_int32_t qs_metaflags; /* Metadata flags. */ + u_int32_t qs_nkeys; /* Number of unique keys. */ + u_int32_t qs_ndata; /* Number of data items. */ + u_int32_t qs_pagesize; /* Page size. */ + u_int32_t qs_pages; /* Data pages. */ + u_int32_t qs_re_len; /* Fixed-length record length. */ + u_int32_t qs_re_pad; /* Fixed-length record pad. */ + u_int32_t qs_pgfree; /* Bytes free in data pages. */ + u_int32_t qs_first_recno; /* First not deleted record. */ + u_int32_t qs_cur_recno; /* Last allocated record number. */ +}; + +/* Hash statistics structure. */ +struct __db_h_stat { + u_int32_t hash_magic; /* Magic number. */ + u_int32_t hash_version; /* Version number. */ + u_int32_t hash_metaflags; /* Metadata flags. */ + u_int32_t hash_nkeys; /* Number of unique keys. */ + u_int32_t hash_ndata; /* Number of data items. */ + u_int32_t hash_pagesize; /* Page size. */ + u_int32_t hash_nelem; /* Original nelem specified. */ + u_int32_t hash_ffactor; /* Fill factor specified at create. */ + u_int32_t hash_buckets; /* Number of hash buckets. */ + u_int32_t hash_free; /* Pages on the free list. */ + u_int32_t hash_bfree; /* Bytes free on bucket pages. */ + u_int32_t hash_bigpages; /* Number of big key/data pages. */ + u_int32_t hash_big_bfree; /* Bytes free on big item pages. */ + u_int32_t hash_overflows; /* Number of overflow pages. */ + u_int32_t hash_ovfl_free; /* Bytes free on ovfl pages. */ + u_int32_t hash_dup; /* Number of dup pages. */ + u_int32_t hash_dup_free; /* Bytes free on duplicate pages. */ +}; + +int db_create __P((DB **, DB_ENV *, u_int32_t)); +int db_env_create __P((DB_ENV **, u_int32_t)); +int db_env_set_func_close __P((int (*)(int))); +int db_env_set_func_dirfree __P((void (*)(char **, int))); +int db_env_set_func_dirlist __P((int (*)(const char *, char ***, int *))); +int db_env_set_func_exists __P((int (*)(const char *, int *))); +int db_env_set_func_free __P((void (*)(void *))); +int db_env_set_func_fsync __P((int (*)(int))); +int db_env_set_func_ioinfo __P((int (*)(const char *, + int, u_int32_t *, u_int32_t *, u_int32_t *))); +int db_env_set_func_malloc __P((void *(*)(size_t))); +int db_env_set_func_map __P((int (*)(char *, size_t, int, int, void **))); +int db_env_set_func_open __P((int (*)(const char *, int, ...))); +int db_env_set_func_read __P((ssize_t (*)(int, void *, size_t))); +int db_env_set_func_realloc __P((void *(*)(void *, size_t))); +int db_env_set_func_rename __P((int (*)(const char *, const char *))); +int db_env_set_func_seek + __P((int (*)(int, size_t, db_pgno_t, u_int32_t, int, int))); +int db_env_set_func_sleep __P((int (*)(u_long, u_long))); +int db_env_set_func_unlink __P((int (*)(const char *))); +int db_env_set_func_unmap __P((int (*)(void *, size_t))); +int db_env_set_func_write __P((ssize_t (*)(int, const void *, size_t))); +int db_env_set_func_yield __P((int (*)(void))); +int db_env_set_pageyield __P((int)); +int db_env_set_panicstate __P((int)); +int db_env_set_region_init __P((int)); +int db_env_set_tas_spins __P((u_int32_t)); +char *db_strerror __P((int)); +char *db_version __P((int *, int *, int *)); + +/******************************************************* + * Locking + *******************************************************/ +#define DB_LOCKVERSION 1 + +/* Flag values for lock_vec(), lock_get(). */ +#define DB_LOCK_NOWAIT 0x01 /* Don't wait on unavailable lock. */ +#define DB_LOCK_RECORD 0x02 /* Internal: record lock. */ +#define DB_LOCK_UPGRADE 0x04 /* Internal: upgrade existing lock. */ +#define DB_LOCK_SWITCH 0x08 /* Internal: switch existing lock. */ + +/* Flag values for lock_detect(). */ +#define DB_LOCK_CONFLICT 0x01 /* Run on any conflict. */ + +/* + * Request types. + * + * !!! + * Changes here must be reflected in java/src/com/sleepycat/db/Db.java. + */ +typedef enum { + DB_LOCK_DUMP=0, /* Display held locks. */ + DB_LOCK_GET, /* Get the lock. */ + DB_LOCK_INHERIT, /* Pass locks to parent. */ + DB_LOCK_PUT, /* Release the lock. */ + DB_LOCK_PUT_ALL, /* Release locker's locks. */ + DB_LOCK_PUT_OBJ /* Release locker's locks on obj. */ +} db_lockop_t; + +/* + * Simple R/W lock modes and for multi-granularity intention locking. + * + * !!! + * These values are NOT random, as they are used as an index into the lock + * conflicts arrays, i.e., DB_LOCK_IWRITE must be == 3, and DB_LOCK_IREAD + * must be == 4. + * + * !!! + * Changes here must be reflected in java/src/com/sleepycat/db/Db.java. + */ +typedef enum { + DB_LOCK_NG=0, /* Not granted. */ + DB_LOCK_READ, /* Shared/read. */ + DB_LOCK_WRITE, /* Exclusive/write. */ + DB_LOCK_WAIT, /* Wait for event */ + DB_LOCK_IWRITE, /* Intent exclusive/write. */ + DB_LOCK_IREAD, /* Intent to share/read. */ + DB_LOCK_IWR /* Intent to read and write. */ +} db_lockmode_t; + +/* + * Status of a lock. + */ +typedef enum { + DB_LSTAT_ABORTED, /* Lock belongs to an aborted txn. */ + DB_LSTAT_ERR, /* Lock is bad. */ + DB_LSTAT_FREE, /* Lock is unallocated. */ + DB_LSTAT_HELD, /* Lock is currently held. */ + DB_LSTAT_NOGRANT, /* Lock was not granted. */ + DB_LSTAT_PENDING, /* Lock was waiting and has been + * promoted; waiting for the owner + * to run and upgrade it to held. */ + DB_LSTAT_WAITING /* Lock is on the wait queue. */ +} db_status_t; + +/* Lock request structure. */ +struct __db_lockreq { + db_lockop_t op; /* Operation. */ + db_lockmode_t mode; /* Requested mode. */ + u_int32_t locker; /* Locker identity. */ + DBT *obj; /* Object being locked. */ + DB_LOCK lock; /* Lock returned. */ +}; + +/* + * Commonly used conflict matrices. + * + */ + +/* Multi-granularity locking. */ +#define DB_LOCK_RIW_N 7 +extern const u_int8_t db_riw_conflicts[]; + +struct __db_lock_stat { + u_int32_t st_lastid; /* Last allocated locker ID. */ + u_int32_t st_maxlocks; /* Maximum number of locks in table. */ + u_int32_t st_maxlockers; /* Maximum number of lockers in table. */ + u_int32_t st_maxobjects; /* Maximum number of objects in table. */ + u_int32_t st_nmodes; /* Number of lock modes. */ + u_int32_t st_nlocks; /* Current number of locks. */ + u_int32_t st_maxnlocks; /* Maximum number of locks so far. */ + u_int32_t st_nlockers; /* Current number of lockers. */ + u_int32_t st_maxnlockers; /* Maximum number of lockers so far. */ + u_int32_t st_nobjects; /* Current number of objects. */ + u_int32_t st_maxnobjects; /* Maximum number of objects so far. */ + u_int32_t st_nconflicts; /* Number of lock conflicts. */ + u_int32_t st_nrequests; /* Number of lock gets. */ + u_int32_t st_nreleases; /* Number of lock puts. */ + u_int32_t st_nnowaits; /* Number of requests that would have + waited, but NOWAIT was set. */ + u_int32_t st_ndeadlocks; /* Number of lock deadlocks. */ + u_int32_t st_region_wait; /* Region lock granted after wait. */ + u_int32_t st_region_nowait; /* Region lock granted without wait. */ + u_int32_t st_regsize; /* Region size. */ +}; + +int lock_detect __P((DB_ENV *, u_int32_t, u_int32_t, int *)); +int lock_get __P((DB_ENV *, + u_int32_t, u_int32_t, const DBT *, db_lockmode_t, DB_LOCK *)); +int lock_id __P((DB_ENV *, u_int32_t *)); +int lock_put __P((DB_ENV *, DB_LOCK *)); +int lock_stat __P((DB_ENV *, DB_LOCK_STAT **, void *(*)(size_t))); +int lock_vec __P((DB_ENV *, + u_int32_t, u_int32_t, DB_LOCKREQ *, int, DB_LOCKREQ **)); + +/******************************************************* + * Logging. + *******************************************************/ +/* Flag values for log_archive(). */ +#define DB_ARCH_ABS 0x001 /* Absolute pathnames. */ +#define DB_ARCH_DATA 0x002 /* Data files. */ +#define DB_ARCH_LOG 0x004 /* Log files. */ + +/* + * A DB_LSN has two parts, a fileid which identifies a specific file, and an + * offset within that file. The fileid is an unsigned 4-byte quantity that + * uniquely identifies a file within the log directory -- currently a simple + * counter inside the log. The offset is also an unsigned 4-byte value. The + * log manager guarantees the offset is never more than 4 bytes by switching + * to a new log file before the maximum length imposed by an unsigned 4-byte + * offset is reached. + */ +struct __db_lsn { + u_int32_t file; /* File ID. */ + u_int32_t offset; /* File offset. */ +}; + +/* Log statistics structure. */ +struct __db_log_stat { + u_int32_t st_magic; /* Log file magic number. */ + u_int32_t st_version; /* Log file version number. */ + int st_mode; /* Log file mode. */ + u_int32_t st_lg_bsize; /* Log buffer size. */ + u_int32_t st_lg_max; /* Maximum log file size. */ + u_int32_t st_w_bytes; /* Bytes to log. */ + u_int32_t st_w_mbytes; /* Megabytes to log. */ + u_int32_t st_wc_bytes; /* Bytes to log since checkpoint. */ + u_int32_t st_wc_mbytes; /* Megabytes to log since checkpoint. */ + u_int32_t st_wcount; /* Total writes to the log. */ + u_int32_t st_wcount_fill; /* Overflow writes to the log. */ + u_int32_t st_scount; /* Total syncs to the log. */ + u_int32_t st_region_wait; /* Region lock granted after wait. */ + u_int32_t st_region_nowait; /* Region lock granted without wait. */ + u_int32_t st_cur_file; /* Current log file number. */ + u_int32_t st_cur_offset; /* Current log file offset. */ + u_int32_t st_regsize; /* Region size. */ +}; + +int log_archive __P((DB_ENV *, char **[], u_int32_t, void *(*)(size_t))); +int log_compare __P((const DB_LSN *, const DB_LSN *)); +int log_file __P((DB_ENV *, const DB_LSN *, char *, size_t)); +int log_flush __P((DB_ENV *, const DB_LSN *)); +int log_get __P((DB_ENV *, DB_LSN *, DBT *, u_int32_t)); +int log_put __P((DB_ENV *, DB_LSN *, const DBT *, u_int32_t)); +int log_register __P((DB_ENV *, DB *, const char *)); +int log_stat __P((DB_ENV *, DB_LOG_STAT **, void *(*)(size_t))); +int log_unregister __P((DB_ENV *, DB *)); + +/******************************************************* + * Mpool + *******************************************************/ +/* Flag values for memp_fget(). */ +#define DB_MPOOL_CREATE 0x001 /* Create a page. */ +#define DB_MPOOL_LAST 0x002 /* Return the last page. */ +#define DB_MPOOL_NEW 0x004 /* Create a new page. */ +#define DB_MPOOL_NEW_GROUP 0x008 /* Create a group of pages. */ +#define DB_MPOOL_EXTENT 0x010 /* Get for an extent. */ + +/* Flag values for memp_fput(), memp_fset(). */ +#define DB_MPOOL_CLEAN 0x001 /* Page is not modified. */ +#define DB_MPOOL_DIRTY 0x002 /* Page is modified. */ +#define DB_MPOOL_DISCARD 0x004 /* Don't cache the page. */ + +/* Mpool statistics structure. */ +struct __db_mpool_stat { + u_int32_t st_cache_hit; /* Pages found in the cache. */ + u_int32_t st_cache_miss; /* Pages not found in the cache. */ + u_int32_t st_map; /* Pages from mapped files. */ + u_int32_t st_page_create; /* Pages created in the cache. */ + u_int32_t st_page_in; /* Pages read in. */ + u_int32_t st_page_out; /* Pages written out. */ + u_int32_t st_ro_evict; /* Clean pages forced from the cache. */ + u_int32_t st_rw_evict; /* Dirty pages forced from the cache. */ + u_int32_t st_hash_buckets; /* Number of hash buckets. */ + u_int32_t st_hash_searches; /* Total hash chain searches. */ + u_int32_t st_hash_longest; /* Longest hash chain searched. */ + u_int32_t st_hash_examined; /* Total hash entries searched. */ + u_int32_t st_page_clean; /* Clean pages. */ + u_int32_t st_page_dirty; /* Dirty pages. */ + u_int32_t st_page_trickle; /* Pages written by memp_trickle. */ + u_int32_t st_region_wait; /* Region lock granted after wait. */ + u_int32_t st_region_nowait; /* Region lock granted without wait. */ + u_int32_t st_gbytes; /* Total cache size: GB. */ + u_int32_t st_bytes; /* Total cache size: B. */ + u_int32_t st_ncache; /* Number of caches. */ + u_int32_t st_regsize; /* Cache size. */ +}; + +/* Mpool file open information structure. */ +struct __db_mpool_finfo { + int ftype; /* File type. */ + DBT *pgcookie; /* Byte-string passed to pgin/pgout. */ + u_int8_t *fileid; /* Unique file ID. */ + int32_t lsn_offset; /* LSN offset in page. */ + u_int32_t clear_len; /* Cleared length on created pages. */ +}; + +/* Mpool file statistics structure. */ +struct __db_mpool_fstat { + char *file_name; /* File name. */ + size_t st_pagesize; /* Page size. */ + u_int32_t st_cache_hit; /* Pages found in the cache. */ + u_int32_t st_cache_miss; /* Pages not found in the cache. */ + u_int32_t st_map; /* Pages from mapped files. */ + u_int32_t st_page_create; /* Pages created in the cache. */ + u_int32_t st_page_in; /* Pages read in. */ + u_int32_t st_page_out; /* Pages written out. */ +}; + +int memp_fclose __P((DB_MPOOLFILE *)); +int memp_fget __P((DB_MPOOLFILE *, db_pgno_t *, u_int32_t, void *)); +int memp_fopen __P((DB_ENV *, const char *, + u_int32_t, int, size_t, DB_MPOOL_FINFO *, DB_MPOOLFILE **)); +int memp_fput __P((DB_MPOOLFILE *, void *, u_int32_t)); +int memp_fset __P((DB_MPOOLFILE *, void *, u_int32_t)); +int memp_fsync __P((DB_MPOOLFILE *)); +int memp_register __P((DB_ENV *, int, + int (*)(DB_ENV *, db_pgno_t, void *, DBT *), + int (*)(DB_ENV *, db_pgno_t, void *, DBT *))); +int memp_stat __P((DB_ENV *, + DB_MPOOL_STAT **, DB_MPOOL_FSTAT ***, void *(*)(size_t))); +int memp_sync __P((DB_ENV *, DB_LSN *)); +int memp_trickle __P((DB_ENV *, int, int *)); + +/******************************************************* + * Transactions. + *******************************************************/ +#define DB_TXNVERSION 1 + +/* Operations values to the tx_recover() function. */ +#define DB_TXN_BACKWARD_ROLL 1 /* Read the log backwards. */ +#define DB_TXN_FORWARD_ROLL 2 /* Read the log forwards. */ +#define DB_TXN_OPENFILES 3 /* Read for open files. */ +#define DB_TXN_REDO 4 /* Redo the operation. */ +#define DB_TXN_UNDO 5 /* Undo the operation. */ + +/* Internal transaction status values. */ + +/* Transaction statistics structure. */ +struct __db_txn_active { + u_int32_t txnid; /* Transaction ID */ + u_int32_t parentid; /* Transaction ID of parent */ + DB_LSN lsn; /* Lsn of the begin record */ +}; + +struct __db_txn_stat { + DB_LSN st_last_ckp; /* lsn of the last checkpoint */ + DB_LSN st_pending_ckp; /* last checkpoint did not finish */ + time_t st_time_ckp; /* time of last checkpoint */ + u_int32_t st_last_txnid; /* last transaction id given out */ + u_int32_t st_maxtxns; /* maximum txns possible */ + u_int32_t st_naborts; /* number of aborted transactions */ + u_int32_t st_nbegins; /* number of begun transactions */ + u_int32_t st_ncommits; /* number of committed transactions */ + u_int32_t st_nactive; /* number of active transactions */ + u_int32_t st_maxnactive; /* maximum active transactions */ + DB_TXN_ACTIVE + *st_txnarray; /* array of active transactions */ + u_int32_t st_region_wait; /* Region lock granted after wait. */ + u_int32_t st_region_nowait; /* Region lock granted without wait. */ + u_int32_t st_regsize; /* Region size. */ +}; + +int txn_abort __P((DB_TXN *)); +int txn_begin __P((DB_ENV *, DB_TXN *, DB_TXN **, u_int32_t)); +int txn_checkpoint __P((DB_ENV *, u_int32_t, u_int32_t, u_int32_t)); +int txn_commit __P((DB_TXN *, u_int32_t)); +u_int32_t txn_id __P((DB_TXN *)); +int txn_prepare __P((DB_TXN *)); +int txn_stat __P((DB_ENV *, DB_TXN_STAT **, void *(*)(size_t))); + +#ifndef DB_DBM_HSEARCH +#define DB_DBM_HSEARCH 0 /* No historic interfaces by default. */ +#endif +#if DB_DBM_HSEARCH != 0 +/******************************************************* + * Dbm/Ndbm historic interfaces. + *******************************************************/ +#define DBM_INSERT 0 /* Flags to dbm_store(). */ +#define DBM_REPLACE 1 + +/* + * The DB support for ndbm(3) always appends this suffix to the + * file name to avoid overwriting the user's original database. + */ +#define DBM_SUFFIX ".db" + +#if defined(_XPG4_2) +typedef struct { + char *dptr; + size_t dsize; +} datum; +#else +typedef struct { + char *dptr; + int dsize; +} datum; +#endif + +/* + * Translate DBM calls into DB calls so that DB doesn't step on the + * application's name space. + * + * The global variables dbrdonly, dirf and pagf were not retained when 4BSD + * replaced the dbm interface with ndbm, and are not supported here. + */ +#define dbminit(a) __db_dbm_init(a) +#define dbmclose __db_dbm_close +#if !defined(__cplusplus) +#define delete(a) __db_dbm_delete(a) +#endif +#define fetch(a) __db_dbm_fetch(a) +#define firstkey __db_dbm_firstkey +#define nextkey(a) __db_dbm_nextkey(a) +#define store(a, b) __db_dbm_store(a, b) + +/* Prototype the DB calls. */ +int __db_dbm_close __P((void)); +int __db_dbm_dbrdonly __P((void)); +int __db_dbm_delete __P((datum)); +int __db_dbm_dirf __P((void)); +datum __db_dbm_fetch __P((datum)); +datum __db_dbm_firstkey __P((void)); +int __db_dbm_init __P((char *)); +datum __db_dbm_nextkey __P((datum)); +int __db_dbm_pagf __P((void)); +int __db_dbm_store __P((datum, datum)); + +/* + * Translate NDBM calls into DB calls so that DB doesn't step on the + * application's name space. + */ +#define dbm_clearerr(a) __db_ndbm_clearerr(a) +#define dbm_close(a) __db_ndbm_close(a) +#define dbm_delete(a, b) __db_ndbm_delete(a, b) +#define dbm_dirfno(a) __db_ndbm_dirfno(a) +#define dbm_error(a) __db_ndbm_error(a) +#define dbm_fetch(a, b) __db_ndbm_fetch(a, b) +#define dbm_firstkey(a) __db_ndbm_firstkey(a) +#define dbm_nextkey(a) __db_ndbm_nextkey(a) +#define dbm_open(a, b, c) __db_ndbm_open(a, b, c) +#define dbm_pagfno(a) __db_ndbm_pagfno(a) +#define dbm_rdonly(a) __db_ndbm_rdonly(a) +#define dbm_store(a, b, c, d) __db_ndbm_store(a, b, c, d) + +/* Prototype the DB calls. */ +int __db_ndbm_clearerr __P((DBM *)); +void __db_ndbm_close __P((DBM *)); +int __db_ndbm_delete __P((DBM *, datum)); +int __db_ndbm_dirfno __P((DBM *)); +int __db_ndbm_error __P((DBM *)); +datum __db_ndbm_fetch __P((DBM *, datum)); +datum __db_ndbm_firstkey __P((DBM *)); +datum __db_ndbm_nextkey __P((DBM *)); +DBM *__db_ndbm_open __P((const char *, int, int)); +int __db_ndbm_pagfno __P((DBM *)); +int __db_ndbm_rdonly __P((DBM *)); +int __db_ndbm_store __P((DBM *, datum, datum, int)); + +/******************************************************* + * Hsearch historic interface. + *******************************************************/ +typedef enum { + FIND, ENTER +} ACTION; + +typedef struct entry { + char *key; + char *data; +} ENTRY; + +/* + * Translate HSEARCH calls into DB calls so that DB doesn't step on the + * application's name space. + */ +#define hcreate(a) __db_hcreate(a) +#define hdestroy __db_hdestroy +#define hsearch(a, b) __db_hsearch(a, b) + +/* Prototype the DB calls. */ +int __db_hcreate __P((size_t)); +void __db_hdestroy __P((void)); +ENTRY *__db_hsearch __P((ENTRY, ACTION)); +#endif /* DB_DBM_HSEARCH */ + +/* + * XXX + * MacOS: Reset Metrowerks C enum sizes. + */ +#ifdef __MWERKS__ +#pragma enumsalwaysint reset +#endif + +#if defined(__cplusplus) +} +#endif + +#endif /* !_DB_H_ */ diff --git a/db/include/db_185.h b/db/include/db_185.h new file mode 100644 index 000000000..e50ebb0ad --- /dev/null +++ b/db/include/db_185.h @@ -0,0 +1,175 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: db_185.h,v 11.4 2000/02/14 02:59:54 bostic Exp $ + */ + +#ifndef _DB_185_H_ +#define _DB_185_H_ + +#include + +#include + +/* + * XXX + * Handle function prototypes and the keyword "const". This steps on name + * space that DB doesn't control, but all of the other solutions are worse. + */ +#undef __P +#if defined(__STDC__) || defined(__cplusplus) +#define __P(protos) protos /* ANSI C prototypes */ +#else +#define const +#define __P(protos) () /* K&R C preprocessor */ +#endif + +#define RET_ERROR -1 /* Return values. */ +#define RET_SUCCESS 0 +#define RET_SPECIAL 1 + +#ifndef __BIT_TYPES_DEFINED__ +#define __BIT_TYPES_DEFINED__ +@u_int8_decl@ +@int16_decl@ +@u_int16_decl@ +@int32_decl@ +@u_int32_decl@ +#endif + +/* + * XXX + * SGI/IRIX already has a pgno_t. + */ +#ifdef sgi +#define pgno_t db_pgno_t +#endif + +#define MAX_PAGE_NUMBER 0xffffffff /* >= # of pages in a file */ +typedef u_int32_t pgno_t; +#define MAX_PAGE_OFFSET 65535 /* >= # of bytes in a page */ +typedef u_int16_t indx_t; +#define MAX_REC_NUMBER 0xffffffff /* >= # of records in a tree */ +typedef u_int32_t recno_t; + +/* Key/data structure -- a Data-Base Thang. */ +typedef struct { + void *data; /* data */ + size_t size; /* data length */ +} DBT; + +/* Routine flags. */ +#define R_CURSOR 1 /* del, put, seq */ +#define __R_UNUSED 2 /* UNUSED */ +#define R_FIRST 3 /* seq */ +#define R_IAFTER 4 /* put (RECNO) */ +#define R_IBEFORE 5 /* put (RECNO) */ +#define R_LAST 6 /* seq (BTREE, RECNO) */ +#define R_NEXT 7 /* seq */ +#define R_NOOVERWRITE 8 /* put */ +#define R_PREV 9 /* seq (BTREE, RECNO) */ +#define R_SETCURSOR 10 /* put (RECNO) */ +#define R_RECNOSYNC 11 /* sync (RECNO) */ + +typedef enum { DB_BTREE, DB_HASH, DB_RECNO } DBTYPE; + +/* Access method description structure. */ +typedef struct __db { + DBTYPE type; /* Underlying db type. */ + int (*close) __P((struct __db *)); + int (*del) __P((const struct __db *, const DBT *, u_int)); + int (*get) __P((const struct __db *, const DBT *, DBT *, u_int)); + int (*put) __P((const struct __db *, DBT *, const DBT *, u_int)); + int (*seq) __P((const struct __db *, DBT *, DBT *, u_int)); + int (*sync) __P((const struct __db *, u_int)); + void *internal; /* Access method private. */ + int (*fd) __P((const struct __db *)); +} DB; + +#define BTREEMAGIC 0x053162 +#define BTREEVERSION 3 + +/* Structure used to pass parameters to the btree routines. */ +typedef struct { +#define R_DUP 0x01 /* duplicate keys */ + u_int32_t flags; + u_int32_t cachesize; /* bytes to cache */ + u_int32_t maxkeypage; /* maximum keys per page */ + u_int32_t minkeypage; /* minimum keys per page */ + u_int32_t psize; /* page size */ + int (*compare) /* comparison function */ + __P((const DBT *, const DBT *)); + size_t (*prefix) /* prefix function */ + __P((const DBT *, const DBT *)); + int lorder; /* byte order */ +} BTREEINFO; + +#define HASHMAGIC 0x061561 +#define HASHVERSION 2 + +/* Structure used to pass parameters to the hashing routines. */ +typedef struct { + u_int32_t bsize; /* bucket size */ + u_int32_t ffactor; /* fill factor */ + u_int32_t nelem; /* number of elements */ + u_int32_t cachesize; /* bytes to cache */ + u_int32_t /* hash function */ + (*hash) __P((const void *, size_t)); + int lorder; /* byte order */ +} HASHINFO; + +/* Structure used to pass parameters to the record routines. */ +typedef struct { +#define R_FIXEDLEN 0x01 /* fixed-length records */ +#define R_NOKEY 0x02 /* key not required */ +#define R_SNAPSHOT 0x04 /* snapshot the input */ + u_int32_t flags; + u_int32_t cachesize; /* bytes to cache */ + u_int32_t psize; /* page size */ + int lorder; /* byte order */ + size_t reclen; /* record length (fixed-length records) */ + u_char bval; /* delimiting byte (variable-length records */ + char *bfname; /* btree file name */ +} RECNOINFO; + +#if defined(__cplusplus) +extern "C" { +#endif +#define dbopen __db185_open +DB *__db185_open __P((const char *, int, int, DBTYPE, const void *)); + +#if defined(__cplusplus) +} +#endif +#endif /* !_DB_185_H_ */ diff --git a/db/include/db_am.h b/db/include/db_am.h new file mode 100644 index 000000000..3a41eb3bb --- /dev/null +++ b/db/include/db_am.h @@ -0,0 +1,131 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: db_am.h,v 11.21 2000/12/12 17:43:56 bostic Exp $ + */ +#ifndef _DB_AM_H_ +#define _DB_AM_H_ + +#define DB_MINPAGECACHE 10 /* Min pages access methods cache. */ + +/* DB recovery operation codes. The low bits used to have flags or'd in. */ +#define DB_ADD_DUP 0x10 +#define DB_REM_DUP 0x20 +#define DB_ADD_BIG 0x30 +#define DB_REM_BIG 0x40 +#define DB_UNUSED_1 0x50 +#define DB_UNUSED_2 0x60 +#define DB_ADD_PAGE 0x70 +#define DB_REM_PAGE 0x80 + +/* + * This is a grotesque naming hack. We have modified the btree page + * allocation and freeing functions to be generic and have therefore + * moved them into the access-method independent portion of the code. + * However, since we didn't want to create new log records and routines + * for them, we left their logging and recovery functions over in btree. + * To make the code look prettier, we macro them, but this is sure to + * confuse the heck out of everyone. + */ +#define __db_pg_alloc_log __bam_pg_alloc_log +#define __db_pg_free_log __bam_pg_free_log + +/* + * Standard initialization and shutdown macros for all recovery functions. + * + * Requires the following local variables: + * + * DB *file_dbp; + * DB_MPOOLFILE *mpf; + * int ret; + */ +#define REC_INTRO(func, inc_count) { \ + file_dbp = NULL; \ + dbc = NULL; \ + if ((ret = func(dbenv, dbtp->data, &argp)) != 0) \ + goto out; \ + if ((ret = __db_fileid_to_db(dbenv, \ + &file_dbp, argp->fileid, inc_count)) != 0) { \ + if (ret == DB_DELETED) { \ + ret = 0; \ + goto done; \ + } \ + goto out; \ + } \ + if (file_dbp == NULL) \ + goto out; \ + if ((ret = file_dbp->cursor(file_dbp, NULL, &dbc, 0)) != 0) \ + goto out; \ + F_SET(dbc, DBC_RECOVER); \ + mpf = file_dbp->mpf; \ +} + +#define REC_CLOSE { \ + int __t_ret; \ + if (argp != NULL) \ + __os_free(argp, sizeof(*argp)); \ + if (dbc != NULL && (__t_ret = dbc->c_close(dbc)) != 0 && ret == 0) \ + return (__t_ret); \ + return (ret); \ +} + +/* + * No-op versions of the same macros. + */ +#define REC_NOOP_INTRO(func) { \ + if ((ret = func(dbenv, dbtp->data, &argp)) != 0) \ + return (ret); \ +} +#define REC_NOOP_CLOSE \ + if (argp != NULL) \ + __os_free(argp, sizeof(*argp)); \ + return (ret); \ + +/* + * Standard debugging macro for all recovery functions. + */ +#ifdef DEBUG_RECOVER +#define REC_PRINT(func) \ + (void)func(dbenv, dbtp, lsnp, op, info); +#else +#define REC_PRINT(func) +#endif + +/* + * Flags to __db_lget + */ +#define LCK_COUPLE 0x01 /* Lock Couple */ +#define LCK_ALWAYS 0x02 /* Lock even for off page dup cursors */ +#define LCK_ROLLBACK 0x04 /* Lock even if in rollback */ + +/* + * If doing transactions we have to hold the locks associated with a data item + * from a page for the entire transaction. However, we don't have to hold the + * locks associated with walking the tree. Distinguish between the two so that + * we don't tie up the internal pages of the tree longer than necessary. + */ +#define __LPUT(dbc, lock) \ + (lock.off != LOCK_INVALID ? \ + lock_put((dbc)->dbp->dbenv, &(lock)) : 0) +#define __TLPUT(dbc, lock) \ + (lock.off != LOCK_INVALID && \ + (dbc)->txn == NULL ? lock_put((dbc)->dbp->dbenv, &(lock)) : 0) + +#ifdef DIAGNOSTIC +#define DB_CHECK_TXN(dbp, txn) \ + if (txn != NULL) \ + F_SET(dbp, DB_AM_TXN); \ + else if (F_ISSET(dbp, DB_AM_TXN)) \ + return (__db_missing_txn_err((dbp)->dbenv)); +#else +#define DB_CHECK_TXN(dbp, txn) +#endif + +#include "db_dispatch.h" +#include "db_auto.h" +#include "crdel_auto.h" +#include "db_ext.h" +#endif diff --git a/db/include/db_auto.h b/db/include/db_auto.h new file mode 100644 index 000000000..88bf7419b --- /dev/null +++ b/db/include/db_auto.h @@ -0,0 +1,140 @@ +/* Do not edit: automatically built by gen_rec.awk. */ + +#ifndef db_AUTO_H +#define db_AUTO_H + +#define DB_db_addrem 41 +typedef struct _db_addrem_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + u_int32_t opcode; + int32_t fileid; + db_pgno_t pgno; + u_int32_t indx; + size_t nbytes; + DBT hdr; + DBT dbt; + DB_LSN pagelsn; +} __db_addrem_args; + +int __db_addrem_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, u_int32_t, int32_t, db_pgno_t, u_int32_t, size_t, const DBT *, const DBT *, DB_LSN *)); +int __db_addrem_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_addrem_read __P((DB_ENV *, void *, __db_addrem_args **)); + +#define DB_db_split 42 +typedef struct _db_split_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + u_int32_t opcode; + int32_t fileid; + db_pgno_t pgno; + DBT pageimage; + DB_LSN pagelsn; +} __db_split_args; + +int __db_split_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_split_read __P((DB_ENV *, void *, __db_split_args **)); + +#define DB_db_big 43 +typedef struct _db_big_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + u_int32_t opcode; + int32_t fileid; + db_pgno_t pgno; + db_pgno_t prev_pgno; + db_pgno_t next_pgno; + DBT dbt; + DB_LSN pagelsn; + DB_LSN prevlsn; + DB_LSN nextlsn; +} __db_big_args; + +int __db_big_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, u_int32_t, int32_t, db_pgno_t, db_pgno_t, db_pgno_t, const DBT *, DB_LSN *, DB_LSN *, DB_LSN *)); +int __db_big_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_big_read __P((DB_ENV *, void *, __db_big_args **)); + +#define DB_db_ovref 44 +typedef struct _db_ovref_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t pgno; + int32_t adjust; + DB_LSN lsn; +} __db_ovref_args; + +int __db_ovref_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, int32_t, db_pgno_t, int32_t, DB_LSN *)); +int __db_ovref_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_ovref_read __P((DB_ENV *, void *, __db_ovref_args **)); + +#define DB_db_relink 45 +typedef struct _db_relink_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + u_int32_t opcode; + int32_t fileid; + db_pgno_t pgno; + DB_LSN lsn; + db_pgno_t prev; + DB_LSN lsn_prev; + db_pgno_t next; + DB_LSN lsn_next; +} __db_relink_args; + +int __db_relink_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, u_int32_t, int32_t, db_pgno_t, DB_LSN *, db_pgno_t, DB_LSN *, db_pgno_t, DB_LSN *)); +int __db_relink_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_relink_read __P((DB_ENV *, void *, __db_relink_args **)); + +#define DB_db_addpage 46 +typedef struct _db_addpage_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t pgno; + DB_LSN lsn; + db_pgno_t nextpgno; + DB_LSN nextlsn; +} __db_addpage_args; + +int __db_addpage_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_addpage_read __P((DB_ENV *, void *, __db_addpage_args **)); + +#define DB_db_debug 47 +typedef struct _db_debug_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + DBT op; + int32_t fileid; + DBT key; + DBT data; + u_int32_t arg_flags; +} __db_debug_args; + +int __db_debug_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, const DBT *, int32_t, const DBT *, const DBT *, u_int32_t)); +int __db_debug_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_debug_read __P((DB_ENV *, void *, __db_debug_args **)); + +#define DB_db_noop 48 +typedef struct _db_noop_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t pgno; + DB_LSN prevlsn; +} __db_noop_args; + +int __db_noop_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, int32_t, db_pgno_t, DB_LSN *)); +int __db_noop_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_noop_read __P((DB_ENV *, void *, __db_noop_args **)); +int __db_init_print __P((DB_ENV *)); +int __db_init_recover __P((DB_ENV *)); +#endif diff --git a/db/include/db_cxx.h b/db/include/db_cxx.h new file mode 100644 index 000000000..b5599ee69 --- /dev/null +++ b/db/include/db_cxx.h @@ -0,0 +1,652 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: db_cxx.h,v 11.44 2000/12/21 20:30:18 dda Exp $ + */ + +#ifndef _DB_CXX_H_ +#define _DB_CXX_H_ +// +// C++ assumptions: +// +// To ensure portability to many platforms, both new and old, we make +// few assumptions about the C++ compiler and library. For example, +// we do not expect STL, templates or namespaces to be available. The +// "newest" C++ feature used is exceptions, which are used liberally +// to transmit error information. Even the use of exceptions can be +// disabled at runtime, to do so, use the DB_CXX_NO_EXCEPTIONS flags +// with the DbEnv or Db constructor. +// +// C++ naming conventions: +// +// - All top level class names start with Db. +// - All class members start with lower case letter. +// - All private data members are suffixed with underscore. +// - Use underscores to divide names into multiple words. +// - Simple data accessors are named with get_ or set_ prefix. +// - All method names are taken from names of functions in the C +// layer of db (usually by dropping a prefix like "db_"). +// These methods have the same argument types and order, +// other than dropping the explicit arg that acts as "this". +// +// As a rule, each DbFoo object has exactly one underlying DB_FOO struct +// (defined in db.h) associated with it. In some cases, we inherit directly +// from the DB_FOO structure to make this relationship explicit. Often, +// the underlying C layer allocates and deallocates these structures, so +// there is no easy way to add any data to the DbFoo class. When you see +// a comment about whether data is permitted to be added, this is what +// is going on. Of course, if we need to add data to such C++ classes +// in the future, we will arrange to have an indirect pointer to the +// DB_FOO struct (as some of the classes already have). +// + +//////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// +// +// Forward declarations +// + +#include +#include +#include "db.h" + +class Db; // forward +class Dbc; // forward +class DbEnv; // forward +class DbException; // forward +class DbInfo; // forward +class DbLock; // forward +class DbLsn; // forward +class DbMpoolFile; // forward +class Dbt; // forward +class DbTxn; // forward + +// These classes are not defined here and should be invisible +// to the user, but some compilers require forward references. +// There is one for each use of the DEFINE_DB_CLASS macro. + +class DbImp; +class DbEnvImp; +class DbMpoolFileImp; +class DbTxnImp; + +//////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// +// +// Mechanisms for declaring classes +// + +// +// Every class defined in this file has an _exported next to the class name. +// This is needed for WinTel machines so that the class methods can +// be exported or imported in a DLL as appropriate. Users of the DLL +// use the define DB_USE_DLL. When the DLL is built, DB_CREATE_DLL +// must be defined. +// +#if defined(_MSC_VER) + +# if defined(DB_CREATE_DLL) +# define _exported __declspec(dllexport) // creator of dll +# elif defined(DB_USE_DLL) +# define _exported __declspec(dllimport) // user of dll +# else +# define _exported // static lib creator or user +# endif + +#else + +# define _exported + +#endif + +// DEFINE_DB_CLASS defines an imp_ data member and imp() accessor. +// The underlying type is a pointer to an opaque *Imp class, that +// gets converted to the correct implementation class by the implementation. +// +// Since these defines use "private/public" labels, and leave the access +// being "private", we always use these by convention before any data +// members in the private section of a class. Keeping them in the +// private section also emphasizes that they are off limits to user code. +// +#define DEFINE_DB_CLASS(name) \ + public: class name##Imp* imp() { return (imp_); } \ + public: const class name##Imp* constimp() const { return (imp_); } \ + private: class name##Imp* imp_ + +//////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// +// +// Turn off inappropriate compiler warnings +// + +#ifdef _MSC_VER + +// These are level 4 warnings that are explicitly disabled. +// With Visual C++, by default you do not see above level 3 unless +// you use /W4. But we like to compile with the highest level +// warnings to catch other errors. +// +// 4201: nameless struct/union +// triggered by standard include file +// +// 4514: unreferenced inline function has been removed +// certain include files in MSVC define methods that are not called +// +#pragma warning(disable: 4201 4514) + +#endif + +// Some interfaces can be customized by allowing users +// to define callback functions. For performance and +// logistical reasons, some callbacks require you do +// declare the functions in C, or in an extern "C" block. +// +extern "C" { + typedef void * (*db_malloc_fcn_type) + (size_t); + typedef void * (*db_realloc_fcn_type) + (void *, size_t); + typedef int (*bt_compare_fcn_type) + (DB *, const DBT *, const DBT *); + typedef size_t (*bt_prefix_fcn_type) + (DB *, const DBT *, const DBT *); + typedef int (*dup_compare_fcn_type) + (DB *, const DBT *, const DBT *); + typedef u_int32_t (*h_hash_fcn_type) + (DB *, const void *, u_int32_t); + typedef int (*pgin_fcn_type)(DB_ENV *dbenv, + db_pgno_t pgno, void *pgaddr, DBT *pgcookie); + typedef int (*pgout_fcn_type)(DB_ENV *dbenv, + db_pgno_t pgno, void *pgaddr, DBT *pgcookie); +}; + +//////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// +// +// Exception classes +// + +// Almost any error in the DB library throws a DbException. +// Every exception should be considered an abnormality +// (e.g. bug, misuse of DB, file system error). +// +// NOTE: We would like to inherit from class exception and +// let it handle what(), but there are +// MSVC++ problems when is included. +// +class _exported DbException +{ +public: + virtual ~DbException(); + DbException(int err); + DbException(const char *description); + DbException(const char *prefix, int err); + DbException(const char *prefix1, const char *prefix2, int err); + int get_errno() const; + virtual const char *what() const; + + DbException(const DbException &); + DbException &operator = (const DbException &); + +private: + char *what_; + int err_; // errno +}; + +//////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// +// +// Lock classes +// + +class _exported DbLock +{ + friend class DbEnv; + +public: + DbLock(); + + int put(DbEnv *env); + + DbLock(const DbLock &); + DbLock &operator = (const DbLock &); + +protected: + // We can add data to this class if needed + // since its contained class is not allocated by db. + // (see comment at top) + + DbLock(DB_LOCK); + DB_LOCK lock_; +}; + +//////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// +// +// Log classes +// + +class _exported DbLsn : protected DB_LSN +{ + friend class DbEnv; // friendship needed to cast to base class +}; + +//////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// +// +// Memory pool classes +// + +class _exported DbMpoolFile +{ + friend class DbEnv; + +public: + int close(); + int get(db_pgno_t *pgnoaddr, u_int32_t flags, void *pagep); + int put(void *pgaddr, u_int32_t flags); + int set(void *pgaddr, u_int32_t flags); + int sync(); + + static int open(DbEnv *envp, const char *file, + u_int32_t flags, int mode, size_t pagesize, + DB_MPOOL_FINFO *finfop, DbMpoolFile **mpf); + +private: + // We can add data to this class if needed + // since it is implemented via a pointer. + // (see comment at top) + + // Note: use DbMpoolFile::open() + // to get pointers to a DbMpoolFile, + // and call DbMpoolFile::close() rather than delete to release them. + // + DbMpoolFile(); + + // Shut g++ up. +protected: + ~DbMpoolFile(); + +private: + // no copying + DbMpoolFile(const DbMpoolFile &); + void operator = (const DbMpoolFile &); + + DEFINE_DB_CLASS(DbMpoolFile); +}; + +//////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// +// +// Transaction classes +// + +class _exported DbTxn +{ + friend class DbEnv; + +public: + int abort(); + int commit(u_int32_t flags); + u_int32_t id(); + int prepare(); + +private: + // We can add data to this class if needed + // since it is implemented via a pointer. + // (see comment at top) + + // Note: use DbEnv::txn_begin() to get pointers to a DbTxn, + // and call DbTxn::abort() or DbTxn::commit rather than + // delete to release them. + // + DbTxn(); + ~DbTxn(); + + // no copying + DbTxn(const DbTxn &); + void operator = (const DbTxn &); + + DEFINE_DB_CLASS(DbTxn); +}; + +// +// Berkeley DB environment class. Provides functions for opening databases. +// User of this library can use this class as a starting point for +// developing a DB application - derive their application class from +// this one, add application control logic. +// +// Note that if you use the default constructor, you must explicitly +// call appinit() before any other db activity (e.g. opening files) +// +class _exported DbEnv +{ + friend class Db; + friend class DbLock; + friend class DbMpoolFile; + +public: + + ~DbEnv(); + + // After using this constructor, you can set any needed + // parameters for the environment using the set_* methods. + // Then call open() to finish initializing the environment + // and attaching it to underlying files. + // + DbEnv(u_int32_t flags); + + // These methods match those in the C interface. + // + int close(u_int32_t); + void err(int, const char *, ...); + void errx(const char *, ...); + int open(const char *, u_int32_t, int); + int remove(const char *, u_int32_t); + int set_cachesize(u_int32_t, u_int32_t, int); + int set_data_dir(const char *); + void set_errcall(void (*)(const char *, char *)); + void set_errfile(FILE *); + void set_errpfx(const char *); + int set_flags(u_int32_t, int); + int set_feedback(void (*)(DbEnv *, int, int)); + int set_recovery_init(int (*)(DbEnv *)); + int set_lg_bsize(u_int32_t); + int set_lg_dir(const char *); + int set_lg_max(u_int32_t); + int set_lk_conflicts(u_int8_t *, int); + int set_lk_detect(u_int32_t); + int set_lk_max(u_int32_t); + int set_lk_max_lockers(u_int32_t); + int set_lk_max_locks(u_int32_t); + int set_lk_max_objects(u_int32_t); + int set_mp_mmapsize(size_t); + int set_mutexlocks(int); + static int set_pageyield(int); + int set_paniccall(void (*)(DbEnv *, int)); + static int set_panicstate(int); + static int set_region_init(int); + int set_server(char *, long, long, u_int32_t); + int set_shm_key(long); + int set_tmp_dir(const char *); + static int set_tas_spins(u_int32_t); + int set_tx_max(u_int32_t); + int set_tx_recover(int (*)(DbEnv *, Dbt *, DbLsn *, db_recops)); + int set_tx_timestamp(time_t *); + int set_verbose(u_int32_t which, int onoff); + + // Version information. A static method so it can be obtained anytime. + // + static char *version(int *major, int *minor, int *patch); + + // Convert DB errors to strings + static char *strerror(int); + + // If an error is detected and the error call function + // or stream is set, a message is dispatched or printed. + // If a prefix is set, each message is prefixed. + // + // You can use set_errcall() or set_errfile() above to control + // error functionality. Alternatively, you can call + // set_error_stream() to force all errors to a C++ stream. + // It is unwise to mix these approaches. + // + void set_error_stream(ostream *); + + // used internally + static void runtime_error(const char *caller, int err, + int error_policy); + + // Lock functions + // + int lock_detect(u_int32_t flags, u_int32_t atype, int *aborted); + int lock_get(u_int32_t locker, u_int32_t flags, const Dbt *obj, + db_lockmode_t lock_mode, DbLock *lock); + int lock_id(u_int32_t *idp); + int lock_stat(DB_LOCK_STAT **statp, db_malloc_fcn_type db_malloc_fcn); + int lock_vec(u_int32_t locker, u_int32_t flags, DB_LOCKREQ list[], + int nlist, DB_LOCKREQ **elistp); + + // Log functions + // + int log_archive(char **list[], u_int32_t flags, db_malloc_fcn_type db_malloc_fcn); + static int log_compare(const DbLsn *lsn0, const DbLsn *lsn1); + int log_file(DbLsn *lsn, char *namep, size_t len); + int log_flush(const DbLsn *lsn); + int log_get(DbLsn *lsn, Dbt *data, u_int32_t flags); + int log_put(DbLsn *lsn, const Dbt *data, u_int32_t flags); + + int log_register(Db *dbp, const char *name); + int log_stat(DB_LOG_STAT **spp, db_malloc_fcn_type db_malloc_fcn); + int log_unregister(Db *dbp); + + // Mpool functions + // + int memp_register(int ftype, + pgin_fcn_type pgin_fcn, + pgout_fcn_type pgout_fcn); + + int memp_stat(DB_MPOOL_STAT **gsp, DB_MPOOL_FSTAT ***fsp, + db_malloc_fcn_type db_malloc_fcn); + int memp_sync(DbLsn *lsn); + int memp_trickle(int pct, int *nwrotep); + + // Transaction functions + // + int txn_begin(DbTxn *pid, DbTxn **tid, u_int32_t flags); + int txn_checkpoint(u_int32_t kbyte, u_int32_t min, u_int32_t flags); + int txn_stat(DB_TXN_STAT **statp, db_malloc_fcn_type db_malloc_fcn); + + // These are public only because they need to be called + // via C functions. They should never be called by users + // of this class. + // + static void _stream_error_function(const char *, char *); + static int _tx_recover_intercept(DB_ENV *env, DBT *dbt, DB_LSN *lsn, + db_recops op); + static void _paniccall_intercept(DB_ENV *env, int errval); + static int _recovery_init_intercept(DB_ENV *env); + static void _feedback_intercept(DB_ENV *env, int opcode, int pct); + static void _destroy_check(const char *str, int isDbEnv); + +private: + void cleanup(); + int initialize(DB_ENV *env); + int error_policy(); + + // Used internally + DbEnv(DB_ENV *, u_int32_t flags); + + // no copying + DbEnv(const DbEnv &); + void operator = (const DbEnv &); + + DEFINE_DB_CLASS(DbEnv); + + // instance data + int construct_error_; + u_int32_t construct_flags_; + Db *headdb_; + Db *taildb_; + int (*tx_recover_callback_)(DbEnv *, Dbt *, DbLsn *, db_recops); + int (*recovery_init_callback_)(DbEnv *); + void (*paniccall_callback_)(DbEnv *, int); + void (*feedback_callback_)(DbEnv *, int, int); + + // class data + static ostream *error_stream_; +}; + +//////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// +// +// Table access classes +// + +// +// Represents a database table = a set of keys with associated values. +// +class _exported Db +{ + friend class DbEnv; + +public: + Db(DbEnv*, u_int32_t); // create a Db object, then call open() + ~Db(); // does *not* call close. + + // These methods exactly match those in the C interface. + // + int close(u_int32_t flags); + int cursor(DbTxn *txnid, Dbc **cursorp, u_int32_t flags); + int del(DbTxn *txnid, Dbt *key, u_int32_t flags); + void err(int, const char *, ...); + void errx(const char *, ...); + int fd(int *fdp); + int get(DbTxn *txnid, Dbt *key, Dbt *data, u_int32_t flags); + int get_byteswapped() const; + DBTYPE get_type() const; + int join(Dbc **curslist, Dbc **dbcp, u_int32_t flags); + int key_range(DbTxn *, Dbt *, DB_KEY_RANGE *, u_int32_t); + int open(const char *, const char *subname, DBTYPE, u_int32_t, int); + int put(DbTxn *, Dbt *, Dbt *, u_int32_t); + int remove(const char *, const char *, u_int32_t); + int rename(const char *, const char *, const char *, u_int32_t); + int set_bt_compare(bt_compare_fcn_type); + int set_bt_maxkey(u_int32_t); + int set_bt_minkey(u_int32_t); + int set_bt_prefix(bt_prefix_fcn_type); + int set_cachesize(u_int32_t, u_int32_t, int); + int set_dup_compare(dup_compare_fcn_type); + void set_errcall(void (*)(const char *, char *)); + void set_errfile(FILE *); + void set_errpfx(const char *); + int set_append_recno(int (*)(Db *, Dbt *, db_recno_t)); + int set_feedback(void (*)(Db *, int, int)); + int set_flags(u_int32_t); + int set_h_ffactor(u_int32_t); + int set_h_hash(h_hash_fcn_type); + int set_h_nelem(u_int32_t); + int set_lorder(int); + int set_malloc(db_malloc_fcn_type); + int set_pagesize(u_int32_t); + int set_paniccall(void (*)(DbEnv *, int)); + int set_realloc(db_realloc_fcn_type); + int set_re_delim(int); + int set_re_len(u_int32_t); + int set_re_pad(int); + int set_re_source(char *); + int set_q_extentsize(u_int32_t); + int stat(void *sp, db_malloc_fcn_type db_malloc_fcn, u_int32_t flags); + int sync(u_int32_t flags); + int upgrade(const char *name, u_int32_t flags); + int verify(const char *, const char *, ostream *, u_int32_t); + + // This additional method is available for C++ + // + void set_error_stream(ostream *); + + // These are public only because it needs to be called + // via C functions. It should never be called by users + // of this class. + // + static void _feedback_intercept(DB *db, int opcode, int pct); + static int _append_recno_intercept(DB *db, DBT *data, db_recno_t recno); +private: + + // no copying + Db(const Db &); + Db &operator = (const Db &); + + DEFINE_DB_CLASS(Db); + + void cleanup(); + int initialize(); + int error_policy(); + + // instance data + DbEnv *env_; + Db *next_; + Db *prev_; + int construct_error_; + u_int32_t flags_; + u_int32_t construct_flags_; + void (*feedback_callback_)(Db *, int, int); + int (*append_recno_callback_)(Db *, Dbt *, db_recno_t); +}; + +// +// A chunk of data, maybe a key or value. +// +class _exported Dbt : private DBT +{ + friend class Dbc; + friend class Db; + friend class DbEnv; + +public: + + // key/data + void *get_data() const; + void set_data(void *); + + // key/data length + u_int32_t get_size() const; + void set_size(u_int32_t); + + // RO: length of user buffer. + u_int32_t get_ulen() const; + void set_ulen(u_int32_t); + + // RO: get/put record length. + u_int32_t get_dlen() const; + void set_dlen(u_int32_t); + + // RO: get/put record offset. + u_int32_t get_doff() const; + void set_doff(u_int32_t); + + // flags + u_int32_t get_flags() const; + void set_flags(u_int32_t); + + Dbt(void *data, size_t size); + Dbt(); + ~Dbt(); + Dbt(const Dbt &); + Dbt &operator = (const Dbt &); + +private: + // We can add data to this class if needed + // since parent class is not allocated by db. + // (see comment at top) +}; + +class _exported Dbc : protected DBC +{ + friend class Db; + +public: + int close(); + int count(db_recno_t *countp, u_int32_t flags); + int del(u_int32_t flags); + int dup(Dbc** cursorp, u_int32_t flags); + int get(Dbt* key, Dbt *data, u_int32_t flags); + int put(Dbt* key, Dbt *data, u_int32_t flags); + +private: + // No data is permitted in this class (see comment at top) + + // Note: use Db::cursor() to get pointers to a Dbc, + // and call Dbc::close() rather than delete to release them. + // + Dbc(); + ~Dbc(); + + // no copying + Dbc(const Dbc &); + Dbc &operator = (const Dbc &); +}; +#endif /* !_DB_CXX_H_ */ diff --git a/db/include/db_dispatch.h b/db/include/db_dispatch.h new file mode 100644 index 000000000..003acee6f --- /dev/null +++ b/db/include/db_dispatch.h @@ -0,0 +1,95 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1995, 1996 + * The President and Fellows of Harvard University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: db_dispatch.h,v 11.17 2000/12/14 07:39:13 ubell Exp $ + */ + +#ifndef _DB_DISPATCH_H_ +#define _DB_DISPATCH_H_ + +/* + * Declarations and typedefs for the list of transaction IDs used during + * recovery. This is a generic list used to pass along whatever information + * we need during recovery. + */ +struct __db_txnhead { + LIST_HEAD(__db_headlink, __db_txnlist) head; + u_int32_t maxid; + int32_t generation; +}; + +#define TXNLIST_INVALID_ID 0xffffffff +struct __db_txnlist { + db_txnlist_type type; + LIST_ENTRY(__db_txnlist) links; + union { + struct { + u_int32_t txnid; + int32_t generation; + int32_t aborted; + } t; + struct { +#define TXNLIST_FLAG_DELETED 0x1 +#define TXNLIST_FLAG_CLOSED 0x2 + u_int32_t flags; + int32_t fileid; + u_int32_t count; + char *fname; + } d; + struct { + int32_t ntxns; + int32_t maxn; + DB_LSN *lsn_array; + } l; + struct { + int32_t nentries; + int32_t maxentry; + char *fname; + int32_t fileid; + db_pgno_t *pgno_array; + u_int8_t uid[DB_FILE_ID_LEN]; + } p; + } u; +}; + +/* + * Flag value for __db_txnlist_lsnadd. Distinguish whether we are replacing + * an entry in the transaction list or adding a new one. + */ + +#define TXNLIST_NEW 0x1 + +#define DB_user_BEGIN 10000 + +#endif diff --git a/db/include/db_ext.h b/db/include/db_ext.h new file mode 100644 index 000000000..efe254247 --- /dev/null +++ b/db/include/db_ext.h @@ -0,0 +1,208 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _db_ext_h_ +#define _db_ext_h_ +#if defined(__cplusplus) +extern "C" { +#endif +int __crdel_fileopen_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __crdel_metasub_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __crdel_metapage_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __crdel_delete_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __crdel_rename_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_open __P((DB *, + const char *, const char *, DBTYPE, u_int32_t, int)); +int __db_dbopen __P((DB *, const char *, u_int32_t, int, db_pgno_t)); +int __db_master_open __P((DB *, + const char *, u_int32_t, int, DB **)); +int __db_dbenv_setup __P((DB *, const char *, u_int32_t)); +int __db_close __P((DB *, u_int32_t)); +int __db_remove __P((DB *, const char *, const char *, u_int32_t)); +int __db_rename __P((DB *, + const char *, const char *, const char *, u_int32_t)); +int __db_metabegin __P((DB *, DB_LOCK *)); +int __db_metaend __P((DB *, + DB_LOCK *, int, int (*)(DB *, void *), void *)); +int __db_log_page __P((DB *, + const char *, DB_LSN *, db_pgno_t, PAGE *)); +int __db_backup_name __P((DB_ENV *, + const char *, char **, DB_LSN *)); +DB *__dblist_get __P((DB_ENV *, u_int32_t)); +int __db_testcopy __P((DB *, const char *)); +int __db_cursor __P((DB *, DB_TXN *, DBC **, u_int32_t)); +int __db_icursor + __P((DB *, DB_TXN *, DBTYPE, db_pgno_t, int, DBC **)); +int __db_cprint __P((DB *)); +int __db_fd __P((DB *, int *)); +int __db_get __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t)); +int __db_put __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t)); +int __db_sync __P((DB *, u_int32_t)); +int __db_c_close __P((DBC *)); +int __db_c_destroy __P((DBC *)); +int __db_c_count __P((DBC *, db_recno_t *, u_int32_t)); +int __db_c_del __P((DBC *, u_int32_t)); +int __db_c_dup __P((DBC *, DBC **, u_int32_t)); +int __db_c_newopd __P((DBC *, db_pgno_t, DBC **)); +int __db_c_get __P((DBC *, DBT *, DBT *, u_int32_t)); +int __db_c_put __P((DBC *, DBT *, DBT *, u_int32_t)); +int __db_duperr __P((DB *, u_int32_t)); +int __db_pgin __P((DB_ENV *, db_pgno_t, void *, DBT *)); +int __db_pgout __P((DB_ENV *, db_pgno_t, void *, DBT *)); +void __db_metaswap __P((PAGE *)); +int __db_byteswap __P((DB_ENV *, db_pgno_t, PAGE *, size_t, int)); +int __db_dispatch __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_add_recovery __P((DB_ENV *, + int (*)(DB_ENV *, DBT *, DB_LSN *, db_recops, void *), u_int32_t)); +int __deprecated_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_txnlist_init __P((DB_ENV *, void *)); +int __db_txnlist_add __P((DB_ENV *, void *, u_int32_t, int32_t)); +int __db_txnlist_remove __P((void *, u_int32_t)); +int __db_txnlist_close __P((void *, int32_t, u_int32_t)); +int __db_txnlist_delete __P((DB_ENV *, + void *, char *, u_int32_t, int)); +void __db_txnlist_end __P((DB_ENV *, void *)); +int __db_txnlist_find __P((void *, u_int32_t)); +void __db_txnlist_gen __P((void *, int)); +int __db_txnlist_lsnadd __P((DB_ENV *, void *, DB_LSN *, u_int32_t)); +int __db_txnlist_lsnhead __P((void *, DB_LSN **)); +int __db_txnlist_lsninit __P((DB_ENV *, DB_TXNHEAD *, DB_LSN *)); +int __db_add_limbo __P((DB_ENV *, + void *, int32_t, db_pgno_t, int32_t)); +int __db_do_the_limbo __P((DB_ENV *, DB_TXNHEAD *)); +int __db_txnlist_pgnoadd __P((DB_ENV *, DB_TXNHEAD *, + int32_t, u_int8_t [DB_FILE_ID_LEN], char *, db_pgno_t)); +void __db_txnlist_print __P((void *)); + int __db_ditem __P((DBC *, PAGE *, u_int32_t, u_int32_t)); +int __db_pitem + __P((DBC *, PAGE *, u_int32_t, u_int32_t, DBT *, DBT *)); +int __db_relink __P((DBC *, u_int32_t, PAGE *, PAGE **, int)); +int __db_cursorchk __P((const DB *, u_int32_t, int)); +int __db_ccountchk __P((const DB *, u_int32_t, int)); +int __db_cdelchk __P((const DB *, u_int32_t, int, int)); +int __db_cgetchk __P((const DB *, DBT *, DBT *, u_int32_t, int)); +int __db_cputchk __P((const DB *, + const DBT *, DBT *, u_int32_t, int, int)); +int __db_closechk __P((const DB *, u_int32_t)); +int __db_delchk __P((const DB *, DBT *, u_int32_t, int)); +int __db_getchk __P((const DB *, const DBT *, DBT *, u_int32_t)); +int __db_joinchk __P((const DB *, DBC * const *, u_int32_t)); +int __db_joingetchk __P((const DB *, DBT *, u_int32_t)); +int __db_putchk + __P((const DB *, DBT *, const DBT *, u_int32_t, int, int)); +int __db_removechk __P((const DB *, u_int32_t)); +int __db_statchk __P((const DB *, u_int32_t)); +int __db_syncchk __P((const DB *, u_int32_t)); +int __db_join __P((DB *, DBC **, DBC **, u_int32_t)); +int __db_new __P((DBC *, u_int32_t, PAGE **)); +int __db_free __P((DBC *, PAGE *)); +int __db_lprint __P((DBC *)); +int __db_lget __P((DBC *, + int, db_pgno_t, db_lockmode_t, int, DB_LOCK *)); +int __dbh_am_chk __P((DB *, u_int32_t)); +#ifdef HAVE_RPC +int __dbcl_init __P((DB *, DB_ENV *, u_int32_t)); +#endif +int __db_goff __P((DB *, DBT *, + u_int32_t, db_pgno_t, void **, u_int32_t *)); +int __db_poff __P((DBC *, const DBT *, db_pgno_t *)); +int __db_ovref __P((DBC *, db_pgno_t, int32_t)); +int __db_doff __P((DBC *, db_pgno_t)); +int __db_moff __P((DB *, const DBT *, db_pgno_t, u_int32_t, + int (*)(DB *, const DBT *, const DBT *), int *)); +int __db_vrfy_overflow __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, + u_int32_t)); +int __db_vrfy_ovfl_structure + __P((DB *, VRFY_DBINFO *, db_pgno_t, u_int32_t, u_int32_t)); +int __db_safe_goff __P((DB *, VRFY_DBINFO *, db_pgno_t, + DBT *, void **, u_int32_t)); +void __db_loadme __P((void)); +int __db_dump __P((DB *, char *, char *)); +int __db_prnpage __P((DB *, db_pgno_t)); +int __db_prpage __P((DB *, PAGE *, u_int32_t)); +void __db_pr __P((u_int8_t *, u_int32_t)); +int __db_prdbt __P((DBT *, int, const char *, void *, + int (*)(void *, const void *), int, VRFY_DBINFO *)); +void __db_prflags __P((u_int32_t, const FN *, FILE *)); +const char *__db_pagetype_to_string __P((u_int32_t)); +int __db_prheader __P((DB *, char *, int, int, void *, + int (*)(void *, const void *), VRFY_DBINFO *, db_pgno_t)); +int __db_prfooter __P((void *, int (*)(void *, const void *))); +int __db_addrem_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_big_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_ovref_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_relink_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_debug_recover __P((DB_ENV *, + DBT *, DB_LSN *, db_recops, void *)); +int __db_noop_recover __P((DB_ENV *, + DBT *, DB_LSN *, db_recops, void *)); +int __db_traverse_dup __P((DB *, + db_pgno_t, int (*)(DB *, PAGE *, void *, int *), void *)); +int __db_traverse_big __P((DB *, + db_pgno_t, int (*)(DB *, PAGE *, void *, int *), void *)); +int __db_reclaim_callback __P((DB *, PAGE *, void *, int *)); +int __db_ret __P((DB *, + PAGE *, u_int32_t, DBT *, void **, u_int32_t *)); +int __db_retcopy __P((DB *, DBT *, + void *, u_int32_t, void **, u_int32_t *)); +int __db_upgrade __P((DB *, const char *, u_int32_t)); +int __db_lastpgno __P((DB *, char *, DB_FH *, db_pgno_t *)); +int __db_31_offdup __P((DB *, char *, DB_FH *, int, db_pgno_t *)); +int __db_verify + __P((DB *, const char *, const char *, FILE *, u_int32_t)); +int __db_verify_callback __P((void *, const void *)); +int __db_verify_internal __P((DB *, const char *, + const char *, void *, int (*)(void *, const void *), u_int32_t)); +int __db_vrfy_datapage + __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, u_int32_t)); +int __db_vrfy_meta + __P((DB *, VRFY_DBINFO *, DBMETA *, db_pgno_t, u_int32_t)); +int __db_vrfy_struct_feedback __P((DB *, VRFY_DBINFO *)); +int __db_salvage __P((DB *, VRFY_DBINFO *, db_pgno_t, PAGE *, + void *, int (*)(void *, const void *), u_int32_t)); +int __db_vrfy_inpitem __P((DB *, PAGE *, + db_pgno_t, u_int32_t, int, u_int32_t, u_int32_t *, u_int32_t *)); +int __db_vrfy_duptype + __P((DB *, VRFY_DBINFO *, db_pgno_t, u_int32_t)); +int __db_salvage_duptree __P((DB *, VRFY_DBINFO *, db_pgno_t, + DBT *, void *, int (*)(void *, const void *), u_int32_t)); +int __db_salvage_subdbpg + __P((DB *, VRFY_DBINFO *, PAGE *, void *, + int (*)(void *, const void *), u_int32_t)); +int __db_vrfy_dbinfo_create + __P((DB_ENV *, u_int32_t, VRFY_DBINFO **)); +int __db_vrfy_dbinfo_destroy __P((VRFY_DBINFO *)); +int __db_vrfy_getpageinfo + __P((VRFY_DBINFO *, db_pgno_t, VRFY_PAGEINFO **)); +int __db_vrfy_putpageinfo __P((VRFY_DBINFO *, VRFY_PAGEINFO *)); +int __db_vrfy_pgset __P((DB_ENV *, u_int32_t, DB **)); +int __db_vrfy_pgset_get __P((DB *, db_pgno_t, int *)); +int __db_vrfy_pgset_inc __P((DB *, db_pgno_t)); +int __db_vrfy_pgset_dec __P((DB *, db_pgno_t)); +int __db_vrfy_pgset_next __P((DBC *, db_pgno_t *)); +int __db_vrfy_childcursor __P((VRFY_DBINFO *, DBC **)); +int __db_vrfy_childput + __P((VRFY_DBINFO *, db_pgno_t, VRFY_CHILDINFO *)); +int __db_vrfy_ccset __P((DBC *, db_pgno_t, VRFY_CHILDINFO **)); +int __db_vrfy_ccnext __P((DBC *, VRFY_CHILDINFO **)); +int __db_vrfy_ccclose __P((DBC *)); +int __db_vrfy_pageinfo_create __P((VRFY_PAGEINFO **)); +int __db_salvage_init __P((VRFY_DBINFO *)); +void __db_salvage_destroy __P((VRFY_DBINFO *)); +int __db_salvage_getnext + __P((VRFY_DBINFO *, db_pgno_t *, u_int32_t *)); +int __db_salvage_isdone __P((VRFY_DBINFO *, db_pgno_t)); +int __db_salvage_markdone __P((VRFY_DBINFO *, db_pgno_t)); +int __db_salvage_markneeded + __P((VRFY_DBINFO *, db_pgno_t, u_int32_t)); +#if defined(__cplusplus) +} +#endif +#endif /* _db_ext_h_ */ diff --git a/db/include/db_int.src b/db/include/db_int.src new file mode 100644 index 000000000..347169ab5 --- /dev/null +++ b/db/include/db_int.src @@ -0,0 +1,397 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: db_int.src,v 11.42 2001/01/11 17:49:17 krinsky Exp $ + */ + +#ifndef _DB_INTERNAL_H_ +#define _DB_INTERNAL_H_ + +/******************************************************* + * General includes. + *******************************************************/ +#include "db.h" + +#ifndef NO_SYSTEM_INCLUDES +#if defined(__STDC__) || defined(__cplusplus) +#include +#else +#include +#endif +#include +#endif + +#include "queue.h" +#include "shqueue.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +/******************************************************* + * General purpose constants and macros. + *******************************************************/ +#define UINT16_T_MAX 0xffff /* Maximum 16 bit unsigned. */ +#define UINT32_T_MAX 0xffffffff /* Maximum 32 bit unsigned. */ + +#define MEGABYTE 1048576 +#define GIGABYTE 1073741824 + +#define MS_PER_SEC 1000 /* Milliseconds in a second. */ +#define USEC_PER_MS 1000 /* Microseconds in a millisecond. */ + +#define DB_MIN_PGSIZE 0x000200 /* Minimum page size (512). */ +#define DB_MAX_PGSIZE 0x010000 /* Maximum page size (65536). */ + +#define RECNO_OOB 0 /* Illegal record number. */ + +/* + * If we are unable to determine the underlying filesystem block size, use + * 8K on the grounds that most OS's use less than 8K for a VM page size. + */ +#define DB_DEF_IOSIZE (8 * 1024) + +/* + * Aligning items to particular sizes or in pages or memory. + * + * db_align_t -- + * Largest integral type, used to align structures in memory. We don't store + * floating point types in structures, so integral types should be sufficient + * (and we don't have to worry about systems that store floats in other than + * power-of-2 numbers of bytes). Additionally this fixes compiler that rewrite + * structure assignments and ANSI C memcpy calls to be in-line instructions + * that happen to require alignment. Note: this alignment isn't sufficient for + * mutexes, which depend on things like cache line alignment. Mutex alignment + * is handled separately, in mutex.h. + * + * db_alignp_t -- + * Integral type that's the same size as a pointer. There are places where + * DB modifies pointers by discarding the bottom bits to guarantee alignment. + * We can't use db_align_t, it may be larger than the pointer, and compilers + * get upset about that. So far we haven't run on any machine where there + * isn't an integral type the same size as a pointer -- here's hoping. + */ +@db_align_t_decl@ +@db_alignp_t_decl@ + +/* Align an integer to a specific boundary. */ +#undef ALIGN +#define ALIGN(value, bound) \ + (((value) + (bound) - 1) & ~(((u_int)bound) - 1)) + +/* Align a pointer to a specific boundary. */ +#undef ALIGNP +#define ALIGNP(value, bound) ALIGN((db_alignp_t)value, bound) + +/* + * There are several on-page structures that are declared to have a number of + * fields followed by a variable length array of items. The structure size + * without including the variable length array or the address of the first of + * those elements can be found using SSZ. + * + * This macro can also be used to find the offset of a structure element in a + * structure. This is used in various places to copy structure elements from + * unaligned memory references, e.g., pointers into a packed page. + * + * There are two versions because compilers object if you take the address of + * an array. + */ +#undef SSZ +#define SSZ(name, field) ((int)&(((name *)0)->field)) + +#undef SSZA +#define SSZA(name, field) ((int)&(((name *)0)->field[0])) + +/* + * Print an address as a u_long (a u_long is the largest type we can print + * portably). Most 64-bit systems have made longs 64-bits, so this should + * work. + */ +#define P_TO_ULONG(p) ((u_long)(db_alignp_t)(p)) + +/* Structure used to print flag values. */ +typedef struct __fn { + u_int32_t mask; /* Flag value. */ + const char *name; /* Flag name. */ +} FN; + +/* Set, clear and test flags. */ +#define FLD_CLR(fld, f) (fld) &= ~(f) +#define FLD_ISSET(fld, f) ((fld) & (f)) +#define FLD_SET(fld, f) (fld) |= (f) +#define F_CLR(p, f) (p)->flags &= ~(f) +#define F_ISSET(p, f) ((p)->flags & (f)) +#define F_SET(p, f) (p)->flags |= (f) +#define LF_CLR(f) (flags &= ~(f)) +#define LF_ISSET(f) (flags & (f)) +#define LF_SET(f) (flags |= (f)) + +/* Display separator string. */ +#undef DB_LINE +#define DB_LINE "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=" + +/* Unused, or not-used-yet variable. "Shut that bloody compiler up!" */ +#define COMPQUIET(n, v) (n) = (v) + +/******************************************************* + * Files. + *******************************************************/ + /* + * We use 1024 as the maximum path length. It's too hard to figure out what + * the real path length is, as it was traditionally stored in , + * and that file isn't always available. + */ +#undef MAXPATHLEN +#define MAXPATHLEN 1024 + +#define PATH_DOT "." /* Current working directory. */ +#define PATH_SEPARATOR "/" /* Path separator character. */ + +/* + * Flags understood by __os_open. + */ +#define DB_OSO_CREATE 0x001 /* POSIX: O_CREAT */ +#define DB_OSO_EXCL 0x002 /* POSIX: O_EXCL */ +#define DB_OSO_LOG 0x004 /* Opening a log file. */ +#define DB_OSO_RDONLY 0x008 /* POSIX: O_RDONLY */ +#define DB_OSO_REGION 0x010 /* Opening a region file. */ +#define DB_OSO_SEQ 0x020 /* Expected sequential access. */ +#define DB_OSO_TEMP 0x040 /* Remove after last close. */ +#define DB_OSO_TRUNC 0x080 /* POSIX: O_TRUNC */ + +/* + * Seek options understood by __os_seek. + */ +typedef enum { + DB_OS_SEEK_CUR, /* POSIX: SEEK_CUR */ + DB_OS_SEEK_END, /* POSIX: SEEK_END */ + DB_OS_SEEK_SET /* POSIX: SEEK_SET */ +} DB_OS_SEEK; + +/******************************************************* + * Environment. + *******************************************************/ +/* Type passed to __db_appname(). */ +typedef enum { + DB_APP_NONE=0, /* No type (region). */ + DB_APP_DATA, /* Data file. */ + DB_APP_LOG, /* Log file. */ + DB_APP_TMP /* Temporary file. */ +} APPNAME; + +/* + * CDB_LOCKING CDB product locking. + * LOCKING_ON Locking has been configured. + * LOGGING_ON Logging has been configured. + * MPOOL_ON Memory pool has been configured. + * TXN_ON Transactions have been configured. + */ +#define CDB_LOCKING(dbenv) F_ISSET(dbenv, DB_ENV_CDB) +#define LOCKING_ON(dbenv) ((dbenv)->lk_handle != NULL) +#define LOGGING_ON(dbenv) ((dbenv)->lg_handle != NULL) +#define MPOOL_ON(dbenv) ((dbenv)->mp_handle != NULL) +#define TXN_ON(dbenv) ((dbenv)->tx_handle != NULL) + +/* + * STD_LOCKING Standard locking, that is, locking was configured and CDB + * was not. We do not do locking in off-page duplicate trees, + * so we check for that in the cursor first. + */ +#define STD_LOCKING(dbc) \ + (!F_ISSET(dbc, DBC_OPD) && \ + !CDB_LOCKING((dbc)->dbp->dbenv) && LOCKING_ON((dbc)->dbp->dbenv)) + +/* + * IS_RECOVERING The system is running recovery. + */ +#define IS_RECOVERING(dbenv) \ + (LOGGING_ON(dbenv) && \ + F_ISSET((DB_LOG *)(dbenv)->lg_handle, DBLOG_RECOVER)) + +/* Most initialization methods cannot be called after open is called. */ +#define ENV_ILLEGAL_AFTER_OPEN(dbenv, name) \ + if (F_ISSET((dbenv), DB_ENV_OPEN_CALLED)) \ + return (__db_mi_open(dbenv, name, 1)); + +/* We're not actually user hostile, honest. */ +#define ENV_REQUIRES_CONFIG(dbenv, handle, subsystem) \ + if (handle == NULL) \ + return (__db_env_config(dbenv, subsystem)); + +/******************************************************* + * Database Access Methods. + *******************************************************/ +/* + * DB_IS_THREADED -- + * The database handle is free-threaded (was opened with DB_THREAD). + */ +#define DB_IS_THREADED(dbp) \ + ((dbp)->mutexp != NULL) + +/* Initialization methods are often illegal before/after open is called. */ +#define DB_ILLEGAL_AFTER_OPEN(dbp, name) \ + if (F_ISSET((dbp), DB_OPEN_CALLED)) \ + return (__db_mi_open(dbp->dbenv, name, 1)); +#define DB_ILLEGAL_BEFORE_OPEN(dbp, name) \ + if (!F_ISSET((dbp), DB_OPEN_CALLED)) \ + return (__db_mi_open(dbp->dbenv, name, 0)); +/* Some initialization methods are illegal if environment isn't local. */ +#define DB_ILLEGAL_IN_ENV(dbp, name) \ + if (!F_ISSET(dbp->dbenv, DB_ENV_DBLOCAL)) \ + return (__db_mi_env(dbp->dbenv, name)); +#define DB_ILLEGAL_METHOD(dbp, flags) { \ + int __ret; \ + if ((__ret = __dbh_am_chk(dbp, flags)) != 0) \ + return (__ret); \ +} + +/* + * Common DBC->internal fields. Each access method adds additional fields + * to this list, but the initial fields are common. + */ +#define __DBC_INTERNAL \ + DBC *opd; /* Off-page duplicate cursor. */\ + \ + void *page; /* Referenced page. */ \ + db_pgno_t root; /* Tree root. */ \ + db_pgno_t pgno; /* Referenced page number. */ \ + db_indx_t indx; /* Referenced key item index. */\ + \ + DB_LOCK lock; /* Cursor lock. */ \ + db_lockmode_t lock_mode; /* Lock mode. */ + +struct __dbc_internal { + __DBC_INTERNAL +}; + +/* + * Access-method-common macro for determining whether a cursor + * has been initialized. + */ +#define IS_INITIALIZED(dbc) ((dbc)->internal->pgno != PGNO_INVALID) + +/******************************************************* + * Mpool. + *******************************************************/ +/* + * File types for DB access methods. Negative numbers are reserved to DB. + */ +#define DB_FTYPE_SET -1 /* Call pgin/pgout functions. */ +#define DB_FTYPE_NOTSET 0 /* Don't call... */ + +/* Structure used as the DB pgin/pgout pgcookie. */ +typedef struct __dbpginfo { + size_t db_pagesize; /* Underlying page size. */ + int needswap; /* If swapping required. */ +} DB_PGINFO; + +/******************************************************* + * Log. + *******************************************************/ +/* Initialize an LSN to 'zero'. */ +#define ZERO_LSN(LSN) do { \ + (LSN).file = 0; \ + (LSN).offset = 0; \ +} while (0) + +/* Return 1 if LSN is a 'zero' lsn, otherwise return 0. */ +#define IS_ZERO_LSN(LSN) ((LSN).file == 0) + +/* Test if we need to log a change. */ +#define DB_LOGGING(dbc) \ + (LOGGING_ON((dbc)->dbp->dbenv) && !F_ISSET(dbc, DBC_RECOVER)) + +/* Internal flag for use with internal __log_unregister. */ +#define DB_LOGONLY 0x01 +/******************************************************* + * Txn. + *******************************************************/ +#define DB_NONBLOCK(C) ((C)->txn != NULL && F_ISSET((C)->txn, TXN_NOWAIT)) +#define IS_SUBTRANSACTION(txn) \ + ((txn) != NULL && (txn)->parent != NULL) + +/******************************************************* + * Global variables. + *******************************************************/ +#ifdef HAVE_VXWORKS +#include "semLib.h" +#endif + +/* + * DB global variables. Done in a single structure to minimize the name-space + * pollution. + */ +typedef struct __db_globals { + u_int32_t db_pageyield; /* db_set_pageyield */ + u_int32_t db_panic; /* db_set_panic */ + u_int32_t db_region_init; /* db_set_region_init */ + u_int32_t db_tas_spins; /* db_set_tas_spins */ +#ifdef HAVE_VXWORKS + u_int32_t db_global_init; /* VxWorks: inited */ + SEM_ID db_global_lock; /* VxWorks: global semaphore */ +#endif + /* XA: list of opened environments. */ + TAILQ_HEAD(__db_envq, __db_env) db_envq; +} DB_GLOBALS; + +#ifdef DB_INITIALIZE_DB_GLOBALS +DB_GLOBALS __db_global_values = { + 0, /* db_set_pageyield */ + 1, /* db_set_panic */ + 0, /* db_set_region_init */ + 0, /* db_set_tas_spins */ +#ifdef HAVE_VXWORKS + 0, /* db_global_init */ + NULL, /* db_global_lock */ +#endif + /* XA environment queue */ + {NULL, &__db_global_values.db_envq.tqh_first} +}; +#else +extern DB_GLOBALS __db_global_values; +#endif +#define DB_GLOBAL(v) __db_global_values.v + +/* Forward structure declarations. */ +struct __db_reginfo_t; typedef struct __db_reginfo_t REGINFO; +struct __mutex_t; typedef struct __mutex_t MUTEX; +struct __vrfy_childinfo; typedef struct __vrfy_childinfo VRFY_CHILDINFO; +struct __vrfy_dbinfo; typedef struct __vrfy_dbinfo VRFY_DBINFO; +struct __vrfy_pageinfo; typedef struct __vrfy_pageinfo VRFY_PAGEINFO; +struct __db_txnlist; typedef struct __db_txnlist DB_TXNLIST; +struct __db_txnhead; typedef struct __db_txnhead DB_TXNHEAD; +typedef enum { + TXNLIST_DELETE, + TXNLIST_LSN, + TXNLIST_TXNID, + TXNLIST_PGNO +} db_txnlist_type; + +/* + * Currently, region offsets are limited to 32-bits. I expect that's going + * to have to be fixed in the not-too-distant future, since we won't want to + * split 100Gb memory pools into that many different regions. It's typedef'd + * so it won't be too painful to upgrade. + */ +typedef u_int32_t roff_t; + +#if defined(__cplusplus) +} +#endif + +/******************************************************* + * More general includes. + *******************************************************/ +#include "debug.h" +#include "mutex.h" +#include "region.h" +#include "mutex_ext.h" +#include "env_ext.h" +#include "os.h" +#include "os_ext.h" +#include "common_ext.h" + +#endif /* !_DB_INTERNAL_H_ */ diff --git a/db/include/db_join.h b/db/include/db_join.h new file mode 100644 index 000000000..d92887bb5 --- /dev/null +++ b/db/include/db_join.h @@ -0,0 +1,30 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * @(#)db_join.h 11.1 (Sleepycat) 7/25/99 + */ + +#ifndef _DB_JOIN_H_ +#define _DB_JOIN_H_ + +/* + * Joins use a join cursor that is similar to a regular DB cursor except + * that it only supports c_get and c_close functionality. Also, it does + * not support the full range of flags for get. + */ +typedef struct __join_cursor { + u_int8_t *j_exhausted; /* Array of flags; is cursor i exhausted? */ + DBC **j_curslist; /* Array of cursors in the join: constant. */ + DBC **j_fdupcurs; /* Cursors w/ first intances of current dup. */ + DBC **j_workcurs; /* Scratch cursor copies to muck with. */ + DB *j_primary; /* Primary dbp. */ + DBT j_key; /* Used to do lookups. */ + u_int32_t j_ncurs; /* How many cursors do we have? */ +#define JOIN_RETRY 0x01 /* Error on primary get; re-return same key. */ + u_int32_t flags; +} JOIN_CURSOR; + +#endif diff --git a/db/include/db_page.h b/db/include/db_page.h new file mode 100644 index 000000000..806642414 --- /dev/null +++ b/db/include/db_page.h @@ -0,0 +1,576 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: db_page.h,v 11.28 2000/12/06 19:55:45 ubell Exp $ + */ + +#ifndef _DB_PAGE_H_ +#define _DB_PAGE_H_ + +#if defined(__cplusplus) +extern "C" { +#endif + +/* + * DB page formats. + * + * !!! + * This implementation requires that values within the following structures + * NOT be padded -- note, ANSI C permits random padding within structures. + * If your compiler pads randomly you can just forget ever making DB run on + * your system. In addition, no data type can require larger alignment than + * its own size, e.g., a 4-byte data element may not require 8-byte alignment. + * + * Note that key/data lengths are often stored in db_indx_t's -- this is + * not accidental, nor does it limit the key/data size. If the key/data + * item fits on a page, it's guaranteed to be small enough to fit into a + * db_indx_t, and storing it in one saves space. + */ + +#define PGNO_INVALID 0 /* Invalid page number in any database. */ +#define PGNO_BASE_MD 0 /* Base database: metadata page number. */ + +/* Page types. */ +#define P_INVALID 0 /* Invalid page type. */ +#define __P_DUPLICATE 1 /* Duplicate. DEPRECATED in 3.1 */ +#define P_HASH 2 /* Hash. */ +#define P_IBTREE 3 /* Btree internal. */ +#define P_IRECNO 4 /* Recno internal. */ +#define P_LBTREE 5 /* Btree leaf. */ +#define P_LRECNO 6 /* Recno leaf. */ +#define P_OVERFLOW 7 /* Overflow. */ +#define P_HASHMETA 8 /* Hash metadata page. */ +#define P_BTREEMETA 9 /* Btree metadata page. */ +#define P_QAMMETA 10 /* Queue metadata page. */ +#define P_QAMDATA 11 /* Queue data page. */ +#define P_LDUP 12 /* Off-page duplicate leaf. */ +#define P_PAGETYPE_MAX 13 + +/* + * When we create pages in mpool, we ask mpool to clear some number of bytes + * in the header. This number must be at least as big as the regular page + * headers and cover enough of the btree and hash meta-data pages to obliterate + * the page type. + */ +#define DB_PAGE_DB_LEN 32 +#define DB_PAGE_QUEUE_LEN 0 + +/************************************************************************ + GENERIC METADATA PAGE HEADER + * + * !!! + * The magic and version numbers have to be in the same place in all versions + * of the metadata page as the application may not have upgraded the database. + ************************************************************************/ +typedef struct _dbmeta31 { + DB_LSN lsn; /* 00-07: LSN. */ + db_pgno_t pgno; /* 08-11: Current page number. */ + u_int32_t magic; /* 12-15: Magic number. */ + u_int32_t version; /* 16-19: Version. */ + u_int32_t pagesize; /* 20-23: Pagesize. */ + u_int8_t unused1[1]; /* 24: Unused. */ + u_int8_t type; /* 25: Page type. */ + u_int8_t unused2[2]; /* 26-27: Unused. */ + u_int32_t free; /* 28-31: Free list page number. */ + DB_LSN unused3; /* 32-39: former Lsn for allocation */ + u_int32_t key_count; /* 40-43: Cached key count. */ + u_int32_t record_count; /* 44-47: Cached record count. */ + u_int32_t flags; /* 48-51: Flags: unique to each AM. */ + /* 52-71: Unique file ID. */ + u_int8_t uid[DB_FILE_ID_LEN]; +} DBMETA31, DBMETA; + +/************************************************************************ + BTREE METADATA PAGE LAYOUT + ************************************************************************/ +typedef struct _btmeta31 { +#define BTM_DUP 0x001 /* Duplicates. */ +#define BTM_RECNO 0x002 /* Recno tree. */ +#define BTM_RECNUM 0x004 /* Btree: maintain record count. */ +#define BTM_FIXEDLEN 0x008 /* Recno: fixed length records. */ +#define BTM_RENUMBER 0x010 /* Recno: renumber on insert/delete. */ +#define BTM_SUBDB 0x020 /* Subdatabases. */ +#define BTM_DUPSORT 0x040 /* Duplicates are sorted. */ +#define BTM_MASK 0x07f + DBMETA dbmeta; /* 00-71: Generic meta-data header. */ + + u_int32_t maxkey; /* 72-75: Btree: Maxkey. */ + u_int32_t minkey; /* 76-79: Btree: Minkey. */ + u_int32_t re_len; /* 80-83: Recno: fixed-length record length. */ + u_int32_t re_pad; /* 84-87: Recno: fixed-length record pad. */ + u_int32_t root; /* 88-92: Root page. */ + + /* + * Minimum page size is 128. + */ +} BTMETA31, BTMETA; + +/************************************************************************ + HASH METADATA PAGE LAYOUT + ************************************************************************/ +typedef struct _hashmeta31 { +#define DB_HASH_DUP 0x01 /* Duplicates. */ +#define DB_HASH_SUBDB 0x02 /* Subdatabases. */ +#define DB_HASH_DUPSORT 0x04 /* Duplicates are sorted. */ + DBMETA dbmeta; /* 00-71: Generic meta-data page header. */ + + u_int32_t max_bucket; /* 72-75: ID of Maximum bucket in use */ + u_int32_t high_mask; /* 76-79: Modulo mask into table */ + u_int32_t low_mask; /* 80-83: Modulo mask into table lower half */ + u_int32_t ffactor; /* 84-87: Fill factor */ + u_int32_t nelem; /* 88-91: Number of keys in hash table */ + u_int32_t h_charkey; /* 92-95: Value of hash(CHARKEY) */ +#define NCACHED 32 /* number of spare points */ + /* 96-223: Spare pages for overflow */ + u_int32_t spares[NCACHED]; + + /* + * Minimum page size is 256. + */ +} HMETA31, HMETA; + +/************************************************************************ + QUEUE METADATA PAGE LAYOUT + ************************************************************************/ +/* + * QAM Meta data page structure + * + */ +typedef struct _qmeta32 { + DBMETA dbmeta; /* 00-71: Generic meta-data header. */ + + u_int32_t first_recno; /* 72-75: First not deleted record. */ + u_int32_t cur_recno; /* 76-79: Last recno allocated. */ + u_int32_t re_len; /* 80-83: Fixed-length record length. */ + u_int32_t re_pad; /* 84-87: Fixed-length record pad. */ + u_int32_t rec_page; /* 88-91: Records Per Page. */ + u_int32_t page_ext; /* 92-95: Pages per extent */ + + /* + * Minimum page size is 128. + */ +} QMETA32, QMETA; + +/* + * DBMETASIZE is a constant used by __db_file_setup and DB->verify + * as a buffer which is guaranteed to be larger than any possible + * metadata page size and smaller than any disk sector. + */ +#define DBMETASIZE 256 + +/************************************************************************ + BTREE/HASH MAIN PAGE LAYOUT + ************************************************************************/ +/* + * +-----------------------------------+ + * | lsn | pgno | prev pgno | + * +-----------------------------------+ + * | next pgno | entries | hf offset | + * +-----------------------------------+ + * | level | type | index | + * +-----------------------------------+ + * | index | free --> | + * +-----------+-----------------------+ + * | F R E E A R E A | + * +-----------------------------------+ + * | <-- free | item | + * +-----------------------------------+ + * | item | item | item | + * +-----------------------------------+ + * + * sizeof(PAGE) == 26 bytes, and the following indices are guaranteed to be + * two-byte aligned. + * + * For hash and btree leaf pages, index items are paired, e.g., inp[0] is the + * key for inp[1]'s data. All other types of pages only contain single items. + */ +typedef struct _db_page { + DB_LSN lsn; /* 00-07: Log sequence number. */ + db_pgno_t pgno; /* 08-11: Current page number. */ + db_pgno_t prev_pgno; /* 12-15: Previous page number. */ + db_pgno_t next_pgno; /* 16-19: Next page number. */ + db_indx_t entries; /* 20-21: Number of items on the page. */ + db_indx_t hf_offset; /* 22-23: High free byte page offset. */ + + /* + * The btree levels are numbered from the leaf to the root, starting + * with 1, so the leaf is level 1, its parent is level 2, and so on. + * We maintain this level on all btree pages, but the only place that + * we actually need it is on the root page. It would not be difficult + * to hide the byte on the root page once it becomes an internal page, + * so we could get this byte back if we needed it for something else. + */ +#define LEAFLEVEL 1 +#define MAXBTREELEVEL 255 + u_int8_t level; /* 24: Btree tree level. */ + u_int8_t type; /* 25: Page type. */ + db_indx_t inp[1]; /* Variable length index of items. */ +} PAGE; + +/* PAGE element macros. */ +#define LSN(p) (((PAGE *)p)->lsn) +#define PGNO(p) (((PAGE *)p)->pgno) +#define PREV_PGNO(p) (((PAGE *)p)->prev_pgno) +#define NEXT_PGNO(p) (((PAGE *)p)->next_pgno) +#define NUM_ENT(p) (((PAGE *)p)->entries) +#define HOFFSET(p) (((PAGE *)p)->hf_offset) +#define LEVEL(p) (((PAGE *)p)->level) +#define TYPE(p) (((PAGE *)p)->type) + +/************************************************************************ + QUEUE MAIN PAGE LAYOUT + ************************************************************************/ +typedef struct _qpage { + DB_LSN lsn; /* 00-07: Log sequence number. */ + db_pgno_t pgno; /* 08-11: Current page number. */ + u_int32_t unused0[3]; /* 12-23: Unused. */ + u_int8_t unused1[1]; /* 24: Unused. */ + u_int8_t type; /* 25: Page type. */ + u_int8_t unused2[2]; /* 26-27: Unused. */ +} QPAGE; + +/* + * !!! + * The next_pgno and prev_pgno fields are not maintained for btree and recno + * internal pages. Doing so only provides a minor performance improvement, + * it's hard to do when deleting internal pages, and it increases the chance + * of deadlock during deletes and splits because we have to re-link pages at + * more than the leaf level. + * + * !!! + * The btree/recno access method needs db_recno_t bytes of space on the root + * page to specify how many records are stored in the tree. (The alternative + * is to store the number of records in the meta-data page, which will create + * a second hot spot in trees being actively modified, or recalculate it from + * the BINTERNAL fields on each access.) Overload the PREV_PGNO field. + */ +#define RE_NREC(p) \ + ((TYPE(p) == P_IBTREE || TYPE(p) == P_IRECNO) ? \ + PREV_PGNO(p) : (TYPE(p) == P_LBTREE ? NUM_ENT(p) / 2 : NUM_ENT(p))) +#define RE_NREC_ADJ(p, adj) \ + PREV_PGNO(p) += adj; +#define RE_NREC_SET(p, num) \ + PREV_PGNO(p) = num; + +/* + * Initialize a page. + * + * !!! + * Don't modify the page's LSN, code depends on it being unchanged after a + * P_INIT call. + */ +#define P_INIT(pg, pg_size, n, pg_prev, pg_next, btl, pg_type) do { \ + PGNO(pg) = n; \ + PREV_PGNO(pg) = pg_prev; \ + NEXT_PGNO(pg) = pg_next; \ + NUM_ENT(pg) = 0; \ + HOFFSET(pg) = pg_size; \ + LEVEL(pg) = btl; \ + TYPE(pg) = pg_type; \ +} while (0) + +/* Page header length (offset to first index). */ +#define P_OVERHEAD (SSZA(PAGE, inp)) + +/* First free byte. */ +#define LOFFSET(pg) (P_OVERHEAD + NUM_ENT(pg) * sizeof(db_indx_t)) + +/* Free space on a regular page. */ +#define P_FREESPACE(pg) (HOFFSET(pg) - LOFFSET(pg)) + +/* Get a pointer to the bytes at a specific index. */ +#define P_ENTRY(pg, indx) ((u_int8_t *)pg + ((PAGE *)pg)->inp[indx]) + +/************************************************************************ + OVERFLOW PAGE LAYOUT + ************************************************************************/ + +/* + * Overflow items are referenced by HOFFPAGE and BOVERFLOW structures, which + * store a page number (the first page of the overflow item) and a length + * (the total length of the overflow item). The overflow item consists of + * some number of overflow pages, linked by the next_pgno field of the page. + * A next_pgno field of PGNO_INVALID flags the end of the overflow item. + * + * Overflow page overloads: + * The amount of overflow data stored on each page is stored in the + * hf_offset field. + * + * The implementation reference counts overflow items as it's possible + * for them to be promoted onto btree internal pages. The reference + * count is stored in the entries field. + */ +#define OV_LEN(p) (((PAGE *)p)->hf_offset) +#define OV_REF(p) (((PAGE *)p)->entries) + +/* Maximum number of bytes that you can put on an overflow page. */ +#define P_MAXSPACE(psize) ((psize) - P_OVERHEAD) + +/* Free space on an overflow page. */ +#define P_OVFLSPACE(psize, pg) (P_MAXSPACE(psize) - HOFFSET(pg)) + +/************************************************************************ + HASH PAGE LAYOUT + ************************************************************************/ + +/* Each index references a group of bytes on the page. */ +#define H_KEYDATA 1 /* Key/data item. */ +#define H_DUPLICATE 2 /* Duplicate key/data item. */ +#define H_OFFPAGE 3 /* Overflow key/data item. */ +#define H_OFFDUP 4 /* Overflow page of duplicates. */ + +/* + * !!! + * Items on hash pages are (potentially) unaligned, so we can never cast the + * (page + offset) pointer to an HKEYDATA, HOFFPAGE or HOFFDUP structure, as + * we do with B+tree on-page structures. Because we frequently want the type + * field, it requires no alignment, and it's in the same location in all three + * structures, there's a pair of macros. + */ +#define HPAGE_PTYPE(p) (*(u_int8_t *)p) +#define HPAGE_TYPE(pg, indx) (*P_ENTRY(pg, indx)) + +/* + * The first and second types are H_KEYDATA and H_DUPLICATE, represented + * by the HKEYDATA structure: + * + * +-----------------------------------+ + * | type | key/data ... | + * +-----------------------------------+ + * + * For duplicates, the data field encodes duplicate elements in the data + * field: + * + * +---------------------------------------------------------------+ + * | type | len1 | element1 | len1 | len2 | element2 | len2 | + * +---------------------------------------------------------------+ + * + * Thus, by keeping track of the offset in the element, we can do both + * backward and forward traversal. + */ +typedef struct _hkeydata { + u_int8_t type; /* 00: Page type. */ + u_int8_t data[1]; /* Variable length key/data item. */ +} HKEYDATA; +#define HKEYDATA_DATA(p) (((u_int8_t *)p) + SSZA(HKEYDATA, data)) + +/* + * The length of any HKEYDATA item. Note that indx is an element index, + * not a PAIR index. + */ +#define LEN_HITEM(pg, pgsize, indx) \ + (((indx) == 0 ? pgsize : \ + ((PAGE *)(pg))->inp[indx - 1]) - ((PAGE *)(pg))->inp[indx]) + +#define LEN_HKEYDATA(pg, psize, indx) \ + (LEN_HITEM(pg, psize, indx) - HKEYDATA_SIZE(0)) + +/* + * Page space required to add a new HKEYDATA item to the page, with and + * without the index value. + */ +#define HKEYDATA_SIZE(len) \ + ((len) + SSZA(HKEYDATA, data)) +#define HKEYDATA_PSIZE(len) \ + (HKEYDATA_SIZE(len) + sizeof(db_indx_t)) + +/* Put a HKEYDATA item at the location referenced by a page entry. */ +#define PUT_HKEYDATA(pe, kd, len, type) { \ + ((HKEYDATA *)pe)->type = type; \ + memcpy((u_int8_t *)pe + sizeof(u_int8_t), kd, len); \ +} + +/* + * Macros the describe the page layout in terms of key-data pairs. + */ +#define H_NUMPAIRS(pg) (NUM_ENT(pg) / 2) +#define H_KEYINDEX(indx) (indx) +#define H_DATAINDEX(indx) ((indx) + 1) +#define H_PAIRKEY(pg, indx) P_ENTRY(pg, H_KEYINDEX(indx)) +#define H_PAIRDATA(pg, indx) P_ENTRY(pg, H_DATAINDEX(indx)) +#define H_PAIRSIZE(pg, psize, indx) \ + (LEN_HITEM(pg, psize, H_KEYINDEX(indx)) + \ + LEN_HITEM(pg, psize, H_DATAINDEX(indx))) +#define LEN_HDATA(p, psize, indx) LEN_HKEYDATA(p, psize, H_DATAINDEX(indx)) +#define LEN_HKEY(p, psize, indx) LEN_HKEYDATA(p, psize, H_KEYINDEX(indx)) + +/* + * The third type is the H_OFFPAGE, represented by the HOFFPAGE structure: + */ +typedef struct _hoffpage { + u_int8_t type; /* 00: Page type and delete flag. */ + u_int8_t unused[3]; /* 01-03: Padding, unused. */ + db_pgno_t pgno; /* 04-07: Offpage page number. */ + u_int32_t tlen; /* 08-11: Total length of item. */ +} HOFFPAGE; + +#define HOFFPAGE_PGNO(p) (((u_int8_t *)p) + SSZ(HOFFPAGE, pgno)) +#define HOFFPAGE_TLEN(p) (((u_int8_t *)p) + SSZ(HOFFPAGE, tlen)) + +/* + * Page space required to add a new HOFFPAGE item to the page, with and + * without the index value. + */ +#define HOFFPAGE_SIZE (sizeof(HOFFPAGE)) +#define HOFFPAGE_PSIZE (HOFFPAGE_SIZE + sizeof(db_indx_t)) + +/* + * The fourth type is H_OFFDUP represented by the HOFFDUP structure: + */ +typedef struct _hoffdup { + u_int8_t type; /* 00: Page type and delete flag. */ + u_int8_t unused[3]; /* 01-03: Padding, unused. */ + db_pgno_t pgno; /* 04-07: Offpage page number. */ +} HOFFDUP; +#define HOFFDUP_PGNO(p) (((u_int8_t *)p) + SSZ(HOFFDUP, pgno)) + +/* + * Page space required to add a new HOFFDUP item to the page, with and + * without the index value. + */ +#define HOFFDUP_SIZE (sizeof(HOFFDUP)) + +/************************************************************************ + BTREE PAGE LAYOUT + ************************************************************************/ + +/* Each index references a group of bytes on the page. */ +#define B_KEYDATA 1 /* Key/data item. */ +#define B_DUPLICATE 2 /* Duplicate key/data item. */ +#define B_OVERFLOW 3 /* Overflow key/data item. */ + +/* + * We have to store a deleted entry flag in the page. The reason is complex, + * but the simple version is that we can't delete on-page items referenced by + * a cursor -- the return order of subsequent insertions might be wrong. The + * delete flag is an overload of the top bit of the type byte. + */ +#define B_DELETE (0x80) +#define B_DCLR(t) (t) &= ~B_DELETE +#define B_DSET(t) (t) |= B_DELETE +#define B_DISSET(t) ((t) & B_DELETE) + +#define B_TYPE(t) ((t) & ~B_DELETE) +#define B_TSET(t, type, deleted) { \ + (t) = (type); \ + if (deleted) \ + B_DSET(t); \ +} + +/* + * The first type is B_KEYDATA, represented by the BKEYDATA structure: + */ +typedef struct _bkeydata { + db_indx_t len; /* 00-01: Key/data item length. */ + u_int8_t type; /* 02: Page type AND DELETE FLAG. */ + u_int8_t data[1]; /* Variable length key/data item. */ +} BKEYDATA; + +/* Get a BKEYDATA item for a specific index. */ +#define GET_BKEYDATA(pg, indx) \ + ((BKEYDATA *)P_ENTRY(pg, indx)) + +/* + * Page space required to add a new BKEYDATA item to the page, with and + * without the index value. + */ +#define BKEYDATA_SIZE(len) \ + ALIGN((len) + SSZA(BKEYDATA, data), sizeof(u_int32_t)) +#define BKEYDATA_PSIZE(len) \ + (BKEYDATA_SIZE(len) + sizeof(db_indx_t)) + +/* + * The second and third types are B_DUPLICATE and B_OVERFLOW, represented + * by the BOVERFLOW structure. + */ +typedef struct _boverflow { + db_indx_t unused1; /* 00-01: Padding, unused. */ + u_int8_t type; /* 02: Page type AND DELETE FLAG. */ + u_int8_t unused2; /* 03: Padding, unused. */ + db_pgno_t pgno; /* 04-07: Next page number. */ + u_int32_t tlen; /* 08-11: Total length of item. */ +} BOVERFLOW; + +/* Get a BOVERFLOW item for a specific index. */ +#define GET_BOVERFLOW(pg, indx) \ + ((BOVERFLOW *)P_ENTRY(pg, indx)) + +/* + * Page space required to add a new BOVERFLOW item to the page, with and + * without the index value. + */ +#define BOVERFLOW_SIZE \ + ALIGN(sizeof(BOVERFLOW), sizeof(u_int32_t)) +#define BOVERFLOW_PSIZE \ + (BOVERFLOW_SIZE + sizeof(db_indx_t)) + +/* + * Btree leaf and hash page layouts group indices in sets of two, one for the + * key and one for the data. Everything else does it in sets of one to save + * space. Use the following macros so that it's real obvious what's going on. + */ +#define O_INDX 1 +#define P_INDX 2 + +/************************************************************************ + BTREE INTERNAL PAGE LAYOUT + ************************************************************************/ + +/* + * Btree internal entry. + */ +typedef struct _binternal { + db_indx_t len; /* 00-01: Key/data item length. */ + u_int8_t type; /* 02: Page type AND DELETE FLAG. */ + u_int8_t unused; /* 03: Padding, unused. */ + db_pgno_t pgno; /* 04-07: Page number of referenced page. */ + db_recno_t nrecs; /* 08-11: Subtree record count. */ + u_int8_t data[1]; /* Variable length key item. */ +} BINTERNAL; + +/* Get a BINTERNAL item for a specific index. */ +#define GET_BINTERNAL(pg, indx) \ + ((BINTERNAL *)P_ENTRY(pg, indx)) + +/* + * Page space required to add a new BINTERNAL item to the page, with and + * without the index value. + */ +#define BINTERNAL_SIZE(len) \ + ALIGN((len) + SSZA(BINTERNAL, data), sizeof(u_int32_t)) +#define BINTERNAL_PSIZE(len) \ + (BINTERNAL_SIZE(len) + sizeof(db_indx_t)) + +/************************************************************************ + RECNO INTERNAL PAGE LAYOUT + ************************************************************************/ + +/* + * The recno internal entry. + */ +typedef struct _rinternal { + db_pgno_t pgno; /* 00-03: Page number of referenced page. */ + db_recno_t nrecs; /* 04-07: Subtree record count. */ +} RINTERNAL; + +/* Get a RINTERNAL item for a specific index. */ +#define GET_RINTERNAL(pg, indx) \ + ((RINTERNAL *)P_ENTRY(pg, indx)) + +/* + * Page space required to add a new RINTERNAL item to the page, with and + * without the index value. + */ +#define RINTERNAL_SIZE \ + ALIGN(sizeof(RINTERNAL), sizeof(u_int32_t)) +#define RINTERNAL_PSIZE \ + (RINTERNAL_SIZE + sizeof(db_indx_t)) + +#if defined(__cplusplus) +} +#endif + +#endif /* _DB_PAGE_H_ */ diff --git a/db/include/db_server.h b/db/include/db_server.h new file mode 100644 index 000000000..e12fdb212 --- /dev/null +++ b/db/include/db_server.h @@ -0,0 +1,762 @@ +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#ifndef _DB_SERVER_H_RPCGEN +#define _DB_SERVER_H_RPCGEN + +#include + +struct __env_cachesize_msg { + u_int dbenvcl_id; + u_int gbytes; + u_int bytes; + u_int ncache; +}; +typedef struct __env_cachesize_msg __env_cachesize_msg; + +struct __env_cachesize_reply { + u_int status; +}; +typedef struct __env_cachesize_reply __env_cachesize_reply; + +struct __env_close_msg { + u_int dbenvcl_id; + u_int flags; +}; +typedef struct __env_close_msg __env_close_msg; + +struct __env_close_reply { + u_int status; +}; +typedef struct __env_close_reply __env_close_reply; + +struct __env_create_msg { + u_int timeout; +}; +typedef struct __env_create_msg __env_create_msg; + +struct __env_create_reply { + u_int status; + u_int envcl_id; +}; +typedef struct __env_create_reply __env_create_reply; + +struct __env_flags_msg { + u_int dbenvcl_id; + u_int flags; + u_int onoff; +}; +typedef struct __env_flags_msg __env_flags_msg; + +struct __env_flags_reply { + u_int status; +}; +typedef struct __env_flags_reply __env_flags_reply; + +struct __env_open_msg { + u_int dbenvcl_id; + char *home; + u_int flags; + u_int mode; +}; +typedef struct __env_open_msg __env_open_msg; + +struct __env_open_reply { + u_int status; +}; +typedef struct __env_open_reply __env_open_reply; + +struct __env_remove_msg { + u_int dbenvcl_id; + char *home; + u_int flags; +}; +typedef struct __env_remove_msg __env_remove_msg; + +struct __env_remove_reply { + u_int status; +}; +typedef struct __env_remove_reply __env_remove_reply; + +struct __txn_abort_msg { + u_int txnpcl_id; +}; +typedef struct __txn_abort_msg __txn_abort_msg; + +struct __txn_abort_reply { + u_int status; +}; +typedef struct __txn_abort_reply __txn_abort_reply; + +struct __txn_begin_msg { + u_int envpcl_id; + u_int parentcl_id; + u_int flags; +}; +typedef struct __txn_begin_msg __txn_begin_msg; + +struct __txn_begin_reply { + u_int status; + u_int txnidcl_id; +}; +typedef struct __txn_begin_reply __txn_begin_reply; + +struct __txn_commit_msg { + u_int txnpcl_id; + u_int flags; +}; +typedef struct __txn_commit_msg __txn_commit_msg; + +struct __txn_commit_reply { + u_int status; +}; +typedef struct __txn_commit_reply __txn_commit_reply; + +struct __db_bt_maxkey_msg { + u_int dbpcl_id; + u_int maxkey; +}; +typedef struct __db_bt_maxkey_msg __db_bt_maxkey_msg; + +struct __db_bt_maxkey_reply { + u_int status; +}; +typedef struct __db_bt_maxkey_reply __db_bt_maxkey_reply; + +struct __db_bt_minkey_msg { + u_int dbpcl_id; + u_int minkey; +}; +typedef struct __db_bt_minkey_msg __db_bt_minkey_msg; + +struct __db_bt_minkey_reply { + u_int status; +}; +typedef struct __db_bt_minkey_reply __db_bt_minkey_reply; + +struct __db_close_msg { + u_int dbpcl_id; + u_int flags; +}; +typedef struct __db_close_msg __db_close_msg; + +struct __db_close_reply { + u_int status; +}; +typedef struct __db_close_reply __db_close_reply; + +struct __db_create_msg { + u_int flags; + u_int envpcl_id; +}; +typedef struct __db_create_msg __db_create_msg; + +struct __db_create_reply { + u_int status; + u_int dbpcl_id; +}; +typedef struct __db_create_reply __db_create_reply; + +struct __db_del_msg { + u_int dbpcl_id; + u_int txnpcl_id; + u_int keydlen; + u_int keydoff; + u_int keyflags; + struct { + u_int keydata_len; + char *keydata_val; + } keydata; + u_int flags; +}; +typedef struct __db_del_msg __db_del_msg; + +struct __db_del_reply { + u_int status; +}; +typedef struct __db_del_reply __db_del_reply; + +struct __db_extentsize_msg { + u_int dbpcl_id; + u_int extentsize; +}; +typedef struct __db_extentsize_msg __db_extentsize_msg; + +struct __db_extentsize_reply { + u_int status; +}; +typedef struct __db_extentsize_reply __db_extentsize_reply; + +struct __db_flags_msg { + u_int dbpcl_id; + u_int flags; +}; +typedef struct __db_flags_msg __db_flags_msg; + +struct __db_flags_reply { + u_int status; +}; +typedef struct __db_flags_reply __db_flags_reply; + +struct __db_get_msg { + u_int dbpcl_id; + u_int txnpcl_id; + u_int keydlen; + u_int keydoff; + u_int keyflags; + struct { + u_int keydata_len; + char *keydata_val; + } keydata; + u_int datadlen; + u_int datadoff; + u_int dataflags; + struct { + u_int datadata_len; + char *datadata_val; + } datadata; + u_int flags; +}; +typedef struct __db_get_msg __db_get_msg; + +struct __db_get_reply { + u_int status; + struct { + u_int keydata_len; + char *keydata_val; + } keydata; + struct { + u_int datadata_len; + char *datadata_val; + } datadata; +}; +typedef struct __db_get_reply __db_get_reply; + +struct __db_h_ffactor_msg { + u_int dbpcl_id; + u_int ffactor; +}; +typedef struct __db_h_ffactor_msg __db_h_ffactor_msg; + +struct __db_h_ffactor_reply { + u_int status; +}; +typedef struct __db_h_ffactor_reply __db_h_ffactor_reply; + +struct __db_h_nelem_msg { + u_int dbpcl_id; + u_int nelem; +}; +typedef struct __db_h_nelem_msg __db_h_nelem_msg; + +struct __db_h_nelem_reply { + u_int status; +}; +typedef struct __db_h_nelem_reply __db_h_nelem_reply; + +struct __db_key_range_msg { + u_int dbpcl_id; + u_int txnpcl_id; + u_int keydlen; + u_int keydoff; + u_int keyflags; + struct { + u_int keydata_len; + char *keydata_val; + } keydata; + u_int flags; +}; +typedef struct __db_key_range_msg __db_key_range_msg; + +struct __db_key_range_reply { + u_int status; + double less; + double equal; + double greater; +}; +typedef struct __db_key_range_reply __db_key_range_reply; + +struct __db_lorder_msg { + u_int dbpcl_id; + u_int lorder; +}; +typedef struct __db_lorder_msg __db_lorder_msg; + +struct __db_lorder_reply { + u_int status; +}; +typedef struct __db_lorder_reply __db_lorder_reply; + +struct __db_open_msg { + u_int dbpcl_id; + char *name; + char *subdb; + u_int type; + u_int flags; + u_int mode; +}; +typedef struct __db_open_msg __db_open_msg; + +struct __db_open_reply { + u_int status; + u_int type; + u_int dbflags; +}; +typedef struct __db_open_reply __db_open_reply; + +struct __db_pagesize_msg { + u_int dbpcl_id; + u_int pagesize; +}; +typedef struct __db_pagesize_msg __db_pagesize_msg; + +struct __db_pagesize_reply { + u_int status; +}; +typedef struct __db_pagesize_reply __db_pagesize_reply; + +struct __db_put_msg { + u_int dbpcl_id; + u_int txnpcl_id; + u_int keydlen; + u_int keydoff; + u_int keyflags; + struct { + u_int keydata_len; + char *keydata_val; + } keydata; + u_int datadlen; + u_int datadoff; + u_int dataflags; + struct { + u_int datadata_len; + char *datadata_val; + } datadata; + u_int flags; +}; +typedef struct __db_put_msg __db_put_msg; + +struct __db_put_reply { + u_int status; + struct { + u_int keydata_len; + char *keydata_val; + } keydata; +}; +typedef struct __db_put_reply __db_put_reply; + +struct __db_re_delim_msg { + u_int dbpcl_id; + u_int delim; +}; +typedef struct __db_re_delim_msg __db_re_delim_msg; + +struct __db_re_delim_reply { + u_int status; +}; +typedef struct __db_re_delim_reply __db_re_delim_reply; + +struct __db_re_len_msg { + u_int dbpcl_id; + u_int len; +}; +typedef struct __db_re_len_msg __db_re_len_msg; + +struct __db_re_len_reply { + u_int status; +}; +typedef struct __db_re_len_reply __db_re_len_reply; + +struct __db_re_pad_msg { + u_int dbpcl_id; + u_int pad; +}; +typedef struct __db_re_pad_msg __db_re_pad_msg; + +struct __db_re_pad_reply { + u_int status; +}; +typedef struct __db_re_pad_reply __db_re_pad_reply; + +struct __db_remove_msg { + u_int dbpcl_id; + char *name; + char *subdb; + u_int flags; +}; +typedef struct __db_remove_msg __db_remove_msg; + +struct __db_remove_reply { + u_int status; +}; +typedef struct __db_remove_reply __db_remove_reply; + +struct __db_rename_msg { + u_int dbpcl_id; + char *name; + char *subdb; + char *newname; + u_int flags; +}; +typedef struct __db_rename_msg __db_rename_msg; + +struct __db_rename_reply { + u_int status; +}; +typedef struct __db_rename_reply __db_rename_reply; + +struct __db_stat_msg { + u_int dbpcl_id; + u_int flags; +}; +typedef struct __db_stat_msg __db_stat_msg; + +struct __db_stat_statsreplist { + struct { + u_int ent_len; + char *ent_val; + } ent; + struct __db_stat_statsreplist *next; +}; +typedef struct __db_stat_statsreplist __db_stat_statsreplist; + +struct __db_stat_reply { + u_int status; + __db_stat_statsreplist *statslist; +}; +typedef struct __db_stat_reply __db_stat_reply; + +struct __db_swapped_msg { + u_int dbpcl_id; +}; +typedef struct __db_swapped_msg __db_swapped_msg; + +struct __db_swapped_reply { + u_int status; +}; +typedef struct __db_swapped_reply __db_swapped_reply; + +struct __db_sync_msg { + u_int dbpcl_id; + u_int flags; +}; +typedef struct __db_sync_msg __db_sync_msg; + +struct __db_sync_reply { + u_int status; +}; +typedef struct __db_sync_reply __db_sync_reply; + +struct __db_cursor_msg { + u_int dbpcl_id; + u_int txnpcl_id; + u_int flags; +}; +typedef struct __db_cursor_msg __db_cursor_msg; + +struct __db_cursor_reply { + u_int status; + u_int dbcidcl_id; +}; +typedef struct __db_cursor_reply __db_cursor_reply; + +struct __db_join_curslist { + struct { + u_int ent_len; + char *ent_val; + } ent; + struct __db_join_curslist *next; +}; +typedef struct __db_join_curslist __db_join_curslist; + +struct __db_join_msg { + u_int dbpcl_id; + __db_join_curslist *curslist; + u_int flags; +}; +typedef struct __db_join_msg __db_join_msg; + +struct __db_join_reply { + u_int status; + u_int dbcidcl_id; +}; +typedef struct __db_join_reply __db_join_reply; + +struct __dbc_close_msg { + u_int dbccl_id; +}; +typedef struct __dbc_close_msg __dbc_close_msg; + +struct __dbc_close_reply { + u_int status; +}; +typedef struct __dbc_close_reply __dbc_close_reply; + +struct __dbc_count_msg { + u_int dbccl_id; + u_int flags; +}; +typedef struct __dbc_count_msg __dbc_count_msg; + +struct __dbc_count_reply { + u_int status; + u_int dupcount; +}; +typedef struct __dbc_count_reply __dbc_count_reply; + +struct __dbc_del_msg { + u_int dbccl_id; + u_int flags; +}; +typedef struct __dbc_del_msg __dbc_del_msg; + +struct __dbc_del_reply { + u_int status; +}; +typedef struct __dbc_del_reply __dbc_del_reply; + +struct __dbc_dup_msg { + u_int dbccl_id; + u_int flags; +}; +typedef struct __dbc_dup_msg __dbc_dup_msg; + +struct __dbc_dup_reply { + u_int status; + u_int dbcidcl_id; +}; +typedef struct __dbc_dup_reply __dbc_dup_reply; + +struct __dbc_get_msg { + u_int dbccl_id; + u_int keydlen; + u_int keydoff; + u_int keyflags; + struct { + u_int keydata_len; + char *keydata_val; + } keydata; + u_int datadlen; + u_int datadoff; + u_int dataflags; + struct { + u_int datadata_len; + char *datadata_val; + } datadata; + u_int flags; +}; +typedef struct __dbc_get_msg __dbc_get_msg; + +struct __dbc_get_reply { + u_int status; + struct { + u_int keydata_len; + char *keydata_val; + } keydata; + struct { + u_int datadata_len; + char *datadata_val; + } datadata; +}; +typedef struct __dbc_get_reply __dbc_get_reply; + +struct __dbc_put_msg { + u_int dbccl_id; + u_int keydlen; + u_int keydoff; + u_int keyflags; + struct { + u_int keydata_len; + char *keydata_val; + } keydata; + u_int datadlen; + u_int datadoff; + u_int dataflags; + struct { + u_int datadata_len; + char *datadata_val; + } datadata; + u_int flags; +}; +typedef struct __dbc_put_msg __dbc_put_msg; + +struct __dbc_put_reply { + u_int status; + struct { + u_int keydata_len; + char *keydata_val; + } keydata; +}; +typedef struct __dbc_put_reply __dbc_put_reply; + +#define DB_SERVERPROG ((unsigned long)(351457)) +#define DB_SERVERVERS ((unsigned long)(1)) +#define __DB_env_cachesize ((unsigned long)(1)) +extern __env_cachesize_reply * __db_env_cachesize_1(); +#define __DB_env_close ((unsigned long)(2)) +extern __env_close_reply * __db_env_close_1(); +#define __DB_env_create ((unsigned long)(3)) +extern __env_create_reply * __db_env_create_1(); +#define __DB_env_flags ((unsigned long)(4)) +extern __env_flags_reply * __db_env_flags_1(); +#define __DB_env_open ((unsigned long)(5)) +extern __env_open_reply * __db_env_open_1(); +#define __DB_env_remove ((unsigned long)(6)) +extern __env_remove_reply * __db_env_remove_1(); +#define __DB_txn_abort ((unsigned long)(7)) +extern __txn_abort_reply * __db_txn_abort_1(); +#define __DB_txn_begin ((unsigned long)(8)) +extern __txn_begin_reply * __db_txn_begin_1(); +#define __DB_txn_commit ((unsigned long)(9)) +extern __txn_commit_reply * __db_txn_commit_1(); +#define __DB_db_bt_maxkey ((unsigned long)(10)) +extern __db_bt_maxkey_reply * __db_db_bt_maxkey_1(); +#define __DB_db_bt_minkey ((unsigned long)(11)) +extern __db_bt_minkey_reply * __db_db_bt_minkey_1(); +#define __DB_db_close ((unsigned long)(12)) +extern __db_close_reply * __db_db_close_1(); +#define __DB_db_create ((unsigned long)(13)) +extern __db_create_reply * __db_db_create_1(); +#define __DB_db_del ((unsigned long)(14)) +extern __db_del_reply * __db_db_del_1(); +#define __DB_db_extentsize ((unsigned long)(15)) +extern __db_extentsize_reply * __db_db_extentsize_1(); +#define __DB_db_flags ((unsigned long)(16)) +extern __db_flags_reply * __db_db_flags_1(); +#define __DB_db_get ((unsigned long)(17)) +extern __db_get_reply * __db_db_get_1(); +#define __DB_db_h_ffactor ((unsigned long)(18)) +extern __db_h_ffactor_reply * __db_db_h_ffactor_1(); +#define __DB_db_h_nelem ((unsigned long)(19)) +extern __db_h_nelem_reply * __db_db_h_nelem_1(); +#define __DB_db_key_range ((unsigned long)(20)) +extern __db_key_range_reply * __db_db_key_range_1(); +#define __DB_db_lorder ((unsigned long)(21)) +extern __db_lorder_reply * __db_db_lorder_1(); +#define __DB_db_open ((unsigned long)(22)) +extern __db_open_reply * __db_db_open_1(); +#define __DB_db_pagesize ((unsigned long)(23)) +extern __db_pagesize_reply * __db_db_pagesize_1(); +#define __DB_db_put ((unsigned long)(24)) +extern __db_put_reply * __db_db_put_1(); +#define __DB_db_re_delim ((unsigned long)(25)) +extern __db_re_delim_reply * __db_db_re_delim_1(); +#define __DB_db_re_len ((unsigned long)(26)) +extern __db_re_len_reply * __db_db_re_len_1(); +#define __DB_db_re_pad ((unsigned long)(27)) +extern __db_re_pad_reply * __db_db_re_pad_1(); +#define __DB_db_remove ((unsigned long)(28)) +extern __db_remove_reply * __db_db_remove_1(); +#define __DB_db_rename ((unsigned long)(29)) +extern __db_rename_reply * __db_db_rename_1(); +#define __DB_db_stat ((unsigned long)(30)) +extern __db_stat_reply * __db_db_stat_1(); +#define __DB_db_swapped ((unsigned long)(31)) +extern __db_swapped_reply * __db_db_swapped_1(); +#define __DB_db_sync ((unsigned long)(32)) +extern __db_sync_reply * __db_db_sync_1(); +#define __DB_db_cursor ((unsigned long)(33)) +extern __db_cursor_reply * __db_db_cursor_1(); +#define __DB_db_join ((unsigned long)(34)) +extern __db_join_reply * __db_db_join_1(); +#define __DB_dbc_close ((unsigned long)(35)) +extern __dbc_close_reply * __db_dbc_close_1(); +#define __DB_dbc_count ((unsigned long)(36)) +extern __dbc_count_reply * __db_dbc_count_1(); +#define __DB_dbc_del ((unsigned long)(37)) +extern __dbc_del_reply * __db_dbc_del_1(); +#define __DB_dbc_dup ((unsigned long)(38)) +extern __dbc_dup_reply * __db_dbc_dup_1(); +#define __DB_dbc_get ((unsigned long)(39)) +extern __dbc_get_reply * __db_dbc_get_1(); +#define __DB_dbc_put ((unsigned long)(40)) +extern __dbc_put_reply * __db_dbc_put_1(); +extern int db_serverprog_1_freeresult(); + +/* the xdr functions */ +extern bool_t xdr___env_cachesize_msg(); +extern bool_t xdr___env_cachesize_reply(); +extern bool_t xdr___env_close_msg(); +extern bool_t xdr___env_close_reply(); +extern bool_t xdr___env_create_msg(); +extern bool_t xdr___env_create_reply(); +extern bool_t xdr___env_flags_msg(); +extern bool_t xdr___env_flags_reply(); +extern bool_t xdr___env_open_msg(); +extern bool_t xdr___env_open_reply(); +extern bool_t xdr___env_remove_msg(); +extern bool_t xdr___env_remove_reply(); +extern bool_t xdr___txn_abort_msg(); +extern bool_t xdr___txn_abort_reply(); +extern bool_t xdr___txn_begin_msg(); +extern bool_t xdr___txn_begin_reply(); +extern bool_t xdr___txn_commit_msg(); +extern bool_t xdr___txn_commit_reply(); +extern bool_t xdr___db_bt_maxkey_msg(); +extern bool_t xdr___db_bt_maxkey_reply(); +extern bool_t xdr___db_bt_minkey_msg(); +extern bool_t xdr___db_bt_minkey_reply(); +extern bool_t xdr___db_close_msg(); +extern bool_t xdr___db_close_reply(); +extern bool_t xdr___db_create_msg(); +extern bool_t xdr___db_create_reply(); +extern bool_t xdr___db_del_msg(); +extern bool_t xdr___db_del_reply(); +extern bool_t xdr___db_extentsize_msg(); +extern bool_t xdr___db_extentsize_reply(); +extern bool_t xdr___db_flags_msg(); +extern bool_t xdr___db_flags_reply(); +extern bool_t xdr___db_get_msg(); +extern bool_t xdr___db_get_reply(); +extern bool_t xdr___db_h_ffactor_msg(); +extern bool_t xdr___db_h_ffactor_reply(); +extern bool_t xdr___db_h_nelem_msg(); +extern bool_t xdr___db_h_nelem_reply(); +extern bool_t xdr___db_key_range_msg(); +extern bool_t xdr___db_key_range_reply(); +extern bool_t xdr___db_lorder_msg(); +extern bool_t xdr___db_lorder_reply(); +extern bool_t xdr___db_open_msg(); +extern bool_t xdr___db_open_reply(); +extern bool_t xdr___db_pagesize_msg(); +extern bool_t xdr___db_pagesize_reply(); +extern bool_t xdr___db_put_msg(); +extern bool_t xdr___db_put_reply(); +extern bool_t xdr___db_re_delim_msg(); +extern bool_t xdr___db_re_delim_reply(); +extern bool_t xdr___db_re_len_msg(); +extern bool_t xdr___db_re_len_reply(); +extern bool_t xdr___db_re_pad_msg(); +extern bool_t xdr___db_re_pad_reply(); +extern bool_t xdr___db_remove_msg(); +extern bool_t xdr___db_remove_reply(); +extern bool_t xdr___db_rename_msg(); +extern bool_t xdr___db_rename_reply(); +extern bool_t xdr___db_stat_msg(); +extern bool_t xdr___db_stat_statsreplist(); +extern bool_t xdr___db_stat_reply(); +extern bool_t xdr___db_swapped_msg(); +extern bool_t xdr___db_swapped_reply(); +extern bool_t xdr___db_sync_msg(); +extern bool_t xdr___db_sync_reply(); +extern bool_t xdr___db_cursor_msg(); +extern bool_t xdr___db_cursor_reply(); +extern bool_t xdr___db_join_curslist(); +extern bool_t xdr___db_join_msg(); +extern bool_t xdr___db_join_reply(); +extern bool_t xdr___dbc_close_msg(); +extern bool_t xdr___dbc_close_reply(); +extern bool_t xdr___dbc_count_msg(); +extern bool_t xdr___dbc_count_reply(); +extern bool_t xdr___dbc_del_msg(); +extern bool_t xdr___dbc_del_reply(); +extern bool_t xdr___dbc_dup_msg(); +extern bool_t xdr___dbc_dup_reply(); +extern bool_t xdr___dbc_get_msg(); +extern bool_t xdr___dbc_get_reply(); +extern bool_t xdr___dbc_put_msg(); +extern bool_t xdr___dbc_put_reply(); + +#endif /* !_DB_SERVER_H_RPCGEN */ diff --git a/db/include/db_server_int.h b/db/include/db_server_int.h new file mode 100644 index 000000000..69e88ea5a --- /dev/null +++ b/db/include/db_server_int.h @@ -0,0 +1,85 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: db_server_int.h,v 1.13 2001/01/11 18:19:52 bostic Exp $ + */ + +#ifndef _DB_SERVER_INT_H_ +#define _DB_SERVER_INT_H_ + +#define DB_SERVER_TIMEOUT 300 /* 5 minutes */ +#define DB_SERVER_MAXTIMEOUT 1200 /* 20 minutes */ +#define DB_SERVER_IDLETIMEOUT 86400 /* 1 day */ + +#define CT_CURSOR 0x001 /* Cursor */ +#define CT_DB 0x002 /* Database */ +#define CT_ENV 0x004 /* Env */ +#define CT_TXN 0x008 /* Txn */ + +#define CT_JOIN 0x10000000 /* Join cursor component */ +#define CT_JOINCUR 0x20000000 /* Join cursor */ + +typedef struct home_entry home_entry; +struct home_entry { + LIST_ENTRY(home_entry) entries; + char *home; + char *dir; + char *name; +}; + +/* + * We maintain an activity timestamp for each handle. However, we + * set it to point, possibly to the ct_active field of its own handle + * or it may point to the ct_active field of a parent. In the case + * of nested transactions and any cursors within transactions it must + * point to the ct_active field of the ultimate parent of the transaction + * no matter how deeply it is nested. + */ +typedef struct ct_entry ct_entry; +struct ct_entry { + LIST_ENTRY(ct_entry) entries; /* List of entries */ + union { + DB_ENV *envp; /* H_ENV */ + DB_TXN *txnp; /* H_TXN */ + DB *dbp; /* H_DB */ + DBC *dbc; /* H_CURSOR */ + void *anyp; + } handle_u; + long ct_id; /* Client ID */ + long *ct_activep; /* Activity timestamp pointer*/ + long *ct_origp; /* Original timestamp pointer*/ + long ct_active; /* Activity timestamp */ + long ct_timeout; /* Resource timeout */ + long ct_idle; /* Idle timeout */ + u_int32_t ct_type; /* This entry's type */ + struct ct_entry *ct_parent; /* Its parent */ + struct ct_entry *ct_envparent; /* Its environment */ +}; + +#define ct_envp handle_u.envp +#define ct_txnp handle_u.txnp +#define ct_dbp handle_u.dbp +#define ct_dbc handle_u.dbc +#define ct_anyp handle_u.anyp + +extern int __dbsrv_verbose; + +/* + * Get ctp and activate it. + * Assumes local variable 'replyp'. + * NOTE: May 'return' from macro. + */ +#define ACTIVATE_CTP(ctp, id, type) { \ + (ctp) = get_tableent(id); \ + if ((ctp) == NULL) { \ + replyp->status = DB_NOSERVER_ID;\ + return; \ + } \ + DB_ASSERT((ctp)->ct_type & (type)); \ + __dbsrv_active(ctp); \ +} + +#endif /* _DB_SERVER_INT_H_ */ diff --git a/db/include/db_shash.h b/db/include/db_shash.h new file mode 100644 index 000000000..0b9aac98f --- /dev/null +++ b/db/include/db_shash.h @@ -0,0 +1,77 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: db_shash.h,v 11.7 2000/12/12 17:43:56 bostic Exp $ + */ + +/* Hash Headers */ +typedef SH_TAILQ_HEAD(__hash_head) DB_HASHTAB; + +/* + * HASHLOOKUP -- + * + * Look up something in a shared memory hash table. The "elt" argument + * should be a key, and cmp_func must know how to compare a key to whatever + * structure it is that appears in the hash table. The comparison function + * + * begin: address of the beginning of the hash table. + * ndx: index into table for this item. + * type: the structure type of the elements that are linked in each bucket. + * field: the name of the field by which the "type" structures are linked. + * elt: the item for which we are searching in the hash table. + * res: the variable into which we'll store the element if we find it. + * cmp: called as: cmp(lookup_elt, table_elt). + * + * If the element is not in the hash table, this macro exits with res set + * to NULL. + */ +#define HASHLOOKUP(begin, ndx, type, field, elt, res, cmp) do { \ + DB_HASHTAB *__bucket; \ + \ + __bucket = &begin[ndx]; \ + for (res = SH_TAILQ_FIRST(__bucket, type); \ + res != NULL; res = SH_TAILQ_NEXT(res, field, type)) \ + if (cmp(elt, res)) \ + break; \ +} while (0) + +/* + * HASHINSERT -- + * + * Insert a new entry into the hash table. This assumes that you already + * have the bucket locked and that lookup has failed; don't call it if you + * haven't already called HASHLOOKUP. If you do, you could get duplicate + * entries. + * + * begin: the beginning address of the hash table. + * ndx: the index for this element. + * type: the structure type of the elements that are linked in each bucket. + * field: the name of the field by which the "type" structures are linked. + * elt: the item to be inserted. + */ +#define HASHINSERT(begin, ndx, type, field, elt) do { \ + DB_HASHTAB *__bucket; \ + \ + __bucket = &begin[ndx]; \ + SH_TAILQ_INSERT_HEAD(__bucket, elt, field, type); \ +} while (0) + +/* + * HASHREMOVE_EL -- + * Given the object "obj" in the table, remove it. + * + * begin: address of the beginning of the hash table. + * ndx: index into hash table of where this element belongs. + * type: the structure type of the elements that are linked in each bucket. + * field: the name of the field by which the "type" structures are linked. + * obj: the object in the table that we with to delete. + */ +#define HASHREMOVE_EL(begin, ndx, type, field, obj) { \ + DB_HASHTAB *__bucket; \ + \ + __bucket = &begin[ndx]; \ + SH_TAILQ_REMOVE(__bucket, obj, field, type); \ +} diff --git a/db/include/db_swap.h b/db/include/db_swap.h new file mode 100644 index 000000000..bc96afb7a --- /dev/null +++ b/db/include/db_swap.h @@ -0,0 +1,115 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: db_swap.h,v 11.5 2000/03/28 16:14:36 bostic Exp $ + */ + +#ifndef _DB_SWAP_H_ +#define _DB_SWAP_H_ + +/* + * Little endian <==> big endian 32-bit swap macros. + * M_32_SWAP swap a memory location + * P_32_COPY copy potentially unaligned 4 byte quantities + * P_32_SWAP swap a referenced memory location + */ +#define M_32_SWAP(a) { \ + u_int32_t _tmp; \ + _tmp = a; \ + ((u_int8_t *)&a)[0] = ((u_int8_t *)&_tmp)[3]; \ + ((u_int8_t *)&a)[1] = ((u_int8_t *)&_tmp)[2]; \ + ((u_int8_t *)&a)[2] = ((u_int8_t *)&_tmp)[1]; \ + ((u_int8_t *)&a)[3] = ((u_int8_t *)&_tmp)[0]; \ +} +#define P_32_COPY(a, b) { \ + ((u_int8_t *)b)[0] = ((u_int8_t *)a)[0]; \ + ((u_int8_t *)b)[1] = ((u_int8_t *)a)[1]; \ + ((u_int8_t *)b)[2] = ((u_int8_t *)a)[2]; \ + ((u_int8_t *)b)[3] = ((u_int8_t *)a)[3]; \ +} +#define P_32_SWAP(a) { \ + u_int32_t _tmp; \ + P_32_COPY(a, &_tmp); \ + ((u_int8_t *)a)[0] = ((u_int8_t *)&_tmp)[3]; \ + ((u_int8_t *)a)[1] = ((u_int8_t *)&_tmp)[2]; \ + ((u_int8_t *)a)[2] = ((u_int8_t *)&_tmp)[1]; \ + ((u_int8_t *)a)[3] = ((u_int8_t *)&_tmp)[0]; \ +} + +/* + * Little endian <==> big endian 16-bit swap macros. + * M_16_SWAP swap a memory location + * P_16_COPY copy potentially unaligned 2 byte quantities + * P_16_SWAP swap a referenced memory location + */ +#define M_16_SWAP(a) { \ + u_int16_t _tmp; \ + _tmp = (u_int16_t)a; \ + ((u_int8_t *)&a)[0] = ((u_int8_t *)&_tmp)[1]; \ + ((u_int8_t *)&a)[1] = ((u_int8_t *)&_tmp)[0]; \ +} +#define P_16_COPY(a, b) { \ + ((u_int8_t *)b)[0] = ((u_int8_t *)a)[0]; \ + ((u_int8_t *)b)[1] = ((u_int8_t *)a)[1]; \ +} +#define P_16_SWAP(a) { \ + u_int16_t _tmp; \ + P_16_COPY(a, &_tmp); \ + ((u_int8_t *)a)[0] = ((u_int8_t *)&_tmp)[1]; \ + ((u_int8_t *)a)[1] = ((u_int8_t *)&_tmp)[0]; \ +} + +#define SWAP32(p) { \ + P_32_SWAP(p); \ + (p) += sizeof(u_int32_t); \ +} +#define SWAP16(p) { \ + P_16_SWAP(p); \ + (p) += sizeof(u_int16_t); \ +} + +/* + * DB has local versions of htonl() and ntohl() that only operate on pointers + * to the right size memory locations, the portability magic for finding the + * real ones isn't worth the effort. + */ +#if defined(WORDS_BIGENDIAN) +#define DB_HTONL(p) +#define DB_NTOHL(p) +#else +#define DB_HTONL(p) P_32_SWAP(p) +#define DB_NTOHL(p) P_32_SWAP(p) +#endif + +#endif /* !_DB_SWAP_H_ */ diff --git a/db/include/db_upgrade.h b/db/include/db_upgrade.h new file mode 100644 index 000000000..d8d996452 --- /dev/null +++ b/db/include/db_upgrade.h @@ -0,0 +1,174 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: db_upgrade.h,v 1.5 2000/11/16 23:40:56 ubell Exp $ + */ + +#ifndef _DB_UPGRADE_H_ +#define _DB_UPGRADE_H_ + +/* + * This file defines the metadata pages from the previous release. + * These structures are only used to upgrade old versions of databases. + */ + +/* Structures from the 3.1 release */ +/* + * QAM Meta data page structure + * + */ +typedef struct _qmeta31 { + DBMETA dbmeta; /* 00-71: Generic meta-data header. */ + + u_int32_t start; /* 72-75: Start offset. */ + u_int32_t first_recno; /* 76-79: First not deleted record. */ + u_int32_t cur_recno; /* 80-83: Last recno allocated. */ + u_int32_t re_len; /* 84-87: Fixed-length record length. */ + u_int32_t re_pad; /* 88-91: Fixed-length record pad. */ + u_int32_t rec_page; /* 92-95: Records Per Page. */ + + /* + * Minimum page size is 128. + */ +} QMETA31; + +/* Structures from the 3.0 release */ + +typedef struct _dbmeta30 { + DB_LSN lsn; /* 00-07: LSN. */ + db_pgno_t pgno; /* 08-11: Current page number. */ + u_int32_t magic; /* 12-15: Magic number. */ + u_int32_t version; /* 16-19: Version. */ + u_int32_t pagesize; /* 20-23: Pagesize. */ + u_int8_t unused1[1]; /* 24: Unused. */ + u_int8_t type; /* 25: Page type. */ + u_int8_t unused2[2]; /* 26-27: Unused. */ + u_int32_t free; /* 28-31: Free list page number. */ + u_int32_t flags; /* 32-35: Flags: unique to each AM. */ + /* 36-55: Unique file ID. */ + u_int8_t uid[DB_FILE_ID_LEN]; +} DBMETA30; + +/************************************************************************ + BTREE METADATA PAGE LAYOUT + ************************************************************************/ +typedef struct _btmeta30 { + DBMETA30 dbmeta; /* 00-55: Generic meta-data header. */ + + u_int32_t maxkey; /* 56-59: Btree: Maxkey. */ + u_int32_t minkey; /* 60-63: Btree: Minkey. */ + u_int32_t re_len; /* 64-67: Recno: fixed-length record length. */ + u_int32_t re_pad; /* 68-71: Recno: fixed-length record pad. */ + u_int32_t root; /* 72-75: Root page. */ + + /* + * Minimum page size is 128. + */ +} BTMETA30; + +/************************************************************************ + HASH METADATA PAGE LAYOUT + ************************************************************************/ +typedef struct _hashmeta30 { + DBMETA30 dbmeta; /* 00-55: Generic meta-data page header. */ + + u_int32_t max_bucket; /* 56-59: ID of Maximum bucket in use */ + u_int32_t high_mask; /* 60-63: Modulo mask into table */ + u_int32_t low_mask; /* 64-67: Modulo mask into table lower half */ + u_int32_t ffactor; /* 68-71: Fill factor */ + u_int32_t nelem; /* 72-75: Number of keys in hash table */ + u_int32_t h_charkey; /* 76-79: Value of hash(CHARKEY) */ +#define NCACHED30 32 /* number of spare points */ + /* 80-207: Spare pages for overflow */ + u_int32_t spares[NCACHED30]; + + /* + * Minimum page size is 256. + */ +} HMETA30; + +/************************************************************************ + QUEUE METADATA PAGE LAYOUT + ************************************************************************/ +/* + * QAM Meta data page structure + * + */ +typedef struct _qmeta30 { + DBMETA30 dbmeta; /* 00-55: Generic meta-data header. */ + + u_int32_t start; /* 56-59: Start offset. */ + u_int32_t first_recno; /* 60-63: First not deleted record. */ + u_int32_t cur_recno; /* 64-67: Last recno allocated. */ + u_int32_t re_len; /* 68-71: Fixed-length record length. */ + u_int32_t re_pad; /* 72-75: Fixed-length record pad. */ + u_int32_t rec_page; /* 76-79: Records Per Page. */ + + /* + * Minimum page size is 128. + */ +} QMETA30; + +/* Structures from Release 2.x */ + +/************************************************************************ + BTREE METADATA PAGE LAYOUT + ************************************************************************/ + +/* + * Btree metadata page layout: + */ +typedef struct _btmeta2X { + DB_LSN lsn; /* 00-07: LSN. */ + db_pgno_t pgno; /* 08-11: Current page number. */ + u_int32_t magic; /* 12-15: Magic number. */ + u_int32_t version; /* 16-19: Version. */ + u_int32_t pagesize; /* 20-23: Pagesize. */ + u_int32_t maxkey; /* 24-27: Btree: Maxkey. */ + u_int32_t minkey; /* 28-31: Btree: Minkey. */ + u_int32_t free; /* 32-35: Free list page number. */ + u_int32_t flags; /* 36-39: Flags. */ + u_int32_t re_len; /* 40-43: Recno: fixed-length record length. */ + u_int32_t re_pad; /* 44-47: Recno: fixed-length record pad. */ + /* 48-67: Unique file ID. */ + u_int8_t uid[DB_FILE_ID_LEN]; +} BTMETA2X; + +/************************************************************************ + HASH METADATA PAGE LAYOUT + ************************************************************************/ + +/* + * Hash metadata page layout: + */ +/* Hash Table Information */ +typedef struct hashhdr { /* Disk resident portion */ + DB_LSN lsn; /* 00-07: LSN of the header page */ + db_pgno_t pgno; /* 08-11: Page number (btree compatibility). */ + u_int32_t magic; /* 12-15: Magic NO for hash tables */ + u_int32_t version; /* 16-19: Version ID */ + u_int32_t pagesize; /* 20-23: Bucket/Page Size */ + u_int32_t ovfl_point; /* 24-27: Overflow page allocation location */ + u_int32_t last_freed; /* 28-31: Last freed overflow page pgno */ + u_int32_t max_bucket; /* 32-35: ID of Maximum bucket in use */ + u_int32_t high_mask; /* 36-39: Modulo mask into table */ + u_int32_t low_mask; /* 40-43: Modulo mask into table lower half */ + u_int32_t ffactor; /* 44-47: Fill factor */ + u_int32_t nelem; /* 48-51: Number of keys in hash table */ + u_int32_t h_charkey; /* 52-55: Value of hash(CHARKEY) */ + u_int32_t flags; /* 56-59: Allow duplicates. */ +#define NCACHED2X 32 /* number of spare points */ + /* 60-187: Spare pages for overflow */ + u_int32_t spares[NCACHED2X]; + /* 188-207: Unique file ID. */ + u_int8_t uid[DB_FILE_ID_LEN]; + + /* + * Minimum page size is 256. + */ +} HASHHDR; + +#endif diff --git a/db/include/db_verify.h b/db/include/db_verify.h new file mode 100644 index 000000000..2507f1f10 --- /dev/null +++ b/db/include/db_verify.h @@ -0,0 +1,191 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: db_verify.h,v 1.18 2000/12/31 17:51:52 bostic Exp $ + */ + +#ifndef _DB_VERIFY_H_ +#define _DB_VERIFY_H_ + +/* + * Structures and macros for the storage and retrieval of all information + * needed for inter-page verification of a database. + */ + +/* + * EPRINT is the macro for error printing. Takes as an arg the arg set + * for DB->err. + */ +#define EPRINT(x) \ + do { \ + if (!LF_ISSET(DB_SALVAGE)) \ + __db_err x; \ + } while (0) + +/* For fatal type errors--i.e., verifier bugs. */ +#define TYPE_ERR_PRINT(dbenv, func, pgno, ptype) \ + EPRINT(((dbenv), "%s called on nonsensical page %lu of type %lu", \ + (func), (u_long)(pgno), (u_long)(ptype))); + +/* Is x a power of two? (Tests true for zero, which doesn't matter here.) */ +#define POWER_OF_TWO(x) (((x) & ((x) - 1)) == 0) + +#define IS_VALID_PAGESIZE(x) \ + (POWER_OF_TWO(x) && (x) >= DB_MIN_PGSIZE && ((x) <= DB_MAX_PGSIZE)) + +/* + * Note that 0 is, in general, a valid pgno, despite equalling PGNO_INVALID; + * we have to test it separately where it's not appropriate. + */ +#define IS_VALID_PGNO(x) ((x) <= vdp->last_pgno) + +/* + * Flags understood by the btree structure checks (esp. __bam_vrfy_subtree). + * These share the same space as the global flags to __db_verify, and must not + * dip below 0x00010000. + */ +#define ST_DUPOK 0x00010000 /* Duplicates are acceptable. */ +#define ST_DUPSET 0x00020000 /* Subtree is in a duplicate tree. */ +#define ST_DUPSORT 0x00040000 /* Duplicates are sorted. */ +#define ST_IS_RECNO 0x00080000 /* Subtree is a recno. */ +#define ST_OVFL_LEAF 0x00100000 /* Overflow reffed from leaf page. */ +#define ST_RECNUM 0x00200000 /* Subtree has record numbering on. */ +#define ST_RELEN 0x00400000 /* Subtree has fixed-length records. */ +#define ST_TOPLEVEL 0x00800000 /* Subtree == entire tree */ + +/* + * Flags understood by __bam_salvage and __db_salvage. These need not share + * the same space with the __bam_vrfy_subtree flags, but must share with + * __db_verify. + */ +#define SA_SKIPFIRSTKEY 0x00080000 + +/* + * VRFY_DBINFO is the fundamental structure; it either represents the database + * of subdatabases, or the sole database if there are no subdatabases. + */ +struct __vrfy_dbinfo { + /* Info about this database in particular. */ + DBTYPE type; + + /* List of subdatabase meta pages, if any. */ + LIST_HEAD(__subdbs, __vrfy_childinfo) subdbs; + + /* File-global info--stores VRFY_PAGEINFOs for each page. */ + DB *pgdbp; + + /* Child database--stores VRFY_CHILDINFOs of each page. */ + DB *cdbp; + + /* Page info structures currently in use. */ + LIST_HEAD(__activepips, __vrfy_pageinfo) activepips; + + /* + * DB we use to keep track of which pages are linked somehow + * during verification. 0 is the default, "unseen"; 1 is seen. + */ + DB *pgset; + + /* + * This is a database we use during salvaging to keep track of which + * overflow and dup pages we need to come back to at the end and print + * with key "UNKNOWN". Pages which print with a good key get set + * to SALVAGE_IGNORE; others get set, as appropriate, to SALVAGE_LDUP, + * SALVAGE_LRECNODUP, SALVAGE_OVERFLOW for normal db overflow pages, + * and SALVAGE_BTREE, SALVAGE_LRECNO, and SALVAGE_HASH for subdb + * pages. + */ +#define SALVAGE_INVALID 0 +#define SALVAGE_IGNORE 1 +#define SALVAGE_LDUP 2 +#define SALVAGE_LRECNODUP 3 +#define SALVAGE_OVERFLOW 4 +#define SALVAGE_LBTREE 5 +#define SALVAGE_HASH 6 +#define SALVAGE_LRECNO 7 + DB *salvage_pages; + + db_pgno_t last_pgno; + db_pgno_t pgs_remaining; /* For dbp->db_feedback(). */ + + /* Queue needs these to verify data pages in the first pass. */ + u_int32_t re_len; + u_int32_t rec_page; + +#define SALVAGE_PRINTHEADER 0x01 +#define SALVAGE_PRINTFOOTER 0x02 + u_int32_t flags; +}; /* VRFY_DBINFO */ + +/* + * The amount of state information we need per-page is small enough that + * it's not worth the trouble to define separate structures for each + * possible type of page, and since we're doing verification with these we + * have to be open to the possibility that page N will be of a completely + * unexpected type anyway. So we define one structure here with all the + * info we need for inter-page verification. + */ +struct __vrfy_pageinfo { + u_int8_t type; + u_int8_t bt_level; + u_int8_t unused1; + u_int8_t unused2; + db_pgno_t pgno; + db_pgno_t prev_pgno; + db_pgno_t next_pgno; + + /* meta pages */ + db_pgno_t root; + db_pgno_t free; /* Free list head. */ + + db_indx_t entries; /* Actual number of entries. */ + u_int16_t unused; + db_recno_t rec_cnt; /* Record count. */ + u_int32_t re_len; /* Record length. */ + u_int32_t bt_minkey; + u_int32_t bt_maxkey; + u_int32_t h_ffactor; + u_int32_t h_nelem; + + /* overflow pages */ + /* + * Note that refcount is the refcount for an overflow page; pi_refcount + * is this structure's own refcount! + */ + u_int32_t refcount; + u_int32_t olen; + +#define VRFY_DUPS_UNSORTED 0x0001 /* Have to flag the negative! */ +#define VRFY_HAS_DUPS 0x0002 +#define VRFY_HAS_DUPSORT 0x0004 /* Has the flag set. */ +#define VRFY_HAS_SUBDBS 0x0008 +#define VRFY_HAS_RECNUMS 0x0010 +#define VRFY_INCOMPLETE 0x0020 /* Meta or item order checks incomp. */ +#define VRFY_IS_ALLZEROES 0x0040 /* Hash page we haven't touched? */ +#define VRFY_IS_FIXEDLEN 0x0080 +#define VRFY_IS_RECNO 0x0100 +#define VRFY_IS_RRECNO 0x0200 +#define VRFY_OVFL_LEAFSEEN 0x0400 + u_int32_t flags; + + LIST_ENTRY(__vrfy_pageinfo) links; + u_int32_t pi_refcount; +}; /* VRFY_PAGEINFO */ + +struct __vrfy_childinfo { + db_pgno_t pgno; + +#define V_DUPLICATE 1 /* off-page dup metadata */ +#define V_OVERFLOW 2 /* overflow page */ +#define V_RECNO 3 /* btree internal or leaf page */ + u_int32_t type; + db_recno_t nrecs; /* record count on a btree subtree */ + u_int32_t tlen; /* ovfl. item total size */ + + LIST_ENTRY(__vrfy_childinfo) links; +}; /* VRFY_CHILDINFO */ + +#endif /* _DB_VERIFY_H_ */ diff --git a/db/include/debug.h b/db/include/debug.h new file mode 100644 index 000000000..9a3ffc1ac --- /dev/null +++ b/db/include/debug.h @@ -0,0 +1,104 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: debug.h,v 11.17 2000/07/07 15:50:36 bostic Exp $ + */ + +#if defined(__cplusplus) +extern "C" { +#endif + +/* + * When running with #DIAGNOSTIC defined, we smash memory and do memory + * guarding with a special byte value. + */ +#define CLEAR_BYTE 0xdb +#define GUARD_BYTE 0xdc + +/* + * DB assertions. + */ +#if defined(DIAGNOSTIC) && defined(__STDC__) +#define DB_ASSERT(e) ((e) ? (void)0 : __db_assert(#e, __FILE__, __LINE__)) +#else +#define DB_ASSERT(e) ((void)0) +#endif + +/* + * Purify and other run-time tools complain about uninitialized reads/writes + * of structure fields whose only purpose is padding, as well as when heap + * memory that was never initialized is written to disk. + */ +#ifdef UMRW +#define UMRW_SET(v) (v) = 0 +#else +#define UMRW_SET(v) +#endif + +/* + * Debugging macro to log operations. + * If DEBUG_WOP is defined, log operations that modify the database. + * If DEBUG_ROP is defined, log operations that read the database. + * + * D dbp + * T txn + * O operation (string) + * K key + * A data + * F flags + */ +#define LOG_OP(C, T, O, K, A, F) { \ + DB_LSN __lsn; \ + DBT __op; \ + if (DB_LOGGING((C))) { \ + memset(&__op, 0, sizeof(__op)); \ + __op.data = O; \ + __op.size = strlen(O) + 1; \ + (void)__db_debug_log((C)->dbp->dbenv, \ + T, &__lsn, 0, &__op, (C)->dbp->log_fileid, K, A, F);\ + } \ +} +#ifdef DEBUG_ROP +#define DEBUG_LREAD(C, T, O, K, A, F) LOG_OP(C, T, O, K, A, F) +#else +#define DEBUG_LREAD(C, T, O, K, A, F) +#endif +#ifdef DEBUG_WOP +#define DEBUG_LWRITE(C, T, O, K, A, F) LOG_OP(C, T, O, K, A, F) +#else +#define DEBUG_LWRITE(C, T, O, K, A, F) +#endif + +/* + * Hook for testing recovery at various places in the create/delete paths. + */ +#if CONFIG_TEST +#define DB_TEST_RECOVERY(dbp, val, ret, name) \ +do { \ + int __ret; \ + PANIC_CHECK((dbp)->dbenv); \ + if ((dbp)->dbenv->test_copy == (val)) { \ + /* COPY the FILE */ \ + if (F_ISSET((dbp), DB_OPEN_CALLED) && (dbp)->mpf != NULL) \ + (void)(dbp)->sync((dbp), 0); \ + if ((__ret = __db_testcopy((dbp), (name))) != 0) \ + (ret) = __db_panic((dbp)->dbenv, __ret); \ + } \ + if ((dbp)->dbenv->test_abort == (val)) { \ + /* ABORT the TXN */ \ + (ret) = EINVAL; \ + goto db_tr_err; \ + } \ +} while (0) +#define DB_TEST_RECOVERY_LABEL db_tr_err: +#else +#define DB_TEST_RECOVERY(dbp, val, ret, name) +#define DB_TEST_RECOVERY_LABEL +#endif + +#if defined(__cplusplus) +} +#endif diff --git a/db/include/env_ext.h b/db/include/env_ext.h new file mode 100644 index 000000000..0e7313fde --- /dev/null +++ b/db/include/env_ext.h @@ -0,0 +1,35 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _env_ext_h_ +#define _env_ext_h_ +#if defined(__cplusplus) +extern "C" { +#endif +void __db_shalloc_init __P((void *, size_t)); +int __db_shalloc_size __P((size_t, size_t)); +int __db_shalloc __P((void *, size_t, size_t, void *)); +void __db_shalloc_free __P((void *, void *)); +size_t __db_shalloc_count __P((void *)); +size_t __db_shsizeof __P((void *)); +void __db_shalloc_dump __P((void *, FILE *)); +int __db_tablesize __P((u_int32_t)); +void __db_hashinit __P((void *, u_int32_t)); +int __dbenv_init __P((DB_ENV *)); +int __db_mi_env __P((DB_ENV *, const char *)); +int __db_mi_open __P((DB_ENV *, const char *, int)); +int __db_env_config __P((DB_ENV *, int)); +int __dbenv_open __P((DB_ENV *, const char *, u_int32_t, int)); +int __dbenv_remove __P((DB_ENV *, const char *, u_int32_t)); +int __dbenv_close __P((DB_ENV *, u_int32_t)); +int __db_appname __P((DB_ENV *, APPNAME, + const char *, const char *, u_int32_t, DB_FH *, char **)); +int __db_apprec __P((DB_ENV *, u_int32_t)); +int __db_e_attach __P((DB_ENV *, u_int32_t *)); +int __db_e_detach __P((DB_ENV *, int)); +int __db_e_remove __P((DB_ENV *, int)); +int __db_e_stat __P((DB_ENV *, REGENV *, REGION *, int *)); +int __db_r_attach __P((DB_ENV *, REGINFO *, size_t)); +int __db_r_detach __P((DB_ENV *, REGINFO *, int)); +#if defined(__cplusplus) +} +#endif +#endif /* _env_ext_h_ */ diff --git a/db/include/gen_client_ext.h b/db/include/gen_client_ext.h new file mode 100644 index 000000000..5675b74d3 --- /dev/null +++ b/db/include/gen_client_ext.h @@ -0,0 +1,121 @@ +/* Do not edit: automatically built by gen_rpc.awk. */ +int __dbcl_env_cachesize __P((DB_ENV *, u_int32_t, u_int32_t, int)); +int __dbcl_env_close __P((DB_ENV *, u_int32_t)); +int __dbcl_env_close_ret __P((DB_ENV *, u_int32_t, __env_close_reply *)); +int __dbcl_rpc_illegal __P((DB_ENV *, char *)); +int __dbcl_set_data_dir __P((DB_ENV *, const char *)); +int __dbcl_env_set_feedback __P((DB_ENV *, void (*)(DB_ENV *, int, int))); +int __dbcl_env_flags __P((DB_ENV *, u_int32_t, int)); +int __dbcl_set_lg_bsize __P((DB_ENV *, u_int32_t)); +int __dbcl_set_lg_dir __P((DB_ENV *, const char *)); +int __dbcl_set_lg_max __P((DB_ENV *, u_int32_t)); +int __dbcl_set_lk_conflict __P((DB_ENV *, u_int8_t *, int)); +int __dbcl_set_lk_detect __P((DB_ENV *, u_int32_t)); +int __dbcl_set_lk_max __P((DB_ENV *, u_int32_t)); +int __dbcl_set_lk_max_locks __P((DB_ENV *, u_int32_t)); +int __dbcl_set_lk_max_lockers __P((DB_ENV *, u_int32_t)); +int __dbcl_set_lk_max_objects __P((DB_ENV *, u_int32_t)); +int __dbcl_set_mp_mmapsize __P((DB_ENV *, size_t)); +int __dbcl_set_mutex_locks __P((DB_ENV *, int)); +int __dbcl_env_open __P((DB_ENV *, const char *, u_int32_t, int)); +int __dbcl_env_open_ret __P((DB_ENV *, const char *, u_int32_t, int, __env_open_reply *)); +int __dbcl_env_paniccall __P((DB_ENV *, void (*)(DB_ENV *, int))); +int __dbcl_set_recovery_init __P((DB_ENV *, int (*)(DB_ENV *))); +int __dbcl_env_remove __P((DB_ENV *, const char *, u_int32_t)); +int __dbcl_env_remove_ret __P((DB_ENV *, const char *, u_int32_t, __env_remove_reply *)); +int __dbcl_set_shm_key __P((DB_ENV *, long)); +int __dbcl_set_tmp_dir __P((DB_ENV *, const char *)); +int __dbcl_set_tx_recover __P((DB_ENV *, int (*)(DB_ENV *, DBT *, DB_LSN *, db_recops))); +int __dbcl_set_tx_max __P((DB_ENV *, u_int32_t)); +int __dbcl_set_tx_timestamp __P((DB_ENV *, time_t *)); +int __dbcl_set_verbose __P((DB_ENV *, u_int32_t, int)); +int __dbcl_txn_abort __P((DB_TXN *)); +int __dbcl_txn_abort_ret __P((DB_TXN *, __txn_abort_reply *)); +int __dbcl_txn_begin __P((DB_ENV *, DB_TXN *, DB_TXN **, u_int32_t)); +int __dbcl_txn_begin_ret __P((DB_ENV *, DB_TXN *, DB_TXN **, u_int32_t, __txn_begin_reply *)); +int __dbcl_txn_checkpoint __P((DB_ENV *, u_int32_t, u_int32_t)); +int __dbcl_txn_commit __P((DB_TXN *, u_int32_t)); +int __dbcl_txn_commit_ret __P((DB_TXN *, u_int32_t, __txn_commit_reply *)); +int __dbcl_txn_prepare __P((DB_TXN *)); +int __dbcl_txn_stat __P((DB_ENV *, DB_TXN_STAT **, void *(*)(size_t))); +int __dbcl_db_bt_compare __P((DB *, int (*)(DB *, const DBT *, const DBT *))); +int __dbcl_db_bt_maxkey __P((DB *, u_int32_t)); +int __dbcl_db_bt_minkey __P((DB *, u_int32_t)); +int __dbcl_db_bt_prefix __P((DB *, size_t(*)(DB *, const DBT *, const DBT *))); +int __dbcl_db_set_append_recno __P((DB *, int (*)(DB *, DBT *, db_recno_t))); +int __dbcl_db_cachesize __P((DB *, u_int32_t, u_int32_t, int)); +int __dbcl_db_close __P((DB *, u_int32_t)); +int __dbcl_db_close_ret __P((DB *, u_int32_t, __db_close_reply *)); +int __dbcl_db_del __P((DB *, DB_TXN *, DBT *, u_int32_t)); +int __dbcl_db_extentsize __P((DB *, u_int32_t)); +int __dbcl_db_fd __P((DB *, int *)); +int __dbcl_db_feedback __P((DB *, void (*)(DB *, int, int))); +int __dbcl_db_flags __P((DB *, u_int32_t)); +int __dbcl_db_get __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t)); +int __dbcl_db_get_ret __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t, __db_get_reply *)); +int __dbcl_db_h_ffactor __P((DB *, u_int32_t)); +int __dbcl_db_h_hash __P((DB *, u_int32_t(*)(DB *, const void *, u_int32_t))); +int __dbcl_db_h_nelem __P((DB *, u_int32_t)); +int __dbcl_db_key_range __P((DB *, DB_TXN *, DBT *, DB_KEY_RANGE *, u_int32_t)); +int __dbcl_db_key_range_ret __P((DB *, DB_TXN *, DBT *, DB_KEY_RANGE *, u_int32_t, __db_key_range_reply *)); +int __dbcl_db_lorder __P((DB *, int)); +int __dbcl_db_malloc __P((DB *, void *(*)(size_t))); +int __dbcl_db_open __P((DB *, const char *, const char *, DBTYPE, u_int32_t, int)); +int __dbcl_db_open_ret __P((DB *, const char *, const char *, DBTYPE, u_int32_t, int, __db_open_reply *)); +int __dbcl_db_pagesize __P((DB *, u_int32_t)); +int __dbcl_db_panic __P((DB *, void (*)(DB_ENV *, int))); +int __dbcl_db_put __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t)); +int __dbcl_db_put_ret __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t, __db_put_reply *)); +int __dbcl_db_realloc __P((DB *, void *(*)(void *, size_t))); +int __dbcl_db_re_delim __P((DB *, int)); +int __dbcl_db_re_len __P((DB *, u_int32_t)); +int __dbcl_db_re_pad __P((DB *, int)); +int __dbcl_db_re_source __P((DB *, const char *)); +int __dbcl_db_remove __P((DB *, const char *, const char *, u_int32_t)); +int __dbcl_db_remove_ret __P((DB *, const char *, const char *, u_int32_t, __db_remove_reply *)); +int __dbcl_db_rename __P((DB *, const char *, const char *, const char *, u_int32_t)); +int __dbcl_db_rename_ret __P((DB *, const char *, const char *, const char *, u_int32_t, __db_rename_reply *)); +int __dbcl_db_stat __P((DB *, void *, void *(*)(size_t), u_int32_t)); +int __dbcl_db_stat_ret __P((DB *, void *, void *(*)(size_t), u_int32_t, __db_stat_reply *)); +int __dbcl_db_swapped __P((DB *)); +int __dbcl_db_sync __P((DB *, u_int32_t)); +int __dbcl_db_upgrade __P((DB *, const char *, u_int32_t)); +int __dbcl_db_cursor __P((DB *, DB_TXN *, DBC **, u_int32_t)); +int __dbcl_db_cursor_ret __P((DB *, DB_TXN *, DBC **, u_int32_t, __db_cursor_reply *)); +int __dbcl_db_join __P((DB *, DBC **, DBC **, u_int32_t)); +int __dbcl_db_join_ret __P((DB *, DBC **, DBC **, u_int32_t, __db_join_reply *)); +int __dbcl_dbc_close __P((DBC *)); +int __dbcl_dbc_close_ret __P((DBC *, __dbc_close_reply *)); +int __dbcl_dbc_count __P((DBC *, db_recno_t *, u_int32_t)); +int __dbcl_dbc_count_ret __P((DBC *, db_recno_t *, u_int32_t, __dbc_count_reply *)); +int __dbcl_dbc_del __P((DBC *, u_int32_t)); +int __dbcl_dbc_dup __P((DBC *, DBC **, u_int32_t)); +int __dbcl_dbc_dup_ret __P((DBC *, DBC **, u_int32_t, __dbc_dup_reply *)); +int __dbcl_dbc_get __P((DBC *, DBT *, DBT *, u_int32_t)); +int __dbcl_dbc_get_ret __P((DBC *, DBT *, DBT *, u_int32_t, __dbc_get_reply *)); +int __dbcl_dbc_put __P((DBC *, DBT *, DBT *, u_int32_t)); +int __dbcl_dbc_put_ret __P((DBC *, DBT *, DBT *, u_int32_t, __dbc_put_reply *)); +int __dbcl_lock_detect __P((DB_ENV *, u_int32_t, u_int32_t, int *)); +int __dbcl_lock_get __P((DB_ENV *, u_int32_t, u_int32_t, const DBT *, db_lockmode_t, DB_LOCK *)); +int __dbcl_lock_id __P((DB_ENV *, u_int32_t *)); +int __dbcl_lock_put __P((DB_ENV *, DB_LOCK *)); +int __dbcl_lock_stat __P((DB_ENV *, DB_LOCK_STAT **, void *(*)(size_t))); +int __dbcl_lock_vec __P((DB_ENV *, u_int32_t, u_int32_t, DB_LOCKREQ *, int, DB_LOCKREQ **)); +int __dbcl_log_archive __P((DB_ENV *, char ***, u_int32_t, void *(*)(size_t))); +int __dbcl_log_file __P((DB_ENV *, const DB_LSN *, char *, size_t)); +int __dbcl_log_flush __P((DB_ENV *, const DB_LSN *)); +int __dbcl_log_get __P((DB_ENV *, DB_LSN *, DBT *, u_int32_t)); +int __dbcl_log_put __P((DB_ENV *, DB_LSN *, const DBT *, u_int32_t)); +int __dbcl_log_register __P((DB_ENV *, DB *, const char *)); +int __dbcl_log_stat __P((DB_ENV *, DB_LOG_STAT **, void *(*)(size_t))); +int __dbcl_log_unregister __P((DB_ENV *, DB *)); +int __dbcl_memp_fclose __P((DB_MPOOLFILE *)); +int __dbcl_memp_fget __P((DB_MPOOLFILE *, db_pgno_t *, u_int32_t, void **)); +int __dbcl_memp_fopen __P((DB_ENV *, const char *, u_int32_t, int, size_t, DB_MPOOL_FINFO *, DB_MPOOLFILE **)); +int __dbcl_memp_fput __P((DB_MPOOLFILE *, void *, u_int32_t)); +int __dbcl_memp_fset __P((DB_MPOOLFILE *, void *, u_int32_t)); +int __dbcl_memp_fsync __P((DB_MPOOLFILE *)); +int __dbcl_memp_register __P((DB_ENV *, int, int (*)(DB_ENV *, db_pgno_t, void *, DBT *), int (*)(DB_ENV *, db_pgno_t, void *, DBT *))); +int __dbcl_memp_stat __P((DB_ENV *, DB_MPOOL_STAT **, DB_MPOOL_FSTAT ***, void *(*)(size_t))); +int __dbcl_memp_sync __P((DB_ENV *, DB_LSN *)); +int __dbcl_memp_trickle __P((DB_ENV *, int, int *)); diff --git a/db/include/gen_server_ext.h b/db/include/gen_server_ext.h new file mode 100644 index 000000000..9037d908f --- /dev/null +++ b/db/include/gen_server_ext.h @@ -0,0 +1,106 @@ +/* Do not edit: automatically built by gen_rpc.awk. */ +__env_cachesize_reply * __db_env_cachesize_1 __P((__env_cachesize_msg *)); +void __env_cachesize_1_proc __P((long, u_int32_t, u_int32_t, + u_int32_t, __env_cachesize_reply *)); +__env_close_reply * __db_env_close_1 __P((__env_close_msg *)); +void __env_close_1_proc __P((long, u_int32_t, __env_close_reply *)); +__env_create_reply * __db_env_create_1 __P((__env_create_msg *)); +void __env_create_1_proc __P((u_int32_t, __env_create_reply *)); +__env_flags_reply * __db_env_flags_1 __P((__env_flags_msg *)); +void __env_flags_1_proc __P((long, u_int32_t, u_int32_t, __env_flags_reply *)); +__env_open_reply * __db_env_open_1 __P((__env_open_msg *)); +void __env_open_1_proc __P((long, char *, u_int32_t, + u_int32_t, __env_open_reply *)); +__env_remove_reply * __db_env_remove_1 __P((__env_remove_msg *)); +void __env_remove_1_proc __P((long, char *, u_int32_t, __env_remove_reply *)); +__txn_abort_reply * __db_txn_abort_1 __P((__txn_abort_msg *)); +void __txn_abort_1_proc __P((long, __txn_abort_reply *)); +__txn_begin_reply * __db_txn_begin_1 __P((__txn_begin_msg *)); +void __txn_begin_1_proc __P((long, long, + u_int32_t, __txn_begin_reply *)); +__txn_commit_reply * __db_txn_commit_1 __P((__txn_commit_msg *)); +void __txn_commit_1_proc __P((long, u_int32_t, __txn_commit_reply *)); +__db_bt_maxkey_reply * __db_db_bt_maxkey_1 __P((__db_bt_maxkey_msg *)); +void __db_bt_maxkey_1_proc __P((long, u_int32_t, __db_bt_maxkey_reply *)); +__db_bt_minkey_reply * __db_db_bt_minkey_1 __P((__db_bt_minkey_msg *)); +void __db_bt_minkey_1_proc __P((long, u_int32_t, __db_bt_minkey_reply *)); +__db_close_reply * __db_db_close_1 __P((__db_close_msg *)); +void __db_close_1_proc __P((long, u_int32_t, __db_close_reply *)); +__db_create_reply * __db_db_create_1 __P((__db_create_msg *)); +void __db_create_1_proc __P((u_int32_t, long, __db_create_reply *)); +__db_del_reply * __db_db_del_1 __P((__db_del_msg *)); +void __db_del_1_proc __P((long, long, u_int32_t, + u_int32_t, u_int32_t, void *, u_int32_t, + u_int32_t, __db_del_reply *)); +__db_extentsize_reply * __db_db_extentsize_1 __P((__db_extentsize_msg *)); +void __db_extentsize_1_proc __P((long, u_int32_t, __db_extentsize_reply *)); +__db_flags_reply * __db_db_flags_1 __P((__db_flags_msg *)); +void __db_flags_1_proc __P((long, u_int32_t, __db_flags_reply *)); +__db_get_reply * __db_db_get_1 __P((__db_get_msg *)); +void __db_get_1_proc __P((long, long, u_int32_t, + u_int32_t, u_int32_t, void *, u_int32_t, + u_int32_t, u_int32_t, u_int32_t, void *, + u_int32_t, u_int32_t, __db_get_reply *, int *)); +__db_h_ffactor_reply * __db_db_h_ffactor_1 __P((__db_h_ffactor_msg *)); +void __db_h_ffactor_1_proc __P((long, u_int32_t, __db_h_ffactor_reply *)); +__db_h_nelem_reply * __db_db_h_nelem_1 __P((__db_h_nelem_msg *)); +void __db_h_nelem_1_proc __P((long, u_int32_t, __db_h_nelem_reply *)); +__db_key_range_reply * __db_db_key_range_1 __P((__db_key_range_msg *)); +void __db_key_range_1_proc __P((long, long, u_int32_t, + u_int32_t, u_int32_t, void *, u_int32_t, + u_int32_t, __db_key_range_reply *)); +__db_lorder_reply * __db_db_lorder_1 __P((__db_lorder_msg *)); +void __db_lorder_1_proc __P((long, u_int32_t, __db_lorder_reply *)); +__db_open_reply * __db_db_open_1 __P((__db_open_msg *)); +void __db_open_1_proc __P((long, char *, char *, + u_int32_t, u_int32_t, u_int32_t, __db_open_reply *)); +__db_pagesize_reply * __db_db_pagesize_1 __P((__db_pagesize_msg *)); +void __db_pagesize_1_proc __P((long, u_int32_t, __db_pagesize_reply *)); +__db_put_reply * __db_db_put_1 __P((__db_put_msg *)); +void __db_put_1_proc __P((long, long, u_int32_t, + u_int32_t, u_int32_t, void *, u_int32_t, + u_int32_t, u_int32_t, u_int32_t, void *, + u_int32_t, u_int32_t, __db_put_reply *, int *)); +__db_re_delim_reply * __db_db_re_delim_1 __P((__db_re_delim_msg *)); +void __db_re_delim_1_proc __P((long, u_int32_t, __db_re_delim_reply *)); +__db_re_len_reply * __db_db_re_len_1 __P((__db_re_len_msg *)); +void __db_re_len_1_proc __P((long, u_int32_t, __db_re_len_reply *)); +__db_re_pad_reply * __db_db_re_pad_1 __P((__db_re_pad_msg *)); +void __db_re_pad_1_proc __P((long, u_int32_t, __db_re_pad_reply *)); +__db_remove_reply * __db_db_remove_1 __P((__db_remove_msg *)); +void __db_remove_1_proc __P((long, char *, char *, + u_int32_t, __db_remove_reply *)); +__db_rename_reply * __db_db_rename_1 __P((__db_rename_msg *)); +void __db_rename_1_proc __P((long, char *, char *, + char *, u_int32_t, __db_rename_reply *)); +__db_stat_reply * __db_db_stat_1 __P((__db_stat_msg *)); +void __db_stat_1_proc __P((long, + u_int32_t, __db_stat_reply *, int *)); +__db_swapped_reply * __db_db_swapped_1 __P((__db_swapped_msg *)); +void __db_swapped_1_proc __P((long, __db_swapped_reply *)); +__db_sync_reply * __db_db_sync_1 __P((__db_sync_msg *)); +void __db_sync_1_proc __P((long, u_int32_t, __db_sync_reply *)); +__db_cursor_reply * __db_db_cursor_1 __P((__db_cursor_msg *)); +void __db_cursor_1_proc __P((long, long, + u_int32_t, __db_cursor_reply *)); +__db_join_reply * __db_db_join_1 __P((__db_join_msg *)); +void __db_join_1_proc __P((long, u_int32_t *, + u_int32_t, __db_join_reply *)); +__dbc_close_reply * __db_dbc_close_1 __P((__dbc_close_msg *)); +void __dbc_close_1_proc __P((long, __dbc_close_reply *)); +__dbc_count_reply * __db_dbc_count_1 __P((__dbc_count_msg *)); +void __dbc_count_1_proc __P((long, u_int32_t, __dbc_count_reply *)); +__dbc_del_reply * __db_dbc_del_1 __P((__dbc_del_msg *)); +void __dbc_del_1_proc __P((long, u_int32_t, __dbc_del_reply *)); +__dbc_dup_reply * __db_dbc_dup_1 __P((__dbc_dup_msg *)); +void __dbc_dup_1_proc __P((long, u_int32_t, __dbc_dup_reply *)); +__dbc_get_reply * __db_dbc_get_1 __P((__dbc_get_msg *)); +void __dbc_get_1_proc __P((long, u_int32_t, u_int32_t, + u_int32_t, void *, u_int32_t, u_int32_t, + u_int32_t, u_int32_t, void *, u_int32_t, + u_int32_t, __dbc_get_reply *, int *)); +__dbc_put_reply * __db_dbc_put_1 __P((__dbc_put_msg *)); +void __dbc_put_1_proc __P((long, u_int32_t, u_int32_t, + u_int32_t, void *, u_int32_t, u_int32_t, + u_int32_t, u_int32_t, void *, u_int32_t, + u_int32_t, __dbc_put_reply *, int *)); diff --git a/db/include/hash.h b/db/include/hash.h new file mode 100644 index 000000000..14a88c80b --- /dev/null +++ b/db/include/hash.h @@ -0,0 +1,140 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994 + * Margo Seltzer. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Margo Seltzer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: hash.h,v 11.19 2000/12/21 23:05:16 krinsky Exp $ + */ + +/* Hash internal structure. */ +typedef struct hash_t { + db_pgno_t meta_pgno; /* Page number of the meta data page. */ + u_int32_t h_ffactor; /* Fill factor. */ + u_int32_t h_nelem; /* Number of elements. */ + /* Hash function. */ + u_int32_t (*h_hash) __P((DB *, const void *, u_int32_t)); +} HASH; + +/* Cursor structure definitions. */ +typedef struct cursor_t { + /* struct __dbc_internal */ + __DBC_INTERNAL + + /* Hash private part */ + + /* Per-thread information */ + DB_LOCK hlock; /* Metadata page lock. */ + HMETA *hdr; /* Pointer to meta-data page. */ + PAGE *split_buf; /* Temporary buffer for splits. */ + + /* Hash cursor information */ + db_pgno_t bucket; /* Bucket we are traversing. */ + db_pgno_t lbucket; /* Bucket for which we are locked. */ + db_indx_t dup_off; /* Offset within a duplicate set. */ + db_indx_t dup_len; /* Length of current duplicate. */ + db_indx_t dup_tlen; /* Total length of duplicate entry. */ + u_int32_t seek_size; /* Number of bytes we need for add. */ + db_pgno_t seek_found_page;/* Page on which we can insert. */ + u_int32_t order; /* Relative order among deleted curs. */ + +#define H_CONTINUE 0x0001 /* Join--search strictly fwd for data */ +#define H_DELETED 0x0002 /* Cursor item is deleted. */ +#define H_DIRTY 0x0004 /* Meta-data page needs to be written */ +#define H_DUPONLY 0x0008 /* Dups only; do not change key. */ +#define H_EXPAND 0x0010 /* Table expanded. */ +#define H_ISDUP 0x0020 /* Cursor is within duplicate set. */ +#define H_NEXT_NODUP 0x0040 /* Get next non-dup entry. */ +#define H_NOMORE 0x0080 /* No more entries in bucket. */ +#define H_OK 0x0100 /* Request succeeded. */ + u_int32_t flags; +} HASH_CURSOR; + +/* Test string. */ +#define CHARKEY "%$sniglet^&" + +/* Overflow management */ +/* + * The spares table indicates the page number at which each doubling begins. + * From this page number we subtract the number of buckets already allocated + * so that we can do a simple addition to calculate the page number here. + */ +#define BS_TO_PAGE(bucket, spares) \ + ((bucket) + (spares)[__db_log2((bucket) + 1)]) +#define BUCKET_TO_PAGE(I, B) (BS_TO_PAGE((B), (I)->hdr->spares)) + +/* Constraints about much data goes on a page. */ + +#define MINFILL 4 +#define ISBIG(I, N) (((N) > ((I)->hdr->dbmeta.pagesize / MINFILL)) ? 1 : 0) + +/* Shorthands for accessing structure */ +#define NDX_INVALID 0xFFFF +#define BUCKET_INVALID 0xFFFFFFFF + +/* On page duplicates are stored as a string of size-data-size triples. */ +#define DUP_SIZE(len) ((len) + 2 * sizeof(db_indx_t)) + +/* Log messages types (these are subtypes within a record type) */ +#define PAIR_KEYMASK 0x1 +#define PAIR_DATAMASK 0x2 +#define PAIR_DUPMASK 0x4 +#define PAIR_MASK 0xf +#define PAIR_ISKEYBIG(N) (N & PAIR_KEYMASK) +#define PAIR_ISDATABIG(N) (N & PAIR_DATAMASK) +#define PAIR_ISDATADUP(N) (N & PAIR_DUPMASK) +#define OPCODE_OF(N) (N & ~PAIR_MASK) + +#define PUTPAIR 0x20 +#define DELPAIR 0x30 +#define PUTOVFL 0x40 +#define DELOVFL 0x50 +#define HASH_UNUSED1 0x60 +#define HASH_UNUSED2 0x70 +#define SPLITOLD 0x80 +#define SPLITNEW 0x90 + +typedef enum { + DB_HAM_CHGPG = 1, + DB_HAM_SPLIT = 2, + DB_HAM_DUP = 3 +} db_ham_mode; + +#include "hash_auto.h" +#include "hash_ext.h" +#include "db_am.h" diff --git a/db/include/hash_auto.h b/db/include/hash_auto.h new file mode 100644 index 000000000..5d816d5bb --- /dev/null +++ b/db/include/hash_auto.h @@ -0,0 +1,248 @@ +/* Do not edit: automatically built by gen_rec.awk. */ + +#ifndef ham_AUTO_H +#define ham_AUTO_H + +#define DB_ham_insdel 21 +typedef struct _ham_insdel_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + u_int32_t opcode; + int32_t fileid; + db_pgno_t pgno; + u_int32_t ndx; + DB_LSN pagelsn; + DBT key; + DBT data; +} __ham_insdel_args; + +int __ham_insdel_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, u_int32_t, int32_t, db_pgno_t, u_int32_t, DB_LSN *, const DBT *, const DBT *)); +int __ham_insdel_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_insdel_read __P((DB_ENV *, void *, __ham_insdel_args **)); + +#define DB_ham_newpage 22 +typedef struct _ham_newpage_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + u_int32_t opcode; + int32_t fileid; + db_pgno_t prev_pgno; + DB_LSN prevlsn; + db_pgno_t new_pgno; + DB_LSN pagelsn; + db_pgno_t next_pgno; + DB_LSN nextlsn; +} __ham_newpage_args; + +int __ham_newpage_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, u_int32_t, int32_t, db_pgno_t, DB_LSN *, db_pgno_t, DB_LSN *, db_pgno_t, DB_LSN *)); +int __ham_newpage_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_newpage_read __P((DB_ENV *, void *, __ham_newpage_args **)); + +#define DB_ham_splitmeta 23 +typedef struct _ham_splitmeta_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + u_int32_t bucket; + u_int32_t ovflpoint; + u_int32_t spares; + DB_LSN metalsn; +} __ham_splitmeta_args; + +int __ham_splitmeta_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_splitmeta_read __P((DB_ENV *, void *, __ham_splitmeta_args **)); + +#define DB_ham_splitdata 24 +typedef struct _ham_splitdata_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + u_int32_t opcode; + db_pgno_t pgno; + DBT pageimage; + DB_LSN pagelsn; +} __ham_splitdata_args; + +int __ham_splitdata_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, int32_t, u_int32_t, db_pgno_t, const DBT *, DB_LSN *)); +int __ham_splitdata_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_splitdata_read __P((DB_ENV *, void *, __ham_splitdata_args **)); + +#define DB_ham_replace 25 +typedef struct _ham_replace_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t pgno; + u_int32_t ndx; + DB_LSN pagelsn; + int32_t off; + DBT olditem; + DBT newitem; + u_int32_t makedup; +} __ham_replace_args; + +int __ham_replace_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, int32_t, db_pgno_t, u_int32_t, DB_LSN *, int32_t, const DBT *, const DBT *, u_int32_t)); +int __ham_replace_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_replace_read __P((DB_ENV *, void *, __ham_replace_args **)); + +#define DB_ham_newpgno 26 +typedef struct _ham_newpgno_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + u_int32_t opcode; + int32_t fileid; + db_pgno_t pgno; + db_pgno_t free_pgno; + u_int32_t old_type; + db_pgno_t old_pgno; + u_int32_t new_type; + DB_LSN pagelsn; + DB_LSN metalsn; +} __ham_newpgno_args; + +int __ham_newpgno_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_newpgno_read __P((DB_ENV *, void *, __ham_newpgno_args **)); + +#define DB_ham_ovfl 27 +typedef struct _ham_ovfl_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t start_pgno; + u_int32_t npages; + db_pgno_t free_pgno; + u_int32_t ovflpoint; + DB_LSN metalsn; +} __ham_ovfl_args; + +int __ham_ovfl_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_ovfl_read __P((DB_ENV *, void *, __ham_ovfl_args **)); + +#define DB_ham_copypage 28 +typedef struct _ham_copypage_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t pgno; + DB_LSN pagelsn; + db_pgno_t next_pgno; + DB_LSN nextlsn; + db_pgno_t nnext_pgno; + DB_LSN nnextlsn; + DBT page; +} __ham_copypage_args; + +int __ham_copypage_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, int32_t, db_pgno_t, DB_LSN *, db_pgno_t, DB_LSN *, db_pgno_t, DB_LSN *, const DBT *)); +int __ham_copypage_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_copypage_read __P((DB_ENV *, void *, __ham_copypage_args **)); + +#define DB_ham_metagroup 29 +typedef struct _ham_metagroup_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + u_int32_t bucket; + db_pgno_t pgno; + DB_LSN metalsn; + DB_LSN pagelsn; +} __ham_metagroup_args; + +int __ham_metagroup_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, int32_t, u_int32_t, db_pgno_t, DB_LSN *, DB_LSN *)); +int __ham_metagroup_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_metagroup_read __P((DB_ENV *, void *, __ham_metagroup_args **)); + +#define DB_ham_groupalloc1 30 +typedef struct _ham_groupalloc1_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t pgno; + DB_LSN metalsn; + DB_LSN mmetalsn; + db_pgno_t start_pgno; + u_int32_t num; +} __ham_groupalloc1_args; + +int __ham_groupalloc1_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_groupalloc1_read __P((DB_ENV *, void *, __ham_groupalloc1_args **)); + +#define DB_ham_groupalloc2 31 +typedef struct _ham_groupalloc2_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + DB_LSN meta_lsn; + DB_LSN alloc_lsn; + db_pgno_t start_pgno; + u_int32_t num; + db_pgno_t free; +} __ham_groupalloc2_args; + +int __ham_groupalloc2_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_groupalloc2_read __P((DB_ENV *, void *, __ham_groupalloc2_args **)); + +#define DB_ham_groupalloc 32 +typedef struct _ham_groupalloc_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + DB_LSN meta_lsn; + db_pgno_t start_pgno; + u_int32_t num; + db_pgno_t free; +} __ham_groupalloc_args; + +int __ham_groupalloc_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, int32_t, DB_LSN *, db_pgno_t, u_int32_t, db_pgno_t)); +int __ham_groupalloc_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_groupalloc_read __P((DB_ENV *, void *, __ham_groupalloc_args **)); + +#define DB_ham_curadj 33 +typedef struct _ham_curadj_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t pgno; + u_int32_t indx; + u_int32_t len; + u_int32_t dup_off; + int add; + int is_dup; + u_int32_t order; +} __ham_curadj_args; + +int __ham_curadj_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, int32_t, db_pgno_t, u_int32_t, u_int32_t, u_int32_t, int, int, u_int32_t)); +int __ham_curadj_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_curadj_read __P((DB_ENV *, void *, __ham_curadj_args **)); + +#define DB_ham_chgpg 34 +typedef struct _ham_chgpg_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_ham_mode mode; + db_pgno_t old_pgno; + db_pgno_t new_pgno; + u_int32_t old_indx; + u_int32_t new_indx; +} __ham_chgpg_args; + +int __ham_chgpg_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, int32_t, db_ham_mode, db_pgno_t, db_pgno_t, u_int32_t, u_int32_t)); +int __ham_chgpg_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_chgpg_read __P((DB_ENV *, void *, __ham_chgpg_args **)); +int __ham_init_print __P((DB_ENV *)); +int __ham_init_recover __P((DB_ENV *)); +#endif diff --git a/db/include/hash_ext.h b/db/include/hash_ext.h new file mode 100644 index 000000000..babb77a79 --- /dev/null +++ b/db/include/hash_ext.h @@ -0,0 +1,106 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _hash_ext_h_ +#define _hash_ext_h_ +#if defined(__cplusplus) +extern "C" { +#endif +int __ham_metachk __P((DB *, const char *, HMETA *)); +int __ham_open __P((DB *, const char *, db_pgno_t, u_int32_t)); +int __ham_c_init __P((DBC *)); +int __ham_c_count __P((DBC *, db_recno_t *)); +int __ham_c_dup __P((DBC *, DBC *)); +u_int32_t __ham_call_hash __P((DBC *, u_int8_t *, int32_t)); +int __ham_init_dbt __P((DB_ENV *, + DBT *, u_int32_t, void **, u_int32_t *)); +int __ham_c_update + __P((DBC *, u_int32_t, int, int)); +int __ham_get_clist __P((DB *, + db_pgno_t, u_int32_t, DBC ***)); +int __ham_c_chgpg + __P((DBC *, db_pgno_t, u_int32_t, db_pgno_t, u_int32_t)); +int __ham_pgin __P((DB_ENV *, db_pgno_t, void *, DBT *)); +int __ham_pgout __P((DB_ENV *, db_pgno_t, void *, DBT *)); +int __ham_mswap __P((void *)); +int __ham_add_dup __P((DBC *, DBT *, u_int32_t, db_pgno_t *)); +int __ham_dup_convert __P((DBC *)); +int __ham_make_dup __P((DB_ENV *, + const DBT *, DBT *d, void **, u_int32_t *)); +void __ham_move_offpage __P((DBC *, PAGE *, u_int32_t, db_pgno_t)); +void __ham_dsearch __P((DBC *, DBT *, u_int32_t *, int *)); +int __ham_cprint __P((DB *)); +u_int32_t __ham_func2 __P((DB *, const void *, u_int32_t)); +u_int32_t __ham_func3 __P((DB *, const void *, u_int32_t)); +u_int32_t __ham_func4 __P((DB *, const void *, u_int32_t)); +u_int32_t __ham_func5 __P((DB *, const void *, u_int32_t)); +int __ham_get_meta __P((DBC *)); +int __ham_release_meta __P((DBC *)); +int __ham_dirty_meta __P((DBC *)); +int __ham_db_create __P((DB *)); +int __ham_db_close __P((DB *)); +int __ham_item __P((DBC *, db_lockmode_t, db_pgno_t *)); +int __ham_item_reset __P((DBC *)); +void __ham_item_init __P((DBC *)); +int __ham_item_last __P((DBC *, db_lockmode_t, db_pgno_t *)); +int __ham_item_first __P((DBC *, db_lockmode_t, db_pgno_t *)); +int __ham_item_prev __P((DBC *, db_lockmode_t, db_pgno_t *)); +int __ham_item_next __P((DBC *, db_lockmode_t, db_pgno_t *)); +void __ham_putitem __P((PAGE *p, const DBT *, int)); +void __ham_reputpair + __P((PAGE *p, u_int32_t, u_int32_t, const DBT *, const DBT *)); +int __ham_del_pair __P((DBC *, int)); +int __ham_replpair __P((DBC *, DBT *, u_int32_t)); +void __ham_onpage_replace __P((PAGE *, size_t, u_int32_t, int32_t, + int32_t, DBT *)); +int __ham_split_page __P((DBC *, u_int32_t, u_int32_t)); +int __ham_add_el __P((DBC *, const DBT *, const DBT *, int)); +void __ham_copy_item __P((size_t, PAGE *, u_int32_t, PAGE *)); +int __ham_add_ovflpage __P((DBC *, PAGE *, int, PAGE **)); +int __ham_get_cpage __P((DBC *, db_lockmode_t)); +int __ham_next_cpage __P((DBC *, db_pgno_t, int)); +int __ham_lock_bucket __P((DBC *, db_lockmode_t)); +void __ham_dpair __P((DB *, PAGE *, u_int32_t)); +int __ham_insdel_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_newpage_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_replace_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_splitdata_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_copypage_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_metagroup_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_groupalloc_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_curadj_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_chgpg_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_reclaim __P((DB *, DB_TXN *txn)); +int __ham_stat __P((DB *, void *, void *(*)(size_t), u_int32_t)); + int __ham_traverse __P((DB *, DBC *, db_lockmode_t, + int (*)(DB *, PAGE *, void *, int *), void *)); +int __ham_30_hashmeta __P((DB *, char *, u_int8_t *)); +int __ham_30_sizefix __P((DB *, DB_FH *, char *, u_int8_t *)); +int __ham_31_hashmeta + __P((DB *, char *, u_int32_t, DB_FH *, PAGE *, int *)); +int __ham_31_hash + __P((DB *, char *, u_int32_t, DB_FH *, PAGE *, int *)); +int __ham_vrfy_meta __P((DB *, VRFY_DBINFO *, HMETA *, + db_pgno_t, u_int32_t)); +int __ham_vrfy __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, + u_int32_t)); +int __ham_vrfy_structure __P((DB *, VRFY_DBINFO *, db_pgno_t, + u_int32_t)); +int __ham_vrfy_hashing __P((DB *, + u_int32_t, HMETA *, u_int32_t, db_pgno_t, u_int32_t, + u_int32_t (*) __P((DB *, const void *, u_int32_t)))); +int __ham_salvage __P((DB *, VRFY_DBINFO *, db_pgno_t, PAGE *, + void *, int (*)(void *, const void *), u_int32_t)); +int __ham_meta2pgset __P((DB *, VRFY_DBINFO *, HMETA *, u_int32_t, + DB *)); +#if defined(__cplusplus) +} +#endif +#endif /* _hash_ext_h_ */ diff --git a/db/include/lock.h b/db/include/lock.h new file mode 100644 index 000000000..e4a01ddf9 --- /dev/null +++ b/db/include/lock.h @@ -0,0 +1,190 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: lock.h,v 11.20 2000/12/12 17:43:56 bostic Exp $ + */ + +#define DB_LOCK_DEFAULT_N 1000 /* Default # of locks in region. */ + +/* + * Out of band value for a lock. Locks contain an offset into a lock region, + * so we use an invalid region offset to indicate an invalid or unset lock. + */ +#define LOCK_INVALID INVALID_ROFF + +/* + * The locker id space is divided between the transaction manager and the lock + * manager. Lock IDs start at 0 and go to DB_LOCK_MAXID. Txn IDs start at + * DB_LOCK_MAXID + 1 and go up to TXN_INVALID. + */ +#define DB_LOCK_MAXID 0x7fffffff + +/* + * DB_LOCKREGION -- + * The lock shared region. + */ +typedef struct __db_lockregion { + u_int32_t id; /* unique id generator */ + u_int32_t need_dd; /* flag for deadlock detector */ + u_int32_t detect; /* run dd on every conflict */ + /* free lock header */ + SH_TAILQ_HEAD(__flock) free_locks; + /* free obj header */ + SH_TAILQ_HEAD(__fobj) free_objs; + /* free locker header */ + SH_TAILQ_HEAD(__flocker) free_lockers; + SH_TAILQ_HEAD(__dobj) dd_objs; /* objects with waiters */ + u_int32_t maxlocks; /* maximum number of locks in table */ + u_int32_t maxlockers; /* maximum number of lockers in table */ + u_int32_t maxobjects; /* maximum number of objects in table */ + u_int32_t locker_t_size; /* size of locker hash table */ + u_int32_t object_t_size; /* size of object hash table */ + u_int32_t nmodes; /* number of lock modes */ + u_int32_t nlocks; /* current number of locks */ + u_int32_t maxnlocks; /* maximum number of locks so far*/ + u_int32_t nlockers; /* current number of lockers */ + u_int32_t maxnlockers; /* maximum number of lockers so far */ + u_int32_t nobjects; /* current number of objects */ + u_int32_t maxnobjects; /* maximum number of objects so far */ + roff_t conf_off; /* offset of conflicts array */ + roff_t obj_off; /* offset of object hash table */ + roff_t osynch_off; /* offset of the object mutex table */ + roff_t locker_off; /* offset of locker hash table */ + roff_t lsynch_off; /* offset of the locker mutex table */ + u_int32_t nconflicts; /* number of lock conflicts */ + u_int32_t nrequests; /* number of lock gets */ + u_int32_t nreleases; /* number of lock puts */ + u_int32_t nnowaits; /* number of lock requests that would + have waited without nowait */ + u_int32_t ndeadlocks; /* number of deadlocks */ +#ifdef MUTEX_SYSTEM_RESOURCES + roff_t maint_off; /* offset of region maintenance info */ +#endif +} DB_LOCKREGION; + +/* + * Since we will store DBTs in shared memory, we need the equivalent of a + * DBT that will work in shared memory. + */ +typedef struct __sh_dbt { + u_int32_t size; /* Byte length. */ + ssize_t off; /* Region offset. */ +} SH_DBT; + +#define SH_DBT_PTR(p) ((void *)(((u_int8_t *)(p)) + (p)->off)) + +/* + * Object structures; these live in the object hash table. + */ +typedef struct __db_lockobj { + SH_DBT lockobj; /* Identifies object locked. */ + SH_TAILQ_ENTRY links; /* Links for free list or hash list. */ + SH_TAILQ_ENTRY dd_links; /* Links for dd list. */ + SH_TAILQ_HEAD(__wait) waiters; /* List of waiting locks. */ + SH_TAILQ_HEAD(__hold) holders; /* List of held locks. */ + /* Declare room in the object to hold + * typical DB lock structures so that + * we do not have to allocate them from + * shalloc at run-time. */ + u_int8_t objdata[sizeof(struct __db_ilock)]; +} DB_LOCKOBJ; + +/* + * Locker structures; these live in the locker hash table. + */ +typedef struct __db_locker { + u_int32_t id; /* Locker id. */ + u_int32_t dd_id; /* Deadlock detector id. */ + size_t master_locker; /* Locker of master transaction. */ + size_t parent_locker; /* Parent of this child. */ + SH_LIST_HEAD(_child) child_locker; /* List of descendant txns; + only used in a "master" + txn. */ + SH_LIST_ENTRY child_link; /* Links transactions in the family; + elements of the child_locker + list. */ + SH_TAILQ_ENTRY links; /* Links for free list. */ + SH_LIST_HEAD(_held) heldby; /* Locks held by this locker. */ + +#define DB_LOCKER_DELETED 0x0001 + u_int32_t flags; +} DB_LOCKER; + +/* + * Lockers can be freed if they are not part of a transaction family. + * Members of a family either point at the master transaction or are + * the master transaction and have children lockers. + */ +#define LOCKER_FREEABLE(lp) \ + ((lp)->master_locker == TXN_INVALID_ID && \ + SH_LIST_FIRST(&(lp)->child_locker, __db_locker) == NULL) + +/* + * DB_LOCKTAB -- + * The primary library lock data structure (i.e., the one referenced + * by the environment, as opposed to the internal one laid out in the region.) + */ +typedef struct __db_locktab { + DB_ENV *dbenv; /* Environment. */ + REGINFO reginfo; /* Region information. */ + u_int8_t *conflicts; /* Pointer to conflict matrix. */ + DB_HASHTAB *obj_tab; /* Beginning of object hash table. */ + DB_HASHTAB *locker_tab; /* Beginning of locker hash table. */ +} DB_LOCKTAB; + +/* Test for conflicts. */ +#define CONFLICTS(T, R, HELD, WANTED) \ + (T)->conflicts[(HELD) * (R)->nmodes + (WANTED)] + +#define OBJ_LINKS_VALID(L) ((L)->links.stqe_prev != -1) + +struct __db_lock { + /* + * Wait on mutex to wait on lock. You reference your own mutex with + * ID 0 and others reference your mutex with ID 1. + */ + MUTEX mutex; + + u_int32_t holder; /* Who holds this lock. */ + u_int32_t gen; /* Generation count. */ + SH_TAILQ_ENTRY links; /* Free or holder/waiter list. */ + SH_LIST_ENTRY locker_links; /* List of locks held by a locker. */ + u_int32_t refcount; /* Reference count the lock. */ + db_lockmode_t mode; /* What sort of lock. */ + ssize_t obj; /* Relative offset of object struct. */ + db_status_t status; /* Status of this lock. */ +}; + +/* + * Flag values for __lock_put_internal: + * DB_LOCK_DOALL: Unlock all references in this lock (instead of only 1). + * DB_LOCK_FREE: Free the lock (used in checklocker). + * DB_LOCK_IGNOREDEL: Remove from the locker hash table even if already + deleted (used in checklocker). + * DB_LOCK_NOPROMOTE: Don't bother running promotion when releasing locks + * (used by __lock_put_internal). + * DB_LOCK_UNLINK: Remove from the locker links (used in checklocker). + */ +#define DB_LOCK_DOALL 0x001 +#define DB_LOCK_FREE 0x002 +#define DB_LOCK_IGNOREDEL 0x004 +#define DB_LOCK_NOPROMOTE 0x008 +#define DB_LOCK_UNLINK 0x010 +#define DB_LOCK_NOWAITERS 0x020 + +/* + * Macros to get/release different types of mutexes. + */ +#define OBJECT_LOCK(lt, reg, obj, ndx) \ + ndx = __lock_ohash(obj) % (reg)->object_t_size +#define SHOBJECT_LOCK(lt, reg, shobj, ndx) \ + ndx = __lock_lhash(shobj) % (reg)->object_t_size +#define LOCKER_LOCK(lt, reg, locker, ndx) \ + ndx = __lock_locker_hash(locker) % (reg)->locker_t_size; + +#define LOCKREGION(dbenv, lt) R_LOCK((dbenv), &(lt)->reginfo) +#define UNLOCKREGION(dbenv, lt) R_UNLOCK((dbenv), &(lt)->reginfo) +#include "lock_ext.h" diff --git a/db/include/lock_ext.h b/db/include/lock_ext.h new file mode 100644 index 000000000..7ed9b1c69 --- /dev/null +++ b/db/include/lock_ext.h @@ -0,0 +1,39 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _lock_ext_h_ +#define _lock_ext_h_ +#if defined(__cplusplus) +extern "C" { +#endif +int __lock_downgrade __P((DB_ENV *, + DB_LOCK *, db_lockmode_t, u_int32_t)); +int __lock_addfamilylocker __P((DB_ENV *, u_int32_t, u_int32_t)); +int __lock_freefamilylocker __P((DB_LOCKTAB *, u_int32_t)); +void __lock_freelocker __P((DB_LOCKTAB *, + DB_LOCKREGION *, DB_LOCKER *, u_int32_t)); +int __lock_getlocker __P((DB_LOCKTAB *, + u_int32_t, u_int32_t, int, DB_LOCKER **)); +int __lock_getobj __P((DB_LOCKTAB *, + const DBT *, u_int32_t, int, DB_LOCKOBJ **)); +int __lock_promote __P((DB_LOCKTAB *, DB_LOCKOBJ *, int)); +void __lock_printlock __P((DB_LOCKTAB *, struct __db_lock *, int)); +int __lock_set_lk_conflicts __P((DB_ENV *, u_int8_t *, int)); +int __lock_set_lk_detect __P((DB_ENV *, u_int32_t)); +int __lock_set_lk_max __P((DB_ENV *, u_int32_t)); +int __lock_set_lk_max_locks __P((DB_ENV *, u_int32_t)); +int __lock_set_lk_max_lockers __P((DB_ENV *, u_int32_t)); +int __lock_set_lk_max_objects __P((DB_ENV *, u_int32_t)); +void __lock_dbenv_create __P((DB_ENV *)); +void __lock_dbenv_close __P((DB_ENV *)); +int __lock_open __P((DB_ENV *)); +int __lock_close __P((DB_ENV *)); +void __lock_region_destroy __P((DB_ENV *, REGINFO *)); +void __lock_dump_region __P((DB_ENV *, char *, FILE *)); +int __lock_cmp __P((const DBT *, DB_LOCKOBJ *)); +int __lock_locker_cmp __P((u_int32_t, DB_LOCKER *)); +u_int32_t __lock_ohash __P((const DBT *)); +u_int32_t __lock_lhash __P((DB_LOCKOBJ *)); +u_int32_t __lock_locker_hash __P((u_int32_t)); +#if defined(__cplusplus) +} +#endif +#endif /* _lock_ext_h_ */ diff --git a/db/include/log.h b/db/include/log.h new file mode 100644 index 000000000..08c2b8076 --- /dev/null +++ b/db/include/log.h @@ -0,0 +1,208 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: log.h,v 11.19 2001/01/11 18:19:52 bostic Exp $ + */ + +#ifndef _LOG_H_ +#define _LOG_H_ + +struct __db_log; typedef struct __db_log DB_LOG; +struct __fname; typedef struct __fname FNAME; +struct __hdr; typedef struct __hdr HDR; +struct __log; typedef struct __log LOG; +struct __log_persist; typedef struct __log_persist LOGP; + +#define LFPREFIX "log." /* Log file name prefix. */ +#define LFNAME "log.%010d" /* Log file name template. */ +#define LFNAME_V1 "log.%05d" /* Log file name template, rev 1. */ + +#define LG_MAX_DEFAULT (10 * MEGABYTE) /* 10 MB. */ +#define LG_BSIZE_DEFAULT (32 * 1024) /* 32 KB. */ +#define LG_BASE_REGION_SIZE (60 * 1024) /* 60 KB. */ + +/* + * The per-process table that maps log file-id's to DB structures. + */ +typedef struct __db_entry { + TAILQ_HEAD(dblist, __db) dblist; /* Associated DB structures. */ + u_int32_t refcount; /* Reference counted. */ + u_int32_t count; /* Number of ops on a deleted db. */ + int deleted; /* File was not found during open. */ +} DB_ENTRY; + +/* + * DB_LOG + * Per-process log structure. + */ +struct __db_log { +/* + * These fields need to be protected for multi-threaded support. + * + * !!! + * As this structure is allocated in per-process memory, the mutex may need + * to be stored elsewhere on architectures unable to support mutexes in heap + * memory, e.g., HP/UX 9. + */ + MUTEX *mutexp; /* Mutex for thread protection. */ + + DB_ENTRY *dbentry; /* Recovery file-id mapping. */ +#define DB_GROW_SIZE 64 + int32_t dbentry_cnt; /* Entries. Grows by DB_GROW_SIZE. */ + +/* + * These fields are always accessed while the region lock is held, so they do + * not have to be protected by the thread lock as well, OR, they are only used + * when threads are not being used, i.e. most cursor operations are disallowed + * on threaded logs. + */ + u_int32_t lfname; /* Log file "name". */ + DB_FH lfh; /* Log file handle. */ + + DB_LSN c_lsn; /* Cursor: current LSN. */ + DBT c_dbt; /* Cursor: return DBT structure. */ + DB_FH c_fh; /* Cursor: file handle. */ + FILE *c_fp; /* Cursor: file pointer. */ + u_int32_t c_off; /* Cursor: previous record offset. */ + u_int32_t c_len; /* Cursor: current record length. */ + u_int32_t r_file; /* Cursor: current read file */ + u_int32_t r_off; /* Cursor: offset of read buffer. */ + u_int32_t r_size; /* Cursor: size of data in read buf. */ + + u_int8_t *bufp; /* Region buffer. */ + u_int8_t *readbufp; /* Read buffer. */ + +/* These fields are not protected. */ + DB_ENV *dbenv; /* Reference to error information. */ + REGINFO reginfo; /* Region information. */ + +/* + * These fields are used by XA; since XA forbids threaded execution, these + * do not have to be protected. + */ + void *xa_info; /* Committed transaction list that + * has to be carried between calls + * to xa_recover. */ + DB_LSN xa_lsn; /* Position of an XA recovery scan. */ + DB_LSN xa_first; /* LSN to which we need to roll back + for this XA recovery scan. */ + +#define DBLOG_RECOVER 0x01 /* We are in recovery. */ +#define DBLOG_FORCE_OPEN 0x02 /* Force the db open even + * if it appears to be deleted. + */ + u_int32_t flags; +}; + +/* + * HDR -- + * Log record header. + */ +struct __hdr { + u_int32_t prev; /* Previous offset. */ + u_int32_t cksum; /* Current checksum. */ + u_int32_t len; /* Current length. */ +}; + +struct __log_persist { + u_int32_t magic; /* DB_LOGMAGIC */ + u_int32_t version; /* DB_LOGVERSION */ + + u_int32_t lg_max; /* Maximum file size. */ + int mode; /* Log file mode. */ +}; + +/* + * LOG -- + * Shared log region. One of these is allocated in shared memory, + * and describes the log. + */ +struct __log { + LOGP persist; /* Persistent information. */ + + SH_TAILQ_HEAD(__fq) fq; /* List of file names. */ + + /* + * The lsn LSN is the file offset that we're about to write and which + * we will return to the user. + */ + DB_LSN lsn; /* LSN at current file offset. */ + + /* + * The s_lsn LSN is the last LSN that we know is on disk, not just + * written, but synced. + */ + DB_LSN s_lsn; /* LSN of the last sync. */ + + u_int32_t len; /* Length of the last record. */ + + u_int32_t w_off; /* Current write offset in the file. */ + + DB_LSN chkpt_lsn; /* LSN of the last checkpoint. */ + time_t chkpt; /* Time of the last checkpoint. */ + + DB_LOG_STAT stat; /* Log statistics. */ + + /* + * The f_lsn LSN is the LSN (returned to the user) that "owns" the + * first byte of the buffer. If the record associated with the LSN + * spans buffers, it may not reflect the physical file location of + * the first byte of the buffer. + */ + DB_LSN f_lsn; /* LSN of first byte in the buffer. */ + size_t b_off; /* Current offset in the buffer. */ + + roff_t buffer_off; /* Log buffer offset. */ + u_int32_t buffer_size; /* Log buffer size. */ +}; + +/* + * FNAME -- + * File name and id. + */ +struct __fname { + SH_TAILQ_ENTRY q; /* File name queue. */ + + u_int16_t ref; /* Reference count. */ + u_int16_t locked; /* Table is locked. */ + + int32_t id; /* Logging file id. */ + DBTYPE s_type; /* Saved DB type. */ + + roff_t name_off; /* Name offset. */ + db_pgno_t meta_pgno; /* Page number of the meta page. */ + u_int8_t ufid[DB_FILE_ID_LEN]; /* Unique file id. */ +}; + +/* File open/close register log record opcodes. */ +#define LOG_CHECKPOINT 1 /* Checkpoint: file name/id dump. */ +#define LOG_CLOSE 2 /* File close. */ +#define LOG_OPEN 3 /* File open. */ + +#define CHECK_LSN(redo, cmp, lsn, prev) \ + DB_ASSERT(!DB_REDO(redo) || (cmp) >= 0); \ + if (DB_REDO(redo) && (cmp) < 0) { \ + __db_err(dbenv, \ + "Log sequence error: page LSN %lu:%lu; previous LSN %lu %lu", \ + (u_long)(lsn)->file, (u_long)(lsn)->offset, \ + (u_long)(prev)->file, (u_long)(prev)->offset); \ + goto out; \ + } + +/* + * Status codes indicating the validity of a log file examined by + * __log_valid(). + */ +typedef enum { + DB_LV_INCOMPLETE, + DB_LV_NORMAL, + DB_LV_OLD_READABLE, + DB_LV_OLD_UNREADABLE +} logfile_validity; + +#include "log_auto.h" +#include "log_ext.h" +#endif /* _LOG_H_ */ diff --git a/db/include/log_auto.h b/db/include/log_auto.h new file mode 100644 index 000000000..ddbcbcb3e --- /dev/null +++ b/db/include/log_auto.h @@ -0,0 +1,39 @@ +/* Do not edit: automatically built by gen_rec.awk. */ + +#ifndef log_AUTO_H +#define log_AUTO_H + +#define DB_log_register1 1 +typedef struct _log_register1_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + u_int32_t opcode; + DBT name; + DBT uid; + int32_t fileid; + DBTYPE ftype; +} __log_register1_args; + +int __log_register1_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __log_register1_read __P((DB_ENV *, void *, __log_register1_args **)); + +#define DB_log_register 2 +typedef struct _log_register_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + u_int32_t opcode; + DBT name; + DBT uid; + int32_t fileid; + DBTYPE ftype; + db_pgno_t meta_pgno; +} __log_register_args; + +int __log_register_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, u_int32_t, const DBT *, const DBT *, int32_t, DBTYPE, db_pgno_t)); +int __log_register_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __log_register_read __P((DB_ENV *, void *, __log_register_args **)); +int __log_init_print __P((DB_ENV *)); +int __log_init_recover __P((DB_ENV *)); +#endif diff --git a/db/include/log_ext.h b/db/include/log_ext.h new file mode 100644 index 000000000..985c5d774 --- /dev/null +++ b/db/include/log_ext.h @@ -0,0 +1,33 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _log_ext_h_ +#define _log_ext_h_ +#if defined(__cplusplus) +extern "C" { +#endif +int __log_open __P((DB_ENV *)); +int __log_find __P((DB_LOG *, int, int *, logfile_validity *)); +int __log_valid __P((DB_LOG *, u_int32_t, int, logfile_validity *)); +int __log_close __P((DB_ENV *)); +int __log_lastckp __P((DB_ENV *, DB_LSN *)); +int __log_findckp __P((DB_ENV *, DB_LSN *)); +int __log_get __P((DB_LOG *, DB_LSN *, DBT *, u_int32_t, int)); +void __log_dbenv_create __P((DB_ENV *)); +int __log_put __P((DB_ENV *, DB_LSN *, const DBT *, u_int32_t)); +int __log_name __P((DB_LOG *, + u_int32_t, char **, DB_FH *, u_int32_t)); +int __log_register_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __log_reopen_file __P((DB_ENV *, + char *, int32_t, u_int8_t *, db_pgno_t)); +int __log_add_logid __P((DB_ENV *, DB_LOG *, DB *, int32_t)); +int __db_fileid_to_db __P((DB_ENV *, DB **, int32_t, int)); +void __log_close_files __P((DB_ENV *)); +void __log_rem_logid __P((DB_LOG *, DB *, int32_t)); +int __log_lid_to_fname __P((DB_LOG *, int32_t, FNAME **)); +int __log_filelist_update + __P((DB_ENV *, DB *, int32_t, const char *, int *)); +int __log_file_lock __P((DB *)); +#if defined(__cplusplus) +} +#endif +#endif /* _log_ext_h_ */ diff --git a/db/include/mp.h b/db/include/mp.h new file mode 100644 index 000000000..233cb1c2b --- /dev/null +++ b/db/include/mp.h @@ -0,0 +1,244 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: mp.h,v 11.16 2001/01/10 04:50:53 ubell Exp $ + */ + +struct __bh; typedef struct __bh BH; +struct __db_mpool; typedef struct __db_mpool DB_MPOOL; +struct __db_mpreg; typedef struct __db_mpreg DB_MPREG; +struct __mpool; typedef struct __mpool MPOOL; +struct __mpoolfile; typedef struct __mpoolfile MPOOLFILE; + +/* We require at least 40K of cache. */ +#define DB_CACHESIZE_MIN (20 * 1024) + +/* + * DB_MPOOL -- + * Per-process memory pool structure. + */ +struct __db_mpool { + /* These fields need to be protected for multi-threaded support. */ + MUTEX *mutexp; /* Structure thread lock. */ + + /* List of pgin/pgout routines. */ + LIST_HEAD(__db_mpregh, __db_mpreg) dbregq; + + /* List of DB_MPOOLFILE's. */ + TAILQ_HEAD(__db_mpoolfileh, __db_mpoolfile) dbmfq; + + /* These fields are not thread-protected. */ + DB_ENV *dbenv; /* Reference to error information. */ + + u_int32_t nreg; /* N underlying cache regions. */ + REGINFO *reginfo; /* Underlying cache regions. */ +}; + +/* + * DB_MPREG -- + * DB_MPOOL registry of pgin/pgout functions. + */ +struct __db_mpreg { + LIST_ENTRY(__db_mpreg) q; /* Linked list. */ + + int ftype; /* File type. */ + /* Pgin, pgout routines. */ + int (*pgin) __P((DB_ENV *, db_pgno_t, void *, DBT *)); + int (*pgout) __P((DB_ENV *, db_pgno_t, void *, DBT *)); +}; + +/* + * DB_MPOOLFILE -- + * Per-process DB_MPOOLFILE information. + */ +struct __db_mpoolfile { + /* These fields need to be protected for multi-threaded support. */ + MUTEX *mutexp; /* Structure thread lock. */ + + DB_FH fh; /* Underlying file handle. */ + + u_int32_t ref; /* Reference count. */ + + /* + * !!! + * This field is a special case -- it's protected by the region lock + * NOT the thread lock. The reason for this is that we always have + * the region lock immediately before or after we modify the field, + * and we don't want to use the structure lock to protect it because + * then I/O (which is done with the structure lock held because of + * the race between the seek and write of the file descriptor) will + * block any other put/get calls using this DB_MPOOLFILE structure. + */ + u_int32_t pinref; /* Pinned block reference count. */ + + /* + * !!! + * This field is a special case -- it's protected by the region lock + * since it's manipulated only when new files are added to the list. + */ + TAILQ_ENTRY(__db_mpoolfile) q; /* Linked list of DB_MPOOLFILE's. */ + + /* These fields are not thread-protected. */ + DB_MPOOL *dbmp; /* Overlying DB_MPOOL. */ + MPOOLFILE *mfp; /* Underlying MPOOLFILE. */ + + void *addr; /* Address of mmap'd region. */ + size_t len; /* Length of mmap'd region. */ + + /* These fields need to be protected for multi-threaded support. */ +#define MP_READONLY 0x01 /* File is readonly. */ +#define MP_UPGRADE 0x02 /* File descriptor is readwrite. */ +#define MP_UPGRADE_FAIL 0x04 /* Upgrade wasn't possible. */ + u_int32_t flags; +}; + +/* + * NCACHE -- + * Select a cache based on the page number. This assumes accesses are + * uniform across pages, which is probably OK -- what we really want to + * avoid is anything that puts all the pages for any single file in the + * same cache, as we expect that file access will be bursty. + */ +#define NCACHE(mp, pgno) \ + ((pgno) % ((MPOOL *)mp)->nreg) + +/* + * NBUCKET -- + * We make the assumption that early pages of the file are more likely + * to be retrieved than the later pages, which means the top bits will + * be more interesting for hashing as they're less likely to collide. + * That said, as 512 8K pages represents a 4MB file, so only reasonably + * large files will have page numbers with any other than the bottom 9 + * bits set. We XOR in the MPOOL offset of the MPOOLFILE that backs the + * page, since that should also be unique for the page. We don't want + * to do anything very fancy -- speed is more important to us than using + * good hashing. + */ +#define NBUCKET(mc, mf_offset, pgno) \ + (((pgno) ^ ((mf_offset) << 9)) % (mc)->htab_buckets) + +/* + * MPOOL -- + * Shared memory pool region. + */ +struct __mpool { + /* + * The memory pool can be broken up into individual pieces/files. + * Not what we would have liked, but on Solaris you can allocate + * only a little more than 2GB of memory in a contiguous chunk, + * and I expect to see more systems with similar issues. + * + * The first of these pieces/files describes the entire pool, all + * subsequent ones only describe a part of the cache. + * + * We single-thread memp_sync and memp_fsync calls. + * + * This mutex is intended *only* to single-thread access to the call, + * it is not used to protect the lsn and lsn_cnt fields, the region + * lock is used to protect them. + */ + MUTEX sync_mutex; /* Checkpoint lock. */ + DB_LSN lsn; /* Maximum checkpoint LSN. */ + u_int32_t lsn_cnt; /* Checkpoint buffers left to write. */ + + SH_TAILQ_HEAD(__mpfq) mpfq; /* List of MPOOLFILEs. */ + + u_int32_t nreg; /* Number of underlying REGIONS. */ + roff_t regids; /* Array of underlying REGION Ids. */ + +#define MP_LSN_RETRY 0x01 /* Retry all BH_WRITE buffers. */ + u_int32_t flags; + + /* + * The following structure fields only describe the cache portion of + * the region. + */ + SH_TAILQ_HEAD(__bhq) bhq; /* LRU list of buffer headers. */ + + int htab_buckets; /* Number of hash table entries. */ + roff_t htab; /* Hash table offset. */ + + DB_MPOOL_STAT stat; /* Per-cache mpool statistics. */ +#ifdef MUTEX_SYSTEM_RESOURCES + roff_t maint_off; /* Maintenance information offset */ +#endif +}; + +/* + * MPOOLFILE -- + * Shared DB_MPOOLFILE information. + */ +struct __mpoolfile { + SH_TAILQ_ENTRY q; /* List of MPOOLFILEs */ + + db_pgno_t mpf_cnt; /* Ref count: DB_MPOOLFILEs. */ + db_pgno_t block_cnt; /* Ref count: blocks in cache. */ + db_pgno_t lsn_cnt; /* Checkpoint buffers left to write. */ + + int ftype; /* File type. */ + int32_t lsn_off; /* Page's LSN offset. */ + u_int32_t clear_len; /* Bytes to clear on page create. */ + + roff_t path_off; /* File name location. */ + roff_t fileid_off; /* File identification location. */ + + roff_t pgcookie_len; /* Pgin/pgout cookie length. */ + roff_t pgcookie_off; /* Pgin/pgout cookie location. */ + + db_pgno_t last_pgno; /* Last page in the file. */ + db_pgno_t orig_last_pgno; /* Original last page in the file. */ + + DB_MPOOL_FSTAT stat; /* Per-file mpool statistics. */ + +#define MP_CAN_MMAP 0x01 /* If the file can be mmap'd. */ +#define MP_DEADFILE 0x02 /* Dirty pages can simply be trashed. */ +#define MP_TEMP 0x04 /* Backing file is a temporary. */ +#define MP_UNLINK 0x08 /* Unlink file on last close. */ + u_int32_t flags; +}; + +/* + * BH_TO_CACHE -- + * Return the cache where we can find the specified buffer header. + */ +#define BH_TO_CACHE(dbmp, bhp) \ + (dbmp)->reginfo[NCACHE((dbmp)->reginfo[0].primary, (bhp)->pgno)].primary + +/* + * BH -- + * Buffer header. + */ +struct __bh { + MUTEX mutex; /* Buffer thread/process lock. */ + + u_int16_t ref; /* Reference count. */ + +#define BH_CALLPGIN 0x001 /* Page needs to be reworked... */ +#define BH_DIRTY 0x002 /* Page was modified. */ +#define BH_DISCARD 0x004 /* Page is useless. */ +#define BH_LOCKED 0x008 /* Page is locked (I/O in progress). */ +#define BH_SYNC 0x010 /* memp sync: write the page */ +#define BH_SYNC_LOGFLSH 0x020 /* memp sync: also flush the log */ +#define BH_TRASH 0x040 /* Page is garbage. */ + u_int16_t flags; + + SH_TAILQ_ENTRY q; /* LRU queue. */ + SH_TAILQ_ENTRY hq; /* MPOOL hash bucket queue. */ + + db_pgno_t pgno; /* Underlying MPOOLFILE page number. */ + roff_t mf_offset; /* Associated MPOOLFILE offset. */ + + /* + * !!! + * This array must be at least size_t aligned -- the DB access methods + * put PAGE and other structures into it, and then access them directly. + * (We guarantee size_t alignment to applications in the documentation, + * too.) + */ + u_int8_t buf[1]; /* Variable length data. */ +}; + +#include "mp_ext.h" diff --git a/db/include/mp_ext.h b/db/include/mp_ext.h new file mode 100644 index 000000000..9f2b8c61f --- /dev/null +++ b/db/include/mp_ext.h @@ -0,0 +1,33 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _mp_ext_h_ +#define _mp_ext_h_ +#if defined(__cplusplus) +extern "C" { +#endif +int __memp_alloc __P((DB_MPOOL *, + REGINFO *, MPOOLFILE *, size_t, roff_t *, void *)); +int __memp_bhwrite + __P((DB_MPOOL *, MPOOLFILE *, BH *, int *, int *)); +int __memp_pgread __P((DB_MPOOLFILE *, BH *, int)); +int __memp_pgwrite + __P((DB_MPOOL *, DB_MPOOLFILE *, BH *, int *, int *)); +int __memp_pg __P((DB_MPOOLFILE *, BH *, int)); +void __memp_bhfree __P((DB_MPOOL *, BH *, int)); +void __memp_set_unlink __P((DB_MPOOLFILE *)); +void __memp_clear_unlink __P((DB_MPOOLFILE *)); +int __memp_fopen __P((DB_MPOOL *, MPOOLFILE *, const char *, + u_int32_t, int, size_t, int, DB_MPOOL_FINFO *, DB_MPOOLFILE **)); +void __memp_mf_discard __P((DB_MPOOL *, MPOOLFILE *)); +int __memp_fremove __P((DB_MPOOLFILE *)); +char * __memp_fn __P((DB_MPOOLFILE *)); +char * __memp_fns __P((DB_MPOOL *, MPOOLFILE *)); +void __memp_dbenv_create __P((DB_ENV *)); +int __memp_open __P((DB_ENV *)); +int __memp_close __P((DB_ENV *)); +void __mpool_region_destroy __P((DB_ENV *, REGINFO *)); +void __memp_dump_region __P((DB_ENV *, char *, FILE *)); +int __mp_xxx_fh __P((DB_MPOOLFILE *, DB_FH **)); +#if defined(__cplusplus) +} +#endif +#endif /* _mp_ext_h_ */ diff --git a/db/include/mutex.h b/db/include/mutex.h new file mode 100644 index 000000000..a8a414510 --- /dev/null +++ b/db/include/mutex.h @@ -0,0 +1,744 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: mutex.h,v 11.41 2000/12/22 19:28:15 bostic Exp $ + */ + +/* + * Some of the Berkeley DB ports require single-threading at various + * places in the code. In those cases, these #defines will be set. + */ +#define DB_BEGIN_SINGLE_THREAD +#define DB_END_SINGLE_THREAD + +/* + * When the underlying system mutexes require system resources, we have + * to clean up after application failure. This violates the rule that + * we never look at a shared region after a failure, but there's no other + * choice. In those cases, this #define is set. + */ +#ifdef HAVE_QNX +#define MUTEX_SYSTEM_RESOURCES +#endif + +/********************************************************************* + * POSIX.1 pthreads interface. + *********************************************************************/ +#ifdef HAVE_MUTEX_PTHREADS +#include + +#define MUTEX_FIELDS \ + pthread_mutex_t mutex; /* Mutex. */ \ + pthread_cond_t cond; /* Condition variable. */ +#endif + +/********************************************************************* + * Solaris lwp threads interface. + * + * !!! + * We use LWP mutexes on Solaris instead of UI or POSIX mutexes (both of + * which are available), for two reasons. First, the Solaris C library + * includes versions of the both UI and POSIX thread mutex interfaces, but + * they are broken in that they don't support inter-process locking, and + * there's no way to detect it, e.g., calls to configure the mutexes for + * inter-process locking succeed without error. So, we use LWP mutexes so + * that we don't fail in fairly undetectable ways because the application + * wasn't linked with the appropriate threads library. Second, there were + * bugs in SunOS 5.7 (Solaris 7) where if an application loaded the C library + * before loading the libthread/libpthread threads libraries (e.g., by using + * dlopen to load the DB library), the pwrite64 interface would be translated + * into a call to pwrite and DB would drop core. + *********************************************************************/ +#ifdef HAVE_MUTEX_SOLARIS_LWP +/* + * XXX + * Don't change to -- although lwp.h is listed in the + * Solaris manual page as the correct include to use, it causes the Solaris + * compiler on SunOS 2.6 to fail. + */ +#include + +#define MUTEX_FIELDS \ + lwp_mutex_t mutex; /* Mutex. */ \ + lwp_cond_t cond; /* Condition variable. */ +#endif + +/********************************************************************* + * Solaris/Unixware threads interface. + *********************************************************************/ +#ifdef HAVE_MUTEX_UI_THREADS +#include +#include + +#define MUTEX_FIELDS \ + mutex_t mutex; /* Mutex. */ \ + cond_t cond; /* Condition variable. */ +#endif + +/********************************************************************* + * AIX C library functions. + *********************************************************************/ +#ifdef HAVE_MUTEX_AIX_CHECK_LOCK +#include +typedef int tsl_t; +#define MUTEX_ALIGN sizeof(int) + +#ifdef LOAD_ACTUAL_MUTEX_CODE +#define MUTEX_INIT(x) 0 +#define MUTEX_SET(x) (!_check_lock(x, 0, 1)) +#define MUTEX_UNSET(x) _clear_lock(x, 0) +#endif +#endif + +/********************************************************************* + * General C library functions (msemaphore). + * + * !!! + * Check for HPPA as a special case, because it requires unusual alignment, + * and doesn't support semaphores in malloc(3) or shmget(2) memory. + * + * !!! + * Do not remove the MSEM_IF_NOWAIT flag. The problem is that if a single + * process makes two msem_lock() calls in a row, the second one returns an + * error. We depend on the fact that we can lock against ourselves in the + * locking subsystem, where we set up a mutex so that we can block ourselves. + * Tested on OSF1 v4.0. + *********************************************************************/ +#ifdef HAVE_MUTEX_HPPA_MSEM_INIT +#define MUTEX_NO_MALLOC_LOCKS +#define MUTEX_NO_SHMGET_LOCKS + +#define MUTEX_ALIGN 16 +#endif + +#if defined(HAVE_MUTEX_MSEM_INIT) || defined(HAVE_MUTEX_HPPA_MSEM_INIT) +#include +typedef msemaphore tsl_t; + +#ifndef MUTEX_ALIGN +#define MUTEX_ALIGN sizeof(int) +#endif + +#ifdef LOAD_ACTUAL_MUTEX_CODE +#define MUTEX_INIT(x) (msem_init(x, MSEM_UNLOCKED) <= (msemaphore *)0) +#define MUTEX_SET(x) (!msem_lock(x, MSEM_IF_NOWAIT)) +#define MUTEX_UNSET(x) msem_unlock(x, 0) +#endif +#endif + +/********************************************************************* + * Plan 9 library functions. + *********************************************************************/ +#ifdef HAVE_MUTEX_PLAN9 +typedef Lock tsl_t; + +#define MUTEX_ALIGN sizeof(int) + +#define MUTEX_INIT(x) (memset(x, 0, sizeof(Lock)), 0) +#define MUTEX_SET(x) canlock(x) +#define MUTEX_UNSET(x) unlock(x) +#endif + +/********************************************************************* + * Reliant UNIX C library functions. + *********************************************************************/ +#ifdef HAVE_MUTEX_RELIANTUNIX_INITSPIN +#include +typedef spinlock_t tsl_t; + +#ifdef LOAD_ACTUAL_MUTEX_CODE +#define MUTEX_INIT(x) (initspin(x, 1), 0) +#define MUTEX_SET(x) (cspinlock(x) == 0) +#define MUTEX_UNSET(x) spinunlock(x) +#endif +#endif + +/********************************************************************* + * General C library functions (POSIX 1003.1 sema_XXX). + * + * !!! + * Never selected by autoconfig in this release (semaphore calls are known + * to not work in Solaris 5.5). + *********************************************************************/ +#ifdef HAVE_MUTEX_SEMA_INIT +#include +typedef sema_t tsl_t; +#define MUTEX_ALIGN sizeof(int) + +#ifdef LOAD_ACTUAL_MUTEX_CODE +#define MUTEX_DESTROY(x) sema_destroy(x) +#define MUTEX_INIT(x) (sema_init(x, 1, USYNC_PROCESS, NULL) != 0) +#define MUTEX_SET(x) (sema_wait(x) == 0) +#define MUTEX_UNSET(x) sema_post(x) +#endif +#endif + +/********************************************************************* + * SGI C library functions. + *********************************************************************/ +#ifdef HAVE_MUTEX_SGI_INIT_LOCK +#include +typedef abilock_t tsl_t; +#define MUTEX_ALIGN sizeof(int) + +#ifdef LOAD_ACTUAL_MUTEX_CODE +#define MUTEX_INIT(x) (init_lock(x) != 0) +#define MUTEX_SET(x) (!acquire_lock(x)) +#define MUTEX_UNSET(x) release_lock(x) +#endif +#endif + +/********************************************************************* + * Solaris C library functions. + * + * !!! + * These are undocumented functions, but they're the only ones that work + * correctly as far as we know. + *********************************************************************/ +#ifdef HAVE_MUTEX_SOLARIS_LOCK_TRY +#include +typedef lock_t tsl_t; +#define MUTEX_ALIGN sizeof(int) + +#ifdef LOAD_ACTUAL_MUTEX_CODE +#define MUTEX_INIT(x) 0 +#define MUTEX_SET(x) _lock_try(x) +#define MUTEX_UNSET(x) _lock_clear(x) +#endif +#endif + +/********************************************************************* + * VMS. + *********************************************************************/ +#ifdef HAVE_MUTEX_VMS +#include ; +#include +typedef unsigned char tsl_t; +#define MUTEX_ALIGN sizeof(unsigned int) + +#ifdef LOAD_ACTUAL_MUTEX_CODE +#ifdef __ALPHA +#define MUTEX_SET(tsl) (!__TESTBITSSI(tsl, 0)) +#else /* __VAX */ +#define MUTEX_SET(tsl) (!(int)_BBSSI(0, tsl)) +#endif +#define MUTEX_UNSET(tsl) (*(tsl) = 0) +#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl) +#endif +#endif + +/********************************************************************* + * VxWorks + * Use basic binary semaphores in VxWorks, as we currently do not need + * any special features. We do need the ability to single-thread the + * entire system, however, because VxWorks doesn't support the open(2) + * flag O_EXCL, the mechanism we normally use to single thread access + * when we're first looking for a DB environment. + *********************************************************************/ +#ifdef HAVE_MUTEX_VXWORKS +#define MUTEX_SYSTEM_RESOURCES + +#include "semLib.h" +typedef SEM_ID tsl_t; +#define MUTEX_ALIGN sizeof(unsigned int) + +#ifdef LOAD_ACTUAL_MUTEX_CODE +#define MUTEX_SET(tsl) (semTake((*tsl), WAIT_FOREVER) == OK) +#define MUTEX_UNSET(tsl) (semGive((*tsl)) == OK) +#define MUTEX_INIT(tsl) \ + ((*(tsl) = semBCreate(SEM_Q_FIFO, SEM_FULL)) == NULL) +#define MUTEX_DESTROY(tsl) semDelete(*tsl) +#endif + +/* + * Use the taskLock() mutex to eliminate a race where two tasks are + * trying to initialize the global lock at the same time. + */ +#undef DB_BEGIN_SINGLE_THREAD +#define DB_BEGIN_SINGLE_THREAD \ +do { \ + if (DB_GLOBAL(db_global_init)) \ + (void)semTake(DB_GLOBAL(db_global_lock), WAIT_FOREVER); \ + else { \ + taskLock(); \ + if (DB_GLOBAL(db_global_init)) { \ + taskUnlock(); \ + (void)semTake(DB_GLOBAL(db_global_lock), \ + WAIT_FOREVER); \ + continue; \ + } \ + DB_GLOBAL(db_global_lock) = \ + semBCreate(SEM_Q_FIFO, SEM_EMPTY); \ + if (DB_GLOBAL(db_global_lock) != NULL) \ + DB_GLOBAL(db_global_init) = 1; \ + taskUnlock(); \ + } \ +} while (DB_GLOBAL(db_global_init) == 0) +#undef DB_END_SINGLE_THREAD +#define DB_END_SINGLE_THREAD (void)semGive(DB_GLOBAL(db_global_lock)) +#endif + +/********************************************************************* + * Win16 + * + * Win16 spinlocks are simple because we cannot possibly be preempted. + * + * !!! + * We should simplify this by always returning a no-need-to-lock lock + * when we initialize the mutex. + *********************************************************************/ +#ifdef HAVE_MUTEX_WIN16 +typedef unsigned int tsl_t; +#define MUTEX_ALIGN sizeof(unsigned int) + +#ifdef LOAD_ACTUAL_MUTEX_CODE +#define MUTEX_INIT(x) 0 +#define MUTEX_SET(tsl) (*(tsl) = 1) +#define MUTEX_UNSET(tsl) (*(tsl) = 0) +#endif +#endif + +/********************************************************************* + * Win32 + *********************************************************************/ +#ifdef HAVE_MUTEX_WIN32 +typedef unsigned int tsl_t; +#define MUTEX_ALIGN sizeof(unsigned int) + +#ifdef LOAD_ACTUAL_MUTEX_CODE +#define MUTEX_INIT(x) 0 +#define MUTEX_SET(tsl) (!InterlockedExchange((PLONG)tsl, 1)) +#define MUTEX_UNSET(tsl) (*(tsl) = 0) +#endif +#endif + +/********************************************************************* + * 68K/gcc assembly. + *********************************************************************/ +#ifdef HAVE_MUTEX_68K_GCC_ASSEMBLY +typedef unsigned char tsl_t; + +#ifdef LOAD_ACTUAL_MUTEX_CODE +/* + * For gcc/68K, 0 is clear, 1 is set. + */ +#define MUTEX_SET(tsl) ({ \ + register tsl_t *__l = (tsl); \ + int __r; \ + asm volatile("tas %1; \n \ + seq %0" \ + : "=dm" (__r), "=m" (*__l) \ + : "1" (*__l) \ + ); \ + __r & 1; \ +}) + +#define MUTEX_UNSET(tsl) (*(tsl) = 0) +#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl) +#endif +#endif + +/********************************************************************* + * ALPHA/gcc assembly. + *********************************************************************/ +#ifdef HAVE_MUTEX_ALPHA_GCC_ASSEMBLY +typedef u_int32_t tsl_t; +#define MUTEX_ALIGN 4 + +#ifdef LOAD_ACTUAL_MUTEX_CODE +/* + * For gcc/alpha. Should return 0 if could not acquire the lock, 1 if + * lock was acquired properly. + */ +#ifdef __GNUC__ +static inline int +MUTEX_SET(tsl_t *tsl) { + register tsl_t *__l = tsl; + register tsl_t __r; + asm volatile( + "1: ldl_l %0,%2\n" + " blbs %0,2f\n" + " or $31,1,%0\n" + " stl_c %0,%1\n" + " beq %0,3f\n" + " mb\n" + " br 3f\n" + "2: xor %0,%0\n" + "3:" + : "=&r"(__r), "=m"(*__l) : "1"(*__l) : "memory"); + return __r; +} + +/* + * Unset mutex. Judging by Alpha Architecture Handbook, the mb instruction + * might be necessary before unlocking + */ +static inline int +MUTEX_UNSET(tsl_t *tsl) { + asm volatile(" mb\n"); + return *tsl = 0; +} +#endif + +#ifdef __DECC +#include +#define MUTEX_SET(tsl) (__LOCK_LONG_RETRY((tsl), 1) != 0) +#define MUTEX_UNSET(tsl) (*(tsl) = 0) +#endif + +#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl) +#endif +#endif + +/********************************************************************* + * HPPA/gcc assembly. + *********************************************************************/ +#ifdef HAVE_MUTEX_HPPA_GCC_ASSEMBLY +typedef u_int32_t tsl_t; +#define MUTEX_ALIGN 16 + +#ifdef LOAD_ACTUAL_MUTEX_CODE +/* + * The PA-RISC has a "load and clear" instead of a "test and set" instruction. + * The 32-bit word used by that instruction must be 16-byte aligned. We could + * use the "aligned" attribute in GCC but that doesn't work for stack variables. + */ +#define MUTEX_SET(tsl) ({ \ + register tsl_t *__l = (tsl); \ + int __r; \ + asm volatile("ldcws 0(%1),%0" : "=r" (__r) : "r" (__l)); \ + __r & 1; \ +}) + +#define MUTEX_UNSET(tsl) (*(tsl) = -1) +#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl) +#endif +#endif + +/********************************************************************* + * IA64/gcc assembly. + *********************************************************************/ +#ifdef HAVE_MUTEX_IA64_GCC_ASSEMBLY +typedef unsigned char tsl_t; + +#ifdef LOAD_ACTUAL_MUTEX_CODE +/* + * For gcc/ia64, 0 is clear, 1 is set. + */ +#define MUTEX_SET(tsl) ({ \ + register tsl_t *__l = (tsl); \ + long __r; \ + asm volatile("xchg1 %0=%1,%3" : "=r"(__r), "=m"(*__l) : "1"(*__l), "r"(1));\ + __r ^ 1; \ +}) + +/* + * Store through a "volatile" pointer so we get a store with "release" + * semantics. + */ +#define MUTEX_UNSET(tsl) (*(volatile unsigned char *)(tsl) = 0) +#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl) +#endif +#endif + +/********************************************************************* + * PowerPC/gcc assembly. + *********************************************************************/ +#ifdef HAVE_MUTEX_PPC_GCC_ASSEMBLY +typedef u_int32_t tsl_t; + +#ifdef LOAD_ACTUAL_MUTEX_CODE +/* + * The PowerPC does a sort of pseudo-atomic locking. You set up a + * 'reservation' on a chunk of memory containing a mutex by loading the + * mutex value with LWARX. If the mutex has an 'unlocked' (arbitrary) + * value, you then try storing into it with STWCX. If no other process or + * thread broke your 'reservation' by modifying the memory containing the + * mutex, then the STCWX succeeds; otherwise it fails and you try to get + * a reservation again. + * + * While mutexes are explicitly 4 bytes, a 'reservation' applies to an + * entire cache line, normally 32 bytes, aligned naturally. If the mutex + * lives near data that gets changed a lot, there's a chance that you'll + * see more broken reservations than you might otherwise. The only + * situation in which this might be a problem is if one processor is + * beating on a variable in the same cache block as the mutex while another + * processor tries to acquire the mutex. That's bad news regardless + * because of the way it bashes caches, but if you can't guarantee that a + * mutex will reside in a relatively quiescent cache line, you might + * consider padding the mutex to force it to live in a cache line by + * itself. No, you aren't guaranteed that cache lines are 32 bytes. Some + * embedded processors use 16-byte cache lines, while some 64-bit + * processors use 128-bit cache lines. But assuming a 32-byte cache line + * won't get you into trouble for now. + * + * If mutex locking is a bottleneck, then you can speed it up by adding a + * regular LWZ load before the LWARX load, so that you can test for the + * common case of a locked mutex without wasting cycles making a reservation. + * + * 'set' mutexes have the value 1, like on Intel; the returned value from + * MUTEX_SET() is 1 if the mutex previously had its low bit set, 0 otherwise. + */ +#define MUTEX_SET(tsl) ({ \ + int __one = 1; \ + int __r; \ + tsl_t *__l = (tsl); \ + asm volatile (" \ +0: \ + lwarx %0,0,%1; \ + cmpwi %0,0; \ + bne 1f; \ + stwcx. %2,0,%1; \ + bne- 0b; \ +1:" \ + : "=&r" (__r) \ + : "r" (__l), "r" (__one)); \ + __r & 1; \ +}) + +#define MUTEX_UNSET(tsl) (*(tsl) = 0) +#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl) +#endif +#endif + +/********************************************************************* + * SCO/cc assembly. + *********************************************************************/ +#ifdef HAVE_MUTEX_SCO_X86_CC_ASSEMBLY +typedef unsigned char tsl_t; + +#ifdef LOAD_ACTUAL_MUTEX_CODE +/* + * UnixWare has threads in libthread, but OpenServer doesn't (yet). + * + * For cc/x86, 0 is clear, 1 is set. + */ + +#if defined(__USLC__) +asm int +_tsl_set(void *tsl) +{ +%mem tsl + movl tsl, %ecx + movl $1, %eax + lock + xchgb (%ecx),%al + xorl $1,%eax +} +#endif + +#define MUTEX_SET(tsl) _tsl_set(tsl) +#define MUTEX_UNSET(tsl) (*(tsl) = 0) +#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl) +#endif +#endif + +/********************************************************************* + * Sparc/gcc assembly. + *********************************************************************/ +#ifdef HAVE_MUTEX_SPARC_GCC_ASSEMBLY +typedef unsigned char tsl_t; + +#ifdef LOAD_ACTUAL_MUTEX_CODE +/* + * + * The ldstub instruction takes the location specified by its first argument + * (a register containing a memory address) and loads its contents into its + * second argument (a register) and atomically sets the contents the location + * specified by its first argument to a byte of 1s. (The value in the second + * argument is never read, but only overwritten.) + * + * The stbar is needed for v8, and is implemented as membar #sync on v9, + + so is functional there as well. For v7, stbar may generate an illegal + + instruction and we have no way to tell what we're running on. Some + + operating systems notice and skip this instruction in the fault handler. + * + * For gcc/sparc, 0 is clear, 1 is set. + */ +#define MUTEX_SET(tsl) ({ \ + register tsl_t *__l = (tsl); \ + register tsl_t __r; \ + __asm__ volatile \ + ("ldstub [%1],%0; stbar" \ + : "=r"( __r) : "r" (__l)); \ + !__r; \ +}) + +#define MUTEX_UNSET(tsl) (*(tsl) = 0) +#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl) +#endif +#endif + +/********************************************************************* + * UTS/cc assembly. + *********************************************************************/ +#ifdef HAVE_MUTEX_UTS_CC_ASSEMBLY +typedef int tsl_t; + +#define MUTEX_ALIGN sizeof(int) +#ifdef LOAD_ACTUAL_MUTEX_CODE +#define MUTEX_INIT(x) 0 +#define MUTEX_SET(x) (!uts_lock(x, 1)) +#define MUTEX_UNSET(x) (*(x) = 0) +#endif +#endif + +/********************************************************************* + * x86/gcc assembly. + *********************************************************************/ +#ifdef HAVE_MUTEX_X86_GCC_ASSEMBLY +typedef unsigned char tsl_t; + +#ifdef LOAD_ACTUAL_MUTEX_CODE +/* + * For gcc/x86, 0 is clear, 1 is set. + */ +#define MUTEX_SET(tsl) ({ \ + register tsl_t *__l = (tsl); \ + int __r; \ + asm volatile("movl $1,%%eax; lock; xchgb %1,%%al; xorl $1,%%eax"\ + : "=&a" (__r), "=m" (*__l) \ + : "1" (*__l) \ + ); \ + __r & 1; \ +}) + +#define MUTEX_UNSET(tsl) (*(tsl) = 0) +#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl) +#endif +#endif + +/* + * Mutex alignment defaults to one byte. + * + * !!! + * Various systems require different alignments for mutexes (the worst we've + * seen so far is 16-bytes on some HP architectures). Malloc(3) is assumed + * to return reasonable alignment, all other mutex users must ensure proper + * alignment locally. + */ +#ifndef MUTEX_ALIGN +#define MUTEX_ALIGN 1 +#endif + +/* + * Mutex destruction defaults to a no-op. + */ +#ifdef LOAD_ACTUAL_MUTEX_CODE +#ifndef MUTEX_DESTROY +#define MUTEX_DESTROY(x) +#endif +#endif + +#define MUTEX_IGNORE 0x001 /* Ignore, no lock required. */ +#define MUTEX_INITED 0x002 /* Mutex is successfully initialized */ +#define MUTEX_SELF_BLOCK 0x004 /* Must block self. */ +#define MUTEX_THREAD 0x008 /* Thread-only mutex. */ + +/* Mutex. */ +struct __mutex_t { +#ifdef HAVE_MUTEX_THREADS +#ifdef MUTEX_FIELDS + MUTEX_FIELDS +#else + tsl_t tas; /* Test and set. */ +#endif + u_int32_t spins; /* Spins before block. */ + u_int32_t locked; /* !0 if locked. */ +#else + u_int32_t off; /* Byte offset to lock. */ + u_int32_t pid; /* Lock holder: 0 or process pid. */ +#endif + u_int32_t mutex_set_wait; /* Granted after wait. */ + u_int32_t mutex_set_nowait; /* Granted without waiting. */ +#ifdef MUTEX_SYSTEM_RESOURCES + roff_t reg_off; /* Shared lock info offset. */ +#endif + + u_int8_t flags; /* MUTEX_XXX */ +}; + +/* Redirect calls to the correct functions. */ +#ifdef HAVE_MUTEX_THREADS +#if defined(HAVE_MUTEX_PTHREADS) || defined(HAVE_MUTEX_SOLARIS_LWP) || defined(HAVE_MUTEX_UI_THREADS) +#define __db_mutex_init(a, b, c, d) __db_pthread_mutex_init(a, b, d) +#define __db_mutex_lock(a, b, c) __db_pthread_mutex_lock(a, b) +#define __db_mutex_unlock(a, b) __db_pthread_mutex_unlock(a, b) +#define __db_mutex_destroy(a) __db_pthread_mutex_destroy(a) +#else +#define __db_mutex_init(a, b, c, d) __db_tas_mutex_init(a, b, d) +#define __db_mutex_lock(a, b, c) __db_tas_mutex_lock(a, b) +#define __db_mutex_unlock(a, b) __db_tas_mutex_unlock(a, b) +#define __db_mutex_destroy(a) __db_tas_mutex_destroy(a) +#endif +#else +#define __db_mutex_init(a, b, c, d) __db_fcntl_mutex_init(a, b, c) +#define __db_mutex_lock(a, b, c) __db_fcntl_mutex_lock(a, b, c) +#define __db_mutex_unlock(a, b) __db_fcntl_mutex_unlock(a, b) +#define __db_mutex_destroy(a) __db_fcntl_mutex_destroy(a) +#endif + +/* Redirect system resource calls to correct functions */ +#ifdef MUTEX_SYSTEM_RESOURCES +#define __db_maintinit(a, b, c) __db_shreg_maintinit(a, b, c) +#define __db_shlocks_clear(a, b, c) __db_shreg_locks_clear(a, b, c) +#define __db_shlocks_destroy(a, b) __db_shreg_locks_destroy(a, b) +#define __db_shmutex_init(a, b, c, d, e, f) \ + __db_shreg_mutex_init(a, b, c, d, e, f) +#else +#define __db_maintinit(a, b, c) +#define __db_shlocks_clear(a, b, c) +#define __db_shlocks_destroy(a, b) +#define __db_shmutex_init(a, b, c, d, e, f) __db_mutex_init(a, b, c, d) +#endif + +/* + * Lock/unlock a mutex. If the mutex was marked as uninteresting, the thread + * of control can proceed without it. + * + * If the lock is for threads-only, then it was optionally not allocated and + * file handles aren't necessary, as threaded applications aren't supported by + * fcntl(2) locking. + */ +#ifdef DIAGNOSTIC + /* + * XXX + * We want to switch threads as often as possible. Yield every time + * we get a mutex to ensure contention. + */ +#define MUTEX_LOCK(dbenv, mp, fh) \ + if (!F_ISSET((MUTEX *)(mp), MUTEX_IGNORE)) \ + (void)__db_mutex_lock(dbenv, mp, fh); \ + if (DB_GLOBAL(db_pageyield)) \ + __os_yield(NULL, 1); +#else +#define MUTEX_LOCK(dbenv, mp, fh) \ + if (!F_ISSET((MUTEX *)(mp), MUTEX_IGNORE)) \ + (void)__db_mutex_lock(dbenv, mp, fh); +#endif +#define MUTEX_UNLOCK(dbenv, mp) \ + if (!F_ISSET((MUTEX *)(mp), MUTEX_IGNORE)) \ + (void)__db_mutex_unlock(dbenv, mp); +#define MUTEX_THREAD_LOCK(dbenv, mp) \ + if (mp != NULL) \ + MUTEX_LOCK(dbenv, mp, NULL) +#define MUTEX_THREAD_UNLOCK(dbenv, mp) \ + if (mp != NULL) \ + MUTEX_UNLOCK(dbenv, mp) + +/* + * We use a single file descriptor for fcntl(2) locking, and (generally) the + * object's offset in a shared region as the byte that we're locking. So, + * there's a (remote) possibility that two objects might have the same offsets + * such that the locks could conflict, resulting in deadlock. To avoid this + * possibility, we offset the region offset by a small integer value, using a + * different offset for each subsystem's locks. Since all region objects are + * suitably aligned, the offset guarantees that we don't collide with another + * region's objects. + */ +#define DB_FCNTL_OFF_GEN 0 /* Everything else. */ +#define DB_FCNTL_OFF_LOCK 1 /* Lock subsystem offset. */ +#define DB_FCNTL_OFF_MPOOL 2 /* Mpool subsystem offset. */ diff --git a/db/include/mutex_ext.h b/db/include/mutex_ext.h new file mode 100644 index 000000000..040a6615e --- /dev/null +++ b/db/include/mutex_ext.h @@ -0,0 +1,31 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _mutex_ext_h_ +#define _mutex_ext_h_ +#if defined(__cplusplus) +extern "C" { +#endif +int __db_fcntl_mutex_init __P((DB_ENV *, MUTEX *, u_int32_t)); +int __db_fcntl_mutex_lock __P((DB_ENV *, MUTEX *, DB_FH *)); +int __db_fcntl_mutex_unlock __P((DB_ENV *, MUTEX *)); +int __db_fcntl_mutex_destroy __P((MUTEX *)); +int __db_pthread_mutex_init __P((DB_ENV *, MUTEX *, u_int32_t)); +int __db_pthread_mutex_lock __P((DB_ENV *, MUTEX *)); +int __db_pthread_mutex_unlock __P((DB_ENV *, MUTEX *)); +int __db_pthread_mutex_destroy __P((MUTEX *)); +int __db_tas_mutex_init __P((DB_ENV *, MUTEX *, u_int32_t)); +int __db_tas_mutex_lock __P((DB_ENV *, MUTEX *)); +int __db_tas_mutex_unlock __P((DB_ENV *, MUTEX *)); +int __db_tas_mutex_destroy __P((MUTEX *)); +int __db_mutex_alloc __P((DB_ENV *, REGINFO *, MUTEX **)); +void __db_mutex_free __P((DB_ENV *, REGINFO *, MUTEX *)); +int __db_shreg_locks_record __P((DB_ENV *, MUTEX *, REGINFO *, + REGMAINT *)); +void __db_shreg_locks_clear __P((MUTEX *, REGINFO *, REGMAINT *)); +void __db_shreg_locks_destroy __P((REGINFO *, REGMAINT *)); +int __db_shreg_mutex_init __P((DB_ENV *, MUTEX *, u_int32_t, + u_int32_t, REGINFO *, REGMAINT *)); +void __db_shreg_maintinit __P((REGINFO *, void *addr, size_t)); +#if defined(__cplusplus) +} +#endif +#endif /* _mutex_ext_h_ */ diff --git a/db/include/os.h b/db/include/os.h new file mode 100644 index 000000000..b5d469e88 --- /dev/null +++ b/db/include/os.h @@ -0,0 +1,46 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: os.h,v 11.5 2000/10/27 20:32:01 dda Exp $ + */ + +#if defined(__cplusplus) +extern "C" { +#endif +/* + * Filehandle. + */ +struct __fh_t { +#if defined(DB_WIN32) + HANDLE handle; /* Windows/32 file handle. */ +#endif + int fd; /* POSIX file descriptor. */ + + u_int32_t log_size; /* XXX: Log file size. */ + +#define DB_FH_NOSYNC 0x01 /* Handle doesn't need to be sync'd. */ +#define DB_FH_VALID 0x02 /* Handle is valid. */ + u_int8_t flags; +}; + +/* + * We group certain seek/write calls into a single function so that we + * can use pread(2)/pwrite(2) where they're available. + */ +#define DB_IO_READ 1 +#define DB_IO_WRITE 2 +typedef struct __io_t { + DB_FH *fhp; /* I/O file handle. */ + MUTEX *mutexp; /* Mutex to lock. */ + size_t pagesize; /* Page size. */ + db_pgno_t pgno; /* Page number. */ + u_int8_t *buf; /* Buffer. */ + size_t bytes; /* Bytes read/written. */ +} DB_IO; + +#if defined(__cplusplus) +} +#endif diff --git a/db/include/os_ext.h b/db/include/os_ext.h new file mode 100644 index 000000000..ae9e3d304 --- /dev/null +++ b/db/include/os_ext.h @@ -0,0 +1,62 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _os_ext_h_ +#define _os_ext_h_ +#if defined(__cplusplus) +extern "C" { +#endif +int __os_abspath __P((const char *)); +int __os_strdup __P((DB_ENV *, const char *, void *)); +int __os_calloc __P((DB_ENV *, size_t, size_t, void *)); +int __os_malloc __P((DB_ENV *, size_t, void *(*)(size_t), void *)); +int __os_realloc __P((DB_ENV *, + size_t, void *(*)(void *, size_t), void *)); +void __os_free __P((void *, size_t)); +void __os_freestr __P((void *)); +void *__ua_memcpy __P((void *, const void *, size_t)); +int __os_dirlist __P((DB_ENV *, const char *, char ***, int *)); +void __os_dirfree __P((char **, int)); +int __os_get_errno __P((void)); +void __os_set_errno __P((int)); +int __os_fileid __P((DB_ENV *, const char *, int, u_int8_t *)); +int __os_finit __P((DB_ENV *, DB_FH *, size_t, int)); +int __os_fpinit __P((DB_ENV *, DB_FH *, db_pgno_t, int, int)); +int __os_fsync __P((DB_ENV *, DB_FH *)); +int __os_openhandle __P((DB_ENV *, const char *, int, int, DB_FH *)); +int __os_closehandle __P((DB_FH *)); +int __os_r_sysattach __P((DB_ENV *, REGINFO *, REGION *)); +int __os_r_sysdetach __P((DB_ENV *, REGINFO *, int)); +int __os_mapfile __P((DB_ENV *, + char *, DB_FH *, size_t, int, void **)); +int __os_unmapfile __P((DB_ENV *, void *, size_t)); +u_int32_t __db_oflags __P((int)); +int __db_omode __P((const char *)); +int __os_open __P((DB_ENV *, const char *, u_int32_t, int, DB_FH *)); +int __os_shmname __P((DB_ENV *, const char *, char **)); +int __os_r_attach __P((DB_ENV *, REGINFO *, REGION *)); +int __os_r_detach __P((DB_ENV *, REGINFO *, int)); +int __os_rename __P((DB_ENV *, const char *, const char *)); +int __os_isroot __P((void)); +char *__db_rpath __P((const char *)); +int __os_io __P((DB_ENV *, DB_IO *, int, size_t *)); +int __os_read __P((DB_ENV *, DB_FH *, void *, size_t, size_t *)); +int __os_write __P((DB_ENV *, DB_FH *, void *, size_t, size_t *)); +int __os_seek __P((DB_ENV *, + DB_FH *, size_t, db_pgno_t, u_int32_t, int, DB_OS_SEEK)); +int __os_sleep __P((DB_ENV *, u_long, u_long)); +int __os_spin __P((void)); +void __os_yield __P((DB_ENV*, u_long)); +int __os_exists __P((const char *, int *)); +int __os_ioinfo __P((DB_ENV *, const char *, + DB_FH *, u_int32_t *, u_int32_t *, u_int32_t *)); +int __os_tmpdir __P((DB_ENV *, u_int32_t)); +int __os_unlink __P((DB_ENV *, const char *)); +int __os_region_unlink __P((DB_ENV *, const char *)); +#if defined(DB_WIN32) +int __os_win32_errno __P((void)); +#endif +int __os_fpinit __P((DB_ENV *, DB_FH *, db_pgno_t, int, int)); +int __os_is_winnt __P((void)); +#if defined(__cplusplus) +} +#endif +#endif /* _os_ext_h_ */ diff --git a/db/include/os_jump.h b/db/include/os_jump.h new file mode 100644 index 000000000..681ba82d5 --- /dev/null +++ b/db/include/os_jump.h @@ -0,0 +1,34 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: os_jump.h,v 11.3 2000/02/14 02:59:55 bostic Exp $ + */ + +/* Calls which can be replaced by the application. */ +struct __db_jumptab { + int (*j_close) __P((int)); + void (*j_dirfree) __P((char **, int)); + int (*j_dirlist) __P((const char *, char ***, int *)); + int (*j_exists) __P((const char *, int *)); + void (*j_free) __P((void *)); + int (*j_fsync) __P((int)); + int (*j_ioinfo) __P((const char *, + int, u_int32_t *, u_int32_t *, u_int32_t *)); + void *(*j_malloc) __P((size_t)); + int (*j_map) __P((char *, size_t, int, int, void **)); + int (*j_open) __P((const char *, int, ...)); + ssize_t (*j_read) __P((int, void *, size_t)); + void *(*j_realloc) __P((void *, size_t)); + int (*j_rename) __P((const char *, const char *)); + int (*j_seek) __P((int, size_t, db_pgno_t, u_int32_t, int, int)); + int (*j_sleep) __P((u_long, u_long)); + int (*j_unlink) __P((const char *)); + int (*j_unmap) __P((void *, size_t)); + ssize_t (*j_write) __P((int, const void *, size_t)); + int (*j_yield) __P((void)); +}; + +extern struct __db_jumptab __db_jump; diff --git a/db/include/qam.h b/db/include/qam.h new file mode 100644 index 000000000..88cd68776 --- /dev/null +++ b/db/include/qam.h @@ -0,0 +1,150 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: qam.h,v 11.26 2001/01/11 18:19:52 bostic Exp $ + */ + +/* + * QAM data elements: a status field and the data. + */ +typedef struct _qamdata { + u_int8_t flags; /* 00: delete bit. */ +#define QAM_VALID 0x01 +#define QAM_SET 0x02 + u_int8_t data[1]; /* Record. */ +} QAMDATA; + +struct __queue; typedef struct __queue QUEUE; +struct __qcursor; typedef struct __qcursor QUEUE_CURSOR; + +struct __qcursor { + /* struct __dbc_internal */ + __DBC_INTERNAL + + /* Queue private part */ + + /* Per-thread information: queue private. */ + db_recno_t recno; /* Current record number. */ + + u_int32_t flags; +}; + +/* + * The in-memory, per-tree queue data structure. + */ + +typedef struct __mpfarray { + u_int32_t n_extent; /* Number of extents in table. */ + u_int32_t low_extent; /* First extent open. */ + u_int32_t hi_extent; /* Last extent open. */ + struct __qmpf { + int pinref; + DB_MPOOLFILE *mpf; + } *mpfarray; /* Array of open extents. */ +} MPFARRAY; + +struct __queue { + db_pgno_t q_meta; /* Database meta-data page. */ + db_pgno_t q_root; /* Database root page. */ + + int re_pad; /* Fixed-length padding byte. */ + u_int32_t re_len; /* Length for fixed-length records. */ + u_int32_t rec_page; /* records per page */ + u_int32_t page_ext; /* Pages per extent */ + MPFARRAY array1, array2; /* File arrays. */ + DB_MPOOL_FINFO finfo; /* Initialized info struct. */ + DB_PGINFO pginfo; /* Initialized pginfo struct. */ + DBT pgcookie; /* Initialized pgcookie. */ + char *path; /* Space allocated to file pathname. */ + char *name; /* The name of the file. */ + char *dir; /* The dir of the file. */ + int mode; /* Mode to open extents. */ +}; + +/* Format for queue extent names. */ +#define QUEUE_EXTENT "%s/__dbq.%s.%d" + +typedef struct __qam_filelist { + DB_MPOOLFILE *mpf; + u_int32_t id; +} QUEUE_FILELIST; + +/* + * Caculate the page number of a recno + * + * Number of records per page = + * Divide the available space on the page by the record len + header. + * + * Page number for record = + * divide the physical record number by the records per page + * add the root page number + * For now the root page will always be 1, but we might want to change + * in the future (e.g. multiple fixed len queues per file). + * + * Index of record on page = + * physical record number, less the logical pno times records/page + */ +#define CALC_QAM_RECNO_PER_PAGE(dbp) \ + (((dbp)->pgsize - sizeof(QPAGE)) / \ + ALIGN(((QUEUE *)(dbp)->q_internal)->re_len + \ + sizeof(QAMDATA) - SSZA(QAMDATA, data), sizeof(u_int32_t))) + +#define QAM_RECNO_PER_PAGE(dbp) (((QUEUE*)(dbp)->q_internal)->rec_page) + +#define QAM_RECNO_PAGE(dbp, recno) \ + (((QUEUE *)(dbp)->q_internal)->q_root \ + + (((recno) - 1) / QAM_RECNO_PER_PAGE(dbp))) + +#define QAM_RECNO_INDEX(dbp, pgno, recno) \ + (((recno) - 1) - (QAM_RECNO_PER_PAGE(dbp) \ + * (pgno - ((QUEUE *)(dbp)->q_internal)->q_root))) + +#define QAM_GET_RECORD(dbp, page, index) \ + ((QAMDATA *)((u_int8_t *)(page) + \ + sizeof(QPAGE) + (ALIGN(sizeof(QAMDATA) - SSZA(QAMDATA, data) + \ + ((QUEUE *)(dbp)->q_internal)->re_len, sizeof(u_int32_t)) * index))) + +#define QAM_AFTER_CURRENT(meta, recno) \ + ((recno) > (meta)->cur_recno && \ + ((meta)->first_recno <= (meta)->cur_recno || (recno) < (meta)->first_recno)) + +#define QAM_BEFORE_FIRST(meta, recno) \ + ((recno) < (meta)->first_recno && \ + ((meta->first_recno <= (meta)->cur_recno || (recno) > (meta)->cur_recno))) + +#define QAM_NOT_VALID(meta, recno) \ + (recno == RECNO_OOB || \ + QAM_BEFORE_FIRST(meta, recno) || QAM_AFTER_CURRENT(meta, recno)) + +/* + * Log opcodes for the mvptr routine. + */ +#define QAM_SETFIRST 0x01 +#define QAM_SETCUR 0x02 + +/* + * Parameter to __qam_position. + */ +typedef enum { + QAM_READ, + QAM_WRITE, + QAM_CONSUME +} qam_position_mode; + +typedef enum { + QAM_PROBE_GET, + QAM_PROBE_PUT, + QAM_PROBE_MPF +} qam_probe_mode; + +#define __qam_fget(dbp, pgnoaddr, flags, addrp) \ + __qam_fprobe(dbp, *pgnoaddr, addrp, QAM_PROBE_GET, flags) + +#define __qam_fput(dbp, pageno, addrp, flags) \ + __qam_fprobe(dbp, pageno, addrp, QAM_PROBE_PUT, flags) + +#include "qam_auto.h" +#include "qam_ext.h" diff --git a/db/include/qam_auto.h b/db/include/qam_auto.h new file mode 100644 index 000000000..8362b2118 --- /dev/null +++ b/db/include/qam_auto.h @@ -0,0 +1,129 @@ +/* Do not edit: automatically built by gen_rec.awk. */ + +#ifndef qam_AUTO_H +#define qam_AUTO_H + +#define DB_qam_inc 76 +typedef struct _qam_inc_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + DB_LSN lsn; +} __qam_inc_args; + +int __qam_inc_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, int32_t, DB_LSN *)); +int __qam_inc_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __qam_inc_read __P((DB_ENV *, void *, __qam_inc_args **)); + +#define DB_qam_incfirst 77 +typedef struct _qam_incfirst_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_recno_t recno; +} __qam_incfirst_args; + +int __qam_incfirst_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, int32_t, db_recno_t)); +int __qam_incfirst_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __qam_incfirst_read __P((DB_ENV *, void *, __qam_incfirst_args **)); + +#define DB_qam_mvptr 78 +typedef struct _qam_mvptr_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + u_int32_t opcode; + int32_t fileid; + db_recno_t old_first; + db_recno_t new_first; + db_recno_t old_cur; + db_recno_t new_cur; + DB_LSN metalsn; +} __qam_mvptr_args; + +int __qam_mvptr_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, u_int32_t, int32_t, db_recno_t, db_recno_t, db_recno_t, db_recno_t, DB_LSN *)); +int __qam_mvptr_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __qam_mvptr_read __P((DB_ENV *, void *, __qam_mvptr_args **)); + +#define DB_qam_del 79 +typedef struct _qam_del_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + DB_LSN lsn; + db_pgno_t pgno; + u_int32_t indx; + db_recno_t recno; +} __qam_del_args; + +int __qam_del_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, int32_t, DB_LSN *, db_pgno_t, u_int32_t, db_recno_t)); +int __qam_del_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __qam_del_read __P((DB_ENV *, void *, __qam_del_args **)); + +#define DB_qam_add 80 +typedef struct _qam_add_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + DB_LSN lsn; + db_pgno_t pgno; + u_int32_t indx; + db_recno_t recno; + DBT data; + u_int32_t vflag; + DBT olddata; +} __qam_add_args; + +int __qam_add_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, int32_t, DB_LSN *, db_pgno_t, u_int32_t, db_recno_t, const DBT *, u_int32_t, const DBT *)); +int __qam_add_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __qam_add_read __P((DB_ENV *, void *, __qam_add_args **)); + +#define DB_qam_delete 81 +typedef struct _qam_delete_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + DBT name; + DB_LSN lsn; +} __qam_delete_args; + +int __qam_delete_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, const DBT *, DB_LSN *)); +int __qam_delete_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __qam_delete_read __P((DB_ENV *, void *, __qam_delete_args **)); + +#define DB_qam_rename 82 +typedef struct _qam_rename_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + DBT name; + DBT newname; +} __qam_rename_args; + +int __qam_rename_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, const DBT *, const DBT *)); +int __qam_rename_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __qam_rename_read __P((DB_ENV *, void *, __qam_rename_args **)); + +#define DB_qam_delext 83 +typedef struct _qam_delext_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + DB_LSN lsn; + db_pgno_t pgno; + u_int32_t indx; + db_recno_t recno; + DBT data; +} __qam_delext_args; + +int __qam_delext_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, int32_t, DB_LSN *, db_pgno_t, u_int32_t, db_recno_t, const DBT *)); +int __qam_delext_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __qam_delext_read __P((DB_ENV *, void *, __qam_delext_args **)); +int __qam_init_print __P((DB_ENV *)); +int __qam_init_recover __P((DB_ENV *)); +#endif diff --git a/db/include/qam_ext.h b/db/include/qam_ext.h new file mode 100644 index 000000000..f6e95110c --- /dev/null +++ b/db/include/qam_ext.h @@ -0,0 +1,56 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _qam_ext_h_ +#define _qam_ext_h_ +#if defined(__cplusplus) +extern "C" { +#endif +int __qam_position + __P((DBC *, db_recno_t *, qam_position_mode, int *)); +int __qam_pitem + __P((DBC *, QPAGE *, u_int32_t, db_recno_t, DBT *)); +int __qam_put __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t)); +int __qam_delete __P((DB *, DB_TXN *, DBT *, u_int32_t)); +int __qam_c_dup __P((DBC *, DBC *)); +int __qam_c_init __P((DBC *)); +int __qam_mswap __P((PAGE *)); +int __qam_pgin_out __P((DB_ENV *, db_pgno_t, void *, DBT *)); +int __qam_fprobe __P((DB *, db_pgno_t, void *, qam_probe_mode, int)); +int __qam_fclose __P((DB *, db_pgno_t)); +int __qam_fremove __P((DB *, db_pgno_t)); +int __qam_sync __P((DB *, u_int32_t)); +int __qam_gen_filelist __P(( DB *, QUEUE_FILELIST **)); +int __qam_db_create __P((DB *)); +int __qam_db_close __P((DB *)); +int __db_prqueue __P((DB *, u_int32_t)); +int __qam_remove __P((DB *, const char *, + const char *, DB_LSN *, int (**)(DB *, void*), void **)); +int __qam_rename __P((DB *, + const char *, const char *, const char *)); +int __qam_open __P((DB *, const char *, db_pgno_t, int, u_int32_t)); +int __qam_metachk __P((DB *, const char *, QMETA *)); +int __qam_inc_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __qam_incfirst_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __qam_mvptr_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __qam_del_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __qam_delext_recover __P((DB_ENV *, + DBT *, DB_LSN *, db_recops, void *)); +int __qam_add_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __qam_delete_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __qam_rename_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __qam_stat __P((DB *, void *, void *(*)(size_t), u_int32_t)); +int __qam_31_qammeta __P((DB *, char *, u_int8_t *)); +int __qam_32_qammeta __P((DB *, char *, u_int8_t *)); +int __qam_vrfy_meta __P((DB *, VRFY_DBINFO *, QMETA *, + db_pgno_t, u_int32_t)); +int __qam_vrfy_data __P((DB *, VRFY_DBINFO *, QPAGE *, + db_pgno_t, u_int32_t)); +int __qam_vrfy_structure __P((DB *, VRFY_DBINFO *, u_int32_t)); +#if defined(__cplusplus) +} +#endif +#endif /* _qam_ext_h_ */ diff --git a/db/include/queue.h b/db/include/queue.h new file mode 100644 index 000000000..8d4a771ad --- /dev/null +++ b/db/include/queue.h @@ -0,0 +1,319 @@ +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + */ + +/* + * XXX + * We #undef the queue macros because there are incompatible versions of this + * file and these macros on various systems. What makes the problem worse is + * they are included and/or defined by system include files which we may have + * already loaded into Berkeley DB before getting here. For example, FreeBSD's + * includes its system , and VxWorks UnixLib.h defines + * several of the LIST_XXX macros. Make sure we use ours. + */ +#undef LIST_HEAD +#undef LIST_ENTRY +#undef LIST_FIRST +#undef LIST_NEXT +#undef LIST_INIT +#undef LIST_INSERT_AFTER +#undef LIST_INSERT_BEFORE +#undef LIST_INSERT_HEAD +#undef LIST_REMOVE +#undef TAILQ_HEAD +#undef TAILQ_ENTRY +#undef TAILQ_FIRST +#undef TAILQ_NEXT +#undef TAILQ_INIT +#undef TAILQ_INSERT_HEAD +#undef TAILQ_INSERT_TAIL +#undef TAILQ_INSERT_AFTER +#undef TAILQ_INSERT_BEFORE +#undef TAILQ_REMOVE +#undef CIRCLEQ_HEAD +#undef CIRCLEQ_ENTRY +#undef CIRCLEQ_FIRST +#undef CIRCLEQ_LAST +#undef CIRCLEQ_NEXT +#undef CIRCLEQ_PREV +#undef CIRCLEQ_INIT +#undef CIRCLEQ_INSERT_AFTER +#undef CIRCLEQ_INSERT_BEFORE +#undef CIRCLEQ_INSERT_HEAD +#undef CIRCLEQ_INSERT_TAIL +#undef CIRCLEQ_REMOVE + +/* + * This file defines three types of data structures: lists, tail queues, + * and circular queues. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may only be traversed in the forward direction. + * + * A circle queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the list. + * A circle queue may be traversed in either direction, but has a more + * complex end of list detection. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +#if defined(__cplusplus) +extern "C" { +#endif + +/* + * List definitions. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +#define LIST_FIRST(head) ((head)->lh_first) +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +/* + * List functions. + */ +#define LIST_INIT(head) { \ + (head)->lh_first = NULL; \ +} + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ + (listelm)->field.le_next->field.le_prev = \ + &(elm)->field.le_next; \ + (listelm)->field.le_next = (elm); \ + (elm)->field.le_prev = &(listelm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + (elm)->field.le_next = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &(elm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.le_next = (head)->lh_first) != NULL) \ + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ + (head)->lh_first = (elm); \ + (elm)->field.le_prev = &(head)->lh_first; \ +} while (0) + +#define LIST_REMOVE(elm, field) do { \ + if ((elm)->field.le_next != NULL) \ + (elm)->field.le_next->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = (elm)->field.le_next; \ +} while (0) + +/* + * Tail queue definitions. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ +} + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} + +#define TAILQ_FIRST(head) ((head)->tqh_first) +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +/* + * Tail queue functions. + */ +#define TAILQ_INIT(head) do { \ + (head)->tqh_first = NULL; \ + (head)->tqh_last = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ + (head)->tqh_first->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_first = (elm); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.tqe_next = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (listelm)->field.tqe_next = (elm); \ + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if (((elm)->field.tqe_next) != NULL) \ + (elm)->field.tqe_next->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ +} while (0) + +/* + * This macro is used to fixup the queue after moving the head. + */ +#define TAILQ_REINSERT_HEAD(head, elm, field) do { \ + DB_ASSERT((head)->tqh_first == (elm)); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ +} while (0) + +/* + * Circular queue definitions. + */ +#define CIRCLEQ_HEAD(name, type) \ +struct name { \ + struct type *cqh_first; /* first element */ \ + struct type *cqh_last; /* last element */ \ +} + +#define CIRCLEQ_ENTRY(type) \ +struct { \ + struct type *cqe_next; /* next element */ \ + struct type *cqe_prev; /* previous element */ \ +} + +#define CIRCLEQ_FIRST(head) ((head)->cqh_first) +#define CIRCLEQ_LAST(head) ((head)->cqh_last) +#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) +#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) + +/* + * Circular queue functions. + */ +#define CIRCLEQ_INIT(head) do { \ + (head)->cqh_first = (void *)(head); \ + (head)->cqh_last = (void *)(head); \ +} while (0) + +#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm)->field.cqe_next; \ + (elm)->field.cqe_prev = (listelm); \ + if ((listelm)->field.cqe_next == (void *)(head)) \ + (head)->cqh_last = (elm); \ + else \ + (listelm)->field.cqe_next->field.cqe_prev = (elm); \ + (listelm)->field.cqe_next = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm); \ + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ + if ((listelm)->field.cqe_prev == (void *)(head)) \ + (head)->cqh_first = (elm); \ + else \ + (listelm)->field.cqe_prev->field.cqe_next = (elm); \ + (listelm)->field.cqe_prev = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.cqe_next = (head)->cqh_first; \ + (elm)->field.cqe_prev = (void *)(head); \ + if ((head)->cqh_last == (void *)(head)) \ + (head)->cqh_last = (elm); \ + else \ + (head)->cqh_first->field.cqe_prev = (elm); \ + (head)->cqh_first = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.cqe_next = (void *)(head); \ + (elm)->field.cqe_prev = (head)->cqh_last; \ + if ((head)->cqh_first == (void *)(head)) \ + (head)->cqh_first = (elm); \ + else \ + (head)->cqh_last->field.cqe_next = (elm); \ + (head)->cqh_last = (elm); \ +} while (0) + +#define CIRCLEQ_REMOVE(head, elm, field) do { \ + if ((elm)->field.cqe_next == (void *)(head)) \ + (head)->cqh_last = (elm)->field.cqe_prev; \ + else \ + (elm)->field.cqe_next->field.cqe_prev = \ + (elm)->field.cqe_prev; \ + if ((elm)->field.cqe_prev == (void *)(head)) \ + (head)->cqh_first = (elm)->field.cqe_next; \ + else \ + (elm)->field.cqe_prev->field.cqe_next = \ + (elm)->field.cqe_next; \ +} while (0) + +#if defined(__cplusplus) +} +#endif diff --git a/db/include/region.h b/db/include/region.h new file mode 100644 index 000000000..c5882d09a --- /dev/null +++ b/db/include/region.h @@ -0,0 +1,292 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: region.h,v 11.13 2000/11/15 19:25:37 sue Exp $ + */ + +/* + * The DB environment consists of some number of "regions", which are described + * by the following four structures: + * + * REGENV -- shared information about the environment + * REGENV_REF -- file describing system memory version of REGENV + * REGION -- shared information about a single region + * REGINFO -- per-process information about a REGION + * + * There are three types of memory that hold regions: + * per-process heap (malloc) + * file mapped into memory (mmap, MapViewOfFile) + * system memory (shmget, CreateFileMapping) + * + * If the regions are private to a process, they're in malloc. If they're + * public, they're in file mapped memory, or, optionally, in system memory. + * Regions in the filesystem are named "__db.001", "__db.002" and so on. If + * we're not using a private environment allocated using malloc(3), the file + * "__db.001" will always exist, as we use it to synchronize on the regions, + * whether they exist in file mapped memory or system memory. + * + * The file "__db.001" contains a REGENV structure and a linked list of some + * number of REGION structures. Each of the REGION structures describes and + * locks one of the underlying shared regions used by DB. + * + * __db.001 + * +---------+ + * |REGENV | + * +---------+ +----------+ + * |REGION |-> | __db.002 | + * | | +----------+ + * +---------+ +----------+ + * |REGION |-> | __db.003 | + * | | +----------+ + * +---------+ +----------+ + * |REGION |-> | __db.004 | + * | | +----------+ + * +---------+ + * + * The only tricky part about manipulating the regions is correctly creating + * or joining the REGENV file, i.e., __db.001. We have to be absolutely sure + * that only one process creates it, and that everyone else joins it without + * seeing inconsistent data. Once that region is created, we can use normal + * shared locking procedures to do mutal exclusion for all other regions. + * + * One of the REGION structures in the main environment region describes the + * environment region itself. + * + * To lock a region, locate the REGION structure that describes it and acquire + * the region's mutex. There is one exception to this rule -- the lock for the + * environment region itself is in the REGENV structure, and not in the REGION + * that describes the environment region. That's so that we can acquire a lock + * without walking linked lists that could potentially change underneath us. + * The REGION will not be moved or removed during the life of the region, and + * so long-lived references to it can be held by the process. + * + * All requests to create or join a region return a REGINFO structure, which + * is held by the caller and used to open and subsequently close the reference + * to the region. The REGINFO structure contains the per-process information + * that we need to access the region. + * + * The one remaining complication. If the regions (including the environment + * region) live in system memory, and the system memory isn't "named" somehow + * in the filesystem name space, we need some way of finding it. Do this by + * by writing the REGENV_REF structure into the "__db.001" file. When we find + * a __db.001 file that is too small to be a real, on-disk environment, we use + * the information it contains to redirect to the real "__db.001" file/memory. + * This currently only happens when the REGENV file is in shared system memory. + * + * Although DB does not currently grow regions when they run out of memory, it + * would be possible to do so. To grow a region, allocate a new region of the + * appropriate size, then copy the old region over it and insert the additional + * space into the already existing shalloc arena. Callers may have to fix up + * local references, but that should be easy to do. This failed in historic + * versions of DB because the region lock lived in the mapped memory, and when + * it was unmapped and remapped (or copied), threads could lose track of it. + * Once we moved that lock into a region that is never unmapped, growing should + * work. That all said, current versions of DB don't implement region grow + * because some systems don't support mutex copying, e.g., from OSF1 V4.0: + * + * The address of an msemaphore structure may be significant. If the + * msemaphore structure contains any value copied from an msemaphore + * structure at a different address, the result is undefined. + */ + +#if defined(__cplusplus) +extern "C" { +#endif + +#define DB_REGION_FMT "__db.%03d" /* Region file name format. */ +#define DB_REGION_NAME_NUM 5 /* First digit offset in file names. */ +#define DB_REGION_NAME_LENGTH 8 /* Length of file names. */ + +#define DB_REGION_ENV "__db.001" /* Primary environment name. */ + +#define INVALID_REGION_ID 0 /* Out-of-band region ID. */ +#define REGION_ID_ENV 1 /* Primary environment ID. */ + +typedef enum { + INVALID_REGION_TYPE=0, /* Region type. */ + REGION_TYPE_ENV, + REGION_TYPE_LOCK, + REGION_TYPE_LOG, + REGION_TYPE_MPOOL, + REGION_TYPE_MUTEX, + REGION_TYPE_TXN } reg_type; + +#define INVALID_REGION_SEGID -1 /* Segment IDs are either shmget(2) or + * Win16 segment identifiers. They are + * both stored in a "long", and we need + * an out-of-band value. + */ +/* + * Nothing can live at region offset 0, because, in all cases, that's where + * we store *something*. Lots of code needs an out-of-band value for region + * offsets, so we use 0. + */ +#define INVALID_ROFF 0 + +/* Reference describing system memory version of REGENV. */ +typedef struct __db_reg_env_ref { + roff_t size; /* Region size. */ + long segid; /* UNIX shmget(2) ID. */ +} REGENV_REF; + +/* Per-environment region information. */ +typedef struct __db_reg_env { + /* + * !!! + * The mutex must be the first entry in the structure to guarantee + * correct alignment. + */ + MUTEX mutex; /* Environment mutex. */ + + /* + * !!! + * Note, the magic and panic fields are NOT protected by any mutex, + * and for this reason cannot be anything more complicated than a + * zero/non-zero value. + * + * !!! + * The valid region magic number must appear at the same byte offset + * in both the environment and each shared region, as Windows/95 uses + * it to determine if the memory has been zeroed since it was last used. + */ + u_int32_t magic; /* Valid region magic number. */ + + int panic; /* Environment is dead. */ + + int majver; /* Major DB version number. */ + int minver; /* Minor DB version number. */ + int patch; /* Patch DB version number. */ + + u_int32_t init_flags; /* Flags the env was initialized with.*/ + + /* List of regions. */ + SH_LIST_HEAD(__db_regionh) regionq; + + u_int32_t refcnt; /* References to the environment. */ + + size_t pad; /* Guarantee that following memory is + * size_t aligned. This is necessary + * because we're going to store the + * allocation region information there. + */ +} REGENV; + +/* Per-region shared region information. */ +typedef struct __db_region { + /* + * !!! + * The mutex must be the first entry in the structure to guarantee + * correct alignment. + */ + MUTEX mutex; /* Region mutex. */ + + /* + * !!! + * The valid region magic number must appear at the same byte offset + * in both the environment and each shared region, as Windows/95 uses + * it to determine if the memory has been zeroed since it was last used. + */ + u_int32_t magic; + + SH_LIST_ENTRY q; /* Linked list of REGIONs. */ + + reg_type type; /* Region type. */ + u_int32_t id; /* Region id. */ + + roff_t size; /* Region size in bytes. */ + + roff_t primary; /* Primary data structure offset. */ + + long segid; /* UNIX shmget(2), Win16 segment ID. */ +} REGION; + +/* + * Per-process/per-attachment information about a single region. + */ +struct __db_reginfo_t { /* __db_r_attach IN parameters. */ + reg_type type; /* Region type. */ + u_int32_t id; /* Region id. */ + int mode; /* File creation mode. */ + + /* __db_r_attach OUT parameters. */ + REGION *rp; /* Shared region. */ + + char *name; /* Region file name. */ + + void *addr; /* Region allocation address. */ + void *primary; /* Primary data structure address. */ + + void *wnt_handle; /* Win/NT HANDLE. */ + +#define REGION_CREATE 0x01 /* Caller created region. */ +#define REGION_CREATE_OK 0x02 /* Caller willing to create region. */ +#define REGION_JOIN_OK 0x04 /* Caller is looking for a match. */ + u_int32_t flags; +}; + +/* + * Mutex maintenance information each subsystem region must keep track + * of to manage resources adequately. + */ +typedef struct __db_regmaint_stat_t { + u_int32_t st_hint_hit; + u_int32_t st_hint_miss; + u_int32_t st_records; + u_int32_t st_clears; + u_int32_t st_destroys; + u_int32_t st_max_locks; +} REGMAINT_STAT; + +typedef struct __db_regmaint_t { + u_int32_t reglocks; /* Maximum # of mutexes we track. */ + u_int32_t regmutex_hint; /* Hint for next slot */ + REGMAINT_STAT stat; /* Stats */ + roff_t regmutexes[1]; /* Region mutexes in use. */ +} REGMAINT; + +/* + * R_ADDR Return a per-process address for a shared region offset. + * R_OFFSET Return a shared region offset for a per-process address. + * + * !!! + * R_OFFSET should really be returning a ptrdiff_t, but that's not yet + * portable. We use u_int32_t, which restricts regions to 4Gb in size. + */ +#define R_ADDR(base, offset) \ + ((void *)((u_int8_t *)((base)->addr) + offset)) +#define R_OFFSET(base, p) \ + ((u_int32_t)((u_int8_t *)(p) - (u_int8_t *)(base)->addr)) + +/* + * R_LOCK Lock/unlock a region. + * R_UNLOCK + */ +#define R_LOCK(dbenv, reginfo) \ + MUTEX_LOCK(dbenv, &(reginfo)->rp->mutex, (dbenv)->lockfhp) +#define R_UNLOCK(dbenv, reginfo) \ + MUTEX_UNLOCK(dbenv, &(reginfo)->rp->mutex) + +/* PANIC_CHECK: Check to see if the DB environment is dead. */ +#define PANIC_CHECK(dbenv) \ + if (DB_GLOBAL(db_panic) && \ + (dbenv)->reginfo != NULL && ((REGENV *) \ + ((REGINFO *)(dbenv)->reginfo)->primary)->panic != 0) \ + return (DB_RUNRECOVERY); + +/* + * All regions are created on 8K boundaries out of sheer paranoia, so that + * we don't make some underlying VM unhappy. + */ +#define OS_ROUNDOFF(i, s) { \ + (i) += (s) - 1; \ + (i) -= (i) % (s); \ +} +#define OS_VMPAGESIZE (8 * 1024) +#define OS_VMROUNDOFF(i) OS_ROUNDOFF(i, OS_VMPAGESIZE) + +#if defined(__cplusplus) +} +#endif diff --git a/db/include/rpc_client_ext.h b/db/include/rpc_client_ext.h new file mode 100644 index 000000000..a5c4689cd --- /dev/null +++ b/db/include/rpc_client_ext.h @@ -0,0 +1,19 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _rpc_client_ext_h_ +#define _rpc_client_ext_h_ +#if defined(__cplusplus) +extern "C" { +#endif +int __dbcl_envserver __P((DB_ENV *, char *, long, long, u_int32_t)); +int __dbcl_refresh __P((DB_ENV *)); +int __dbcl_txn_close __P((DB_ENV *)); +void __dbcl_txn_end __P((DB_TXN *)); +int __dbcl_c_destroy __P((DBC *)); +void __dbcl_c_refresh __P((DBC *)); +int __dbcl_c_setup __P((long, DB *, DBC **)); +int __dbcl_retcopy __P((DB_ENV *, DBT *, void *, u_int32_t)); +int __dbcl_dbclose_common __P((DB *)); +#if defined(__cplusplus) +} +#endif +#endif /* _rpc_client_ext_h_ */ diff --git a/db/include/rpc_server_ext.h b/db/include/rpc_server_ext.h new file mode 100644 index 000000000..4abb07681 --- /dev/null +++ b/db/include/rpc_server_ext.h @@ -0,0 +1,21 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _rpc_server_ext_h_ +#define _rpc_server_ext_h_ +#if defined(__cplusplus) +extern "C" { +#endif +void __db_stats_freelist __P((__db_stat_statsreplist **)); +void __dbsrv_settimeout __P((ct_entry *, u_int32_t)); +void __dbsrv_timeout __P((int)); +void __dbclear_ctp __P((ct_entry *)); +void __dbdel_ctp __P((ct_entry *)); +ct_entry *new_ct_ent __P((u_int32_t *)); +ct_entry *get_tableent __P((long)); +void __dbsrv_active __P((ct_entry *)); +int __dbc_close_int __P((ct_entry *)); +int __dbenv_close_int __P((long, int)); +char *get_home __P((char *)); +#if defined(__cplusplus) +} +#endif +#endif /* _rpc_server_ext_h_ */ diff --git a/db/include/shqueue.h b/db/include/shqueue.h new file mode 100644 index 000000000..115c5d39e --- /dev/null +++ b/db/include/shqueue.h @@ -0,0 +1,337 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: shqueue.h,v 11.6 2000/11/14 20:20:28 bostic Exp $ + */ +#ifndef _SYS_SHQUEUE_H_ +#define _SYS_SHQUEUE_H_ + +/* + * This file defines three types of data structures: lists, tail queues, and + * circular queues, similarly to the include file . + * + * The difference is that this set of macros can be used for structures that + * reside in shared memory that may be mapped at different addresses in each + * process. In most cases, the macros for shared structures exactly mirror + * the normal macros, although the macro calls require an additional type + * parameter, only used by the HEAD and ENTRY macros of the standard macros. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +#if defined(__cplusplus) +extern "C" { +#endif + +/* + * Shared list definitions. + */ +#define SH_LIST_HEAD(name) \ +struct name { \ + ssize_t slh_first; /* first element */ \ +} + +#define SH_LIST_ENTRY \ +struct { \ + ssize_t sle_next; /* relative offset next element */ \ + ssize_t sle_prev; /* relative offset of prev element */ \ +} + +/* + * Shared list functions. Since we use relative offsets for pointers, + * 0 is a valid offset. Therefore, we use -1 to indicate end of list. + * The macros ending in "P" return pointers without checking for end + * of list, the others check for end of list and evaluate to either a + * pointer or NULL. + */ + +#define SH_LIST_FIRSTP(head, type) \ + ((struct type *)(((u_int8_t *)(head)) + (head)->slh_first)) + +#define SH_LIST_FIRST(head, type) \ + ((head)->slh_first == -1 ? NULL : \ + ((struct type *)(((u_int8_t *)(head)) + (head)->slh_first))) + +#define SH_LIST_NEXTP(elm, field, type) \ + ((struct type *)(((u_int8_t *)(elm)) + (elm)->field.sle_next)) + +#define SH_LIST_NEXT(elm, field, type) \ + ((elm)->field.sle_next == -1 ? NULL : \ + ((struct type *)(((u_int8_t *)(elm)) + (elm)->field.sle_next))) + +#define SH_LIST_PREV(elm, field) \ + ((ssize_t *)(((u_int8_t *)(elm)) + (elm)->field.sle_prev)) + +#define SH_PTR_TO_OFF(src, dest) \ + ((ssize_t)(((u_int8_t *)(dest)) - ((u_int8_t *)(src)))) + +/* + * Take the element's next pointer and calculate what the corresponding + * Prev pointer should be -- basically it is the negation plus the offset + * of the next field in the structure. + */ +#define SH_LIST_NEXT_TO_PREV(elm, field) \ + (-(elm)->field.sle_next + SH_PTR_TO_OFF(elm, &(elm)->field.sle_next)) + +#define SH_LIST_INIT(head) (head)->slh_first = -1 + +#define SH_LIST_INSERT_AFTER(listelm, elm, field, type) do { \ + if ((listelm)->field.sle_next != -1) { \ + (elm)->field.sle_next = SH_PTR_TO_OFF(elm, \ + SH_LIST_NEXTP(listelm, field, type)); \ + SH_LIST_NEXTP(listelm, field, type)->field.sle_prev = \ + SH_LIST_NEXT_TO_PREV(elm, field); \ + } else \ + (elm)->field.sle_next = -1; \ + (listelm)->field.sle_next = SH_PTR_TO_OFF(listelm, elm); \ + (elm)->field.sle_prev = SH_LIST_NEXT_TO_PREV(listelm, field); \ +} while (0) + +#define SH_LIST_INSERT_HEAD(head, elm, field, type) do { \ + if ((head)->slh_first != -1) { \ + (elm)->field.sle_next = \ + (head)->slh_first - SH_PTR_TO_OFF(head, elm); \ + SH_LIST_FIRSTP(head, type)->field.sle_prev = \ + SH_LIST_NEXT_TO_PREV(elm, field); \ + } else \ + (elm)->field.sle_next = -1; \ + (head)->slh_first = SH_PTR_TO_OFF(head, elm); \ + (elm)->field.sle_prev = SH_PTR_TO_OFF(elm, &(head)->slh_first); \ +} while (0) + +#define SH_LIST_REMOVE(elm, field, type) do { \ + if ((elm)->field.sle_next != -1) { \ + SH_LIST_NEXTP(elm, field, type)->field.sle_prev = \ + (elm)->field.sle_prev - (elm)->field.sle_next; \ + *SH_LIST_PREV(elm, field) += (elm)->field.sle_next; \ + } else \ + *SH_LIST_PREV(elm, field) = -1; \ +} while (0) + +/* + * Shared tail queue definitions. + */ +#define SH_TAILQ_HEAD(name) \ +struct name { \ + ssize_t stqh_first; /* relative offset of first element */ \ + ssize_t stqh_last; /* relative offset of last's next */ \ +} + +#define SH_TAILQ_ENTRY \ +struct { \ + ssize_t stqe_next; /* relative offset of next element */ \ + ssize_t stqe_prev; /* relative offset of prev's next */ \ +} + +/* + * Shared tail queue functions. + */ +#define SH_TAILQ_FIRSTP(head, type) \ + ((struct type *)((u_int8_t *)(head) + (head)->stqh_first)) + +#define SH_TAILQ_FIRST(head, type) \ + ((head)->stqh_first == -1 ? NULL : SH_TAILQ_FIRSTP(head, type)) + +#define SH_TAILQ_NEXTP(elm, field, type) \ + ((struct type *)((u_int8_t *)(elm) + (elm)->field.stqe_next)) + +#define SH_TAILQ_NEXT(elm, field, type) \ + ((elm)->field.stqe_next == -1 ? NULL : SH_TAILQ_NEXTP(elm, field, type)) + +#define SH_TAILQ_PREVP(elm, field) \ + ((ssize_t *)((u_int8_t *)(elm) + (elm)->field.stqe_prev)) + +#define SH_TAILQ_LAST(head) \ + ((ssize_t *)(((u_int8_t *)(head)) + (head)->stqh_last)) + +#define SH_TAILQ_NEXT_TO_PREV(elm, field) \ + (-(elm)->field.stqe_next + SH_PTR_TO_OFF(elm, &(elm)->field.stqe_next)) + +#define SH_TAILQ_INIT(head) { \ + (head)->stqh_first = -1; \ + (head)->stqh_last = SH_PTR_TO_OFF(head, &(head)->stqh_first); \ +} + +#define SH_TAILQ_INSERT_HEAD(head, elm, field, type) do { \ + if ((head)->stqh_first != -1) { \ + (elm)->field.stqe_next = \ + (head)->stqh_first - SH_PTR_TO_OFF(head, elm); \ + SH_TAILQ_FIRSTP(head, type)->field.stqe_prev = \ + SH_TAILQ_NEXT_TO_PREV(elm, field); \ + } else { \ + (elm)->field.stqe_next = -1; \ + (head)->stqh_last = \ + SH_PTR_TO_OFF(head, &(elm)->field.stqe_next); \ + } \ + (head)->stqh_first = SH_PTR_TO_OFF(head, elm); \ + (elm)->field.stqe_prev = \ + SH_PTR_TO_OFF(elm, &(head)->stqh_first); \ +} while (0) + +#define SH_TAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.stqe_next = -1; \ + (elm)->field.stqe_prev = \ + -SH_PTR_TO_OFF(head, elm) + (head)->stqh_last; \ + if ((head)->stqh_last == \ + SH_PTR_TO_OFF((head), &(head)->stqh_first)) \ + (head)->stqh_first = SH_PTR_TO_OFF(head, elm); \ + else \ + *SH_TAILQ_LAST(head) = -(head)->stqh_last + \ + SH_PTR_TO_OFF((elm), &(elm)->field.stqe_next) + \ + SH_PTR_TO_OFF(head, elm); \ + (head)->stqh_last = \ + SH_PTR_TO_OFF(head, &((elm)->field.stqe_next)); \ +} while (0) + +#define SH_TAILQ_INSERT_AFTER(head, listelm, elm, field, type) do { \ + if ((listelm)->field.stqe_next != -1) { \ + (elm)->field.stqe_next = (listelm)->field.stqe_next - \ + SH_PTR_TO_OFF(listelm, elm); \ + SH_TAILQ_NEXTP(listelm, field, type)->field.stqe_prev = \ + SH_TAILQ_NEXT_TO_PREV(elm, field); \ + } else { \ + (elm)->field.stqe_next = -1; \ + (head)->stqh_last = \ + SH_PTR_TO_OFF(head, &elm->field.stqe_next); \ + } \ + (listelm)->field.stqe_next = SH_PTR_TO_OFF(listelm, elm); \ + (elm)->field.stqe_prev = SH_TAILQ_NEXT_TO_PREV(listelm, field); \ +} while (0) + +#define SH_TAILQ_REMOVE(head, elm, field, type) do { \ + if ((elm)->field.stqe_next != -1) { \ + SH_TAILQ_NEXTP(elm, field, type)->field.stqe_prev = \ + (elm)->field.stqe_prev + \ + SH_PTR_TO_OFF(SH_TAILQ_NEXTP(elm, \ + field, type), elm); \ + *SH_TAILQ_PREVP(elm, field) += elm->field.stqe_next; \ + } else { \ + (head)->stqh_last = (elm)->field.stqe_prev + \ + SH_PTR_TO_OFF(head, elm); \ + *SH_TAILQ_PREVP(elm, field) = -1; \ + } \ +} while (0) + +/* + * Shared circular queue definitions. + */ +#define SH_CIRCLEQ_HEAD(name) \ +struct name { \ + ssize_t scqh_first; /* first element */ \ + ssize_t scqh_last; /* last element */ \ +} + +#define SH_CIRCLEQ_ENTRY \ +struct { \ + ssize_t scqe_next; /* next element */ \ + ssize_t scqe_prev; /* previous element */ \ +} + +/* + * Shared circular queue functions. + */ +#define SH_CIRCLEQ_FIRSTP(head, type) \ + ((struct type *)(((u_int8_t *)(head)) + (head)->scqh_first)) + +#define SH_CIRCLEQ_FIRST(head, type) \ + ((head)->scqh_first == -1 ? \ + (void *)head : SH_CIRCLEQ_FIRSTP(head, type)) + +#define SH_CIRCLEQ_LASTP(head, type) \ + ((struct type *)(((u_int8_t *)(head)) + (head)->scqh_last)) + +#define SH_CIRCLEQ_LAST(head, type) \ + ((head)->scqh_last == -1 ? (void *)head : SH_CIRCLEQ_LASTP(head, type)) + +#define SH_CIRCLEQ_NEXTP(elm, field, type) \ + ((struct type *)(((u_int8_t *)(elm)) + (elm)->field.scqe_next)) + +#define SH_CIRCLEQ_NEXT(head, elm, field, type) \ + ((elm)->field.scqe_next == SH_PTR_TO_OFF(elm, head) ? \ + (void *)head : SH_CIRCLEQ_NEXTP(elm, field, type)) + +#define SH_CIRCLEQ_PREVP(elm, field, type) \ + ((struct type *)(((u_int8_t *)(elm)) + (elm)->field.scqe_prev)) + +#define SH_CIRCLEQ_PREV(head, elm, field, type) \ + ((elm)->field.scqe_prev == SH_PTR_TO_OFF(elm, head) ? \ + (void *)head : SH_CIRCLEQ_PREVP(elm, field, type)) + +#define SH_CIRCLEQ_INIT(head) { \ + (head)->scqh_first = 0; \ + (head)->scqh_last = 0; \ +} + +#define SH_CIRCLEQ_INSERT_AFTER(head, listelm, elm, field, type) do { \ + (elm)->field.scqe_prev = SH_PTR_TO_OFF(elm, listelm); \ + (elm)->field.scqe_next = (listelm)->field.scqe_next + \ + (elm)->field.scqe_prev; \ + if (SH_CIRCLEQ_NEXTP(listelm, field, type) == (void *)head) \ + (head)->scqh_last = SH_PTR_TO_OFF(head, elm); \ + else \ + SH_CIRCLEQ_NEXTP(listelm, \ + field, type)->field.scqe_prev = \ + SH_PTR_TO_OFF(SH_CIRCLEQ_NEXTP(listelm, \ + field, type), elm); \ + (listelm)->field.scqe_next = -(elm)->field.scqe_prev; \ +} while (0) + +#define SH_CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field, type) do { \ + (elm)->field.scqe_next = SH_PTR_TO_OFF(elm, listelm); \ + (elm)->field.scqe_prev = (elm)->field.scqe_next - \ + SH_CIRCLEQ_PREVP(listelm, field, type)->field.scqe_next;\ + if (SH_CIRCLEQ_PREVP(listelm, field, type) == (void *)(head)) \ + (head)->scqh_first = SH_PTR_TO_OFF(head, elm); \ + else \ + SH_CIRCLEQ_PREVP(listelm, \ + field, type)->field.scqe_next = \ + SH_PTR_TO_OFF(SH_CIRCLEQ_PREVP(listelm, \ + field, type), elm); \ + (listelm)->field.scqe_prev = -(elm)->field.scqe_next; \ +} while (0) + +#define SH_CIRCLEQ_INSERT_HEAD(head, elm, field, type) do { \ + (elm)->field.scqe_prev = SH_PTR_TO_OFF(elm, head); \ + (elm)->field.scqe_next = (head)->scqh_first + \ + (elm)->field.scqe_prev; \ + if ((head)->scqh_last == 0) \ + (head)->scqh_last = -(elm)->field.scqe_prev; \ + else \ + SH_CIRCLEQ_FIRSTP(head, type)->field.scqe_prev = \ + SH_PTR_TO_OFF(SH_CIRCLEQ_FIRSTP(head, type), elm); \ + (head)->scqh_first = -(elm)->field.scqe_prev; \ +} while (0) + +#define SH_CIRCLEQ_INSERT_TAIL(head, elm, field, type) do { \ + (elm)->field.scqe_next = SH_PTR_TO_OFF(elm, head); \ + (elm)->field.scqe_prev = (head)->scqh_last + \ + (elm)->field.scqe_next; \ + if ((head)->scqh_first == 0) \ + (head)->scqh_first = -(elm)->field.scqe_next; \ + else \ + SH_CIRCLEQ_LASTP(head, type)->field.scqe_next = \ + SH_PTR_TO_OFF(SH_CIRCLEQ_LASTP(head, type), elm); \ + (head)->scqh_last = -(elm)->field.scqe_next; \ +} while (0) + +#define SH_CIRCLEQ_REMOVE(head, elm, field, type) do { \ + if (SH_CIRCLEQ_NEXTP(elm, field, type) == (void *)(head)) \ + (head)->scqh_last += (elm)->field.scqe_prev; \ + else \ + SH_CIRCLEQ_NEXTP(elm, field, type)->field.scqe_prev += \ + (elm)->field.scqe_prev; \ + if (SH_CIRCLEQ_PREVP(elm, field, type) == (void *)(head)) \ + (head)->scqh_first += (elm)->field.scqe_next; \ + else \ + SH_CIRCLEQ_PREVP(elm, field, type)->field.scqe_next += \ + (elm)->field.scqe_next; \ +} while (0) + +#if defined(__cplusplus) +} +#endif + +#endif /* !_SYS_SHQUEUE_H_ */ diff --git a/db/include/tcl_db.h b/db/include/tcl_db.h new file mode 100644 index 000000000..254006c2f --- /dev/null +++ b/db/include/tcl_db.h @@ -0,0 +1,219 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: tcl_db.h,v 11.9 2000/12/12 17:43:56 bostic Exp $ + */ + +#define MSG_SIZE 100 /* Message size */ + +enum INFOTYPE { + I_ENV, I_DB, I_DBC, I_TXN, I_MP, I_PG, I_LOCK, I_NDBM, I_MUTEX }; + +#define MAX_ID 8 /* Maximum number of sub-id's we need */ + +#define DBTCL_DBM 1 +#define DBTCL_NDBM 2 + +typedef struct _mutex_entry { + union { + struct { + MUTEX real_m; + u_int32_t real_val; + } r; + /* + * This is here to make sure that each of the mutex structures + * are 16-byte aligned, which is required on HP architectures. + * The db_mutex_t structure might be >32 bytes itself, or the + * real_val might push it over the 32 byte boundary. The best + * we can do is use a 48 byte boundary. + */ + char c[48]; + } u; +} _MUTEX_ENTRY; + +#define m u.r.real_m +#define val u.r.real_val + +typedef struct _mutex_data { + DB_ENV *env; + REGINFO reginfo; + _MUTEX_ENTRY *marray; + size_t size; + u_int32_t n_mutex; +} _MUTEX_DATA; + +/* + * Why use a home grown package over the Tcl_Hash functions? + * + * We could have implemented the stuff below without maintaining our + * own list manipulation, efficiently hashing it with the available + * Tcl functions (Tcl_CreateHashEntry, Tcl_GetHashValue, etc). I chose + * not to do so for these reasons: + * + * We still need the information below. Using the hashing only removes + * us from needing the next/prev pointers. We still need the structure + * itself because we need more than one value associated with a widget. + * We need to keep track of parent pointers for sub-widgets (like cursors) + * so we can correctly close. We need to keep track of individual widget's + * id counters for any sub-widgets they may have. We need to be able to + * associate the name/client data outside the scope of the widget. + * + * So, is it better to use the hashing rather than + * the linear list we have now? I decided against it for the simple reason + * that to access the structure would require two calls. The first is + * Tcl_FindHashEntry(table, key) and then, once we have the entry, we'd + * have to do Tcl_GetHashValue(entry) to get the pointer of the structure. + * + * I believe the number of simultaneous DB widgets in existence at one time + * is not going to be that large (more than several dozen) such that + * linearly searching the list is not going to impact performance in a + * noticable way. Should performance be impacted due to the size of the + * info list, then perhaps it is time to revisit this decision. + */ +typedef struct dbtcl_info { + LIST_ENTRY(dbtcl_info) entries; + Tcl_Interp *i_interp; + char *i_name; + enum INFOTYPE i_type; + union infop { + DB_ENV *envp; + void *anyp; + DB *dbp; + DBC *dbcp; + DB_TXN *txnp; + DB_MPOOLFILE *mp; + DB_LOCK *lock; + _MUTEX_DATA *mutex; +#if 0 + DBM *ndbmp; /* Compatibility */ +#endif + } un; + union data { + int anydata; + db_pgno_t pgno; + u_int32_t lockid; + } und; + union data2 { + int anydata; + size_t pagesz; + } und2; + DBT i_lockobj; + FILE *i_err; + char *i_errpfx; + struct dbtcl_info *i_parent; + int i_otherid[MAX_ID]; +} DBTCL_INFO; + +extern int __debug_on, __debug_print, __debug_stop, __debug_test; +LIST_HEAD(infohead, dbtcl_info) __db_infohead; + +#define i_anyp un.anyp +#define i_pagep un.anyp +#define i_envp un.envp +#define i_dbp un.dbp +#define i_dbcp un.dbcp +#define i_txnp un.txnp +#define i_mp un.mp +#define i_lock un.lock +#define i_mutex un.mutex +#if 0 +#define i_ndbm un.ndbmp +#endif + +#define i_data und.anydata +#define i_pgno und.pgno +#define i_locker und.lockid +#define i_data2 und2.anydata +#define i_pgsz und2.pagesz + +#define i_envtxnid i_otherid[0] +#define i_envmpid i_otherid[1] +#define i_envlockid i_otherid[2] +#define i_envmutexid i_otherid[3] + +#define i_mppgid i_otherid[0] + +#define i_dbdbcid i_otherid[0] + +#define NAME_TO_ENV(name) (DB_ENV *)_NameToPtr((name)) +#define NAME_TO_DB(name) (DB *)_NameToPtr((name)) +#define NAME_TO_DBC(name) (DBC *)_NameToPtr((name)) +#define NAME_TO_TXN(name) (DB_TXN *)_NameToPtr((name)) +#define NAME_TO_MP(name) (DB_MPOOLFILE *)_NameToPtr((name)) +#define NAME_TO_LOCK(name) (DB_LOCK *)_NameToPtr((name)) + +/* + * MAKE_STAT_LIST appends a {name value} pair to a result list + * that MUST be called 'res' that is a Tcl_Obj * in the local + * function. This macro also assumes a label "error" to go to + * in the even of a Tcl error. For stat functions this will + * typically go before the "free" function to free the stat structure + * returned by DB. + */ +#define MAKE_STAT_LIST(s,v) \ +do { \ + result = _SetListElemInt(interp, res, (s), (v)); \ + if (result != TCL_OK) \ + goto error; \ +} while (0) + +/* + * MAKE_STAT_STRLIST appends a {name string} pair to a result list + * that MUST be called 'res' that is a Tcl_Obj * in the local + * function. This macro also assumes a label "error" to go to + * in the even of a Tcl error. For stat functions this will + * typically go before the "free" function to free the stat structure + * returned by DB. + */ +#define MAKE_STAT_STRLIST(s,s1) \ +do { \ + result = _SetListElem(interp, res, (s), strlen(s), \ + (s1), strlen(s1)); \ + if (result != TCL_OK) \ + goto error; \ +} while (0) + +/* + * FLAG_CHECK checks that the given flag is not set yet. + * If it is, it sets up an error message. + */ +#define FLAG_CHECK(flag) \ +do { \ + if ((flag) != 0) { \ + Tcl_SetResult(interp, \ + " Only 1 policy can be specified.\n", \ + TCL_STATIC); \ + result = TCL_ERROR; \ + break; \ + } \ +} while (0) + +/* + * FLAG_CHECK2 checks that the given flag is not set yet or is + * only set to the given allowed value. + * If it is, it sets up an error message. + */ +#define FLAG_CHECK2(flag,val) \ +do { \ + if ((flag) != 0 && (flag) != (val)) { \ + Tcl_SetResult(interp, \ + " Only 1 policy can be specified.\n", \ + TCL_STATIC); \ + result = TCL_ERROR; \ + break; \ + } \ +} while (0) + +/* + * IS_HELP checks whether the arg we bombed on is -?, which is a help option. + * If it is, we return TCL_OK (but leave the result set to whatever + * Tcl_GetIndexFromObj says, which lists all the valid options. Otherwise + * return TCL_ERROR. + */ +#define IS_HELP(s) \ + (strcmp(Tcl_GetStringFromObj(s,NULL), "-?") == 0) ? TCL_OK : TCL_ERROR + +#include "tcl_ext.h" diff --git a/db/include/tcl_ext.h b/db/include/tcl_ext.h new file mode 100644 index 000000000..9baf7e4fd --- /dev/null +++ b/db/include/tcl_ext.h @@ -0,0 +1,89 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _tcl_ext_h_ +#define _tcl_ext_h_ +#if defined(__cplusplus) +extern "C" { +#endif +int bdb_HCommand __P((Tcl_Interp *, int, Tcl_Obj * CONST*)); +#if DB_DBM_HSEARCH != 0 +int bdb_NdbmOpen __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DBM **)); +#endif +#if DB_DBM_HSEARCH != 0 +int bdb_DbmCommand + __P((Tcl_Interp *, int, Tcl_Obj * CONST*, int, DBM *)); +#endif +int ndbm_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*)); +int bdb_RandCommand __P((Tcl_Interp *, int, Tcl_Obj * CONST*)); +int tcl_Mutex __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *, + DBTCL_INFO *)); +int db_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*)); +int dbc_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*)); +int env_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*)); +int tcl_EnvRemove __P((Tcl_Interp *, int, Tcl_Obj * CONST*, + DB_ENV *, DBTCL_INFO *)); +int tcl_EnvVerbose __P((Tcl_Interp *, DB_ENV *, Tcl_Obj *, + Tcl_Obj *)); +int tcl_EnvTest __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *)); +DBTCL_INFO *_NewInfo __P((Tcl_Interp *, + void *, char *, enum INFOTYPE)); +void *_NameToPtr __P((CONST char *)); +char *_PtrToName __P((CONST void *)); +DBTCL_INFO *_PtrToInfo __P((CONST void *)); +DBTCL_INFO *_NameToInfo __P((CONST char *)); +void _SetInfoData __P((DBTCL_INFO *, void *)); +void _DeleteInfo __P((DBTCL_INFO *)); +int _SetListElem __P((Tcl_Interp *, + Tcl_Obj *, void *, int, void *, int)); +int _SetListElemInt __P((Tcl_Interp *, Tcl_Obj *, void *, int)); +int _SetListRecnoElem __P((Tcl_Interp *, Tcl_Obj *, + db_recno_t, u_char *, int)); +int _GetGlobPrefix __P((char *, char **)); +int _ReturnSetup __P((Tcl_Interp *, int, char *)); +int _ErrorSetup __P((Tcl_Interp *, int, char *)); +void _ErrorFunc __P((CONST char *, char *)); +int _GetLsn __P((Tcl_Interp *, Tcl_Obj *, DB_LSN *)); +void _debug_check __P((void)); +int tcl_LockDetect __P((Tcl_Interp *, int, + Tcl_Obj * CONST*, DB_ENV *)); +int tcl_LockGet __P((Tcl_Interp *, int, + Tcl_Obj * CONST*, DB_ENV *)); +int tcl_LockStat __P((Tcl_Interp *, int, + Tcl_Obj * CONST*, DB_ENV *)); +int tcl_LockVec __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *)); +int tcl_LogArchive __P((Tcl_Interp *, int, + Tcl_Obj * CONST*, DB_ENV *)); +int tcl_LogCompare __P((Tcl_Interp *, int, + Tcl_Obj * CONST*)); +int tcl_LogFile __P((Tcl_Interp *, int, + Tcl_Obj * CONST*, DB_ENV *)); +int tcl_LogFlush __P((Tcl_Interp *, int, + Tcl_Obj * CONST*, DB_ENV *)); +int tcl_LogGet __P((Tcl_Interp *, int, + Tcl_Obj * CONST*, DB_ENV *)); +int tcl_LogPut __P((Tcl_Interp *, int, + Tcl_Obj * CONST*, DB_ENV *)); +int tcl_LogRegister __P((Tcl_Interp *, int, + Tcl_Obj * CONST*, DB_ENV *)); +int tcl_LogStat __P((Tcl_Interp *, int, + Tcl_Obj * CONST*, DB_ENV *)); +int tcl_LogUnregister __P((Tcl_Interp *, int, + Tcl_Obj * CONST*, DB_ENV *)); +void _MpInfoDelete __P((Tcl_Interp *, DBTCL_INFO *)); +int tcl_MpSync __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *)); +int tcl_MpTrickle __P((Tcl_Interp *, int, + Tcl_Obj * CONST*, DB_ENV *)); +int tcl_Mp __P((Tcl_Interp *, int, + Tcl_Obj * CONST*, DB_ENV *, DBTCL_INFO *)); +int tcl_MpStat __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *)); +void _TxnInfoDelete __P((Tcl_Interp *, DBTCL_INFO *)); +int tcl_TxnCheckpoint __P((Tcl_Interp *, int, + Tcl_Obj * CONST*, DB_ENV *)); +int tcl_Txn __P((Tcl_Interp *, int, + Tcl_Obj * CONST*, DB_ENV *, DBTCL_INFO *)); +int tcl_TxnStat __P((Tcl_Interp *, int, + Tcl_Obj * CONST*, DB_ENV *)); +int txn_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*)); +#if defined(__cplusplus) +} +#endif +#endif /* _tcl_ext_h_ */ diff --git a/db/include/txn.h b/db/include/txn.h new file mode 100644 index 000000000..009a1ca15 --- /dev/null +++ b/db/include/txn.h @@ -0,0 +1,150 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: txn.h,v 11.12 2001/01/02 17:23:39 margo Exp $ + */ + +#ifndef _TXN_H_ +#define _TXN_H_ + +#include "xa.h" + +struct __db_txnmgr; typedef struct __db_txnmgr DB_TXNMGR; +struct __db_txnregion; typedef struct __db_txnregion DB_TXNREGION; + +/* + * !!! + * TXN_MINIMUM = (DB_LOCK_MAXID + 1) but this makes compilers complain. + */ +#define TXN_MINIMUM 0x80000000 +#define TXN_INVALID 0xffffffff /* Maximum number of txn ids. */ +#define TXN_INVALID_ID 0 /* Invalid transaction ID. */ + +#define DEF_MAX_TXNS 20 /* Default max transactions. */ + +/* The structure allocated for every transaction. */ +struct __db_txn { + DB_TXNMGR *mgrp; /* Pointer to transaction manager. */ + DB_TXN *parent; /* Pointer to transaction's parent. */ + DB_LSN last_lsn; /* Lsn of last log write. */ + u_int32_t txnid; /* Unique transaction id. */ + roff_t off; /* Detail structure within region. */ + TAILQ_ENTRY(__db_txn) links; /* Links transactions off manager. */ + TAILQ_HEAD(__kids, __db_txn) kids; /* Child transactions. */ + TAILQ_ENTRY(__db_txn) klinks; /* Links child transactions. */ + u_int32_t cursors; /* Number of cursors open for txn */ + +#define TXN_CHILDCOMMIT 0x01 /* Transaction that has committed. */ +#define TXN_MALLOC 0x02 /* Structure allocated by TXN system. */ +#define TXN_NOSYNC 0x04 /* Do not sync on prepare and commit. */ +#define TXN_NOWAIT 0x08 /* Do not wait on locks. */ +#define TXN_SYNC 0x10 /* Sync on prepare and commit. */ + u_int32_t flags; +}; + +/* + * Internal data maintained in shared memory for each transaction. + */ +typedef char DB_XID[XIDDATASIZE]; + +typedef struct __txn_detail { + u_int32_t txnid; /* current transaction id + used to link free list also */ + DB_LSN last_lsn; /* last lsn written for this txn */ + DB_LSN begin_lsn; /* lsn of begin record */ + roff_t parent; /* Offset of transaction's parent. */ + +#define TXN_RUNNING 1 +#define TXN_ABORTED 2 +#define TXN_PREPARED 3 +#define TXN_COMMITTED 4 + u_int32_t status; /* status of the transaction */ + + SH_TAILQ_ENTRY links; /* free/active list */ + +#define TXN_XA_ABORTED 1 +#define TXN_XA_DEADLOCKED 2 +#define TXN_XA_ENDED 3 +#define TXN_XA_PREPARED 4 +#define TXN_XA_STARTED 5 +#define TXN_XA_SUSPENDED 6 + u_int32_t xa_status; /* XA status */ + + /* + * XID (xid_t) structure: because these fields are logged, the + * sizes have to be explicit. + */ + DB_XID xid; /* XA global transaction id */ + u_int32_t bqual; /* bqual_length from XID */ + u_int32_t gtrid; /* gtrid_length from XID */ + int32_t format; /* XA format */ +} TXN_DETAIL; + +/* + * DB_TXNMGR -- + * The transaction manager encapsulates the transaction system. + */ +struct __db_txnmgr { +/* + * These fields need to be protected for multi-threaded support. + * + * !!! + * As this structure is allocated in per-process memory, the mutex may need + * to be stored elsewhere on architectures unable to support mutexes in heap + * memory, e.g., HP/UX 9. + */ + MUTEX *mutexp; /* Lock list of active transactions + * (including the content of each + * TXN_DETAIL structure on the list). + */ + /* List of active transactions. */ + TAILQ_HEAD(_chain, __db_txn) txn_chain; + +/* These fields are never updated after creation, and so not protected. */ + DB_ENV *dbenv; /* Environment. */ + REGINFO reginfo; /* Region information. */ +}; + +/* + * DB_TXNREGION -- + * The primary transaction data structure in the shared memory region. + */ +struct __db_txnregion { + u_int32_t maxtxns; /* maximum number of active TXNs */ + u_int32_t last_txnid; /* last transaction id given out */ + DB_LSN pending_ckp; /* last checkpoint did not finish */ + DB_LSN last_ckp; /* lsn of the last checkpoint */ + time_t time_ckp; /* time of last checkpoint */ + u_int32_t logtype; /* type of logging */ + u_int32_t locktype; /* lock type */ + u_int32_t naborts; /* number of aborted TXNs */ + u_int32_t ncommits; /* number of committed TXNs */ + u_int32_t nbegins; /* number of begun TXNs */ + u_int32_t nactive; /* number of active TXNs */ + u_int32_t maxnactive; /* maximum number of active TXNs */ + /* active TXN list */ + SH_TAILQ_HEAD(__active) active_txn; +}; + +/* + * Make the region large enough to hold N transaction detail structures + * plus some space to hold thread handles and the beginning of the shalloc + * region. + */ +#define TXN_REGION_SIZE(N) \ + (sizeof(DB_TXNREGION) + N * sizeof(TXN_DETAIL) + 1000) + +/* + * Log record types. + */ +#define TXN_COMMIT 1 +#define TXN_PREPARE 2 + +#include "txn_auto.h" +#include "txn_ext.h" + +#include "xa_ext.h" +#endif /* !_TXN_H_ */ diff --git a/db/include/txn_auto.h b/db/include/txn_auto.h new file mode 100644 index 000000000..c9cb5cfae --- /dev/null +++ b/db/include/txn_auto.h @@ -0,0 +1,114 @@ +/* Do not edit: automatically built by gen_rec.awk. */ + +#ifndef txn_AUTO_H +#define txn_AUTO_H + +#define DB_txn_old_regop 6 +typedef struct _txn_old_regop_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + u_int32_t opcode; +} __txn_old_regop_args; + +int __txn_old_regop_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __txn_old_regop_read __P((DB_ENV *, void *, __txn_old_regop_args **)); + +#define DB_txn_regop 10 +typedef struct _txn_regop_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + u_int32_t opcode; + int32_t timestamp; +} __txn_regop_args; + +int __txn_regop_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, u_int32_t, int32_t)); +int __txn_regop_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __txn_regop_read __P((DB_ENV *, void *, __txn_regop_args **)); + +#define DB_txn_old_ckp 7 +typedef struct _txn_old_ckp_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + DB_LSN ckp_lsn; + DB_LSN last_ckp; +} __txn_old_ckp_args; + +int __txn_old_ckp_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __txn_old_ckp_read __P((DB_ENV *, void *, __txn_old_ckp_args **)); + +#define DB_txn_ckp 11 +typedef struct _txn_ckp_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + DB_LSN ckp_lsn; + DB_LSN last_ckp; + int32_t timestamp; +} __txn_ckp_args; + +int __txn_ckp_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, DB_LSN *, DB_LSN *, int32_t)); +int __txn_ckp_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __txn_ckp_read __P((DB_ENV *, void *, __txn_ckp_args **)); + +#define DB_txn_xa_regop_old 8 +typedef struct _txn_xa_regop_old_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + u_int32_t opcode; + DBT xid; + int32_t formatID; + u_int32_t gtrid; + u_int32_t bqual; +} __txn_xa_regop_old_args; + +int __txn_xa_regop_old_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __txn_xa_regop_old_read __P((DB_ENV *, void *, __txn_xa_regop_old_args **)); + +#define DB_txn_xa_regop 13 +typedef struct _txn_xa_regop_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + u_int32_t opcode; + DBT xid; + int32_t formatID; + u_int32_t gtrid; + u_int32_t bqual; + DB_LSN begin_lsn; +} __txn_xa_regop_args; + +int __txn_xa_regop_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, u_int32_t, const DBT *, int32_t, u_int32_t, u_int32_t, DB_LSN *)); +int __txn_xa_regop_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __txn_xa_regop_read __P((DB_ENV *, void *, __txn_xa_regop_args **)); + +#define DB_txn_child_old 9 +typedef struct _txn_child_old_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + u_int32_t opcode; + u_int32_t parent; +} __txn_child_old_args; + +int __txn_child_old_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __txn_child_old_read __P((DB_ENV *, void *, __txn_child_old_args **)); + +#define DB_txn_child 12 +typedef struct _txn_child_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + u_int32_t child; + DB_LSN c_lsn; +} __txn_child_args; + +int __txn_child_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, u_int32_t, DB_LSN *)); +int __txn_child_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __txn_child_read __P((DB_ENV *, void *, __txn_child_args **)); +int __txn_init_print __P((DB_ENV *)); +int __txn_init_recover __P((DB_ENV *)); +#endif diff --git a/db/include/txn_ext.h b/db/include/txn_ext.h new file mode 100644 index 000000000..ee6922d70 --- /dev/null +++ b/db/include/txn_ext.h @@ -0,0 +1,24 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _txn_ext_h_ +#define _txn_ext_h_ +#if defined(__cplusplus) +extern "C" { +#endif +int __txn_xa_begin __P((DB_ENV *, DB_TXN *)); +int __txn_end __P((DB_TXN *, int)); +int __txn_activekids __P((DB_ENV *, u_int32_t, DB_TXN *)); +int __txn_regop_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __txn_xa_regop_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __txn_ckp_recover +__P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __txn_child_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +void __txn_dbenv_create __P((DB_ENV *)); +int __txn_open __P((DB_ENV *)); +int __txn_close __P((DB_ENV *)); +#if defined(__cplusplus) +} +#endif +#endif /* _txn_ext_h_ */ diff --git a/db/include/xa.h b/db/include/xa.h new file mode 100644 index 000000000..ce4617926 --- /dev/null +++ b/db/include/xa.h @@ -0,0 +1,179 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: xa.h,v 11.3 2000/02/14 02:59:55 bostic Exp $ + */ +/* + * Start of xa.h header + * + * Define a symbol to prevent multiple inclusions of this header file + */ +#ifndef XA_H +#define XA_H + +/* + * Transaction branch identification: XID and NULLXID: + */ +#define XIDDATASIZE 128 /* size in bytes */ +#define MAXGTRIDSIZE 64 /* maximum size in bytes of gtrid */ +#define MAXBQUALSIZE 64 /* maximum size in bytes of bqual */ + +struct xid_t { + long formatID; /* format identifier */ + long gtrid_length; /* value from 1 through 64 */ + long bqual_length; /* value from 1 through 64 */ + char data[XIDDATASIZE]; +}; +typedef struct xid_t XID; +/* + * A value of -1 in formatID means that the XID is null. + */ + +/* + * Declarations of routines by which RMs call TMs: + */ +extern int ax_reg __P((int, XID *, long)); +extern int ax_unreg __P((int, long)); + +/* + * XA Switch Data Structure + */ +#define RMNAMESZ 32 /* length of resource manager name, */ + /* including the null terminator */ +#define MAXINFOSIZE 256 /* maximum size in bytes of xa_info */ + /* strings, including the null + terminator */ +struct xa_switch_t { + char name[RMNAMESZ]; /* name of resource manager */ + long flags; /* resource manager specific options */ + long version; /* must be 0 */ + int (*xa_open_entry) /* xa_open function pointer */ + __P((char *, int, long)); + int (*xa_close_entry) /* xa_close function pointer */ + __P((char *, int, long)); + int (*xa_start_entry) /* xa_start function pointer */ + __P((XID *, int, long)); + int (*xa_end_entry) /* xa_end function pointer */ + __P((XID *, int, long)); + int (*xa_rollback_entry) /* xa_rollback function pointer */ + __P((XID *, int, long)); + int (*xa_prepare_entry) /* xa_prepare function pointer */ + __P((XID *, int, long)); + int (*xa_commit_entry) /* xa_commit function pointer */ + __P((XID *, int, long)); + int (*xa_recover_entry) /* xa_recover function pointer */ + __P((XID *, long, int, long)); + int (*xa_forget_entry) /* xa_forget function pointer */ + __P((XID *, int, long)); + int (*xa_complete_entry) /* xa_complete function pointer */ + __P((int *, int *, int, long)); +}; + +/* + * Flag definitions for the RM switch + */ +#define TMNOFLAGS 0x00000000L /* no resource manager features + selected */ +#define TMREGISTER 0x00000001L /* resource manager dynamically + registers */ +#define TMNOMIGRATE 0x00000002L /* resource manager does not support + association migration */ +#define TMUSEASYNC 0x00000004L /* resource manager supports + asynchronous operations */ +/* + * Flag definitions for xa_ and ax_ routines + */ +/* use TMNOFLAGGS, defined above, when not specifying other flags */ +#define TMASYNC 0x80000000L /* perform routine asynchronously */ +#define TMONEPHASE 0x40000000L /* caller is using one-phase commit + optimisation */ +#define TMFAIL 0x20000000L /* dissociates caller and marks + transaction branch rollback-only */ +#define TMNOWAIT 0x10000000L /* return if blocking condition + exists */ +#define TMRESUME 0x08000000L /* caller is resuming association with + suspended transaction branch */ +#define TMSUCCESS 0x04000000L /* dissociate caller from transaction + branch */ +#define TMSUSPEND 0x02000000L /* caller is suspending, not ending, + association */ +#define TMSTARTRSCAN 0x01000000L /* start a recovery scan */ +#define TMENDRSCAN 0x00800000L /* end a recovery scan */ +#define TMMULTIPLE 0x00400000L /* wait for any asynchronous + operation */ +#define TMJOIN 0x00200000L /* caller is joining existing + transaction branch */ +#define TMMIGRATE 0x00100000L /* caller intends to perform + migration */ + +/* + * ax_() return codes (transaction manager reports to resource manager) + */ +#define TM_JOIN 2 /* caller is joining existing + transaction branch */ +#define TM_RESUME 1 /* caller is resuming association with + suspended transaction branch */ +#define TM_OK 0 /* normal execution */ +#define TMER_TMERR -1 /* an error occurred in the transaction + manager */ +#define TMER_INVAL -2 /* invalid arguments were given */ +#define TMER_PROTO -3 /* routine invoked in an improper + context */ + +/* + * xa_() return codes (resource manager reports to transaction manager) + */ +#define XA_RBBASE 100 /* The inclusive lower bound of the + rollback codes */ +#define XA_RBROLLBACK XA_RBBASE /* The rollback was caused by an + unspecified reason */ +#define XA_RBCOMMFAIL XA_RBBASE+1 /* The rollback was caused by a + communication failure */ +#define XA_RBDEADLOCK XA_RBBASE+2 /* A deadlock was detected */ +#define XA_RBINTEGRITY XA_RBBASE+3 /* A condition that violates the + integrity of the resources was + detected */ +#define XA_RBOTHER XA_RBBASE+4 /* The resource manager rolled back the + transaction branch for a reason not + on this list */ +#define XA_RBPROTO XA_RBBASE+5 /* A protocol error occurred in the + resource manager */ +#define XA_RBTIMEOUT XA_RBBASE+6 /* A transaction branch took too long */ +#define XA_RBTRANSIENT XA_RBBASE+7 /* May retry the transaction branch */ +#define XA_RBEND XA_RBTRANSIENT /* The inclusive upper bound of the + rollback codes */ +#define XA_NOMIGRATE 9 /* resumption must occur where + suspension occurred */ +#define XA_HEURHAZ 8 /* the transaction branch may have + been heuristically completed */ +#define XA_HEURCOM 7 /* the transaction branch has been + heuristically committed */ +#define XA_HEURRB 6 /* the transaction branch has been + heuristically rolled back */ +#define XA_HEURMIX 5 /* the transaction branch has been + heuristically committed and rolled + back */ +#define XA_RETRY 4 /* routine returned with no effect and + may be re-issued */ +#define XA_RDONLY 3 /* the transaction branch was read-only + and has been committed */ +#define XA_OK 0 /* normal execution */ +#define XAER_ASYNC -2 /* asynchronous operation already + outstanding */ +#define XAER_RMERR -3 /* a resource manager error occurred in + the transaction branch */ +#define XAER_NOTA -4 /* the XID is not valid */ +#define XAER_INVAL -5 /* invalid arguments were given */ +#define XAER_PROTO -6 /* routine invoked in an improper + context */ +#define XAER_RMFAIL -7 /* resource manager unavailable */ +#define XAER_DUPID -8 /* the XID already exists */ +#define XAER_OUTSIDE -9 /* resource manager doing work outside + transaction */ +#endif /* ifndef XA_H */ +/* + * End of xa.h header + */ diff --git a/db/include/xa_ext.h b/db/include/xa_ext.h new file mode 100644 index 000000000..cc16ba183 --- /dev/null +++ b/db/include/xa_ext.h @@ -0,0 +1,17 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _xa_ext_h_ +#define _xa_ext_h_ +#if defined(__cplusplus) +extern "C" { +#endif +int __db_xa_create __P((DB *)); +int __db_rmid_to_env __P((int rmid, DB_ENV **envp)); +int __db_xid_to_txn __P((DB_ENV *, XID *, size_t *)); +int __db_map_rmid __P((int, DB_ENV *)); +int __db_unmap_rmid __P((int)); +int __db_map_xid __P((DB_ENV *, XID *, size_t)); +void __db_unmap_xid __P((DB_ENV *, XID *, size_t)); +#if defined(__cplusplus) +} +#endif +#endif /* _xa_ext_h_ */ diff --git a/db/java/src/com/sleepycat/db/Db.java b/db/java/src/com/sleepycat/db/Db.java new file mode 100644 index 000000000..de11e2841 --- /dev/null +++ b/db/java/src/com/sleepycat/db/Db.java @@ -0,0 +1,710 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: Db.java,v 11.38 2000/12/31 19:26:22 bostic Exp $ + */ + +package com.sleepycat.db; + +import java.io.OutputStream; +import java.io.FileNotFoundException; + +/** + * + * @author Donald D. Anderson + */ +public class Db +{ + // All constant and flag values used with Db* classes are defined here. + + // Collectively, these constants are known by the name + // "DBTYPE" in the documentation. + // + public static final int DB_BTREE = 1; // B+tree + public static final int DB_HASH = 2; // Extended Linear Hashing. + public static final int DB_RECNO = 3; // Fixed and variable-length records. + public static final int DB_QUEUE = 4; // Queue + public static final int DB_UNKNOWN = 5; // Figure it out on open. + + // Flags understood by DbEnv() + // + // Note: DB_CXX_NO_EXCEPTIONS will have no effect in Java. + // + public static final int DB_CXX_NO_EXCEPTIONS; // C++: return error values + public static final int DB_CLIENT; // Open for a client environment. + + // Flags understood by Db() + // + public static final int DB_XA_CREATE; // Open in an XA environment. + + // Flags understood by Db.open(), DbEnv.open(). + // + public static final int DB_CREATE; // O_CREAT: create file as necessary. + public static final int DB_NOMMAP; // Don't mmap underlying file. + public static final int DB_THREAD; // Free-thread DB package handles. + + // Flags understood by only DbEnv.open(). + // + public static final int DB_LOCKDOWN; // Lock memory into physical core. + public static final int DB_PRIVATE; // DB_ENV is process local. + + // + // Flags understood by DbEnv.txn_begin(). + // + public static final int DB_TXN_NOWAIT; // Do not wait for locks in this TXN. + public static final int DB_TXN_SYNC; // Always sync log on commit. + + // Flags understood by DbEnv.set_flags(). + // + public static final int DB_CDB_ALLDB; // In CDB, lock across environment. + + // + // Flags understood by Db.open(). + // + public static final int DB_EXCL; // Exclusive open (O_EXCL). + public static final int DB_RDONLY; // Read-only (O_RDONLY). + public static final int DB_TRUNCATE; // Discard existing DB. + public static final int DB_UPGRADE; // Upgrade if necessary. + + // + // DB (user visible) error return codes. + // + public static final int DB_INCOMPLETE = -30999; // Sync didn't finish. + public static final int DB_KEYEMPTY = -30998; // The key/data pair was deleted or + // was never created by the user. + public static final int DB_KEYEXIST = -30997; // The key/data pair already exists. + public static final int DB_LOCK_DEADLOCK = -30996; // Locker killed to resolve deadlock. + public static final int DB_LOCK_NOTGRANTED = -30995; // Lock unavailable, no-wait set. + public static final int DB_NOSERVER = -30994; // Server panic return. + public static final int DB_NOSERVER_HOME = -30993; // Bad home sent to server. + public static final int DB_NOSERVER_ID = -30992; // Bad ID sent to server. + public static final int DB_NOTFOUND = -30991; // Key/data pair not found (EOF). + public static final int DB_OLD_VERSION = -30990; // Out-of-date version. + public static final int DB_RUNRECOVERY = -30989; // Panic return. + public static final int DB_VERIFY_BAD = -30988; // Verify failed; bad format. + + // + // Flags used by DbEnv.open and DbEnv.remove. + // + public static final int DB_FORCE; // Force (anything). + public static final int DB_INIT_CDB; // Concurrent Access Methods. + public static final int DB_INIT_LOCK; // Initialize locking. + public static final int DB_INIT_LOG; // Initialize logging. + public static final int DB_INIT_MPOOL; // Initialize mpool. + public static final int DB_INIT_TXN; // Initialize transactions. + public static final int DB_JOINENV; // Initialize all subsystems present. + public static final int DB_RECOVER; // Run normal recovery. + public static final int DB_RECOVER_FATAL; // Run catastrophic recovery. + public static final int DB_SYSTEM_MEM; // Use system-backed memory. + public static final int DB_TXN_NOSYNC; // Do not sync log on commit. + public static final int DB_USE_ENVIRON; // Use the environment. + public static final int DB_USE_ENVIRON_ROOT; // Use the environment if root. + + // + // Operations values to the tx_recover() function. + // + public static final int DB_TXN_BACKWARD_ROLL = 1; + public static final int DB_TXN_FORWARD_ROLL = 2; + public static final int DB_TXN_OPENFILES = 3; + public static final int DB_TXN_REDO = 4; + public static final int DB_TXN_UNDO = 5; + + // + // Verbose flags; used for DbEnv.set_verbose + // + public static final int DB_VERB_CHKPOINT; // List checkpoints. + public static final int DB_VERB_DEADLOCK; // Deadlock detection information. + public static final int DB_VERB_RECOVERY; // Recovery information. + public static final int DB_VERB_WAITSFOR; // Dump waits-for table. + + // + // Deadlock detector modes; used in the DBENV structure to configure the + // locking subsystem. + // + public static final int DB_LOCK_NORUN; + public static final int DB_LOCK_DEFAULT; + public static final int DB_LOCK_OLDEST; + public static final int DB_LOCK_RANDOM; + public static final int DB_LOCK_YOUNGEST; + + // + // Flags understood by only Db.set_flags. + // + public static final int DB_DUP; // Btree, Hash: duplicate keys. + public static final int DB_DUPSORT; // Btree, Hash: duplicate keys. + public static final int DB_RECNUM; // Btree: record numbers. + public static final int DB_RENUMBER; // Recno: renumber on insert/delete. + public static final int DB_REVSPLITOFF;// Btree: turn off reverse splits. + public static final int DB_SNAPSHOT; // Recno: snapshot the input. + + // + // Flags understood by only Db.join + // + public static final int DB_JOIN_NOSORT;// Don't try to optimize join. + + // + // Flags understood by only Db.verify + // + public static final int DB_NOORDERCHK; // Skip order check; subdb w/ user func + public static final int DB_ORDERCHKONLY;// Only perform an order check on subdb + public static final int DB_SALVAGE; // Salvage what looks like data. + public static final int DB_AGGRESSIVE; // Salvage anything which might be data. + + // Collectively, these constants are known by the name + // "db_lockmode_t" in the documentation. + // + public static final int DB_LOCK_NG = 0; // Not granted. + public static final int DB_LOCK_READ = 1; // Shared/read. + public static final int DB_LOCK_WRITE = 2; // Exclusive/write. + public static final int DB_LOCK_IWRITE = 3; // Intent exclusive/write. + public static final int DB_LOCK_IREAD = 4; // Intent to share/read. + public static final int DB_LOCK_IWR = 5; // Intent to read and write. + + // Collectively, these constants are known by the name + // "db_lockop_t" in the documentation. + // + public static final int DB_LOCK_DUMP = 0; // Display held locks. + public static final int DB_LOCK_GET = 1; // Get the lock. + /* Not visible to API: DB_LOCK_INHERIT = 2 // Pass locks to parent. */ + public static final int DB_LOCK_PUT = 3; // Release the lock. + public static final int DB_LOCK_PUT_ALL = 4;// Release locker's locks. + public static final int DB_LOCK_PUT_OBJ = 5;// Release locker's locks on obj. + + // Flag values for DbLock.vec() + public static final int DB_LOCK_NOWAIT; // Don't wait on unavailable lock. + + // Flag values for DbLock.detect() + public static final int DB_LOCK_CONFLICT; // Run on any conflict. + + // + // Flag values for DbLog.archive() + // + public static final int DB_ARCH_ABS; // Absolute pathnames. + public static final int DB_ARCH_DATA; // Data files. + public static final int DB_ARCH_LOG; // Log files. + + // + // DB access method and cursor operation values. + // Each value is an operation code to which + // additional bit flags are added. + // + public static final int DB_AFTER; // Dbc.put() + public static final int DB_APPEND; // Db.put() + public static final int DB_BEFORE; // Dbc.put() + public static final int DB_CACHED_COUNTS; // Db.stat() + public static final int DB_CHECKPOINT; // DbLog.put(), DbLog.get() + public static final int DB_CONSUME; // Db.get() + public static final int DB_CONSUME_WAIT; // Db.get() + public static final int DB_CURLSN; // DbLog.put() + public static final int DB_CURRENT; // Dbc.get(), Dbc.put(), DbLog.get() + public static final int DB_FIRST; // Dbc.get(), DbLog.get() + public static final int DB_FLUSH; // DbLog.put() + public static final int DB_GET_BOTH; // Db.get(), Dbc.get() + public static final int DB_GET_RECNO; // Dbc.get() + public static final int DB_JOIN_ITEM; // Dbc.get() + public static final int DB_KEYFIRST; // Dbc.put() + public static final int DB_KEYLAST; // Dbc.put() + public static final int DB_LAST; // Dbc.get(), DbLog.get() + public static final int DB_NEXT; // Dbc.get(), DbLog.get() + public static final int DB_NEXT_DUP; // Dbc.get() + public static final int DB_NEXT_NODUP; // Dbc.get() + public static final int DB_NODUPDATA; // Don't permit duplicated data + public static final int DB_NOOVERWRITE;// Db.put() + public static final int DB_NOSYNC; // Db.close() + public static final int DB_POSITION; // Dbc.dup() + public static final int DB_PREV; // Dbc.get(), DbLog.get() + public static final int DB_PREV_NODUP; // Dbc.get() + public static final int DB_RECORDCOUNT;// Db.stat() + public static final int DB_SET; // Dbc.get(), DbLog.get() + public static final int DB_SET_RANGE; // Dbc.get() + public static final int DB_SET_RECNO; // Dbc.get() + public static final int DB_WRITECURSOR;// Db.cursor() + + // Other flags that can be added to an operation codes above. + // + public static final int DB_RMW; // Acquire write flag immediately. + + // Collectively, these values are used for Dbt flags + // + // Return in allocated memory. + public static final int DB_DBT_MALLOC; + + // Partial put/get. + public static final int DB_DBT_PARTIAL; + + // Return in realloc'd memory. + public static final int DB_DBT_REALLOC; + + // Return in user's memory. + public static final int DB_DBT_USERMEM; + + // Note: the env can be null + // + public Db(DbEnv env, int flags) + throws DbException + { + constructor_env_ = env; + _init(env, flags); + if (env == null) { + dbenv_ = new DbEnv(this); + } + else { + dbenv_ = env; + } + dbenv_._add_db(this); + } + + // + // Our parent DbEnv is notifying us that the environment is closing. + // + /*package*/ void _notify_dbenv_close() + { + dbenv_ = null; + _notify_internal(); + } + + private native void _init(DbEnv env, int flags) + throws DbException; + + private native void _notify_internal(); + + // methods + // + + public synchronized int close(int flags) + throws DbException + { + int err; + + dbenv_._remove_db(this); + err = _close(flags); + if (constructor_env_ == null) { + dbenv_._notify_db_close(); + } + return err; + } + + public native int _close(int flags) + throws DbException; + + public native Dbc cursor(DbTxn txnid, int flags) + throws DbException; + + public native int del(DbTxn txnid, Dbt key, int flags) + throws DbException; + + public native void err(int errcode, String message); + + public native void errx(String message); + + public native int fd() + throws DbException; + + // overrides Object.finalize + protected void finalize() + throws Throwable + { + _finalize(dbenv_.errcall_, dbenv_.errpfx_); + } + + protected native void _finalize(DbErrcall errcall, String errpfx) + throws Throwable; + + // returns: 0, DB_NOTFOUND, or throws error + public native int get(DbTxn txnid, Dbt key, Dbt data, int flags) + throws DbException; + + public native boolean get_byteswapped(); + + public native /*DBTYPE*/ int get_type(); + + public native Dbc join(Dbc curslist[], int flags) + throws DbException; + + public native void key_range(DbTxn txn, Dbt key, + DbKeyRange range, int flags) + throws DbException; + + public synchronized void open(String file, String database, + /*DBTYPE*/ int type, + int flags, int mode) + throws DbException, FileNotFoundException + { + _open(file, database, type, flags, mode); + } + + // (Internal) + public native void _open(String file, String database, + /*DBTYPE*/ int type, + int flags, int mode) + throws DbException, FileNotFoundException; + + + // returns: 0, DB_KEYEXIST, or throws error + public native int put(DbTxn txnid, Dbt key, Dbt data, int flags) + throws DbException; + + public synchronized native void rename(String file, String database, + String newname, int flags) + throws DbException, FileNotFoundException; + + public synchronized native void remove(String file, String database, + int flags) + throws DbException, FileNotFoundException; + + // Comparison function. + public void set_append_recno(DbAppendRecno append_recno) + throws DbException + { + append_recno_ = append_recno; + append_recno_changed(append_recno); + } + + // (Internal) + private native void append_recno_changed(DbAppendRecno append_recno) + throws DbException; + + // Comparison function. + public void set_bt_compare(DbBtreeCompare bt_compare) + throws DbException + { + bt_compare_ = bt_compare; + bt_compare_changed(bt_compare); + } + + // (Internal) + private native void bt_compare_changed(DbBtreeCompare bt_compare) + throws DbException; + + // Maximum keys per page. + public native void set_bt_maxkey(int maxkey) + throws DbException; + + // Minimum keys per page. + public native void set_bt_minkey(int minkey) + throws DbException; + + // Prefix function. + public void set_bt_prefix(DbBtreePrefix bt_prefix) + throws DbException + { + bt_prefix_ = bt_prefix; + bt_prefix_changed(bt_prefix); + } + + // (Internal) + private native void bt_prefix_changed(DbBtreePrefix bt_prefix) + throws DbException; + + // Set cache size + public native void set_cachesize(int gbytes, int bytes, int ncaches) + throws DbException; + + // Duplication resolution + public void set_dup_compare(DbDupCompare dup_compare) + throws DbException + { + dup_compare_ = dup_compare; + dup_compare_changed(dup_compare); + } + + // (Internal) + private native void dup_compare_changed(DbDupCompare dup_compare) + throws DbException; + + // Error message callback. + public void set_errcall(DbErrcall errcall) + { + if (dbenv_ != null) + dbenv_.set_errcall(errcall); + } + + // Error stream. + public void set_error_stream(OutputStream s) + { + DbOutputStreamErrcall errcall = new DbOutputStreamErrcall(s); + set_errcall(errcall); + } + + // Error message prefix. + public void set_errpfx(String errpfx) + { + if (dbenv_ != null) + dbenv_.set_errpfx(errpfx); + } + + + // Feedback + public void set_feedback(DbFeedback feedback) + throws DbException + { + feedback_ = feedback; + feedback_changed(feedback); + } + + // (Internal) + private native void feedback_changed(DbFeedback feedback) + throws DbException; + + // Flags. + public native void set_flags(/*u_int32_t*/ int flags); + + // Fill factor. + public native void set_h_ffactor(/*unsigned*/ int h_ffactor); + + // Hash function. + public void set_h_hash(DbHash h_hash) + throws DbException + { + h_hash_ = h_hash; + hash_changed(h_hash); + } + + // (Internal) + private native void hash_changed(DbHash hash) + throws DbException; + + // Number of elements. + public native void set_h_nelem(/*unsigned*/ int h_nelem); + + // Byte order. + public native void set_lorder(int lorder); + + // Underlying page size. + public native void set_pagesize(/*size_t*/ long pagesize); + + // Variable-length delimiting byte. + public native void set_re_delim(int re_delim); + + // Length for fixed-length records. + public native void set_re_len(/*u_int32_t*/ int re_len); + + // Fixed-length padding byte. + public native void set_re_pad(int re_pad); + + // Source file name. + public native void set_re_source(String re_source); + + // Extent size of Queue + public native void set_q_extentsize(/*u_int32_t*/ int extent_size); + + // returns a DbBtreeStat or DbHashStat + public native Object stat(int flags) + throws DbException; + + public native int sync(int flags) + throws DbException; + + public native void upgrade(String name, int flags) + throws DbException; + + public native void verify(String name, String subdb, + OutputStream outstr, int flags) + throws DbException; + + //////////////////////////////////////////////////////////////// + // + // private data + // + private long private_dbobj_ = 0; + private long private_info_ = 0; + private DbEnv dbenv_ = null; + private DbEnv constructor_env_ = null; + private DbFeedback feedback_ = null; + private DbAppendRecno append_recno_ = null; + private DbBtreeCompare bt_compare_ = null; + private DbBtreePrefix bt_prefix_ = null; + private DbDupCompare dup_compare_ = null; + private DbHash h_hash_ = null; + + //////////////////////////////////////////////////////////////// + // + // static methods and data that implement + // loading the native library and doing any + // extra sanity checks on startup. + // + private static boolean already_loaded_ = false; + + public static void load_db() + { + if (already_loaded_) + return; + + // An alternate library name can be specified via a property. + // + String overrideLibname = System.getProperty("sleepycat.db.libname"); + if (overrideLibname != null) { + System.loadLibrary(overrideLibname); + } + else { + String os = System.getProperty("os.name"); + if (os != null && os.startsWith("Windows")) { + // library name is "libdb_java30.dll" (for example) on Win/* + System.loadLibrary("libdb_java" + + DbConstants.DB_VERSION_MAJOR + + DbConstants.DB_VERSION_MINOR); + } + else { + // library name is "libdb_java-3.0.so" (for example) on UNIX + // Note: "db_java" isn't good enough; + // some Unixes require us to use the explicit SONAME. + System.loadLibrary("db_java-" + + DbConstants.DB_VERSION_MAJOR + "." + + DbConstants.DB_VERSION_MINOR); + } + } + + already_loaded_ = true; + } + + static private native void one_time_init(); + + static private void check_constant(int c1, int c2) + { + if (c1 != c2) { + System.err.println("Db: constant mismatch"); + System.exit(1); + } + } + + static { + Db.load_db(); + + // Note: constant values are stored in DbConstants, which + // is automatically generated. Initializing constants in + // static code insulates users from the possibility of + // changing constants. + // + DB_CXX_NO_EXCEPTIONS = DbConstants.DB_CXX_NO_EXCEPTIONS; + DB_CLIENT = DbConstants.DB_CLIENT; + DB_XA_CREATE = DbConstants.DB_XA_CREATE; + + DB_CREATE = DbConstants.DB_CREATE; + DB_NOMMAP = DbConstants.DB_NOMMAP; + DB_THREAD = DbConstants.DB_THREAD; + + DB_LOCKDOWN = DbConstants.DB_LOCKDOWN; + DB_PRIVATE = DbConstants.DB_PRIVATE; + DB_TXN_NOWAIT = DbConstants.DB_TXN_NOWAIT; + DB_TXN_SYNC = DbConstants.DB_TXN_SYNC; + DB_CDB_ALLDB = DbConstants.DB_CDB_ALLDB; + + DB_EXCL = DbConstants.DB_EXCL; + DB_RDONLY = DbConstants.DB_RDONLY; + DB_TRUNCATE = DbConstants.DB_TRUNCATE; + DB_UPGRADE = DbConstants.DB_UPGRADE; + + // These constants are not assigned, but rather checked. + // Having initialized constants for these values allows + // them to be used as case values in switch statements. + // + check_constant(DB_INCOMPLETE, DbConstants.DB_INCOMPLETE); + check_constant(DB_KEYEMPTY, DbConstants.DB_KEYEMPTY); + check_constant(DB_KEYEXIST, DbConstants.DB_KEYEXIST); + check_constant(DB_LOCK_DEADLOCK, DbConstants.DB_LOCK_DEADLOCK); + check_constant(DB_LOCK_NOTGRANTED, DbConstants.DB_LOCK_NOTGRANTED); + check_constant(DB_NOSERVER, DbConstants.DB_NOSERVER); + check_constant(DB_NOSERVER_HOME, DbConstants.DB_NOSERVER_HOME); + check_constant(DB_NOSERVER_ID, DbConstants.DB_NOSERVER_ID); + check_constant(DB_NOTFOUND, DbConstants.DB_NOTFOUND); + check_constant(DB_OLD_VERSION, DbConstants.DB_OLD_VERSION); + check_constant(DB_RUNRECOVERY, DbConstants.DB_RUNRECOVERY); + check_constant(DB_VERIFY_BAD, DbConstants.DB_VERIFY_BAD); + check_constant(DB_TXN_BACKWARD_ROLL, DbConstants.DB_TXN_BACKWARD_ROLL); + check_constant(DB_TXN_FORWARD_ROLL, DbConstants.DB_TXN_FORWARD_ROLL); + check_constant(DB_TXN_OPENFILES, DbConstants.DB_TXN_OPENFILES); + check_constant(DB_TXN_REDO, DbConstants.DB_TXN_REDO); + check_constant(DB_TXN_UNDO, DbConstants.DB_TXN_UNDO); + + DB_FORCE = DbConstants.DB_FORCE; + DB_INIT_CDB = DbConstants.DB_INIT_CDB; + DB_INIT_LOCK = DbConstants.DB_INIT_LOCK; + DB_INIT_LOG = DbConstants.DB_INIT_LOG; + DB_INIT_MPOOL = DbConstants.DB_INIT_MPOOL; + DB_INIT_TXN = DbConstants.DB_INIT_TXN; + DB_JOINENV = DbConstants.DB_JOINENV; + DB_RECOVER = DbConstants.DB_RECOVER; + DB_RECOVER_FATAL = DbConstants.DB_RECOVER_FATAL; + DB_SYSTEM_MEM = DbConstants.DB_SYSTEM_MEM; + DB_TXN_NOSYNC = DbConstants.DB_TXN_NOSYNC; + DB_USE_ENVIRON = DbConstants.DB_USE_ENVIRON; + DB_USE_ENVIRON_ROOT = DbConstants.DB_USE_ENVIRON_ROOT; + + DB_VERB_CHKPOINT = DbConstants.DB_VERB_CHKPOINT; + DB_VERB_DEADLOCK = DbConstants.DB_VERB_DEADLOCK; + DB_VERB_RECOVERY = DbConstants.DB_VERB_RECOVERY; + DB_VERB_WAITSFOR = DbConstants.DB_VERB_WAITSFOR; + + DB_LOCK_NORUN = DbConstants.DB_LOCK_NORUN; + DB_LOCK_DEFAULT = DbConstants.DB_LOCK_DEFAULT; + DB_LOCK_OLDEST = DbConstants.DB_LOCK_OLDEST; + DB_LOCK_RANDOM = DbConstants.DB_LOCK_RANDOM; + DB_LOCK_YOUNGEST = DbConstants.DB_LOCK_YOUNGEST; + + DB_DUP = DbConstants.DB_DUP; + DB_DUPSORT = DbConstants.DB_DUPSORT; + DB_RECNUM = DbConstants.DB_RECNUM; + DB_RENUMBER = DbConstants.DB_RENUMBER; + DB_REVSPLITOFF = DbConstants.DB_REVSPLITOFF; + DB_SNAPSHOT = DbConstants.DB_SNAPSHOT; + + DB_JOIN_NOSORT = DbConstants.DB_JOIN_NOSORT; + + DB_NOORDERCHK = DbConstants.DB_NOORDERCHK; + DB_ORDERCHKONLY = DbConstants.DB_ORDERCHKONLY; + DB_SALVAGE = DbConstants.DB_SALVAGE; + DB_AGGRESSIVE = DbConstants.DB_AGGRESSIVE; + + DB_LOCK_NOWAIT = DbConstants.DB_LOCK_NOWAIT; + DB_LOCK_CONFLICT = DbConstants.DB_LOCK_CONFLICT; + + DB_ARCH_ABS = DbConstants.DB_ARCH_ABS; + DB_ARCH_DATA = DbConstants.DB_ARCH_DATA; + DB_ARCH_LOG = DbConstants.DB_ARCH_LOG; + + DB_AFTER = DbConstants.DB_AFTER; + DB_APPEND = DbConstants.DB_APPEND; + DB_BEFORE = DbConstants.DB_BEFORE; + DB_CACHED_COUNTS = DbConstants.DB_CACHED_COUNTS; + DB_CHECKPOINT = DbConstants.DB_CHECKPOINT; + DB_CONSUME = DbConstants.DB_CONSUME; + DB_CONSUME_WAIT = DbConstants.DB_CONSUME_WAIT; + DB_CURLSN = DbConstants.DB_CURLSN; + DB_CURRENT = DbConstants.DB_CURRENT; + DB_FIRST = DbConstants.DB_FIRST; + DB_FLUSH = DbConstants.DB_FLUSH; + DB_GET_BOTH = DbConstants.DB_GET_BOTH; + DB_GET_RECNO = DbConstants.DB_GET_RECNO; + DB_JOIN_ITEM = DbConstants.DB_JOIN_ITEM; + DB_KEYFIRST = DbConstants.DB_KEYFIRST; + DB_KEYLAST = DbConstants.DB_KEYLAST; + DB_LAST = DbConstants.DB_LAST; + DB_NEXT = DbConstants.DB_NEXT; + DB_NEXT_DUP = DbConstants.DB_NEXT_DUP; + DB_NEXT_NODUP = DbConstants.DB_NEXT_NODUP; + DB_NODUPDATA = DbConstants.DB_NODUPDATA; + DB_NOOVERWRITE = DbConstants.DB_NOOVERWRITE; + DB_NOSYNC = DbConstants.DB_NOSYNC; + DB_POSITION = DbConstants.DB_POSITION; + DB_PREV = DbConstants.DB_PREV; + DB_PREV_NODUP = DbConstants.DB_PREV_NODUP; + DB_RECORDCOUNT = DbConstants.DB_RECORDCOUNT; + DB_RMW = DbConstants.DB_RMW; + DB_SET = DbConstants.DB_SET; + DB_SET_RANGE = DbConstants.DB_SET_RANGE; + DB_SET_RECNO = DbConstants.DB_SET_RECNO; + DB_WRITECURSOR = DbConstants.DB_WRITECURSOR; + + DB_DBT_MALLOC = DbConstants.DB_DBT_MALLOC; + DB_DBT_PARTIAL = DbConstants.DB_DBT_PARTIAL; + DB_DBT_REALLOC = DbConstants.DB_DBT_REALLOC; + DB_DBT_USERMEM = DbConstants.DB_DBT_USERMEM; + + one_time_init(); + } +} + +// end of Db.java diff --git a/db/java/src/com/sleepycat/db/DbAppendRecno.java b/db/java/src/com/sleepycat/db/DbAppendRecno.java new file mode 100644 index 000000000..ffe40e95f --- /dev/null +++ b/db/java/src/com/sleepycat/db/DbAppendRecno.java @@ -0,0 +1,22 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: DbAppendRecno.java,v 11.1 2000/07/31 20:28:30 dda Exp $ + */ + +package com.sleepycat.db; + +/* + * This interface is used by Db.set_append_recno() + * + */ +public interface DbAppendRecno +{ + public abstract void db_append_recno(Db db, Dbt data, int recno) + throws DbException; +} + +// end of DbAppendRecno.java diff --git a/db/java/src/com/sleepycat/db/DbBtreeCompare.java b/db/java/src/com/sleepycat/db/DbBtreeCompare.java new file mode 100644 index 000000000..2e5306af2 --- /dev/null +++ b/db/java/src/com/sleepycat/db/DbBtreeCompare.java @@ -0,0 +1,21 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: DbBtreeCompare.java,v 11.2 2000/07/04 20:53:19 dda Exp $ + */ + +package com.sleepycat.db; + +/* + * This interface is used by DbEnv.set_bt_compare() + * + */ +public interface DbBtreeCompare +{ + public abstract int bt_compare(Db db, Dbt dbt1, Dbt dbt2); +} + +// end of DbBtreeCompare.java diff --git a/db/java/src/com/sleepycat/db/DbBtreePrefix.java b/db/java/src/com/sleepycat/db/DbBtreePrefix.java new file mode 100644 index 000000000..27e630543 --- /dev/null +++ b/db/java/src/com/sleepycat/db/DbBtreePrefix.java @@ -0,0 +1,21 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: DbBtreePrefix.java,v 11.2 2000/07/04 20:53:19 dda Exp $ + */ + +package com.sleepycat.db; + +/* + * This interface is used by DbEnv.set_bt_prefix() + * + */ +public interface DbBtreePrefix +{ + public abstract int bt_prefix(Db db, Dbt dbt1, Dbt dbt2); +} + +// end of DbBtreePrefix.java diff --git a/db/java/src/com/sleepycat/db/DbBtreeStat.java b/db/java/src/com/sleepycat/db/DbBtreeStat.java new file mode 100644 index 000000000..8dea8da10 --- /dev/null +++ b/db/java/src/com/sleepycat/db/DbBtreeStat.java @@ -0,0 +1,40 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: DbBtreeStat.java,v 11.5 2000/05/04 02:54:55 dda Exp $ + */ + +package com.sleepycat.db; + +/* + * This is filled in and returned by the + * Db.stat() method. + */ +public class DbBtreeStat +{ + public int bt_magic; // Magic number. + public int bt_version; // Version number. + public int bt_metaflags; // Meta-data flags. + public int bt_nkeys; // Number of unique keys. + public int bt_ndata; // Number of data items. + public int bt_pagesize; // Page size. + public int bt_maxkey; // Maxkey value. + public int bt_minkey; // Minkey value. + public int bt_re_len; // Fixed-length record length. + public int bt_re_pad; // Fixed-length record pad. + public int bt_levels; // Tree levels. + public int bt_int_pg; // Internal pages. + public int bt_leaf_pg; // Leaf pages. + public int bt_dup_pg; // Duplicate pages. + public int bt_over_pg; // Overflow pages. + public int bt_free; // Pages on the free list. + public int bt_int_pgfree; // Bytes free in internal pages. + public int bt_leaf_pgfree; // Bytes free in leaf pages. + public int bt_dup_pgfree; // Bytes free in duplicate pages. + public int bt_over_pgfree; // Bytes free in overflow pages. +} + +// end of DbBtreeStat.java diff --git a/db/java/src/com/sleepycat/db/DbConstants.java b/db/java/src/com/sleepycat/db/DbConstants.java new file mode 100644 index 000000000..491b1fce2 --- /dev/null +++ b/db/java/src/com/sleepycat/db/DbConstants.java @@ -0,0 +1,217 @@ +// DO NOT EDIT: automatically built by dist/s_java. + +package com.sleepycat.db; + +public class DbConstants +{ + public static final int DB_MAX_PAGES = 0xffffffff; + public static final int DB_MAX_RECORDS = 0xffffffff; + public static final int DB_DBT_ISSET = 0x001; + public static final int DB_DBT_MALLOC = 0x002; + public static final int DB_DBT_PARTIAL = 0x004; + public static final int DB_DBT_REALLOC = 0x008; + public static final int DB_DBT_USERMEM = 0x010; + public static final int DB_DBT_DUPOK = 0x020; + public static final int DB_CREATE = 0x000001; + public static final int DB_CXX_NO_EXCEPTIONS = 0x000002; + public static final int DB_FORCE = 0x000004; + public static final int DB_NOMMAP = 0x000008; + public static final int DB_RDONLY = 0x000010; + public static final int DB_RECOVER = 0x000020; + public static final int DB_THREAD = 0x000040; + public static final int DB_TXN_NOSYNC = 0x000080; + public static final int DB_USE_ENVIRON = 0x000100; + public static final int DB_USE_ENVIRON_ROOT = 0x000200; + public static final int DB_CLIENT = 0x000400; + public static final int DB_XA_CREATE = 0x000400; + public static final int DB_INIT_CDB = 0x000400; + public static final int DB_INIT_LOCK = 0x000800; + public static final int DB_INIT_LOG = 0x001000; + public static final int DB_INIT_MPOOL = 0x002000; + public static final int DB_INIT_TXN = 0x004000; + public static final int DB_JOINENV = 0x008000; + public static final int DB_LOCKDOWN = 0x010000; + public static final int DB_PRIVATE = 0x020000; + public static final int DB_RECOVER_FATAL = 0x040000; + public static final int DB_SYSTEM_MEM = 0x080000; + public static final int DB_EXCL = 0x000400; + public static final int DB_FCNTL_LOCKING = 0x000800; + public static final int DB_ODDFILESIZE = 0x001000; + public static final int DB_RDWRMASTER = 0x002000; + public static final int DB_TRUNCATE = 0x004000; + public static final int DB_EXTENT = 0x008000; + public static final int DB_TXN_NOWAIT = 0x000400; + public static final int DB_TXN_SYNC = 0x000800; + public static final int DB_CDB_ALLDB = 0x000400; + public static final int DB_UPGRADE = 0x000400; + public static final int DB_VERIFY = 0x000800; + public static final int DB_DUP = 0x0001; + public static final int DB_DUPSORT = 0x0002; + public static final int DB_RECNUM = 0x0004; + public static final int DB_RENUMBER = 0x0008; + public static final int DB_REVSPLITOFF = 0x0010; + public static final int DB_SNAPSHOT = 0x0020; + public static final int DB_JOIN_NOSORT = 0x0001; + public static final int DB_AGGRESSIVE = 0x0001; + public static final int DB_NOORDERCHK = 0x0002; + public static final int DB_ORDERCHKONLY = 0x0004; + public static final int DB_PR_PAGE = 0x0008; + public static final int DB_PR_HEADERS = 0x0010; + public static final int DB_PR_RECOVERYTEST = 0x0020; + public static final int DB_SALVAGE = 0x0040; + public static final int DB_VRFY_FLAGMASK = 0xffff; + public static final int DB_LOCK_NORUN = 0; + public static final int DB_LOCK_DEFAULT = 1; + public static final int DB_LOCK_OLDEST = 2; + public static final int DB_LOCK_RANDOM = 3; + public static final int DB_LOCK_YOUNGEST = 4; + public static final int DB_REGION_MAGIC = 0x120897; + public static final int DB_VERB_CHKPOINT = 0x0001; + public static final int DB_VERB_DEADLOCK = 0x0002; + public static final int DB_VERB_RECOVERY = 0x0004; + public static final int DB_VERB_WAITSFOR = 0x0008; + public static final int DB_TEST_PREOPEN = 1; + public static final int DB_TEST_POSTOPEN = 2; + public static final int DB_TEST_POSTLOGMETA = 3; + public static final int DB_TEST_POSTLOG = 4; + public static final int DB_TEST_POSTSYNC = 5; + public static final int DB_TEST_PRERENAME = 6; + public static final int DB_TEST_POSTRENAME = 7; + public static final int DB_ENV_CDB = 0x00001; + public static final int DB_ENV_CDB_ALLDB = 0x00002; + public static final int DB_ENV_CREATE = 0x00004; + public static final int DB_ENV_DBLOCAL = 0x00008; + public static final int DB_ENV_LOCKDOWN = 0x00010; + public static final int DB_ENV_NOMMAP = 0x00020; + public static final int DB_ENV_OPEN_CALLED = 0x00040; + public static final int DB_ENV_PRIVATE = 0x00080; + public static final int DB_ENV_RPCCLIENT = 0x00100; + public static final int DB_ENV_STANDALONE = 0x00200; + public static final int DB_ENV_SYSTEM_MEM = 0x00400; + public static final int DB_ENV_THREAD = 0x00800; + public static final int DB_ENV_TXN_NOSYNC = 0x01000; + public static final int DB_ENV_USER_ALLOC = 0x02000; + public static final int DB_BTREEVERSION = 8; + public static final int DB_BTREEOLDVER = 6; + public static final int DB_BTREEMAGIC = 0x053162; + public static final int DB_HASHVERSION = 7; + public static final int DB_HASHOLDVER = 4; + public static final int DB_HASHMAGIC = 0x061561; + public static final int DB_QAMVERSION = 3; + public static final int DB_QAMOLDVER = 1; + public static final int DB_QAMMAGIC = 0x042253; + public static final int DB_LOGVERSION = 3; + public static final int DB_LOGOLDVER = 3; + public static final int DB_LOGMAGIC = 0x040988; + public static final int DB_AFTER = 1; + public static final int DB_APPEND = 2; + public static final int DB_BEFORE = 3; + public static final int DB_CACHED_COUNTS = 4; + public static final int DB_CHECKPOINT = 5; + public static final int DB_CONSUME = 6; + public static final int DB_CONSUME_WAIT = 7; + public static final int DB_CURLSN = 8; + public static final int DB_CURRENT = 9; + public static final int DB_FIRST = 10; + public static final int DB_FLUSH = 11; + public static final int DB_GET_BOTH = 12; + public static final int DB_GET_BOTHC = 13; + public static final int DB_GET_RECNO = 14; + public static final int DB_JOIN_ITEM = 15; + public static final int DB_KEYFIRST = 16; + public static final int DB_KEYLAST = 17; + public static final int DB_LAST = 18; + public static final int DB_NEXT = 19; + public static final int DB_NEXT_DUP = 20; + public static final int DB_NEXT_NODUP = 21; + public static final int DB_NODUPDATA = 22; + public static final int DB_NOOVERWRITE = 23; + public static final int DB_NOSYNC = 24; + public static final int DB_POSITION = 25; + public static final int DB_POSITIONI = 26; + public static final int DB_PREV = 27; + public static final int DB_PREV_NODUP = 28; + public static final int DB_RECORDCOUNT = 29; + public static final int DB_SET = 30; + public static final int DB_SET_RANGE = 31; + public static final int DB_SET_RECNO = 32; + public static final int DB_WRITECURSOR = 33; + public static final int DB_WRITELOCK = 34; + public static final int DB_OPFLAGS_MASK = 0x000000ff; + public static final int DB_RMW = 0x80000000; + public static final int DB_INCOMPLETE = -30999; + public static final int DB_KEYEMPTY = -30998; + public static final int DB_KEYEXIST = -30997; + public static final int DB_LOCK_DEADLOCK = -30996; + public static final int DB_LOCK_NOTGRANTED = -30995; + public static final int DB_NOSERVER = -30994; + public static final int DB_NOSERVER_HOME = -30993; + public static final int DB_NOSERVER_ID = -30992; + public static final int DB_NOTFOUND = -30991; + public static final int DB_OLD_VERSION = -30990; + public static final int DB_RUNRECOVERY = -30989; + public static final int DB_VERIFY_BAD = -30988; + public static final int DB_ALREADY_ABORTED = -30899; + public static final int DB_DELETED = -30898; + public static final int DB_JAVA_CALLBACK = -30897; + public static final int DB_NEEDSPLIT = -30896; + public static final int DB_SWAPBYTES = -30895; + public static final int DB_TXN_CKP = -30894; + public static final int DB_VERIFY_FATAL = -30893; + public static final int DB_FILE_ID_LEN = 20; + public static final int DB_LOGFILEID_INVALID = -1; + public static final int DB_OK_BTREE = 0x01; + public static final int DB_OK_HASH = 0x02; + public static final int DB_OK_QUEUE = 0x04; + public static final int DB_OK_RECNO = 0x08; + public static final int DB_AM_DISCARD = 0x00001; + public static final int DB_AM_DUP = 0x00002; + public static final int DB_AM_DUPSORT = 0x00004; + public static final int DB_AM_INMEM = 0x00008; + public static final int DB_AM_PGDEF = 0x00010; + public static final int DB_AM_RDONLY = 0x00020; + public static final int DB_AM_RECOVER = 0x00040; + public static final int DB_AM_SUBDB = 0x00080; + public static final int DB_AM_SWAP = 0x00100; + public static final int DB_AM_TXN = 0x00200; + public static final int DB_AM_VERIFYING = 0x00400; + public static final int DB_BT_RECNUM = 0x00800; + public static final int DB_BT_REVSPLIT = 0x01000; + public static final int DB_DBM_ERROR = 0x02000; + public static final int DB_OPEN_CALLED = 0x04000; + public static final int DB_RE_DELIMITER = 0x08000; + public static final int DB_RE_FIXEDLEN = 0x10000; + public static final int DB_RE_PAD = 0x20000; + public static final int DB_RE_RENUMBER = 0x40000; + public static final int DB_RE_SNAPSHOT = 0x80000; + public static final int DB_RECORD_LOCK = 1; + public static final int DB_PAGE_LOCK = 2; + public static final int DB_LOCKVERSION = 1; + public static final int DB_LOCK_NOWAIT = 0x01; + public static final int DB_LOCK_RECORD = 0x02; + public static final int DB_LOCK_UPGRADE = 0x04; + public static final int DB_LOCK_SWITCH = 0x08; + public static final int DB_LOCK_CONFLICT = 0x01; + public static final int DB_LOCK_RIW_N = 7; + public static final int DB_ARCH_ABS = 0x001; + public static final int DB_ARCH_DATA = 0x002; + public static final int DB_ARCH_LOG = 0x004; + public static final int DB_MPOOL_CREATE = 0x001; + public static final int DB_MPOOL_LAST = 0x002; + public static final int DB_MPOOL_NEW = 0x004; + public static final int DB_MPOOL_NEW_GROUP = 0x008; + public static final int DB_MPOOL_EXTENT = 0x010; + public static final int DB_MPOOL_CLEAN = 0x001; + public static final int DB_MPOOL_DIRTY = 0x002; + public static final int DB_MPOOL_DISCARD = 0x004; + public static final int DB_TXNVERSION = 1; + public static final int DB_TXN_BACKWARD_ROLL = 1; + public static final int DB_TXN_FORWARD_ROLL = 2; + public static final int DB_TXN_OPENFILES = 3; + public static final int DB_TXN_REDO = 4; + public static final int DB_TXN_UNDO = 5; + public static final int DB_DBM_HSEARCH = 0; + public static final int DB_VERSION_MAJOR = 3; + public static final int DB_VERSION_MINOR = 2; + public static final int DB_VERSION_PATCH = 9; +} diff --git a/db/java/src/com/sleepycat/db/DbDeadlockException.java b/db/java/src/com/sleepycat/db/DbDeadlockException.java new file mode 100644 index 000000000..beab2ad62 --- /dev/null +++ b/db/java/src/com/sleepycat/db/DbDeadlockException.java @@ -0,0 +1,28 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: DbDeadlockException.java,v 11.3 2000/02/14 02:59:56 bostic Exp $ + */ + +package com.sleepycat.db; + +public class DbDeadlockException extends DbException +{ + // methods + // + + public DbDeadlockException(String s) + { + super(s); + } + + public DbDeadlockException(String s, int errno) + { + super(s, errno); + } +} + +// end of DbDeadlockException.java diff --git a/db/java/src/com/sleepycat/db/DbDupCompare.java b/db/java/src/com/sleepycat/db/DbDupCompare.java new file mode 100644 index 000000000..3d4b5a736 --- /dev/null +++ b/db/java/src/com/sleepycat/db/DbDupCompare.java @@ -0,0 +1,21 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: DbDupCompare.java,v 11.2 2000/07/04 20:53:19 dda Exp $ + */ + +package com.sleepycat.db; + +/* + * This interface is used by DbEnv.set_dup_compare() + * + */ +public interface DbDupCompare +{ + public abstract int dup_compare(Db db, Dbt dbt1, Dbt dbt2); +} + +// end of DbDupCompare.java diff --git a/db/java/src/com/sleepycat/db/DbEnv.java b/db/java/src/com/sleepycat/db/DbEnv.java new file mode 100644 index 000000000..6e9ce7ae3 --- /dev/null +++ b/db/java/src/com/sleepycat/db/DbEnv.java @@ -0,0 +1,392 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: DbEnv.java,v 11.25 2001/01/04 14:23:30 dda Exp $ + */ + +package com.sleepycat.db; + +import java.io.OutputStream; +import java.io.FileNotFoundException; +import java.util.Date; +import java.util.Enumeration; +import java.util.Vector; + +/** + * + * @author Donald D. Anderson + */ +public class DbEnv +{ + // methods + // + + // + // After using this constructor, set any parameters via + // the set_* access methods below, and finally open + // the environment by calling open(). + // + public DbEnv(int flags) + { + constructor_flags_ = flags; + _init(errstream_, constructor_flags_); + } + + // + // This constructor is purposely not public. + // It is used internally to create a DbEnv wrapper + // when an underlying environment already exists. + // + /*package*/ DbEnv(Db db) + { + _init_using_db(errstream_, db); + } + + // + // When a Db is created, it is kept in a private list, + // so that Db's can be notified when the environment + // is closed. This allows us to detect and guard + // against the following situation: + // DbEnv env = new DbEnv(0); + // Db db = new Db(0); + // env.close(); + // db.close(); + // + // This *is* a programming error, but not protecting + // against it will crash the VM. + // + /*package*/ void _add_db(Db db) + { + dblist_.addElement(db); + } + + // + // Remove from the private list of Db's. + // + /*package*/ void _remove_db(Db db) + { + dblist_.removeElement(db); + } + + // + // Iterate all the Db's in the list, and + // notify them that the environment is closing, + // so they can clean up. + // + /*package*/ void _notify_dbs() + { + Enumeration enum = dblist_.elements(); + while (enum.hasMoreElements()) { + Db db = (Db)enum.nextElement(); + db._notify_dbenv_close(); + } + dblist_.removeAllElements(); + } + + // close discards any internal memory. + // After using close, the DbEnv can be reopened. + // + public synchronized void close(int flags) + throws DbException + { + _notify_dbs(); + _close(flags); + } + + // (Internal) + private native void _close(int flags) + throws DbException; + + public native void err(int errcode, String message); + + public native void errx(String message); + + // overrides Object.finalize + protected void finalize() + throws Throwable + { + _notify_dbs(); + _finalize(errcall_, errpfx_); + } + + // (Internal) + protected native void _finalize(DbErrcall errcall, String errpfx) + throws Throwable; + + // (Internal) + private native void _init(DbErrcall errcall, int flags); + + // (Internal) + private native void _init_using_db(DbErrcall errcall, Db db); + + /*package*/ native void _notify_db_close(); + + public native void open(String db_home, int flags, int mode) + throws DbException, FileNotFoundException; + + // remove removes any files and discards any internal memory. + // (i.e. implicitly it does a close, if the environment is open). + // After using close, the DbEnv can no longer be used; + // create another one if needed. + // + public native synchronized void remove(String db_home, int flags) + throws DbException, FileNotFoundException; + + //////////////////////////////////////////////////////////////// + // simple get/set access methods + // + // If you are calling set_ methods, you need to + // use the constructor with one argument along with open(). + + public native void set_cachesize(int gbytes, int bytes, int ncaches) + throws DbException; + + // Error message callback. + public void set_errcall(DbErrcall errcall) + { + errcall_ = errcall; + _set_errcall(errcall); + } + + public native void _set_errcall(DbErrcall errcall); + + // Error stream. + public void set_error_stream(OutputStream s) + { + DbOutputStreamErrcall errcall = new DbOutputStreamErrcall(s); + set_errcall(errcall); + } + + // Error message prefix. + public void set_errpfx(String errpfx) + { + errpfx_ = errpfx; + _set_errpfx(errpfx); + } + + private native void _set_errpfx(String errpfx); + + // Feedback + public void set_feedback(DbFeedback feedback) + throws DbException + { + feedback_ = feedback; + feedback_changed(feedback); + } + + // (Internal) + private native void feedback_changed(DbFeedback feedback) + throws DbException; + + // Generate debugging messages. + public native void set_verbose(int which, int onoff) + throws DbException; + + public native void set_data_dir(String data_dir) + throws DbException; + + // Log buffer size. + public native void set_lg_bsize(/*u_int32_t*/ int lg_max) + throws DbException; + + // Log directory. + public native void set_lg_dir(String lg_dir) + throws DbException; + + // Maximum log file size. + public native void set_lg_max(/*u_int32_t*/ int lg_max) + throws DbException; + + // Two dimensional conflict matrix. + public native void set_lk_conflicts(byte[][] lk_conflicts) + throws DbException; + + // Deadlock detect on every conflict. + public native void set_lk_detect(/*u_int32_t*/ int lk_detect) + throws DbException; + + /** + * @deprecated DB 3.2.6, see the online documentation. + */ + // Maximum number of locks. + public native void set_lk_max(/*unsigned*/ int lk_max) + throws DbException; + + // Maximum number of lockers. + public native void set_lk_max_lockers(/*unsigned*/ int lk_max_lockers) + throws DbException; + + // Maximum number of locks. + public native void set_lk_max_locks(/*unsigned*/ int lk_max_locks) + throws DbException; + + // Maximum number of locked objects. + public native void set_lk_max_objects(/*unsigned*/ int lk_max_objects) + throws DbException; + + // Maximum file size for mmap. + public native void set_mp_mmapsize(/*size_t*/ long mmapsize) + throws DbException; + + public native void set_mutexlocks(int mutexlocks) + throws DbException; + + public native static void set_pageyield(int pageyield) + throws DbException; + + public native static void set_panicstate(int panicstate) + throws DbException; + + public void set_recovery_init(DbRecoveryInit recovery_init) + throws DbException + { + recovery_init_ = recovery_init; + recovery_init_changed(recovery_init); + } + + // (Internal) + private native void recovery_init_changed(DbRecoveryInit recovery_init) + throws DbException; + + public native static void set_region_init(int region_init) + throws DbException; + + public native void set_flags(int flags, int onoff) + throws DbException; + + public native void set_server(String host, long cl_timeout, + long sv_timeout, int flags) + throws DbException; + + public native void set_shm_key(long shm_key) + throws DbException; + + public native static void set_tas_spins(int tas_spins) + throws DbException; + + public native void set_tmp_dir(String tmp_dir) + throws DbException; + + // Feedback + public void set_tx_recover(DbTxnRecover tx_recover) + throws DbException + { + tx_recover_ = tx_recover; + tx_recover_changed(tx_recover); + } + + // (Internal) + private native void tx_recover_changed(DbTxnRecover tx_recover) + throws DbException; + + // Maximum number of transactions. + public native void set_tx_max(/*unsigned*/ int tx_max) + throws DbException; + + // Note: only the seconds (not milliseconds) of the timestamp + // are used in this API. + public void set_tx_timestamp(Date timestamp) + throws DbException + { + _set_tx_timestamp(timestamp.getTime()/1000); + } + + // (Internal) + private native void _set_tx_timestamp(long seconds) + throws DbException; + + // Versioning information + public native static int get_version_major(); + public native static int get_version_minor(); + public native static int get_version_patch(); + public native static String get_version_string(); + + // Convert DB error codes to strings + public native static String strerror(int errcode); + + public native int lock_detect(int flags, int atype) + throws DbException; + + public native DbLock lock_get(/*u_int32_t*/ int locker, + int flags, + Dbt obj, + /*db_lockmode_t*/ int lock_mode) + throws DbException; + + public native /*u_int32_t*/ int lock_id() + throws DbException; + + public native DbLockStat lock_stat() + throws DbException; + + public native String[] log_archive(int flags) + throws DbException; + + public native static int log_compare(DbLsn lsn0, DbLsn lsn1); + + public native String log_file(DbLsn lsn) + throws DbException; + + public native void log_flush(DbLsn lsn) + throws DbException; + + public native void log_get(DbLsn lsn, Dbt data, int flags) + throws DbException; + + public native void log_put(DbLsn lsn, Dbt data, int flags) + throws DbException; + + public native DbLogStat log_stat() + throws DbException; + + public native void log_register(Db dbp, String name) + throws DbException; + + public native void log_unregister(Db dbp) + throws DbException; + + public native DbMpoolStat memp_stat() + throws DbException; + + public native DbMpoolFStat[] memp_fstat() + throws DbException; + + public native int memp_trickle(int pct) + throws DbException; + + public native DbTxn txn_begin(DbTxn pid, int flags) + throws DbException; + + public native int txn_checkpoint(int kbyte, int min, int flags) + throws DbException; + + + public native DbTxnStat txn_stat() + throws DbException; + + //////////////////////////////////////////////////////////////// + // + // private data + // + private long private_dbobj_ = 0; + private long private_info_ = 0; + private int constructor_flags_ = 0; + private Vector dblist_ = new Vector(); // Db's that are open + private DbFeedback feedback_ = null; + private DbRecoveryInit recovery_init_ = null; + private DbTxnRecover tx_recover_ = null; + private DbOutputStreamErrcall errstream_ = + new DbOutputStreamErrcall(System.err); + /*package*/ DbErrcall errcall_ = errstream_; + /*package*/ String errpfx_; + + static { + Db.load_db(); + } + +} + +// end of DbEnv.java diff --git a/db/java/src/com/sleepycat/db/DbEnvFeedback.java b/db/java/src/com/sleepycat/db/DbEnvFeedback.java new file mode 100644 index 000000000..9eec2b819 --- /dev/null +++ b/db/java/src/com/sleepycat/db/DbEnvFeedback.java @@ -0,0 +1,19 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: DbEnvFeedback.java,v 11.3 2000/02/14 02:59:56 bostic Exp $ + */ + +package com.sleepycat.db; + +public interface DbEnvFeedback +{ + // methods + // + public abstract void feedback(DbEnv env, int opcode, int pct); +} + +// end of DbFeedback.java diff --git a/db/java/src/com/sleepycat/db/DbErrcall.java b/db/java/src/com/sleepycat/db/DbErrcall.java new file mode 100644 index 000000000..62d3a3e08 --- /dev/null +++ b/db/java/src/com/sleepycat/db/DbErrcall.java @@ -0,0 +1,23 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: DbErrcall.java,v 11.3 2000/02/14 02:59:56 bostic Exp $ + */ + +package com.sleepycat.db; + +/** + * + * @author Donald D. Anderson + */ +public interface DbErrcall +{ + // methods + // + public abstract void errcall(String prefix, String buffer); +} + +// end of DbErrcall.java diff --git a/db/java/src/com/sleepycat/db/DbException.java b/db/java/src/com/sleepycat/db/DbException.java new file mode 100644 index 000000000..ed4d020b6 --- /dev/null +++ b/db/java/src/com/sleepycat/db/DbException.java @@ -0,0 +1,56 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: DbException.java,v 11.4 2000/02/14 02:59:56 bostic Exp $ + */ + +package com.sleepycat.db; + +/** + * + * @author Donald D. Anderson + */ +public class DbException extends Exception +{ + // methods + // + + public DbException(String s) + { + super(s); + } + + public DbException(String s, int errno) + { + super(s); + this.errno_ = errno; + } + + public String toString() + { + String s = super.toString(); + if (errno_ == 0) + return s; + else + return s + ": " + DbEnv.strerror(errno_); + + } + + // get/set methods + // + + public int get_errno() + { + return errno_; + } + + // private data + // + + private int errno_ = 0; +} + +// end of DbException.java diff --git a/db/java/src/com/sleepycat/db/DbFeedback.java b/db/java/src/com/sleepycat/db/DbFeedback.java new file mode 100644 index 000000000..d932d951a --- /dev/null +++ b/db/java/src/com/sleepycat/db/DbFeedback.java @@ -0,0 +1,23 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: DbFeedback.java,v 11.4 2000/02/14 02:59:56 bostic Exp $ + */ + +package com.sleepycat.db; + +/** + * + * @author Donald D. Anderson + */ +public interface DbFeedback +{ + // methods + // + public abstract void feedback(Db db, int opcode, int pct); +} + +// end of DbFeedback.java diff --git a/db/java/src/com/sleepycat/db/DbHash.java b/db/java/src/com/sleepycat/db/DbHash.java new file mode 100644 index 000000000..a72c2070b --- /dev/null +++ b/db/java/src/com/sleepycat/db/DbHash.java @@ -0,0 +1,21 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: DbHash.java,v 11.1 2000/07/04 20:53:19 dda Exp $ + */ + +package com.sleepycat.db; + +/* + * This interface is used by DbEnv.set_bt_compare() + * + */ +public interface DbHash +{ + public abstract int hash(Db db, byte[] data, int len); +} + +// end of DbHash.java diff --git a/db/java/src/com/sleepycat/db/DbHashStat.java b/db/java/src/com/sleepycat/db/DbHashStat.java new file mode 100644 index 000000000..621543447 --- /dev/null +++ b/db/java/src/com/sleepycat/db/DbHashStat.java @@ -0,0 +1,37 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: DbHashStat.java,v 11.6 2000/05/04 02:54:55 dda Exp $ + */ + +package com.sleepycat.db; + +/* + * This is filled in and returned by the + * Db.stat() method. + */ +public class DbHashStat +{ + public int hash_magic; // Magic number. + public int hash_version; // Version number. + public int hash_metaflags; // Metadata flags. + public int hash_nkeys; // Number of unique keys. + public int hash_ndata; // Number of data items. + public int hash_pagesize; // Page size. + public int hash_nelem; // Original nelem specified. + public int hash_ffactor; // Fill factor specified at create. + public int hash_buckets; // Number of hash buckets. + public int hash_free; // Pages on the free list. + public int hash_bfree; // Bytes free on bucket pages. + public int hash_bigpages; // Number of big key/data pages. + public int hash_big_bfree; // Bytes free on big item pages. + public int hash_overflows; // Number of overflow pages. + public int hash_ovfl_free; // Bytes free on ovfl pages. + public int hash_dup; // Number of dup pages. + public int hash_dup_free; // Bytes free on duplicate pages. +} + +// end of DbHashStat.java diff --git a/db/java/src/com/sleepycat/db/DbKeyRange.java b/db/java/src/com/sleepycat/db/DbKeyRange.java new file mode 100644 index 000000000..6a86afd91 --- /dev/null +++ b/db/java/src/com/sleepycat/db/DbKeyRange.java @@ -0,0 +1,23 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: DbKeyRange.java,v 1.1 2000/04/12 15:07:02 dda Exp $ + */ + +package com.sleepycat.db; + +/** + * + * @author Donald D. Anderson + */ +public class DbKeyRange +{ + public double less; + public double equal; + public double greater; +} + +// end of DbKeyRange.java diff --git a/db/java/src/com/sleepycat/db/DbLock.java b/db/java/src/com/sleepycat/db/DbLock.java new file mode 100644 index 000000000..bc467913e --- /dev/null +++ b/db/java/src/com/sleepycat/db/DbLock.java @@ -0,0 +1,38 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: DbLock.java,v 11.4 2000/05/25 04:18:13 dda Exp $ + */ + +package com.sleepycat.db; + +/** + * + * @author Donald D. Anderson + */ +public class DbLock +{ + protected native void finalize() + throws Throwable; + + // methods + // + public native void put(DbEnv env) + throws DbException; + + // get/set methods + // + + // private data + // + private long private_dbobj_ = 0; + + static { + Db.load_db(); + } +} + +// end of DbLock.java diff --git a/db/java/src/com/sleepycat/db/DbLockStat.java b/db/java/src/com/sleepycat/db/DbLockStat.java new file mode 100644 index 000000000..f23f2ad5d --- /dev/null +++ b/db/java/src/com/sleepycat/db/DbLockStat.java @@ -0,0 +1,30 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: DbLockStat.java,v 11.3 2000/02/14 02:59:56 bostic Exp $ + */ + +package com.sleepycat.db; + +/* + * This is filled in and returned by the + * DbLockTab.stat() method. + */ +public class DbLockStat +{ + public int st_maxlocks; // Maximum number of locks in table. + public int st_nmodes; // Number of lock modes. + public int st_nlockers; // Number of lockers. + public int st_nconflicts; // Number of lock conflicts. + public int st_nrequests; // Number of lock gets. + public int st_nreleases; // Number of lock puts. + public int st_ndeadlocks; // Number of lock deadlocks. + public int st_region_wait; // Region lock granted after wait. + public int st_region_nowait; // Region lock granted without wait. + public int st_regsize; // Region size. +} + +// end of DbLockStat.java diff --git a/db/java/src/com/sleepycat/db/DbLogStat.java b/db/java/src/com/sleepycat/db/DbLogStat.java new file mode 100644 index 000000000..d708f1c41 --- /dev/null +++ b/db/java/src/com/sleepycat/db/DbLogStat.java @@ -0,0 +1,35 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: DbLogStat.java,v 11.3 2000/02/14 02:59:56 bostic Exp $ + */ + +package com.sleepycat.db; + +/* + * This is filled in and returned by the + * DbLog.stat() method. + */ +public class DbLogStat +{ + public int st_magic; // Log file magic number. + public int st_version; // Log file version number. + public int st_mode; // Log file mode. + public int st_lg_max; // Maximum log file size. + public int st_w_bytes; // Bytes to log. + public int st_w_mbytes; // Megabytes to log. + public int st_wc_bytes; // Bytes to log since checkpoint. + public int st_wc_mbytes; // Megabytes to log since checkpoint. + public int st_wcount; // Total syncs to the log. + public int st_scount; // Total writes to the log. + public int st_region_wait; // Region lock granted after wait. + public int st_region_nowait; // Region lock granted without wait. + public int st_cur_file; // Current log file number. + public int st_cur_offset; // Current log file offset. + public int st_regsize; // Region size. +} + +// end of DbLogStat.java diff --git a/db/java/src/com/sleepycat/db/DbLsn.java b/db/java/src/com/sleepycat/db/DbLsn.java new file mode 100644 index 000000000..ff36ac61c --- /dev/null +++ b/db/java/src/com/sleepycat/db/DbLsn.java @@ -0,0 +1,42 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: DbLsn.java,v 11.5 2000/09/11 16:21:37 dda Exp $ + */ + +package com.sleepycat.db; + +/** + * + * @author Donald D. Anderson + */ +public class DbLsn +{ + // methods + // + public DbLsn() + { + init_lsn(); + } + + protected native void finalize() + throws Throwable; + + private native void init_lsn(); + + // get/set methods + // + + // private data + // + private long private_dbobj_ = 0; + + static { + Db.load_db(); + } +} + +// end of DbLsn.java diff --git a/db/java/src/com/sleepycat/db/DbMemoryException.java b/db/java/src/com/sleepycat/db/DbMemoryException.java new file mode 100644 index 000000000..67a29a1f1 --- /dev/null +++ b/db/java/src/com/sleepycat/db/DbMemoryException.java @@ -0,0 +1,28 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: DbMemoryException.java,v 11.3 2000/02/14 02:59:56 bostic Exp $ + */ + +package com.sleepycat.db; + +public class DbMemoryException extends DbException +{ + // methods + // + + public DbMemoryException(String s) + { + super(s); + } + + public DbMemoryException(String s, int errno) + { + super(s, errno); + } +} + +// end of DbMemoryException.java diff --git a/db/java/src/com/sleepycat/db/DbMpoolFStat.java b/db/java/src/com/sleepycat/db/DbMpoolFStat.java new file mode 100644 index 000000000..44497b3bf --- /dev/null +++ b/db/java/src/com/sleepycat/db/DbMpoolFStat.java @@ -0,0 +1,28 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: DbMpoolFStat.java,v 11.3 2000/02/14 02:59:56 bostic Exp $ + */ + +package com.sleepycat.db; + +/* + * This is filled in and returned by the + * DbMpool.fstat() method. + */ +public class DbMpoolFStat +{ + public String file_name; // File name. + public int st_pagesize; // Page size. + public int st_cache_hit; // Pages found in the cache. + public int st_cache_miss; // Pages not found in the cache. + public int st_map; // Pages from mapped files. + public int st_page_create; // Pages created in the cache. + public int st_page_in; // Pages read in. + public int st_page_out; // Pages written out. +} + +// end of DbMpoolFStat.java diff --git a/db/java/src/com/sleepycat/db/DbMpoolStat.java b/db/java/src/com/sleepycat/db/DbMpoolStat.java new file mode 100644 index 000000000..8a6d75e36 --- /dev/null +++ b/db/java/src/com/sleepycat/db/DbMpoolStat.java @@ -0,0 +1,42 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: DbMpoolStat.java,v 11.3 2000/02/14 02:59:56 bostic Exp $ + */ + +package com.sleepycat.db; + +/* + * This is filled in and returned by the + * DbMpool.stat() method. + */ +public class DbMpoolStat +{ + /** + * @deprecated As of Berkeley DB 2.8.2, cachesize for mpool unavailable. + */ + public int st_cachesize; // Cache size. + public int st_cache_hit; // Pages found in the cache. + public int st_cache_miss; // Pages not found in the cache. + public int st_map; // Pages from mapped files. + public int st_page_create; // Pages created in the cache. + public int st_page_in; // Pages read in. + public int st_page_out; // Pages written out. + public int st_ro_evict; // Clean pages forced from the cache. + public int st_rw_evict; // Dirty pages forced from the cache. + public int st_hash_buckets; // Number of hash buckets. + public int st_hash_searches; // Total hash chain searches. + public int st_hash_longest; // Longest hash chain searched. + public int st_hash_examined; // Total hash entries searched. + public int st_page_clean; // Clean pages. + public int st_page_dirty; // Dirty pages. + public int st_page_trickle; // Pages written by memp_trickle. + public int st_region_wait; // Region lock granted after wait. + public int st_region_nowait; // Region lock granted without wait. + public int st_regsize; // Region size. +} + +// end of DbMpoolStat.java diff --git a/db/java/src/com/sleepycat/db/DbOutputStreamErrcall.java b/db/java/src/com/sleepycat/db/DbOutputStreamErrcall.java new file mode 100644 index 000000000..4f962d9a3 --- /dev/null +++ b/db/java/src/com/sleepycat/db/DbOutputStreamErrcall.java @@ -0,0 +1,58 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: DbOutputStreamErrcall.java,v 11.3 2000/02/14 02:59:56 bostic Exp $ + */ + +package com.sleepycat.db; +import java.io.OutputStream; +import java.io.IOException; + +/** + * + * @author Donald D. Anderson + * + * This class is not public, as it is only used internally + * by Db to implement a default error handler. + */ + +/*package*/ class DbOutputStreamErrcall implements DbErrcall +{ + DbOutputStreamErrcall(OutputStream stream) + { + this.stream_ = stream; + } + + // errcall implements DbErrcall + // + public void errcall(String prefix, String buffer) + { + try { + if (prefix != null) { + stream_.write(prefix.getBytes()); + stream_.write((new String(": ")).getBytes()); + } + stream_.write(buffer.getBytes()); + stream_.write((new String("\n")).getBytes()); + } + catch (IOException e) { + + // well, we tried. + // Do our best to report the problem by other means. + // + System.err.println("DbOutputStreamErrcall Exception: " + e); + if (prefix != null) + System.err.print(prefix + ": "); + System.err.println(buffer + "\n"); + } + } + + // private data + // + private OutputStream stream_; +} + +// end of DbOutputStreamErrcall.java diff --git a/db/java/src/com/sleepycat/db/DbQueueStat.java b/db/java/src/com/sleepycat/db/DbQueueStat.java new file mode 100644 index 000000000..652878b1a --- /dev/null +++ b/db/java/src/com/sleepycat/db/DbQueueStat.java @@ -0,0 +1,32 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: DbQueueStat.java,v 11.5 2000/11/07 18:45:27 dda Exp $ + */ + +package com.sleepycat.db; + +/* + * This is filled in and returned by the + * Db.stat() method. + */ +public class DbQueueStat +{ + public int qs_magic; // Magic number. + public int qs_version; // Version number. + public int qs_metaflags; // Metadata flags. + public int qs_nkeys; // Number of unique keys. + public int qs_ndata; // Number of data items. + public int qs_pagesize; // Page size. + public int qs_pages; // Data pages. + public int qs_re_len; // Fixed-length record length. + public int qs_re_pad; // Fixed-length record pad. + public int qs_pgfree; // Bytes free in data pages. + public int qs_first_recno; // First not deleted record. + public int qs_cur_recno; // Last allocated record number. +} + +// end of DbQueueStat.java diff --git a/db/java/src/com/sleepycat/db/DbRecoveryInit.java b/db/java/src/com/sleepycat/db/DbRecoveryInit.java new file mode 100644 index 000000000..b32eebcaa --- /dev/null +++ b/db/java/src/com/sleepycat/db/DbRecoveryInit.java @@ -0,0 +1,23 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: DbRecoveryInit.java,v 11.3 2000/02/14 02:59:56 bostic Exp $ + */ + +package com.sleepycat.db; + +/** + * + * @author Donald D. Anderson + */ +public interface DbRecoveryInit +{ + // methods + // + public abstract void recovery_init(DbEnv dbenv); +} + +// end of DbRecoveryInit.java diff --git a/db/java/src/com/sleepycat/db/DbRunRecoveryException.java b/db/java/src/com/sleepycat/db/DbRunRecoveryException.java new file mode 100644 index 000000000..78736b6ed --- /dev/null +++ b/db/java/src/com/sleepycat/db/DbRunRecoveryException.java @@ -0,0 +1,32 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: DbRunRecoveryException.java,v 11.3 2000/02/14 02:59:56 bostic Exp $ + */ + +package com.sleepycat.db; + +/** + * + * @author Donald D. Anderson + */ +public class DbRunRecoveryException extends DbException +{ + // methods + // + + public DbRunRecoveryException(String s) + { + super(s); + } + + public DbRunRecoveryException(String s, int errno) + { + super(s, errno); + } +} + +// end of DbRunRecoveryException.java diff --git a/db/java/src/com/sleepycat/db/DbTxn.java b/db/java/src/com/sleepycat/db/DbTxn.java new file mode 100644 index 000000000..201ff94c8 --- /dev/null +++ b/db/java/src/com/sleepycat/db/DbTxn.java @@ -0,0 +1,47 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: DbTxn.java,v 11.5 2000/05/25 04:18:13 dda Exp $ + */ + +package com.sleepycat.db; + +/** + * + * @author Donald D. Anderson + */ +public class DbTxn +{ + // methods + // + public native void abort() + throws DbException; + + public native void commit(int flags) + throws DbException; + + public native /*u_int32_t*/ int id() + throws DbException; + + public native void prepare() + throws DbException; + + protected native void finalize() + throws Throwable; + + // get/set methods + // + + // private data + // + private long private_dbobj_ = 0; + + static { + Db.load_db(); + } +} + +// end of DbTxn.java diff --git a/db/java/src/com/sleepycat/db/DbTxnRecover.java b/db/java/src/com/sleepycat/db/DbTxnRecover.java new file mode 100644 index 000000000..ee4793594 --- /dev/null +++ b/db/java/src/com/sleepycat/db/DbTxnRecover.java @@ -0,0 +1,22 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: DbTxnRecover.java,v 11.1 2000/06/29 18:08:17 dda Exp $ + */ + +package com.sleepycat.db; + +/* + * This interface is used by DbEnv.set_tx_recover() + * + */ +public interface DbTxnRecover +{ + // The value of recops is one of the Db.DB_TXN_* constants + public abstract int tx_recover(DbEnv env, Dbt dbt, DbLsn lsn, int recops); +} + +// end of DbBtreeCompare.java diff --git a/db/java/src/com/sleepycat/db/DbTxnStat.java b/db/java/src/com/sleepycat/db/DbTxnStat.java new file mode 100644 index 000000000..e72addb00 --- /dev/null +++ b/db/java/src/com/sleepycat/db/DbTxnStat.java @@ -0,0 +1,40 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: DbTxnStat.java,v 11.3 2000/02/14 02:59:56 bostic Exp $ + */ + +package com.sleepycat.db; + +/* + * This is filled in and returned by the + * DbTxnMgr.fstat() method. + */ +public class DbTxnStat +{ + public static class Active { + public int txnid; // Transaction ID + public int parentid; // Transaction ID of parent + public DbLsn lsn; // Lsn of the begin record + }; + + public DbLsn st_last_ckp; // lsn of the last checkpoint + public DbLsn st_pending_ckp; // last checkpoint did not finish + public long st_time_ckp; // time of last checkpoint (UNIX secs) + public int st_last_txnid; // last transaction id given out + public int st_maxtxns; // maximum number of active txns + public int st_naborts; // number of aborted transactions + public int st_nbegins; // number of begun transactions + public int st_ncommits; // number of committed transactions + public int st_nactive; // number of active transactions + public int st_maxnactive; // maximum active transactions + public Active st_txnarray[]; // array of active transactions + public int st_region_wait; // Region lock granted after wait. + public int st_region_nowait; // Region lock granted without wait. + public int st_regsize; // Region size. +} + +// end of DbTxnStat.java diff --git a/db/java/src/com/sleepycat/db/Dbc.java b/db/java/src/com/sleepycat/db/Dbc.java new file mode 100644 index 000000000..b097cbad8 --- /dev/null +++ b/db/java/src/com/sleepycat/db/Dbc.java @@ -0,0 +1,56 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: Dbc.java,v 11.5 2000/05/25 04:18:13 dda Exp $ + */ + +package com.sleepycat.db; + +/** + * + * @author Donald D. Anderson + */ +public class Dbc +{ + // methods + // + public native void close() + throws DbException; + + public native int count(int flags) + throws DbException; + + // returns: 0, DB_KEYEMPTY, or throws error + public native int del(int flags) + throws DbException; + + public native Dbc dup(int flags) + throws DbException; + + // returns: 0, DB_NOTFOUND, or throws error + public native int get(Dbt key, Dbt data, int flags) + throws DbException; + + // returns: 0, DB_KEYEXIST, or throws error + public native int put(Dbt key, Dbt data, int flags) + throws DbException; + + protected native void finalize() + throws Throwable; + + // get/set methods + // + + // private data + // + private long private_dbobj_ = 0; + + static { + Db.load_db(); + } +} + +// end of Dbc.java diff --git a/db/java/src/com/sleepycat/db/Dbt.java b/db/java/src/com/sleepycat/db/Dbt.java new file mode 100644 index 000000000..bbb478cd5 --- /dev/null +++ b/db/java/src/com/sleepycat/db/Dbt.java @@ -0,0 +1,110 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: Dbt.java,v 11.6 2000/06/16 03:34:01 dda Exp $ + */ + +package com.sleepycat.db; + +/** + * + * @author Donald D. Anderson + */ +public class Dbt +{ + // methods + // + + protected native void finalize() + throws Throwable; + + // get/set methods + // + + // key/data + + public void set_data(byte[] data) + { + // internal_set_data is separated from set_data in case + // we want to have set_data automatically set some other + // fields (size, etc.) someday. + // + internal_set_data(data); + } + + public native byte[] get_data(); + private native void internal_set_data(byte[] data); + + // These are not in the original DB interface, + // but they can be used to get/set the offset + // into the attached byte array. + // + public native void set_offset(int off); + public native int get_offset(); + + // key/data length + public native /*u_int32_t*/ int get_size(); + public native void set_size(/*u_int32_t*/ int size); + + // RO: length of user buffer. + public native /*u_int32_t*/ int get_ulen(); + public native void set_ulen(/*u_int32_t*/ int ulen); + + // RO: get/put record length. + public native /*u_int32_t*/ int get_dlen(); + public native void set_dlen(/*u_int32_t*/ int dlen); + + // RO: get/put record offset. + public native /*u_int32_t*/ int get_doff(); + public native void set_doff(/*u_int32_t*/ int doff); + + // flags + public native /*u_int32_t*/ int get_flags(); + public native void set_flags(/*u_int32_t*/ int flags); + + // These are not in the original DB interface. + // They can be used to set the recno key for a Dbt. + // Note: you must set the data field to an array of + // at least four bytes before calling either of these. + // + public native void set_recno_key_data(int recno); + public native int get_recno_key_data(); + + public Dbt(byte[] data) + { + init(); + internal_set_data(data); + if (data != null) + set_size(data.length); + } + + public Dbt(byte[] data, int off, int len) + { + this(data); + set_ulen(len); + set_offset(off); + } + + public Dbt() + { + init(); + } + + // private methods + // + private native void init(); + + // private data + // + private long private_dbobj_ = 0; + + static { + Db.load_db(); + } +} + + +// end of Dbt.java diff --git a/db/java/src/com/sleepycat/examples/AccessExample.java b/db/java/src/com/sleepycat/examples/AccessExample.java new file mode 100644 index 000000000..f3a98c2c7 --- /dev/null +++ b/db/java/src/com/sleepycat/examples/AccessExample.java @@ -0,0 +1,186 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: AccessExample.java,v 11.5 2000/12/13 07:09:42 krinsky Exp $ + */ + +package com.sleepycat.examples; + +import com.sleepycat.db.*; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.InputStreamReader; +import java.io.IOException; +import java.io.PrintStream; + +class AccessExample +{ + private static final String FileName = "access.db"; + + public AccessExample() + { + } + + private static void usage() + { + System.err.println("usage: AccessExample\n"); + System.exit(1); + } + + public static void main(String argv[]) + { + try + { + AccessExample app = new AccessExample(); + app.run(); + } + catch (DbException dbe) + { + System.err.println("AccessExample: " + dbe.toString()); + System.exit(1); + } + catch (FileNotFoundException fnfe) + { + System.err.println("AccessExample: " + fnfe.toString()); + System.exit(1); + } + System.exit(0); + } + + // Prompts for a line, and keeps prompting until a non blank + // line is returned. Returns null on error. + // + static public String askForLine(InputStreamReader reader, + PrintStream out, String prompt) + { + String result = ""; + while (result != null && result.length() == 0) { + out.print(prompt); + out.flush(); + result = getLine(reader); + } + return result; + } + + // Not terribly efficient, but does the job. + // Works for reading a line from stdin or a file. + // Returns null on EOF. If EOF appears in the middle + // of a line, returns that line, then null on next call. + // + static public String getLine(InputStreamReader reader) + { + StringBuffer b = new StringBuffer(); + int c; + try { + while ((c = reader.read()) != -1 && c != '\n') { + if (c != '\r') + b.append((char)c); + } + } + catch (IOException ioe) { + c = -1; + } + + if (c == -1 && b.length() == 0) + return null; + else + return b.toString(); + } + + public void run() + throws DbException, FileNotFoundException + { + // Remove the previous database. + new File(FileName).delete(); + + // Create the database object. + // There is no environment for this simple example. + Db table = new Db(null, 0); + table.set_error_stream(System.err); + table.set_errpfx("AccessExample"); + table.open(FileName, null, Db.DB_BTREE, Db.DB_CREATE, 0644); + + // + // Insert records into the database, where the key is the user + // input and the data is the user input in reverse order. + // + InputStreamReader reader = new InputStreamReader(System.in); + + for (;;) { + String line = askForLine(reader, System.out, "input> "); + if (line == null) + break; + + String reversed = (new StringBuffer(line)).reverse().toString(); + + // See definition of StringDbt below + // + StringDbt key = new StringDbt(line); + StringDbt data = new StringDbt(reversed); + + try + { + int err; + if ((err = table.put(null, + key, data, Db.DB_NOOVERWRITE)) == Db.DB_KEYEXIST) { + System.out.println("Key " + line + " already exists."); + } + } + catch (DbException dbe) + { + System.out.println(dbe.toString()); + } + System.out.println(""); + } + + // Acquire an iterator for the table. + Dbc iterator; + iterator = table.cursor(null, 0); + + // Walk through the table, printing the key/data pairs. + // See class StringDbt defined below. + // + StringDbt key = new StringDbt(); + StringDbt data = new StringDbt(); + while (iterator.get(key, data, Db.DB_NEXT) == 0) + { + System.out.println(key.getString() + " : " + data.getString()); + } + iterator.close(); + table.close(0); + } + + // Here's an example of how you can extend a Dbt in a straightforward + // way to allow easy storage/retrieval of strings, or whatever + // kind of data you wish. We've declared it as a static inner + // class, but it need not be. + // + static /*inner*/ + class StringDbt extends Dbt + { + StringDbt() + { + set_flags(Db.DB_DBT_MALLOC); // tell Db to allocate on retrieval + } + + StringDbt(String value) + { + setString(value); + set_flags(Db.DB_DBT_MALLOC); // tell Db to allocate on retrieval + } + + void setString(String value) + { + set_data(value.getBytes()); + set_size(value.length()); + } + + String getString() + { + return new String(get_data(), 0, get_size()); + } + } +} diff --git a/db/java/src/com/sleepycat/examples/BtRecExample.java b/db/java/src/com/sleepycat/examples/BtRecExample.java new file mode 100644 index 000000000..5101f676a --- /dev/null +++ b/db/java/src/com/sleepycat/examples/BtRecExample.java @@ -0,0 +1,348 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: BtRecExample.java,v 11.6 2000/02/19 20:58:02 bostic Exp $ + */ + +package com.sleepycat.examples; + +import com.sleepycat.db.*; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.InputStreamReader; +import java.io.IOException; +import java.io.PrintStream; + +public class BtRecExample +{ + static final String progname = "BtRecExample"; // Program name. + static final String database = "access.db"; + static final String wordlist = "../test/wordlist"; + + BtRecExample(BufferedReader reader) + throws DbException, IOException, FileNotFoundException + { + int ret; + + // Remove the previous database. + File f = new File(database); + f.delete(); + + dbp = new Db(null, 0); + + dbp.set_error_stream(System.err); + dbp.set_errpfx(progname); + dbp.set_pagesize(1024); // 1K page sizes. + + dbp.set_flags(Db.DB_RECNUM); // Record numbers. + dbp.open(database, null, Db.DB_BTREE, Db.DB_CREATE, 0664); + + // + // Insert records into the database, where the key is the word + // preceded by its record number, and the data is the same, but + // in reverse order. + // + + for (int cnt = 1; cnt <= 1000; ++cnt) { + String numstr = String.valueOf(cnt); + while (numstr.length() < 4) + numstr = "0" + numstr; + String buf = numstr + '_' + reader.readLine(); + StringBuffer rbuf = new StringBuffer(buf).reverse(); + + StringDbt key = new StringDbt(buf); + StringDbt data = new StringDbt(rbuf.toString()); + + if ((ret = dbp.put(null, key, data, Db.DB_NOOVERWRITE)) != 0) { + if (ret != Db.DB_KEYEXIST) + throw new DbException("Db.put failed" + ret); + } + } + } + + void run() + throws DbException + { + int recno; + int ret; + + // Acquire a cursor for the database. + dbcp = dbp.cursor(null, 0); + + // + // Prompt the user for a record number, then retrieve and display + // that record. + // + InputStreamReader reader = new InputStreamReader(System.in); + + for (;;) { + // Get a record number. + String line = askForLine(reader, System.out, "recno #> "); + if (line == null) + break; + + try { + recno = Integer.parseInt(line); + } + catch (NumberFormatException nfe) { + System.err.println("Bad record number: " + nfe); + continue; + } + + // + // Start with a fresh key each time, the dbp.get() routine returns + // the key and data pair, not just the key! + // + RecnoStringDbt key = new RecnoStringDbt(recno, 100); + RecnoStringDbt data = new RecnoStringDbt(100); + + if ((ret = dbcp.get(key, data, Db.DB_SET_RECNO)) != 0) { + throw new DbException("Dbc.get failed", ret); + } + + // Display the key and data. + show("k/d\t", key, data); + + // Move the cursor a record forward. + if ((ret = dbcp.get(key, data, Db.DB_NEXT)) != 0) { + throw new DbException("Dbc.get failed", ret); + } + + // Display the key and data. + show("next\t", key, data); + + RecnoStringDbt datano = new RecnoStringDbt(100); + + // + // Retrieve the record number for the following record into + // local memory. + // + if ((ret = dbcp.get(key, datano, Db.DB_GET_RECNO)) != 0) { + if (ret != Db.DB_NOTFOUND && ret != Db.DB_KEYEMPTY) { + throw new DbException("Dbc.get failed", ret); + } + } + else { + recno = datano.getRecno(); + System.out.println("retrieved recno: " + recno); + } + } + + dbcp.close(); + dbcp = null; + } + + // + // Print out the number of records in the database. + // + void stats() + throws DbException + { + DbBtreeStat statp; + + statp = (DbBtreeStat)dbp.stat(0); + System.out.println(progname + ": database contains " + + statp.bt_ndata + " records"); + } + + void show(String msg, RecnoStringDbt key, RecnoStringDbt data) + throws DbException + { + System.out.println(msg + key.getString() + ": " + data.getString()); + } + + public void shutdown() + throws DbException + { + if (dbcp != null) { + dbcp.close(); + dbcp = null; + } + if (dbp != null) { + dbp.close(0); + dbp = null; + } + } + + public static void main(String argv[]) + { + + try { + // Open the word database. + FileReader freader = new FileReader(wordlist); + + BtRecExample app = new BtRecExample(new BufferedReader(freader)); + + // Close the word database. + freader.close(); + freader = null; + + app.stats(); + app.run(); + } + catch (FileNotFoundException fnfe) { + System.err.println(progname + ": unexpected open error " + fnfe); + System.exit (1); + } + catch (IOException ioe) { + System.err.println(progname + ": open " + wordlist + ": " + ioe); + System.exit (1); + } + catch (DbException dbe) { + System.err.println("Exception: " + dbe); + System.exit(dbe.get_errno()); + } + + System.exit(0); + } + + void + usage() + { + System.err.println("usage: " + progname); + System.exit(1); + } + + // Prompts for a line, and keeps prompting until a non blank + // line is returned. Returns null on error. + // + static public String askForLine(InputStreamReader reader, + PrintStream out, String prompt) + { + String result = ""; + while (result != null && result.length() == 0) { + out.print(prompt); + out.flush(); + result = getLine(reader); + } + return result; + } + + // Not terribly efficient, but does the job. + // Works for reading a line from stdin or a file. + // Returns null on EOF. If EOF appears in the middle + // of a line, returns that line, then null on next call. + // + static public String getLine(InputStreamReader reader) + { + StringBuffer b = new StringBuffer(); + int c; + try { + while ((c = reader.read()) != -1 && c != '\n') { + if (c != '\r') + b.append((char)c); + } + } + catch (IOException ioe) { + c = -1; + } + + if (c == -1 && b.length() == 0) + return null; + else + return b.toString(); + } + + private Dbc dbcp; + private Db dbp; + + // Here's an example of how you can extend a Dbt in a straightforward + // way to allow easy storage/retrieval of strings. + // We've declared it as a static inner class, but it need not be. + // + static /*inner*/ + class StringDbt extends Dbt + { + StringDbt(byte[] arr) + { + set_flags(Db.DB_DBT_USERMEM); + set_data(arr); + set_size(arr.length); + } + + StringDbt() + { + set_flags(Db.DB_DBT_MALLOC); // tell Db to allocate on retrieval + } + + StringDbt(String value) + { + setString(value); + set_flags(Db.DB_DBT_MALLOC); // tell Db to allocate on retrieval + } + + void setString(String value) + { + set_data(value.getBytes()); + set_size(value.length()); + // must set ulen because sometimes a string is returned + set_ulen(value.length()); + } + + String getString() + { + return new String(get_data(), 0, get_size()); + } + } + + // Here's an example of how you can extend a Dbt to store + // (potentially) both recno's and strings in the same + // structure. + // + static /*inner*/ + class RecnoStringDbt extends Dbt + { + RecnoStringDbt(int maxsize) + { + this(0, maxsize); // let other constructor do most of the work + } + + RecnoStringDbt(int value, int maxsize) + { + set_flags(Db.DB_DBT_USERMEM); // do not allocate on retrieval + arr = new byte[maxsize]; + set_data(arr); // use our local array for data + set_ulen(maxsize); // size of return storage + setRecno(value); + } + + RecnoStringDbt(String value, int maxsize) + { + set_flags(Db.DB_DBT_USERMEM); // do not allocate on retrieval + arr = new byte[maxsize]; + set_data(arr); // use our local array for data + set_ulen(maxsize); // size of return storage + setString(value); + } + + void setRecno(int value) + { + set_recno_key_data(value); + set_size(arr.length); + } + + void setString(String value) + { + set_data(value.getBytes()); + set_size(value.length()); + } + + int getRecno() + { + return get_recno_key_data(); + } + + String getString() + { + return new String(get_data(), 0, get_size()); + } + + byte arr[]; + } +} diff --git a/db/java/src/com/sleepycat/examples/EnvExample.java b/db/java/src/com/sleepycat/examples/EnvExample.java new file mode 100644 index 000000000..f1b855836 --- /dev/null +++ b/db/java/src/com/sleepycat/examples/EnvExample.java @@ -0,0 +1,128 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: EnvExample.java,v 11.7 2000/09/25 13:16:51 dda Exp $ + */ + +package com.sleepycat.examples; + +import com.sleepycat.db.*; +import java.io.FileNotFoundException; +import java.io.OutputStream; + +/* + * An example of a program using DbEnv to configure its DB + * environment. + * + * For comparison purposes, this example uses a similar structure + * as examples/ex_env.c and examples_cxx/EnvExample.cpp. + */ +public class EnvExample +{ + private static final String progname = "EnvExample"; + private static final String DATABASE_HOME = "/tmp/database"; + + private static void db_application() + throws DbException + { + // Do something interesting... + // Your application goes here. + } + + private static void db_setup(String home, String data_dir, + OutputStream errs) + throws DbException, FileNotFoundException + { + // + // Create an environment object and initialize it for error + // reporting. + // + DbEnv dbenv = new DbEnv(0); + dbenv.set_error_stream(errs); + dbenv.set_errpfx(progname); + + // + // We want to specify the shared memory buffer pool cachesize, + // but everything else is the default. + // + dbenv.set_cachesize(0, 64 * 1024, 0); + + // Databases are in a subdirectory. + dbenv.set_data_dir(data_dir); + + // Open the environment with full transactional support. + // + // open() will throw a DbException if there is an error. + // + // open is declared to throw a FileNotFoundException, which normally + // shouldn't occur with the DB_CREATE option. + // + dbenv.open(DATABASE_HOME, + Db.DB_CREATE | Db.DB_INIT_LOCK | Db.DB_INIT_LOG | + Db.DB_INIT_MPOOL | Db.DB_INIT_TXN, 0); + + try { + + // Start your application. + db_application(); + + } + finally { + + // Close the environment. Doing this in the + // finally block ensures it is done, even if + // an error is thrown. + // + dbenv.close(0); + } + } + + private static void db_teardown(String home, String data_dir, + OutputStream errs) + throws DbException, FileNotFoundException + { + // Remove the shared database regions. + + DbEnv dbenv = new DbEnv(0); + + dbenv.set_error_stream(errs); + dbenv.set_errpfx(progname); + dbenv.set_data_dir(data_dir); + dbenv.remove(home, 0); + } + + public static void main(String[] args) + { + // + // All of the shared database files live in /tmp/database, + // but data files live in /database. + // + // Using Berkeley DB in C/C++, we need to allocate two elements + // in the array and set config[1] to NULL. This is not + // necessary in Java. + // + String home = DATABASE_HOME; + String config = "/database/files"; + + try { + System.out.println("Setup env"); + db_setup(home, config, System.err); + + System.out.println("Teardown env"); + db_teardown(home, config, System.err); + } + catch (DbException dbe) { + System.err.println(progname + ": environment open: " + dbe.toString()); + System.exit (1); + } + catch (FileNotFoundException fnfe) { + System.err.println(progname + + ": unexpected open environment error " + fnfe); + System.exit (1); + } + } + +} diff --git a/db/java/src/com/sleepycat/examples/LockExample.java b/db/java/src/com/sleepycat/examples/LockExample.java new file mode 100644 index 000000000..33b7d0538 --- /dev/null +++ b/db/java/src/com/sleepycat/examples/LockExample.java @@ -0,0 +1,235 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: LockExample.java,v 11.5 2001/01/04 14:23:30 dda Exp $ + */ + +package com.sleepycat.examples; + +import com.sleepycat.db.*; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.IOException; +import java.io.PrintStream; +import java.util.Vector; + +// +// An example of a program using DbLock and related classes. +// +class LockExample extends DbEnv +{ + private static final String progname = "LockExample"; + private static final String LOCK_HOME = "TESTDIR"; + + public LockExample(String home, int maxlocks, boolean do_unlink) + throws DbException, FileNotFoundException + { + super(0); + if (do_unlink) { + remove(home, Db.DB_FORCE); + } + else { + set_error_stream(System.err); + set_errpfx("LockExample"); + if (maxlocks != 0) + set_lk_max_locks(maxlocks); + open(home, Db.DB_CREATE|Db.DB_INIT_LOCK, 0); + } + } + + // Prompts for a line, and keeps prompting until a non blank + // line is returned. Returns null on error. + // + static public String askForLine(InputStreamReader reader, + PrintStream out, String prompt) + { + String result = ""; + while (result != null && result.length() == 0) { + out.print(prompt); + out.flush(); + result = getLine(reader); + } + return result; + } + + // Not terribly efficient, but does the job. + // Works for reading a line from stdin or a file. + // Returns null on EOF. If EOF appears in the middle + // of a line, returns that line, then null on next call. + // + static public String getLine(InputStreamReader reader) + { + StringBuffer b = new StringBuffer(); + int c; + try { + while ((c = reader.read()) != -1 && c != '\n') { + if (c != '\r') + b.append((char)c); + } + } + catch (IOException ioe) { + c = -1; + } + + if (c == -1 && b.length() == 0) + return null; + else + return b.toString(); + } + + public void run() + throws DbException + { + long held; + int len = 0, locker; + int ret; + boolean did_get = false; + int lockid = 0; + InputStreamReader in = new InputStreamReader(System.in); + Vector locks = new Vector(); + + // + // Accept lock requests. + // + locker = lock_id(); + for (held = 0;;) { + String opbuf = askForLine(in, System.out, + "Operation get/release [get]> "); + if (opbuf == null) + break; + + try { + if (opbuf.equals("get")) { + // Acquire a lock. + String objbuf = askForLine(in, System.out, + "input object (text string) to lock> "); + if (objbuf == null) + break; + + String lockbuf; + do { + lockbuf = askForLine(in, System.out, + "lock type read/write [read]> "); + if (lockbuf == null) + break; + len = lockbuf.length(); + } while (len >= 1 && + !lockbuf.equals("read") && + !lockbuf.equals("write")); + + int lock_type; + if (len <= 1 || lockbuf.equals("read")) + lock_type = Db.DB_LOCK_READ; + else + lock_type = Db.DB_LOCK_WRITE; + + Dbt dbt = new Dbt(objbuf.getBytes()); + + DbLock lock; + did_get = true; + lock = lock_get(locker, Db.DB_LOCK_NOWAIT, + dbt, lock_type); + lockid = locks.size(); + locks.addElement(lock); + } else { + // Release a lock. + String objbuf; + objbuf = askForLine(in, System.out, + "input lock to release> "); + if (objbuf == null) + break; + + lockid = Integer.parseInt(objbuf, 16); + if (lockid < 0 || lockid >= locks.size()) { + System.out.println("Lock #" + lockid + " out of range"); + continue; + } + did_get = false; + DbLock lock = (DbLock)locks.elementAt(lockid); + lock.put(this); + } + System.out.println("Lock #" + lockid + " " + + (did_get ? "granted" : "released")); + held += did_get ? 1 : -1; + } + catch (DbException dbe) { + switch (dbe.get_errno()) { + case Db.DB_LOCK_NOTGRANTED: + System.out.println("Lock not granted"); + break; + case Db.DB_LOCK_DEADLOCK: + System.err.println("LockExample: lock_" + + (did_get ? "get" : "put") + + ": returned DEADLOCK"); + break; + default: + System.err.println("LockExample: lock_get: " + dbe.toString()); + } + } + } + System.out.println(); + System.out.println("Closing lock region " + String.valueOf(held) + + " locks held"); + } + + private static void usage() + { + System.err.println("usage: LockExample [-u] [-h home] [-m maxlocks]"); + System.exit(1); + } + + public static void main(String argv[]) + { + String home = LOCK_HOME; + boolean do_unlink = false; + int maxlocks = 0; + + for (int i = 0; i < argv.length; ++i) { + if (argv[i].equals("-h")) { + if (++i >= argv.length) + usage(); + home = argv[i]; + } + else if (argv[i].equals("-m")) { + if (++i >= argv.length) + usage(); + + try { + maxlocks = Integer.parseInt(argv[i]); + } + catch (NumberFormatException nfe) { + usage(); + } + } + else if (argv[i].equals("-u")) { + do_unlink = true; + } + else { + usage(); + } + } + + try { + if (do_unlink) { + // Create an environment that immediately + // removes all files. + LockExample tmp = new LockExample(home, maxlocks, do_unlink); + } + + LockExample app = new LockExample(home, maxlocks, do_unlink); + app.run(); + app.close(0); + } + catch (DbException dbe) { + System.err.println(progname + ": " + dbe.toString()); + } + catch (Throwable t) { + System.err.println(progname + ": " + t.toString()); + } + System.out.println("LockExample completed"); + } +} diff --git a/db/java/src/com/sleepycat/examples/TpcbExample.java b/db/java/src/com/sleepycat/examples/TpcbExample.java new file mode 100644 index 000000000..29a907908 --- /dev/null +++ b/db/java/src/com/sleepycat/examples/TpcbExample.java @@ -0,0 +1,831 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: TpcbExample.java,v 11.9 2000/04/01 15:52:15 dda Exp $ + */ + +package com.sleepycat.examples; + +import com.sleepycat.db.*; +import java.io.FileNotFoundException; +import java.util.Calendar; +import java.util.Date; +import java.util.Random; +import java.util.GregorianCalendar; +import java.math.BigDecimal; + +// +// This program implements a basic TPC/B driver program. To create the +// TPC/B database, run with the -i (init) flag. The number of records +// with which to populate the account, history, branch, and teller tables +// is specified by the a, s, b, and t flags respectively. To run a TPC/B +// test, use the n flag to indicate a number of transactions to run (note +// that you can run many of these processes in parallel to simulate a +// multiuser test run). +// +class TpcbExample extends DbEnv +{ + public static final int TELLERS_PER_BRANCH = 10; + public static final int ACCOUNTS_PER_TELLER = 10000; + public static final int HISTORY_PER_BRANCH = 2592000; + + // + // The default configuration that adheres to TPCB scaling rules requires + // nearly 3 GB of space. To avoid requiring that much space for testing, + // we set the parameters much lower. If you want to run a valid 10 TPS + // configuration, uncomment the VALID_SCALING configuration + // + + // VALID_SCALING configuration + /* + public static final int ACCOUNTS = 1000000; + public static final int BRANCHES = 10; + public static final int TELLERS = 100; + public static final int HISTORY = 25920000; + */ + + // TINY configuration + /* + public static final int ACCOUNTS = 1000; + public static final int BRANCHES = 10; + public static final int TELLERS = 100; + public static final int HISTORY = 10000; + */ + + // Default configuration + public static final int ACCOUNTS = 100000; + public static final int BRANCHES = 10; + public static final int TELLERS = 100; + public static final int HISTORY = 259200; + + public static final int HISTORY_LEN = 100; + public static final int RECLEN = 100; + public static final int BEGID = 1000000; + + // used by random_id() + public static final int ACCOUNT = 0; + public static final int BRANCH = 1; + public static final int TELLER = 2; + + private static boolean verbose = false; + private static final String progname = "TpcbExample"; // Program name. + + public TpcbExample(String home, int cachesize, + boolean initializing, int flags) + throws DbException, FileNotFoundException + { + super(0); + set_error_stream(System.err); + set_errpfx(progname); + set_cachesize(0, cachesize == 0 ? 4 * 1024 * 1024 : cachesize, 0); + + int local_flags = flags | Db.DB_CREATE; + if (initializing) + local_flags |= Db.DB_INIT_MPOOL; + else + local_flags |= Db.DB_INIT_TXN | Db.DB_INIT_LOCK | + Db.DB_INIT_LOG | Db.DB_INIT_MPOOL; + + open(home, local_flags, 0); // may throw DbException + } + + // + // Initialize the database to the specified number of accounts, branches, + // history records, and tellers. + // + // Note: num_h was unused in the original ex_tpcb.c example. + // + public void + populate(int num_a, int num_b, int num_h, int num_t) + { + Db dbp = null; + + int err; + int balance, idnum; + int end_anum, end_bnum, end_tnum; + int start_anum, start_bnum, start_tnum; + int h_nelem; + + idnum = BEGID; + balance = 500000; + + h_nelem = num_a; + + try { + dbp = new Db(this, 0); + dbp.set_h_nelem(h_nelem); + dbp.open("account", null, + Db.DB_HASH, Db.DB_CREATE | Db.DB_TRUNCATE, 0644); + } + // can be DbException or FileNotFoundException + catch (Exception e1) { + errExit(e1, "Open of account file failed"); + } + + start_anum = idnum; + populateTable(dbp, idnum, balance, h_nelem, "account"); + idnum += h_nelem; + end_anum = idnum - 1; + try { + dbp.close(0); + } + catch (DbException e2) { + errExit(e2, "Account file close failed"); + } + + if (verbose) + System.out.println("Populated accounts: " + + String.valueOf(start_anum) + " - " + String.valueOf(end_anum)); + + // + // Since the number of branches is very small, we want to use very + // small pages and only 1 key per page. This is the poor-man's way + // of getting key locking instead of page locking. + // + h_nelem = (int)num_b; + + try { + dbp = new Db(this, 0); + + dbp.set_h_nelem(h_nelem); + dbp.set_h_ffactor(1); + dbp.set_pagesize(512); + + dbp.open("branch", null, + Db.DB_HASH, Db.DB_CREATE | Db.DB_TRUNCATE, 0644); + } + // can be DbException or FileNotFoundException + catch (Exception e3) { + errExit(e3, "Branch file create failed"); + } + start_bnum = idnum; + populateTable(dbp, idnum, balance, h_nelem, "branch"); + idnum += h_nelem; + end_bnum = idnum - 1; + + try { + dbp.close(0); + } + catch (DbException dbe4) { + errExit(dbe4, "Close of branch file failed"); + } + + if (verbose) + System.out.println("Populated branches: " + + String.valueOf(start_bnum) + " - " + String.valueOf(end_bnum)); + + // + // In the case of tellers, we also want small pages, but we'll let + // the fill factor dynamically adjust itself. + // + h_nelem = (int)num_t; + + try { + + dbp = new Db(this, 0); + + dbp.set_h_nelem(h_nelem); + dbp.set_h_ffactor(0); + dbp.set_pagesize(512); + + dbp.open("teller", null, + Db.DB_HASH, Db.DB_CREATE | Db.DB_TRUNCATE, 0644); + } + // can be DbException or FileNotFoundException + catch (Exception e5) { + errExit(e5, "Teller file create failed"); + } + + start_tnum = idnum; + populateTable(dbp, idnum, balance, h_nelem, "teller"); + idnum += h_nelem; + end_tnum = idnum - 1; + + try { + dbp.close(0); + } + catch (DbException e6) { + errExit(e6, "Close of teller file failed"); + } + + if (verbose) + System.out.println("Populated tellers: " + + String.valueOf(start_tnum) + " - " + String.valueOf(end_tnum)); + + try { + dbp = new Db(this, 0); + dbp.set_re_len(HISTORY_LEN); + dbp.open("history", null, + Db.DB_RECNO, Db.DB_CREATE | Db.DB_TRUNCATE, 0644); + } + // can be DbException or FileNotFoundException + catch (Exception e7) { + errExit(e7, "Create of history file failed"); + } + + populateHistory(dbp, num_h, num_a, num_b, num_t); + + try { + dbp.close(0); + } + catch (DbException e8) { + errExit(e8, "Close of history file failed"); + } + } + + public void + populateTable(Db dbp, + int start_id, int balance, + int nrecs, String msg) + { + Defrec drec = new Defrec(); + + Dbt kdbt = new Dbt(drec.data); + kdbt.set_size(4); // sizeof(int) + Dbt ddbt = new Dbt(drec.data); + ddbt.set_size(drec.data.length); // uses whole array + + try { + for (int i = 0; i < nrecs; i++) { + kdbt.set_recno_key_data(start_id + (int)i); + drec.set_balance(balance); + dbp.put(null, kdbt, ddbt, Db.DB_NOOVERWRITE); + } + } + catch (DbException dbe) { + System.err.println("Failure initializing " + msg + " file: " + + dbe.toString()); + System.exit(1); + } + } + + public void + populateHistory(Db dbp, int nrecs, + int anum, int bnum, int tnum) + { + Histrec hrec = new Histrec(); + hrec.set_amount(10); + + byte arr[] = new byte[4]; // sizeof(int) + int i; + Dbt kdbt = new Dbt(arr); + kdbt.set_size(arr.length); + Dbt ddbt = new Dbt(hrec.data); + ddbt.set_size(hrec.data.length); + + try { + for (i = 1; i <= nrecs; i++) { + kdbt.set_recno_key_data(i); + + hrec.set_aid(random_id(ACCOUNT, anum, bnum, tnum)); + hrec.set_bid(random_id(BRANCH, anum, bnum, tnum)); + hrec.set_tid(random_id(TELLER, anum, bnum, tnum)); + + dbp.put(null, kdbt, ddbt, Db.DB_APPEND); + } + } + catch (DbException dbe) { + errExit(dbe, "Failure initializing history file"); + } + } + + static Random rand = new Random(); + + public static int + random_int(int lo, int hi) + { + int ret; + int t; + + t = rand.nextInt(); + if (t < 0) + t = -t; + ret = (int)(((double)t / ((double)(Integer.MAX_VALUE) + 1)) * + (hi - lo + 1)); + ret += lo; + return (ret); + } + + public static int + random_id(int type, int accounts, int branches, int tellers) + { + int min, max, num; + + max = min = BEGID; + num = accounts; + switch(type) { + case TELLER: + min += branches; + num = tellers; + // Fallthrough + case BRANCH: + if (type == BRANCH) + num = branches; + min += accounts; + // Fallthrough + case ACCOUNT: + max = min + num - 1; + } + return (random_int(min, max)); + } + + public void + run(int n, int accounts, int branches, int tellers) + { + Db adb = null; + Db bdb = null; + Db hdb = null; + Db tdb = null; + double gtps, itps; + int failed, ifailed, ret, txns; + long starttime, curtime, lasttime; + + // + // Open the database files. + // + int err; + try { + adb = new Db(this, 0); + adb.open("account", null, Db.DB_UNKNOWN, 0, 0); + bdb = new Db(this, 0); + bdb.open("branch", null, Db.DB_UNKNOWN, 0, 0); + tdb = new Db(this, 0); + tdb.open("teller", null, Db.DB_UNKNOWN, 0, 0); + hdb = new Db(this, 0); + hdb.open("history", null, Db.DB_UNKNOWN, 0, 0); + } + catch (DbException dbe) { + errExit(dbe, "Open of db files failed"); + } + catch (FileNotFoundException fnfe) { + errExit(fnfe, "Open of db files failed, missing file"); + } + + txns = failed = ifailed = 0; + starttime = (new Date()).getTime(); + lasttime = starttime; + while (n-- > 0) { + txns++; + ret = txn(adb, bdb, tdb, hdb, accounts, branches, tellers); + if (ret != 0) { + failed++; + ifailed++; + } + if (n % 5000 == 0) { + curtime = (new Date()).getTime(); + gtps = (double)(txns - failed) / + ((curtime - starttime) / 1000.0); + itps = (double)(5000 - ifailed) / + ((curtime - lasttime) / 1000.0); + System.out.print(String.valueOf(txns) + " txns " + + String.valueOf(failed) + " failed "); + System.out.println(showRounded(gtps, 2) + " TPS (gross) " + + showRounded(itps, 2) + " TPS (interval)"); + lasttime = curtime; + ifailed = 0; + } + } + + try { + adb.close(0); + bdb.close(0); + tdb.close(0); + hdb.close(0); + } + catch (DbException dbe2) { + errExit(dbe2, "Close of db files failed"); + } + + System.out.println((long)txns + " transactions begun " + + String.valueOf(failed) + " failed"); + + } + + // + // XXX Figure out the appropriate way to pick out IDs. + // + public int + txn(Db adb, Db bdb, Db tdb, Db hdb, + int anum, int bnum, int tnum) + { + Dbc acurs = null; + Dbc bcurs = null; + Dbc hcurs = null; + Dbc tcurs = null; + DbTxn t = null; + + Defrec rec = new Defrec(); + Histrec hrec = new Histrec(); + int account, branch, teller; + + Dbt d_dbt = new Dbt(); + Dbt d_histdbt = new Dbt(); + Dbt k_dbt = new Dbt(); + Dbt k_histdbt = new Dbt(); + + account = random_id(ACCOUNT, anum, bnum, tnum); + branch = random_id(BRANCH, anum, bnum, tnum); + teller = random_id(TELLER, anum, bnum, tnum); + + // The history key will not actually be retrieved, + // but it does need to be set to something. + byte hist_key[] = new byte[4]; + k_histdbt.set_data(hist_key); + k_histdbt.set_size(4 /* == sizeof(int)*/); + + byte key_bytes[] = new byte[4]; + k_dbt.set_data(key_bytes); + k_dbt.set_size(4 /* == sizeof(int)*/); + + d_dbt.set_flags(Db.DB_DBT_USERMEM); + d_dbt.set_data(rec.data); + d_dbt.set_ulen(rec.length()); + + hrec.set_aid(account); + hrec.set_bid(branch); + hrec.set_tid(teller); + hrec.set_amount(10); + // Request 0 bytes since we're just positioning. + d_histdbt.set_flags(Db.DB_DBT_PARTIAL); + + // START TIMING + + try { + t = txn_begin(null, 0); + + acurs = adb.cursor(t, 0); + bcurs = bdb.cursor(t, 0); + tcurs = tdb.cursor(t, 0); + hcurs = hdb.cursor(t, 0); + + // Account record + k_dbt.set_recno_key_data(account); + if (acurs.get(k_dbt, d_dbt, Db.DB_SET) != 0) + throw new TpcbException("acurs get failed"); + rec.set_balance(rec.get_balance() + 10); + acurs.put(k_dbt, d_dbt, Db.DB_CURRENT); + + // Branch record + k_dbt.set_recno_key_data(branch); + if (bcurs.get(k_dbt, d_dbt, Db.DB_SET) != 0) + throw new TpcbException("bcurs get failed"); + rec.set_balance(rec.get_balance() + 10); + bcurs.put(k_dbt, d_dbt, Db.DB_CURRENT); + + // Teller record + k_dbt.set_recno_key_data(teller); + if (tcurs.get(k_dbt, d_dbt, Db.DB_SET) != 0) + throw new TpcbException("ccurs get failed"); + rec.set_balance(rec.get_balance() + 10); + tcurs.put(k_dbt, d_dbt, Db.DB_CURRENT); + + // History record + d_histdbt.set_flags(0); + d_histdbt.set_data(hrec.data); + d_histdbt.set_ulen(hrec.length()); + if (hdb.put(t, k_histdbt, d_histdbt, Db.DB_APPEND) != 0) + throw(new DbException("put failed")); + + acurs.close(); + bcurs.close(); + tcurs.close(); + hcurs.close(); + + t.commit(0); + + // END TIMING + return (0); + + } + catch (Exception e) { + try { + if (acurs != null) + acurs.close(); + if (bcurs != null) + bcurs.close(); + if (tcurs != null) + tcurs.close(); + if (hcurs != null) + hcurs.close(); + if (t != null) + t.abort(); + } + catch (DbException dbe) { + // not much we can do here. + } + + if (verbose) { + System.out.println("Transaction A=" + String.valueOf(account) + + " B=" + String.valueOf(branch) + + " T=" + String.valueOf(teller) + " failed"); + System.out.println("Reason: " + e.toString()); + } + return (-1); + } + } + + static void errExit(Exception err, String s) + { + System.err.print(progname + ": "); + if (s != null) { + System.err.print(s + ": "); + } + System.err.println(err.toString()); + System.exit(1); + } + + public static void main(String argv[]) + { + long seed; + int accounts, branches, tellers, history; + boolean iflag, txn_no_sync; + int mpool, ntxns; + String home, endarg; + + home = "TESTDIR"; + accounts = branches = history = tellers = 0; + txn_no_sync = false; + mpool = ntxns = 0; + verbose = false; + iflag = false; + seed = (new GregorianCalendar()).get(Calendar.SECOND); + + for (int i = 0; i < argv.length; ++i) + { + if (argv[i].equals("-a")) { + // Number of account records + if ((accounts = Integer.parseInt(argv[++i])) <= 0) + invarg(argv[i]); + } + else if (argv[i].equals("-b")) { + // Number of branch records + if ((branches = Integer.parseInt(argv[++i])) <= 0) + invarg(argv[i]); + } + else if (argv[i].equals("-c")) { + // Cachesize in bytes + if ((mpool = Integer.parseInt(argv[++i])) <= 0) + invarg(argv[i]); + } + else if (argv[i].equals("-f")) { + // Fast mode: no txn sync. + txn_no_sync = true; + } + else if (argv[i].equals("-h")) { + // DB home. + home = argv[++i]; + } + else if (argv[i].equals("-i")) { + // Initialize the test. + iflag = true; + } + else if (argv[i].equals("-n")) { + // Number of transactions + if ((ntxns = Integer.parseInt(argv[++i])) <= 0) + invarg(argv[i]); + } + else if (argv[i].equals("-S")) { + // Random number seed. + seed = Long.parseLong(argv[++i]); + if (seed <= 0) + invarg(argv[i]); + } + else if (argv[i].equals("-s")) { + // Number of history records + if ((history = Integer.parseInt(argv[++i])) <= 0) + invarg(argv[i]); + } + else if (argv[i].equals("-t")) { + // Number of teller records + if ((tellers = Integer.parseInt(argv[++i])) <= 0) + invarg(argv[i]); + } + else if (argv[i].equals("-v")) { + // Verbose option. + verbose = true; + } + else + { + usage(); + } + } + + rand.setSeed((int)seed); + + TpcbExample app = null; + + // Initialize the database environment. + // Must be done in within a try block. + // + try { + app = new TpcbExample(home, mpool, iflag, + txn_no_sync ? Db.DB_TXN_NOSYNC : 0); + } + catch (Exception e1) { + errExit(e1, "initializing environment failed"); + } + + accounts = accounts == 0 ? ACCOUNTS : accounts; + branches = branches == 0 ? BRANCHES : branches; + tellers = tellers == 0 ? TELLERS : tellers; + history = history == 0 ? HISTORY : history; + + if (verbose) + System.out.println((long)accounts + " Accounts " + + String.valueOf(branches) + " Branches " + + String.valueOf(tellers) + " Tellers " + + String.valueOf(history) + " History"); + + if (iflag) { + if (ntxns != 0) + usage(); + app.populate(accounts, branches, history, tellers); + } + else { + if (ntxns == 0) + usage(); + app.run(ntxns, accounts, branches, tellers); + } + + // Shut down the application. + + try { + app.close(0); + } + catch (DbException dbe2) { + errExit(dbe2, "appexit failed"); + } + + System.exit(0); + } + + private static void invarg(String str) + { + System.err.println("TpcbExample: invalid argument: " + str); + System.exit(1); + } + + private static void usage() + { + System.err.println( + "usage: TpcbExample [-fiv] [-a accounts] [-b branches]\n" + + " [-c cachesize] [-h home] [-n transactions ]\n" + + " [-S seed] [-s history] [-t tellers]"); + System.exit(1); + } + + // round 'd' to 'scale' digits, and return result as string + private String showRounded(double d, int scale) + { + return new BigDecimal(d). + setScale(scale, BigDecimal.ROUND_HALF_DOWN).toString(); + } + + // The byte order is our choice. + // + static long get_int_in_array(byte[] array, int offset) + { + return + ((0xff & array[offset+0]) << 0) | + ((0xff & array[offset+1]) << 8) | + ((0xff & array[offset+2]) << 16) | + ((0xff & array[offset+3]) << 24); + } + + // Note: Value needs to be long to avoid sign extension + static void set_int_in_array(byte[] array, int offset, long value) + { + array[offset+0] = (byte)((value >> 0) & 0x0ff); + array[offset+1] = (byte)((value >> 8) & 0x0ff); + array[offset+2] = (byte)((value >> 16) & 0x0ff); + array[offset+3] = (byte)((value >> 24) & 0x0ff); + } + +}; + +// Simulate the following C struct: +// struct Defrec { +// u_int32_t id; +// u_int32_t balance; +// u_int8_t pad[RECLEN - sizeof(int) - sizeof(int)]; +// }; + +class Defrec +{ + public Defrec() + { + data = new byte[TpcbExample.RECLEN]; + } + + public int length() + { + return TpcbExample.RECLEN; + } + + public long get_id() + { + return TpcbExample.get_int_in_array(data, 0); + } + + public void set_id(long value) + { + TpcbExample.set_int_in_array(data, 0, value); + } + + public long get_balance() + { + return TpcbExample.get_int_in_array(data, 4); + } + + public void set_balance(long value) + { + TpcbExample.set_int_in_array(data, 4, value); + } + + static { + Defrec d = new Defrec(); + d.set_balance(500000); + } + + public byte[] data; +} + +// Simulate the following C struct: +// struct Histrec { +// u_int32_t aid; +// u_int32_t bid; +// u_int32_t tid; +// u_int32_t amount; +// u_int8_t pad[RECLEN - 4 * sizeof(u_int32_t)]; +// }; + +class Histrec +{ + public Histrec() + { + data = new byte[TpcbExample.RECLEN]; + } + + public int length() + { + return TpcbExample.RECLEN; + } + + public long get_aid() + { + return TpcbExample.get_int_in_array(data, 0); + } + + public void set_aid(long value) + { + TpcbExample.set_int_in_array(data, 0, value); + } + + public long get_bid() + { + return TpcbExample.get_int_in_array(data, 4); + } + + public void set_bid(long value) + { + TpcbExample.set_int_in_array(data, 4, value); + } + + public long get_tid() + { + return TpcbExample.get_int_in_array(data, 8); + } + + public void set_tid(long value) + { + TpcbExample.set_int_in_array(data, 8, value); + } + + public long get_amount() + { + return TpcbExample.get_int_in_array(data, 12); + } + + public void set_amount(long value) + { + TpcbExample.set_int_in_array(data, 12, value); + } + + public byte[] data; +} + +class TpcbException extends Exception +{ + TpcbException() + { + super(); + } + + TpcbException(String s) + { + super(s); + } +} diff --git a/db/libdb_java/checkapi.prl b/db/libdb_java/checkapi.prl new file mode 100644 index 000000000..25882c056 --- /dev/null +++ b/db/libdb_java/checkapi.prl @@ -0,0 +1,132 @@ +# +# Released to public domain by Donald Anderson dda@world.std.com +# No warranties. +# +# Perl script to check for matching of JNI interfaces to implementation. +# We check all .cpp arguments and .h arguments and make sure that for +# each .h declaration (marked by JNIEXPORT keyword), there is a .cpp +# definition for the same function (also marked by JNIEXPORT keyword), +# and vice versa. Definitions and declarations are determined solely +# by whether they are in a .h or .cpp file - we don't do any further +# analysis. +# +# Some additions made to help with Berkeley DB sources: +# +# Berkeley DB Java sources use JAVADB_*_ACCESS #defines +# to quickly define routine access functions. + +foreach $file (<@ARGV>) { # glob allows direct use from Win* makefiles + open (FILE, $file) || die "$file: cannot open\n"; + $dot_h = 0; + if ($file =~ /.*[hH]$/) { + $dot_h = 1; + } + $in_def = 0; +nextline: + while () { + chop; + if (/JNIEXPORT/ || /^JAVADB_.*_ACCESS/) { + $in_def = 1; + $def = ""; + } + if ($in_def == 1) { + $def .= $_; + } + if (/\)/) { + $line = ""; + $in_def = 0; + if ($def eq "") { + next nextline; + } + $_ = $def; + # remove comments + s@/\*[^*]*\*/@@g; + s@[ ][ ]*@ @g; + s@JNIEnv *\* *@JNIEnv @g; + s@([,*()]) @\1@g; + s@ ([,*()])@\1@g; + + s/JAVADB_WO_ACCESS_METHOD/JAVADB_WO_ACCESS/; + + if (/^JAVADB_.*_ACCESS/) { + s@ *@ @g; + s@_ACCESS_STRING\(([^,]*),@_ACCESS(\1,jstring,@; + s@_ACCESS_BEFORE_APPINIT@_ACCESS@; + s@_ACCESS\(@,normal,@; + s@JAVADB_@@; + s@\)@,@; + @vars = split(/,/); + $get = 0; + $set = 0; + if (@vars[0] eq "RW") { + $get = 1; + $set = 1; + } + if (@vars[0] eq "RO") { + $get = 1; + } + if (@vars[0] eq "WO") { + $set = 1; + } + if ($get == 0 && $set == 0) { + print "Invalid use of JAVADB_ macro\n"; + } + if ($set == 1) { + $line = "JNIEXPORT void JNICALL Java_com_sleepycat_db_@vars[2]_set_1@vars[4](JNIEnv,jobject,@vars[3])"; + } + if ($get == 1) { + $line2 = "JNIEXPORT @vars[3] JNICALL Java_com_sleepycat_db_@vars[2]_get_1@vars[4](JNIEnv,jobject)"; + } + } + else { + s@([,(][a-zA-Z0-9_]*) [a-zA-Z0-9_]*@\1@g; + s@;$@@g; + $line = $_; + } + + $def = ""; + + if ($line ne "") { + if ($lines{$line} eq "") { + $lines{$line} = 0; + } + if ($dot_h == 1) { + $lines{$line} += 1; + } + else { + $lines{$line} -= 1; + } + $line = ""; + } + if ($line2 ne "") { + if ($lines{$line2} eq "") { + $lines{$line2} = 0; + } + if ($dot_h == 1) { + $lines{$line2} += 1; + } + else { + $lines{$line2} -= 1; + } + $line2 = ""; + } + } + } + close (FILE); +} + +$status = 0; +foreach $key (sort keys %lines) { + if ($lines{$key} != 0) { + if ($lines{$key} > 0) { + print "Missing .cpp implementation: $lines${key}\n"; + $status = 1; + } + else { + print "Missing .h declaration: $lines${key}\n"; + $status = 1; + } + } +} + +exit ($status); diff --git a/db/libdb_java/com_sleepycat_db_Db.h b/db/libdb_java/com_sleepycat_db_Db.h new file mode 100644 index 000000000..d9e1f1cbb --- /dev/null +++ b/db/libdb_java/com_sleepycat_db_Db.h @@ -0,0 +1,349 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class com_sleepycat_db_Db */ + +#ifndef _Included_com_sleepycat_db_Db +#define _Included_com_sleepycat_db_Db +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: com_sleepycat_db_Db + * Method: _init + * Signature: (Lcom/sleepycat/db/DbEnv;I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db__1init + (JNIEnv *, jobject, jobject, jint); + +/* + * Class: com_sleepycat_db_Db + * Method: _notify_internal + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db__1notify_1internal + (JNIEnv *, jobject); + +/* + * Class: com_sleepycat_db_Db + * Method: _close + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_com_sleepycat_db_Db__1close + (JNIEnv *, jobject, jint); + +/* + * Class: com_sleepycat_db_Db + * Method: cursor + * Signature: (Lcom/sleepycat/db/DbTxn;I)Lcom/sleepycat/db/Dbc; + */ +JNIEXPORT jobject JNICALL Java_com_sleepycat_db_Db_cursor + (JNIEnv *, jobject, jobject, jint); + +/* + * Class: com_sleepycat_db_Db + * Method: del + * Signature: (Lcom/sleepycat/db/DbTxn;Lcom/sleepycat/db/Dbt;I)I + */ +JNIEXPORT jint JNICALL Java_com_sleepycat_db_Db_del + (JNIEnv *, jobject, jobject, jobject, jint); + +/* + * Class: com_sleepycat_db_Db + * Method: err + * Signature: (ILjava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_err + (JNIEnv *, jobject, jint, jstring); + +/* + * Class: com_sleepycat_db_Db + * Method: errx + * Signature: (Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_errx + (JNIEnv *, jobject, jstring); + +/* + * Class: com_sleepycat_db_Db + * Method: fd + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_sleepycat_db_Db_fd + (JNIEnv *, jobject); + +/* + * Class: com_sleepycat_db_Db + * Method: _finalize + * Signature: (Lcom/sleepycat/db/DbErrcall;Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db__1finalize + (JNIEnv *, jobject, jobject, jstring); + +/* + * Class: com_sleepycat_db_Db + * Method: get + * Signature: (Lcom/sleepycat/db/DbTxn;Lcom/sleepycat/db/Dbt;Lcom/sleepycat/db/Dbt;I)I + */ +JNIEXPORT jint JNICALL Java_com_sleepycat_db_Db_get + (JNIEnv *, jobject, jobject, jobject, jobject, jint); + +/* + * Class: com_sleepycat_db_Db + * Method: get_byteswapped + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL Java_com_sleepycat_db_Db_get_1byteswapped + (JNIEnv *, jobject); + +/* + * Class: com_sleepycat_db_Db + * Method: get_type + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_sleepycat_db_Db_get_1type + (JNIEnv *, jobject); + +/* + * Class: com_sleepycat_db_Db + * Method: join + * Signature: ([Lcom/sleepycat/db/Dbc;I)Lcom/sleepycat/db/Dbc; + */ +JNIEXPORT jobject JNICALL Java_com_sleepycat_db_Db_join + (JNIEnv *, jobject, jobjectArray, jint); + +/* + * Class: com_sleepycat_db_Db + * Method: key_range + * Signature: (Lcom/sleepycat/db/DbTxn;Lcom/sleepycat/db/Dbt;Lcom/sleepycat/db/DbKeyRange;I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_key_1range + (JNIEnv *, jobject, jobject, jobject, jobject, jint); + +/* + * Class: com_sleepycat_db_Db + * Method: _open + * Signature: (Ljava/lang/String;Ljava/lang/String;III)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db__1open + (JNIEnv *, jobject, jstring, jstring, jint, jint, jint); + +/* + * Class: com_sleepycat_db_Db + * Method: put + * Signature: (Lcom/sleepycat/db/DbTxn;Lcom/sleepycat/db/Dbt;Lcom/sleepycat/db/Dbt;I)I + */ +JNIEXPORT jint JNICALL Java_com_sleepycat_db_Db_put + (JNIEnv *, jobject, jobject, jobject, jobject, jint); + +/* + * Class: com_sleepycat_db_Db + * Method: rename + * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_rename + (JNIEnv *, jobject, jstring, jstring, jstring, jint); + +/* + * Class: com_sleepycat_db_Db + * Method: remove + * Signature: (Ljava/lang/String;Ljava/lang/String;I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_remove + (JNIEnv *, jobject, jstring, jstring, jint); + +/* + * Class: com_sleepycat_db_Db + * Method: append_recno_changed + * Signature: (Lcom/sleepycat/db/DbAppendRecno;)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_append_1recno_1changed + (JNIEnv *, jobject, jobject); + +/* + * Class: com_sleepycat_db_Db + * Method: bt_compare_changed + * Signature: (Lcom/sleepycat/db/DbBtreeCompare;)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_bt_1compare_1changed + (JNIEnv *, jobject, jobject); + +/* + * Class: com_sleepycat_db_Db + * Method: set_bt_maxkey + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_set_1bt_1maxkey + (JNIEnv *, jobject, jint); + +/* + * Class: com_sleepycat_db_Db + * Method: set_bt_minkey + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_set_1bt_1minkey + (JNIEnv *, jobject, jint); + +/* + * Class: com_sleepycat_db_Db + * Method: bt_prefix_changed + * Signature: (Lcom/sleepycat/db/DbBtreePrefix;)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_bt_1prefix_1changed + (JNIEnv *, jobject, jobject); + +/* + * Class: com_sleepycat_db_Db + * Method: set_cachesize + * Signature: (III)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_set_1cachesize + (JNIEnv *, jobject, jint, jint, jint); + +/* + * Class: com_sleepycat_db_Db + * Method: dup_compare_changed + * Signature: (Lcom/sleepycat/db/DbDupCompare;)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_dup_1compare_1changed + (JNIEnv *, jobject, jobject); + +/* + * Class: com_sleepycat_db_Db + * Method: feedback_changed + * Signature: (Lcom/sleepycat/db/DbFeedback;)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_feedback_1changed + (JNIEnv *, jobject, jobject); + +/* + * Class: com_sleepycat_db_Db + * Method: set_flags + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_set_1flags + (JNIEnv *, jobject, jint); + +/* + * Class: com_sleepycat_db_Db + * Method: set_h_ffactor + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_set_1h_1ffactor + (JNIEnv *, jobject, jint); + +/* + * Class: com_sleepycat_db_Db + * Method: hash_changed + * Signature: (Lcom/sleepycat/db/DbHash;)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_hash_1changed + (JNIEnv *, jobject, jobject); + +/* + * Class: com_sleepycat_db_Db + * Method: set_h_nelem + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_set_1h_1nelem + (JNIEnv *, jobject, jint); + +/* + * Class: com_sleepycat_db_Db + * Method: set_lorder + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_set_1lorder + (JNIEnv *, jobject, jint); + +/* + * Class: com_sleepycat_db_Db + * Method: set_pagesize + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_set_1pagesize + (JNIEnv *, jobject, jlong); + +/* + * Class: com_sleepycat_db_Db + * Method: set_re_delim + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_set_1re_1delim + (JNIEnv *, jobject, jint); + +/* + * Class: com_sleepycat_db_Db + * Method: set_re_len + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_set_1re_1len + (JNIEnv *, jobject, jint); + +/* + * Class: com_sleepycat_db_Db + * Method: set_re_pad + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_set_1re_1pad + (JNIEnv *, jobject, jint); + +/* + * Class: com_sleepycat_db_Db + * Method: set_re_source + * Signature: (Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_set_1re_1source + (JNIEnv *, jobject, jstring); + +/* + * Class: com_sleepycat_db_Db + * Method: set_q_extentsize + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_set_1q_1extentsize + (JNIEnv *, jobject, jint); + +/* + * Class: com_sleepycat_db_Db + * Method: stat + * Signature: (I)Ljava/lang/Object; + */ +JNIEXPORT jobject JNICALL Java_com_sleepycat_db_Db_stat + (JNIEnv *, jobject, jint); + +/* + * Class: com_sleepycat_db_Db + * Method: sync + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_com_sleepycat_db_Db_sync + (JNIEnv *, jobject, jint); + +/* + * Class: com_sleepycat_db_Db + * Method: upgrade + * Signature: (Ljava/lang/String;I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_upgrade + (JNIEnv *, jobject, jstring, jint); + +/* + * Class: com_sleepycat_db_Db + * Method: verify + * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/io/OutputStream;I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_verify + (JNIEnv *, jobject, jstring, jstring, jobject, jint); + +/* + * Class: com_sleepycat_db_Db + * Method: one_time_init + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_one_1time_1init + (JNIEnv *, jclass); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/db/libdb_java/com_sleepycat_db_DbEnv.h b/db/libdb_java/com_sleepycat_db_DbEnv.h new file mode 100644 index 000000000..4168ea9ab --- /dev/null +++ b/db/libdb_java/com_sleepycat_db_DbEnv.h @@ -0,0 +1,509 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class com_sleepycat_db_DbEnv */ + +#ifndef _Included_com_sleepycat_db_DbEnv +#define _Included_com_sleepycat_db_DbEnv +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: com_sleepycat_db_DbEnv + * Method: _close + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv__1close + (JNIEnv *, jobject, jint); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: err + * Signature: (ILjava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_err + (JNIEnv *, jobject, jint, jstring); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: errx + * Signature: (Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_errx + (JNIEnv *, jobject, jstring); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: _finalize + * Signature: (Lcom/sleepycat/db/DbErrcall;Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv__1finalize + (JNIEnv *, jobject, jobject, jstring); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: _init + * Signature: (Lcom/sleepycat/db/DbErrcall;I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv__1init + (JNIEnv *, jobject, jobject, jint); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: _init_using_db + * Signature: (Lcom/sleepycat/db/DbErrcall;Lcom/sleepycat/db/Db;)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv__1init_1using_1db + (JNIEnv *, jobject, jobject, jobject); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: _notify_db_close + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv__1notify_1db_1close + (JNIEnv *, jobject); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: open + * Signature: (Ljava/lang/String;II)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_open + (JNIEnv *, jobject, jstring, jint, jint); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: remove + * Signature: (Ljava/lang/String;I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_remove + (JNIEnv *, jobject, jstring, jint); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: set_cachesize + * Signature: (III)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_set_1cachesize + (JNIEnv *, jobject, jint, jint, jint); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: _set_errcall + * Signature: (Lcom/sleepycat/db/DbErrcall;)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv__1set_1errcall + (JNIEnv *, jobject, jobject); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: _set_errpfx + * Signature: (Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv__1set_1errpfx + (JNIEnv *, jobject, jstring); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: feedback_changed + * Signature: (Lcom/sleepycat/db/DbFeedback;)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_feedback_1changed + (JNIEnv *, jobject, jobject); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: set_verbose + * Signature: (II)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_set_1verbose + (JNIEnv *, jobject, jint, jint); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: set_data_dir + * Signature: (Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_set_1data_1dir + (JNIEnv *, jobject, jstring); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: set_lg_bsize + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_set_1lg_1bsize + (JNIEnv *, jobject, jint); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: set_lg_dir + * Signature: (Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_set_1lg_1dir + (JNIEnv *, jobject, jstring); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: set_lg_max + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_set_1lg_1max + (JNIEnv *, jobject, jint); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: set_lk_conflicts + * Signature: ([[B)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_set_1lk_1conflicts + (JNIEnv *, jobject, jobjectArray); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: set_lk_detect + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_set_1lk_1detect + (JNIEnv *, jobject, jint); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: set_lk_max + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_set_1lk_1max + (JNIEnv *, jobject, jint); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: set_lk_max_lockers + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_set_1lk_1max_1lockers + (JNIEnv *, jobject, jint); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: set_lk_max_locks + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_set_1lk_1max_1locks + (JNIEnv *, jobject, jint); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: set_lk_max_objects + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_set_1lk_1max_1objects + (JNIEnv *, jobject, jint); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: set_mp_mmapsize + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_set_1mp_1mmapsize + (JNIEnv *, jobject, jlong); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: set_mutexlocks + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_set_1mutexlocks + (JNIEnv *, jobject, jint); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: set_pageyield + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_set_1pageyield + (JNIEnv *, jclass, jint); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: set_panicstate + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_set_1panicstate + (JNIEnv *, jclass, jint); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: recovery_init_changed + * Signature: (Lcom/sleepycat/db/DbRecoveryInit;)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_recovery_1init_1changed + (JNIEnv *, jobject, jobject); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: set_region_init + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_set_1region_1init + (JNIEnv *, jclass, jint); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: set_flags + * Signature: (II)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_set_1flags + (JNIEnv *, jobject, jint, jint); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: set_server + * Signature: (Ljava/lang/String;JJI)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_set_1server + (JNIEnv *, jobject, jstring, jlong, jlong, jint); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: set_shm_key + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_set_1shm_1key + (JNIEnv *, jobject, jlong); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: set_tas_spins + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_set_1tas_1spins + (JNIEnv *, jclass, jint); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: set_tmp_dir + * Signature: (Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_set_1tmp_1dir + (JNIEnv *, jobject, jstring); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: tx_recover_changed + * Signature: (Lcom/sleepycat/db/DbTxnRecover;)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_tx_1recover_1changed + (JNIEnv *, jobject, jobject); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: set_tx_max + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_set_1tx_1max + (JNIEnv *, jobject, jint); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: _set_tx_timestamp + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv__1set_1tx_1timestamp + (JNIEnv *, jobject, jlong); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: get_version_major + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_sleepycat_db_DbEnv_get_1version_1major + (JNIEnv *, jclass); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: get_version_minor + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_sleepycat_db_DbEnv_get_1version_1minor + (JNIEnv *, jclass); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: get_version_patch + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_sleepycat_db_DbEnv_get_1version_1patch + (JNIEnv *, jclass); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: get_version_string + * Signature: ()Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_com_sleepycat_db_DbEnv_get_1version_1string + (JNIEnv *, jclass); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: strerror + * Signature: (I)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_com_sleepycat_db_DbEnv_strerror + (JNIEnv *, jclass, jint); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: lock_detect + * Signature: (II)I + */ +JNIEXPORT jint JNICALL Java_com_sleepycat_db_DbEnv_lock_1detect + (JNIEnv *, jobject, jint, jint); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: lock_get + * Signature: (IILcom/sleepycat/db/Dbt;I)Lcom/sleepycat/db/DbLock; + */ +JNIEXPORT jobject JNICALL Java_com_sleepycat_db_DbEnv_lock_1get + (JNIEnv *, jobject, jint, jint, jobject, jint); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: lock_id + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_sleepycat_db_DbEnv_lock_1id + (JNIEnv *, jobject); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: lock_stat + * Signature: ()Lcom/sleepycat/db/DbLockStat; + */ +JNIEXPORT jobject JNICALL Java_com_sleepycat_db_DbEnv_lock_1stat + (JNIEnv *, jobject); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: log_archive + * Signature: (I)[Ljava/lang/String; + */ +JNIEXPORT jobjectArray JNICALL Java_com_sleepycat_db_DbEnv_log_1archive + (JNIEnv *, jobject, jint); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: log_compare + * Signature: (Lcom/sleepycat/db/DbLsn;Lcom/sleepycat/db/DbLsn;)I + */ +JNIEXPORT jint JNICALL Java_com_sleepycat_db_DbEnv_log_1compare + (JNIEnv *, jclass, jobject, jobject); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: log_file + * Signature: (Lcom/sleepycat/db/DbLsn;)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_com_sleepycat_db_DbEnv_log_1file + (JNIEnv *, jobject, jobject); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: log_flush + * Signature: (Lcom/sleepycat/db/DbLsn;)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_log_1flush + (JNIEnv *, jobject, jobject); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: log_get + * Signature: (Lcom/sleepycat/db/DbLsn;Lcom/sleepycat/db/Dbt;I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_log_1get + (JNIEnv *, jobject, jobject, jobject, jint); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: log_put + * Signature: (Lcom/sleepycat/db/DbLsn;Lcom/sleepycat/db/Dbt;I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_log_1put + (JNIEnv *, jobject, jobject, jobject, jint); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: log_stat + * Signature: ()Lcom/sleepycat/db/DbLogStat; + */ +JNIEXPORT jobject JNICALL Java_com_sleepycat_db_DbEnv_log_1stat + (JNIEnv *, jobject); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: log_register + * Signature: (Lcom/sleepycat/db/Db;Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_log_1register + (JNIEnv *, jobject, jobject, jstring); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: log_unregister + * Signature: (Lcom/sleepycat/db/Db;)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_log_1unregister + (JNIEnv *, jobject, jobject); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: memp_stat + * Signature: ()Lcom/sleepycat/db/DbMpoolStat; + */ +JNIEXPORT jobject JNICALL Java_com_sleepycat_db_DbEnv_memp_1stat + (JNIEnv *, jobject); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: memp_fstat + * Signature: ()[Lcom/sleepycat/db/DbMpoolFStat; + */ +JNIEXPORT jobjectArray JNICALL Java_com_sleepycat_db_DbEnv_memp_1fstat + (JNIEnv *, jobject); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: memp_trickle + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_com_sleepycat_db_DbEnv_memp_1trickle + (JNIEnv *, jobject, jint); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: txn_begin + * Signature: (Lcom/sleepycat/db/DbTxn;I)Lcom/sleepycat/db/DbTxn; + */ +JNIEXPORT jobject JNICALL Java_com_sleepycat_db_DbEnv_txn_1begin + (JNIEnv *, jobject, jobject, jint); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: txn_checkpoint + * Signature: (III)I + */ +JNIEXPORT jint JNICALL Java_com_sleepycat_db_DbEnv_txn_1checkpoint + (JNIEnv *, jobject, jint, jint, jint); + +/* + * Class: com_sleepycat_db_DbEnv + * Method: txn_stat + * Signature: ()Lcom/sleepycat/db/DbTxnStat; + */ +JNIEXPORT jobject JNICALL Java_com_sleepycat_db_DbEnv_txn_1stat + (JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/db/libdb_java/com_sleepycat_db_DbLock.h b/db/libdb_java/com_sleepycat_db_DbLock.h new file mode 100644 index 000000000..8a1c135bb --- /dev/null +++ b/db/libdb_java/com_sleepycat_db_DbLock.h @@ -0,0 +1,29 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class com_sleepycat_db_DbLock */ + +#ifndef _Included_com_sleepycat_db_DbLock +#define _Included_com_sleepycat_db_DbLock +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: com_sleepycat_db_DbLock + * Method: finalize + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbLock_finalize + (JNIEnv *, jobject); + +/* + * Class: com_sleepycat_db_DbLock + * Method: put + * Signature: (Lcom/sleepycat/db/DbEnv;)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbLock_put + (JNIEnv *, jobject, jobject); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/db/libdb_java/com_sleepycat_db_DbLsn.h b/db/libdb_java/com_sleepycat_db_DbLsn.h new file mode 100644 index 000000000..093eaf372 --- /dev/null +++ b/db/libdb_java/com_sleepycat_db_DbLsn.h @@ -0,0 +1,29 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class com_sleepycat_db_DbLsn */ + +#ifndef _Included_com_sleepycat_db_DbLsn +#define _Included_com_sleepycat_db_DbLsn +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: com_sleepycat_db_DbLsn + * Method: finalize + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbLsn_finalize + (JNIEnv *, jobject); + +/* + * Class: com_sleepycat_db_DbLsn + * Method: init_lsn + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbLsn_init_1lsn + (JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/db/libdb_java/com_sleepycat_db_DbTxn.h b/db/libdb_java/com_sleepycat_db_DbTxn.h new file mode 100644 index 000000000..4dcf47405 --- /dev/null +++ b/db/libdb_java/com_sleepycat_db_DbTxn.h @@ -0,0 +1,53 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class com_sleepycat_db_DbTxn */ + +#ifndef _Included_com_sleepycat_db_DbTxn +#define _Included_com_sleepycat_db_DbTxn +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: com_sleepycat_db_DbTxn + * Method: abort + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbTxn_abort + (JNIEnv *, jobject); + +/* + * Class: com_sleepycat_db_DbTxn + * Method: commit + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbTxn_commit + (JNIEnv *, jobject, jint); + +/* + * Class: com_sleepycat_db_DbTxn + * Method: id + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_sleepycat_db_DbTxn_id + (JNIEnv *, jobject); + +/* + * Class: com_sleepycat_db_DbTxn + * Method: prepare + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbTxn_prepare + (JNIEnv *, jobject); + +/* + * Class: com_sleepycat_db_DbTxn + * Method: finalize + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbTxn_finalize + (JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/db/libdb_java/com_sleepycat_db_Dbc.h b/db/libdb_java/com_sleepycat_db_Dbc.h new file mode 100644 index 000000000..e62679c6f --- /dev/null +++ b/db/libdb_java/com_sleepycat_db_Dbc.h @@ -0,0 +1,69 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class com_sleepycat_db_Dbc */ + +#ifndef _Included_com_sleepycat_db_Dbc +#define _Included_com_sleepycat_db_Dbc +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: com_sleepycat_db_Dbc + * Method: close + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Dbc_close + (JNIEnv *, jobject); + +/* + * Class: com_sleepycat_db_Dbc + * Method: count + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_com_sleepycat_db_Dbc_count + (JNIEnv *, jobject, jint); + +/* + * Class: com_sleepycat_db_Dbc + * Method: del + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_com_sleepycat_db_Dbc_del + (JNIEnv *, jobject, jint); + +/* + * Class: com_sleepycat_db_Dbc + * Method: dup + * Signature: (I)Lcom/sleepycat/db/Dbc; + */ +JNIEXPORT jobject JNICALL Java_com_sleepycat_db_Dbc_dup + (JNIEnv *, jobject, jint); + +/* + * Class: com_sleepycat_db_Dbc + * Method: get + * Signature: (Lcom/sleepycat/db/Dbt;Lcom/sleepycat/db/Dbt;I)I + */ +JNIEXPORT jint JNICALL Java_com_sleepycat_db_Dbc_get + (JNIEnv *, jobject, jobject, jobject, jint); + +/* + * Class: com_sleepycat_db_Dbc + * Method: put + * Signature: (Lcom/sleepycat/db/Dbt;Lcom/sleepycat/db/Dbt;I)I + */ +JNIEXPORT jint JNICALL Java_com_sleepycat_db_Dbc_put + (JNIEnv *, jobject, jobject, jobject, jint); + +/* + * Class: com_sleepycat_db_Dbc + * Method: finalize + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Dbc_finalize + (JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/db/libdb_java/com_sleepycat_db_Dbt.h b/db/libdb_java/com_sleepycat_db_Dbt.h new file mode 100644 index 000000000..cdb58c682 --- /dev/null +++ b/db/libdb_java/com_sleepycat_db_Dbt.h @@ -0,0 +1,157 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class com_sleepycat_db_Dbt */ + +#ifndef _Included_com_sleepycat_db_Dbt +#define _Included_com_sleepycat_db_Dbt +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: com_sleepycat_db_Dbt + * Method: finalize + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Dbt_finalize + (JNIEnv *, jobject); + +/* + * Class: com_sleepycat_db_Dbt + * Method: get_data + * Signature: ()[B + */ +JNIEXPORT jbyteArray JNICALL Java_com_sleepycat_db_Dbt_get_1data + (JNIEnv *, jobject); + +/* + * Class: com_sleepycat_db_Dbt + * Method: internal_set_data + * Signature: ([B)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Dbt_internal_1set_1data + (JNIEnv *, jobject, jbyteArray); + +/* + * Class: com_sleepycat_db_Dbt + * Method: set_offset + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Dbt_set_1offset + (JNIEnv *, jobject, jint); + +/* + * Class: com_sleepycat_db_Dbt + * Method: get_offset + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_sleepycat_db_Dbt_get_1offset + (JNIEnv *, jobject); + +/* + * Class: com_sleepycat_db_Dbt + * Method: get_size + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_sleepycat_db_Dbt_get_1size + (JNIEnv *, jobject); + +/* + * Class: com_sleepycat_db_Dbt + * Method: set_size + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Dbt_set_1size + (JNIEnv *, jobject, jint); + +/* + * Class: com_sleepycat_db_Dbt + * Method: get_ulen + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_sleepycat_db_Dbt_get_1ulen + (JNIEnv *, jobject); + +/* + * Class: com_sleepycat_db_Dbt + * Method: set_ulen + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Dbt_set_1ulen + (JNIEnv *, jobject, jint); + +/* + * Class: com_sleepycat_db_Dbt + * Method: get_dlen + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_sleepycat_db_Dbt_get_1dlen + (JNIEnv *, jobject); + +/* + * Class: com_sleepycat_db_Dbt + * Method: set_dlen + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Dbt_set_1dlen + (JNIEnv *, jobject, jint); + +/* + * Class: com_sleepycat_db_Dbt + * Method: get_doff + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_sleepycat_db_Dbt_get_1doff + (JNIEnv *, jobject); + +/* + * Class: com_sleepycat_db_Dbt + * Method: set_doff + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Dbt_set_1doff + (JNIEnv *, jobject, jint); + +/* + * Class: com_sleepycat_db_Dbt + * Method: get_flags + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_sleepycat_db_Dbt_get_1flags + (JNIEnv *, jobject); + +/* + * Class: com_sleepycat_db_Dbt + * Method: set_flags + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Dbt_set_1flags + (JNIEnv *, jobject, jint); + +/* + * Class: com_sleepycat_db_Dbt + * Method: set_recno_key_data + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Dbt_set_1recno_1key_1data + (JNIEnv *, jobject, jint); + +/* + * Class: com_sleepycat_db_Dbt + * Method: get_recno_key_data + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_sleepycat_db_Dbt_get_1recno_1key_1data + (JNIEnv *, jobject); + +/* + * Class: com_sleepycat_db_Dbt + * Method: init + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Dbt_init + (JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/db/libdb_java/java_Db.c b/db/libdb_java/java_Db.c new file mode 100644 index 000000000..5b01e5068 --- /dev/null +++ b/db/libdb_java/java_Db.c @@ -0,0 +1,964 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: java_Db.c,v 11.34 2000/11/30 00:58:38 ubell Exp $"; +#endif /* not lint */ + +#include +#include +#include + +#include "db.h" +#include "db_int.h" +#include "db_page.h" +#include "db_ext.h" +#include "java_util.h" +#include "com_sleepycat_db_Db.h" + +/* This struct is used in Db.verify and its callback */ +struct verify_callback_struct { + JNIEnv *env; + jobject streamobj; + jbyteArray bytes; + int nbytes; + jmethodID writemid; +}; + +JAVADB_WO_ACCESS_METHOD(Db, jint, flags, DB, flags) +JAVADB_WO_ACCESS_METHOD(Db, jint, h_1ffactor, DB, h_ffactor) +JAVADB_WO_ACCESS_METHOD(Db, jint, h_1nelem, DB, h_nelem) +JAVADB_WO_ACCESS_METHOD(Db, jint, lorder, DB, lorder) +JAVADB_WO_ACCESS_METHOD(Db, jint, re_1delim, DB, re_delim) +JAVADB_WO_ACCESS_METHOD(Db, jint, re_1len, DB, re_len) +JAVADB_WO_ACCESS_METHOD(Db, jint, re_1pad, DB, re_pad) +JAVADB_WO_ACCESS_METHOD(Db, jint, q_1extentsize, DB, q_extentsize) +JAVADB_WO_ACCESS_METHOD(Db, jint, bt_1maxkey, DB, bt_maxkey) +JAVADB_WO_ACCESS_METHOD(Db, jint, bt_1minkey, DB, bt_minkey) + +/* This only gets called once ever, at the beginning of execution + * and can be used to initialize unchanging methodIds, fieldIds, etc. + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_one_1time_1init + (JNIEnv *jnienv, /*Db.class*/ jclass jthisclass) +{ + COMPQUIET(jnienv, NULL); + COMPQUIET(jthisclass, NULL); +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db__1init + (JNIEnv *jnienv, /*Db*/ jobject jthis, /*DbEnv*/ jobject jdbenv, jint flags) +{ + int err; + DB *db; + DB_JAVAINFO *dbinfo; + DB_ENV *dbenv; + + dbenv = get_DB_ENV(jnienv, jdbenv); + dbinfo = get_DB_JAVAINFO(jnienv, jthis); + DB_ASSERT(dbinfo == NULL); + + err = db_create(&db, dbenv, flags); + if (verify_return(jnienv, err, 0)) { + set_private_dbobj(jnienv, name_DB, jthis, db); + dbinfo = dbji_construct(jnienv, flags); + set_private_info(jnienv, name_DB, jthis, dbinfo); + db->cj_internal = dbinfo; + } +} + +JNIEXPORT jint JNICALL Java_com_sleepycat_db_Db__1close + (JNIEnv *jnienv, /*Db*/ jobject jthis, jint flags) +{ + int err; + DB *db; + DB_JAVAINFO *dbinfo; + + db = get_DB(jnienv, jthis); + dbinfo = get_DB_JAVAINFO(jnienv, jthis); + if (!verify_non_null(jnienv, db)) + return (0); + + JAVADB_API_BEGIN(db, jthis); + + /* Null out the private data to indicate the DB is invalid. + * We do this in advance to help guard against multithreading + * issues. + */ + set_private_dbobj(jnienv, name_DB, jthis, 0); + + err = db->close(db, flags); + if (err != DB_INCOMPLETE) + verify_return(jnienv, err, 0); + dbji_dealloc(dbinfo, jnienv); + + /* don't call JAVADB_API_END - db cannot be used */ + return (err); +} + +/* We are being notified that the parent DbEnv has closed. + * Zero out the pointer to the DB, since it is no longer + * valid, to prevent mistakes. The user will get a null + * pointer exception if they try to use this Db again. + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db__1notify_1internal + (JNIEnv *jnienv, /*Db*/ jobject jthis) +{ + set_private_dbobj(jnienv, name_DB, jthis, 0); +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_append_1recno_1changed + (JNIEnv *jnienv, /*Db*/ jobject jthis, /*DbAppendRecno*/ jobject jcallback) +{ + DB *db; + DB_JAVAINFO *dbinfo; + + db = get_DB(jnienv, jthis); + if (!verify_non_null(jnienv, db)) + return; + + JAVADB_API_BEGIN(db, jthis); + dbinfo = (DB_JAVAINFO*)db->cj_internal; + dbji_set_append_recno_object(dbinfo, jnienv, db, jcallback); + JAVADB_API_END(db); +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_bt_1compare_1changed + (JNIEnv *jnienv, /*Db*/ jobject jthis, /*DbBtreeCompare*/ jobject jbtcompare) +{ + DB *db; + DB_JAVAINFO *dbinfo; + + db = get_DB(jnienv, jthis); + if (!verify_non_null(jnienv, db)) + return; + + JAVADB_API_BEGIN(db, jthis); + dbinfo = (DB_JAVAINFO*)db->cj_internal; + dbji_set_bt_compare_object(dbinfo, jnienv, db, jbtcompare); + JAVADB_API_END(db); +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_bt_1prefix_1changed + (JNIEnv *jnienv, /*Db*/ jobject jthis, /*DbBtreePrefix*/ jobject jbtprefix) +{ + DB *db; + DB_JAVAINFO *dbinfo; + + db = get_DB(jnienv, jthis); + if (!verify_non_null(jnienv, db)) + return; + + JAVADB_API_BEGIN(db, jthis); + dbinfo = (DB_JAVAINFO*)db->cj_internal; + dbji_set_bt_prefix_object(dbinfo, jnienv, db, jbtprefix); + JAVADB_API_END(db); +} + +JNIEXPORT jobject JNICALL Java_com_sleepycat_db_Db_cursor + (JNIEnv *jnienv, /*Db*/ jobject jthis, /*DbTxn*/ jobject txnid, jint flags) +{ + int err; + DBC *dbc; + DB *db = get_DB(jnienv, jthis); + DB_TXN *dbtxnid = get_DB_TXN(jnienv, txnid); + + if (!verify_non_null(jnienv, db)) + return (NULL); + err = db->cursor(db, dbtxnid, &dbc, flags); + verify_return(jnienv, err, 0); + return (get_Dbc(jnienv, dbc)); +} + +JNIEXPORT jint JNICALL Java_com_sleepycat_db_Db_del + (JNIEnv *jnienv, /*Db*/ jobject jthis, /*DbTxn*/ jobject txnid, + /*Dbt*/ jobject key, jint dbflags) +{ + int err; + DB_TXN *dbtxnid; + DB *db; + JDBT dbkey; + + err = 0; + db = get_DB(jnienv, jthis); + if (!verify_non_null(jnienv, db)) + return (0); + + JAVADB_API_BEGIN(db, jthis); + dbtxnid = get_DB_TXN(jnienv, txnid); + if (jdbt_lock(&dbkey, jnienv, key, inOp) != 0) + goto out; + + err = db->del(db, dbtxnid, &dbkey.dbt->dbt, dbflags); + if (err != DB_NOTFOUND) { + verify_return(jnienv, err, 0); + } + + out: + jdbt_unlock(&dbkey, jnienv); + JAVADB_API_END(db); + return (err); +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_dup_1compare_1changed + (JNIEnv *jnienv, /*Db*/ jobject jthis, /*DbDupCompare*/ jobject jdupcompare) +{ + DB *db; + DB_JAVAINFO *dbinfo; + + db = get_DB(jnienv, jthis); + if (!verify_non_null(jnienv, db)) + return; + + JAVADB_API_BEGIN(db, jthis); + dbinfo = (DB_JAVAINFO*)db->cj_internal; + dbji_set_dup_compare_object(dbinfo, jnienv, db, jdupcompare); + JAVADB_API_END(db); +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_err + (JNIEnv *jnienv, /*Db*/ jobject jthis, jint ecode, jstring msg) +{ + DB *db; + JSTR msg_string; + + if (jstr_lock(&msg_string, jnienv, msg) != 0) + goto out; + db = get_DB(jnienv, jthis); + if (!verify_non_null(jnienv, db)) + goto out; + + JAVADB_API_BEGIN(db, jthis); + db->err(db, ecode, msg_string.string); + JAVADB_API_END(db); + + out: + jstr_unlock(&msg_string, jnienv); +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_errx + (JNIEnv *jnienv, /*Db*/ jobject jthis, jstring msg) +{ + JSTR msg_string; + DB *db = get_DB(jnienv, jthis); + + if (jstr_lock(&msg_string, jnienv, msg) != 0) + goto out; + if (!verify_non_null(jnienv, db)) + goto out; + + JAVADB_API_BEGIN(db, jthis); + db->errx(db, msg_string.string); + JAVADB_API_END(db); + + out: + jstr_unlock(&msg_string, jnienv); +} + +JNIEXPORT jint JNICALL Java_com_sleepycat_db_Db_fd + (JNIEnv *jnienv, /*Db*/ jobject jthis) +{ + int err; + int return_value = 0; + DB *db = get_DB(jnienv, jthis); + + if (!verify_non_null(jnienv, db)) + return (0); + + JAVADB_API_BEGIN(db, jthis); + err = db->fd(db, &return_value); + verify_return(jnienv, err, 0); + JAVADB_API_END(db); + + return (return_value); +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_feedback_1changed + (JNIEnv *jnienv, /*Db*/ jobject jthis, /*DbFeedback*/ jobject jfeedback) +{ + DB *db; + DB_JAVAINFO *dbinfo; + + db = get_DB(jnienv, jthis); + if (!verify_non_null(jnienv, db)) + return; + + JAVADB_API_BEGIN(db, jthis); + dbinfo = (DB_JAVAINFO*)db->cj_internal; + dbji_set_feedback_object(dbinfo, jnienv, db, jfeedback); + JAVADB_API_END(db); +} + +JNIEXPORT jint JNICALL Java_com_sleepycat_db_Db_get + (JNIEnv *jnienv, /*Db*/ jobject jthis, /*DbTxn*/ jobject txnid, + /*Dbt*/ jobject key, /*Dbt*/ jobject data, jint flags) +{ + int err, op_flags, retry; + DB *db; + OpKind keyop, dataop; + DB_TXN *dbtxnid; + JDBT dbkey, dbdata; + + err = 0; + db = get_DB(jnienv, jthis); + if (!verify_non_null(jnienv, db)) + goto out3; + + JAVADB_API_BEGIN(db, jthis); + + /* Depending on flags, the key may be input/output. */ + keyop = inOp; + dataop = outOp; + op_flags = flags & DB_OPFLAGS_MASK; + if (op_flags == DB_SET_RECNO) { + keyop = inOutOp; + } + else if (op_flags == DB_GET_BOTH) { + keyop = inOutOp; + dataop = inOutOp; + } + + dbtxnid = get_DB_TXN(jnienv, txnid); + + if (jdbt_lock(&dbkey, jnienv, key, keyop) != 0) + goto out2; + if (jdbt_lock(&dbdata, jnienv, data, dataop) != 0) + goto out1; + for (retry = 0; retry < 3; retry++) { + err = db->get(db, dbtxnid, &dbkey.dbt->dbt, &dbdata.dbt->dbt, flags); + + /* If we failed due to lack of memory in our DBT arrays, + * retry. + */ + if (err != ENOMEM) + break; + if (!jdbt_realloc(&dbdata, jnienv)) + break; + } + if (err != DB_NOTFOUND) { + verify_return(jnienv, err, 0); + } + out1: + jdbt_unlock(&dbdata, jnienv); + out2: + jdbt_unlock(&dbkey, jnienv); + out3: + JAVADB_API_END(db); + return (err); +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_hash_1changed + (JNIEnv *jnienv, /*Db*/ jobject jthis, /*DbHash*/ jobject jhash) +{ + DB *db; + DB_JAVAINFO *dbinfo; + + db = get_DB(jnienv, jthis); + if (!verify_non_null(jnienv, db)) + return; + + JAVADB_API_BEGIN(db, jthis); + dbinfo = (DB_JAVAINFO*)db->cj_internal; + dbji_set_h_hash_object(dbinfo, jnienv, db, jhash); + JAVADB_API_END(db); +} + +JNIEXPORT jobject JNICALL Java_com_sleepycat_db_Db_join + (JNIEnv *jnienv, /*Db*/ jobject jthis, /*Dbc[]*/ jobjectArray curslist, + jint flags) +{ + int err; + DB *db = get_DB(jnienv, jthis); + int count = (*jnienv)->GetArrayLength(jnienv, curslist); + DBC **newlist = (DBC **)malloc(sizeof(DBC *) * (count+1)); + DBC *dbc; + int i; + + /* Convert the java array of Dbc's to a C array of DBC's. */ + for (i=0; iGetObjectArrayElement(jnienv, curslist, i); + if (jobj == 0) { + /* + * An embedded null in the array is treated + * as an endpoint. + */ + newlist[i] = 0; + break; + } + else { + newlist[i] = get_DBC(jnienv, jobj); + } + } + newlist[count] = 0; + + if (!verify_non_null(jnienv, db)) + return (NULL); + JAVADB_API_BEGIN(db, jthis); + + err = db->join(db, newlist, &dbc, flags); + free(newlist); + verify_return(jnienv, err, 0); + + JAVADB_API_END(db); + return (get_Dbc(jnienv, dbc)); +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_key_1range + (JNIEnv *jnienv, /*Db*/ jobject jthis, /*DbTxn*/ jobject jtxn, + /*Dbt*/ jobject jkey, jobject /*DbKeyRange*/ range, jint flags) +{ + int err; + DB *db = get_DB(jnienv, jthis); + DB_TXN *txn = get_DB_TXN(jnienv, jtxn); + JDBT dbkey; + DB_KEY_RANGE result; + jfieldID fid; + jclass krclass; + + if (!verify_non_null(jnienv, db)) + return; + JAVADB_API_BEGIN(db, jthis); + if (!verify_non_null(jnienv, range)) + return; + if (jdbt_lock(&dbkey, jnienv, jkey, inOp) != 0) + goto out; + err = db->key_range(db, txn, &dbkey.dbt->dbt, &result, flags); + if (verify_return(jnienv, err, 0)) { + /* fill in the values of the DbKeyRange structure */ + krclass = get_class(jnienv, "DbKeyRange"); + fid = (*jnienv)->GetFieldID(jnienv, krclass, "less", "D"); + (*jnienv)->SetDoubleField(jnienv, range, fid, result.less); + fid = (*jnienv)->GetFieldID(jnienv, krclass, "equal", "D"); + (*jnienv)->SetDoubleField(jnienv, range, fid, result.equal); + fid = (*jnienv)->GetFieldID(jnienv, krclass, "greater", "D"); + (*jnienv)->SetDoubleField(jnienv, range, fid, result.greater); + } + out: + jdbt_unlock(&dbkey, jnienv); + JAVADB_API_END(db); +} + +JNIEXPORT jint JNICALL Java_com_sleepycat_db_Db_put + (JNIEnv *jnienv, /*Db*/ jobject jthis, /*DbTxn*/ jobject txnid, + /*Dbt*/ jobject key, /*Dbt*/ jobject data, jint flags) +{ + int err; + DB *db; + DB_TXN *dbtxnid; + JDBT dbkey, dbdata; + + err = 0; + db = get_DB(jnienv, jthis); + dbtxnid = get_DB_TXN(jnienv, txnid); + if (!verify_non_null(jnienv, db)) + return (0); /* error will be thrown, retval doesn't matter */ + JAVADB_API_BEGIN(db, jthis); + + if (jdbt_lock(&dbkey, jnienv, key, inOp) != 0) + goto out2; + if (jdbt_lock(&dbdata, jnienv, data, inOp) != 0) + goto out1; + + if (!verify_non_null(jnienv, db)) + goto out1; + err = db->put(db, dbtxnid, &dbkey.dbt->dbt, &dbdata.dbt->dbt, flags); + if (err != DB_KEYEXIST) { + verify_return(jnienv, err, 0); + } + out1: + jdbt_unlock(&dbdata, jnienv); + out2: + jdbt_unlock(&dbkey, jnienv); + JAVADB_API_END(db); + return (err); +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_rename + (JNIEnv *jnienv, /*Db*/ jobject jthis, jstring file, + jstring database, jstring newname, jint flags) +{ + int err; + DB *db; + DB_JAVAINFO *dbinfo; + JSTR j_file; + JSTR j_database; + JSTR j_newname; + + db = get_DB(jnienv, jthis); + dbinfo = get_DB_JAVAINFO(jnienv, jthis); + if (!verify_non_null(jnienv, db)) + return; + JAVADB_API_BEGIN(db, jthis); + if (jstr_lock(&j_file, jnienv, file) != 0) + goto out3; + if (jstr_lock(&j_database, jnienv, database) != 0) + goto out2; + if (jstr_lock(&j_newname, jnienv, newname) != 0) + goto out1; + + err = db->rename(db, j_file.string, j_database.string, + j_newname.string, flags); + + verify_return(jnienv, err, EXCEPTION_FILE_NOT_FOUND); + dbji_dealloc(dbinfo, jnienv); + set_private_dbobj(jnienv, name_DB, jthis, 0); + + out1: + jstr_unlock(&j_newname, jnienv); + out2: + jstr_unlock(&j_database, jnienv); + out3: + jstr_unlock(&j_file, jnienv); + /* don't call JAVADB_API_END - db cannot be used */ +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_remove + (JNIEnv *jnienv, /*Db*/ jobject jthis, jstring file, + jstring database, jint flags) +{ + int err; + DB *db = get_DB(jnienv, jthis); + DB_JAVAINFO *dbinfo = get_DB_JAVAINFO(jnienv, jthis); + JSTR j_file; + JSTR j_database; + + dbinfo = get_DB_JAVAINFO(jnienv, jthis); + if (!verify_non_null(jnienv, db)) + return; + JAVADB_API_BEGIN(db, jthis); + if (jstr_lock(&j_file, jnienv, file) != 0) + goto out2; + if (jstr_lock(&j_database, jnienv, database) != 0) + goto out1; + err = db->remove(db, j_file.string, j_database.string, flags); + + set_private_dbobj(jnienv, name_DB, jthis, 0); + verify_return(jnienv, err, EXCEPTION_FILE_NOT_FOUND); + dbji_dealloc(dbinfo, jnienv); + + out1: + jstr_unlock(&j_database, jnienv); + out2: + jstr_unlock(&j_file, jnienv); + /* don't call JAVADB_API_END - db cannot be used */ +} + +JNIEXPORT void JNICALL + Java_com_sleepycat_db_Db_set_1pagesize + (JNIEnv *jnienv, /*Db*/ jobject jthis, jlong value) +{ + int err; + DB *db; + + db = get_DB(jnienv, jthis); + if (verify_non_null(jnienv, db)) { + JAVADB_API_BEGIN(db, jthis); + err = db->set_pagesize(db, (u_int32_t)value); + verify_return(jnienv, err, 0); + JAVADB_API_END(db); + } +} + +JNIEXPORT void JNICALL + Java_com_sleepycat_db_Db_set_1cachesize + (JNIEnv *jnienv, /*Db*/ jobject jthis, jint gbytes, jint bytes, + jint ncaches) +{ + int err; + DB *db; + + db = get_DB(jnienv, jthis); + if (verify_non_null(jnienv, db)) { + JAVADB_API_BEGIN(db, jthis); + err = db->set_cachesize(db, gbytes, bytes, ncaches); + verify_return(jnienv, err, 0); + JAVADB_API_END(db); + } +} + +JNIEXPORT void JNICALL + Java_com_sleepycat_db_Db_set_1re_1source + (JNIEnv *jnienv, /*Db*/ jobject jthis, jstring re_source) +{ + int err; + DB *db; + + db = get_DB(jnienv, jthis); + if (verify_non_null(jnienv, db)) { + JAVADB_API_BEGIN(db, jthis); + + /* XXX does the string from get_c_string ever get freed? */ + if (re_source != NULL) + err = db->set_re_source(db, get_c_string(jnienv, re_source)); + else + err = db->set_re_source(db, 0); + + verify_return(jnienv, err, 0); + JAVADB_API_END(db); + } +} + +JNIEXPORT jobject JNICALL Java_com_sleepycat_db_Db_stat + (JNIEnv *jnienv, jobject jthis, jint flags) +{ + int err; + DB *db = get_DB(jnienv, jthis); + jobject retval = NULL; + jclass dbclass; + void *statp = 0; + DB_BTREE_STAT *bstp; + DB_HASH_STAT *hstp; + DB_QUEUE_STAT *qstp; + + if (!verify_non_null(jnienv, db)) + return (NULL); + + JAVADB_API_BEGIN(db, jthis); + + err = db->stat(db, &statp, NULL, flags); + if (verify_return(jnienv, err, 0)) { + DBTYPE dbtype = db->get_type(db); + switch (dbtype) { + + /* Btree and recno share the same stat structure */ + case DB_BTREE: + case DB_RECNO: + bstp = (DB_BTREE_STAT *)statp; + retval = create_default_object(jnienv, + name_DB_BTREE_STAT); + dbclass = get_class(jnienv, name_DB_BTREE_STAT); + + /* Set the individual fields */ + set_int_field(jnienv, dbclass, retval, + "bt_magic", bstp->bt_magic); + set_int_field(jnienv, dbclass, retval, + "bt_version", bstp->bt_version); + set_int_field(jnienv, dbclass, retval, + "bt_metaflags", bstp->bt_metaflags); + set_int_field(jnienv, dbclass, retval, + "bt_nkeys", bstp->bt_nkeys); + set_int_field(jnienv, dbclass, retval, + "bt_ndata", bstp->bt_ndata); + set_int_field(jnienv, dbclass, retval, + "bt_pagesize", bstp->bt_pagesize); + set_int_field(jnienv, dbclass, retval, + "bt_maxkey", bstp->bt_maxkey); + set_int_field(jnienv, dbclass, retval, + "bt_minkey", bstp->bt_minkey); + set_int_field(jnienv, dbclass, retval, + "bt_re_len", bstp->bt_re_len); + set_int_field(jnienv, dbclass, retval, + "bt_re_pad", bstp->bt_re_pad); + set_int_field(jnienv, dbclass, retval, + "bt_levels", bstp->bt_levels); + set_int_field(jnienv, dbclass, retval, + "bt_int_pg", bstp->bt_int_pg); + set_int_field(jnienv, dbclass, retval, + "bt_leaf_pg", bstp->bt_leaf_pg); + set_int_field(jnienv, dbclass, retval, + "bt_dup_pg", bstp->bt_dup_pg); + set_int_field(jnienv, dbclass, retval, + "bt_over_pg", bstp->bt_over_pg); + set_int_field(jnienv, dbclass, retval, + "bt_free", bstp->bt_free); + set_int_field(jnienv, dbclass, retval, + "bt_int_pgfree", bstp->bt_int_pgfree); + set_int_field(jnienv, dbclass, retval, + "bt_leaf_pgfree", bstp->bt_leaf_pgfree); + set_int_field(jnienv, dbclass, retval, + "bt_dup_pgfree", bstp->bt_dup_pgfree); + set_int_field(jnienv, dbclass, retval, + "bt_over_pgfree", bstp->bt_over_pgfree); + + break; + + /* Hash stat structure */ + case DB_HASH: + hstp = (DB_HASH_STAT *)statp; + retval = create_default_object(jnienv, + name_DB_HASH_STAT); + dbclass = get_class(jnienv, name_DB_HASH_STAT); + + /* Set the individual fields */ + set_int_field(jnienv, dbclass, retval, + "hash_magic", hstp->hash_magic); + set_int_field(jnienv, dbclass, retval, + "hash_version", hstp->hash_version); + set_int_field(jnienv, dbclass, retval, + "hash_metaflags", hstp->hash_metaflags); + set_int_field(jnienv, dbclass, retval, + "hash_nkeys", hstp->hash_nkeys); + set_int_field(jnienv, dbclass, retval, + "hash_ndata", hstp->hash_ndata); + set_int_field(jnienv, dbclass, retval, + "hash_pagesize", hstp->hash_pagesize); + set_int_field(jnienv, dbclass, retval, + "hash_nelem", hstp->hash_nelem); + set_int_field(jnienv, dbclass, retval, + "hash_ffactor", hstp->hash_ffactor); + set_int_field(jnienv, dbclass, retval, + "hash_buckets", hstp->hash_buckets); + set_int_field(jnienv, dbclass, retval, + "hash_free", hstp->hash_free); + set_int_field(jnienv, dbclass, retval, + "hash_bfree", hstp->hash_bfree); + set_int_field(jnienv, dbclass, retval, + "hash_bigpages", hstp->hash_bigpages); + set_int_field(jnienv, dbclass, retval, + "hash_big_bfree", hstp->hash_big_bfree); + set_int_field(jnienv, dbclass, retval, + "hash_overflows", hstp->hash_overflows); + set_int_field(jnienv, dbclass, retval, + "hash_ovfl_free", hstp->hash_ovfl_free); + set_int_field(jnienv, dbclass, retval, + "hash_dup", hstp->hash_dup); + set_int_field(jnienv, dbclass, retval, + "hash_dup_free", hstp->hash_dup_free); + + break; + + case DB_QUEUE: + qstp = (DB_QUEUE_STAT *)statp; + retval = create_default_object(jnienv, + name_DB_QUEUE_STAT); + dbclass = get_class(jnienv, name_DB_QUEUE_STAT); + + /* Set the individual fields */ + set_int_field(jnienv, dbclass, retval, + "qs_magic", qstp->qs_magic); + set_int_field(jnienv, dbclass, retval, + "qs_version", qstp->qs_version); + set_int_field(jnienv, dbclass, retval, + "qs_metaflags", qstp->qs_metaflags); + set_int_field(jnienv, dbclass, retval, + "qs_nkeys", qstp->qs_nkeys); + set_int_field(jnienv, dbclass, retval, + "qs_ndata", qstp->qs_ndata); + set_int_field(jnienv, dbclass, retval, + "qs_pagesize", qstp->qs_pagesize); + set_int_field(jnienv, dbclass, retval, + "qs_pages", qstp->qs_pages); + set_int_field(jnienv, dbclass, retval, + "qs_re_len", qstp->qs_re_len); + set_int_field(jnienv, dbclass, retval, + "qs_re_pad", qstp->qs_re_pad); + set_int_field(jnienv, dbclass, retval, + "qs_pgfree", qstp->qs_pgfree); + set_int_field(jnienv, dbclass, retval, + "qs_first_recno", qstp->qs_first_recno); + set_int_field(jnienv, dbclass, retval, + "qs_cur_recno", qstp->qs_cur_recno); + break; + + /* That's all the database types we're aware of! */ + default: + report_exception(jnienv, + "Db.stat not implemented for types" + "other than HASH, BTREE and RECNO", + EINVAL, 0); + break; + } + free(statp); + } + JAVADB_API_END(db); + return (retval); +} + +JNIEXPORT jint JNICALL Java_com_sleepycat_db_Db_sync + (JNIEnv *jnienv, /*Db*/ jobject jthis, jint flags) +{ + int err; + DB *db = get_DB(jnienv, jthis); + + if (!verify_non_null(jnienv, db)) + return (0); + JAVADB_API_BEGIN(db, jthis); + err = db->sync(db, flags); + if (err != DB_INCOMPLETE) + verify_return(jnienv, err, 0); + JAVADB_API_END(db); + return (err); +} + +JNIEXPORT jboolean JNICALL Java_com_sleepycat_db_Db_get_1byteswapped + (JNIEnv *jnienv, /*Db*/ jobject jthis) +{ + DB *db; + jboolean retval; + + db = get_DB(jnienv, jthis); + if (!verify_non_null(jnienv, db)) + return (0); + + JAVADB_API_BEGIN(db, jthis); + retval = db->get_byteswapped(db) ? 1 : 0; + JAVADB_API_END(db); + return (retval); +} + +JNIEXPORT jint JNICALL Java_com_sleepycat_db_Db_get_1type + (JNIEnv *jnienv, /*Db*/ jobject jthis) +{ + DB *db; + + db = get_DB(jnienv, jthis); + if (!verify_non_null(jnienv, db)) + return (0); + + return ((jint)db->type); +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db__1open + (JNIEnv *jnienv, /*Db*/ jobject jthis, jstring file, jstring database, + jint type, jint flags, jint mode) +{ + int err; + DB *db; + JSTR dbfile; + JSTR dbdatabase; + + /* Java is assumed to be threaded. */ + flags |= DB_THREAD; + + db = get_DB(jnienv, jthis); + if (jstr_lock(&dbfile, jnienv, file) != 0) + goto out2; + if (jstr_lock(&dbdatabase, jnienv, database) != 0) + goto out1; + if (verify_non_null(jnienv, db)) { + JAVADB_API_BEGIN(db, jthis); + err = db->open(db, dbfile.string, dbdatabase.string, + (DBTYPE)type, flags, mode); + verify_return(jnienv, err, EXCEPTION_FILE_NOT_FOUND); + JAVADB_API_END(db); + } + out1: + jstr_unlock(&dbdatabase, jnienv); + out2: + jstr_unlock(&dbfile, jnienv); +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_upgrade + (JNIEnv *jnienv, /*Db*/ jobject jthis, jstring name, + jint flags) +{ + int err; + DB *db = get_DB(jnienv, jthis); + JSTR j_name; + + if (verify_non_null(jnienv, db)) { + JAVADB_API_BEGIN(db, jthis); + if (jstr_lock(&j_name, jnienv, name) != 0) + goto out; + err = db->upgrade(db, j_name.string, flags); + verify_return(jnienv, err, 0); + JAVADB_API_END(db); + } + out: + jstr_unlock(&j_name, jnienv); +} + +static int java_verify_callback(void *handle, const void *str_arg) +{ + char *str; + struct verify_callback_struct *vc; + int len; + jthrowable except; + JNIEnv *jnienv; + + str = (char *)str_arg; + vc = (struct verify_callback_struct *)handle; + jnienv = vc->env; + len = strlen(str)+1; + if (len > vc->nbytes) { + vc->nbytes = len; + vc->bytes = (*jnienv)->NewByteArray(jnienv, len); + } + (*jnienv)->SetByteArrayRegion(jnienv, vc->bytes, 0, len, (jbyte*)str); + (*jnienv)->CallVoidMethod(jnienv, vc->streamobj, + vc->writemid, vc->bytes, 0, len-1); + + if ((except = (*jnienv)->ExceptionOccurred(jnienv)) != NULL) + return (EIO); + + return (0); +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db_verify + (JNIEnv *jnienv, /*Db*/ jobject jthis, jstring name, + jstring subdb, jobject stream, jint flags) +{ + int err; + DB *db; + JSTR j_name; + JSTR j_subdb; + struct verify_callback_struct vcs; + jclass streamclass; + + db = get_DB(jnienv, jthis); + if (!verify_non_null(jnienv, db)) + return; + JAVADB_API_BEGIN(db, jthis); + + if (jstr_lock(&j_name, jnienv, name) != 0) + goto out2; + if (jstr_lock(&j_subdb, jnienv, subdb) != 0) + goto out1; + + /* set up everything we need for the callbacks */ + vcs.env = jnienv; + vcs.streamobj = stream; + vcs.nbytes = 100; + vcs.bytes = (*jnienv)->NewByteArray(jnienv, vcs.nbytes); + + /* get the method ID for OutputStream.write(byte[], int, int); */ + streamclass = (*jnienv)->FindClass(jnienv, "java/io/OutputStream"); + vcs.writemid = (*jnienv)->GetMethodID(jnienv, streamclass, + "write", "([BII)V"); + + /* invoke verify - this will invoke the callback repeatedly. */ + err = __db_verify_internal(db, j_name.string, j_subdb.string, + &vcs, java_verify_callback, flags); + verify_return(jnienv, err, 0); + +out1: + jstr_unlock(&j_subdb, jnienv); +out2: + jstr_unlock(&j_name, jnienv); + JAVADB_API_END(db); +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_Db__1finalize + (JNIEnv *jnienv, jobject jthis, + jobject /*DbErrcall*/ errcall, jstring errpfx) +{ + DB_JAVAINFO *dbinfo; + DB *db; + + dbinfo = get_DB_JAVAINFO(jnienv, jthis); + db = get_DB(jnienv, jthis); + DB_ASSERT(dbinfo != NULL); + + /* Note: We can never be sure if the underlying DB is attached to + * a DB_ENV that was already closed. Sure, that's a user error, + * but it shouldn't crash the VM. Therefore, we cannot just + * automatically close if the handle indicates we are not yet + * closed. The best we can do is detect this and report it. + */ + if (db != NULL) { + /* If this error occurs, this object was never closed. */ + report_errcall(jnienv, errcall, errpfx, + "Db.finalize: open Db object destroyed"); + } + + /* Shouldn't see this object again, but just in case */ + set_private_dbobj(jnienv, name_DB, jthis, 0); + set_private_info(jnienv, name_DB, jthis, 0); + + dbji_destroy(dbinfo, jnienv); +} diff --git a/db/libdb_java/java_DbEnv.c b/db/libdb_java/java_DbEnv.c new file mode 100644 index 000000000..ff9207dd2 --- /dev/null +++ b/db/libdb_java/java_DbEnv.c @@ -0,0 +1,1300 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: java_DbEnv.c,v 11.37 2001/01/11 18:19:52 bostic Exp $"; +#endif /* not lint */ + +#include +#include +#include + +#include "db.h" +#include "db_int.h" +#include "java_util.h" +#include "com_sleepycat_db_DbEnv.h" + +/* We keep these lined up, and alphabetical by field name, + * for comparison with C++'s list. + */ +JAVADB_WO_ACCESS_STRING(DbEnv, data_1dir, DB_ENV, data_dir) +JAVADB_WO_ACCESS_METHOD(DbEnv, jint, lg_1bsize, DB_ENV, lg_bsize) +JAVADB_WO_ACCESS_STRING(DbEnv, lg_1dir, DB_ENV, lg_dir) +JAVADB_WO_ACCESS_METHOD(DbEnv, jint, lg_1max, DB_ENV, lg_max) +JAVADB_WO_ACCESS_METHOD(DbEnv, jint, lk_1detect, DB_ENV, lk_detect) +JAVADB_WO_ACCESS_METHOD(DbEnv, jint, lk_1max, DB_ENV, lk_max) +JAVADB_WO_ACCESS_METHOD(DbEnv, jint, lk_1max_1locks, DB_ENV, lk_max_locks) +JAVADB_WO_ACCESS_METHOD(DbEnv, jint, lk_1max_1lockers, DB_ENV, lk_max_lockers) +JAVADB_WO_ACCESS_METHOD(DbEnv, jint, lk_1max_1objects, DB_ENV, lk_max_objects) +/* mp_mmapsize is declared below, it needs an extra cast */ +JAVADB_WO_ACCESS_METHOD(DbEnv, jint, mutexlocks, DB_ENV, mutexlocks) +JAVADB_WO_ACCESS_STRING(DbEnv, tmp_1dir, DB_ENV, tmp_dir) +JAVADB_WO_ACCESS_METHOD(DbEnv, jint, tx_1max, DB_ENV, tx_max) + +static void DbEnv_errcall_callback(const char *prefix, char *message) +{ + JNIEnv *jnienv; + DB_ENV_JAVAINFO *envinfo = (DB_ENV_JAVAINFO *)prefix; + jstring pre; + + /* Note: these error cases are "impossible", and would + * normally warrant an exception. However, without + * a jnienv, we cannot throw an exception... + * We don't want to trap or exit, since the point of + * this facility is for the user to completely control + * error situations. + */ + if (envinfo == NULL) { + /* Something is *really* wrong here, the + * prefix is set in every environment created. + */ + fprintf(stderr, "Error callback failed!\n"); + fprintf(stderr, "error: %s\n", message); + return; + } + + /* Should always succeed... */ + jnienv = dbjie_get_jnienv(envinfo); + + if (jnienv == NULL) { + + /* But just in case... */ + fprintf(stderr, "Cannot attach to current thread!\n"); + fprintf(stderr, "error: %s\n", message); + return; + } + + pre = dbjie_get_errpfx(envinfo, jnienv); + report_errcall(jnienv, dbjie_get_errcall(envinfo), pre, message); +} + +static void DbEnv_initialize(JNIEnv *jnienv, DB_ENV *dbenv, + /*DbEnv*/ jobject jenv, + /*DbErrcall*/ jobject jerrcall, + int is_dbopen) +{ + DB_ENV_JAVAINFO *envinfo; + + envinfo = get_DB_ENV_JAVAINFO(jnienv, jenv); + DB_ASSERT(envinfo == NULL); + envinfo = dbjie_construct(jnienv, jerrcall, is_dbopen); + set_private_info(jnienv, name_DB_ENV, jenv, envinfo); + dbenv->set_errpfx(dbenv, (const char*)envinfo); + dbenv->set_errcall(dbenv, DbEnv_errcall_callback); + dbenv->cj_internal = envinfo; + set_private_dbobj(jnienv, name_DB_ENV, jenv, dbenv); +} + +/* This is called when this DbEnv was made on behalf of a Db + * created directly (without a parent DbEnv), and the Db is + * being closed. We'll zero out the pointer to the DB_ENV, + * since it is no longer valid, to prevent mistakes. + */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv__1notify_1db_1close + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis) +{ + DB_ENV_JAVAINFO *dbenvinfo; + + set_private_dbobj(jnienv, name_DB_ENV, jthis, 0); + dbenvinfo = get_DB_ENV_JAVAINFO(jnienv, jthis); + if (dbenvinfo != NULL) + dbjie_dealloc(dbenvinfo, jnienv); +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_feedback_1changed + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis, /*DbFeedback*/ jobject jfeedback) +{ + DB_ENV *dbenv; + DB_ENV_JAVAINFO *dbenvinfo; + + dbenv = get_DB_ENV(jnienv, jthis); + dbenvinfo = get_DB_ENV_JAVAINFO(jnienv, jthis); + if (!verify_non_null(jnienv, dbenv) || + !verify_non_null(jnienv, dbenvinfo)) + return; + + JAVADB_ENV_API_BEGIN(dbenv, jthis); + dbjie_set_feedback_object(dbenvinfo, jnienv, dbenv, jfeedback); + JAVADB_ENV_API_END(dbenv); +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv__1init + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis, jobject /*DbErrcall*/ jerrcall, + jint flags) +{ + int err; + DB_ENV *dbenv; + + err = db_env_create(&dbenv, flags); + if (verify_return(jnienv, err, 0)) + DbEnv_initialize(jnienv, dbenv, jthis, jerrcall, 0); +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv__1init_1using_1db + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis, jobject /*DbErrcall*/ jerrcall, + /*Db*/ jobject jdb) +{ + DB_ENV *dbenv; + DB *db; + + db = get_DB(jnienv, jdb); + dbenv = db->dbenv; + DbEnv_initialize(jnienv, dbenv, jthis, jerrcall, 1); +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_open + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis, jstring db_home, + jint flags, jint mode) +{ + int err; + DB_ENV *dbenv; + JSTR j_home; + DB_ENV_JAVAINFO *dbenvinfo; + + dbenv = get_DB_ENV(jnienv, jthis); + dbenvinfo = get_DB_ENV_JAVAINFO(jnienv, jthis); + if (!verify_non_null(jnienv, dbenv) || + !verify_non_null(jnienv, dbenvinfo)) + return; + JAVADB_ENV_API_BEGIN(dbenv, jthis); + if (jstr_lock(&j_home, jnienv, db_home) != 0) + goto out; + + /* Java is assumed to be threaded. */ + flags |= DB_THREAD; + + err = dbenv->open(dbenv, j_home.string, flags, mode); + verify_return(jnienv, err, EXCEPTION_FILE_NOT_FOUND); + out: + jstr_unlock(&j_home, jnienv); + JAVADB_ENV_API_END(dbenv); +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_remove + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis, jstring db_home, jint flags) +{ + DB_ENV *dbenv; + DB_ENV_JAVAINFO *dbenvinfo; + JSTR j_home; + int err = 0; + + dbenv = get_DB_ENV(jnienv, jthis); + dbenvinfo = get_DB_ENV_JAVAINFO(jnienv, jthis); + if (!verify_non_null(jnienv, dbenv)) + return; + JAVADB_ENV_API_BEGIN(dbenv, jthis); + if (jstr_lock(&j_home, jnienv, db_home) != 0) + goto out; + + err = dbenv->remove(dbenv, j_home.string, flags); + set_private_dbobj(jnienv, name_DB_ENV, jthis, 0); + + if (dbenvinfo != NULL) + dbjie_dealloc(dbenvinfo, jnienv); + + verify_return(jnienv, err, 0); + out: + jstr_unlock(&j_home, jnienv); + /* don't call JAVADB_ENV_API_END - env cannot be used */ +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv__1close + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis, jint flags) +{ + int err; + DB_ENV *dbenv; + DB_ENV_JAVAINFO *dbenvinfo; + + dbenv = get_DB_ENV(jnienv, jthis); + dbenvinfo = get_DB_ENV_JAVAINFO(jnienv, jthis); + if (!verify_non_null(jnienv, dbenv)) + return; + + JAVADB_ENV_API_BEGIN(dbenv, jthis); + + err = dbenv->close(dbenv, flags); + set_private_dbobj(jnienv, name_DB_ENV, jthis, 0); + + if (dbenvinfo != NULL) + dbjie_dealloc(dbenvinfo, jnienv); + + /* Throw an exception if the close failed. */ + verify_return(jnienv, err, 0); + + /* don't call JAVADB_ENV_API_END - env cannot be used */ +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_err + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis, jint ecode, jstring msg) +{ + JSTR msg_string; + DB_ENV *dbenv; + + dbenv = get_DB_ENV(jnienv, jthis); + if (!verify_non_null(jnienv, dbenv)) + return; + + JAVADB_ENV_API_BEGIN(dbenv, jthis); + + if (jstr_lock(&msg_string, jnienv, msg) != 0) + goto out; + + dbenv->err(dbenv, ecode, msg_string.string); + out: + jstr_unlock(&msg_string, jnienv); + JAVADB_ENV_API_END(dbenv); +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_errx + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis, jstring msg) +{ + JSTR msg_string; + DB_ENV *dbenv; + + dbenv = get_DB_ENV(jnienv, jthis); + if (!verify_non_null(jnienv, dbenv)) + return; + + JAVADB_ENV_API_BEGIN(dbenv, jthis); + + if (jstr_lock(&msg_string, jnienv, msg) != 0) + goto out; + + dbenv->errx(dbenv, msg_string.string); + out: + jstr_unlock(&msg_string, jnienv); + JAVADB_ENV_API_END(dbenv); +} + +/*static*/ +JNIEXPORT jstring JNICALL Java_com_sleepycat_db_DbEnv_strerror + (JNIEnv *jnienv, jclass jthis_class, jint ecode) +{ + const char *message; + + COMPQUIET(jthis_class, NULL); + message = db_strerror(ecode); + return (get_java_string(jnienv, message)); +} + +JNIEXPORT void JNICALL + Java_com_sleepycat_db_DbEnv_set_1cachesize + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis, jint gbytes, jint bytes, + jint ncaches) +{ + DB_ENV *dbenv; + int err; + + dbenv = get_DB_ENV(jnienv, jthis); + if (verify_non_null(jnienv, dbenv)) { + JAVADB_ENV_API_BEGIN(dbenv, jthis); + err = dbenv->set_cachesize(dbenv, gbytes, bytes, ncaches); + verify_return(jnienv, err, 0); + JAVADB_ENV_API_END(dbenv); + } +} + +JNIEXPORT void JNICALL + Java_com_sleepycat_db_DbEnv_set_1flags + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis, jint flags, jint onoff) +{ + DB_ENV *dbenv; + int err; + + dbenv = get_DB_ENV(jnienv, jthis); + if (verify_non_null(jnienv, dbenv)) { + JAVADB_ENV_API_BEGIN(dbenv, jthis); + err = dbenv->set_flags(dbenv, flags, onoff); + verify_return(jnienv, err, 0); + JAVADB_ENV_API_END(dbenv); + } +} + +JNIEXPORT void JNICALL + Java_com_sleepycat_db_DbEnv_set_1mp_1mmapsize + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis, jlong value) +{ + DB_ENV *dbenv; + int err; + + dbenv = get_DB_ENV(jnienv, jthis); + if (verify_non_null(jnienv, dbenv)) { + JAVADB_ENV_API_BEGIN(dbenv, jthis); + err = dbenv->set_mp_mmapsize(dbenv, (size_t)value); + verify_return(jnienv, err, 0); + JAVADB_ENV_API_END(dbenv); + } +} + +/*static*/ +JNIEXPORT void JNICALL + Java_com_sleepycat_db_DbEnv_set_1pageyield + (JNIEnv *jnienv, jclass jthis_class, jint value) +{ + int err; + + COMPQUIET(jthis_class, NULL); + err = db_env_set_pageyield(value); + verify_return(jnienv, err, 0); +} + +/*static*/ +JNIEXPORT void JNICALL + Java_com_sleepycat_db_DbEnv_set_1panicstate + (JNIEnv *jnienv, jclass jthis_class, jint value) +{ + int err; + + COMPQUIET(jthis_class, NULL); + err = db_env_set_panicstate(value); + verify_return(jnienv, err, 0); +} + +/*static*/ +JNIEXPORT void JNICALL + Java_com_sleepycat_db_DbEnv_set_1region_1init + (JNIEnv *jnienv, jclass jthis_class, jint value) +{ + int err; + + COMPQUIET(jthis_class, NULL); + err = db_env_set_region_init(value); + verify_return(jnienv, err, 0); +} + +/*static*/ +JNIEXPORT void JNICALL + Java_com_sleepycat_db_DbEnv_set_1tas_1spins + (JNIEnv *jnienv, jclass jthis_class, jint value) +{ + int err; + + COMPQUIET(jthis_class, NULL); + err = db_env_set_tas_spins(value); + verify_return(jnienv, err, 0); +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_recovery_1init_1changed + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis, /*DbRecoveryInit*/ jobject jrecoveryinit) +{ + DB_ENV *dbenv; + DB_ENV_JAVAINFO *dbenvinfo; + + dbenv = get_DB_ENV(jnienv, jthis); + dbenvinfo = get_DB_ENV_JAVAINFO(jnienv, jthis); + if (!verify_non_null(jnienv, dbenv) || + !verify_non_null(jnienv, dbenv)) + return; + + JAVADB_ENV_API_BEGIN(dbenv, jthis); + dbjie_set_recovery_init_object(dbenvinfo, jnienv, dbenv, jrecoveryinit); + JAVADB_ENV_API_END(dbenv); +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_set_1lk_1conflicts + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis, jobjectArray array) +{ + DB_ENV *dbenv; + DB_ENV_JAVAINFO *dbenvinfo; + int err; + jsize i, len; + unsigned char *newarr; + + dbenv = get_DB_ENV(jnienv, jthis); + dbenvinfo = get_DB_ENV_JAVAINFO(jnienv, jthis); + if (!verify_non_null(jnienv, dbenv) || + !verify_non_null(jnienv, dbenvinfo)) + return; + + JAVADB_ENV_API_BEGIN(dbenv, jthis); + + len = (*jnienv)->GetArrayLength(jnienv, array); + + newarr = (unsigned char *)malloc(sizeof(unsigned char) * len * len); + + for (i=0; iGetObjectArrayElement(jnienv, array, i); + (*jnienv)->GetByteArrayRegion(jnienv, (jbyteArray)subArray, + 0, len, + (jbyte *)&newarr[i*len]); + } + dbjie_set_conflict(dbenvinfo, newarr); + err = dbenv->set_lk_conflicts(dbenv, newarr, len); + verify_return(jnienv, err, 0); + JAVADB_ENV_API_END(dbenv); +} + +JNIEXPORT void JNICALL + Java_com_sleepycat_db_DbEnv_set_1server + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis, jstring jhost, jlong tsec, + jlong ssec, jint flags) +{ + int err; + DB_ENV *dbenv = get_DB_ENV(jnienv, jthis); + const char *host = (*jnienv)->GetStringUTFChars(jnienv, jhost, NULL); + + if (verify_non_null(jnienv, dbenv)) { + JAVADB_ENV_API_BEGIN(dbenv, jthis); + err = dbenv->set_server(dbenv, (char *)host, + (long)tsec, (long)ssec, flags); + + /* Throw an exception if the call failed. */ + verify_return(jnienv, err, 0); + JAVADB_ENV_API_END(dbenv); + } +} + +JNIEXPORT void JNICALL + Java_com_sleepycat_db_DbEnv_set_1shm_1key + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis, jlong shm_key) +{ + int err; + DB_ENV *dbenv = get_DB_ENV(jnienv, jthis); + + if (verify_non_null(jnienv, dbenv)) { + JAVADB_ENV_API_BEGIN(dbenv, jthis); + err = dbenv->set_shm_key(dbenv, (long)shm_key); + + /* Throw an exception if the call failed. */ + verify_return(jnienv, err, 0); + JAVADB_ENV_API_END(dbenv); + } +} + +JNIEXPORT void JNICALL + Java_com_sleepycat_db_DbEnv__1set_1tx_1timestamp + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis, jlong seconds) +{ + int err; + DB_ENV *dbenv = get_DB_ENV(jnienv, jthis); + time_t time = seconds; + + if (verify_non_null(jnienv, dbenv)) { + JAVADB_ENV_API_BEGIN(dbenv, jthis); + err = dbenv->set_tx_timestamp(dbenv, &time); + + /* Throw an exception if the call failed. */ + verify_return(jnienv, err, 0); + JAVADB_ENV_API_END(dbenv); + } +} + +JNIEXPORT void JNICALL + Java_com_sleepycat_db_DbEnv_set_1verbose + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis, jint which, jint onoff) +{ + int err; + DB_ENV *dbenv = get_DB_ENV(jnienv, jthis); + + if (verify_non_null(jnienv, dbenv)) { + JAVADB_ENV_API_BEGIN(dbenv, jthis); + err = dbenv->set_verbose(dbenv, which, onoff); + + /* Throw an exception if the call failed. */ + verify_return(jnienv, err, 0); + JAVADB_ENV_API_END(dbenv); + } +} + +/*static*/ +JNIEXPORT jint JNICALL Java_com_sleepycat_db_DbEnv_get_1version_1major + (JNIEnv * jnienv, jclass this_class) +{ + COMPQUIET(jnienv, NULL); + COMPQUIET(this_class, NULL); + + return (DB_VERSION_MAJOR); +} + +/*static*/ +JNIEXPORT jint JNICALL Java_com_sleepycat_db_DbEnv_get_1version_1minor + (JNIEnv * jnienv, jclass this_class) +{ + COMPQUIET(jnienv, NULL); + COMPQUIET(this_class, NULL); + + return (DB_VERSION_MINOR); +} + +/*static*/ +JNIEXPORT jint JNICALL Java_com_sleepycat_db_DbEnv_get_1version_1patch + (JNIEnv * jnienv, jclass this_class) +{ + COMPQUIET(jnienv, NULL); + COMPQUIET(this_class, NULL); + + return (DB_VERSION_PATCH); +} + +/*static*/ +JNIEXPORT jstring JNICALL Java_com_sleepycat_db_DbEnv_get_1version_1string + (JNIEnv *jnienv, jclass this_class) +{ + COMPQUIET(this_class, NULL); + + return ((*jnienv)->NewStringUTF(jnienv, DB_VERSION_STRING)); +} + +JNIEXPORT jint JNICALL Java_com_sleepycat_db_DbEnv_lock_1id + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis) +{ + int err; + u_int32_t id; + DB_ENV *dbenv = get_DB_ENV(jnienv, jthis); + + if (!verify_non_null(jnienv, dbenv)) + return (-1); + JAVADB_ENV_API_BEGIN(dbenv, jthis); + err = lock_id(dbenv, &id); + verify_return(jnienv, err, 0); + JAVADB_ENV_API_END(dbenv); + return (id); +} + +JNIEXPORT jobject JNICALL Java_com_sleepycat_db_DbEnv_lock_1stat + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis) +{ + int err; + DB_ENV *dbenv = get_DB_ENV(jnienv, jthis); + DB_LOCK_STAT *statp = NULL; + jobject retval = NULL; + jclass dbclass; + + if (!verify_non_null(jnienv, dbenv)) + return (NULL); + JAVADB_ENV_API_BEGIN(dbenv, jthis); + + /* We cannot use the default allocator (on Win* platforms anyway) + * because it often causes problems when we free storage + * in a DLL that was allocated in another DLL. Using + * our own allocator (ours just calls malloc!) ensures + * that there is no mismatch. + */ + err = lock_stat(dbenv, &statp, NULL); + if (verify_return(jnienv, err, 0)) { + retval = create_default_object(jnienv, name_DB_LOCK_STAT); + dbclass = get_class(jnienv, name_DB_LOCK_STAT); + + /* Set the individual fields */ + set_int_field(jnienv, dbclass, retval, + "st_maxlocks", statp->st_maxlocks); + set_int_field(jnienv, dbclass, retval, + "st_nmodes", statp->st_nmodes); + set_int_field(jnienv, dbclass, retval, + "st_nlockers", statp->st_nlockers); + set_int_field(jnienv, dbclass, retval, + "st_nconflicts", statp->st_nconflicts); + set_int_field(jnienv, dbclass, retval, + "st_nrequests", statp->st_nrequests); + set_int_field(jnienv, dbclass, retval, + "st_nreleases", statp->st_nreleases); + set_int_field(jnienv, dbclass, retval, + "st_ndeadlocks", statp->st_ndeadlocks); + set_int_field(jnienv, dbclass, retval, + "st_region_wait", statp->st_region_wait); + set_int_field(jnienv, dbclass, retval, + "st_region_nowait", statp->st_region_nowait); + set_int_field(jnienv, dbclass, retval, + "st_regsize", statp->st_regsize); + + free(statp); + } + JAVADB_ENV_API_END(dbenv); + return (retval); +} + +JNIEXPORT jint JNICALL Java_com_sleepycat_db_DbEnv_lock_1detect + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis, jint atype, jint flags) +{ + int err; + DB_ENV *dbenv = get_DB_ENV(jnienv, jthis); + int aborted; + + if (!verify_non_null(jnienv, dbenv)) + return (0); + JAVADB_ENV_API_BEGIN(dbenv, jthis); + err = lock_detect(dbenv, atype, flags, &aborted); + verify_return(jnienv, err, 0); + JAVADB_ENV_API_END(dbenv); + return (aborted); +} + +JNIEXPORT /*DbLock*/ jobject JNICALL Java_com_sleepycat_db_DbEnv_lock_1get + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis, /*u_int32_t*/ jint locker, + jint flags, /*const Dbt*/ jobject obj, /*db_lockmode_t*/ jint lock_mode) +{ + int err; + DB_ENV *dbenv; + DB_LOCK *dblock; + JDBT dbobj; + /*DbLock*/ jobject retval; + + dbenv = get_DB_ENV(jnienv, jthis); + if (!verify_non_null(jnienv, dbenv)) + return (NULL); + + JAVADB_ENV_API_BEGIN(dbenv, jthis); + dblock = (DB_LOCK*)malloc(sizeof(DB_LOCK)); + memset(dblock, 0, sizeof(DB_LOCK)); + err = 0; + retval = NULL; + if (jdbt_lock(&dbobj, jnienv, obj, inOp) != 0) + goto out; + + err = lock_get(dbenv, locker, flags, &dbobj.dbt->dbt, + (db_lockmode_t)lock_mode, dblock); + if (verify_return(jnienv, err, 0)) { + retval = create_default_object(jnienv, name_DB_LOCK); + set_private_dbobj(jnienv, name_DB_LOCK, retval, dblock); + } + out: + jdbt_unlock(&dbobj, jnienv); + JAVADB_ENV_API_END(dbenv); + return (retval); +} + +JNIEXPORT jobjectArray JNICALL Java_com_sleepycat_db_DbEnv_log_1archive + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis, jint flags) +{ + int err, len, i; + char** ret; + jclass stringClass; + jobjectArray strarray; + DB_ENV *dbenv; + + dbenv = get_DB_ENV(jnienv, jthis); + strarray = NULL; + if (!verify_non_null(jnienv, dbenv)) + return (0); + JAVADB_ENV_API_BEGIN(dbenv, jthis); + err = log_archive(dbenv, &ret, flags, 0); + if (!verify_return(jnienv, err, 0)) + return (0); + + if (ret != NULL) { + len = 0; + while (ret[len] != NULL) + len++; + stringClass = (*jnienv)->FindClass(jnienv, "java/lang/String"); + strarray = (*jnienv)->NewObjectArray(jnienv, len, + stringClass, 0); + for (i=0; iNewStringUTF(jnienv, ret[i]); + (*jnienv)->SetObjectArrayElement(jnienv, strarray, + i, str); + } + } + JAVADB_ENV_API_END(dbenv); + return (strarray); +} + +JNIEXPORT jint JNICALL Java_com_sleepycat_db_DbEnv_log_1compare + (JNIEnv *jnienv, jclass jthis_class, + /*DbLsn*/ jobject lsn0, /*DbLsn*/ jobject lsn1) +{ + DB_LSN *dblsn0; + DB_LSN *dblsn1; + + COMPQUIET(jthis_class, NULL); + dblsn0 = get_DB_LSN(jnienv, lsn0); + dblsn1 = get_DB_LSN(jnienv, lsn1); + + return (log_compare(dblsn0, dblsn1)); +} + +JNIEXPORT jstring JNICALL Java_com_sleepycat_db_DbEnv_log_1file + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis, /*DbLsn*/ jobject lsn) +{ + int err; + DB_ENV *dbenv = get_DB_ENV(jnienv, jthis); + DB_LSN *dblsn = get_DB_LSN(jnienv, lsn); + char filename[FILENAME_MAX+1] = ""; + + if (!verify_non_null(jnienv, dbenv)) + return (NULL); + + JAVADB_ENV_API_BEGIN(dbenv, jthis); + + err = log_file(dbenv, dblsn, filename, FILENAME_MAX); + verify_return(jnienv, err, 0); + filename[FILENAME_MAX] = '\0'; /* just to be sure */ + JAVADB_ENV_API_END(dbenv); + return (get_java_string(jnienv, filename)); +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_log_1flush + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis, /*DbLsn*/ jobject lsn) +{ + int err; + DB_ENV *dbenv = get_DB_ENV(jnienv, jthis); + DB_LSN *dblsn = get_DB_LSN(jnienv, lsn); + + if (!verify_non_null(jnienv, dbenv)) + return; + + JAVADB_ENV_API_BEGIN(dbenv, jthis); + + err = log_flush(dbenv, dblsn); + verify_return(jnienv, err, 0); + JAVADB_ENV_API_END(dbenv); +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_log_1get + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis, /*DbLsn*/ jobject lsn, + /*DbDbt*/ jobject data, jint flags) +{ + int err, retry; + DB_ENV *dbenv; + DB_LSN *dblsn; + JDBT dbdata; + + dbenv = get_DB_ENV(jnienv, jthis); + dblsn = get_DB_LSN(jnienv, lsn); + + if (!verify_non_null(jnienv, dbenv)) + return; + + JAVADB_ENV_API_BEGIN(dbenv, jthis); + + if (jdbt_lock(&dbdata, jnienv, data, outOp) != 0) + goto out; + + for (retry = 0; retry < 3; retry++) { + err = log_get(dbenv, dblsn, &dbdata.dbt->dbt, flags); + /* If we failed due to lack of memory in our DBT arrays, + * retry. + */ + if (err != ENOMEM) + break; + if (!jdbt_realloc(&dbdata, jnienv)) + break; + } + + verify_return(jnienv, err, 0); + + out: + jdbt_unlock(&dbdata, jnienv); + JAVADB_ENV_API_END(dbenv); +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_log_1put + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis, /*DbLsn*/ jobject lsn, + /*DbDbt*/ jobject data, jint flags) +{ + int err; + DB_ENV *dbenv; + DB_LSN *dblsn; + JDBT dbdata; + + dbenv = get_DB_ENV(jnienv, jthis); + dblsn = get_DB_LSN(jnienv, lsn); + if (!verify_non_null(jnienv, dbenv)) + return; + + JAVADB_ENV_API_BEGIN(dbenv, jthis); + + if (jdbt_lock(&dbdata, jnienv, data, inOp) != 0) + goto out; + + err = log_put(dbenv, dblsn, &dbdata.dbt->dbt, flags); + verify_return(jnienv, err, 0); + out: + jdbt_unlock(&dbdata, jnienv); + JAVADB_ENV_API_END(dbenv); +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_log_1register + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis, /*Db*/ jobject dbp, + jstring name) +{ + int err; + DB_ENV *dbenv; + DB *dbdb; + JSTR dbname; + + dbenv = get_DB_ENV(jnienv, jthis); + dbdb = get_DB(jnienv, dbp); + if (!verify_non_null(jnienv, dbenv)) + return; + + JAVADB_ENV_API_BEGIN(dbenv, jthis); + + if (jstr_lock(&dbname, jnienv, name) != 0) + goto out; + + err = log_register(dbenv, dbdb, dbname.string); + verify_return(jnienv, err, 0); + out: + jstr_unlock(&dbname, jnienv); + JAVADB_ENV_API_END(dbenv); +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_log_1unregister + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis, /*Db*/ jobject dbp) +{ + int err; + DB_ENV *dbenv; + DB *dbdb; + + dbenv = get_DB_ENV(jnienv, jthis); + dbdb = get_DB(jnienv, dbp); + if (!verify_non_null(jnienv, dbenv)) + return; + + JAVADB_ENV_API_BEGIN(dbenv, jthis); + + err = log_unregister(dbenv, dbdb); + verify_return(jnienv, err, 0); + JAVADB_ENV_API_END(dbenv); +} + +JNIEXPORT jobject JNICALL Java_com_sleepycat_db_DbEnv_log_1stat + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis) +{ + int err; + DB_ENV *dbenv; + DB_LOG_STAT *statp; + jobject retval; + jclass dbclass; + + retval = NULL; + statp = NULL; + dbenv = get_DB_ENV(jnienv, jthis); + if (!verify_non_null(jnienv, dbenv)) + return (NULL); + + JAVADB_ENV_API_BEGIN(dbenv, jthis); + + /* We cannot use the default allocator (on Win* platforms anyway) + * because it often causes problems when we free storage + * in a DLL that was allocated in another DLL. Using + * our own allocator (ours just calls malloc!) ensures + * that there is no mismatch. + */ + err = log_stat(dbenv, &statp, NULL); + if (verify_return(jnienv, err, 0)) { + retval = create_default_object(jnienv, name_DB_LOG_STAT); + dbclass = get_class(jnienv, name_DB_LOG_STAT); + + /* Set the individual fields */ + set_int_field(jnienv, dbclass, retval, + "st_magic", statp->st_magic); + set_int_field(jnienv, dbclass, retval, + "st_version", statp->st_version); + set_int_field(jnienv, dbclass, retval, + "st_mode", statp->st_mode); + set_int_field(jnienv, dbclass, retval, + "st_lg_max", statp->st_lg_max); + set_int_field(jnienv, dbclass, retval, + "st_w_bytes", statp->st_w_bytes); + set_int_field(jnienv, dbclass, retval, + "st_w_mbytes", statp->st_w_mbytes); + set_int_field(jnienv, dbclass, retval, + "st_wc_bytes", statp->st_wc_bytes); + set_int_field(jnienv, dbclass, retval, + "st_wc_mbytes", statp->st_wc_mbytes); + set_int_field(jnienv, dbclass, retval, + "st_wcount", statp->st_wcount); + set_int_field(jnienv, dbclass, retval, + "st_scount", statp->st_scount); + set_int_field(jnienv, dbclass, retval, + "st_region_wait", statp->st_region_wait); + set_int_field(jnienv, dbclass, retval, + "st_region_nowait", statp->st_region_nowait); + set_int_field(jnienv, dbclass, retval, + "st_cur_file", statp->st_cur_file); + set_int_field(jnienv, dbclass, retval, + "st_cur_offset", statp->st_cur_offset); + set_int_field(jnienv, dbclass, retval, + "st_regsize", statp->st_regsize); + + free(statp); + } + JAVADB_ENV_API_END(dbenv); + return (retval); +} + +JNIEXPORT jobject JNICALL Java_com_sleepycat_db_DbEnv_memp_1stat + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis) +{ + int err; + jclass dbclass; + DB_ENV *dbenv; + DB_MPOOL_STAT *statp; + jobject retval; + + retval = NULL; + statp = NULL; + dbenv = get_DB_ENV(jnienv, jthis); + if (!verify_non_null(jnienv, dbenv)) + return (NULL); + + JAVADB_ENV_API_BEGIN(dbenv, jthis); + + /* We cannot use the default allocator (on Win* platforms anyway) + * because it often causes problems when we free storage + * in a DLL that was allocated in another DLL. Using + * our own allocator (ours just calls malloc!) ensures + * that there is no mismatch. + */ + err = memp_stat(dbenv, &statp, 0, NULL); + if (verify_return(jnienv, err, 0)) { + retval = create_default_object(jnienv, name_DB_MPOOL_STAT); + dbclass = get_class(jnienv, name_DB_MPOOL_STAT); + + set_int_field(jnienv, dbclass, retval, "st_cachesize", 0); + set_int_field(jnienv, dbclass, retval, + "st_cache_hit", statp->st_cache_hit); + set_int_field(jnienv, dbclass, retval, + "st_cache_miss", statp->st_cache_miss); + set_int_field(jnienv, dbclass, retval, + "st_map", statp->st_map); + set_int_field(jnienv, dbclass, retval, + "st_page_create", statp->st_page_create); + set_int_field(jnienv, dbclass, retval, + "st_page_in", statp->st_page_in); + set_int_field(jnienv, dbclass, retval, + "st_page_out", statp->st_page_out); + set_int_field(jnienv, dbclass, retval, + "st_ro_evict", statp->st_ro_evict); + set_int_field(jnienv, dbclass, retval, + "st_rw_evict", statp->st_rw_evict); + set_int_field(jnienv, dbclass, retval, + "st_hash_buckets", statp->st_hash_buckets); + set_int_field(jnienv, dbclass, retval, + "st_hash_searches", statp->st_hash_searches); + set_int_field(jnienv, dbclass, retval, + "st_hash_longest", statp->st_hash_longest); + set_int_field(jnienv, dbclass, retval, + "st_hash_examined", statp->st_hash_examined); + set_int_field(jnienv, dbclass, retval, + "st_page_clean", statp->st_page_clean); + set_int_field(jnienv, dbclass, retval, + "st_page_dirty", statp->st_page_dirty); + set_int_field(jnienv, dbclass, retval, + "st_page_trickle", statp->st_page_trickle); + set_int_field(jnienv, dbclass, retval, + "st_region_wait", statp->st_region_wait); + set_int_field(jnienv, dbclass, retval, + "st_region_nowait", statp->st_region_nowait); + set_int_field(jnienv, dbclass, retval, + "st_regsize", statp->st_regsize); + + free(statp); + } + JAVADB_ENV_API_END(dbenv); + return (retval); +} + +JNIEXPORT jobjectArray JNICALL Java_com_sleepycat_db_DbEnv_memp_1fstat + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis) +{ + int err, i, len; + jclass fstat_class; + DB_ENV *dbenv; + DB_MPOOL_FSTAT **fstatp; + jobjectArray retval; + jfieldID filename_id; + jstring jfilename; + + fstatp = NULL; + retval = NULL; + dbenv = get_DB_ENV(jnienv, jthis); + if (!verify_non_null(jnienv, dbenv)) + return (NULL); + + JAVADB_ENV_API_BEGIN(dbenv, jthis); + + /* We cannot use the default allocator (on Win* platforms anyway) + * because it often causes problems when we free storage + * in a DLL that was allocated in another DLL. Using + * our own allocator (ours just calls malloc!) ensures + * that there is no mismatch. + */ + err = memp_stat(dbenv, 0, &fstatp, NULL); + if (verify_return(jnienv, err, 0)) { + len = 0; + while (fstatp[len]) + len++; + fstat_class = get_class(jnienv, name_DB_MPOOL_FSTAT); + retval = (*jnienv)->NewObjectArray(jnienv, len, + fstat_class, 0); + for (i=0; iSetObjectArrayElement(jnienv, retval, + i, obj); + + /* Set the string field. */ + filename_id = + (*jnienv)->GetFieldID(jnienv, fstat_class, + "file_name", + string_signature); + jfilename = + get_java_string(jnienv, fstatp[i]->file_name); + (*jnienv)->SetObjectField(jnienv, obj, + filename_id, jfilename); + + set_int_field(jnienv, fstat_class, obj, + "st_pagesize", fstatp[i]->st_pagesize); + set_int_field(jnienv, fstat_class, obj, + "st_cache_hit", fstatp[i]->st_cache_hit); + set_int_field(jnienv, fstat_class, obj, + "st_cache_miss", fstatp[i]->st_cache_miss); + set_int_field(jnienv, fstat_class, obj, + "st_map", fstatp[i]->st_map); + set_int_field(jnienv, fstat_class, obj, + "st_page_create", fstatp[i]->st_page_create); + set_int_field(jnienv, fstat_class, obj, + "st_page_in", fstatp[i]->st_page_in); + set_int_field(jnienv, fstat_class, obj, + "st_page_out", fstatp[i]->st_page_out); + free(fstatp[i]); + } + free(fstatp); + } + JAVADB_ENV_API_END(dbenv); + return (retval); +} + +JNIEXPORT jint JNICALL Java_com_sleepycat_db_DbEnv_memp_1trickle + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis, jint pct) +{ + int err; + DB_ENV *dbenv = get_DB_ENV(jnienv, jthis); + int result = 0; + + if (verify_non_null(jnienv, dbenv)) { + JAVADB_ENV_API_BEGIN(dbenv, jthis); + err = memp_trickle(dbenv, pct, &result); + verify_return(jnienv, err, 0); + JAVADB_ENV_API_END(dbenv); + } + return (result); +} + +JNIEXPORT jobject JNICALL Java_com_sleepycat_db_DbEnv_txn_1begin + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis, /*DbTxn*/ jobject pid, jint flags) +{ + int err; + DB_TXN *dbpid, *result; + DB_ENV *dbenv; + + dbenv = get_DB_ENV(jnienv, jthis); + if (!verify_non_null(jnienv, dbenv)) + return (0); + + JAVADB_ENV_API_BEGIN(dbenv, jthis); + + dbpid = get_DB_TXN(jnienv, pid); + result = 0; + + err = txn_begin(dbenv, dbpid, &result, flags); + if (!verify_return(jnienv, err, 0)) + return (0); + JAVADB_ENV_API_END(dbenv); + return (get_DbTxn(jnienv, result)); +} + +JNIEXPORT jint JNICALL Java_com_sleepycat_db_DbEnv_txn_1checkpoint + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis, jint kbyte, jint min, jint flags) +{ + int err; + DB_ENV *dbenv = get_DB_ENV(jnienv, jthis); + + if (!verify_non_null(jnienv, dbenv)) + return (0); + JAVADB_ENV_API_BEGIN(dbenv, jthis); + err = txn_checkpoint(dbenv, kbyte, min, flags); + if (err != DB_INCOMPLETE) + verify_return(jnienv, err, 0); + JAVADB_ENV_API_END(dbenv); + return (err); +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv_tx_1recover_1changed + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis, /*DbFeedback*/ jobject jtxrecover) +{ + DB_ENV *dbenv; + DB_ENV_JAVAINFO *dbenvinfo; + + dbenv = get_DB_ENV(jnienv, jthis); + dbenvinfo = get_DB_ENV_JAVAINFO(jnienv, jthis); + if (!verify_non_null(jnienv, dbenv) || + !verify_non_null(jnienv, dbenvinfo)) + return; + + JAVADB_ENV_API_BEGIN(dbenv, jthis); + dbjie_set_tx_recover_object(dbenvinfo, jnienv, dbenv, jtxrecover); + JAVADB_ENV_API_END(dbenv); +} + +JNIEXPORT jobject JNICALL Java_com_sleepycat_db_DbEnv_txn_1stat + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis) +{ + int err; + DB_ENV *dbenv; + DB_TXN_STAT *statp; + jobject retval, obj; + jclass dbclass, active_class; + char active_signature[512]; + jfieldID arrid; + jobjectArray actives; + unsigned int i; + + retval = NULL; + statp = NULL; + dbenv = get_DB_ENV(jnienv, jthis); + if (!verify_non_null(jnienv, dbenv)) + return (NULL); + + JAVADB_ENV_API_BEGIN(dbenv, jthis); + + /* We cannot use the default allocator (on Win* platforms anyway) + * because it often causes problems when we free storage + * in a DLL that was allocated in another DLL. Using + * our own allocator (ours just calls malloc!) ensures + * that there is no mismatch. + */ + err = txn_stat(dbenv, &statp, NULL); + if (verify_return(jnienv, err, 0)) { + retval = create_default_object(jnienv, name_DB_TXN_STAT); + dbclass = get_class(jnienv, name_DB_TXN_STAT); + + /* Set the individual fields */ + + set_lsn_field(jnienv, dbclass, retval, + "st_last_ckp", statp->st_last_ckp); + set_lsn_field(jnienv, dbclass, retval, + "st_pending_ckp", statp->st_pending_ckp); + set_long_field(jnienv, dbclass, retval, + "st_time_ckp", statp->st_time_ckp); + set_int_field(jnienv, dbclass, retval, + "st_last_txnid", statp->st_last_txnid); + set_int_field(jnienv, dbclass, retval, + "st_maxtxns", statp->st_maxtxns); + set_int_field(jnienv, dbclass, retval, + "st_naborts", statp->st_naborts); + set_int_field(jnienv, dbclass, retval, + "st_nbegins", statp->st_nbegins); + set_int_field(jnienv, dbclass, retval, + "st_ncommits", statp->st_ncommits); + set_int_field(jnienv, dbclass, retval, + "st_nactive", statp->st_nactive); + set_int_field(jnienv, dbclass, retval, + "st_maxnactive", statp->st_maxnactive); + + active_class = get_class(jnienv, name_DB_TXN_STAT_ACTIVE); + actives = + (*jnienv)->NewObjectArray(jnienv, statp->st_nactive, + active_class, 0); + + /* Set the st_txnarray field. This is a little more involved + * than other fields, since the type is an array, so none + * of our utility functions help. + */ + strncpy(active_signature, "[L", sizeof(active_signature)); + strncat(active_signature, DB_PACKAGE_NAME, + sizeof(active_signature)); + strncat(active_signature, name_DB_TXN_STAT_ACTIVE, + sizeof(active_signature)); + strncat(active_signature, ";", sizeof(active_signature)); + + arrid = (*jnienv)->GetFieldID(jnienv, dbclass, "st_txnarray", + active_signature); + (*jnienv)->SetObjectField(jnienv, retval, arrid, actives); + + /* Now fill the in the elements of st_txnarray. */ + for (i=0; ist_nactive; i++) { + obj = create_default_object(jnienv, name_DB_TXN_STAT_ACTIVE); + (*jnienv)->SetObjectArrayElement(jnienv, actives, i, obj); + + set_int_field(jnienv, active_class, obj, + "txnid", statp->st_txnarray[i].txnid); + set_int_field(jnienv, active_class, obj, + "parentid", statp->st_txnarray[i].parentid); + set_lsn_field(jnienv, active_class, obj, + "lsn", statp->st_txnarray[i].lsn); + } + set_int_field(jnienv, dbclass, retval, + "st_region_wait", statp->st_region_wait); + set_int_field(jnienv, dbclass, retval, + "st_region_nowait", statp->st_region_nowait); + set_int_field(jnienv, dbclass, retval, + "st_regsize", statp->st_regsize); + + free(statp); + } + JAVADB_ENV_API_END(dbenv); + return (retval); +} + +/* See discussion on errpfx, errcall in DB_ENV_JAVAINFO */ +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv__1set_1errcall + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis, jobject errcall) +{ + DB_ENV *dbenv; + DB_ENV_JAVAINFO *dbenvinfo; + + dbenv = get_DB_ENV(jnienv, jthis); + dbenvinfo = get_DB_ENV_JAVAINFO(jnienv, jthis); + + if (verify_non_null(jnienv, dbenv) && + verify_non_null(jnienv, dbenvinfo)) { + + JAVADB_ENV_API_BEGIN(dbenv, jthis); + dbjie_set_errcall(dbenvinfo, jnienv, errcall); + JAVADB_ENV_API_END(dbenv); + } +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv__1set_1errpfx + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis, jstring str) +{ + DB_ENV *dbenv; + DB_ENV_JAVAINFO *dbenvinfo; + + dbenv = get_DB_ENV(jnienv, jthis); + dbenvinfo = get_DB_ENV_JAVAINFO(jnienv, jthis); + + if (verify_non_null(jnienv, dbenv) && + verify_non_null(jnienv, dbenvinfo)) { + + JAVADB_ENV_API_BEGIN(dbenv, jthis); + dbjie_set_errpfx(dbenvinfo, jnienv, str); + JAVADB_ENV_API_END(dbenv); + } +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbEnv__1finalize + (JNIEnv *jnienv, /*DbEnv*/ jobject jthis, + jobject /*DbErrcall*/ errcall, jstring errpfx) +{ + DB_ENV *dbenv; + DB_ENV_JAVAINFO *envinfo; + + dbenv = get_DB_ENV(jnienv, jthis); + envinfo = get_DB_ENV_JAVAINFO(jnienv, jthis); + DB_ASSERT(envinfo != NULL); + + /* Note: We detect unclosed DbEnvs and report it. + */ + if (dbenv != NULL && envinfo != NULL && !dbjie_is_dbopen(envinfo)) { + + /* If this error occurs, this object was never closed. */ + report_errcall(jnienv, errcall, errpfx, + "DbEnv.finalize: open DbEnv object destroyed"); + } + + /* Shouldn't see this object again, but just in case */ + set_private_dbobj(jnienv, name_DB_ENV, jthis, 0); + set_private_info(jnienv, name_DB_ENV, jthis, 0); + + dbjie_destroy(envinfo, jnienv); +} diff --git a/db/libdb_java/java_DbLock.c b/db/libdb_java/java_DbLock.c new file mode 100644 index 000000000..287ca6622 --- /dev/null +++ b/db/libdb_java/java_DbLock.c @@ -0,0 +1,55 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: java_DbLock.c,v 11.4 2000/11/30 00:58:39 ubell Exp $"; +#endif /* not lint */ + +#include +#include +#include + +#include "db.h" +#include "java_util.h" +#include "com_sleepycat_db_DbLock.h" + +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbLock_put + (JNIEnv *jnienv, jobject jthis, /*DbEnv*/ jobject env) +{ + int err; + DB_LOCK *dblock = get_DB_LOCK(jnienv, jthis); + DB_ENV *dbenv = get_DB_ENV(jnienv, env); + + if (!verify_non_null(jnienv, dbenv)) + return; + + if (!verify_non_null(jnienv, dblock)) + return; + + err = lock_put(dbenv, dblock); + if (verify_return(jnienv, err, 0)) { + /* After a successful put, the DbLock can no longer + * be used, so we release the storage related to it + * (allocated in DbEnv.lock_get() or lock_tget()). + */ + free(dblock); + + set_private_dbobj(jnienv, name_DB_LOCK, jthis, 0); + } +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbLock_finalize + (JNIEnv *jnienv, jobject jthis) +{ + DB_LOCK *dblock = get_DB_LOCK(jnienv, jthis); + if (dblock) { + /* Free any data related to DB_LOCK here */ + free(dblock); + } + set_private_dbobj(jnienv, name_DB_LOCK, jthis, 0); /* paranoia */ +} diff --git a/db/libdb_java/java_DbLsn.c b/db/libdb_java/java_DbLsn.c new file mode 100644 index 000000000..8f26f2ecb --- /dev/null +++ b/db/libdb_java/java_DbLsn.c @@ -0,0 +1,43 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: java_DbLsn.c,v 11.5 2000/11/30 00:58:39 ubell Exp $"; +#endif /* not lint */ + +#include +#include +#include +#include /* needed for FILENAME_MAX */ + +#include "db.h" +#include "db_int.h" +#include "java_util.h" +#include "com_sleepycat_db_DbLsn.h" + +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbLsn_init_1lsn + (JNIEnv *jnienv, /*DbLsn*/ jobject jthis) +{ + /* Note: the DB_LSN object stored in the private_dbobj_ + * is allocated in get_DbLsn(). + */ + + COMPQUIET(jnienv, NULL); + COMPQUIET(jthis, NULL); +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbLsn_finalize + (JNIEnv *jnienv, jobject jthis) +{ + DB_LSN *dblsn; + + dblsn = get_DB_LSN(jnienv, jthis); + if (dblsn) { + free(dblsn); + } +} diff --git a/db/libdb_java/java_DbTxn.c b/db/libdb_java/java_DbTxn.c new file mode 100644 index 000000000..67c2599a6 --- /dev/null +++ b/db/libdb_java/java_DbTxn.c @@ -0,0 +1,82 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: java_DbTxn.c,v 11.3 2000/09/18 18:32:25 dda Exp $"; +#endif /* not lint */ + +#include +#include +#include +#include + +#include "db.h" +#include "java_util.h" +#include "com_sleepycat_db_DbTxn.h" + +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbTxn_abort + (JNIEnv *jnienv, jobject jthis) +{ + int err; + DB_TXN *dbtxn = get_DB_TXN(jnienv, jthis); + if (!verify_non_null(jnienv, dbtxn)) + return; + + err = txn_abort(dbtxn); + verify_return(jnienv, err, 0); +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbTxn_commit + (JNIEnv *jnienv, jobject jthis, jint flags) +{ + int err; + DB_TXN *dbtxn = get_DB_TXN(jnienv, jthis); + if (!verify_non_null(jnienv, dbtxn)) + return; + + err = txn_commit(dbtxn, flags); + verify_return(jnienv, err, 0); +} + +JNIEXPORT jint JNICALL Java_com_sleepycat_db_DbTxn_id + (JNIEnv *jnienv, jobject jthis) +{ + int retval = 0; + DB_TXN *dbtxn = get_DB_TXN(jnienv, jthis); + if (!verify_non_null(jnienv, dbtxn)) + return (-1); + + /* No error to check for from txn_id */ + retval = txn_id(dbtxn); + return (retval); +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbTxn_prepare + (JNIEnv *jnienv, jobject jthis) +{ + int err; + DB_TXN *dbtxn = get_DB_TXN(jnienv, jthis); + if (!verify_non_null(jnienv, dbtxn)) + return; + + err = txn_prepare(dbtxn); + verify_return(jnienv, err, 0); +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_DbTxn_finalize + (JNIEnv *jnienv, jobject jthis) +{ + DB_TXN *dbtxn = get_DB_TXN(jnienv, jthis); + if (dbtxn) { + /* Free any data related to DB_TXN here + * Note: we don't make a policy of doing + * a commit or abort here. The txnmgr + * should be closed, and DB will clean up. + */ + } +} diff --git a/db/libdb_java/java_Dbc.c b/db/libdb_java/java_Dbc.c new file mode 100644 index 000000000..f1d0acdec --- /dev/null +++ b/db/libdb_java/java_Dbc.c @@ -0,0 +1,196 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: java_Dbc.c,v 11.10 2000/10/25 19:54:55 dda Exp $"; +#endif /* not lint */ + +#include +#include +#include +#include +#ifdef DIAGNOSTIC +#include +#endif + +#include "db.h" +#include "db_int.h" +#include "java_util.h" +#include "com_sleepycat_db_Dbc.h" + +JNIEXPORT void JNICALL Java_com_sleepycat_db_Dbc_close + (JNIEnv *jnienv, jobject jthis) +{ + int err; + DBC *dbc = get_DBC(jnienv, jthis); + + if (!verify_non_null(jnienv, dbc)) + return; + err = dbc->c_close(dbc); + if (verify_return(jnienv, err, 0)) { + set_private_dbobj(jnienv, name_DBC, jthis, 0); + } +} + +JNIEXPORT jint JNICALL Java_com_sleepycat_db_Dbc_count + (JNIEnv *jnienv, jobject jthis, jint flags) +{ + int err; + DBC *dbc = get_DBC(jnienv, jthis); + db_recno_t count; + + if (!verify_non_null(jnienv, dbc)) + return (0); + err = dbc->c_count(dbc, &count, flags); + verify_return(jnienv, err, 0); + return (count); +} + +JNIEXPORT jint JNICALL Java_com_sleepycat_db_Dbc_del + (JNIEnv *jnienv, jobject jthis, jint flags) +{ + int err; + DBC *dbc = get_DBC(jnienv, jthis); + + if (!verify_non_null(jnienv, dbc)) + return (0); + err = dbc->c_del(dbc, flags); + if (err != DB_KEYEMPTY) { + verify_return(jnienv, err, 0); + } + return (err); +} + +JNIEXPORT jobject JNICALL Java_com_sleepycat_db_Dbc_dup + (JNIEnv *jnienv, jobject jthis, jint flags) +{ + int err; + DBC *dbc = get_DBC(jnienv, jthis); + DBC *dbc_ret = NULL; + + if (!verify_non_null(jnienv, dbc)) + return (0); + err = dbc->c_dup(dbc, &dbc_ret, flags); + if (!verify_return(jnienv, err, 0)) + return (0); + + return (get_Dbc(jnienv, dbc_ret)); +} + +JNIEXPORT jint JNICALL Java_com_sleepycat_db_Dbc_get + (JNIEnv *jnienv, jobject jthis, + /*Dbt*/ jobject key, /*Dbt*/ jobject data, jint flags) +{ + int err, retry, op_flags; + DBC *dbc; + JDBT dbkey, dbdata; + OpKind keyop, dataop; + + /* Depending on flags, the user may be supplying the key, + * or else we may have to retrieve it. + */ + err = 0; + keyop = outOp; + dataop = outOp; + + op_flags = flags & DB_OPFLAGS_MASK; + if (op_flags == DB_SET) { + keyop = inOp; + } + else if (op_flags == DB_SET_RANGE || + op_flags == DB_SET_RECNO) { + keyop = inOutOp; + } + else if (op_flags == DB_GET_BOTH) { + keyop = inOutOp; + dataop = inOutOp; + } + + dbc = get_DBC(jnienv, jthis); + if (jdbt_lock(&dbkey, jnienv, key, keyop) != 0) + goto out2; + if (jdbt_lock(&dbdata, jnienv, data, dataop) != 0) + goto out1; + + if (!verify_non_null(jnienv, dbc)) + goto out1; + + for (retry = 0; retry < 3; retry++) { + err = dbc->c_get(dbc, &dbkey.dbt->dbt, &dbdata.dbt->dbt, flags); + + /* If we failed due to lack of memory in our DBT arrays, + * retry. + */ + if (err != ENOMEM) + break; + if (!jdbt_realloc(&dbkey, jnienv) && !jdbt_realloc(&dbdata, jnienv)) + break; + } + if (err != DB_NOTFOUND) { + verify_return(jnienv, err, 0); + } + out1: + jdbt_unlock(&dbdata, jnienv); + out2: + jdbt_unlock(&dbkey, jnienv); + return (err); +} + +JNIEXPORT jint JNICALL Java_com_sleepycat_db_Dbc_put + (JNIEnv *jnienv, jobject jthis, + /*Dbt*/ jobject key, /*Dbt*/ jobject data, jint flags) +{ + int err; + DBC *dbc; + JDBT dbkey, dbdata; + + err = 0; + dbc = get_DBC(jnienv, jthis); + if (jdbt_lock(&dbkey, jnienv, key, inOp) != 0) + goto out2; + if (jdbt_lock(&dbdata, jnienv, data, inOp) != 0) + goto out1; + + if (!verify_non_null(jnienv, dbc)) + goto out1; + err = dbc->c_put(dbc, &dbkey.dbt->dbt, &dbdata.dbt->dbt, flags); + if (err != DB_KEYEXIST) { + verify_return(jnienv, err, 0); + } + out1: + jdbt_unlock(&dbdata, jnienv); + out2: + jdbt_unlock(&dbkey, jnienv); + return (err); +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_Dbc_finalize + (JNIEnv *jnienv, jobject jthis) +{ + /* Free any data related to DBC here. + * If we ever have java-only data embedded in the DBC + * and need to do this, we'll have to track Dbc's + * according to which Db owns them, just as + * we track Db's according to which DbEnv owns them. + * That's necessary to avoid double freeing that + * comes about when closes interact with GC. + */ + +#ifdef DIAGNOSTIC + DBC *dbc; + + dbc = get_DBC(jnienv, jthis); + if (dbc != NULL) + fprintf(stderr, "Java API: Dbc has not been closed\n"); +#else + + COMPQUIET(jnienv, NULL); + COMPQUIET(jthis, NULL); + +#endif +} diff --git a/db/libdb_java/java_Dbt.c b/db/libdb_java/java_Dbt.c new file mode 100644 index 000000000..0e094da6a --- /dev/null +++ b/db/libdb_java/java_Dbt.c @@ -0,0 +1,176 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: java_Dbt.c,v 11.10 2000/10/25 19:54:55 dda Exp $"; +#endif /* not lint */ + +#include +#include +#include +#include + +#include "db.h" +#include "java_util.h" +#include "com_sleepycat_db_Dbt.h" + +JAVADB_RW_ACCESS(Dbt, jint, size, DBT, size) +JAVADB_RW_ACCESS(Dbt, jint, ulen, DBT, ulen) +JAVADB_RW_ACCESS(Dbt, jint, dlen, DBT, dlen) +JAVADB_RW_ACCESS(Dbt, jint, doff, DBT, doff) +JAVADB_RW_ACCESS(Dbt, jint, flags, DBT, flags) + +JNIEXPORT void JNICALL Java_com_sleepycat_db_Dbt_init + (JNIEnv *jnienv, jobject jthis) +{ + DBT_JAVAINFO *dbtji; + + dbtji = dbjit_construct(); + set_private_dbobj(jnienv, name_DBT, jthis, dbtji); +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_Dbt_internal_1set_1data + (JNIEnv *jnienv, jobject jthis, jbyteArray array) +{ + DBT_JAVAINFO *db_this; + + db_this = get_DBT_JAVAINFO(jnienv, jthis); + if (verify_non_null(jnienv, db_this)) { + + /* If we previously allocated an array for java, + * must release reference. + */ + dbjit_release(db_this, jnienv); + + /* Make the array a global ref, + * it won't be GC'd till we release it. + */ + if (array) + array = (jbyteArray)NEW_GLOBAL_REF(jnienv, array); + db_this->array_ = array; + } +} + +JNIEXPORT jbyteArray JNICALL Java_com_sleepycat_db_Dbt_get_1data + (JNIEnv *jnienv, jobject jthis) +{ + DBT_JAVAINFO *db_this; + jbyteArray arr; + int len; + + db_this = get_DBT_JAVAINFO(jnienv, jthis); + if (verify_non_null(jnienv, db_this)) { + /* XXX this will copy the data on each call to get_data, + * even if it is unchanged. + */ + if (db_this->create_array_ != 0) { + /* XXX we should reuse the existing array if we can */ + len = db_this->dbt.size; + if (db_this->array_ != NULL) + DELETE_GLOBAL_REF(jnienv, db_this->array_); + arr = (*jnienv)->NewByteArray(jnienv, len); + db_this->array_ = + (jbyteArray)NEW_GLOBAL_REF(jnienv, arr); + (*jnienv)->SetByteArrayRegion(jnienv, arr, 0, len, + db_this->dbt.data); + } + return (db_this->array_); + } + return (0); +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_Dbt_set_1offset + (JNIEnv *jnienv, jobject jthis, jint offset) +{ + DBT_JAVAINFO *db_this; + + db_this = get_DBT_JAVAINFO(jnienv, jthis); + if (verify_non_null(jnienv, db_this)) { + db_this->offset_ = offset; + } +} + +JNIEXPORT jint JNICALL Java_com_sleepycat_db_Dbt_get_1offset + (JNIEnv *jnienv, jobject jthis) +{ + DBT_JAVAINFO *db_this; + + db_this = get_DBT_JAVAINFO(jnienv, jthis); + if (verify_non_null(jnienv, db_this)) { + return db_this->offset_; + } + return (0); +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_Dbt_set_1recno_1key_1data(JNIEnv *jnienv, jobject jthis, jint value) +{ + JDBT jdbt; + + if (jdbt_lock(&jdbt, jnienv, jthis, inOp) != 0) + goto out; + + if (!jdbt.dbt->dbt.data || + jdbt.java_array_len_ < sizeof(db_recno_t)) { + char buf[200]; + sprintf(buf, "set_recno_key_data error: %p %p %d %d", + &jdbt.dbt->dbt, jdbt.dbt->dbt.data, + jdbt.dbt->dbt.ulen, sizeof(db_recno_t)); + report_exception(jnienv, buf, 0, 0); + } + else { + *(db_recno_t*)(jdbt.dbt->dbt.data) = value; + } + out: + jdbt_unlock(&jdbt, jnienv); +} + +JNIEXPORT jint JNICALL Java_com_sleepycat_db_Dbt_get_1recno_1key_1data(JNIEnv *jnienv, jobject jthis) +{ + jint ret; + JDBT jdbt; + + ret = 0; + + /* Although this is kind of like "retrieve", we don't support + * DB_DBT_MALLOC for this operation, so we tell jdbt_lock + * that is not a retrieve. + */ + if (jdbt_lock(&jdbt, jnienv, jthis, inOp) != 0) + goto out; + + if (!jdbt.dbt->dbt.data || + jdbt.java_array_len_ < sizeof(db_recno_t)) { + char buf[200]; + sprintf(buf, "get_recno_key_data error: %p %p %d %d", + &jdbt.dbt->dbt, jdbt.dbt->dbt.data, + jdbt.dbt->dbt.ulen, sizeof(db_recno_t)); + report_exception(jnienv, buf, 0, 0); + } + else { + ret = *(db_recno_t*)(jdbt.dbt->dbt.data); + } + out: + jdbt_unlock(&jdbt, jnienv); + return (ret); +} + +JNIEXPORT void JNICALL Java_com_sleepycat_db_Dbt_finalize + (JNIEnv *jnienv, jobject jthis) +{ + DBT_JAVAINFO *dbtji; + + dbtji = get_DBT_JAVAINFO(jnienv, jthis); + if (dbtji) { + /* Free any data related to DBT here */ + dbjit_release(dbtji, jnienv); + + /* Extra paranoia */ + memset(dbtji, 0, sizeof(DBT_JAVAINFO)); + free(dbtji); + } +} diff --git a/db/libdb_java/java_info.c b/db/libdb_java/java_info.c new file mode 100644 index 000000000..ccd469fa2 --- /dev/null +++ b/db/libdb_java/java_info.c @@ -0,0 +1,1001 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: java_info.c,v 11.18 2000/10/28 13:09:39 dda Exp $"; +#endif /* not lint */ + +#include +#include +#include +#include + +#include "db.h" +#include "db_int.h" +#include "java_util.h" + +/**************************************************************** + * + * Callback functions + * + */ + +static void Db_feedback_callback(DB *db, int opcode, int percent) +{ + DB_JAVAINFO *dbinfo; + + DB_ASSERT(db != NULL); + dbinfo = (DB_JAVAINFO *)db->cj_internal; + dbji_call_feedback(dbinfo, db, dbinfo->jdbref_, opcode, percent); +} + +static int Db_append_recno_callback(DB *db, DBT *dbt, db_recno_t recno) +{ + DB_JAVAINFO *dbinfo; + + dbinfo = (DB_JAVAINFO *)db->cj_internal; + return (dbji_call_append_recno(dbinfo, db, dbinfo->jdbref_, dbt, recno)); +} + +static int Db_bt_compare_callback(DB *db, const DBT *dbt1, const DBT *dbt2) +{ + DB_JAVAINFO *dbinfo; + + dbinfo = (DB_JAVAINFO *)db->cj_internal; + return (dbji_call_bt_compare(dbinfo, db, dbinfo->jdbref_, dbt1, dbt2)); +} + +static size_t Db_bt_prefix_callback(DB *db, const DBT *dbt1, const DBT *dbt2) +{ + DB_JAVAINFO *dbinfo; + + dbinfo = (DB_JAVAINFO *)db->cj_internal; + return (dbji_call_bt_prefix(dbinfo, db, dbinfo->jdbref_, dbt1, dbt2)); +} + +static int Db_dup_compare_callback(DB *db, const DBT *dbt1, const DBT *dbt2) +{ + DB_JAVAINFO *dbinfo; + + dbinfo = (DB_JAVAINFO *)db->cj_internal; + return (dbji_call_dup_compare(dbinfo, db, dbinfo->jdbref_, dbt1, dbt2)); +} + +static u_int32_t Db_h_hash_callback(DB *db, const void *data, u_int32_t len) +{ + DB_JAVAINFO *dbinfo; + + dbinfo = (DB_JAVAINFO *)db->cj_internal; + return (dbji_call_h_hash(dbinfo, db, dbinfo->jdbref_, data, len)); +} + +static void DbEnv_feedback_callback(DB_ENV *dbenv, int opcode, int percent) +{ + DB_ENV_JAVAINFO *dbinfo; + + DB_ASSERT(dbenv != NULL); + dbinfo = (DB_ENV_JAVAINFO *)dbenv->cj_internal; + dbjie_call_feedback(dbinfo, dbenv, dbinfo->jenvref_, opcode, percent); +} + +static int DbEnv_recovery_init_callback(DB_ENV *dbenv) +{ + DB_ENV_JAVAINFO *dbinfo; + + dbinfo = (DB_ENV_JAVAINFO *)dbenv->cj_internal; + return (dbjie_call_recovery_init(dbinfo, dbenv, dbinfo->jenvref_)); +} + +static int DbEnv_tx_recover_callback(DB_ENV *dbenv, DBT *dbt, + DB_LSN *lsn, db_recops recops) +{ + DB_ENV_JAVAINFO *dbinfo; + + DB_ASSERT(dbenv != NULL); + dbinfo = (DB_ENV_JAVAINFO *)dbenv->cj_internal; + return dbjie_call_tx_recover(dbinfo, dbenv, dbinfo->jenvref_, dbt, + lsn, recops); +} + +/**************************************************************** + * + * Implementation of class DBT_javainfo + * + */ +DBT_JAVAINFO * +dbjit_construct() +{ + DBT_JAVAINFO *dbjit; + + dbjit = (DBT_JAVAINFO *)malloc(sizeof(DBT_JAVAINFO)); + memset(dbjit, 0, sizeof(DBT_JAVAINFO)); + return (dbjit); +} + +void dbjit_destroy(DBT_JAVAINFO *dbjit) +{ + /* Sanity check: + * We cannot delete the global ref because we don't have a JNIEnv. + */ + if (dbjit->array_ != NULL) { + fprintf(stderr, "object is not freed\n"); + } + + /* Extra paranoia */ + memset(dbjit, 0, sizeof(DB_JAVAINFO)); + free(dbjit); +} + +void dbjit_release(DBT_JAVAINFO *dbjit, JNIEnv *jnienv) +{ + if (dbjit->array_ != NULL) { + DELETE_GLOBAL_REF(jnienv, dbjit->array_); + dbjit->array_ = NULL; + } +} + +/**************************************************************** + * + * Implementation of class DB_ENV_JAVAINFO + * + */ + +/* create/initialize an object */ +DB_ENV_JAVAINFO * +dbjie_construct(JNIEnv *jnienv, + jobject default_errcall, + int is_dbopen) +{ + DB_ENV_JAVAINFO *dbjie; + + dbjie = (DB_ENV_JAVAINFO *)malloc(sizeof(DB_ENV_JAVAINFO)); + memset(dbjie, 0, sizeof(DB_ENV_JAVAINFO)); + dbjie->is_dbopen_ = is_dbopen; + + if ((*jnienv)->GetJavaVM(jnienv, &dbjie->javavm_) != 0) { + free(dbjie); + report_exception(jnienv, "cannot get Java VM", 0, 0); + return (NULL); + } + + /* The default error call just prints to the 'System.err' + * stream. If the user does set_errcall to null, we'll + * want to have a reference to set it back to. + * + * Why do we have always set db_errcall to our own callback? + * Because it makes the interaction between setting the + * error prefix, error stream, and user's error callback + * that much easier. + */ + dbjie->default_errcall_ = NEW_GLOBAL_REF(jnienv, default_errcall); + dbjie->errcall_ = NEW_GLOBAL_REF(jnienv, default_errcall); + return (dbjie); +} + +/* release all objects held by this this one */ +void dbjie_dealloc(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv) +{ + if (dbjie->recovery_init_ != NULL) { + DELETE_GLOBAL_REF(jnienv, dbjie->recovery_init_); + dbjie->recovery_init_ = NULL; + } + if (dbjie->feedback_ != NULL) { + DELETE_GLOBAL_REF(jnienv, dbjie->feedback_); + dbjie->feedback_ = NULL; + } + if (dbjie->tx_recover_ != NULL) { + DELETE_GLOBAL_REF(jnienv, dbjie->tx_recover_); + dbjie->tx_recover_ = NULL; + } + if (dbjie->errcall_ != NULL) { + DELETE_GLOBAL_REF(jnienv, dbjie->errcall_); + dbjie->errcall_ = NULL; + } + if (dbjie->default_errcall_ != NULL) { + DELETE_GLOBAL_REF(jnienv, dbjie->default_errcall_); + dbjie->default_errcall_ = NULL; + } + + if (dbjie->conflict_ != NULL) { + free(dbjie->conflict_); + dbjie->conflict_ = NULL; + } + if (dbjie->errpfx_ != NULL) { + free(dbjie->errpfx_); + dbjie->errpfx_ = NULL; + } +} + +/* free this object, releasing anything allocated on its behalf */ +void dbjie_destroy(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv) +{ + dbjie_dealloc(dbjie, jnienv); + + /* Extra paranoia */ + memset(dbjie, 0, sizeof(DB_ENV_JAVAINFO)); + free(dbjie); +} + +/* Attach to the current thread that is running and + * return that. We use the java virtual machine + * that we saved in the constructor. + */ +JNIEnv * +dbjie_get_jnienv(DB_ENV_JAVAINFO *dbjie) +{ + /* Note: + * Different versions of the JNI disagree on the signature + * for AttachCurrentThread. The most recent documentation + * seems to say that (JNIEnv **) is correct, but newer + * JNIs seem to use (void **), oddly enough. + */ +#ifdef JNI_VERSION_1_2 + void *attachret = 0; +#else + JNIEnv *attachret = 0; +#endif + + /* This should always succeed, as we are called via + * some Java activity. I think therefore I am (a thread). + */ + if ((*dbjie->javavm_)->AttachCurrentThread(dbjie->javavm_, &attachret, 0) != 0) + return (0); + + return ((JNIEnv *)attachret); +} + +jstring +dbjie_get_errpfx(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv) +{ + return (get_java_string(jnienv, dbjie->errpfx_)); +} + +void +dbjie_set_errcall(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv, jobject new_errcall) +{ + /* If the new_errcall is null, we'll set the error call + * to the default one. + */ + if (new_errcall == NULL) + new_errcall = dbjie->default_errcall_; + + DELETE_GLOBAL_REF(jnienv, dbjie->errcall_); + dbjie->errcall_ = NEW_GLOBAL_REF(jnienv, new_errcall); +} + +void +dbjie_set_errpfx(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv, jstring errpfx) +{ + if (dbjie->errpfx_ != NULL) + free(dbjie->errpfx_); + + if (errpfx) + dbjie->errpfx_ = get_c_string(jnienv, errpfx); + else + dbjie->errpfx_ = NULL; +} + +void +dbjie_set_conflict(DB_ENV_JAVAINFO *dbjie, unsigned char *newarr) +{ + if (dbjie->conflict_) + free(dbjie->conflict_); + dbjie->conflict_ = newarr; +} + +void dbjie_set_feedback_object(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv, + DB_ENV *dbenv, jobject jfeedback) +{ + int err; + + if (dbjie->feedback_ != NULL) { + DELETE_GLOBAL_REF(jnienv, dbjie->feedback_); + } + if (jfeedback == NULL) { + if ((err = dbenv->set_feedback(dbenv, NULL)) != 0) + report_exception(jnienv, "set_feedback failed", + err, 0); + } + else { + if ((err = dbenv->set_feedback(dbenv, + DbEnv_feedback_callback)) != 0) + report_exception(jnienv, "set_feedback failed", + err, 0); + } + + dbjie->feedback_ = NEW_GLOBAL_REF(jnienv, jfeedback); +} + +void dbjie_call_feedback(DB_ENV_JAVAINFO *dbjie, DB_ENV *dbenv, jobject jenv, + int opcode, int percent) +{ + JNIEnv *jnienv; + jclass feedback_class; + jmethodID id; + + COMPQUIET(dbenv, NULL); + jnienv = dbjie_get_jnienv(dbjie); + if (jnienv == NULL) { + fprintf(stderr, "Cannot attach to current thread!\n"); + return; + } + + feedback_class = get_class(jnienv, name_DbEnvFeedback); + id = (*jnienv)->GetMethodID(jnienv, feedback_class, + "feedback", + "(Lcom/sleepycat/db/DbEnv;II)V"); + if (!id) { + fprintf(stderr, "Cannot find callback class\n"); + return; + } + + (*jnienv)->CallVoidMethod(jnienv, dbjie->feedback_, id, + jenv, (jint)opcode, (jint)percent); +} + +void dbjie_set_recovery_init_object(DB_ENV_JAVAINFO *dbjie, + JNIEnv *jnienv, DB_ENV *dbenv, + jobject jrecovery_init) +{ + int err; + + if (dbjie->recovery_init_ != NULL) { + DELETE_GLOBAL_REF(jnienv, dbjie->recovery_init_); + } + if (jrecovery_init == NULL) { + if ((err = dbenv->set_recovery_init(dbenv, NULL)) != 0) + report_exception(jnienv, "set_recovery_init failed", + err, 0); + } + else { + if ((err = dbenv->set_recovery_init(dbenv, + DbEnv_recovery_init_callback)) != 0) + report_exception(jnienv, "set_recovery_init failed", + err, 0); + } + + dbjie->recovery_init_ = NEW_GLOBAL_REF(jnienv, jrecovery_init); +} + +int dbjie_call_recovery_init(DB_ENV_JAVAINFO *dbjie, DB_ENV *dbenv, + jobject jenv) +{ + JNIEnv *jnienv; + jclass recovery_init_class; + jmethodID id; + + COMPQUIET(dbenv, NULL); + jnienv = dbjie_get_jnienv(dbjie); + if (jnienv == NULL) { + fprintf(stderr, "Cannot attach to current thread!\n"); + return (EINVAL); + } + + recovery_init_class = get_class(jnienv, name_DbRecoveryInit); + id = (*jnienv)->GetMethodID(jnienv, recovery_init_class, + "recovery_init", + "(Lcom/sleepycat/db/DbEnv;)V"); + if (!id) { + fprintf(stderr, "Cannot find callback class\n"); + return (EINVAL); + } + return (*jnienv)->CallIntMethod(jnienv, dbjie->recovery_init_, + id, jenv); +} + +void dbjie_set_tx_recover_object(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv, + DB_ENV *dbenv, jobject jtx_recover) +{ + int err; + + if (dbjie->tx_recover_ != NULL) { + DELETE_GLOBAL_REF(jnienv, dbjie->tx_recover_); + } + if (jtx_recover == NULL) { + if ((err = dbenv->set_tx_recover(dbenv, NULL)) != 0) + report_exception(jnienv, "set_tx_recover failed", + err, 0); + } + else { + if ((err = dbenv->set_tx_recover(dbenv, + DbEnv_tx_recover_callback)) != 0) + report_exception(jnienv, "set_tx_recover failed", + err, 0); + } + + dbjie->tx_recover_ = NEW_GLOBAL_REF(jnienv, jtx_recover); +} + +int dbjie_call_tx_recover(DB_ENV_JAVAINFO *dbjie, DB_ENV *dbenv, jobject jenv, + DBT *dbt, DB_LSN *lsn, int recops) +{ + JNIEnv *jnienv; + jclass tx_recover_class; + jmethodID id; + jobject jdbt; + jobject jlsn; + + COMPQUIET(dbenv, NULL); + jnienv = dbjie_get_jnienv(dbjie); + if (jnienv == NULL) { + fprintf(stderr, "Cannot attach to current thread!\n"); + return (0); + } + + tx_recover_class = get_class(jnienv, name_DbTxnRecover); + id = (*jnienv)->GetMethodID(jnienv, tx_recover_class, + "tx_recover", + "(Lcom/sleepycat/db/DbEnv;" + "Lcom/sleepycat/db/Dbt;" + "Lcom/sleepycat/db/DbLsn;" + "I)I"); + if (!id) { + fprintf(stderr, "Cannot find callback class\n"); + return (0); + } + + if (dbt == NULL) + jdbt = NULL; + else + jdbt = get_Dbt(jnienv, dbt); + + if (lsn == NULL) + jlsn = NULL; + else + jlsn = get_DbLsn(jnienv, *lsn); + + return (*jnienv)->CallIntMethod(jnienv, dbjie->tx_recover_, id, jenv, + jdbt, jlsn, recops); +} + +jobject dbjie_get_errcall(DB_ENV_JAVAINFO *dbjie) +{ + return (dbjie->errcall_); +} + +int dbjie_is_dbopen(DB_ENV_JAVAINFO *dbjie) +{ + return (dbjie->is_dbopen_); +} + +/**************************************************************** + * + * Implementation of class DB_JAVAINFO + * + */ + +DB_JAVAINFO *dbji_construct(JNIEnv *jnienv, jint flags) +{ + DB_JAVAINFO *dbji; + + dbji = (DB_JAVAINFO *)malloc(sizeof(DB_JAVAINFO)); + memset(dbji, 0, sizeof(DB_JAVAINFO)); + + if ((*jnienv)->GetJavaVM(jnienv, &dbji->javavm_) != 0) { + report_exception(jnienv, "cannot get Java VM", 0, 0); + free(dbji); + return (NULL); + } + dbji->construct_flags_ = flags; + return (dbji); +} + +void +dbji_dealloc(DB_JAVAINFO *dbji, JNIEnv *jnienv) +{ + if (dbji->append_recno_ != NULL) { + DELETE_GLOBAL_REF(jnienv, dbji->append_recno_); + dbji->append_recno_ = NULL; + } + if (dbji->bt_compare_ != NULL) { + DELETE_GLOBAL_REF(jnienv, dbji->bt_compare_); + dbji->bt_compare_ = NULL; + } + if (dbji->bt_prefix_ != NULL) { + DELETE_GLOBAL_REF(jnienv, dbji->bt_prefix_); + dbji->bt_prefix_ = NULL; + } + if (dbji->dup_compare_ != NULL) { + DELETE_GLOBAL_REF(jnienv, dbji->dup_compare_); + dbji->dup_compare_ = NULL; + } + if (dbji->feedback_ != NULL) { + DELETE_GLOBAL_REF(jnienv, dbji->feedback_); + dbji->feedback_ = NULL; + } + if (dbji->h_hash_ != NULL) { + DELETE_GLOBAL_REF(jnienv, dbji->h_hash_); + dbji->h_hash_ = NULL; + } +} + +void +dbji_destroy(DB_JAVAINFO *dbji, JNIEnv *jnienv) +{ + dbji_dealloc(dbji, jnienv); + free(dbji); +} + +JNIEnv *dbji_get_jnienv(DB_JAVAINFO *dbji) +{ + /* Note: + * Different versions of the JNI disagree on the signature + * for AttachCurrentThread. The most recent documentation + * seems to say that (JNIEnv **) is correct, but newer + * JNIs seem to use (void **), oddly enough. + */ +#ifdef JNI_VERSION_1_2 + void *attachret = 0; +#else + JNIEnv *attachret = 0; +#endif + + /* This should always succeed, as we are called via + * some Java activity. I think therefore I am (a thread). + */ + if ((*dbji->javavm_)->AttachCurrentThread(dbji->javavm_, &attachret, 0) != 0) + return (0); + + return ((JNIEnv *)attachret); +} + +jint dbji_get_flags(DB_JAVAINFO *dbji) +{ + return (dbji->construct_flags_); +} + +void dbji_set_feedback_object(DB_JAVAINFO *dbji, JNIEnv *jnienv, + DB *db, jobject jfeedback) +{ + jclass feedback_class; + + if (dbji->feedback_method_id_ == NULL) { + feedback_class = get_class(jnienv, name_DbFeedback); + dbji->feedback_method_id_ = + (*jnienv)->GetMethodID(jnienv, feedback_class, + "feedback", + "(Lcom/sleepycat/db/Db;II)V"); + if (dbji->feedback_method_id_ != NULL) { + /* XXX + * We should really have a better way + * to translate this to a Java exception class. + * In theory, it shouldn't happen. + */ + report_exception(jnienv, "Cannot find callback method", + EFAULT, 0); + return; + } + } + + if (dbji->feedback_ != NULL) { + DELETE_GLOBAL_REF(jnienv, dbji->feedback_); + } + if (jfeedback == NULL) { + db->set_feedback(db, NULL); + } + else { + db->set_feedback(db, Db_feedback_callback); + } + + dbji->feedback_ = NEW_GLOBAL_REF(jnienv, jfeedback); + +} + +void dbji_call_feedback(DB_JAVAINFO *dbji, DB *db, jobject jdb, + int opcode, int percent) +{ + JNIEnv *jnienv; + + COMPQUIET(db, NULL); + jnienv = dbji_get_jnienv(dbji); + if (jnienv == NULL) { + fprintf(stderr, "Cannot attach to current thread!\n"); + return; + } + + DB_ASSERT(dbji->feedback_method_id_ != NULL); + (*jnienv)->CallVoidMethod(jnienv, dbji->feedback_, + dbji->feedback_method_id_, + jdb, (jint)opcode, (jint)percent); +} + +void dbji_set_append_recno_object(DB_JAVAINFO *dbji, JNIEnv *jnienv, + DB *db, jobject jcallback) +{ + jclass append_recno_class; + + if (dbji->append_recno_method_id_ == NULL) { + append_recno_class = get_class(jnienv, name_DbAppendRecno); + dbji->append_recno_method_id_ = + (*jnienv)->GetMethodID(jnienv, append_recno_class, + "db_append_recno", + "(Lcom/sleepycat/db/Db;" + "Lcom/sleepycat/db/Dbt;I)V"); + if (dbji->append_recno_method_id_ == NULL) { + /* XXX + * We should really have a better way + * to translate this to a Java exception class. + * In theory, it shouldn't happen. + */ + report_exception(jnienv, "Cannot find callback method", + EFAULT, 0); + return; + } + } + + if (dbji->append_recno_ != NULL) { + DELETE_GLOBAL_REF(jnienv, dbji->append_recno_); + } + if (jcallback == NULL) { + db->set_append_recno(db, NULL); + } + else { + db->set_append_recno(db, Db_append_recno_callback); + } + + dbji->append_recno_ = NEW_GLOBAL_REF(jnienv, jcallback); +} + +extern int dbji_call_append_recno(DB_JAVAINFO *dbji, DB *db, jobject jdb, + DBT *dbt, jint recno) +{ + JNIEnv *jnienv; + jobject jdbt; + DBT_JAVAINFO *dbtji; + jbyteArray arr; + unsigned int arraylen; + unsigned char *data; + + COMPQUIET(db, NULL); + jnienv = dbji_get_jnienv(dbji); + if (jnienv == NULL) { + fprintf(stderr, "Cannot attach to current thread!\n"); + return (0); + } + + /* XXX + * We should have a pool of Dbt objects used for this purpose + * instead of creating new ones each time. Because of + * multithreading, we may need an arbitrary number (more than two). + * We might also have a byte arrays that grow as needed, + * so we don't need to allocate those either. + * + * Note, we do not set the 'create_array_' flag as on other + * callbacks as we are creating the array here. + */ + jdbt = create_default_object(jnienv, name_DBT); + dbtji = get_DBT_JAVAINFO(jnienv, jdbt); + memcpy(&dbtji->dbt, dbt, sizeof(DBT)); + dbtji->dbt.data = NULL; + arr = (*jnienv)->NewByteArray(jnienv, dbt->size); + (*jnienv)->SetByteArrayRegion(jnienv, arr, 0, dbt->size, + (jbyte *)dbt->data); + dbtji->array_ = (jbyteArray)NEW_GLOBAL_REF(jnienv, arr); + + DB_ASSERT(dbji->append_recno_method_id_ != NULL); + (*jnienv)->CallVoidMethod(jnienv, dbji->append_recno_, + dbji->append_recno_method_id_, + jdb, jdbt, recno); + + /* The underlying C API requires that an errno be returned + * on error. Java users know nothing of errnos, so we + * allow them to throw exceptions instead. We leave the + * exception in place and return DB_JAVA_CALLBACK to the C API + * that called us. Eventually the DB->get will fail and + * when java prepares to throw an exception in + * report_exception(), this will be spotted as a special case, + * and the original exception will be preserved. + * + * Note: we have sometimes noticed strange behavior with + * exceptions under Linux 1.1.7 JVM. (i.e. multiple calls + * to ExceptionOccurred() may report different results). + * Currently we don't know of any problems related to this + * in our code, but if it pops up in the future, users are + * encouranged to get a more recent JVM. + */ + if ((*jnienv)->ExceptionOccurred(jnienv) != NULL) + return (DB_JAVA_CALLBACK); + + if (dbtji->array_ == NULL) { + report_exception(jnienv, "Dbt.data is null", 0, 0); + return (EFAULT); + } + + arraylen = (*jnienv)->GetArrayLength(jnienv, dbtji->array_); + if (dbtji->offset_ < 0 ) { + report_exception(jnienv, "Dbt.offset illegal", 0, 0); + return (EFAULT); + } + if (dbt->ulen + dbtji->offset_ > arraylen) { + report_exception(jnienv, + "Dbt.ulen + Dbt.offset greater than array length", 0, 0); + return (EFAULT); + } + + data = (*jnienv)->GetByteArrayElements(jnienv, dbtji->array_, + (jboolean *)0); + dbt->data = data + dbtji->offset_; + return (0); +} + +void dbji_set_bt_compare_object(DB_JAVAINFO *dbji, JNIEnv *jnienv, + DB *db, jobject jcompare) +{ + jclass bt_compare_class; + + if (dbji->bt_compare_method_id_ == NULL) { + bt_compare_class = get_class(jnienv, name_DbBtreeCompare); + dbji->bt_compare_method_id_ = + (*jnienv)->GetMethodID(jnienv, bt_compare_class, + "bt_compare", + "(Lcom/sleepycat/db/Db;" + "Lcom/sleepycat/db/Dbt;" + "Lcom/sleepycat/db/Dbt;)I"); + if (dbji->bt_compare_method_id_ == NULL) { + /* XXX + * We should really have a better way + * to translate this to a Java exception class. + * In theory, it shouldn't happen. + */ + report_exception(jnienv, "Cannot find callback method", + EFAULT, 0); + return; + } + } + + if (dbji->bt_compare_ != NULL) { + DELETE_GLOBAL_REF(jnienv, dbji->bt_compare_); + } + if (jcompare == NULL) { + db->set_bt_compare(db, NULL); + } + else { + db->set_bt_compare(db, Db_bt_compare_callback); + } + + dbji->bt_compare_ = NEW_GLOBAL_REF(jnienv, jcompare); +} + +int dbji_call_bt_compare(DB_JAVAINFO *dbji, DB *db, jobject jdb, + const DBT *dbt1, const DBT *dbt2) +{ + JNIEnv *jnienv; + jobject jdbt1, jdbt2; + DBT_JAVAINFO *dbtji1, *dbtji2; + + COMPQUIET(db, NULL); + jnienv = dbji_get_jnienv(dbji); + if (jnienv == NULL) { + fprintf(stderr, "Cannot attach to current thread!\n"); + return (0); + } + + /* XXX + * We should have a pool of Dbt objects used for this purpose + * instead of creating new ones each time. Because of + * multithreading, we may need an arbitrary number (more than two). + * We might also have a byte arrays that grow as needed, + * so we don't need to allocate those either. + */ + jdbt1 = create_default_object(jnienv, name_DBT); + jdbt2 = create_default_object(jnienv, name_DBT); + dbtji1 = get_DBT_JAVAINFO(jnienv, jdbt1); + memcpy(&dbtji1->dbt, dbt1, sizeof(DBT)); + dbtji1->create_array_ = 1; + dbtji2 = get_DBT_JAVAINFO(jnienv, jdbt2); + memcpy(&dbtji2->dbt, dbt2, sizeof(DBT)); + dbtji2->create_array_ = 1; + + DB_ASSERT(dbji->bt_compare_method_id_ != NULL); + return (*jnienv)->CallIntMethod(jnienv, dbji->bt_compare_, + dbji->bt_compare_method_id_, + jdb, jdbt1, jdbt2); +} + +void dbji_set_bt_prefix_object(DB_JAVAINFO *dbji, JNIEnv *jnienv, + DB *db, jobject jprefix) +{ + jclass bt_prefix_class; + + if (dbji->bt_prefix_method_id_ == NULL) { + bt_prefix_class = get_class(jnienv, name_DbBtreePrefix); + dbji->bt_prefix_method_id_ = + (*jnienv)->GetMethodID(jnienv, bt_prefix_class, + "bt_prefix", + "(Lcom/sleepycat/db/Db;" + "Lcom/sleepycat/db/Dbt;" + "Lcom/sleepycat/db/Dbt;)I"); + if (dbji->bt_prefix_method_id_ == NULL) { + /* XXX + * We should really have a better way + * to translate this to a Java exception class. + * In theory, it shouldn't happen. + */ + report_exception(jnienv, "Cannot find callback method", + EFAULT, 0); + return; + } + } + + if (dbji->bt_prefix_ != NULL) { + DELETE_GLOBAL_REF(jnienv, dbji->bt_prefix_); + } + if (jprefix == NULL) { + db->set_bt_prefix(db, NULL); + } + else { + db->set_bt_prefix(db, Db_bt_prefix_callback); + } + + dbji->bt_prefix_ = NEW_GLOBAL_REF(jnienv, jprefix); +} + +size_t dbji_call_bt_prefix(DB_JAVAINFO *dbji, DB *db, jobject jdb, + const DBT *dbt1, const DBT *dbt2) +{ + JNIEnv *jnienv; + jobject jdbt1, jdbt2; + DBT_JAVAINFO *dbtji1, *dbtji2; + + COMPQUIET(db, NULL); + jnienv = dbji_get_jnienv(dbji); + if (jnienv == NULL) { + fprintf(stderr, "Cannot attach to current thread!\n"); + return (0); + } + + /* XXX + * We should have a pool of Dbt objects used for this purpose + * instead of creating new ones each time. Because of + * multithreading, we may need an arbitrary number (more than two). + * We might also have a byte arrays that grow as needed, + * so we don't need to allocate those either. + */ + jdbt1 = create_default_object(jnienv, name_DBT); + jdbt2 = create_default_object(jnienv, name_DBT); + dbtji1 = get_DBT_JAVAINFO(jnienv, jdbt1); + memcpy(&dbtji1->dbt, dbt1, sizeof(DBT)); + dbtji1->create_array_ = 1; + dbtji2 = get_DBT_JAVAINFO(jnienv, jdbt2); + memcpy(&dbtji2->dbt, dbt2, sizeof(DBT)); + dbtji2->create_array_ = 1; + + DB_ASSERT(dbji->bt_prefix_method_id_ != NULL); + return (size_t)(*jnienv)->CallIntMethod(jnienv, dbji->bt_prefix_, + dbji->bt_prefix_method_id_, + jdb, jdbt1, jdbt2); +} + +void dbji_set_dup_compare_object(DB_JAVAINFO *dbji, JNIEnv *jnienv, + DB *db, jobject jcompare) +{ + jclass dup_compare_class; + + if (dbji->dup_compare_method_id_ == NULL) { + dup_compare_class = get_class(jnienv, name_DbDupCompare); + dbji->dup_compare_method_id_ = + (*jnienv)->GetMethodID(jnienv, dup_compare_class, + "dup_compare", + "(Lcom/sleepycat/db/Db;" + "Lcom/sleepycat/db/Dbt;" + "Lcom/sleepycat/db/Dbt;)I"); + if (dbji->dup_compare_method_id_ == NULL) { + /* XXX + * We should really have a better way + * to translate this to a Java exception class. + * In theory, it shouldn't happen. + */ + report_exception(jnienv, "Cannot find callback method", + EFAULT, 0); + return; + } + } + + if (dbji->dup_compare_ != NULL) + DELETE_GLOBAL_REF(jnienv, dbji->dup_compare_); + + if (jcompare == NULL) + db->set_dup_compare(db, NULL); + else + db->set_dup_compare(db, Db_dup_compare_callback); + + dbji->dup_compare_ = NEW_GLOBAL_REF(jnienv, jcompare); +} + +int dbji_call_dup_compare(DB_JAVAINFO *dbji, DB *db, jobject jdb, + const DBT *dbt1, const DBT *dbt2) +{ + JNIEnv *jnienv; + jobject jdbt1, jdbt2; + DBT_JAVAINFO *dbtji1, *dbtji2; + + COMPQUIET(db, NULL); + jnienv = dbji_get_jnienv(dbji); + if (jnienv == NULL) { + fprintf(stderr, "Cannot attach to current thread!\n"); + return (0); + } + + /* XXX + * We should have a pool of Dbt objects used for this purpose + * instead of creating new ones each time. Because of + * multithreading, we may need an arbitrary number (more than two). + * We might also have a byte arrays that grow as needed, + * so we don't need to allocate those either. + */ + jdbt1 = create_default_object(jnienv, name_DBT); + jdbt2 = create_default_object(jnienv, name_DBT); + dbtji1 = get_DBT_JAVAINFO(jnienv, jdbt1); + memcpy(&dbtji1->dbt, dbt1, sizeof(DBT)); + dbtji1->create_array_ = 1; + dbtji2 = get_DBT_JAVAINFO(jnienv, jdbt2); + memcpy(&dbtji2->dbt, dbt2, sizeof(DBT)); + dbtji2->create_array_ = 1; + + DB_ASSERT(dbji->dup_compare_method_id_ != NULL); + return (*jnienv)->CallIntMethod(jnienv, dbji->dup_compare_, + dbji->dup_compare_method_id_, + jdb, jdbt1, jdbt2); +} + +void dbji_set_h_hash_object(DB_JAVAINFO *dbji, JNIEnv *jnienv, + DB *db, jobject jhash) +{ + jclass h_hash_class; + + if (dbji->h_hash_method_id_ == NULL) { + h_hash_class = get_class(jnienv, name_DbHash); + dbji->h_hash_method_id_ = + (*jnienv)->GetMethodID(jnienv, h_hash_class, + "hash", + "(Lcom/sleepycat/db/Db;" + "[BI)I"); + if (dbji->h_hash_method_id_ == NULL) { + /* XXX + * We should really have a better way + * to translate this to a Java exception class. + * In theory, it shouldn't happen. + */ + report_exception(jnienv, "Cannot find callback method", + EFAULT, 0); + return; + } + } + + if (dbji->h_hash_ != NULL) + DELETE_GLOBAL_REF(jnienv, dbji->h_hash_); + + if (jhash == NULL) + db->set_h_hash(db, NULL); + else + db->set_h_hash(db, Db_h_hash_callback); + + dbji->h_hash_ = NEW_GLOBAL_REF(jnienv, jhash); +} + +int dbji_call_h_hash(DB_JAVAINFO *dbji, DB *db, jobject jdb, + const void *data, int len) +{ + JNIEnv *jnienv; + jbyteArray jarray; + + COMPQUIET(db, NULL); + jnienv = dbji_get_jnienv(dbji); + if (jnienv == NULL) { + fprintf(stderr, "Cannot attach to current thread!\n"); + return (0); + } + + DB_ASSERT(dbji->h_hash_method_id_ != NULL); + + jarray = (*jnienv)->NewByteArray(jnienv, len); + (*jnienv)->SetByteArrayRegion(jnienv, jarray, 0, len, (void *)data); + return (*jnienv)->CallIntMethod(jnienv, dbji->h_hash_, + dbji->h_hash_method_id_, + jdb, jarray, len); +} diff --git a/db/libdb_java/java_info.h b/db/libdb_java/java_info.h new file mode 100644 index 000000000..69032be80 --- /dev/null +++ b/db/libdb_java/java_info.h @@ -0,0 +1,200 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: java_info.h,v 11.17 2000/07/31 20:28:30 dda Exp $ + */ + +#ifndef _JAVA_INFO_H_ +#define _JAVA_INFO_H_ + +/* + * "Info" classes for Java implementation of Berkeley DB API. + * These classes hold extra information for which there is + * no room or counterpart in the base classes used in the C API. + * In the case of a DBT, the DBT_javainfo class is stored in the + * 'private' variable of the java Dbt, and the DBT_javainfo is subclassed + * from a DBT. In the case of DB and DB_ENV, the appropriate + * info objects are pointed to by the DB and DB_ENV objects. + * This is convenient to implement callbacks. + */ + +/**************************************************************** + * + * Declaration of class DBT_javainfo + * + * A DBT_javainfo is created whenever a Dbt (java) object is created, + * and a pointer to it is stored in its private info storage. + * It is subclassed from DBT, because we must retain some extra + * information in it while it is in use. In particular, when + * a java array is associated with it, we need to keep a Globally + * Locked reference to it so it is not GC'd. This reference is + * destroyed when the Dbt is GC'd. + */ +typedef struct _dbt_javainfo +{ + DBT dbt; + DB *db_; /* associated DB */ + jobject dbtref_; /* the java Dbt object */ + jbyteArray array_; + int offset_; + int create_array_; /* flag to create the array as needed */ +} +DBT_JAVAINFO; /* used with all 'dbtji' functions */ + +extern DBT_JAVAINFO *dbjit_construct(); +extern void dbjit_release(DBT_JAVAINFO *dbjit, JNIEnv *jnienv); + +/**************************************************************** + * + * Declaration of class DB_ENV_JAVAINFO + * + * A DB_ENV_JAVAINFO is allocated and stuffed into the cj_internal + * and the db_errpfx for every DB_ENV created. It holds a + * little extra info that is needed to support callbacks. + * + * There's a bit of trickery here, because we have built this + * above a layer that has a C function callback that gets + * invoked when an error occurs. One of the C callback's arguments + * is the prefix from the DB_ENV, but since we stuffed a pointer + * to our own DB_ENV_JAVAINFO into the prefix, we get that object as an + * argument to the C callback. Thus, the C callback can have + * access to much more than just the prefix, and it needs that + * to call back into the Java enviroment. + * + * The DB_ENV_JAVAINFO object holds a copy of the Java Virtual Machine, + * which is needed to attach to the current running thread + * whenever we need to make a callback. (This is more reliable + * than our previous approach, which was to save the thread + * that created the DbEnv). It also has the Java callback object, + * as well as a 'default' callback object that is used when the + * caller sets the callback to null. It also has the original + * error prefix, since we overwrote the one in the DB_ENV. + * There are also fields that are unrelated to the handling + * of callbacks, but are convenient to attach to a DB_ENV. + * + * Note: We assume that the Java layer is the only one + * fiddling with the contents of db_errpfx, db_errcall, cj_internal + * for a DB_ENV that was created via Java. Since the Java layer should + * have the only pointer to such a DB_ENV, this should be true. + */ +typedef struct _db_env_javainfo +{ + JavaVM *javavm_; + int is_dbopen_; + char *errpfx_; + jobject jdbref_; /* temporary reference */ + jobject jenvref_; /* temporary reference */ + jobject default_errcall_; /* global reference */ + jobject errcall_; /* global reference */ + jobject feedback_; /* global reference */ + jobject tx_recover_; /* global reference */ + jobject recovery_init_; /* global reference */ + unsigned char *conflict_; +} +DB_ENV_JAVAINFO; /* used with all 'dbjie' functions */ + +/* create/initialize an object */ +extern DB_ENV_JAVAINFO *dbjie_construct(JNIEnv *jnienv, + jobject default_errcall, + int is_dbopen); + +/* release all objects held by this this one */ +extern void dbjie_dealloc(DB_ENV_JAVAINFO *, JNIEnv *jnienv); + +/* free this object, releasing anything allocated on its behalf */ +extern void dbjie_destroy(DB_ENV_JAVAINFO *, JNIEnv *jnienv); + +/* This gets the environment for the current thread */ +extern JNIEnv *dbjie_get_jnienv(DB_ENV_JAVAINFO *); + +extern void dbjie_set_errpfx(DB_ENV_JAVAINFO *, JNIEnv *jnienv, + jstring errpfx); +extern jstring dbjie_get_errpfx(DB_ENV_JAVAINFO *, JNIEnv *jnienv); +extern void dbjie_set_errcall(DB_ENV_JAVAINFO *, JNIEnv *jnienv, + jobject new_errcall); +extern void dbjie_set_conflict(DB_ENV_JAVAINFO *, unsigned char *v); +extern void dbjie_set_feedback_object(DB_ENV_JAVAINFO *, JNIEnv *jnienv, + DB_ENV *dbenv, jobject value); +extern void dbjie_call_feedback(DB_ENV_JAVAINFO *, DB_ENV *dbenv, jobject jenv, + int opcode, int percent); +extern void dbjie_set_recovery_init_object(DB_ENV_JAVAINFO *, JNIEnv *jnienv, + DB_ENV *dbenv, jobject value); +extern int dbjie_call_recovery_init(DB_ENV_JAVAINFO *, DB_ENV *dbenv, + jobject jenv); +extern void dbjie_set_tx_recover_object(DB_ENV_JAVAINFO *, JNIEnv *jnienv, + DB_ENV *dbenv, jobject value); +extern int dbjie_call_tx_recover(DB_ENV_JAVAINFO *, + DB_ENV *dbenv, jobject jenv, + DBT *dbt, DB_LSN *lsn, int recops); +extern jobject dbjie_get_errcall(DB_ENV_JAVAINFO *) ; +extern int dbjie_is_dbopen(DB_ENV_JAVAINFO *); + +/**************************************************************** + * + * Declaration of class DB_JAVAINFO + * + * A DB_JAVAINFO is allocated and stuffed into the cj_internal field + * for every DB created. It holds a little extra info that is needed + * to support callbacks. + * + * Note: We assume that the Java layer is the only one + * fiddling with the contents of cj_internal + * for a DB that was created via Java. Since the Java layer should + * have the only pointer to such a DB, this should be true. + */ +typedef struct _db_javainfo +{ + JavaVM *javavm_; + jobject jdbref_; /* temporary reference during callback */ + jobject feedback_; /* global reference */ + jobject append_recno_; /* global reference */ + jobject bt_compare_; /* global reference */ + jobject bt_prefix_; /* global reference */ + jobject dup_compare_; /* global reference */ + jobject h_hash_; /* global reference */ + jmethodID feedback_method_id_; + jmethodID append_recno_method_id_; + jmethodID bt_compare_method_id_; + jmethodID bt_prefix_method_id_; + jmethodID dup_compare_method_id_; + jmethodID h_hash_method_id_; + jint construct_flags_; +} DB_JAVAINFO; + +/* create/initialize an object */ +extern DB_JAVAINFO *dbji_construct(JNIEnv *jnienv, jint flags); + +/* release all objects held by this this one */ +extern void dbji_dealloc(DB_JAVAINFO *, JNIEnv *jnienv); + +/* free this object, releasing anything allocated on its behalf */ +extern void dbji_destroy(DB_JAVAINFO *, JNIEnv *jnienv); + +/* This gets the environment for the current thread */ +extern JNIEnv *dbji_get_jnienv(); +extern jint dbji_get_flags(); + +extern void dbji_set_feedback_object(DB_JAVAINFO *, JNIEnv *jnienv, DB *db, jobject value); +extern void dbji_call_feedback(DB_JAVAINFO *, DB *db, jobject jdb, + int opcode, int percent); + +extern void dbji_set_append_recno_object(DB_JAVAINFO *, JNIEnv *jnienv, DB *db, jobject value); +extern int dbji_call_append_recno(DB_JAVAINFO *, DB *db, jobject jdb, + DBT *dbt, jint recno); +extern void dbji_set_bt_compare_object(DB_JAVAINFO *, JNIEnv *jnienv, DB *db, jobject value); +extern int dbji_call_bt_compare(DB_JAVAINFO *, DB *db, jobject jdb, + const DBT *dbt1, const DBT *dbt2); +extern void dbji_set_bt_prefix_object(DB_JAVAINFO *, JNIEnv *jnienv, DB *db, jobject value); +extern size_t dbji_call_bt_prefix(DB_JAVAINFO *, DB *db, jobject jdb, + const DBT *dbt1, const DBT *dbt2); +extern void dbji_set_dup_compare_object(DB_JAVAINFO *, JNIEnv *jnienv, DB *db, jobject value); +extern int dbji_call_dup_compare(DB_JAVAINFO *, DB *db, jobject jdb, + const DBT *dbt1, const DBT *dbt2); +extern void dbji_set_h_hash_object(DB_JAVAINFO *, JNIEnv *jnienv, DB *db, jobject value); +extern int dbji_call_h_hash(DB_JAVAINFO *, DB *db, jobject jdb, + const void *data, int len); + +#endif /* !_JAVA_INFO_H_ */ diff --git a/db/libdb_java/java_locked.c b/db/libdb_java/java_locked.c new file mode 100644 index 000000000..a5603df5d --- /dev/null +++ b/db/libdb_java/java_locked.c @@ -0,0 +1,294 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: java_locked.c,v 11.11 2000/10/25 19:54:55 dda Exp $"; +#endif /* not lint */ + +#include +#include +#include +#include + +#include "db.h" +#include "java_util.h" + +/**************************************************************** + * + * Implementation of class LockedDBT + * + */ +int +jdbt_lock(JDBT *jdbt, JNIEnv *jnienv, jobject obj, OpKind kind) +{ + DBT *dbt; + + jdbt->obj_ = obj; + jdbt->do_realloc_ = 0; + jdbt->kind_ = kind; + jdbt->java_array_len_= 0; + jdbt->java_data_ = 0; + jdbt->before_data_ = 0; + jdbt->has_error_ = 0; + jdbt->dbt = (DBT_JAVAINFO *)get_private_dbobj(jnienv, name_DBT, obj); + + if (!verify_non_null(jnienv, jdbt->dbt)) { + jdbt->has_error_ = 1; + return (EINVAL); + } + dbt = &jdbt->dbt->dbt; + + if (kind == outOp && + (dbt->flags & (DB_DBT_USERMEM | DB_DBT_MALLOC | DB_DBT_REALLOC)) == 0) { + report_exception(jnienv, + "Dbt.flags must be set to Db.DB_DBT_USERMEM, " + "Db.DB_DBT_MALLOC or Db.DB_DBT_REALLOC", + 0, 0); + jdbt->has_error_ = 1; + return (EINVAL); + } + + /* If this is requested to be realloc, we cannot use the + * underlying realloc, because the array we will pass in + * is not allocated by us, but the Java VM, so it cannot + * be successfully realloced. We simulate the reallocation, + * by using USERMEM and reallocating the java array when a + * ENOMEM error occurs. We change the flags during the operation, + * and they are reset when the operation completes (in the + * LockedDBT destructor. + */ + if ((dbt->flags & DB_DBT_REALLOC) != 0) { + dbt->flags &= ~DB_DBT_REALLOC; + dbt->flags |= DB_DBT_USERMEM; + jdbt->do_realloc_ = 1; + } + + if ((dbt->flags & DB_DBT_USERMEM) || kind != outOp) { + + /* If writing with DB_DBT_USERMEM/REALLOC + * or it's a set (or get/set) operation, + * then the data should point to a java array. + * Note that outOp means data is coming out of the database + * (it's a get). inOp means data is going into the database + * (either a put, or a key input). + */ + if (!jdbt->dbt->array_) { + report_exception(jnienv, "Dbt.data is null", 0, 0); + jdbt->has_error_ = 1; + return (EINVAL); + } + + /* Verify other parameters */ + jdbt->java_array_len_ = (*jnienv)->GetArrayLength(jnienv, jdbt->dbt->array_); + if (jdbt->dbt->offset_ < 0 ) { + report_exception(jnienv, "Dbt.offset illegal", 0, 0); + jdbt->has_error_ = 1; + return (EINVAL); + } + if (dbt->ulen + jdbt->dbt->offset_ > jdbt->java_array_len_) { + report_exception(jnienv, + "Dbt.ulen + Dbt.offset greater than array length", 0, 0); + jdbt->has_error_ = 1; + return (EINVAL); + } + + jdbt->java_data_ = (*jnienv)->GetByteArrayElements(jnienv, jdbt->dbt->array_, + (jboolean *)0); + dbt->data = jdbt->before_data_ = jdbt->java_data_ + jdbt->dbt->offset_; + } + else { + + /* If writing with DB_DBT_MALLOC, then the data is + * allocated by DB. + */ + dbt->data = jdbt->before_data_ = 0; + } + return (0); +} + +/* The LockedDBT destructor is called when the java handler returns + * to the user, since that's when the LockedDBT objects go out of scope. + * Since it is thus called after any call to the underlying database, + * it copies any information from temporary structures back to user + * accessible arrays, and of course must free memory and remove references. + */ +void +jdbt_unlock(JDBT *jdbt, JNIEnv *jnienv) +{ + DBT *dbt; + + dbt = &jdbt->dbt->dbt; + + /* Fix up the flags if we changed them. */ + if (jdbt->do_realloc_) { + dbt->flags &= ~DB_DBT_USERMEM; + dbt->flags |= DB_DBT_REALLOC; + } + + if ((dbt->flags & (DB_DBT_USERMEM | DB_DBT_REALLOC)) || + jdbt->kind_ == inOp) { + + /* If writing with DB_DBT_USERMEM/REALLOC or it's a set + * (or get/set) operation, then the data may be already in + * the java array, in which case, we just need to release it. + * If DB didn't put it in the array (indicated by the + * dbt->data changing), we need to do that + */ + if (jdbt->before_data_ != jdbt->java_data_) { + (*jnienv)->SetByteArrayRegion(jnienv, + jdbt->dbt->array_, + jdbt->dbt->offset_, + dbt->ulen, + jdbt->before_data_); + } + (*jnienv)->ReleaseByteArrayElements(jnienv, jdbt->dbt->array_, jdbt->java_data_, 0); + dbt->data = 0; + } + if ((dbt->flags & DB_DBT_MALLOC) && jdbt->kind_ != inOp) { + + /* If writing with DB_DBT_MALLOC, then the data was allocated + * by DB. If dbt->data is zero, it means an error occurred + * (and should have been already reported). + */ + if (dbt->data) { + + /* Release any old references. */ + dbjit_release(jdbt->dbt, jnienv); + + /* In the case of SET_RANGE, the key is inOutOp + * and when not found, its data will be left as + * its original value. Only copy and free it + * here if it has been allocated by DB + * (dbt->data has changed). + */ + if (dbt->data != jdbt->before_data_) { + jdbt->dbt->array_ = (jbyteArray) + NEW_GLOBAL_REF(jnienv, + (*jnienv)->NewByteArray(jnienv, + dbt->size)); + jdbt->dbt->offset_ = 0; + (*jnienv)->SetByteArrayRegion(jnienv, + jdbt->dbt->array_, 0, dbt->size, + (jbyte *)dbt->data); + free(dbt->data); + dbt->data = 0; + } + } + } +} + +/* Realloc the java array to receive data if the DBT was marked + * for realloc, and the last operation set the size field to an + * amount greater than ulen. + */ +int jdbt_realloc(JDBT *jdbt, JNIEnv *jnienv) +{ + DBT *dbt; + + dbt = &jdbt->dbt->dbt; + + if (!jdbt->do_realloc_ || jdbt->has_error_ || dbt->size <= dbt->ulen) + return (0); + + (*jnienv)->ReleaseByteArrayElements(jnienv, jdbt->dbt->array_, jdbt->java_data_, 0); + dbjit_release(jdbt->dbt, jnienv); + + /* We allocate a new array of the needed size. + * We'll set the offset to 0, as the old offset + * really doesn't make any sense. + */ + jdbt->java_array_len_ = dbt->ulen = dbt->size; + jdbt->dbt->offset_ = 0; + jdbt->dbt->array_ = (jbyteArray) + NEW_GLOBAL_REF(jnienv, (*jnienv)->NewByteArray(jnienv, dbt->size)); + + jdbt->java_data_ = (*jnienv)->GetByteArrayElements(jnienv, + jdbt->dbt->array_, + (jboolean *)0); + dbt->data = jdbt->before_data_ = jdbt->java_data_; + return (1); +} + +/**************************************************************** + * + * Implementation of class JSTR + * + */ +int +jstr_lock(JSTR *js, JNIEnv *jnienv, jstring jstr) +{ + js->jstr_ = jstr; + + if (jstr == 0) + js->string = 0; + else + js->string = (*jnienv)->GetStringUTFChars(jnienv, jstr, + (jboolean *)0); + return (0); +} + +void jstr_unlock(JSTR *js, JNIEnv *jnienv) +{ + if (js->jstr_) + (*jnienv)->ReleaseStringUTFChars(jnienv, js->jstr_, js->string); +} + +/**************************************************************** + * + * Implementation of class JSTRARRAY + * + */ +int +jstrarray_lock(JSTRARRAY *jsa, JNIEnv *jnienv, jobjectArray arr) +{ + int i; + + jsa->arr_ = arr; + jsa->array = 0; + + if (arr != 0) { + int count = (*jnienv)->GetArrayLength(jnienv, arr); + const char **new_array = + (const char **)malloc((sizeof(const char *))*(count+1)); + for (i=0; iGetObjectArrayElement(jnienv, arr, i); + if (jstr == 0) { + /* + * An embedded null in the string array + * is treated as an endpoint. + */ + new_array[i] = 0; + break; + } + else { + new_array[i] = + (*jnienv)->GetStringUTFChars(jnienv, jstr, (jboolean *)0); + } + } + new_array[count] = 0; + jsa->array = new_array; + } + return (0); +} + +void jstrarray_unlock(JSTRARRAY *jsa, JNIEnv *jnienv) +{ + int i; + jstring jstr; + + if (jsa->arr_) { + int count = (*jnienv)->GetArrayLength(jnienv, jsa->arr_); + for (i=0; iarray[i] == 0) + break; + jstr = (jstring)(*jnienv)->GetObjectArrayElement(jnienv, jsa->arr_, i); + (*jnienv)->ReleaseStringUTFChars(jnienv, jstr, jsa->array[i]); + } + free((void*)jsa->array); + } +} diff --git a/db/libdb_java/java_locked.h b/db/libdb_java/java_locked.h new file mode 100644 index 000000000..9b88cdd06 --- /dev/null +++ b/db/libdb_java/java_locked.h @@ -0,0 +1,98 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: java_locked.h,v 11.9 2000/10/25 19:54:55 dda Exp $ + */ + +#ifndef _JAVA_LOCKED_H_ +#define _JAVA_LOCKED_H_ + +/* + * Used internally by LockedDBT constructor. + */ +typedef enum _OpKind { + inOp, /* setting data in database (passing data in) */ + outOp, /* getting data from database to user memory */ + inOutOp /* both getting/setting data */ +} OpKind; + +/* + * + * Declaration of JDBT + * + * A JDBT object exists during a + * single native call to the DB API. Its constructor's job is + * to temporarily convert any java array found in the DBT_JAVAINFO + * to actual bytes in memory that remain locked in place. These + * bytes are used during the call to the underlying DB C layer, + * and are released and/or copied back by the destructor. + * Thus, a LockedDBT must be declared as a stack object to + * function properly. + */ +typedef struct _jdbt +{ + /* these are accessed externally to ldbt_ functions */ + DBT_JAVAINFO *dbt; + unsigned int java_array_len_; + + /* these are for used internally by ldbt_ functions */ + jobject obj_; + jbyte *java_data_; + jbyte *before_data_; + int has_error_; + int do_realloc_; + OpKind kind_; +} JDBT; + +extern int jdbt_lock(JDBT *, JNIEnv *jnienv, jobject obj, OpKind kind); +extern void jdbt_unlock(JDBT *, JNIEnv *jnienv); /* this unlocks and frees the memory */ +extern int jdbt_realloc(JDBT *, JNIEnv *jnienv); /* returns 1 if reallocation took place */ + +/**************************************************************** + * + * Declaration of JSTR + * + * A JSTR exists temporarily to convert a java jstring object + * to a char *. Because the memory for the char * string is + * managed by the JVM, it must be released when we are done + * looking at it. Typically, jstr_lock() is called at the + * beginning of a function for each jstring object, and jstr_unlock + * is called at the end of each function for each JSTR. + */ +typedef struct _jstr +{ + /* this accessed externally to jstr_ functions */ + const char *string; + + /* this is used internally by jstr_ functions */ + jstring jstr_; +} JSTR; + +extern int jstr_lock(JSTR *, JNIEnv *jnienv, jstring jstr); +extern void jstr_unlock(JSTR *, JNIEnv *jnienv); /* this unlocks and frees mem */ + +/**************************************************************** + * + * Declaration of class LockedStrarray + * + * Given a java jobjectArray object (that must be a String[]), + * we extract the individual strings and build a const char ** + * When the LockedStrarray object is destroyed, the individual + * strings are released. + */ +typedef struct _jstrarray +{ + /* this accessed externally to jstrarray_ functions */ + const char **array; + + /* this is used internally by jstrarray_ functions */ + jobjectArray arr_; +} JSTRARRAY; + +extern int jstrarray_lock(JSTRARRAY *, JNIEnv *jnienv, jobjectArray arr); +extern void jstrarray_unlock(JSTRARRAY *, JNIEnv *jnienv); /* this unlocks and frees mem */ + +#endif /* !_JAVA_LOCKED_H_ */ diff --git a/db/libdb_java/java_util.c b/db/libdb_java/java_util.c new file mode 100644 index 000000000..f42ceafbe --- /dev/null +++ b/db/libdb_java/java_util.c @@ -0,0 +1,556 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: java_util.c,v 11.17 2000/10/28 13:09:39 dda Exp $"; +#endif /* not lint */ + +#include +#include +#include +#include + +#include "db.h" +#include "java_util.h" + +#ifdef DB_WIN32 +#define sys_errlist _sys_errlist +#define sys_nerr _sys_nerr +#endif + +const char * const name_DB = "Db"; +const char * const name_DB_BTREE_STAT = "DbBtreeStat"; +const char * const name_DBC = "Dbc"; +const char * const name_DB_DEADLOCK_EX = "DbDeadlockException"; +const char * const name_DB_ENV = "DbEnv"; +const char * const name_DB_EXCEPTION = "DbException"; +const char * const name_DB_HASH_STAT = "DbHashStat"; +const char * const name_DB_LOCK = "DbLock"; +const char * const name_DB_LOCK_STAT = "DbLockStat"; +const char * const name_DB_LOG_STAT = "DbLogStat"; +const char * const name_DB_LSN = "DbLsn"; +const char * const name_DB_MEMORY_EX = "DbMemoryException"; +const char * const name_DB_MPOOL_FSTAT = "DbMpoolFStat"; +const char * const name_DB_MPOOL_STAT = "DbMpoolStat"; +const char * const name_DB_QUEUE_STAT = "DbQueueStat"; +const char * const name_DB_RUNRECOVERY_EX = "DbRunRecoveryException"; +const char * const name_DBT = "Dbt"; +const char * const name_DB_TXN = "DbTxn"; +const char * const name_DB_TXN_STAT = "DbTxnStat"; +const char * const name_DB_TXN_STAT_ACTIVE = "DbTxnStat$Active"; +const char * const name_DbAppendRecno = "DbAppendRecno"; +const char * const name_DbBtreeCompare = "DbBtreeCompare"; +const char * const name_DbBtreePrefix = "DbBtreePrefix"; +const char * const name_DbDupCompare = "DbDupCompare"; +const char * const name_DbEnvFeedback = "DbEnvFeedback"; +const char * const name_DbErrcall = "DbErrcall"; +const char * const name_DbHash = "DbHash"; +const char * const name_DbFeedback = "DbFeedback"; +const char * const name_DbRecoveryInit = "DbRecoveryInit"; +const char * const name_DbTxnRecover = "DbTxnRecover"; + +const char * const string_signature = "Ljava/lang/String;"; + +/**************************************************************** + * + * Utility functions used by "glue" functions. + * + */ + +/* Get the private data from a Db* object that points back to a C DB_* object. + * The private data is stored in the object as a Java long (64 bits), + * which is long enough to store a pointer on current architectures. + */ +void *get_private_dbobj(JNIEnv *jnienv, const char *classname, + jobject obj) +{ + jclass dbClass; + jfieldID id; + long_to_ptr lp; + + if (!obj) + return (0); + + dbClass = get_class(jnienv, classname); + id = (*jnienv)->GetFieldID(jnienv, dbClass, "private_dbobj_", "J"); + lp.java_long = (*jnienv)->GetLongField(jnienv, obj, id); + return (lp.ptr); +} + +/* Set the private data in a Db* object that points back to a C DB_* object. + * The private data is stored in the object as a Java long (64 bits), + * which is long enough to store a pointer on current architectures. + */ +void set_private_dbobj(JNIEnv *jnienv, const char *classname, + jobject obj, void *value) +{ + long_to_ptr lp; + jclass dbClass; + jfieldID id; + + lp.java_long = 0; /* no junk in case sizes mismatch */ + lp.ptr = value; + dbClass = get_class(jnienv, classname); + id = (*jnienv)->GetFieldID(jnienv, dbClass, "private_dbobj_", "J"); + (*jnienv)->SetLongField(jnienv, obj, id, lp.java_long); +} + +/* Get the private data in a Db/DbEnv object that holds additional 'side data'. + * The private data is stored in the object as a Java long (64 bits), + * which is long enough to store a pointer on current architectures. + */ +void *get_private_info(JNIEnv *jnienv, const char *classname, + jobject obj) +{ + jclass dbClass; + jfieldID id; + long_to_ptr lp; + + if (!obj) + return (0); + + dbClass = get_class(jnienv, classname); + id = (*jnienv)->GetFieldID(jnienv, dbClass, "private_info_", "J"); + lp.java_long = (*jnienv)->GetLongField(jnienv, obj, id); + return (lp.ptr); +} + +/* Set the private data in a Db/DbEnv object that holds additional 'side data'. + * The private data is stored in the object as a Java long (64 bits), + * which is long enough to store a pointer on current architectures. + */ +void set_private_info(JNIEnv *jnienv, const char *classname, + jobject obj, void *value) +{ + long_to_ptr lp; + jclass dbClass; + jfieldID id; + + lp.java_long = 0; /* no junk in case sizes mismatch */ + lp.ptr = value; + dbClass = get_class(jnienv, classname); + id = (*jnienv)->GetFieldID(jnienv, dbClass, "private_info_", "J"); + (*jnienv)->SetLongField(jnienv, obj, id, lp.java_long); +} + +/* + * Given a non-qualified name (e.g. "foo"), get the class handle + * for the fully qualified name (e.g. "com.sleepycat.db.foo") + */ +jclass get_class(JNIEnv *jnienv, const char *classname) +{ + /* Note: PERFORMANCE: It should be possible to cache jclass's. + * If we do a NewGlobalRef on each one, we can keep them + * around in a table. A jclass is a jobject, and + * since NewGlobalRef returns a jobject, it isn't + * technically right, but it would likely work with + * most implementations. Possibly make it configurable. + */ + char fullname[128] = DB_PACKAGE_NAME; + strncat(fullname, classname, sizeof(fullname)); + return ((*jnienv)->FindClass(jnienv, fullname)); +} + +/* Set an individual field in a Db* object. + * The field must be a DB object type. + */ +void set_object_field(JNIEnv *jnienv, jclass class_of_this, + jobject jthis, const char *object_classname, + const char *name_of_field, jobject obj) +{ + char signature[512]; + jfieldID id; + + strncpy(signature, "L", sizeof(signature)); + strncat(signature, DB_PACKAGE_NAME, sizeof(signature)); + strncat(signature, object_classname, sizeof(signature)); + strncat(signature, ";", sizeof(signature)); + + id = (*jnienv)->GetFieldID(jnienv, class_of_this, name_of_field, signature); + (*jnienv)->SetObjectField(jnienv, jthis, id, obj); +} + +/* Set an individual field in a Db* object. + * The field must be an integer type. + */ +void set_int_field(JNIEnv *jnienv, jclass class_of_this, + jobject jthis, const char *name_of_field, jint value) +{ + jfieldID id = (*jnienv)->GetFieldID(jnienv, class_of_this, name_of_field, "I"); + (*jnienv)->SetIntField(jnienv, jthis, id, value); +} + +/* Set an individual field in a Db* object. + * The field must be an integer type. + */ +void set_long_field(JNIEnv *jnienv, jclass class_of_this, + jobject jthis, const char *name_of_field, jlong value) +{ + jfieldID id = (*jnienv)->GetFieldID(jnienv, class_of_this, name_of_field, "J"); + (*jnienv)->SetLongField(jnienv, jthis, id, value); +} + +/* Set an individual field in a Db* object. + * The field must be an integer type. + */ +void set_lsn_field(JNIEnv *jnienv, jclass class_of_this, + jobject jthis, const char *name_of_field, DB_LSN value) +{ + set_object_field(jnienv, class_of_this, jthis, name_DB_LSN, + name_of_field, get_DbLsn(jnienv, value)); +} + +/* Report an exception back to the java side. + */ +void report_exception(JNIEnv *jnienv, const char *text, int err, + unsigned long expect_mask) +{ + jstring textString; + jclass dbexcept; + jclass javaexcept; + jmethodID constructId; + jthrowable obj; + + textString = NULL; + dbexcept = NULL; + javaexcept = NULL; + constructId = NULL; + obj = NULL; + + switch (err) { + /* DB_JAVA_CALLBACK is returned by dbji_call_append_recno() + * (the append_recno callback) when the Java version of the + * callback has thrown an exception, and we want to pass the + * exception on. The exception has already been thrown, we + * don't want to throw a new one. + */ + case DB_JAVA_CALLBACK: + break; + case ENOMEM: + dbexcept = get_class(jnienv, name_DB_MEMORY_EX); + break; + case ENOENT: + /* In this case there is a corresponding standard java + * exception type that we'll use. First we make sure + * that the calling function expected this kind of error, + * if not we give an 'internal error' DbException, since + * we must not throw an exception type that isn't + * declared in the signature. + * + * We'll make this a little more general if/when we add + * more java standard exceptions. + */ + if ((expect_mask & EXCEPTION_FILE_NOT_FOUND) == 0) { + char errstr[1024]; + + strncpy(errstr, "internal error: unexpected errno: ", + sizeof(errstr)); + strncat(errstr, text, sizeof(errstr)); + textString = get_java_string(jnienv, errstr); + dbexcept = get_class(jnienv, name_DB_EXCEPTION); + } + else { + javaexcept = + (*jnienv)->FindClass(jnienv, "java/io/FileNotFoundException"); + } + break; + case DB_RUNRECOVERY: + dbexcept = get_class(jnienv, name_DB_RUNRECOVERY_EX); + break; + case DB_LOCK_DEADLOCK: + dbexcept = get_class(jnienv, name_DB_DEADLOCK_EX); + break; + default: + dbexcept = get_class(jnienv, name_DB_EXCEPTION); + break; + } + if (dbexcept != NULL) { + if (textString == NULL) + textString = get_java_string(jnienv, text); + constructId = (*jnienv)->GetMethodID(jnienv, dbexcept, + "", + "(Ljava/lang/String;I)V"); + obj = (jthrowable)(*jnienv)->NewObject(jnienv, dbexcept, + constructId, textString, + err); + (*jnienv)->Throw(jnienv, obj); + } + else if (javaexcept != NULL) { + javaexcept = + (*jnienv)->FindClass(jnienv, "java/io/FileNotFoundException"); + (*jnienv)->ThrowNew(jnienv, javaexcept, text); + } +} + +/* Report an error via the errcall mechanism. + */ +void report_errcall(JNIEnv *jnienv, jobject errcall, + jstring prefix, const char *message) +{ + jmethodID id; + jclass errcall_class; + jstring msg; + + errcall_class = get_class(jnienv, name_DbErrcall); + msg = get_java_string(jnienv, message); + + id = (*jnienv)->GetMethodID(jnienv, errcall_class, + "errcall", + "(Ljava/lang/String;Ljava/lang/String;)V"); + if (id == NULL) { + fprintf(stderr, "Cannot get errcall methodID!\n"); + fprintf(stderr, "error: %s\n", message); + return; + } + + (*jnienv)->CallVoidMethod(jnienv, errcall, id, prefix, msg); +} + +/* If the object is null, report an exception and return false (0), + * otherwise return true (1). + */ +int verify_non_null(JNIEnv *jnienv, void *obj) +{ + if (obj == NULL) { + report_exception(jnienv, "null object", EINVAL, 0); + return (0); + } + return (1); +} + +/* If the error code is non-zero, report an exception and return false (0), + * otherwise return true (1). + */ +int verify_return(JNIEnv *jnienv, int err, unsigned long expect_mask) +{ + if (err == 0) + return 1; + + report_exception(jnienv, db_strerror(err), err, expect_mask); + return 0; +} + +/* Create an object of the given class, calling its default constructor. + */ +jobject create_default_object(JNIEnv *jnienv, const char *class_name) +{ + jclass dbclass = get_class(jnienv, class_name); + jmethodID id = (*jnienv)->GetMethodID(jnienv, dbclass, "", "()V"); + jobject object = (*jnienv)->NewObject(jnienv, dbclass, id); + return (object); +} + +/* Convert an DB object to a Java encapsulation of that object. + * Note: This implementation creates a new Java object on each call, + * so it is generally useful when a new DB object has just been created. + */ +jobject convert_object(JNIEnv *jnienv, const char *class_name, void *dbobj) +{ + jobject jo; + + if (!dbobj) + return (0); + + jo = create_default_object(jnienv, class_name); + set_private_dbobj(jnienv, class_name, jo, dbobj); + return (jo); +} + +/* Create a copy of the string + */ +char *dup_string(const char *str) +{ + int len; + char *retval; + + len = strlen(str) + 1; + retval = (char *)malloc(sizeof(char)*len); + strncpy(retval, str, len); + return (retval); +} + +/* Create a java string from the given string + */ +jstring get_java_string(JNIEnv *jnienv, const char* string) +{ + if (string == 0) + return (0); + return ((*jnienv)->NewStringUTF(jnienv, string)); +} + +/* Create a malloc'ed copy of the java string. + * Caller must free it. + */ +char *get_c_string(JNIEnv *jnienv, jstring jstr) +{ + const jbyte *utf; + char *retval; + + utf = (*jnienv)->GetStringUTFChars(jnienv, jstr, NULL); + retval = dup_string((const char *)utf); + (*jnienv)->ReleaseStringUTFChars(jnienv, jstr, utf); + return retval; +} + +/* Convert a java object to the various C pointers they represent. + */ +DB *get_DB(JNIEnv *jnienv, jobject obj) +{ + return ((DB *)get_private_dbobj(jnienv, name_DB, obj)); +} + +DB_BTREE_STAT *get_DB_BTREE_STAT(JNIEnv *jnienv, jobject obj) +{ + return ((DB_BTREE_STAT *)get_private_dbobj(jnienv, name_DB_BTREE_STAT, obj)); +} + +DBC *get_DBC(JNIEnv *jnienv, jobject obj) +{ + return ((DBC *)get_private_dbobj(jnienv, name_DBC, obj)); +} + +DB_ENV *get_DB_ENV(JNIEnv *jnienv, jobject obj) +{ + return ((DB_ENV *)get_private_dbobj(jnienv, name_DB_ENV, obj)); +} + +DB_ENV_JAVAINFO *get_DB_ENV_JAVAINFO(JNIEnv *jnienv, jobject obj) +{ + return ((DB_ENV_JAVAINFO *)get_private_info(jnienv, name_DB_ENV, obj)); +} + +DB_HASH_STAT *get_DB_HASH_STAT(JNIEnv *jnienv, jobject obj) +{ + return ((DB_HASH_STAT *)get_private_dbobj(jnienv, name_DB_HASH_STAT, obj)); +} + +DB_JAVAINFO *get_DB_JAVAINFO(JNIEnv *jnienv, jobject obj) +{ + return ((DB_JAVAINFO *)get_private_info(jnienv, name_DB, obj)); +} + +DB_LOCK *get_DB_LOCK(JNIEnv *jnienv, jobject obj) +{ + return ((DB_LOCK *)get_private_dbobj(jnienv, name_DB_LOCK, obj)); +} + +DB_LOG_STAT *get_DB_LOG_STAT(JNIEnv *jnienv, jobject obj) +{ + return ((DB_LOG_STAT *)get_private_dbobj(jnienv, name_DB_LOG_STAT, obj)); +} + +DB_LSN *get_DB_LSN(JNIEnv *jnienv, jobject obj) +{ + return ((DB_LSN *)get_private_dbobj(jnienv, name_DB_LSN, obj)); +} + +DB_MPOOL_FSTAT *get_DB_MPOOL_FSTAT(JNIEnv *jnienv, jobject obj) +{ + return ((DB_MPOOL_FSTAT *)get_private_dbobj(jnienv, name_DB_MPOOL_FSTAT, obj)); +} + +DB_MPOOL_STAT *get_DB_MPOOL_STAT(JNIEnv *jnienv, jobject obj) +{ + return ((DB_MPOOL_STAT *)get_private_dbobj(jnienv, name_DB_MPOOL_STAT, obj)); +} + +DB_QUEUE_STAT *get_DB_QUEUE_STAT(JNIEnv *jnienv, jobject obj) +{ + return ((DB_QUEUE_STAT *)get_private_dbobj(jnienv, name_DB_QUEUE_STAT, obj)); +} + +DB_TXN *get_DB_TXN(JNIEnv *jnienv, jobject obj) +{ + return ((DB_TXN *)get_private_dbobj(jnienv, name_DB_TXN, obj)); +} + +DB_TXN_STAT *get_DB_TXN_STAT(JNIEnv *jnienv, jobject obj) +{ + return ((DB_TXN_STAT *)get_private_dbobj(jnienv, name_DB_TXN_STAT, obj)); +} + +DBT *get_DBT(JNIEnv *jnienv, jobject obj) +{ + DBT_JAVAINFO *ji; + + ji = (DBT_JAVAINFO *)get_private_dbobj(jnienv, name_DBT, obj); + if (ji == NULL) + return (NULL); + else + return (&ji->dbt); +} + +DBT_JAVAINFO *get_DBT_JAVAINFO(JNIEnv *jnienv, jobject obj) +{ + return ((DBT_JAVAINFO *)get_private_dbobj(jnienv, name_DBT, obj)); +} + +/* Convert a C pointer to the various Java objects they represent. + */ +jobject get_DbBtreeStat(JNIEnv *jnienv, DB_BTREE_STAT *dbobj) +{ + return (convert_object(jnienv, name_DB_BTREE_STAT, dbobj)); +} + +jobject get_Dbc(JNIEnv *jnienv, DBC *dbobj) +{ + return (convert_object(jnienv, name_DBC, dbobj)); +} + +jobject get_DbHashStat(JNIEnv *jnienv, DB_HASH_STAT *dbobj) +{ + return (convert_object(jnienv, name_DB_HASH_STAT, dbobj)); +} + +jobject get_DbLogStat(JNIEnv *jnienv, DB_LOG_STAT *dbobj) +{ + return (convert_object(jnienv, name_DB_LOG_STAT, dbobj)); +} + +/* LSNs are different since they are really normally + * treated as by-value objects. We actually create + * a pointer to the LSN and store that, deleting it + * when the LSN is GC'd. + */ +jobject get_DbLsn(JNIEnv *jnienv, DB_LSN dbobj) +{ + DB_LSN *lsnp = (DB_LSN *)malloc(sizeof(DB_LSN)); + memset(lsnp, 0, sizeof(DB_LSN)); + *lsnp = dbobj; + return (convert_object(jnienv, name_DB_LSN, lsnp)); +} + +jobject get_Dbt(JNIEnv *jnienv, DBT *dbt) +{ + return (convert_object(jnienv, name_DBT, dbt)); +} + +jobject get_DbMpoolFStat(JNIEnv *jnienv, DB_MPOOL_FSTAT *dbobj) +{ + return (convert_object(jnienv, name_DB_MPOOL_FSTAT, dbobj)); +} + +jobject get_DbMpoolStat(JNIEnv *jnienv, DB_MPOOL_STAT *dbobj) +{ + return (convert_object(jnienv, name_DB_MPOOL_STAT, dbobj)); +} + +jobject get_DbQueueStat(JNIEnv *jnienv, DB_QUEUE_STAT *dbobj) +{ + return (convert_object(jnienv, name_DB_QUEUE_STAT, dbobj)); +} + +jobject get_DbTxn(JNIEnv *jnienv, DB_TXN *dbobj) +{ + return (convert_object(jnienv, name_DB_TXN, dbobj)); +} + +jobject get_DbTxnStat(JNIEnv *jnienv, DB_TXN_STAT *dbobj) +{ + return (convert_object(jnienv, name_DB_TXN_STAT, dbobj)); +} diff --git a/db/libdb_java/java_util.h b/db/libdb_java/java_util.h new file mode 100644 index 000000000..eb47dc676 --- /dev/null +++ b/db/libdb_java/java_util.h @@ -0,0 +1,359 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: java_util.h,v 11.22 2001/01/11 18:19:53 bostic Exp $ + */ + +#ifndef _JAVA_UTIL_H_ +#define _JAVA_UTIL_H_ + +#ifdef _MSC_VER + +/* These are level 4 warnings that are explicitly disabled. + * With Visual C++, by default you do not see above level 3 unless + * you use /W4. But we like to compile with the highest level + * warnings to catch other errors. + * + * 4201: nameless struct/union + * triggered by standard include file + * + * 4244: '=' : convert from '__int64' to 'unsigned int', possible loss of data + * results from making size_t data members correspond to jlongs + * + * 4514: unreferenced inline function has been removed + * jni.h defines methods that are not called + * + * 4127: conditional expression is constant + * occurs because of arg in JAVADB_RW_ACCESS_STRING macro + */ +#pragma warning(disable: 4244 4201 4514 4127) + +#endif + +#include "db_config.h" +#include "db.h" +#include "java_info.h" +#include "java_locked.h" +#include +#include /* needed for memset */ + +#define DB_PACKAGE_NAME "com/sleepycat/db/" + +/* Union to convert longs to pointers (see {get,set}_private_dbobj). + */ +typedef union { + jlong java_long; + void *ptr; +} long_to_ptr; + +/**************************************************************** + * + * Utility functions and definitions used by "glue" functions. + * + */ + +#define NOT_IMPLEMENTED(str) \ + report_exception(jnienv, str /*concatenate*/ ": not implemented", 0) + +/* Get, delete a global reference. + * Making this operation a function call allows for + * easier tracking for debugging. Global references + * are mostly grabbed at 'open' and 'close' points, + * so there shouldn't be a big performance hit. + * + * Macro-izing this makes it easier to add debugging code + * to track unreleased references. + */ +#ifdef DBJAVA_DEBUG +#include +static void wrdebug(const char *str) +{ + write(2, str, strlen(str)); + write(2, "\n", 1); +} + +static jobject debug_new_global_ref(JNIEnv *jnienv, jobject obj, const char *s) +{ + wrdebug(s); + return (*jnienv)->NewGlobalRef(jnienv, obj); +} + +static void debug_delete_global_ref(JNIEnv *jnienv, jobject obj, const char *s) +{ + wrdebug(s); + (*jnienv)->DeleteGlobalRef(jnienv, obj); +} + +#define NEW_GLOBAL_REF(jnienv, obj) \ + debug_new_global_ref(jnienv, obj, "+Ref: " #obj) +#define DELETE_GLOBAL_REF(jnienv, obj) \ + debug_delete_global_ref(jnienv, obj, "-Ref: " #obj) +#else +#define NEW_GLOBAL_REF(jnienv, obj) (*jnienv)->NewGlobalRef(jnienv, obj) +#define DELETE_GLOBAL_REF(jnienv, obj) (*jnienv)->DeleteGlobalRef(jnienv, obj) +#define wrdebug(x) +#endif + +/* Get the private data from a Db* object that points back to a C DB_* object. + * The private data is stored in the object as a Java long (64 bits), + * which is long enough to store a pointer on current architectures. + */ +void *get_private_dbobj(JNIEnv *jnienv, const char *classname, + jobject obj); + +/* Set the private data in a Db* object that points back to a C DB_* object. + * The private data is stored in the object as a Java long (64 bits), + * which is long enough to store a pointer on current architectures. + */ +void set_private_dbobj(JNIEnv *jnienv, const char *classname, + jobject obj, void *value); + +/* Get the private data in a Db/DbEnv object that holds additional 'side data'. + * The private data is stored in the object as a Java long (64 bits), + * which is long enough to store a pointer on current architectures. + */ +void *get_private_info(JNIEnv *jnienv, const char *classname, + jobject obj); + +/* Set the private data in a Db/DbEnv object that holds additional 'side data'. + * The private data is stored in the object as a Java long (64 bits), + * which is long enough to store a pointer on current architectures. + */ +void set_private_info(JNIEnv *jnienv, const char *classname, + jobject obj, void *value); + +/* + * Given a non-qualified name (e.g. "foo"), get the class handl + * for the fully qualified name (e.g. "com.sleepycat.db.foo") + */ +jclass get_class(JNIEnv *jnienv, const char *classname); + +/* Set an individual field in a Db* object. + * The field must be a DB object type. + */ +void set_object_field(JNIEnv *jnienv, jclass class_of_this, + jobject jthis, const char *object_classname, + const char *name_of_field, jobject obj); + +/* Set an individual field in a Db* object. + * The field must be an integer type. + */ +void set_int_field(JNIEnv *jnienv, jclass class_of_this, + jobject jthis, const char *name_of_field, jint value); + +/* Set an individual field in a Db* object. + * The field must be an integer type. + */ +void set_long_field(JNIEnv *jnienv, jclass class_of_this, + jobject jthis, const char *name_of_field, jlong value); + +/* Set an individual field in a Db* object. + * The field must be an DbLsn type. + */ +void set_lsn_field(JNIEnv *jnienv, jclass class_of_this, + jobject jthis, const char *name_of_field, DB_LSN value); + +/* Values of expect_mask + */ +static const int EXCEPTION_FILE_NOT_FOUND = 0x0001; + +/* Report an exception back to the java side. + */ +void report_exception(JNIEnv *jnienv, const char *text, int err, + unsigned long expect_mask); + +/* Report an error via the errcall mechanism. + */ +void report_errcall(JNIEnv *jnienv, jobject errcall, + jstring prefix, const char *message); + +/* If the object is null, report an exception and return false (0), + * otherwise return true (1). + */ +int verify_non_null(JNIEnv *jnienv, void *obj); + +/* If the error code is non-zero, report an exception and return false (0), + * otherwise return true (1). + */ +int verify_return(JNIEnv *jnienv, int err, unsigned long expect_mask); + +/* Create an object of the given class, calling its default constructor. + */ +jobject create_default_object(JNIEnv *jnienv, const char *class_name); + +/* Convert an DB object to a Java encapsulation of that object. + * Note: This implementation creates a new Java object on each call, + * so it is generally useful when a new DB object has just been created. + */ +jobject convert_object(JNIEnv *jnienv, const char *class_name, void *dbobj); + +/* Create a copy of the string + */ +char *dup_string(const char *str); + +/* Create a malloc'ed copy of the java string. + * Caller must free it. + */ +char *get_c_string(JNIEnv *jnienv, jstring jstr); + +/* Create a java string from the given string + */ +jstring get_java_string(JNIEnv *jnienv, const char* string); + +/* Convert a java object to the various C pointers they represent. + */ +DB *get_DB (JNIEnv *jnienv, jobject obj); +DB_BTREE_STAT *get_DB_BTREE_STAT (JNIEnv *jnienv, jobject obj); +DBC *get_DBC (JNIEnv *jnienv, jobject obj); +DB_ENV *get_DB_ENV (JNIEnv *jnienv, jobject obj); +DB_ENV_JAVAINFO *get_DB_ENV_JAVAINFO (JNIEnv *jnienv, jobject obj); +DB_HASH_STAT *get_DB_HASH_STAT (JNIEnv *jnienv, jobject obj); +DB_JAVAINFO *get_DB_JAVAINFO (JNIEnv *jnienv, jobject obj); +DB_LOCK *get_DB_LOCK (JNIEnv *jnienv, jobject obj); +DB_LOG_STAT *get_DB_LOG_STAT (JNIEnv *jnienv, jobject obj); +DB_LSN *get_DB_LSN (JNIEnv *jnienv, jobject obj); +DB_MPOOL_FSTAT *get_DB_MPOOL_FSTAT(JNIEnv *jnienv, jobject obj); +DB_MPOOL_STAT *get_DB_MPOOL_STAT (JNIEnv *jnienv, jobject obj); +DB_QUEUE_STAT *get_DB_QUEUE_STAT (JNIEnv *jnienv, jobject obj); +DB_TXN *get_DB_TXN (JNIEnv *jnienv, jobject obj); +DB_TXN_STAT *get_DB_TXN_STAT (JNIEnv *jnienv, jobject obj); +DBT *get_DBT (JNIEnv *jnienv, jobject obj); +DBT_JAVAINFO *get_DBT_JAVAINFO (JNIEnv *jnienv, jobject obj); + +/* From a C object, create a Java object. + */ +jobject get_DbBtreeStat (JNIEnv *jnienv, DB_BTREE_STAT *dbobj); +jobject get_Dbc (JNIEnv *jnienv, DBC *dbobj); +jobject get_DbHashStat (JNIEnv *jnienv, DB_HASH_STAT *dbobj); +jobject get_DbLogStat (JNIEnv *jnienv, DB_LOG_STAT *dbobj); +jobject get_DbLsn (JNIEnv *jnienv, DB_LSN dbobj); +jobject get_DbMpoolStat (JNIEnv *jnienv, DB_MPOOL_STAT *dbobj); +jobject get_DbMpoolFStat (JNIEnv *jnienv, DB_MPOOL_FSTAT *dbobj); +jobject get_DbQueueStat (JNIEnv *jnienv, DB_QUEUE_STAT *dbobj); +jobject get_Dbt (JNIEnv *jnienv, DBT *dbt); +jobject get_DbTxn (JNIEnv *jnienv, DB_TXN *dbobj); +jobject get_DbTxnStat (JNIEnv *jnienv, DB_TXN_STAT *dbobj); + +/* The java names of DB classes */ +extern const char * const name_DB; +extern const char * const name_DB_BTREE_STAT; +extern const char * const name_DBC; +extern const char * const name_DB_DEADLOCK_EX; +extern const char * const name_DB_ENV; +extern const char * const name_DB_EXCEPTION; +extern const char * const name_DB_HASH_STAT; +extern const char * const name_DB_LOCK; +extern const char * const name_DB_LOCK_STAT; +extern const char * const name_DB_LOG_STAT; +extern const char * const name_DB_LSN; +extern const char * const name_DB_MEMORY_EX; +extern const char * const name_DB_MPOOL_FSTAT; +extern const char * const name_DB_MPOOL_STAT; +extern const char * const name_DB_QUEUE_STAT; +extern const char * const name_DB_RUNRECOVERY_EX; +extern const char * const name_DBT; +extern const char * const name_DB_TXN; +extern const char * const name_DB_TXN_STAT; +extern const char * const name_DB_TXN_STAT_ACTIVE; +extern const char * const name_DbAppendRecno; +extern const char * const name_DbBtreeCompare; +extern const char * const name_DbBtreePrefix; +extern const char * const name_DbDupCompare; +extern const char * const name_DbEnvFeedback; +extern const char * const name_DbErrcall; +extern const char * const name_DbFeedback; +extern const char * const name_DbHash; +extern const char * const name_DbRecoveryInit; +extern const char * const name_DbTxnRecover; + +extern const char * const string_signature; + +#define JAVADB_RO_ACCESS(j_class, j_fieldtype, j_field, c_type, c_field) \ +JNIEXPORT j_fieldtype JNICALL \ + Java_com_sleepycat_db_##j_class##_get_1##j_field \ + (JNIEnv *jnienv, jobject jthis) \ +{ \ + c_type *db_this = get_##c_type(jnienv, jthis); \ + \ + if (verify_non_null(jnienv, db_this)) { \ + return db_this->c_field; \ + } \ + return 0; \ +} + +#define JAVADB_WO_ACCESS(j_class, j_fieldtype, j_field, c_type, c_field) \ +JNIEXPORT void JNICALL \ + Java_com_sleepycat_db_##j_class##_set_1##j_field \ + (JNIEnv *jnienv, jobject jthis, j_fieldtype value) \ +{ \ + c_type *db_this = get_##c_type(jnienv, jthis); \ + \ + if (verify_non_null(jnienv, db_this)) { \ + db_this->c_field = value; \ + } \ +} + +/* This is a variant of the JAVADB_WO_ACCESS macro to define a simple set_ + * method using a C "method" call. These should be used with set_ + * methods that cannot invoke java 'callbacks' (no set_ method currently + * does that). That assumption allows us to optimize (and simplify) + * by not calling API_BEGIN/END macros. + */ +#define JAVADB_WO_ACCESS_METHOD(j_class, j_fieldtype, \ + j_field, c_type, c_field) \ +JNIEXPORT void JNICALL \ + Java_com_sleepycat_db_##j_class##_set_1##j_field \ + (JNIEnv *jnienv, jobject jthis, j_fieldtype value) \ +{ \ + c_type *db_this; \ + int err; \ + \ + db_this = get_##c_type(jnienv, jthis); \ + if (verify_non_null(jnienv, db_this)) { \ + err = db_this->set_##c_field(db_this, value); \ + verify_return(jnienv, err, 0); \ + } \ +} + +#define JAVADB_RW_ACCESS(j_class, j_fieldtype, j_field, c_type, c_field) \ + JAVADB_RO_ACCESS(j_class, j_fieldtype, j_field, c_type, c_field) \ + JAVADB_WO_ACCESS(j_class, j_fieldtype, j_field, c_type, c_field) + +#define JAVADB_WO_ACCESS_STRING(j_class, j_field, c_type, c_field) \ +JNIEXPORT void JNICALL \ + Java_com_sleepycat_db_##j_class##_set_1##j_field \ + (JNIEnv *jnienv, jobject jthis, jstring value) \ +{ \ + c_type *db_this; \ + int err; \ + \ + db_this = get_##c_type(jnienv, jthis); \ + if (verify_non_null(jnienv, db_this)) { \ + err = db_this->set_##c_field(db_this, \ + (*jnienv)->GetStringUTFChars(jnienv, value, NULL)); \ + verify_return(jnienv, err, 0); \ + } \ +} + +#define JAVADB_API_BEGIN(db, jthis) \ + if ((db) != NULL) \ + ((DB_JAVAINFO*)(db)->cj_internal)->jdbref_ = \ + ((DB_ENV_JAVAINFO*)((db)->dbenv->cj_internal))->jdbref_ = (jthis) + +#define JAVADB_API_END(db) \ + if ((db) != NULL) \ + ((DB_JAVAINFO*)(db)->cj_internal)->jdbref_ = \ + ((DB_ENV_JAVAINFO*)((db)->dbenv->cj_internal))->jdbref_ = 0 + +#define JAVADB_ENV_API_BEGIN(dbenv, jthis) \ + if ((dbenv) != NULL) \ + ((DB_ENV_JAVAINFO*)((dbenv)->cj_internal))->jenvref_ = (jthis) + +#define JAVADB_ENV_API_END(dbenv) \ + if ((dbenv) != NULL) \ + ((DB_ENV_JAVAINFO*)((dbenv)->cj_internal))->jenvref_ = 0 + +#endif /* !_JAVA_UTIL_H_ */ diff --git a/db/lock/Design b/db/lock/Design new file mode 100644 index 000000000..ac8f0b02f --- /dev/null +++ b/db/lock/Design @@ -0,0 +1,293 @@ +# $Id: Design,v 11.3 2000/02/19 20:58:03 bostic Exp $ + +Synchronization in the Locking Subsystem + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +1. Data structures +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +The lock manager maintains 3 different structures: + +Objects (__db_lockobj): + Describes an object that is locked. When used with DB, this consists + of a __db_ilock (a file identifier and a page number). + +Lockers (__db_locker): + Identifies a specific locker ID and maintains the head of a list of + locks held by a locker (for using during transaction commit/abort). + +Locks (__db_lock): + Describes a particular object lock held on behalf of a particular + locker id. + +Objects and Lockers reference Locks. + +These structures are organized via two synchronized hash tables. Each +hash table consists of two physical arrays: the array of actual hash +buckets and an array of mutexes so we can lock individual buckets, rather +than the whole table. + +One hash table contains Objects and the other hash table contains Lockers. +Objects contain two lists of locks, waiters and holders: holders currently +hold a lock on the Object, waiters are lock waiting to be granted. +Lockers are a single linked list that connects the Locks held on behalf +of the specific locker ID. + +In the diagram below: + +Locker ID #1 holds a lock on Object #1 (L1) and Object #2 (L5), and is +waiting on a lock on Object #1 (L3). + +Locker ID #2 holds a lock on Object #1 (L2) and is waiting on a lock for +Object #2 (L7). + +Locker ID #3 is waiting for a lock on Object #2 (L6). + + OBJECT ----------------------- + HASH | | + ----|------------- | + ________ _______ | | ________ | | + | |-->| O1 |--|---|-->| O2 | | | + |_______| |_____| | | |______| V | + | | W H--->L1->L2 W H--->L5 | holders + |_______| | | | | V + | | ------->L3 \ ------->L6------>L7 waiters + |_______| / \ \ + . . / \ \ + . . | \ \ + . . | \ ----------- + |_______| | -------------- | + | | ____|____ ___|_____ _|______ + |_______| | | | | | | + | | | LID1 | | LID2 | | LID3 | + |_______| |_______| |_______| |______| + ^ ^ ^ + | | | + ___|________________________|________|___ + LOCKER | | | | | | | | | + HASH | | | | | | | | | + | | | | | | | | | + |____|____|____|____|____|____|____|____| + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +2. Synchronization +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +There are four types of mutexes in the subsystem. + +Object mutexes; + These map one-to-one to each bucket in the Object hash table. + Holding a mutex on an Object bucket secures all the Objects in + that bucket as well as the Lock structures linked from those + Objects. All fields in the Locks EXCEPT the Locker links (the + links that attach Locks by Locker ID) are protected by these + mutexes. + +Locker mutexes: + These map one-to-one to each bucket in the Locker hash table. + Holding a mutex on a Locker bucket secures the Locker structures + and the Locker links in the Locks. + +Memory mutex: + This mutex allows calls to allocate/free memory, i.e. calls to + __db_shalloc and __db_shalloc_free, as well as manipulation of + the Object, Locker and Lock free lists. + +Region mutex: + This mutex is currently only used to protect the locker ids. + It may also be needed later to provide exclusive access to + the region for deadlock detection. + +Creating or removing a Lock requires locking both the Object lock and the +Locker lock (and eventually the shalloc lock to return the item to the +free list). + +The locking hierarchy is as follows: + + The Region mutex may never be acquired after any other mutex. + + The Object mutex may be acquired after the Region mutex. + + The Locker mutex may be acquired after the Region and Object + mutexes. + + The Memory mutex may be acquired after any mutex. + +So, if both and Object mutex and a Locker mutex are going to be acquired, +the Object mutex must be acquired first. + +The Memory mutex may be acquired after any other mutex, but no other mutexes +can be acquired once the Memory mutex is held. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +3. The algorithms: +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +The locking subsystem supports four basic operations: + Get a Lock (lock_get) + + Release a Lock (lock_put) + + Release all the Locks on a specific Object (lock_vec) + + Release all the Locks for a specific Locker (lock_vec) + +Get a lock: + Acquire Object bucket mutex. + Acquire Locker bucket mutex. + + Acquire Memory mutex. + If the Object does not exist + Take an Object off the freelist. + If the Locker doesn't exist + Take a Locker off the freelist. + Take a Lock off the free list. + Release Memory mutex. + + Add Lock to the Object list. + Add Lock to the Locker list. + Release Locker bucket mutex + + If the lock cannot be granted + Release Object bucket mutex + Acquire lock mutex (blocks) + + Acquire Object bucket mutex + If lock acquisition did not succeed (e.g, deadlock) + Acquire Locker bucket mutex + If locker should be destroyed + Remove locker from hash table + Acquire Memory mutex + Return locker to free list + Release Memory mutex + Release Locker bucket mutex + + If object should be released + Acquire Memory mutex + Return object to free list + Release Memory mutex + + Release Object bucket mutex + +Release a lock: + Acquire Object bucket mutex. + (Requires that we be able to find the Object hash bucket + without looking inside the Lock itself.) + + If releasing a single lock and the user provided generation number + doesn't match the Lock's generation number, the Lock has been reused + and we return failure. + + Enter lock_put_internal: + if the Lock is still on the Object's lists: + Increment Lock's generation number. + Remove Lock from the Object's list (NULL link fields). + Promote locks for the Object. + + Enter locker_list_removal + Acquire Locker bucket mutex. + If Locker doesn't exist: + Release Locker bucket mutex + Release Object bucket mutex + Return error. + Else if Locker marked as deleted: + dont_release = TRUE + Else + Remove Lock from Locker list. + If Locker has no more locks + Remove Locker from table. + Acquire Memory mutex. + Return Locker to free list + Release Memory mutex + Release Locker bucket mutex. + Exit locker_list_removal + + If (!dont_release) + Acquire Memory mutex + Return Lock to free list + Release Memory mutex + + Exit lock_put_internal + + Release Object bucket mutex + +Release all the Locks on a specific Object (lock_vec, DB_PUT_ALL_OBJ): + + Acquire Object bucket mutex. + + For each lock on the waiter list: + lock_put_internal + For each lock on the holder list: + lock_put_internal + + Release Object bucket mutex. + +Release all the Locks for a specific Locker (lock_vec, DB_PUT_ALL): + + Acquire Locker bucket mutex. + Mark Locker deleted. + Release Locker mutex. + + For each lock on the Locker's list: + Remove from locker's list + (The lock could get put back on the free list in + lock_put and then could get reallocated and the + act of setting its locker links could clobber us.) + Perform "Release a Lock" above: skip locker_list_removal. + + Acquire Locker bucket mutex. + Remove Locker + Release Locker mutex. + + Acquire Memory mutex + Return Locker to free list + Release Memory mutex + +Deadlock detection (lock_detect): + + For each bucket in Object table + Acquire the Object bucket mutex. + create waitsfor + + For each bucket in Object table + Release the Object mutex. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +FAQ: +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +Q: Why do you need generation numbers? +A: If a lock has been released due to a transaction abort (potentially in a + different process), and then lock is released by a thread of control + unaware of the abort, the lock might have potentially been re-allocated + to a different object. The generation numbers detect this problem. + + Note, we assume that reads/writes of lock generation numbers are atomic, + if they are not, it is theoretically possible that a re-allocated lock + could be mistaken for another lock. + +Q: Why is is safe to walk the Locker list without holding any mutexes at + all? +A: Locks are created with both the Object and Locker bucket mutexes held. + Once created, they removed in two ways: + + a) when a specific Lock is released, in which case, the Object and + Locker bucket mutexes are again held, and + + b) when all Locks for a specific Locker Id is released. + + In case b), the Locker bucket mutex is held while the Locker chain is + marked as "destroyed", which blocks any further access to the Locker + chain. Then, each individual Object bucket mutex is acquired when each + individual Lock is removed. + +Q: What are the implications of doing fine grain locking? + +A: Since we no longer globally lock the entire region, lock_vec will no + longer be atomic. We still execute the items in a lock_vec in order, + so things like lock-coupling still work, but you can't make any + guarantees about atomicity. + +Q: How do I configure for FINE_GRAIN locking? + +A: We currently do not support any automatic configuration for FINE_GRAIN + locking. When we do, will need to document that atomicity discussion + listed above (it is bug-report #553). diff --git a/db/lock/lock.c b/db/lock/lock.c new file mode 100644 index 000000000..8d246f7de --- /dev/null +++ b/db/lock/lock.c @@ -0,0 +1,1439 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: lock.c,v 11.40 2000/12/19 23:18:58 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#ifdef HAVE_RPC +#include "db_server.h" +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_shash.h" +#include "lock.h" +#include "log.h" +#include "db_am.h" +#include "txn.h" + +#ifdef HAVE_RPC +#include "gen_client_ext.h" +#include "rpc_client_ext.h" +#endif + +static int __lock_checklocker __P((DB_LOCKTAB *, + struct __db_lock *, u_int32_t, u_int32_t, int *)); +static int __lock_get_internal __P((DB_LOCKTAB *, u_int32_t, + u_int32_t, const DBT *, db_lockmode_t, DB_LOCK *)); +static int __lock_is_parent __P((DB_LOCKTAB *, u_int32_t, DB_LOCKER *)); +static int __lock_put_internal __P((DB_LOCKTAB *, + struct __db_lock *, u_int32_t, u_int32_t)); +static int __lock_put_nolock __P((DB_ENV *, DB_LOCK *, int *, int)); +static void __lock_remove_waiter __P((DB_ENV *, + DB_LOCKOBJ *, struct __db_lock *, db_status_t)); + +static const char __db_lock_err[] = "Lock table is out of available %s"; +static const char __db_lock_invalid[] = "%s: Lock is no longer valid"; +static const char __db_locker_invalid[] = "Locker is not valid"; + +/* + * lock_id -- + * Generate a unique locker id. + */ +int +lock_id(dbenv, idp) + DB_ENV *dbenv; + u_int32_t *idp; +{ + DB_LOCKTAB *lt; + DB_LOCKREGION *region; + +#ifdef HAVE_RPC + if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) + return (__dbcl_lock_id(dbenv, idp)); +#endif + + PANIC_CHECK(dbenv); + ENV_REQUIRES_CONFIG(dbenv, dbenv->lk_handle, DB_INIT_LOCK); + + lt = dbenv->lk_handle; + region = lt->reginfo.primary; + + /* + * Note that we are letting locker IDs wrap. + * + * This is potentially dangerous in that it's conceivable that you + * could be allocating a new locker id and still have someone using + * it. However, the alternatives are that we keep a bitmap of + * locker ids or we forbid wrapping. Both are probably bad. The + * bitmap of locker ids will take up 64 MB of space. Forbidding + * wrapping means that we'll run out of locker IDs after 2 billion. + * In order for the wrap bug to fire, we'd need to have something + * that stayed open while 2 billion locker ids were used up. Since + * we cache cursors it means that something would have to stay open + * sufficiently long that we open and close a lot of files and a + * lot of cursors within them. Betting that this won't happen seems + * to the lesser of the evils. + */ + LOCKREGION(dbenv, lt); + if (region->id >= DB_LOCK_MAXID) + region->id = 0; + *idp = ++region->id; + UNLOCKREGION(dbenv, lt); + + return (0); +} + +/* + * Vector lock routine. This function takes a set of operations + * and performs them all at once. In addition, lock_vec provides + * functionality for lock inheritance, releasing all locks for a + * given locker (used during transaction commit/abort), releasing + * all locks on a given object, and generating debugging information. + */ +int +lock_vec(dbenv, locker, flags, list, nlist, elistp) + DB_ENV *dbenv; + u_int32_t locker, flags; + int nlist; + DB_LOCKREQ *list, **elistp; +{ + struct __db_lock *lp, *next_lock; + DB_LOCKER *sh_locker, *sh_parent; + DB_LOCKOBJ *obj, *sh_obj; + DB_LOCKREGION *region; + DB_LOCKTAB *lt; + u_int32_t lndx, ndx; + int did_abort, i, ret, run_dd; + +#ifdef HAVE_RPC + if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) + return (__dbcl_lock_vec(dbenv, locker, + flags, list, nlist, elistp)); +#endif + PANIC_CHECK(dbenv); + ENV_REQUIRES_CONFIG(dbenv, dbenv->lk_handle, DB_INIT_LOCK); + + /* Validate arguments. */ + if ((ret = __db_fchk(dbenv, "lock_vec", flags, DB_LOCK_NOWAIT)) != 0) + return (ret); + + lt = dbenv->lk_handle; + region = lt->reginfo.primary; + + run_dd = 0; + LOCKREGION(dbenv, (DB_LOCKTAB *)dbenv->lk_handle); + for (i = 0, ret = 0; i < nlist && ret == 0; i++) + switch (list[i].op) { + case DB_LOCK_GET: + ret = __lock_get_internal(dbenv->lk_handle, + locker, flags, + list[i].obj, list[i].mode, &list[i].lock); + break; + case DB_LOCK_INHERIT: + + /* + * Get the committing locker and mark it as deleted. + * This allows us to traverse the locker links without + * worrying that someone else is deleting locks out + * from under us. However, if the locker doesn't + * exist, that just means that the child holds no + * locks, so inheritance is easy! + */ + LOCKER_LOCK(lt, region, locker, ndx); + if ((ret = __lock_getlocker(lt, + locker, ndx, 0, &sh_locker)) != 0 || + sh_locker == NULL || + F_ISSET(sh_locker, DB_LOCKER_DELETED)) { + if (ret == 0 && sh_locker != NULL) + ret = EACCES; + __db_err(dbenv, __db_locker_invalid); + break; + } + + /* Make sure we are a child transaction. */ + if (sh_locker->parent_locker == INVALID_ROFF) { + __db_err(dbenv, "Not a child transaction"); + ret = EINVAL; + break; + } + sh_parent = (DB_LOCKER *) + R_ADDR(<->reginfo, sh_locker->parent_locker); + F_SET(sh_locker, DB_LOCKER_DELETED); + + /* + * Now, lock the parent locker; move locks from + * the committing list to the parent's list. + */ + LOCKER_LOCK(lt, region, locker, ndx); + if (F_ISSET(sh_parent, DB_LOCKER_DELETED)) { + if (ret == 0) { + __db_err(dbenv, + "Parent locker is not valid"); + ret = EACCES; + } + break; + } + + for (lp = SH_LIST_FIRST(&sh_locker->heldby, __db_lock); + lp != NULL; + lp = SH_LIST_FIRST(&sh_locker->heldby, __db_lock)) { + SH_LIST_REMOVE(lp, locker_links, __db_lock); + SH_LIST_INSERT_HEAD(&sh_parent->heldby, lp, + locker_links, __db_lock); + lp->holder = sh_parent->id; + + /* Get the object associated with this lock. */ + obj = (DB_LOCKOBJ *)((u_int8_t *)lp + lp->obj); + + (void)__lock_promote(lt, obj, + LF_ISSET(DB_LOCK_NOWAITERS)); + } + + /* Now free the original locker. */ + ret = __lock_checklocker(lt, + NULL, locker, DB_LOCK_IGNOREDEL, NULL); + break; + case DB_LOCK_PUT: + ret = + __lock_put_nolock(dbenv, &list[i].lock, &run_dd, 0); + break; + case DB_LOCK_PUT_ALL: + /* + * Get the locker and mark it as deleted. This + * allows us to traverse the locker links without + * worrying that someone else is deleting locks out + * from under us. Since the locker may hold no + * locks (i.e., you could call abort before you've + * done any work), it's perfectly reasonable for there + * to be no locker; this is not an error. + */ + LOCKER_LOCK(lt, region, locker, ndx); + if ((ret = __lock_getlocker(lt, + locker, ndx, 0, &sh_locker)) != 0 || + sh_locker == NULL || + F_ISSET(sh_locker, DB_LOCKER_DELETED)) + /* + * If ret is set, then we'll generate an + * error. If it's not set, we have nothing + * to do. + */ + break; + F_SET(sh_locker, DB_LOCKER_DELETED); + + /* Now traverse the locks, releasing each one. */ + for (lp = SH_LIST_FIRST(&sh_locker->heldby, __db_lock); + lp != NULL; + lp = SH_LIST_FIRST(&sh_locker->heldby, __db_lock)) { + SH_LIST_REMOVE(lp, locker_links, __db_lock); + sh_obj = + (DB_LOCKOBJ *)((u_int8_t *)lp + lp->obj); + SHOBJECT_LOCK(lt, region, sh_obj, lndx); + ret = __lock_put_internal(lt, + lp, lndx, DB_LOCK_FREE | DB_LOCK_DOALL); + if (ret != 0) + break; + } + ret = __lock_checklocker(lt, + NULL, locker, DB_LOCK_IGNOREDEL, NULL); + break; + case DB_LOCK_PUT_OBJ: + /* Remove all the locks associated with an object. */ + OBJECT_LOCK(lt, region, list[i].obj, ndx); + if ((ret = __lock_getobj(lt, list[i].obj, + ndx, 0, &sh_obj)) != 0 || sh_obj == NULL) { + if (ret == 0) + ret = EINVAL; + break; + } + + /* + * Go through both waiters and holders. Don't bother + * to run promotion, because everyone is getting + * released. The processes waiting will still get + * awakened as their waiters are released. + */ + for (lp = SH_TAILQ_FIRST(&sh_obj->waiters, __db_lock); + ret == 0 && lp != NULL; + lp = SH_TAILQ_FIRST(&sh_obj->waiters, __db_lock)) + ret = __lock_put_internal(lt, + lp, ndx, DB_LOCK_NOPROMOTE | DB_LOCK_DOALL); + + /* + * On the last time around, the object will get + * reclaimed by __lock_put_internal, structure the + * loop carefully so we do not get bitten. + */ + for (lp = SH_TAILQ_FIRST(&sh_obj->holders, __db_lock); + ret == 0 && lp != NULL; + lp = next_lock) { + next_lock = SH_TAILQ_NEXT(lp, links, __db_lock); + ret = __lock_put_internal(lt, + lp, ndx, DB_LOCK_NOPROMOTE | DB_LOCK_DOALL); + } + break; +#ifdef DEBUG + case DB_LOCK_DUMP: + /* Find the locker. */ + LOCKER_LOCK(lt, region, locker, ndx); + if ((ret = __lock_getlocker(lt, + locker, ndx, 0, &sh_locker)) != 0 + || sh_locker == NULL + || F_ISSET(sh_locker, DB_LOCKER_DELETED)) + break; + + for (lp = SH_LIST_FIRST(&sh_locker->heldby, __db_lock); + lp != NULL; + lp = SH_LIST_NEXT(lp, locker_links, __db_lock)) { + __lock_printlock(lt, lp, 1); + } + break; +#endif + default: + __db_err(dbenv, + "Invalid lock operation: %d", list[i].op); + ret = EINVAL; + break; + } + + if (ret == 0 && region->need_dd && region->detect != DB_LOCK_NORUN) { + run_dd = 1; + region->need_dd = 0; + } + UNLOCKREGION(dbenv, (DB_LOCKTAB *)dbenv->lk_handle); + + if (run_dd) + (void)lock_detect(dbenv, 0, region->detect, &did_abort); + + if (ret != 0 && elistp != NULL) + *elistp = &list[i - 1]; + + return (ret); +} + +/* + * Lock acquisition routines. There are two library interfaces: + * + * lock_get -- + * original lock get interface that takes a locker id. + * + * All the work for lock_get (and for the GET option of lock_vec) is done + * inside of lock_get_internal. + */ +int +lock_get(dbenv, locker, flags, obj, lock_mode, lock) + DB_ENV *dbenv; + u_int32_t locker, flags; + const DBT *obj; + db_lockmode_t lock_mode; + DB_LOCK *lock; +{ + int ret; + +#ifdef HAVE_RPC + if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) + return (__dbcl_lock_get(dbenv, locker, + flags, obj, lock_mode, lock)); +#endif + PANIC_CHECK(dbenv); + ENV_REQUIRES_CONFIG(dbenv, dbenv->lk_handle, DB_INIT_LOCK); + + if (IS_RECOVERING(dbenv)) { + lock->off = LOCK_INVALID; + return (0); + } + + /* Validate arguments. */ + if ((ret = __db_fchk(dbenv, + "lock_get", flags, + DB_LOCK_NOWAIT | DB_LOCK_UPGRADE | DB_LOCK_SWITCH)) != 0) + return (ret); + + LOCKREGION(dbenv, (DB_LOCKTAB *)dbenv->lk_handle); + ret = __lock_get_internal(dbenv->lk_handle, + locker, flags, obj, lock_mode, lock); + UNLOCKREGION(dbenv, (DB_LOCKTAB *)dbenv->lk_handle); + return (ret); +} + +static int +__lock_get_internal(lt, locker, flags, obj, lock_mode, lock) + DB_LOCKTAB *lt; + u_int32_t locker, flags; + const DBT *obj; + db_lockmode_t lock_mode; + DB_LOCK *lock; +{ + struct __db_lock *newl, *lp; + DB_ENV *dbenv; + DB_LOCKER *sh_locker; + DB_LOCKOBJ *sh_obj; + DB_LOCKREGION *region; + u_int32_t locker_ndx; + int did_abort, freed, ihold, on_locker_list, no_dd, ret; + + no_dd = ret = 0; + on_locker_list = 0; + region = lt->reginfo.primary; + dbenv = lt->dbenv; + + /* + * If we are not going to reuse this lock, initialize + * the offset to invalid so that if we fail it + * will not look like a valid lock. + */ + if (!LF_ISSET(DB_LOCK_UPGRADE | DB_LOCK_SWITCH)) + lock->off = LOCK_INVALID; + + /* + * Check that the lock mode is valid. + */ + if ((u_int32_t)lock_mode >= region->nmodes) { + __db_err(dbenv, + "lock_get: invalid lock mode %lu\n", (u_long)lock_mode); + return (EINVAL); + } + + /* Allocate a new lock. Optimize for the common case of a grant. */ + region->nrequests++; + if ((newl = SH_TAILQ_FIRST(®ion->free_locks, __db_lock)) != NULL) + SH_TAILQ_REMOVE(®ion->free_locks, newl, links, __db_lock); + if (newl == NULL) { + __db_err(dbenv, __db_lock_err, "locks"); + return (ENOMEM); + } + if (++region->nlocks > region->maxnlocks) + region->maxnlocks = region->nlocks; + + /* Allocate a new object. */ + OBJECT_LOCK(lt, region, obj, lock->ndx); + if ((ret = __lock_getobj(lt, obj, lock->ndx, 1, &sh_obj)) != 0) + goto err; + + /* Get the locker, we may need it to find our parent. */ + LOCKER_LOCK(lt, region, locker, locker_ndx); + if ((ret = + __lock_getlocker(lt, locker, locker_ndx, 1, &sh_locker)) != 0) { + /* + * XXX: Margo + * CLEANUP the object and the lock. + */ + return (ret); + } + + /* + * Now we have a lock and an object and we need to see if we should + * grant the lock. We use a FIFO ordering so we can only grant a + * new lock if it does not conflict with anyone on the holders list + * OR anyone on the waiters list. The reason that we don't grant if + * there's a conflict is that this can lead to starvation (a writer + * waiting on a popularly read item will never be granted). The + * downside of this is that a waiting reader can prevent an upgrade + * from reader to writer, which is not uncommon. + * + * There is one exception to the no-conflict rule. If a lock is held + * by the requesting locker AND the new lock does not conflict with + * any other holders, then we grant the lock. The most common place + * this happens is when the holder has a WRITE lock and a READ lock + * request comes in for the same locker. If we do not grant the read + * lock, then we guarantee deadlock. + * + * In case of conflict, we put the new lock on the end of the waiters + * list, unless we are upgrading in which case the locker goes on the + * front of the list. + */ + ihold = 0; + lp = NULL; + if (LF_ISSET(DB_LOCK_SWITCH)) + goto put_lock; + + for (lp = SH_TAILQ_FIRST(&sh_obj->holders, __db_lock); + lp != NULL; + lp = SH_TAILQ_NEXT(lp, links, __db_lock)) { + if (locker == lp->holder || + __lock_is_parent(lt, lp->holder, sh_locker)) { + if (lp->mode == lock_mode && + lp->status == DB_LSTAT_HELD) { + if (LF_ISSET(DB_LOCK_UPGRADE)) + goto upgrade; + + /* + * Lock is held, so we can increment the + * reference count and return this lock. + */ + lp->refcount++; + lock->off = R_OFFSET(<->reginfo, lp); + lock->gen = lp->gen; + + ret = 0; + goto done; + } else + ihold = 1; + } else if (CONFLICTS(lt, region, lp->mode, lock_mode)) + break; + } + + /* + * Make the new lock point to the new object, initialize fields. + * + * This lock is not linked in anywhere, so we can muck with it + * without holding any mutexes. + */ +put_lock: + newl->holder = locker; + newl->refcount = 1; + newl->mode = lock_mode; + newl->obj = SH_PTR_TO_OFF(newl, sh_obj); + newl->status = DB_LSTAT_HELD; + + /* + * If we are upgrading, then there are two scenarios. Either + * we had no conflicts, so we can do the upgrade. Or, there + * is a conflict and we should wait at the HEAD of the waiters + * list. + */ + if (LF_ISSET(DB_LOCK_UPGRADE)) { + if (lp == NULL) + goto upgrade; + + /* + * There was a conflict, wait. If this is the first waiter, + * add the object to the deadlock detector's list. + */ + if (SH_TAILQ_FIRST(&sh_obj->waiters, __db_lock) == NULL) + SH_TAILQ_INSERT_HEAD(®ion->dd_objs, + sh_obj, dd_links, __db_lockobj); + + SH_TAILQ_INSERT_HEAD(&sh_obj->waiters, newl, links, __db_lock); + goto llist; + } + + if (lp == NULL && !ihold) + for (lp = SH_TAILQ_FIRST(&sh_obj->waiters, __db_lock); + lp != NULL; + lp = SH_TAILQ_NEXT(lp, links, __db_lock)) { + if (CONFLICTS(lt, region, lp->mode, lock_mode) && + locker != lp->holder) + break; + } + if (!LF_ISSET(DB_LOCK_SWITCH) && lp == NULL) + SH_TAILQ_INSERT_TAIL(&sh_obj->holders, newl, links); + else if (!LF_ISSET(DB_LOCK_NOWAIT)) { + /* + * If this is the first waiter, add the object to the + * deadlock detector's list. + */ + if (SH_TAILQ_FIRST(&sh_obj->waiters, __db_lock) == NULL) + SH_TAILQ_INSERT_HEAD(®ion->dd_objs, + sh_obj, dd_links, __db_lockobj); + SH_TAILQ_INSERT_TAIL(&sh_obj->waiters, newl, links); + } else { + ret = DB_LOCK_NOTGRANTED; + if (SH_LIST_FIRST(&sh_locker->heldby, __db_lock) == NULL + && LOCKER_FREEABLE(sh_locker)) + __lock_freelocker( lt, region, sh_locker, locker_ndx); + region->nnowaits++; + goto err; + } + +llist: + /* + * Now, insert the lock onto its locker's list. If the locker does + * not currently hold any locks, there's no reason to run a deadlock + * detector, save that information. + */ + on_locker_list = 1; + no_dd = sh_locker->master_locker == INVALID_ROFF + && SH_LIST_FIRST(&sh_locker->child_locker, __db_locker) == NULL + && SH_LIST_FIRST(&sh_locker->heldby, __db_lock) == NULL; + + SH_LIST_INSERT_HEAD(&sh_locker->heldby, newl, locker_links, __db_lock); + + if (LF_ISSET(DB_LOCK_SWITCH) || lp != NULL) { + if (LF_ISSET(DB_LOCK_SWITCH) && + (ret = __lock_put_nolock(dbenv, + lock, &ihold, DB_LOCK_NOWAITERS)) != 0) + goto err; + /* + * This is really a blocker for the thread. It should be + * initialized locked, so that when we try to acquire it, we + * block. + */ + newl->status = DB_LSTAT_WAITING; + region->nconflicts++; + if (region->detect == DB_LOCK_NORUN) + region->need_dd = 1; + UNLOCKREGION(dbenv, (DB_LOCKTAB *)dbenv->lk_handle); + + /* + * We are about to wait; before waiting, see if the deadlock + * detector should be run. + */ + if (region->detect != DB_LOCK_NORUN && !no_dd) + (void)lock_detect(dbenv, 0, region->detect, &did_abort); + + MUTEX_LOCK(dbenv, &newl->mutex, dbenv->lockfhp); + LOCKREGION(dbenv, (DB_LOCKTAB *)dbenv->lk_handle); + + if (newl->status != DB_LSTAT_PENDING) { + (void)__lock_checklocker(lt, + newl, newl->holder, 0, &freed); + switch (newl->status) { + case DB_LSTAT_ABORTED: + on_locker_list = 0; + ret = DB_LOCK_DEADLOCK; + break; + case DB_LSTAT_NOGRANT: + ret = DB_LOCK_NOTGRANTED; + break; + default: + ret = EINVAL; + break; + } + goto err; + } else if (LF_ISSET(DB_LOCK_UPGRADE)) { + /* + * The lock that was just granted got put on the + * holders list. Since we're upgrading some other + * lock, we've got to remove it here. + */ + SH_TAILQ_REMOVE( + &sh_obj->holders, newl, links, __db_lock); + /* + * Ensure that the object is not believed to be on + * the object's lists, if we're traversing by locker. + */ + newl->links.stqe_prev = -1; + goto upgrade; + } else + newl->status = DB_LSTAT_HELD; + } + + lock->off = R_OFFSET(<->reginfo, newl); + lock->gen = newl->gen; + + return (0); + +upgrade:/* + * This was an upgrade, so return the new lock to the free list and + * upgrade the mode of the original lock. + */ + ((struct __db_lock *)R_ADDR(<->reginfo, lock->off))->mode = lock_mode; + + ret = 0; + /* FALLTHROUGH */ + +done: +err: newl->status = DB_LSTAT_FREE; + if (on_locker_list) { + SH_LIST_REMOVE(newl, locker_links, __db_lock); + } + SH_TAILQ_INSERT_HEAD(®ion->free_locks, newl, links, __db_lock); + region->nlocks--; + return (ret); +} + +/* + * Lock release routines. + * + * The user callable one is lock_put and the three we use internally are + * __lock_put_nolock, __lock_put_internal and __lock_downgrade. + */ +int +lock_put(dbenv, lock) + DB_ENV *dbenv; + DB_LOCK *lock; +{ + DB_LOCKTAB *lt; + int ret, run_dd; + +#ifdef HAVE_RPC + if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) + return (__dbcl_lock_put(dbenv, lock)); +#endif + PANIC_CHECK(dbenv); + ENV_REQUIRES_CONFIG(dbenv, dbenv->lk_handle, DB_INIT_LOCK); + + if (IS_RECOVERING(dbenv)) + return (0); + + lt = dbenv->lk_handle; + + LOCKREGION(dbenv, lt); + ret = __lock_put_nolock(dbenv, lock, &run_dd, 0); + UNLOCKREGION(dbenv, lt); + + if (ret == 0 && run_dd) + (void)lock_detect(dbenv, 0, + ((DB_LOCKREGION *)lt->reginfo.primary)->detect, NULL); + return (ret); +} + +static int +__lock_put_nolock(dbenv, lock, runp, flags) + DB_ENV *dbenv; + DB_LOCK *lock; + int *runp; + int flags; +{ + struct __db_lock *lockp; + DB_LOCKREGION *region; + DB_LOCKTAB *lt; + u_int32_t locker; + int ret; + + lt = dbenv->lk_handle; + region = lt->reginfo.primary; + + lockp = (struct __db_lock *)R_ADDR(<->reginfo, lock->off); + lock->off = LOCK_INVALID; + if (lock->gen != lockp->gen) { + __db_err(dbenv, __db_lock_invalid, "lock_put"); + return (EACCES); + } + + locker = lockp->holder; + ret = __lock_put_internal(lt, + lockp, lock->ndx, flags | DB_LOCK_UNLINK | DB_LOCK_FREE); + + *runp = 0; + if (ret == 0 && region->need_dd && region->detect != DB_LOCK_NORUN) { + *runp = 1; + region->need_dd = 0; + } + + return (ret); +} + +/* + * __lock_downgrade -- + * Used by the concurrent access product to downgrade write locks + * back to iwrite locks. + * + * PUBLIC: int __lock_downgrade __P((DB_ENV *, + * PUBLIC: DB_LOCK *, db_lockmode_t, u_int32_t)); + */ +int +__lock_downgrade(dbenv, lock, new_mode, flags) + DB_ENV *dbenv; + DB_LOCK *lock; + db_lockmode_t new_mode; + u_int32_t flags; +{ + struct __db_lock *lockp; + DB_LOCKOBJ *obj; + DB_LOCKREGION *region; + DB_LOCKTAB *lt; + int ret; + + COMPQUIET(flags, 0); + + PANIC_CHECK(dbenv); + + lt = dbenv->lk_handle; + region = lt->reginfo.primary; + + LOCKREGION(dbenv, lt); + + lockp = (struct __db_lock *)R_ADDR(<->reginfo, lock->off); + if (lock->gen != lockp->gen) { + __db_err(dbenv, __db_lock_invalid, "lock_downgrade"); + ret = EACCES; + goto out; + } + + lockp->mode = new_mode; + + /* Get the object associated with this lock. */ + obj = (DB_LOCKOBJ *)((u_int8_t *)lockp + lockp->obj); + (void)__lock_promote(lt, obj, LF_ISSET(DB_LOCK_NOWAITERS)); + + ++region->nreleases; +out: UNLOCKREGION(dbenv, lt); + + return (0); +} + +static int +__lock_put_internal(lt, lockp, obj_ndx, flags) + DB_LOCKTAB *lt; + struct __db_lock *lockp; + u_int32_t obj_ndx; + u_int32_t flags; +{ + DB_LOCKOBJ *sh_obj; + DB_LOCKREGION *region; + int no_reclaim, ret, state_changed; + + region = lt->reginfo.primary; + no_reclaim = ret = state_changed = 0; + + if (!OBJ_LINKS_VALID(lockp)) { + /* + * Someone removed this lock while we were doing a release + * by locker id. We are trying to free this lock, but it's + * already been done; all we need to do is return it to the + * free list. + */ + lockp->status = DB_LSTAT_FREE; + SH_TAILQ_INSERT_HEAD( + ®ion->free_locks, lockp, links, __db_lock); + region->nlocks--; + return (0); + } + + if (LF_ISSET(DB_LOCK_DOALL)) + region->nreleases += lockp->refcount; + else + region->nreleases++; + + if (!LF_ISSET(DB_LOCK_DOALL) && lockp->refcount > 1) { + lockp->refcount--; + return (0); + } + + /* Increment generation number. */ + lockp->gen++; + + /* Get the object associated with this lock. */ + sh_obj = (DB_LOCKOBJ *)((u_int8_t *)lockp + lockp->obj); + + /* Remove this lock from its holders/waitlist. */ + if (lockp->status != DB_LSTAT_HELD) + __lock_remove_waiter(lt->dbenv, sh_obj, lockp, DB_LSTAT_FREE); + else { + SH_TAILQ_REMOVE(&sh_obj->holders, lockp, links, __db_lock); + lockp->links.stqe_prev = -1; + } + + if (LF_ISSET(DB_LOCK_NOPROMOTE)) + state_changed = 0; + else + state_changed = + __lock_promote(lt, sh_obj, LF_ISSET(DB_LOCK_NOWAITERS)); + + if (LF_ISSET(DB_LOCK_UNLINK)) + ret = __lock_checklocker(lt, lockp, lockp->holder, flags, NULL); + + /* Check if object should be reclaimed. */ + if (SH_TAILQ_FIRST(&sh_obj->holders, __db_lock) == NULL + && SH_TAILQ_FIRST(&sh_obj->waiters, __db_lock) == NULL) { + HASHREMOVE_EL(lt->obj_tab, + obj_ndx, __db_lockobj, links, sh_obj); + if (sh_obj->lockobj.size > sizeof(sh_obj->objdata)) + __db_shalloc_free(lt->reginfo.addr, + SH_DBT_PTR(&sh_obj->lockobj)); + SH_TAILQ_INSERT_HEAD( + ®ion->free_objs, sh_obj, links, __db_lockobj); + region->nobjects--; + state_changed = 1; + } + + /* Free lock. */ + if (!LF_ISSET(DB_LOCK_UNLINK) && LF_ISSET(DB_LOCK_FREE)) { + lockp->status = DB_LSTAT_FREE; + SH_TAILQ_INSERT_HEAD( + ®ion->free_locks, lockp, links, __db_lock); + region->nlocks--; + } + + /* + * If we did not promote anyone; we need to run the deadlock + * detector again. + */ + if (state_changed == 0) + region->need_dd = 1; + + return (ret); +} + +/* + * Utility functions; listed alphabetically. + */ + +/* + * __lock_checklocker -- + * If a locker has no more locks, then we can free the object. + * Return a boolean indicating whether we freed the object or not. + * + * Must be called without the locker's lock set. + */ +static int +__lock_checklocker(lt, lockp, locker, flags, freed) + DB_LOCKTAB *lt; + struct __db_lock *lockp; + u_int32_t locker, flags; + int *freed; +{ + DB_ENV *dbenv; + DB_LOCKER *sh_locker; + DB_LOCKREGION *region; + u_int32_t indx; + int ret; + + dbenv = lt->dbenv; + region = lt->reginfo.primary; + ret = 0; + + if (freed != NULL) + *freed = 0; + + LOCKER_LOCK(lt, region, locker, indx); + + /* If the locker's list is NULL, free up the locker. */ + if ((ret = __lock_getlocker(lt, + locker, indx, 0, &sh_locker)) != 0 || sh_locker == NULL) { + if (ret == 0) + ret = EACCES; + __db_err(lt->dbenv, __db_locker_invalid); + goto freelock; + } + + if (F_ISSET(sh_locker, DB_LOCKER_DELETED)) { + LF_CLR(DB_LOCK_FREE); + if (!LF_ISSET(DB_LOCK_IGNOREDEL)) + goto freelock; + } + + if (LF_ISSET(DB_LOCK_UNLINK)) + SH_LIST_REMOVE(lockp, locker_links, __db_lock); + + if (SH_LIST_FIRST(&sh_locker->heldby, __db_lock) == NULL + && LOCKER_FREEABLE(sh_locker)) { + __lock_freelocker( lt, region, sh_locker, indx); + if (freed != NULL) + *freed = 1; + } + +freelock: + if (LF_ISSET(DB_LOCK_FREE)) { + lockp->status = DB_LSTAT_FREE; + SH_TAILQ_INSERT_HEAD( + ®ion->free_locks, lockp, links, __db_lock); + region->nlocks--; + } + + return (ret); +} + +/* + * __lock_addfamilylocker + * Put a locker entry in for a child transaction. + * + * PUBLIC: int __lock_addfamilylocker __P((DB_ENV *, u_int32_t, u_int32_t)); + */ +int +__lock_addfamilylocker(dbenv, pid, id) + DB_ENV *dbenv; + u_int32_t pid, id; +{ + DB_LOCKER *lockerp, *mlockerp; + DB_LOCKREGION *region; + DB_LOCKTAB *lt; + u_int32_t ndx; + int ret; + + lt = dbenv->lk_handle; + region = lt->reginfo.primary; + LOCKREGION(dbenv, lt); + + /* get/create the parent locker info */ + LOCKER_LOCK(lt, region, pid, ndx); + if ((ret = __lock_getlocker(dbenv->lk_handle, + pid, ndx, 1, &mlockerp)) != 0) + goto err; + + /* + * We assume that only one thread can manipulate + * a single transaction family. + * Therefore the master locker cannot go away while + * we manipulate it, nor can another child in the + * family be created at the same time. + */ + LOCKER_LOCK(lt, region, id, ndx); + if ((ret = __lock_getlocker(dbenv->lk_handle, + id, ndx, 1, &lockerp)) != 0) + goto err; + + /* Point to our parent. */ + lockerp->parent_locker = R_OFFSET(<->reginfo, mlockerp); + + /* See if this locker is the family master. */ + if (mlockerp->master_locker == INVALID_ROFF) + lockerp->master_locker = R_OFFSET(<->reginfo, mlockerp); + else { + lockerp->master_locker = mlockerp->master_locker; + mlockerp = R_ADDR(<->reginfo, mlockerp->master_locker); + } + + /* + * Link the child at the head of the master's list. + * The guess is when looking for deadlock that + * the most recent child is the one thats blocked. + */ + SH_LIST_INSERT_HEAD( + &mlockerp->child_locker, lockerp, child_link, __db_locker); + +err: + UNLOCKREGION(dbenv, lt); + + return (ret); +} + +/* + * __lock_freefamilylocker + * Remove a locker from the hash table and its family. + * + * This must be called without the locker bucket locked. + * + * PUBLIC: int __lock_freefamilylocker __P((DB_LOCKTAB *, u_int32_t)); + */ +int +__lock_freefamilylocker(lt, locker) + DB_LOCKTAB *lt; + u_int32_t locker; +{ + DB_ENV *dbenv; + DB_LOCKER *sh_locker; + DB_LOCKREGION *region; + u_int32_t indx; + int ret; + + dbenv = lt->dbenv; + region = lt->reginfo.primary; + + LOCKREGION(dbenv, lt); + LOCKER_LOCK(lt, region, locker, indx); + + if ((ret = __lock_getlocker(lt, + locker, indx, 0, &sh_locker)) != 0 || sh_locker == NULL) { + if (ret == 0) + ret = EACCES; + goto freelock; + } + if (SH_LIST_FIRST(&sh_locker->heldby, __db_lock) != NULL) { + ret = EINVAL; + __db_err(dbenv, "Freeing locker with locks"); + goto freelock; + } + + /* If this is part of a family, we must fix up its links. */ + if (sh_locker->master_locker != INVALID_ROFF) + SH_LIST_REMOVE(sh_locker, child_link, __db_locker); + + __lock_freelocker(lt, region, sh_locker, indx); + +freelock: + UNLOCKREGION(dbenv, lt); + return (ret); +} + +/* + * __lock_freelocker + * common code for deleting a locker. + * + * This must be called with the locker bucket locked. + * + * PUBLIC: void __lock_freelocker __P((DB_LOCKTAB *, + * PUBLIC: DB_LOCKREGION *, DB_LOCKER *, u_int32_t)); + */ +void +__lock_freelocker(lt, region, sh_locker, indx) + DB_LOCKTAB *lt; + DB_LOCKREGION *region; + DB_LOCKER *sh_locker; + u_int32_t indx; + +{ + HASHREMOVE_EL( + lt->locker_tab, indx, __db_locker, links, sh_locker); + SH_TAILQ_INSERT_HEAD( + ®ion->free_lockers, sh_locker, links, __db_locker); + region->nlockers--; +} + +/* + * __lock_getlocker -- + * Get a locker in the locker hash table. The create parameter + * indicates if the locker should be created if it doesn't exist in + * the table. + * + * This must be called with the locker bucket locked. + * + * PUBLIC: int __lock_getlocker __P((DB_LOCKTAB *, + * PUBLIC: u_int32_t, u_int32_t, int, DB_LOCKER **)); + */ +int +__lock_getlocker(lt, locker, indx, create, retp) + DB_LOCKTAB *lt; + u_int32_t locker, indx; + int create; + DB_LOCKER **retp; +{ + DB_ENV *dbenv; + DB_LOCKER *sh_locker; + DB_LOCKREGION *region; + + dbenv = lt->dbenv; + region = lt->reginfo.primary; + + HASHLOOKUP(lt->locker_tab, + indx, __db_locker, links, locker, sh_locker, __lock_locker_cmp); + + /* + * If we found the locker, then we can just return it. If + * we didn't find the locker, then we need to create it. + */ + if (sh_locker == NULL && create) { + /* Create new locker and then insert it into hash table. */ + if ((sh_locker = SH_TAILQ_FIRST( + ®ion->free_lockers, __db_locker)) == NULL) { + __db_err(lt->dbenv, __db_lock_err, "locker entries"); + return (ENOMEM); + } + SH_TAILQ_REMOVE( + ®ion->free_lockers, sh_locker, links, __db_locker); + if (++region->nlockers > region->maxnlockers) + region->maxnlockers = region->nlockers; + + sh_locker->id = locker; + sh_locker->dd_id = 0; + sh_locker->master_locker = INVALID_ROFF; + sh_locker->parent_locker = INVALID_ROFF; + SH_LIST_INIT(&sh_locker->child_locker); + sh_locker->flags = 0; + SH_LIST_INIT(&sh_locker->heldby); + + HASHINSERT(lt->locker_tab, indx, __db_locker, links, sh_locker); + } + + *retp = sh_locker; + return (0); +} + +/* + * __lock_getobj -- + * Get an object in the object hash table. The create parameter + * indicates if the object should be created if it doesn't exist in + * the table. + * + * This must be called with the object bucket locked. + * + * PUBLIC: int __lock_getobj __P((DB_LOCKTAB *, + * PUBLIC: const DBT *, u_int32_t, int, DB_LOCKOBJ **)); + */ +int +__lock_getobj(lt, obj, ndx, create, retp) + DB_LOCKTAB *lt; + const DBT *obj; + u_int32_t ndx; + int create; + DB_LOCKOBJ **retp; +{ + DB_ENV *dbenv; + DB_LOCKOBJ *sh_obj; + DB_LOCKREGION *region; + int ret; + void *p; + + dbenv = lt->dbenv; + region = lt->reginfo.primary; + + /* Look up the object in the hash table. */ + HASHLOOKUP(lt->obj_tab, + ndx, __db_lockobj, links, obj, sh_obj, __lock_cmp); + + /* + * If we found the object, then we can just return it. If + * we didn't find the object, then we need to create it. + */ + if (sh_obj == NULL && create) { + /* Create new object and then insert it into hash table. */ + if ((sh_obj = + SH_TAILQ_FIRST(®ion->free_objs, __db_lockobj)) == NULL) { + __db_err(lt->dbenv, __db_lock_err, "object entries"); + ret = ENOMEM; + goto err; + } + + /* + * If we can fit this object in the structure, do so instead + * of shalloc-ing space for it. + */ + if (obj->size <= sizeof(sh_obj->objdata)) + p = sh_obj->objdata; + else if ((ret = __db_shalloc( + lt->reginfo.addr, obj->size, 0, &p)) != 0) { + __db_err(dbenv, "No space for lock object storage"); + goto err; + } + + memcpy(p, obj->data, obj->size); + + SH_TAILQ_REMOVE( + ®ion->free_objs, sh_obj, links, __db_lockobj); + if (++region->nobjects > region->maxnobjects) + region->maxnobjects = region->nobjects; + + SH_TAILQ_INIT(&sh_obj->waiters); + SH_TAILQ_INIT(&sh_obj->holders); + sh_obj->lockobj.size = obj->size; + sh_obj->lockobj.off = SH_PTR_TO_OFF(&sh_obj->lockobj, p); + + HASHINSERT(lt->obj_tab, ndx, __db_lockobj, links, sh_obj); + } + + *retp = sh_obj; + return (0); + +err: return (ret); +} + +/* + * __lock_is_parent -- + * Given a locker and a transaction, return 1 if the locker is + * an ancestor of the designcated transaction. This is used to determine + * if we should grant locks that appear to conflict, but don't because + * the lock is already held by an ancestor. + */ +static int +__lock_is_parent(lt, locker, sh_locker) + DB_LOCKTAB *lt; + u_int32_t locker; + DB_LOCKER *sh_locker; +{ + DB_LOCKER *parent; + + parent = sh_locker; + while (parent->parent_locker != INVALID_ROFF) { + parent = (DB_LOCKER *) + R_ADDR(<->reginfo, parent->parent_locker); + if (parent->id == locker) + return (1); + } + + return (0); +} + +/* + * __lock_promote -- + * + * Look through the waiters and holders lists and decide which (if any) + * locks can be promoted. Promote any that are eligible. + * + * PUBLIC: int __lock_promote __P((DB_LOCKTAB *, DB_LOCKOBJ *, int)); + */ +int +__lock_promote(lt, obj, not_waiters) + DB_LOCKTAB *lt; + DB_LOCKOBJ *obj; + int not_waiters; +{ + struct __db_lock *lp_w, *lp_h, *next_waiter; + DB_LOCKER *sh_locker; + DB_LOCKREGION *region; + u_int32_t locker_ndx; + int had_waiters, state_changed; + + region = lt->reginfo.primary; + had_waiters = 0; + + /* + * We need to do lock promotion. We also need to determine if we're + * going to need to run the deadlock detector again. If we release + * locks, and there are waiters, but no one gets promoted, then we + * haven't fundamentally changed the lockmgr state, so we may still + * have a deadlock and we have to run again. However, if there were + * no waiters, or we actually promoted someone, then we are OK and we + * don't have to run it immediately. + * + * During promotion, we look for state changes so we can return this + * information to the caller. + */ + + for (lp_w = SH_TAILQ_FIRST(&obj->waiters, __db_lock), + state_changed = lp_w == NULL; + lp_w != NULL; + lp_w = next_waiter) { + had_waiters = 1; + next_waiter = SH_TAILQ_NEXT(lp_w, links, __db_lock); + /* Are we switching locks? */ + if (not_waiters && lp_w->mode == DB_LOCK_WAIT) + continue; + for (lp_h = SH_TAILQ_FIRST(&obj->holders, __db_lock); + lp_h != NULL; + lp_h = SH_TAILQ_NEXT(lp_h, links, __db_lock)) { + if (lp_h->holder != lp_w->holder && + CONFLICTS(lt, region, lp_h->mode, lp_w->mode)) { + + LOCKER_LOCK(lt, region, lp_w->holder, locker_ndx); + if ((__lock_getlocker(lt, lp_w->holder, + locker_ndx, 0, &sh_locker)) != 0) { + DB_ASSERT(0); + break; + } + if (!__lock_is_parent(lt, + lp_h->holder, sh_locker)) + break; + } + } + if (lp_h != NULL) /* Found a conflict. */ + break; + + /* No conflict, promote the waiting lock. */ + SH_TAILQ_REMOVE(&obj->waiters, lp_w, links, __db_lock); + lp_w->status = DB_LSTAT_PENDING; + SH_TAILQ_INSERT_TAIL(&obj->holders, lp_w, links); + + /* Wake up waiter. */ + MUTEX_UNLOCK(lt->dbenv, &lp_w->mutex); + state_changed = 1; + } + + /* + * If this object had waiters and doesn't any more, then we need + * to remove it from the dd_obj list. + */ + if (had_waiters && SH_TAILQ_FIRST(&obj->waiters, __db_lock) == NULL) + SH_TAILQ_REMOVE(®ion->dd_objs, obj, dd_links, __db_lockobj); + return (state_changed); +} + +/* + * __lock_remove_waiter -- + * Any lock on the waitlist has a process waiting for it. Therefore, + * we can't return the lock to the freelist immediately. Instead, we can + * remove the lock from the list of waiters, set the status field of the + * lock, and then let the process waking up return the lock to the + * free list. + * + * This must be called with the Object bucket locked. + */ +static void +__lock_remove_waiter(dbenv, sh_obj, lockp, status) + DB_ENV *dbenv; + DB_LOCKOBJ *sh_obj; + struct __db_lock *lockp; + db_status_t status; +{ + int do_wakeup; + + do_wakeup = lockp->status == DB_LSTAT_WAITING; + + SH_TAILQ_REMOVE(&sh_obj->waiters, lockp, links, __db_lock); + lockp->links.stqe_prev = -1; + lockp->status = status; + + /* + * Wake whoever is waiting on this lock. + * + * The MUTEX_UNLOCK macro normally resolves to a single argument, + * keep the compiler quiet. + */ + if (do_wakeup) + MUTEX_UNLOCK(dbenv, &lockp->mutex); +} + +/* + * __lock_printlock -- + * + * PUBLIC: void __lock_printlock __P((DB_LOCKTAB *, struct __db_lock *, int)); + */ +void +__lock_printlock(lt, lp, ispgno) + DB_LOCKTAB *lt; + struct __db_lock *lp; + int ispgno; +{ + DB_LOCKOBJ *lockobj; + db_pgno_t pgno; + u_int32_t *fidp; + u_int8_t *ptr, type; + const char *mode, *status; + + switch (lp->mode) { + case DB_LOCK_IREAD: + mode = "IREAD"; + break; + case DB_LOCK_IWR: + mode = "IWR"; + break; + case DB_LOCK_IWRITE: + mode = "IWRITE"; + break; + case DB_LOCK_NG: + mode = "NG"; + break; + case DB_LOCK_READ: + mode = "READ"; + break; + case DB_LOCK_WRITE: + mode = "WRITE"; + break; + case DB_LOCK_WAIT: + mode = "WAIT"; + break; + default: + mode = "UNKNOWN"; + break; + } + switch (lp->status) { + case DB_LSTAT_ABORTED: + status = "ABORT"; + break; + case DB_LSTAT_ERR: + status = "ERROR"; + break; + case DB_LSTAT_FREE: + status = "FREE"; + break; + case DB_LSTAT_HELD: + status = "HELD"; + break; + case DB_LSTAT_NOGRANT: + status = "NONE"; + break; + case DB_LSTAT_WAITING: + status = "WAIT"; + break; + case DB_LSTAT_PENDING: + status = "PENDING"; + break; + default: + status = "UNKNOWN"; + break; + } + printf("\t%lx\t%s\t%lu\t%s\t", + (u_long)lp->holder, mode, (u_long)lp->refcount, status); + + lockobj = (DB_LOCKOBJ *)((u_int8_t *)lp + lp->obj); + ptr = SH_DBT_PTR(&lockobj->lockobj); + if (ispgno && lockobj->lockobj.size == sizeof(struct __db_ilock)) { + /* Assume this is a DBT lock. */ + memcpy(&pgno, ptr, sizeof(db_pgno_t)); + fidp = (u_int32_t *)(ptr + sizeof(db_pgno_t)); + type = *(u_int8_t *)(ptr + sizeof(db_pgno_t) + DB_FILE_ID_LEN); + printf("%s %lu (%lu %lu %lu %lu %lu)\n", + type == DB_PAGE_LOCK ? "page" : "record", + (u_long)pgno, + (u_long)fidp[0], (u_long)fidp[1], (u_long)fidp[2], + (u_long)fidp[3], (u_long)fidp[4]); + } else { + printf("0x%lx ", (u_long)R_OFFSET(<->reginfo, lockobj)); + __db_pr(ptr, lockobj->lockobj.size); + printf("\n"); + } +} diff --git a/db/lock/lock_conflict.c b/db/lock/lock_conflict.c new file mode 100644 index 000000000..2d7945fe2 --- /dev/null +++ b/db/lock/lock_conflict.c @@ -0,0 +1,34 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: lock_conflict.c,v 11.6 2000/12/12 17:38:13 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include +#endif + +#include "db_int.h" + +/* + * The conflict arrays are set up such that the row is the lock you + * are holding and the column is the lock that is desired. + */ + +const u_int8_t db_riw_conflicts[] = { + /* N S X WT IX IS SIX */ + /* N */ 0, 0, 0, 0, 0, 0, 0, + /* S */ 0, 0, 1, 0, 1, 0, 1, + /* X */ 0, 1, 1, 1, 1, 1, 1, + /* WT */ 0, 0, 0, 0, 0, 0, 0, + /* IX */ 0, 1, 1, 0, 0, 0, 0, + /* IS */ 0, 0, 1, 0, 0, 0, 0, + /* SIX */ 0, 1, 1, 0, 0, 0, 0 +}; diff --git a/db/lock/lock_deadlock.c b/db/lock/lock_deadlock.c new file mode 100644 index 000000000..1f37db389 --- /dev/null +++ b/db/lock/lock_deadlock.c @@ -0,0 +1,637 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: lock_deadlock.c,v 11.23 2000/12/08 20:15:31 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#ifdef HAVE_RPC +#include "db_server.h" +#endif + +#include "db_int.h" +#include "db_shash.h" +#include "lock.h" +#include "txn.h" + +#ifdef HAVE_RPC +#include "gen_client_ext.h" +#include "rpc_client_ext.h" +#endif + +#define ISSET_MAP(M, N) ((M)[(N) / 32] & (1 << (N) % 32)) + +#define CLEAR_MAP(M, N) { \ + u_int32_t __i; \ + for (__i = 0; __i < (N); __i++) \ + (M)[__i] = 0; \ +} + +#define SET_MAP(M, B) ((M)[(B) / 32] |= (1 << ((B) % 32))) +#define CLR_MAP(M, B) ((M)[(B) / 32] &= ~(1 << ((B) % 32))) + +#define OR_MAP(D, S, N) { \ + u_int32_t __i; \ + for (__i = 0; __i < (N); __i++) \ + D[__i] |= S[__i]; \ +} +#define BAD_KILLID 0xffffffff + +typedef struct { + int valid; + u_int32_t id; + u_int32_t last_lock; + u_int32_t last_locker_id; + db_pgno_t pgno; +} locker_info; + +static int __dd_abort __P((DB_ENV *, locker_info *)); +static int __dd_build + __P((DB_ENV *, u_int32_t **, u_int32_t *, locker_info **)); +static int __dd_find + __P((DB_ENV *,u_int32_t *, locker_info *, u_int32_t, u_int32_t ***)); + +#ifdef DIAGNOSTIC +static void __dd_debug __P((DB_ENV *, locker_info *, u_int32_t *, u_int32_t)); +#endif + +int +lock_detect(dbenv, flags, atype, abortp) + DB_ENV *dbenv; + u_int32_t flags, atype; + int *abortp; +{ + DB_LOCKREGION *region; + DB_LOCKTAB *lt; + locker_info *idmap; + u_int32_t *bitmap, **deadp, **free_me, i, killid, nentries, nlockers; + int do_pass, ret; + +#ifdef HAVE_RPC + if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) + return (__dbcl_lock_detect(dbenv, flags, atype, abortp)); +#endif + + PANIC_CHECK(dbenv); + ENV_REQUIRES_CONFIG(dbenv, dbenv->lk_handle, DB_INIT_LOCK); + + lt = dbenv->lk_handle; + if (abortp != NULL) + *abortp = 0; + + /* Validate arguments. */ + if ((ret = + __db_fchk(dbenv, "lock_detect", flags, DB_LOCK_CONFLICT)) != 0) + return (ret); + + /* Check if a detector run is necessary. */ + LOCKREGION(dbenv, lt); + if (LF_ISSET(DB_LOCK_CONFLICT)) { + /* Make a pass every time a lock waits. */ + region = lt->reginfo.primary; + do_pass = region->need_dd != 0; + + if (!do_pass) { + UNLOCKREGION(dbenv, lt); + return (0); + } + } + + /* Build the waits-for bitmap. */ + ret = __dd_build(dbenv, &bitmap, &nlockers, &idmap); + UNLOCKREGION(dbenv, lt); + if (ret != 0) + return (ret); + + if (nlockers == 0) + return (0); +#ifdef DIAGNOSTIC + if (FLD_ISSET(dbenv->verbose, DB_VERB_WAITSFOR)) + __dd_debug(dbenv, idmap, bitmap, nlockers); +#endif + /* Find a deadlock. */ + if ((ret = __dd_find(dbenv, bitmap, idmap, nlockers, &deadp)) != 0) + return (ret); + + nentries = ALIGN(nlockers, 32) / 32; + killid = BAD_KILLID; + free_me = deadp; + for (; *deadp != NULL; deadp++) { + if (abortp != NULL) + ++*abortp; + switch (atype) { /* Kill someone. */ + case DB_LOCK_OLDEST: + /* + * Find the first bit set in the current + * array and then look for a lower tid in + * the array. + */ + for (i = 0; i < nlockers; i++) + if (ISSET_MAP(*deadp, i)) { + killid = i; + break; + + } + /* + * It's conceivable that under XA, the locker could + * have gone away. + */ + if (killid == BAD_KILLID) + break; + + /* + * The oldest transaction has the lowest + * transaction id. + */ + for (i = killid + 1; i < nlockers; i++) + if (ISSET_MAP(*deadp, i) && + idmap[i].id < idmap[killid].id) + killid = i; + break; + case DB_LOCK_DEFAULT: + case DB_LOCK_RANDOM: + /* + * We are trying to calculate the id of the + * locker whose entry is indicated by deadlock. + */ + killid = (*deadp - bitmap) / nentries; + break; + case DB_LOCK_YOUNGEST: + /* + * Find the first bit set in the current + * array and then look for a lower tid in + * the array. + */ + for (i = 0; i < nlockers; i++) + if (ISSET_MAP(*deadp, i)) { + killid = i; + break; + } + + /* + * It's conceivable that under XA, the locker could + * have gone away. + */ + if (killid == BAD_KILLID) + break; + + /* + * The youngest transaction has the highest + * transaction id. + */ + for (i = killid + 1; i < nlockers; i++) + if (ISSET_MAP(*deadp, i) && + idmap[i].id > idmap[killid].id) + killid = i; + break; + default: + killid = BAD_KILLID; + ret = EINVAL; + } + + if (killid == BAD_KILLID) + continue; + + /* Kill the locker with lockid idmap[killid]. */ + if ((ret = __dd_abort(dbenv, &idmap[killid])) != 0) { + /* + * It's possible that the lock was already aborted; + * this isn't necessarily a problem, so do not treat + * it as an error. + */ + if (ret == DB_ALREADY_ABORTED) + ret = 0; + else + __db_err(dbenv, + "warning: unable to abort locker %lx", + (u_long)idmap[killid].id); + } else if (FLD_ISSET(dbenv->verbose, DB_VERB_DEADLOCK)) + __db_err(dbenv, + "Aborting locker %lx", (u_long)idmap[killid].id); + } + __os_free(free_me, 0); + __os_free(bitmap, 0); + __os_free(idmap, 0); + + return (ret); +} + +/* + * ======================================================================== + * Utilities + */ + +# define DD_INVALID_ID ((u_int32_t) -1) + +static int +__dd_build(dbenv, bmp, nlockers, idmap) + DB_ENV *dbenv; + u_int32_t **bmp, *nlockers; + locker_info **idmap; +{ + struct __db_lock *lp; + DB_LOCKER *lip, *lockerp, *child; + DB_LOCKOBJ *op, *lo; + DB_LOCKREGION *region; + DB_LOCKTAB *lt; + locker_info *id_array; + u_int32_t *bitmap, count, dd, *entryp, i, id, ndx, nentries, *tmpmap; + u_int8_t *pptr; + int is_first, ret; + + lt = dbenv->lk_handle; + region = lt->reginfo.primary; + + /* + * We'll check how many lockers there are, add a few more in for + * good measure and then allocate all the structures. Then we'll + * verify that we have enough room when we go back in and get the + * mutex the second time. + */ +retry: count = region->nlockers; + region->need_dd = 0; + + if (count == 0) { + *nlockers = 0; + return (0); + } + + if (FLD_ISSET(dbenv->verbose, DB_VERB_DEADLOCK)) + __db_err(dbenv, "%lu lockers", (u_long)count); + + count += 40; + nentries = ALIGN(count, 32) / 32; + + /* + * Allocate enough space for a count by count bitmap matrix. + * + * XXX + * We can probably save the malloc's between iterations just + * reallocing if necessary because count grew by too much. + */ + if ((ret = __os_calloc(dbenv, (size_t)count, + sizeof(u_int32_t) * nentries, &bitmap)) != 0) + return (ret); + + if ((ret = __os_calloc(dbenv, + sizeof(u_int32_t), nentries, &tmpmap)) != 0) { + __os_free(bitmap, sizeof(u_int32_t) * nentries); + return (ret); + } + + if ((ret = __os_calloc(dbenv, + (size_t)count, sizeof(locker_info), &id_array)) != 0) { + __os_free(bitmap, count * sizeof(u_int32_t) * nentries); + __os_free(tmpmap, sizeof(u_int32_t) * nentries); + return (ret); + } + + /* + * Now go back in and actually fill in the matrix. + */ + if (region->nlockers > count) { + __os_free(bitmap, count * sizeof(u_int32_t) * nentries); + __os_free(tmpmap, sizeof(u_int32_t) * nentries); + __os_free(id_array, count * sizeof(locker_info)); + goto retry; + } + + /* + * First we go through and assign each locker a deadlock detector id. + */ + for (id = 0, i = 0; i < region->locker_t_size; i++) { + for (lip = SH_TAILQ_FIRST(<->locker_tab[i], __db_locker); + lip != NULL; lip = SH_TAILQ_NEXT(lip, links, __db_locker)) + if (lip->master_locker == INVALID_ROFF) { + lip->dd_id = id++; + id_array[lip->dd_id].id = lip->id; + } else + lip->dd_id = DD_INVALID_ID; + } + + /* + * We only need consider objects that have waiters, so we use + * the list of objects with waiters (dd_objs) instead of traversing + * the entire hash table. For each object, we traverse the waiters + * list and add an entry in the waitsfor matrix for each waiter/holder + * combination. + */ + for (op = SH_TAILQ_FIRST(®ion->dd_objs, __db_lockobj); + op != NULL; op = SH_TAILQ_NEXT(op, dd_links, __db_lockobj)) { + CLEAR_MAP(tmpmap, nentries); + + /* + * First we go through and create a bit map that + * represents all the holders of this object. + */ + for (lp = SH_TAILQ_FIRST(&op->holders, __db_lock); + lp != NULL; + lp = SH_TAILQ_NEXT(lp, links, __db_lock)) { + LOCKER_LOCK(lt, region, lp->holder, ndx); + if ((ret = __lock_getlocker(lt, + lp->holder, ndx, 0, &lockerp)) != 0) + continue; + if (lockerp->dd_id == DD_INVALID_ID) + dd = ((DB_LOCKER *) + R_ADDR(<->reginfo, + lockerp->master_locker))->dd_id; + else + dd = lockerp->dd_id; + id_array[dd].valid = 1; + + /* + * If the holder has already been aborted, then + * we should ignore it for now. + */ + if (lp->status == DB_LSTAT_HELD) + SET_MAP(tmpmap, dd); + } + + /* + * Next, for each waiter, we set its row in the matrix + * equal to the map of holders we set up above. + */ + for (is_first = 1, + lp = SH_TAILQ_FIRST(&op->waiters, __db_lock); + lp != NULL; + is_first = 0, + lp = SH_TAILQ_NEXT(lp, links, __db_lock)) { + LOCKER_LOCK(lt, region, lp->holder, ndx); + if ((ret = __lock_getlocker(lt, + lp->holder, ndx, 0, &lockerp)) != 0) + continue; + if (lockerp->dd_id == DD_INVALID_ID) + dd = ((DB_LOCKER *) + R_ADDR(<->reginfo, + lockerp->master_locker))->dd_id; + else + dd = lockerp->dd_id; + id_array[dd].valid = 1; + + /* + * If the transaction is pending abortion, then + * ignore it on this iteration. + */ + if (lp->status != DB_LSTAT_WAITING) + continue; + + entryp = bitmap + (nentries * dd); + OR_MAP(entryp, tmpmap, nentries); + /* + * If this is the first waiter on the queue, + * then we remove the waitsfor relationship + * with oneself. However, if it's anywhere + * else on the queue, then we have to keep + * it and we have an automatic deadlock. + */ + if (is_first) + CLR_MAP(entryp, dd); + } + } + + /* Now for each locker; record its last lock. */ + for (id = 0; id < count; id++) { + if (!id_array[id].valid) + continue; + LOCKER_LOCK(lt, region, id_array[id].id, ndx); + if ((ret = __lock_getlocker(lt, + id_array[id].id, ndx, 0, &lockerp)) != 0) { + __db_err(dbenv, + "No locks for locker %lu", (u_long)id_array[id].id); + continue; + } + + /* + * If this is a master transaction, try to + * find one of its children's locks first, + * as they are probably more recent. + */ + child = SH_LIST_FIRST(&lockerp->child_locker, __db_locker); + if (child != NULL) { + do { + lp = SH_LIST_FIRST(&child->heldby, __db_lock); + if (lp != NULL && + lp->status == DB_LSTAT_WAITING) { + id_array[id].last_locker_id = child->id; + goto get_lock; + } + child = SH_LIST_NEXT( + child, child_link, __db_locker); + } while (child != NULL); + } + lp = SH_LIST_FIRST(&lockerp->heldby, __db_lock); + if (lp != NULL) { + id_array[id].last_locker_id = lockerp->id; + get_lock: id_array[id].last_lock = R_OFFSET(<->reginfo, lp); + lo = (DB_LOCKOBJ *)((u_int8_t *)lp + lp->obj); + pptr = SH_DBT_PTR(&lo->lockobj); + if (lo->lockobj.size >= sizeof(db_pgno_t)) + memcpy(&id_array[id].pgno, + pptr, sizeof(db_pgno_t)); + else + id_array[id].pgno = 0; + } + } + + /* Pass complete, reset the deadlock detector bit. */ + region->need_dd = 0; + + /* + * Now we can release everything except the bitmap matrix that we + * created. + */ + *nlockers = id; + *idmap = id_array; + *bmp = bitmap; + __os_free(tmpmap, sizeof(u_int32_t) * nentries); + return (0); +} + +static int +__dd_find(dbenv, bmp, idmap, nlockers, deadp) + DB_ENV *dbenv; + u_int32_t *bmp, nlockers; + locker_info *idmap; + u_int32_t ***deadp; +{ + u_int32_t i, j, k, nentries, *mymap, *tmpmap; + u_int32_t **retp; + int ndead, ndeadalloc, ret; + +#undef INITIAL_DEAD_ALLOC +#define INITIAL_DEAD_ALLOC 8 + + ndeadalloc = INITIAL_DEAD_ALLOC; + ndead = 0; + if ((ret = __os_malloc(dbenv, + ndeadalloc * sizeof(u_int32_t *), NULL, &retp)) != 0) + return (ret); + + /* + * For each locker, OR in the bits from the lockers on which that + * locker is waiting. + */ + nentries = ALIGN(nlockers, 32) / 32; + for (mymap = bmp, i = 0; i < nlockers; i++, mymap += nentries) { + if (!idmap[i].valid) + continue; + for (j = 0; j < nlockers; j++) { + if (!ISSET_MAP(mymap, j)) + continue; + + /* Find the map for this bit. */ + tmpmap = bmp + (nentries * j); + OR_MAP(mymap, tmpmap, nentries); + if (!ISSET_MAP(mymap, i)) + continue; + + /* Make sure we leave room for NULL. */ + if (ndead + 2 >= ndeadalloc) { + ndeadalloc <<= 1; + /* + * If the alloc fails, then simply return the + * deadlocks that we already have. + */ + if (__os_realloc(dbenv, + ndeadalloc * sizeof(u_int32_t), + NULL, &retp) != 0) { + retp[ndead] = NULL; + *deadp = retp; + return (0); + } + } + retp[ndead++] = mymap; + + /* Mark all participants in this deadlock invalid. */ + for (k = 0; k < nlockers; k++) + if (ISSET_MAP(mymap, k)) + idmap[k].valid = 0; + break; + } + } + retp[ndead] = NULL; + *deadp = retp; + return (0); +} + +static int +__dd_abort(dbenv, info) + DB_ENV *dbenv; + locker_info *info; +{ + struct __db_lock *lockp; + DB_LOCKER *lockerp; + DB_LOCKOBJ *sh_obj; + DB_LOCKREGION *region; + DB_LOCKTAB *lt; + u_int32_t ndx; + int ret; + + lt = dbenv->lk_handle; + region = lt->reginfo.primary; + + LOCKREGION(dbenv, lt); + /* Find the locker's last lock. */ + LOCKER_LOCK(lt, region, info->last_locker_id, ndx); + if ((ret = __lock_getlocker(lt, + info->last_locker_id, ndx, 0, &lockerp)) != 0 || lockerp == NULL) { + if (ret == 0) + ret = DB_ALREADY_ABORTED; + goto out; + } + + lockp = SH_LIST_FIRST(&lockerp->heldby, __db_lock); + + /* + * It's possible that this locker was already aborted. If that's + * the case, make sure that we remove its locker from the hash table. + */ + if (lockp == NULL) { + if (LOCKER_FREEABLE(lockerp)) { + __lock_freelocker(lt, region, lockerp, ndx); + goto out; + } + } else if (R_OFFSET(<->reginfo, lockp) != info->last_lock || + lockp->status != DB_LSTAT_WAITING) { + ret = DB_ALREADY_ABORTED; + goto out; + } + + sh_obj = (DB_LOCKOBJ *)((u_int8_t *)lockp + lockp->obj); + SH_LIST_REMOVE(lockp, locker_links, __db_lock); + + /* Abort lock, take it off list, and wake up this lock. */ + SHOBJECT_LOCK(lt, region, sh_obj, ndx); + lockp->status = DB_LSTAT_ABORTED; + SH_TAILQ_REMOVE(&sh_obj->waiters, lockp, links, __db_lock); + + /* + * Either the waiters list is now empty, in which case we remove + * it from dd_objs, or it is not empty, in which case we need to + * do promotion. + */ + if (SH_TAILQ_FIRST(&sh_obj->waiters, __db_lock) == NULL) + SH_TAILQ_REMOVE(®ion->dd_objs, + sh_obj, dd_links, __db_lockobj); + else + ret = __lock_promote(lt, sh_obj, 0); + MUTEX_UNLOCK(dbenv, &lockp->mutex); + + region->ndeadlocks++; + UNLOCKREGION(dbenv, lt); + + return (0); + +out: UNLOCKREGION(dbenv, lt); + return (ret); +} + +#ifdef DIAGNOSTIC +static void +__dd_debug(dbenv, idmap, bitmap, nlockers) + DB_ENV *dbenv; + locker_info *idmap; + u_int32_t *bitmap, nlockers; +{ + u_int32_t i, j, *mymap, nentries; + int ret; + char *msgbuf; + + __db_err(dbenv, "Waitsfor array\nWaiter:\tWaiting on:"); + + /* Allocate space to print 10 bytes per item waited on. */ +#undef MSGBUF_LEN +#define MSGBUF_LEN ((nlockers + 1) * 10 + 64) + if ((ret = __os_malloc(dbenv, MSGBUF_LEN, NULL, &msgbuf)) != 0) + return; + + nentries = ALIGN(nlockers, 32) / 32; + for (mymap = bitmap, i = 0; i < nlockers; i++, mymap += nentries) { + if (!idmap[i].valid) + continue; + sprintf(msgbuf, /* Waiter. */ + "%lx/%lu:\t", (u_long)idmap[i].id, (u_long)idmap[i].pgno); + for (j = 0; j < nlockers; j++) + if (ISSET_MAP(mymap, j)) + sprintf(msgbuf, "%s %lx", msgbuf, + (u_long)idmap[j].id); + (void)sprintf(msgbuf, + "%s %lu", msgbuf, (u_long)idmap[i].last_lock); + __db_err(dbenv, msgbuf); + } + + __os_free(msgbuf, MSGBUF_LEN); +} +#endif diff --git a/db/lock/lock_method.c b/db/lock/lock_method.c new file mode 100644 index 000000000..46ed9e516 --- /dev/null +++ b/db/lock/lock_method.c @@ -0,0 +1,148 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: lock_method.c,v 11.5 2000/12/21 19:16:42 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_shash.h" +#include "lock.h" + +/* + * __lock_set_lk_conflicts + * Set the conflicts matrix. + * + * PUBLIC: int __lock_set_lk_conflicts __P((DB_ENV *, u_int8_t *, int)); + */ +int +__lock_set_lk_conflicts(dbenv, lk_conflicts, lk_modes) + DB_ENV *dbenv; + u_int8_t *lk_conflicts; + int lk_modes; +{ + int ret; + + ENV_ILLEGAL_AFTER_OPEN(dbenv, "set_lk_conflicts"); + + if (dbenv->lk_conflicts != NULL) { + __os_free(dbenv->lk_conflicts, + dbenv->lk_modes * dbenv->lk_modes); + dbenv->lk_conflicts = NULL; + } + if ((ret = __os_malloc(dbenv, + lk_modes * lk_modes, NULL, &dbenv->lk_conflicts)) != 0) + return (ret); + memcpy(dbenv->lk_conflicts, lk_conflicts, lk_modes * lk_modes); + dbenv->lk_modes = lk_modes; + + return (0); +} + +/* + * __lock_set_lk_detect + * Set the automatic deadlock detection. + * + * PUBLIC: int __lock_set_lk_detect __P((DB_ENV *, u_int32_t)); + */ +int +__lock_set_lk_detect(dbenv, lk_detect) + DB_ENV *dbenv; + u_int32_t lk_detect; +{ + ENV_ILLEGAL_AFTER_OPEN(dbenv, "set_lk_detect"); + + switch (lk_detect) { + case DB_LOCK_DEFAULT: + case DB_LOCK_OLDEST: + case DB_LOCK_RANDOM: + case DB_LOCK_YOUNGEST: + break; + default: + return (EINVAL); + } + dbenv->lk_detect = lk_detect; + return (0); +} + +/* + * __lock_set_lk_max + * Set the lock table size. + * + * PUBLIC: int __lock_set_lk_max __P((DB_ENV *, u_int32_t)); + */ +int +__lock_set_lk_max(dbenv, lk_max) + DB_ENV *dbenv; + u_int32_t lk_max; +{ + ENV_ILLEGAL_AFTER_OPEN(dbenv, "set_lk_max"); + + dbenv->lk_max = lk_max; + dbenv->lk_max_objects = lk_max; + dbenv->lk_max_lockers = lk_max; + return (0); +} + +/* + * __lock_set_lk_max_locks + * Set the lock table size. + * + * PUBLIC: int __lock_set_lk_max_locks __P((DB_ENV *, u_int32_t)); + */ +int +__lock_set_lk_max_locks(dbenv, lk_max) + DB_ENV *dbenv; + u_int32_t lk_max; +{ + ENV_ILLEGAL_AFTER_OPEN(dbenv, "set_lk_max_locks"); + + dbenv->lk_max = lk_max; + return (0); +} + +/* + * __lock_set_lk_max_lockers + * Set the lock table size. + * + * PUBLIC: int __lock_set_lk_max_lockers __P((DB_ENV *, u_int32_t)); + */ +int +__lock_set_lk_max_lockers(dbenv, lk_max) + DB_ENV *dbenv; + u_int32_t lk_max; +{ + ENV_ILLEGAL_AFTER_OPEN(dbenv, "set_lk_max_lockers"); + + dbenv->lk_max_lockers = lk_max; + return (0); +} + +/* + * __lock_set_lk_max_objects + * Set the lock table size. + * + * PUBLIC: int __lock_set_lk_max_objects __P((DB_ENV *, u_int32_t)); + */ +int +__lock_set_lk_max_objects(dbenv, lk_max) + DB_ENV *dbenv; + u_int32_t lk_max; +{ + ENV_ILLEGAL_AFTER_OPEN(dbenv, "set_lk_max_objects"); + + dbenv->lk_max_objects = lk_max; + return (0); +} diff --git a/db/lock/lock_region.c b/db/lock/lock_region.c new file mode 100644 index 000000000..4bd4ee4b7 --- /dev/null +++ b/db/lock/lock_region.c @@ -0,0 +1,430 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: lock_region.c,v 11.41 2000/12/20 21:53:04 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#ifdef HAVE_RPC +#include "db_server.h" +#endif + +#include "db_int.h" +#include "db_shash.h" +#include "lock.h" + +#ifdef HAVE_RPC +#include "gen_client_ext.h" +#include "rpc_client_ext.h" +#endif + +static int __lock_init __P((DB_ENV *, DB_LOCKTAB *)); +static size_t + __lock_region_size __P((DB_ENV *)); + +#ifdef MUTEX_SYSTEM_RESOURCES +static size_t __lock_region_maint __P((DB_ENV *)); +#endif + +/* + * This conflict array is used for concurrent db access (CDB). It + * uses the same locks as the db_rw_conflict array, but adds an IW + * mode to be used for write cursors. + */ +#define DB_LOCK_CDB_N 5 +static u_int8_t const db_cdb_conflicts[] = { + /* N R W WT IW*/ + /* N */ 0, 0, 0, 0, 0, + /* R */ 0, 0, 1, 0, 0, + /* W */ 0, 1, 1, 1, 1, + /* WT */ 0, 0, 0, 0, 0, + /* IW */ 0, 0, 1, 0, 1, +}; + +/* + * __lock_dbenv_create -- + * Lock specific creation of the DB_ENV structure. + * + * PUBLIC: void __lock_dbenv_create __P((DB_ENV *)); + */ +void +__lock_dbenv_create(dbenv) + DB_ENV *dbenv; +{ + dbenv->lk_max = DB_LOCK_DEFAULT_N; + dbenv->lk_max_lockers = DB_LOCK_DEFAULT_N; + dbenv->lk_max_objects = DB_LOCK_DEFAULT_N; + + dbenv->set_lk_conflicts = __lock_set_lk_conflicts; + dbenv->set_lk_detect = __lock_set_lk_detect; + dbenv->set_lk_max = __lock_set_lk_max; + dbenv->set_lk_max_locks = __lock_set_lk_max_locks; + dbenv->set_lk_max_lockers = __lock_set_lk_max_lockers; + dbenv->set_lk_max_objects = __lock_set_lk_max_objects; + +#ifdef HAVE_RPC + /* + * If we have a client, overwrite what we just set up to point + * to the client functions. + */ + if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) { + dbenv->set_lk_conflicts = __dbcl_set_lk_conflict; + dbenv->set_lk_detect = __dbcl_set_lk_detect; + dbenv->set_lk_max = __dbcl_set_lk_max; + dbenv->set_lk_max_locks = __dbcl_set_lk_max_locks; + dbenv->set_lk_max_lockers = __dbcl_set_lk_max_lockers; + dbenv->set_lk_max_objects = __dbcl_set_lk_max_objects; + } +#endif +} + +/* + * __lock_dbenv_close -- + * Lock specific destruction of the DB_ENV structure. + * + * PUBLIC: void __lock_dbenv_close __P((DB_ENV *)); + */ +void +__lock_dbenv_close(dbenv) + DB_ENV *dbenv; +{ + if (!F_ISSET(dbenv, DB_ENV_USER_ALLOC) && dbenv->lk_conflicts != NULL) { + __os_free(dbenv->lk_conflicts, + dbenv->lk_modes * dbenv->lk_modes); + dbenv->lk_conflicts = NULL; + } +} + +/* + * __lock_open -- + * Internal version of lock_open: only called from DB_ENV->open. + * + * PUBLIC: int __lock_open __P((DB_ENV *)); + */ +int +__lock_open(dbenv) + DB_ENV *dbenv; +{ + DB_LOCKREGION *region; + DB_LOCKTAB *lt; + size_t size; + int ret; + + /* Create the lock table structure. */ + if ((ret = __os_calloc(dbenv, 1, sizeof(DB_LOCKTAB), <)) != 0) + return (ret); + lt->dbenv = dbenv; + + /* Join/create the lock region. */ + lt->reginfo.type = REGION_TYPE_LOCK; + lt->reginfo.id = INVALID_REGION_ID; + lt->reginfo.mode = dbenv->db_mode; + lt->reginfo.flags = REGION_JOIN_OK; + if (F_ISSET(dbenv, DB_ENV_CREATE)) + F_SET(<->reginfo, REGION_CREATE_OK); + size = __lock_region_size(dbenv); + if ((ret = __db_r_attach(dbenv, <->reginfo, size)) != 0) + goto err; + + /* If we created the region, initialize it. */ + if (F_ISSET(<->reginfo, REGION_CREATE)) + if ((ret = __lock_init(dbenv, lt)) != 0) + goto err; + + /* Set the local addresses. */ + region = lt->reginfo.primary = + R_ADDR(<->reginfo, lt->reginfo.rp->primary); + + /* Check for incompatible automatic deadlock detection requests. */ + if (dbenv->lk_detect != DB_LOCK_NORUN) { + if (region->detect != DB_LOCK_NORUN && + dbenv->lk_detect != DB_LOCK_DEFAULT && + region->detect != dbenv->lk_detect) { + __db_err(dbenv, + "lock_open: incompatible deadlock detector mode"); + ret = EINVAL; + goto err; + } + + /* + * Upgrade if our caller wants automatic detection, and it + * was not currently being done, whether or not we created + * the region. + */ + if (region->detect == DB_LOCK_NORUN) + region->detect = dbenv->lk_detect; + } + + /* Set remaining pointers into region. */ + lt->conflicts = (u_int8_t *)R_ADDR(<->reginfo, region->conf_off); + lt->obj_tab = (DB_HASHTAB *)R_ADDR(<->reginfo, region->obj_off); + lt->locker_tab = (DB_HASHTAB *)R_ADDR(<->reginfo, region->locker_off); + + R_UNLOCK(dbenv, <->reginfo); + + dbenv->lk_handle = lt; + return (0); + +err: if (lt->reginfo.addr != NULL) { + if (F_ISSET(<->reginfo, REGION_CREATE)) + ret = __db_panic(dbenv, ret); + R_UNLOCK(dbenv, <->reginfo); + (void)__db_r_detach(dbenv, <->reginfo, 0); + } + __os_free(lt, sizeof(*lt)); + return (ret); +} + +/* + * __lock_init -- + * Initialize the lock region. + */ +static int +__lock_init(dbenv, lt) + DB_ENV *dbenv; + DB_LOCKTAB *lt; +{ + const u_int8_t *lk_conflicts; + struct __db_lock *lp; + DB_LOCKER *lidp; + DB_LOCKOBJ *op; + DB_LOCKREGION *region; +#ifdef MUTEX_SYSTEM_RESOURCES + size_t maint_size; +#endif + u_int32_t i, lk_modes; + u_int8_t *addr; + int ret; + + if ((ret = __db_shalloc(lt->reginfo.addr, + sizeof(DB_LOCKREGION), 0, <->reginfo.primary)) != 0) + goto mem_err; + lt->reginfo.rp->primary = R_OFFSET(<->reginfo, lt->reginfo.primary); + region = lt->reginfo.primary; + memset(region, 0, sizeof(*region)); + + /* Select a conflict matrix if none specified. */ + if (dbenv->lk_modes == 0) + if (CDB_LOCKING(dbenv)) { + lk_modes = DB_LOCK_CDB_N; + lk_conflicts = db_cdb_conflicts; + } else { + lk_modes = DB_LOCK_RIW_N; + lk_conflicts = db_riw_conflicts; + } + else { + lk_modes = dbenv->lk_modes; + lk_conflicts = dbenv->lk_conflicts; + } + + region->id = 0; + region->need_dd = 0; + region->detect = DB_LOCK_NORUN; + region->maxlocks = dbenv->lk_max; + region->maxlockers = dbenv->lk_max_lockers; + region->maxobjects = dbenv->lk_max_objects; + region->locker_t_size = __db_tablesize(dbenv->lk_max_lockers); + region->object_t_size = __db_tablesize(dbenv->lk_max_objects); + region->nmodes = lk_modes; + region->nlocks = 0; + region->maxnlocks = 0; + region->nlockers = 0; + region->maxnlockers = 0; + region->nobjects = 0; + region->maxnobjects = 0; + region->nconflicts = 0; + region->nrequests = 0; + region->nreleases = 0; + region->ndeadlocks = 0; + + /* Allocate room for the conflict matrix and initialize it. */ + if ((ret = + __db_shalloc(lt->reginfo.addr, lk_modes * lk_modes, 0, &addr)) != 0) + goto mem_err; + memcpy(addr, lk_conflicts, lk_modes * lk_modes); + region->conf_off = R_OFFSET(<->reginfo, addr); + + /* Allocate room for the object hash table and initialize it. */ + if ((ret = __db_shalloc(lt->reginfo.addr, + region->object_t_size * sizeof(DB_HASHTAB), 0, &addr)) != 0) + goto mem_err; + __db_hashinit(addr, region->object_t_size); + region->obj_off = R_OFFSET(<->reginfo, addr); + + /* Allocate room for the locker hash table and initialize it. */ + if ((ret = __db_shalloc(lt->reginfo.addr, + region->locker_t_size * sizeof(DB_HASHTAB), 0, &addr)) != 0) + goto mem_err; + __db_hashinit(addr, region->locker_t_size); + region->locker_off = R_OFFSET(<->reginfo, addr); + +#ifdef MUTEX_SYSTEM_RESOURCES + maint_size = __lock_region_maint(dbenv); + /* Allocate room for the locker maintenance info and initialize it. */ + if ((ret = __db_shalloc(lt->reginfo.addr, + sizeof(REGMAINT) + maint_size, 0, &addr)) != 0) + goto mem_err; + __db_maintinit(<->reginfo, addr, maint_size); + region->maint_off = R_OFFSET(<->reginfo, addr); +#endif + + /* + * Initialize locks onto a free list. Initialize and lock the mutex + * so that when we need to block, all we need do is try to acquire + * the mutex. + */ + SH_TAILQ_INIT(®ion->free_locks); + for (i = 0; i < region->maxlocks; ++i) { + if ((ret = __db_shalloc(lt->reginfo.addr, + sizeof(struct __db_lock), MUTEX_ALIGN, &lp)) != 0) + goto mem_err; + lp->status = DB_LSTAT_FREE; + if ((ret = __db_shmutex_init(dbenv, &lp->mutex, + R_OFFSET(<->reginfo, &lp->mutex) + DB_FCNTL_OFF_LOCK, + MUTEX_SELF_BLOCK, <->reginfo, + (REGMAINT *)R_ADDR(<->reginfo, region->maint_off))) != 0) + return (ret); + MUTEX_LOCK(dbenv, &lp->mutex, lt->dbenv->lockfhp); + SH_TAILQ_INSERT_HEAD(®ion->free_locks, lp, links, __db_lock); + } + + /* Initialize objects onto a free list. */ + SH_TAILQ_INIT(®ion->dd_objs); + SH_TAILQ_INIT(®ion->free_objs); + for (i = 0; i < region->maxobjects; ++i) { + if ((ret = __db_shalloc(lt->reginfo.addr, + sizeof(DB_LOCKOBJ), 0, &op)) != 0) + goto mem_err; + SH_TAILQ_INSERT_HEAD( + ®ion->free_objs, op, links, __db_lockobj); + } + + /* Initialize lockers onto a free list. */ + SH_TAILQ_INIT(®ion->free_lockers); + for (i = 0; i < region->maxlockers; ++i) { + if ((ret = __db_shalloc(lt->reginfo.addr, + sizeof(DB_LOCKER), 0, &lidp)) != 0) { +mem_err: __db_err(dbenv, "Unable to allocate memory for the lock table"); + return (ret); + } + SH_TAILQ_INSERT_HEAD( + ®ion->free_lockers, lidp, links, __db_locker); + } + + return (0); +} + +/* + * __lock_close -- + * Internal version of lock_close: only called from db_appinit. + * + * PUBLIC: int __lock_close __P((DB_ENV *)); + */ +int +__lock_close(dbenv) + DB_ENV *dbenv; +{ + DB_LOCKTAB *lt; + int ret; + + lt = dbenv->lk_handle; + + /* Detach from the region. */ + ret = __db_r_detach(dbenv, <->reginfo, 0); + + __os_free(lt, sizeof(*lt)); + + dbenv->lk_handle = NULL; + return (ret); +} + +/* + * __lock_region_size -- + * Return the region size. + */ +static size_t +__lock_region_size(dbenv) + DB_ENV *dbenv; +{ + size_t retval; + + /* + * Figure out how much space we're going to need. This list should + * map one-to-one with the __db_shalloc calls in __lock_init. + */ + retval = 0; + retval += __db_shalloc_size(sizeof(DB_LOCKREGION), 1); + retval += __db_shalloc_size(dbenv->lk_modes * dbenv->lk_modes, 1); + retval += __db_shalloc_size( + __db_tablesize(dbenv->lk_max_lockers) * (sizeof(DB_HASHTAB)), 1); + retval += __db_shalloc_size( + __db_tablesize(dbenv->lk_max_objects) * (sizeof(DB_HASHTAB)), 1); +#ifdef MUTEX_SYSTEM_RESOURCES + retval += + __db_shalloc_size(sizeof(REGMAINT) + __lock_region_maint(dbenv), 1); +#endif + retval += __db_shalloc_size( + sizeof(struct __db_lock), MUTEX_ALIGN) * dbenv->lk_max; + retval += __db_shalloc_size(sizeof(DB_LOCKOBJ), 1) * dbenv->lk_max_objects; + retval += __db_shalloc_size(sizeof(DB_LOCKER), 1) * dbenv->lk_max_lockers; + + /* + * Include 16 bytes of string space per lock. DB doesn't use it + * because we pre-allocate lock space for DBTs in the structure. + */ + retval += __db_shalloc_size(dbenv->lk_max * 16, sizeof(size_t)); + + /* And we keep getting this wrong, let's be generous. */ + retval += retval / 4; + + return (retval); +} + +#ifdef MUTEX_SYSTEM_RESOURCES +/* + * __lock_region_maint -- + * Return the amount of space needed for region maintenance info. + */ +static size_t +__lock_region_maint(dbenv) + DB_ENV *dbenv; +{ + size_t s; + + s = sizeof(MUTEX *) * dbenv->lk_max; + return (s); +} +#endif + +/* + * __lock_region_destroy + * Destroy any region maintenance info. + * + * PUBLIC: void __lock_region_destroy __P((DB_ENV *, REGINFO *)); + */ +void +__lock_region_destroy(dbenv, infop) + DB_ENV *dbenv; + REGINFO *infop; +{ + DB_LOCKREGION *region; + + COMPQUIET(dbenv, NULL); + region = R_ADDR(infop, infop->rp->primary); + + __db_shlocks_destroy(infop, + (REGMAINT *)R_ADDR(infop, region->maint_off)); + return; +} diff --git a/db/lock/lock_stat.c b/db/lock/lock_stat.c new file mode 100644 index 000000000..ed5b60d0d --- /dev/null +++ b/db/lock/lock_stat.c @@ -0,0 +1,308 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: lock_stat.c,v 11.4 2000/12/08 20:15:31 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#ifdef HAVE_RPC +#include "db_server.h" +#endif + +#include "db_int.h" +#include "db_shash.h" +#include "lock.h" + +#ifdef HAVE_RPC +#include "gen_client_ext.h" +#include "rpc_client_ext.h" +#endif + +static void __lock_dump_locker __P((DB_LOCKTAB *, DB_LOCKER *, FILE *)); +static void __lock_dump_object __P((DB_LOCKTAB *, DB_LOCKOBJ *, FILE *)); +static const char * + __lock_dump_status __P((db_status_t)); + +/* + * lock_stat -- + * Return LOCK statistics. + */ +int +lock_stat(dbenv, statp, db_malloc) + DB_ENV *dbenv; + DB_LOCK_STAT **statp; + void *(*db_malloc) __P((size_t)); +{ + DB_LOCKREGION *region; + DB_LOCKTAB *lt; + DB_LOCK_STAT *stats; + int ret; + +#ifdef HAVE_RPC + if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) + return (__dbcl_lock_stat(dbenv, statp, db_malloc)); +#endif + + PANIC_CHECK(dbenv); + ENV_REQUIRES_CONFIG(dbenv, dbenv->lk_handle, DB_INIT_LOCK); + + *statp = NULL; + + lt = dbenv->lk_handle; + + if ((ret = __os_malloc(dbenv, sizeof(*stats), db_malloc, &stats)) != 0) + return (ret); + + /* Copy out the global statistics. */ + R_LOCK(dbenv, <->reginfo); + + region = lt->reginfo.primary; + stats->st_lastid = region->id; + stats->st_maxlocks = region->maxlocks; + stats->st_maxlockers = region->maxlockers; + stats->st_maxobjects = region->maxobjects; + stats->st_nmodes = region->nmodes; + stats->st_nlockers = region->nlockers; + stats->st_maxnlockers = region->maxnlockers; + stats->st_nobjects = region->nobjects; + stats->st_maxnobjects = region->maxnobjects; + stats->st_nlocks = region->nlocks; + stats->st_maxnlocks = region->maxnlocks; + stats->st_nconflicts = region->nconflicts; + stats->st_nrequests = region->nrequests; + stats->st_nreleases = region->nreleases; + stats->st_nnowaits = region->nnowaits; + stats->st_ndeadlocks = region->ndeadlocks; + + stats->st_region_wait = lt->reginfo.rp->mutex.mutex_set_wait; + stats->st_region_nowait = lt->reginfo.rp->mutex.mutex_set_nowait; + stats->st_regsize = lt->reginfo.rp->size; + + R_UNLOCK(dbenv, <->reginfo); + + *statp = stats; + return (0); +} + +#define LOCK_DUMP_CONF 0x001 /* Conflict matrix. */ +#define LOCK_DUMP_FREE 0x002 /* Display lock free list. */ +#define LOCK_DUMP_LOCKERS 0x004 /* Display lockers. */ +#define LOCK_DUMP_MEM 0x008 /* Display region memory. */ +#define LOCK_DUMP_OBJECTS 0x010 /* Display objects. */ +#define LOCK_DUMP_ALL 0x01f /* Display all. */ + +/* + * __lock_dump_region -- + * + * PUBLIC: void __lock_dump_region __P((DB_ENV *, char *, FILE *)); + */ +void +__lock_dump_region(dbenv, area, fp) + DB_ENV *dbenv; + char *area; + FILE *fp; +{ + struct __db_lock *lp; + DB_LOCKER *lip; + DB_LOCKOBJ *op; + DB_LOCKREGION *lrp; + DB_LOCKTAB *lt; + u_int32_t flags, i, j; + int label; + + /* Make it easy to call from the debugger. */ + if (fp == NULL) + fp = stderr; + + for (flags = 0; *area != '\0'; ++area) + switch (*area) { + case 'A': + LF_SET(LOCK_DUMP_ALL); + break; + case 'c': + LF_SET(LOCK_DUMP_CONF); + break; + case 'f': + LF_SET(LOCK_DUMP_FREE); + break; + case 'l': + LF_SET(LOCK_DUMP_LOCKERS); + break; + case 'm': + LF_SET(LOCK_DUMP_MEM); + break; + case 'o': + LF_SET(LOCK_DUMP_OBJECTS); + break; + } + + lt = dbenv->lk_handle; + lrp = lt->reginfo.primary; + LOCKREGION(dbenv, lt); + + fprintf(fp, "%s\nLock region parameters\n", DB_LINE); + fprintf(fp, "%s: %lu, %s: %lu, %s: %lu, %s: %lu, %s: %lu, %s: %lu, %s: %lu\n", + "locker table size", (u_long)lrp->locker_t_size, + "object table size", (u_long)lrp->object_t_size, + "obj_off", (u_long)lrp->obj_off, + "osynch_off", (u_long)lrp->osynch_off, + "locker_off", (u_long)lrp->locker_off, + "lsynch_off", (u_long)lrp->lsynch_off, + "need_dd", (u_long)lrp->need_dd); + + if (LF_ISSET(LOCK_DUMP_CONF)) { + fprintf(fp, "\n%s\nConflict matrix\n", DB_LINE); + for (i = 0; i < lrp->nmodes; i++) { + for (j = 0; j < lrp->nmodes; j++) + fprintf(fp, "%lu\t", + (u_long)lt->conflicts[i * lrp->nmodes + j]); + fprintf(fp, "\n"); + } + } + + if (LF_ISSET(LOCK_DUMP_LOCKERS)) { + fprintf(fp, "%s\nLocker hash buckets\n", DB_LINE); + for (i = 0; i < lrp->locker_t_size; i++) { + label = 1; + for (lip = + SH_TAILQ_FIRST(<->locker_tab[i], __db_locker); + lip != NULL; + lip = SH_TAILQ_NEXT(lip, links, __db_locker)) { + if (label) { + fprintf(fp, "Bucket %lu:\n", (u_long)i); + label = 0; + } + __lock_dump_locker(lt, lip, fp); + } + } + } + + if (LF_ISSET(LOCK_DUMP_OBJECTS)) { + fprintf(fp, "%s\nObject hash buckets\n", DB_LINE); + for (i = 0; i < lrp->object_t_size; i++) { + label = 1; + for (op = SH_TAILQ_FIRST(<->obj_tab[i], __db_lockobj); + op != NULL; + op = SH_TAILQ_NEXT(op, links, __db_lockobj)) { + if (label) { + fprintf(fp, "Bucket %lu:\n", (u_long)i); + label = 0; + } + __lock_dump_object(lt, op, fp); + } + } + } + + if (LF_ISSET(LOCK_DUMP_FREE)) { + fprintf(fp, "%s\nLock free list\n", DB_LINE); + for (lp = SH_TAILQ_FIRST(&lrp->free_locks, __db_lock); + lp != NULL; + lp = SH_TAILQ_NEXT(lp, links, __db_lock)) + fprintf(fp, "0x%lx: %lu\t%lu\t%s\t0x%lx\n", (u_long)lp, + (u_long)lp->holder, (u_long)lp->mode, + __lock_dump_status(lp->status), (u_long)lp->obj); + + fprintf(fp, "%s\nObject free list\n", DB_LINE); + for (op = SH_TAILQ_FIRST(&lrp->free_objs, __db_lockobj); + op != NULL; + op = SH_TAILQ_NEXT(op, links, __db_lockobj)) + fprintf(fp, "0x%lx\n", (u_long)op); + + fprintf(fp, "%s\nLocker free list\n", DB_LINE); + for (lip = SH_TAILQ_FIRST(&lrp->free_lockers, __db_locker); + lip != NULL; + lip = SH_TAILQ_NEXT(lip, links, __db_locker)) + fprintf(fp, "0x%lx\n", (u_long)lip); + } + + if (LF_ISSET(LOCK_DUMP_MEM)) + __db_shalloc_dump(lt->reginfo.addr, fp); + + UNLOCKREGION(dbenv, lt); +} + +static void +__lock_dump_locker(lt, lip, fp) + DB_LOCKTAB *lt; + DB_LOCKER *lip; + FILE *fp; +{ + struct __db_lock *lp; + + fprintf(fp, "L %lx [%ld]", (u_long)lip->id, (long)lip->dd_id); + fprintf(fp, " %s ", F_ISSET(lip, DB_LOCKER_DELETED) ? "(D)" : " "); + + if ((lp = SH_LIST_FIRST(&lip->heldby, __db_lock)) == NULL) + fprintf(fp, "\n"); + else + for (; lp != NULL; + lp = SH_LIST_NEXT(lp, locker_links, __db_lock)) + __lock_printlock(lt, lp, 1); +} + +static void +__lock_dump_object(lt, op, fp) + DB_LOCKTAB *lt; + DB_LOCKOBJ *op; + FILE *fp; +{ + struct __db_lock *lp; + u_int32_t j; + u_int8_t *ptr; + u_int ch; + + ptr = SH_DBT_PTR(&op->lockobj); + for (j = 0; j < op->lockobj.size; ptr++, j++) { + ch = *ptr; + fprintf(fp, isprint(ch) ? "%c" : "\\%o", ch); + } + fprintf(fp, "\n"); + + fprintf(fp, "H:"); + for (lp = + SH_TAILQ_FIRST(&op->holders, __db_lock); + lp != NULL; + lp = SH_TAILQ_NEXT(lp, links, __db_lock)) + __lock_printlock(lt, lp, 1); + lp = SH_TAILQ_FIRST(&op->waiters, __db_lock); + if (lp != NULL) { + fprintf(fp, "\nW:"); + for (; lp != NULL; lp = SH_TAILQ_NEXT(lp, links, __db_lock)) + __lock_printlock(lt, lp, 1); + } +} + +static const char * +__lock_dump_status(status) + db_status_t status; +{ + switch (status) { + case DB_LSTAT_ABORTED: + return ("aborted"); + case DB_LSTAT_ERR: + return ("err"); + case DB_LSTAT_FREE: + return ("free"); + case DB_LSTAT_HELD: + return ("held"); + case DB_LSTAT_NOGRANT: + return ("nogrant"); + case DB_LSTAT_PENDING: + return ("pending"); + case DB_LSTAT_WAITING: + return ("waiting"); + } + return ("unknown status"); +} diff --git a/db/lock/lock_util.c b/db/lock/lock_util.c new file mode 100644 index 000000000..fd5c6ad90 --- /dev/null +++ b/db/lock/lock_util.c @@ -0,0 +1,138 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: lock_util.c,v 11.5 2000/07/04 18:28:24 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_shash.h" +#include "hash.h" +#include "lock.h" + +/* + * __lock_cmp -- + * This function is used to compare a DBT that is about to be entered + * into a hash table with an object already in the hash table. Note + * that it just returns true on equal and 0 on not-equal. Therefore + * this function cannot be used as a sort function; its purpose is to + * be used as a hash comparison function. + * + * PUBLIC: int __lock_cmp __P((const DBT *, DB_LOCKOBJ *)); + */ +int +__lock_cmp(dbt, lock_obj) + const DBT *dbt; + DB_LOCKOBJ *lock_obj; +{ + void *obj_data; + + obj_data = SH_DBT_PTR(&lock_obj->lockobj); + return (dbt->size == lock_obj->lockobj.size && + memcmp(dbt->data, obj_data, dbt->size) == 0); +} + +/* + * PUBLIC: int __lock_locker_cmp __P((u_int32_t, DB_LOCKER *)); + */ +int +__lock_locker_cmp(locker, sh_locker) + u_int32_t locker; + DB_LOCKER *sh_locker; +{ + return (locker == sh_locker->id); +} + +/* + * The next two functions are the hash functions used to store objects in the + * lock hash tables. They are hashing the same items, but one (__lock_ohash) + * takes a DBT (used for hashing a parameter passed from the user) and the + * other (__lock_lhash) takes a DB_LOCKOBJ (used for hashing something that is + * already in the lock manager). In both cases, we have a special check to + * fast path the case where we think we are doing a hash on a DB page/fileid + * pair. If the size is right, then we do the fast hash. + * + * We know that DB uses DB_LOCK_ILOCK types for its lock objects. The first + * four bytes are the 4-byte page number and the next DB_FILE_ID_LEN bytes + * are a unique file id, where the first 4 bytes on UNIX systems are the file + * inode number, and the first 4 bytes on Windows systems are the FileIndexLow + * bytes. So, we use the XOR of the page number and the first four bytes of + * the file id to produce a 32-bit hash value. + * + * We have no particular reason to believe that this algorithm will produce + * a good hash, but we want a fast hash more than we want a good one, when + * we're coming through this code path. + */ +#define FAST_HASH(P) { \ + u_int32_t __h; \ + u_int8_t *__cp, *__hp; \ + __hp = (u_int8_t *)&__h; \ + __cp = (u_int8_t *)(P); \ + __hp[0] = __cp[0] ^ __cp[4]; \ + __hp[1] = __cp[1] ^ __cp[5]; \ + __hp[2] = __cp[2] ^ __cp[6]; \ + __hp[3] = __cp[3] ^ __cp[7]; \ + return (__h); \ +} + +/* + * __lock_ohash -- + * + * PUBLIC: u_int32_t __lock_ohash __P((const DBT *)); + */ +u_int32_t +__lock_ohash(dbt) + const DBT *dbt; +{ + if (dbt->size == sizeof(DB_LOCK_ILOCK)) + FAST_HASH(dbt->data); + + return (__ham_func5(NULL, dbt->data, dbt->size)); +} + +/* + * __lock_lhash -- + * + * PUBLIC: u_int32_t __lock_lhash __P((DB_LOCKOBJ *)); + */ +u_int32_t +__lock_lhash(lock_obj) + DB_LOCKOBJ *lock_obj; +{ + void *obj_data; + + obj_data = SH_DBT_PTR(&lock_obj->lockobj); + + if (lock_obj->lockobj.size == sizeof(DB_LOCK_ILOCK)) + FAST_HASH(obj_data); + + return (__ham_func5(NULL, obj_data, lock_obj->lockobj.size)); +} + +/* + * __lock_locker_hash -- + * Hash function for entering lockers into the locker hash table. + * Since these are simply 32-bit unsigned integers, just return + * the locker value. + * + * PUBLIC: u_int32_t __lock_locker_hash __P((u_int32_t)); + */ +u_int32_t +__lock_locker_hash(locker) + u_int32_t locker; +{ + return (locker); +} diff --git a/db/log/log.c b/db/log/log.c new file mode 100644 index 000000000..69af16248 --- /dev/null +++ b/db/log/log.c @@ -0,0 +1,653 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: log.c,v 11.42 2001/01/15 16:42:37 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#endif + +#ifdef HAVE_RPC +#include "db_server.h" +#endif + +#include "db_int.h" +#include "log.h" +#include "db_dispatch.h" +#include "txn.h" +#include "txn_auto.h" + +#ifdef HAVE_RPC +#include "gen_client_ext.h" +#include "rpc_client_ext.h" +#endif + +static int __log_init __P((DB_ENV *, DB_LOG *)); +static int __log_recover __P((DB_LOG *)); + +/* + * __log_open -- + * Internal version of log_open: only called from DB_ENV->open. + * + * PUBLIC: int __log_open __P((DB_ENV *)); + */ +int +__log_open(dbenv) + DB_ENV *dbenv; +{ + DB_LOG *dblp; + LOG *lp; + int ret; + u_int8_t *readbufp; + + readbufp = NULL; + + /* Create/initialize the DB_LOG structure. */ + if ((ret = __os_calloc(dbenv, 1, sizeof(DB_LOG), &dblp)) != 0) + return (ret); + if ((ret = __os_calloc(dbenv, 1, dbenv->lg_bsize, &readbufp)) != 0) + goto err; + ZERO_LSN(dblp->c_lsn); + dblp->dbenv = dbenv; + + /* Join/create the log region. */ + dblp->reginfo.type = REGION_TYPE_LOG; + dblp->reginfo.id = INVALID_REGION_ID; + dblp->reginfo.mode = dbenv->db_mode; + dblp->reginfo.flags = REGION_JOIN_OK; + if (F_ISSET(dbenv, DB_ENV_CREATE)) + F_SET(&dblp->reginfo, REGION_CREATE_OK); + if ((ret = __db_r_attach( + dbenv, &dblp->reginfo, LG_BASE_REGION_SIZE + dbenv->lg_bsize)) != 0) + goto err; + + dblp->readbufp = readbufp; + + /* If we created the region, initialize it. */ + if (F_ISSET(&dblp->reginfo, REGION_CREATE) && + (ret = __log_init(dbenv, dblp)) != 0) + goto err; + + /* Set the local addresses. */ + lp = dblp->reginfo.primary = + R_ADDR(&dblp->reginfo, dblp->reginfo.rp->primary); + dblp->bufp = R_ADDR(&dblp->reginfo, lp->buffer_off); + + /* + * If the region is threaded, then we have to lock both the handles + * and the region, and we need to allocate a mutex for that purpose. + */ + if (F_ISSET(dbenv, DB_ENV_THREAD)) { + if ((ret = __db_mutex_alloc( + dbenv, &dblp->reginfo, &dblp->mutexp)) != 0) + goto err; + if ((ret = __db_mutex_init( + dbenv, dblp->mutexp, 0, MUTEX_THREAD)) != 0) + goto err; + } + + R_UNLOCK(dbenv, &dblp->reginfo); + + dblp->r_file = 0; + dblp->r_off = 0; + dblp->r_size = 0; + dbenv->lg_handle = dblp; + return (0); + +err: if (dblp->reginfo.addr != NULL) { + if (F_ISSET(&dblp->reginfo, REGION_CREATE)) + ret = __db_panic(dbenv, ret); + R_UNLOCK(dbenv, &dblp->reginfo); + (void)__db_r_detach(dbenv, &dblp->reginfo, 0); + } + + if (readbufp != NULL) + __os_free(readbufp, dbenv->lg_bsize); + if (dblp->mutexp != NULL) + __db_mutex_free(dbenv, &dblp->reginfo, dblp->mutexp); + __os_free(dblp, sizeof(*dblp)); + return (ret); +} + +/* + * __log_init -- + * Initialize a log region in shared memory. + */ +static int +__log_init(dbenv, dblp) + DB_ENV *dbenv; + DB_LOG *dblp; +{ + LOG *region; + int ret; + void *p; + + if ((ret = __db_shalloc(dblp->reginfo.addr, + sizeof(*region), 0, &dblp->reginfo.primary)) != 0) + goto mem_err; + dblp->reginfo.rp->primary = + R_OFFSET(&dblp->reginfo, dblp->reginfo.primary); + region = dblp->reginfo.primary; + memset(region, 0, sizeof(*region)); + + region->persist.lg_max = dbenv->lg_max; + region->persist.magic = DB_LOGMAGIC; + region->persist.version = DB_LOGVERSION; + region->persist.mode = dbenv->db_mode; + SH_TAILQ_INIT(®ion->fq); + + /* Initialize LOG LSNs. */ + region->lsn.file = 1; + region->lsn.offset = 0; + + /* Initialize the buffer. */ + if ((ret = + __db_shalloc(dblp->reginfo.addr, dbenv->lg_bsize, 0, &p)) != 0) { +mem_err: __db_err(dbenv, "Unable to allocate memory for the log buffer"); + return (ret); + } + region->buffer_size = dbenv->lg_bsize; + region->buffer_off = R_OFFSET(&dblp->reginfo, p); + + /* Try and recover any previous log files before releasing the lock. */ + return (__log_recover(dblp)); +} + +/* + * __log_recover -- + * Recover a log. + */ +static int +__log_recover(dblp) + DB_LOG *dblp; +{ + DBT dbt; + DB_LSN lsn; + LOG *lp; + int cnt, found_checkpoint, ret; + u_int32_t chk; + logfile_validity status; + + lp = dblp->reginfo.primary; + + /* + * Find a log file. If none exist, we simply return, leaving + * everything initialized to a new log. + */ + if ((ret = __log_find(dblp, 0, &cnt, &status)) != 0) + return (ret); + if (cnt == 0) + return (0); + + /* + * If the last file is an old version, readable or no, start a new + * file. Don't bother finding checkpoints; if we didn't take a + * checkpoint right before upgrading, the user screwed up anyway. + */ + if (status == DB_LV_OLD_READABLE || status == DB_LV_OLD_UNREADABLE) { + lp->lsn.file = lp->s_lsn.file = cnt + 1; + lp->lsn.offset = lp->s_lsn.offset = 0; + goto skipsearch; + } + DB_ASSERT(status == DB_LV_NORMAL); + + /* + * We have the last useful log file and we've loaded any persistent + * information. Set the end point of the log past the end of the last + * file. Read the last file, looking for the last checkpoint and + * the log's end. + */ + lp->lsn.file = cnt + 1; + lp->lsn.offset = 0; + lsn.file = cnt; + lsn.offset = 0; + + /* Set the cursor. Shouldn't fail; leave error messages on. */ + memset(&dbt, 0, sizeof(dbt)); + if ((ret = __log_get(dblp, &lsn, &dbt, DB_SET, 0)) != 0) + return (ret); + + /* + * Read to the end of the file, saving checkpoints. This will fail + * at some point, so turn off error messages. + */ + found_checkpoint = 0; + while (__log_get(dblp, &lsn, &dbt, DB_NEXT, 1) == 0) { + if (dbt.size < sizeof(u_int32_t)) + continue; + memcpy(&chk, dbt.data, sizeof(u_int32_t)); + if (chk == DB_txn_ckp) { + lp->chkpt_lsn = lsn; + found_checkpoint = 1; + } + } + + /* + * We now know where the end of the log is. Set the first LSN that + * we want to return to an application and the LSN of the last known + * record on disk. + */ + lp->lsn = lsn; + lp->s_lsn = lsn; + lp->lsn.offset += dblp->c_len; + lp->s_lsn.offset += dblp->c_len; + + /* Set up the current buffer information, too. */ + lp->len = dblp->c_len; + lp->b_off = 0; + lp->w_off = lp->lsn.offset; + + /* + * It's possible that we didn't find a checkpoint because there wasn't + * one in the last log file. Start searching. + */ + if (!found_checkpoint && cnt > 1) { + lsn.file = cnt; + lsn.offset = 0; + + /* Set the cursor. Shouldn't fail, leave error messages on. */ + if ((ret = __log_get(dblp, &lsn, &dbt, DB_SET, 0)) != 0) + return (ret); + + /* + * Read to the end of the file, saving checkpoints. Again, + * this can fail if there are no checkpoints in any log file, + * so turn error messages off. + */ + while (__log_get(dblp, &lsn, &dbt, DB_PREV, 1) == 0) { + if (dbt.size < sizeof(u_int32_t)) + continue; + memcpy(&chk, dbt.data, sizeof(u_int32_t)); + if (chk == DB_txn_ckp) { + lp->chkpt_lsn = lsn; + found_checkpoint = 1; + break; + } + } + } + + /* If we never find a checkpoint, that's okay, just 0 it out. */ + if (!found_checkpoint) +skipsearch: ZERO_LSN(lp->chkpt_lsn); + + /* + * Reset the cursor lsn to the beginning of the log, so that an + * initial call to DB_NEXT does the right thing. + */ + ZERO_LSN(dblp->c_lsn); + + if (FLD_ISSET(dblp->dbenv->verbose, DB_VERB_RECOVERY)) + __db_err(dblp->dbenv, + "Finding last valid log LSN: file: %lu offset %lu", + (u_long)lp->lsn.file, (u_long)lp->lsn.offset); + + return (0); +} + +/* + * __log_find -- + * Try to find a log file. If find_first is set, valp will contain + * the number of the first readable log file, else it will contain the number + * of the last log file (which may be too old to read). + * + * PUBLIC: int __log_find __P((DB_LOG *, int, int *, logfile_validity *)); + */ +int +__log_find(dblp, find_first, valp, statusp) + DB_LOG *dblp; + int find_first, *valp; + logfile_validity *statusp; +{ + logfile_validity clv_status, status; + u_int32_t clv, logval; + int cnt, fcnt, ret; + const char *dir; + char **names, *p, *q, savech; + + clv_status = status = DB_LV_NORMAL; + + /* Return a value of 0 as the log file number on failure. */ + *valp = 0; + + /* Find the directory name. */ + if ((ret = __log_name(dblp, 1, &p, NULL, 0)) != 0) + return (ret); + if ((q = __db_rpath(p)) == NULL) { + COMPQUIET(savech, 0); + dir = PATH_DOT; + } else { + savech = *q; + *q = '\0'; + dir = p; + } + + /* Get the list of file names. */ + ret = __os_dirlist(dblp->dbenv, dir, &names, &fcnt); + + /* + * !!! + * We overwrote a byte in the string with a nul. Restore the string + * so that the diagnostic checks in the memory allocation code work + * and any error messages display the right file name. + */ + if (q != NULL) + *q = savech; + + if (ret != 0) { + __db_err(dblp->dbenv, "%s: %s", dir, db_strerror(ret)); + __os_freestr(p); + return (ret); + } + + /* Search for a valid log file name. */ + for (cnt = fcnt, clv = logval = 0; --cnt >= 0;) { + if (strncmp(names[cnt], LFPREFIX, sizeof(LFPREFIX) - 1) != 0) + continue; + + /* + * Use atol, not atoi; if an "int" is 16-bits, the largest + * log file name won't fit. + */ + clv = atol(names[cnt] + (sizeof(LFPREFIX) - 1)); + if (find_first) { + if (logval != 0 && clv > logval) + continue; + } else + if (logval != 0 && clv < logval) + continue; + + /* + * Take note of whether the log file logval is + * an old version or incompletely initialized. + */ + if ((ret = __log_valid(dblp, clv, 1, &status)) != 0) + goto err; + switch (status) { + case DB_LV_INCOMPLETE: + /* + * It's acceptable for the last log file to + * have been incompletely initialized--it's possible + * to create a log file but not write anything to it, + * and recovery needs to gracefully handle this. + * + * Just ignore it; we don't want to return this + * as a valid log file. + */ + break; + case DB_LV_NORMAL: + case DB_LV_OLD_READABLE: + logval = clv; + clv_status = status; + break; + case DB_LV_OLD_UNREADABLE: + /* + * Continue; we want the oldest valid log, + * and clv is too old to be useful. We don't + * want it to supplant logval if we're looking for + * the oldest valid log, but we do want to return + * it if it's the last log file--we want the very + * last file number, so that our caller can + * start a new file after it. + * + * The code here assumes that there will never + * be a too-old log that's preceded by a log + * of the current version, but in order to + * attain that state of affairs the user + * would have had to really seriously screw + * up; I think we can safely assume this won't + * happen. + */ + if (!find_first) { + logval = clv; + clv_status = status; + } + break; + } + } + + *valp = logval; + +err: __os_dirfree(names, fcnt); + __os_freestr(p); + *statusp = clv_status; + + return (ret); +} + +/* + * log_valid -- + * Validate a log file. Returns an error code in the event of + * a fatal flaw in a the specified log file; returns success with + * a code indicating the currentness and completeness of the specified + * log file if it is not unexpectedly flawed (that is, if it's perfectly + * normal, if it's zero-length, or if it's an old version). + * + * PUBLIC: int __log_valid __P((DB_LOG *, u_int32_t, int, logfile_validity *)); + */ +int +__log_valid(dblp, number, set_persist, statusp) + DB_LOG *dblp; + u_int32_t number; + int set_persist; + logfile_validity *statusp; +{ + DB_FH fh; + LOG *region; + LOGP persist; + char *fname; + int ret; + logfile_validity status; + size_t nw; + + status = DB_LV_NORMAL; + + /* Try to open the log file. */ + if ((ret = __log_name(dblp, + number, &fname, &fh, DB_OSO_RDONLY | DB_OSO_SEQ)) != 0) { + __os_freestr(fname); + return (ret); + } + + /* Try to read the header. */ + if ((ret = + __os_seek(dblp->dbenv, + &fh, 0, 0, sizeof(HDR), 0, DB_OS_SEEK_SET)) != 0 || + (ret = + __os_read(dblp->dbenv, &fh, &persist, sizeof(LOGP), &nw)) != 0 || + nw != sizeof(LOGP)) { + if (ret == 0) + status = DB_LV_INCOMPLETE; + else + /* + * The error was a fatal read error, not just an + * incompletely initialized log file. + */ + __db_err(dblp->dbenv, "Ignoring log file: %s: %s", + fname, db_strerror(ret)); + + (void)__os_closehandle(&fh); + goto err; + } + (void)__os_closehandle(&fh); + + /* Validate the header. */ + if (persist.magic != DB_LOGMAGIC) { + __db_err(dblp->dbenv, + "Ignoring log file: %s: magic number %lx, not %lx", + fname, (u_long)persist.magic, (u_long)DB_LOGMAGIC); + ret = EINVAL; + goto err; + } + + /* + * Set our status code to indicate whether the log file + * belongs to an unreadable or readable old version; leave it + * alone if and only if the log file version is the current one. + */ + if (persist.version > DB_LOGVERSION) { + /* This is a fatal error--the log file is newer than DB. */ + __db_err(dblp->dbenv, + "Ignoring log file: %s: unsupported log version %lu", + fname, (u_long)persist.version); + ret = EINVAL; + goto err; + } else if (persist.version < DB_LOGOLDVER) { + status = DB_LV_OLD_UNREADABLE; + /* + * We don't want to set persistent info based on an + * unreadable region, so jump to "err". + */ + goto err; + } else if (persist.version < DB_LOGVERSION) + status = DB_LV_OLD_READABLE; + + /* + * If the log is thus far readable and we're doing system + * initialization, set the region's persistent information + * based on the headers. + */ + if (set_persist) { + region = dblp->reginfo.primary; + region->persist.lg_max = persist.lg_max; + region->persist.mode = persist.mode; + } + +err: __os_freestr(fname); + *statusp = status; + return (ret); +} + +/* + * __log_close -- + * Internal version of log_close: only called from dbenv_refresh. + * + * PUBLIC: int __log_close __P((DB_ENV *)); + */ +int +__log_close(dbenv) + DB_ENV *dbenv; +{ + DB_LOG *dblp; + int ret, t_ret; + + ret = 0; + dblp = dbenv->lg_handle; + + /* We may have opened files as part of XA; if so, close them. */ + F_SET(dblp, DBLOG_RECOVER); + __log_close_files(dbenv); + + /* Discard the per-thread lock. */ + if (dblp->mutexp != NULL) + __db_mutex_free(dbenv, &dblp->reginfo, dblp->mutexp); + + /* Detach from the region. */ + ret = __db_r_detach(dbenv, &dblp->reginfo, 0); + + /* Close open files, release allocated memory. */ + if (F_ISSET(&dblp->lfh, DB_FH_VALID) && + (t_ret = __os_closehandle(&dblp->lfh)) != 0 && ret == 0) + ret = t_ret; + if (dblp->c_dbt.data != NULL) + __os_free(dblp->c_dbt.data, dblp->c_dbt.ulen); + if (F_ISSET(&dblp->c_fh, DB_FH_VALID) && + (t_ret = __os_closehandle(&dblp->c_fh)) != 0 && ret == 0) + ret = t_ret; + if (dblp->dbentry != NULL) + __os_free(dblp->dbentry, + (dblp->dbentry_cnt * sizeof(DB_ENTRY))); + if (dblp->readbufp != NULL) + __os_free(dblp->readbufp, dbenv->lg_bsize); + + __os_free(dblp, sizeof(*dblp)); + + dbenv->lg_handle = NULL; + return (ret); +} + +/* + * log_stat -- + * Return LOG statistics. + */ +int +log_stat(dbenv, statp, db_malloc) + DB_ENV *dbenv; + DB_LOG_STAT **statp; + void *(*db_malloc) __P((size_t)); +{ + DB_LOG *dblp; + DB_LOG_STAT *stats; + LOG *region; + int ret; + +#ifdef HAVE_RPC + if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) + return (__dbcl_log_stat(dbenv, statp, db_malloc)); +#endif + + PANIC_CHECK(dbenv); + ENV_REQUIRES_CONFIG(dbenv, dbenv->lg_handle, DB_INIT_LOG); + + *statp = NULL; + + dblp = dbenv->lg_handle; + region = dblp->reginfo.primary; + + if ((ret = __os_malloc(dbenv, + sizeof(DB_LOG_STAT), db_malloc, &stats)) != 0) + return (ret); + + /* Copy out the global statistics. */ + R_LOCK(dbenv, &dblp->reginfo); + *stats = region->stat; + + stats->st_magic = region->persist.magic; + stats->st_version = region->persist.version; + stats->st_mode = region->persist.mode; + stats->st_lg_bsize = region->buffer_size; + stats->st_lg_max = region->persist.lg_max; + + stats->st_region_wait = dblp->reginfo.rp->mutex.mutex_set_wait; + stats->st_region_nowait = dblp->reginfo.rp->mutex.mutex_set_nowait; + stats->st_regsize = dblp->reginfo.rp->size; + + stats->st_cur_file = region->lsn.file; + stats->st_cur_offset = region->lsn.offset; + + R_UNLOCK(dbenv, &dblp->reginfo); + + *statp = stats; + return (0); +} + +/* + * __log_lastckp -- + * Return the current chkpt_lsn, so that we can store it in + * the transaction region and keep the chain of checkpoints + * unbroken across environment recreates. + * + * PUBLIC: int __log_lastckp __P((DB_ENV *, DB_LSN *)); + */ +int +__log_lastckp(dbenv, lsnp) + DB_ENV *dbenv; + DB_LSN *lsnp; +{ + LOG *lp; + + lp = (LOG *)(((DB_LOG *)dbenv->lg_handle)->reginfo.primary); + + *lsnp = lp->chkpt_lsn; + return (0); +} diff --git a/db/log/log.src b/db/log/log.src new file mode 100644 index 000000000..a92fae8de --- /dev/null +++ b/db/log/log.src @@ -0,0 +1,46 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: log.src,v 10.12 2000/02/17 20:24:10 bostic Exp $ + */ + +PREFIX log + +INCLUDE #include "db_config.h" +INCLUDE +INCLUDE #ifndef NO_SYSTEM_INCLUDES +INCLUDE #include +INCLUDE +INCLUDE #include +INCLUDE #include +INCLUDE #include +INCLUDE #endif +INCLUDE +INCLUDE #include "db_int.h" +INCLUDE #include "db_page.h" +INCLUDE #include "db_dispatch.h" +INCLUDE #include "db_am.h" +INCLUDE #include "log.h" +INCLUDE #include "txn.h" +INCLUDE + +/* Used for registering name/id translations at open or close. */ +DEPRECATED register1 1 +ARG opcode u_int32_t lu +DBT name DBT s +DBT uid DBT s +ARG fileid int32_t ld +ARG ftype DBTYPE lx +END + +BEGIN register 2 +ARG opcode u_int32_t lu +DBT name DBT s +DBT uid DBT s +ARG fileid int32_t ld +ARG ftype DBTYPE lx +ARG meta_pgno db_pgno_t lu +END diff --git a/db/log/log_archive.c b/db/log/log_archive.c new file mode 100644 index 000000000..83728c79e --- /dev/null +++ b/db/log/log_archive.c @@ -0,0 +1,447 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: log_archive.c,v 11.13 2000/11/30 00:58:40 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#endif + +#ifdef HAVE_RPC +#include "db_server.h" +#endif + +#include "db_int.h" +#include "db_dispatch.h" +#include "log.h" +#include "clib_ext.h" /* XXX: needed for getcwd. */ + +#ifdef HAVE_RPC +#include "gen_client_ext.h" +#include "rpc_client_ext.h" +#endif + +static int __absname __P((DB_ENV *, char *, char *, char **)); +static int __build_data __P((DB_ENV *, char *, char ***, void *(*)(size_t))); +static int __cmpfunc __P((const void *, const void *)); +static int __usermem __P((DB_ENV *, char ***, void *(*)(size_t))); + +/* + * log_archive -- + * Supporting function for db_archive(1). + */ +int +log_archive(dbenv, listp, flags, db_malloc) + DB_ENV *dbenv; + char ***listp; + u_int32_t flags; + void *(*db_malloc) __P((size_t)); +{ + DBT rec; + DB_LOG *dblp; + DB_LSN stable_lsn; + u_int32_t fnum; + int array_size, n, ret; + char **array, **arrayp, *name, *p, *pref, buf[MAXPATHLEN]; + +#ifdef HAVE_RPC + if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) + return (__dbcl_log_archive(dbenv, listp, flags, db_malloc)); +#endif + + PANIC_CHECK(dbenv); + ENV_REQUIRES_CONFIG(dbenv, dbenv->lg_handle, DB_INIT_LOG); + + name = NULL; + dblp = dbenv->lg_handle; + COMPQUIET(fnum, 0); + +#define OKFLAGS (DB_ARCH_ABS | DB_ARCH_DATA | DB_ARCH_LOG) + if (flags != 0) { + if ((ret = + __db_fchk(dbenv, "log_archive", flags, OKFLAGS)) != 0) + return (ret); + if ((ret = + __db_fcchk(dbenv, + "log_archive", flags, DB_ARCH_DATA, DB_ARCH_LOG)) != 0) + return (ret); + } + + /* + * Get the absolute pathname of the current directory. It would + * be nice to get the shortest pathname of the database directory, + * but that's just not possible. + * + * XXX + * Can't trust getcwd(3) to set a valid errno. If it doesn't, just + * guess that we ran out of memory. + */ + if (LF_ISSET(DB_ARCH_ABS)) { + __os_set_errno(0); + if ((pref = getcwd(buf, sizeof(buf))) == NULL) { + if (__os_get_errno() == 0) + __os_set_errno(ENOMEM); + return (__os_get_errno()); + } + } else + pref = NULL; + + switch (LF_ISSET(~DB_ARCH_ABS)) { + case DB_ARCH_DATA: + return (__build_data(dbenv, pref, listp, db_malloc)); + case DB_ARCH_LOG: + memset(&rec, 0, sizeof(rec)); + if (F_ISSET(dbenv, DB_ENV_THREAD)) + F_SET(&rec, DB_DBT_MALLOC); + if ((ret = log_get(dbenv, &stable_lsn, &rec, DB_LAST)) != 0) + return (ret); + if (F_ISSET(dbenv, DB_ENV_THREAD)) + __os_free(rec.data, rec.size); + fnum = stable_lsn.file; + break; + case 0: + if ((ret = __log_findckp(dbenv, &stable_lsn)) != 0) { + /* + * A return of DB_NOTFOUND means that we didn't find + * any records in the log (so we are not going to be + * deleting any log files). + */ + if (ret != DB_NOTFOUND) + return (ret); + *listp = NULL; + return (0); + } + /* Remove any log files before the last stable LSN. */ + fnum = stable_lsn.file - 1; + break; + } + +#define LIST_INCREMENT 64 + /* Get some initial space. */ + array_size = 10; + if ((ret = __os_malloc(dbenv, + sizeof(char *) * array_size, NULL, &array)) != 0) + return (ret); + array[0] = NULL; + + /* Build an array of the file names. */ + for (n = 0; fnum > 0; --fnum) { + if ((ret = __log_name(dblp, fnum, &name, NULL, 0)) != 0) + goto err; + if (__os_exists(name, NULL) != 0) { + if (LF_ISSET(DB_ARCH_LOG) && fnum == stable_lsn.file) + continue; + __os_freestr(name); + name = NULL; + break; + } + + if (n >= array_size - 1) { + array_size += LIST_INCREMENT; + if ((ret = __os_realloc(dbenv, + sizeof(char *) * array_size, NULL, &array)) != 0) + goto err; + } + + if (LF_ISSET(DB_ARCH_ABS)) { + if ((ret = __absname(dbenv, + pref, name, &array[n])) != 0) + goto err; + __os_freestr(name); + } else if ((p = __db_rpath(name)) != NULL) { + if ((ret = __os_strdup(dbenv, p + 1, &array[n])) != 0) + goto err; + __os_freestr(name); + } else + array[n] = name; + + name = NULL; + array[++n] = NULL; + } + + /* If there's nothing to return, we're done. */ + if (n == 0) { + *listp = NULL; + ret = 0; + goto err; + } + + /* Sort the list. */ + qsort(array, (size_t)n, sizeof(char *), __cmpfunc); + + /* Rework the memory. */ + if ((ret = __usermem(dbenv, &array, db_malloc)) != 0) + goto err; + + *listp = array; + return (0); + +err: if (array != NULL) { + for (arrayp = array; *arrayp != NULL; ++arrayp) + __os_freestr(*arrayp); + __os_free(array, sizeof(char *) * array_size); + } + if (name != NULL) + __os_freestr(name); + return (ret); +} + +/* + * __build_data -- + * Build a list of datafiles for return. + */ +static int +__build_data(dbenv, pref, listp, db_malloc) + DB_ENV *dbenv; + char *pref, ***listp; + void *(*db_malloc) __P((size_t)); +{ + DBT rec; + DB_LSN lsn; + __log_register_args *argp; + u_int32_t rectype; + int array_size, last, n, nxt, ret; + char **array, **arrayp, *p, *real_name; + + /* Get some initial space. */ + array_size = 10; + if ((ret = __os_malloc(dbenv, + sizeof(char *) * array_size, NULL, &array)) != 0) + return (ret); + array[0] = NULL; + + memset(&rec, 0, sizeof(rec)); + if (F_ISSET(dbenv, DB_ENV_THREAD)) + F_SET(&rec, DB_DBT_MALLOC); + for (n = 0, ret = log_get(dbenv, &lsn, &rec, DB_FIRST); + ret == 0; ret = log_get(dbenv, &lsn, &rec, DB_NEXT)) { + if (rec.size < sizeof(rectype)) { + ret = EINVAL; + __db_err(dbenv, "log_archive: bad log record"); + goto lg_free; + } + + memcpy(&rectype, rec.data, sizeof(rectype)); + if (rectype != DB_log_register) { + if (F_ISSET(dbenv, DB_ENV_THREAD)) { + __os_free(rec.data, rec.size); + rec.data = NULL; + } + continue; + } + if ((ret = __log_register_read(dbenv, rec.data, &argp)) != 0) { + ret = EINVAL; + __db_err(dbenv, + "log_archive: unable to read log record"); + goto lg_free; + } + + if (n >= array_size - 1) { + array_size += LIST_INCREMENT; + if ((ret = __os_realloc(dbenv, + sizeof(char *) * array_size, NULL, &array)) != 0) + goto lg_free; + } + + if ((ret = __os_strdup(dbenv, + argp->name.data, &array[n])) != 0) { +lg_free: if (F_ISSET(&rec, DB_DBT_MALLOC) && rec.data != NULL) + __os_free(rec.data, rec.size); + goto err1; + } + + array[++n] = NULL; + __os_free(argp, 0); + + if (F_ISSET(dbenv, DB_ENV_THREAD)) { + __os_free(rec.data, rec.size); + rec.data = NULL; + } + } + + /* If there's nothing to return, we're done. */ + if (n == 0) { + ret = 0; + *listp = NULL; + goto err1; + } + + /* Sort the list. */ + qsort(array, (size_t)n, sizeof(char *), __cmpfunc); + + /* + * Build the real pathnames, discarding nonexistent files and + * duplicates. + */ + for (last = nxt = 0; nxt < n;) { + /* + * Discard duplicates. Last is the next slot we're going + * to return to the user, nxt is the next slot that we're + * going to consider. + */ + if (last != nxt) { + array[last] = array[nxt]; + array[nxt] = NULL; + } + for (++nxt; nxt < n && + strcmp(array[last], array[nxt]) == 0; ++nxt) { + __os_freestr(array[nxt]); + array[nxt] = NULL; + } + + /* Get the real name. */ + if ((ret = __db_appname(dbenv, + DB_APP_DATA, NULL, array[last], 0, NULL, &real_name)) != 0) + goto err2; + + /* If the file doesn't exist, ignore it. */ + if (__os_exists(real_name, NULL) != 0) { + __os_freestr(real_name); + __os_freestr(array[last]); + array[last] = NULL; + continue; + } + + /* Rework the name as requested by the user. */ + __os_freestr(array[last]); + array[last] = NULL; + if (pref != NULL) { + ret = __absname(dbenv, pref, real_name, &array[last]); + __os_freestr(real_name); + if (ret != 0) + goto err2; + } else if ((p = __db_rpath(real_name)) != NULL) { + ret = __os_strdup(dbenv, p + 1, &array[last]); + __os_freestr(real_name); + if (ret != 0) + goto err2; + } else + array[last] = real_name; + ++last; + } + + /* NULL-terminate the list. */ + array[last] = NULL; + + /* Rework the memory. */ + if ((ret = __usermem(dbenv, &array, db_malloc)) != 0) + goto err1; + + *listp = array; + return (0); + +err2: /* + * XXX + * We've possibly inserted NULLs into the array list, so clean up a + * bit so that the other error processing works. + */ + if (array != NULL) + for (; nxt < n; ++nxt) + __os_freestr(array[nxt]); + /* FALLTHROUGH */ + +err1: if (array != NULL) { + for (arrayp = array; *arrayp != NULL; ++arrayp) + __os_freestr(*arrayp); + __os_free(array, array_size * sizeof(char *)); + } + return (ret); +} + +/* + * __absname -- + * Return an absolute path name for the file. + */ +static int +__absname(dbenv, pref, name, newnamep) + DB_ENV *dbenv; + char *pref, *name, **newnamep; +{ + size_t l_pref, l_name; + int isabspath, ret; + char *newname; + + l_name = strlen(name); + isabspath = __os_abspath(name); + l_pref = isabspath ? 0 : strlen(pref); + + /* Malloc space for concatenating the two. */ + if ((ret = __os_malloc(dbenv, + l_pref + l_name + 2, NULL, &newname)) != 0) + return (ret); + *newnamep = newname; + + /* Build the name. If `name' is an absolute path, ignore any prefix. */ + if (!isabspath) { + memcpy(newname, pref, l_pref); + if (strchr(PATH_SEPARATOR, newname[l_pref - 1]) == NULL) + newname[l_pref++] = PATH_SEPARATOR[0]; + } + memcpy(newname + l_pref, name, l_name + 1); + + return (0); +} + +/* + * __usermem -- + * Create a single chunk of memory that holds the returned information. + * If the user has their own malloc routine, use it. + */ +static int +__usermem(dbenv, listp, db_malloc) + DB_ENV *dbenv; + char ***listp; + void *(*db_malloc) __P((size_t)); +{ + size_t len; + int ret; + char **array, **arrayp, **orig, *strp; + + /* Find out how much space we need. */ + for (len = 0, orig = *listp; *orig != NULL; ++orig) + len += sizeof(char *) + strlen(*orig) + 1; + len += sizeof(char *); + + /* Allocate it and set up the pointers. */ + if ((ret = __os_malloc(dbenv, len, db_malloc, &array)) != 0) + return (ret); + + strp = (char *)(array + (orig - *listp) + 1); + + /* Copy the original information into the new memory. */ + for (orig = *listp, arrayp = array; *orig != NULL; ++orig, ++arrayp) { + len = strlen(*orig); + memcpy(strp, *orig, len + 1); + *arrayp = strp; + strp += len + 1; + + __os_freestr(*orig); + } + + /* NULL-terminate the list. */ + *arrayp = NULL; + + __os_free(*listp, 0); + *listp = array; + + return (0); +} + +static int +__cmpfunc(p1, p2) + const void *p1, *p2; +{ + return (strcmp(*((char * const *)p1), *((char * const *)p2))); +} diff --git a/db/log/log_auto.c b/db/log/log_auto.c new file mode 100644 index 000000000..281296cc2 --- /dev/null +++ b/db/log/log_auto.c @@ -0,0 +1,326 @@ +/* Do not edit: automatically built by gen_rec.awk. */ +#include "db_config.h" + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_dispatch.h" +#include "db_am.h" +#include "log.h" +#include "txn.h" + +int +__log_register1_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __log_register1_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __log_register1_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]log_register1: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\topcode: %lu\n", (u_long)argp->opcode); + printf("\tname: "); + for (i = 0; i < argp->name.size; i++) { + ch = ((u_int8_t *)argp->name.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\tuid: "); + for (i = 0; i < argp->uid.size; i++) { + ch = ((u_int8_t *)argp->uid.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tftype: 0x%lx\n", (u_long)argp->ftype); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__log_register1_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __log_register1_args **argpp; +{ + __log_register1_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__log_register1_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->opcode, bp, sizeof(argp->opcode)); + bp += sizeof(argp->opcode); + memset(&argp->name, 0, sizeof(argp->name)); + memcpy(&argp->name.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->name.data = bp; + bp += argp->name.size; + memset(&argp->uid, 0, sizeof(argp->uid)); + memcpy(&argp->uid.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->uid.data = bp; + bp += argp->uid.size; + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->ftype, bp, sizeof(argp->ftype)); + bp += sizeof(argp->ftype); + *argpp = argp; + return (0); +} + +int +__log_register_log(dbenv, txnid, ret_lsnp, flags, + opcode, name, uid, fileid, ftype, meta_pgno) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + u_int32_t opcode; + const DBT *name; + const DBT *uid; + int32_t fileid; + DBTYPE ftype; + db_pgno_t meta_pgno; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t zero; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_log_register; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(opcode) + + sizeof(u_int32_t) + (name == NULL ? 0 : name->size) + + sizeof(u_int32_t) + (uid == NULL ? 0 : uid->size) + + sizeof(fileid) + + sizeof(ftype) + + sizeof(meta_pgno); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &opcode, sizeof(opcode)); + bp += sizeof(opcode); + if (name == NULL) { + zero = 0; + memcpy(bp, &zero, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + } else { + memcpy(bp, &name->size, sizeof(name->size)); + bp += sizeof(name->size); + memcpy(bp, name->data, name->size); + bp += name->size; + } + if (uid == NULL) { + zero = 0; + memcpy(bp, &zero, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + } else { + memcpy(bp, &uid->size, sizeof(uid->size)); + bp += sizeof(uid->size); + memcpy(bp, uid->data, uid->size); + bp += uid->size; + } + memcpy(bp, &fileid, sizeof(fileid)); + bp += sizeof(fileid); + memcpy(bp, &ftype, sizeof(ftype)); + bp += sizeof(ftype); + memcpy(bp, &meta_pgno, sizeof(meta_pgno)); + bp += sizeof(meta_pgno); + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = __log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__log_register_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __log_register_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __log_register_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]log_register: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\topcode: %lu\n", (u_long)argp->opcode); + printf("\tname: "); + for (i = 0; i < argp->name.size; i++) { + ch = ((u_int8_t *)argp->name.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\tuid: "); + for (i = 0; i < argp->uid.size; i++) { + ch = ((u_int8_t *)argp->uid.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tftype: 0x%lx\n", (u_long)argp->ftype); + printf("\tmeta_pgno: %lu\n", (u_long)argp->meta_pgno); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__log_register_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __log_register_args **argpp; +{ + __log_register_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__log_register_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->opcode, bp, sizeof(argp->opcode)); + bp += sizeof(argp->opcode); + memset(&argp->name, 0, sizeof(argp->name)); + memcpy(&argp->name.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->name.data = bp; + bp += argp->name.size; + memset(&argp->uid, 0, sizeof(argp->uid)); + memcpy(&argp->uid.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->uid.data = bp; + bp += argp->uid.size; + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->ftype, bp, sizeof(argp->ftype)); + bp += sizeof(argp->ftype); + memcpy(&argp->meta_pgno, bp, sizeof(argp->meta_pgno)); + bp += sizeof(argp->meta_pgno); + *argpp = argp; + return (0); +} + +int +__log_init_print(dbenv) + DB_ENV *dbenv; +{ + int ret; + + if ((ret = __db_add_recovery(dbenv, + __log_register1_print, DB_log_register1)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __log_register_print, DB_log_register)) != 0) + return (ret); + return (0); +} + +int +__log_init_recover(dbenv) + DB_ENV *dbenv; +{ + int ret; + + if ((ret = __db_add_recovery(dbenv, + __deprecated_recover, DB_log_register1)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __log_register_recover, DB_log_register)) != 0) + return (ret); + return (0); +} + diff --git a/db/log/log_compare.c b/db/log/log_compare.c new file mode 100644 index 000000000..9bc3c028a --- /dev/null +++ b/db/log/log_compare.c @@ -0,0 +1,34 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: log_compare.c,v 11.3 2000/02/14 02:59:59 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include +#endif + +#include "db_int.h" + +/* + * log_compare -- + * Compare two LSN's; return 1, 0, -1 if first is >, == or < second. + */ +int +log_compare(lsn0, lsn1) + const DB_LSN *lsn0, *lsn1; +{ + if (lsn0->file != lsn1->file) + return (lsn0->file < lsn1->file ? -1 : 1); + + if (lsn0->offset != lsn1->offset) + return (lsn0->offset < lsn1->offset ? -1 : 1); + + return (0); +} diff --git a/db/log/log_findckp.c b/db/log/log_findckp.c new file mode 100644 index 000000000..b1e8fddbd --- /dev/null +++ b/db/log/log_findckp.c @@ -0,0 +1,135 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: log_findckp.c,v 11.5 2000/11/30 00:58:40 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "log.h" +#include "txn.h" + +/* + * __log_findckp -- + * + * Looks for the most recent checkpoint that occurs before the most recent + * checkpoint LSN, subject to the constraint that there must be at least two + * checkpoints. The reason you need two checkpoints is that you might have + * crashed during the most recent one and may not have a copy of all the + * open files. This is the point from which recovery can start and the + * point up to which archival/truncation can take place. Checkpoints in + * the log look like: + * + * ------------------------------------------------------------------- + * | ckp A, ckplsn 100 | .... record .... | ckp B, ckplsn 600 | ... + * ------------------------------------------------------------------- + * LSN 500 LSN 1000 + * + * If we read what log returns from using the DB_CKP parameter to logput, + * we'll get the record at LSN 1000. The checkpoint LSN there is 600. + * Now we have to scan backwards looking for a checkpoint before LSN 600. + * We find one at 500. This means that we can truncate the log before + * 500 or run recovery beginning at 500. + * + * Returns 0 if we find a suitable checkpoint or we retrieved the first + * record in the log from which to start. Returns DB_NOTFOUND if there + * are no log records, errno on error. + * + * PUBLIC: int __log_findckp __P((DB_ENV *, DB_LSN *)); + */ +int +__log_findckp(dbenv, lsnp) + DB_ENV *dbenv; + DB_LSN *lsnp; +{ + DBT data; + DB_LSN ckp_lsn, final_ckp, last_ckp, next_lsn; + __txn_ckp_args *ckp_args; + int ret; + + /* + * Need to find the appropriate point from which to begin + * recovery. + */ + memset(&data, 0, sizeof(data)); + if (F_ISSET(dbenv, DB_ENV_THREAD)) + F_SET(&data, DB_DBT_MALLOC); + ZERO_LSN(ckp_lsn); + if ((ret = log_get(dbenv, &last_ckp, &data, DB_CHECKPOINT)) != 0) { + if (ret == ENOENT) + goto get_first; + else + return (ret); + } + final_ckp = last_ckp; + + next_lsn = last_ckp; + do { + if (F_ISSET(dbenv, DB_ENV_THREAD)) + __os_free(data.data, data.size); + + if ((ret = log_get(dbenv, &next_lsn, &data, DB_SET)) != 0) + return (ret); + if ((ret = __txn_ckp_read(dbenv, data.data, &ckp_args)) != 0) { + if (F_ISSET(dbenv, DB_ENV_THREAD)) + __os_free(data.data, data.size); + return (ret); + } + if (IS_ZERO_LSN(ckp_lsn)) + ckp_lsn = ckp_args->ckp_lsn; + if (FLD_ISSET(dbenv->verbose, DB_VERB_CHKPOINT)) { + __db_err(dbenv, "Checkpoint at: [%lu][%lu]", + (u_long)last_ckp.file, (u_long)last_ckp.offset); + __db_err(dbenv, "Checkpoint LSN: [%lu][%lu]", + (u_long)ckp_args->ckp_lsn.file, + (u_long)ckp_args->ckp_lsn.offset); + __db_err(dbenv, "Previous checkpoint: [%lu][%lu]", + (u_long)ckp_args->last_ckp.file, + (u_long)ckp_args->last_ckp.offset); + } + last_ckp = next_lsn; + next_lsn = ckp_args->last_ckp; + __os_free(ckp_args, sizeof(*ckp_args)); + + /* + * Keep looping until either you 1) run out of checkpoints, + * 2) you've found a checkpoint before the most recent + * checkpoint's LSN and you have at least 2 checkpoints. + */ + } while (!IS_ZERO_LSN(next_lsn) && + (log_compare(&last_ckp, &ckp_lsn) > 0 || + log_compare(&final_ckp, &last_ckp) == 0)); + + if (F_ISSET(dbenv, DB_ENV_THREAD)) + __os_free(data.data, data.size); + + /* + * At this point, either, next_lsn is ZERO or ckp_lsn is the + * checkpoint lsn and last_ckp is the LSN of the last checkpoint + * before ckp_lsn. If the compare in the loop is still true, then + * next_lsn must be 0 and we need to roll forward from the + * beginning of the log. + */ + if (log_compare(&last_ckp, &ckp_lsn) >= 0 || + log_compare(&final_ckp, &last_ckp) == 0) { +get_first: if ((ret = log_get(dbenv, &last_ckp, &data, DB_FIRST)) != 0) + return (ret); + if (F_ISSET(dbenv, DB_ENV_THREAD)) + __os_free(data.data, data.size); + } + *lsnp = last_ckp; + + return (IS_ZERO_LSN(last_ckp) ? DB_NOTFOUND : 0); +} diff --git a/db/log/log_get.c b/db/log/log_get.c new file mode 100644 index 000000000..b75d50a62 --- /dev/null +++ b/db/log/log_get.c @@ -0,0 +1,465 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: log_get.c,v 11.32 2001/01/11 18:19:53 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#endif + +#ifdef HAVE_RPC +#include "db_server.h" +#endif + +#include "db_int.h" +#include "db_page.h" +#include "log.h" +#include "hash.h" + +#ifdef HAVE_RPC +#include "gen_client_ext.h" +#include "rpc_client_ext.h" +#endif + +/* + * log_get -- + * Get a log record. + */ +int +log_get(dbenv, alsn, dbt, flags) + DB_ENV *dbenv; + DB_LSN *alsn; + DBT *dbt; + u_int32_t flags; +{ + DB_LOG *dblp; + DB_LSN saved_lsn; + int ret; + +#ifdef HAVE_RPC + if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) + return (__dbcl_log_get(dbenv, alsn, dbt, flags)); +#endif + + PANIC_CHECK(dbenv); + ENV_REQUIRES_CONFIG(dbenv, dbenv->lg_handle, DB_INIT_LOG); + + /* Validate arguments. */ + if (flags != DB_CHECKPOINT && flags != DB_CURRENT && + flags != DB_FIRST && flags != DB_LAST && + flags != DB_NEXT && flags != DB_PREV && flags != DB_SET) + return (__db_ferr(dbenv, "log_get", 1)); + + if (F_ISSET(dbenv, DB_ENV_THREAD)) { + if (flags == DB_NEXT || flags == DB_PREV || flags == DB_CURRENT) + return (__db_ferr(dbenv, "log_get", 1)); + if (!F_ISSET(dbt, + DB_DBT_MALLOC | DB_DBT_REALLOC | DB_DBT_USERMEM)) + return (__db_ferr(dbenv, "threaded data", 1)); + } + + dblp = dbenv->lg_handle; + R_LOCK(dbenv, &dblp->reginfo); + + /* + * The alsn field is only initialized if DB_SET is the flag, so this + * assignment causes uninitialized memory complaints for other flag + * values. + */ +#ifdef UMRW + if (flags == DB_SET) + saved_lsn = *alsn; + else + ZERO_LSN(saved_lsn); +#else + saved_lsn = *alsn; +#endif + + /* + * If we get one of the log's header records, repeat the operation. + * This assumes that applications don't ever request the log header + * records by LSN, but that seems reasonable to me. + */ + if ((ret = __log_get(dblp, + alsn, dbt, flags, 0)) == 0 && alsn->offset == 0) { + switch (flags) { + case DB_FIRST: + flags = DB_NEXT; + break; + case DB_LAST: + flags = DB_PREV; + break; + } + if (F_ISSET(dbt, DB_DBT_MALLOC)) { + __os_free(dbt->data, dbt->size); + dbt->data = NULL; + } + ret = __log_get(dblp, alsn, dbt, flags, 0); + } + if (ret != 0) + *alsn = saved_lsn; + + R_UNLOCK(dbenv, &dblp->reginfo); + + return (ret); +} + +/* + * __log_get -- + * Get a log record; internal version. + * + * PUBLIC: int __log_get __P((DB_LOG *, DB_LSN *, DBT *, u_int32_t, int)); + */ +int +__log_get(dblp, alsn, dbt, flags, silent) + DB_LOG *dblp; + DB_LSN *alsn; + DBT *dbt; + u_int32_t flags; + int silent; +{ + DB_ENV *dbenv; + DB_LSN nlsn; + HDR hdr; + LOG *lp; + const char *fail; + char *np, *tbuf; + int cnt, ret; + logfile_validity status; + size_t len, nr; + u_int32_t offset; + u_int8_t *p; + void *shortp, *readp; + + lp = dblp->reginfo.primary; + fail = np = tbuf = NULL; + dbenv = dblp->dbenv; + + nlsn = dblp->c_lsn; + switch (flags) { + case DB_CHECKPOINT: + nlsn = lp->chkpt_lsn; + if (IS_ZERO_LSN(nlsn)) { + /* No db_err. The caller may expect this. */ + ret = ENOENT; + goto err2; + } + break; + case DB_NEXT: /* Next log record. */ + if (!IS_ZERO_LSN(nlsn)) { + /* Increment the cursor by the cursor record size. */ + nlsn.offset += dblp->c_len; + break; + } + /* FALLTHROUGH */ + case DB_FIRST: /* Find the first log record. */ + /* Find the first log file. */ + if ((ret = __log_find(dblp, 1, &cnt, &status)) != 0) + goto err2; + + /* + * We want any readable version, so either DB_LV_NORMAL + * or DB_LV_OLD_READABLE is acceptable here. If it's + * not one of those two, there is no first log record that + * we can read. + */ + if (status != DB_LV_NORMAL && status != DB_LV_OLD_READABLE) { + ret = DB_NOTFOUND; + goto err2; + } + + /* + * We may have only entered records in the buffer, and not + * yet written a log file. If no log files were found and + * there's anything in the buffer, it belongs to file 1. + */ + if (cnt == 0) + cnt = 1; + + nlsn.file = cnt; + nlsn.offset = 0; + break; + case DB_CURRENT: /* Current log record. */ + break; + case DB_PREV: /* Previous log record. */ + if (!IS_ZERO_LSN(nlsn)) { + /* If at start-of-file, move to the previous file. */ + if (nlsn.offset == 0) { + if (nlsn.file == 1 || + __log_valid(dblp, + nlsn.file - 1, 0, &status) != 0) + return (DB_NOTFOUND); + + if (status != DB_LV_NORMAL && + status != DB_LV_OLD_READABLE) + return (DB_NOTFOUND); + + --nlsn.file; + nlsn.offset = dblp->c_off; + } else + nlsn.offset = dblp->c_off; + break; + } + /* FALLTHROUGH */ + case DB_LAST: /* Last log record. */ + nlsn.file = lp->lsn.file; + nlsn.offset = lp->lsn.offset - lp->len; + break; + case DB_SET: /* Set log record. */ + nlsn = *alsn; + break; + } + + if (0) { /* Move to the next file. */ +next_file: ++nlsn.file; + nlsn.offset = 0; + } + + /* Return 1 if the request is past the end of the log. */ + if (nlsn.file > lp->lsn.file || + (nlsn.file == lp->lsn.file && nlsn.offset >= lp->lsn.offset)) + return (DB_NOTFOUND); + + /* If we've switched files, discard the current file handle. */ + if (dblp->c_lsn.file != nlsn.file && + F_ISSET(&dblp->c_fh, DB_FH_VALID)) { + (void)__os_closehandle(&dblp->c_fh); + } + + /* If the entire record is in the in-memory buffer, copy it out. */ + if (nlsn.file == lp->lsn.file && nlsn.offset >= lp->w_off) { + /* Copy the header. */ + p = dblp->bufp + (nlsn.offset - lp->w_off); + memcpy(&hdr, p, sizeof(HDR)); + + /* Copy the record. */ + len = hdr.len - sizeof(HDR); + if ((ret = __db_retcopy(NULL, dbt, p + sizeof(HDR), + len, &dblp->c_dbt.data, &dblp->c_dbt.ulen)) != 0) + goto err2; + goto cksum; + } + + shortp = NULL; + + /* Acquire a file descriptor. */ + if (!F_ISSET(&dblp->c_fh, DB_FH_VALID)) { + if ((ret = __log_name(dblp, nlsn.file, + &np, &dblp->c_fh, DB_OSO_RDONLY | DB_OSO_SEQ)) != 0) { + fail = np; + goto err1; + } + __os_freestr(np); + np = NULL; + } + + /* See if we've already read this */ + if (nlsn.file == dblp->r_file && nlsn.offset > dblp->r_off + && nlsn.offset + sizeof(HDR) < dblp->r_off + dblp->r_size) + goto got_header; + + /* + * Seek to the header offset and read the header. Because the file + * may be pre-allocated, we have to make sure that we're not reading + * past the information in the start of the in-memory buffer. + */ + + readp = &hdr; + offset = nlsn.offset; + if (nlsn.file == lp->lsn.file && offset + sizeof(HDR) > lp->w_off) + nr = lp->w_off - offset; + else if (dblp->readbufp == NULL) + nr = sizeof(HDR); + else { + nr = lp->buffer_size; + readp = dblp->readbufp; + dblp->r_file = nlsn.file; + /* Going backwards. Put the current in the middle. */ + if (flags == DB_PREV || flags == DB_LAST) { + if (offset <= lp->buffer_size/2) + offset = 0; + else + offset = offset - lp->buffer_size/2; + } + if (nlsn.file == lp->lsn.file && offset + nr > lp->lsn.offset) + nr = lp->lsn.offset - offset; + dblp->r_off = offset; + } + + if ((ret = __os_seek(dblp->dbenv, + &dblp->c_fh, 0, 0, offset, 0, DB_OS_SEEK_SET)) != 0) { + fail = "seek"; + goto err1; + } + if ((ret = __os_read(dblp->dbenv, &dblp->c_fh, readp, nr, &nr)) != 0) { + fail = "read"; + goto err1; + } + if (nr < sizeof(HDR)) { + /* If read returns EOF, try the next file. */ + if (nr == 0) { + if (flags != DB_NEXT || nlsn.file == lp->lsn.file) + goto corrupt; + goto next_file; + } + + if (dblp->readbufp != NULL) + memcpy((u_int8_t *) &hdr, readp, nr); + + /* + * If read returns a short count the rest of the record has + * to be in the in-memory buffer. + */ + if (lp->b_off < sizeof(HDR) - nr) + goto corrupt; + + /* Get the rest of the header from the in-memory buffer. */ + memcpy((u_int8_t *)&hdr + nr, dblp->bufp, sizeof(HDR) - nr); + + if (hdr.len == 0) + goto next_file; + + shortp = dblp->bufp + (sizeof(HDR) - nr); + } + + else if (dblp->readbufp != NULL) { + dblp->r_size = nr; +got_header: memcpy((u_int8_t *)&hdr, + dblp->readbufp + (nlsn.offset - dblp->r_off), sizeof(HDR)); + } + + /* + * Check for buffers of 0's, that's what we usually see during recovery, + * although it's certainly not something on which we can depend. Check + * for impossibly large records. The malloc should fail later, but we + * have customers that run mallocs that handle allocation failure as a + * fatal error. + */ + if (hdr.len == 0) + goto next_file; + if (hdr.len <= sizeof(HDR) || hdr.len > lp->persist.lg_max) + goto corrupt; + len = hdr.len - sizeof(HDR); + + /* If we've already moved to the in-memory buffer, fill from there. */ + if (shortp != NULL) { + if (lp->b_off < ((u_int8_t *)shortp - dblp->bufp) + len) + goto corrupt; + if ((ret = __db_retcopy(NULL, dbt, shortp, len, + &dblp->c_dbt.data, &dblp->c_dbt.ulen)) != 0) + goto err2; + goto cksum; + } + + if (dblp->readbufp != NULL) { + if (nlsn.offset + hdr.len < dblp->r_off + dblp->r_size) { + if ((ret = __db_retcopy(NULL, dbt, dblp->readbufp + + (nlsn.offset - dblp->r_off) + sizeof(HDR), + len, &dblp->c_dbt.data, &dblp->c_dbt.ulen)) != 0) + goto err2; + goto cksum; + } else if ((ret = __os_seek(dblp->dbenv, &dblp->c_fh, 0, + 0, nlsn.offset + sizeof(HDR), 0, DB_OS_SEEK_SET)) != 0) { + fail = "seek"; + goto err1; + } + } + + /* + * Allocate temporary memory to hold the record. + * + * XXX + * We're calling malloc(3) with a region locked. This isn't + * a good idea. + */ + if ((ret = __os_malloc(dbenv, len, NULL, &tbuf)) != 0) + goto err1; + + /* + * Read the record into the buffer. If read returns a short count, + * there was an error or the rest of the record is in the in-memory + * buffer. Note, the information may be garbage if we're in recovery, + * so don't read past the end of the buffer's memory. + * + * Because the file may be pre-allocated, we have to make sure that + * we're not reading past the information in the start of the in-memory + * buffer. + */ + if (nlsn.file == lp->lsn.file && + nlsn.offset + sizeof(HDR) + len > lp->w_off) + nr = lp->w_off - (nlsn.offset + sizeof(HDR)); + else + nr = len; + if ((ret = __os_read(dblp->dbenv, &dblp->c_fh, tbuf, nr, &nr)) != 0) { + fail = "read"; + goto err1; + } + if (len - nr > lp->buffer_size) + goto corrupt; + if (nr != len) { + if (lp->b_off < len - nr) + goto corrupt; + + /* Get the rest of the record from the in-memory buffer. */ + memcpy((u_int8_t *)tbuf + nr, dblp->bufp, len - nr); + } + + /* Copy the record into the user's DBT. */ + if ((ret = __db_retcopy(NULL, dbt, tbuf, len, + &dblp->c_dbt.data, &dblp->c_dbt.ulen)) != 0) + goto err2; + __os_free(tbuf, 0); + tbuf = NULL; + +cksum: /* + * If the user specified a partial record read, the checksum can't + * match. It's not an obvious thing to do, but a user testing for + * the length of a record might do it. + */ + if (!F_ISSET(dbt, DB_DBT_PARTIAL) && + hdr.cksum != __ham_func4(NULL, dbt->data, dbt->size)) { + if (!silent) + __db_err(dbenv, "log_get: checksum mismatch"); + goto corrupt; + } + + /* Update the cursor and the return lsn. */ + dblp->c_off = hdr.prev; + dblp->c_len = hdr.len; + dblp->c_lsn = nlsn; + *alsn = nlsn; + + return (0); + +corrupt:/* + * This is the catchall -- for some reason we didn't find enough + * information or it wasn't reasonable information, and it wasn't + * because a system call failed. + */ + ret = EIO; + fail = "read"; + +err1: if (!silent) { + if (fail == NULL) + __db_err(dbenv, "log_get: %s", db_strerror(ret)); + else + __db_err(dbenv, + "log_get: %s: %s", fail, db_strerror(ret)); + } + +err2: if (np != NULL) + __os_freestr(np); + if (tbuf != NULL) + __os_free(tbuf, 0); + return (ret); +} diff --git a/db/log/log_method.c b/db/log/log_method.c new file mode 100644 index 000000000..883f485d8 --- /dev/null +++ b/db/log/log_method.c @@ -0,0 +1,121 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: log_method.c,v 11.14 2000/11/30 00:58:40 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#endif + +#ifdef HAVE_RPC +#include "db_server.h" +#endif + +#include "db_int.h" +#include "log.h" + +#ifdef HAVE_RPC +#include "gen_client_ext.h" +#include "rpc_client_ext.h" +#endif + +static int __log_set_lg_max __P((DB_ENV *, u_int32_t)); +static int __log_set_lg_bsize __P((DB_ENV *, u_int32_t)); +static int __log_set_lg_dir __P((DB_ENV *, const char *)); + +/* + * __log_dbenv_create -- + * Log specific initialization of the DB_ENV structure. + * + * PUBLIC: void __log_dbenv_create __P((DB_ENV *)); + */ +void +__log_dbenv_create(dbenv) + DB_ENV *dbenv; +{ + dbenv->lg_bsize = LG_BSIZE_DEFAULT; + dbenv->set_lg_bsize = __log_set_lg_bsize; + + dbenv->lg_max = LG_MAX_DEFAULT; + dbenv->set_lg_max = __log_set_lg_max; + + dbenv->set_lg_dir = __log_set_lg_dir; +#ifdef HAVE_RPC + /* + * If we have a client, overwrite what we just setup to + * point to client functions. + */ + if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) { + dbenv->set_lg_bsize = __dbcl_set_lg_bsize; + dbenv->set_lg_max = __dbcl_set_lg_max; + dbenv->set_lg_dir = __dbcl_set_lg_dir; + } +#endif +} + +/* + * __log_set_lg_bsize -- + * Set the log buffer size. + */ +static int +__log_set_lg_bsize(dbenv, lg_bsize) + DB_ENV *dbenv; + u_int32_t lg_bsize; +{ + ENV_ILLEGAL_AFTER_OPEN(dbenv, "set_lg_bsize"); + + /* Let's not be silly. */ + if (lg_bsize > dbenv->lg_max / 4) { + __db_err(dbenv, "log buffer size must be <= log file size / 4"); + return (EINVAL); + } + + dbenv->lg_bsize = lg_bsize; + return (0); +} + +/* + * __log_set_lg_max -- + * Set the maximum log file size. + */ +static int +__log_set_lg_max(dbenv, lg_max) + DB_ENV *dbenv; + u_int32_t lg_max; +{ + ENV_ILLEGAL_AFTER_OPEN(dbenv, "set_lg_max"); + + /* Let's not be silly. */ + if (lg_max < dbenv->lg_bsize * 4) { + __db_err(dbenv, "log file size must be >= log buffer size * 4"); + return (EINVAL); + } + + dbenv->lg_max = lg_max; + return (0); +} + +/* + * __log_set_lg_dir -- + * Set the log file directory. + */ +static int +__log_set_lg_dir(dbenv, dir) + DB_ENV *dbenv; + const char *dir; +{ + if (dbenv->db_log_dir != NULL) + __os_freestr(dbenv->db_log_dir); + return (__os_strdup(dbenv, dir, &dbenv->db_log_dir)); +} diff --git a/db/log/log_put.c b/db/log/log_put.c new file mode 100644 index 000000000..e5cdedb54 --- /dev/null +++ b/db/log/log_put.c @@ -0,0 +1,701 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: log_put.c,v 11.26 2000/11/30 00:58:40 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#if TIME_WITH_SYS_TIME +#include +#include +#else +#if HAVE_SYS_TIME_H +#include +#else +#include +#endif +#endif + +#include +#include +#include +#endif + +#ifdef HAVE_RPC +#include "db_server.h" +#endif + +#include "db_int.h" +#include "db_page.h" +#include "log.h" +#include "hash.h" +#include "clib_ext.h" + +#ifdef HAVE_RPC +#include "gen_client_ext.h" +#include "rpc_client_ext.h" +#endif + +static int __log_fill __P((DB_LOG *, DB_LSN *, void *, u_int32_t)); +static int __log_flush __P((DB_LOG *, const DB_LSN *)); +static int __log_newfh __P((DB_LOG *)); +static int __log_putr __P((DB_LOG *, DB_LSN *, const DBT *, u_int32_t)); +static int __log_open_files __P((DB_ENV *)); +static int __log_write __P((DB_LOG *, void *, u_int32_t)); + +/* + * log_put -- + * Write a log record. + */ +int +log_put(dbenv, lsn, dbt, flags) + DB_ENV *dbenv; + DB_LSN *lsn; + const DBT *dbt; + u_int32_t flags; +{ + DB_LOG *dblp; + int ret; + +#ifdef HAVE_RPC + if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) + return (__dbcl_log_put(dbenv, lsn, dbt, flags)); +#endif + + PANIC_CHECK(dbenv); + ENV_REQUIRES_CONFIG(dbenv, dbenv->lg_handle, DB_INIT_LOG); + + /* Validate arguments. */ + if (flags != 0 && flags != DB_CHECKPOINT && + flags != DB_CURLSN && flags != DB_FLUSH) + return (__db_ferr(dbenv, "log_put", 0)); + + dblp = dbenv->lg_handle; + R_LOCK(dbenv, &dblp->reginfo); + ret = __log_put(dbenv, lsn, dbt, flags); + R_UNLOCK(dbenv, &dblp->reginfo); + return (ret); +} + +/* + * __log_put -- + * Write a log record; internal version. + * + * PUBLIC: int __log_put __P((DB_ENV *, DB_LSN *, const DBT *, u_int32_t)); + */ +int +__log_put(dbenv, lsn, dbt, flags) + DB_ENV *dbenv; + DB_LSN *lsn; + const DBT *dbt; + u_int32_t flags; +{ + DBT t; + DB_LOG *dblp; + LOG *lp; + u_int32_t lastoff; + int ret; + + dblp = dbenv->lg_handle; + lp = dblp->reginfo.primary; + + /* + * If the application just wants to know where we are, fill in + * the information. Currently used by the transaction manager + * to avoid writing TXN_begin records. + */ + if (flags == DB_CURLSN) { + lsn->file = lp->lsn.file; + lsn->offset = lp->lsn.offset; + return (0); + } + + /* If this information won't fit in the file, swap files. */ + if (lp->lsn.offset + sizeof(HDR) + dbt->size > lp->persist.lg_max) { + if (sizeof(HDR) + + sizeof(LOGP) + dbt->size > lp->persist.lg_max) { + __db_err(dbenv, + "log_put: record larger than maximum file size"); + return (EINVAL); + } + + /* Flush the log. */ + if ((ret = __log_flush(dblp, NULL)) != 0) + return (ret); + + /* + * Save the last known offset from the previous file, we'll + * need it to initialize the persistent header information. + */ + lastoff = lp->lsn.offset; + + /* Point the current LSN to the new file. */ + ++lp->lsn.file; + lp->lsn.offset = 0; + + /* Reset the file write offset. */ + lp->w_off = 0; + } else + lastoff = 0; + + /* Initialize the LSN information returned to the user. */ + lsn->file = lp->lsn.file; + lsn->offset = lp->lsn.offset; + + /* + * Insert persistent information as the first record in every file. + * Note that the previous length is wrong for the very first record + * of the log, but that's okay, we check for it during retrieval. + */ + if (lp->lsn.offset == 0) { + t.data = &lp->persist; + t.size = sizeof(LOGP); + if ((ret = __log_putr(dblp, lsn, + &t, lastoff == 0 ? 0 : lastoff - lp->len)) != 0) + return (ret); + + /* + * Record files open in this log. + * If we are recovering then we are in the + * process of outputting the files, don't do + * it again. + */ + if (!F_ISSET(dblp, DBLOG_RECOVER) && + (ret = __log_open_files(dbenv)) != 0) + return (ret); + + /* Update the LSN information returned to the user. */ + lsn->file = lp->lsn.file; + lsn->offset = lp->lsn.offset; + } + + /* Write the application's log record. */ + if ((ret = __log_putr(dblp, lsn, dbt, lp->lsn.offset - lp->len)) != 0) + return (ret); + + /* + * On a checkpoint, we: + * Put out the checkpoint record (above). + * Save the LSN of the checkpoint in the shared region. + * Append the set of file name information into the log. + */ + if (flags == DB_CHECKPOINT) { + lp->chkpt_lsn = *lsn; + if ((ret = __log_open_files(dbenv)) != 0) + return (ret); + } + + /* + * On a checkpoint or when flush is requested, we: + * Flush the current buffer contents to disk. + * Sync the log to disk. + */ + if (flags == DB_FLUSH || flags == DB_CHECKPOINT) + if ((ret = __log_flush(dblp, NULL)) != 0) + return (ret); + + /* + * On a checkpoint, we: + * Save the time the checkpoint was written. + * Reset the bytes written since the last checkpoint. + */ + if (flags == DB_CHECKPOINT) { + (void)time(&lp->chkpt); + lp->stat.st_wc_bytes = lp->stat.st_wc_mbytes = 0; + } + return (0); +} + +/* + * __log_putr -- + * Actually put a record into the log. + */ +static int +__log_putr(dblp, lsn, dbt, prev) + DB_LOG *dblp; + DB_LSN *lsn; + const DBT *dbt; + u_int32_t prev; +{ + HDR hdr; + LOG *lp; + int ret; + + lp = dblp->reginfo.primary; + + /* + * Initialize the header. If we just switched files, lsn.offset will + * be 0, and what we really want is the offset of the previous record + * in the previous file. Fortunately, prev holds the value we want. + */ + hdr.prev = prev; + hdr.len = sizeof(HDR) + dbt->size; + hdr.cksum = __ham_func4(NULL, dbt->data, dbt->size); + + if ((ret = __log_fill(dblp, lsn, &hdr, sizeof(HDR))) != 0) + return (ret); + lp->len = sizeof(HDR); + lp->lsn.offset += sizeof(HDR); + + if ((ret = __log_fill(dblp, lsn, dbt->data, dbt->size)) != 0) + return (ret); + lp->len += dbt->size; + lp->lsn.offset += dbt->size; + return (0); +} + +/* + * log_flush -- + * Write all records less than or equal to the specified LSN. + */ +int +log_flush(dbenv, lsn) + DB_ENV *dbenv; + const DB_LSN *lsn; +{ + DB_LOG *dblp; + int ret; + +#ifdef HAVE_RPC + if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) + return (__dbcl_log_flush(dbenv, lsn)); +#endif + + PANIC_CHECK(dbenv); + ENV_REQUIRES_CONFIG(dbenv, dbenv->lg_handle, DB_INIT_LOG); + + dblp = dbenv->lg_handle; + R_LOCK(dbenv, &dblp->reginfo); + ret = __log_flush(dblp, lsn); + R_UNLOCK(dbenv, &dblp->reginfo); + return (ret); +} + +/* + * __log_flush -- + * Write all records less than or equal to the specified LSN; internal + * version. + */ +static int +__log_flush(dblp, lsn) + DB_LOG *dblp; + const DB_LSN *lsn; +{ + DB_LSN t_lsn; + LOG *lp; + int current, ret; + + ret = 0; + lp = dblp->reginfo.primary; + + /* + * If no LSN specified, flush the entire log by setting the flush LSN + * to the last LSN written in the log. Otherwise, check that the LSN + * isn't a non-existent record for the log. + */ + if (lsn == NULL) { + t_lsn.file = lp->lsn.file; + t_lsn.offset = lp->lsn.offset - lp->len; + lsn = &t_lsn; + } else + if (lsn->file > lp->lsn.file || + (lsn->file == lp->lsn.file && + lsn->offset > lp->lsn.offset - lp->len)) { + __db_err(dblp->dbenv, + "log_flush: LSN past current end-of-log"); + return (EINVAL); + } + + /* + * If the LSN is less than or equal to the last-sync'd LSN, we're done. + * Note, the last-sync LSN saved in s_lsn is the LSN of the first byte + * after the byte we absolutely know was written to disk, so the test + * is <, not <=. + */ + if (lsn->file < lp->s_lsn.file || + (lsn->file == lp->s_lsn.file && lsn->offset < lp->s_lsn.offset)) + return (0); + + /* + * We may need to write the current buffer. We have to write the + * current buffer if the flush LSN is greater than or equal to the + * buffer's starting LSN. + */ + current = 0; + if (lp->b_off != 0 && log_compare(lsn, &lp->f_lsn) >= 0) { + if ((ret = __log_write(dblp, dblp->bufp, lp->b_off)) != 0) + return (ret); + + lp->b_off = 0; + current = 1; + } + + /* + * It's possible that this thread may never have written to this log + * file. Acquire a file descriptor if we don't already have one. + * One last check -- if we're not writing anything from the current + * buffer, don't bother. We have nothing to write and nothing to + * sync. + */ + if (dblp->lfname != lp->lsn.file) { + if (!current) + return (0); + if ((ret = __log_newfh(dblp)) != 0) + return (ret); + } + + /* Sync all writes to disk. */ + if ((ret = __os_fsync(dblp->dbenv, &dblp->lfh)) != 0) + return (__db_panic(dblp->dbenv, ret)); + ++lp->stat.st_scount; + + /* Set the last-synced LSN, using the on-disk write offset. */ + lp->s_lsn.file = lp->f_lsn.file; + lp->s_lsn.offset = lp->w_off; + + return (0); +} + +/* + * __log_fill -- + * Write information into the log. + */ +static int +__log_fill(dblp, lsn, addr, len) + DB_LOG *dblp; + DB_LSN *lsn; + void *addr; + u_int32_t len; +{ + LOG *lp; + u_int32_t bsize, nrec; + size_t nw, remain; + int ret; + + lp = dblp->reginfo.primary; + bsize = lp->buffer_size; + + while (len > 0) { /* Copy out the data. */ + /* + * If we're beginning a new buffer, note the user LSN to which + * the first byte of the buffer belongs. We have to know this + * when flushing the buffer so that we know if the in-memory + * buffer needs to be flushed. + */ + if (lp->b_off == 0) + lp->f_lsn = *lsn; + + /* + * If we're on a buffer boundary and the data is big enough, + * copy as many records as we can directly from the data. + */ + if (lp->b_off == 0 && len >= bsize) { + nrec = len / bsize; + if ((ret = __log_write(dblp, addr, nrec * bsize)) != 0) + return (ret); + addr = (u_int8_t *)addr + nrec * bsize; + len -= nrec * bsize; + ++lp->stat.st_wcount_fill; + continue; + } + + /* Figure out how many bytes we can copy this time. */ + remain = bsize - lp->b_off; + nw = remain > len ? len : remain; + memcpy(dblp->bufp + lp->b_off, addr, nw); + addr = (u_int8_t *)addr + nw; + len -= nw; + lp->b_off += nw; + + /* If we fill the buffer, flush it. */ + if (lp->b_off == bsize) { + if ((ret = __log_write(dblp, dblp->bufp, bsize)) != 0) + return (ret); + lp->b_off = 0; + ++lp->stat.st_wcount_fill; + } + } + return (0); +} + +/* + * __log_write -- + * Write the log buffer to disk. + */ +static int +__log_write(dblp, addr, len) + DB_LOG *dblp; + void *addr; + u_int32_t len; +{ + LOG *lp; + size_t nw; + int ret; + + /* + * If we haven't opened the log file yet or the current one + * has changed, acquire a new log file. + */ + lp = dblp->reginfo.primary; + if (!F_ISSET(&dblp->lfh, DB_FH_VALID) || dblp->lfname != lp->lsn.file) + if ((ret = __log_newfh(dblp)) != 0) + return (ret); + + /* + * Seek to the offset in the file (someone may have written it + * since we last did). + */ + if ((ret = + __os_seek(dblp->dbenv, + &dblp->lfh, 0, 0, lp->w_off, 0, DB_OS_SEEK_SET)) != 0 || + (ret = __os_write(dblp->dbenv, &dblp->lfh, addr, len, &nw)) != 0) + return (__db_panic(dblp->dbenv, ret)); + if (nw != len) { + __db_err(dblp->dbenv, "Short write while writing log"); + return (EIO); + } + + /* Reset the buffer offset and update the seek offset. */ + lp->w_off += len; + + /* Update written statistics. */ + if ((lp->stat.st_w_bytes += len) >= MEGABYTE) { + lp->stat.st_w_bytes -= MEGABYTE; + ++lp->stat.st_w_mbytes; + } + if ((lp->stat.st_wc_bytes += len) >= MEGABYTE) { + lp->stat.st_wc_bytes -= MEGABYTE; + ++lp->stat.st_wc_mbytes; + } + ++lp->stat.st_wcount; + + return (0); +} + +/* + * log_file -- + * Map a DB_LSN to a file name. + */ +int +log_file(dbenv, lsn, namep, len) + DB_ENV *dbenv; + const DB_LSN *lsn; + char *namep; + size_t len; +{ + DB_LOG *dblp; + int ret; + char *name; + +#ifdef HAVE_RPC + if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) + return (__dbcl_log_file(dbenv, lsn, namep, len)); +#endif + + PANIC_CHECK(dbenv); + ENV_REQUIRES_CONFIG(dbenv, dbenv->lg_handle, DB_INIT_LOG); + + dblp = dbenv->lg_handle; + R_LOCK(dbenv, &dblp->reginfo); + ret = __log_name(dblp, lsn->file, &name, NULL, 0); + R_UNLOCK(dbenv, &dblp->reginfo); + if (ret != 0) + return (ret); + + /* Check to make sure there's enough room and copy the name. */ + if (len < strlen(name) + 1) { + *namep = '\0'; + __db_err(dbenv, "log_file: name buffer is too short"); + return (EINVAL); + } + (void)strcpy(namep, name); + __os_freestr(name); + + return (0); +} + +/* + * __log_newfh -- + * Acquire a file handle for the current log file. + */ +static int +__log_newfh(dblp) + DB_LOG *dblp; +{ + LOG *lp; + int ret; + char *name; + + /* Close any previous file descriptor. */ + if (F_ISSET(&dblp->lfh, DB_FH_VALID)) + (void)__os_closehandle(&dblp->lfh); + + /* Get the path of the new file and open it. */ + lp = dblp->reginfo.primary; + dblp->lfname = lp->lsn.file; + + /* + * Adding DB_OSO_LOG to the flags may add additional platform-specific + * optimizations. On WinNT, the logfile is preallocated, which may + * have a time penalty at startup, but have better overall throughput. + * We are not certain that this works reliably, so enable at your own + * risk. + * + * XXX: + * Initialize the log file size. This is a hack to push the log's + * maximum size down into the Windows __os_open routine, because it + * wants to pre-allocate it. + */ + dblp->lfh.log_size = dblp->dbenv->lg_max; + if ((ret = __log_name(dblp, dblp->lfname, + &name, &dblp->lfh, + DB_OSO_CREATE |/* DB_OSO_LOG |*/ DB_OSO_SEQ)) != 0) + __db_err(dblp->dbenv, + "log_put: %s: %s", name, db_strerror(ret)); + + __os_freestr(name); + return (ret); +} + +/* + * __log_name -- + * Return the log name for a particular file, and optionally open it. + * + * PUBLIC: int __log_name __P((DB_LOG *, + * PUBLIC: u_int32_t, char **, DB_FH *, u_int32_t)); + */ +int +__log_name(dblp, filenumber, namep, fhp, flags) + DB_LOG *dblp; + u_int32_t filenumber, flags; + char **namep; + DB_FH *fhp; +{ + LOG *lp; + int ret; + char *oname; + char old[sizeof(LFPREFIX) + 5 + 20], new[sizeof(LFPREFIX) + 10 + 20]; + + lp = dblp->reginfo.primary; + + /* + * !!! + * The semantics of this routine are bizarre. + * + * The reason for all of this is that we need a place where we can + * intercept requests for log files, and, if appropriate, check for + * both the old-style and new-style log file names. The trick is + * that all callers of this routine that are opening the log file + * read-only want to use an old-style file name if they can't find + * a match using a new-style name. The only down-side is that some + * callers may check for the old-style when they really don't need + * to, but that shouldn't mess up anything, and we only check for + * the old-style name when we've already failed to find a new-style + * one. + * + * Create a new-style file name, and if we're not going to open the + * file, return regardless. + */ + (void)snprintf(new, sizeof(new), LFNAME, filenumber); + if ((ret = __db_appname(dblp->dbenv, + DB_APP_LOG, NULL, new, 0, NULL, namep)) != 0 || fhp == NULL) + return (ret); + + /* Open the new-style file -- if we succeed, we're done. */ + if ((ret = __os_open(dblp->dbenv, + *namep, flags, lp->persist.mode, fhp)) == 0) + return (0); + + /* + * The open failed... if the DB_RDONLY flag isn't set, we're done, + * the caller isn't interested in old-style files. + */ + if (!LF_ISSET(DB_OSO_RDONLY)) { + __db_err(dblp->dbenv, + "%s: log file open failed: %s", *namep, db_strerror(ret)); + return (__db_panic(dblp->dbenv, ret)); + } + + /* Create an old-style file name. */ + (void)snprintf(old, sizeof(old), LFNAME_V1, filenumber); + if ((ret = __db_appname(dblp->dbenv, + DB_APP_LOG, NULL, old, 0, NULL, &oname)) != 0) + goto err; + + /* + * Open the old-style file -- if we succeed, we're done. Free the + * space allocated for the new-style name and return the old-style + * name to the caller. + */ + if ((ret = __os_open(dblp->dbenv, + oname, flags, lp->persist.mode, fhp)) == 0) { + __os_freestr(*namep); + *namep = oname; + return (0); + } + + /* + * Couldn't find either style of name -- return the new-style name + * for the caller's error message. If it's an old-style name that's + * actually missing we're going to confuse the user with the error + * message, but that implies that not only were we looking for an + * old-style name, but we expected it to exist and we weren't just + * looking for any log file. That's not a likely error. + */ +err: __os_freestr(oname); + return (ret); +} + +static int +__log_open_files(dbenv) + DB_ENV *dbenv; +{ + DB_LOG *dblp; + DB_LSN r_unused; + DBT fid_dbt, t; + FNAME *fnp; + LOG *lp; + int ret; + + dblp = dbenv->lg_handle; + lp = dblp->reginfo.primary; + + for (fnp = SH_TAILQ_FIRST(&lp->fq, __fname); + fnp != NULL; fnp = SH_TAILQ_NEXT(fnp, q, __fname)) { + if (fnp->ref == 0) /* Entry not in use. */ + continue; + if (fnp->name_off != INVALID_ROFF) { + memset(&t, 0, sizeof(t)); + t.data = R_ADDR(&dblp->reginfo, fnp->name_off); + t.size = strlen(t.data) + 1; + } + memset(&fid_dbt, 0, sizeof(fid_dbt)); + fid_dbt.data = fnp->ufid; + fid_dbt.size = DB_FILE_ID_LEN; + /* + * Output LOG_CHECKPOINT records which will be + * processed during the OPENFILES pass of recovery. + * At the end of recovery we want to output the + * files that were open so that a future recovery + * run will have the correct files open during + * a backward pass. For this we output LOG_CLOSE + * records so that the files will be closed on + * the forward pass. + */ + if ((ret = __log_register_log(dbenv, + NULL, &r_unused, 0, + F_ISSET(dblp, DBLOG_RECOVER) ? LOG_CLOSE : LOG_CHECKPOINT, + fnp->name_off == INVALID_ROFF ? NULL : &t, + &fid_dbt, fnp->id, fnp->s_type, fnp->meta_pgno)) != 0) + return (ret); + } + return (0); +} diff --git a/db/log/log_rec.c b/db/log/log_rec.c new file mode 100644 index 000000000..a87184829 --- /dev/null +++ b/db/log/log_rec.c @@ -0,0 +1,621 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1995, 1996 + * The President and Fellows of Harvard University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: log_rec.c,v 11.48 2001/01/11 18:19:53 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_am.h" +#include "log.h" + +static int __log_do_open __P((DB_ENV *, DB_LOG *, + u_int8_t *, char *, DBTYPE, int32_t, db_pgno_t)); +static int __log_open_file __P((DB_ENV *, DB_LOG *, __log_register_args *)); + +/* + * PUBLIC: int __log_register_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__log_register_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + DB_ENTRY *dbe; + DB_LOG *logp; + DB *dbp; + __log_register_args *argp; + int do_rem, ret, t_ret; + + logp = dbenv->lg_handle; + dbp = NULL; + +#ifdef DEBUG_RECOVER + REC_PRINT(__log_register_print); +#endif + COMPQUIET(lsnp, NULL); + + if ((ret = __log_register_read(dbenv, dbtp->data, &argp)) != 0) + goto out; + + if ((argp->opcode == LOG_OPEN && + (DB_REDO(op) || op == DB_TXN_OPENFILES)) || + (argp->opcode == LOG_CLOSE && DB_UNDO(op))) { + /* + * If we are redoing an open or undoing a close, then we need + * to open a file. We must open the file even if + * the meta page is not yet written as we may be creating it. + */ + if (op == DB_TXN_OPENFILES) + F_SET(logp, DBLOG_FORCE_OPEN); + ret = __log_open_file(dbenv, logp, argp); + F_CLR(logp, DBLOG_FORCE_OPEN); + if (ret == ENOENT || ret == EINVAL) { + if (op == DB_TXN_OPENFILES && argp->name.size != 0 && + (ret = __db_txnlist_delete(dbenv, info, + argp->name.data, argp->fileid, 0)) != 0) + goto out; + ret = 0; + } + } else if (argp->opcode != LOG_CHECKPOINT) { + /* + * If we are undoing an open, then we need to close the file. + * + * If the file is deleted, then we can just ignore this close. + * Otherwise, we should usually have a valid dbp we should + * close or whose reference count should be decremented. + * However, if we shut down without closing a file, we may, in + * fact, not have the file open, and that's OK. + */ + do_rem = 0; + MUTEX_THREAD_LOCK(dbenv, logp->mutexp); + if (argp->fileid < logp->dbentry_cnt) { + dbe = &logp->dbentry[argp->fileid]; + + DB_ASSERT(dbe->refcount == 1); + + ret = __db_txnlist_close(info, + argp->fileid, dbe->count); + if ((dbp = TAILQ_FIRST(&dbe->dblist)) != NULL) + (void)log_unregister(dbenv, dbp); + do_rem = 1; + } + MUTEX_THREAD_UNLOCK(dbenv, logp->mutexp); + if (do_rem) { + (void)__log_rem_logid(logp, dbp, argp->fileid); + /* + * If remove or rename has closed the file, don't + * sync. + */ + if (dbp != NULL && + (t_ret = dbp->close(dbp, + dbp->mpf == NULL ? DB_NOSYNC : 0)) != 0 && ret == 0) + ret = t_ret; + } + } else if (DB_UNDO(op) || op == DB_TXN_OPENFILES) { + /* + * It's a checkpoint and we are rolling backward. It + * is possible that the system was shut down and thus + * ended with a stable checkpoint; this file was never + * closed and has therefore not been reopened yet. If + * so, we need to try to open it. + */ + ret = __log_open_file(dbenv, logp, argp); + if (ret == ENOENT || ret == EINVAL) { + if (argp->name.size != 0 && (ret = + __db_txnlist_delete(dbenv, info, + argp->name.data, argp->fileid, 0)) != 0) + goto out; + ret = 0; + } + } + +out: if (argp != NULL) + __os_free(argp, 0); + return (ret); +} + +/* + * __log_open_file -- + * Called during log_register recovery. Make sure that we have an + * entry in the dbentry table for this ndx. Returns 0 on success, + * non-zero on error. + */ +static int +__log_open_file(dbenv, lp, argp) + DB_ENV *dbenv; + DB_LOG *lp; + __log_register_args *argp; +{ + DB_ENTRY *dbe; + DB *dbp; + + /* + * We never re-open temporary files. Temp files are only + * useful during aborts in which case the dbp was entered + * when the file was registered. During recovery, we treat + * temp files as properly deleted files, allowing the open to + * fail and not reporting any errors when recovery fails to + * get a valid dbp from db_fileid_to_db. + */ + if (argp->name.size == 0) { + (void)__log_add_logid(dbenv, lp, NULL, argp->fileid); + return (ENOENT); + } + + /* + * Because of reference counting, we cannot automatically close files + * during recovery, so when we're opening, we have to check that the + * name we are opening is what we expect. If it's not, then we close + * the old file and open the new one. + */ + MUTEX_THREAD_LOCK(dbenv, lp->mutexp); + if (argp->fileid < lp->dbentry_cnt) + dbe = &lp->dbentry[argp->fileid]; + else + dbe = NULL; + + if (dbe != NULL) { + dbe->deleted = 0; + if ((dbp = TAILQ_FIRST(&dbe->dblist)) != NULL) { + if (dbp->meta_pgno != argp->meta_pgno || + memcmp(dbp->fileid, + argp->uid.data, DB_FILE_ID_LEN) != 0) { + MUTEX_THREAD_UNLOCK(dbenv, lp->mutexp); + goto reopen; + } + if (!F_ISSET(lp, DBLOG_RECOVER)) + dbe->refcount++; + MUTEX_THREAD_UNLOCK(dbenv, lp->mutexp); + return (0); + } + } + + MUTEX_THREAD_UNLOCK(dbenv, lp->mutexp); + if (0) { +reopen: (void)log_unregister(dbp->dbenv, dbp); + (void)__log_rem_logid(lp, dbp, argp->fileid); + dbp->close(dbp, 0); + } + + return (__log_do_open(dbenv, lp, + argp->uid.data, argp->name.data, + argp->ftype, argp->fileid, argp->meta_pgno)); +} + +/* + * log_reopen_file -- close and reopen a db file. + * Must be called when a metadata page changes. + * + * PUBLIC: int __log_reopen_file __P((DB_ENV *, + * PUBLIC: char *, int32_t, u_int8_t *, db_pgno_t)); + * + */ +int +__log_reopen_file(dbenv, name, ndx, fileid, meta_pgno) + DB_ENV *dbenv; + char *name; + int32_t ndx; + u_int8_t *fileid; + db_pgno_t meta_pgno; +{ + DB *dbp; + DB_LOG *logp; + DBTYPE ftype; + FNAME *fnp; + LOG *lp; + char *tmp_name; + int ret; + + logp = dbenv->lg_handle; + + if (name == NULL) { + R_LOCK(dbenv, &logp->reginfo); + + lp = logp->reginfo.primary; + + for (fnp = SH_TAILQ_FIRST(&lp->fq, __fname); + fnp != NULL; fnp = SH_TAILQ_NEXT(fnp, q, __fname)) { + if (fnp->ref == 0) /* Entry not in use. */ + continue; + if (memcmp(fnp->ufid, fileid, DB_FILE_ID_LEN) == 0) + break; + } + + if (fnp == 0 || fnp->name_off == INVALID_ROFF) { + __db_err(dbenv, + "metasub recover: non-existent file id"); + return (EINVAL); + } + + name = R_ADDR(&logp->reginfo, fnp->name_off); + ret = __os_strdup(dbenv, name, &tmp_name); + R_UNLOCK(dbenv, &logp->reginfo); + if (ret != 0) + goto out; + name = tmp_name; + } else + tmp_name = NULL; + + if ((ret = __db_fileid_to_db(dbenv, &dbp, ndx, 0)) != 0) + goto out; + ftype = dbp->type; + (void)log_unregister(dbenv, dbp); + (void)__log_rem_logid(logp, dbp, ndx); + (void)dbp->close(dbp, 0); + + ret = __log_do_open(dbenv, logp, fileid, name, ftype, ndx, meta_pgno); + + if (tmp_name != NULL) + __os_free(tmp_name, 0); + +out: return (ret); +} + +/* + * __log_do_open -- + * Open files referenced in the log. This is the part of the open that + * is not protected by the thread mutex. + */ +static int +__log_do_open(dbenv, lp, uid, name, ftype, ndx, meta_pgno) + DB_ENV *dbenv; + DB_LOG *lp; + u_int8_t *uid; + char *name; + DBTYPE ftype; + int32_t ndx; + db_pgno_t meta_pgno; +{ + DB *dbp; + int ret; + u_int8_t zeroid[DB_FILE_ID_LEN]; + + if ((ret = db_create(&dbp, lp->dbenv, 0)) != 0) + return (ret); + + dbp->log_fileid = ndx; + + /* + * This is needed to signal to the locking routines called while + * opening databases that we are potentially undoing a transaction + * from an XA process. Since the XA process does not share + * locks with the aborting transaction this prevents us from + * deadlocking during the open during rollback. + * Because this routine is called either during recovery or during an + * XA_ABORT, we can safely set DB_AM_RECOVER in the dbp since it + * will not be shared with other threads. + */ + F_SET(dbp, DB_AM_RECOVER); + if (meta_pgno != PGNO_BASE_MD) + memcpy(dbp->fileid, uid, DB_FILE_ID_LEN); + dbp->type = ftype; + if ((ret = + __db_dbopen(dbp, name, 0, __db_omode("rw----"), meta_pgno)) == 0) { + /* + * Verify that we are opening the same file that we were + * referring to when we wrote this log record. + */ + if (memcmp(uid, dbp->fileid, DB_FILE_ID_LEN) != 0) { + memset(zeroid, 0, DB_FILE_ID_LEN); + if (memcmp(dbp->fileid, zeroid, DB_FILE_ID_LEN) != 0) + goto not_right; + memcpy(dbp->fileid, uid, DB_FILE_ID_LEN); + } + if (IS_RECOVERING(dbenv)) { + (void)log_register(dbp->dbenv, dbp, name); + (void)__log_add_logid(dbenv, lp, dbp, ndx); + } + return (0); + } + +not_right: + (void)dbp->close(dbp, 0); + (void)__log_add_logid(dbenv, lp, NULL, ndx); + + return (ENOENT); +} + +/* + * __log_add_logid -- + * Adds a DB entry to the log's DB entry table. + * + * PUBLIC: int __log_add_logid __P((DB_ENV *, DB_LOG *, DB *, int32_t)); + */ +int +__log_add_logid(dbenv, logp, dbp, ndx) + DB_ENV *dbenv; + DB_LOG *logp; + DB *dbp; + int32_t ndx; +{ + DB *dbtmp; + int32_t i; + int ret; + + ret = 0; + + MUTEX_THREAD_LOCK(dbenv, logp->mutexp); + + /* + * Check if we need to grow the table. Note, ndx is 0-based (the + * index into the DB entry table) an dbentry_cnt is 1-based, the + * number of available slots. + */ + if (logp->dbentry_cnt <= ndx) { + if ((ret = __os_realloc(dbenv, + (ndx + DB_GROW_SIZE) * sizeof(DB_ENTRY), + NULL, &logp->dbentry)) != 0) + goto err; + + /* + * We have moved the head of the queue. + * Fix up the queue header of an empty queue or the previous + * pointer of the first element. + */ + for (i = 0; i < logp->dbentry_cnt; i++) { + if ((dbtmp = + TAILQ_FIRST(&logp->dbentry[i].dblist)) == NULL) + TAILQ_INIT(&logp->dbentry[i].dblist); + else + TAILQ_REINSERT_HEAD( + &logp->dbentry[i].dblist, dbp, links); + } + + /* Initialize the new entries. */ + for (i = logp->dbentry_cnt; i < ndx + DB_GROW_SIZE; i++) { + logp->dbentry[i].count = 0; + TAILQ_INIT(&logp->dbentry[i].dblist); + logp->dbentry[i].deleted = 0; + logp->dbentry[i].refcount = 0; + } + + logp->dbentry_cnt = i; + } + + if (logp->dbentry[ndx].deleted == 0 && + TAILQ_FIRST(&logp->dbentry[ndx].dblist) == NULL) { + logp->dbentry[ndx].count = 0; + if (dbp != NULL) + TAILQ_INSERT_HEAD(&logp->dbentry[ndx].dblist, + dbp, links); + logp->dbentry[ndx].deleted = dbp == NULL; + logp->dbentry[ndx].refcount = 1; + } else if (!F_ISSET(logp, DBLOG_RECOVER)) { + if (dbp != NULL) + TAILQ_INSERT_HEAD(&logp->dbentry[ndx].dblist, + dbp, links); + logp->dbentry[ndx].refcount++; + } + +err: MUTEX_THREAD_UNLOCK(dbenv, logp->mutexp); + return (ret); +} + +/* + * __db_fileid_to_db -- + * Return the DB corresponding to the specified fileid. + * + * PUBLIC: int __db_fileid_to_db __P((DB_ENV *, DB **, int32_t, int)); + */ +int +__db_fileid_to_db(dbenv, dbpp, ndx, inc) + DB_ENV *dbenv; + DB **dbpp; + int32_t ndx; + int inc; +{ + DB_LOG *logp; + DB *dbp; + FNAME *fname; + int ret; + char *name; + + ret = 0; + logp = dbenv->lg_handle; + + MUTEX_THREAD_LOCK(dbenv, logp->mutexp); + + /* + * Under XA, a process different than the one issuing DB operations + * may abort a transaction. In this case, recovery routines are run + * by a process that does not necessarily have the file open, so we + * we must open the file explicitly. + */ + if (ndx >= logp->dbentry_cnt || + (!logp->dbentry[ndx].deleted && + (dbp = TAILQ_FIRST(&logp->dbentry[ndx].dblist)) == NULL)) { + if (F_ISSET(logp, DBLOG_RECOVER)) { + ret = ENOENT; + goto err; + } + if (__log_lid_to_fname(logp, ndx, &fname) != 0) { + /* Couldn't find entry; this is a fatal error. */ + __db_err(dbenv, "Missing log fileid entry"); + ret = EINVAL; + goto err; + } + name = R_ADDR(&logp->reginfo, fname->name_off); + + /* + * __log_do_open is called without protection of the + * log thread lock. + */ + MUTEX_THREAD_UNLOCK(dbenv, logp->mutexp); + + /* + * At this point, we are not holding the thread lock, so exit + * directly instead of going through the exit code at the + * bottom. If the __log_do_open succeeded, then we don't need + * to do any of the remaining error checking at the end of this + * routine. + */ + if ((ret = __log_do_open(dbenv, logp, + fname->ufid, name, fname->s_type, + ndx, fname->meta_pgno)) != 0) + return (ret); + + *dbpp = TAILQ_FIRST(&logp->dbentry[ndx].dblist); + return (0); + } + + /* + * Return DB_DELETED if the file has been deleted (it's not an error). + */ + if (logp->dbentry[ndx].deleted) { + ret = DB_DELETED; + if (inc) + logp->dbentry[ndx].count++; + goto err; + } + + /* + * Otherwise return 0, but if we don't have a corresponding DB, it's + * an error. + */ + if ((*dbpp = TAILQ_FIRST(&logp->dbentry[ndx].dblist)) == NULL) + ret = ENOENT; + +err: MUTEX_THREAD_UNLOCK(dbenv, logp->mutexp); + return (ret); +} + +/* + * __log_close_files -- + * Close files that were opened by the recovery daemon. We sync the + * file, unless its mpf pointer has been NULLed by a db_remove or + * db_rename. We may not have flushed the log_register record that + * closes the file. + * + * PUBLIC: void __log_close_files __P((DB_ENV *)); + */ +void +__log_close_files(dbenv) + DB_ENV *dbenv; +{ + DB_ENTRY *dbe; + DB_LOG *logp; + DB *dbp; + int32_t i; + + logp = dbenv->lg_handle; + MUTEX_THREAD_LOCK(dbenv, logp->mutexp); + for (i = 0; i < logp->dbentry_cnt; i++) { + dbe = &logp->dbentry[i]; + while ((dbp = TAILQ_FIRST(&dbe->dblist)) != NULL) { + (void)log_unregister(dbenv, dbp); + TAILQ_REMOVE(&dbe->dblist, dbp, links); + (void)dbp->close(dbp, dbp->mpf == NULL ? DB_NOSYNC : 0); + } + dbe->deleted = 0; + dbe->refcount = 0; + } + MUTEX_THREAD_UNLOCK(dbenv, logp->mutexp); +} + +/* + * __log_rem_logid + * Remove an entry from the log table. Find the appropriate DB and + * unlink it from the linked list off the table. If the DB is NULL, treat + * this as a simple refcount decrement. + * + * PUBLIC: void __log_rem_logid __P((DB_LOG *, DB *, int32_t)); + */ +void +__log_rem_logid(logp, dbp, ndx) + DB_LOG *logp; + DB *dbp; + int32_t ndx; +{ + DB *xdbp; + + MUTEX_THREAD_LOCK(logp->dbenv, logp->mutexp); + if (--logp->dbentry[ndx].refcount == 0) { + TAILQ_INIT(&logp->dbentry[ndx].dblist); + logp->dbentry[ndx].deleted = 0; + } else if (dbp != NULL) + for (xdbp = TAILQ_FIRST(&logp->dbentry[ndx].dblist); + xdbp != NULL; + xdbp = TAILQ_NEXT(xdbp, links)) + if (xdbp == dbp) { + TAILQ_REMOVE(&logp->dbentry[ndx].dblist, + xdbp, links); + break; + } + + MUTEX_THREAD_UNLOCK(logp->dbenv, logp->mutexp); +} + +/* + * __log_lid_to_fname -- + * Traverse the shared-memory region looking for the entry that + * matches the passed log fileid. Returns 0 on success; -1 on error. + * PUBLIC: int __log_lid_to_fname __P((DB_LOG *, int32_t, FNAME **)); + */ +int +__log_lid_to_fname(dblp, lid, fnamep) + DB_LOG *dblp; + int32_t lid; + FNAME **fnamep; +{ + FNAME *fnp; + LOG *lp; + + lp = dblp->reginfo.primary; + + for (fnp = SH_TAILQ_FIRST(&lp->fq, __fname); + fnp != NULL; fnp = SH_TAILQ_NEXT(fnp, q, __fname)) { + if (fnp->ref == 0) /* Entry not in use. */ + continue; + if (fnp->id == lid) { + *fnamep = fnp; + return (0); + } + } + return (-1); +} diff --git a/db/log/log_register.c b/db/log/log_register.c new file mode 100644 index 000000000..1e0e523d8 --- /dev/null +++ b/db/log/log_register.c @@ -0,0 +1,433 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: log_register.c,v 11.35 2001/01/10 16:04:19 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#ifdef HAVE_RPC +#include "db_server.h" +#endif + +#include "db_int.h" +#include "log.h" + +#ifdef HAVE_RPC +#include "gen_client_ext.h" +#include "rpc_client_ext.h" +#endif + +/* + * log_register -- + * Register a file name. + */ +int +log_register(dbenv, dbp, name) + DB_ENV *dbenv; + DB *dbp; + const char *name; +{ + DBT fid_dbt, r_name; + DB_LOG *dblp; + DB_LSN r_unused; + FNAME *found_fnp, *fnp, *recover_fnp, *reuse_fnp; + LOG *lp; + size_t len; + int32_t maxid; + int inserted, ok, ret; + void *namep; + +#ifdef HAVE_RPC + if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) + return (__dbcl_log_register(dbenv, dbp, name)); +#endif + + PANIC_CHECK(dbenv); + ENV_REQUIRES_CONFIG(dbenv, dbenv->lg_handle, DB_INIT_LOG); + + dblp = dbenv->lg_handle; + lp = dblp->reginfo.primary; + fnp = reuse_fnp = NULL; + inserted = ret = 0; + namep = NULL; + + /* Check the arguments. */ + if (dbp->type != DB_BTREE && dbp->type != DB_QUEUE && + dbp->type != DB_HASH && dbp->type != DB_RECNO) { + __db_err(dbenv, "log_register: unknown DB file type"); + return (EINVAL); + } + + R_LOCK(dbenv, &dblp->reginfo); + + /* + * See if we've already got this file in the log, finding the + * (maximum+1) in-use file id and some available file id (if we + * find an available fid, we'll use it, else we'll have to allocate + * one after the maximum that we found). + */ + ok = 0; + found_fnp = recover_fnp = NULL; + for (maxid = 0, fnp = SH_TAILQ_FIRST(&lp->fq, __fname); + fnp != NULL; fnp = SH_TAILQ_NEXT(fnp, q, __fname)) { + if (F_ISSET(dblp, DBLOG_RECOVER) && fnp->id == dbp->log_fileid) + recover_fnp = fnp; + if (fnp->ref == 0) { /* Entry is not in use. */ + if (reuse_fnp == NULL) + reuse_fnp = fnp; + continue; + } + if (memcmp(dbp->fileid, fnp->ufid, DB_FILE_ID_LEN) == 0) { + if (fnp->meta_pgno == 0) { + if (fnp->locked == 1) { + __db_err(dbenv, "File is locked"); + return (EINVAL); + } + if (found_fnp != NULL) { + fnp = found_fnp; + goto found; + } + ok = 1; + } + if (dbp->meta_pgno == fnp->meta_pgno) { + if (F_ISSET(dblp, DBLOG_RECOVER)) { + if (fnp->id != dbp->log_fileid) { + /* + * If we are in recovery, there + * is only one dbp on the list. + * If the refcount goes to 0, + * we will clear the list. If + * it doesn't, we want to leave + * the dbp where it is, so + * passing a NULL to rem_logid + * is correct. + */ + __log_rem_logid(dblp, + NULL, fnp->id); + if (recover_fnp != NULL) + break; + continue; + } + fnp->ref = 1; + goto found; + } + ++fnp->ref; + if (ok) + goto found; + found_fnp = fnp; + } + } + if (maxid <= fnp->id) + maxid = fnp->id + 1; + } + if ((fnp = found_fnp) != NULL) + goto found; + + /* Fill in fnp structure. */ + if (recover_fnp != NULL) /* This has the right number */ + fnp = recover_fnp; + else if (reuse_fnp != NULL) /* Reuse existing one. */ + fnp = reuse_fnp; + else { /* Allocate a new one. */ + if ((ret = __db_shalloc(dblp->reginfo.addr, + sizeof(FNAME), 0, &fnp)) != 0) + goto mem_err; + fnp->id = maxid; + } + + if (F_ISSET(dblp, DBLOG_RECOVER)) + fnp->id = dbp->log_fileid; + + fnp->ref = 1; + fnp->locked = 0; + fnp->s_type = dbp->type; + memcpy(fnp->ufid, dbp->fileid, DB_FILE_ID_LEN); + fnp->meta_pgno = dbp->meta_pgno; + + if (name != NULL) { + len = strlen(name) + 1; + if ((ret = + __db_shalloc(dblp->reginfo.addr, len, 0, &namep)) != 0) { +mem_err: __db_err(dbenv, + "Unable to allocate memory to register %s", name); + goto err; + } + fnp->name_off = R_OFFSET(&dblp->reginfo, namep); + memcpy(namep, name, len); + } else + fnp->name_off = INVALID_ROFF; + + /* Only do the insert if we allocated a new fnp. */ + if (reuse_fnp == NULL && recover_fnp == NULL) + SH_TAILQ_INSERT_HEAD(&lp->fq, fnp, q, __fname); + inserted = 1; + + /* Log the registry. */ + if (!F_ISSET(dblp, DBLOG_RECOVER)) { + /* + * We allow logging on in-memory databases, so the name here + * could be NULL. + */ + if (name != NULL) { + r_name.data = (void *)name; + r_name.size = strlen(name) + 1; + } + memset(&fid_dbt, 0, sizeof(fid_dbt)); + fid_dbt.data = dbp->fileid; + fid_dbt.size = DB_FILE_ID_LEN; + if ((ret = __log_register_log(dbenv, NULL, &r_unused, + 0, LOG_OPEN, name == NULL ? NULL : &r_name, + &fid_dbt, fnp->id, dbp->type, dbp->meta_pgno)) != 0) + goto err; + } + +found: /* + * If we found the entry in the shared area, then the file is + * already open, so there is no need to log the open. We only + * log the open and closes on the first open and last close. + */ + if (!F_ISSET(dblp, DBLOG_RECOVER) && + (ret = __log_add_logid(dbenv, dblp, dbp, fnp->id)) != 0) + goto err; + + if (!F_ISSET(dblp, DBLOG_RECOVER)) + dbp->log_fileid = fnp->id; + + if (0) { +err: if (inserted) + SH_TAILQ_REMOVE(&lp->fq, fnp, q, __fname); + if (namep != NULL) + __db_shalloc_free(dblp->reginfo.addr, namep); + if (fnp != NULL) + __db_shalloc_free(dblp->reginfo.addr, fnp); + } + + R_UNLOCK(dbenv, &dblp->reginfo); + + return (ret); +} + +/* + * log_unregister -- + * Discard a registered file name. + */ +int +log_unregister(dbenv, dbp) + DB_ENV *dbenv; + DB *dbp; +{ + int ret; + +#ifdef HAVE_RPC + if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) + return (__dbcl_log_unregister(dbenv, dbp)); +#endif + + PANIC_CHECK(dbenv); + ENV_REQUIRES_CONFIG(dbenv, dbenv->lg_handle, DB_INIT_LOG); + + ret = __log_filelist_update(dbenv, dbp, dbp->log_fileid, NULL, NULL); + dbp->log_fileid = DB_LOGFILEID_INVALID; + return (ret); +} + +/* + * PUBLIC: int __log_filelist_update + * PUBLIC: __P((DB_ENV *, DB *, int32_t, const char *, int *)); + * + * Utility player for updating and logging the file list. Called + * for 3 reasons: + * 1) mark file closed: newname == NULL. + * 2) change filename: newname != NULL. + * 3) from recovery to verify & change filename if necessary, set != NULL. + */ +int +__log_filelist_update(dbenv, dbp, fid, newname, set) + DB_ENV *dbenv; + DB *dbp; + int32_t fid; + const char *newname; + int *set; +{ + DBT fid_dbt, r_name; + DB_LOG *dblp; + DB_LSN r_unused; + FNAME *fnp; + LOG *lp; + u_int32_t len, newlen; + int ret; + void *namep; + + ret = 0; + dblp = dbenv->lg_handle; + lp = dblp->reginfo.primary; + + R_LOCK(dbenv, &dblp->reginfo); + + /* Find the entry in the log. */ + for (fnp = SH_TAILQ_FIRST(&lp->fq, __fname); + fnp != NULL; fnp = SH_TAILQ_NEXT(fnp, q, __fname)) + if (fid == fnp->id) + break; + if (fnp == NULL) { + __db_err(dbenv, "log_unregister: non-existent file id"); + ret = EINVAL; + goto ret1; + } + + /* + * Log the unregistry only if this is the last one and we are + * really closing the file or if this is an abort of a created + * file and we need to make sure there is a record in the log. + */ + namep = NULL; + len = 0; + if (fnp->name_off != INVALID_ROFF) { + namep = R_ADDR(&dblp->reginfo, fnp->name_off); + len = strlen(namep) + 1; + } + if (!F_ISSET(dblp, DBLOG_RECOVER) && fnp->ref == 1) { + if (namep != NULL) { + memset(&r_name, 0, sizeof(r_name)); + r_name.data = namep; + r_name.size = len; + } + memset(&fid_dbt, 0, sizeof(fid_dbt)); + fid_dbt.data = fnp->ufid; + fid_dbt.size = DB_FILE_ID_LEN; + if ((ret = __log_register_log(dbenv, NULL, &r_unused, + 0, LOG_CLOSE, + fnp->name_off == INVALID_ROFF ? NULL : &r_name, + &fid_dbt, fid, fnp->s_type, fnp->meta_pgno)) + != 0) + goto ret1; + } + + /* + * If we are changing the name we must log this fact. + */ + if (newname != NULL) { + DB_ASSERT(fnp->ref == 1); + newlen = strlen(newname) + 1; + if (!F_ISSET(dblp, DBLOG_RECOVER)) { + r_name.data = (void *) newname; + r_name.size = newlen; + if ((ret = __log_register_log(dbenv, + NULL, &r_unused, 0, LOG_OPEN, &r_name, &fid_dbt, + fnp->id, fnp->s_type, fnp->meta_pgno)) != 0) + goto ret1; + } + + /* + * Check to see if the name is already correct. + */ + if (set != NULL) { + if (len != newlen || memcmp(namep, newname, len) != 0) + *set = 1; + else { + *set = 0; + goto ret1; + } + } + + /* + * Change the name, realloc memory if necessary + */ + if (len < newlen) { + __db_shalloc_free(dblp->reginfo.addr, + R_ADDR(&dblp->reginfo, fnp->name_off)); + if ((ret = __db_shalloc( + dblp->reginfo.addr, newlen, 0, &namep)) != 0) { + __db_err(dbenv, + "Unable to allocate memory to register %s", + newname); + goto ret1; + } + fnp->name_off = R_OFFSET(&dblp->reginfo, namep); + } else + namep = R_ADDR(&dblp->reginfo, fnp->name_off); + memcpy(namep, newname, newlen); + } else { + + /* + * If more than 1 reference, just decrement the reference + * and return. Otherwise, free the name if one exists. + */ + DB_ASSERT(fnp->ref >= 1); + --fnp->ref; + if (fnp->ref == 0) { + if (fnp->name_off != INVALID_ROFF) + __db_shalloc_free(dblp->reginfo.addr, + R_ADDR(&dblp->reginfo, fnp->name_off)); + fnp->name_off = INVALID_ROFF; + } + + /* + * Remove from the process local table. If this + * operation is taking place during recovery, then + * the logid was never added to the table, so do not remove it. + */ + if (!F_ISSET(dblp, DBLOG_RECOVER)) + __log_rem_logid(dblp, dbp, fid); + } + +ret1: R_UNLOCK(dbenv, &dblp->reginfo); + return (ret); +} + +/* + * __log_file_lock -- lock a file for single access + * This only works if logging is on. + * + * PUBLIC: int __log_file_lock __P((DB *)); + */ +int +__log_file_lock(dbp) + DB *dbp; +{ + DB_ENV *dbenv; + DB_LOG *dblp; + FNAME *fnp; + LOG *lp; + int ret; + + dbenv = dbp->dbenv; + dblp = dbenv->lg_handle; + lp = dblp->reginfo.primary; + + ret = 0; + R_LOCK(dbenv, &dblp->reginfo); + + for (fnp = SH_TAILQ_FIRST(&lp->fq, __fname); + fnp != NULL; fnp = SH_TAILQ_NEXT(fnp, q, __fname)) { + if (fnp->ref == 0) + continue; + + if (!memcmp(dbp->fileid, fnp->ufid, DB_FILE_ID_LEN)) { + if (fnp->meta_pgno == 0) { + if (fnp->ref != 1) + goto err; + + fnp->locked = 1; + } else { +err: __db_err(dbp->dbenv, "File is open"); + ret = EINVAL; + goto done; + } + + } + } +done: R_UNLOCK(dbenv, &dblp->reginfo); + return (ret); +} diff --git a/db/mp/Design b/db/mp/Design new file mode 100644 index 000000000..1b26aae6c --- /dev/null +++ b/db/mp/Design @@ -0,0 +1,52 @@ +$Id: Design,v 11.2 1999/11/21 23:08:27 bostic Exp $ + +There are three ways we do locking in the mpool code: + +Locking a handle mutex to provide concurrency for DB_THREAD operations. +Locking the region mutex to provide mutual exclusion while reading and + writing structures in the shared region. +Locking buffer header mutexes during I/O. + +The first will not be further described here. We use the shared mpool +region lock to provide mutual exclusion while reading/modifying all of +the data structures, including the buffer headers. We use a per-buffer +header lock to wait on buffer I/O. The order of locking is as follows: + +Searching for a buffer: + Acquire the region lock. + Find the buffer header. + Increment the reference count (guarantee the buffer stays). + While the BH_LOCKED flag is set (I/O is going on) { + Release the region lock. + Explicitly yield the processor if it's not the first pass + through this loop, otherwise, we can simply spin because + we'll be simply switching between the two locks. + Request the buffer lock. + The I/O will complete... + Acquire the buffer lock. + Release the buffer lock. + Acquire the region lock. + } + Return the buffer. + +Reading/writing a buffer: + Acquire the region lock. + Find/create the buffer header. + If reading, increment the reference count (guarantee the buffer stays). + Set the BH_LOCKED flag. + Acquire the buffer lock (guaranteed not to block). + Release the region lock. + Do the I/O and/or initialize the buffer contents. + Release the buffer lock. + At this point, the buffer lock is available, but the logical + operation (flagged by BH_LOCKED) is not yet completed. For + this reason, among others, threads checking the BH_LOCKED flag + must loop around their test. + Acquire the region lock. + Clear the BH_LOCKED flag. + Release the region lock. + Return/discard the buffer. + +Pointers to DB_MPOOL, MPOOL, DB_MPOOLFILE and MPOOLFILE structures are +not reacquired when a region lock is reacquired because they couldn't +have been closed/discarded and because they never move in memory. diff --git a/db/mp/mp_alloc.c b/db/mp/mp_alloc.c new file mode 100644 index 000000000..731f569f5 --- /dev/null +++ b/db/mp/mp_alloc.c @@ -0,0 +1,152 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: mp_alloc.c,v 11.7 2000/04/20 21:14:18 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include +#endif + +#include "db_int.h" +#include "db_shash.h" +#include "mp.h" + +/* + * __memp_alloc -- + * Allocate some space from a cache region. + * + * PUBLIC: int __memp_alloc __P((DB_MPOOL *, + * PUBLIC: REGINFO *, MPOOLFILE *, size_t, roff_t *, void *)); + */ +int +__memp_alloc(dbmp, memreg, mfp, len, offsetp, retp) + DB_MPOOL *dbmp; + REGINFO *memreg; + MPOOLFILE *mfp; + size_t len; + roff_t *offsetp; + void *retp; +{ + BH *bhp, *nbhp; + MPOOL *c_mp; + MPOOLFILE *bh_mfp; + size_t total; + int nomore, restart, ret, wrote; + void *p; + + c_mp = memreg->primary; + + /* + * If we're allocating a buffer, and the one we're discarding is the + * same size, we don't want to waste the time to re-integrate it into + * the shared memory free list. If the DB_MPOOLFILE argument isn't + * NULL, we'll compare the underlying page sizes of the two buffers + * before free-ing and re-allocating buffers. + */ + if (mfp != NULL) + len = (sizeof(BH) - sizeof(u_int8_t)) + mfp->stat.st_pagesize; + + nomore = 0; +alloc: if ((ret = __db_shalloc(memreg->addr, len, MUTEX_ALIGN, &p)) == 0) { + if (offsetp != NULL) + *offsetp = R_OFFSET(memreg, p); + *(void **)retp = p; + return (0); + } + if (nomore) { + __db_err(dbmp->dbenv, + "Unable to allocate %lu bytes from mpool shared region: %s\n", + (u_long)len, db_strerror(ret)); + return (ret); + } + +retry: /* Find a buffer we can flush; pure LRU. */ + restart = total = 0; + for (bhp = + SH_TAILQ_FIRST(&c_mp->bhq, __bh); bhp != NULL; bhp = nbhp) { + nbhp = SH_TAILQ_NEXT(bhp, q, __bh); + + /* Ignore pinned or locked (I/O in progress) buffers. */ + if (bhp->ref != 0 || F_ISSET(bhp, BH_LOCKED)) + continue; + + /* Find the associated MPOOLFILE. */ + bh_mfp = R_ADDR(dbmp->reginfo, bhp->mf_offset); + + /* Write the page if it's dirty. */ + if (F_ISSET(bhp, BH_DIRTY)) { + ++bhp->ref; + if ((ret = __memp_bhwrite(dbmp, + bh_mfp, bhp, &restart, &wrote)) != 0) + return (ret); + --bhp->ref; + + /* + * Another process may have acquired this buffer and + * incremented the ref count after we wrote it. + */ + if (bhp->ref != 0) + goto retry; + + /* + * If we wrote the page, continue and free the buffer. + * We don't have to rewalk the list to acquire the + * buffer because it was never available for any other + * process to modify it. + * + * If we didn't write the page, but we discarded and + * reacquired the region lock, restart the list walk. + * + * If we neither wrote the buffer nor discarded the + * region lock, continue down the buffer list. + */ + if (wrote) + ++c_mp->stat.st_rw_evict; + else { + if (restart) + goto retry; + continue; + } + } else + ++c_mp->stat.st_ro_evict; + + /* + * Check to see if the buffer is the size we're looking for. + * If it is, simply reuse it. + */ + if (mfp != NULL && + mfp->stat.st_pagesize == bh_mfp->stat.st_pagesize) { + __memp_bhfree(dbmp, bhp, 0); + + if (offsetp != NULL) + *offsetp = R_OFFSET(memreg, bhp); + *(void **)retp = bhp; + return (0); + } + + /* Note how much space we've freed, and free the buffer. */ + total += __db_shsizeof(bhp); + __memp_bhfree(dbmp, bhp, 1); + + /* + * Retry as soon as we've freed up sufficient space. If we + * have to coalesce of memory to satisfy the request, don't + * try until it's likely (possible?) that we'll succeed. + */ + if (total >= 3 * len) + goto alloc; + + /* Restart the walk if we discarded the region lock. */ + if (restart) + goto retry; + } + nomore = 1; + goto alloc; +} diff --git a/db/mp/mp_bh.c b/db/mp/mp_bh.c new file mode 100644 index 000000000..e802b165b --- /dev/null +++ b/db/mp/mp_bh.c @@ -0,0 +1,662 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: mp_bh.c,v 11.25 2001/01/10 04:50:53 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#endif + +#include "db_int.h" +#include "db_shash.h" +#include "mp.h" +#include "log.h" +#include "db_page.h" + +static int __memp_upgrade __P((DB_MPOOL *, DB_MPOOLFILE *, MPOOLFILE *)); + +/* + * __memp_bhwrite -- + * Write the page associated with a given bucket header. + * + * PUBLIC: int __memp_bhwrite + * PUBLIC: __P((DB_MPOOL *, MPOOLFILE *, BH *, int *, int *)); + */ +int +__memp_bhwrite(dbmp, mfp, bhp, restartp, wrotep) + DB_MPOOL *dbmp; + MPOOLFILE *mfp; + BH *bhp; + int *restartp, *wrotep; +{ + DB_MPOOLFILE *dbmfp; + DB_MPREG *mpreg; + int incremented, ret; + + if (restartp != NULL) + *restartp = 0; + if (wrotep != NULL) + *wrotep = 0; + incremented = 0; + + /* + * If the file has been removed or is a closed temporary file, Jump + * right ahead and pretend that we've found the file we want-- the + * page-write function knows how to handle the fact that we don't have + * (or need!) any real file descriptor information. + */ + if (F_ISSET(mfp, MP_DEADFILE)) { + dbmfp = NULL; + goto found; + } + + /* + * Walk the process' DB_MPOOLFILE list and find a file descriptor for + * the file. We also check that the descriptor is open for writing. + * If we find a descriptor on the file that's not open for writing, we + * try and upgrade it to make it writeable. If that fails, we're done. + */ + MUTEX_THREAD_LOCK(dbmp->dbenv, dbmp->mutexp); + for (dbmfp = TAILQ_FIRST(&dbmp->dbmfq); + dbmfp != NULL; dbmfp = TAILQ_NEXT(dbmfp, q)) + if (dbmfp->mfp == mfp) { + if (F_ISSET(dbmfp, MP_READONLY) && + __memp_upgrade(dbmp, dbmfp, mfp)) { + MUTEX_THREAD_UNLOCK(dbmp->dbenv, dbmp->mutexp); + return (0); + } + + /* + * Increment the reference count -- see the comment in + * memp_fclose(). + */ + ++dbmfp->ref; + incremented = 1; + break; + } + MUTEX_THREAD_UNLOCK(dbmp->dbenv, dbmp->mutexp); + if (dbmfp != NULL) + goto found; + + /* + * !!! + * Don't try to attach to temporary files. There are two problems in + * trying to do that. First, if we have different privileges than the + * process that "owns" the temporary file, we might create the backing + * disk file such that the owning process couldn't read/write its own + * buffers, e.g., memp_trickle() running as root creating a file owned + * as root, mode 600. Second, if the temporary file has already been + * created, we don't have any way of finding out what its real name is, + * and, even if we did, it was already unlinked (so that it won't be + * left if the process dies horribly). This decision causes a problem, + * however: if the temporary file consumes the entire buffer cache, + * and the owner doesn't flush the buffers to disk, we could end up + * with resource starvation, and the memp_trickle() thread couldn't do + * anything about it. That's a pretty unlikely scenario, though. + * + * Note that we should never get here when the temporary file + * in question has already been closed in another process, in which + * case it should be marked MP_DEADFILE. + */ + if (F_ISSET(mfp, MP_TEMP)) { + DB_ASSERT(!F_ISSET(mfp, MP_DEADFILE)); + return (0); + } + + /* + * It's not a page from a file we've opened. If the file requires + * input/output processing, see if this process has ever registered + * information as to how to write this type of file. If not, there's + * nothing we can do. + */ + if (mfp->ftype != 0) { + MUTEX_THREAD_LOCK(dbmp->dbenv, dbmp->mutexp); + for (mpreg = LIST_FIRST(&dbmp->dbregq); + mpreg != NULL; mpreg = LIST_NEXT(mpreg, q)) + if (mpreg->ftype == mfp->ftype) + break; + MUTEX_THREAD_UNLOCK(dbmp->dbenv, dbmp->mutexp); + if (mpreg == NULL) + return (0); + } + + /* + * Try and open the file, attaching to the underlying shared area. + * Ignore any error, assume it's a permissions problem. + * + * XXX + * There's no negative cache, so we may repeatedly try and open files + * that we have previously tried (and failed) to open. + */ + if (__memp_fopen(dbmp, mfp, R_ADDR(dbmp->reginfo, mfp->path_off), + 0, 0, mfp->stat.st_pagesize, 0, NULL, &dbmfp) != 0) + return (0); + +found: ret = __memp_pgwrite(dbmp, dbmfp, bhp, restartp, wrotep); + + if (incremented) { + MUTEX_THREAD_LOCK(dbmp->dbenv, dbmp->mutexp); + --dbmfp->ref; + MUTEX_THREAD_UNLOCK(dbmp->dbenv, dbmp->mutexp); + } + + return (ret); +} + +/* + * __memp_pgread -- + * Read a page from a file. + * + * PUBLIC: int __memp_pgread __P((DB_MPOOLFILE *, BH *, int)); + */ +int +__memp_pgread(dbmfp, bhp, can_create) + DB_MPOOLFILE *dbmfp; + BH *bhp; + int can_create; +{ + DB_IO db_io; + DB_ENV *dbenv; + DB_MPOOL *dbmp; + MPOOLFILE *mfp; + size_t len, pagesize; + size_t nr; + int created, ret; + + dbmp = dbmfp->dbmp; + dbenv = dbmp->dbenv; + mfp = dbmfp->mfp; + pagesize = mfp->stat.st_pagesize; + + F_SET(bhp, BH_LOCKED | BH_TRASH); + MUTEX_LOCK(dbenv, &bhp->mutex, dbenv->lockfhp); + R_UNLOCK(dbenv, dbmp->reginfo); + + /* + * Temporary files may not yet have been created. We don't create + * them now, we create them when the pages have to be flushed. + */ + nr = 0; + if (F_ISSET(&dbmfp->fh, DB_FH_VALID)) { + /* + * Ignore read errors if we have permission to create the page. + * Assume that the page doesn't exist, and that we'll create it + * when we write it out. + * + * XXX + * Theoretically, we could overwrite a page of data if it were + * possible for a file to be successfully opened for reading + * and then for the read to fail. Shouldn't ever happen, but + * it might be worth checking to see if the offset is past the + * known end-of-file. + */ + db_io.fhp = &dbmfp->fh; + db_io.mutexp = dbmfp->mutexp; + db_io.pagesize = db_io.bytes = pagesize; + db_io.pgno = bhp->pgno; + db_io.buf = bhp->buf; + + ret = __os_io(dbenv, &db_io, DB_IO_READ, &nr); + } else + ret = 0; + + created = 0; + if (nr < pagesize) { + if (can_create) + created = 1; + else { + /* + * If we had a short read, ret may be 0. This may not + * be an error -- in particular DB recovery processing + * may request pages that have never been written to + * disk, in which case we won't find the page. So, the + * caller must know how to handle the error. + */ + if (ret == 0) + ret = EIO; + goto err; + } + } + + /* + * Clear any bytes we didn't read that need to be cleared. If we're + * running in diagnostic mode, smash any bytes on the page that are + * unknown quantities for the caller. + */ + if (nr != pagesize) { + len = mfp->clear_len == 0 ? pagesize : mfp->clear_len; + if (nr < len) + memset(bhp->buf + nr, 0, len - nr); +#ifdef DIAGNOSTIC + if (nr > len) + len = nr; + if (len < pagesize) + memset(bhp->buf + len, CLEAR_BYTE, pagesize - len); +#endif + } + + /* Call any pgin function. */ + ret = mfp->ftype == 0 ? 0 : __memp_pg(dbmfp, bhp, 1); + + /* Unlock the buffer and reacquire the region lock. */ +err: MUTEX_UNLOCK(dbenv, &bhp->mutex); + R_LOCK(dbenv, dbmp->reginfo); + + /* + * If no errors occurred, the data is now valid, clear the BH_TRASH + * flag; regardless, clear the lock bit and let other threads proceed. + */ + F_CLR(bhp, BH_LOCKED); + if (ret == 0) { + F_CLR(bhp, BH_TRASH); + + /* Update the statistics. */ + if (created) + ++mfp->stat.st_page_create; + else + ++mfp->stat.st_page_in; + } + + return (ret); +} + +/* + * __memp_pgwrite -- + * Write a page to a file. + * + * PUBLIC: int __memp_pgwrite + * PUBLIC: __P((DB_MPOOL *, DB_MPOOLFILE *, BH *, int *, int *)); + */ +int +__memp_pgwrite(dbmp, dbmfp, bhp, restartp, wrotep) + DB_MPOOL *dbmp; + DB_MPOOLFILE *dbmfp; + BH *bhp; + int *restartp, *wrotep; +{ + DB_ENV *dbenv; + DB_IO db_io; + DB_LSN lsn; + MPOOL *c_mp, *mp; + MPOOLFILE *mfp; + size_t nw; + int callpgin, dosync, ret, syncfail; + const char *fail; + + dbenv = dbmp->dbenv; + mp = dbmp->reginfo[0].primary; + mfp = dbmfp == NULL ? NULL : dbmfp->mfp; + + if (restartp != NULL) + *restartp = 0; + if (wrotep != NULL) + *wrotep = 0; + callpgin = 0; + + /* + * Check the dirty bit -- this buffer may have been written since we + * decided to write it. + */ + if (!F_ISSET(bhp, BH_DIRTY)) { + if (wrotep != NULL) + *wrotep = 1; + return (0); + } + + MUTEX_LOCK(dbenv, &bhp->mutex, dbenv->lockfhp); + + /* + * If there were two writers, we may have just been waiting while the + * other writer completed I/O on this buffer. Check the dirty bit one + * more time. + */ + if (!F_ISSET(bhp, BH_DIRTY)) { + MUTEX_UNLOCK(dbenv, &bhp->mutex); + + if (wrotep != NULL) + *wrotep = 1; + return (0); + } + + F_SET(bhp, BH_LOCKED); + R_UNLOCK(dbenv, dbmp->reginfo); + + if (restartp != NULL) + *restartp = 1; + + /* + * It's possible that the underlying file doesn't exist, either + * because of an outright removal or because it was a temporary + * file that's been closed. + * + * !!! + * Once we pass this point, we know that dbmfp and mfp aren't NULL, + * and that we have a valid file reference. + */ + if (mfp == NULL || F_ISSET(mfp, MP_DEADFILE)) + goto file_dead; + + /* + * Ensure the appropriate log records are on disk. If the page is + * being written as part of a sync operation, the flush has already + * been done, unless it was written by the application *after* the + * sync was scheduled. + */ + if (LOGGING_ON(dbenv) && + (!F_ISSET(bhp, BH_SYNC) || F_ISSET(bhp, BH_SYNC_LOGFLSH))) { + memcpy(&lsn, bhp->buf + mfp->lsn_off, sizeof(DB_LSN)); + if ((ret = log_flush(dbenv, &lsn)) != 0) + goto err; + } + DB_ASSERT(!LOGGING_ON(dbenv) || + log_compare(&((LOG *)((DB_LOG *) + dbenv->lg_handle)->reginfo.primary)->s_lsn, &LSN(bhp->buf)) > 0); + + /* + * Call any pgout function. We set the callpgin flag so that we flag + * that the contents of the buffer will need to be passed through pgin + * before they are reused. + */ + if (mfp->ftype == 0) + ret = 0; + else { + callpgin = 1; + if ((ret = __memp_pg(dbmfp, bhp, 0)) != 0) + goto err; + } + + /* Temporary files may not yet have been created. */ + if (!F_ISSET(&dbmfp->fh, DB_FH_VALID)) { + MUTEX_THREAD_LOCK(dbenv, dbmp->mutexp); + if (!F_ISSET(&dbmfp->fh, DB_FH_VALID) && + ((ret = __db_appname(dbenv, DB_APP_TMP, NULL, NULL, + DB_OSO_CREATE | DB_OSO_EXCL | DB_OSO_TEMP, + &dbmfp->fh, NULL)) != 0 || + !F_ISSET(&dbmfp->fh, DB_FH_VALID))) { + MUTEX_THREAD_UNLOCK(dbenv, dbmp->mutexp); + __db_err(dbenv, + "unable to create temporary backing file"); + goto err; + } + MUTEX_THREAD_UNLOCK(dbenv, dbmp->mutexp); + } + + /* Write the page. */ + db_io.fhp = &dbmfp->fh; + db_io.mutexp = dbmfp->mutexp; + db_io.pagesize = db_io.bytes = mfp->stat.st_pagesize; + db_io.pgno = bhp->pgno; + db_io.buf = bhp->buf; + if ((ret = __os_io(dbenv, &db_io, DB_IO_WRITE, &nw)) != 0) { + ret = __db_panic(dbenv, ret); + fail = "write"; + goto syserr; + } + if (nw != mfp->stat.st_pagesize) { + ret = EIO; + fail = "write"; + goto syserr; + } + +file_dead: + /* + * !!! + * Once we pass this point, dbmfp and mfp may be NULL, we may not have + * a valid file reference. + * + * Unlock the buffer and reacquire the region lock. + */ + MUTEX_UNLOCK(dbenv, &bhp->mutex); + R_LOCK(dbenv, dbmp->reginfo); + + /* + * Clean up the flags based on a successful write. + * + * If we rewrote the page, it will need processing by the pgin + * routine before reuse. + */ + if (callpgin) + F_SET(bhp, BH_CALLPGIN); + F_CLR(bhp, BH_DIRTY | BH_LOCKED); + + /* + * If we write a buffer for which a checkpoint is waiting, update + * the count of pending buffers (both in the mpool as a whole and + * for this file). If the count for this file goes to zero, set a + * flag so we flush the writes. + */ + dosync = 0; + if (F_ISSET(bhp, BH_SYNC)) { + F_CLR(bhp, BH_SYNC | BH_SYNC_LOGFLSH); + + --mp->lsn_cnt; + if (mfp != NULL) + dosync = --mfp->lsn_cnt == 0 ? 1 : 0; + } + + /* Update the page clean/dirty statistics. */ + c_mp = BH_TO_CACHE(dbmp, bhp); + ++c_mp->stat.st_page_clean; + --c_mp->stat.st_page_dirty; + + /* Update I/O statistics. */ + if (mfp != NULL) + ++mfp->stat.st_page_out; + + /* + * Do the sync after everything else has been updated, so any incoming + * checkpoint doesn't see inconsistent information. + * + * XXX: + * Don't lock the region around the sync, fsync(2) has no atomicity + * issues. + * + * XXX: + * We ignore errors from the sync -- it makes no sense to return an + * error to the calling process, so set a flag causing the checkpoint + * to be retried later. There is a possibility, of course, that a + * subsequent checkpoint was started and that we're going to force it + * to fail. That should be unlikely, and fixing it would be difficult. + */ + if (dosync) { + R_UNLOCK(dbenv, dbmp->reginfo); + syncfail = __os_fsync(dbenv, &dbmfp->fh) != 0; + R_LOCK(dbenv, dbmp->reginfo); + if (syncfail) + F_SET(mp, MP_LSN_RETRY); + } + + if (wrotep != NULL) + *wrotep = 1; + + return (0); + +syserr: __db_err(dbenv, "%s: %s failed for page %lu", + __memp_fn(dbmfp), fail, (u_long)bhp->pgno); + +err: /* Unlock the buffer and reacquire the region lock. */ + MUTEX_UNLOCK(dbenv, &bhp->mutex); + R_LOCK(dbenv, dbmp->reginfo); + + /* + * Clean up the flags based on a failure. + * + * The page remains dirty but we remove our lock. If we rewrote the + * page, it will need processing by the pgin routine before reuse. + */ + if (callpgin) + F_SET(bhp, BH_CALLPGIN); + F_CLR(bhp, BH_LOCKED); + + return (ret); +} + +/* + * __memp_pg -- + * Call the pgin/pgout routine. + * + * PUBLIC: int __memp_pg __P((DB_MPOOLFILE *, BH *, int)); + */ +int +__memp_pg(dbmfp, bhp, is_pgin) + DB_MPOOLFILE *dbmfp; + BH *bhp; + int is_pgin; +{ + DBT dbt, *dbtp; + DB_MPOOL *dbmp; + DB_MPREG *mpreg; + MPOOLFILE *mfp; + int ftype, ret; + + dbmp = dbmfp->dbmp; + mfp = dbmfp->mfp; + + MUTEX_THREAD_LOCK(dbmp->dbenv, dbmp->mutexp); + + ftype = mfp->ftype; + for (mpreg = LIST_FIRST(&dbmp->dbregq); + mpreg != NULL; mpreg = LIST_NEXT(mpreg, q)) { + if (ftype != mpreg->ftype) + continue; + if (mfp->pgcookie_len == 0) + dbtp = NULL; + else { + dbt.size = mfp->pgcookie_len; + dbt.data = R_ADDR(dbmp->reginfo, mfp->pgcookie_off); + dbtp = &dbt; + } + MUTEX_THREAD_UNLOCK(dbmp->dbenv, dbmp->mutexp); + + if (is_pgin) { + if (mpreg->pgin != NULL && + (ret = mpreg->pgin(dbmp->dbenv, + bhp->pgno, bhp->buf, dbtp)) != 0) + goto err; + } else + if (mpreg->pgout != NULL && + (ret = mpreg->pgout(dbmp->dbenv, + bhp->pgno, bhp->buf, dbtp)) != 0) + goto err; + break; + } + + if (mpreg == NULL) + MUTEX_THREAD_UNLOCK(dbmp->dbenv, dbmp->mutexp); + + return (0); + +err: MUTEX_THREAD_UNLOCK(dbmp->dbenv, dbmp->mutexp); + __db_err(dbmp->dbenv, "%s: %s failed for page %lu", + __memp_fn(dbmfp), is_pgin ? "pgin" : "pgout", (u_long)bhp->pgno); + return (ret); +} + +/* + * __memp_bhfree -- + * Free a bucket header and its referenced data. + * + * PUBLIC: void __memp_bhfree __P((DB_MPOOL *, BH *, int)); + */ +void +__memp_bhfree(dbmp, bhp, free_mem) + DB_MPOOL *dbmp; + BH *bhp; + int free_mem; +{ + DB_HASHTAB *dbht; + MPOOL *c_mp, *mp; + MPOOLFILE *mfp; + int n_bucket, n_cache; + + mp = dbmp->reginfo[0].primary; + c_mp = BH_TO_CACHE(dbmp, bhp); + n_cache = NCACHE(mp, bhp->pgno); + n_bucket = NBUCKET(c_mp, bhp->mf_offset, bhp->pgno); + dbht = R_ADDR(&dbmp->reginfo[n_cache], c_mp->htab); + + /* Delete the buffer header from the hash bucket queue. */ + SH_TAILQ_REMOVE(&dbht[n_bucket], bhp, hq, __bh); + + /* Delete the buffer header from the LRU queue. */ + SH_TAILQ_REMOVE(&c_mp->bhq, bhp, q, __bh); + + /* Clear the mutex this buffer recorded */ + __db_shlocks_clear(&bhp->mutex, &dbmp->reginfo[n_cache], + (REGMAINT *)R_ADDR(&dbmp->reginfo[n_cache], mp->maint_off)); + /* + * Find the underlying MPOOLFILE and decrement its reference count. + * If this is its last reference, remove it. + */ + mfp = R_ADDR(dbmp->reginfo, bhp->mf_offset); + if (--mfp->block_cnt == 0 && mfp->mpf_cnt == 0) + __memp_mf_discard(dbmp, mfp); + + /* + * If we're not reusing it immediately, free the buffer header + * and data for real. + */ + if (free_mem) { + --c_mp->stat.st_page_clean; + __db_shalloc_free(dbmp->reginfo[n_cache].addr, bhp); + } +} + +/* + * __memp_upgrade -- + * Upgrade a file descriptor from readonly to readwrite. + */ +static int +__memp_upgrade(dbmp, dbmfp, mfp) + DB_MPOOL *dbmp; + DB_MPOOLFILE *dbmfp; + MPOOLFILE *mfp; +{ + DB_FH fh; + int ret; + char *rpath; + + /* + * !!! + * We expect the handle to already be locked. + */ + + /* Check to see if we've already upgraded. */ + if (F_ISSET(dbmfp, MP_UPGRADE)) + return (0); + + /* Check to see if we've already failed. */ + if (F_ISSET(dbmfp, MP_UPGRADE_FAIL)) + return (1); + + /* + * Calculate the real name for this file and try to open it read/write. + * We know we have a valid pathname for the file because it's the only + * way we could have gotten a file descriptor of any kind. + */ + if ((ret = __db_appname(dbmp->dbenv, DB_APP_DATA, + NULL, R_ADDR(dbmp->reginfo, mfp->path_off), 0, NULL, &rpath)) != 0) + return (ret); + if (__os_open(dbmp->dbenv, rpath, 0, 0, &fh) != 0) { + F_SET(dbmfp, MP_UPGRADE_FAIL); + ret = 1; + } else { + /* Swap the descriptors and set the upgrade flag. */ + (void)__os_closehandle(&dbmfp->fh); + dbmfp->fh = fh; + F_SET(dbmfp, MP_UPGRADE); + ret = 0; + } + __os_freestr(rpath); + return (ret); +} diff --git a/db/mp/mp_fget.c b/db/mp/mp_fget.c new file mode 100644 index 000000000..1bff5e136 --- /dev/null +++ b/db/mp/mp_fget.c @@ -0,0 +1,417 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: mp_fget.c,v 11.28 2001/01/10 04:50:53 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#ifdef HAVE_RPC +#include "db_server.h" +#endif + +#include "db_int.h" +#include "db_shash.h" +#include "mp.h" + +#ifdef HAVE_RPC +#include "gen_client_ext.h" +#include "rpc_client_ext.h" +#endif + +/* + * memp_fget -- + * Get a page from the file. + */ +int +memp_fget(dbmfp, pgnoaddr, flags, addrp) + DB_MPOOLFILE *dbmfp; + db_pgno_t *pgnoaddr; + u_int32_t flags; + void *addrp; +{ + BH *bhp; + DB_ENV *dbenv; + DB_MPOOL *dbmp; + DB_HASHTAB *dbht; + MPOOL *c_mp, *mp; + MPOOLFILE *mfp; + size_t n_bucket, n_cache, mf_offset; + u_int32_t st_hsearch; + int b_incr, first, ret; + + dbmp = dbmfp->dbmp; + dbenv = dbmp->dbenv; + mp = dbmp->reginfo[0].primary; + mfp = dbmfp->mfp; +#ifdef HAVE_RPC + if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) + return (__dbcl_memp_fget(dbmfp, pgnoaddr, flags, addrp)); +#endif + + PANIC_CHECK(dbenv); + + /* + * Validate arguments. + * + * !!! + * Don't test for DB_MPOOL_CREATE and DB_MPOOL_NEW flags for readonly + * files here, and create non-existent pages in readonly files if the + * flags are set, later. The reason is that the hash access method + * wants to get empty pages that don't really exist in readonly files. + * The only alternative is for hash to write the last "bucket" all the + * time, which we don't want to do because one of our big goals in life + * is to keep database files small. It's sleazy as hell, but we catch + * any attempt to actually write the file in memp_fput(). + */ +#define OKFLAGS \ + (DB_MPOOL_CREATE | DB_MPOOL_LAST | \ + DB_MPOOL_NEW | DB_MPOOL_NEW_GROUP | DB_MPOOL_EXTENT) + if (flags != 0) { + if ((ret = __db_fchk(dbenv, "memp_fget", flags, OKFLAGS)) != 0) + return (ret); + + switch (flags & ~DB_MPOOL_EXTENT) { + case DB_MPOOL_CREATE: + case DB_MPOOL_LAST: + case DB_MPOOL_NEW: + case DB_MPOOL_NEW_GROUP: + case 0: + break; + default: + return (__db_ferr(dbenv, "memp_fget", 1)); + } + } + +#ifdef DIAGNOSTIC + /* + * XXX + * We want to switch threads as often as possible. Yield every time + * we get a new page to ensure contention. + */ + if (DB_GLOBAL(db_pageyield)) + __os_yield(dbenv, 1); +#endif + + /* Initialize remaining local variables. */ + mf_offset = R_OFFSET(dbmp->reginfo, mfp); + bhp = NULL; + st_hsearch = 0; + b_incr = ret = 0; + + R_LOCK(dbenv, dbmp->reginfo); + + /* + * Check for the new, last or last + 1 page requests. + * + * Examine and update the file's last_pgno value. We don't care if + * the last_pgno value immediately changes due to another thread -- + * at this instant in time, the value is correct. We do increment the + * current last_pgno value if the thread is asking for a new page, + * however, to ensure that two threads creating pages don't get the + * same one. + * + * If we create a page, there is the potential that a page after it + * in the file will be written before it will be written. Recovery + * depends on pages that are "created" in the file by subsequent pages + * being written be zeroed out, not have random garbage. Ensure that + * the OS agrees. + * + * !!! + * DB_MPOOL_NEW_GROUP is undocumented -- the hash access method needs + * to allocate contiguous groups of pages in order to do subdatabases. + * We return the first page in the group, but the caller must put an + * LSN on the *last* page and write it, otherwise after a crash we may + * not create all of the pages we need to create. + */ + if (LF_ISSET(DB_MPOOL_LAST | DB_MPOOL_NEW | DB_MPOOL_NEW_GROUP)) { + if (LF_ISSET(DB_MPOOL_NEW)) { + if (F_ISSET(&dbmfp->fh, DB_FH_VALID) && (ret = + __os_fpinit(dbenv, &dbmfp->fh, mfp->last_pgno + 1, + 1, mfp->stat.st_pagesize)) != 0) { + R_UNLOCK(dbenv, dbmp->reginfo); + return (ret); + } + ++mfp->last_pgno; + } + if (LF_ISSET(DB_MPOOL_NEW_GROUP)) { + if (F_ISSET(&dbmfp->fh, DB_FH_VALID) && (ret = + __os_fpinit(dbenv, &dbmfp->fh, mfp->last_pgno + 1, + (int)*pgnoaddr, mfp->stat.st_pagesize)) != 0) { + R_UNLOCK(dbenv, dbmp->reginfo); + return (ret); + } + mfp->last_pgno += *pgnoaddr; + } + *pgnoaddr = mfp->last_pgno; + } + + /* + * Determine the hash bucket where this page will live, and get local + * pointers to the cache and its hash table. + */ + n_cache = NCACHE(mp, *pgnoaddr); + c_mp = dbmp->reginfo[n_cache].primary; + n_bucket = NBUCKET(c_mp, mf_offset, *pgnoaddr); + dbht = R_ADDR(&dbmp->reginfo[n_cache], c_mp->htab); + + if (LF_ISSET(DB_MPOOL_NEW | DB_MPOOL_NEW_GROUP)) + goto alloc; + + /* + * If mmap'ing the file and the page is not past the end of the file, + * just return a pointer. + * + * The page may be past the end of the file, so check the page number + * argument against the original length of the file. If we previously + * returned pages past the original end of the file, last_pgno will + * have been updated to match the "new" end of the file, and checking + * against it would return pointers past the end of the mmap'd region. + * + * If another process has opened the file for writing since we mmap'd + * it, we will start playing the game by their rules, i.e. everything + * goes through the cache. All pages previously returned will be safe, + * as long as the correct locking protocol was observed. + * + * XXX + * We don't discard the map because we don't know when all of the + * pages will have been discarded from the process' address space. + * It would be possible to do so by reference counting the open + * pages from the mmap, but it's unclear to me that it's worth it. + */ + if (dbmfp->addr != NULL && F_ISSET(mfp, MP_CAN_MMAP)) { + if (*pgnoaddr > mfp->orig_last_pgno) { + /* + * !!! + * See the comment above about non-existent pages and + * the hash access method. + */ + if (!LF_ISSET(DB_MPOOL_CREATE)) { + if (!LF_ISSET(DB_MPOOL_EXTENT)) + __db_err(dbenv, + "%s: page %lu doesn't exist", + __memp_fn(dbmfp), (u_long)*pgnoaddr); + ret = EINVAL; + goto err; + } + } else { + *(void **)addrp = + R_ADDR(dbmfp, *pgnoaddr * mfp->stat.st_pagesize); + ++mfp->stat.st_map; + goto done; + } + } + + /* Search the hash chain for the page. */ + for (bhp = SH_TAILQ_FIRST(&dbht[n_bucket], __bh); + bhp != NULL; bhp = SH_TAILQ_NEXT(bhp, hq, __bh)) { + ++st_hsearch; + if (bhp->pgno != *pgnoaddr || bhp->mf_offset != mf_offset) + continue; + + /* Increment the reference count. */ + if (bhp->ref == UINT16_T_MAX) { + __db_err(dbenv, + "%s: page %lu: reference count overflow", + __memp_fn(dbmfp), (u_long)bhp->pgno); + ret = EINVAL; + goto err; + } + + /* + * Increment the reference count. We may discard the region + * lock as we evaluate and/or read the buffer, so we need to + * ensure that it doesn't move and that its contents remain + * unchanged. + */ + ++bhp->ref; + b_incr = 1; + + /* + * Any buffer we find might be trouble. + * + * BH_LOCKED -- + * I/O is in progress. Because we've incremented the buffer + * reference count, we know the buffer can't move. Unlock + * the region lock, wait for the I/O to complete, and reacquire + * the region. + */ + for (first = 1; F_ISSET(bhp, BH_LOCKED); first = 0) { + R_UNLOCK(dbenv, dbmp->reginfo); + + /* + * Explicitly yield the processor if it's not the first + * pass through this loop -- if we don't, we might end + * up running to the end of our CPU quantum as we will + * simply be swapping between the two locks. + */ + if (!first) + __os_yield(dbenv, 1); + + MUTEX_LOCK(dbenv, &bhp->mutex, dbenv->lockfhp); + /* Wait for I/O to finish... */ + MUTEX_UNLOCK(dbenv, &bhp->mutex); + R_LOCK(dbenv, dbmp->reginfo); + } + + /* + * BH_TRASH -- + * The contents of the buffer are garbage. Shouldn't happen, + * and this read is likely to fail, but might as well try. + */ + if (F_ISSET(bhp, BH_TRASH)) + goto reread; + + /* + * BH_CALLPGIN -- + * The buffer was converted so it could be written, and the + * contents need to be converted again. + */ + if (F_ISSET(bhp, BH_CALLPGIN)) { + if ((ret = __memp_pg(dbmfp, bhp, 1)) != 0) + goto err; + F_CLR(bhp, BH_CALLPGIN); + } + + ++mfp->stat.st_cache_hit; + *(void **)addrp = bhp->buf; + goto done; + } + +alloc: /* Allocate new buffer header and data space. */ + if ((ret = __memp_alloc(dbmp, + &dbmp->reginfo[n_cache], mfp, 0, NULL, &bhp)) != 0) + goto err; + + ++c_mp->stat.st_page_clean; + + /* + * Initialize the BH fields so that we can call the __memp_bhfree + * routine if an error occurs. + */ + memset(bhp, 0, sizeof(BH)); + bhp->ref = 1; + bhp->pgno = *pgnoaddr; + bhp->mf_offset = mf_offset; + + /* Increment the count of buffers referenced by this MPOOLFILE. */ + ++mfp->block_cnt; + + /* + * Prepend the bucket header to the head of the appropriate MPOOL + * bucket hash list. Append the bucket header to the tail of the + * MPOOL LRU chain. + */ + SH_TAILQ_INSERT_HEAD(&dbht[n_bucket], bhp, hq, __bh); + SH_TAILQ_INSERT_TAIL(&c_mp->bhq, bhp, q); + +#ifdef DIAGNOSTIC + if ((db_alignp_t)bhp->buf & (sizeof(size_t) - 1)) { + __db_err(dbenv, "Internal error: BH data NOT size_t aligned."); + ret = EINVAL; + __memp_bhfree(dbmp, bhp, 1); + goto err; + } +#endif + + if ((ret = __db_shmutex_init(dbenv, &bhp->mutex, + R_OFFSET(dbmp->reginfo, &bhp->mutex) + DB_FCNTL_OFF_MPOOL, + 0, &dbmp->reginfo[n_cache], + (REGMAINT *)R_ADDR(&dbmp->reginfo[n_cache], c_mp->maint_off))) + != 0) { + __memp_bhfree(dbmp, bhp, 1); + goto err; + } + + /* + * If we created the page, zero it out and continue. + * + * !!! + * Note: DB_MPOOL_NEW specifically doesn't call the pgin function. + * If DB_MPOOL_CREATE is used, then the application's pgin function + * has to be able to handle pages of 0's -- if it uses DB_MPOOL_NEW, + * it can detect all of its page creates, and not bother. + * + * If we're running in diagnostic mode, smash any bytes on the + * page that are unknown quantities for the caller. + * + * Otherwise, read the page into memory, optionally creating it if + * DB_MPOOL_CREATE is set. + */ + if (LF_ISSET(DB_MPOOL_NEW | DB_MPOOL_NEW_GROUP)) { + if (mfp->clear_len == 0) + memset(bhp->buf, 0, mfp->stat.st_pagesize); + else { + memset(bhp->buf, 0, mfp->clear_len); +#ifdef DIAGNOSTIC + memset(bhp->buf + mfp->clear_len, CLEAR_BYTE, + mfp->stat.st_pagesize - mfp->clear_len); +#endif + } + + ++mfp->stat.st_page_create; + } else { + /* + * It's possible for the read function to fail, which means + * that we fail as well. Note, the __memp_pgread() function + * discards the region lock, so the buffer must be pinned + * down so that it cannot move and its contents are unchanged. + */ +reread: if ((ret = __memp_pgread(dbmfp, + bhp, LF_ISSET(DB_MPOOL_CREATE|DB_MPOOL_EXTENT))) != 0) { + /* + * !!! + * Discard the buffer unless another thread is waiting + * on our I/O to complete. Regardless, the header has + * the BH_TRASH flag set. + */ + if (bhp->ref == 1) + __memp_bhfree(dbmp, bhp, 1); + goto err; + } + + ++mfp->stat.st_cache_miss; + } + + /* + * If we're returning a page after our current notion of the last-page, + * update our information. Note, there's no way to un-instantiate this + * page, it's going to exist whether it's returned to us dirty or not. + */ + if (bhp->pgno > mfp->last_pgno) + mfp->last_pgno = bhp->pgno; + + *(void **)addrp = bhp->buf; + +done: /* Update the chain search statistics. */ + if (st_hsearch) { + ++c_mp->stat.st_hash_searches; + if (st_hsearch > c_mp->stat.st_hash_longest) + c_mp->stat.st_hash_longest = st_hsearch; + c_mp->stat.st_hash_examined += st_hsearch; + } + + ++dbmfp->pinref; + + R_UNLOCK(dbenv, dbmp->reginfo); + + return (0); + +err: /* Discard our reference. */ + if (b_incr) + --bhp->ref; + R_UNLOCK(dbenv, dbmp->reginfo); + + *(void **)addrp = NULL; + return (ret); +} diff --git a/db/mp/mp_fopen.c b/db/mp/mp_fopen.c new file mode 100644 index 000000000..3611ded18 --- /dev/null +++ b/db/mp/mp_fopen.c @@ -0,0 +1,756 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: mp_fopen.c,v 11.41 2001/01/10 04:50:53 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#ifdef HAVE_RPC +#include "db_server.h" +#endif + +#include "db_int.h" +#include "db_shash.h" +#include "mp.h" + +#ifdef HAVE_RPC +#include "gen_client_ext.h" +#include "rpc_client_ext.h" +#endif + +static int __memp_mf_open __P((DB_MPOOL *, const char *, + size_t, db_pgno_t, DB_MPOOL_FINFO *, u_int32_t, MPOOLFILE **)); + +/* + * MEMP_FREMOVE -- + * Discard an MPOOLFILE and any buffers it references: update the flags + * so we never try to write buffers associated with the file, nor can we + * find it when looking for files to join. In addition, clear the ftype + * field, there's no reason to post-process pages, they can be discarded + * by any thread. + */ +#define MEMP_FREMOVE(mfp) { \ + mfp->ftype = 0; \ + F_SET(mfp, MP_DEADFILE); \ +} + +/* + * memp_fopen -- + * Open a backing file for the memory pool. + */ +int +memp_fopen(dbenv, path, flags, mode, pagesize, finfop, retp) + DB_ENV *dbenv; + const char *path; + u_int32_t flags; + int mode; + size_t pagesize; + DB_MPOOL_FINFO *finfop; + DB_MPOOLFILE **retp; +{ + DB_MPOOL *dbmp; + int ret; + +#ifdef HAVE_RPC + if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) + return (__dbcl_memp_fopen(dbenv, path, flags, + mode, pagesize, finfop, retp)); +#endif + + PANIC_CHECK(dbenv); + ENV_REQUIRES_CONFIG(dbenv, dbenv->mp_handle, DB_INIT_MPOOL); + + dbmp = dbenv->mp_handle; + + /* Validate arguments. */ + if ((ret = __db_fchk(dbenv, "memp_fopen", flags, + DB_CREATE | + DB_NOMMAP | DB_ODDFILESIZE | DB_RDONLY | DB_TRUNCATE)) != 0) + return (ret); + + /* Require a non-zero pagesize. */ + if (pagesize == 0 || + (finfop != NULL && finfop->clear_len > pagesize)) { + __db_err(dbenv, "memp_fopen: illegal page size."); + return (EINVAL); + } + + return (__memp_fopen(dbmp, + NULL, path, flags, mode, pagesize, 1, finfop, retp)); +} + +/* + * __memp_set_unlink -- set unlink on last close flag. + * + * PUBLIC: void __memp_set_unlink __P((DB_MPOOLFILE *)); + */ +void +__memp_set_unlink(dbmpf) + DB_MPOOLFILE *dbmpf; +{ + DB_MPOOL *dbmp; + dbmp = dbmpf->dbmp; + + R_LOCK(dbmp->dbenv, dbmp->reginfo); + F_SET(dbmpf->mfp, MP_UNLINK); + R_UNLOCK(dbmp->dbenv, dbmp->reginfo); +} + +/* + * __memp_clear_unlink -- clear unlink on last close flag. + * + * PUBLIC: void __memp_clear_unlink __P((DB_MPOOLFILE *)); + */ +void +__memp_clear_unlink(dbmpf) + DB_MPOOLFILE *dbmpf; +{ + DB_MPOOL *dbmp; + dbmp = dbmpf->dbmp; + + /* + * This bit is protected in the queue code because the metapage + * is locked so we can avoid geting the region lock. + * If this gets used from other than the queue code, we cannot. + */ + if (!F_ISSET(dbmpf->mfp, MP_UNLINK)) + return; + R_LOCK(dbmp->dbenv, dbmp->reginfo); + F_CLR(dbmpf->mfp, MP_UNLINK); + R_UNLOCK(dbmp->dbenv, dbmp->reginfo); +} + +/* + * __memp_fopen -- + * Open a backing file for the memory pool; internal version. + * + * PUBLIC: int __memp_fopen __P((DB_MPOOL *, MPOOLFILE *, const char *, + * PUBLIC: u_int32_t, int, size_t, int, DB_MPOOL_FINFO *, DB_MPOOLFILE **)); + */ +int +__memp_fopen(dbmp, mfp, path, flags, mode, pagesize, needlock, finfop, retp) + DB_MPOOL *dbmp; + MPOOLFILE *mfp; + const char *path; + u_int32_t flags; + int mode, needlock; + size_t pagesize; + DB_MPOOL_FINFO *finfop; + DB_MPOOLFILE **retp; +{ + DB_ENV *dbenv; + DB_MPOOLFILE *dbmfp; + DB_MPOOL_FINFO finfo; + db_pgno_t last_pgno; + size_t maxmap; + u_int32_t mbytes, bytes, oflags; + int ret; + u_int8_t idbuf[DB_FILE_ID_LEN]; + char *rpath; + + dbenv = dbmp->dbenv; + ret = 0; + rpath = NULL; + + /* + * If mfp is provided, we take the DB_MPOOL_FINFO information from + * the mfp. We don't bother initializing everything, because some + * of them are expensive to acquire. If no mfp is provided and the + * finfop argument is NULL, we default the values. + */ + if (finfop == NULL) { + memset(&finfo, 0, sizeof(finfo)); + if (mfp != NULL) { + finfo.ftype = mfp->ftype; + finfo.pgcookie = NULL; + finfo.fileid = NULL; + finfo.lsn_offset = mfp->lsn_off; + finfo.clear_len = mfp->clear_len; + } else { + finfo.ftype = 0; + finfo.pgcookie = NULL; + finfo.fileid = NULL; + finfo.lsn_offset = -1; + finfo.clear_len = 0; + } + finfop = &finfo; + } + + /* Allocate and initialize the per-process structure. */ + if ((ret = __os_calloc(dbenv, 1, sizeof(DB_MPOOLFILE), &dbmfp)) != 0) + return (ret); + dbmfp->dbmp = dbmp; + dbmfp->ref = 1; + if (LF_ISSET(DB_RDONLY)) + F_SET(dbmfp, MP_READONLY); + + if (path == NULL) { + if (LF_ISSET(DB_RDONLY)) { + __db_err(dbenv, + "memp_fopen: temporary files can't be readonly"); + ret = EINVAL; + goto err; + } + last_pgno = 0; + } else { + /* Get the real name for this file and open it. */ + if ((ret = __db_appname(dbenv, + DB_APP_DATA, NULL, path, 0, NULL, &rpath)) != 0) + goto err; + oflags = 0; + if (LF_ISSET(DB_CREATE)) + oflags |= DB_OSO_CREATE; + if (LF_ISSET(DB_RDONLY)) + oflags |= DB_OSO_RDONLY; + if ((ret = + __os_open(dbenv, rpath, oflags, mode, &dbmfp->fh)) != 0) { + if (!LF_ISSET(DB_EXTENT)) + __db_err(dbenv, + "%s: %s", rpath, db_strerror(ret)); + goto err; + } + + /* + * Don't permit files that aren't a multiple of the pagesize, + * and find the number of the last page in the file, all the + * time being careful not to overflow 32 bits. + * + * !!! + * We can't use off_t's here, or in any code in the mainline + * library for that matter. (We have to use them in the os + * stubs, of course, as there are system calls that take them + * as arguments.) The reason is that some customers build in + * environments where an off_t is 32-bits, but still run where + * offsets are 64-bits, and they pay us a lot of money. + */ + if ((ret = __os_ioinfo(dbenv, rpath, + &dbmfp->fh, &mbytes, &bytes, NULL)) != 0) { + __db_err(dbenv, "%s: %s", rpath, db_strerror(ret)); + goto err; + } + + /* + * If we're doing a verify, we might have to cope with + * a truncated file; if the file size is not a multiple + * of the page size, round down to a page--we'll + * take care of the partial page outside the memp system. + */ + + /* Page sizes have to be a power-of-two, ignore mbytes. */ + if (bytes % pagesize != 0) { + if (LF_ISSET(DB_ODDFILESIZE)) + /* + * If we're doing a verify, we might + * have to cope with a truncated file; + * round down, we'll worry about the partial + * page outside the memp system. + */ + bytes -= (bytes % pagesize); + else { + __db_err(dbenv, + "%s: file size not a multiple of the pagesize", + rpath); + ret = EINVAL; + goto err; + } + } + + last_pgno = mbytes * (MEGABYTE / pagesize); + last_pgno += bytes / pagesize; + + /* Correction: page numbers are zero-based, not 1-based. */ + if (last_pgno != 0) + --last_pgno; + + /* + * Get the file id if we weren't given one. Generated file id's + * don't use timestamps, otherwise there'd be no chance of any + * other process joining the party. + */ + if (finfop->fileid == NULL) { + if ((ret = __os_fileid(dbenv, rpath, 0, idbuf)) != 0) + goto err; + finfop->fileid = idbuf; + } + } + + /* + * If we weren't provided an underlying shared object to join with, + * find/allocate the shared file objects. Also allocate space for + * for the per-process thread lock. + */ + if (needlock) + R_LOCK(dbenv, dbmp->reginfo); + if (mfp == NULL) + ret = __memp_mf_open( + dbmp, path, pagesize, last_pgno, finfop, flags, &mfp); + else { + ++mfp->mpf_cnt; + ret = 0; + } + if (needlock) + R_UNLOCK(dbenv, dbmp->reginfo); + if (ret != 0) + goto err; + + if (F_ISSET(dbenv, DB_ENV_THREAD)) { + if ((ret = __db_mutex_alloc( + dbenv, dbmp->reginfo, &dbmfp->mutexp)) != 0) + goto err; + if ((ret = __db_mutex_init( + dbenv, dbmfp->mutexp, 0, MUTEX_THREAD)) != 0) + goto err; + + /* XXX: KEITH: CLOSE THE FILE ON FAILURE? */ + } + + dbmfp->mfp = mfp; + + /* + * If a file: + * + is read-only + * + isn't temporary + * + doesn't require any pgin/pgout support + * + the DB_NOMMAP flag wasn't set (in either the file open or + * the environment in which it was opened) + * + and is less than mp_mmapsize bytes in size + * + * we can mmap it instead of reading/writing buffers. Don't do error + * checking based on the mmap call failure. We want to do normal I/O + * on the file if the reason we failed was because the file was on an + * NFS mounted partition, and we can fail in buffer I/O just as easily + * as here. + * + * XXX + * We'd like to test to see if the file is too big to mmap. Since we + * don't know what size or type off_t's or size_t's are, or the largest + * unsigned integral type is, or what random insanity the local C + * compiler will perpetrate, doing the comparison in a portable way is + * flatly impossible. Hope that mmap fails if the file is too large. + */ +#define DB_MAXMMAPSIZE (10 * 1024 * 1024) /* 10 Mb. */ + if (F_ISSET(mfp, MP_CAN_MMAP)) { + if (!F_ISSET(dbmfp, MP_READONLY)) + F_CLR(mfp, MP_CAN_MMAP); + if (path == NULL) + F_CLR(mfp, MP_CAN_MMAP); + if (finfop->ftype != 0) + F_CLR(mfp, MP_CAN_MMAP); + if (LF_ISSET(DB_NOMMAP) || F_ISSET(dbenv, DB_ENV_NOMMAP)) + F_CLR(mfp, MP_CAN_MMAP); + maxmap = dbenv->mp_mmapsize == 0 ? + DB_MAXMMAPSIZE : dbenv->mp_mmapsize; + if (mbytes > maxmap / MEGABYTE || + (mbytes == maxmap / MEGABYTE && bytes >= maxmap % MEGABYTE)) + F_CLR(mfp, MP_CAN_MMAP); + } + dbmfp->addr = NULL; + if (F_ISSET(mfp, MP_CAN_MMAP)) { + dbmfp->len = (size_t)mbytes * MEGABYTE + bytes; + if (__os_mapfile(dbenv, rpath, + &dbmfp->fh, dbmfp->len, 1, &dbmfp->addr) != 0) { + dbmfp->addr = NULL; + F_CLR(mfp, MP_CAN_MMAP); + } + } + if (rpath != NULL) + __os_freestr(rpath); + + MUTEX_THREAD_LOCK(dbenv, dbmp->mutexp); + TAILQ_INSERT_TAIL(&dbmp->dbmfq, dbmfp, q); + MUTEX_THREAD_UNLOCK(dbenv, dbmp->mutexp); + + *retp = dbmfp; + return (0); + +err: /* + * Note that we do not have to free the thread mutex, because we + * never get to here after we have successfully allocated it. + */ + if (rpath != NULL) + __os_freestr(rpath); + if (F_ISSET(&dbmfp->fh, DB_FH_VALID)) + (void)__os_closehandle(&dbmfp->fh); + if (dbmfp != NULL) { + if (dbmfp->mutexp != NULL) + __db_mutex_free(dbenv, dbmp->reginfo, dbmfp->mutexp); + __os_free(dbmfp, sizeof(DB_MPOOLFILE)); + } + return (ret); +} + +/* + * __memp_mf_open -- + * Open an MPOOLFILE. + */ +static int +__memp_mf_open(dbmp, path, pagesize, last_pgno, finfop, flags, retp) + DB_MPOOL *dbmp; + const char *path; + size_t pagesize; + db_pgno_t last_pgno; + DB_MPOOL_FINFO *finfop; + u_int32_t flags; + MPOOLFILE **retp; +{ + MPOOL *mp; + MPOOLFILE *mfp; + int ret; + void *p; + +#define ISTEMPORARY (path == NULL) + + /* + * If not creating a temporary file, walk the list of MPOOLFILE's, + * looking for a matching file. Files backed by temporary files + * or previously removed files can't match. + * + * DB_TRUNCATE support. + * + * The fileID is a filesystem unique number (e.g., a UNIX dev/inode + * pair) plus a timestamp. If files are removed and created in less + * than a second, the fileID can be repeated. The problem with + * repetition happens when the file that previously had the fileID + * value still has pages in the pool, since we don't want to use them + * to satisfy requests for the new file. + * + * Because the DB_TRUNCATE flag reuses the dev/inode pair, repeated + * opens with that flag set guarantees matching fileIDs when the + * machine can open a file and then re-open with truncate within a + * second. For this reason, we pass that flag down, and, if we find + * a matching entry, we ensure that it's never found again, and we + * create a new entry for the current request. + */ + if (!ISTEMPORARY) { + mp = dbmp->reginfo[0].primary; + for (mfp = SH_TAILQ_FIRST(&mp->mpfq, __mpoolfile); + mfp != NULL; mfp = SH_TAILQ_NEXT(mfp, q, __mpoolfile)) { + if (F_ISSET(mfp, MP_DEADFILE | MP_TEMP)) + continue; + if (memcmp(finfop->fileid, R_ADDR(dbmp->reginfo, + mfp->fileid_off), DB_FILE_ID_LEN) == 0) { + if (LF_ISSET(DB_TRUNCATE)) { + MEMP_FREMOVE(mfp); + continue; + } + if (finfop->clear_len != mfp->clear_len || + pagesize != mfp->stat.st_pagesize) { + __db_err(dbmp->dbenv, + "%s: page size or clear length changed", + path); + return (EINVAL); + } + + /* + * It's possible that our needs for pre- and + * post-processing are changing. For example, + * an application created a hash subdatabase + * in a database that was previously all btree. + */ + if (finfop->ftype != 0) + mfp->ftype = finfop->ftype; + + ++mfp->mpf_cnt; + + *retp = mfp; + return (0); + } + } + } + + /* Allocate a new MPOOLFILE. */ + if ((ret = __memp_alloc( + dbmp, dbmp->reginfo, NULL, sizeof(MPOOLFILE), NULL, &mfp)) != 0) + goto mem_err; + *retp = mfp; + + /* Initialize the structure. */ + memset(mfp, 0, sizeof(MPOOLFILE)); + mfp->mpf_cnt = 1; + mfp->ftype = finfop->ftype; + mfp->lsn_off = finfop->lsn_offset; + mfp->clear_len = finfop->clear_len; + + /* + * If the user specifies DB_MPOOL_LAST or DB_MPOOL_NEW on a memp_fget, + * we have to know the last page in the file. Figure it out and save + * it away. + */ + mfp->stat.st_pagesize = pagesize; + mfp->orig_last_pgno = mfp->last_pgno = last_pgno; + + if (ISTEMPORARY) + F_SET(mfp, MP_TEMP); + else { + /* Copy the file path into shared memory. */ + if ((ret = __memp_alloc(dbmp, dbmp->reginfo, + NULL, strlen(path) + 1, &mfp->path_off, &p)) != 0) + goto err; + memcpy(p, path, strlen(path) + 1); + + /* Copy the file identification string into shared memory. */ + if ((ret = __memp_alloc(dbmp, dbmp->reginfo, + NULL, DB_FILE_ID_LEN, &mfp->fileid_off, &p)) != 0) + goto err; + memcpy(p, finfop->fileid, DB_FILE_ID_LEN); + + F_SET(mfp, MP_CAN_MMAP); + } + + /* Copy the page cookie into shared memory. */ + if (finfop->pgcookie == NULL || finfop->pgcookie->size == 0) { + mfp->pgcookie_len = 0; + mfp->pgcookie_off = 0; + } else { + if ((ret = __memp_alloc(dbmp, dbmp->reginfo, + NULL, finfop->pgcookie->size, &mfp->pgcookie_off, &p)) != 0) + goto err; + memcpy(p, finfop->pgcookie->data, finfop->pgcookie->size); + mfp->pgcookie_len = finfop->pgcookie->size; + } + + /* Prepend the MPOOLFILE to the list of MPOOLFILE's. */ + mp = dbmp->reginfo[0].primary; + SH_TAILQ_INSERT_HEAD(&mp->mpfq, mfp, q, __mpoolfile); + + if (0) { +err: if (mfp->path_off != 0) + __db_shalloc_free(dbmp->reginfo[0].addr, + R_ADDR(dbmp->reginfo, mfp->path_off)); + if (mfp->fileid_off != 0) + __db_shalloc_free(dbmp->reginfo[0].addr, + R_ADDR(dbmp->reginfo, mfp->fileid_off)); + if (mfp != NULL) + __db_shalloc_free(dbmp->reginfo[0].addr, mfp); +mem_err: __db_err(dbmp->dbenv, + "Unable to allocate memory for mpool file"); + } + return (ret); +} + +/* + * memp_fclose -- + * Close a backing file for the memory pool. + */ +int +memp_fclose(dbmfp) + DB_MPOOLFILE *dbmfp; +{ + DB_ENV *dbenv; + DB_MPOOL *dbmp; + MPOOLFILE *mfp; + char *rpath; + int ret, t_ret; + + dbmp = dbmfp->dbmp; + dbenv = dbmp->dbenv; + ret = 0; + + PANIC_CHECK(dbenv); + +#ifdef HAVE_RPC + if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) + return (__dbcl_memp_fclose(dbmfp)); +#endif + + /* + * Remove the DB_MPOOLFILE from the queue. This has to happen before + * we perform any action that can fail, otherwise __memp_close may + * loop infinitely when calling us to discard all of the DB_MPOOLFILEs. + */ + for (;;) { + MUTEX_THREAD_LOCK(dbenv, dbmp->mutexp); + + /* + * We have to reference count DB_MPOOLFILE structures as other + * threads may be using them. The problem only happens if the + * application makes a bad design choice. Here's the path: + * + * Thread A opens a database. + * Thread B uses thread A's DB_MPOOLFILE to write a buffer + * in order to free up memory in the mpool cache. + * Thread A closes the database while thread B is using the + * DB_MPOOLFILE structure. + * + * By opening all databases before creating the threads, and + * closing them after the threads have exited, applications + * get better performance and avoid the problem path entirely. + * + * Regardless, holding the DB_MPOOLFILE to flush a dirty buffer + * is a short-term lock, even in worst case, since we better be + * the only thread of control using the DB_MPOOLFILE structure + * to read pages *into* the cache. Wait until we're the only + * reference holder and remove the DB_MPOOLFILE structure from + * the list, so nobody else can even find it. + */ + if (dbmfp->ref == 1) { + TAILQ_REMOVE(&dbmp->dbmfq, dbmfp, q); + break; + } + MUTEX_THREAD_UNLOCK(dbenv, dbmp->mutexp); + + (void)__os_sleep(dbenv, 1, 0); + } + MUTEX_THREAD_UNLOCK(dbenv, dbmp->mutexp); + + /* Complain if pinned blocks never returned. */ + if (dbmfp->pinref != 0) + __db_err(dbenv, "%s: close: %lu blocks left pinned", + __memp_fn(dbmfp), (u_long)dbmfp->pinref); + + /* Discard any mmap information. */ + if (dbmfp->addr != NULL && + (ret = __os_unmapfile(dbenv, dbmfp->addr, dbmfp->len)) != 0) + __db_err(dbenv, "%s: %s", __memp_fn(dbmfp), db_strerror(ret)); + + /* Close the file; temporary files may not yet have been created. */ + if (F_ISSET(&dbmfp->fh, DB_FH_VALID) && + (t_ret = __os_closehandle(&dbmfp->fh)) != 0) { + __db_err(dbenv, "%s: %s", __memp_fn(dbmfp), db_strerror(t_ret)); + if (ret != 0) + t_ret = ret; + } + + /* Discard the thread mutex. */ + if (dbmfp->mutexp != NULL) + __db_mutex_free(dbenv, dbmp->reginfo, dbmfp->mutexp); + + /* + * Discard our reference on the the underlying MPOOLFILE, and close + * it if it's no longer useful to anyone. + * + * If we're not discarding it, and it's a temp file, this means + * all the outstanding references belong to unflushed buffers. + * (A temp file can only be referenced by one DB_MPOOLFILE). + * We don't care about preserving any of those buffers, so mark + * the MPOOLFILE as dead so that when we try to flush them, + * even the dirty ones just get discarded. + */ + R_LOCK(dbenv, dbmp->reginfo); + mfp = dbmfp->mfp; + if (--mfp->mpf_cnt == 0) { + if (F_ISSET(mfp, MP_UNLINK)) { + MEMP_FREMOVE(mfp); + if ((t_ret = __db_appname(dbmp->dbenv, + DB_APP_DATA, NULL, R_ADDR(dbmp->reginfo, + mfp->path_off), 0, NULL, &rpath)) != 0 && ret == 0) + ret = t_ret; + if (t_ret == 0 && (t_ret = + __os_unlink(dbmp->dbenv, rpath) != 0 && ret == 0)) + ret = t_ret; + __os_free(rpath, 0); + } + if (mfp->block_cnt == 0) + __memp_mf_discard(dbmp, mfp); + } + else if (F_ISSET(mfp, MP_TEMP)) + MEMP_FREMOVE(mfp); + R_UNLOCK(dbenv, dbmp->reginfo); + + /* Discard the DB_MPOOLFILE structure. */ + __os_free(dbmfp, sizeof(DB_MPOOLFILE)); + + return (ret); +} + +/* + * __memp_mf_discard -- + * Discard an MPOOLFILE. + * + * PUBLIC: void __memp_mf_discard __P((DB_MPOOL *, MPOOLFILE *)); + */ +void +__memp_mf_discard(dbmp, mfp) + DB_MPOOL *dbmp; + MPOOLFILE *mfp; +{ + MPOOL *mp; + + mp = dbmp->reginfo[0].primary; + + /* Delete from the list of MPOOLFILEs. */ + SH_TAILQ_REMOVE(&mp->mpfq, mfp, q, __mpoolfile); + + /* Free the space. */ + if (mfp->path_off != 0) + __db_shalloc_free(dbmp->reginfo[0].addr, + R_ADDR(dbmp->reginfo, mfp->path_off)); + if (mfp->fileid_off != 0) + __db_shalloc_free(dbmp->reginfo[0].addr, + R_ADDR(dbmp->reginfo, mfp->fileid_off)); + if (mfp->pgcookie_off != 0) + __db_shalloc_free(dbmp->reginfo[0].addr, + R_ADDR(dbmp->reginfo, mfp->pgcookie_off)); + __db_shalloc_free(dbmp->reginfo[0].addr, mfp); +} + +/* + * __memp_fremove -- + * Remove an underlying file from the system. + * + * PUBLIC: int __memp_fremove __P((DB_MPOOLFILE *)); + */ +int +__memp_fremove(dbmfp) + DB_MPOOLFILE *dbmfp; +{ + DB_ENV *dbenv; + DB_MPOOL *dbmp; + MPOOLFILE *mfp; + + dbmp = dbmfp->dbmp; + dbenv = dbmp->dbenv; + mfp = dbmfp->mfp; + + PANIC_CHECK(dbenv); + + R_LOCK(dbenv, dbmp->reginfo); + + MEMP_FREMOVE(mfp); + + R_UNLOCK(dbenv, dbmp->reginfo); + + return (0); +} + +/* + * __memp_fn -- + * On errors we print whatever is available as the file name. + * + * PUBLIC: char * __memp_fn __P((DB_MPOOLFILE *)); + */ +char * +__memp_fn(dbmfp) + DB_MPOOLFILE *dbmfp; +{ + return (__memp_fns(dbmfp->dbmp, dbmfp->mfp)); +} + +/* + * __memp_fns -- + * On errors we print whatever is available as the file name. + * + * PUBLIC: char * __memp_fns __P((DB_MPOOL *, MPOOLFILE *)); + * + */ +char * +__memp_fns(dbmp, mfp) + DB_MPOOL *dbmp; + MPOOLFILE *mfp; +{ + if (mfp->path_off == 0) + return ((char *)"temporary"); + + return ((char *)R_ADDR(dbmp->reginfo, mfp->path_off)); +} diff --git a/db/mp/mp_fput.c b/db/mp/mp_fput.c new file mode 100644 index 000000000..be03b721f --- /dev/null +++ b/db/mp/mp_fput.c @@ -0,0 +1,186 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: mp_fput.c,v 11.16 2000/11/30 00:58:41 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#endif + +#ifdef HAVE_RPC +#include "db_server.h" +#endif + +#include "db_int.h" +#include "db_shash.h" +#include "mp.h" + +#ifdef HAVE_RPC +#include "gen_client_ext.h" +#include "rpc_client_ext.h" +#endif + +/* + * memp_fput -- + * Mpool file put function. + */ +int +memp_fput(dbmfp, pgaddr, flags) + DB_MPOOLFILE *dbmfp; + void *pgaddr; + u_int32_t flags; +{ + BH *bhp; + DB_ENV *dbenv; + DB_MPOOL *dbmp; + MPOOL *c_mp, *mp; + int ret, wrote; + + dbmp = dbmfp->dbmp; + dbenv = dbmp->dbenv; + mp = dbmp->reginfo[0].primary; + +#ifdef HAVE_RPC + if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) + return (__dbcl_memp_fput(dbmfp, pgaddr, flags)); +#endif + + PANIC_CHECK(dbenv); + + /* Validate arguments. */ + if (flags) { + if ((ret = __db_fchk(dbenv, "memp_fput", flags, + DB_MPOOL_CLEAN | DB_MPOOL_DIRTY | DB_MPOOL_DISCARD)) != 0) + return (ret); + if ((ret = __db_fcchk(dbenv, "memp_fput", + flags, DB_MPOOL_CLEAN, DB_MPOOL_DIRTY)) != 0) + return (ret); + + if (LF_ISSET(DB_MPOOL_DIRTY) && F_ISSET(dbmfp, MP_READONLY)) { + __db_err(dbenv, + "%s: dirty flag set for readonly file page", + __memp_fn(dbmfp)); + return (EACCES); + } + } + + R_LOCK(dbenv, dbmp->reginfo); + + /* Decrement the pinned reference count. */ + if (dbmfp->pinref == 0) { + __db_err(dbenv, + "%s: more pages returned than retrieved", __memp_fn(dbmfp)); + R_UNLOCK(dbenv, dbmp->reginfo); + return (EINVAL); + } else + --dbmfp->pinref; + + /* + * If we're mapping the file, there's nothing to do. Because we can + * stop mapping the file at any time, we have to check on each buffer + * to see if the address we gave the application was part of the map + * region. + */ + if (dbmfp->addr != NULL && pgaddr >= dbmfp->addr && + (u_int8_t *)pgaddr <= (u_int8_t *)dbmfp->addr + dbmfp->len) { + R_UNLOCK(dbenv, dbmp->reginfo); + return (0); + } + + /* Convert the page address to a buffer header. */ + bhp = (BH *)((u_int8_t *)pgaddr - SSZA(BH, buf)); + + /* Convert the buffer header to a cache. */ + c_mp = BH_TO_CACHE(dbmp, bhp); + +/* UNLOCK THE REGION, LOCK THE CACHE. */ + + /* Set/clear the page bits. */ + if (LF_ISSET(DB_MPOOL_CLEAN) && F_ISSET(bhp, BH_DIRTY)) { + ++c_mp->stat.st_page_clean; + --c_mp->stat.st_page_dirty; + F_CLR(bhp, BH_DIRTY); + } + if (LF_ISSET(DB_MPOOL_DIRTY) && !F_ISSET(bhp, BH_DIRTY)) { + --c_mp->stat.st_page_clean; + ++c_mp->stat.st_page_dirty; + F_SET(bhp, BH_DIRTY); + } + if (LF_ISSET(DB_MPOOL_DISCARD)) + F_SET(bhp, BH_DISCARD); + + /* + * If the page is dirty and being scheduled to be written as part of + * a checkpoint, we no longer know that the log is up-to-date. + */ + if (F_ISSET(bhp, BH_DIRTY) && F_ISSET(bhp, BH_SYNC)) + F_SET(bhp, BH_SYNC_LOGFLSH); + + /* + * Check for a reference count going to zero. This can happen if the + * application returns a page twice. + */ + if (bhp->ref == 0) { + __db_err(dbenv, "%s: page %lu: unpinned page returned", + __memp_fn(dbmfp), (u_long)bhp->pgno); + R_UNLOCK(dbenv, dbmp->reginfo); + return (EINVAL); + } + + /* + * If more than one reference to the page, we're done. Ignore the + * discard flags (for now) and leave it at its position in the LRU + * chain. The rest gets done at last reference close. + */ + if (--bhp->ref > 0) { + R_UNLOCK(dbenv, dbmp->reginfo); + return (0); + } + + /* + * Move the buffer to the head/tail of the LRU chain. We do this + * before writing the buffer for checkpoint purposes, as the write + * can discard the region lock and allow another process to acquire + * buffer. We could keep that from happening, but there seems no + * reason to do so. + */ + SH_TAILQ_REMOVE(&c_mp->bhq, bhp, q, __bh); + if (F_ISSET(bhp, BH_DISCARD)) + SH_TAILQ_INSERT_HEAD(&c_mp->bhq, bhp, q, __bh); + else + SH_TAILQ_INSERT_TAIL(&c_mp->bhq, bhp, q); + + /* + * If this buffer is scheduled for writing because of a checkpoint, we + * need to write it (if it's dirty), or update the checkpoint counters + * (if it's not dirty). If we try to write it and can't, that's not + * necessarily an error as it's not completely unreasonable that the + * application have permission to write the underlying file, but set a + * flag so that the next time the memp_sync function is called we try + * writing it there, as the checkpoint thread of control better be able + * to write all of the files. + */ + if (F_ISSET(bhp, BH_SYNC)) { + if (F_ISSET(bhp, BH_DIRTY)) { + if (__memp_bhwrite(dbmp, + dbmfp->mfp, bhp, NULL, &wrote) != 0 || !wrote) + F_SET(mp, MP_LSN_RETRY); + } else { + F_CLR(bhp, BH_SYNC); + + --mp->lsn_cnt; + --dbmfp->mfp->lsn_cnt; + } + } + + R_UNLOCK(dbenv, dbmp->reginfo); + return (0); +} diff --git a/db/mp/mp_fset.c b/db/mp/mp_fset.c new file mode 100644 index 000000000..08313c9b6 --- /dev/null +++ b/db/mp/mp_fset.c @@ -0,0 +1,98 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: mp_fset.c,v 11.13 2000/11/30 00:58:41 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#endif + +#ifdef HAVE_RPC +#include "db_server.h" +#endif + +#include "db_int.h" +#include "db_shash.h" +#include "mp.h" + +#ifdef HAVE_RPC +#include "gen_client_ext.h" +#include "rpc_client_ext.h" +#endif + +/* + * memp_fset -- + * Mpool page set-flag routine. + */ +int +memp_fset(dbmfp, pgaddr, flags) + DB_MPOOLFILE *dbmfp; + void *pgaddr; + u_int32_t flags; +{ + BH *bhp; + DB_ENV *dbenv; + DB_MPOOL *dbmp; + MPOOL *c_mp, *mp; + int ret; + + dbmp = dbmfp->dbmp; + dbenv = dbmp->dbenv; + mp = dbmp->reginfo[0].primary; + +#ifdef HAVE_RPC + if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) + return (__dbcl_memp_fset(dbmfp, pgaddr, flags)); +#endif + + PANIC_CHECK(dbenv); + + /* Validate arguments. */ + if (flags == 0) + return (__db_ferr(dbenv, "memp_fset", 1)); + + if ((ret = __db_fchk(dbenv, "memp_fset", flags, + DB_MPOOL_DIRTY | DB_MPOOL_CLEAN | DB_MPOOL_DISCARD)) != 0) + return (ret); + if ((ret = __db_fcchk(dbenv, "memp_fset", + flags, DB_MPOOL_CLEAN, DB_MPOOL_DIRTY)) != 0) + return (ret); + + if (LF_ISSET(DB_MPOOL_DIRTY) && F_ISSET(dbmfp, MP_READONLY)) { + __db_err(dbenv, "%s: dirty flag set for readonly file page", + __memp_fn(dbmfp)); + return (EACCES); + } + + /* Convert the page address to a buffer header. */ + bhp = (BH *)((u_int8_t *)pgaddr - SSZA(BH, buf)); + + /* Convert the buffer header to a cache. */ + c_mp = BH_TO_CACHE(dbmp, bhp); + + R_LOCK(dbenv, dbmp->reginfo); + + if (LF_ISSET(DB_MPOOL_CLEAN) && F_ISSET(bhp, BH_DIRTY)) { + ++c_mp->stat.st_page_clean; + --c_mp->stat.st_page_dirty; + F_CLR(bhp, BH_DIRTY); + } + if (LF_ISSET(DB_MPOOL_DIRTY) && !F_ISSET(bhp, BH_DIRTY)) { + --c_mp->stat.st_page_clean; + ++c_mp->stat.st_page_dirty; + F_SET(bhp, BH_DIRTY); + } + if (LF_ISSET(DB_MPOOL_DISCARD)) + F_SET(bhp, BH_DISCARD); + + R_UNLOCK(dbenv, dbmp->reginfo); + return (0); +} diff --git a/db/mp/mp_method.c b/db/mp/mp_method.c new file mode 100644 index 000000000..85a6239b0 --- /dev/null +++ b/db/mp/mp_method.c @@ -0,0 +1,115 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: mp_method.c,v 11.10 2000/04/04 20:12:04 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include +#endif + +#ifdef HAVE_RPC +#include "db_server.h" +#endif + +#include "db_int.h" +#include "db_shash.h" +#include "mp.h" + +#ifdef HAVE_RPC +#include "gen_client_ext.h" +#include "rpc_client_ext.h" +#endif + +static int __memp_set_cachesize __P((DB_ENV *, u_int32_t, u_int32_t, int)); +static int __memp_set_mp_mmapsize __P((DB_ENV *, size_t)); + +/* + * __memp_dbenv_create -- + * Mpool specific creation of the DB_ENV structure. + * + * PUBLIC: void __memp_dbenv_create __P((DB_ENV *)); + */ +void +__memp_dbenv_create(dbenv) + DB_ENV *dbenv; +{ + /* + * We default to 32 8K pages. We don't default to a flat 256K, because + * some systems require significantly more memory to hold 32 pages than + * others. For example, HP-UX with POSIX pthreads needs 88 bytes for + * a POSIX pthread mutex and almost 200 bytes per buffer header, while + * Solaris needs 24 and 52 bytes for the same structures. + */ + dbenv->mp_bytes = 32 * ((8 * 1024) + sizeof(BH)); + dbenv->mp_ncache = 1; + + dbenv->set_mp_mmapsize = __memp_set_mp_mmapsize; + dbenv->set_cachesize = __memp_set_cachesize; + +#ifdef HAVE_RPC + /* + * If we have a client, overwrite what we just setup to + * point to client functions. + */ + if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) { + dbenv->set_cachesize = __dbcl_env_cachesize; + dbenv->set_mp_mmapsize = __dbcl_set_mp_mmapsize; + } +#endif + +} + +/* + * __memp_set_cachesize -- + * Initialize the cache size. + */ +static int +__memp_set_cachesize(dbenv, gbytes, bytes, ncache) + DB_ENV *dbenv; + u_int32_t gbytes, bytes; + int ncache; +{ + ENV_ILLEGAL_AFTER_OPEN(dbenv, "set_cachesize"); + + dbenv->mp_gbytes = gbytes + bytes / GIGABYTE; + dbenv->mp_bytes = bytes % GIGABYTE; + dbenv->mp_ncache = ncache == 0 ? 1 : ncache; + + /* + * If the application requested less than 500Mb, increase the + * cachesize by 25% to account for our overhead. (I'm guessing + * that caches over 500Mb are specifically sized, i.e., it's + * a large server and the application actually knows how much + * memory is available.) + * + * There is a minimum cache size, regardless. + */ + if (dbenv->mp_gbytes == 0) { + if (dbenv->mp_bytes < 500 * MEGABYTE) + dbenv->mp_bytes += dbenv->mp_bytes / 4; + if (dbenv->mp_bytes < DB_CACHESIZE_MIN) + dbenv->mp_bytes = DB_CACHESIZE_MIN; + } + + return (0); +} + +/* + * __memp_set_mp_mmapsize -- + * Set the maximum mapped file size. + */ +static int +__memp_set_mp_mmapsize(dbenv, mp_mmapsize ) + DB_ENV *dbenv; + size_t mp_mmapsize; +{ + dbenv->mp_mmapsize = mp_mmapsize; + return (0); +} diff --git a/db/mp/mp_region.c b/db/mp/mp_region.c new file mode 100644 index 000000000..4b85466ce --- /dev/null +++ b/db/mp/mp_region.c @@ -0,0 +1,357 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: mp_region.c,v 11.26 2000/11/30 00:58:41 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_shash.h" +#include "mp.h" + +static int __mpool_init __P((DB_ENV *, DB_MPOOL *, int, int)); +#ifdef MUTEX_SYSTEM_RESOURCES +static size_t __mpool_region_maint __P((REGINFO *)); +#endif + +/* + * __memp_open -- + * Internal version of memp_open: only called from DB_ENV->open. + * + * PUBLIC: int __memp_open __P((DB_ENV *)); + */ +int +__memp_open(dbenv) + DB_ENV *dbenv; +{ + DB_MPOOL *dbmp; + MPOOL *mp; + REGINFO reginfo; + roff_t reg_size, *regids; + u_int32_t i; + int htab_buckets, ret; + + /* Figure out how big each cache region is. */ + reg_size = (dbenv->mp_gbytes / dbenv->mp_ncache) * GIGABYTE; + reg_size += ((dbenv->mp_gbytes % + dbenv->mp_ncache) * GIGABYTE) / dbenv->mp_ncache; + reg_size += dbenv->mp_bytes / dbenv->mp_ncache; + + /* + * Figure out how many hash buckets each region will have. Assume we + * want to keep the hash chains with under 10 pages on each chain. We + * don't know the pagesize in advance, and it may differ for different + * files. Use a pagesize of 1K for the calculation -- we walk these + * chains a lot, they must be kept short. + */ + htab_buckets = __db_tablesize((reg_size / (1 * 1024)) / 10); + + /* Create and initialize the DB_MPOOL structure. */ + if ((ret = __os_calloc(dbenv, 1, sizeof(*dbmp), &dbmp)) != 0) + return (ret); + LIST_INIT(&dbmp->dbregq); + TAILQ_INIT(&dbmp->dbmfq); + dbmp->dbenv = dbenv; + + /* Join/create the first mpool region. */ + memset(®info, 0, sizeof(REGINFO)); + reginfo.type = REGION_TYPE_MPOOL; + reginfo.id = INVALID_REGION_ID; + reginfo.mode = dbenv->db_mode; + reginfo.flags = REGION_JOIN_OK; + if (F_ISSET(dbenv, DB_ENV_CREATE)) + F_SET(®info, REGION_CREATE_OK); + if ((ret = __db_r_attach(dbenv, ®info, reg_size)) != 0) + goto err; + + /* + * If we created the region, initialize it. Create or join any + * additional regions. + */ + if (F_ISSET(®info, REGION_CREATE)) { + /* + * We define how many regions there are going to be, allocate + * the REGINFO structures and create them. Make sure we don't + * clear the wrong entries on error. + */ + dbmp->nreg = dbenv->mp_ncache; + if ((ret = __os_calloc(dbenv, + dbmp->nreg, sizeof(REGINFO), &dbmp->reginfo)) != 0) + goto err; + /* Make sure we don't clear the wrong entries on error. */ + for (i = 0; i < dbmp->nreg; ++i) + dbmp->reginfo[i].id = INVALID_REGION_ID; + dbmp->reginfo[0] = reginfo; + + /* Initialize the first region. */ + if ((ret = __mpool_init(dbenv, dbmp, 0, htab_buckets)) != 0) + goto err; + + /* + * Create/initialize remaining regions and copy their IDs into + * the first region. + */ + mp = R_ADDR(dbmp->reginfo, dbmp->reginfo[0].rp->primary); + regids = R_ADDR(dbmp->reginfo, mp->regids); + for (i = 1; i < dbmp->nreg; ++i) { + dbmp->reginfo[i].type = REGION_TYPE_MPOOL; + dbmp->reginfo[i].id = INVALID_REGION_ID; + dbmp->reginfo[i].mode = dbenv->db_mode; + dbmp->reginfo[i].flags = REGION_CREATE_OK; + if ((ret = __db_r_attach( + dbenv, &dbmp->reginfo[i], reg_size)) != 0) + goto err; + if ((ret = + __mpool_init(dbenv, dbmp, i, htab_buckets)) != 0) + goto err; + R_UNLOCK(dbenv, &dbmp->reginfo[i]); + + regids[i] = dbmp->reginfo[i].id; + } + } else { + /* + * Determine how many regions there are going to be, allocate + * the REGINFO structures and fill in local copies of that + * information. + */ + mp = R_ADDR(®info, reginfo.rp->primary); + dbmp->nreg = mp->nreg; + if ((ret = __os_calloc(dbenv, + dbmp->nreg, sizeof(REGINFO), &dbmp->reginfo)) != 0) + goto err; + /* Make sure we don't clear the wrong entries on error. */ + for (i = 0; i < dbmp->nreg; ++i) + dbmp->reginfo[i].id = INVALID_REGION_ID; + dbmp->reginfo[0] = reginfo; + + /* Join remaining regions. */ + regids = R_ADDR(dbmp->reginfo, mp->regids); + for (i = 1; i < dbmp->nreg; ++i) { + dbmp->reginfo[i].type = REGION_TYPE_MPOOL; + dbmp->reginfo[i].id = regids[i]; + dbmp->reginfo[i].mode = 0; + dbmp->reginfo[i].flags = REGION_JOIN_OK; + if ((ret = __db_r_attach( + dbenv, &dbmp->reginfo[i], 0)) != 0) + goto err; + R_UNLOCK(dbenv, &dbmp->reginfo[i]); + } + } + + /* Set the local addresses for the regions. */ + for (i = 0; i < dbmp->nreg; ++i) + dbmp->reginfo[i].primary = + R_ADDR(&dbmp->reginfo[i], dbmp->reginfo[i].rp->primary); + + /* If the region is threaded, allocate a mutex to lock the handles. */ + if (F_ISSET(dbenv, DB_ENV_THREAD)) { + if ((ret = __db_mutex_alloc( + dbenv, dbmp->reginfo, &dbmp->mutexp)) != 0) { + goto err; + } + if ((ret = + __db_mutex_init(dbenv, dbmp->mutexp, 0, MUTEX_THREAD)) != 0) + goto err; + } + + R_UNLOCK(dbenv, dbmp->reginfo); + + dbenv->mp_handle = dbmp; + return (0); + +err: if (dbmp->reginfo != NULL && dbmp->reginfo[0].addr != NULL) { + if (F_ISSET(dbmp->reginfo, REGION_CREATE)) + ret = __db_panic(dbenv, ret); + + R_UNLOCK(dbenv, dbmp->reginfo); + + for (i = 0; i < dbmp->nreg; ++i) + if (dbmp->reginfo[i].id != INVALID_REGION_ID) + (void)__db_r_detach( + dbenv, &dbmp->reginfo[i], 0); + __os_free(dbmp->reginfo, + dbmp->nreg * sizeof(*dbmp->reginfo)); + } + if (dbmp->mutexp != NULL) + __db_mutex_free(dbenv, dbmp->reginfo, dbmp->mutexp); + __os_free(dbmp, sizeof(*dbmp)); + return (ret); +} + +/* + * __mpool_init -- + * Initialize a MPOOL structure in shared memory. + */ +static int +__mpool_init(dbenv, dbmp, reginfo_off, htab_buckets) + DB_ENV *dbenv; + DB_MPOOL *dbmp; + int reginfo_off, htab_buckets; +{ + DB_HASHTAB *htab; + MPOOL *mp; + REGINFO *reginfo; +#ifdef MUTEX_SYSTEM_RESOURCES + size_t maint_size; +#endif + int ret; + void *p; + + mp = NULL; + + reginfo = &dbmp->reginfo[reginfo_off]; + if ((ret = __db_shalloc(reginfo->addr, + sizeof(MPOOL), MUTEX_ALIGN, ®info->primary)) != 0) + goto mem_err; + reginfo->rp->primary = R_OFFSET(reginfo, reginfo->primary); + mp = reginfo->primary; + memset(mp, 0, sizeof(*mp)); + +#ifdef MUTEX_SYSTEM_RESOURCES + maint_size = __mpool_region_maint(reginfo); + /* Allocate room for the maintenance info and initialize it. */ + if ((ret = __db_shalloc(reginfo->addr, + sizeof(REGMAINT) + maint_size, 0, &p)) != 0) + goto mem_err; + __db_maintinit(reginfo, p, maint_size); + mp->maint_off = R_OFFSET(reginfo, p); +#endif + + if (reginfo_off == 0) { + SH_TAILQ_INIT(&mp->mpfq); + + if ((ret = __db_shmutex_init(dbenv, &mp->sync_mutex, + R_OFFSET(dbmp->reginfo, &mp->sync_mutex) + + DB_FCNTL_OFF_MPOOL, 0, dbmp->reginfo, + (REGMAINT *)R_ADDR(dbmp->reginfo, mp->maint_off))) != 0) + goto err; + + ZERO_LSN(mp->lsn); + mp->lsn_cnt = 0; + + mp->nreg = dbmp->nreg; + if ((ret = __db_shalloc(dbmp->reginfo[0].addr, + dbmp->nreg * sizeof(int), 0, &p)) != 0) + goto mem_err; + mp->regids = R_OFFSET(dbmp->reginfo, p); + } + + SH_TAILQ_INIT(&mp->bhq); + + /* Allocate hash table space and initialize it. */ + if ((ret = __db_shalloc(reginfo->addr, + htab_buckets * sizeof(DB_HASHTAB), 0, &htab)) != 0) + goto mem_err; + __db_hashinit(htab, htab_buckets); + mp->htab = R_OFFSET(reginfo, htab); + mp->htab_buckets = htab_buckets; + + return (0); + +mem_err:__db_err(dbenv, "Unable to allocate memory for mpool region"); +err: if (reginfo->primary != NULL) + __db_shalloc_free(reginfo->addr, reginfo->primary); + return (ret); +} + +/* + * __memp_close -- + * Internal version of memp_close: only called from DB_ENV->close. + * + * PUBLIC: int __memp_close __P((DB_ENV *)); + */ +int +__memp_close(dbenv) + DB_ENV *dbenv; +{ + DB_MPOOL *dbmp; + DB_MPOOLFILE *dbmfp; + DB_MPREG *mpreg; + u_int32_t i; + int ret, t_ret; + + ret = 0; + dbmp = dbenv->mp_handle; + + /* Discard DB_MPREGs. */ + while ((mpreg = LIST_FIRST(&dbmp->dbregq)) != NULL) { + LIST_REMOVE(mpreg, q); + __os_free(mpreg, sizeof(DB_MPREG)); + } + + /* Discard DB_MPOOLFILEs. */ + while ((dbmfp = TAILQ_FIRST(&dbmp->dbmfq)) != NULL) + if ((t_ret = memp_fclose(dbmfp)) != 0 && ret == 0) + ret = t_ret; + + /* Discard the thread mutex. */ + if (dbmp->mutexp != NULL) + __db_mutex_free(dbenv, dbmp->reginfo, dbmp->mutexp); + + /* Detach from the region(s). */ + for (i = 0; i < dbmp->nreg; ++i) + if ((t_ret = __db_r_detach( + dbenv, &dbmp->reginfo[i], 0)) != 0 && ret == 0) + ret = t_ret; + + __os_free(dbmp->reginfo, dbmp->nreg * sizeof(*dbmp->reginfo)); + __os_free(dbmp, sizeof(*dbmp)); + + dbenv->mp_handle = NULL; + return (ret); +} + +#ifdef MUTEX_SYSTEM_RESOURCES +/* + * __mpool_region_maint -- + * Return the amount of space needed for region maintenance info. + * + */ +static size_t +__mpool_region_maint(infop) + REGINFO *infop; +{ + size_t s; + int numlocks; + + /* + * For mutex maintenance we need one mutex per possible page. + * Compute the maximum number of pages this cache can have. + * Also add in an mpool mutex. + */ + numlocks = ((infop->rp->size / DB_MIN_PGSIZE) + 1); + s = sizeof(roff_t) * numlocks; + return (s); +} +#endif + +/* + * __mpool_region_destroy + * Destroy any region maintenance info. + * + * PUBLIC: void __mpool_region_destroy __P((DB_ENV *, REGINFO *)); + */ +void +__mpool_region_destroy(dbenv, infop) + DB_ENV *dbenv; + REGINFO *infop; +{ + MPOOL *mp; + + COMPQUIET(dbenv, NULL); + mp = R_ADDR(infop, infop->rp->primary); + + __db_shlocks_destroy(infop, (REGMAINT *)R_ADDR(infop, mp->maint_off)); + return; +} diff --git a/db/mp/mp_register.c b/db/mp/mp_register.c new file mode 100644 index 000000000..27859f69d --- /dev/null +++ b/db/mp/mp_register.c @@ -0,0 +1,85 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: mp_register.c,v 11.12 2000/11/15 19:25:39 sue Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include +#endif + +#ifdef HAVE_RPC +#include "db_server.h" +#endif + +#include "db_int.h" +#include "db_shash.h" +#include "mp.h" + +#ifdef HAVE_RPC +#include "gen_client_ext.h" +#include "rpc_client_ext.h" +#endif + +/* + * memp_register -- + * Register a file type's pgin, pgout routines. + */ +int +memp_register(dbenv, ftype, pgin, pgout) + DB_ENV *dbenv; + int ftype; + int (*pgin) __P((DB_ENV *, db_pgno_t, void *, DBT *)); + int (*pgout) __P((DB_ENV *, db_pgno_t, void *, DBT *)); +{ + DB_MPOOL *dbmp; + DB_MPREG *mpreg; + int ret; + +#ifdef HAVE_RPC + if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) + return (__dbcl_memp_register(dbenv, ftype, pgin, pgout)); +#endif + + PANIC_CHECK(dbenv); + ENV_REQUIRES_CONFIG(dbenv, dbenv->mp_handle, DB_INIT_MPOOL); + + dbmp = dbenv->mp_handle; + + /* + * Chances are good that the item has already been registered, as the + * DB access methods are the folks that call this routine. If already + * registered, just update the entry, although it's probably unchanged. + */ + MUTEX_THREAD_LOCK(dbenv, dbmp->mutexp); + for (mpreg = LIST_FIRST(&dbmp->dbregq); + mpreg != NULL; mpreg = LIST_NEXT(mpreg, q)) + if (mpreg->ftype == ftype) { + mpreg->pgin = pgin; + mpreg->pgout = pgout; + break; + } + MUTEX_THREAD_UNLOCK(dbenv, dbmp->mutexp); + if (mpreg != NULL) + return (0); + + /* New entry. */ + if ((ret = __os_malloc(dbenv, sizeof(DB_MPREG), NULL, &mpreg)) != 0) + return (ret); + + mpreg->ftype = ftype; + mpreg->pgin = pgin; + mpreg->pgout = pgout; + + MUTEX_THREAD_LOCK(dbenv, dbmp->mutexp); + LIST_INSERT_HEAD(&dbmp->dbregq, mpreg, q); + MUTEX_THREAD_UNLOCK(dbenv, dbmp->mutexp); + + return (0); +} diff --git a/db/mp/mp_stat.c b/db/mp/mp_stat.c new file mode 100644 index 000000000..798251344 --- /dev/null +++ b/db/mp/mp_stat.c @@ -0,0 +1,388 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: mp_stat.c,v 11.21 2001/01/09 16:59:30 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#endif + +#ifdef HAVE_RPC +#include "db_server.h" +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_shash.h" +#include "db_am.h" +#include "mp.h" + +#ifdef HAVE_RPC +#include "gen_client_ext.h" +#include "rpc_client_ext.h" +#endif + +static void __memp_dumpcache + __P((DB_MPOOL *, REGINFO *, size_t *, FILE *, u_int32_t)); +static void __memp_pbh __P((DB_MPOOL *, BH *, size_t *, FILE *)); + +/* + * memp_stat -- + * Display MPOOL statistics. + */ +int +memp_stat(dbenv, gspp, fspp, db_malloc) + DB_ENV *dbenv; + DB_MPOOL_STAT **gspp; + DB_MPOOL_FSTAT ***fspp; + void *(*db_malloc) __P((size_t)); +{ + DB_MPOOL *dbmp; + DB_MPOOL_FSTAT **tfsp, *tstruct; + DB_MPOOL_STAT *sp; + MPOOL *c_mp, *mp; + MPOOLFILE *mfp; + char *tname; + size_t len, nlen; + u_int32_t i; + int ret; + char *name; + +#ifdef HAVE_RPC + if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) + return (__dbcl_memp_stat(dbenv, gspp, fspp, db_malloc)); +#endif + + PANIC_CHECK(dbenv); + ENV_REQUIRES_CONFIG(dbenv, dbenv->mp_handle, DB_INIT_MPOOL); + + dbmp = dbenv->mp_handle; + sp = NULL; + + /* Global statistics. */ + mp = dbmp->reginfo[0].primary; + if (gspp != NULL) { + *gspp = NULL; + + if ((ret = __os_calloc(dbenv, 1, sizeof(**gspp), gspp)) != 0) + return (ret); + sp = *gspp; + + /* + * Initialization and information that is not maintained on + * a per-cache basis. + */ + sp->st_hash_longest = 0; + sp->st_region_wait = dbmp->reginfo[0].rp->mutex.mutex_set_wait; + sp->st_region_nowait = + dbmp->reginfo[0].rp->mutex.mutex_set_nowait; + sp->st_gbytes = dbenv->mp_gbytes; + sp->st_bytes = dbenv->mp_bytes; + sp->st_ncache = dbmp->nreg; + sp->st_regsize = dbmp->reginfo[0].rp->size; + + R_LOCK(dbenv, dbmp->reginfo); + + /* Walk the cache list and accumulate the global information. */ + for (i = 0; i < mp->nreg; ++i) { + c_mp = dbmp->reginfo[i].primary; + sp->st_cache_hit += c_mp->stat.st_cache_hit; + sp->st_cache_miss += c_mp->stat.st_cache_miss; + sp->st_map += c_mp->stat.st_map; + sp->st_page_create += c_mp->stat.st_page_create; + sp->st_page_in += c_mp->stat.st_page_in; + sp->st_page_out += c_mp->stat.st_page_out; + sp->st_ro_evict += c_mp->stat.st_ro_evict; + sp->st_rw_evict += c_mp->stat.st_rw_evict; + sp->st_hash_buckets += c_mp->stat.st_hash_buckets; + sp->st_hash_searches += c_mp->stat.st_hash_searches; + if (c_mp->stat.st_hash_longest > sp->st_hash_longest) + sp->st_hash_longest = + c_mp->stat.st_hash_longest; + sp->st_hash_examined += c_mp->stat.st_hash_examined; + sp->st_page_clean += c_mp->stat.st_page_clean; + sp->st_page_dirty += c_mp->stat.st_page_dirty; + sp->st_page_trickle += c_mp->stat.st_page_trickle; + sp->st_region_wait += c_mp->stat.st_region_wait; + sp->st_region_nowait += c_mp->stat.st_region_nowait; + } + + /* + * We have duplicate statistics fields in the cache and + * per-file structures. The counters are only incremented + * in the per-file structures, though. The intent is that + * if we ever flush files from the pool we can save their + * last known totals in the cache structure. + */ + for (mfp = SH_TAILQ_FIRST(&mp->mpfq, __mpoolfile); + mfp != NULL; mfp = SH_TAILQ_NEXT(mfp, q, __mpoolfile)) { + sp->st_cache_hit += mfp->stat.st_cache_hit; + sp->st_cache_miss += mfp->stat.st_cache_miss; + sp->st_map += mfp->stat.st_map; + sp->st_page_create += mfp->stat.st_page_create; + sp->st_page_in += mfp->stat.st_page_in; + sp->st_page_out += mfp->stat.st_page_out; + } + + R_UNLOCK(dbenv, dbmp->reginfo); + } + + /* Per-file statistics. */ + if (fspp != NULL) { + *fspp = NULL; + + R_LOCK(dbenv, dbmp->reginfo); + + /* Count the MPOOLFILE structures. */ + for (i = 0, len = 0, + mfp = SH_TAILQ_FIRST(&mp->mpfq, __mpoolfile); + mfp != NULL; + ++i, mfp = SH_TAILQ_NEXT(mfp, q, __mpoolfile)) + len += sizeof(DB_MPOOL_FSTAT *) + + sizeof(DB_MPOOL_FSTAT) + + strlen(__memp_fns(dbmp, mfp)) + 1; + len += sizeof(DB_MPOOL_FSTAT *); /* Trailing NULL */ + + R_UNLOCK(dbenv, dbmp->reginfo); + + if (len == 0) + return (0); + + /* Allocate space */ + if ((ret = __os_malloc(dbenv, len, db_malloc, fspp)) != 0) + return (ret); + + R_LOCK(dbenv, dbmp->reginfo); + + /* + * Build each individual entry. We assume that an array of + * pointers are aligned correctly to be followed by an array + * of structures, which should be safe (in this particular + * case, the first element of the structure is a pointer, so + * we're doubly safe). The array is followed by space for + * the text file names. + * + * Add 1 to i because we need to skip over the NULL. + */ + tfsp = *fspp; + tstruct = (DB_MPOOL_FSTAT *)(tfsp + i + 1); + tname = (char *)(tstruct + i); + + for (mfp = SH_TAILQ_FIRST(&mp->mpfq, __mpoolfile); + mfp != NULL; + ++tfsp, ++tstruct, tname += nlen, + mfp = SH_TAILQ_NEXT(mfp, q, __mpoolfile)) { + name = __memp_fns(dbmp, mfp); + nlen = strlen(name) + 1; + *tfsp = tstruct; + *tstruct = mfp->stat; + tstruct->file_name = tname; + memcpy(tname, name, nlen); + } + *tfsp = NULL; + + R_UNLOCK(dbenv, dbmp->reginfo); + } + return (0); +} + +#define FMAP_ENTRIES 200 /* Files we map. */ + +#define MPOOL_DUMP_HASH 0x01 /* Debug hash chains. */ +#define MPOOL_DUMP_LRU 0x02 /* Debug LRU chains. */ +#define MPOOL_DUMP_MEM 0x04 /* Debug region memory. */ +#define MPOOL_DUMP_ALL 0x07 /* Debug all. */ + +/* + * __memp_dump_region -- + * Display MPOOL structures. + * + * PUBLIC: void __memp_dump_region __P((DB_ENV *, char *, FILE *)); + */ +void +__memp_dump_region(dbenv, area, fp) + DB_ENV *dbenv; + char *area; + FILE *fp; +{ + DB_MPOOL *dbmp; + DB_MPOOLFILE *dbmfp; + MPOOL *mp; + MPOOLFILE *mfp; + size_t fmap[FMAP_ENTRIES + 1]; + u_int32_t i, flags; + int cnt; + u_int8_t *p; + + dbmp = dbenv->mp_handle; + + /* Make it easy to call from the debugger. */ + if (fp == NULL) + fp = stderr; + + for (flags = 0; *area != '\0'; ++area) + switch (*area) { + case 'A': + LF_SET(MPOOL_DUMP_ALL); + break; + case 'h': + LF_SET(MPOOL_DUMP_HASH); + break; + case 'l': + LF_SET(MPOOL_DUMP_LRU); + break; + case 'm': + LF_SET(MPOOL_DUMP_MEM); + break; + } + + R_LOCK(dbenv, dbmp->reginfo); + + mp = dbmp->reginfo[0].primary; + + /* Display MPOOL structures. */ + (void)fprintf(fp, "%s\nPool (region addr 0x%lx)\n", + DB_LINE, (u_long)dbmp->reginfo[0].addr); + + /* Display the MPOOLFILE structures. */ + cnt = 0; + for (mfp = SH_TAILQ_FIRST(&mp->mpfq, __mpoolfile); + mfp != NULL; mfp = SH_TAILQ_NEXT(mfp, q, __mpoolfile), ++cnt) { + (void)fprintf(fp, "File #%d: %s: type %ld, %s\n\t [UID: ", + cnt + 1, __memp_fns(dbmp, mfp), (long)mfp->ftype, + F_ISSET(mfp, MP_CAN_MMAP) ? "mmap" : "read/write"); + p = R_ADDR(dbmp->reginfo, mfp->fileid_off); + for (i = 0; i < DB_FILE_ID_LEN; ++i) { + (void)fprintf(fp, "%x", *p++); + if (i < DB_FILE_ID_LEN - 1) + (void)fprintf(fp, " "); + } + (void)fprintf(fp, "]\n"); + if (cnt < FMAP_ENTRIES) + fmap[cnt] = R_OFFSET(dbmp->reginfo, mfp); + } + + for (dbmfp = TAILQ_FIRST(&dbmp->dbmfq); + dbmfp != NULL; dbmfp = TAILQ_NEXT(dbmfp, q), ++cnt) { + (void)fprintf(fp, "File #%d: %s: per-process, %s\n", + cnt + 1, __memp_fn(dbmfp), + F_ISSET(dbmfp, MP_READONLY) ? "readonly" : "read/write"); + if (cnt < FMAP_ENTRIES) + fmap[cnt] = R_OFFSET(dbmp->reginfo, mfp); + } + if (cnt < FMAP_ENTRIES) + fmap[cnt] = INVALID_ROFF; + else + fmap[FMAP_ENTRIES] = INVALID_ROFF; + + /* Dump the memory pools. */ + for (i = 0; i < mp->nreg; ++i) { + (void)fprintf(fp, "%s\nCache #%d:\n", DB_LINE, i + 1); + __memp_dumpcache(dbmp, &dbmp->reginfo[i], fmap, fp, flags); + } + + R_UNLOCK(dbenv, dbmp->reginfo); + + /* Flush in case we're debugging. */ + (void)fflush(fp); +} + +/* + * __memp_dumpcache -- + * Display statistics for a cache. + */ +static void +__memp_dumpcache(dbmp, reginfo, fmap, fp, flags) + DB_MPOOL *dbmp; + REGINFO *reginfo; + size_t *fmap; + FILE *fp; + u_int32_t flags; +{ + BH *bhp; + DB_HASHTAB *dbht; + MPOOL *c_mp; + int bucket; + + c_mp = reginfo->primary; + + /* Display the hash table list of BH's. */ + if (LF_ISSET(MPOOL_DUMP_HASH)) { + (void)fprintf(fp, + "%s\nBH hash table (%lu hash slots)\npageno, file, ref, address\n", + DB_LINE, (u_long)c_mp->htab_buckets); + for (dbht = R_ADDR(reginfo, c_mp->htab), + bucket = 0; bucket < c_mp->htab_buckets; ++dbht, ++bucket) { + if (SH_TAILQ_FIRST(dbht, __bh) != NULL) + (void)fprintf(fp, "%lu:\n", (u_long)bucket); + for (bhp = SH_TAILQ_FIRST(dbht, __bh); + bhp != NULL; bhp = SH_TAILQ_NEXT(bhp, hq, __bh)) + __memp_pbh(dbmp, bhp, fmap, fp); + } + } + + /* Display the LRU list of BH's. */ + if (LF_ISSET(MPOOL_DUMP_LRU)) { + (void)fprintf(fp, "%s\nBH LRU list\n", DB_LINE); + (void)fprintf(fp, "pageno, file, ref, address\n"); + for (bhp = SH_TAILQ_FIRST(&c_mp->bhq, __bh); + bhp != NULL; bhp = SH_TAILQ_NEXT(bhp, q, __bh)) + __memp_pbh(dbmp, bhp, fmap, fp); + } + + /* Dump the memory pool. */ + if (LF_ISSET(MPOOL_DUMP_MEM)) + __db_shalloc_dump(reginfo->addr, fp); +} + +/* + * __memp_pbh -- + * Display a BH structure. + */ +static void +__memp_pbh(dbmp, bhp, fmap, fp) + DB_MPOOL *dbmp; + BH *bhp; + size_t *fmap; + FILE *fp; +{ + static const FN fn[] = { + { BH_CALLPGIN, "callpgin" }, + { BH_DIRTY, "dirty" }, + { BH_DISCARD, "discard" }, + { BH_LOCKED, "locked" }, + { BH_SYNC, "sync" }, + { BH_SYNC_LOGFLSH, "sync:logflush" }, + { BH_TRASH, "trash" }, + { 0, NULL } + }; + int i; + + for (i = 0; i < FMAP_ENTRIES; ++i) + if (fmap[i] == INVALID_ROFF || fmap[i] == bhp->mf_offset) + break; + + if (fmap[i] == INVALID_ROFF) + (void)fprintf(fp, " %4lu, %lu, %2lu, %lu", + (u_long)bhp->pgno, (u_long)bhp->mf_offset, + (u_long)bhp->ref, (u_long)R_OFFSET(dbmp->reginfo, bhp)); + else + (void)fprintf(fp, " %4lu, #%d, %2lu, %lu", + (u_long)bhp->pgno, i + 1, + (u_long)bhp->ref, (u_long)R_OFFSET(dbmp->reginfo, bhp)); + + __db_prflags(bhp->flags, fn, fp); + + (void)fprintf(fp, "\n"); +} diff --git a/db/mp/mp_sync.c b/db/mp/mp_sync.c new file mode 100644 index 000000000..1b0751db7 --- /dev/null +++ b/db/mp/mp_sync.c @@ -0,0 +1,658 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: mp_sync.c,v 11.29 2001/01/11 18:19:53 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#ifdef HAVE_RPC +#include "db_server.h" +#endif + +#include "db_int.h" +#include "db_shash.h" +#include "mp.h" + +#ifdef HAVE_RPC +#include "gen_client_ext.h" +#include "rpc_client_ext.h" +#endif + +static int __bhcmp __P((const void *, const void *)); +static int __memp_fsync __P((DB_MPOOLFILE *)); +static int __memp_sballoc __P((DB_ENV *, BH ***, u_int32_t *)); + +/* + * memp_sync -- + * Mpool sync function. + */ +int +memp_sync(dbenv, lsnp) + DB_ENV *dbenv; + DB_LSN *lsnp; +{ + BH *bhp, **bharray; + DB_MPOOL *dbmp; + DB_LSN tlsn; + MPOOL *c_mp, *mp; + MPOOLFILE *mfp; + u_int32_t ar_cnt, i, ndirty; + int ret, retry_done, retry_need, wrote; + +#ifdef HAVE_RPC + if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) + return (__dbcl_memp_sync(dbenv, lsnp)); +#endif + + PANIC_CHECK(dbenv); + ENV_REQUIRES_CONFIG(dbenv, dbenv->mp_handle, DB_INIT_MPOOL); + + dbmp = dbenv->mp_handle; + mp = dbmp->reginfo[0].primary; + + /* + * If no LSN is provided, flush the entire cache. + * + * !!! + * Our current behavior is to flush the entire cache, so there's + * nothing special we have to do here other than deal with NULL + * pointers. + */ + if (lsnp == NULL) { + ZERO_LSN(tlsn); + lsnp = &tlsn; + F_SET(mp, MP_LSN_RETRY); + } else if (!LOGGING_ON(dbenv)) { + __db_err(dbenv, "memp_sync: requires logging"); + return (EINVAL); + } + + /* + * Sync calls are single-threaded so that we don't have multiple + * threads, with different checkpoint LSNs, walking the caches + * and updating the checkpoint LSNs and how many buffers remain + * to be written for the checkpoint. This shouldn't be a problem, + * any application that has multiple checkpoint threads isn't what + * I'd call trustworthy. + */ + MUTEX_LOCK(dbenv, &mp->sync_mutex, dbenv->lockfhp); + + /* + * If the application is asking about a previous call to memp_sync(), + * and we haven't found any buffers that the application holding the + * pin couldn't write, return yes or no based on the current count. + * Note, if the application is asking about a LSN *smaller* than one + * we've already handled or are currently handling, then we return a + * result based on the count for the larger LSN. + */ + R_LOCK(dbenv, dbmp->reginfo); + if (!IS_ZERO_LSN(*lsnp) && + !F_ISSET(mp, MP_LSN_RETRY) && log_compare(lsnp, &mp->lsn) <= 0) { + if (mp->lsn_cnt == 0) { + *lsnp = mp->lsn; + ret = 0; + } else + ret = DB_INCOMPLETE; + + R_UNLOCK(dbenv, dbmp->reginfo); + MUTEX_UNLOCK(dbenv, &mp->sync_mutex); + return (ret); + } + + /* + * Allocate room for a list of buffers, and decide how many buffers + * we can pin down. + * + * !!! + * Note: __memp_sballoc has released the region lock if we're not + * continuing forward. + */ + if ((ret = + __memp_sballoc(dbenv, &bharray, &ndirty)) != 0 || ndirty == 0) { + MUTEX_UNLOCK(dbenv, &mp->sync_mutex); + return (ret); + } + + retry_done = 0; +retry: retry_need = 0; + /* + * Start a new checkpoint. + * + * Save the LSN. We know that it's a new LSN, a retry, or larger than + * the one for which we were already doing a checkpoint. (BTW, I don't + * expect to see multiple LSN's from the same or multiple processes, + * but You Just Never Know. Responding as if they all called with the + * largest of the LSNs specified makes everything work.) + * + * We don't currently use the LSN we save. We could potentially save + * the last-written LSN in each buffer header and use it to determine + * what buffers need to be written. The problem with this is that it's + * sizeof(LSN) more bytes of buffer header. We currently write all the + * dirty buffers instead, but with a sufficiently large cache that's + * going to be a problem. + */ + mp->lsn = *lsnp; + + /* + * Clear the global count of buffers waiting to be written, walk the + * list of files clearing the count of buffers waiting to be written. + * + * Clear the retry flag. + */ + mp->lsn_cnt = 0; + for (mfp = SH_TAILQ_FIRST(&mp->mpfq, __mpoolfile); + mfp != NULL; mfp = SH_TAILQ_NEXT(mfp, q, __mpoolfile)) + mfp->lsn_cnt = 0; + F_CLR(mp, MP_LSN_RETRY); + + /* + * Walk each cache's list of buffers and mark all dirty buffers to be + * written and all pinned buffers to be potentially written (we can't + * know if they'll need to be written until the holder returns them to + * the cache). We do this in one pass while holding the region locked + * so that processes can't make new buffers dirty, causing us to never + * finish. Since the application may have restarted the sync using a + * different LSN value, clear any BH_SYNC | BH_SYNC_LOGFLSH flags that + * appear leftover from previous calls. + * + * Keep a count of the total number of buffers we need to write in + * MPOOL->lsn_cnt, and for each file, in MPOOLFILE->lsn_count. + */ + for (ar_cnt = 0, i = 0; i < mp->nreg; ++i) { + c_mp = dbmp->reginfo[i].primary; + for (bhp = SH_TAILQ_FIRST(&c_mp->bhq, __bh); + bhp != NULL; bhp = SH_TAILQ_NEXT(bhp, q, __bh)) { + if (F_ISSET(bhp, BH_DIRTY) || bhp->ref != 0) { + F_SET(bhp, BH_SYNC); + + ++mp->lsn_cnt; + + mfp = R_ADDR(dbmp->reginfo, bhp->mf_offset); + ++mfp->lsn_cnt; + + /* + * If the buffer isn't being used, we can write + * it immediately, so increment its reference + * count to lock it down, and save a reference + * to it. + * + * If we've run out space to store buffer refs, + * we're screwed. We don't want to realloc the + * array while holding a region lock, so we set + * a flag and deal with it later. + */ + if (bhp->ref == 0) { + ++bhp->ref; + bharray[ar_cnt] = bhp; + + if (++ar_cnt >= ndirty) { + retry_need = 1; + break; + } + } + } else + if (F_ISSET(bhp, BH_SYNC)) + F_CLR(bhp, BH_SYNC | BH_SYNC_LOGFLSH); + } + if (ar_cnt >= ndirty) + break; + } + + /* If there no buffers we can write immediately, we're done. */ + if (ar_cnt == 0) { + ret = mp->lsn_cnt ? DB_INCOMPLETE : 0; + goto done; + } + + R_UNLOCK(dbenv, dbmp->reginfo); + + /* + * Sort the buffers we're going to write immediately. + * + * We try and write the buffers in file/page order: it should reduce + * seeks by the underlying filesystem and possibly reduce the actual + * number of writes. + */ + if (ar_cnt > 1) + qsort(bharray, ar_cnt, sizeof(BH *), __bhcmp); + + /* + * Flush the log. We have to ensure the log records reflecting the + * changes on the database pages we're writing have already made it + * to disk. We usually do that as we write each page, but if we + * are going to write a large number of pages, repeatedly acquiring + * the log region lock is going to be expensive. Flush the entire + * log now, so that sync doesn't require any more log flushes. + */ + if (LOGGING_ON(dbenv) && (ret = log_flush(dbenv, NULL)) != 0) + goto done; + + R_LOCK(dbenv, dbmp->reginfo); + + /* Walk the array, writing buffers. */ + for (i = 0; i < ar_cnt; ++i) { + /* + * It's possible for a thread to have gotten the buffer since + * we listed it for writing. If the reference count is still + * 1, we're the only ones using the buffer, go ahead and write. + * If it's >1, then skip the buffer and assume that it will be + * written when it's returned to the cache. + */ + if (bharray[i]->ref > 1) { + --bharray[i]->ref; + continue; + } + + /* Write the buffer. */ + mfp = R_ADDR(dbmp->reginfo, bharray[i]->mf_offset); + ret = __memp_bhwrite(dbmp, mfp, bharray[i], NULL, &wrote); + + /* Release the buffer. */ + --bharray[i]->ref; + + if (ret == 0 && wrote) + continue; + + /* + * Any process syncing the shared memory buffer pool had best + * be able to write to any underlying file. Be understanding, + * but firm, on this point. + */ + if (ret == 0) { + __db_err(dbenv, "%s: unable to flush page: %lu", + __memp_fns(dbmp, mfp), (u_long)bharray[i]->pgno); + ret = EPERM; + } + + /* + * On error, clear MPOOL->lsn and set MP_LSN_RETRY so that no + * future checkpoint return can depend on this failure. Clear + * the buffer's BH_SYNC flag, because it's used to determine + * if lsn_cnt values are incremented/decremented. Don't bother + * to reset/clear: + * + * MPOOL->lsn_cnt + * MPOOLFILE->lsn_cnt + * + * they don't make any difference. + */ + ZERO_LSN(mp->lsn); + F_SET(mp, MP_LSN_RETRY); + + /* Release any buffers we're still pinning down. */ + while (++i < ar_cnt) { + bhp = bharray[i]; + --bhp->ref; + F_CLR(bhp, BH_SYNC | BH_SYNC_LOGFLSH); + } + + goto done; + } + + ret = mp->lsn_cnt != 0 ? DB_INCOMPLETE : 0; + + /* + * If there were too many buffers and we're not returning an error, we + * re-try the checkpoint once -- since we allocated 80% of the total + * buffer count, once should be enough. If it still doesn't work, some + * other thread of control is dirtying buffers as fast as we're writing + * them, and we might as well give up for now. In the latter case, set + * the global retry flag, we'll have to start from scratch on the next + * checkpoint. + */ + if (retry_need) { + if (retry_done) { + ret = DB_INCOMPLETE; + F_SET(mp, MP_LSN_RETRY); + } else { + retry_done = 1; + goto retry; + } + } + +done: R_UNLOCK(dbenv, dbmp->reginfo); + MUTEX_UNLOCK(dbenv, &mp->sync_mutex); + + __os_free(bharray, ndirty * sizeof(BH *)); + + return (ret); +} + +/* + * memp_fsync -- + * Mpool file sync function. + */ +int +memp_fsync(dbmfp) + DB_MPOOLFILE *dbmfp; +{ + DB_ENV *dbenv; + DB_MPOOL *dbmp; + int is_tmp; + + dbmp = dbmfp->dbmp; + dbenv = dbmp->dbenv; + +#ifdef HAVE_RPC + if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) + return (__dbcl_memp_fsync(dbmfp)); +#endif + + PANIC_CHECK(dbenv); + + /* + * If this handle doesn't have a file descriptor that's open for + * writing, or if the file is a temporary, there's no reason to + * proceed further. + */ + if (F_ISSET(dbmfp, MP_READONLY)) + return (0); + + R_LOCK(dbenv, dbmp->reginfo); + is_tmp = F_ISSET(dbmfp->mfp, MP_TEMP); + R_UNLOCK(dbenv, dbmp->reginfo); + if (is_tmp) + return (0); + + return (__memp_fsync(dbmfp)); +} + +/* + * __mp_xxx_fh -- + * Return a file descriptor for DB 1.85 compatibility locking. + * + * PUBLIC: int __mp_xxx_fh __P((DB_MPOOLFILE *, DB_FH **)); + */ +int +__mp_xxx_fh(dbmfp, fhp) + DB_MPOOLFILE *dbmfp; + DB_FH **fhp; +{ + /* + * This is a truly spectacular layering violation, intended ONLY to + * support compatibility for the DB 1.85 DB->fd call. + * + * Sync the database file to disk, creating the file as necessary. + * + * We skip the MP_READONLY and MP_TEMP tests done by memp_fsync(3). + * The MP_READONLY test isn't interesting because we will either + * already have a file descriptor (we opened the database file for + * reading) or we aren't readonly (we created the database which + * requires write privileges). The MP_TEMP test isn't interesting + * because we want to write to the backing file regardless so that + * we get a file descriptor to return. + */ + *fhp = &dbmfp->fh; + return (F_ISSET(&dbmfp->fh, DB_FH_VALID) ? 0 : __memp_fsync(dbmfp)); +} + +/* + * __memp_fsync -- + * Mpool file internal sync function. + */ +static int +__memp_fsync(dbmfp) + DB_MPOOLFILE *dbmfp; +{ + BH *bhp, **bharray; + DB_ENV *dbenv; + DB_MPOOL *dbmp; + MPOOL *c_mp, *mp; + size_t mf_offset; + u_int32_t ar_cnt, i, ndirty; + int incomplete, ret, retry_done, retry_need, wrote; + + dbmp = dbmfp->dbmp; + dbenv = dbmp->dbenv; + mp = dbmp->reginfo[0].primary; + + R_LOCK(dbenv, dbmp->reginfo); + + /* + * Allocate room for a list of buffers, and decide how many buffers + * we can pin down. + * + * !!! + * Note: __memp_sballoc has released our region lock if we're not + * continuing forward. + */ + if ((ret = + __memp_sballoc(dbenv, &bharray, &ndirty)) != 0 || ndirty == 0) + return (ret); + + retry_done = 0; +retry: retry_need = 0; + /* + * Walk each cache's list of buffers and mark all dirty buffers to be + * written and all pinned buffers to be potentially written (we can't + * know if they'll need to be written until the holder returns them to + * the cache). We do this in one pass while holding the region locked + * so that processes can't make new buffers dirty, causing us to never + * finish. + */ + mf_offset = R_OFFSET(dbmp->reginfo, dbmfp->mfp); + for (ar_cnt = 0, incomplete = 0, i = 0; i < mp->nreg; ++i) { + c_mp = dbmp->reginfo[i].primary; + for (bhp = SH_TAILQ_FIRST(&c_mp->bhq, __bh); + bhp != NULL; bhp = SH_TAILQ_NEXT(bhp, q, __bh)) { + if (!F_ISSET(bhp, BH_DIRTY) || + bhp->mf_offset != mf_offset) + continue; + if (bhp->ref != 0 || F_ISSET(bhp, BH_LOCKED)) { + incomplete = 1; + continue; + } + + /* + * If the buffer isn't being used, we can write + * it immediately, so increment its reference + * count to lock it down, and save a reference + * to it. + * + * If we've run out space to store buffer refs, + * we're screwed. We don't want to realloc the + * array while holding a region lock, so we set + * a flag and deal with it later. + */ + ++bhp->ref; + bharray[ar_cnt] = bhp; + if (++ar_cnt >= ndirty) { + retry_need = 1; + break; + } + } + if (ar_cnt >= ndirty) + break; + } + + /* If there no buffers we can write immediately, we're done. */ + if (ar_cnt == 0) { + ret = 0; + goto done; + } + + R_UNLOCK(dbenv, dbmp->reginfo); + + /* Sort the buffers we're going to write. */ + if (ar_cnt > 1) + qsort(bharray, ar_cnt, sizeof(BH *), __bhcmp); + + R_LOCK(dbenv, dbmp->reginfo); + + /* Walk the array, writing buffers. */ + for (i = 0; i < ar_cnt;) { + /* + * It's possible for a thread to have gotten the buffer since + * we listed it for writing. If the reference count is still + * 1, we're the only ones using the buffer, go ahead and write. + * If it's >1, then skip the buffer and assume that it will be + * written when it's returned to the cache. + */ + if (bharray[i]->ref > 1) { + incomplete = 1; + --bharray[i++]->ref; + continue; + } + + /* Write the buffer. */ + ret = __memp_pgwrite(dbmp, dbmfp, bharray[i], NULL, &wrote); + + /* Release the buffer. */ + --bharray[i++]->ref; + + if (ret == 0) { + if (!wrote) + incomplete = 1; + continue; + } + + /* + * On error: + * + * Release any buffers we're still pinning down. + */ + while (i < ar_cnt) + --bharray[i++]->ref; + break; + } + + /* + * If there were too many buffers and we're not returning an error, we + * re-try the flush once -- since we allocated 80% of the total + * buffer count, once should be enough. If it still doesn't work, some + * other thread of control is dirtying buffers as fast as we're writing + * them, and we might as well give up. + */ + if (retry_need) { + if (retry_done) + incomplete = 1; + else { + retry_done = 1; + goto retry; + } + } + +done: R_UNLOCK(dbenv, dbmp->reginfo); + + __os_free(bharray, ndirty * sizeof(BH *)); + + /* + * Sync the underlying file as the last thing we do, so that the OS + * has a maximal opportunity to flush buffers before we request it. + * + * !!!: + * Don't lock the region around the sync, fsync(2) has no atomicity + * issues. + */ + if (ret == 0) + ret = incomplete ? + DB_INCOMPLETE : __os_fsync(dbenv, &dbmfp->fh); + + return (ret); +} + +/* + * __memp_sballoc -- + * Allocate room for a list of buffers. + */ +static int +__memp_sballoc(dbenv, bharrayp, ndirtyp) + DB_ENV *dbenv; + BH ***bharrayp; + u_int32_t *ndirtyp; +{ + DB_MPOOL *dbmp; + MPOOL *c_mp, *mp; + u_int32_t i, nclean, ndirty, maxpin; + int ret; + + dbmp = dbenv->mp_handle; + mp = dbmp->reginfo[0].primary; + + /* + * We don't want to hold the region lock while we write the buffers, + * so only lock it while we create a list. + * + * Walk through the list of caches, figuring out how many buffers + * we're going to need. + * + * Make a point of not holding the region lock across the library + * allocation call. + */ + for (nclean = ndirty = 0, i = 0; i < mp->nreg; ++i) { + c_mp = dbmp->reginfo[i].primary; + ndirty += c_mp->stat.st_page_dirty; + nclean += c_mp->stat.st_page_clean; + } + R_UNLOCK(dbenv, dbmp->reginfo); + if (ndirty == 0) { + *ndirtyp = 0; + return (0); + } + + /* + * We don't want to pin down the entire buffer cache, otherwise we'll + * starve threads needing new pages. Don't pin down more than 80% of + * the cache, making sure that we don't screw up just because only a + * few pages have been created. + */ + maxpin = ((ndirty + nclean) * 8) / 10; + if (maxpin < 10) + maxpin = 10; + + /* + * Get a good-sized block of memory to hold buffer pointers, we don't + * want to run out, but correct if we want to allocate more than we + * would be allowed to store, regardless. + */ + ndirty += ndirty / 2 + 10; + if (ndirty > maxpin) + ndirty = maxpin; + if ((ret = + __os_malloc(dbenv, ndirty * sizeof(BH *), NULL, bharrayp)) != 0) + return (ret); + + *ndirtyp = ndirty; + + R_LOCK(dbenv, dbmp->reginfo); + + return (0); +} + +static int +__bhcmp(p1, p2) + const void *p1, *p2; +{ + BH *bhp1, *bhp2; + + bhp1 = *(BH * const *)p1; + bhp2 = *(BH * const *)p2; + + /* Sort by file (shared memory pool offset). */ + if (bhp1->mf_offset < bhp2->mf_offset) + return (-1); + if (bhp1->mf_offset > bhp2->mf_offset) + return (1); + + /* + * !!! + * Defend against badly written quicksort code calling the comparison + * function with two identical pointers (e.g., WATCOM C++ (Power++)). + */ + if (bhp1->pgno < bhp2->pgno) + return (-1); + if (bhp1->pgno > bhp2->pgno) + return (1); + return (0); +} diff --git a/db/mp/mp_trickle.c b/db/mp/mp_trickle.c new file mode 100644 index 000000000..f937805cf --- /dev/null +++ b/db/mp/mp_trickle.c @@ -0,0 +1,149 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: mp_trickle.c,v 11.12 2000/11/30 00:58:41 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#ifdef HAVE_RPC +#include "db_server.h" +#endif + +#include "db_int.h" +#include "db_shash.h" +#include "mp.h" + +#ifdef HAVE_RPC +#include "gen_client_ext.h" +#include "rpc_client_ext.h" +#endif + +static int __memp_trick __P((DB_ENV *, int, int, int *)); + +/* + * memp_trickle -- + * Keep a specified percentage of the buffers clean. + */ +int +memp_trickle(dbenv, pct, nwrotep) + DB_ENV *dbenv; + int pct, *nwrotep; +{ + DB_MPOOL *dbmp; + MPOOL *mp; + u_int32_t i; + int ret; + +#ifdef HAVE_RPC + if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) + return (__dbcl_memp_trickle(dbenv, pct, nwrotep)); +#endif + + PANIC_CHECK(dbenv); + ENV_REQUIRES_CONFIG(dbenv, dbenv->mp_handle, DB_INIT_MPOOL); + + dbmp = dbenv->mp_handle; + mp = dbmp->reginfo[0].primary; + + if (nwrotep != NULL) + *nwrotep = 0; + + if (pct < 1 || pct > 100) + return (EINVAL); + + R_LOCK(dbenv, dbmp->reginfo); + + /* Loop through the caches... */ + for (ret = 0, i = 0; i < mp->nreg; ++i) + if ((ret = __memp_trick(dbenv, i, pct, nwrotep)) != 0) + break; + + R_UNLOCK(dbenv, dbmp->reginfo); + return (ret); +} + +/* + * __memp_trick -- + * Trickle a single cache. + */ +static int +__memp_trick(dbenv, ncache, pct, nwrotep) + DB_ENV *dbenv; + int ncache, pct, *nwrotep; +{ + BH *bhp; + DB_MPOOL *dbmp; + MPOOL *c_mp; + MPOOLFILE *mfp; + db_pgno_t pgno; + u_long total; + int ret, wrote; + + dbmp = dbenv->mp_handle; + c_mp = dbmp->reginfo[ncache].primary; + + /* + * If there are sufficient clean buffers, or no buffers or no dirty + * buffers, we're done. + * + * XXX + * Using st_page_clean and st_page_dirty is our only choice at the + * moment, but it's not as correct as we might like in the presence + * of pools with more than one buffer size, as a free 512-byte buffer + * isn't the same as a free 8K buffer. + */ +loop: total = c_mp->stat.st_page_clean + c_mp->stat.st_page_dirty; + if (total == 0 || c_mp->stat.st_page_dirty == 0 || + (c_mp->stat.st_page_clean * 100) / total >= (u_long)pct) + return (0); + + /* Loop until we write a buffer. */ + for (bhp = SH_TAILQ_FIRST(&c_mp->bhq, __bh); + bhp != NULL; bhp = SH_TAILQ_NEXT(bhp, q, __bh)) { + if (bhp->ref != 0 || + !F_ISSET(bhp, BH_DIRTY) || F_ISSET(bhp, BH_LOCKED)) + continue; + + mfp = R_ADDR(dbmp->reginfo, bhp->mf_offset); + + /* + * We can't write to temporary files -- see the comment in + * mp_bh.c:__memp_bhwrite(). + */ + if (F_ISSET(mfp, MP_TEMP)) + continue; + + pgno = bhp->pgno; + if ((ret = __memp_bhwrite(dbmp, mfp, bhp, NULL, &wrote)) != 0) + return (ret); + + /* + * Any process syncing the shared memory buffer pool had better + * be able to write to any underlying file. Be understanding, + * but firm, on this point. + */ + if (!wrote) { + __db_err(dbenv, "%s: unable to flush page: %lu", + __memp_fns(dbmp, mfp), (u_long)pgno); + return (EPERM); + } + + ++c_mp->stat.st_page_trickle; + if (nwrotep != NULL) + ++*nwrotep; + goto loop; + } + + return (0); +} diff --git a/db/mutex/README b/db/mutex/README new file mode 100644 index 000000000..323c34f1e --- /dev/null +++ b/db/mutex/README @@ -0,0 +1,108 @@ +# $Id: README,v 11.2 1999/11/21 18:12:48 bostic Exp $ + +Note: this only applies to locking using test-and-set and fcntl calls, +pthreads were added after this was written. + +Resource locking routines: lock based on a db_mutex_t. All this gunk +(including trying to make assembly code portable), is necessary because +System V semaphores require system calls for uncontested locks and we +don't want to make two system calls per resource lock. + +First, this is how it works. The db_mutex_t structure contains a resource +test-and-set lock (tsl), a file offset, a pid for debugging and statistics +information. + +If HAVE_MUTEX_THREADS is defined (i.e. we know how to do test-and-sets +for this compiler/architecture combination), we try and lock the resource +tsl __os_spin() times. If we can't acquire the lock that way, we use a +system call to sleep for 1ms, 2ms, 4ms, etc. (The time is bounded at 1 +second, just in case.) Using the timer backoff means that there are two +assumptions: that locks are held for brief periods (never over system +calls or I/O) and that locks are not hotly contested. + +If HAVE_MUTEX_THREADS is not defined, i.e. we can't do test-and-sets, we +use a file descriptor to do byte locking on a file at a specified offset. +In this case, ALL of the locking is done in the kernel. Because file +descriptors are allocated per process, we have to provide the file +descriptor as part of the lock call. We still have to do timer backoff +because we need to be able to block ourselves, i.e. the lock manager +causes processes to wait by having the process acquire a mutex and then +attempting to re-acquire the mutex. There's no way to use kernel locking +to block yourself, i.e. if you hold a lock and attempt to re-acquire it, +the attempt will succeed. + +Next, let's talk about why it doesn't work the way a reasonable person +would think it should work. + +Ideally, we'd have the ability to try to lock the resource tsl, and if +that fails, increment a counter of waiting processes, then block in the +kernel until the tsl is released. The process holding the resource tsl +would see the wait counter when it went to release the resource tsl, and +would wake any waiting processes up after releasing the lock. This would +actually require both another tsl (call it the mutex tsl) and +synchronization between the call that blocks in the kernel and the actual +resource tsl. The mutex tsl would be used to protect accesses to the +db_mutex_t itself. Locking the mutex tsl would be done by a busy loop, +which is safe because processes would never block holding that tsl (all +they would do is try to obtain the resource tsl and set/check the wait +count). The problem in this model is that the blocking call into the +kernel requires a blocking semaphore, i.e. one whose normal state is +locked. + +The only portable forms of locking under UNIX are fcntl(2) on a file +descriptor/offset, and System V semaphores. Neither of these locking +methods are sufficient to solve the problem. + +The problem with fcntl locking is that only the process that obtained the +lock can release it. Remember, we want the normal state of the kernel +semaphore to be locked. So, if the creator of the db_mutex_t were to +initialize the lock to "locked", then a second process locks the resource +tsl, and then a third process needs to block, waiting for the resource +tsl, when the second process wants to wake up the third process, it can't +because it's not the holder of the lock! For the second process to be +the holder of the lock, we would have to make a system call per +uncontested lock, which is what we were trying to get away from in the +first place. + +There are some hybrid schemes, such as signaling the holder of the lock, +or using a different blocking offset depending on which process is +holding the lock, but it gets complicated fairly quickly. I'm open to +suggestions, but I'm not holding my breath. + +Regardless, we use this form of locking when HAVE_SPINLOCKS is not +defined, (i.e. we're locking in the kernel) because it doesn't have the +limitations found in System V semaphores, and because the normal state of +the kernel object in that case is unlocked, so the process releasing the +lock is also the holder of the lock. + +The System V semaphore design has a number of other limitations that make +it inappropriate for this task. Namely: + +First, the semaphore key name space is separate from the file system name +space (although there exist methods for using file names to create +semaphore keys). If we use a well-known key, there's no reason to believe +that any particular key will not already be in use, either by another +instance of the DB application or some other application, in which case +the DB application will fail. If we create a key, then we have to use a +file system name to rendezvous and pass around the key. + +Second, System V semaphores traditionally have compile-time, system-wide +limits on the number of semaphore keys that you can have. Typically, that +number is far too low for any practical purpose. Since the semaphores +permit more than a single slot per semaphore key, we could try and get +around that limit by using multiple slots, but that means that the file +that we're using for rendezvous is going to have to contain slot +information as well as semaphore key information, and we're going to be +reading/writing it on every db_mutex_t init or destroy operation. Anyhow, +similar compile-time, system-wide limits on the numbers of slots per +semaphore key kick in, and you're right back where you started. + +My fantasy is that once POSIX.1 standard mutexes are in wide-spread use, +we can switch to them. My guess is that it won't happen, because the +POSIX semaphores are only required to work for threads within a process, +and not independent processes. + +Note: there are races in the statistics code, but since it's just that, +I didn't bother fixing them. (The fix requires a mutex tsl, so, when/if +this code is fixed to do rational locking (see above), then change the +statistics update code to acquire/release the mutex tsl. diff --git a/db/mutex/mut_fcntl.c b/db/mutex/mut_fcntl.c new file mode 100644 index 000000000..02f4d4044 --- /dev/null +++ b/db/mutex/mut_fcntl.c @@ -0,0 +1,174 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: mut_fcntl.c,v 11.11 2001/01/11 18:19:53 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#include +#endif + +#include "db_int.h" + +/* + * __db_fcntl_mutex_init -- + * Initialize a DB mutex structure. + * + * PUBLIC: int __db_fcntl_mutex_init __P((DB_ENV *, MUTEX *, u_int32_t)); + */ +int +__db_fcntl_mutex_init(dbenv, mutexp, offset) + DB_ENV *dbenv; + MUTEX *mutexp; + u_int32_t offset; +{ + memset(mutexp, 0, sizeof(*mutexp)); + + /* + * This is where we decide to ignore locks we don't need to set -- if + * the application is private, we don't need any locks. + */ + if (F_ISSET(dbenv, DB_ENV_PRIVATE)) { + F_SET(mutexp, MUTEX_IGNORE); + return (0); + } + + mutexp->off = offset; +#ifdef MUTEX_SYSTEM_RESOURCES + mutexp->reg_off = INVALID_ROFF; +#endif + F_SET(mutexp, MUTEX_INITED); + + return (0); +} + +/* + * __db_fcntl_mutex_lock + * Lock on a mutex, blocking if necessary. + * + * PUBLIC: int __db_fcntl_mutex_lock __P((DB_ENV *, MUTEX *, DB_FH *)); + */ +int +__db_fcntl_mutex_lock(dbenv, mutexp, fhp) + DB_ENV *dbenv; + MUTEX *mutexp; + DB_FH *fhp; +{ + struct flock k_lock; + int locked, ms, waited; + + if (!dbenv->db_mutexlocks) + return (0); + + /* Initialize the lock. */ + k_lock.l_whence = SEEK_SET; + k_lock.l_start = mutexp->off; + k_lock.l_len = 1; + + for (locked = waited = 0;;) { + /* + * Wait for the lock to become available; wait 1ms initially, + * up to 1 second. + */ + for (ms = 1; mutexp->pid != 0;) { + waited = 1; + __os_yield(NULL, ms * USEC_PER_MS); + if ((ms <<= 1) > MS_PER_SEC) + ms = MS_PER_SEC; + } + + /* Acquire an exclusive kernel lock. */ + k_lock.l_type = F_WRLCK; + if (fcntl(fhp->fd, F_SETLKW, &k_lock)) + return (__os_get_errno()); + + /* If the resource is still available, it's ours. */ + if (mutexp->pid == 0) { + locked = 1; + mutexp->pid = (u_int32_t)getpid(); + } + + /* Release the kernel lock. */ + k_lock.l_type = F_UNLCK; + if (fcntl(fhp->fd, F_SETLK, &k_lock)) + return (__os_get_errno()); + + /* + * If we got the resource lock we're done. + * + * !!! + * We can't check to see if the lock is ours, because we may + * be trying to block ourselves in the lock manager, and so + * the holder of the lock that's preventing us from getting + * the lock may be us! (Seriously.) + */ + if (locked) + break; + } + + if (waited) + ++mutexp->mutex_set_wait; + else + ++mutexp->mutex_set_nowait; + return (0); +} + +/* + * __db_fcntl_mutex_unlock -- + * Release a lock. + * + * PUBLIC: int __db_fcntl_mutex_unlock __P((DB_ENV *, MUTEX *)); + */ +int +__db_fcntl_mutex_unlock(dbenv, mutexp) + DB_ENV *dbenv; + MUTEX *mutexp; +{ + if (!dbenv->db_mutexlocks) + return (0); + +#ifdef DIAGNOSTIC +#define MSG "mutex_unlock: ERROR: released lock that was unlocked\n" +#ifndef STDERR_FILENO +#define STDERR_FILENO 2 +#endif + if (mutexp->pid == 0) + write(STDERR_FILENO, MSG, sizeof(MSG) - 1); +#endif + + /* + * Release the resource. We don't have to acquire any locks because + * processes trying to acquire the lock are checking for a pid set to + * 0/non-0, not to any specific value. + */ + mutexp->pid = 0; + + return (0); +} + +/* + * __db_fcntl_mutex_destroy -- + * Destroy a MUTEX. + * + * PUBLIC: int __db_fcntl_mutex_destroy __P((MUTEX *)); + */ +int +__db_fcntl_mutex_destroy(mutexp) + MUTEX *mutexp; +{ + COMPQUIET(mutexp, NULL); + + return (0); +} diff --git a/db/mutex/mut_pthread.c b/db/mutex/mut_pthread.c new file mode 100644 index 000000000..3de4abcef --- /dev/null +++ b/db/mutex/mut_pthread.c @@ -0,0 +1,328 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: mut_pthread.c,v 11.33 2001/01/09 00:56:16 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#endif + +#include "db_int.h" + +#ifdef DIAGNOSTIC +#undef MSG1 +#define MSG1 "mutex_lock: ERROR: lock currently in use: pid: %lu.\n" +#undef MSG2 +#define MSG2 "mutex_unlock: ERROR: lock already unlocked\n" +#ifndef STDERR_FILENO +#define STDERR_FILENO 2 +#endif +#endif + +#ifdef HAVE_MUTEX_SOLARIS_LWP +#define pthread_cond_signal _lwp_cond_signal +#define pthread_cond_wait _lwp_cond_wait +#define pthread_mutex_lock _lwp_mutex_lock +#define pthread_mutex_trylock _lwp_mutex_trylock +#define pthread_mutex_unlock _lwp_mutex_unlock +#define pthread_self _lwp_self +#define pthread_mutex_destroy(x) 0 +#endif +#ifdef HAVE_MUTEX_UI_THREADS +#define pthread_cond_signal cond_signal +#define pthread_cond_wait cond_wait +#define pthread_mutex_lock mutex_lock +#define pthread_mutex_trylock mutex_trylock +#define pthread_mutex_unlock mutex_unlock +#define pthread_self thr_self +#define pthread_mutex_destroy mutex_destroy +#endif + +#define PTHREAD_UNLOCK_ATTEMPTS 5 + +/* + * __db_pthread_mutex_init -- + * Initialize a MUTEX. + * + * PUBLIC: int __db_pthread_mutex_init __P((DB_ENV *, MUTEX *, u_int32_t)); + */ +int +__db_pthread_mutex_init(dbenv, mutexp, flags) + DB_ENV *dbenv; + MUTEX *mutexp; + u_int32_t flags; +{ + int ret; + + ret = 0; + memset(mutexp, 0, sizeof(*mutexp)); + + /* + * If this is a thread lock or the process has told us that there are + * no other processes in the environment, use thread-only locks, they + * are faster in some cases. + * + * This is where we decide to ignore locks we don't need to set -- if + * the application isn't threaded, there aren't any threads to block. + */ + if (LF_ISSET(MUTEX_THREAD) || F_ISSET(dbenv, DB_ENV_PRIVATE)) { + if (!F_ISSET(dbenv, DB_ENV_THREAD)) { + F_SET(mutexp, MUTEX_IGNORE); + return (0); + } + F_SET(mutexp, MUTEX_THREAD); + } + +#ifdef HAVE_MUTEX_PTHREADS + { + pthread_condattr_t condattr, *condattrp = NULL; + pthread_mutexattr_t mutexattr, *mutexattrp = NULL; + + if (!F_ISSET(mutexp, MUTEX_THREAD)) { + ret = pthread_condattr_init(&condattr); + if (ret == 0) + ret = pthread_condattr_setpshared( + &condattr, PTHREAD_PROCESS_SHARED); + condattrp = &condattr; + + if (ret == 0) + ret = pthread_mutexattr_init(&mutexattr); + if (ret == 0) + ret = pthread_mutexattr_setpshared( + &mutexattr, PTHREAD_PROCESS_SHARED); + mutexattrp = &mutexattr; + } + + if (ret == 0) + ret = pthread_mutex_init(&mutexp->mutex, mutexattrp); + if (mutexattrp != NULL) + pthread_mutexattr_destroy(mutexattrp); + if (LF_ISSET(MUTEX_SELF_BLOCK)) { + if (ret == 0) + ret = pthread_cond_init(&mutexp->cond, condattrp); + + F_SET(mutexp, MUTEX_SELF_BLOCK); + if (condattrp != NULL) + pthread_condattr_destroy(condattrp); + }} +#endif +#ifdef HAVE_MUTEX_SOLARIS_LWP + /* + * XXX + * Gcc complains about missing braces in the static initializations of + * lwp_cond_t and lwp_mutex_t structures because the structures contain + * sub-structures/unions and the Solaris include file that defines the + * initialization values doesn't have surrounding braces. There's not + * much we can do. + */ + if (F_ISSET(mutexp, MUTEX_THREAD)) { + static lwp_mutex_t mi = DEFAULTMUTEX; + + mutexp->mutex = mi; + } else { + static lwp_mutex_t mi = SHAREDMUTEX; + + mutexp->mutex = mi; + } + if (LF_ISSET(MUTEX_SELF_BLOCK)) { + if (F_ISSET(mutexp, MUTEX_THREAD)) { + static lwp_cond_t ci = DEFAULTCV; + + mutexp->cond = ci; + } else { + static lwp_cond_t ci = SHAREDCV; + + mutexp->cond = ci; + } + F_SET(mutexp, MUTEX_SELF_BLOCK); + } +#endif +#ifdef HAVE_MUTEX_UI_THREADS + { + int type; + + type = F_ISSET(mutexp, MUTEX_THREAD) ? USYNC_THREAD : USYNC_PROCESS; + + ret = mutex_init(&mutexp->mutex, type, NULL); + if (ret == 0 && LF_ISSET(MUTEX_SELF_BLOCK)) { + ret = cond_init(&mutexp->cond, type, NULL); + + F_SET(mutexp, MUTEX_SELF_BLOCK); + }} +#endif + + mutexp->spins = __os_spin(); +#ifdef MUTEX_SYSTEM_RESOURCES + mutexp->reg_off = INVALID_ROFF; +#endif + if (ret == 0) + F_SET(mutexp, MUTEX_INITED); + + return (ret); +} + +/* + * __db_pthread_mutex_lock + * Lock on a mutex, logically blocking if necessary. + * + * PUBLIC: int __db_pthread_mutex_lock __P((DB_ENV *, MUTEX *)); + */ +int +__db_pthread_mutex_lock(dbenv, mutexp) + DB_ENV *dbenv; + MUTEX *mutexp; +{ + u_int32_t nspins; + int i, ret, waited; + + if (!dbenv->db_mutexlocks || F_ISSET(mutexp, MUTEX_IGNORE)) + return (0); + + /* Attempt to acquire the resource for N spins. */ + for (nspins = mutexp->spins; nspins > 0; --nspins) + if (pthread_mutex_trylock(&mutexp->mutex) == 0) + break; + + if (nspins == 0 && (ret = pthread_mutex_lock(&mutexp->mutex)) != 0) + return (ret); + + if (F_ISSET(mutexp, MUTEX_SELF_BLOCK)) { + for (waited = 0; mutexp->locked != 0; waited = 1) { + ret = pthread_cond_wait(&mutexp->cond, &mutexp->mutex); + /* + * !!! + * Solaris bug workaround: + * pthread_cond_wait() sometimes returns ETIME -- out + * of sheer paranoia, check both ETIME and ETIMEDOUT. + * We believe this happens when the application uses + * SIGALRM for some purpose, e.g., the C library sleep + * call, and Solaris delivers the signal to the wrong + * LWP. + */ + if (ret != 0 && ret != ETIME && ret != ETIMEDOUT) + return (ret); + } + + if (waited) + ++mutexp->mutex_set_wait; + else + ++mutexp->mutex_set_nowait; + +#ifdef DIAGNOSTIC + mutexp->locked = (u_int32_t)pthread_self(); +#else + mutexp->locked = 1; +#endif + /* + * According to HP-UX engineers contacted by Netscape, + * pthread_mutex_unlock() will occasionally return EFAULT + * for no good reason on mutexes in shared memory regions, + * and the correct caller behavior is to try again. Do + * so, up to PTHREAD_UNLOCK_ATTEMPTS consecutive times. + * Note that we don't bother to restrict this to HP-UX; + * it should be harmless elsewhere. [#2471] + */ + i = PTHREAD_UNLOCK_ATTEMPTS; + do { + ret = pthread_mutex_unlock(&mutexp->mutex); + } while (ret == EFAULT && --i > 0); + if (ret != 0) + return (ret); + } else { + if (nspins == mutexp->spins) + ++mutexp->mutex_set_nowait; + else + ++mutexp->mutex_set_wait; +#ifdef DIAGNOSTIC + if (mutexp->locked) { + char msgbuf[128]; + (void)snprintf(msgbuf, + sizeof(msgbuf), MSG1, (u_long)mutexp->locked); + (void)write(STDERR_FILENO, msgbuf, strlen(msgbuf)); + } + mutexp->locked = (u_int32_t)pthread_self(); +#else + mutexp->locked = 1; +#endif + } + return (0); +} + +/* + * __db_pthread_mutex_unlock -- + * Release a lock. + * + * PUBLIC: int __db_pthread_mutex_unlock __P((DB_ENV *, MUTEX *)); + */ +int +__db_pthread_mutex_unlock(dbenv, mutexp) + DB_ENV *dbenv; + MUTEX *mutexp; +{ + int i, ret; + + if (!dbenv->db_mutexlocks || F_ISSET(mutexp, MUTEX_IGNORE)) + return (0); + +#ifdef DIAGNOSTIC + if (!mutexp->locked) + (void)write(STDERR_FILENO, MSG2, sizeof(MSG2) - 1); +#endif + + if (F_ISSET(mutexp, MUTEX_SELF_BLOCK)) { + if ((ret = pthread_mutex_lock(&mutexp->mutex)) != 0) + return (ret); + + mutexp->locked = 0; + + if ((ret = pthread_cond_signal(&mutexp->cond)) != 0) + return (ret); + + /* See comment above; workaround for [#2471]. */ + i = PTHREAD_UNLOCK_ATTEMPTS; + do { + ret = pthread_mutex_unlock(&mutexp->mutex); + } while (ret == EFAULT && --i > 0); + if (ret != 0) + return (ret); + } else { + mutexp->locked = 0; + + /* See comment above; workaround for [#2471]. */ + i = PTHREAD_UNLOCK_ATTEMPTS; + do { + ret = pthread_mutex_unlock(&mutexp->mutex); + } while (ret == EFAULT && --i > 0); + if (ret != 0) + return (ret); + } + + return (0); +} + +/* + * __db_pthread_mutex_destroy -- + * Destroy a MUTEX. + * + * PUBLIC: int __db_pthread_mutex_destroy __P((MUTEX *)); + */ +int +__db_pthread_mutex_destroy(mutexp) + MUTEX *mutexp; +{ + if (F_ISSET(mutexp, MUTEX_IGNORE)) + return (0); + + return (pthread_mutex_destroy(&mutexp->mutex)); +} diff --git a/db/mutex/mut_tas.c b/db/mutex/mut_tas.c new file mode 100644 index 000000000..4b0db4bdf --- /dev/null +++ b/db/mutex/mut_tas.c @@ -0,0 +1,200 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: mut_tas.c,v 11.18 2000/11/30 00:58:41 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#endif + +/* + * This is where we load in the actual test-and-set mutex code. + */ +#define LOAD_ACTUAL_MUTEX_CODE +#include "db_int.h" + +#ifdef DIAGNOSTIC +#undef MSG1 +#define MSG1 "mutex_lock: ERROR: lock currently in use: pid: %lu.\n" +#undef MSG2 +#define MSG2 "mutex_unlock: ERROR: lock already unlocked\n" +#ifndef STDERR_FILENO +#define STDERR_FILENO 2 +#endif +#endif + +/* + * __db_tas_mutex_init -- + * Initialize a MUTEX. + * + * PUBLIC: int __db_tas_mutex_init __P((DB_ENV *, MUTEX *, u_int32_t)); + */ +int +__db_tas_mutex_init(dbenv, mutexp, flags) + DB_ENV *dbenv; + MUTEX *mutexp; + u_int32_t flags; +{ + /* Check alignment. */ + DB_ASSERT(((db_alignp_t)mutexp & (MUTEX_ALIGN - 1)) == 0); + + memset(mutexp, 0, sizeof(*mutexp)); + + /* + * If this is a thread lock or the process has told us that there are + * no other processes in the environment, use thread-only locks, they + * are faster in some cases. + * + * This is where we decide to ignore locks we don't need to set -- if + * the application isn't threaded, there aren't any threads to block. + */ + if (LF_ISSET(MUTEX_THREAD) || F_ISSET(dbenv, DB_ENV_PRIVATE)) { + if (!F_ISSET(dbenv, DB_ENV_THREAD)) { + F_SET(mutexp, MUTEX_IGNORE); + return (0); + } + F_SET(mutexp, MUTEX_THREAD); + } + + /* Initialize the lock. */ + if (MUTEX_INIT(&mutexp->tas)) + return (__os_get_errno()); + + mutexp->spins = __os_spin(); +#ifdef MUTEX_SYSTEM_RESOURCES + mutexp->reg_off = INVALID_ROFF; +#endif + F_SET(mutexp, MUTEX_INITED); + + return (0); +} + +/* + * __db_tas_mutex_lock + * Lock on a mutex, logically blocking if necessary. + * + * PUBLIC: int __db_tas_mutex_lock __P((DB_ENV *, MUTEX *)); + */ +int +__db_tas_mutex_lock(dbenv, mutexp) + DB_ENV *dbenv; + MUTEX *mutexp; +{ + u_long ms; + int nspins; + + if (!dbenv->db_mutexlocks || F_ISSET(mutexp, MUTEX_IGNORE)) + return (0); + + ms = 1; + +loop: /* Attempt to acquire the resource for N spins. */ + for (nspins = mutexp->spins; nspins > 0; --nspins) { +#ifdef HAVE_MUTEX_HPPA_MSEM_INIT +relock: +#endif + if (!MUTEX_SET(&mutexp->tas)) + continue; +#ifdef HAVE_MUTEX_HPPA_MSEM_INIT + /* + * HP semaphores are unlocked automatically when a holding + * process exits. If the mutex appears to be locked + * (mutexp->locked != 0) but we got here, assume this has + * happened. Stick our own pid into mutexp->locked and + * lock again. (The default state of the mutexes used to + * block in __lock_get_internal is locked, so exiting with + * a locked mutex is reasonable behavior for a process that + * happened to initialize or use one of them.) + */ + if (mutexp->locked != 0) { + mutexp->locked = (u_int32_t)getpid(); + goto relock; + } + /* + * If we make it here, locked == 0, the diagnostic won't fire, + * and we were really unlocked by someone calling the + * DB mutex unlock function. + */ +#endif +#ifdef DIAGNOSTIC + if (mutexp->locked != 0) { + char msgbuf[128]; + (void)snprintf(msgbuf, + sizeof(msgbuf), MSG1, (u_long)mutexp->locked); + (void)write(STDERR_FILENO, msgbuf, strlen(msgbuf)); + } +#endif +#if defined(DIAGNOSTIC) || defined(HAVE_MUTEX_HPPA_MSEM_INIT) + mutexp->locked = (u_int32_t)getpid(); +#endif + if (ms == 1) + ++mutexp->mutex_set_nowait; + else + ++mutexp->mutex_set_wait; + return (0); + } + + /* Yield the processor; wait 1ms initially, up to 1 second. */ + __os_yield(NULL, ms * USEC_PER_MS); + if ((ms <<= 1) > MS_PER_SEC) + ms = MS_PER_SEC; + + goto loop; +} + +/* + * __db_tas_mutex_unlock -- + * Release a lock. + * + * PUBLIC: int __db_tas_mutex_unlock __P((DB_ENV *, MUTEX *)); + */ +int +__db_tas_mutex_unlock(dbenv, mutexp) + DB_ENV *dbenv; + MUTEX *mutexp; +{ + if (!dbenv->db_mutexlocks || F_ISSET(mutexp, MUTEX_IGNORE)) + return (0); + +#ifdef DIAGNOSTIC + if (!mutexp->locked) + (void)write(STDERR_FILENO, MSG2, sizeof(MSG2) - 1); +#endif +#if defined(DIAGNOSTIC) || defined(HAVE_MUTEX_HPPA_MSEM_INIT) + mutexp->locked = 0; +#endif + + MUTEX_UNSET(&mutexp->tas); + + return (0); +} + +/* + * __db_tas_mutex_destroy -- + * Destroy a MUTEX. + * + * PUBLIC: int __db_tas_mutex_destroy __P((MUTEX *)); + */ +int +__db_tas_mutex_destroy(mutexp) + MUTEX *mutexp; +{ + if (F_ISSET(mutexp, MUTEX_IGNORE)) + return (0); + + MUTEX_DESTROY(&mutexp->tas); + + return (0); +} diff --git a/db/mutex/mutex.c b/db/mutex/mutex.c new file mode 100644 index 000000000..acc4af9bf --- /dev/null +++ b/db/mutex/mutex.c @@ -0,0 +1,253 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: mutex.c,v 11.14 2000/11/30 00:58:42 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#endif + +#include "db_int.h" + +/* + * __db_mutex_alloc -- + * Allocate and initialize a mutex. + * + * PUBLIC: int __db_mutex_alloc __P((DB_ENV *, REGINFO *, MUTEX **)); + */ +int +__db_mutex_alloc(dbenv, infop, storep) + DB_ENV *dbenv; + REGINFO *infop; + MUTEX **storep; +{ + int ret; + + /* + * If the architecture supports mutexes in heap memory, use that + * memory. If it doesn't, we have to allocate space in a region. + * + * XXX + * There's a nasty starvation issue here for applications running + * on systems that don't support mutexes in heap memory. If the + * normal state of the entire region is dirty (e.g., mpool), then + * we can run out of memory to allocate for mutexes when new files + * are opened in the pool. We're not trying to fix this for now, + * because the only known system where we can see this failure at + * the moment is HP-UX 10.XX. + */ +#ifdef MUTEX_NO_MALLOC_LOCKS + R_LOCK(dbenv, infop); + ret = __db_shalloc(infop->addr, sizeof(MUTEX), MUTEX_ALIGN, storep); + R_UNLOCK(dbenv, infop); +#else + COMPQUIET(dbenv, NULL); + COMPQUIET(infop, NULL); + ret = __os_calloc(dbenv, 1, sizeof(MUTEX), storep); +#endif + if (ret != 0) + __db_err(dbenv, "Unable to allocate memory for mutex"); + return (ret); +} + +/* + * __db_mutex_free -- + * Free a mutex. + * + * PUBLIC: void __db_mutex_free __P((DB_ENV *, REGINFO *, MUTEX *)); + */ +void +__db_mutex_free(dbenv, infop, mutexp) + DB_ENV *dbenv; + REGINFO *infop; + MUTEX *mutexp; +{ + if (F_ISSET(mutexp, MUTEX_INITED)) + __db_mutex_destroy(mutexp); + +#ifdef MUTEX_NO_MALLOC_LOCKS + R_LOCK(dbenv, infop); + __db_shalloc_free(infop->addr, mutexp); + R_UNLOCK(dbenv, infop); +#else + COMPQUIET(dbenv, NULL); + COMPQUIET(infop, NULL); + __os_free(mutexp, sizeof(*mutexp)); +#endif +} + +#ifdef MUTEX_SYSTEM_RESOURCES +/* + * __db_shreg_locks_record -- + * Record an entry in the shared locks area. + * Region lock must be held in caller. + * + * PUBLIC: int __db_shreg_locks_record __P((DB_ENV *, MUTEX *, REGINFO *, + * PUBLIC: REGMAINT *)); + */ +int +__db_shreg_locks_record(dbenv, mutexp, infop, rp) + DB_ENV *dbenv; + MUTEX *mutexp; + REGINFO *infop; + REGMAINT *rp; +{ + u_int i; + + if (!F_ISSET(mutexp, MUTEX_INITED)) + return (0); + DB_ASSERT(mutexp->reg_off == INVALID_ROFF); + rp->stat.st_records++; + i = (roff_t *)R_ADDR(infop, rp->regmutex_hint) - &rp->regmutexes[0]; + if (rp->regmutexes[i] != INVALID_ROFF) { + /* + * Our hint failed, search for a open slot. + */ + rp->stat.st_hint_miss++; + for (i = 0; i < rp->reglocks; i++) + if (rp->regmutexes[i] == INVALID_ROFF) + break; + if (i == rp->reglocks) { + rp->stat.st_max_locks++; + __db_err(dbenv, + "Region mutexes: Exceeded maximum lock slots %lu", + (u_long)rp->reglocks); + return (ENOMEM); + } + } else + rp->stat.st_hint_hit++; + /* + * When we get here, i is an empty slot. Record this + * mutex, set hint to point to the next slot and we are done. + */ + rp->regmutexes[i] = R_OFFSET(infop, mutexp); + mutexp->reg_off = R_OFFSET(infop, &rp->regmutexes[i]); + rp->regmutex_hint = (i < rp->reglocks - 1) ? + R_OFFSET(infop, &rp->regmutexes[i+1]) : + R_OFFSET(infop, &rp->regmutexes[0]); + return (0); +} + +/* + * __db_shreg_locks_clear -- + * Erase an entry in the shared locks area. + * Region lock must be held in caller. + * + * PUBLIC: void __db_shreg_locks_clear __P((MUTEX *, REGINFO *, REGMAINT *)); + */ +void +__db_shreg_locks_clear(mutexp, infop, rp) + MUTEX *mutexp; + REGINFO *infop; + REGMAINT *rp; +{ + if (!F_ISSET(mutexp, MUTEX_INITED)) + return; + /* + * This function is generally only called on a forcible + * remove of an environment. We recorded our index in + * the mutex. Find it and clear it. + */ + DB_ASSERT(mutexp->reg_off != INVALID_ROFF); + DB_ASSERT(*(roff_t *)R_ADDR(infop, mutexp->reg_off) == \ + R_OFFSET(infop, mutexp)); + *(roff_t *)R_ADDR(infop, mutexp->reg_off) = 0; + rp->regmutex_hint = mutexp->reg_off; + rp->stat.st_clears++; + mutexp->reg_off = INVALID_ROFF; + __db_mutex_destroy(mutexp); +} + +/* + * __db_shreg_locks_destroy -- + * Destroy all mutexes in a region's range. + * + * PUBLIC: void __db_shreg_locks_destroy __P((REGINFO *, REGMAINT *)); + */ +void +__db_shreg_locks_destroy(infop, rp) + REGINFO *infop; + REGMAINT *rp; +{ + u_int32_t i; + + /* + * Go through the list of all mutexes and destroy them. + */ + for (i = 0; i < rp->reglocks; i++) + if (rp->regmutexes[i] != 0) { + rp->stat.st_destroys++; + __db_mutex_destroy((MUTEX *)R_ADDR(infop, + rp->regmutexes[i])); + } +} + +/* + * __db_shreg_mutex_init -- + * Initialize a shared memory mutex. + * + * PUBLIC: int __db_shreg_mutex_init __P((DB_ENV *, MUTEX *, u_int32_t, + * PUBLIC: u_int32_t, REGINFO *, REGMAINT *)); + */ +int +__db_shreg_mutex_init(dbenv, mutexp, offset, flags, infop, rp) + DB_ENV *dbenv; + MUTEX *mutexp; + u_int32_t offset; + u_int32_t flags; + REGINFO *infop; + REGMAINT *rp; +{ + int ret; + + if ((ret = __db_mutex_init(dbenv, mutexp, offset, flags)) != 0) + return (ret); + /* + * !!! + * Since __db_mutex_init is a macro, we may not be + * using the 'offset' as it is only used for one type + * of mutex. We COMPQUIET it here, after the call above. + */ + COMPQUIET(offset, 0); + + if (!F_ISSET(mutexp, MUTEX_THREAD)) + ret = __db_shreg_locks_record(dbenv, mutexp, infop, rp); + /* + * If we couldn't record it and we are returning an error, + * we need to destroy the mutex we just created. + */ + if (ret) + __db_mutex_destroy(mutexp); + + return (ret); +} + +/* + * __db_shreg_maintinit -- + * Initialize a region's maintenance information. + * + * PUBLIC: void __db_shreg_maintinit __P((REGINFO *, void *addr, size_t)); + */ +void +__db_shreg_maintinit(infop, addr, size) + REGINFO *infop; + void *addr; + size_t size; +{ + REGMAINT *rp; + + rp = (REGMAINT *)addr; + memset(addr, 0, sizeof(REGMAINT)); + rp->reglocks = size / sizeof(roff_t); + rp->regmutex_hint = R_OFFSET(infop, &rp->regmutexes[0]); +} +#endif /* MUTEX_SYSTEM_RESOURCES */ diff --git a/db/mutex/uts4_cc.s b/db/mutex/uts4_cc.s new file mode 100644 index 000000000..ee5f4143b --- /dev/null +++ b/db/mutex/uts4_cc.s @@ -0,0 +1,21 @@ + / + / int uts_lock ( int *p, int i ); + / Update the lock word pointed to by p with the + / value i, using compare-and-swap. + / Returns 0 if update was successful. + / Returns 1 if update failed. + / + entry uts_lock + uts_lock: + using .,r15 + st r2,8(sp) / Save R2 + l r2,64+0(sp) / R2 -> word to update + slr r0, r0 / R0 = current lock value must be 0 + l r1,64+4(sp) / R1 = new lock value + cs r0,r1,0(r2) / Try the update ... + be x / ... Success. Return 0 + la r0,1 / ... Failure. Return 1 + x: / + l r2,8(sp) / Restore R2 + b 2(,r14) / Return to caller + drop r15 diff --git a/db/os/os_abs.c b/db/os/os_abs.c new file mode 100644 index 000000000..04be98733 --- /dev/null +++ b/db/os/os_abs.c @@ -0,0 +1,31 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: os_abs.c,v 11.3 2000/02/14 03:00:04 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include +#endif + +#include "db_int.h" + +/* + * __os_abspath -- + * Return if a path is an absolute path. + * + * PUBLIC: int __os_abspath __P((const char *)); + */ +int +__os_abspath(path) + const char *path; +{ + return (path[0] == '/'); +} diff --git a/db/os/os_alloc.c b/db/os/os_alloc.c new file mode 100644 index 000000000..ee4a0f3c9 --- /dev/null +++ b/db/os/os_alloc.c @@ -0,0 +1,342 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: os_alloc.c,v 11.18 2000/11/30 00:58:42 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#endif + +#include "db_int.h" +#include "os_jump.h" + +#ifdef DIAGNOSTIC +static void __os_guard __P((void)); +#endif + +/* + * !!! + * Correct for systems that return NULL when you allocate 0 bytes of memory. + * There are several places in DB where we allocate the number of bytes held + * by the key/data item, and it can be 0. Correct here so that malloc never + * returns a NULL for that reason (which behavior is permitted by ANSI). We + * could make these calls macros on non-Alpha architectures (that's where we + * saw the problem), but it's probably not worth the autoconf complexity. + * + * !!! + * Correct for systems that don't set errno when malloc and friends fail. + * + * Out of memory. + * We wish to hold the whole sky, + * But we never will. + */ + +/* + * __os_strdup -- + * The strdup(3) function for DB. + * + * PUBLIC: int __os_strdup __P((DB_ENV *, const char *, void *)); + */ +int +__os_strdup(dbenv, str, storep) + DB_ENV *dbenv; + const char *str; + void *storep; +{ + size_t size; + int ret; + void *p; + + *(void **)storep = NULL; + + size = strlen(str) + 1; + if ((ret = __os_malloc(dbenv, size, NULL, &p)) != 0) + return (ret); + + memcpy(p, str, size); + + *(void **)storep = p; + return (0); +} + +/* + * __os_calloc -- + * The calloc(3) function for DB. + * + * PUBLIC: int __os_calloc __P((DB_ENV *, size_t, size_t, void *)); + */ +int +__os_calloc(dbenv, num, size, storep) + DB_ENV *dbenv; + size_t num, size; + void *storep; +{ + void *p; + int ret; + + size *= num; + if ((ret = __os_malloc(dbenv, size, NULL, &p)) != 0) + return (ret); + + memset(p, 0, size); + + *(void **)storep = p; + return (0); +} + +/* + * __os_malloc -- + * The malloc(3) function for DB. + * + * PUBLIC: int __os_malloc __P((DB_ENV *, size_t, void *(*)(size_t), void *)); + */ +int +__os_malloc(dbenv, size, db_malloc, storep) + DB_ENV *dbenv; + size_t size; + void *(*db_malloc) __P((size_t)), *storep; +{ + int ret; + void *p; + + *(void **)storep = NULL; + + /* Never allocate 0 bytes -- some C libraries don't like it. */ + if (size == 0) + ++size; +#ifdef DIAGNOSTIC + else + ++size; /* Add room for a guard byte. */ +#endif + + /* Some C libraries don't correctly set errno when malloc(3) fails. */ + __os_set_errno(0); + if (db_malloc != NULL) + p = db_malloc(size); + else if (__db_jump.j_malloc != NULL) + p = __db_jump.j_malloc(size); + else + p = malloc(size); + if (p == NULL) { + ret = __os_get_errno(); + if (ret == 0) { + __os_set_errno(ENOMEM); + ret = ENOMEM; + } + __db_err(dbenv, + "malloc: %s: %lu", strerror(ret), (u_long)size); + return (ret); + } + +#ifdef DIAGNOSTIC + /* + * Guard bytes: if #DIAGNOSTIC is defined, we allocate an additional + * byte after the memory and set it to a special value that we check + * for when the memory is free'd. This is fine for structures, but + * not quite so fine for strings. There are places in DB where memory + * is allocated sufficient to hold the largest possible string that + * we'll see, and then only some subset of the memory is used. To + * support this usage, the __os_freestr() function checks the byte + * after the string's nul, which may or may not be the last byte in + * the originally allocated memory. + */ + memset(p, CLEAR_BYTE, size); /* Initialize guard byte. */ +#endif + *(void **)storep = p; + + return (0); +} + +/* + * __os_realloc -- + * The realloc(3) function for DB. + * + * PUBLIC: int __os_realloc __P((DB_ENV *, + * PUBLIC: size_t, void *(*)(void *, size_t), void *)); + */ +int +__os_realloc(dbenv, size, db_realloc, storep) + DB_ENV *dbenv; + size_t size; + void *(*db_realloc) __P((void *, size_t)), *storep; +{ + int ret; + void *p, *ptr; + + ptr = *(void **)storep; + + /* If we haven't yet allocated anything yet, simply call malloc. */ + if (ptr == NULL && db_realloc == NULL) + return (__os_malloc(dbenv, size, NULL, storep)); + + /* Never allocate 0 bytes -- some C libraries don't like it. */ + if (size == 0) + ++size; +#ifdef DIAGNOSTIC + else + ++size; /* Add room for a guard byte. */ +#endif + + /* + * Some C libraries don't correctly set errno when realloc(3) fails. + * + * Don't overwrite the original pointer, there are places in DB we + * try to continue after realloc fails. + */ + __os_set_errno(0); + if (db_realloc != NULL) + p = db_realloc(ptr, size); + else if (__db_jump.j_realloc != NULL) + p = __db_jump.j_realloc(ptr, size); + else + p = realloc(ptr, size); + if (p == NULL) { + if ((ret = __os_get_errno()) == 0) { + ret = ENOMEM; + __os_set_errno(ENOMEM); + } + __db_err(dbenv, + "realloc: %s: %lu", strerror(ret), (u_long)size); + return (ret); + } +#ifdef DIAGNOSTIC + ((u_int8_t *)p)[size - 1] = CLEAR_BYTE; /* Initialize guard byte. */ +#endif + + *(void **)storep = p; + + return (0); +} + +/* + * __os_free -- + * The free(3) function for DB. + * + * PUBLIC: void __os_free __P((void *, size_t)); + */ +void +__os_free(ptr, size) + void *ptr; + size_t size; +{ +#ifdef DIAGNOSTIC + if (size != 0) { + /* + * Check that the guard byte (one past the end of the memory) is + * still CLEAR_BYTE. + */ + if (((u_int8_t *)ptr)[size] != CLEAR_BYTE) + __os_guard(); + + /* Clear memory. */ + if (size != 0) + memset(ptr, CLEAR_BYTE, size); + } +#else + COMPQUIET(size, 0); +#endif + + if (__db_jump.j_free != NULL) + __db_jump.j_free(ptr); + else + free(ptr); +} + +/* + * __os_freestr -- + * The free(3) function for DB, freeing a string. + * + * PUBLIC: void __os_freestr __P((void *)); + */ +void +__os_freestr(ptr) + void *ptr; +{ +#ifdef DIAGNOSTIC + size_t size; + + size = strlen(ptr) + 1; + + /* + * Check that the guard byte (one past the end of the memory) is + * still CLEAR_BYTE. + */ + if (((u_int8_t *)ptr)[size] != CLEAR_BYTE) + __os_guard(); + + /* Clear memory. */ + memset(ptr, CLEAR_BYTE, size); +#endif + + if (__db_jump.j_free != NULL) + __db_jump.j_free(ptr); + else + free(ptr); +} + +#ifdef DIAGNOSTIC +/* + * __os_guard -- + * Complain and abort. + */ +static void +__os_guard() +{ + /* + * Eventually, once we push a DB_ENV handle down to these + * routines, we should use the standard output channels. + */ + fprintf(stderr, "Guard byte incorrect during free.\n"); + abort(); + /* NOTREACHED */ +} +#endif + +/* + * __ua_memcpy -- + * Copy memory to memory without relying on any kind of alignment. + * + * There are places in DB that we have unaligned data, for example, + * when we've stored a structure in a log record as a DBT, and now + * we want to look at it. Unfortunately, if you have code like: + * + * struct a { + * int x; + * } *p; + * + * void *func_argument; + * int local; + * + * p = (struct a *)func_argument; + * memcpy(&local, p->x, sizeof(local)); + * + * compilers optimize to use inline instructions requiring alignment, + * and records in the log don't have any particular alignment. (This + * isn't a compiler bug, because it's a structure they're allowed to + * assume alignment.) + * + * Casting the memcpy arguments to (u_int8_t *) appears to work most + * of the time, but we've seen examples where it wasn't sufficient + * and there's nothing in ANSI C that requires that work. + * + * PUBLIC: void *__ua_memcpy __P((void *, const void *, size_t)); + */ +void * +__ua_memcpy(dst, src, len) + void *dst; + const void *src; + size_t len; +{ + return ((void *)memcpy(dst, src, len)); +} diff --git a/db/os/os_dir.c b/db/os/os_dir.c new file mode 100644 index 000000000..50d00a556 --- /dev/null +++ b/db/os/os_dir.c @@ -0,0 +1,108 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: os_dir.c,v 11.8 2000/06/27 17:29:52 sue Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#if HAVE_DIRENT_H +# include +# define NAMLEN(dirent) strlen((dirent)->d_name) +#else +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# if HAVE_SYS_NDIR_H +# include +# endif +# if HAVE_SYS_DIR_H +# include +# endif +# if HAVE_NDIR_H +# include +# endif +#endif + +#endif + +#include "db_int.h" +#include "os_jump.h" + +/* + * __os_dirlist -- + * Return a list of the files in a directory. + * + * PUBLIC: int __os_dirlist __P((DB_ENV *, const char *, char ***, int *)); + */ +int +__os_dirlist(dbenv, dir, namesp, cntp) + DB_ENV *dbenv; + const char *dir; + char ***namesp; + int *cntp; +{ + struct dirent *dp; + DIR *dirp; + int arraysz, cnt, ret; + char **names; + + if (__db_jump.j_dirlist != NULL) + return (__db_jump.j_dirlist(dir, namesp, cntp)); + +#ifdef HAVE_VXWORKS + if ((dirp = opendir((char *)dir)) == NULL) +#else + if ((dirp = opendir(dir)) == NULL) +#endif + return (__os_get_errno()); + names = NULL; + for (arraysz = cnt = 0; (dp = readdir(dirp)) != NULL; ++cnt) { + if (cnt >= arraysz) { + arraysz += 100; + if ((ret = __os_realloc(dbenv, + arraysz * sizeof(names[0]), NULL, &names)) != 0) + goto nomem; + } + if ((ret = __os_strdup(dbenv, dp->d_name, &names[cnt])) != 0) + goto nomem; + } + (void)closedir(dirp); + + *namesp = names; + *cntp = cnt; + return (0); + +nomem: if (names != NULL) + __os_dirfree(names, cnt); + if (dirp != NULL) + (void)closedir(dirp); + return (ret); +} + +/* + * __os_dirfree -- + * Free the list of files. + * + * PUBLIC: void __os_dirfree __P((char **, int)); + */ +void +__os_dirfree(names, cnt) + char **names; + int cnt; +{ + if (__db_jump.j_dirfree != NULL) + __db_jump.j_dirfree(names, cnt); + else { + while (cnt > 0) + __os_free(names[--cnt], 0); + __os_free(names, 0); + } +} diff --git a/db/os/os_errno.c b/db/os/os_errno.c new file mode 100644 index 000000000..f9b60f635 --- /dev/null +++ b/db/os/os_errno.c @@ -0,0 +1,44 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: os_errno.c,v 11.3 2000/02/14 03:00:05 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include +#endif + +#include "db_int.h" + +/* + * __os_get_errno -- + * Return the value of errno. + * + * PUBLIC: int __os_get_errno __P((void)); + */ +int +__os_get_errno() +{ + /* This routine must be able to return the same value repeatedly. */ + return (errno); +} + +/* + * __os_set_errno -- + * Set the value of errno. + * + * PUBLIC: void __os_set_errno __P((int)); + */ +void +__os_set_errno(evalue) + int evalue; +{ + errno = evalue; +} diff --git a/db/os/os_fid.c b/db/os/os_fid.c new file mode 100644 index 000000000..f853f6a8d --- /dev/null +++ b/db/os/os_fid.c @@ -0,0 +1,140 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: os_fid.c,v 11.7 2000/10/26 14:17:05 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include +#include + +#if TIME_WITH_SYS_TIME +#include +#include +#else +#if HAVE_SYS_TIME_H +#include +#else +#include +#endif +#endif + +#include +#include +#endif + +#include "db_int.h" + +#define SERIAL_INIT 0 +static u_int32_t fid_serial = SERIAL_INIT; + +/* + * __os_fileid -- + * Return a unique identifier for a file. + * + * PUBLIC: int __os_fileid __P((DB_ENV *, const char *, int, u_int8_t *)); + */ +int +__os_fileid(dbenv, fname, unique_okay, fidp) + DB_ENV *dbenv; + const char *fname; + int unique_okay; + u_int8_t *fidp; +{ + struct stat sb; + size_t i; + int ret; + u_int32_t tmp; + u_int8_t *p; + + /* Clear the buffer. */ + memset(fidp, 0, DB_FILE_ID_LEN); + + /* On POSIX/UNIX, use a dev/inode pair. */ +#ifdef HAVE_VXWORKS + if (stat((char *)fname, &sb)) { +#else + if (stat(fname, &sb)) { +#endif + ret = __os_get_errno(); + __db_err(dbenv, "%s: %s", fname, strerror(ret)); + return (ret); + } + + /* + * Initialize/increment the serial number we use to help avoid + * fileid collisions. Note that we don't bother with locking; + * it's unpleasant to do from down in here, and if we race on + * this no real harm will be done, since the finished fileid + * has so many other components. + * + * We increment by 100000 on each call as a simple way of + * randomizing; simply incrementing seems potentially less useful + * if pids are also simply incremented, since this is process-local + * and we may be one of a set of processes starting up. 100000 + * pushes us out of pid space on most platforms, and has few + * interesting properties in base 2. + */ + if (fid_serial == SERIAL_INIT) + fid_serial = (u_int32_t)getpid(); + else + fid_serial += 100000; + + /* + * !!! + * Nothing is ever big enough -- on Sparc V9, st_ino, st_dev and the + * time_t types are all 8 bytes. As DB_FILE_ID_LEN is only 20 bytes, + * we convert to a (potentially) smaller fixed-size type and use it. + * + * We don't worry about byte sexing or the actual variable sizes. + * + * When this routine is called from the DB access methods, it's only + * called once -- whatever ID is generated when a database is created + * is stored in the database file's metadata, and that is what is + * saved in the mpool region's information to uniquely identify the + * file. + * + * When called from the mpool layer this routine will be called each + * time a new thread of control wants to share the file, which makes + * things tougher. As far as byte sexing goes, since the mpool region + * lives on a single host, there's no issue of that -- the entire + * region is byte sex dependent. As far as variable sizes go, we make + * the simplifying assumption that 32-bit and 64-bit processes will + * get the same 32-bit values if we truncate any returned 64-bit value + * to a 32-bit value. When we're called from the mpool layer, though, + * we need to be careful not to include anything that isn't + * reproducible for a given file, such as the timestamp or serial + * number. + */ + tmp = (u_int32_t)sb.st_ino; + for (p = (u_int8_t *)&tmp, i = sizeof(u_int32_t); i > 0; --i) + *fidp++ = *p++; + + tmp = (u_int32_t)sb.st_dev; + for (p = (u_int8_t *)&tmp, i = sizeof(u_int32_t); i > 0; --i) + *fidp++ = *p++; + + if (unique_okay) { + /* + * We want the number of seconds, not the high-order 0 bits, + * so convert the returned time_t to a (potentially) smaller + * fixed-size type. + */ + tmp = (u_int32_t)time(NULL); + for (p = (u_int8_t *)&tmp, i = sizeof(u_int32_t); i > 0; --i) + *fidp++ = *p++; + + for (p = (u_int8_t *)&fid_serial, i = sizeof(u_int32_t); + i > 0; --i) + *fidp++ = *p++; + } + + return (0); +} diff --git a/db/os/os_finit.c b/db/os/os_finit.c new file mode 100644 index 000000000..23b606ecb --- /dev/null +++ b/db/os/os_finit.c @@ -0,0 +1,111 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: os_finit.c,v 11.8 2000/11/30 00:58:42 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" + +/* + * __os_finit -- + * Initialize a regular file, optionally zero-filling it as well. + * + * PUBLIC: int __os_finit __P((DB_ENV *, DB_FH *, size_t, int)); + */ +int +__os_finit(dbenv, fhp, size, zerofill) + DB_ENV *dbenv; + DB_FH *fhp; + size_t size; + int zerofill; +{ + db_pgno_t pages; + size_t i; + size_t nw; + u_int32_t relative; + int ret; + char buf[OS_VMPAGESIZE]; + + /* Write nuls to the new bytes. */ + memset(buf, 0, sizeof(buf)); + + /* + * Extend the region by writing the last page. If the region is >4Gb, + * increment may be larger than the maximum possible seek "relative" + * argument, as it's an unsigned 32-bit value. Break the offset into + * pages of 1MB each so that we don't overflow (2^20 + 2^32 is bigger + * than any memory I expect to see for awhile). + */ + if ((ret = __os_seek(dbenv, fhp, 0, 0, 0, 0, DB_OS_SEEK_END)) != 0) + return (ret); + pages = (size - OS_VMPAGESIZE) / MEGABYTE; + relative = (size - OS_VMPAGESIZE) % MEGABYTE; + if ((ret = __os_seek(dbenv, + fhp, MEGABYTE, pages, relative, 0, DB_OS_SEEK_CUR)) != 0) + return (ret); + if ((ret = __os_write(dbenv, fhp, buf, sizeof(buf), &nw)) != 0) + return (ret); + if (nw != sizeof(buf)) + return (EIO); + + /* + * We may want to guarantee that there is enough disk space for the + * file, so we also write a byte to each page. We write the byte + * because reading it is insufficient on systems smart enough not to + * instantiate disk pages to satisfy a read (e.g., Solaris). + */ + if (zerofill) { + pages = size / MEGABYTE; + relative = size % MEGABYTE; + if ((ret = __os_seek(dbenv, fhp, + MEGABYTE, pages, relative, 1, DB_OS_SEEK_END)) != 0) + return (ret); + + /* Write a byte to each page. */ + for (i = 0; i < size; i += OS_VMPAGESIZE) { + if ((ret = __os_write(dbenv, fhp, buf, 1, &nw)) != 0) + return (ret); + if (nw != 1) + return (EIO); + if ((ret = __os_seek(dbenv, fhp, + 0, 0, OS_VMPAGESIZE - 1, 0, DB_OS_SEEK_CUR)) != 0) + return (ret); + } + } + return (0); +} + +/* + * __os_fpinit -- + * Initialize a page in a regular file. + * + * PUBLIC: int __os_fpinit __P((DB_ENV *, DB_FH *, db_pgno_t, int, int)); + */ +int +__os_fpinit(dbenv, fhp, pgno, pagecount, pagesize) + DB_ENV *dbenv; + DB_FH *fhp; + db_pgno_t pgno; + int pagecount, pagesize; +{ + COMPQUIET(dbenv, NULL); + COMPQUIET(fhp, NULL); + COMPQUIET(pgno, 0); + COMPQUIET(pagecount, 0); + COMPQUIET(pagesize, 0); + + return (0); +} diff --git a/db/os/os_fsync.c b/db/os/os_fsync.c new file mode 100644 index 000000000..f5fd5f56a --- /dev/null +++ b/db/os/os_fsync.c @@ -0,0 +1,90 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: os_fsync.c,v 11.9 2000/04/04 23:29:20 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include /* XXX: Required by __hp3000s900 */ +#include +#include +#endif + +#include "db_int.h" +#include "os_jump.h" + +#ifdef HAVE_VXWORKS +#include "ioLib.h" + +#define fsync(fd) __vx_fsync(fd); + +int +__vx_fsync(fd) + int fd; +{ + int ret; + + /* + * The results of ioctl are driver dependent. Some will return the + * number of bytes sync'ed. Only if it returns 'ERROR' should we + * flag it. + */ + if ((ret = ioctl(fd, FIOSYNC, 0)) != ERROR) + return (0); + return (ret); +} +#endif + +#ifdef __hp3000s900 +#define fsync(fd) __mpe_fsync(fd); + +int +__mpe_fsync(fd) + int fd; +{ + extern FCONTROL(short, short, void *); + + FCONTROL(_MPE_FILENO(fd), 2, NULL); /* Flush the buffers */ + FCONTROL(_MPE_FILENO(fd), 6, NULL); /* Write the EOF */ + return (0); +} +#endif + +/* + * __os_fsync -- + * Flush a file descriptor. + * + * PUBLIC: int __os_fsync __P((DB_ENV *, DB_FH *)); + */ +int +__os_fsync(dbenv, fhp) + DB_ENV *dbenv; + DB_FH *fhp; +{ + int ret; + + /* + * Do nothing if the file descriptor has been marked as not requiring + * any sync to disk. + */ + if (F_ISSET(fhp, DB_FH_NOSYNC)) + return (0); + + ret = __db_jump.j_fsync != NULL ? + __db_jump.j_fsync(fhp->fd) : fsync(fhp->fd); + + if (ret != 0) { + ret = __os_get_errno(); + __db_err(dbenv, "fsync %s", strerror(ret)); + } + return (ret); +} diff --git a/db/os/os_handle.c b/db/os/os_handle.c new file mode 100644 index 000000000..b127c5ff5 --- /dev/null +++ b/db/os/os_handle.c @@ -0,0 +1,165 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: os_handle.c,v 11.19 2000/11/30 00:58:42 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#endif + +#include "db_int.h" +#include "os_jump.h" + +/* + * __os_openhandle -- + * Open a file, using POSIX 1003.1 open flags. + * + * PUBLIC: int __os_openhandle __P((DB_ENV *, const char *, int, int, DB_FH *)); + */ +int +__os_openhandle(dbenv, name, flags, mode, fhp) + DB_ENV *dbenv; + const char *name; + int flags, mode; + DB_FH *fhp; +{ + int ret, nrepeat; +#ifdef HAVE_VXWORKS + int newflags; +#endif + + memset(fhp, 0, sizeof(*fhp)); + + /* If the application specified an interface, use it. */ + if (__db_jump.j_open != NULL) { + if ((fhp->fd = __db_jump.j_open(name, flags, mode)) == -1) + return (__os_get_errno()); + F_SET(fhp, DB_FH_VALID); + return (0); + } + + for (ret = 0, nrepeat = 1; nrepeat < 4; ++nrepeat) { +#ifdef HAVE_VXWORKS + /* + * VxWorks does not support O_CREAT on open, you have to use + * creat() instead. (It does not support O_EXCL or O_TRUNC + * either, even though they are defined "for future support".) + * If O_EXCL is specified, single thread and try to open the + * file. If successful, return EEXIST. Otherwise, call creat + * and then end single threading. + */ + if (LF_ISSET(O_CREAT)) { + DB_BEGIN_SINGLE_THREAD; + newflags = flags & ~(O_CREAT | O_EXCL); + if (LF_ISSET(O_EXCL)) { + if ((fhp->fd = + open(name, newflags, mode)) != -1) { + /* + * If we get here, we want O_EXCL + * create, and it exists. Close and + * return EEXISTS. + */ + (void)close(fhp->fd); + DB_END_SINGLE_THREAD; + return (EEXIST); + } + /* + * XXX + * Assume any error means non-existence. + * Unfortunately return values (even for + * non-existence) are driver specific so + * there is no single error we can use to + * verify we truly got the equivalent of + * ENOENT. + */ + } + fhp->fd = creat(name, newflags); + DB_END_SINGLE_THREAD; + } else + + /* FALLTHROUGH */ +#endif +#ifdef __VMS + /* + * !!! + * Open with full sharing on VMS. + * + * We use these flags because they are the ones set by the VMS + * CRTL mmap() call when it opens a file, and we have to be + * able to open files that mmap() has previously opened, e.g., + * when we're joining already existing DB regions. + */ + fhp->fd = open(name, flags, mode, "shr=get,put,upd,del,upi"); +#else + fhp->fd = open(name, flags, mode); +#endif + + if (fhp->fd == -1) { + /* + * If it's a "temporary" error, we retry up to 3 times, + * waiting up to 12 seconds. While it's not a problem + * if we can't open a database, an inability to open a + * log file is cause for serious dismay. + */ + ret = __os_get_errno(); + if (ret == ENFILE || ret == EMFILE || ret == ENOSPC) { + (void)__os_sleep(dbenv, nrepeat * 2, 0); + continue; + } + } else { +#if defined(HAVE_FCNTL_F_SETFD) + /* Deny file descriptor access to any child process. */ + if (fcntl(fhp->fd, F_SETFD, 1) == -1) { + ret = __os_get_errno(); + __db_err(dbenv, "fcntl(F_SETFD): %s", + strerror(ret)); + (void)__os_closehandle(fhp); + } else +#endif + F_SET(fhp, DB_FH_VALID); + } + break; + } + + return (ret); +} + +/* + * __os_closehandle -- + * Close a file. + * + * PUBLIC: int __os_closehandle __P((DB_FH *)); + */ +int +__os_closehandle(fhp) + DB_FH *fhp; +{ + int ret; + + /* Don't close file descriptors that were never opened. */ + DB_ASSERT(F_ISSET(fhp, DB_FH_VALID) && fhp->fd != -1); + + ret = __db_jump.j_close != NULL ? + __db_jump.j_close(fhp->fd) : close(fhp->fd); + + /* + * Smash the POSIX file descriptor -- it's never tested, but we want + * to catch any mistakes. + */ + fhp->fd = -1; + F_CLR(fhp, DB_FH_VALID); + + return (ret == 0 ? 0 : __os_get_errno()); +} diff --git a/db/os/os_map.c b/db/os/os_map.c new file mode 100644 index 000000000..bb96a917d --- /dev/null +++ b/db/os/os_map.c @@ -0,0 +1,436 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: os_map.c,v 11.32 2000/11/30 00:58:42 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include +#ifdef HAVE_MMAP +#include +#endif + +#ifdef HAVE_SHMGET +#include +#include +#endif + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_ext.h" +#include "os_jump.h" + +#ifdef HAVE_MMAP +static int __os_map __P((DB_ENV *, char *, DB_FH *, size_t, int, int, void **)); +#endif +#ifndef HAVE_SHMGET +static int __db_nosystemmem __P((DB_ENV *)); +#endif + +/* + * __os_r_sysattach -- + * Create/join a shared memory region. + * + * PUBLIC: int __os_r_sysattach __P((DB_ENV *, REGINFO *, REGION *)); + */ +int +__os_r_sysattach(dbenv, infop, rp) + DB_ENV *dbenv; + REGINFO *infop; + REGION *rp; +{ + if (F_ISSET(dbenv, DB_ENV_SYSTEM_MEM)) { + /* + * If the region is in system memory on UNIX, we use shmget(2). + * + * !!! + * There exist spinlocks that don't work in shmget memory, e.g., + * the HP/UX msemaphore interface. If we don't have locks that + * will work in shmget memory, we better be private and not be + * threaded. If we reach this point, we know we're public, so + * it's an error. + */ +#if defined(MUTEX_NO_SHMGET_LOCKS) + __db_err(dbenv, + "architecture does not support locks inside system shared memory"); + return (EINVAL); +#endif +#if defined(HAVE_SHMGET) + { + key_t segid; + int id, ret; + + /* + * We could potentially create based on REGION_CREATE_OK, but + * that's dangerous -- we might get crammed in sideways if + * some of the expected regions exist but others do not. Also, + * if the requested size differs from an existing region's + * actual size, then all sorts of nasty things can happen. + * Basing create solely on REGION_CREATE is much safer -- a + * recovery will get us straightened out. + */ + if (F_ISSET(infop, REGION_CREATE)) { + /* + * The application must give us a base System V IPC key + * value. Adjust that value based on the region's ID, + * and correct so the user's original value appears in + * the ipcs output. + */ + if (dbenv->shm_key == INVALID_REGION_SEGID) { + __db_err(dbenv, + "no base system shared memory ID specified"); + return (EINVAL); + } + segid = (key_t)(dbenv->shm_key + (infop->id - 1)); + + /* + * If map to an existing region, assume the application + * crashed and we're restarting. Delete the old region + * and re-try. If that fails, return an error, the + * application will have to select a different segment + * ID or clean up some other way. + */ + if ((id = shmget(segid, 0, 0)) != -1) { + (void)shmctl(id, IPC_RMID, NULL); + if ((id = shmget(segid, 0, 0)) != -1) { + __db_err(dbenv, + "shmget: key: %ld: shared system memory region already exists", + (long)segid); + return (EAGAIN); + } + } + if ((id = + shmget(segid, rp->size, IPC_CREAT | 0600)) == -1) { + ret = __os_get_errno(); + __db_err(dbenv, + "shmget: key: %ld: unable to create shared system memory region: %s", + (long)segid, strerror(ret)); + return (ret); + } + rp->segid = id; + } else + id = rp->segid; + + if ((infop->addr = shmat(id, NULL, 0)) == (void *)-1) { + infop->addr = NULL; + ret = __os_get_errno(); + __db_err(dbenv, + "shmat: id %d: unable to attach to shared system memory region: %s", + id, strerror(ret)); + return (ret); + } + + return (0); + } +#else + return (__db_nosystemmem(dbenv)); +#endif + } + +#ifdef HAVE_MMAP + { + DB_FH fh; + int ret; + + /* + * Try to open/create the shared region file. We DO NOT need to + * ensure that multiple threads/processes attempting to + * simultaneously create the region are properly ordered, + * our caller has already taken care of that. + */ + if ((ret = __os_open(dbenv, infop->name, DB_OSO_REGION | + (F_ISSET(infop, REGION_CREATE_OK) ? DB_OSO_CREATE : 0), + infop->mode, &fh)) != 0) + __db_err(dbenv, "%s: %s", infop->name, db_strerror(ret)); + + /* + * If we created the file, grow it to its full size before mapping + * it in. We really want to avoid touching the buffer cache after + * mmap(2) is called, doing anything else confuses the hell out of + * systems without merged VM/buffer cache systems, or, more to the + * point, *badly* merged VM/buffer cache systems. + */ + if (ret == 0 && F_ISSET(infop, REGION_CREATE)) + ret = __os_finit(dbenv, + &fh, rp->size, DB_GLOBAL(db_region_init)); + + /* Map the file in. */ + if (ret == 0) + ret = __os_map(dbenv, + infop->name, &fh, rp->size, 1, 0, &infop->addr); + + (void)__os_closehandle(&fh); + + return (ret); + } +#else + COMPQUIET(infop, NULL); + COMPQUIET(rp, NULL); + __db_err(dbenv, + "architecture lacks mmap(2), shared environments not possible"); + return (__db_eopnotsup(dbenv)); +#endif +} + +/* + * __os_r_sysdetach -- + * Detach from a shared memory region. + * + * PUBLIC: int __os_r_sysdetach __P((DB_ENV *, REGINFO *, int)); + */ +int +__os_r_sysdetach(dbenv, infop, destroy) + DB_ENV *dbenv; + REGINFO *infop; + int destroy; +{ + REGION *rp; + + rp = infop->rp; + + if (F_ISSET(dbenv, DB_ENV_SYSTEM_MEM)) { +#ifdef HAVE_SHMGET + int ret, segid; + + /* + * We may be about to remove the memory referenced by rp, + * save the segment ID, and (optionally) wipe the original. + */ + segid = rp->segid; + if (destroy) + rp->segid = INVALID_REGION_SEGID; + + if (shmdt(infop->addr) != 0) { + ret = __os_get_errno(); + __db_err(dbenv, "shmdt: %s", strerror(ret)); + return (ret); + } + + if (destroy && shmctl(segid, IPC_RMID, + NULL) != 0 && (ret = __os_get_errno()) != EINVAL) { + __db_err(dbenv, + "shmctl: id %ld: unable to delete system shared memory region: %s", + segid, strerror(ret)); + return (ret); + } + + return (0); +#else + return (__db_nosystemmem(dbenv)); +#endif + } + +#ifdef HAVE_MMAP +#ifdef HAVE_MUNLOCK + if (F_ISSET(dbenv, DB_ENV_LOCKDOWN)) + (void)munlock(infop->addr, rp->size); +#endif + if (munmap(infop->addr, rp->size) != 0) { + int ret; + + ret = __os_get_errno(); + __db_err(dbenv, "munmap: %s", strerror(ret)); + return (ret); + } + + if (destroy && __os_region_unlink(dbenv, infop->name) != 0) + return (__os_get_errno()); + + return (0); +#else + COMPQUIET(destroy, 0); + return (EINVAL); +#endif +} + +/* + * __os_mapfile -- + * Map in a shared memory file. + * + * PUBLIC: int __os_mapfile __P((DB_ENV *, + * PUBLIC: char *, DB_FH *, size_t, int, void **)); + */ +int +__os_mapfile(dbenv, path, fhp, len, is_rdonly, addrp) + DB_ENV *dbenv; + char *path; + DB_FH *fhp; + int is_rdonly; + size_t len; + void **addrp; +{ +#if defined(HAVE_MMAP) && !defined(HAVE_QNX) + return (__os_map(dbenv, path, fhp, len, 0, is_rdonly, addrp)); +#else + COMPQUIET(dbenv, NULL); + COMPQUIET(path, NULL); + COMPQUIET(fhp, NULL); + COMPQUIET(is_rdonly, 0); + COMPQUIET(len, 0); + COMPQUIET(addrp, NULL); + return (EINVAL); +#endif +} + +/* + * __os_unmapfile -- + * Unmap the shared memory file. + * + * PUBLIC: int __os_unmapfile __P((DB_ENV *, void *, size_t)); + */ +int +__os_unmapfile(dbenv, addr, len) + DB_ENV *dbenv; + void *addr; + size_t len; +{ + /* If the user replaced the map call, call through their interface. */ + if (__db_jump.j_unmap != NULL) + return (__db_jump.j_unmap(addr, len)); + +#ifdef HAVE_MMAP +#ifdef HAVE_MUNLOCK + if (F_ISSET(dbenv, DB_ENV_LOCKDOWN)) + (void)munlock(addr, len); +#else + COMPQUIET(dbenv, NULL); +#endif + return (munmap(addr, len) ? __os_get_errno() : 0); +#else + COMPQUIET(dbenv, NULL); + + return (EINVAL); +#endif +} + +#ifdef HAVE_MMAP +/* + * __os_map -- + * Call the mmap(2) function. + */ +static int +__os_map(dbenv, path, fhp, len, is_region, is_rdonly, addrp) + DB_ENV *dbenv; + char *path; + DB_FH *fhp; + int is_region, is_rdonly; + size_t len; + void **addrp; +{ + void *p; + int flags, prot, ret; + + /* If the user replaced the map call, call through their interface. */ + if (__db_jump.j_map != NULL) + return (__db_jump.j_map + (path, len, is_region, is_rdonly, addrp)); + + /* + * If it's read-only, it's private, and if it's not, it's shared. + * Don't bother with an additional parameter. + */ + flags = is_rdonly ? MAP_PRIVATE : MAP_SHARED; + +#ifdef MAP_FILE + /* + * Historically, MAP_FILE was required for mapping regular files, + * even though it was the default. Some systems have it, some + * don't, some that have it set it to 0. + */ + flags |= MAP_FILE; +#endif + + /* + * I know of no systems that implement the flag to tell the system + * that the region contains semaphores, but it's not an unreasonable + * thing to do, and has been part of the design since forever. I + * don't think anyone will object, but don't set it for read-only + * files, it doesn't make sense. + */ +#ifdef MAP_HASSEMAPHORE + if (is_region && !is_rdonly) + flags |= MAP_HASSEMAPHORE; +#else + COMPQUIET(is_region, 0); +#endif + + prot = PROT_READ | (is_rdonly ? 0 : PROT_WRITE); + + /* + * XXX + * Work around a bug in the VMS V7.1 mmap() implementation. To map + * a file into memory on VMS it needs to be opened in a certain way, + * originally. To get the file opened in that certain way, the VMS + * mmap() closes the file and re-opens it. When it does this, it + * doesn't flush any caches out to disk before closing. The problem + * this causes us is that when the memory cache doesn't get written + * out, the file isn't big enough to match the memory chunk and the + * mmap() call fails. This call to fsync() fixes the problem. DEC + * thinks this isn't a bug because of language in XPG5 discussing user + * responsibility for on-disk and in-memory synchronization. + */ +#ifdef VMS + if (__os_fsync(dbenv, fhp) == -1) + return (__os_get_errno()); +#endif + + /* MAP_FAILED was not defined in early mmap implementations. */ +#ifndef MAP_FAILED +#define MAP_FAILED -1 +#endif + if ((p = mmap(NULL, + len, prot, flags, fhp->fd, (off_t)0)) == (void *)MAP_FAILED) { + ret = __os_get_errno(); + __db_err(dbenv, "mmap: %s", strerror(ret)); + return (ret); + } + +#ifdef HAVE_MLOCK + /* + * If it's a region, we want to make sure that the memory isn't paged. + * For example, Solaris will page large mpools because it thinks that + * I/O buffer memory is more important than we are. The mlock system + * call may or may not succeed (mlock is restricted to the super-user + * on some systems). Currently, the only other use of mmap in DB is + * to map read-only databases -- we don't want them paged, either, so + * the call isn't conditional. + */ + if (F_ISSET(dbenv, DB_ENV_LOCKDOWN) && mlock(p, len) != 0) { + ret = __os_get_errno(); + (void)munmap(p, len); + __db_err(dbenv, "mlock: %s", strerror(ret)); + return (ret); + } +#else + COMPQUIET(dbenv, NULL); +#endif + + *addrp = p; + return (0); +} +#endif + +#ifndef HAVE_SHMGET +/* + * __db_nosystemmem -- + * No system memory environments error message. + */ +static int +__db_nosystemmem(dbenv) + DB_ENV *dbenv; +{ + __db_err(dbenv, + "architecture doesn't support environments in system memory"); + return (__db_eopnotsup(dbenv)); +} +#endif diff --git a/db/os/os_method.c b/db/os/os_method.c new file mode 100644 index 000000000..0e2bd3947 --- /dev/null +++ b/db/os/os_method.c @@ -0,0 +1,206 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: os_method.c,v 11.6 2000/11/15 19:25:39 sue Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include +#endif + +#include "db_int.h" +#include "os_jump.h" + +struct __db_jumptab __db_jump; + +int +db_env_set_func_close(func_close) + int (*func_close) __P((int)); +{ + __db_jump.j_close = func_close; + return (0); +} + +int +db_env_set_func_dirfree(func_dirfree) + void (*func_dirfree) __P((char **, int)); +{ + __db_jump.j_dirfree = func_dirfree; + return (0); +} + +int +db_env_set_func_dirlist(func_dirlist) + int (*func_dirlist) __P((const char *, char ***, int *)); +{ + __db_jump.j_dirlist = func_dirlist; + return (0); +} + +int +db_env_set_func_exists(func_exists) + int (*func_exists) __P((const char *, int *)); +{ + __db_jump.j_exists = func_exists; + return (0); +} + +int +db_env_set_func_free(func_free) + void (*func_free) __P((void *)); +{ + __db_jump.j_free = func_free; + return (0); +} + +int +db_env_set_func_fsync(func_fsync) + int (*func_fsync) __P((int)); +{ + __db_jump.j_fsync = func_fsync; + return (0); +} + +int +db_env_set_func_ioinfo(func_ioinfo) + int (*func_ioinfo) + __P((const char *, int, u_int32_t *, u_int32_t *, u_int32_t *)); +{ + __db_jump.j_ioinfo = func_ioinfo; + return (0); +} + +int +db_env_set_func_malloc(func_malloc) + void *(*func_malloc) __P((size_t)); +{ + __db_jump.j_malloc = func_malloc; + return (0); +} + +int +db_env_set_func_map(func_map) + int (*func_map) __P((char *, size_t, int, int, void **)); +{ + __db_jump.j_map = func_map; + return (0); +} + +int +db_env_set_func_open(func_open) + int (*func_open) __P((const char *, int, ...)); +{ + __db_jump.j_open = func_open; + return (0); +} + +int +db_env_set_func_read(func_read) + ssize_t (*func_read) __P((int, void *, size_t)); +{ + __db_jump.j_read = func_read; + return (0); +} + +int +db_env_set_func_realloc(func_realloc) + void *(*func_realloc) __P((void *, size_t)); +{ + __db_jump.j_realloc = func_realloc; + return (0); +} + +int +db_env_set_func_rename(func_rename) + int (*func_rename) __P((const char *, const char *)); +{ + __db_jump.j_rename = func_rename; + return (0); +} + +int +db_env_set_func_seek(func_seek) + int (*func_seek) __P((int, size_t, db_pgno_t, u_int32_t, int, int)); +{ + __db_jump.j_seek = func_seek; + return (0); +} + +int +db_env_set_func_sleep(func_sleep) + int (*func_sleep) __P((u_long, u_long)); +{ + __db_jump.j_sleep = func_sleep; + return (0); +} + +int +db_env_set_func_unlink(func_unlink) + int (*func_unlink) __P((const char *)); +{ + __db_jump.j_unlink = func_unlink; + return (0); +} + +int +db_env_set_func_unmap(func_unmap) + int (*func_unmap) __P((void *, size_t)); +{ + __db_jump.j_unmap = func_unmap; + return (0); +} + +int +db_env_set_func_write(func_write) + ssize_t (*func_write) __P((int, const void *, size_t)); +{ + __db_jump.j_write = func_write; + return (0); +} + +int +db_env_set_func_yield(func_yield) + int (*func_yield) __P((void)); +{ + __db_jump.j_yield = func_yield; + return (0); +} + +int +db_env_set_pageyield(onoff) + int onoff; +{ + DB_GLOBAL(db_pageyield) = onoff; + return (0); +} + +int +db_env_set_panicstate(onoff) + int onoff; +{ + DB_GLOBAL(db_panic) = onoff; + return (0); +} + +int +db_env_set_region_init(onoff) + int onoff; +{ + DB_GLOBAL(db_region_init) = onoff; + return (0); +} + +int +db_env_set_tas_spins(tas_spins) + u_int32_t tas_spins; +{ + DB_GLOBAL(db_tas_spins) = tas_spins; + return (0); +} diff --git a/db/os/os_oflags.c b/db/os/os_oflags.c new file mode 100644 index 000000000..fd413bdac --- /dev/null +++ b/db/os/os_oflags.c @@ -0,0 +1,106 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: os_oflags.c,v 11.6 2000/10/27 20:32:02 dda Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include +#include + +#include +#endif + +#include "db_int.h" + +/* + * __db_oflags -- + * Convert open(2) flags to DB flags. + * + * PUBLIC: u_int32_t __db_oflags __P((int)); + */ +u_int32_t +__db_oflags(oflags) + int oflags; +{ + u_int32_t dbflags; + + dbflags = 0; + + if (oflags & O_CREAT) + dbflags |= DB_CREATE; + + if (oflags & O_TRUNC) + dbflags |= DB_TRUNCATE; + + /* + * !!! + * Convert POSIX 1003.1 open(2) mode flags to DB flags. This isn't + * an exact science as few POSIX implementations have a flag value + * for O_RDONLY, it's simply the lack of a write flag. + */ +#ifndef O_ACCMODE +#define O_ACCMODE (O_RDONLY | O_RDWR | O_WRONLY) +#endif + switch (oflags & O_ACCMODE) { + case O_RDWR: + case O_WRONLY: + break; + default: + dbflags |= DB_RDONLY; + break; + } + return (dbflags); +} + +/* + * __db_omode -- + * Convert a permission string to the correct open(2) flags. + * + * PUBLIC: int __db_omode __P((const char *)); + */ +int +__db_omode(perm) + const char *perm; +{ + int mode; + +#ifndef S_IRUSR +#ifdef DB_WIN32 +#define S_IRUSR S_IREAD /* R for owner */ +#define S_IWUSR S_IWRITE /* W for owner */ +#define S_IRGRP 0 /* R for group */ +#define S_IWGRP 0 /* W for group */ +#define S_IROTH 0 /* R for other */ +#define S_IWOTH 0 /* W for other */ +#else +#define S_IRUSR 0000400 /* R for owner */ +#define S_IWUSR 0000200 /* W for owner */ +#define S_IRGRP 0000040 /* R for group */ +#define S_IWGRP 0000020 /* W for group */ +#define S_IROTH 0000004 /* R for other */ +#define S_IWOTH 0000002 /* W for other */ +#endif /* DB_WIN32 */ +#endif + mode = 0; + if (perm[0] == 'r') + mode |= S_IRUSR; + if (perm[1] == 'w') + mode |= S_IWUSR; + if (perm[2] == 'r') + mode |= S_IRGRP; + if (perm[3] == 'w') + mode |= S_IWGRP; + if (perm[4] == 'r') + mode |= S_IROTH; + if (perm[5] == 'w') + mode |= S_IWOTH; + return (mode); +} diff --git a/db/os/os_open.c b/db/os/os_open.c new file mode 100644 index 000000000..cdc75cd73 --- /dev/null +++ b/db/os/os_open.c @@ -0,0 +1,226 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: os_open.c,v 11.21 2001/01/11 18:19:53 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#endif + +#include "db_int.h" + +#ifdef HAVE_QNX +static int __os_region_open __P((DB_ENV *, const char *, int, int, DB_FH *)); +#endif + +/* + * __os_open -- + * Open a file. + * + * PUBLIC: int __os_open __P((DB_ENV *, const char *, u_int32_t, int, DB_FH *)); + */ +int +__os_open(dbenv, name, flags, mode, fhp) + DB_ENV *dbenv; + const char *name; + u_int32_t flags; + int mode; + DB_FH *fhp; +{ + int oflags, ret; + + oflags = 0; + +#if defined(O_BINARY) + /* + * If there's a binary-mode open flag, set it, we never want any + * kind of translation. Some systems do translations by default, + * e.g., with Cygwin, the default mode for an open() is set by the + * mode of the mount that underlies the file. + */ + oflags |= O_BINARY; +#endif + + /* + * DB requires the POSIX 1003.1 semantic that two files opened at the + * same time with DB_OSO_CREATE/O_CREAT and DB_OSO_EXCL/O_EXCL flags + * set return an EEXIST failure in at least one. + */ + if (LF_ISSET(DB_OSO_CREATE)) + oflags |= O_CREAT; + + if (LF_ISSET(DB_OSO_EXCL)) + oflags |= O_EXCL; + +#if defined(O_DSYNC) && defined(XXX_NEVER_SET) + /* + * !!! + * We should get better performance if we push the log files to disk + * immediately instead of waiting for the sync. However, Solaris + * (and likely any other system based on the 4BSD filesystem releases), + * doesn't implement O_DSYNC correctly, only flushing data blocks and + * not inode or indirect blocks. + */ + if (LF_ISSET(DB_OSO_LOG)) + oflags |= O_DSYNC; +#endif + + if (LF_ISSET(DB_OSO_RDONLY)) + oflags |= O_RDONLY; + else + oflags |= O_RDWR; + + if (LF_ISSET(DB_OSO_TRUNC)) + oflags |= O_TRUNC; + +#ifdef HAVE_QNX + if (LF_ISSET(DB_OSO_REGION)) + return (__os_region_open(dbenv, name, oflags, mode, fhp)); +#endif + /* Open the file. */ + if ((ret = __os_openhandle(dbenv, name, oflags, mode, fhp)) != 0) + return (ret); + + /* + * Delete any temporary file. + * + * !!! + * There's a race here, where we've created a file and we crash before + * we can unlink it. Temporary files aren't common in DB, regardless, + * it's not a security problem because the file is empty. There's no + * reasonable way to avoid the race (playing signal games isn't worth + * the portability nightmare), so we just live with it. + */ + if (LF_ISSET(DB_OSO_TEMP)) + (void)__os_unlink(dbenv, name); + + return (0); +} + +#ifdef HAVE_QNX +/* + * __os_region_open -- + * Open a shared memory region file using POSIX shm_open. + */ +static int +__os_region_open(dbenv, name, oflags, mode, fhp) + DB_ENV *dbenv; + const char *name; + int oflags; + int mode; + DB_FH *fhp; +{ + int ret; + char *newname; + + if ((ret = __os_shmname(dbenv, name, &newname)) != 0) + goto err; + memset(fhp, 0, sizeof(*fhp)); + fhp->fd = shm_open(newname, oflags, mode); + if (fhp->fd == -1) + ret = __os_get_errno(); + else { +#ifdef HAVE_FCNTL_F_SETFD + /* Deny file descriptor acces to any child process. */ + if (fcntl(fhp->fd, F_SETFD, 1) == -1) { + ret = __os_get_errno(); + __db_err(dbenv, "fcntl(F_SETFD): %s", strerror(ret)); + __os_closehandle(fhp); + } else +#endif + F_SET(fhp, DB_FH_VALID); + } + /* + * Once we have created the object, we don't need the name + * anymore. Other callers of this will convert themselves. + */ +err: + if (newname != NULL) + __os_free(newname, 0); + return (ret); +} + +/* + * __os_shmname -- + * Translate a pathname into a shm_open memory object name. + * + * PUBLIC: int __os_shmname __P((DB_ENV *, const char *, char **)); + */ +int +__os_shmname(dbenv, name, newnamep) + DB_ENV *dbenv; + const char *name; + char **newnamep; +{ + int ret; + size_t size; + char *p, *q, *tmpname; + + *newnamep = NULL; + + /* + * POSIX states that the name for a shared memory object + * may begin with a slash '/' and support for subsequent + * slashes is implementation-dependent. The one implementation + * we know of right now, QNX, forbids subsequent slashes. + * We don't want to be parsing pathnames for '.' and '..' in + * the middle. In order to allow easy conversion, just take + * the last component as the shared memory name. This limits + * the namespace a bit, but makes our job a lot easier. + * + * We should not be modifying user memory, so we use our own. + * Caller is responsible for freeing the memory we give them. + */ + if ((ret = __os_strdup(dbenv, name, &tmpname)) != 0) + return (ret); + /* + * Skip over filename component. + * We set that separator to '\0' so that we can do another + * __db_rpath. However, we immediately set it then to ':' + * so that we end up with the tailing directory:filename. + * We require a home directory component. Return an error + * if there isn't one. + */ + p = __db_rpath(tmpname); + if (p == NULL) + return (EINVAL); + if (p != tmpname) { + *p = '\0'; + q = p; + p = __db_rpath(tmpname); + *q = ':'; + } + if (p != NULL) { + /* + * If we have a path component, copy and return it. + */ + ret = __os_strdup(dbenv, p, newnamep); + __os_free(tmpname, 0); + return (ret); + } + + /* + * We were given just a directory name with no path components. + * Add a leading slash, and copy the remainder. + */ + size = strlen(tmpname) + 2; + if ((ret = __os_malloc(dbenv, size, NULL, &p)) != 0) + return (ret); + p[0] = '/'; + memcpy(&p[1], tmpname, size-1); + __os_free(tmpname, 0); + *newnamep = p; + return (0); +} +#endif diff --git a/db/os/os_region.c b/db/os/os_region.c new file mode 100644 index 000000000..1e36fc2cb --- /dev/null +++ b/db/os/os_region.c @@ -0,0 +1,116 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: os_region.c,v 11.9 2000/11/30 00:58:42 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#endif + +#include "db_int.h" +#include "os_jump.h" + +/* + * __os_r_attach -- + * Attach to a shared memory region. + * + * PUBLIC: int __os_r_attach __P((DB_ENV *, REGINFO *, REGION *)); + */ +int +__os_r_attach(dbenv, infop, rp) + DB_ENV *dbenv; + REGINFO *infop; + REGION *rp; +{ + int ret; + /* Round off the requested size for the underlying VM. */ + OS_VMROUNDOFF(rp->size); + +#ifdef DB_REGIONSIZE_MAX + /* Some architectures have hard limits on the maximum region size. */ + if (rp->size > DB_REGIONSIZE_MAX) { + __db_err(dbenv, "region size %lu is too large; maximum is %lu", + (u_long)rp->size, (u_long)DB_REGIONSIZE_MAX); + return (EINVAL); + } +#endif + + /* + * If a region is private, malloc the memory. + * + * !!! + * If this fails because the region is too large to malloc, mmap(2) + * using the MAP_ANON or MAP_ANONYMOUS flags would be an alternative. + * I don't know of any architectures (yet!) where malloc is a problem. + */ + if (F_ISSET(dbenv, DB_ENV_PRIVATE)) { +#if defined(MUTEX_NO_MALLOC_LOCKS) + /* + * !!! + * There exist spinlocks that don't work in malloc memory, e.g., + * the HP/UX msemaphore interface. If we don't have locks that + * will work in malloc memory, we better not be private or not + * be threaded. + */ + if (F_ISSET(dbenv, DB_ENV_THREAD)) { + __db_err(dbenv, "%s", + "architecture does not support locks inside process-local (malloc) memory"); + __db_err(dbenv, "%s", + "application may not specify both DB_PRIVATE and DB_THREAD"); + return (EINVAL); + } +#endif + if ((ret = + __os_malloc(dbenv, rp->size, NULL, &infop->addr)) != 0) + return (ret); +#if defined(UMRW) && !defined(DIAGNOSTIC) + memset(infop->addr, CLEAR_BYTE, rp->size); +#endif + return (0); + } + + /* If the user replaced the map call, call through their interface. */ + if (__db_jump.j_map != NULL) + return (__db_jump.j_map(infop->name, + rp->size, 1, 0, &infop->addr)); + + return (__os_r_sysattach(dbenv, infop, rp)); +} + +/* + * __os_r_detach -- + * Detach from a shared memory region. + * + * PUBLIC: int __os_r_detach __P((DB_ENV *, REGINFO *, int)); + */ +int +__os_r_detach(dbenv, infop, destroy) + DB_ENV *dbenv; + REGINFO *infop; + int destroy; +{ + REGION *rp; + + rp = infop->rp; + + /* If a region is private, free the memory. */ + if (F_ISSET(dbenv, DB_ENV_PRIVATE)) { + __os_free(infop->addr, rp->size); + return (0); + } + + /* If the user replaced the map call, call through their interface. */ + if (__db_jump.j_unmap != NULL) + return (__db_jump.j_unmap(infop->addr, rp->size)); + + return (__os_r_sysdetach(dbenv, infop, destroy)); +} diff --git a/db/os/os_rename.c b/db/os/os_rename.c new file mode 100644 index 000000000..8108bba67 --- /dev/null +++ b/db/os/os_rename.c @@ -0,0 +1,46 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: os_rename.c,v 11.6 2000/04/14 16:56:33 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#endif + +#include "db_int.h" +#include "os_jump.h" + +/* + * __os_rename -- + * Rename a file. + * + * PUBLIC: int __os_rename __P((DB_ENV *, const char *, const char *)); + */ +int +__os_rename(dbenv, old, new) + DB_ENV *dbenv; + const char *old, *new; +{ + int ret; + + ret = __db_jump.j_rename != NULL ? + __db_jump.j_rename(old, new) : rename(old, new); + + if (ret == -1) { + ret = __os_get_errno(); + __db_err(dbenv, "Rename %s %s: %s", old, new, strerror(ret)); + } + + return (ret); +} diff --git a/db/os/os_root.c b/db/os/os_root.c new file mode 100644 index 000000000..753285c1b --- /dev/null +++ b/db/os/os_root.c @@ -0,0 +1,36 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: os_root.c,v 11.4 2000/02/14 03:00:05 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" + +/* + * __os_isroot -- + * Return if user has special permissions. + * + * PUBLIC: int __os_isroot __P((void)); + */ +int +__os_isroot() +{ +#ifdef HAVE_GETUID + return (getuid() == 0); +#else + return (0); +#endif +} diff --git a/db/os/os_rpath.c b/db/os/os_rpath.c new file mode 100644 index 000000000..75d394ef2 --- /dev/null +++ b/db/os/os_rpath.c @@ -0,0 +1,69 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: os_rpath.c,v 11.5 2000/06/30 13:40:30 sue Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include +#endif + +#include "db_int.h" +#ifdef HAVE_VXWORKS +#include "iosLib.h" +#endif + +/* + * __db_rpath -- + * Return the last path separator in the path or NULL if none found. + * + * PUBLIC: char *__db_rpath __P((const char *)); + */ +char * +__db_rpath(path) + const char *path; +{ + const char *s, *last; +#ifdef HAVE_VXWORKS + DEV_HDR *dummy; + char *ptail; + + /* + * VxWorks devices can be rooted at any name. We want to + * skip over the device name and not take into account any + * PATH_SEPARATOR characters that might be in that name. + * + * XXX [#2393] + * VxWorks supports having a filename directly follow a device + * name with no separator. I.e. to access a file 'xxx' in + * the top level directory of a device mounted at "mydrive" + * you could say "mydrivexxx" or "mydrive/xxx" or "mydrive\xxx". + * We do not support the first usage here. + * XXX + */ + if ((dummy = iosDevFind((char *)path, &ptail)) == NULL) + s = path; + else + s = ptail; +#else + s = path; +#endif + + last = NULL; + if (PATH_SEPARATOR[1] != '\0') { + for (; s[0] != '\0'; ++s) + if (strchr(PATH_SEPARATOR, s[0]) != NULL) + last = s; + } else + for (; s[0] != '\0'; ++s) + if (s[0] == PATH_SEPARATOR[0]) + last = s; + return ((char *)last); +} diff --git a/db/os/os_rw.c b/db/os/os_rw.c new file mode 100644 index 000000000..7e8e1255d --- /dev/null +++ b/db/os/os_rw.c @@ -0,0 +1,147 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: os_rw.c,v 11.15 2000/11/15 19:25:39 sue Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#endif + +#include "db_int.h" +#include "os_jump.h" + +/* + * __os_io -- + * Do an I/O. + * + * PUBLIC: int __os_io __P((DB_ENV *, DB_IO *, int, size_t *)); + */ +int +__os_io(dbenv, db_iop, op, niop) + DB_ENV *dbenv; + DB_IO *db_iop; + int op; + size_t *niop; +{ + int ret; + +#if defined(HAVE_PREAD) && defined(HAVE_PWRITE) + switch (op) { + case DB_IO_READ: + if (__db_jump.j_read != NULL) + goto slow; + *niop = pread(db_iop->fhp->fd, db_iop->buf, + db_iop->bytes, (off_t)db_iop->pgno * db_iop->pagesize); + break; + case DB_IO_WRITE: + if (__db_jump.j_write != NULL) + goto slow; + *niop = pwrite(db_iop->fhp->fd, db_iop->buf, + db_iop->bytes, (off_t)db_iop->pgno * db_iop->pagesize); + break; + } + if (*niop == (size_t)db_iop->bytes) + return (0); +slow: +#endif + MUTEX_THREAD_LOCK(dbenv, db_iop->mutexp); + + if ((ret = __os_seek(dbenv, db_iop->fhp, + db_iop->pagesize, db_iop->pgno, 0, 0, DB_OS_SEEK_SET)) != 0) + goto err; + switch (op) { + case DB_IO_READ: + ret = __os_read(dbenv, + db_iop->fhp, db_iop->buf, db_iop->bytes, niop); + break; + case DB_IO_WRITE: + ret = __os_write(dbenv, + db_iop->fhp, db_iop->buf, db_iop->bytes, niop); + break; + } + +err: MUTEX_THREAD_UNLOCK(dbenv, db_iop->mutexp); + + return (ret); + +} + +/* + * __os_read -- + * Read from a file handle. + * + * PUBLIC: int __os_read __P((DB_ENV *, DB_FH *, void *, size_t, size_t *)); + */ +int +__os_read(dbenv, fhp, addr, len, nrp) + DB_ENV *dbenv; + DB_FH *fhp; + void *addr; + size_t len; + size_t *nrp; +{ + size_t offset; + ssize_t nr; + int ret; + u_int8_t *taddr; + + for (taddr = addr, + offset = 0; offset < len; taddr += nr, offset += nr) { + if ((nr = __db_jump.j_read != NULL ? + __db_jump.j_read(fhp->fd, taddr, len - offset) : + read(fhp->fd, taddr, len - offset)) < 0) { + ret = __os_get_errno(); + __db_err(dbenv, "read: 0x%x, %lu: %s", taddr, + (u_long)len-offset, strerror(ret)); + return (ret); + } + if (nr == 0) + break; + } + *nrp = taddr - (u_int8_t *)addr; + return (0); +} + +/* + * __os_write -- + * Write to a file handle. + * + * PUBLIC: int __os_write __P((DB_ENV *, DB_FH *, void *, size_t, size_t *)); + */ +int +__os_write(dbenv, fhp, addr, len, nwp) + DB_ENV *dbenv; + DB_FH *fhp; + void *addr; + size_t len; + size_t *nwp; +{ + size_t offset; + ssize_t nw; + int ret; + u_int8_t *taddr; + + for (taddr = addr, + offset = 0; offset < len; taddr += nw, offset += nw) + if ((nw = __db_jump.j_write != NULL ? + __db_jump.j_write(fhp->fd, taddr, len - offset) : + write(fhp->fd, taddr, len - offset)) < 0) { + ret = __os_get_errno(); + __db_err(dbenv, "write: 0x%x, %lu: %s", taddr, + (u_long)len-offset, strerror(ret)); + return (ret); + } + *nwp = len; + return (0); +} diff --git a/db/os/os_seek.c b/db/os/os_seek.c new file mode 100644 index 000000000..1c4dc2238 --- /dev/null +++ b/db/os/os_seek.c @@ -0,0 +1,76 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: os_seek.c,v 11.12 2000/11/30 00:58:42 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#endif + +#include "db_int.h" +#include "os_jump.h" + +/* + * __os_seek -- + * Seek to a page/byte offset in the file. + * + * PUBLIC: int __os_seek __P((DB_ENV *, + * PUBLIC: DB_FH *, size_t, db_pgno_t, u_int32_t, int, DB_OS_SEEK)); + */ +int +__os_seek(dbenv, fhp, pgsize, pageno, relative, isrewind, db_whence) + DB_ENV *dbenv; + DB_FH *fhp; + size_t pgsize; + db_pgno_t pageno; + u_int32_t relative; + int isrewind; + DB_OS_SEEK db_whence; +{ + off_t offset; + int ret, whence; + + switch (db_whence) { + case DB_OS_SEEK_CUR: + whence = SEEK_CUR; + break; + case DB_OS_SEEK_END: + whence = SEEK_END; + break; + case DB_OS_SEEK_SET: + whence = SEEK_SET; + break; + default: + return (EINVAL); + } + + if (__db_jump.j_seek != NULL) + ret = __db_jump.j_seek(fhp->fd, + pgsize, pageno, relative, isrewind, whence); + else { + offset = (off_t)pgsize * pageno + relative; + if (isrewind) + offset = -offset; + ret = + lseek(fhp->fd, offset, whence) == -1 ? __os_get_errno() : 0; + } + + if (ret != 0) + __db_err(dbenv, "seek: %lu %d %d: %s", + (u_long)pgsize * pageno + relative, + isrewind, db_whence, strerror(ret)); + + return (ret); +} diff --git a/db/os/os_sleep.c b/db/os/os_sleep.c new file mode 100644 index 000000000..137cd73b7 --- /dev/null +++ b/db/os/os_sleep.c @@ -0,0 +1,77 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: os_sleep.c,v 11.7 2000/04/07 14:26:36 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#ifdef HAVE_SYS_SELECT_H +#include +#endif + +#ifdef HAVE_VXWORKS +#include +#include +#else +#if TIME_WITH_SYS_TIME +#include +#include +#else +#if HAVE_SYS_TIME_H +#include +#else +#include +#endif /* HAVE_SYS_TIME_H */ +#endif /* TIME_WITH SYS_TIME */ +#endif /* HAVE_VXWORKS */ + +#include +#include +#endif + +#include "db_int.h" +#include "os_jump.h" + +/* + * __os_sleep -- + * Yield the processor for a period of time. + * + * PUBLIC: int __os_sleep __P((DB_ENV *, u_long, u_long)); + */ +int +__os_sleep(dbenv, secs, usecs) + DB_ENV *dbenv; + u_long secs, usecs; /* Seconds and microseconds. */ +{ + struct timeval t; + int ret; + + /* Don't require that the values be normalized. */ + for (; usecs >= 1000000; usecs -= 1000000) + ++secs; + + if (__db_jump.j_sleep != NULL) + return (__db_jump.j_sleep(secs, usecs)); + + /* + * It's important that we yield the processor here so that other + * processes or threads are permitted to run. + */ + t.tv_sec = secs; + t.tv_usec = usecs; + ret = select(0, NULL, NULL, NULL, &t) == -1 ? __os_get_errno() : 0; + + if (ret != 0) + __db_err(dbenv, "select: %s", strerror(ret)); + + return (ret); +} diff --git a/db/os/os_spin.c b/db/os/os_spin.c new file mode 100644 index 000000000..b0800b988 --- /dev/null +++ b/db/os/os_spin.c @@ -0,0 +1,109 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: os_spin.c,v 11.5 2000/03/30 01:46:42 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include +#if defined(HAVE_PSTAT_GETDYNAMIC) +#include +#endif + +#include +#include +#endif + +#include "db_int.h" +#include "os_jump.h" + +#if defined(HAVE_PSTAT_GETDYNAMIC) +/* + * __os_pstat_getdynamic -- + * HP/UX. + */ +static int +__os_pstat_getdynamic() +{ + struct pst_dynamic psd; + + return (pstat_getdynamic(&psd, + sizeof(psd), (size_t)1, 0) == -1 ? 1 : psd.psd_proc_cnt); +} +#endif + +#if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN) +/* + * __os_sysconf -- + * Solaris, Linux. + */ +static int +__os_sysconf() +{ + int nproc; + + return ((nproc = sysconf(_SC_NPROCESSORS_ONLN)) > 1 ? nproc : 1); +} +#endif + +/* + * __os_spin -- + * Return the number of default spins before blocking. + * + * PUBLIC: int __os_spin __P((void)); + */ +int +__os_spin() +{ + /* + * If the application specified a value or we've already figured it + * out, return it. + * + * XXX + * We don't want to repeatedly call the underlying function because + * it can be expensive (e.g., requiring multiple filesystem accesses + * under Debian Linux). + */ + if (DB_GLOBAL(db_tas_spins) != 0) + return (DB_GLOBAL(db_tas_spins)); + + DB_GLOBAL(db_tas_spins) = 1; +#if defined(HAVE_PSTAT_GETDYNAMIC) + DB_GLOBAL(db_tas_spins) = __os_pstat_getdynamic(); +#endif +#if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN) + DB_GLOBAL(db_tas_spins) = __os_sysconf(); +#endif + + /* + * Spin 50 times per processor, we have anecdotal evidence that this + * is a reasonable value. + */ + if (DB_GLOBAL(db_tas_spins) != 1) + DB_GLOBAL(db_tas_spins) *= 50; + + return (DB_GLOBAL(db_tas_spins)); +} + +/* + * __os_yield -- + * Yield the processor. + * + * PUBLIC: void __os_yield __P((DB_ENV*, u_long)); + */ +void +__os_yield(dbenv, usecs) + DB_ENV *dbenv; + u_long usecs; +{ + if (__db_jump.j_yield != NULL && __db_jump.j_yield() == 0) + return; + __os_sleep(dbenv, 0, usecs); +} diff --git a/db/os/os_stat.c b/db/os/os_stat.c new file mode 100644 index 000000000..1590e8ecd --- /dev/null +++ b/db/os/os_stat.c @@ -0,0 +1,108 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: os_stat.c,v 11.8 2000/10/27 20:32:02 dda Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include +#include +#include +#endif + +#include "db_int.h" +#include "os_jump.h" + +/* + * __os_exists -- + * Return if the file exists. + * + * PUBLIC: int __os_exists __P((const char *, int *)); + */ +int +__os_exists(path, isdirp) + const char *path; + int *isdirp; +{ + struct stat sb; + + if (__db_jump.j_exists != NULL) + return (__db_jump.j_exists(path, isdirp)); + +#ifdef HAVE_VXWORKS + if (stat((char *)path, &sb) != 0) +#else + if (stat(path, &sb) != 0) +#endif + return (__os_get_errno()); + +#if !defined(S_ISDIR) || defined(STAT_MACROS_BROKEN) +#ifdef DB_WIN32 +#define S_ISDIR(m) (_S_IFDIR & (m)) +#else +#define S_ISDIR(m) (((m) & 0170000) == 0040000) +#endif +#endif + if (isdirp != NULL) + *isdirp = S_ISDIR(sb.st_mode); + + return (0); +} + +/* + * __os_ioinfo -- + * Return file size and I/O size; abstracted to make it easier + * to replace. + * + * PUBLIC: int __os_ioinfo __P((DB_ENV *, const char *, + * PUBLIC: DB_FH *, u_int32_t *, u_int32_t *, u_int32_t *)); + */ +int +__os_ioinfo(dbenv, path, fhp, mbytesp, bytesp, iosizep) + DB_ENV *dbenv; + const char *path; + DB_FH *fhp; + u_int32_t *mbytesp, *bytesp, *iosizep; +{ + int ret; + struct stat sb; + + if (__db_jump.j_ioinfo != NULL) + return (__db_jump.j_ioinfo(path, + fhp->fd, mbytesp, bytesp, iosizep)); + + if (fstat(fhp->fd, &sb) == -1) { + ret = __os_get_errno(); + __db_err(dbenv, "fstat: %s", strerror(ret)); + return (ret); + } + + /* Return the size of the file. */ + if (mbytesp != NULL) + *mbytesp = sb.st_size / MEGABYTE; + if (bytesp != NULL) + *bytesp = sb.st_size % MEGABYTE; + + /* + * Return the underlying filesystem blocksize, if available. + * + * XXX + * Check for a 0 size -- the HP MPE/iX architecture has st_blksize, + * but it's always 0. + */ +#ifdef HAVE_ST_BLKSIZE + if (iosizep != NULL && (*iosizep = sb.st_blksize) == 0) + *iosizep = DB_DEF_IOSIZE; +#else + if (iosizep != NULL) + *iosizep = DB_DEF_IOSIZE; +#endif + return (0); +} diff --git a/db/os/os_tmpdir.c b/db/os/os_tmpdir.c new file mode 100644 index 000000000..0dff5c5b7 --- /dev/null +++ b/db/os/os_tmpdir.c @@ -0,0 +1,119 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: os_tmpdir.c,v 11.16 2001/01/08 20:42:06 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" + +#ifdef macintosh +#include +#endif + +/* + * __os_tmpdir -- + * Set the temporary directory path. + * + * The order of items in the list structure and the order of checks in + * the environment are documented. + * + * PUBLIC: int __os_tmpdir __P((DB_ENV *, u_int32_t)); + */ +int +__os_tmpdir(dbenv, flags) + DB_ENV *dbenv; + u_int32_t flags; +{ + /* + * !!! + * Don't change this to: + * + * static const char * const list[] + * + * because it creates a text relocation in position independent code. + */ + static const char * list[] = { + "/var/tmp", + "/usr/tmp", + "/temp", /* Windows. */ + "/tmp", + "C:/temp", /* Windows. */ + "C:/tmp", /* Windows. */ + NULL + }; + const char * const *lp, *p; + + /* Use the environment if it's permitted and initialized. */ + if (LF_ISSET(DB_USE_ENVIRON) || + (LF_ISSET(DB_USE_ENVIRON_ROOT) && __os_isroot())) { + if ((p = getenv("TMPDIR")) != NULL && p[0] == '\0') { + __db_err(dbenv, "illegal TMPDIR environment variable"); + return (EINVAL); + } + /* Windows */ + if (p == NULL && (p = getenv("TEMP")) != NULL && p[0] == '\0') { + __db_err(dbenv, "illegal TEMP environment variable"); + return (EINVAL); + } + /* Windows */ + if (p == NULL && (p = getenv("TMP")) != NULL && p[0] == '\0') { + __db_err(dbenv, "illegal TMP environment variable"); + return (EINVAL); + } + /* Macintosh */ + if (p == NULL && + (p = getenv("TempFolder")) != NULL && p[0] == '\0') { + __db_err(dbenv, + "illegal TempFolder environment variable"); + return (EINVAL); + } + if (p != NULL) + return (__os_strdup(dbenv, p, &dbenv->db_tmp_dir)); + } + +#ifdef macintosh + /* Get the path to the temporary folder. */ + {FSSpec spec; + + if (!Special2FSSpec(kTemporaryFolderType, + kOnSystemDisk, 0, &spec)) + return (__os_strdup(dbenv, + FSp2FullPath(&spec), &dbenv->db_tmp_dir)); + } +#endif +#ifdef DB_WIN32 + /* Get the path to the temporary directory. */ + {int isdir, len; + char *eos, temp[MAXPATHLEN + 1]; + + if ((len = GetTempPath(sizeof(temp) - 1, temp)) > 2) { + eos = &temp[len]; + *eos-- = '\0'; + if (*eos == '\\' || *eos == '/') + *eos = '\0'; + if (__os_exists(temp, &isdir) == 0 && isdir != 0) + return (__os_strdup(dbenv, + temp, &dbenv->db_tmp_dir)); + } + } +#endif + + /* Step through the static list looking for a possibility. */ + for (lp = list; *lp != NULL; ++lp) + if (__os_exists(*lp, NULL) == 0) + return (__os_strdup(dbenv, *lp, &dbenv->db_tmp_dir)); + return (0); +} diff --git a/db/os/os_unlink.c b/db/os/os_unlink.c new file mode 100644 index 000000000..56c401fe3 --- /dev/null +++ b/db/os/os_unlink.c @@ -0,0 +1,106 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: os_unlink.c,v 11.13 2000/11/30 00:58:42 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#endif + +#include "db_int.h" +#include "os_jump.h" + +/* + * __os_unlink -- + * Remove a file. + * + * PUBLIC: int __os_unlink __P((DB_ENV *, const char *)); + */ +int +__os_unlink(dbenv, path) + DB_ENV *dbenv; + const char *path; +{ + int ret; + + ret = __db_jump.j_unlink != NULL ? + __db_jump.j_unlink(path) : +#ifdef HAVE_VXWORKS + unlink((char *)path); +#else + unlink(path); +#endif + if (ret == -1) { + ret = __os_get_errno(); + /* + * XXX + * We really shouldn't be looking at this value ourselves, + * but ENOENT usually signals that a file is missing, and + * we attempt to unlink things (such as v. 2.x environment + * regions, in DB_ENV->remove) that we're expecting not to + * be there. Reporting errors in these cases is annoying. + */ +#ifdef HAVE_VXWORKS + /* + * XXX + * The results of unlink are file system driver specific + * on VxWorks. In the case of removing a file that did + * not exist, some, at least, return an error, but with + * an errno of 0, not ENOENT. + * + * Code below falls through to original if-statement only + * we didn't get a "successful" error. + */ + if (ret != 0) + /* FALLTHROUGH */ +#endif + if (ret != ENOENT) + __db_err(dbenv, "Unlink: %s: %s", path, strerror(ret)); + } + + return (ret); +} + +/* + * __os_region_unlink -- + * Remove a shared memory object file. + * + * PUBLIC: int __os_region_unlink __P((DB_ENV *, const char *)); + */ +int +__os_region_unlink(dbenv, path) + DB_ENV *dbenv; + const char *path; +{ +#ifdef HAVE_QNX + int ret; + char *newname; + + if ((ret = __os_shmname(dbenv, path, &newname)) != 0) + goto err; + + if ((ret = shm_unlink(newname)) != 0) { + ret = __os_get_errno(); + if (ret != ENOENT) + __db_err(dbenv, "Shm_unlink: %s: %s", + newname, strerror(ret)); + } +err: + if (newname != NULL) + __os_free(newname, 0); + return (ret); +#else + return (__os_unlink(dbenv, path)); +#endif +} diff --git a/db/os_vxworks/os_abs.c b/db/os_vxworks/os_abs.c new file mode 100644 index 000000000..162a556d3 --- /dev/null +++ b/db/os_vxworks/os_abs.c @@ -0,0 +1,45 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: os_abs.c,v 1.4 2000/08/09 19:09:48 sue Exp $"; +#endif /* not lint */ + +#include "db_int.h" +#include "iosLib.h" + +/* + * __os_abspath -- + * Return if a path is an absolute path. + */ +int +__os_abspath(path) + const char *path; +{ + DEV_HDR *dummy; + char *ptail; + + /* + * VxWorks devices can be rooted at any name at all. + * Use iosDevFind() to see if name matches any of our devices. + */ + if ((dummy = iosDevFind((char *)path, &ptail)) == NULL) + return (0); + /* + * If the routine used the default device, then we are not + * an abs path. + */ + if (ptail == path) + return (0); + /* + * If the path starts with a '/', then we are an absolute path, + * using the host machine, otherwise we are not. + */ + return (path[0] == '/'); +} diff --git a/db/os_vxworks/os_finit.c b/db/os_vxworks/os_finit.c new file mode 100644 index 000000000..305f52f09 --- /dev/null +++ b/db/os_vxworks/os_finit.c @@ -0,0 +1,57 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: os_finit.c,v 1.1 2000/06/21 20:05:18 sue Exp $"; +#endif /* not lint */ + +#include "db_int.h" + +/* + * __os_fpinit -- + * Initialize a page in a regular file. + * + * PUBLIC: int __os_fpinit __P((DB_ENV *, DB_FH *, db_pgno_t, int, int)); + */ +int +__os_fpinit(dbenv, fhp, pgno, pagecount, pagesize) + DB_ENV *dbenv; + DB_FH *fhp; + db_pgno_t pgno; + int pagecount, pagesize; +{ + size_t nw, totalbytes, curbytes; + int ret; + char buf[1024]; + + /* + * Some VxWorks FS drivers do not zero-fill pages that were never + * explicitly written to the file, they give you random garbage, + * and that breaks DB. + */ + if ((ret = __os_seek(dbenv, + fhp, pagesize, pgno, 0, 0, DB_OS_SEEK_SET)) != 0) + return (ret); + + memset(buf, 0, sizeof(buf)); + totalbytes = pagecount * pagesize; + + while (totalbytes > 0) { + if (totalbytes > sizeof(buf)) + curbytes = sizeof(buf); + else + curbytes = totalbytes; + if ((ret = __os_write(dbenv, fhp, buf, curbytes, &nw)) != 0) + return (ret); + if (nw != curbytes) + return (EIO); + totalbytes -= curbytes; + } + return (0); +} diff --git a/db/os_vxworks/os_map.c b/db/os_vxworks/os_map.c new file mode 100644 index 000000000..7397995d1 --- /dev/null +++ b/db/os_vxworks/os_map.c @@ -0,0 +1,440 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * This code is derived from software contributed to Sleepycat Software by + * Frederick G.M. Roeber of Netscape Communications Corp. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: os_map.c,v 1.14 2000/12/04 19:01:43 sue Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include +#include +#endif + +#include "db_int.h" +#include "common_ext.h" + +/* + * DB uses memory-mapped files for two things: + * faster access of read-only databases, and + * shared memory for process synchronization and locking. + * The code carefully does not mix the two uses. The first-case uses are + * actually written such that memory-mapping isn't really required -- it's + * merely a convenience -- so we don't have to worry much about it. In the + * second case, it's solely used as a shared memory mechanism, so that's + * all we have to replace. + * + * All memory in VxWorks is shared, and a task can allocate memory and keep + * notes. So I merely have to allocate memory, remember the "filename" for + * that memory, and issue small-integer segment IDs which index the list of + * these shared-memory segments. Subsequent opens are checked against the + * list of already open segments. + */ +typedef struct { + void *segment; /* Segment address. */ + u_int32_t size; /* Segment size. */ + char *name; /* Segment name. */ + long segid; /* Segment ID. */ +} os_segdata_t; + +static os_segdata_t *__os_segdata; /* Segment table. */ +static int __os_segdata_size; /* Segment table size. */ + +#define OS_SEGDATA_STARTING_SIZE 16 +#define OS_SEGDATA_INCREMENT 16 + +static int __os_segdata_allocate + __P((DB_ENV *, const char *, REGINFO *, REGION *)); +static int __os_segdata_find_byname + __P((DB_ENV *, const char *, REGINFO *, REGION *)); +static int __os_segdata_init __P((DB_ENV *)); +static int __os_segdata_new __P((DB_ENV *, int *)); +static int __os_segdata_release __P((DB_ENV *, REGION *, int)); + +/* + * __os_r_sysattach -- + * Create/join a shared memory region. + * + * PUBLIC: int __os_r_sysattach __P((DB_ENV *, REGINFO *, REGION *)); + */ +int +__os_r_sysattach(dbenv, infop, rp) + DB_ENV *dbenv; + REGINFO *infop; + REGION *rp; +{ + int ret; + + if (__os_segdata == NULL) + __os_segdata_init(dbenv); + + DB_BEGIN_SINGLE_THREAD; + + /* Try to find an already existing segment. */ + ret = __os_segdata_find_byname(dbenv, infop->name, infop, rp); + + /* + * If we are trying to join a region, it is easy, either we + * found it and we return, or we didn't find it and we return + * an error that it doesn't exist. + */ + if (!F_ISSET(infop, REGION_CREATE)) { + if (ret != 0) { + __db_err(dbenv, "segment %s does not exist", + infop->name); + ret = EAGAIN; + } + goto out; + } + + /* + * If we get here, we are trying to create the region. + * There are several things to consider: + * - if we have an error (not a found or not-found value), return. + * - they better have shm_key set. + * - if the region is already there (ret == 0 from above), + * assume the application crashed and we're restarting. + * Delete the old region. + * - try to create the region. + */ + if (ret != 0 && ret != ENOENT) + goto out; + + if (dbenv->shm_key == INVALID_REGION_SEGID) { + __db_err(dbenv, "no base shared memory ID specified"); + ret = EAGAIN; + goto out; + } + if (ret == 0 && __os_segdata_release(dbenv, rp, 1) != 0) { + __db_err(dbenv, + "key: %ld: shared memory region already exists", + dbenv->shm_key + (infop->id - 1)); + ret = EAGAIN; + goto out; + } + + ret = __os_segdata_allocate(dbenv, infop->name, infop, rp); +out: + DB_END_SINGLE_THREAD; + return (ret); +} + +/* + * __os_r_sysdetach -- + * Detach from a shared region. + * + * PUBLIC: int __os_r_sysdetach __P((DB_ENV *, REGINFO *, int)); + */ +int +__os_r_sysdetach(dbenv, infop, destroy) + DB_ENV *dbenv; + REGINFO *infop; + int destroy; +{ + /* + * If just detaching, there is no mapping to discard. + * If destroying, remove the region. + */ + if (destroy) + return (__os_segdata_release(dbenv, infop->rp, 0)); + return (0); +} + +/* + * __os_mapfile -- + * Map in a shared memory file. + * + * PUBLIC: int __os_mapfile __P((DB_ENV *, + * PUBLIC: char *, DB_FH *, size_t, int, void **)); + */ +int +__os_mapfile(dbenv, path, fhp, len, is_rdonly, addrp) + DB_ENV *dbenv; + char *path; + DB_FH *fhp; + int is_rdonly; + size_t len; + void **addrp; +{ + /* We cannot map in regular files in VxWorks. */ + COMPQUIET(dbenv, NULL); + COMPQUIET(path, NULL); + COMPQUIET(fhp, NULL); + COMPQUIET(is_rdonly, 0); + COMPQUIET(len, 0); + COMPQUIET(addrp, NULL); + return (EINVAL); +} + +/* + * __os_unmapfile -- + * Unmap the shared memory file. + * + * PUBLIC: int __os_unmapfile __P((DB_ENV *, void *, size_t)); + */ +int +__os_unmapfile(dbenv, addr, len) + DB_ENV *dbenv; + void *addr; + size_t len; +{ + /* We cannot map in regular files in VxWorks. */ + COMPQUIET(addr, NULL); + COMPQUIET(len, 0); + return (EINVAL); +} + +/* + * __os_segdata_init -- + * Initializes the library's table of shared memory segments. + * Called once on the first time through __os_segdata_new(). + */ +static int +__os_segdata_init(dbenv) + DB_ENV *dbenv; +{ + int ret; + + if (__os_segdata != NULL) { + __db_err(dbenv, "shared memory segment already exists"); + return (EEXIST); + } + + /* + * The lock init call returns a locked lock. + */ + DB_BEGIN_SINGLE_THREAD; + __os_segdata_size = OS_SEGDATA_STARTING_SIZE; + ret = __os_calloc(dbenv, + __os_segdata_size, sizeof(os_segdata_t), &__os_segdata); + DB_END_SINGLE_THREAD; + return (ret); +} + +/* + * __os_segdata_destroy -- + * Destroys the library's table of shared memory segments. It also + * frees all linked data: the segments themselves, and their names. + * Currently not called. This function should be called if the + * user creates a function to unload or shutdown. + * + * PUBLIC: int __os_segdata_destroy __P((void)); + */ +int +__os_segdata_destroy() +{ + os_segdata_t *p; + int i; + + if (__os_segdata == NULL) + return (0); + + DB_BEGIN_SINGLE_THREAD; + for (i = 0; i < __os_segdata_size; i++) { + p = &__os_segdata[i]; + if (p->name != NULL) { + __os_freestr(p->name); + p->name = NULL; + } + if (p->segment != NULL) { + __os_free(p->segment, p->size); + p->segment = NULL; + } + p->size = 0; + } + + __os_free(__os_segdata, __os_segdata_size * sizeof(os_segdata_t)); + __os_segdata = NULL; + __os_segdata_size = 0; + DB_END_SINGLE_THREAD; + + return (0); +} + +/* + * __os_segdata_allocate -- + * Creates a new segment of the specified size, optionally with the + * specified name. + * + * Assumes it is called with the SEGDATA lock taken. + */ +static int +__os_segdata_allocate(dbenv, name, infop, rp) + DB_ENV *dbenv; + const char *name; + REGINFO *infop; + REGION *rp; +{ + os_segdata_t *p; + int id, ret; + + if ((ret = __os_segdata_new(dbenv, &id)) != 0) + return (ret); + + p = &__os_segdata[id]; + if ((ret = __os_calloc(dbenv, 1, rp->size, &p->segment)) != 0) + return (ret); + if ((ret = __os_strdup(dbenv, name, &p->name)) != 0) { + __os_free(p->segment, rp->size); + p->segment = NULL; + return (ret); + } + p->size = rp->size; + p->segid = dbenv->shm_key + infop->id - 1; + + infop->addr = p->segment; + rp->segid = id; + + return (0); +} + +/* + * __os_segdata_new -- + * Finds a new segdata slot. Does not initialise it, so the fd returned + * is only valid until you call this again. + * + * Assumes it is called with the SEGDATA lock taken. + */ +static int +__os_segdata_new(dbenv, segidp) + DB_ENV *dbenv; + int *segidp; +{ + os_segdata_t *p; + int i, newsize, ret; + + if (__os_segdata == NULL) { + __db_err(dbenv, "shared memory segment not initialized"); + return (EAGAIN); + } + + for (i = 0; i < __os_segdata_size; i++) { + p = &__os_segdata[i]; + if (p->segment == NULL) { + *segidp = i; + return (0); + } + } + + /* + * No more free slots, expand. + */ + newsize = __os_segdata_size + OS_SEGDATA_INCREMENT; + if ((ret = __os_realloc(dbenv, newsize * sizeof(os_segdata_t), + NULL, &__os_segdata)) != 0) + return (ret); + memset(&__os_segdata[__os_segdata_size], + 0, OS_SEGDATA_INCREMENT * sizeof(os_segdata_t)); + + *segidp = __os_segdata_size; + __os_segdata_size = newsize; + + return (0); +} + +/* + * __os_segdata_find_byname -- + * Finds a segment by its name and shm_key. + * + * Assumes it is called with the SEGDATA lock taken. + * + * PUBLIC: __os_segdata_find_byname + * PUBLIC: __P((DB_ENV *, const char *, REGINFO *, REGION *)); + */ +static int +__os_segdata_find_byname(dbenv, name, infop, rp) + DB_ENV *dbenv; + const char *name; + REGINFO *infop; + REGION *rp; +{ + os_segdata_t *p; + long segid; + int i; + + if (__os_segdata == NULL) { + __db_err(dbenv, "shared memory segment not initialized"); + return (EAGAIN); + } + + if (name == NULL) { + __db_err(dbenv, "no segment name given"); + return (EAGAIN); + } + + /* + * If we are creating the region, compute the segid. + * If we are joining the region, we use the segid in the + * index we are given. + */ + if (F_ISSET(infop, REGION_CREATE)) + segid = dbenv->shm_key + (infop->id - 1); + else { + if (rp->segid >= __os_segdata_size || + rp->segid == INVALID_REGION_SEGID) { + __db_err(dbenv, "Invalid segment id given"); + return (EAGAIN); + } + segid = __os_segdata[rp->segid].segid; + } + for (i = 0; i < __os_segdata_size; i++) { + p = &__os_segdata[i]; + if (p->name != NULL && strcmp(name, p->name) == 0 && + p->segid == segid) { + infop->addr = p->segment; + rp->segid = i; + return (0); + } + } + return (ENOENT); +} + +/* + * __os_segdata_release -- + * Free a segdata entry. + */ +static int +__os_segdata_release(dbenv, rp, is_locked) + DB_ENV *dbenv; + REGION *rp; + int is_locked; +{ + os_segdata_t *p; + + if (__os_segdata == NULL) { + __db_err(dbenv, "shared memory segment not initialized"); + return (EAGAIN); + } + + if (rp->segid < 0 || rp->segid >= __os_segdata_size) { + __db_err(dbenv, "segment id %ld out of range", rp->segid); + return (EINVAL); + } + + if (is_locked == 0) + DB_BEGIN_SINGLE_THREAD; + p = &__os_segdata[rp->segid]; + if (p->name != NULL) { + __os_freestr(p->name); + p->name = NULL; + } + if (p->segment != NULL) { + __os_free(p->segment, p->size); + p->segment = NULL; + } + p->size = 0; + if (is_locked == 0) + DB_END_SINGLE_THREAD; + + /* Any shrink-table logic could go here */ + + return (0); +} diff --git a/db/os_win32/os_abs.c b/db/os_win32/os_abs.c new file mode 100644 index 000000000..7b1e3fd05 --- /dev/null +++ b/db/os_win32/os_abs.c @@ -0,0 +1,33 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: os_abs.c,v 11.3 2000/02/14 03:00:06 bostic Exp $"; +#endif /* not lint */ + +#include "db_int.h" + +/* + * __os_abspath -- + * Return if a path is an absolute path. + */ +int +__os_abspath(path) + const char *path; +{ + /* + * !!! + * Check for drive specifications, e.g., "C:". In addition, the path + * separator used by the win32 DB (PATH_SEPARATOR) is \; look for both + * / and \ since these are user-input paths. + */ + if (isalpha(path[0]) && path[1] == ':') + path += 2; + return (path[0] == '/' || path[0] == '\\'); +} diff --git a/db/os_win32/os_dir.c b/db/os_win32/os_dir.c new file mode 100644 index 000000000..d37b76010 --- /dev/null +++ b/db/os_win32/os_dir.c @@ -0,0 +1,82 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: os_dir.c,v 11.4 2000/03/28 21:50:17 ubell Exp $"; +#endif /* not lint */ + +#include "db_int.h" +#include "os_jump.h" + +/* + * __os_dirlist -- + * Return a list of the files in a directory. + */ +int +__os_dirlist(dbenv, dir, namesp, cntp) + DB_ENV *dbenv; + const char *dir; + char ***namesp; + int *cntp; +{ + struct _finddata_t fdata; + long dirhandle; + int arraysz, cnt, finished, ret; + char **names, filespec[MAXPATHLEN]; + + if (__db_jump.j_dirlist != NULL) + return (__db_jump.j_dirlist(dir, namesp, cntp)); + + (void)snprintf(filespec, sizeof(filespec), "%s/*", dir); + if ((dirhandle = _findfirst(filespec, &fdata)) == -1) + return (__os_get_errno()); + + names = NULL; + finished = 0; + for (arraysz = cnt = 0; finished != 1; ++cnt) { + if (cnt >= arraysz) { + arraysz += 100; + if ((ret = __os_realloc(dbenv, + arraysz * sizeof(names[0]), NULL, &names)) != 0) + goto nomem; + } + if ((ret = __os_strdup(dbenv, fdata.name, &names[cnt])) != 0) + goto nomem; + if (_findnext(dirhandle,&fdata) != 0) + finished = 1; + } + _findclose(dirhandle); + + *namesp = names; + *cntp = cnt; + return (0); + +nomem: if (names != NULL) + __os_dirfree(names, cnt); + return (ret); +} + +/* + * __os_dirfree -- + * Free the list of files. + */ +void +__os_dirfree(names, cnt) + char **names; + int cnt; +{ + if (__db_jump.j_dirfree != NULL) { + __db_jump.j_dirfree(names, cnt); + return; + } + + while (cnt > 0) + __os_free(names[--cnt], 0); + __os_free(names, 0); +} diff --git a/db/os_win32/os_errno.c b/db/os_win32/os_errno.c new file mode 100644 index 000000000..8324826b6 --- /dev/null +++ b/db/os_win32/os_errno.c @@ -0,0 +1,146 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: os_errno.c,v 11.5 2000/11/30 00:58:43 ubell Exp $"; +#endif /* not lint */ + +#include "db_int.h" + +/* + * __os_get_errno -- + * Return the value of errno. + */ +int +__os_get_errno() +{ + /* This routine must be able to return the same value repeatedly. */ + return (errno); +} + +/* + * __os_set_errno -- + * Set the value of errno. + */ +void +__os_set_errno(evalue) + int evalue; +{ + errno = evalue; +} + +/* + * __os_win32_errno -- + * Return the last Windows error as an errno. + * We give generic error returns: + * + * EFAULT means Win* call failed, + * and GetLastError provided no extra info. + * + * EIO means error on Win* call. + * and we were unable to provide a meaningful errno for this Windows + * error. More information is only available by setting a breakpoint + * here. + * + * PUBLIC: #if defined(DB_WIN32) + * PUBLIC: int __os_win32_errno __P((void)); + * PUBLIC: #endif + */ +int +__os_win32_errno(void) +{ + DWORD last_error; + int ret; + + /* + * It's possible that errno was set after the error. + * The caller must take care to set it to 0 before + * any system operation. + */ + if (__os_get_errno() != 0) + return (__os_get_errno()); + + last_error = GetLastError(); + + /* + * Take our best guess at translating some of the Windows error + * codes. We really care about only a few of these. + */ + switch (last_error) { + case ERROR_FILE_NOT_FOUND: + case ERROR_INVALID_DRIVE: + case ERROR_PATH_NOT_FOUND: + ret = ENOENT; + break; + + case ERROR_NO_MORE_FILES: + case ERROR_TOO_MANY_OPEN_FILES: + ret = EMFILE; + break; + + case ERROR_ACCESS_DENIED: + ret = EPERM; + break; + + case ERROR_INVALID_HANDLE: + ret = EBADF; + break; + + case ERROR_NOT_ENOUGH_MEMORY: + ret = ENOMEM; + break; + + case ERROR_DISK_FULL: + ret = ENOSPC; + + case ERROR_ARENA_TRASHED: + case ERROR_BAD_COMMAND: + case ERROR_BAD_ENVIRONMENT: + case ERROR_BAD_FORMAT: + case ERROR_GEN_FAILURE: + case ERROR_INVALID_ACCESS: + case ERROR_INVALID_BLOCK: + case ERROR_INVALID_DATA: + case ERROR_READ_FAULT: + case ERROR_WRITE_FAULT: + ret = EFAULT; + break; + + case ERROR_FILE_EXISTS: + ret = EEXIST; + break; + + case ERROR_NOT_SAME_DEVICE: + ret = EXDEV; + break; + + case ERROR_WRITE_PROTECT: + ret = EACCES; + break; + + case ERROR_NOT_READY: + ret = EBUSY; + break; + + case ERROR_LOCK_VIOLATION: + case ERROR_SHARING_VIOLATION: + ret = EBUSY; + break; + + case 0: + ret = EFAULT; + break; + + default: + ret = EIO; /* Generic error. */ + break; + } + + return (ret); +} diff --git a/db/os_win32/os_fid.c b/db/os_win32/os_fid.c new file mode 100644 index 000000000..c66ac5210 --- /dev/null +++ b/db/os_win32/os_fid.c @@ -0,0 +1,145 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: os_fid.c,v 11.7 2000/10/26 14:18:08 bostic Exp $"; +#endif /* not lint */ + +#include "db_int.h" + +#define SERIAL_INIT 0 +static u_int32_t fid_serial = SERIAL_INIT; + +/* + * __os_fileid -- + * Return a unique identifier for a file. + */ +int +__os_fileid(dbenv, fname, unique_okay, fidp) + DB_ENV *dbenv; + const char *fname; + int unique_okay; + u_int8_t *fidp; +{ + size_t i; + u_int32_t tmp; + u_int8_t *p; + int ret; + + /* + * The documentation for GetFileInformationByHandle() states that the + * inode-type numbers are not constant between processes. Actually, + * they are, they're the NTFS MFT indexes. So, this works on NTFS, + * but perhaps not on other platforms, and perhaps not over a network. + * Can't think of a better solution right now. + */ + DB_FH fh; + HANDLE handle; + BY_HANDLE_FILE_INFORMATION fi; + BOOL retval = FALSE; + + /* Clear the buffer. */ + memset(fidp, 0, DB_FILE_ID_LEN); + + /* + * Initialize/increment the serial number we use to help avoid + * fileid collisions. Note that we don't bother with locking; + * it's unpleasant to do from down in here, and if we race on + * this no real harm will be done, since the finished fileid + * has so many other components. + * + * We increment by 100000 on each call as a simple way of + * randomizing; simply incrementing seems potentially less useful + * if pids are also simply incremented, since this is process-local + * and we may be one of a set of processes starting up. 100000 + * pushes us out of pid space on most platforms, and has few + * interesting properties in base 2. + */ + if (fid_serial == SERIAL_INIT) + fid_serial = (u_int32_t)getpid(); + else + fid_serial += 100000; + + /* + * First we open the file, because we're not given a handle to it. + * If we can't open it, we're in trouble. + */ + if ((ret = __os_open(dbenv, fname, DB_OSO_RDONLY, _S_IREAD, &fh)) != 0) + return (ret); + + /* File open, get its info */ + handle = (HANDLE)_get_osfhandle(fh.fd); + if (handle == INVALID_HANDLE_VALUE) + ret = __os_win32_errno(); + else + if ((retval = GetFileInformationByHandle(handle, &fi)) == FALSE) + ret = __os_win32_errno(); + __os_closehandle(&fh); + + if (handle == INVALID_HANDLE_VALUE || retval == FALSE) + return (ret); + + /* + * We want the three 32-bit words which tell us the volume ID and + * the file ID. We make a crude attempt to copy the bytes over to + * the callers buffer. + * + * We don't worry about byte sexing or the actual variable sizes. + * + * When this routine is called from the DB access methods, it's only + * called once -- whatever ID is generated when a database is created + * is stored in the database file's metadata, and that is what is + * saved in the mpool region's information to uniquely identify the + * file. + * + * When called from the mpool layer this routine will be called each + * time a new thread of control wants to share the file, which makes + * things tougher. As far as byte sexing goes, since the mpool region + * lives on a single host, there's no issue of that -- the entire + * region is byte sex dependent. As far as variable sizes go, we make + * the simplifying assumption that 32-bit and 64-bit processes will + * get the same 32-bit values if we truncate any returned 64-bit value + * to a 32-bit value. + */ + tmp = (u_int32_t)fi.nFileIndexLow; + for (p = (u_int8_t *)&tmp, i = sizeof(u_int32_t); i > 0; --i) + *fidp++ = *p++; + tmp = (u_int32_t)fi.nFileIndexHigh; + for (p = (u_int8_t *)&tmp, i = sizeof(u_int32_t); i > 0; --i) + *fidp++ = *p++; + if (unique_okay) { + /* + * Use the system time to try to get a unique value + * within this process. A millisecond counter + * overflows 32 bits in about 49 days. So we use 8 + * bytes, and don't bother with the volume ID, which + * is not very useful for our purposes. + */ + SYSTEMTIME st; + + GetSystemTime(&st); + tmp = (st.wYear - 1900) * 12 + (st.wMonth - 1); + for (p = (u_int8_t *)&tmp, i = sizeof(u_int32_t); i > 0; --i) + *fidp++ = *p++; + tmp = ((((st.wDay - 1) * 24 + st.wHour) * 60 + + st.wMinute) * 60 + st.wSecond) * 1000 + + st.wMilliseconds; + for (p = (u_int8_t *)&tmp, i = sizeof(u_int32_t); i > 0; --i) + *fidp++ = *p++; + for (p = (u_int8_t *)&fid_serial, i = sizeof(u_int32_t); + i > 0; --i) + *fidp++ = *p++; + } else { + tmp = (u_int32_t)fi.dwVolumeSerialNumber; + for (p = (u_int8_t *)&tmp, i = sizeof(u_int32_t); i > 0; --i) + *fidp++ = *p++; + } + + return (0); +} diff --git a/db/os_win32/os_finit.c b/db/os_win32/os_finit.c new file mode 100644 index 000000000..61d2a33c7 --- /dev/null +++ b/db/os_win32/os_finit.c @@ -0,0 +1,60 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: os_finit.c,v 11.9 2000/03/29 20:50:52 ubell Exp $"; +#endif /* not lint */ + +#include "db_int.h" + +/* + * __os_fpinit -- + * Initialize a page in a regular file. + * + * PUBLIC: int __os_fpinit __P((DB_ENV *, DB_FH *, db_pgno_t, int, int)); + */ +int +__os_fpinit(dbenv, fhp, pgno, pagecount, pagesize) + DB_ENV *dbenv; + DB_FH *fhp; + db_pgno_t pgno; + int pagecount, pagesize; +{ + size_t nw, totalbytes, curbytes; + int ret; + char buf[1024]; + + /* + * Windows/NT zero-fills pages that were never explicitly written to + * the file. Windows 95/98 gives you random garbage, and that breaks + * DB. + */ + if (__os_is_winnt()) + return (0); + + if ((ret = __os_seek(dbenv, + fhp, pagesize, pgno, 0, 0, DB_OS_SEEK_SET)) != 0) + return (ret); + + memset(buf, 0, sizeof(buf)); + totalbytes = pagecount * pagesize; + + while (totalbytes > 0) { + if (totalbytes > sizeof(buf)) + curbytes = sizeof(buf); + else + curbytes = totalbytes; + if ((ret = __os_write(dbenv, fhp, buf, curbytes, &nw)) != 0) + return (ret); + if (nw != curbytes) + return (EIO); + totalbytes -= curbytes; + } + return (0); +} diff --git a/db/os_win32/os_map.c b/db/os_win32/os_map.c new file mode 100644 index 000000000..d7b2839ed --- /dev/null +++ b/db/os_win32/os_map.c @@ -0,0 +1,310 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: os_map.c,v 11.22 2000/10/26 14:18:08 bostic Exp $"; +#endif /* not lint */ + +#include "db_int.h" +#include "os_jump.h" + +static int __os_map + __P((DB_ENV *, char *, REGINFO *, DB_FH *, size_t, int, int, int, void **)); +static int __os_unique_name __P((char *, int, char *)); + +/* + * __os_r_sysattach -- + * Create/join a shared memory region. + */ +int +__os_r_sysattach(dbenv, infop, rp) + DB_ENV *dbenv; + REGINFO *infop; + REGION *rp; +{ + DB_FH fh; + int is_system, ret; + + /* + * Try to open/create the file. We DO NOT need to ensure that multiple + * threads/processes attempting to simultaneously create the region are + * properly ordered, our caller has already taken care of that. + */ + if ((ret = __os_open(dbenv, infop->name, + F_ISSET(infop, REGION_CREATE_OK) ? DB_OSO_CREATE: 0, + infop->mode, &fh)) != 0) { + __db_err(dbenv, "%s: %s", infop->name, db_strerror(ret)); + return (ret); + } + + /* + * On Windows/9X, files that are opened by multiple processes do not + * share data correctly. For this reason, the DB_SYSTEM_MEM flag is + * implied for any application that does not specify the DB_PRIVATE + * flag. + */ + is_system = F_ISSET(dbenv, DB_ENV_SYSTEM_MEM) || + (!F_ISSET(dbenv, DB_ENV_PRIVATE) && __os_is_winnt() == 0); + + /* + * Map the file in. If we're creating an in-system-memory region, + * specify a segment ID (which is never used again) so that the + * calling code writes out the REGENV_REF structure to the primary + * environment file. + */ + ret = __os_map(dbenv, infop->name, infop, &fh, rp->size, + 1, is_system, 0, &infop->addr); + if (ret == 0 && is_system == 1) + rp->segid = 1; + + (void)__os_closehandle(&fh); + + return (ret); +} + +/* + * __os_r_sysdetach -- + * Detach from a shared memory region. + */ +int +__os_r_sysdetach(dbenv, infop, destroy) + DB_ENV *dbenv; + REGINFO *infop; + int destroy; +{ + int ret, t_ret; + + if (infop->wnt_handle != NULL) { + (void)CloseHandle(*((HANDLE*)(infop->wnt_handle))); + __os_free(infop->wnt_handle, sizeof(HANDLE)); + } + + __os_set_errno(0); + ret = !UnmapViewOfFile(infop->addr) ? __os_win32_errno() : 0; + if (ret != 0) + __db_err(dbenv, "UnmapViewOfFile: %s", strerror(ret)); + + if (F_ISSET(dbenv, DB_ENV_SYSTEM_MEM) && destroy && + (t_ret = __os_unlink(dbenv, infop->name)) != 0 && ret == 0) + ret = t_ret; + + return (ret); +} + +/* + * __os_mapfile -- + * Map in a shared memory file. + */ +int +__os_mapfile(dbenv, path, fhp, len, is_rdonly, addr) + DB_ENV *dbenv; + char *path; + DB_FH *fhp; + int is_rdonly; + size_t len; + void **addr; +{ + /* If the user replaced the map call, call through their interface. */ + if (__db_jump.j_map != NULL) + return (__db_jump.j_map(path, len, 0, is_rdonly, addr)); + + return (__os_map(dbenv, path, NULL, fhp, len, 0, 0, is_rdonly, addr)); +} + +/* + * __os_unmapfile -- + * Unmap the shared memory file. + */ +int +__os_unmapfile(dbenv, addr, len) + DB_ENV *dbenv; + void *addr; + size_t len; +{ + /* If the user replaced the map call, call through their interface. */ + if (__db_jump.j_unmap != NULL) + return (__db_jump.j_unmap(addr, len)); + + __os_set_errno(0); + return (!UnmapViewOfFile(addr) ? __os_win32_errno() : 0); +} + +/* + * __os_unique_name -- + * Create a unique identifying name from a pathname (may be absolute or + * relative) and/or a file descriptor. + * + * The name returned must be unique (different files map to different + * names), and repeatable (same files, map to same names). It's not + * so easy to do by name. Should handle not only: + * + * foo.bar == ./foo.bar == c:/whatever_path/foo.bar + * + * but also understand that: + * + * foo.bar == Foo.Bar (FAT file system) + * foo.bar != Foo.Bar (NTFS) + * + * The best solution is to use the identifying number in the file + * information structure (similar to UNIX inode #). + */ +static int +__os_unique_name(orig_path, fd, result_path) + char *orig_path, *result_path; + int fd; +{ + BY_HANDLE_FILE_INFORMATION fileinfo; + + __os_set_errno(0); + if (!GetFileInformationByHandle( + (HANDLE)_get_osfhandle(fd), &fileinfo)) + return (__os_win32_errno()); + (void)sprintf(result_path, "%ld.%ld.%ld", + fileinfo.dwVolumeSerialNumber, + fileinfo.nFileIndexHigh, fileinfo.nFileIndexLow); + return (0); +} + +/* + * __os_map -- + * The mmap(2) function for Windows. + */ +static int +__os_map(dbenv, path, infop, fhp, len, is_region, is_system, is_rdonly, addr) + DB_ENV *dbenv; + REGINFO *infop; + char *path; + DB_FH *fhp; + int is_region, is_system, is_rdonly; + size_t len; + void **addr; +{ + HANDLE hMemory; + REGENV *renv; + int ret; + void *pMemory; + char shmem_name[MAXPATHLEN]; + int use_pagefile; + + ret = 0; + if (infop != NULL) + infop->wnt_handle = NULL; + + use_pagefile = is_region && is_system; + + /* + * If creating a region in system space, get a matching name in the + * paging file namespace. + */ + if (use_pagefile) { + (void)strcpy(shmem_name, "__db_shmem."); + if ((ret = __os_unique_name(path, fhp->fd, + &shmem_name[strlen(shmem_name)])) != 0) + return (ret); + } + + /* + * XXX + * DB: We have not implemented copy-on-write here. + * + * XXX + * DB: This code will fail if the library is ever compiled on a 64-bit + * machine. + * + * XXX + * If this is an region in system memory, let's try opening using the + * OpenFileMapping() first. Why, oh why are we doing this? + * + * Well, we might be asking the OS for a handle to a pre-existing + * memory section, or we might be the first to get here and want the + * section created. CreateFileMapping() sounds like it will do both + * jobs. But, not so. It seems to mess up making the commit charge to + * the process. It thinks, incorrectly, that when we want to join a + * previously existing section, that it should make a commit charge + * for the whole section. In fact, there is no new committed memory + * whatever. The call can fail if there is insufficient memory free + * to handle the erroneous commit charge. So, we find that the bogus + * commit is not made if we call OpenFileMapping(). So we do that + * first, and only call CreateFileMapping() if we're really creating + * the section. + */ + hMemory = NULL; + __os_set_errno(0); + if (use_pagefile) + hMemory = OpenFileMapping( + is_rdonly ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS, + 0, + shmem_name); + + if (hMemory == NULL) + hMemory = CreateFileMapping( + use_pagefile ? + (HANDLE)0xFFFFFFFF : (HANDLE)_get_osfhandle(fhp->fd), + 0, + is_rdonly ? PAGE_READONLY : PAGE_READWRITE, + 0, len, + use_pagefile ? shmem_name : NULL); + if (hMemory == NULL) { + __db_err(dbenv, + "OpenFileMapping: %s", strerror(__os_win32_errno())); + return (__os_win32_errno()); + } + + pMemory = MapViewOfFile(hMemory, + (is_rdonly ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS), 0, 0, len); + if (pMemory == NULL) { + __db_err(dbenv, + "MapViewOfFile: %s", strerror(__os_win32_errno())); + return (__os_win32_errno()); + } + + /* + * XXX + * It turns out that the kernel object underlying the named section + * is reference counted, but that the call to MapViewOfFile() above + * does NOT increment the reference count! So, if we close the handle + * here, the kernel deletes the object from the kernel namespace. + * When a second process comes along to join the region, the kernel + * happily creates a new object with the same name, but completely + * different identity. The two processes then have distinct isolated + * mapped sections, not at all what was wanted. Not closing the handle + * here fixes this problem. We carry the handle around in the region + * structure so we can close it when unmap is called. Ignore malloc + * errors, it just means we leak the memory. + */ + if (use_pagefile && infop != NULL) { + if (__os_malloc(NULL, + sizeof(HANDLE), NULL, &infop->wnt_handle) == 0) + memcpy(infop->wnt_handle, &hMemory, sizeof(HANDLE)); + } else + CloseHandle(hMemory); + + if (is_region) { + /* + * XXX + * Windows/95 zeroes anonymous memory regions at last close. + * This means that the backing file can exist and reference + * the region, but the region itself is no longer initialized. + * If the caller is capable of creating the region, update + * the REGINFO structure so that they do so. + */ + renv = (REGENV *)pMemory; + if (renv->magic == 0) + if (F_ISSET(infop, REGION_CREATE_OK)) + F_SET(infop, REGION_CREATE); + else { + (void)UnmapViewOfFile(pMemory); + pMemory = NULL; + ret = EAGAIN; + } + } + + *addr = pMemory; + return (ret); +} diff --git a/db/os_win32/os_open.c b/db/os_win32/os_open.c new file mode 100644 index 000000000..7ecd96126 --- /dev/null +++ b/db/os_win32/os_open.c @@ -0,0 +1,201 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: os_open.c,v 11.9 2000/11/30 00:58:43 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#include +#endif + +#include "db_int.h" +#include "os_jump.h" + +int __os_win32_errno __P((void)); + +/* + * __os_open -- + * Open a file descriptor. + */ +int +__os_open(dbenv, name, flags, mode, fhp) + DB_ENV *dbenv; + const char *name; + u_int32_t flags; + int mode; + DB_FH *fhp; +{ + DWORD bytesWritten; + HANDLE wh; + u_int32_t log_size; + int access, attr, oflags, share, createflag; + int ret, nrepeat; + + /* + * The "public" interface to the __os_open routine passes around POSIX + * 1003.1 flags, not DB flags. If the user has defined their own open + * interface, use the POSIX flags. + */ + if (__db_jump.j_open != NULL) { + oflags = O_BINARY | O_NOINHERIT; + + if (LF_ISSET(DB_OSO_CREATE)) + oflags |= O_CREAT; + + if (LF_ISSET(DB_OSO_EXCL)) + oflags |= O_EXCL; + + if (LF_ISSET(DB_OSO_RDONLY)) + oflags |= O_RDONLY; + else + oflags |= O_RDWR; + + if (LF_ISSET(DB_OSO_SEQ)) + oflags |= _O_SEQUENTIAL; + else + oflags |= _O_RANDOM; + + if (LF_ISSET(DB_OSO_TEMP)) + oflags |= _O_TEMPORARY; + + if (LF_ISSET(DB_OSO_TRUNC)) + oflags |= O_TRUNC; + + return (__os_openhandle(dbenv, name, oflags, mode, fhp)); + } + + if (LF_ISSET(DB_OSO_LOG)) + log_size = fhp->log_size; /* XXX: Gag. */ + + memset(fhp, 0, sizeof(*fhp)); + + /* + * Otherwise, use the Windows/32 CreateFile interface so that we can + * play magic games with log files to get data flush effects similar + * to the POSIX O_DSYNC flag. + * + * !!! + * We currently ignore the 'mode' argument. It would be possible + * to construct a set of security attributes that we could pass to + * CreateFile that would accurately represents the mode. In worst + * case, this would require looking up user and all group names and + * creating an entry for each. Alternatively, we could call the + * _chmod (partial emulation) function after file creation, although + * this leaves us with an obvious race. However, these efforts are + * largely meaningless on FAT, the most common file system, which + * only has a "readable" and "writeable" flag, applying to all users. + */ + wh = INVALID_HANDLE_VALUE; + + access = GENERIC_READ; + if (!LF_ISSET(DB_OSO_RDONLY)) + access |= GENERIC_WRITE; + + share = FILE_SHARE_READ | FILE_SHARE_WRITE; + attr = FILE_ATTRIBUTE_NORMAL; + + /* + * Reproduce POSIX 1003.1 semantics: if O_CREATE and O_EXCL are both + * specified, fail, returning EEXIST, unless we create the file. + */ + if (LF_ISSET(DB_OSO_CREATE) && LF_ISSET(DB_OSO_EXCL)) + createflag = CREATE_NEW; /* create only if !exist*/ + else if (!LF_ISSET(DB_OSO_CREATE) && LF_ISSET(DB_OSO_TRUNC)) + createflag = TRUNCATE_EXISTING; /* truncate, fail if !exist */ + else if (LF_ISSET(DB_OSO_TRUNC)) + createflag = CREATE_ALWAYS; /* create and truncate */ + else if (LF_ISSET(DB_OSO_CREATE)) + createflag = OPEN_ALWAYS; /* open or create */ + else + createflag = OPEN_EXISTING; /* open only if existing */ + + if (LF_ISSET(DB_OSO_LOG)) { + F_SET(fhp, DB_FH_NOSYNC); + attr |= FILE_FLAG_WRITE_THROUGH; + } + + if (LF_ISSET(DB_OSO_SEQ)) + attr |= FILE_FLAG_SEQUENTIAL_SCAN; + else + attr |= FILE_FLAG_RANDOM_ACCESS; + + if (LF_ISSET(DB_OSO_TEMP)) + attr |= FILE_FLAG_DELETE_ON_CLOSE; + + for (nrepeat = 1; nrepeat < 4; ++nrepeat) { + ret = 0; + __os_set_errno(0); + wh = CreateFile(name, access, share, NULL, createflag, attr, 0); + if (wh == INVALID_HANDLE_VALUE) { + /* + * If it's a "temporary" error, we retry up to 3 times, + * waiting up to 12 seconds. While it's not a problem + * if we can't open a database, an inability to open a + * log file is cause for serious dismay. + */ + ret = __os_win32_errno(); + if (ret == ENFILE || ret == EMFILE || ret == ENOSPC) { + (void)__os_sleep(dbenv, nrepeat * 2, 0); + continue; + } + goto err; + } + break; + } + + /* + * Special handling needed for log files. To get Windows to not update + * the MFT metadata on each write, extend the file to its maximum size. + * Windows will allocate all the data blocks and store them in the MFT + * (inode) area. In addition, flush the MFT area to disk. + * This strategy only works for Win/NT; Win/9X does not + * guarantee that the logs will be zero filled. + */ + if (LF_ISSET(DB_OSO_LOG) && log_size != 0 && + __os_is_winnt()) { + if (SetFilePointer(wh, + log_size - 1, NULL, FILE_BEGIN) == (DWORD)-1) + goto err; + if (WriteFile(wh, "\x00", 1, &bytesWritten, NULL) == 0) + goto err; + if (bytesWritten != 1) + goto err; + if (SetEndOfFile(wh) == 0) + goto err; + if (SetFilePointer(wh, 0, NULL, FILE_BEGIN) == (DWORD)-1) + goto err; + if (FlushFileBuffers(wh) == 0) + goto err; + } + + /* + * We acquire a POSIX file descriptor as this allows us to use the + * general UNIX I/O routines instead of writing Windows specific + * ones. Closing that file descriptor is sufficient to close the + * Windows HANDLE. + */ + fhp->fd = + _open_osfhandle((long)wh, LF_ISSET(DB_OSO_RDONLY) ? O_RDONLY : 0); + fhp->handle = wh; + F_SET(fhp, DB_FH_VALID); + + return (0); + +err: if (ret == 0) + ret = __os_win32_errno(); + if (wh != INVALID_HANDLE_VALUE) + (void)CloseHandle(wh); + return (ret); +} diff --git a/db/os_win32/os_rename.c b/db/os_win32/os_rename.c new file mode 100644 index 000000000..c82482046 --- /dev/null +++ b/db/os_win32/os_rename.c @@ -0,0 +1,57 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: os_rename.c,v 1.2 2000/06/13 19:52:19 dda Exp $"; +#endif /* not lint */ + +#include "db_int.h" +#include "os_jump.h" + +/* + * __os_rename -- + * Rename a file. + */ +int +__os_rename(dbenv, old, new) + DB_ENV *dbenv; + const char *old, *new; +{ + int ret; + + ret = 0; + if (__db_jump.j_rename != NULL) { + if (__db_jump.j_rename(old, new) == -1) + ret = __os_get_errno(); + } + else { + /* Normally we would use a single MoveFileEx call with + * MOVEFILE_REPLACE_EXISTING flag to simulate Unix rename(). + * But if the target file exists, and the two files' 8.3 + * names are identical, a Windows bug causes the target file + * to be deleted, but the original file will not be renamed, + * and an ENOENT error will be returned. (See MSDN for a + * description of the bug). + * + * After the failed call, a MoveFile seems to perform + * the rename correctly (even another call to MoveFileEx + * does not)! The expense of this extra call only occurs + * on systems with the bug: Windows/98, for one, but + * apparently not Windows/NT and Windows/2000. + */ + if (MoveFileEx(old, new, MOVEFILE_REPLACE_EXISTING) != TRUE) + ret = __os_win32_errno(); + if (ret == ENOENT && MoveFile(old, new) == TRUE) + ret = 0; + } + if (ret != 0) + __db_err(dbenv, "Rename %s %s: %s", old, new, strerror(ret)); + + return (ret); +} diff --git a/db/os_win32/os_seek.c b/db/os_win32/os_seek.c new file mode 100644 index 000000000..8cf3c98aa --- /dev/null +++ b/db/os_win32/os_seek.c @@ -0,0 +1,65 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: os_seek.c,v 11.8 2000/05/17 19:30:19 bostic Exp $"; +#endif /* not lint */ + +#include "db_int.h" +#include "os_jump.h" + +/* + * __os_seek -- + * Seek to a page/byte offset in the file. + */ +int +__os_seek(dbenv, fhp, pgsize, pageno, relative, isrewind, db_whence) + DB_ENV *dbenv; + DB_FH *fhp; + size_t pgsize; + db_pgno_t pageno; + u_int32_t relative; + int isrewind; + DB_OS_SEEK db_whence; +{ + __int64 offset; + int ret, whence; + + switch (db_whence) { + case DB_OS_SEEK_CUR: + whence = SEEK_CUR; + break; + case DB_OS_SEEK_END: + whence = SEEK_END; + break; + case DB_OS_SEEK_SET: + whence = SEEK_SET; + break; + default: + return (EINVAL); + } + + if (__db_jump.j_seek != NULL) + ret = __db_jump.j_seek(fhp->fd, pgsize, pageno, + relative, isrewind, whence); + else { + offset = (__int64)pgsize * pageno + relative; + if (isrewind) + offset = -offset; + ret = _lseeki64( + fhp->fd, offset, whence) == -1 ? __os_get_errno() : 0; + } + + if (ret != 0) + __db_err(dbenv, "seek: %lu %d %d: %s", + (u_long)pgsize * pageno + relative, + isrewind, db_whence, strerror(ret)); + + return (ret); +} diff --git a/db/os_win32/os_sleep.c b/db/os_win32/os_sleep.c new file mode 100644 index 000000000..f0248a583 --- /dev/null +++ b/db/os_win32/os_sleep.c @@ -0,0 +1,41 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: os_sleep.c,v 11.4 2000/03/30 01:46:43 ubell Exp $"; +#endif /* not lint */ + +#include "db_int.h" +#include "os_jump.h" + +/* + * __os_sleep -- + * Yield the processor for a period of time. + */ +int +__os_sleep(dbenv, secs, usecs) + DB_ENV *dbenv; + u_long secs, usecs; /* Seconds and microseconds. */ +{ + COMPQUIET(dbenv, NULL); + + /* Don't require that the values be normalized. */ + for (; usecs >= 1000000; ++secs, usecs -= 1000000) + ; + + if (__db_jump.j_sleep != NULL) + return (__db_jump.j_sleep(secs, usecs)); + + /* + * It's important that we yield the processor here so that other + * processes or threads are permitted to run. + */ + Sleep(secs * 1000 + usecs / 1000); + return (0); +} diff --git a/db/os_win32/os_spin.c b/db/os_win32/os_spin.c new file mode 100644 index 000000000..f250c523d --- /dev/null +++ b/db/os_win32/os_spin.c @@ -0,0 +1,59 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: os_spin.c,v 11.6 2000/05/17 19:30:19 bostic Exp $"; +#endif /* not lint */ + +#include "db_int.h" +#include "os_jump.h" + +/* + * __os_spin -- + * Return the number of default spins before blocking. + */ +int +__os_spin() +{ + SYSTEM_INFO SystemInfo; + + /* + * If the application specified a value or we've already figured it + * out, return it. + */ + if (DB_GLOBAL(db_tas_spins) != 0) + return (DB_GLOBAL(db_tas_spins)); + + /* Get the number of processors */ + GetSystemInfo(&SystemInfo); + + /* + * Spin 50 times per processor -- we have anecdotal evidence that this + * is a reasonable value. + */ + if (SystemInfo.dwNumberOfProcessors > 1) + DB_GLOBAL(db_tas_spins) = 50 * SystemInfo.dwNumberOfProcessors; + else + DB_GLOBAL(db_tas_spins) = 1; + return (DB_GLOBAL(db_tas_spins)); +} + +/* + * __os_yield -- + * Yield the processor. + */ +void +__os_yield(dbenv, usecs) + DB_ENV *dbenv; + u_long usecs; +{ + if (__db_jump.j_yield != NULL && __db_jump.j_yield() == 0) + return; + __os_sleep(dbenv, 0, usecs); +} diff --git a/db/os_win32/os_type.c b/db/os_win32/os_type.c new file mode 100644 index 000000000..a82fc4b1d --- /dev/null +++ b/db/os_win32/os_type.c @@ -0,0 +1,35 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: os_type.c,v 11.3 2000/02/14 03:00:07 bostic Exp $"; +#endif /* not lint */ + +/* + * __os_is_winnt -- + * Return 1 if Windows/NT, otherwise 0. + * + * PUBLIC: int __os_is_winnt __P((void)); + */ +int +__os_is_winnt() +{ + static int __os_type = -1; + + /* + * The value of __os_type is computed only once, and cached to + * avoid the overhead of repeated calls to GetVersion(). + */ + if (__os_type == -1) + if ((GetVersion() & 0x80000000) == 0) + __os_type = 1; + else + __os_type = 0; + return (__os_type); +} diff --git a/db/perl.BerkeleyDB/BerkeleyDB.pm b/db/perl.BerkeleyDB/BerkeleyDB.pm new file mode 100644 index 000000000..cc172a2bd --- /dev/null +++ b/db/perl.BerkeleyDB/BerkeleyDB.pm @@ -0,0 +1,1227 @@ + +package BerkeleyDB; + + +# Copyright (c) 1997-2001 Paul Marquess. All rights reserved. +# This program is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. +# + +# The documentation for this module is at the bottom of this file, +# after the line __END__. + +BEGIN { require 5.004_04 } + +use strict; +use Carp; +use vars qw($VERSION @ISA @EXPORT $AUTOLOAD); + +$VERSION = '0.13'; + +require Exporter; +require DynaLoader; +require AutoLoader; +use IO ; + +@ISA = qw(Exporter DynaLoader); +# Items to export into callers namespace by default. Note: do not export +# names by default without a very good reason. Use EXPORT_OK instead. +# Do not simply export all your public functions/methods/constants. +@EXPORT = qw( + + DB_AFTER + DB_APPEND + DB_ARCH_ABS + DB_ARCH_DATA + DB_ARCH_LOG + DB_BEFORE + DB_BTREE + DB_BTREEMAGIC + DB_BTREEOLDVER + DB_BTREEVERSION + DB_CHECKPOINT + DB_CONSUME + DB_CREATE + DB_CURLSN + DB_CURRENT + DB_DBT_MALLOC + DB_DBT_PARTIAL + DB_DBT_USERMEM + DB_DELETED + DB_DELIMITER + DB_DUP + DB_DUPSORT + DB_ENV_APPINIT + DB_ENV_STANDALONE + DB_ENV_THREAD + DB_EXCL + DB_FILE_ID_LEN + DB_FIRST + DB_FIXEDLEN + DB_FLUSH + DB_FORCE + DB_GET_BOTH + DB_GET_RECNO + DB_HASH + DB_HASHMAGIC + DB_HASHOLDVER + DB_HASHVERSION + DB_INCOMPLETE + DB_INIT_CDB + DB_INIT_LOCK + DB_INIT_LOG + DB_INIT_MPOOL + DB_INIT_TXN + DB_JOIN_ITEM + DB_KEYEMPTY + DB_KEYEXIST + DB_KEYFIRST + DB_KEYLAST + DB_LAST + DB_LOCKMAGIC + DB_LOCKVERSION + DB_LOCK_CONFLICT + DB_LOCK_DEADLOCK + DB_LOCK_DEFAULT + DB_LOCK_GET + DB_LOCK_NORUN + DB_LOCK_NOTGRANTED + DB_LOCK_NOTHELD + DB_LOCK_NOWAIT + DB_LOCK_OLDEST + DB_LOCK_RANDOM + DB_LOCK_RIW_N + DB_LOCK_RW_N + DB_LOCK_YOUNGEST + DB_LOGMAGIC + DB_LOGOLDVER + DB_MAX_PAGES + DB_MAX_RECORDS + DB_MPOOL_CLEAN + DB_MPOOL_CREATE + DB_MPOOL_DIRTY + DB_MPOOL_DISCARD + DB_MPOOL_LAST + DB_MPOOL_NEW + DB_MPOOL_PRIVATE + DB_MUTEXDEBUG + DB_MUTEXLOCKS + DB_NEEDSPLIT + DB_NEXT + DB_NEXT_DUP + DB_NOMMAP + DB_NOOVERWRITE + DB_NOSYNC + DB_NOTFOUND + DB_PAD + DB_PAGEYIELD + DB_POSITION + DB_PREV + DB_PRIVATE + DB_QUEUE + DB_RDONLY + DB_RECNO + DB_RECNUM + DB_RECORDCOUNT + DB_RECOVER + DB_RECOVER_FATAL + DB_REGISTERED + DB_RENUMBER + DB_RMW + DB_RUNRECOVERY + DB_SEQUENTIAL + DB_SET + DB_SET_RANGE + DB_SET_RECNO + DB_SNAPSHOT + DB_SWAPBYTES + DB_TEMPORARY + DB_THREAD + DB_TRUNCATE + DB_TXNMAGIC + DB_TXNVERSION + DB_TXN_BACKWARD_ROLL + DB_TXN_CKP + DB_TXN_FORWARD_ROLL + DB_TXN_LOCK_2PL + DB_TXN_LOCK_MASK + DB_TXN_LOCK_OPTIMIST + DB_TXN_LOCK_OPTIMISTIC + DB_TXN_LOG_MASK + DB_TXN_LOG_REDO + DB_TXN_LOG_UNDO + DB_TXN_LOG_UNDOREDO + DB_TXN_NOSYNC + DB_TXN_NOWAIT + DB_TXN_OPENFILES + DB_TXN_REDO + DB_TXN_SYNC + DB_TXN_UNDO + DB_USE_ENVIRON + DB_USE_ENVIRON_ROOT + DB_VERSION_MAJOR + DB_VERSION_MINOR + DB_VERSION_PATCH + DB_WRITECURSOR + ); + +sub AUTOLOAD { + # This AUTOLOAD is used to 'autoload' constants from the constant() + # XS function. If a constant is not found then control is passed + # to the AUTOLOAD in AutoLoader. + + my $constname; + ($constname = $AUTOLOAD) =~ s/.*:://; + my $val = constant($constname, @_ ? $_[0] : 0); + if ($! != 0) { + if ($! =~ /Invalid/) { + $AutoLoader::AUTOLOAD = $AUTOLOAD; + goto &AutoLoader::AUTOLOAD; + } + else { + croak "Your vendor has not defined BerkeleyDB macro $constname"; + } + } + eval "sub $AUTOLOAD { $val }"; + goto &$AUTOLOAD; +} + +bootstrap BerkeleyDB $VERSION; + +# Preloaded methods go here. + + +sub ParseParameters($@) +{ + my ($default, @rest) = @_ ; + my (%got) = %$default ; + my (@Bad) ; + my ($key, $value) ; + my $sub = (caller(1))[3] ; + my %options = () ; + local ($Carp::CarpLevel) = 1 ; + + # allow the options to be passed as a hash reference or + # as the complete hash. + if (@rest == 1) { + + croak "$sub: parameter is not a reference to a hash" + if ref $rest[0] ne "HASH" ; + + %options = %{ $rest[0] } ; + } + elsif (@rest >= 2) { + %options = @rest ; + } + + while (($key, $value) = each %options) + { + $key =~ s/^-// ; + + if (exists $default->{$key}) + { $got{$key} = $value } + else + { push (@Bad, $key) } + } + + if (@Bad) { + my ($bad) = join(", ", @Bad) ; + croak "unknown key value(s) @Bad" ; + } + + return \%got ; +} + +use UNIVERSAL qw( isa ) ; + +sub env_remove +{ + # Usage: + # + # $env = new BerkeleyDB::Env + # [ -Home => $path, ] + # [ -Config => { name => value, name => value } + # [ -Flags => DB_INIT_LOCK| ] + # ; + + my $got = BerkeleyDB::ParseParameters({ + Home => undef, + Flags => 0, + Config => undef, + }, @_) ; + + if (defined $got->{ErrFile}) { + if (!isaFilehandle($got->{ErrFile})) { + my $handle = new IO::File ">$got->{ErrFile}" + or croak "Cannot open file $got->{ErrFile}: $!\n" ; + $got->{ErrFile} = $handle ; + } + } + + + if (defined $got->{Config}) { + croak("Config parameter must be a hash reference") + if ! ref $got->{Config} eq 'HASH' ; + + @BerkeleyDB::a = () ; + my $k = "" ; my $v = "" ; + while (($k, $v) = each %{$got->{Config}}) { + push @BerkeleyDB::a, "$k\t$v" ; + } + + $got->{"Config"} = pack("p*", @BerkeleyDB::a, undef) + if @BerkeleyDB::a ; + } + + return _env_remove($got) ; +} + +sub db_remove +{ + my $got = BerkeleyDB::ParseParameters( + { + Filename => undef, + Subname => undef, + Flags => 0, + Env => undef, + }, @_) ; + + croak("Must specify a filename") + if ! defined $got->{Filename} ; + + croak("Env not of type BerkeleyDB::Env") + if defined $got->{Env} and ! isa($got->{Env},'BerkeleyDB::Env'); + + return _db_remove($got); +} + +package BerkeleyDB::Env ; + +use UNIVERSAL qw( isa ) ; +use Carp ; +use vars qw( %valid_config_keys ) ; + +sub isaFilehandle +{ + my $fh = shift ; + + return ((isa($fh,'GLOB') or isa(\$fh,'GLOB')) and defined fileno($fh) ) + +} + +%valid_config_keys = map { $_, 1 } qw( DB_DATA_DIR DB_LOG_DIR DB_TEMP_DIR ) ; + +sub new +{ + # Usage: + # + # $env = new BerkeleyDB::Env + # [ -Home => $path, ] + # [ -Mode => mode, ] + # [ -Config => { name => value, name => value } + # [ -ErrFile => filename or filehandle, ] + # [ -ErrPrefix => "string", ] + # [ -Flags => DB_INIT_LOCK| ] + # [ -Cachesize => number ] + # [ -LockDetect => ] + # [ -Verbose => boolean ] + # ; + + my $pkg = shift ; + my $got = BerkeleyDB::ParseParameters({ + Home => undef, + Server => undef, + Mode => 0666, + ErrFile => undef, + ErrPrefix => undef, + Flags => 0, + Cachesize => 0, + LockDetect => 0, + Verbose => 0, + Config => undef, + }, @_) ; + + if (defined $got->{ErrFile}) { + if (!isaFilehandle($got->{ErrFile})) { + my $handle = new IO::File ">$got->{ErrFile}" + or croak "Cannot open file $got->{ErrFile}: $!\n" ; + $got->{ErrFile} = $handle ; + } + } + + + my %config ; + if (defined $got->{Config}) { + croak("Config parameter must be a hash reference") + if ! ref $got->{Config} eq 'HASH' ; + + %config = %{ $got->{Config} } ; + @BerkeleyDB::a = () ; + my $k = "" ; my $v = "" ; + while (($k, $v) = each %config) { + if ($BerkeleyDB::db_version >= 3.1 && ! $valid_config_keys{$k} ) { + $BerkeleyDB::Error = "illegal name-value pair: $k $v\n" ; + croak $BerkeleyDB::Error ; + } + push @BerkeleyDB::a, "$k\t$v" ; + } + + $got->{"Config"} = pack("p*", @BerkeleyDB::a, undef) + if @BerkeleyDB::a ; + } + + my ($addr) = _db_appinit($pkg, $got) ; + my $obj ; + $obj = bless [$addr] , $pkg if $addr ; + if ($obj && $BerkeleyDB::db_version >= 3.1 && keys %config) { + my ($k, $v); + while (($k, $v) = each %config) { + if ($k eq 'DB_DATA_DIR') + { $obj->set_data_dir($v) } + elsif ($k eq 'DB_LOG_DIR') + { $obj->set_lg_dir($v) } + elsif ($k eq 'DB_TEMP_DIR') + { $obj->set_tmp_dir($v) } + else { + $BerkeleyDB::Error = "illegal name-value pair: $k $v\n" ; + croak $BerkeleyDB::Error + } + } + } + return $obj ; +} + + +sub TxnMgr +{ + my $env = shift ; + my ($addr) = $env->_TxnMgr() ; + my $obj ; + $obj = bless [$addr, $env] , "BerkeleyDB::TxnMgr" if $addr ; + return $obj ; +} + +sub txn_begin +{ + my $env = shift ; + my ($addr) = $env->_txn_begin(@_) ; + my $obj ; + $obj = bless [$addr, $env] , "BerkeleyDB::Txn" if $addr ; + return $obj ; +} + +sub DESTROY +{ + my $self = shift ; + $self->_DESTROY() ; +} + +package BerkeleyDB::Hash ; + +use vars qw(@ISA) ; +@ISA = qw( BerkeleyDB::Common BerkeleyDB::_tiedHash ) ; +use UNIVERSAL qw( isa ) ; +use Carp ; + +sub new +{ + my $self = shift ; + my $got = BerkeleyDB::ParseParameters( + { + # Generic Stuff + Filename => undef, + Subname => undef, + #Flags => BerkeleyDB::DB_CREATE(), + Flags => 0, + Property => 0, + Mode => 0666, + Cachesize => 0, + Lorder => 0, + Pagesize => 0, + Env => undef, + #Tie => undef, + Txn => undef, + + # Hash specific + Ffactor => 0, + Nelem => 0, + Hash => undef, + DupCompare => undef, + + # BerkeleyDB specific + ReadKey => undef, + WriteKey => undef, + ReadValue => undef, + WriteValue => undef, + }, @_) ; + + croak("Env not of type BerkeleyDB::Env") + if defined $got->{Env} and ! isa($got->{Env},'BerkeleyDB::Env'); + + croak("Txn not of type BerkeleyDB::Txn") + if defined $got->{Txn} and ! isa($got->{Txn},'BerkeleyDB::Txn'); + + croak("-Tie needs a reference to a hash") + if defined $got->{Tie} and $got->{Tie} !~ /HASH/ ; + + my ($addr) = _db_open_hash($self, $got); + my $obj ; + if ($addr) { + $obj = bless [$addr] , $self ; + push @{ $obj }, $got->{Env} if $got->{Env} ; + $obj->Txn($got->{Txn}) if $got->{Txn} ; + } + return $obj ; +} + +*TIEHASH = \&new ; + + +package BerkeleyDB::Btree ; + +use vars qw(@ISA) ; +@ISA = qw( BerkeleyDB::Common BerkeleyDB::_tiedHash ) ; +use UNIVERSAL qw( isa ) ; +use Carp ; + +sub new +{ + my $self = shift ; + my $got = BerkeleyDB::ParseParameters( + { + # Generic Stuff + Filename => undef, + Subname => undef, + #Flags => BerkeleyDB::DB_CREATE(), + Flags => 0, + Property => 0, + Mode => 0666, + Cachesize => 0, + Lorder => 0, + Pagesize => 0, + Env => undef, + #Tie => undef, + Txn => undef, + + # Btree specific + Minkey => 0, + Compare => undef, + DupCompare => undef, + Prefix => undef, + }, @_) ; + + croak("Env not of type BerkeleyDB::Env") + if defined $got->{Env} and ! isa($got->{Env},'BerkeleyDB::Env'); + + croak("Txn not of type BerkeleyDB::Txn") + if defined $got->{Txn} and ! isa($got->{Txn},'BerkeleyDB::Txn'); + + croak("-Tie needs a reference to a hash") + if defined $got->{Tie} and $got->{Tie} !~ /HASH/ ; + + my ($addr) = _db_open_btree($self, $got); + my $obj ; + if ($addr) { + $obj = bless [$addr] , $self ; + push @{ $obj }, $got->{Env} if $got->{Env} ; + $obj->Txn($got->{Txn}) if $got->{Txn} ; + } + return $obj ; +} + +*BerkeleyDB::Btree::TIEHASH = \&BerkeleyDB::Btree::new ; + + +package BerkeleyDB::Recno ; + +use vars qw(@ISA) ; +@ISA = qw( BerkeleyDB::Common BerkeleyDB::_tiedArray ) ; +use UNIVERSAL qw( isa ) ; +use Carp ; + +sub new +{ + my $self = shift ; + my $got = BerkeleyDB::ParseParameters( + { + # Generic Stuff + Filename => undef, + Subname => undef, + #Flags => BerkeleyDB::DB_CREATE(), + Flags => 0, + Property => 0, + Mode => 0666, + Cachesize => 0, + Lorder => 0, + Pagesize => 0, + Env => undef, + #Tie => undef, + Txn => undef, + + # Recno specific + Delim => undef, + Len => undef, + Pad => undef, + Source => undef, + ArrayBase => 1, # lowest index in array + }, @_) ; + + croak("Env not of type BerkeleyDB::Env") + if defined $got->{Env} and ! isa($got->{Env},'BerkeleyDB::Env'); + + croak("Txn not of type BerkeleyDB::Txn") + if defined $got->{Txn} and ! isa($got->{Txn},'BerkeleyDB::Txn'); + + croak("Tie needs a reference to an array") + if defined $got->{Tie} and $got->{Tie} !~ /ARRAY/ ; + + croak("ArrayBase can only be 0 or 1, parsed $got->{ArrayBase}") + if $got->{ArrayBase} != 1 and $got->{ArrayBase} != 0 ; + + + $got->{Fname} = $got->{Filename} if defined $got->{Filename} ; + + my ($addr) = _db_open_recno($self, $got); + my $obj ; + if ($addr) { + $obj = bless [$addr] , $self ; + push @{ $obj }, $got->{Env} if $got->{Env} ; + $obj->Txn($got->{Txn}) if $got->{Txn} ; + } + return $obj ; +} + +*BerkeleyDB::Recno::TIEARRAY = \&BerkeleyDB::Recno::new ; +*BerkeleyDB::Recno::db_stat = \&BerkeleyDB::Btree::db_stat ; + +package BerkeleyDB::Queue ; + +use vars qw(@ISA) ; +@ISA = qw( BerkeleyDB::Common BerkeleyDB::_tiedArray ) ; +use UNIVERSAL qw( isa ) ; +use Carp ; + +sub new +{ + my $self = shift ; + my $got = BerkeleyDB::ParseParameters( + { + # Generic Stuff + Filename => undef, + Subname => undef, + #Flags => BerkeleyDB::DB_CREATE(), + Flags => 0, + Property => 0, + Mode => 0666, + Cachesize => 0, + Lorder => 0, + Pagesize => 0, + Env => undef, + #Tie => undef, + Txn => undef, + + # Queue specific + Len => undef, + Pad => undef, + ArrayBase => 1, # lowest index in array + ExtentSize => undef, + }, @_) ; + + croak("Env not of type BerkeleyDB::Env") + if defined $got->{Env} and ! isa($got->{Env},'BerkeleyDB::Env'); + + croak("Txn not of type BerkeleyDB::Txn") + if defined $got->{Txn} and ! isa($got->{Txn},'BerkeleyDB::Txn'); + + croak("Tie needs a reference to an array") + if defined $got->{Tie} and $got->{Tie} !~ /ARRAY/ ; + + croak("ArrayBase can only be 0 or 1, parsed $got->{ArrayBase}") + if $got->{ArrayBase} != 1 and $got->{ArrayBase} != 0 ; + + + my ($addr) = _db_open_queue($self, $got); + my $obj ; + if ($addr) { + $obj = bless [$addr] , $self ; + push @{ $obj }, $got->{Env} if $got->{Env} ; + $obj->Txn($got->{Txn}) if $got->{Txn} ; + } + return $obj ; +} + +*BerkeleyDB::Queue::TIEARRAY = \&BerkeleyDB::Queue::new ; + +## package BerkeleyDB::Text ; +## +## use vars qw(@ISA) ; +## @ISA = qw( BerkeleyDB::Common BerkeleyDB::_tiedArray ) ; +## use UNIVERSAL qw( isa ) ; +## use Carp ; +## +## sub new +## { +## my $self = shift ; +## my $got = BerkeleyDB::ParseParameters( +## { +## # Generic Stuff +## Filename => undef, +## #Flags => BerkeleyDB::DB_CREATE(), +## Flags => 0, +## Property => 0, +## Mode => 0666, +## Cachesize => 0, +## Lorder => 0, +## Pagesize => 0, +## Env => undef, +## #Tie => undef, +## Txn => undef, +## +## # Recno specific +## Delim => undef, +## Len => undef, +## Pad => undef, +## Btree => undef, +## }, @_) ; +## +## croak("Env not of type BerkeleyDB::Env") +## if defined $got->{Env} and ! isa($got->{Env},'BerkeleyDB::Env'); +## +## croak("Txn not of type BerkeleyDB::Txn") +## if defined $got->{Txn} and ! isa($got->{Txn},'BerkeleyDB::Txn'); +## +## croak("-Tie needs a reference to an array") +## if defined $got->{Tie} and $got->{Tie} !~ /ARRAY/ ; +## +## # rearange for recno +## $got->{Source} = $got->{Filename} if defined $got->{Filename} ; +## delete $got->{Filename} ; +## $got->{Fname} = $got->{Btree} if defined $got->{Btree} ; +## return BerkeleyDB::Recno::_db_open_recno($self, $got); +## } +## +## *BerkeleyDB::Text::TIEARRAY = \&BerkeleyDB::Text::new ; +## *BerkeleyDB::Text::db_stat = \&BerkeleyDB::Btree::db_stat ; + +package BerkeleyDB::Unknown ; + +use vars qw(@ISA) ; +@ISA = qw( BerkeleyDB::Common BerkeleyDB::_tiedArray ) ; +use UNIVERSAL qw( isa ) ; +use Carp ; + +sub new +{ + my $self = shift ; + my $got = BerkeleyDB::ParseParameters( + { + # Generic Stuff + Filename => undef, + Subname => undef, + #Flags => BerkeleyDB::DB_CREATE(), + Flags => 0, + Property => 0, + Mode => 0666, + Cachesize => 0, + Lorder => 0, + Pagesize => 0, + Env => undef, + #Tie => undef, + Txn => undef, + + }, @_) ; + + croak("Env not of type BerkeleyDB::Env") + if defined $got->{Env} and ! isa($got->{Env},'BerkeleyDB::Env'); + + croak("Txn not of type BerkeleyDB::Txn") + if defined $got->{Txn} and ! isa($got->{Txn},'BerkeleyDB::Txn'); + + croak("-Tie needs a reference to a hash") + if defined $got->{Tie} and $got->{Tie} !~ /HASH/ ; + + my ($addr, $type) = _db_open_unknown($got); + my $obj ; + if ($addr) { + $obj = bless [$addr], "BerkeleyDB::$type" ; + push @{ $obj }, $got->{Env} if $got->{Env} ; + $obj->Txn($got->{Txn}) if $got->{Txn} ; + } + return $obj ; +} + + +package BerkeleyDB::_tiedHash ; + +use Carp ; + +#sub TIEHASH +#{ +# my $self = shift ; +# my $db_object = shift ; +# +#print "Tiehash REF=[$self] [" . (ref $self) . "]\n" ; +# +# return bless { Obj => $db_object}, $self ; +#} + +sub Tie +{ + # Usage: + # + # $db->Tie \%hash ; + # + + my $self = shift ; + + #print "Tie method REF=[$self] [" . (ref $self) . "]\n" ; + + croak("usage \$x->Tie \\%hash\n") unless @_ ; + my $ref = shift ; + + croak("Tie needs a reference to a hash") + if defined $ref and $ref !~ /HASH/ ; + + #tie %{ $ref }, ref($self), $self ; + tie %{ $ref }, "BerkeleyDB::_tiedHash", $self ; + return undef ; +} + + +sub TIEHASH +{ + my $self = shift ; + my $db_object = shift ; + #return bless $db_object, 'BerkeleyDB::Common' ; + return $db_object ; +} + +sub STORE +{ + my $self = shift ; + my $key = shift ; + my $value = shift ; + + $self->db_put($key, $value) ; +} + +sub FETCH +{ + my $self = shift ; + my $key = shift ; + my $value = undef ; + $self->db_get($key, $value) ; + + return $value ; +} + +sub EXISTS +{ + my $self = shift ; + my $key = shift ; + my $value = undef ; + $self->db_get($key, $value) == 0 ; +} + +sub DELETE +{ + my $self = shift ; + my $key = shift ; + $self->db_del($key) ; +} + +sub CLEAR +{ + my $self = shift ; + my ($key, $value) = (0, 0) ; + my $cursor = $self->db_cursor() ; + while ($cursor->c_get($key, $value, BerkeleyDB::DB_PREV()) == 0) + { $cursor->c_del() } + #1 while $cursor->c_del() == 0 ; + # cursor will self-destruct +} + +#sub DESTROY +#{ +# my $self = shift ; +# print "BerkeleyDB::_tieHash::DESTROY\n" ; +# $self->{Cursor}->c_close() if $self->{Cursor} ; +#} + +package BerkeleyDB::_tiedArray ; + +use Carp ; + +sub Tie +{ + # Usage: + # + # $db->Tie \@array ; + # + + my $self = shift ; + + #print "Tie method REF=[$self] [" . (ref $self) . "]\n" ; + + croak("usage \$x->Tie \\%hash\n") unless @_ ; + my $ref = shift ; + + croak("Tie needs a reference to an array") + if defined $ref and $ref !~ /ARRAY/ ; + + #tie %{ $ref }, ref($self), $self ; + tie @{ $ref }, "BerkeleyDB::_tiedArray", $self ; + return undef ; +} + + +#sub TIEARRAY +#{ +# my $self = shift ; +# my $db_object = shift ; +# +#print "Tiearray REF=[$self] [" . (ref $self) . "]\n" ; +# +# return bless { Obj => $db_object}, $self ; +#} + +sub TIEARRAY +{ + my $self = shift ; + my $db_object = shift ; + #return bless $db_object, 'BerkeleyDB::Common' ; + return $db_object ; +} + +sub STORE +{ + my $self = shift ; + my $key = shift ; + my $value = shift ; + + $self->db_put($key, $value) ; +} + +sub FETCH +{ + my $self = shift ; + my $key = shift ; + my $value = undef ; + $self->db_get($key, $value) ; + + return $value ; +} + +*CLEAR = \&BerkeleyDB::_tiedHash::CLEAR ; +*FIRSTKEY = \&BerkeleyDB::_tiedHash::FIRSTKEY ; +*NEXTKEY = \&BerkeleyDB::_tiedHash::NEXTKEY ; + +sub EXTEND {} # don't do anything with EXTEND + + +sub SHIFT +{ + my $self = shift; + my ($key, $value) = (0, 0) ; + my $cursor = $self->db_cursor() ; + return undef if $cursor->c_get($key, $value, BerkeleyDB::DB_FIRST()) != 0 ; + return undef if $cursor->c_del() != 0 ; + + return $value ; +} + + +sub UNSHIFT +{ + my $self = shift; + croak "unshift is unsupported with Queue databases" + if $self->type == BerkeleyDB::DB_QUEUE() ; + if (@_) + { + my ($key, $value) = (0, 0) ; + my $cursor = $self->db_cursor() ; + if ($cursor->c_get($key, $value, BerkeleyDB::DB_FIRST()) == 0) + { + foreach $value (reverse @_) + { + $key = 0 ; + $cursor->c_put($key, $value, BerkeleyDB::DB_BEFORE()) ; + } + } + } +} + +sub PUSH +{ + my $self = shift; + if (@_) + { + my ($key, $value) = (0, 0) ; + my $cursor = $self->db_cursor() ; + if ($cursor->c_get($key, $value, BerkeleyDB::DB_LAST()) == 0) + { + foreach $value (@_) + { + ++ $key ; + $self->db_put($key, $value) ; + } + } + +# can use this when DB_APPEND is fixed. +# foreach $value (@_) +# { +# my $status = $cursor->c_put($key, $value, BerkeleyDB::DB_AFTER()) ; +#print "[$status]\n" ; +# } + } +} + +sub POP +{ + my $self = shift; + my ($key, $value) = (0, 0) ; + my $cursor = $self->db_cursor() ; + return undef if $cursor->c_get($key, $value, BerkeleyDB::DB_LAST()) != 0 ; + return undef if $cursor->c_del() != 0 ; + + return $value ; +} + +sub SPLICE +{ + my $self = shift; + croak "SPLICE is not implemented yet" ; +} + +*shift = \&SHIFT ; +*unshift = \&UNSHIFT ; +*push = \&PUSH ; +*pop = \&POP ; +*clear = \&CLEAR ; +*length = \&FETCHSIZE ; + +sub STORESIZE +{ + croak "STORESIZE is not implemented yet" ; +#print "STORESIZE @_\n" ; +# my $self = shift; +# my $length = shift ; +# my $current_length = $self->FETCHSIZE() ; +#print "length is $current_length\n"; +# +# if ($length < $current_length) { +#print "Make smaller $length < $current_length\n" ; +# my $key ; +# for ($key = $current_length - 1 ; $key >= $length ; -- $key) +# { $self->db_del($key) } +# } +# elsif ($length > $current_length) { +#print "Make larger $length > $current_length\n" ; +# $self->db_put($length-1, "") ; +# } +# else { print "stay the same\n" } + +} + + + +#sub DESTROY +#{ +# my $self = shift ; +# print "BerkeleyDB::_tieArray::DESTROY\n" ; +#} + + +package BerkeleyDB::Common ; + + +use Carp ; + +sub DESTROY +{ + my $self = shift ; + $self->_DESTROY() ; +} + +sub Txn +{ + my $self = shift ; + my $txn = shift ; + #print "BerkeleyDB::Common::Txn db [$self] txn [$txn]\n" ; + if ($txn) { + $self->_Txn($txn) ; + push @{ $txn }, $self ; + } + else { + $self->_Txn() ; + } + #print "end BerkeleyDB::Common::Txn \n"; +} + + +sub get_dup +{ + croak "Usage: \$db->get_dup(key [,flag])\n" + unless @_ == 2 or @_ == 3 ; + + my $db = shift ; + my $key = shift ; + my $flag = shift ; + my $value = 0 ; + my $origkey = $key ; + my $wantarray = wantarray ; + my %values = () ; + my @values = () ; + my $counter = 0 ; + my $status = 0 ; + my $cursor = $db->db_cursor() ; + + # iterate through the database until either EOF ($status == 0) + # or a different key is encountered ($key ne $origkey). + for ($status = $cursor->c_get($key, $value, BerkeleyDB::DB_SET()) ; + $status == 0 and $key eq $origkey ; + $status = $cursor->c_get($key, $value, BerkeleyDB::DB_NEXT()) ) { + # save the value or count number of matches + if ($wantarray) { + if ($flag) + { ++ $values{$value} } + else + { push (@values, $value) } + } + else + { ++ $counter } + + } + + return ($wantarray ? ($flag ? %values : @values) : $counter) ; +} + +sub db_cursor +{ + my $db = shift ; + my ($addr) = $db->_db_cursor(@_) ; + my $obj ; + $obj = bless [$addr, $db] , "BerkeleyDB::Cursor" if $addr ; + return $obj ; +} + +sub db_join +{ + croak 'Usage: $db->BerkeleyDB::Common::db_join([cursors], flags=0)' + if @_ < 2 || @_ > 3 ; + my $db = shift ; + my ($addr) = $db->_db_join(@_) ; + my $obj ; + $obj = bless [$addr, $db] , "BerkeleyDB::Cursor" if $addr ; + return $obj ; +} + +package BerkeleyDB::Cursor ; + +sub c_close +{ + my $cursor = shift ; + $cursor->[1] = "" ; + return $cursor->_c_close() ; +} + +sub c_dup +{ + my $cursor = shift ; + my ($addr) = $cursor->_c_dup(@_) ; + my $obj ; + $obj = bless [$addr, $cursor->[1]] , "BerkeleyDB::Cursor" if $addr ; + return $obj ; +} + +sub DESTROY +{ + my $self = shift ; + $self->_DESTROY() ; +} + +package BerkeleyDB::TxnMgr ; + +sub DESTROY +{ + my $self = shift ; + $self->_DESTROY() ; +} + +sub txn_begin +{ + my $txnmgr = shift ; + my ($addr) = $txnmgr->_txn_begin(@_) ; + my $obj ; + $obj = bless [$addr, $txnmgr] , "BerkeleyDB::Txn" if $addr ; + return $obj ; +} + +package BerkeleyDB::Txn ; + +sub Txn +{ + my $self = shift ; + my $db ; + # keep a reference to each db in the txn object + foreach $db (@_) { + $db->_Txn($self) ; + push @{ $self}, $db ; + } +} + +sub txn_commit +{ + my $self = shift ; + $self->disassociate() ; + my $status = $self->_txn_commit() ; + return $status ; +} + +sub txn_abort +{ + my $self = shift ; + $self->disassociate() ; + my $status = $self->_txn_abort() ; + return $status ; +} + +sub disassociate +{ + my $self = shift ; + my $db ; + while ( @{ $self } > 2) { + $db = pop @{ $self } ; + $db->Txn() ; + } + #print "end disassociate\n" ; +} + + +sub DESTROY +{ + my $self = shift ; + + $self->disassociate() ; + # first close the close the transaction + $self->_DESTROY() ; +} + +package BerkeleyDB::Term ; + +END +{ + close_everything() ; +} + + +package BerkeleyDB ; + + + +# Autoload methods go after =cut, and are processed by the autosplit program. + +1; +__END__ + + diff --git a/db/perl.BerkeleyDB/BerkeleyDB.pod b/db/perl.BerkeleyDB/BerkeleyDB.pod new file mode 100644 index 000000000..2c5c3feb5 --- /dev/null +++ b/db/perl.BerkeleyDB/BerkeleyDB.pod @@ -0,0 +1,1751 @@ +=head1 NAME + +BerkeleyDB - Perl extension for Berkeley DB version 2 or 3 + +=head1 SYNOPSIS + + use BerkeleyDB; + + $env = new BerkeleyDB::Env [OPTIONS] ; + + $db = tie %hash, 'BerkeleyDB::Hash', [OPTIONS] ; + $db = new BerkeleyDB::Hash [OPTIONS] ; + + $db = tie %hash, 'BerkeleyDB::Btree', [OPTIONS] ; + $db = new BerkeleyDB::Btree [OPTIONS] ; + + $db = tie %hash, 'BerkeleyDB::Recno', [OPTIONS] ; + $db = new BerkeleyDB::Recno [OPTIONS] ; + + $db = tie %hash, 'BerkeleyDB::Queue', [OPTIONS] ; + $db = new BerkeleyDB::Queue [OPTIONS] ; + + $db = new BerkeleyDB::Unknown [OPTIONS] ; + + $status = BerkeleyDB::db_remove [OPTIONS] + + $hash{$key} = $value ; + $value = $hash{$key} ; + each %hash ; + keys %hash ; + values %hash ; + + $status = $db->db_get() + $status = $db->db_put() ; + $status = $db->db_del() ; + $status = $db->db_sync() ; + $status = $db->db_close() ; + $hash_ref = $db->db_stat() ; + $status = $db->db_key_range(); + $type = $db->type() ; + $status = $db->status() ; + $boolean = $db->byteswapped() ; + + ($flag, $old_offset, $old_length) = $db->partial_set($offset, $length) ; + ($flag, $old_offset, $old_length) = $db->partial_clear() ; + + $cursor = $db->db_cursor([$flags]) ; + $newcursor = $cursor->c_dup([$flags]); + $status = $cursor->c_get() ; + $status = $cursor->c_put() ; + $status = $cursor->c_del() ; + $status = $cursor->c_count() ; + $status = $cursor->status() ; + $status = $cursor->c_close() ; + + $cursor = $db->db_join() ; + $status = $cursor->c_get() ; + $status = $cursor->c_close() ; + + $status = $env->txn_checkpoint() + $hash_ref = $env->txn_stat() + $status = $env->setmutexlocks() + + $txn = $env->txn_begin() ; + $status = $txn->txn_prepare() + $status = $txn->txn_commit() + $status = $txn->txn_abort() + $status = $txn->txn_id() + + $BerkeleyDB::Error + $BerkeleyDB::db_version + + # DBM Filters + $old_filter = $db->filter_store_key ( sub { ... } ) ; + $old_filter = $db->filter_store_value( sub { ... } ) ; + $old_filter = $db->filter_fetch_key ( sub { ... } ) ; + $old_filter = $db->filter_fetch_value( sub { ... } ) ; + + # deprecated, but supported + $txn_mgr = $env->TxnMgr(); + $status = $txn_mgr->txn_checkpoint() + $hash_ref = $txn_mgr->txn_stat() + $txn = $txn_mgr->txn_begin() ; + +=head1 DESCRIPTION + +B + +This Perl module provides an interface to most of the functionality +available in Berkeley DB versions 2 and 3. In general it is safe to assume +that the interface provided here to be identical to the Berkeley DB +interface. The main changes have been to make the Berkeley DB API work +in a Perl way. Note that if you are using Berkeley DB 2.x, the new +features available in Berkeley DB 3.x are not available via this module. + +The reader is expected to be familiar with the Berkeley DB +documentation. Where the interface provided here is identical to the +Berkeley DB library and the... TODO + +The B, B, B and B man pages are +particularly relevant. + +The interface to Berkeley DB is implemented with a number of Perl +classes. + +=head1 ENV CLASS + +The B class provides an interface to the Berkeley DB +function B in Berkeley DB 2.x or B and +Bopen> in Berkeley DB 3.x. Its purpose is to initialise a +number of sub-systems that can then be used in a consistent way in all +the databases you make use of the environment. + +If you don't intend using transactions, locking or logging, then you +shouldn't need to make use of B. + +=head2 Synopsis + + $env = new BerkeleyDB::Env + [ -Home => $path, ] + [ -Server => $name, ] + [ -CacheSize => $number, ] + [ -Config => { name => value, name => value }, ] + [ -ErrFile => filename or filehandle, ] + [ -ErrPrefix => "string", ] + [ -Flags => number, ] + [ -LockDetect => number, ] + [ -Verbose => boolean, ] + +=over 5 + +All the parameters to the BerkeleyDB::Env constructor are optional. + +=item -Home + +If present, this parameter should point to an existing directory. Any +files that I specified with an absolute path in the sub-systems +that are initialised by the BerkeleyDB::Env class will be assumed to +live in the B directory. + +For example, in the code fragment below the database "fred.db" will be +opened in the directory "/home/databases" because it was specified as a +relative path, but "joe.db" will be opened in "/other" because it was +part of an absolute path. + + $env = new BerkeleyDB::Env + -Home => "/home/databases" + ... + + $db1 = new BerkeleyDB::Hash + -Filename = "fred.db", + -Env => $env + ... + + $db2 = new BerkeleyDB::Hash + -Filename = "/other/joe.db", + -Env => $env + ... + +=item -Server + +If present, this parameter should be the hostname of a server that is running +the Berkeley DB RPC server. All databases will be accessed via the RPC server. + +=item -Cachesize + +If present, this parameter sets the size of the environments shared memory +buffer pool. + +=item -Config + +This is a variation on the C<-Home> parameter, but it allows finer +control of where specific types of files will be stored. + +The parameter expects a reference to a hash. Valid keys are: +B, B and B + +The code below shows an example of how it can be used. + + $env = new BerkeleyDB::Env + -Config => { DB_DATA_DIR => "/home/databases", + DB_LOG_DIR => "/home/logs", + DB_TMP_DIR => "/home/tmp" + } + ... + +=item -ErrFile + +Expects either the name of a file or a reference to a filehandle. Any +errors generated internally by Berkeley DB will be logged to this file. + +=item -ErrPrefix + +Allows a prefix to be added to the error messages before they are sent +to B<-ErrFile>. + +=item -Flags + +The B parameter specifies both which sub-systems to initialise, +as well as a number of environment-wide options. +See the Berkeley DB documentation for more details of these options. + +Any of the following can be specified by OR'ing them: + +B + +If any of the files specified do not already exist, create them. + +B + +Initialise the Concurrent Access Methods + +B + +Initialise the Locking sub-system. + +B + +Initialise the Logging sub-system. + +B + +Initialise the ... + +B + +Initialise the ... + +B + +Initialise the ... + +B is also specified. + +Initialise the ... + +B + +Initialise the ... + +B + + + +B + +B + +B + +B + +B + +=item -LockDetect + +Specifies what to do when a lock conflict occurs. The value should be one of + +B + +B + +B + +B + +=item -Verbose + +Add extra debugging information to the messages sent to B<-ErrFile>. + +=back + +=head2 Methods + +The environment class has the following methods: + +=over 5 + +=item $env->errPrefix("string") ; + +This method is identical to the B<-ErrPrefix> flag. It allows the +error prefix string to be changed dynamically. + +=item $txn = $env->TxnMgr() + +Constructor for creating a B object. +See L<"TRANSACTIONS"> for more details of using transactions. + +This method is deprecated. Access the transaction methods using the B +methods below from the environment object directly. + +=item $env->txn_begin() + +TODO + +=item $env->txn_stat() + +TODO + +=item $env->txn_checkpoint() + +TODO + +=item $env->status() + +Returns the status of the last BerkeleyDB::Env method. + +=item $env->setmutexlocks() + +Only available in Berkeley Db 3.0 or greater. Calls +B when used with Berkeley DB 3.1.x. When used with +Berkeley DB 3.0 or 3.2 and better it calls Bset_mutexlocks>. + +=back + +=head2 Examples + +TODO. + +=head1 THE DATABASE CLASSES + +B supports the following database formats: + +=over 5 + +=item B + +This database type allows arbitrary key/value pairs to be stored in data +files. This is equivalent to the functionality provided by other +hashing packages like DBM, NDBM, ODBM, GDBM, and SDBM. Remember though, +the files created using B are not compatible with any +of the other packages mentioned. + +A default hashing algorithm, which will be adequate for most applications, +is built into BerkeleyDB. If you do need to use your own hashing algorithm +it is possible to write your own in Perl and have B use +it instead. + +=item B + +The Btree format allows arbitrary key/value pairs to be stored in a +B+tree. + +As with the B format, it is possible to provide a +user defined Perl routine to perform the comparison of keys. By default, +though, the keys are stored in lexical order. + +=item B + +TODO. + + +=item B + +TODO. + +=item B + +This isn't a database format at all. It is used when you want to open an +existing Berkeley DB database without having to know what type is it. + +=back + + +Each of the database formats described above is accessed via a +corresponding B class. These will be described in turn in +the next sections. + +=head1 BerkeleyDB::Hash + +Equivalent to calling B with type B in Berkeley DB 2.x and +calling B followed by Bopen> with type B in +Berkeley DB 3.x. + +Two forms of constructor are supported: + + $db = new BerkeleyDB::Hash + [ -Filename => "filename", ] + [ -Subname => "sub-database name", ] + [ -Flags => flags,] + [ -Property => flags,] + [ -Mode => number,] + [ -Cachesize => number,] + [ -Lorder => number,] + [ -Pagesize => number,] + [ -Env => $env,] + [ -Txn => $txn,] + # BerkeleyDB::Hash specific + [ -Ffactor => number,] + [ -Nelem => number,] + [ -Hash => code reference,] + [ -DupCompare => code reference,] + +and this + + [$db =] tie %hash, 'BerkeleyDB::Hash', + [ -Filename => "filename", ] + [ -Subname => "sub-database name", ] + [ -Flags => flags,] + [ -Property => flags,] + [ -Mode => number,] + [ -Cachesize => number,] + [ -Lorder => number,] + [ -Pagesize => number,] + [ -Env => $env,] + [ -Txn => $txn,] + # BerkeleyDB::Hash specific + [ -Ffactor => number,] + [ -Nelem => number,] + [ -Hash => code reference,] + [ -DupCompare => code reference,] + + +When the "tie" interface is used, reading from and writing to the database +is achieved via the tied hash. In this case the database operates like +a Perl associative array that happens to be stored on disk. + +In addition to the high-level tied hash interface, it is possible to +make use of the underlying methods provided by Berkeley DB + +=head2 Options + +In addition to the standard set of options (see L) +B supports these options: + +=over 5 + +=item -Property + +Used to specify extra flags when opening a database. The following +flags may be specified by logically OR'ing together one or more of the +following values: + +B + +When creating a new database, this flag enables the storing of duplicate +keys in the database. If B is not specified as well, the +duplicates are stored in the order they are created in the database. + +B + +Enables the sorting of duplicate keys in the database. Ignored if +B isn't also specified. + +=item -Ffactor + +=item -Nelem + +See the Berkeley DB documentation for details of these options. + +=item -Hash + +Allows you to provide a user defined hash function. If not specified, +a default hash function is used. Here is a template for a user-defined +hash function + + sub hash + { + my ($data) = shift ; + ... + # return the hash value for $data + return $hash ; + } + + tie %h, "BerkeleyDB::Hash", + -Filename => $filename, + -Hash => \&hash, + ... + +See L<""> for an example. + +=item -DupCompare + +Used in conjunction with the B flag. + + sub compare + { + my ($key, $key2) = @_ ; + ... + # return 0 if $key1 eq $key2 + # -1 if $key1 lt $key2 + # 1 if $key1 gt $key2 + return (-1 , 0 or 1) ; + } + + tie %h, "BerkeleyDB::Hash", + -Filename => $filename, + -Property => DB_DUP|DB_DUPSORT, + -DupCompare => \&compare, + ... + +=back + + +=head2 Methods + +B only supports the standard database methods. +See L. + +=head2 A Simple Tied Hash Example + + use strict ; + use BerkeleyDB ; + use vars qw( %h $k $v ) ; + + my $filename = "fruit" ; + unlink $filename ; + tie %h, "BerkeleyDB::Hash", + -Filename => $filename, + -Flags => DB_CREATE + or die "Cannot open file $filename: $! $BerkeleyDB::Error\n" ; + + # Add a few key/value pairs to the file + $h{"apple"} = "red" ; + $h{"orange"} = "orange" ; + $h{"banana"} = "yellow" ; + $h{"tomato"} = "red" ; + + # Check for existence of a key + print "Banana Exists\n\n" if $h{"banana"} ; + + # Delete a key/value pair. + delete $h{"apple"} ; + + # print the contents of the file + while (($k, $v) = each %h) + { print "$k -> $v\n" } + + untie %h ; + +here is the output: + + Banana Exists + + orange -> orange + tomato -> red + banana -> yellow + +Note that the like ordinary associative arrays, the order of the keys +retrieved from a Hash database are in an apparently random order. + +=head2 Another Simple Hash Example + +Do the same as the previous example but not using tie. + + use strict ; + use BerkeleyDB ; + + my $filename = "fruit" ; + unlink $filename ; + my $db = new BerkeleyDB::Hash + -Filename => $filename, + -Flags => DB_CREATE + or die "Cannot open file $filename: $! $BerkeleyDB::Error\n" ; + + # Add a few key/value pairs to the file + $db->db_put("apple", "red") ; + $db->db_put("orange", "orange") ; + $db->db_put("banana", "yellow") ; + $db->db_put("tomato", "red") ; + + # Check for existence of a key + print "Banana Exists\n\n" if $db->db_get("banana", $v) == 0; + + # Delete a key/value pair. + $db->db_del("apple") ; + + # print the contents of the file + my ($k, $v) = ("", "") ; + my $cursor = $db->db_cursor() ; + while ($cursor->c_get($k, $v, DB_NEXT) == 0) + { print "$k -> $v\n" } + + undef $cursor ; + undef $db ; + +=head2 Duplicate keys + +The code below is a variation on the examples above. This time the hash has +been inverted. The key this time is colour and the value is the fruit name. +The B flag has been specified to allow duplicates. + + use strict ; + use BerkeleyDB ; + + my $filename = "fruit" ; + unlink $filename ; + my $db = new BerkeleyDB::Hash + -Filename => $filename, + -Flags => DB_CREATE, + -Property => DB_DUP + or die "Cannot open file $filename: $! $BerkeleyDB::Error\n" ; + + # Add a few key/value pairs to the file + $db->db_put("red", "apple") ; + $db->db_put("orange", "orange") ; + $db->db_put("green", "banana") ; + $db->db_put("yellow", "banana") ; + $db->db_put("red", "tomato") ; + $db->db_put("green", "apple") ; + + # print the contents of the file + my ($k, $v) = ("", "") ; + my $cursor = $db->db_cursor() ; + while ($cursor->c_get($k, $v, DB_NEXT) == 0) + { print "$k -> $v\n" } + + undef $cursor ; + undef $db ; + +here is the output: + + orange -> orange + yellow -> banana + red -> apple + red -> tomato + green -> banana + green -> apple + +=head2 Sorting Duplicate Keys + +In the previous example, when there were duplicate keys, the values are +sorted in the order they are stored in. The code below is +identical to the previous example except the B flag is +specified. + + use strict ; + use BerkeleyDB ; + + my $filename = "fruit" ; + unlink $filename ; + my $db = new BerkeleyDB::Hash + -Filename => $filename, + -Flags => DB_CREATE, + -Property => DB_DUP | DB_DUPSORT + or die "Cannot open file $filename: $! $BerkeleyDB::Error\n" ; + + # Add a few key/value pairs to the file + $db->db_put("red", "apple") ; + $db->db_put("orange", "orange") ; + $db->db_put("green", "banana") ; + $db->db_put("yellow", "banana") ; + $db->db_put("red", "tomato") ; + $db->db_put("green", "apple") ; + + # print the contents of the file + my ($k, $v) = ("", "") ; + my $cursor = $db->db_cursor() ; + while ($cursor->c_get($k, $v, DB_NEXT) == 0) + { print "$k -> $v\n" } + + undef $cursor ; + undef $db ; + +Notice that in the output below the duplicate values are sorted. + + orange -> orange + yellow -> banana + red -> apple + red -> tomato + green -> apple + green -> banana + +=head2 Custom Sorting Duplicate Keys + +Another variation + +TODO + +=head2 Changing the hash + +TODO + +=head2 Using db_stat + +TODO + +=head1 BerkeleyDB::Btree + +Equivalent to calling B with type B in Berkeley DB 2.x and +calling B followed by Bopen> with type B in +Berkeley DB 3.x. + +Two forms of constructor are supported: + + + $db = new BerkeleyDB::Btree + [ -Filename => "filename", ] + [ -Subname => "sub-database name", ] + [ -Flags => flags,] + [ -Property => flags,] + [ -Mode => number,] + [ -Cachesize => number,] + [ -Lorder => number,] + [ -Pagesize => number,] + [ -Env => $env,] + [ -Txn => $txn,] + # BerkeleyDB::Btree specific + [ -Minkey => number,] + [ -Compare => code reference,] + [ -DupCompare => code reference,] + [ -Prefix => code reference,] + +and this + + [$db =] tie %hash, 'BerkeleyDB::Btree', + [ -Filename => "filename", ] + [ -Subname => "sub-database name", ] + [ -Flags => flags,] + [ -Property => flags,] + [ -Mode => number,] + [ -Cachesize => number,] + [ -Lorder => number,] + [ -Pagesize => number,] + [ -Env => $env,] + [ -Txn => $txn,] + # BerkeleyDB::Btree specific + [ -Minkey => number,] + [ -Compare => code reference,] + [ -DupCompare => code reference,] + [ -Prefix => code reference,] + +=head2 Options + +In addition to the standard set of options (see L) +B supports these options: + +=over 5 + +=item -Property + +Used to specify extra flags when opening a database. The following +flags may be specified by logically OR'ing together one or more of the +following values: + +B + +When creating a new database, this flag enables the storing of duplicate +keys in the database. If B is not specified as well, the +duplicates are stored in the order they are created in the database. + +B + +Enables the sorting of duplicate keys in the database. Ignored if +B isn't also specified. + +=item Minkey + +TODO + +=item Compare + +Allow you to override the default sort order used in the database. See +L<"Changing the sort order"> for an example. + + sub compare + { + my ($key, $key2) = @_ ; + ... + # return 0 if $key1 eq $key2 + # -1 if $key1 lt $key2 + # 1 if $key1 gt $key2 + return (-1 , 0 or 1) ; + } + + tie %h, "BerkeleyDB::Hash", + -Filename => $filename, + -Compare => \&compare, + ... + +=item Prefix + + sub prefix + { + my ($key, $key2) = @_ ; + ... + # return number of bytes of $key2 which are + # necessary to determine that it is greater than $key1 + return $bytes ; + } + + tie %h, "BerkeleyDB::Hash", + -Filename => $filename, + -Prefix => \&prefix, + ... +=item DupCompare + + sub compare + { + my ($key, $key2) = @_ ; + ... + # return 0 if $key1 eq $key2 + # -1 if $key1 lt $key2 + # 1 if $key1 gt $key2 + return (-1 , 0 or 1) ; + } + + tie %h, "BerkeleyDB::Hash", + -Filename => $filename, + -DupCompare => \&compare, + ... + +=back + +=head2 Methods + +B supports the following database methods. +See also L. + +All the methods below return 0 to indicate success. + +=over 5 + +=item $status = $db->db_key_range($key, $less, $equal, $greater [, $flags]) + +Given a key, C<$key>, this method returns the proportion of keys less than +C<$key> in C<$less>, the proportion equal to C<$key> in C<$equal> and the +proportion greater than C<$key> in C<$greater>. + +The proportion is returned as a double in the range 0.0 to 1.0. + +=back + +=head2 A Simple Btree Example + +The code below is a simple example of using a btree database. + + use strict ; + use BerkeleyDB ; + + my $filename = "tree" ; + unlink $filename ; + my %h ; + tie %h, 'BerkeleyDB::Btree', + -Filename => $filename, + -Flags => DB_CREATE + or die "Cannot open $filename: $!\n" ; + + # Add a key/value pair to the file + $h{'Wall'} = 'Larry' ; + $h{'Smith'} = 'John' ; + $h{'mouse'} = 'mickey' ; + $h{'duck'} = 'donald' ; + + # Delete + delete $h{"duck"} ; + + # Cycle through the keys printing them in order. + # Note it is not necessary to sort the keys as + # the btree will have kept them in order automatically. + foreach (keys %h) + { print "$_\n" } + + untie %h ; + +Here is the output from the code above. The keys have been sorted using +Berkeley DB's default sorting algorithm. + + Smith + Wall + mouse + + +=head2 Changing the sort order + +It is possible to supply your own sorting algorithm if the one that Berkeley +DB used isn't suitable. The code below is identical to the previous example +except for the case insensitive compare function. + + use strict ; + use BerkeleyDB ; + + my $filename = "tree" ; + unlink $filename ; + my %h ; + tie %h, 'BerkeleyDB::Btree', + -Filename => $filename, + -Flags => DB_CREATE, + -Compare => sub { lc $_[0] cmp lc $_[1] } + or die "Cannot open $filename: $!\n" ; + + # Add a key/value pair to the file + $h{'Wall'} = 'Larry' ; + $h{'Smith'} = 'John' ; + $h{'mouse'} = 'mickey' ; + $h{'duck'} = 'donald' ; + + # Delete + delete $h{"duck"} ; + + # Cycle through the keys printing them in order. + # Note it is not necessary to sort the keys as + # the btree will have kept them in order automatically. + foreach (keys %h) + { print "$_\n" } + + untie %h ; + +Here is the output from the code above. + + mouse + Smith + Wall + +There are a few point to bear in mind if you want to change the +ordering in a BTREE database: + +=over 5 + +=item 1. + +The new compare function must be specified when you create the database. + +=item 2. + +You cannot change the ordering once the database has been created. Thus +you must use the same compare function every time you access the +database. + +=back + +=head2 Using db_stat + +TODO + +=head1 BerkeleyDB::Recno + +Equivalent to calling B with type B in Berkeley DB 2.x and +calling B followed by Bopen> with type B in +Berkeley DB 3.x. + +Two forms of constructor are supported: + + $db = new BerkeleyDB::Recno + [ -Filename => "filename", ] + [ -Subname => "sub-database name", ] + [ -Flags => flags,] + [ -Property => flags,] + [ -Mode => number,] + [ -Cachesize => number,] + [ -Lorder => number,] + [ -Pagesize => number,] + [ -Env => $env,] + [ -Txn => $txn,] + # BerkeleyDB::Recno specific + [ -Delim => byte,] + [ -Len => number,] + [ -Pad => byte,] + [ -Source => filename,] + +and this + + [$db =] tie @arry, 'BerkeleyDB::Recno', + [ -Filename => "filename", ] + [ -Subname => "sub-database name", ] + [ -Flags => flags,] + [ -Property => flags,] + [ -Mode => number,] + [ -Cachesize => number,] + [ -Lorder => number,] + [ -Pagesize => number,] + [ -Env => $env,] + [ -Txn => $txn,] + # BerkeleyDB::Recno specific + [ -Delim => byte,] + [ -Len => number,] + [ -Pad => byte,] + [ -Source => filename,] + +=head2 A Recno Example + +Here is a simple example that uses RECNO (if you are using a version +of Perl earlier than 5.004_57 this example won't work -- see +L for a workaround). + + use strict ; + use BerkeleyDB ; + + my $filename = "text" ; + unlink $filename ; + + my @h ; + tie @h, 'BerkeleyDB::Recno', + -Filename => $filename, + -Flags => DB_CREATE, + -Property => DB_RENUMBER + or die "Cannot open $filename: $!\n" ; + + # Add a few key/value pairs to the file + $h[0] = "orange" ; + $h[1] = "blue" ; + $h[2] = "yellow" ; + + push @h, "green", "black" ; + + my $elements = scalar @h ; + print "The array contains $elements entries\n" ; + + my $last = pop @h ; + print "popped $last\n" ; + + unshift @h, "white" ; + my $first = shift @h ; + print "shifted $first\n" ; + + # Check for existence of a key + print "Element 1 Exists with value $h[1]\n" if $h[1] ; + + untie @h ; + +Here is the output from the script: + + The array contains 5 entries + popped black + shifted white + Element 1 Exists with value blue + The last element is green + The 2nd last element is yellow + +=head1 BerkeleyDB::Queue + +Equivalent to calling B followed by Bopen> with +type B in Berkeley DB 3.x. This database format isn't available if +you use Berkeley DB 2.x. + +Two forms of constructor are supported: + + $db = new BerkeleyDB::Queue + [ -Filename => "filename", ] + [ -Subname => "sub-database name", ] + [ -Flags => flags,] + [ -Property => flags,] + [ -Mode => number,] + [ -Cachesize => number,] + [ -Lorder => number,] + [ -Pagesize => number,] + [ -Env => $env,] + [ -Txn => $txn,] + # BerkeleyDB::Queue specific + [ -Len => number,] + [ -Pad => byte,] + [ -ExtentSize => number, ] + +and this + + [$db =] tie @arry, 'BerkeleyDB::Queue', + [ -Filename => "filename", ] + [ -Subname => "sub-database name", ] + [ -Flags => flags,] + [ -Property => flags,] + [ -Mode => number,] + [ -Cachesize => number,] + [ -Lorder => number,] + [ -Pagesize => number,] + [ -Env => $env,] + [ -Txn => $txn,] + # BerkeleyDB::Queue specific + [ -Len => number,] + [ -Pad => byte,] + + +=head1 BerkeleyDB::Unknown + +This class is used to open an existing database. + +Equivalent to calling B with type B in Berkeley DB 2.x and +calling B followed by Bopen> with type B in +Berkeley DB 3.x. + +The constructor looks like this: + + $db = new BerkeleyDB::Unknown + [ -Filename => "filename", ] + [ -Subname => "sub-database name", ] + [ -Flags => flags,] + [ -Property => flags,] + [ -Mode => number,] + [ -Cachesize => number,] + [ -Lorder => number,] + [ -Pagesize => number,] + [ -Env => $env,] + [ -Txn => $txn,] + + +=head2 An example + +=head1 COMMON OPTIONS + +All database access class constructors support the common set of +options defined below. All are optional. + +=over 5 + +=item -Filename + +The database filename. If no filename is specified, a temporary file will +be created and removed once the program terminates. + +=item -Subname + +Specifies the name of the sub-database to open. +This option is only valid if you are using Berkeley DB 3.x. + +=item -Flags + +Specify how the database will be opened/created. The valid flags are: + +B + +Create any underlying files, as necessary. If the files do not already +exist and the B flag is not specified, the call will fail. + +B + +Not supported by BerkeleyDB. + +B + +Opens the database in read-only mode. + +B + +Not supported by BerkeleyDB. + +B + +If the database file already exists, remove all the data before +opening it. + +=item -Mode + +Determines the file protection when the database is created. Defaults +to 0666. + +=item -Cachesize + +=item -Lorder + +=item -Pagesize + +=item -Env + +When working under a Berkeley DB environment, this parameter + +Defaults to no environment. + +=item -Txn + +TODO. + +=back + +=head1 COMMON DATABASE METHODS + +All the database interfaces support the common set of methods defined +below. + +All the methods below return 0 to indicate success. + +=head2 $status = $db->db_get($key, $value [, $flags]) + +Given a key (C<$key>) this method reads the value associated with it +from the database. If it exists, the value read from the database is +returned in the C<$value> parameter. + +The B<$flags> parameter is optional. If present, it must be set to B +of the following values: + +=over 5 + +=item B + +When the B flag is specified, B checks for the +existence of B the C<$key> B C<$value> in the database. + +=item B + +TODO. + +=back + +In addition, the following value may be set by logically OR'ing it into +the B<$flags> parameter: + +=over 5 + +=item B + +TODO + +=back + + +=head2 $status = $db->db_put($key, $value [, $flags]) + +Stores a key/value pair in the database. + +The B<$flags> parameter is optional. If present it must be set to B +of the following values: + +=over 5 + +=item B + +This flag is only applicable when accessing a B +database. + +TODO. + + +=item B + +If this flag is specified and C<$key> already exists in the database, +the call to B will return B. + +=back + +=head2 $status = $db->db_del($key [, $flags]) + +Deletes a key/value pair in the database associated with C<$key>. +If duplicate keys are enabled in the database, B will delete +B key/value pairs with key C<$key>. + +The B<$flags> parameter is optional and is currently unused. + +=head2 $status = $db->db_sync() + +If any parts of the database are in memory, write them to the database. + +=head2 $cursor = $db->db_cursor([$flags]) + +Creates a cursor object. This is used to access the contents of the +database sequentially. See L for details of the methods +available when working with cursors. + +The B<$flags> parameter is optional. If present it must be set to B +of the following values: + +=over 5 + +=item B + +TODO. + +=back + +=head2 ($flag, $old_offset, $old_length) = $db->partial_set($offset, $length) ; + +TODO + +=head2 ($flag, $old_offset, $old_length) = $db->partial_clear() ; + +TODO + +=head2 $db->byteswapped() + +TODO + +=head2 $db->type() + +Returns the type of the database. The possible return code are B +for a B database, B for a B +database and B for a B database. This method +is typically used when a database has been opened with +B. + +=item $ref = $db->db_stat() + +Returns a reference to an associative array containing information about +the database. The keys of the associative array correspond directly to the +names of the fields defined in the Berkeley DB documentation. For example, +in the DB documentation, the field B stores the version of the +Btree database. Assuming you called B on a Btree database the +equivalent field would be accessed as follows: + + $version = $ref->{'bt_version'} ; + +If you are using Berkeley DB 3.x, this method will work will all database +formats. When DB 2.x is used, it only works with B. + +=head2 $status = $db->status() + +Returns the status of the last C<$db> method called. + +=head1 CURSORS + +A cursor is used whenever you want to access the contents of a database +in sequential order. +A cursor object is created with the C + +A cursor object has the following methods available: + +=head2 $newcursor = $cursor->c_dup($flags) + +Creates a duplicate of C<$cursor>. This method needs Berkeley DB 3.0.x or better. + +The C<$flags> parameter is optional and can take the following value: + +=over 5 + +=item DB_POSITION + +When present this flag will position the new cursor at the same place as the +existing cursor. + +=back + +=head2 $status = $cursor->c_get($key, $value, $flags) + +Reads a key/value pair from the database, returning the data in C<$key> +and C<$value>. The key/value pair actually read is controlled by the +C<$flags> parameter, which can take B of the following values: + +=over 5 + +=item B + +Set the cursor to point to the first key/value pair in the +database. Return the key/value pair in C<$key> and C<$value>. + +=item B + +Set the cursor to point to the last key/value pair in the database. Return +the key/value pair in C<$key> and C<$value>. + +=item B + +If the cursor is already pointing to a key/value pair, it will be +incremented to point to the next key/value pair and return its contents. + +If the cursor isn't initialised, B works just like B. + +If the cursor is already positioned at the last key/value pair, B +will return B. + +=item B + +This flag is only valid when duplicate keys have been enabled in +a database. +If the cursor is already pointing to a key/value pair and the key of +the next key/value pair is identical, the cursor will be incremented to +point to it and their contents returned. + +=item B + +If the cursor is already pointing to a key/value pair, it will be +decremented to point to the previous key/value pair and return its +contents. + +If the cursor isn't initialised, B works just like B. + +If the cursor is already positioned at the first key/value pair, B +will return B. + +=item B + +If the cursor has been set to point to a key/value pair, return their +contents. +If the key/value pair referenced by the cursor has been deleted, B +will return B. + +=item B + +Set the cursor to point to the key/value pair referenced by B<$key> +and return the value in B<$value>. + +=item B + +This flag is a variation on the B flag. As well as returning +the value, it also returns the key, via B<$key>. +When used with a B database the key matched by B +will be the shortest key (in length) which is greater than or equal to +the key supplied, via B<$key>. This allows partial key searches. +See ??? for an example of how to use this flag. + +=item B + +Another variation on B. This one returns both the key and +the value. + +=item B + +TODO. + +=item B + +TODO. + +=back + +In addition, the following value may be set by logically OR'ing it into +the B<$flags> parameter: + +=over 5 + +=item B + +TODO. + +=back + +=head2 $status = $cursor->c_put($key, $value, $flags) + +Stores the key/value pair in the database. The position that the data is +stored in the database is controlled by the C<$flags> parameter, which +must take B of the following values: + +=over 5 + +=item B + +When used with a Btree or Hash database, a duplicate of the key referenced +by the current cursor position will be created and the contents of +B<$value> will be associated with it - B<$key> is ignored. +The new key/value pair will be stored immediately after the current +cursor position. +Obviously the database has to have been opened with B. + +When used with a Recno ... TODO + + +=item B + +When used with a Btree or Hash database, a duplicate of the key referenced +by the current cursor position will be created and the contents of +B<$value> will be associated with it - B<$key> is ignored. +The new key/value pair will be stored immediately before the current +cursor position. +Obviously the database has to have been opened with B. + +When used with a Recno ... TODO + +=item B + +If the cursor has been initialised, replace the value of the key/value +pair stored in the database with the contents of B<$value>. + +=item B + +Only valid with a Btree or Hash database. This flag is only really +used when duplicates are enabled in the database and sorted duplicates +haven't been specified. +In this case the key/value pair will be inserted as the first entry in +the duplicates for the particular key. + +=item B + +Only valid with a Btree or Hash database. This flag is only really +used when duplicates are enabled in the database and sorted duplicates +haven't been specified. +In this case the key/value pair will be inserted as the last entry in +the duplicates for the particular key. + +=back + +=head2 $status = $cursor->c_del([$flags]) + +This method deletes the key/value pair associated with the current cursor +position. The cursor position will not be changed by this operation, so +any subsequent cursor operation must first initialise the cursor to +point to a valid key/value pair. + +If the key/value pair associated with the cursor have already been +deleted, B will return B. + +The B<$flags> parameter is not used at present. + +=head2 $status = $cursor->c_del($cnt [, $flags]) + +Stores the number of duplicates at the current cursor position in B<$cnt>. + +The B<$flags> parameter is not used at present. This method needs +Berkeley DB 3.1 or better. + +=head2 $status = $cursor->status() + +Returns the status of the last cursor method as a dual type. + +=head2 Cursor Examples + +TODO + +Iterating from first to last, then in reverse. + +examples of each of the flags. + +=head1 JOIN + +Join support for BerkeleyDB is in progress. Watch this space. + +TODO + +=head1 TRANSACTIONS + +TODO. + +=head1 DBM Filters + +A DBM Filter is a piece of code that is be used when you I +want to make the same transformation to all keys and/or values in a DBM +database. All of the database classes (BerkeleyDB::Hash, +BerkeleyDB::Btree and BerkeleyDB::Recno) support DBM Filters. + +There are four methods associated with DBM Filters. All work +identically, and each is used to install (or uninstall) a single DBM +Filter. Each expects a single parameter, namely a reference to a sub. +The only difference between them is the place that the filter is +installed. + +To summarise: + +=over 5 + +=item B + +If a filter has been installed with this method, it will be invoked +every time you write a key to a DBM database. + +=item B + +If a filter has been installed with this method, it will be invoked +every time you write a value to a DBM database. + + +=item B + +If a filter has been installed with this method, it will be invoked +every time you read a key from a DBM database. + +=item B + +If a filter has been installed with this method, it will be invoked +every time you read a value from a DBM database. + +=back + +You can use any combination of the methods, from none, to all four. + +All filter methods return the existing filter, if present, or C +in not. + +To delete a filter pass C to it. + +=head2 The Filter + +When each filter is called by Perl, a local copy of C<$_> will contain +the key or value to be filtered. Filtering is achieved by modifying +the contents of C<$_>. The return code from the filter is ignored. + +=head2 An Example -- the NULL termination problem. + +Consider the following scenario. You have a DBM database that you need +to share with a third-party C application. The C application assumes +that I keys and values are NULL terminated. Unfortunately when +Perl writes to DBM databases it doesn't use NULL termination, so your +Perl application will have to manage NULL termination itself. When you +write to the database you will have to use something like this: + + $hash{"$key\0"} = "$value\0" ; + +Similarly the NULL needs to be taken into account when you are considering +the length of existing keys/values. + +It would be much better if you could ignore the NULL terminations issue +in the main application code and have a mechanism that automatically +added the terminating NULL to all keys and values whenever you write to +the database and have them removed when you read from the database. As I'm +sure you have already guessed, this is a problem that DBM Filters can +fix very easily. + + use strict ; + use BerkeleyDB ; + + my %hash ; + my $filename = "filt.db" ; + unlink $filename ; + + my $db = tie %hash, 'BerkeleyDB::Hash', + -Filename => $filename, + -Flags => DB_CREATE + or die "Cannot open $filename: $!\n" ; + + # Install DBM Filters + $db->filter_fetch_key ( sub { s/\0$// } ) ; + $db->filter_store_key ( sub { $_ .= "\0" } ) ; + $db->filter_fetch_value( sub { s/\0$// } ) ; + $db->filter_store_value( sub { $_ .= "\0" } ) ; + + $hash{"abc"} = "def" ; + my $a = $hash{"ABC"} ; + # ... + undef $db ; + untie %hash ; + +Hopefully the contents of each of the filters should be +self-explanatory. Both "fetch" filters remove the terminating NULL, +and both "store" filters add a terminating NULL. + + +=head2 Another Example -- Key is a C int. + +Here is another real-life example. By default, whenever Perl writes to +a DBM database it always writes the key and value as strings. So when +you use this: + + $hash{12345} = "something" ; + +the key 12345 will get stored in the DBM database as the 5 byte string +"12345". If you actually want the key to be stored in the DBM database +as a C int, you will have to use C when writing, and C +when reading. + +Here is a DBM Filter that does it: + + use strict ; + use BerkeleyDB ; + my %hash ; + my $filename = "filt.db" ; + unlink $filename ; + + + my $db = tie %hash, 'BerkeleyDB::Btree', + -Filename => $filename, + -Flags => DB_CREATE + or die "Cannot open $filename: $!\n" ; + + $db->filter_fetch_key ( sub { $_ = unpack("i", $_) } ) ; + $db->filter_store_key ( sub { $_ = pack ("i", $_) } ) ; + $hash{123} = "def" ; + # ... + undef $db ; + untie %hash ; + +This time only two filters have been used -- we only need to manipulate +the contents of the key, so it wasn't necessary to install any value +filters. + +=head1 Using BerkeleyDB with MLDBM + +Both BerkeleyDB::Hash and BerkeleyDB::Btree can be used with the MLDBM +module. The code fragment below shows how to open associate MLDBM with +BerkeleyDB::Btree. To use BerkeleyDB::Hash just replace +BerkeleyDB::Btree with BerkeleyDB::Hash. + + use strict ; + use BerkeleyDB ; + use MLDBM qw(BerkeleyDB::Btree) ; + use Data::Dumper; + + my $filename = 'testmldbm' ; + my %o ; + + unlink $filename ; + tie %o, 'MLDBM', -Filename => $filename, + -Flags => DB_CREATE + or die "Cannot open database '$filename: $!\n"; + +See the MLDBM documentation for information on how to use the module +and for details of its limitations. + +=head1 EXAMPLES + +TODO. + +=head1 HINTS & TIPS + +=head2 Sharing Databases With C Applications + +There is no technical reason why a Berkeley DB database cannot be +shared by both a Perl and a C application. + +The vast majority of problems that are reported in this area boil down +to the fact that C strings are NULL terminated, whilst Perl strings +are not. See L in the DBM +FILTERS section for a generic way to work around this problem. + + +=head2 The untie Gotcha + +TODO + +=head1 COMMON QUESTIONS + +This section attempts to answer some of the more common questions that +I get asked. + + +=head2 Relationship with DB_File + +Before Berkeley DB 2.x was written there was only one Perl module that +interfaced to Berkeley DB. That module is called B. Although +B can be build with Berkeley DB 1.x, 2.x or 3.x, it only provides +an interface to the functionality available in Berkeley DB 1.x. That +means that it doesn't support transactions, locking or any of the other +new features available in DB 2.x or 3.x. + +=head2 How do I store Perl data structures with BerkeleyDB? + +See L. + +=head1 HISTORY + +See the Changes file. + +=head1 AVAILABILITY + +The most recent version of B can always be found +on CPAN (see L for details), in the directory +F. + +The official web site for Berkeley DB is F. + +=head1 COPYRIGHT + +Copyright (c) 1997-2001 Paul Marquess. All rights reserved. This program +is free software; you can redistribute it and/or modify it under the +same terms as Perl itself. + +Although B is covered by the Perl license, the library it +makes use of, namely Berkeley DB, is not. Berkeley DB has its own +copyright and its own license. Please take the time to read it. + +Here are few words taken from the Berkeley DB FAQ (at +F) regarding the license: + + Do I have to license DB to use it in Perl scripts? + + No. The Berkeley DB license requires that software that uses + Berkeley DB be freely redistributable. In the case of Perl, that + software is Perl, and not your scripts. Any Perl scripts that you + write are your property, including scripts that make use of Berkeley + DB. Neither the Perl license nor the Berkeley DB license + place any restriction on what you may do with them. + +If you are in any doubt about the license situation, contact either the +Berkeley DB authors or the author of BerkeleyDB. +See L<"AUTHOR"> for details. + + +=head1 AUTHOR + +Paul Marquess EPaul.Marquess@btinternet.comE. + +Questions about Berkeley DB may be addressed to Edb@sleepycat.comE. + +=head1 SEE ALSO + +perl(1), DB_File, Berkeley DB. + +=cut diff --git a/db/perl.BerkeleyDB/BerkeleyDB.pod.P b/db/perl.BerkeleyDB/BerkeleyDB.pod.P new file mode 100644 index 000000000..2bcff2d99 --- /dev/null +++ b/db/perl.BerkeleyDB/BerkeleyDB.pod.P @@ -0,0 +1,1518 @@ +=head1 NAME + +BerkeleyDB - Perl extension for Berkeley DB version 2 or 3 + +=head1 SYNOPSIS + + use BerkeleyDB; + + $env = new BerkeleyDB::Env [OPTIONS] ; + + $db = tie %hash, 'BerkeleyDB::Hash', [OPTIONS] ; + $db = new BerkeleyDB::Hash [OPTIONS] ; + + $db = tie %hash, 'BerkeleyDB::Btree', [OPTIONS] ; + $db = new BerkeleyDB::Btree [OPTIONS] ; + + $db = tie %hash, 'BerkeleyDB::Recno', [OPTIONS] ; + $db = new BerkeleyDB::Recno [OPTIONS] ; + + $db = tie %hash, 'BerkeleyDB::Queue', [OPTIONS] ; + $db = new BerkeleyDB::Queue [OPTIONS] ; + + $db = new BerkeleyDB::Unknown [OPTIONS] ; + + $status = BerkeleyDB::db_remove [OPTIONS] + + $hash{$key} = $value ; + $value = $hash{$key} ; + each %hash ; + keys %hash ; + values %hash ; + + $status = $db->db_get() + $status = $db->db_put() ; + $status = $db->db_del() ; + $status = $db->db_sync() ; + $status = $db->db_close() ; + $hash_ref = $db->db_stat() ; + $status = $db->db_key_range(); + $type = $db->type() ; + $status = $db->status() ; + $boolean = $db->byteswapped() ; + + ($flag, $old_offset, $old_length) = $db->partial_set($offset, $length) ; + ($flag, $old_offset, $old_length) = $db->partial_clear() ; + + $cursor = $db->db_cursor([$flags]) ; + $newcursor = $cursor->c_dup([$flags]); + $status = $cursor->c_get() ; + $status = $cursor->c_put() ; + $status = $cursor->c_del() ; + $status = $cursor->c_count() ; + $status = $cursor->status() ; + $status = $cursor->c_close() ; + + $cursor = $db->db_join() ; + $status = $cursor->c_get() ; + $status = $cursor->c_close() ; + + $status = $env->txn_checkpoint() + $hash_ref = $env->txn_stat() + $status = $env->setmutexlocks() + + $txn = $env->txn_begin() ; + $status = $txn->txn_prepare() + $status = $txn->txn_commit() + $status = $txn->txn_abort() + $status = $txn->txn_id() + + $BerkeleyDB::Error + $BerkeleyDB::db_version + + # DBM Filters + $old_filter = $db->filter_store_key ( sub { ... } ) ; + $old_filter = $db->filter_store_value( sub { ... } ) ; + $old_filter = $db->filter_fetch_key ( sub { ... } ) ; + $old_filter = $db->filter_fetch_value( sub { ... } ) ; + + # deprecated, but supported + $txn_mgr = $env->TxnMgr(); + $status = $txn_mgr->txn_checkpoint() + $hash_ref = $txn_mgr->txn_stat() + $txn = $txn_mgr->txn_begin() ; + +=head1 DESCRIPTION + +B + +This Perl module provides an interface to most of the functionality +available in Berkeley DB versions 2 and 3. In general it is safe to assume +that the interface provided here to be identical to the Berkeley DB +interface. The main changes have been to make the Berkeley DB API work +in a Perl way. Note that if you are using Berkeley DB 2.x, the new +features available in Berkeley DB 3.x are not available via this module. + +The reader is expected to be familiar with the Berkeley DB +documentation. Where the interface provided here is identical to the +Berkeley DB library and the... TODO + +The B, B, B and B man pages are +particularly relevant. + +The interface to Berkeley DB is implemented with a number of Perl +classes. + +=head1 ENV CLASS + +The B class provides an interface to the Berkeley DB +function B in Berkeley DB 2.x or B and +Bopen> in Berkeley DB 3.x. Its purpose is to initialise a +number of sub-systems that can then be used in a consistent way in all +the databases you make use of the environment. + +If you don't intend using transactions, locking or logging, then you +shouldn't need to make use of B. + +=head2 Synopsis + + $env = new BerkeleyDB::Env + [ -Home => $path, ] + [ -Server => $name, ] + [ -CacheSize => $number, ] + [ -Config => { name => value, name => value }, ] + [ -ErrFile => filename or filehandle, ] + [ -ErrPrefix => "string", ] + [ -Flags => number, ] + [ -LockDetect => number, ] + [ -Verbose => boolean, ] + +=over 5 + +All the parameters to the BerkeleyDB::Env constructor are optional. + +=item -Home + +If present, this parameter should point to an existing directory. Any +files that I specified with an absolute path in the sub-systems +that are initialised by the BerkeleyDB::Env class will be assumed to +live in the B directory. + +For example, in the code fragment below the database "fred.db" will be +opened in the directory "/home/databases" because it was specified as a +relative path, but "joe.db" will be opened in "/other" because it was +part of an absolute path. + + $env = new BerkeleyDB::Env + -Home => "/home/databases" + ... + + $db1 = new BerkeleyDB::Hash + -Filename = "fred.db", + -Env => $env + ... + + $db2 = new BerkeleyDB::Hash + -Filename = "/other/joe.db", + -Env => $env + ... + +=item -Server + +If present, this parameter should be the hostname of a server that is running +the Berkeley DB RPC server. All databases will be accessed via the RPC server. + +=item -Cachesize + +If present, this parameter sets the size of the environments shared memory +buffer pool. + +=item -Config + +This is a variation on the C<-Home> parameter, but it allows finer +control of where specific types of files will be stored. + +The parameter expects a reference to a hash. Valid keys are: +B, B and B + +The code below shows an example of how it can be used. + + $env = new BerkeleyDB::Env + -Config => { DB_DATA_DIR => "/home/databases", + DB_LOG_DIR => "/home/logs", + DB_TMP_DIR => "/home/tmp" + } + ... + +=item -ErrFile + +Expects either the name of a file or a reference to a filehandle. Any +errors generated internally by Berkeley DB will be logged to this file. + +=item -ErrPrefix + +Allows a prefix to be added to the error messages before they are sent +to B<-ErrFile>. + +=item -Flags + +The B parameter specifies both which sub-systems to initialise, +as well as a number of environment-wide options. +See the Berkeley DB documentation for more details of these options. + +Any of the following can be specified by OR'ing them: + +B + +If any of the files specified do not already exist, create them. + +B + +Initialise the Concurrent Access Methods + +B + +Initialise the Locking sub-system. + +B + +Initialise the Logging sub-system. + +B + +Initialise the ... + +B + +Initialise the ... + +B + +Initialise the ... + +B is also specified. + +Initialise the ... + +B + +Initialise the ... + +B + + + +B + +B + +B + +B + +B + +=item -LockDetect + +Specifies what to do when a lock conflict occurs. The value should be one of + +B + +B + +B + +B + +=item -Verbose + +Add extra debugging information to the messages sent to B<-ErrFile>. + +=back + +=head2 Methods + +The environment class has the following methods: + +=over 5 + +=item $env->errPrefix("string") ; + +This method is identical to the B<-ErrPrefix> flag. It allows the +error prefix string to be changed dynamically. + +=item $txn = $env->TxnMgr() + +Constructor for creating a B object. +See L<"TRANSACTIONS"> for more details of using transactions. + +This method is deprecated. Access the transaction methods using the B +methods below from the environment object directly. + +=item $env->txn_begin() + +TODO + +=item $env->txn_stat() + +TODO + +=item $env->txn_checkpoint() + +TODO + +=item $env->status() + +Returns the status of the last BerkeleyDB::Env method. + +=item $env->setmutexlocks() + +Only available in Berkeley Db 3.0 or greater. Calls +B when used with Berkeley DB 3.1.x. When used with +Berkeley DB 3.0 or 3.2 and better it calls Bset_mutexlocks>. + +=back + +=head2 Examples + +TODO. + +=head1 THE DATABASE CLASSES + +B supports the following database formats: + +=over 5 + +=item B + +This database type allows arbitrary key/value pairs to be stored in data +files. This is equivalent to the functionality provided by other +hashing packages like DBM, NDBM, ODBM, GDBM, and SDBM. Remember though, +the files created using B are not compatible with any +of the other packages mentioned. + +A default hashing algorithm, which will be adequate for most applications, +is built into BerkeleyDB. If you do need to use your own hashing algorithm +it is possible to write your own in Perl and have B use +it instead. + +=item B + +The Btree format allows arbitrary key/value pairs to be stored in a +B+tree. + +As with the B format, it is possible to provide a +user defined Perl routine to perform the comparison of keys. By default, +though, the keys are stored in lexical order. + +=item B + +TODO. + + +=item B + +TODO. + +=item B + +This isn't a database format at all. It is used when you want to open an +existing Berkeley DB database without having to know what type is it. + +=back + + +Each of the database formats described above is accessed via a +corresponding B class. These will be described in turn in +the next sections. + +=head1 BerkeleyDB::Hash + +Equivalent to calling B with type B in Berkeley DB 2.x and +calling B followed by Bopen> with type B in +Berkeley DB 3.x. + +Two forms of constructor are supported: + + $db = new BerkeleyDB::Hash + [ -Filename => "filename", ] + [ -Subname => "sub-database name", ] + [ -Flags => flags,] + [ -Property => flags,] + [ -Mode => number,] + [ -Cachesize => number,] + [ -Lorder => number,] + [ -Pagesize => number,] + [ -Env => $env,] + [ -Txn => $txn,] + # BerkeleyDB::Hash specific + [ -Ffactor => number,] + [ -Nelem => number,] + [ -Hash => code reference,] + [ -DupCompare => code reference,] + +and this + + [$db =] tie %hash, 'BerkeleyDB::Hash', + [ -Filename => "filename", ] + [ -Subname => "sub-database name", ] + [ -Flags => flags,] + [ -Property => flags,] + [ -Mode => number,] + [ -Cachesize => number,] + [ -Lorder => number,] + [ -Pagesize => number,] + [ -Env => $env,] + [ -Txn => $txn,] + # BerkeleyDB::Hash specific + [ -Ffactor => number,] + [ -Nelem => number,] + [ -Hash => code reference,] + [ -DupCompare => code reference,] + + +When the "tie" interface is used, reading from and writing to the database +is achieved via the tied hash. In this case the database operates like +a Perl associative array that happens to be stored on disk. + +In addition to the high-level tied hash interface, it is possible to +make use of the underlying methods provided by Berkeley DB + +=head2 Options + +In addition to the standard set of options (see L) +B supports these options: + +=over 5 + +=item -Property + +Used to specify extra flags when opening a database. The following +flags may be specified by logically OR'ing together one or more of the +following values: + +B + +When creating a new database, this flag enables the storing of duplicate +keys in the database. If B is not specified as well, the +duplicates are stored in the order they are created in the database. + +B + +Enables the sorting of duplicate keys in the database. Ignored if +B isn't also specified. + +=item -Ffactor + +=item -Nelem + +See the Berkeley DB documentation for details of these options. + +=item -Hash + +Allows you to provide a user defined hash function. If not specified, +a default hash function is used. Here is a template for a user-defined +hash function + + sub hash + { + my ($data) = shift ; + ... + # return the hash value for $data + return $hash ; + } + + tie %h, "BerkeleyDB::Hash", + -Filename => $filename, + -Hash => \&hash, + ... + +See L<""> for an example. + +=item -DupCompare + +Used in conjunction with the B flag. + + sub compare + { + my ($key, $key2) = @_ ; + ... + # return 0 if $key1 eq $key2 + # -1 if $key1 lt $key2 + # 1 if $key1 gt $key2 + return (-1 , 0 or 1) ; + } + + tie %h, "BerkeleyDB::Hash", + -Filename => $filename, + -Property => DB_DUP|DB_DUPSORT, + -DupCompare => \&compare, + ... + +=back + + +=head2 Methods + +B only supports the standard database methods. +See L. + +=head2 A Simple Tied Hash Example + +## simpleHash + +here is the output: + + Banana Exists + + orange -> orange + tomato -> red + banana -> yellow + +Note that the like ordinary associative arrays, the order of the keys +retrieved from a Hash database are in an apparently random order. + +=head2 Another Simple Hash Example + +Do the same as the previous example but not using tie. + +## simpleHash2 + +=head2 Duplicate keys + +The code below is a variation on the examples above. This time the hash has +been inverted. The key this time is colour and the value is the fruit name. +The B flag has been specified to allow duplicates. + +##dupHash + +here is the output: + + orange -> orange + yellow -> banana + red -> apple + red -> tomato + green -> banana + green -> apple + +=head2 Sorting Duplicate Keys + +In the previous example, when there were duplicate keys, the values are +sorted in the order they are stored in. The code below is +identical to the previous example except the B flag is +specified. + +##dupSortHash + +Notice that in the output below the duplicate values are sorted. + + orange -> orange + yellow -> banana + red -> apple + red -> tomato + green -> apple + green -> banana + +=head2 Custom Sorting Duplicate Keys + +Another variation + +TODO + +=head2 Changing the hash + +TODO + +=head2 Using db_stat + +TODO + +=head1 BerkeleyDB::Btree + +Equivalent to calling B with type B in Berkeley DB 2.x and +calling B followed by Bopen> with type B in +Berkeley DB 3.x. + +Two forms of constructor are supported: + + + $db = new BerkeleyDB::Btree + [ -Filename => "filename", ] + [ -Subname => "sub-database name", ] + [ -Flags => flags,] + [ -Property => flags,] + [ -Mode => number,] + [ -Cachesize => number,] + [ -Lorder => number,] + [ -Pagesize => number,] + [ -Env => $env,] + [ -Txn => $txn,] + # BerkeleyDB::Btree specific + [ -Minkey => number,] + [ -Compare => code reference,] + [ -DupCompare => code reference,] + [ -Prefix => code reference,] + +and this + + [$db =] tie %hash, 'BerkeleyDB::Btree', + [ -Filename => "filename", ] + [ -Subname => "sub-database name", ] + [ -Flags => flags,] + [ -Property => flags,] + [ -Mode => number,] + [ -Cachesize => number,] + [ -Lorder => number,] + [ -Pagesize => number,] + [ -Env => $env,] + [ -Txn => $txn,] + # BerkeleyDB::Btree specific + [ -Minkey => number,] + [ -Compare => code reference,] + [ -DupCompare => code reference,] + [ -Prefix => code reference,] + +=head2 Options + +In addition to the standard set of options (see L) +B supports these options: + +=over 5 + +=item -Property + +Used to specify extra flags when opening a database. The following +flags may be specified by logically OR'ing together one or more of the +following values: + +B + +When creating a new database, this flag enables the storing of duplicate +keys in the database. If B is not specified as well, the +duplicates are stored in the order they are created in the database. + +B + +Enables the sorting of duplicate keys in the database. Ignored if +B isn't also specified. + +=item Minkey + +TODO + +=item Compare + +Allow you to override the default sort order used in the database. See +L<"Changing the sort order"> for an example. + + sub compare + { + my ($key, $key2) = @_ ; + ... + # return 0 if $key1 eq $key2 + # -1 if $key1 lt $key2 + # 1 if $key1 gt $key2 + return (-1 , 0 or 1) ; + } + + tie %h, "BerkeleyDB::Hash", + -Filename => $filename, + -Compare => \&compare, + ... + +=item Prefix + + sub prefix + { + my ($key, $key2) = @_ ; + ... + # return number of bytes of $key2 which are + # necessary to determine that it is greater than $key1 + return $bytes ; + } + + tie %h, "BerkeleyDB::Hash", + -Filename => $filename, + -Prefix => \&prefix, + ... +=item DupCompare + + sub compare + { + my ($key, $key2) = @_ ; + ... + # return 0 if $key1 eq $key2 + # -1 if $key1 lt $key2 + # 1 if $key1 gt $key2 + return (-1 , 0 or 1) ; + } + + tie %h, "BerkeleyDB::Hash", + -Filename => $filename, + -DupCompare => \&compare, + ... + +=back + +=head2 Methods + +B supports the following database methods. +See also L. + +All the methods below return 0 to indicate success. + +=over 5 + +=item $status = $db->db_key_range($key, $less, $equal, $greater [, $flags]) + +Given a key, C<$key>, this method returns the proportion of keys less than +C<$key> in C<$less>, the proportion equal to C<$key> in C<$equal> and the +proportion greater than C<$key> in C<$greater>. + +The proportion is returned as a double in the range 0.0 to 1.0. + +=back + +=head2 A Simple Btree Example + +The code below is a simple example of using a btree database. + +## btreeSimple + +Here is the output from the code above. The keys have been sorted using +Berkeley DB's default sorting algorithm. + + Smith + Wall + mouse + + +=head2 Changing the sort order + +It is possible to supply your own sorting algorithm if the one that Berkeley +DB used isn't suitable. The code below is identical to the previous example +except for the case insensitive compare function. + +## btreeSortOrder + +Here is the output from the code above. + + mouse + Smith + Wall + +There are a few point to bear in mind if you want to change the +ordering in a BTREE database: + +=over 5 + +=item 1. + +The new compare function must be specified when you create the database. + +=item 2. + +You cannot change the ordering once the database has been created. Thus +you must use the same compare function every time you access the +database. + +=back + +=head2 Using db_stat + +TODO + +=head1 BerkeleyDB::Recno + +Equivalent to calling B with type B in Berkeley DB 2.x and +calling B followed by Bopen> with type B in +Berkeley DB 3.x. + +Two forms of constructor are supported: + + $db = new BerkeleyDB::Recno + [ -Filename => "filename", ] + [ -Subname => "sub-database name", ] + [ -Flags => flags,] + [ -Property => flags,] + [ -Mode => number,] + [ -Cachesize => number,] + [ -Lorder => number,] + [ -Pagesize => number,] + [ -Env => $env,] + [ -Txn => $txn,] + # BerkeleyDB::Recno specific + [ -Delim => byte,] + [ -Len => number,] + [ -Pad => byte,] + [ -Source => filename,] + +and this + + [$db =] tie @arry, 'BerkeleyDB::Recno', + [ -Filename => "filename", ] + [ -Subname => "sub-database name", ] + [ -Flags => flags,] + [ -Property => flags,] + [ -Mode => number,] + [ -Cachesize => number,] + [ -Lorder => number,] + [ -Pagesize => number,] + [ -Env => $env,] + [ -Txn => $txn,] + # BerkeleyDB::Recno specific + [ -Delim => byte,] + [ -Len => number,] + [ -Pad => byte,] + [ -Source => filename,] + +=head2 A Recno Example + +Here is a simple example that uses RECNO (if you are using a version +of Perl earlier than 5.004_57 this example won't work -- see +L for a workaround). + +## simpleRecno + +Here is the output from the script: + + The array contains 5 entries + popped black + shifted white + Element 1 Exists with value blue + The last element is green + The 2nd last element is yellow + +=head1 BerkeleyDB::Queue + +Equivalent to calling B followed by Bopen> with +type B in Berkeley DB 3.x. This database format isn't available if +you use Berkeley DB 2.x. + +Two forms of constructor are supported: + + $db = new BerkeleyDB::Queue + [ -Filename => "filename", ] + [ -Subname => "sub-database name", ] + [ -Flags => flags,] + [ -Property => flags,] + [ -Mode => number,] + [ -Cachesize => number,] + [ -Lorder => number,] + [ -Pagesize => number,] + [ -Env => $env,] + [ -Txn => $txn,] + # BerkeleyDB::Queue specific + [ -Len => number,] + [ -Pad => byte,] + [ -ExtentSize => number, ] + +and this + + [$db =] tie @arry, 'BerkeleyDB::Queue', + [ -Filename => "filename", ] + [ -Subname => "sub-database name", ] + [ -Flags => flags,] + [ -Property => flags,] + [ -Mode => number,] + [ -Cachesize => number,] + [ -Lorder => number,] + [ -Pagesize => number,] + [ -Env => $env,] + [ -Txn => $txn,] + # BerkeleyDB::Queue specific + [ -Len => number,] + [ -Pad => byte,] + + +=head1 BerkeleyDB::Unknown + +This class is used to open an existing database. + +Equivalent to calling B with type B in Berkeley DB 2.x and +calling B followed by Bopen> with type B in +Berkeley DB 3.x. + +The constructor looks like this: + + $db = new BerkeleyDB::Unknown + [ -Filename => "filename", ] + [ -Subname => "sub-database name", ] + [ -Flags => flags,] + [ -Property => flags,] + [ -Mode => number,] + [ -Cachesize => number,] + [ -Lorder => number,] + [ -Pagesize => number,] + [ -Env => $env,] + [ -Txn => $txn,] + + +=head2 An example + +=head1 COMMON OPTIONS + +All database access class constructors support the common set of +options defined below. All are optional. + +=over 5 + +=item -Filename + +The database filename. If no filename is specified, a temporary file will +be created and removed once the program terminates. + +=item -Subname + +Specifies the name of the sub-database to open. +This option is only valid if you are using Berkeley DB 3.x. + +=item -Flags + +Specify how the database will be opened/created. The valid flags are: + +B + +Create any underlying files, as necessary. If the files do not already +exist and the B flag is not specified, the call will fail. + +B + +Not supported by BerkeleyDB. + +B + +Opens the database in read-only mode. + +B + +Not supported by BerkeleyDB. + +B + +If the database file already exists, remove all the data before +opening it. + +=item -Mode + +Determines the file protection when the database is created. Defaults +to 0666. + +=item -Cachesize + +=item -Lorder + +=item -Pagesize + +=item -Env + +When working under a Berkeley DB environment, this parameter + +Defaults to no environment. + +=item -Txn + +TODO. + +=back + +=head1 COMMON DATABASE METHODS + +All the database interfaces support the common set of methods defined +below. + +All the methods below return 0 to indicate success. + +=head2 $status = $db->db_get($key, $value [, $flags]) + +Given a key (C<$key>) this method reads the value associated with it +from the database. If it exists, the value read from the database is +returned in the C<$value> parameter. + +The B<$flags> parameter is optional. If present, it must be set to B +of the following values: + +=over 5 + +=item B + +When the B flag is specified, B checks for the +existence of B the C<$key> B C<$value> in the database. + +=item B + +TODO. + +=back + +In addition, the following value may be set by logically OR'ing it into +the B<$flags> parameter: + +=over 5 + +=item B + +TODO + +=back + + +=head2 $status = $db->db_put($key, $value [, $flags]) + +Stores a key/value pair in the database. + +The B<$flags> parameter is optional. If present it must be set to B +of the following values: + +=over 5 + +=item B + +This flag is only applicable when accessing a B +database. + +TODO. + + +=item B + +If this flag is specified and C<$key> already exists in the database, +the call to B will return B. + +=back + +=head2 $status = $db->db_del($key [, $flags]) + +Deletes a key/value pair in the database associated with C<$key>. +If duplicate keys are enabled in the database, B will delete +B key/value pairs with key C<$key>. + +The B<$flags> parameter is optional and is currently unused. + +=head2 $status = $db->db_sync() + +If any parts of the database are in memory, write them to the database. + +=head2 $cursor = $db->db_cursor([$flags]) + +Creates a cursor object. This is used to access the contents of the +database sequentially. See L for details of the methods +available when working with cursors. + +The B<$flags> parameter is optional. If present it must be set to B +of the following values: + +=over 5 + +=item B + +TODO. + +=back + +=head2 ($flag, $old_offset, $old_length) = $db->partial_set($offset, $length) ; + +TODO + +=head2 ($flag, $old_offset, $old_length) = $db->partial_clear() ; + +TODO + +=head2 $db->byteswapped() + +TODO + +=head2 $db->type() + +Returns the type of the database. The possible return code are B +for a B database, B for a B +database and B for a B database. This method +is typically used when a database has been opened with +B. + +=item $ref = $db->db_stat() + +Returns a reference to an associative array containing information about +the database. The keys of the associative array correspond directly to the +names of the fields defined in the Berkeley DB documentation. For example, +in the DB documentation, the field B stores the version of the +Btree database. Assuming you called B on a Btree database the +equivalent field would be accessed as follows: + + $version = $ref->{'bt_version'} ; + +If you are using Berkeley DB 3.x, this method will work will all database +formats. When DB 2.x is used, it only works with B. + +=head2 $status = $db->status() + +Returns the status of the last C<$db> method called. + +=head1 CURSORS + +A cursor is used whenever you want to access the contents of a database +in sequential order. +A cursor object is created with the C + +A cursor object has the following methods available: + +=head2 $newcursor = $cursor->c_dup($flags) + +Creates a duplicate of C<$cursor>. This method needs Berkeley DB 3.0.x or better. + +The C<$flags> parameter is optional and can take the following value: + +=over 5 + +=item DB_POSITION + +When present this flag will position the new cursor at the same place as the +existing cursor. + +=back + +=head2 $status = $cursor->c_get($key, $value, $flags) + +Reads a key/value pair from the database, returning the data in C<$key> +and C<$value>. The key/value pair actually read is controlled by the +C<$flags> parameter, which can take B of the following values: + +=over 5 + +=item B + +Set the cursor to point to the first key/value pair in the +database. Return the key/value pair in C<$key> and C<$value>. + +=item B + +Set the cursor to point to the last key/value pair in the database. Return +the key/value pair in C<$key> and C<$value>. + +=item B + +If the cursor is already pointing to a key/value pair, it will be +incremented to point to the next key/value pair and return its contents. + +If the cursor isn't initialised, B works just like B. + +If the cursor is already positioned at the last key/value pair, B +will return B. + +=item B + +This flag is only valid when duplicate keys have been enabled in +a database. +If the cursor is already pointing to a key/value pair and the key of +the next key/value pair is identical, the cursor will be incremented to +point to it and their contents returned. + +=item B + +If the cursor is already pointing to a key/value pair, it will be +decremented to point to the previous key/value pair and return its +contents. + +If the cursor isn't initialised, B works just like B. + +If the cursor is already positioned at the first key/value pair, B +will return B. + +=item B + +If the cursor has been set to point to a key/value pair, return their +contents. +If the key/value pair referenced by the cursor has been deleted, B +will return B. + +=item B + +Set the cursor to point to the key/value pair referenced by B<$key> +and return the value in B<$value>. + +=item B + +This flag is a variation on the B flag. As well as returning +the value, it also returns the key, via B<$key>. +When used with a B database the key matched by B +will be the shortest key (in length) which is greater than or equal to +the key supplied, via B<$key>. This allows partial key searches. +See ??? for an example of how to use this flag. + +=item B + +Another variation on B. This one returns both the key and +the value. + +=item B + +TODO. + +=item B + +TODO. + +=back + +In addition, the following value may be set by logically OR'ing it into +the B<$flags> parameter: + +=over 5 + +=item B + +TODO. + +=back + +=head2 $status = $cursor->c_put($key, $value, $flags) + +Stores the key/value pair in the database. The position that the data is +stored in the database is controlled by the C<$flags> parameter, which +must take B of the following values: + +=over 5 + +=item B + +When used with a Btree or Hash database, a duplicate of the key referenced +by the current cursor position will be created and the contents of +B<$value> will be associated with it - B<$key> is ignored. +The new key/value pair will be stored immediately after the current +cursor position. +Obviously the database has to have been opened with B. + +When used with a Recno ... TODO + + +=item B + +When used with a Btree or Hash database, a duplicate of the key referenced +by the current cursor position will be created and the contents of +B<$value> will be associated with it - B<$key> is ignored. +The new key/value pair will be stored immediately before the current +cursor position. +Obviously the database has to have been opened with B. + +When used with a Recno ... TODO + +=item B + +If the cursor has been initialised, replace the value of the key/value +pair stored in the database with the contents of B<$value>. + +=item B + +Only valid with a Btree or Hash database. This flag is only really +used when duplicates are enabled in the database and sorted duplicates +haven't been specified. +In this case the key/value pair will be inserted as the first entry in +the duplicates for the particular key. + +=item B + +Only valid with a Btree or Hash database. This flag is only really +used when duplicates are enabled in the database and sorted duplicates +haven't been specified. +In this case the key/value pair will be inserted as the last entry in +the duplicates for the particular key. + +=back + +=head2 $status = $cursor->c_del([$flags]) + +This method deletes the key/value pair associated with the current cursor +position. The cursor position will not be changed by this operation, so +any subsequent cursor operation must first initialise the cursor to +point to a valid key/value pair. + +If the key/value pair associated with the cursor have already been +deleted, B will return B. + +The B<$flags> parameter is not used at present. + +=head2 $status = $cursor->c_del($cnt [, $flags]) + +Stores the number of duplicates at the current cursor position in B<$cnt>. + +The B<$flags> parameter is not used at present. This method needs +Berkeley DB 3.1 or better. + +=head2 $status = $cursor->status() + +Returns the status of the last cursor method as a dual type. + +=head2 Cursor Examples + +TODO + +Iterating from first to last, then in reverse. + +examples of each of the flags. + +=head1 JOIN + +Join support for BerkeleyDB is in progress. Watch this space. + +TODO + +=head1 TRANSACTIONS + +TODO. + +=head1 DBM Filters + +A DBM Filter is a piece of code that is be used when you I +want to make the same transformation to all keys and/or values in a DBM +database. All of the database classes (BerkeleyDB::Hash, +BerkeleyDB::Btree and BerkeleyDB::Recno) support DBM Filters. + +There are four methods associated with DBM Filters. All work +identically, and each is used to install (or uninstall) a single DBM +Filter. Each expects a single parameter, namely a reference to a sub. +The only difference between them is the place that the filter is +installed. + +To summarise: + +=over 5 + +=item B + +If a filter has been installed with this method, it will be invoked +every time you write a key to a DBM database. + +=item B + +If a filter has been installed with this method, it will be invoked +every time you write a value to a DBM database. + + +=item B + +If a filter has been installed with this method, it will be invoked +every time you read a key from a DBM database. + +=item B + +If a filter has been installed with this method, it will be invoked +every time you read a value from a DBM database. + +=back + +You can use any combination of the methods, from none, to all four. + +All filter methods return the existing filter, if present, or C +in not. + +To delete a filter pass C to it. + +=head2 The Filter + +When each filter is called by Perl, a local copy of C<$_> will contain +the key or value to be filtered. Filtering is achieved by modifying +the contents of C<$_>. The return code from the filter is ignored. + +=head2 An Example -- the NULL termination problem. + +Consider the following scenario. You have a DBM database that you need +to share with a third-party C application. The C application assumes +that I keys and values are NULL terminated. Unfortunately when +Perl writes to DBM databases it doesn't use NULL termination, so your +Perl application will have to manage NULL termination itself. When you +write to the database you will have to use something like this: + + $hash{"$key\0"} = "$value\0" ; + +Similarly the NULL needs to be taken into account when you are considering +the length of existing keys/values. + +It would be much better if you could ignore the NULL terminations issue +in the main application code and have a mechanism that automatically +added the terminating NULL to all keys and values whenever you write to +the database and have them removed when you read from the database. As I'm +sure you have already guessed, this is a problem that DBM Filters can +fix very easily. + +## nullFilter + +Hopefully the contents of each of the filters should be +self-explanatory. Both "fetch" filters remove the terminating NULL, +and both "store" filters add a terminating NULL. + + +=head2 Another Example -- Key is a C int. + +Here is another real-life example. By default, whenever Perl writes to +a DBM database it always writes the key and value as strings. So when +you use this: + + $hash{12345} = "something" ; + +the key 12345 will get stored in the DBM database as the 5 byte string +"12345". If you actually want the key to be stored in the DBM database +as a C int, you will have to use C when writing, and C +when reading. + +Here is a DBM Filter that does it: + +## intFilter + +This time only two filters have been used -- we only need to manipulate +the contents of the key, so it wasn't necessary to install any value +filters. + +=head1 Using BerkeleyDB with MLDBM + +Both BerkeleyDB::Hash and BerkeleyDB::Btree can be used with the MLDBM +module. The code fragment below shows how to open associate MLDBM with +BerkeleyDB::Btree. To use BerkeleyDB::Hash just replace +BerkeleyDB::Btree with BerkeleyDB::Hash. + + use strict ; + use BerkeleyDB ; + use MLDBM qw(BerkeleyDB::Btree) ; + use Data::Dumper; + + my $filename = 'testmldbm' ; + my %o ; + + unlink $filename ; + tie %o, 'MLDBM', -Filename => $filename, + -Flags => DB_CREATE + or die "Cannot open database '$filename: $!\n"; + +See the MLDBM documentation for information on how to use the module +and for details of its limitations. + +=head1 EXAMPLES + +TODO. + +=head1 HINTS & TIPS + +=head2 Sharing Databases With C Applications + +There is no technical reason why a Berkeley DB database cannot be +shared by both a Perl and a C application. + +The vast majority of problems that are reported in this area boil down +to the fact that C strings are NULL terminated, whilst Perl strings +are not. See L in the DBM +FILTERS section for a generic way to work around this problem. + + +=head2 The untie Gotcha + +TODO + +=head1 COMMON QUESTIONS + +This section attempts to answer some of the more common questions that +I get asked. + + +=head2 Relationship with DB_File + +Before Berkeley DB 2.x was written there was only one Perl module that +interfaced to Berkeley DB. That module is called B. Although +B can be build with Berkeley DB 1.x, 2.x or 3.x, it only provides +an interface to the functionality available in Berkeley DB 1.x. That +means that it doesn't support transactions, locking or any of the other +new features available in DB 2.x or 3.x. + +=head2 How do I store Perl data structures with BerkeleyDB? + +See L. + +=head1 HISTORY + +See the Changes file. + +=head1 AVAILABILITY + +The most recent version of B can always be found +on CPAN (see L for details), in the directory +F. + +The official web site for Berkeley DB is F. + +=head1 COPYRIGHT + +Copyright (c) 1997-2001 Paul Marquess. All rights reserved. This program +is free software; you can redistribute it and/or modify it under the +same terms as Perl itself. + +Although B is covered by the Perl license, the library it +makes use of, namely Berkeley DB, is not. Berkeley DB has its own +copyright and its own license. Please take the time to read it. + +Here are few words taken from the Berkeley DB FAQ (at +F) regarding the license: + + Do I have to license DB to use it in Perl scripts? + + No. The Berkeley DB license requires that software that uses + Berkeley DB be freely redistributable. In the case of Perl, that + software is Perl, and not your scripts. Any Perl scripts that you + write are your property, including scripts that make use of Berkeley + DB. Neither the Perl license nor the Berkeley DB license + place any restriction on what you may do with them. + +If you are in any doubt about the license situation, contact either the +Berkeley DB authors or the author of BerkeleyDB. +See L<"AUTHOR"> for details. + + +=head1 AUTHOR + +Paul Marquess EPaul.Marquess@btinternet.comE. + +Questions about Berkeley DB may be addressed to Edb@sleepycat.comE. + +=head1 SEE ALSO + +perl(1), DB_File, Berkeley DB. + +=cut diff --git a/db/perl.BerkeleyDB/BerkeleyDB.xs b/db/perl.BerkeleyDB/BerkeleyDB.xs new file mode 100644 index 000000000..19126c98b --- /dev/null +++ b/db/perl.BerkeleyDB/BerkeleyDB.xs @@ -0,0 +1,3927 @@ +/* + + BerkeleyDB.xs -- Perl 5 interface to Berkeley DB version 2 & 3 + + written by Paul Marquess + + All comments/suggestions/problems are welcome + + Copyright (c) 1997-2001 Paul Marquess. All rights reserved. + This program is free software; you can redistribute it and/or + modify it under the same terms as Perl itself. + + Please refer to the COPYRIGHT section in + + Changes: + 0.01 - First Alpha Release + 0.02 - + +*/ + + + +#ifdef __cplusplus +extern "C" { +#endif +#define PERL_POLLUTE +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" + +/* Being the Berkeley DB we prefer the (which will be + * shortly #included by the ) __attribute__ to the possibly + * already defined __attribute__, for example by GNUC or by Perl. */ + +#undef __attribute__ + +#ifndef PERL_VERSION +# include "patchlevel.h" +# define PERL_REVISION 5 +# define PERL_VERSION PATCHLEVEL +# define PERL_SUBVERSION SUBVERSION +#endif + +#if PERL_REVISION == 5 && (PERL_VERSION < 4 || (PERL_VERSION == 4 && PERL_SUBVERSION <= 75 )) + +# define PL_sv_undef sv_undef +# define PL_na na +# define PL_dirty dirty + +#endif + +#include + +#if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 0) +# define IS_DB_3_0 +#endif + +#if DB_VERSION_MAJOR >= 3 +# define AT_LEAST_DB_3 +#endif + +#if DB_VERSION_MAJOR > 3 || (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR >= 1) +# define AT_LEAST_DB_3_1 +#endif + +#if DB_VERSION_MAJOR > 3 || (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR >= 2) +# define AT_LEAST_DB_3_2 +#endif + +/* need to define DEFSV & SAVE_DEFSV for older version of Perl */ +#ifndef DEFSV +# define DEFSV GvSV(defgv) +#endif + +#ifndef SAVE_DEFSV +# define SAVE_DEFSV SAVESPTR(GvSV(defgv)) +#endif + +#ifndef pTHX +# define pTHX +# define pTHX_ +# define aTHX +# define aTHX_ +#endif + +#ifndef dTHR +# define dTHR +#endif + +#ifndef newSVpvn +# define newSVpvn(a,b) newSVpv(a,b) +#endif + +#ifdef __cplusplus +} +#endif + +#define DBM_FILTERING +#define STRICT_CLOSE +/* #define ALLOW_RECNO_OFFSET */ +/* #define TRACE */ + +#if DB_VERSION_MAJOR == 2 && ! defined(DB_LOCK_DEADLOCK) +# define DB_LOCK_DEADLOCK EAGAIN +#endif /* DB_VERSION_MAJOR == 2 */ + +#if DB_VERSION_MAJOR == 2 +# define DB_QUEUE 4 +#endif /* DB_VERSION_MAJOR == 2 */ + +#ifdef AT_LEAST_DB_3_2 +# define DB_callback DB * db, +#else +# define DB_callback +#endif + +#if DB_VERSION_MAJOR > 2 +typedef struct { + int db_lorder; + size_t db_cachesize; + size_t db_pagesize; + + + void *(*db_malloc) __P((size_t)); + int (*dup_compare) + __P((DB_callback const DBT *, const DBT *)); + + u_int32_t bt_maxkey; + u_int32_t bt_minkey; + int (*bt_compare) + __P((DB_callback const DBT *, const DBT *)); + size_t (*bt_prefix) + __P((DB_callback const DBT *, const DBT *)); + + u_int32_t h_ffactor; + u_int32_t h_nelem; + u_int32_t (*h_hash) + __P((DB_callback const void *, u_int32_t)); + + int re_pad; + int re_delim; + u_int32_t re_len; + char *re_source; + +#define DB_DELIMITER 0x0001 +#define DB_FIXEDLEN 0x0008 +#define DB_PAD 0x0010 + u_int32_t flags; + u_int32_t q_extentsize; +} DB_INFO ; + +#endif /* DB_VERSION_MAJOR > 2 */ + +typedef struct { + int Status ; + /* char ErrBuff[1000] ; */ + SV * ErrPrefix ; + SV * ErrHandle ; + DB_ENV * Env ; + int open_dbs ; + int TxnMgrStatus ; + int active ; + bool txn_enabled ; + } BerkeleyDB_ENV_type ; + + +typedef struct { + DBTYPE type ; + bool recno_or_queue ; + char * filename ; + BerkeleyDB_ENV_type * parent_env ; + DB * dbp ; + SV * compare ; + SV * dup_compare ; + SV * prefix ; + SV * hash ; + int Status ; + DB_INFO * info ; + DBC * cursor ; + DB_TXN * txn ; + int open_cursors ; + u_int32_t partial ; + u_int32_t dlen ; + u_int32_t doff ; + int active ; +#ifdef ALLOW_RECNO_OFFSET + int array_base ; +#endif +#ifdef DBM_FILTERING + SV * filter_fetch_key ; + SV * filter_store_key ; + SV * filter_fetch_value ; + SV * filter_store_value ; + int filtering ; +#endif + } BerkeleyDB_type; + + +typedef struct { + DBTYPE type ; + bool recno_or_queue ; + char * filename ; + DB * dbp ; + SV * compare ; + SV * dup_compare ; + SV * prefix ; + SV * hash ; + int Status ; + DB_INFO * info ; + DBC * cursor ; + DB_TXN * txn ; + BerkeleyDB_type * parent_db ; + u_int32_t partial ; + u_int32_t dlen ; + u_int32_t doff ; + int active ; +#ifdef ALLOW_RECNO_OFFSET + int array_base ; +#endif +#ifdef DBM_FILTERING + SV * filter_fetch_key ; + SV * filter_store_key ; + SV * filter_fetch_value ; + SV * filter_store_value ; + int filtering ; +#endif + } BerkeleyDB_Cursor_type; + +typedef struct { + BerkeleyDB_ENV_type * env ; + } BerkeleyDB_TxnMgr_type ; + +#if 1 +typedef struct { + int Status ; + DB_TXN * txn ; + int active ; + } BerkeleyDB_Txn_type ; +#else +typedef DB_TXN BerkeleyDB_Txn_type ; +#endif + +typedef BerkeleyDB_ENV_type * BerkeleyDB__Env ; +typedef BerkeleyDB_ENV_type * BerkeleyDB__Env__Raw ; +typedef BerkeleyDB_ENV_type * BerkeleyDB__Env__Inner ; +typedef BerkeleyDB_type * BerkeleyDB ; +typedef void * BerkeleyDB__Raw ; +typedef BerkeleyDB_type * BerkeleyDB__Common ; +typedef BerkeleyDB_type * BerkeleyDB__Common__Raw ; +typedef BerkeleyDB_type * BerkeleyDB__Common__Inner ; +typedef BerkeleyDB_type * BerkeleyDB__Hash ; +typedef BerkeleyDB_type * BerkeleyDB__Hash__Raw ; +typedef BerkeleyDB_type * BerkeleyDB__Btree ; +typedef BerkeleyDB_type * BerkeleyDB__Btree__Raw ; +typedef BerkeleyDB_type * BerkeleyDB__Recno ; +typedef BerkeleyDB_type * BerkeleyDB__Recno__Raw ; +typedef BerkeleyDB_type * BerkeleyDB__Queue ; +typedef BerkeleyDB_type * BerkeleyDB__Queue__Raw ; +typedef BerkeleyDB_Cursor_type BerkeleyDB__Cursor_type ; +typedef BerkeleyDB_Cursor_type * BerkeleyDB__Cursor ; +typedef BerkeleyDB_Cursor_type * BerkeleyDB__Cursor__Raw ; +typedef BerkeleyDB_TxnMgr_type * BerkeleyDB__TxnMgr ; +typedef BerkeleyDB_TxnMgr_type * BerkeleyDB__TxnMgr__Raw ; +typedef BerkeleyDB_TxnMgr_type * BerkeleyDB__TxnMgr__Inner ; +typedef BerkeleyDB_Txn_type * BerkeleyDB__Txn ; +typedef BerkeleyDB_Txn_type * BerkeleyDB__Txn__Raw ; +typedef BerkeleyDB_Txn_type * BerkeleyDB__Txn__Inner ; +#if 0 +typedef DB_LOG * BerkeleyDB__Log ; +typedef DB_LOCKTAB * BerkeleyDB__Lock ; +#endif +typedef DBT DBTKEY ; +typedef DBT DBT_OPT ; +typedef DBT DBT_B ; +typedef DBT DBTKEY_B ; +typedef DBT DBTVALUE ; +typedef void * PV_or_NULL ; +typedef PerlIO * IO_or_NULL ; +typedef int DualType ; + +static void +hash_delete(char * hash, IV key); + +#ifdef TRACE +# define Trace(x) printf x +#else +# define Trace(x) +#endif + +#ifdef ALLOW_RECNO_OFFSET +# define RECNO_BASE db->array_base +#else +# define RECNO_BASE 1 +#endif + +#if DB_VERSION_MAJOR == 2 +# define flagSet_DB2(i, f) i |= f +#else +# define flagSet_DB2(i, f) +#endif + +#if DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR < 5 +# define flagSet(bitmask) (flags & (bitmask)) +#else +# define flagSet(bitmask) ((flags & DB_OPFLAGS_MASK) == (bitmask)) +#endif + +#ifdef DBM_FILTERING +#define ckFilter(arg,type,name) \ + if (db->type) { \ + SV * save_defsv ; \ + /* printf("filtering %s\n", name) ;*/ \ + if (db->filtering) \ + softCrash("recursion detected in %s", name) ; \ + db->filtering = TRUE ; \ + save_defsv = newSVsv(DEFSV) ; \ + sv_setsv(DEFSV, arg) ; \ + PUSHMARK(sp) ; \ + (void) perl_call_sv(db->type, G_DISCARD|G_NOARGS); \ + sv_setsv(arg, DEFSV) ; \ + sv_setsv(DEFSV, save_defsv) ; \ + SvREFCNT_dec(save_defsv) ; \ + db->filtering = FALSE ; \ + /*printf("end of filtering %s\n", name) ;*/ \ + } +#else +#define ckFilter(type, sv, name) +#endif + +#define ERR_BUFF "BerkeleyDB::Error" + +#define ZMALLOC(to, typ) ((to = (typ *)safemalloc(sizeof(typ))), \ + Zero(to,1,typ)) + +#define DBT_clear(x) Zero(&x, 1, DBT) ; + +#if 1 +#define getInnerObject(x) SvIV(*av_fetch((AV*)SvRV(x), 0, FALSE)) +#else +#define getInnerObject(x) SvIV((SV*)SvRV(sv)) +#endif + +#define my_sv_setpvn(sv, d, s) (s ? sv_setpvn(sv, d, s) : sv_setpv(sv, "") ) + +#define SetValue_iv(i, k) if ((sv = readHash(hash, k)) && sv != &PL_sv_undef) \ + i = SvIV(sv) +#define SetValue_io(i, k) if ((sv = readHash(hash, k)) && sv != &PL_sv_undef) \ + i = IoOFP(sv_2io(sv)) +#define SetValue_sv(i, k) if ((sv = readHash(hash, k)) && sv != &PL_sv_undef) \ + i = sv +#define SetValue_pv(i, k,t) if ((sv = readHash(hash, k)) && sv != &PL_sv_undef) \ + i = (t)SvPV(sv,PL_na) +#define SetValue_pvx(i, k, t) if ((sv = readHash(hash, k)) && sv != &PL_sv_undef) \ + i = (t)SvPVX(sv) +#define SetValue_ov(i,k,t) if ((sv = readHash(hash, k)) && sv != &PL_sv_undef) {\ + IV tmp = getInnerObject(sv) ; \ + i = (t) tmp ; \ + } + +#define SetValue_ovx(i,k,t) if ((sv = readHash(hash, k)) && sv != &PL_sv_undef) {\ + HV * hv = (HV *)GetInternalObject(sv); \ + SV ** svp = hv_fetch(hv, "db", 2, FALSE);\ + IV tmp = SvIV(*svp); \ + i = (t) tmp ; \ + } + +#define SetValue_ovX(i,k,t) if ((sv = readHash(hash, k)) && sv != &PL_sv_undef) {\ + IV tmp = SvIV(GetInternalObject(sv));\ + i = (t) tmp ; \ + } + +#define LastDBerror DB_RUNRECOVERY + +#define setDUALerrno(var, err) \ + sv_setnv(var, (double)err) ; \ + sv_setpv(var, ((err) ? db_strerror(err) : "")) ;\ + SvNOK_on(var); + +#define OutputValue(arg, name) \ + { if (RETVAL == 0) { \ + my_sv_setpvn(arg, name.data, name.size) ; \ + ckFilter(arg, filter_fetch_value,"filter_fetch_value") ; \ + } \ + } + +#define OutputValue_B(arg, name) \ + { if (RETVAL == 0) { \ + if (db->type == DB_BTREE && \ + flagSet(DB_GET_RECNO)){ \ + sv_setiv(arg, (I32)(*(I32*)name.data) - RECNO_BASE); \ + } \ + else { \ + my_sv_setpvn(arg, name.data, name.size) ; \ + } \ + ckFilter(arg, filter_fetch_value, "filter_fetch_value"); \ + } \ + } + +#define OutputKey(arg, name) \ + { if (RETVAL == 0) \ + { \ + if (!db->recno_or_queue) { \ + my_sv_setpvn(arg, name.data, name.size); \ + } \ + else \ + sv_setiv(arg, (I32)*(I32*)name.data - RECNO_BASE); \ + ckFilter(arg, filter_fetch_key, "filter_fetch_key") ; \ + } \ + } + +#define OutputKey_B(arg, name) \ + { if (RETVAL == 0) \ + { \ + if (db->recno_or_queue || \ + (db->type == DB_BTREE && \ + flagSet(DB_GET_RECNO))){ \ + sv_setiv(arg, (I32)(*(I32*)name.data) - RECNO_BASE); \ + } \ + else { \ + my_sv_setpvn(arg, name.data, name.size); \ + } \ + ckFilter(arg, filter_fetch_key, "filter_fetch_key") ; \ + } \ + } + +#define SetPartial(data,db) \ + data.flags = db->partial ; \ + data.dlen = db->dlen ; \ + data.doff = db->doff ; + +#define ckActive(active, type) \ + { \ + if (!active) \ + softCrash("%s is already closed", type) ; \ + } + +#define ckActive_Environment(a) ckActive(a, "Environment") +#define ckActive_TxnMgr(a) ckActive(a, "Transaction Manager") +#define ckActive_Transaction(a) ckActive(a, "Transaction") +#define ckActive_Database(a) ckActive(a, "Database") +#define ckActive_Cursor(a) ckActive(a, "Cursor") + +/* Internal Global Data */ +static db_recno_t Value ; +static db_recno_t zero = 0 ; +static BerkeleyDB CurrentDB ; +static DBTKEY empty ; +static char ErrBuff[1000] ; + +static char * +my_strdup(const char *s) +{ + if (s == NULL) + return NULL ; + + { + MEM_SIZE l = strlen(s); + char *s1 = (char *)safemalloc(l); + + Copy(s, s1, (MEM_SIZE)l, char); + return s1; + } +} + +#if DB_VERSION_MAJOR == 2 +static char * +db_strerror(int err) +{ + if (err == 0) + return "" ; + + if (err > 0) + return Strerror(err) ; + + switch (err) { + case DB_INCOMPLETE: + return ("DB_INCOMPLETE: Sync was unable to complete"); + case DB_KEYEMPTY: + return ("DB_KEYEMPTY: Non-existent key/data pair"); + case DB_KEYEXIST: + return ("DB_KEYEXIST: Key/data pair already exists"); + case DB_LOCK_DEADLOCK: + return ( + "DB_LOCK_DEADLOCK: Locker killed to resolve a deadlock"); + case DB_LOCK_NOTGRANTED: + return ("DB_LOCK_NOTGRANTED: Lock not granted"); + case DB_LOCK_NOTHELD: + return ("DB_LOCK_NOTHELD: Lock not held by locker"); + case DB_NOTFOUND: + return ("DB_NOTFOUND: No matching key/data pair found"); + case DB_RUNRECOVERY: + return ("DB_RUNRECOVERY: Fatal error, run database recovery"); + default: + return "Unknown Error" ; + + } +} +#endif /* DB_VERSION_MAJOR == 2 */ + +static char * +my_db_strerror(int err) +{ + static char buffer[1000] ; + SV * sv = perl_get_sv(ERR_BUFF, FALSE) ; + sprintf(buffer, "%d: %s", err, db_strerror(err)) ; + if (err && sv) { + strcat(buffer, ", ") ; + strcat(buffer, SvPVX(sv)) ; + } + return buffer; +} + +static void +close_everything(void) +{ + dTHR; + Trace(("close_everything\n")) ; + /* Abort All Transactions */ + { + BerkeleyDB__Txn__Raw tid ; + HE * he ; + I32 len ; + HV * hv = perl_get_hv("BerkeleyDB::Term::Txn", TRUE); + I32 ret = hv_iterinit(hv) ; + int all = 0 ; + int closed = 0 ; + Trace(("BerkeleyDB::Term::close_all_txns dirty=%d\n", PL_dirty)) ; + while ( he = hv_iternext(hv) ) { + tid = * (BerkeleyDB__Txn__Raw *) (IV) hv_iterkey(he, &len) ; + Trace((" Aborting Transaction [%d] in [%d] Active [%d]\n", tid->txn, tid, tid->active)); + if (tid->active) { + txn_abort(tid->txn); + ++ closed ; + } + tid->active = FALSE ; + ++ all ; + } + Trace(("End of BerkeleyDB::Term::close_all_txns aborted %d of %d transactios\n",closed, all)) ; + } + + /* Close All Cursors */ + { + BerkeleyDB__Cursor db ; + HE * he ; + I32 len ; + HV * hv = perl_get_hv("BerkeleyDB::Term::Cursor", TRUE); + I32 ret = hv_iterinit(hv) ; + int all = 0 ; + int closed = 0 ; + Trace(("BerkeleyDB::Term::close_all_cursors \n")) ; + while ( he = hv_iternext(hv) ) { + db = * (BerkeleyDB__Cursor*) (IV) hv_iterkey(he, &len) ; + Trace((" Closing Cursor [%d] in [%d] Active [%d]\n", db->cursor, db, db->active)); + if (db->active) { + ((db->cursor)->c_close)(db->cursor) ; + ++ closed ; + } + db->active = FALSE ; + ++ all ; + } + Trace(("End of BerkeleyDB::Term::close_all_cursors closed %d of %d cursors\n",closed, all)) ; + } + + /* Close All Databases */ + { + BerkeleyDB db ; + HE * he ; + I32 len ; + HV * hv = perl_get_hv("BerkeleyDB::Term::Db", TRUE); + I32 ret = hv_iterinit(hv) ; + int all = 0 ; + int closed = 0 ; + Trace(("BerkeleyDB::Term::close_all_dbs\n" )) ; + while ( he = hv_iternext(hv) ) { + db = * (BerkeleyDB*) (IV) hv_iterkey(he, &len) ; + Trace((" Closing Database [%d] in [%d] Active [%d]\n", db->dbp, db, db->active)); + if (db->active) { + (db->dbp->close)(db->dbp, 0) ; + ++ closed ; + } + db->active = FALSE ; + ++ all ; + } + Trace(("End of BerkeleyDB::Term::close_all_dbs closed %d of %d dbs\n",closed, all)) ; + } + + /* Close All Environments */ + { + BerkeleyDB__Env env ; + HE * he ; + I32 len ; + HV * hv = perl_get_hv("BerkeleyDB::Term::Env", TRUE); + I32 ret = hv_iterinit(hv) ; + int all = 0 ; + int closed = 0 ; + Trace(("BerkeleyDB::Term::close_all_envs\n")) ; + while ( he = hv_iternext(hv) ) { + env = * (BerkeleyDB__Env*) (IV) hv_iterkey(he, &len) ; + Trace((" Closing Environment [%d] in [%d] Active [%d]\n", env->Env, env, env->active)); + if (env->active) { +#if DB_VERSION_MAJOR == 2 + db_appexit(env->Env) ; +#else + (env->Env->close)(env->Env, 0) ; +#endif + ++ closed ; + } + env->active = FALSE ; + ++ all ; + } + Trace(("End of BerkeleyDB::Term::close_all_envs closed %d of %d dbs\n",closed, all)) ; + } + + Trace(("end close_everything\n")) ; + +} + +static void +destroyDB(BerkeleyDB db) +{ + dTHR; + if (! PL_dirty && db->active) { + -- db->open_cursors ; + ((db->dbp)->close)(db->dbp, 0) ; + } + if (db->hash) + SvREFCNT_dec(db->hash) ; + if (db->compare) + SvREFCNT_dec(db->compare) ; + if (db->dup_compare) + SvREFCNT_dec(db->dup_compare) ; + if (db->prefix) + SvREFCNT_dec(db->prefix) ; +#ifdef DBM_FILTERING + if (db->filter_fetch_key) + SvREFCNT_dec(db->filter_fetch_key) ; + if (db->filter_store_key) + SvREFCNT_dec(db->filter_store_key) ; + if (db->filter_fetch_value) + SvREFCNT_dec(db->filter_fetch_value) ; + if (db->filter_store_value) + SvREFCNT_dec(db->filter_store_value) ; +#endif + hash_delete("BerkeleyDB::Term::Db", (IV)db) ; + if (db->filename) + Safefree(db->filename) ; + Safefree(db) ; +} + +static void +softCrash(const char *pat, ...) +{ + char buffer1 [500] ; + char buffer2 [500] ; + va_list args; + va_start(args, pat); + + Trace(("softCrash: %s\n", pat)) ; + +#define ABORT_PREFIX "BerkeleyDB Aborting: " + + /* buffer = (char*) safemalloc(strlen(pat) + strlen(ABORT_PREFIX) + 1) ; */ + strcpy(buffer1, ABORT_PREFIX) ; + strcat(buffer1, pat) ; + + vsprintf(buffer2, buffer1, args) ; + + croak(buffer2); + + /* NOTREACHED */ + va_end(args); +} + + +static I32 +GetArrayLength(BerkeleyDB db) +{ + DBT key ; + DBT value ; + int RETVAL = 0 ; + DBC * cursor ; + + DBT_clear(key) ; + DBT_clear(value) ; +#if DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR < 6 + if ( ((db->dbp)->cursor)(db->dbp, db->txn, &cursor) == 0 ) +#else + if ( ((db->dbp)->cursor)(db->dbp, db->txn, &cursor, 0) == 0 ) +#endif + { + RETVAL = cursor->c_get(cursor, &key, &value, DB_LAST) ; + if (RETVAL == 0) + RETVAL = *(I32 *)key.data ; + else /* No key means empty file */ + RETVAL = 0 ; + cursor->c_close(cursor) ; + } + + Trace(("GetArrayLength got %d\n", RETVAL)) ; + return ((I32)RETVAL) ; +} + +#if 0 + +#define GetRecnoKey(db, value) _GetRecnoKey(db, value) + +static db_recno_t +_GetRecnoKey(BerkeleyDB db, I32 value) +{ + Trace(("GetRecnoKey start value = %d\n", value)) ; + if (db->recno_or_queue && value < 0) { + /* Get the length of the array */ + I32 length = GetArrayLength(db) ; + + /* check for attempt to write before start of array */ + if (length + value + RECNO_BASE <= 0) + softCrash("Modification of non-creatable array value attempted, subscript %ld", (long)value) ; + + value = length + value + RECNO_BASE ; + } + else + ++ value ; + + Trace(("GetRecnoKey end value = %d\n", value)) ; + + return value ; +} + +#else /* ! 0 */ + +#if 0 +#ifdef ALLOW_RECNO_OFFSET +#define GetRecnoKey(db, value) _GetRecnoKey(db, value) + +static db_recno_t +_GetRecnoKey(BerkeleyDB db, I32 value) +{ + if (value + RECNO_BASE < 1) + softCrash("key value %d < base (%d)", (value), RECNO_BASE?0:1) ; + return value + RECNO_BASE ; +} + +#else +#endif /* ALLOW_RECNO_OFFSET */ +#endif /* 0 */ + +#define GetRecnoKey(db, value) ((value) + RECNO_BASE ) + +#endif /* 0 */ + +static SV * +GetInternalObject(SV * sv) +{ + SV * info = (SV*) NULL ; + SV * s ; + MAGIC * mg ; + + Trace(("in GetInternalObject %d\n", sv)) ; + if (sv == NULL || !SvROK(sv)) + return NULL ; + + s = SvRV(sv) ; + if (SvMAGICAL(s)) + { + if (SvTYPE(s) == SVt_PVHV || SvTYPE(s) == SVt_PVAV) + mg = mg_find(s, 'P') ; + else + mg = mg_find(s, 'q') ; + + /* all this testing is probably overkill, but till I know more + about global destruction it stays. + */ + /* if (mg && mg->mg_obj && SvRV(mg->mg_obj) && SvPVX(SvRV(mg->mg_obj))) */ + if (mg && mg->mg_obj && SvRV(mg->mg_obj) ) + info = SvRV(mg->mg_obj) ; + else + info = s ; + } + + Trace(("end of GetInternalObject %d\n", info)) ; + return info ; +} + +static int +btree_compare(DB_callback const DBT * key1, const DBT * key2 ) +{ + dSP ; + void * data1, * data2 ; + int retval ; + int count ; + + data1 = key1->data ; + data2 = key2->data ; + +#ifndef newSVpvn + /* As newSVpv will assume that the data pointer is a null terminated C + string if the size parameter is 0, make sure that data points to an + empty string if the length is 0 + */ + if (key1->size == 0) + data1 = "" ; + if (key2->size == 0) + data2 = "" ; +#endif + + ENTER ; + SAVETMPS; + + PUSHMARK(SP) ; + EXTEND(SP,2) ; + PUSHs(sv_2mortal(newSVpvn(data1,key1->size))); + PUSHs(sv_2mortal(newSVpvn(data2,key2->size))); + PUTBACK ; + + count = perl_call_sv(CurrentDB->compare, G_SCALAR); + + SPAGAIN ; + + if (count != 1) + softCrash ("in btree_compare - expected 1 return value from compare sub, got %d", count) ; + + retval = POPi ; + + PUTBACK ; + FREETMPS ; + LEAVE ; + return (retval) ; + +} + +static int +dup_compare(DB_callback const DBT * key1, const DBT * key2 ) +{ + dSP ; + void * data1, * data2 ; + int retval ; + int count ; + + Trace(("In dup_compare \n")) ; + if (!CurrentDB) + softCrash("Internal Error - No CurrentDB in dup_compare") ; + if (CurrentDB->dup_compare == NULL) + softCrash("in dup_compare: no callback specified for database '%s'", CurrentDB->filename) ; + + data1 = key1->data ; + data2 = key2->data ; + +#ifndef newSVpvn + /* As newSVpv will assume that the data pointer is a null terminated C + string if the size parameter is 0, make sure that data points to an + empty string if the length is 0 + */ + if (key1->size == 0) + data1 = "" ; + if (key2->size == 0) + data2 = "" ; +#endif + + ENTER ; + SAVETMPS; + + PUSHMARK(SP) ; + EXTEND(SP,2) ; + PUSHs(sv_2mortal(newSVpvn(data1,key1->size))); + PUSHs(sv_2mortal(newSVpvn(data2,key2->size))); + PUTBACK ; + + count = perl_call_sv(CurrentDB->dup_compare, G_SCALAR); + + SPAGAIN ; + + if (count != 1) + softCrash ("dup_compare: expected 1 return value from compare sub, got %d", count) ; + + retval = POPi ; + + PUTBACK ; + FREETMPS ; + LEAVE ; + return (retval) ; + +} + +static size_t +btree_prefix(DB_callback const DBT * key1, const DBT * key2 ) +{ + dSP ; + void * data1, * data2 ; + int retval ; + int count ; + + data1 = key1->data ; + data2 = key2->data ; + +#ifndef newSVpvn + /* As newSVpv will assume that the data pointer is a null terminated C + string if the size parameter is 0, make sure that data points to an + empty string if the length is 0 + */ + if (key1->size == 0) + data1 = "" ; + if (key2->size == 0) + data2 = "" ; +#endif + + ENTER ; + SAVETMPS; + + PUSHMARK(SP) ; + EXTEND(SP,2) ; + PUSHs(sv_2mortal(newSVpvn(data1,key1->size))); + PUSHs(sv_2mortal(newSVpvn(data2,key2->size))); + PUTBACK ; + + count = perl_call_sv(CurrentDB->prefix, G_SCALAR); + + SPAGAIN ; + + if (count != 1) + softCrash ("btree_prefix: expected 1 return value from prefix sub, got %d", count) ; + + retval = POPi ; + + PUTBACK ; + FREETMPS ; + LEAVE ; + + return (retval) ; +} + +static u_int32_t +hash_cb(DB_callback const void * data, u_int32_t size) +{ + dSP ; + int retval ; + int count ; + +#ifndef newSVpvn + if (size == 0) + data = "" ; +#endif + + ENTER ; + SAVETMPS; + + PUSHMARK(SP) ; + + XPUSHs(sv_2mortal(newSVpvn((char*)data,size))); + PUTBACK ; + + count = perl_call_sv(CurrentDB->hash, G_SCALAR); + + SPAGAIN ; + + if (count != 1) + softCrash ("hash_cb: expected 1 return value from hash sub, got %d", count) ; + + retval = POPi ; + + PUTBACK ; + FREETMPS ; + LEAVE ; + + return (retval) ; +} + +static void +db_errcall_cb(const char * db_errpfx, char * buffer) +{ +#if 0 + + if (db_errpfx == NULL) + db_errpfx = "" ; + if (buffer == NULL ) + buffer = "" ; + ErrBuff[0] = '\0'; + if (strlen(db_errpfx) + strlen(buffer) + 3 <= 1000) { + if (*db_errpfx != '\0') { + strcat(ErrBuff, db_errpfx) ; + strcat(ErrBuff, ": ") ; + } + strcat(ErrBuff, buffer) ; + } + +#endif + + SV * sv = perl_get_sv(ERR_BUFF, FALSE) ; + if (sv) { + if (db_errpfx) + sv_setpvf(sv, "%s: %s", db_errpfx, buffer) ; + else + sv_setpv(sv, buffer) ; + } +} + +static SV * +readHash(HV * hash, char * key) +{ + SV ** svp; + svp = hv_fetch(hash, key, strlen(key), FALSE); + if (svp && SvOK(*svp)) + return *svp ; + return NULL ; +} + +static void +hash_delete(char * hash, IV key) +{ + HV * hv = perl_get_hv(hash, TRUE); + (void) hv_delete(hv, (char*)&key, sizeof(key), G_DISCARD); +} + +static void +hash_store_iv(char * hash, IV key, IV value) +{ + HV * hv = perl_get_hv(hash, TRUE); + SV ** ret = hv_store(hv, (char*)&key, sizeof(key), newSViv(value), 0); + /* printf("hv_store returned %d\n", ret) ; */ +} + +static void +hv_store_iv(HV * hash, char * key, IV value) +{ + hv_store(hash, key, strlen(key), newSViv(value), 0); +} + +static BerkeleyDB +my_db_open( + BerkeleyDB db , + SV * ref, + SV * ref_dbenv , + BerkeleyDB__Env dbenv , + const char * file, + const char * subname, + DBTYPE type, + int flags, + int mode, + DB_INFO * info + ) +{ + DB_ENV * env = NULL ; + BerkeleyDB RETVAL = NULL ; + DB * dbp ; + int Status ; + + Trace(("_db_open(dbenv[%lu] ref_dbenv [%lu] file[%s] subname [%s] type[%d] flags[%d] mode[%d]\n", + dbenv, ref_dbenv, file, subname, type, flags, mode)) ; + + CurrentDB = db ; + if (dbenv) + env = dbenv->Env ; + +#if DB_VERSION_MAJOR == 2 + if (subname) + softCrash("Subname needs Berkeley DB 3 or better") ; +#endif + +#if DB_VERSION_MAJOR > 2 + Status = db_create(&dbp, env, 0) ; + Trace(("db_create returned %s\n", my_db_strerror(Status))) ; + if (Status) + return RETVAL ; + + if (info->re_source) { + Status = dbp->set_re_source(dbp, info->re_source) ; + Trace(("set_re_source [%s] returned %s\n", + info->re_source, my_db_strerror(Status))); + if (Status) + return RETVAL ; + } + + if (info->db_cachesize) { + Status = dbp->set_cachesize(dbp, 0, info->db_cachesize, 0) ; + Trace(("set_cachesize [%d] returned %s\n", + info->db_cachesize, my_db_strerror(Status))); + if (Status) + return RETVAL ; + } + + if (info->db_lorder) { + Status = dbp->set_lorder(dbp, info->db_lorder) ; + Trace(("set_lorder [%d] returned %s\n", + info->db_lorder, my_db_strerror(Status))); + if (Status) + return RETVAL ; + } + + if (info->db_pagesize) { + Status = dbp->set_pagesize(dbp, info->db_pagesize) ; + Trace(("set_pagesize [%d] returned %s\n", + info->db_pagesize, my_db_strerror(Status))); + if (Status) + return RETVAL ; + } + + if (info->h_ffactor) { + Status = dbp->set_h_ffactor(dbp, info->h_ffactor) ; + Trace(("set_h_ffactor [%d] returned %s\n", + info->h_ffactor, my_db_strerror(Status))); + if (Status) + return RETVAL ; + } + + if (info->h_nelem) { + Status = dbp->set_h_nelem(dbp, info->h_nelem) ; + Trace(("set_h_nelem [%d] returned %s\n", + info->h_nelem, my_db_strerror(Status))); + if (Status) + return RETVAL ; + } + + if (info->bt_minkey) { + Status = dbp->set_bt_minkey(dbp, info->bt_minkey) ; + Trace(("set_bt_minkey [%d] returned %s\n", + info->bt_minkey, my_db_strerror(Status))); + if (Status) + return RETVAL ; + } + + if (info->bt_compare) { + Status = dbp->set_bt_compare(dbp, info->bt_compare) ; + Trace(("set_bt_compare [%d] returned %s\n", + info->bt_compare, my_db_strerror(Status))); + if (Status) + return RETVAL ; + } + + if (info->h_hash) { + Status = dbp->set_h_hash(dbp, info->h_hash) ; + Trace(("set_h_hash [%d] returned %s\n", + info->h_hash, my_db_strerror(Status))); + if (Status) + return RETVAL ; + } + + if (info->dup_compare) { + Status = dbp->set_dup_compare(dbp, info->dup_compare) ; + Trace(("set_dup_compare [%d] returned %s\n", + info->dup_compare, my_db_strerror(Status))); + if (Status) + return RETVAL ; + } + + if (info->bt_prefix) { + Status = dbp->set_bt_prefix(dbp, info->bt_prefix) ; + Trace(("set_bt_prefix [%d] returned %s\n", + info->bt_prefix, my_db_strerror(Status))); + if (Status) + return RETVAL ; + } + + if (info->re_len) { + Status = dbp->set_re_len(dbp, info->re_len) ; + Trace(("set_re_len [%d] returned %s\n", + info->re_len, my_db_strerror(Status))); + if (Status) + return RETVAL ; + } + + if (info->re_delim) { + Status = dbp->set_re_delim(dbp, info->re_delim) ; + Trace(("set_re_delim [%d] returned %s\n", + info->re_delim, my_db_strerror(Status))); + if (Status) + return RETVAL ; + } + + if (info->re_pad) { + Status = dbp->set_re_pad(dbp, info->re_pad) ; + Trace(("set_re_pad [%d] returned %s\n", + info->re_pad, my_db_strerror(Status))); + if (Status) + return RETVAL ; + } + + if (info->flags) { + Status = dbp->set_flags(dbp, info->flags) ; + Trace(("set_flags [%d] returned %s\n", + info->flags, my_db_strerror(Status))); + if (Status) + return RETVAL ; + } + + if (info->q_extentsize) { +#ifdef AT_LEAST_DB_3_2 + Status = dbp->set_q_extentsize(dbp, info->q_extentsize) ; + Trace(("set_flags [%d] returned %s\n", + info->flags, my_db_strerror(Status))); + if (Status) + return RETVAL ; +#else + softCrash("-ExtentSize needs at least Berkeley DB 3.2.x") ; +#endif + } + + if ((Status = (dbp->open)(dbp, file, subname, type, flags, mode)) == 0) { +#else /* DB_VERSION_MAJOR == 2 */ + if ((Status = db_open(file, type, flags, mode, env, info, &dbp)) == 0) { +#endif /* DB_VERSION_MAJOR == 2 */ + + Trace(("db_opened\n")); + RETVAL = db ; + RETVAL->dbp = dbp ; +#if DB_VERSION_MAJOR == 2 + RETVAL->type = dbp->type ; +#else /* DB_VERSION_MAJOR > 2 */ + RETVAL->type = dbp->get_type(dbp) ; +#endif /* DB_VERSION_MAJOR > 2 */ + RETVAL->recno_or_queue = (RETVAL->type == DB_RECNO || + RETVAL->type == DB_QUEUE) ; + RETVAL->filename = my_strdup(file) ; + RETVAL->Status = Status ; + RETVAL->active = TRUE ; + hash_store_iv("BerkeleyDB::Term::Db", (IV)RETVAL, 1) ; + Trace((" storing %d %d in BerkeleyDB::Term::Db\n", RETVAL, dbp)) ; + if (dbenv) { + RETVAL->parent_env = dbenv ; + dbenv->Status = Status ; + ++ dbenv->open_dbs ; + } + } + else { +#if DB_VERSION_MAJOR > 2 + (dbp->close)(dbp, 0) ; +#endif + destroyDB(db) ; + Trace(("db open returned %s\n", my_db_strerror(Status))) ; + } + + return RETVAL ; +} + +static double +constant(char * name, int arg) +{ + errno = 0; + switch (*name) { + case 'A': + break; + case 'B': + break; + case 'C': + break; + case 'D': + if (strEQ(name, "DB_AFTER")) +#ifdef DB_AFTER + return DB_AFTER; +#else + goto not_there; +#endif + if (strEQ(name, "DB_APPEND")) +#ifdef DB_APPEND + return DB_APPEND; +#else + goto not_there; +#endif + if (strEQ(name, "DB_ARCH_ABS")) +#ifdef DB_ARCH_ABS + return DB_ARCH_ABS; +#else + goto not_there; +#endif + if (strEQ(name, "DB_ARCH_DATA")) +#ifdef DB_ARCH_DATA + return DB_ARCH_DATA; +#else + goto not_there; +#endif + if (strEQ(name, "DB_ARCH_LOG")) +#ifdef DB_ARCH_LOG + return DB_ARCH_LOG; +#else + goto not_there; +#endif + if (strEQ(name, "DB_BEFORE")) +#ifdef DB_BEFORE + return DB_BEFORE; +#else + goto not_there; +#endif + if (strEQ(name, "DB_BTREE")) + return DB_BTREE; + if (strEQ(name, "DB_BTREEMAGIC")) +#ifdef DB_BTREEMAGIC + return DB_BTREEMAGIC; +#else + goto not_there; +#endif + if (strEQ(name, "DB_BTREEOLDVER")) +#ifdef DB_BTREEOLDVER + return DB_BTREEOLDVER; +#else + goto not_there; +#endif + if (strEQ(name, "DB_BTREEVERSION")) +#ifdef DB_BTREEVERSION + return DB_BTREEVERSION; +#else + goto not_there; +#endif + if (strEQ(name, "DB_CHECKPOINT")) +#ifdef DB_CHECKPOINT + return DB_CHECKPOINT; +#else + goto not_there; +#endif + if (strEQ(name, "DB_CONSUME")) +#ifdef DB_CONSUME + return DB_CONSUME; +#else + goto not_there; +#endif + if (strEQ(name, "DB_CREATE")) +#ifdef DB_CREATE + return DB_CREATE; +#else + goto not_there; +#endif + if (strEQ(name, "DB_CURLSN")) +#ifdef DB_CURLSN + return DB_CURLSN; +#else + goto not_there; +#endif + if (strEQ(name, "DB_CURRENT")) +#ifdef DB_CURRENT + return DB_CURRENT; +#else + goto not_there; +#endif + if (strEQ(name, "DB_DBT_MALLOC")) +#ifdef DB_DBT_MALLOC + return DB_DBT_MALLOC; +#else + goto not_there; +#endif + if (strEQ(name, "DB_DBT_PARTIAL")) +#ifdef DB_DBT_PARTIAL + return DB_DBT_PARTIAL; +#else + goto not_there; +#endif + if (strEQ(name, "DB_DBT_USERMEM")) +#ifdef DB_DBT_USERMEM + return DB_DBT_USERMEM; +#else + goto not_there; +#endif + if (strEQ(name, "DB_DELETED")) +#ifdef DB_DELETED + return DB_DELETED; +#else + goto not_there; +#endif + if (strEQ(name, "DB_DELIMITER")) +#ifdef DB_DELIMITER + return DB_DELIMITER; +#else + goto not_there; +#endif + if (strEQ(name, "DB_DUP")) +#ifdef DB_DUP + return DB_DUP; +#else + goto not_there; +#endif + if (strEQ(name, "DB_DUPSORT")) +#ifdef DB_DUPSORT + return DB_DUPSORT; +#else + goto not_there; +#endif + if (strEQ(name, "DB_ENV_APPINIT")) +#ifdef DB_ENV_APPINIT + return DB_ENV_APPINIT; +#else + goto not_there; +#endif + if (strEQ(name, "DB_ENV_STANDALONE")) +#ifdef DB_ENV_STANDALONE + return DB_ENV_STANDALONE; +#else + goto not_there; +#endif + if (strEQ(name, "DB_ENV_THREAD")) +#ifdef DB_ENV_THREAD + return DB_ENV_THREAD; +#else + goto not_there; +#endif + if (strEQ(name, "DB_EXCL")) +#ifdef DB_EXCL + return DB_EXCL; +#else + goto not_there; +#endif + if (strEQ(name, "DB_FILE_ID_LEN")) +#ifdef DB_FILE_ID_LEN + return DB_FILE_ID_LEN; +#else + goto not_there; +#endif + if (strEQ(name, "DB_FIRST")) +#ifdef DB_FIRST + return DB_FIRST; +#else + goto not_there; +#endif + if (strEQ(name, "DB_FIXEDLEN")) +#ifdef DB_FIXEDLEN + return DB_FIXEDLEN; +#else + goto not_there; +#endif + if (strEQ(name, "DB_FLUSH")) +#ifdef DB_FLUSH + return DB_FLUSH; +#else + goto not_there; +#endif + if (strEQ(name, "DB_FORCE")) +#ifdef DB_FORCE + return DB_FORCE; +#else + goto not_there; +#endif + if (strEQ(name, "DB_GET_BOTH")) +#ifdef DB_GET_BOTH + return DB_GET_BOTH; +#else + goto not_there; +#endif + if (strEQ(name, "DB_GET_RECNO")) +#ifdef DB_GET_RECNO + return DB_GET_RECNO; +#else + goto not_there; +#endif + if (strEQ(name, "DB_HASH")) + return DB_HASH; + if (strEQ(name, "DB_HASHMAGIC")) +#ifdef DB_HASHMAGIC + return DB_HASHMAGIC; +#else + goto not_there; +#endif + if (strEQ(name, "DB_HASHOLDVER")) +#ifdef DB_HASHOLDVER + return DB_HASHOLDVER; +#else + goto not_there; +#endif + if (strEQ(name, "DB_HASHVERSION")) +#ifdef DB_HASHVERSION + return DB_HASHVERSION; +#else + goto not_there; +#endif + if (strEQ(name, "DB_INCOMPLETE")) +#ifdef DB_INCOMPLETE + return DB_INCOMPLETE; +#else + goto not_there; +#endif + if (strEQ(name, "DB_INIT_CDB")) +#ifdef DB_INIT_CDB + return DB_INIT_CDB; +#else + goto not_there; +#endif + if (strEQ(name, "DB_INIT_LOCK")) +#ifdef DB_INIT_LOCK + return DB_INIT_LOCK; +#else + goto not_there; +#endif + if (strEQ(name, "DB_INIT_LOG")) +#ifdef DB_INIT_LOG + return DB_INIT_LOG; +#else + goto not_there; +#endif + if (strEQ(name, "DB_INIT_MPOOL")) +#ifdef DB_INIT_MPOOL + return DB_INIT_MPOOL; +#else + goto not_there; +#endif + if (strEQ(name, "DB_INIT_TXN")) +#ifdef DB_INIT_TXN + return DB_INIT_TXN; +#else + goto not_there; +#endif + if (strEQ(name, "DB_JOIN_ITEM")) +#ifdef DB_JOIN_ITEM + return DB_JOIN_ITEM; +#else + goto not_there; +#endif + if (strEQ(name, "DB_KEYEMPTY")) +#ifdef DB_KEYEMPTY + return DB_KEYEMPTY; +#else + goto not_there; +#endif + if (strEQ(name, "DB_KEYEXIST")) +#ifdef DB_KEYEXIST + return DB_KEYEXIST; +#else + goto not_there; +#endif + if (strEQ(name, "DB_KEYFIRST")) +#ifdef DB_KEYFIRST + return DB_KEYFIRST; +#else + goto not_there; +#endif + if (strEQ(name, "DB_KEYLAST")) +#ifdef DB_KEYLAST + return DB_KEYLAST; +#else + goto not_there; +#endif + if (strEQ(name, "DB_LAST")) +#ifdef DB_LAST + return DB_LAST; +#else + goto not_there; +#endif + if (strEQ(name, "DB_LOCKMAGIC")) +#ifdef DB_LOCKMAGIC + return DB_LOCKMAGIC; +#else + goto not_there; +#endif + if (strEQ(name, "DB_LOCKVERSION")) +#ifdef DB_LOCKVERSION + return DB_LOCKVERSION; +#else + goto not_there; +#endif + if (strEQ(name, "DB_LOCK_CONFLICT")) +#ifdef DB_LOCK_CONFLICT + return DB_LOCK_CONFLICT; +#else + goto not_there; +#endif + if (strEQ(name, "DB_LOCK_DEADLOCK")) +#ifdef DB_LOCK_DEADLOCK + return DB_LOCK_DEADLOCK; +#else + goto not_there; +#endif + if (strEQ(name, "DB_LOCK_DEFAULT")) +#ifdef DB_LOCK_DEFAULT + return DB_LOCK_DEFAULT; +#else + goto not_there; +#endif + if (strEQ(name, "DB_LOCK_GET")) + return DB_LOCK_GET; + if (strEQ(name, "DB_LOCK_NORUN")) +#ifdef DB_LOCK_NORUN + return DB_LOCK_NORUN; +#else + goto not_there; +#endif + if (strEQ(name, "DB_LOCK_NOTGRANTED")) +#ifdef DB_LOCK_NOTGRANTED + return DB_LOCK_NOTGRANTED; +#else + goto not_there; +#endif + if (strEQ(name, "DB_LOCK_NOTHELD")) +#ifdef DB_LOCK_NOTHELD + return DB_LOCK_NOTHELD; +#else + goto not_there; +#endif + if (strEQ(name, "DB_LOCK_NOWAIT")) +#ifdef DB_LOCK_NOWAIT + return DB_LOCK_NOWAIT; +#else + goto not_there; +#endif + if (strEQ(name, "DB_LOCK_OLDEST")) +#ifdef DB_LOCK_OLDEST + return DB_LOCK_OLDEST; +#else + goto not_there; +#endif + if (strEQ(name, "DB_LOCK_RANDOM")) +#ifdef DB_LOCK_RANDOM + return DB_LOCK_RANDOM; +#else + goto not_there; +#endif + if (strEQ(name, "DB_LOCK_RIW_N")) +#ifdef DB_LOCK_RIW_N + return DB_LOCK_RIW_N; +#else + goto not_there; +#endif + if (strEQ(name, "DB_LOCK_RW_N")) +#ifdef DB_LOCK_RW_N + return DB_LOCK_RW_N; +#else + goto not_there; +#endif + if (strEQ(name, "DB_LOCK_YOUNGEST")) +#ifdef DB_LOCK_YOUNGEST + return DB_LOCK_YOUNGEST; +#else + goto not_there; +#endif + if (strEQ(name, "DB_LOGMAGIC")) +#ifdef DB_LOGMAGIC + return DB_LOGMAGIC; +#else + goto not_there; +#endif + if (strEQ(name, "DB_LOGOLDVER")) +#ifdef DB_LOGOLDVER + return DB_LOGOLDVER; +#else + goto not_there; +#endif + if (strEQ(name, "DB_MAX_PAGES")) +#ifdef DB_MAX_PAGES + return DB_MAX_PAGES; +#else + goto not_there; +#endif + if (strEQ(name, "DB_MAX_RECORDS")) +#ifdef DB_MAX_RECORDS + return DB_MAX_RECORDS; +#else + goto not_there; +#endif + if (strEQ(name, "DB_MPOOL_CLEAN")) +#ifdef DB_MPOOL_CLEAN + return DB_MPOOL_CLEAN; +#else + goto not_there; +#endif + if (strEQ(name, "DB_MPOOL_CREATE")) +#ifdef DB_MPOOL_CREATE + return DB_MPOOL_CREATE; +#else + goto not_there; +#endif + if (strEQ(name, "DB_MPOOL_DIRTY")) +#ifdef DB_MPOOL_DIRTY + return DB_MPOOL_DIRTY; +#else + goto not_there; +#endif + if (strEQ(name, "DB_MPOOL_DISCARD")) +#ifdef DB_MPOOL_DISCARD + return DB_MPOOL_DISCARD; +#else + goto not_there; +#endif + if (strEQ(name, "DB_MPOOL_LAST")) +#ifdef DB_MPOOL_LAST + return DB_MPOOL_LAST; +#else + goto not_there; +#endif + if (strEQ(name, "DB_MPOOL_NEW")) +#ifdef DB_MPOOL_NEW + return DB_MPOOL_NEW; +#else + goto not_there; +#endif + if (strEQ(name, "DB_MPOOL_PRIVATE")) +#ifdef DB_MPOOL_PRIVATE + return DB_MPOOL_PRIVATE; +#else + goto not_there; +#endif + if (strEQ(name, "DB_MUTEXDEBUG")) +#ifdef DB_MUTEXDEBUG + return DB_MUTEXDEBUG; +#else + goto not_there; +#endif + if (strEQ(name, "DB_MUTEXLOCKS")) +#ifdef DB_MUTEXLOCKS + return DB_MUTEXLOCKS; +#else + goto not_there; +#endif + if (strEQ(name, "DB_NEEDSPLIT")) +#ifdef DB_NEEDSPLIT + return DB_NEEDSPLIT; +#else + goto not_there; +#endif + if (strEQ(name, "DB_NEXT")) +#ifdef DB_NEXT + return DB_NEXT; +#else + goto not_there; +#endif + if (strEQ(name, "DB_NEXT_DUP")) +#ifdef DB_NEXT_DUP + return DB_NEXT_DUP; +#else + goto not_there; +#endif + if (strEQ(name, "DB_NOMMAP")) +#ifdef DB_NOMMAP + return DB_NOMMAP; +#else + goto not_there; +#endif + if (strEQ(name, "DB_NOOVERWRITE")) +#ifdef DB_NOOVERWRITE + return DB_NOOVERWRITE; +#else + goto not_there; +#endif + if (strEQ(name, "DB_NOSYNC")) +#ifdef DB_NOSYNC + return DB_NOSYNC; +#else + goto not_there; +#endif + if (strEQ(name, "DB_NOTFOUND")) +#ifdef DB_NOTFOUND + return DB_NOTFOUND; +#else + goto not_there; +#endif + if (strEQ(name, "DB_PAD")) +#ifdef DB_PAD + return DB_PAD; +#else + goto not_there; +#endif + if (strEQ(name, "DB_PAGEYIELD")) +#ifdef DB_PAGEYIELD + return DB_PAGEYIELD; +#else + goto not_there; +#endif + if (strEQ(name, "DB_POSITION")) +#ifdef DB_POSITION + return DB_POSITION; +#else + goto not_there; +#endif + if (strEQ(name, "DB_PREV")) +#ifdef DB_PREV + return DB_PREV; +#else + goto not_there; +#endif + if (strEQ(name, "DB_PRIVATE")) +#ifdef DB_PRIVATE + return DB_PRIVATE; +#else + goto not_there; +#endif + if (strEQ(name, "DB_QUEUE")) + return DB_QUEUE; + if (strEQ(name, "DB_RDONLY")) +#ifdef DB_RDONLY + return DB_RDONLY; +#else + goto not_there; +#endif + if (strEQ(name, "DB_RECNO")) + return DB_RECNO; + if (strEQ(name, "DB_RECNUM")) +#ifdef DB_RECNUM + return DB_RECNUM; +#else + goto not_there; +#endif + if (strEQ(name, "DB_RECORDCOUNT")) +#ifdef DB_RECORDCOUNT + return DB_RECORDCOUNT; +#else + goto not_there; +#endif + if (strEQ(name, "DB_RECOVER")) +#ifdef DB_RECOVER + return DB_RECOVER; +#else + goto not_there; +#endif + if (strEQ(name, "DB_RECOVER_FATAL")) +#ifdef DB_RECOVER_FATAL + return DB_RECOVER_FATAL; +#else + goto not_there; +#endif + if (strEQ(name, "DB_REGISTERED")) +#ifdef DB_REGISTERED + return DB_REGISTERED; +#else + goto not_there; +#endif + if (strEQ(name, "DB_RENUMBER")) +#ifdef DB_RENUMBER + return DB_RENUMBER; +#else + goto not_there; +#endif + if (strEQ(name, "DB_RMW")) +#ifdef DB_RMW + return DB_RMW; +#else + goto not_there; +#endif + if (strEQ(name, "DB_RUNRECOVERY")) +#ifdef DB_RUNRECOVERY + return DB_RUNRECOVERY; +#else + goto not_there; +#endif + if (strEQ(name, "DB_SEQUENTIAL")) +#ifdef DB_SEQUENTIAL + return DB_SEQUENTIAL; +#else + goto not_there; +#endif + if (strEQ(name, "DB_SET")) +#ifdef DB_SET + return DB_SET; +#else + goto not_there; +#endif + if (strEQ(name, "DB_SET_RANGE")) +#ifdef DB_SET_RANGE + return DB_SET_RANGE; +#else + goto not_there; +#endif + if (strEQ(name, "DB_SET_RECNO")) +#ifdef DB_SET_RECNO + return DB_SET_RECNO; +#else + goto not_there; +#endif + if (strEQ(name, "DB_SNAPSHOT")) +#ifdef DB_SNAPSHOT + return DB_SNAPSHOT; +#else + goto not_there; +#endif + if (strEQ(name, "DB_SWAPBYTES")) +#ifdef DB_SWAPBYTES + return DB_SWAPBYTES; +#else + goto not_there; +#endif + if (strEQ(name, "DB_TEMPORARY")) +#ifdef DB_TEMPORARY + return DB_TEMPORARY; +#else + goto not_there; +#endif + if (strEQ(name, "DB_THREAD")) +#ifdef DB_THREAD + return DB_THREAD; +#else + goto not_there; +#endif + if (strEQ(name, "DB_TRUNCATE")) +#ifdef DB_TRUNCATE + return DB_TRUNCATE; +#else + goto not_there; +#endif + if (strEQ(name, "DB_TXNMAGIC")) +#ifdef DB_TXNMAGIC + return DB_TXNMAGIC; +#else + goto not_there; +#endif + if (strEQ(name, "DB_TXNVERSION")) +#ifdef DB_TXNVERSION + return DB_TXNVERSION; +#else + goto not_there; +#endif + if (strEQ(name, "DB_TXN_BACKWARD_ROLL")) + return DB_TXN_BACKWARD_ROLL; + if (strEQ(name, "DB_TXN_CKP")) +#ifdef DB_TXN_CKP + return DB_TXN_CKP; +#else + goto not_there; +#endif + if (strEQ(name, "DB_TXN_FORWARD_ROLL")) + return DB_TXN_FORWARD_ROLL; + if (strEQ(name, "DB_TXN_LOCK_2PL")) +#ifdef DB_TXN_LOCK_2PL + return DB_TXN_LOCK_2PL; +#else + goto not_there; +#endif + if (strEQ(name, "DB_TXN_LOCK_MASK")) +#ifdef DB_TXN_LOCK_MASK + return DB_TXN_LOCK_MASK; +#else + goto not_there; +#endif + if (strEQ(name, "DB_TXN_LOCK_OPTIMIST")) +#ifdef DB_TXN_LOCK_OPTIMIST + return DB_TXN_LOCK_OPTIMIST; +#else + goto not_there; +#endif + if (strEQ(name, "DB_TXN_LOCK_OPTIMISTIC")) +#ifdef DB_TXN_LOCK_OPTIMISTIC + return DB_TXN_LOCK_OPTIMISTIC; +#else + goto not_there; +#endif + if (strEQ(name, "DB_TXN_LOG_MASK")) +#ifdef DB_TXN_LOG_MASK + return DB_TXN_LOG_MASK; +#else + goto not_there; +#endif + if (strEQ(name, "DB_TXN_LOG_REDO")) +#ifdef DB_TXN_LOG_REDO + return DB_TXN_LOG_REDO; +#else + goto not_there; +#endif + if (strEQ(name, "DB_TXN_LOG_UNDO")) +#ifdef DB_TXN_LOG_UNDO + return DB_TXN_LOG_UNDO; +#else + goto not_there; +#endif + if (strEQ(name, "DB_TXN_LOG_UNDOREDO")) +#ifdef DB_TXN_LOG_UNDOREDO + return DB_TXN_LOG_UNDOREDO; +#else + goto not_there; +#endif + if (strEQ(name, "DB_TXN_NOSYNC")) +#ifdef DB_TXN_NOSYNC + return DB_TXN_NOSYNC; +#else + goto not_there; +#endif + if (strEQ(name, "DB_TXN_NOWAIT")) +#ifdef DB_TXN_NOWAIT + return DB_TXN_NOWAIT; +#else + goto not_there; +#endif + if (strEQ(name, "DB_TXN_OPENFILES")) + return DB_TXN_OPENFILES; + if (strEQ(name, "DB_TXN_REDO")) +#ifdef DB_TXN_REDO + return DB_TXN_REDO; +#else + goto not_there; +#endif + if (strEQ(name, "DB_TXN_SYNC")) +#ifdef DB_TXN_SYNC + return DB_TXN_SYNC; +#else + goto not_there; +#endif + if (strEQ(name, "DB_TXN_UNDO")) +#ifdef DB_TXN_UNDO + return DB_TXN_UNDO; +#else + goto not_there; +#endif + if (strEQ(name, "DB_UNKNOWN")) + return DB_UNKNOWN; + if (strEQ(name, "DB_USE_ENVIRON")) +#ifdef DB_USE_ENVIRON + return DB_USE_ENVIRON; +#else + goto not_there; +#endif + if (strEQ(name, "DB_USE_ENVIRON_ROOT")) +#ifdef DB_USE_ENVIRON_ROOT + return DB_USE_ENVIRON_ROOT; +#else + goto not_there; +#endif + if (strEQ(name, "DB_VERSION_MAJOR")) +#ifdef DB_VERSION_MAJOR + return DB_VERSION_MAJOR; +#else + goto not_there; +#endif + if (strEQ(name, "DB_VERSION_MINOR")) +#ifdef DB_VERSION_MINOR + return DB_VERSION_MINOR; +#else + goto not_there; +#endif + if (strEQ(name, "DB_VERSION_PATCH")) +#ifdef DB_VERSION_PATCH + return DB_VERSION_PATCH; +#else + goto not_there; +#endif + if (strEQ(name, "DB_WRITECURSOR")) +#ifdef DB_WRITECURSOR + return DB_WRITECURSOR; +#else + goto not_there; +#endif + break; + case 'E': + break; + case 'F': + break; + case 'G': + break; + case 'H': + break; + case 'I': + break; + case 'J': + break; + case 'K': + break; + case 'L': + break; + case 'M': + break; + case 'N': + break; + case 'O': + break; + case 'P': + break; + case 'Q': + break; + case 'R': + break; + case 'S': + break; + case 'T': + break; + case 'U': + break; + case 'V': + break; + case 'W': + break; + case 'X': + break; + case 'Y': + break; + case 'Z': + break; + case 'a': + break; + case 'b': + break; + case 'c': + break; + case 'd': + break; + case 'e': + break; + case 'f': + break; + case 'g': + break; + case 'h': + break; + case 'i': + break; + case 'j': + break; + case 'k': + break; + case 'l': + break; + case 'm': + break; + case 'n': + break; + case 'o': + break; + case 'p': + break; + case 'q': + break; + case 'r': + break; + case 's': + break; + case 't': + break; + case 'u': + break; + case 'v': + break; + case 'w': + break; + case 'x': + break; + case 'y': + break; + case 'z': + break; + } + errno = EINVAL; + return 0; + +not_there: + errno = ENOENT; + return 0; +} + + +MODULE = BerkeleyDB PACKAGE = BerkeleyDB PREFIX = env_ + +char * +DB_VERSION_STRING() + CODE: + RETVAL = DB_VERSION_STRING ; + OUTPUT: + RETVAL + + +double +constant(name,arg) + char * name + int arg + +#define env_db_version(maj, min, patch) db_version(&maj, &min, &patch) +char * +env_db_version(maj, min, patch) + int maj + int min + int patch + OUTPUT: + RETVAL + maj + min + patch + +int +db_value_set(value, which) + int value + int which + NOT_IMPLEMENTED_YET + + +DualType +_db_remove(ref) + SV * ref + CODE: + { +#if DB_VERSION_MAJOR == 2 + softCrash("BerkeleyDB::db_remove needs Berkeley DB 3.x or better") ; +#else + HV * hash ; + DB * dbp ; + SV * sv ; + const char * db ; + const char * subdb = NULL ; + BerkeleyDB__Env env = NULL ; + DB_ENV * dbenv = NULL ; + u_int32_t flags = 0 ; + + hash = (HV*) SvRV(ref) ; + SetValue_pv(db, "Filename", char *) ; + SetValue_pv(subdb, "Subname", char *) ; + SetValue_iv(flags, "Flags") ; + SetValue_ov(env, "Env", BerkeleyDB__Env) ; + if (env) + dbenv = env->Env ; + RETVAL = db_create(&dbp, dbenv, 0) ; + if (RETVAL == 0) { + RETVAL = dbp->remove(dbp, db, subdb, flags) ; + } +#endif + } + OUTPUT: + RETVAL + +MODULE = BerkeleyDB::Env PACKAGE = BerkeleyDB::Env PREFIX = env_ + + +BerkeleyDB::Env::Raw +_db_appinit(self, ref) + char * self + SV * ref + CODE: + { + HV * hash ; + SV * sv ; + char * home = NULL ; + char * server = NULL ; + char ** config = NULL ; + int flags = 0 ; + int cachesize = 0 ; + int lk_detect = 0 ; + int mode = 0 ; + SV * errprefix = NULL; + DB_ENV * env ; + int status ; + + Trace(("in _db_appinit [%s] %d\n", self, ref)) ; + hash = (HV*) SvRV(ref) ; + SetValue_pv(home, "Home", char *) ; + SetValue_pv(config, "Config", char **) ; + SetValue_sv(errprefix, "ErrPrefix") ; + SetValue_iv(flags, "Flags") ; + SetValue_pv(server, "Server", char *) ; + SetValue_iv(cachesize, "Cachesize") ; + SetValue_iv(lk_detect, "LockDetect") ; +#ifndef AT_LEAST_DB_3_1 + if (server) + softCrash("-Server needs Berkeley DB 3.1 or better") ; +#endif /* ! AT_LEAST_DB_3_1 */ + Trace(("_db_appinit(config=[%d], home=[%s],errprefix=[%s],flags=[%d]\n", + config, home, errprefix, flags)) ; +#ifdef TRACE + if (config) { + int i ; + for (i = 0 ; i < 10 ; ++ i) { + if (config[i] == NULL) { + printf(" End\n") ; + break ; + } + printf(" config = [%s]\n", config[i]) ; + } + } +#endif /* TRACE */ + ZMALLOC(RETVAL, BerkeleyDB_ENV_type) ; + if (flags & DB_INIT_TXN) + RETVAL->txn_enabled = TRUE ; +#if DB_VERSION_MAJOR == 2 + ZMALLOC(RETVAL->Env, DB_ENV) ; + env = RETVAL->Env ; + { + /* Take a copy of the error prefix */ + if (errprefix) { + Trace(("copying errprefix\n" )) ; + RETVAL->ErrPrefix = newSVsv(errprefix) ; + SvPOK_only(RETVAL->ErrPrefix) ; + } + if (RETVAL->ErrPrefix) + RETVAL->Env->db_errpfx = SvPVX(RETVAL->ErrPrefix) ; + + if ((sv = readHash(hash, "ErrFile")) && sv != &PL_sv_undef) { + env->db_errfile = IoOFP(sv_2io(sv)) ; + RETVAL->ErrHandle = newRV(sv) ; + } + /* SetValue_io(RETVAL->Env.db_errfile, "ErrFile") ; */ + SetValue_iv(env->db_verbose, "Verbose") ; + /* env->db_errbuf = RETVAL->ErrBuff ; */ + env->db_errcall = db_errcall_cb ; + RETVAL->active = TRUE ; + status = db_appinit(home, config, env, flags) ; + Trace((" status = %d env %d Env %d\n", status, RETVAL, env)) ; + if (status == 0) + hash_store_iv("BerkeleyDB::Term::Env", (IV)RETVAL, 1) ; + else { + if (RETVAL->ErrHandle) + SvREFCNT_dec(RETVAL->ErrHandle) ; + if (RETVAL->ErrPrefix) + SvREFCNT_dec(RETVAL->ErrPrefix) ; + Safefree(RETVAL->Env) ; + Safefree(RETVAL) ; + RETVAL = NULL ; + } + } +#else /* DB_VERSION_MAJOR > 2 */ +#ifndef AT_LEAST_DB_3_1 +# define DB_CLIENT 0 +#endif + status = db_env_create(&RETVAL->Env, server ? DB_CLIENT : 0) ; + Trace(("db_env_create flags = %d returned %s\n", flags, + my_db_strerror(status))) ; + env = RETVAL->Env ; + if (status == 0 && cachesize) { + status = env->set_cachesize(env, 0, cachesize, 0) ; + Trace(("set_cachesize [%d] returned %s\n", + cachesize, my_db_strerror(status))); + } + + if (status == 0 && lk_detect) { + status = env->set_lk_detect(env, lk_detect) ; + Trace(("set_lk_detect [%d] returned %s\n", + lk_detect, my_db_strerror(status))); + } +#ifdef AT_LEAST_DB_3_1 + /* set the server */ + if (server && status == 0) + { + status = env->set_server(env, server, 0, 0, 0); + Trace(("ENV->set_server server = %s returned %s\n", server, + my_db_strerror(status))) ; + } +#endif + if (status == 0) + { + /* Take a copy of the error prefix */ + if (errprefix) { + Trace(("copying errprefix\n" )) ; + RETVAL->ErrPrefix = newSVsv(errprefix) ; + SvPOK_only(RETVAL->ErrPrefix) ; + } + if (RETVAL->ErrPrefix) + env->set_errpfx(env, SvPVX(RETVAL->ErrPrefix)) ; + + if ((sv = readHash(hash, "ErrFile")) && sv != &PL_sv_undef) { + env->set_errfile(env, IoOFP(sv_2io(sv))) ; + RETVAL->ErrHandle = newRV(sv) ; + } + /* SetValue_iv(RETVAL->Env.db_verbose, "Verbose") ; */ /* TODO */ + SetValue_iv(mode, "Mode") ; + /* RETVAL->Env.db_errbuf = RETVAL->ErrBuff ; */ + env->set_errcall(env, db_errcall_cb) ; + RETVAL->active = TRUE ; +#ifdef IS_DB_3_0 + status = (env->open)(env, home, config, flags, mode) ; +#else /* > 3.0 */ + status = (env->open)(env, home, flags, mode) ; +#endif + Trace(("ENV->open returned %s\n", my_db_strerror(status))) ; + } + + if (status == 0) + hash_store_iv("BerkeleyDB::Term::Env", (IV)RETVAL, 1) ; + else { + (env->close)(env, 0) ; + if (RETVAL->ErrHandle) + SvREFCNT_dec(RETVAL->ErrHandle) ; + if (RETVAL->ErrPrefix) + SvREFCNT_dec(RETVAL->ErrPrefix) ; + Safefree(RETVAL) ; + RETVAL = NULL ; + } +#endif /* DB_VERSION_MAJOR > 2 */ + } + OUTPUT: + RETVAL + +BerkeleyDB::Txn::Raw +_txn_begin(env, pid=NULL, flags=0) + BerkeleyDB::Env env + BerkeleyDB::Txn pid + u_int32_t flags + CODE: + { + DB_TXN *txn ; + DB_TXN *p_id = NULL ; + Trace(("txn_begin pid %d, flags %d\n", pid, flags)) ; +#if DB_VERSION_MAJOR == 2 + if (env->Env->tx_info == NULL) + softCrash("Transaction Manager not enabled") ; +#endif + if (!env->txn_enabled) + softCrash("Transaction Manager not enabled") ; + if (pid) + p_id = pid->txn ; + env->TxnMgrStatus = +#if DB_VERSION_MAJOR == 2 + txn_begin(env->Env->tx_info, p_id, &txn) ; +#else + txn_begin(env->Env, p_id, &txn, flags) ; +#endif + if (env->TxnMgrStatus == 0) { + ZMALLOC(RETVAL, BerkeleyDB_Txn_type) ; + RETVAL->txn = txn ; + RETVAL->active = TRUE ; + Trace(("_txn_begin created txn [%d] in [%d]\n", txn, RETVAL)); + hash_store_iv("BerkeleyDB::Term::Txn", (IV)RETVAL, 1) ; + } + else + RETVAL = NULL ; + } + OUTPUT: + RETVAL + + +#if DB_VERSION_MAJOR == 2 +# define env_txn_checkpoint(e,k,m) txn_checkpoint(e->Env->tx_info, k, m) +#else /* DB 3.0 or better */ +# ifdef AT_LEAST_DB_3_1 +# define env_txn_checkpoint(e,k,m) txn_checkpoint(e->Env, k, m, 0) +# else +# define env_txn_checkpoint(e,k,m) txn_checkpoint(e->Env, k, m) +# endif +#endif +DualType +env_txn_checkpoint(env, kbyte, min) + BerkeleyDB::Env env + long kbyte + long min + +HV * +txn_stat(env) + BerkeleyDB::Env env + HV * RETVAL = NULL ; + CODE: + { + DB_TXN_STAT * stat ; +#if DB_VERSION_MAJOR == 2 + if(txn_stat(env->Env->tx_info, &stat, safemalloc) == 0) { +#else + if(txn_stat(env->Env, &stat, safemalloc) == 0) { +#endif + RETVAL = (HV*)sv_2mortal((SV*)newHV()) ; + hv_store_iv(RETVAL, "st_time_ckp", stat->st_time_ckp) ; + hv_store_iv(RETVAL, "st_last_txnid", stat->st_last_txnid) ; + hv_store_iv(RETVAL, "st_maxtxns", stat->st_maxtxns) ; + hv_store_iv(RETVAL, "st_naborts", stat->st_naborts) ; + hv_store_iv(RETVAL, "st_nbegins", stat->st_nbegins) ; + hv_store_iv(RETVAL, "st_ncommits", stat->st_ncommits) ; + hv_store_iv(RETVAL, "st_nactive", stat->st_nactive) ; +#if DB_VERSION_MAJOR > 2 + hv_store_iv(RETVAL, "st_maxnactive", stat->st_maxnactive) ; + hv_store_iv(RETVAL, "st_regsize", stat->st_regsize) ; + hv_store_iv(RETVAL, "st_region_wait", stat->st_region_wait) ; + hv_store_iv(RETVAL, "st_region_nowait", stat->st_region_nowait) ; +#endif + safefree(stat) ; + } + } + OUTPUT: + RETVAL + +#define EnDis(x) ((x) ? "Enabled" : "Disabled") +void +printEnv(env) + BerkeleyDB::Env env + INIT: + ckActive_Environment(env->active) ; + CODE: +#if 0 + printf("env [0x%X]\n", env) ; + printf(" ErrPrefix [%s]\n", env->ErrPrefix + ? SvPVX(env->ErrPrefix) : 0) ; + printf(" DB_ENV\n") ; + printf(" db_lorder [%d]\n", env->Env.db_lorder) ; + printf(" db_home [%s]\n", env->Env.db_home) ; + printf(" db_data_dir [%s]\n", env->Env.db_data_dir) ; + printf(" db_log_dir [%s]\n", env->Env.db_log_dir) ; + printf(" db_tmp_dir [%s]\n", env->Env.db_tmp_dir) ; + printf(" lk_info [%s]\n", EnDis(env->Env.lk_info)) ; + printf(" lk_max [%d]\n", env->Env.lk_max) ; + printf(" lg_info [%s]\n", EnDis(env->Env.lg_info)) ; + printf(" lg_max [%d]\n", env->Env.lg_max) ; + printf(" mp_info [%s]\n", EnDis(env->Env.mp_info)) ; + printf(" mp_size [%d]\n", env->Env.mp_size) ; + printf(" tx_info [%s]\n", EnDis(env->Env.tx_info)) ; + printf(" tx_max [%d]\n", env->Env.tx_max) ; + printf(" flags [%d]\n", env->Env.flags) ; + printf("\n") ; +#endif + +SV * +errPrefix(env, prefix) + BerkeleyDB::Env env + SV * prefix + INIT: + ckActive_Environment(env->active) ; + CODE: + if (env->ErrPrefix) { + RETVAL = newSVsv(env->ErrPrefix) ; + SvPOK_only(RETVAL) ; + sv_setsv(env->ErrPrefix, prefix) ; + } + else { + RETVAL = NULL ; + env->ErrPrefix = newSVsv(prefix) ; + } + SvPOK_only(env->ErrPrefix) ; +#if DB_VERSION_MAJOR == 2 + env->Env->db_errpfx = SvPVX(env->ErrPrefix) ; +#else + env->Env->set_errpfx(env->Env, SvPVX(env->ErrPrefix)) ; +#endif + OUTPUT: + RETVAL + +DualType +status(env) + BerkeleyDB::Env env + CODE: + RETVAL = env->Status ; + OUTPUT: + RETVAL + +DualType +db_appexit(env) + BerkeleyDB::Env env + INIT: + ckActive_Environment(env->active) ; + CODE: +#ifdef STRICT_CLOSE + if (env->open_dbs) + softCrash("attempted to close an environment with %d open database(s)", + env->open_dbs) ; +#endif /* STRICT_CLOSE */ +#if DB_VERSION_MAJOR == 2 + RETVAL = db_appexit(env->Env) ; +#else + RETVAL = (env->Env->close)(env->Env, 0) ; +#endif + env->active = FALSE ; + hash_delete("BerkeleyDB::Term::Env", (IV)env) ; + OUTPUT: + RETVAL + + +void +_DESTROY(env) + BerkeleyDB::Env env + int RETVAL = 0 ; + CODE: + Trace(("In BerkeleyDB::Env::DESTROY\n")); + Trace((" env %ld Env %ld dirty %d\n", env, &env->Env, PL_dirty)) ; + if (env->active) +#if DB_VERSION_MAJOR == 2 + db_appexit(env->Env) ; +#else + (env->Env->close)(env->Env, 0) ; +#endif + if (env->ErrHandle) + SvREFCNT_dec(env->ErrHandle) ; + if (env->ErrPrefix) + SvREFCNT_dec(env->ErrPrefix) ; +#if DB_VERSION_MAJOR == 2 + Safefree(env->Env) ; +#endif + Safefree(env) ; + hash_delete("BerkeleyDB::Term::Env", (IV)env) ; + Trace(("End of BerkeleyDB::Env::DESTROY %d\n", RETVAL)) ; + +BerkeleyDB::TxnMgr::Raw +_TxnMgr(env) + BerkeleyDB::Env env + INIT: + ckActive_Environment(env->active) ; + if (!env->txn_enabled) + softCrash("Transaction Manager not enabled") ; + CODE: + ZMALLOC(RETVAL, BerkeleyDB_TxnMgr_type) ; + RETVAL->env = env ; + /* hash_store_iv("BerkeleyDB::Term::TxnMgr", (IV)txn, 1) ; */ + OUTPUT: + RETVAL + +int +set_data_dir(env, dir) + BerkeleyDB::Env env + char * dir + INIT: + ckActive_Database(env->active) ; + CODE: +#ifndef AT_LEAST_DB_3_1 + softCrash("$env->set_data_dir needs Berkeley DB 3.1 or better") ; +#else + RETVAL = env->Status = env->Env->set_data_dir(env->Env, dir); +#endif + OUTPUT: + RETVAL + +int +set_lg_dir(env, dir) + BerkeleyDB::Env env + char * dir + INIT: + ckActive_Database(env->active) ; + CODE: +#ifndef AT_LEAST_DB_3_1 + softCrash("$env->set_lg_dir needs Berkeley DB 3.1 or better") ; +#else + RETVAL = env->Status = env->Env->set_lg_dir(env->Env, dir); +#endif + OUTPUT: + RETVAL + +int +set_tmp_dir(env, dir) + BerkeleyDB::Env env + char * dir + INIT: + ckActive_Database(env->active) ; + CODE: +#ifndef AT_LEAST_DB_3_1 + softCrash("$env->set_tmp_dir needs Berkeley DB 3.1 or better") ; +#else + RETVAL = env->Status = env->Env->set_tmp_dir(env->Env, dir); +#endif + OUTPUT: + RETVAL + +int +set_mutexlocks(env, do_lock) + BerkeleyDB::Env env + int do_lock + INIT: + ckActive_Database(env->active) ; + CODE: +#ifndef AT_LEAST_DB_3 + softCrash("$env->set_setmutexlocks needs Berkeley DB 3.0 or better") ; +#else +#if defined(IS_DB_3_0) || defined(AT_LEAST_DB_3_2) + RETVAL = env->Status = env->Env->set_mutexlocks(env->Env, do_lock); +#else /* DB 3.1 */ + RETVAL = env->Status = db_env_set_mutexlocks(do_lock); +#endif +#endif + OUTPUT: + RETVAL + +MODULE = BerkeleyDB::Term PACKAGE = BerkeleyDB::Term + +void +close_everything() + +#define safeCroak(string) softCrash(string) +void +safeCroak(string) + char * string + +MODULE = BerkeleyDB::Hash PACKAGE = BerkeleyDB::Hash PREFIX = hash_ + +BerkeleyDB::Hash::Raw +_db_open_hash(self, ref) + char * self + SV * ref + CODE: + { + HV * hash ; + SV * sv ; + DB_INFO info ; + BerkeleyDB__Env dbenv = NULL; + SV * ref_dbenv = NULL; + const char * file = NULL ; + const char * subname = NULL ; + int flags = 0 ; + int mode = 0 ; + BerkeleyDB db ; + + Trace(("_db_open_hash start\n")) ; + hash = (HV*) SvRV(ref) ; + SetValue_pv(file, "Filename", char *) ; + SetValue_pv(subname, "Subname", char *) ; + SetValue_ov(dbenv, "Env", BerkeleyDB__Env) ; + ref_dbenv = sv ; + SetValue_iv(flags, "Flags") ; + SetValue_iv(mode, "Mode") ; + + Zero(&info, 1, DB_INFO) ; + SetValue_iv(info.db_cachesize, "Cachesize") ; + SetValue_iv(info.db_lorder, "Lorder") ; + SetValue_iv(info.db_pagesize, "Pagesize") ; + SetValue_iv(info.h_ffactor, "Ffactor") ; + SetValue_iv(info.h_nelem, "Nelem") ; + SetValue_iv(info.flags, "Property") ; + ZMALLOC(db, BerkeleyDB_type) ; + if ((sv = readHash(hash, "Hash")) && sv != &PL_sv_undef) { + info.h_hash = hash_cb ; + db->hash = newSVsv(sv) ; + } + /* DB_DUPSORT was introduced in DB 2.5.9 */ + if ((sv = readHash(hash, "DupCompare")) && sv != &PL_sv_undef) { +#ifdef DB_DUPSORT + info.dup_compare = dup_compare ; + db->dup_compare = newSVsv(sv) ; + info.flags |= DB_DUP|DB_DUPSORT ; +#else + croak("DupCompare needs Berkeley DB 2.5.9 or later") ; +#endif + } + RETVAL = my_db_open(db, ref, ref_dbenv, dbenv, file, subname, DB_HASH, flags, mode, &info) ; + Trace(("_db_open_hash end\n")) ; + } + OUTPUT: + RETVAL + + +HV * +db_stat(db, flags=0) + BerkeleyDB::Common db + int flags + HV * RETVAL = NULL ; + INIT: + ckActive_Database(db->active) ; + CODE: + { +#if DB_VERSION_MAJOR == 2 + softCrash("$db->db_stat for a Hash needs Berkeley DB 3.x or better") ; +#else + DB_HASH_STAT * stat ; + db->Status = ((db->dbp)->stat)(db->dbp, &stat, safemalloc, flags) ; + if (db->Status == 0) { + RETVAL = (HV*)sv_2mortal((SV*)newHV()) ; + hv_store_iv(RETVAL, "hash_magic", stat->hash_magic) ; + hv_store_iv(RETVAL, "hash_version", stat->hash_version); + hv_store_iv(RETVAL, "hash_pagesize", stat->hash_pagesize); +#ifdef AT_LEAST_DB_3_1 + hv_store_iv(RETVAL, "hash_nkeys", stat->hash_nkeys); + hv_store_iv(RETVAL, "hash_ndata", stat->hash_ndata); +#else + hv_store_iv(RETVAL, "hash_nrecs", stat->hash_nrecs); +#endif + hv_store_iv(RETVAL, "hash_nelem", stat->hash_nelem); + hv_store_iv(RETVAL, "hash_ffactor", stat->hash_ffactor); + hv_store_iv(RETVAL, "hash_buckets", stat->hash_buckets); + hv_store_iv(RETVAL, "hash_free", stat->hash_free); + hv_store_iv(RETVAL, "hash_bfree", stat->hash_bfree); + hv_store_iv(RETVAL, "hash_bigpages", stat->hash_bigpages); + hv_store_iv(RETVAL, "hash_big_bfree", stat->hash_big_bfree); + hv_store_iv(RETVAL, "hash_overflows", stat->hash_overflows); + hv_store_iv(RETVAL, "hash_ovfl_free", stat->hash_ovfl_free); + hv_store_iv(RETVAL, "hash_dup", stat->hash_dup); + hv_store_iv(RETVAL, "hash_dup_free", stat->hash_dup_free); +#if DB_VERSION_MAJOR >= 3 + hv_store_iv(RETVAL, "hash_metaflags", stat->hash_metaflags); +#endif + safefree(stat) ; + } +#endif + } + OUTPUT: + RETVAL + + +MODULE = BerkeleyDB::Unknown PACKAGE = BerkeleyDB::Unknown PREFIX = hash_ + +void +_db_open_unknown(ref) + SV * ref + PPCODE: + { + HV * hash ; + SV * sv ; + DB_INFO info ; + BerkeleyDB__Env dbenv = NULL; + SV * ref_dbenv = NULL; + const char * file = NULL ; + const char * subname = NULL ; + int flags = 0 ; + int mode = 0 ; + BerkeleyDB db ; + BerkeleyDB RETVAL ; + static char * Names[] = {"", "Btree", "Hash", "Recno"} ; + + hash = (HV*) SvRV(ref) ; + SetValue_pv(file, "Filename", char *) ; + SetValue_pv(subname, "Subname", char *) ; + SetValue_ov(dbenv, "Env", BerkeleyDB__Env) ; + ref_dbenv = sv ; + SetValue_iv(flags, "Flags") ; + SetValue_iv(mode, "Mode") ; + + Zero(&info, 1, DB_INFO) ; + SetValue_iv(info.db_cachesize, "Cachesize") ; + SetValue_iv(info.db_lorder, "Lorder") ; + SetValue_iv(info.db_pagesize, "Pagesize") ; + SetValue_iv(info.h_ffactor, "Ffactor") ; + SetValue_iv(info.h_nelem, "Nelem") ; + SetValue_iv(info.flags, "Property") ; + ZMALLOC(db, BerkeleyDB_type) ; + + RETVAL = my_db_open(db, ref, ref_dbenv, dbenv, file, subname, DB_UNKNOWN, flags, mode, &info) ; + XPUSHs(sv_2mortal(newSViv((IV)RETVAL))); + if (RETVAL) + XPUSHs(sv_2mortal(newSVpv(Names[RETVAL->type], 0))) ; + else + XPUSHs(sv_2mortal(newSViv((IV)NULL))); + } + + + +MODULE = BerkeleyDB::Btree PACKAGE = BerkeleyDB::Btree PREFIX = btree_ + +BerkeleyDB::Btree::Raw +_db_open_btree(self, ref) + char * self + SV * ref + CODE: + { + HV * hash ; + SV * sv ; + DB_INFO info ; + BerkeleyDB__Env dbenv = NULL; + SV * ref_dbenv = NULL; + const char * file = NULL ; + const char * subname = NULL ; + int flags = 0 ; + int mode = 0 ; + BerkeleyDB db ; + + hash = (HV*) SvRV(ref) ; + SetValue_pv(file, "Filename", char*) ; + SetValue_pv(subname, "Subname", char *) ; + SetValue_ov(dbenv, "Env", BerkeleyDB__Env) ; + ref_dbenv = sv ; + SetValue_iv(flags, "Flags") ; + SetValue_iv(mode, "Mode") ; + + Zero(&info, 1, DB_INFO) ; + SetValue_iv(info.db_cachesize, "Cachesize") ; + SetValue_iv(info.db_lorder, "Lorder") ; + SetValue_iv(info.db_pagesize, "Pagesize") ; + SetValue_iv(info.bt_minkey, "Minkey") ; + SetValue_iv(info.flags, "Property") ; + ZMALLOC(db, BerkeleyDB_type) ; + if ((sv = readHash(hash, "Compare")) && sv != &PL_sv_undef) { + info.bt_compare = btree_compare ; + db->compare = newSVsv(sv) ; + } + /* DB_DUPSORT was introduced in DB 2.5.9 */ + if ((sv = readHash(hash, "DupCompare")) && sv != &PL_sv_undef) { +#ifdef DB_DUPSORT + info.dup_compare = dup_compare ; + db->dup_compare = newSVsv(sv) ; + info.flags |= DB_DUP|DB_DUPSORT ; +#else + softCrash("DupCompare needs Berkeley DB 2.5.9 or later") ; +#endif + } + if ((sv = readHash(hash, "Prefix")) && sv != &PL_sv_undef) { + info.bt_prefix = btree_prefix ; + db->prefix = newSVsv(sv) ; + } + + RETVAL = my_db_open(db, ref, ref_dbenv, dbenv, file, subname, DB_BTREE, flags, mode, &info) ; + } + OUTPUT: + RETVAL + + +HV * +db_stat(db, flags=0) + BerkeleyDB::Common db + int flags + HV * RETVAL = NULL ; + INIT: + ckActive_Database(db->active) ; + CODE: + { + DB_BTREE_STAT * stat ; + db->Status = ((db->dbp)->stat)(db->dbp, &stat, safemalloc, flags) ; + if (db->Status == 0) { + RETVAL = (HV*)sv_2mortal((SV*)newHV()) ; + hv_store_iv(RETVAL, "bt_magic", stat->bt_magic); + hv_store_iv(RETVAL, "bt_version", stat->bt_version); +#if DB_VERSION_MAJOR > 2 + hv_store_iv(RETVAL, "bt_metaflags", stat->bt_metaflags) ; + hv_store_iv(RETVAL, "bt_flags", stat->bt_metaflags) ; +#else + hv_store_iv(RETVAL, "bt_flags", stat->bt_flags) ; +#endif + hv_store_iv(RETVAL, "bt_maxkey", stat->bt_maxkey) ; + hv_store_iv(RETVAL, "bt_minkey", stat->bt_minkey); + hv_store_iv(RETVAL, "bt_re_len", stat->bt_re_len); + hv_store_iv(RETVAL, "bt_re_pad", stat->bt_re_pad); + hv_store_iv(RETVAL, "bt_pagesize", stat->bt_pagesize); + hv_store_iv(RETVAL, "bt_levels", stat->bt_levels); +#ifdef AT_LEAST_DB_3_1 + hv_store_iv(RETVAL, "bt_nkeys", stat->bt_nkeys); + hv_store_iv(RETVAL, "bt_ndata", stat->bt_ndata); +#else + hv_store_iv(RETVAL, "bt_nrecs", stat->bt_nrecs); +#endif + hv_store_iv(RETVAL, "bt_int_pg", stat->bt_int_pg); + hv_store_iv(RETVAL, "bt_leaf_pg", stat->bt_leaf_pg); + hv_store_iv(RETVAL, "bt_dup_pg", stat->bt_dup_pg); + hv_store_iv(RETVAL, "bt_over_pg", stat->bt_over_pg); + hv_store_iv(RETVAL, "bt_free", stat->bt_free); +#if DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR < 5 + hv_store_iv(RETVAL, "bt_freed", stat->bt_freed); + hv_store_iv(RETVAL, "bt_pfxsaved", stat->bt_pfxsaved); + hv_store_iv(RETVAL, "bt_split", stat->bt_split); + hv_store_iv(RETVAL, "bt_rootsplit", stat->bt_rootsplit); + hv_store_iv(RETVAL, "bt_fastsplit", stat->bt_fastsplit); + hv_store_iv(RETVAL, "bt_added", stat->bt_added); + hv_store_iv(RETVAL, "bt_deleted", stat->bt_deleted); + hv_store_iv(RETVAL, "bt_get", stat->bt_get); + hv_store_iv(RETVAL, "bt_cache_hit", stat->bt_cache_hit); + hv_store_iv(RETVAL, "bt_cache_miss", stat->bt_cache_miss); +#endif + hv_store_iv(RETVAL, "bt_int_pgfree", stat->bt_int_pgfree); + hv_store_iv(RETVAL, "bt_leaf_pgfree", stat->bt_leaf_pgfree); + hv_store_iv(RETVAL, "bt_dup_pgfree", stat->bt_dup_pgfree); + hv_store_iv(RETVAL, "bt_over_pgfree", stat->bt_over_pgfree); + safefree(stat) ; + } + } + OUTPUT: + RETVAL + + +MODULE = BerkeleyDB::Recno PACKAGE = BerkeleyDB::Recno PREFIX = recno_ + +BerkeleyDB::Recno::Raw +_db_open_recno(self, ref) + char * self + SV * ref + CODE: + { + HV * hash ; + SV * sv ; + DB_INFO info ; + BerkeleyDB__Env dbenv = NULL; + SV * ref_dbenv = NULL; + const char * file = NULL ; + const char * subname = NULL ; + int flags = 0 ; + int mode = 0 ; + BerkeleyDB db ; + + hash = (HV*) SvRV(ref) ; + SetValue_pv(file, "Fname", char*) ; + SetValue_ov(dbenv, "Env", BerkeleyDB__Env) ; + ref_dbenv = sv ; + SetValue_iv(flags, "Flags") ; + SetValue_iv(mode, "Mode") ; + + Zero(&info, 1, DB_INFO) ; + SetValue_iv(info.db_cachesize, "Cachesize") ; + SetValue_iv(info.db_lorder, "Lorder") ; + SetValue_iv(info.db_pagesize, "Pagesize") ; + SetValue_iv(info.bt_minkey, "Minkey") ; + + SetValue_iv(info.flags, "Property") ; + SetValue_pv(info.re_source, "Source", char*) ; + if ((sv = readHash(hash, "Len")) && sv != &PL_sv_undef) { + info.re_len = SvIV(sv) ; ; + flagSet_DB2(info.flags, DB_FIXEDLEN) ; + } + if ((sv = readHash(hash, "Delim")) && sv != &PL_sv_undef) { + info.re_delim = SvPOK(sv) ? *SvPV(sv,PL_na) : SvIV(sv) ; ; + flagSet_DB2(info.flags, DB_DELIMITER) ; + } + if ((sv = readHash(hash, "Pad")) && sv != &PL_sv_undef) { + info.re_pad = (u_int32_t)SvPOK(sv) ? *SvPV(sv,PL_na) : SvIV(sv) ; ; + flagSet_DB2(info.flags, DB_PAD) ; + } + ZMALLOC(db, BerkeleyDB_type) ; +#ifdef ALLOW_RECNO_OFFSET + SetValue_iv(db->array_base, "ArrayBase") ; + db->array_base = (db->array_base == 0 ? 1 : 0) ; +#endif /* ALLOW_RECNO_OFFSET */ + + RETVAL = my_db_open(db, ref, ref_dbenv, dbenv, file, subname, DB_RECNO, flags, mode, &info) ; + } + OUTPUT: + RETVAL + + +MODULE = BerkeleyDB::Queue PACKAGE = BerkeleyDB::Queue PREFIX = recno_ + +BerkeleyDB::Queue::Raw +_db_open_queue(self, ref) + char * self + SV * ref + CODE: + { +#ifndef AT_LEAST_DB_3 + softCrash("BerkeleyDB::Queue needs Berkeley DB 3.0.x or better"); +#else + HV * hash ; + SV * sv ; + DB_INFO info ; + BerkeleyDB__Env dbenv = NULL; + SV * ref_dbenv = NULL; + const char * file = NULL ; + const char * subname = NULL ; + int flags = 0 ; + int mode = 0 ; + BerkeleyDB db ; + + hash = (HV*) SvRV(ref) ; + SetValue_pv(file, "Fname", char*) ; + SetValue_ov(dbenv, "Env", BerkeleyDB__Env) ; + ref_dbenv = sv ; + SetValue_iv(flags, "Flags") ; + SetValue_iv(mode, "Mode") ; + + Zero(&info, 1, DB_INFO) ; + SetValue_iv(info.db_cachesize, "Cachesize") ; + SetValue_iv(info.db_lorder, "Lorder") ; + SetValue_iv(info.db_pagesize, "Pagesize") ; + SetValue_iv(info.bt_minkey, "Minkey") ; + SetValue_iv(info.q_extentsize, "ExtentSize") ; + + + SetValue_iv(info.flags, "Property") ; + if ((sv = readHash(hash, "Len")) && sv != &PL_sv_undef) { + info.re_len = SvIV(sv) ; ; + flagSet_DB2(info.flags, DB_PAD) ; + } + if ((sv = readHash(hash, "Pad")) && sv != &PL_sv_undef) { + info.re_pad = (u_int32_t)SvPOK(sv) ? *SvPV(sv,PL_na) : SvIV(sv) ; ; + flagSet_DB2(info.flags, DB_PAD) ; + } + ZMALLOC(db, BerkeleyDB_type) ; +#ifdef ALLOW_RECNO_OFFSET + SetValue_iv(db->array_base, "ArrayBase") ; + db->array_base = (db->array_base == 0 ? 1 : 0) ; +#endif /* ALLOW_RECNO_OFFSET */ + + RETVAL = my_db_open(db, ref, ref_dbenv, dbenv, file, subname, DB_QUEUE, flags, mode, &info) ; +#endif + } + OUTPUT: + RETVAL + +HV * +db_stat(db, flags=0) + BerkeleyDB::Common db + int flags + HV * RETVAL = NULL ; + INIT: + ckActive_Database(db->active) ; + CODE: + { +#if DB_VERSION_MAJOR == 2 + softCrash("$db->db_stat for a Queue needs Berkeley DB 3.x or better") ; +#else /* Berkeley DB 3, or better */ + DB_QUEUE_STAT * stat ; + db->Status = ((db->dbp)->stat)(db->dbp, &stat, safemalloc, flags) ; + if (db->Status == 0) { + RETVAL = (HV*)sv_2mortal((SV*)newHV()) ; + hv_store_iv(RETVAL, "qs_magic", stat->qs_magic) ; + hv_store_iv(RETVAL, "qs_version", stat->qs_version); +#ifdef AT_LEAST_DB_3_1 + hv_store_iv(RETVAL, "qs_nkeys", stat->qs_nkeys); + hv_store_iv(RETVAL, "qs_ndata", stat->qs_ndata); +#else + hv_store_iv(RETVAL, "qs_nrecs", stat->qs_nrecs); +#endif + hv_store_iv(RETVAL, "qs_pages", stat->qs_pages); + hv_store_iv(RETVAL, "qs_pagesize", stat->qs_pagesize); + hv_store_iv(RETVAL, "qs_pgfree", stat->qs_pgfree); + hv_store_iv(RETVAL, "qs_re_len", stat->qs_re_len); + hv_store_iv(RETVAL, "qs_re_pad", stat->qs_re_pad); +#ifdef AT_LEAST_DB_3_2 +#else + hv_store_iv(RETVAL, "qs_start", stat->qs_start); +#endif + hv_store_iv(RETVAL, "qs_first_recno", stat->qs_first_recno); + hv_store_iv(RETVAL, "qs_cur_recno", stat->qs_cur_recno); +#if DB_VERSION_MAJOR >= 3 + hv_store_iv(RETVAL, "qs_metaflags", stat->qs_metaflags); +#endif + safefree(stat) ; + } +#endif + } + OUTPUT: + RETVAL + + +MODULE = BerkeleyDB::Common PACKAGE = BerkeleyDB::Common PREFIX = dab_ + + +DualType +db_close(db,flags=0) + BerkeleyDB::Common db + int flags + INIT: + ckActive_Database(db->active) ; + CurrentDB = db ; + CODE: + Trace(("BerkeleyDB::Common::db_close %d\n", db)); +#ifdef STRICT_CLOSE + if (db->txn) + softCrash("attempted to close a database while a transaction was still open") ; + if (db->open_cursors) + softCrash("attempted to close a database with %d open cursor(s)", + db->open_cursors) ; +#endif /* STRICT_CLOSE */ + RETVAL = db->Status = ((db->dbp)->close)(db->dbp, flags) ; + if (db->parent_env && db->parent_env->open_dbs) + -- db->parent_env->open_dbs ; + db->active = FALSE ; + hash_delete("BerkeleyDB::Term::Db", (IV)db) ; + -- db->open_cursors ; + Trace(("end of BerkeleyDB::Common::db_close\n")); + OUTPUT: + RETVAL + +void +dab__DESTROY(db) + BerkeleyDB::Common db + CODE: + CurrentDB = db ; + Trace(("In BerkeleyDB::Common::_DESTROY db %d dirty=%d\n", db, PL_dirty)) ; + destroyDB(db) ; + Trace(("End of BerkeleyDB::Common::DESTROY \n")) ; + +#if DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR < 6 +#define db_cursor(db, txn, cur,flags) ((db->dbp)->cursor)(db->dbp, txn, cur) +#else +#define db_cursor(db, txn, cur,flags) ((db->dbp)->cursor)(db->dbp, txn, cur,flags) +#endif +BerkeleyDB::Cursor::Raw +_db_cursor(db, flags=0) + BerkeleyDB::Common db + u_int32_t flags + BerkeleyDB::Cursor RETVAL = NULL ; + INIT: + ckActive_Database(db->active) ; + CODE: + { + DBC * cursor ; + CurrentDB = db ; + if ((db->Status = db_cursor(db, db->txn, &cursor, flags)) == 0){ + ZMALLOC(RETVAL, BerkeleyDB__Cursor_type) ; + db->open_cursors ++ ; + RETVAL->parent_db = db ; + RETVAL->cursor = cursor ; + RETVAL->dbp = db->dbp ; + RETVAL->type = db->type ; + RETVAL->recno_or_queue = db->recno_or_queue ; + RETVAL->filename = my_strdup(db->filename) ; + RETVAL->compare = db->compare ; + RETVAL->dup_compare = db->dup_compare ; + RETVAL->prefix = db->prefix ; + RETVAL->hash = db->hash ; + RETVAL->partial = db->partial ; + RETVAL->doff = db->doff ; + RETVAL->dlen = db->dlen ; + RETVAL->active = TRUE ; +#ifdef ALLOW_RECNO_OFFSET + RETVAL->array_base = db->array_base ; +#endif /* ALLOW_RECNO_OFFSET */ +#ifdef DBM_FILTERING + RETVAL->filtering = FALSE ; + RETVAL->filter_fetch_key = db->filter_fetch_key ; + RETVAL->filter_store_key = db->filter_store_key ; + RETVAL->filter_fetch_value = db->filter_fetch_value ; + RETVAL->filter_store_value = db->filter_store_value ; +#endif + /* RETVAL->info ; */ + hash_store_iv("BerkeleyDB::Term::Cursor", (IV)RETVAL, 1) ; + } + } + OUTPUT: + RETVAL + +BerkeleyDB::Cursor::Raw +_db_join(db, cursors, flags=0) + BerkeleyDB::Common db + AV * cursors + u_int32_t flags + BerkeleyDB::Cursor RETVAL = NULL ; + INIT: + ckActive_Database(db->active) ; + CODE: + { +#if DB_VERSION_MAJOR == 2 && (DB_VERSION_MINOR < 5 || (DB_VERSION_MINOR == 5 && DB_VERSION_PATCH < 2)) + softCrash("join needs Berkeley DB 2.5.2 or later") ; +#else /* Berkeley DB >= 2.5.2 */ + DBC * join_cursor ; + DBC ** cursor_list ; + I32 count = av_len(cursors) + 1 ; + int i ; + CurrentDB = db ; + if (count < 1 ) + softCrash("db_join: No cursors in parameter list") ; + cursor_list = (DBC **)safemalloc(sizeof(DBC*) * (count + 1)); + for (i = 0 ; i < count ; ++i) { + SV * obj = (SV*) * av_fetch(cursors, i, FALSE) ; + BerkeleyDB__Cursor cur = (BerkeleyDB__Cursor) getInnerObject(obj) ; + cursor_list[i] = cur->cursor ; + } + cursor_list[i] = NULL ; +#if DB_VERSION_MAJOR == 2 + if ((db->Status = ((db->dbp)->join)(db->dbp, cursor_list, flags, &join_cursor)) == 0){ +#else + if ((db->Status = ((db->dbp)->join)(db->dbp, cursor_list, &join_cursor, flags)) == 0){ +#endif + ZMALLOC(RETVAL, BerkeleyDB__Cursor_type) ; + db->open_cursors ++ ; + RETVAL->parent_db = db ; + RETVAL->cursor = join_cursor ; + RETVAL->dbp = db->dbp ; + RETVAL->type = db->type ; + RETVAL->filename = my_strdup(db->filename) ; + RETVAL->compare = db->compare ; + RETVAL->dup_compare = db->dup_compare ; + RETVAL->prefix = db->prefix ; + RETVAL->hash = db->hash ; + RETVAL->partial = db->partial ; + RETVAL->doff = db->doff ; + RETVAL->dlen = db->dlen ; + RETVAL->active = TRUE ; +#ifdef ALLOW_RECNO_OFFSET + RETVAL->array_base = db->array_base ; +#endif /* ALLOW_RECNO_OFFSET */ +#ifdef DBM_FILTERING + RETVAL->filtering = FALSE ; + RETVAL->filter_fetch_key = db->filter_fetch_key ; + RETVAL->filter_store_key = db->filter_store_key ; + RETVAL->filter_fetch_value = db->filter_fetch_value ; + RETVAL->filter_store_value = db->filter_store_value ; +#endif + /* RETVAL->info ; */ + hash_store_iv("BerkeleyDB::Term::Cursor", (IV)RETVAL, 1) ; + } + safefree(cursor_list) ; +#endif /* Berkeley DB >= 2.5.2 */ + } + OUTPUT: + RETVAL + +int +ArrayOffset(db) + BerkeleyDB::Common db + INIT: + ckActive_Database(db->active) ; + CODE: +#ifdef ALLOW_RECNO_OFFSET + RETVAL = db->array_base ? 0 : 1 ; +#else + RETVAL = 0 ; +#endif /* ALLOW_RECNO_OFFSET */ + OUTPUT: + RETVAL + +int +type(db) + BerkeleyDB::Common db + INIT: + ckActive_Database(db->active) ; + CODE: + RETVAL = db->type ; + OUTPUT: + RETVAL + +int +byteswapped(db) + BerkeleyDB::Common db + INIT: + ckActive_Database(db->active) ; + CODE: +#if DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR < 5 + softCrash("byteswapped needs Berkeley DB 2.5 or later") ; +#else +#if DB_VERSION_MAJOR == 2 + RETVAL = db->dbp->byteswapped ; +#else + RETVAL = db->dbp->get_byteswapped(db->dbp) ; +#endif +#endif + OUTPUT: + RETVAL + +DualType +status(db) + BerkeleyDB::Common db + CODE: + RETVAL = db->Status ; + OUTPUT: + RETVAL + +#ifdef DBM_FILTERING + +#define setFilter(ftype) \ + { \ + if (db->ftype) \ + RETVAL = sv_mortalcopy(db->ftype) ; \ + ST(0) = RETVAL ; \ + if (db->ftype && (code == &PL_sv_undef)) { \ + SvREFCNT_dec(db->ftype) ; \ + db->ftype = NULL ; \ + } \ + else if (code) { \ + if (db->ftype) \ + sv_setsv(db->ftype, code) ; \ + else \ + db->ftype = newSVsv(code) ; \ + } \ + } + + +SV * +filter_fetch_key(db, code) + BerkeleyDB::Common db + SV * code + SV * RETVAL = &PL_sv_undef ; + CODE: + setFilter(filter_fetch_key) ; + +SV * +filter_store_key(db, code) + BerkeleyDB::Common db + SV * code + SV * RETVAL = &PL_sv_undef ; + CODE: + setFilter(filter_store_key) ; + +SV * +filter_fetch_value(db, code) + BerkeleyDB::Common db + SV * code + SV * RETVAL = &PL_sv_undef ; + CODE: + setFilter(filter_fetch_value) ; + +SV * +filter_store_value(db, code) + BerkeleyDB::Common db + SV * code + SV * RETVAL = &PL_sv_undef ; + CODE: + setFilter(filter_store_value) ; + +#endif /* DBM_FILTERING */ + +void +partial_set(db, offset, length) + BerkeleyDB::Common db + u_int32_t offset + u_int32_t length + INIT: + ckActive_Database(db->active) ; + PPCODE: + if (GIMME == G_ARRAY) { + XPUSHs(sv_2mortal(newSViv(db->partial == DB_DBT_PARTIAL))) ; + XPUSHs(sv_2mortal(newSViv(db->doff))) ; + XPUSHs(sv_2mortal(newSViv(db->dlen))) ; + } + db->partial = DB_DBT_PARTIAL ; + db->doff = offset ; + db->dlen = length ; + + +void +partial_clear(db) + BerkeleyDB::Common db + INIT: + ckActive_Database(db->active) ; + PPCODE: + if (GIMME == G_ARRAY) { + XPUSHs(sv_2mortal(newSViv(db->partial == DB_DBT_PARTIAL))) ; + XPUSHs(sv_2mortal(newSViv(db->doff))) ; + XPUSHs(sv_2mortal(newSViv(db->dlen))) ; + } + db->partial = + db->doff = + db->dlen = 0 ; + + +#define db_del(db, key, flags) \ + (db->Status = ((db->dbp)->del)(db->dbp, db->txn, &key, flags)) +DualType +db_del(db, key, flags=0) + BerkeleyDB::Common db + DBTKEY key + u_int flags + INIT: + ckActive_Database(db->active) ; + CurrentDB = db ; + + +#define db_get(db, key, data, flags) \ + (db->Status = ((db->dbp)->get)(db->dbp, db->txn, &key, &data, flags)) +DualType +db_get(db, key, data, flags=0) + BerkeleyDB::Common db + u_int flags + DBTKEY_B key + DBT_OPT data + INIT: + ckActive_Database(db->active) ; + CurrentDB = db ; + SetPartial(data,db) ; + OUTPUT: + key if (flagSet(DB_SET_RECNO)) OutputValue(ST(1), key) ; + data + +#define db_put(db,key,data,flag) \ + (db->Status = (db->dbp->put)(db->dbp,db->txn,&key,&data,flag)) +DualType +db_put(db, key, data, flags=0) + BerkeleyDB::Common db + DBTKEY key + DBT data + u_int flags + INIT: + ckActive_Database(db->active) ; + CurrentDB = db ; + /* SetPartial(data,db) ; */ + OUTPUT: + key if (flagSet(DB_APPEND)) OutputKey(ST(1), key) ; + +#define db_key_range(db, key, range, flags) \ + (db->Status = ((db->dbp)->key_range)(db->dbp, db->txn, &key, &range, flags)) +DualType +db_key_range(db, key, less, equal, greater, flags=0) + BerkeleyDB::Common db + DBTKEY_B key + double less = NO_INIT + double equal = NO_INIT + double greater = NO_INIT + u_int32_t flags + CODE: + { +#ifndef AT_LEAST_DB_3_1 + softCrash("key_range needs Berkeley DB 3.1.x or later") ; +#else + DB_KEY_RANGE range ; + range.less = range.equal = range.greater = 0.0 ; + ckActive_Database(db->active) ; + CurrentDB = db ; + RETVAL = db_key_range(db, key, range, flags); + if (RETVAL == 0) { + less = range.less ; + equal = range.equal; + greater = range.greater; + } +#endif + } + OUTPUT: + RETVAL + less + equal + greater + + +#define db_fd(d, x) (db->Status = (db->dbp->fd)(db->dbp, &x)) +DualType +db_fd(db) + BerkeleyDB::Common db + INIT: + ckActive_Database(db->active) ; + CODE: + CurrentDB = db ; + db_fd(db, RETVAL) ; + OUTPUT: + RETVAL + + +#define db_sync(db, fl) (db->Status = (db->dbp->sync)(db->dbp, fl)) +DualType +db_sync(db, flags=0) + BerkeleyDB::Common db + u_int flags + INIT: + ckActive_Database(db->active) ; + CurrentDB = db ; + +void +_Txn(db, txn=NULL) + BerkeleyDB::Common db + BerkeleyDB::Txn txn + INIT: + ckActive_Database(db->active) ; + CODE: + if (txn) { + Trace(("_Txn(%d in %d) active [%d]\n", txn->txn, txn, txn->active)); + ckActive_Transaction(txn->active) ; + db->txn = txn->txn ; + } + else { + Trace(("_Txn(undef) \n")); + db->txn = NULL ; + } + + + + +MODULE = BerkeleyDB::Cursor PACKAGE = BerkeleyDB::Cursor PREFIX = cu_ + +BerkeleyDB::Cursor::Raw +_c_dup(db, flags=0) + BerkeleyDB::Cursor db + u_int32_t flags + BerkeleyDB::Cursor RETVAL = NULL ; + INIT: + CurrentDB = db->parent_db ; + ckActive_Database(db->active) ; + CODE: + { +#ifndef AT_LEAST_DB_3 + softCrash("c_dup needs at least Berkeley DB 3.0.x"); +#else + DBC * newcursor ; + db->Status = ((db->cursor)->c_dup)(db->cursor, &newcursor, flags) ; + if (db->Status == 0){ + ZMALLOC(RETVAL, BerkeleyDB__Cursor_type) ; + db->parent_db->open_cursors ++ ; + RETVAL->parent_db = db->parent_db ; + RETVAL->cursor = newcursor ; + RETVAL->dbp = db->dbp ; + RETVAL->type = db->type ; + RETVAL->recno_or_queue = db->recno_or_queue ; + RETVAL->filename = my_strdup(db->filename) ; + RETVAL->compare = db->compare ; + RETVAL->dup_compare = db->dup_compare ; + RETVAL->prefix = db->prefix ; + RETVAL->hash = db->hash ; + RETVAL->partial = db->partial ; + RETVAL->doff = db->doff ; + RETVAL->dlen = db->dlen ; + RETVAL->active = TRUE ; +#ifdef ALLOW_RECNO_OFFSET + RETVAL->array_base = db->array_base ; +#endif /* ALLOW_RECNO_OFFSET */ +#ifdef DBM_FILTERING + RETVAL->filtering = FALSE ; + RETVAL->filter_fetch_key = db->filter_fetch_key ; + RETVAL->filter_store_key = db->filter_store_key ; + RETVAL->filter_fetch_value = db->filter_fetch_value ; + RETVAL->filter_store_value = db->filter_store_value ; +#endif /* DBM_FILTERING */ + /* RETVAL->info ; */ + hash_store_iv("BerkeleyDB::Term::Cursor", (IV)RETVAL, 1) ; + } +#endif + } + OUTPUT: + RETVAL + +DualType +_c_close(db) + BerkeleyDB::Cursor db + INIT: + CurrentDB = db->parent_db ; + ckActive_Cursor(db->active) ; + hash_delete("BerkeleyDB::Term::Cursor", (IV)db) ; + CODE: + RETVAL = db->Status = + ((db->cursor)->c_close)(db->cursor) ; + db->active = FALSE ; + if (db->parent_db->open_cursors) + -- db->parent_db->open_cursors ; + OUTPUT: + RETVAL + +void +_DESTROY(db) + BerkeleyDB::Cursor db + CODE: + CurrentDB = db->parent_db ; + Trace(("In BerkeleyDB::Cursor::_DESTROY db %d dirty=%d active=%d\n", db, PL_dirty, db->active)); + hash_delete("BerkeleyDB::Term::Cursor", (IV)db) ; + if (db->active) + ((db->cursor)->c_close)(db->cursor) ; + if (db->parent_db->open_cursors) + -- db->parent_db->open_cursors ; + Safefree(db->filename) ; + Safefree(db) ; + Trace(("End of BerkeleyDB::Cursor::_DESTROY\n")) ; + +DualType +status(db) + BerkeleyDB::Cursor db + CODE: + RETVAL = db->Status ; + OUTPUT: + RETVAL + + +#define cu_c_del(c,f) (c->Status = ((c->cursor)->c_del)(c->cursor,f)) +DualType +cu_c_del(db, flags=0) + BerkeleyDB::Cursor db + int flags + INIT: + CurrentDB = db->parent_db ; + ckActive_Cursor(db->active) ; + OUTPUT: + RETVAL + + +#define cu_c_get(c,k,d,f) (c->Status = (c->cursor->c_get)(c->cursor,&k,&d,f)) +DualType +cu_c_get(db, key, data, flags=0) + BerkeleyDB::Cursor db + int flags + DBTKEY_B key + DBT_B data + INIT: + Trace(("c_get db [%d] flags [%d]\n", db, flags)) ; + CurrentDB = db->parent_db ; + ckActive_Cursor(db->active) ; + SetPartial(data,db) ; + Trace(("c_get end\n")) ; + OUTPUT: + RETVAL + key + data if (! flagSet(DB_JOIN_ITEM)) OutputValue_B(ST(2), data) ; + + +#define cu_c_put(c,k,d,f) (c->Status = (c->cursor->c_put)(c->cursor,&k,&d,f)) +DualType +cu_c_put(db, key, data, flags=0) + BerkeleyDB::Cursor db + DBTKEY key + DBT data + int flags + INIT: + CurrentDB = db->parent_db ; + ckActive_Cursor(db->active) ; + /* SetPartial(data,db) ; */ + OUTPUT: + RETVAL + +#define cu_c_count(c,p,f) (c->Status = (c->cursor->c_count)(c->cursor,&p,f)) +DualType +cu_c_count(db, count, flags=0) + BerkeleyDB::Cursor db + u_int32_t count = NO_INIT + int flags + CODE: +#ifndef AT_LEAST_DB_3_1 + softCrash("c_count needs at least Berkeley DB 3.1.x"); +#else + Trace(("c_get count [%d] flags [%d]\n", db, flags)) ; + CurrentDB = db->parent_db ; + ckActive_Cursor(db->active) ; + RETVAL = cu_c_count(db, count, flags) ; + Trace((" c_count got %d duplicates\n", count)) ; +#endif + OUTPUT: + RETVAL + count + +MODULE = BerkeleyDB::TxnMgr PACKAGE = BerkeleyDB::TxnMgr PREFIX = xx_ + +BerkeleyDB::Txn::Raw +_txn_begin(txnmgr, pid=NULL, flags=0) + BerkeleyDB::TxnMgr txnmgr + BerkeleyDB::Txn pid + u_int32_t flags + CODE: + { + DB_TXN *txn ; + DB_TXN *p_id = NULL ; +#if DB_VERSION_MAJOR == 2 + if (txnmgr->env->Env->tx_info == NULL) + softCrash("Transaction Manager not enabled") ; +#endif + if (pid) + p_id = pid->txn ; + txnmgr->env->TxnMgrStatus = +#if DB_VERSION_MAJOR == 2 + txn_begin(txnmgr->env->Env->tx_info, p_id, &txn) ; +#else + txn_begin(txnmgr->env->Env, p_id, &txn, flags) ; +#endif + if (txnmgr->env->TxnMgrStatus == 0) { + ZMALLOC(RETVAL, BerkeleyDB_Txn_type) ; + RETVAL->txn = txn ; + RETVAL->active = TRUE ; + Trace(("_txn_begin created txn [%d] in [%d]\n", txn, RETVAL)); + hash_store_iv("BerkeleyDB::Term::Txn", (IV)RETVAL, 1) ; + } + else + RETVAL = NULL ; + } + OUTPUT: + RETVAL + + +DualType +status(mgr) + BerkeleyDB::TxnMgr mgr + CODE: + RETVAL = mgr->env->TxnMgrStatus ; + OUTPUT: + RETVAL + + +void +_DESTROY(mgr) + BerkeleyDB::TxnMgr mgr + CODE: + Trace(("In BerkeleyDB::TxnMgr::DESTROY dirty=%d\n", PL_dirty)) ; + Safefree(mgr) ; + Trace(("End of BerkeleyDB::TxnMgr::DESTROY\n")) ; + +DualType +txn_close(txnp) + BerkeleyDB::TxnMgr txnp + NOT_IMPLEMENTED_YET + + +#if DB_VERSION_MAJOR == 2 +# define xx_txn_checkpoint(t,k,m) txn_checkpoint(t->env->Env->tx_info, k, m) +#else +# ifdef AT_LEAST_DB_3_1 +# define xx_txn_checkpoint(t,k,m) txn_checkpoint(t->env->Env, k, m, 0) +# else +# define xx_txn_checkpoint(t,k,m) txn_checkpoint(t->env->Env, k, m) +# endif +#endif +DualType +xx_txn_checkpoint(txnp, kbyte, min) + BerkeleyDB::TxnMgr txnp + long kbyte + long min + +HV * +txn_stat(txnp) + BerkeleyDB::TxnMgr txnp + HV * RETVAL = NULL ; + CODE: + { + DB_TXN_STAT * stat ; +#if DB_VERSION_MAJOR == 2 + if(txn_stat(txnp->env->Env->tx_info, &stat, safemalloc) == 0) { +#else + if(txn_stat(txnp->env->Env, &stat, safemalloc) == 0) { +#endif + RETVAL = (HV*)sv_2mortal((SV*)newHV()) ; + hv_store_iv(RETVAL, "st_time_ckp", stat->st_time_ckp) ; + hv_store_iv(RETVAL, "st_last_txnid", stat->st_last_txnid) ; + hv_store_iv(RETVAL, "st_maxtxns", stat->st_maxtxns) ; + hv_store_iv(RETVAL, "st_naborts", stat->st_naborts) ; + hv_store_iv(RETVAL, "st_nbegins", stat->st_nbegins) ; + hv_store_iv(RETVAL, "st_ncommits", stat->st_ncommits) ; + hv_store_iv(RETVAL, "st_nactive", stat->st_nactive) ; +#if DB_VERSION_MAJOR > 2 + hv_store_iv(RETVAL, "st_maxnactive", stat->st_maxnactive) ; + hv_store_iv(RETVAL, "st_regsize", stat->st_regsize) ; + hv_store_iv(RETVAL, "st_region_wait", stat->st_region_wait) ; + hv_store_iv(RETVAL, "st_region_nowait", stat->st_region_nowait) ; +#endif + safefree(stat) ; + } + } + OUTPUT: + RETVAL + + +BerkeleyDB::TxnMgr +txn_open(dir, flags, mode, dbenv) + const char * dir + int flags + int mode + BerkeleyDB::Env dbenv + NOT_IMPLEMENTED_YET + + +MODULE = BerkeleyDB::Txn PACKAGE = BerkeleyDB::Txn PREFIX = xx_ + +DualType +status(tid) + BerkeleyDB::Txn tid + CODE: + RETVAL = tid->Status ; + OUTPUT: + RETVAL + +int +_DESTROY(tid) + BerkeleyDB::Txn tid + CODE: + Trace(("In BerkeleyDB::Txn::_DESTROY txn [%d] active [%d] dirty=%d\n", tid->txn, tid->active, PL_dirty)) ; + if (tid->active) + txn_abort(tid->txn) ; + RETVAL = (int)tid ; + hash_delete("BerkeleyDB::Term::Txn", (IV)tid) ; + Safefree(tid) ; + Trace(("End of BerkeleyDB::Txn::DESTROY\n")) ; + OUTPUT: + RETVAL + +#define xx_txn_unlink(d,f,e) txn_unlink(d,f,&(e->Env)) +DualType +xx_txn_unlink(dir, force, dbenv) + const char * dir + int force + BerkeleyDB::Env dbenv + NOT_IMPLEMENTED_YET + +#define xx_txn_prepare(t) (t->Status = txn_prepare(t->txn)) +DualType +xx_txn_prepare(tid) + BerkeleyDB::Txn tid + INIT: + ckActive_Transaction(tid->active) ; + +#if DB_VERSION_MAJOR == 2 +# define _txn_commit(t,flags) (t->Status = txn_commit(t->txn)) +#else +# define _txn_commit(t, flags) (t->Status = txn_commit(t->txn, flags)) +#endif +DualType +_txn_commit(tid, flags=0) + BerkeleyDB::Txn tid + u_int32_t flags + INIT: + ckActive_Transaction(tid->active) ; + hash_delete("BerkeleyDB::Term::Txn", (IV)tid) ; + tid->active = FALSE ; + +#define _txn_abort(t) (t->Status = txn_abort(t->txn)) +DualType +_txn_abort(tid) + BerkeleyDB::Txn tid + INIT: + ckActive_Transaction(tid->active) ; + hash_delete("BerkeleyDB::Term::Txn", (IV)tid) ; + tid->active = FALSE ; + +#define xx_txn_id(t) txn_id(t->txn) +u_int32_t +xx_txn_id(tid) + BerkeleyDB::Txn tid + +MODULE = BerkeleyDB::_tiedHash PACKAGE = BerkeleyDB::_tiedHash + +int +FIRSTKEY(db) + BerkeleyDB::Common db + CODE: + { + DBTKEY key ; + DBT value ; + DBC * cursor ; + + /* + TODO! + set partial value to 0 - to eliminate the retrieval of + the value need to store any existing partial settings & + restore at the end. + + */ + CurrentDB = db ; + DBT_clear(key) ; + DBT_clear(value) ; + /* If necessary create a cursor for FIRSTKEY/NEXTKEY use */ + if (!db->cursor && + (db->Status = db_cursor(db, db->txn, &cursor, 0)) == 0 ) + db->cursor = cursor ; + + if (db->cursor) + RETVAL = (db->Status) = + ((db->cursor)->c_get)(db->cursor, &key, &value, DB_FIRST); + else + RETVAL = db->Status ; + /* check for end of cursor */ + if (RETVAL == DB_NOTFOUND) { + ((db->cursor)->c_close)(db->cursor) ; + db->cursor = NULL ; + } + ST(0) = sv_newmortal(); + OutputKey(ST(0), key) + } + + + +int +NEXTKEY(db, key) + BerkeleyDB::Common db + DBTKEY key + CODE: + { + DBT value ; + + CurrentDB = db ; + DBT_clear(value) ; + key.flags = 0 ; + RETVAL = (db->Status) = + ((db->cursor)->c_get)(db->cursor, &key, &value, DB_NEXT); + + /* check for end of cursor */ + if (RETVAL == DB_NOTFOUND) { + ((db->cursor)->c_close)(db->cursor) ; + db->cursor = NULL ; + } + ST(0) = sv_newmortal(); + OutputKey(ST(0), key) + } + +MODULE = BerkeleyDB::_tiedArray PACKAGE = BerkeleyDB::_tiedArray + +I32 +FETCHSIZE(db) + BerkeleyDB::Common db + CODE: + CurrentDB = db ; + RETVAL = GetArrayLength(db) ; + OUTPUT: + RETVAL + + +MODULE = BerkeleyDB PACKAGE = BerkeleyDB + +BOOT: + { + SV * sv_err = perl_get_sv(ERR_BUFF, GV_ADD|GV_ADDMULTI) ; + SV * version_sv = perl_get_sv("BerkeleyDB::db_version", GV_ADD|GV_ADDMULTI) ; + SV * ver_sv = perl_get_sv("BerkeleyDB::db_ver", GV_ADD|GV_ADDMULTI) ; + int Major, Minor, Patch ; + (void)db_version(&Major, &Minor, &Patch) ; + /* Check that the versions of db.h and libdb.a are the same */ + if (Major != DB_VERSION_MAJOR || Minor != DB_VERSION_MINOR + || Patch != DB_VERSION_PATCH) + croak("\nBerkeleyDB needs compatible versions of libdb & db.h\n\tyou have db.h version %d.%d.%d and libdb version %d.%d.%d\n", + DB_VERSION_MAJOR, DB_VERSION_MINOR, DB_VERSION_PATCH, + Major, Minor, Patch) ; + + if (Major < 2 || (Major == 2 && Minor < 6)) + { + croak("BerkeleyDB needs Berkeley DB 2.6 or greater. This is %d.%d.%d\n", + Major, Minor, Patch) ; + } + sv_setpvf(version_sv, "%d.%d", Major, Minor) ; + sv_setpvf(ver_sv, "%d.%03d%03d", Major, Minor, Patch) ; + sv_setpv(sv_err, ""); + + DBT_clear(empty) ; + empty.data = &zero ; + empty.size = sizeof(db_recno_t) ; + empty.flags = 0 ; + + } + diff --git a/db/perl.BerkeleyDB/BerkeleyDB/Btree.pm b/db/perl.BerkeleyDB/BerkeleyDB/Btree.pm new file mode 100644 index 000000000..ba9a9c008 --- /dev/null +++ b/db/perl.BerkeleyDB/BerkeleyDB/Btree.pm @@ -0,0 +1,8 @@ + +package BerkeleyDB::Btree ; + +# This file is only used for MLDBM + +use BerkeleyDB ; + +1 ; diff --git a/db/perl.BerkeleyDB/BerkeleyDB/Hash.pm b/db/perl.BerkeleyDB/BerkeleyDB/Hash.pm new file mode 100644 index 000000000..8e7bc7e78 --- /dev/null +++ b/db/perl.BerkeleyDB/BerkeleyDB/Hash.pm @@ -0,0 +1,8 @@ + +package BerkeleyDB::Hash ; + +# This file is only used for MLDBM + +use BerkeleyDB ; + +1 ; diff --git a/db/perl.BerkeleyDB/Changes b/db/perl.BerkeleyDB/Changes new file mode 100644 index 000000000..dcaccd4d0 --- /dev/null +++ b/db/perl.BerkeleyDB/Changes @@ -0,0 +1,112 @@ +Revision history for Perl extension BerkeleyDB. + +0.01 23 October 1997 + * first alpha release as BerkDB. + +0.02 30 October 1997 + * renamed module to BerkeleyDB + * fixed a few bugs & added more tests + +0.03 5 May 1998 + * fixed db_get with DB_SET_RECNO + * fixed c_get with DB_SET_RECNO and DB_GET_RECNO + * implemented BerkeleyDB::Unknown + * implemented BerkeleyDB::Recno, including push, pop etc + modified the txn support. + +0.04 19 May 1998 + * Define DEFSV & SAVE_DEFSV if not already defined. This allows + the module to be built with Perl 5.004_04. + +0.05 9 November 1998 + * Added a note to README about how to build Berkeley DB 2.x + when using HP-UX. + * Minor modifications to get the module to build with DB 2.5.x + +0.06 19 December 1998 + * Minor modifications to get the module to build with DB 2.6.x + * Added support for DB 2.6.x's Concurrent Access Method, DB_INIT_CDB. + +0.07 21st September 1999 + * Numerous small bug fixes. + * Added support for sorting duplicate values DB_DUPSORT. + * Added support for DB_GET_BOTH & DB_NEXT_DUP. + * Added get_dup (from DB_File). + * beefed up the documentation. + * Forgot to add the DB_INIT_CDB in BerkeleyDB.pm in previous release. + * Merged the DBM Filter code from DB_File into BerkeleyDB. + * Fixed a nasty bug where a closed transaction was still used with + with dp_put, db_get etc. + * Added logic to gracefully close everything whenever a fatal error + happens. Previously the plug was just pulled. + * It is now a fatal error to explicitly close an environment if there + is still an open database; a database when there are open cursors or + an open transaction; and a cursor if there is an open transaction. + Using object destruction doesn't have this issue, as object + references will ensure everything gets closed in the correct order. + * The BOOT code now checks that the version of db.h & libdb are the + same - this seems to be a common problem on Linux. + * MLDBM support added. + * Support for the new join cursor added. + * Builds with Berkeley DB 3.x + * Updated dbinfo for Berkeley DB 3.x file formats. + * Deprecated the TxnMgr class. As with Berkeley DB version 3, + txn_begin etc are now accessed via the environment object. + +0.08 28nd November 1999 + * More documentation updates + * Changed reference to files in /tmp in examples.t + * Fixed a typo in softCrash that caused problems when building + with a thread-enabled Perl. + * BerkeleyDB::Error wasn't initialised properly. + * ANSI-ified all the static C functions in BerkeleyDB.xs + * Added support for the following DB 3.x features: + + The Queue database type + + db_remove + + subdatabases + + db_stat for Hash & Queue + +0.09 29th November 1999 + * the queue.t & subdb.t test harnesses were outputting a few + spurious warnings. This has been fixed. + +0.10 8th December 1999 + * The DESTROY method was missing for BerkeleyDB::Env. This resulted in + a memory leak. Fixed. + * If opening an environment or database failed, there was a small + memory leak. This has been fixed. + * A thread-enabled Perl it could core when a database was closed. + Problem traced to the strdup function. + +0.11 4th June 2000 + * When built with Berkeley Db 3.x there can be a clash with the close + macro. + * Typo in the definition of DB_WRITECURSOR + * The flags parameter wasn't getting sent to db_cursor + * Plugged small memory leak in db_cursor (DESTROY wasn't freeing + memory) + * Can be built with Berkeley DB 3.1 + + +0.12 2nd August 2000 + * Serious bug with get fixed. Spotted by Sleepycat. + * Added hints file for Solaris & Irix (courtesy of Albert Chin-A-Young) + +0.13 15th January 2001 + * Added support to allow this module to build with Berkeley DB 3.2 + * Updated dbinfo to support Berkeley DB 3.1 & 3.2 file format + changes. + * Documented the Solaris 2.7 core dump problem in README. + * Tidied up the test harness to fix a problem on Solaris where the + "fred" directory wasn't being deleted when it should have been. + * two calls to "open" clashed with a win32 macro. + * size argument for hash_cb is different for Berkeley DB 3.x + * Documented the issue of building on Linux. + * Added -Server, -CacheSize & -LockDetect options + [original patch supplied by Graham Barr] + * Added support for set_mutexlocks, c_count, set_q_extentsize, + key_range, c_dup + * Dropped the "attempted to close a Cursor with an open transaction" + error in c_close. The correct behaviour is that the cursor + should be closed before committing/aborting the transaction. + diff --git a/db/perl.BerkeleyDB/MANIFEST b/db/perl.BerkeleyDB/MANIFEST new file mode 100644 index 000000000..3b8a820d5 --- /dev/null +++ b/db/perl.BerkeleyDB/MANIFEST @@ -0,0 +1,49 @@ +BerkeleyDB.pm +BerkeleyDB.pod +BerkeleyDB.pod.P +BerkeleyDB.xs +BerkeleyDB/Btree.pm +BerkeleyDB/Hash.pm +Changes +config.in +dbinfo +hints/solaris.pl +hints/irix_6_5.pl +Makefile.PL +MANIFEST +mkconsts +mkpod +README +t/btree.t +t/db-3.0.t +t/db-3.1.t +t/db-3.2.t +t/destroy.t +t/env.t +t/examples.t +t/examples.t.T +t/examples3.t +t/examples3.t.T +t/filter.t +t/hash.t +t/join.t +t/mldbm.t +t/queue.t +t/recno.t +t/strict.t +t/subdb.t +t/txn.t +t/unknown.t +Todo +typemap +patches/5.004 +patches/5.004_01 +patches/5.004_02 +patches/5.004_03 +patches/5.004_04 +patches/5.004_05 +patches/5.005 +patches/5.005_01 +patches/5.005_02 +patches/5.005_03 +patches/5.6.0 diff --git a/db/perl.BerkeleyDB/Makefile.PL b/db/perl.BerkeleyDB/Makefile.PL new file mode 100644 index 000000000..399a67618 --- /dev/null +++ b/db/perl.BerkeleyDB/Makefile.PL @@ -0,0 +1,112 @@ +#! perl -w + +# It should not be necessary to edit this file. The configuration for +# BerkeleyDB is controlled from the file config.in + + +BEGIN { die "BerkeleyDB needs Perl 5.004_04 or greater" if $] < 5.004_04 ; } + +use strict ; +use ExtUtils::MakeMaker ; + +my $LIB_DIR ; +my $INC_DIR ; +my $DB_NAME ; +my $LIBS ; + +ParseCONFIG() ; + +if (defined $DB_NAME) + { $LIBS = $DB_NAME } +else { + if ($^O eq 'MSWin32') + { $LIBS = '-llibdb' } + else + { $LIBS = '-ldb' } +} + +# OS2 is a special case, so check for it now. +my $OS2 = "" ; +$OS2 = "-DOS2" if $^O eq 'os2' ; + +WriteMakefile( + NAME => 'BerkeleyDB', + LIBS => ["-L${LIB_DIR} $LIBS"], + MAN3PODS => ' ', # Pods will be built by installman. + INC => "-I$INC_DIR", + VERSION_FROM => 'BerkeleyDB.pm', + XSPROTOARG => '-noprototypes', + DEFINE => "$OS2", + #'macro' => { INSTALLDIRS => 'perl' }, + 'dist' => {COMPRESS=>'gzip', SUFFIX=>'gz'}, + ($] >= 5.005 + ? (ABSTRACT_FROM => 'BerkeleyDB.pod', + AUTHOR => 'Paul Marquess ') + : () + ), + ); + + +sub MY::postamble { + ' +$(NAME).pod: $(NAME).pod.P t/examples.t.T t/examples3.t.T mkpod + perl ./mkpod + +$(NAME).xs: typemap + @$(TOUCH) $(NAME).xs + +Makefile: config.in + + +' ; +} + +sub ParseCONFIG +{ + my ($k, $v) ; + my @badkey = () ; + my %Info = () ; + my @Options = qw( INCLUDE LIB DBNAME ) ; + my %ValidOption = map {$_, 1} @Options ; + my %Parsed = %ValidOption ; + my $CONFIG = 'config.in' ; + + print "Parsing $CONFIG...\n" ; + + # DBNAME is optional, so pretend it has been parsed. + delete $Parsed{'DBNAME'} ; + + open(F, "$CONFIG") or die "Cannot open file $CONFIG: $!\n" ; + while () { + s/^\s*|\s*$//g ; + next if /^\s*$/ or /^\s*#/ ; + s/\s*#\s*$// ; + + ($k, $v) = split(/\s+=\s+/, $_, 2) ; + $k = uc $k ; + if ($ValidOption{$k}) { + delete $Parsed{$k} ; + $Info{$k} = $v ; + } + else { + push(@badkey, $k) ; + } + } + close F ; + + print "Unknown keys in $CONFIG ignored [@badkey]\n" + if @badkey ; + + # check parsed values + my @missing = () ; + die "The following keys are missing from $CONFIG file: [@missing]\n" + if @missing = keys %Parsed ; + + $INC_DIR = $ENV{'BERKELEYDB_INCLUDE'} || $Info{'INCLUDE'} ; + $LIB_DIR = $ENV{'BERKELEYDB_LIB'} || $Info{'LIB'} ; + $DB_NAME = $Info{'DBNAME'} if defined $Info{'DBNAME'} ; + print "Looks Good.\n" ; + +} + +# end of file Makefile.PL diff --git a/db/perl.BerkeleyDB/README b/db/perl.BerkeleyDB/README new file mode 100644 index 000000000..aa905fa80 --- /dev/null +++ b/db/perl.BerkeleyDB/README @@ -0,0 +1,464 @@ + BerkeleyDB + + Version 0.13 + + 15th Jan 2001 + + Copyright (c) 1997-2001 Paul Marquess. All rights reserved. This + program is free software; you can redistribute it and/or modify + it under the same terms as Perl itself. + + +DESCRIPTION +----------- + +BerkeleyDB is a module which allows Perl programs to make use of the +facilities provided by Berkeley DB version 2 or 3. (Note: if you want +to use version 1 of Berkeley DB with Perl you need the DB_File module). + +Berkeley DB is a C library which provides a consistent interface to a +number of database formats. BerkeleyDB provides an interface to all +four of the database types (hash, btree, queue and recno) currently +supported by Berkeley DB. + +For further details see the documentation in the file BerkeleyDB.pod. + +PREREQUISITES +------------- + +Before you can build BerkeleyDB you need to have the following +installed on your system: + + * Perl 5.004_04 or greater. + + * Berkeley DB Version 2.6.4 or greater + + The official web site for Berkeley DB is http://www.sleepycat.com + + The latest version of Berkeley DB is always available there. It + is recommended that you use the most recent version available at + the Sleepycat site. + + The one exception to this advice is where you want to use BerkeleyDB + to access database files created by a third-party application, + like Sendmail. In these cases you must build BerkeleyDB with a + compatible version of Berkeley DB. + + +BUILDING THE MODULE +------------------- + +Assuming you have met all the prerequisites, building the module should +be relatively straightforward. + +Step 1 : If you are running Solaris 2.5, 2.7 or HP-UX 10 read either + the Solaris Notes or HP-UX Notes sections below. + If you are running Linux please read the Linux Notes section + before proceeding. + + +Step 2 : Edit the file config.in to suit you local installation. + Instructions are given in the file. + +Step 3 : Build and test the module using this sequence of commands: + + perl Makefile.PL + make + make test + +INSTALLATION +------------ + + make install + +TROUBLESHOOTING +=============== + +Here are some of the problems that people encounter when building BerkeleyDB. + +Missing db.h or libdb.a +----------------------- + +If you get an error like this: + + cc -c -I./libraries/ -Dbool=char -DHAS_BOOL -I/usr/local/include -O2 + -DVERSION=\"0.07\" -DXS_VERSION=\"0.07\" -fpic + -I/usr/local/lib/perl5/5.00503/i586-linux/CORE BerkeleyDB.c + BerkeleyDB.xs:52: db.h: No such file or directory + +or this: + + cc -c -I./libraries/2.7.5 -Dbool=char -DHAS_BOOL -I/usr/local/include -O2 + -DVERSION=\"0.07\" -DXS_VERSION=\"0.07\" -fpic + -I/usr/local/lib/perl5/5.00503/i586-linux/CORE BerkeleyDB.c + LD_RUN_PATH="/lib" cc -o blib/arch/auto/BerkeleyDB/BerkeleyDB.so -shared + -L/usr/local/lib BerkeleyDB.o + -L/home/paul/perl/ext/BerkDB/BerkeleyDB/libraries -ldb + ld: cannot open -ldb: No such file or directory + +This symptom can imply: + + 1. You don't have Berkeley DB installed on your system at all. + Solution: get & install Berkeley DB. + + 2. You do have Berkeley DB installed, but it isn't in a standard place. + Solution: Edit config.in and set the LIB and INCLUDE variables to point + to the directories where libdb.a and db.h are installed. + +Wrong db.h +---------- + +If you get an error like this when building this module: + + cc -c -I./libraries/ -Dbool=char -DHAS_BOOL -I/usr/local/include -O2 + -DVERSION=\"0.07\" -DXS_VERSION=\"0.07\" -fpic + -I/usr/local/lib/perl5/5.00503/i586-linux/CORE BerkeleyDB.c + BerkeleyDB.xs:93: parse error before `DB_INFO' + BerkeleyDB.xs:93: warning: no semicolon at end of struct or union + BerkeleyDB.xs:94: warning: data definition has no type or storage class + BerkeleyDB.xs:95: parse error before `0x80000000' + BerkeleyDB.xs:110: parse error before `}' + BerkeleyDB.xs:110: warning: data definition has no type or storage class + BerkeleyDB.xs:117: parse error before `DB_ENV' + ... + +This error usually happens when if you only have Berkeley DB version 1 +on your system or you have both version 1 and version 2 (or 3) of Berkeley +DB installed on your system. When building BerkeleyDB it attempts +to use the db.h for Berkeley DB version 1. This perl module can only +be built with Berkeley DB version 2 or 3. + +This symptom can imply: + + 1. You don't have Berkeley DB version 2 or 3 installed on your system + at all. + Solution: get & install Berkeley DB. + + 2. You do have Berkeley DB 2 or 3 installed, but it isn't in a standard + place. + Solution: Edit config.in and set the LIB and INCLUDE variables + to point to the directories where libdb.a and db.h are + installed. + +Undefined Symbol: txn_stat +-------------------------- + +BerkeleyDB seems to have built correctly, but you get an error like this +when you run the test harness: + + $ make test + PERL_DL_NONLAZY=1 /home/paul/perl/install/bin/perl5.00503 + -Iblib/arch -Iblib/lib -I/usr/local/lib/perl5/5.00503/i586-linux + -I/usr/local/lib/perl5/5.00503 -e 'use Test::Harness qw(&runtests $verbose); + $verbose=0; runtests @ARGV;' t/*.t + t/btree.............Can't load 'blib/arch/auto/BerkeleyDB/BerkeleyDB.so' for + module BerkeleyDB: blib/arch/auto/BerkeleyDB/BerkeleyDB.so: + undefined symbol: txn_stat + at /usr/local/lib/perl5/5.00503/i586-linux/DynaLoader.pm line 169. + ... + +This error usually happens when you have both version 1 and version +2 (or 3) of Berkeley DB installed on your system and BerkeleyDB attempts +to build using the db.h for Berkeley DB version 2/3 and the version 1 +library. Unfortunately the two versions aren't compatible with each +other. BerkeleyDB can only be built with Berkeley DB version 2 or 3. + +Solution: Setting the LIB & INCLUDE variables in config.in to point to the + correct directories can sometimes be enough to fix this + problem. If that doesn't work the easiest way to fix the + problem is to either delete or temporarily rename the copies + of db.h and libdb.a that you don't want BerkeleyDB to use. + +Undefined Symbol: db_appinit +---------------------------- + +BerkeleyDB seems to have built correctly, but you get an error like this +when you run the test harness: + + $ make test + PERL_DL_NONLAZY=1 /home/paul/perl/install/bin/perl5.00561 -Iblib/arch + -Iblib/lib -I/home/paul/perl/install/5.005_61/lib/5.00561/i586-linux + -I/home/paul/perl/install/5.005_61/lib/5.00561 -e 'use Test::Harness + qw(&runtests $verbose); $verbose=0; runtests @ARGV;' t/*.t + t/btree.............Can't load 'blib/arch/auto/BerkeleyDB/BerkeleyDB.so' for + module BerkeleyDB: blib/arch/auto/BerkeleyDB/BerkeleyDB.so: + undefined symbol: db_appinit + at /home/paul/perl/install/5.005_61/lib/5.00561/i586-linux/DynaLoader.pm + ... + + +This error usually happens when you have both version 2 and version +3 of Berkeley DB installed on your system and BerkeleyDB attempts +to build using the db.h for Berkeley DB version 2 and the version 3 +library. Unfortunately the two versions aren't compatible with each +other. + +Solution: Setting the LIB & INCLUDE variables in config.in to point to the + correct directories can sometimes be enough to fix this + problem. If that doesn't work the easiest way to fix the + problem is to either delete or temporarily rename the copies + of db.h and libdb.a that you don't want BerkeleyDB to use. + +Undefined Symbol: db_create +--------------------------- + +BerkeleyDB seems to have built correctly, but you get an error like this +when you run the test harness: + + $ make test + PERL_DL_NONLAZY=1 /home/paul/perl/install/bin/perl5.00561 -Iblib/arch + -Iblib/lib -I/home/paul/perl/install/5.005_61/lib/5.00561/i586-linux + -I/home/paul/perl/install/5.005_61/lib/5.00561 -e 'use Test::Harness + qw(&runtests $verbose); $verbose=0; runtests @ARGV;' t/*.t + t/btree.............Can't load 'blib/arch/auto/BerkeleyDB/BerkeleyDB.so' for + module BerkeleyDB: blib/arch/auto/BerkeleyDB/BerkeleyDB.so: + undefined symbol: db_create + at /home/paul/perl/install/5.005_61/lib/5.00561/i586-linux/DynaLoader.pm + ... + +This error usually happens when you have both version 2 and version +3 of Berkeley DB installed on your system and BerkeleyDB attempts +to build using the db.h for Berkeley DB version 3 and the version 2 +library. Unfortunately the two versions aren't compatible with each +other. + +Solution: Setting the LIB & INCLUDE variables in config.in to point to the + correct directories can sometimes be enough to fix this + problem. If that doesn't work the easiest way to fix the + problem is to either delete or temporarily rename the copies + of db.h and libdb.a that you don't want BerkeleyDB to use. + + +Incompatible versions of db.h and libdb +--------------------------------------- + +BerkeleyDB seems to have built correctly, but you get an error like this +when you run the test harness: + + $ make test + PERL_DL_NONLAZY=1 /home/paul/perl/install/bin/perl5.00503 + -Iblib/arch -Iblib/lib -I/usr/local/lib/perl5/5.00503/i586-linux + -I/usr/local/lib/perl5/5.00503 -e 'use Test::Harness qw(&runtests $verbose); + $verbose=0; runtests @ARGV;' t/*.t + t/btree............. + BerkeleyDB needs compatible versions of libdb & db.h + you have db.h version 2.6.4 and libdb version 2.7.5 + BEGIN failed--compilation aborted at t/btree.t line 25. + dubious + Test returned status 255 (wstat 65280, 0xff00) + ... + +Another variation on the theme of having two versions of Berkeley DB on +your system. + +Solution: Setting the LIB & INCLUDE variables in config.in to point to the + correct directories can sometimes be enough to fix this + problem. If that doesn't work the easiest way to fix the + problem is to either delete or temporarily rename the copies + of db.h and libdb.a that you don't want BerkeleyDB to use. + If you are running Linux, please read the Linux Notes section below. + + +Linux Notes +----------- + +Newer versions of Linux (e.g. RedHat 6, SuSe 6) ship with a C library +that has version 2.x of Berkeley DB linked into it. This makes it +difficult to build this module with anything other than the version of +Berkeley DB that shipped with your Linux release. If you do try to use +a different version of Berkeley DB you will most likely get the error +described in the "Incompatible versions of db.h and libdb" section of +this file. + +To make matters worse, prior to Perl 5.6.1, the perl binary itself +*always* included the Berkeley DB library. + +If you want to use a newer version of Berkeley DB with this module, the +easiest solution is to use Perl 5.6.1 (or better) and Berkeley DB 3.x +(or better). + +There are two approaches you can use to get older versions of Perl to +work with specific versions of Berkeley DB. Both have their advantages +and disadvantages. + +The first approach will only work when you want to build a version of +Perl older than 5.6.1 along with Berkeley DB 3.x. If you want to use +Berkeley DB 2.x, you must use the next approach. This approach involves +rebuilding your existing version of Perl after applying an unofficial +patch. The "patches" directory in the this module's source distribution +contains a number of patch files. There is one patch file for every +stable version of Perl since 5.004. Apply the appropriate patch to your +Perl source tree before re-building and installing Perl from scratch. +For example, assuming you are in the top-level source directory for +Perl 5.6.0, the command below will apply the necessary patch. Remember +to replace the path shown below with one that points to this module's +patches directory. + + patch -p1 -N + diff --git a/db/perl.BerkeleyDB/Todo b/db/perl.BerkeleyDB/Todo new file mode 100644 index 000000000..12d53bcf9 --- /dev/null +++ b/db/perl.BerkeleyDB/Todo @@ -0,0 +1,57 @@ + + * Proper documentation. + + * address or document the "close all cursors if you encounter an error" + + * Change the $BerkeleyDB::Error to store the info in the db object, + if possible. + + * $BerkeleyDB::db_version is documented. &db_version isn't. + + * migrate perl code into the .xs file where necessary + + * convert as many of the DB examples files to BerkeleyDB format. + + * add a method to the DB object to allow access to the environment (if there + actually is one). + + +Possibles + + * use '~' magic to store the inner data. + + * for the get stuff zap the value to undef if it doesn't find the + key. This may be more intuitive for those folks who are used with + the $hash{key} interface. + + * Text interface? This can be done as via Recno + + * allow recno to allow base offset for arrays to be either 0 or 1. + + * when duplicate keys are enabled, allow db_put($key, [$val1, $val2,...]) + + +2.x -> 3.x Upgrade +================== + +Environment Verbose +Env->open mode +DB cache size extra parameter +DB->open subdatabases Done +An empty environment causes DB->open to fail +where is __db.001 coming from? db_remove seems to create it. Bug in 3.0.55 +Change db_strerror for 0 to ""? Done +Queue Done +db_stat for Hash & Queue Done +No TxnMgr +DB->remove +ENV->remove +ENV->set_verbose +upgrade + + $env = BerkeleyDB::Env::Create + $env = create BerkeleyDB::Env + $status = $env->open() + + $db = BerkeleyDB::Hash::Create + $status = $db->open() diff --git a/db/perl.BerkeleyDB/config.in b/db/perl.BerkeleyDB/config.in new file mode 100644 index 000000000..c23e6689c --- /dev/null +++ b/db/perl.BerkeleyDB/config.in @@ -0,0 +1,51 @@ +# Filename: config.in +# +# written by Paul Marquess + +# 1. Where is the file db.h? +# +# Change the path below to point to the directory where db.h is +# installed on your system. + +#INCLUDE = /usr/local/include +#INCLUDE = /usr/local/BerkeleyDB/include +#INCLUDE = ./libraries/2.7.5 +#INCLUDE = ./libraries/3.0.55 +#INCLUDE = ./libraries/3.1.17 +INCLUDE = ./libraries/3.2.7 + +# 2. Where is libdb? +# +# Change the path below to point to the directory where libdb is +# installed on your system. + +#LIB = /usr/local/lib +#LIB = /usr/local/BerkeleyDB/lib +#LIB = ./libraries/2.7.5 +#LIB = ./libraries/3.0.55 +#LIB = ./libraries/3.1.17 +LIB = ./libraries/3.2.7 + +# 3. Is the library called libdb? +# +# If you have copies of both 1.x and 2.x Berkeley DB installed on +# your system it can sometimes be tricky to make sure you are using +# the correct one. Renaming one (or creating a symbolic link) to +# include the version number of the library can help. +# +# For example, if you have Berkeley DB 2.6.4 you could rename the +# Berkeley DB library from libdb.a to libdb-2.6.4.a and change the +# DBNAME line below to look like this: +# +# DBNAME = -ldb-2.6.4 +# +# Note: If you are building this module with Win32, -llibdb will be +# used by default. +# +# If you have changed the name of the library, uncomment the line +# below (by removing the leading #) and edit the line to use the name +# you have picked. + +#DBNAME = -ldb-3.0 + +# end of file config.in diff --git a/db/perl.BerkeleyDB/dbinfo b/db/perl.BerkeleyDB/dbinfo new file mode 100755 index 000000000..415411aff --- /dev/null +++ b/db/perl.BerkeleyDB/dbinfo @@ -0,0 +1,109 @@ +#!/usr/local/bin/perl + +# Name: dbinfo -- identify berkeley DB version used to create +# a database file +# +# Author: Paul Marquess +# Version: 1.03 +# Date 17th September 2000 +# +# Copyright (c) 1998-2001 Paul Marquess. All rights reserved. +# This program is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. + +# Todo: Print more stats on a db file, e.g. no of records +# add log/txn/lock files + +use strict ; + +my %Data = + ( + 0x053162 => { + Type => "Btree", + Versions => + { + 1 => "Unknown (older than 1.71)", + 2 => "Unknown (older than 1.71)", + 3 => "1.71 -> 1.85, 1.86", + 4 => "Unknown", + 5 => "2.0.0 -> 2.3.0", + 6 => "2.3.1 -> 2.7.7", + 7 => "3.0.x", + 8 => "3.1.x or greater", + } + }, + 0x061561 => { + Type => "Hash", + Versions => + { + 1 => "Unknown (older than 1.71)", + 2 => "1.71 -> 1.85", + 3 => "1.86", + 4 => "2.0.0 -> 2.1.0", + 5 => "2.2.6 -> 2.7.7", + 6 => "3.0.x", + 7 => "3.1.x or greater", + } + }, + 0x042253 => { + Type => "Queue", + Versions => + { + 1 => "3.0.x", + 2 => "3.1.x", + 3 => "3.2.x or greater", + } + }, + ) ; + +die "Usage: dbinfo file\n" unless @ARGV == 1 ; + +print "testing file $ARGV[0]...\n\n" ; +open (F, "<$ARGV[0]") or die "Cannot open file $ARGV[0]: $!\n" ; + +my $buff ; +read F, $buff, 20 ; + +my (@info) = unpack("NNNNN", $buff) ; +my (@info1) = unpack("VVVVV", $buff) ; +my ($magic, $version, $endian) ; + +if ($Data{$info[0]}) # first try DB 1.x format +{ + $magic = $info[0] ; + $version = $info[1] ; + $endian = "Unknown" ; +} +elsif ($Data{$info[3]}) # next DB 2.x big endian +{ + $magic = $info[3] ; + $version = $info[4] ; + $endian = "Big Endian" ; +} +elsif ($Data{$info1[3]}) # next DB 2.x little endian +{ + $magic = $info1[3] ; + $version = $info1[4] ; + $endian = "Little Endian" ; +} +else + { die "not a Berkeley DB database file.\n" } + +my $type = $Data{$magic} ; +$magic = sprintf "%06X", $magic ; + +my $ver_string = "Unknown" ; +$ver_string = $type->{Versions}{$version} + if defined $type->{Versions}{$version} ; + +print <{Type} file. +File Version ID: $version +Built with Berkeley DB: $ver_string +Byte Order: $endian +Magic: $magic +EOM + +close F ; + +exit ; diff --git a/db/perl.BerkeleyDB/hints/irix_6_5.pl b/db/perl.BerkeleyDB/hints/irix_6_5.pl new file mode 100644 index 000000000..b531673e6 --- /dev/null +++ b/db/perl.BerkeleyDB/hints/irix_6_5.pl @@ -0,0 +1 @@ +$self->{LIBS} = [ "@{$self->{LIBS}} -lthread" ]; diff --git a/db/perl.BerkeleyDB/hints/solaris.pl b/db/perl.BerkeleyDB/hints/solaris.pl new file mode 100644 index 000000000..ddd941d63 --- /dev/null +++ b/db/perl.BerkeleyDB/hints/solaris.pl @@ -0,0 +1 @@ +$self->{LIBS} = [ "@{$self->{LIBS}} -lmt" ]; diff --git a/db/perl.BerkeleyDB/mkconsts b/db/perl.BerkeleyDB/mkconsts new file mode 100644 index 000000000..24ef4fca7 --- /dev/null +++ b/db/perl.BerkeleyDB/mkconsts @@ -0,0 +1,211 @@ +#!/usr/bin/perl + +%constants = ( + # Symbol 0 = define, 1 = enum + DB_AFTER => 0, + DB_APPEND => 0, + DB_ARCH_ABS => 0, + DB_ARCH_DATA => 0, + DB_ARCH_LOG => 0, + DB_BEFORE => 0, + DB_BTREE => 1, + DB_BTREEMAGIC => 0, + DB_BTREEOLDVER => 0, + DB_BTREEVERSION => 0, + DB_CHECKPOINT => 0, + DB_CONSUME => 0, + DB_CREATE => 0, + DB_CURLSN => 0, + DB_CURRENT => 0, + DB_DBT_MALLOC => 0, + DB_DBT_PARTIAL => 0, + DB_DBT_USERMEM => 0, + DB_DELETED => 0, + DB_DELIMITER => 0, + DB_DUP => 0, + DB_DUPSORT => 0, + DB_ENV_APPINIT => 0, + DB_ENV_STANDALONE => 0, + DB_ENV_THREAD => 0, + DB_EXCL => 0, + DB_FILE_ID_LEN => 0, + DB_FIRST => 0, + DB_FIXEDLEN => 0, + DB_FLUSH => 0, + DB_FORCE => 0, + DB_GET_BOTH => 0, + DB_GET_RECNO => 0, + DB_HASH => 1, + DB_HASHMAGIC => 0, + DB_HASHOLDVER => 0, + DB_HASHVERSION => 0, + DB_INCOMPLETE => 0, + DB_INIT_CDB => 0, + DB_INIT_LOCK => 0, + DB_INIT_LOG => 0, + DB_INIT_MPOOL => 0, + DB_INIT_TXN => 0, + DB_JOIN_ITEM => 0, + DB_KEYEMPTY => 0, + DB_KEYEXIST => 0, + DB_KEYFIRST => 0, + DB_KEYLAST => 0, + DB_LAST => 0, + DB_LOCK_CONFLICT => 0, + DB_LOCK_DEADLOCK => 0, + DB_LOCK_DEFAULT => 0, + DB_LOCK_GET => 1, + DB_LOCK_NORUN => 0, + DB_LOCK_NOTGRANTED => 0, + DB_LOCK_NOTHELD => 0, + DB_LOCK_NOWAIT => 0, + DB_LOCK_OLDEST => 0, + DB_LOCK_RANDOM => 0, + DB_LOCK_RIW_N => 0, + DB_LOCK_RW_N => 0, + DB_LOCK_YOUNGEST => 0, + DB_LOCKMAGIC => 0, + DB_LOCKVERSION => 0, + DB_LOGMAGIC => 0, + DB_LOGOLDVER => 0, + DB_MAX_PAGES => 0, + DB_MAX_RECORDS => 0, + DB_MPOOL_CLEAN => 0, + DB_MPOOL_CREATE => 0, + DB_MPOOL_DIRTY => 0, + DB_MPOOL_DISCARD => 0, + DB_MPOOL_LAST => 0, + DB_MPOOL_NEW => 0, + DB_MPOOL_PRIVATE => 0, + DB_MUTEXDEBUG => 0, + DB_MUTEXLOCKS => 0, + DB_NEEDSPLIT => 0, + DB_NEXT => 0, + DB_NEXT_DUP => 0, + DB_NOMMAP => 0, + DB_NOOVERWRITE => 0, + DB_NOSYNC => 0, + DB_NOTFOUND => 0, + DB_PAD => 0, + DB_PAGEYIELD => 0, + DB_POSITION => 0, + DB_PREV => 0, + DB_PRIVATE => 0, + DB_QUEUE => 1, + DB_RDONLY => 0, + DB_RECNO => 1, + DB_RECNUM => 0, + DB_RECORDCOUNT => 0, + DB_RECOVER => 0, + DB_RECOVER_FATAL => 0, + DB_REGISTERED => 0, + DB_RENUMBER => 0, + DB_RMW => 0, + DB_RUNRECOVERY => 0, + DB_SEQUENTIAL => 0, + DB_SET => 0, + DB_SET_RANGE => 0, + DB_SET_RECNO => 0, + DB_SNAPSHOT => 0, + DB_SWAPBYTES => 0, + DB_TEMPORARY => 0, + DB_THREAD => 0, + DB_TRUNCATE => 0, + DB_TXN_ABORT => 1, + DB_TXN_BACKWARD_ROLL => 1, + DB_TXN_CKP => 0, + DB_TXN_FORWARD_ROLL => 1, + DB_TXN_LOCK_2PL => 0, + DB_TXN_LOCK_MASK => 0, + DB_TXN_LOCK_OPTIMISTIC => 0, + DB_TXN_LOG_MASK => 0, + DB_TXN_LOG_REDO => 0, + DB_TXN_LOG_UNDO => 0, + DB_TXN_LOG_UNDOREDO => 0, + DB_TXN_NOSYNC => 0, + DB_TXN_NOWAIT => 0, + DB_TXN_SYNC => 0, + DB_TXN_OPENFILES => 1, + DB_TXN_REDO => 0, + DB_TXN_UNDO => 0, + DB_TXNMAGIC => 0, + DB_TXNVERSION => 0, + DB_TXN_LOCK_OPTIMIST => 0, + DB_UNKNOWN => 1, + DB_USE_ENVIRON => 0, + DB_USE_ENVIRON_ROOT => 0, + DB_VERSION_MAJOR => 0, + DB_VERSION_MINOR => 0, + DB_VERSION_PATCH => 0, + DB_WRITECURSOR => 0, + ) ; + +sub OutputXS +{ + # skip to the marker + if (0) { + while (<>) + { + last if /^MARKER/ ; + print ; + } + } + + foreach my $key (sort keys %constants) + { + my $isEnum = $constants{$key} ; + + if ($isEnum) { + print <) + { + print ; + } + } +} + +sub OutputPM +{ + # skip to the marker + if (0) { + while (<>) + { + last if /^MARKER/ ; + print ; + } + } + + foreach my $key (sort keys %constants) + { + print "\t$key\n"; + } + + if (0) { + while (<>) + { + print ; + } + } +} + +OutputXS() if $ARGV[0] =~ /xs/i ; +OutputPM() if $ARGV[0] =~ /pm/i ; diff --git a/db/perl.BerkeleyDB/mkpod b/db/perl.BerkeleyDB/mkpod new file mode 100755 index 000000000..44bbf3fbf --- /dev/null +++ b/db/perl.BerkeleyDB/mkpod @@ -0,0 +1,146 @@ +#!/usr/local/bin/perl5 + +# Filename: mkpod +# +# Author: Paul Marquess + +# File types +# +# Macro files end with .M +# Tagged source files end with .T +# Output from the code ends with .O +# Pre-Pod file ends with .P +# +# Tags +# +# ## BEGIN tagname +# ... +# ## END tagname +# +# ## 0 +# ## 1 +# + +# Constants + +$TOKEN = '##' ; +$Verbose = 1 if $ARGV[0] =~ /^-v/i ; + +# Macros files first +foreach $file (glob("*.M")) +{ + open (F, "<$file") or die "Cannot open '$file':$!\n" ; + print " Processing Macro file $file\n" ; + while () + { + # Skip blank & comment lines + next if /^\s*$/ || /^\s*#/ ; + + # + ($name, $expand) = split (/\t+/, $_, 2) ; + + $expand =~ s/^\s*// ; + $expand =~ s/\s*$// ; + + if ($expand =~ /\[#/ ) + { + } + + $Macros{$name} = $expand ; + } + close F ; +} + +# Suck up all the code files +foreach $file (glob("t/*.T")) +{ + ($newfile = $file) =~ s/\.T$// ; + open (F, "<$file") or die "Cannot open '$file':$!\n" ; + open (N, ">$newfile") or die "Cannot open '$newfile':$!\n" ; + + print " Processing $file -> $newfile\n" ; + + while ($line = ) + { + if ($line =~ /^$TOKEN\s*BEGIN\s+(\w+)\s*$/ or + $line =~ m[\s*/\*$TOKEN\s*BEGIN\s+(\w+)\s*$] ) + { + print " Section $1 begins\n" if $Verbose ; + $InSection{$1} ++ ; + $Section{$1} = '' unless $Section{$1} ; + } + elsif ($line =~ /^$TOKEN\s*END\s+(\w+)\s*$/ or + $line =~ m[^\s*/\*$TOKEN\s*END\s+(\w+)\s*$] ) + { + warn "Encountered END without a begin [$line]\n" + unless $InSection{$1} ; + + delete $InSection{$1} ; + print " Section $1 ends\n" if $Verbose ; + } + else + { + print N $line ; + chop $line ; + $line =~ s/\s*$// ; + + # Save the current line in each of the sections + foreach( keys %InSection) + { + if ($line !~ /^\s*$/ ) + #{ $Section{$_} .= " $line" } + { $Section{$_} .= $line } + $Section{$_} .= "\n" ; + } + } + + } + + if (%InSection) + { + # Check for unclosed sections + print "The following Sections are not terminated\n" ; + foreach (sort keys %InSection) + { print "\t$_\n" } + exit 1 ; + } + + close F ; + close N ; +} + +print "\n\nCreating pod file(s)\n\n" if $Verbose ; + +@ppods = glob('*.P') ; +#$ppod = $ARGV[0] ; +#$pod = $ARGV[1] ; + +# Now process the pre-pod file +foreach $ppod (@ppods) +{ + ($pod = $ppod) =~ s/\.P$// ; + open (PPOD, "<$ppod") or die "Cannot open file '$ppod': $!\n" ; + open (POD, ">$pod") or die "Cannot open file '$pod': $!\n" ; + + print " $ppod -> $pod\n" ; + + while ($line = ) + { + if ( $line =~ /^\s*$TOKEN\s*(\w+)\s*$/) + { + warn "No code insert '$1' available\n" + unless $Section{$1} ; + + print "Expanding section $1\n" if $Verbose ; + print POD $Section{$1} ; + } + else + { +# $line =~ s/\[#([^\]])]/$Macros{$1}/ge ; + print POD $line ; + } + } + + close PPOD ; + close POD ; +} diff --git a/db/perl.BerkeleyDB/patches/5.004 b/db/perl.BerkeleyDB/patches/5.004 new file mode 100644 index 000000000..143ec95af --- /dev/null +++ b/db/perl.BerkeleyDB/patches/5.004 @@ -0,0 +1,44 @@ +diff perl5.004.orig/Configure perl5.004/Configure +190a191 +> perllibs='' +9904a9906,9913 +> : Remove libraries needed only for extensions +> : The appropriate ext/Foo/Makefile.PL will add them back in, if +> : necessary. +> set X `echo " $libs " | +> sed -e 's@ -lndbm @ @' -e 's@ -lgdbm @ @' -e 's@ -ldbm @ @' -e 's@ -ldb @ @'` +> shift +> perllibs="$*" +> +10372a10382 +> perllibs='$perllibs' +diff perl5.004.orig/Makefile.SH perl5.004/Makefile.SH +122c122 +< libs = $libs $cryptlib +--- +> libs = $perllibs $cryptlib +Common subdirectories: perl5.004.orig/Porting and perl5.004/Porting +Common subdirectories: perl5.004.orig/cygwin32 and perl5.004/cygwin32 +Common subdirectories: perl5.004.orig/eg and perl5.004/eg +Common subdirectories: perl5.004.orig/emacs and perl5.004/emacs +Common subdirectories: perl5.004.orig/ext and perl5.004/ext +Common subdirectories: perl5.004.orig/h2pl and perl5.004/h2pl +Common subdirectories: perl5.004.orig/hints and perl5.004/hints +Common subdirectories: perl5.004.orig/lib and perl5.004/lib +diff perl5.004.orig/myconfig perl5.004/myconfig +38c38 +< libs=$libs +--- +> libs=$perllibs +Common subdirectories: perl5.004.orig/os2 and perl5.004/os2 +diff perl5.004.orig/patchlevel.h perl5.004/patchlevel.h +40a41 +> ,"NODB-1.0 - remove -ldb from core perl binary." +Common subdirectories: perl5.004.orig/plan9 and perl5.004/plan9 +Common subdirectories: perl5.004.orig/pod and perl5.004/pod +Common subdirectories: perl5.004.orig/qnx and perl5.004/qnx +Common subdirectories: perl5.004.orig/t and perl5.004/t +Common subdirectories: perl5.004.orig/utils and perl5.004/utils +Common subdirectories: perl5.004.orig/vms and perl5.004/vms +Common subdirectories: perl5.004.orig/win32 and perl5.004/win32 +Common subdirectories: perl5.004.orig/x2p and perl5.004/x2p diff --git a/db/perl.BerkeleyDB/patches/5.004_01 b/db/perl.BerkeleyDB/patches/5.004_01 new file mode 100644 index 000000000..1b05eb4e0 --- /dev/null +++ b/db/perl.BerkeleyDB/patches/5.004_01 @@ -0,0 +1,217 @@ +diff -rc perl5.004_01.orig/Configure perl5.004_01/Configure +*** perl5.004_01.orig/Configure Wed Jun 11 00:28:03 1997 +--- perl5.004_01/Configure Sun Nov 12 22:12:35 2000 +*************** +*** 188,193 **** +--- 188,194 ---- + mv='' + nroff='' + perl='' ++ perllibs='' + pg='' + pmake='' + pr='' +*************** +*** 9907,9912 **** +--- 9908,9921 ---- + shift + extensions="$*" + ++ : Remove libraries needed only for extensions ++ : The appropriate ext/Foo/Makefile.PL will add them back in, if ++ : necessary. ++ set X `echo " $libs " | ++ sed -e 's@ -lndbm @ @' -e 's@ -lgdbm @ @' -e 's@ -ldbm @ @' -e 's@ -ldb @ @'` ++ shift ++ perllibs="$*" ++ + : Remove build directory name from cppstdin so it can be used from + : either the present location or the final installed location. + echo " " +*************** +*** 10375,10380 **** +--- 10384,10390 ---- + patchlevel='$patchlevel' + path_sep='$path_sep' + perl='$perl' ++ perllibs='$perllibs' + perladmin='$perladmin' + perlpath='$perlpath' + pg='$pg' +diff -rc perl5.004_01.orig/Makefile.SH perl5.004_01/Makefile.SH +*** perl5.004_01.orig/Makefile.SH Thu Jun 12 23:27:56 1997 +--- perl5.004_01/Makefile.SH Sun Nov 12 22:12:35 2000 +*************** +*** 126,132 **** + ext = \$(dynamic_ext) \$(static_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $libs $cryptlib + + public = perl $suidperl utilities translators + +--- 126,132 ---- + ext = \$(dynamic_ext) \$(static_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $perllibs $cryptlib + + public = perl $suidperl utilities translators + +diff -rc perl5.004_01.orig/lib/ExtUtils/Embed.pm perl5.004_01/lib/ExtUtils/Embed.pm +*** perl5.004_01.orig/lib/ExtUtils/Embed.pm Wed Apr 2 22:12:04 1997 +--- perl5.004_01/lib/ExtUtils/Embed.pm Sun Nov 12 22:12:35 2000 +*************** +*** 170,176 **** + @path = $path ? split(/:/, $path) : @INC; + + push(@potential_libs, @link_args) if scalar @link_args; +! push(@potential_libs, $Config{libs}) if defined $std; + + push(@mods, static_ext()) if $std; + +--- 170,176 ---- + @path = $path ? split(/:/, $path) : @INC; + + push(@potential_libs, @link_args) if scalar @link_args; +! push(@potential_libs, $Config{perllibs}) if defined $std; + + push(@mods, static_ext()) if $std; + +diff -rc perl5.004_01.orig/lib/ExtUtils/Liblist.pm perl5.004_01/lib/ExtUtils/Liblist.pm +*** perl5.004_01.orig/lib/ExtUtils/Liblist.pm Sat Jun 7 01:19:44 1997 +--- perl5.004_01/lib/ExtUtils/Liblist.pm Sun Nov 12 22:13:27 2000 +*************** +*** 16,33 **** + + sub _unix_os2_ext { + my($self,$potential_libs, $Verbose) = @_; +! if ($^O =~ 'os2' and $Config{libs}) { + # Dynamic libraries are not transitive, so we may need including + # the libraries linked against perl.dll again. + + $potential_libs .= " " if $potential_libs; +! $potential_libs .= $Config{libs}; + } + return ("", "", "", "") unless $potential_libs; + print STDOUT "Potential libraries are '$potential_libs':\n" if $Verbose; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'libs'}; + my $Config_libext = $Config{lib_ext} || ".a"; + + +--- 16,33 ---- + + sub _unix_os2_ext { + my($self,$potential_libs, $Verbose) = @_; +! if ($^O =~ 'os2' and $Config{perllibs}) { + # Dynamic libraries are not transitive, so we may need including + # the libraries linked against perl.dll again. + + $potential_libs .= " " if $potential_libs; +! $potential_libs .= $Config{perllibs}; + } + return ("", "", "", "") unless $potential_libs; + print STDOUT "Potential libraries are '$potential_libs':\n" if $Verbose; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'perllibs'}; + my $Config_libext = $Config{lib_ext} || ".a"; + + +*************** +*** 186,196 **** + my($self, $potential_libs, $Verbose) = @_; + + # If user did not supply a list, we punt. +! # (caller should probably use the list in $Config{libs}) + return ("", "", "", "") unless $potential_libs; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'libs'}; + my($libpth) = $Config{'libpth'}; + my($libext) = $Config{'lib_ext'} || ".lib"; + +--- 186,196 ---- + my($self, $potential_libs, $Verbose) = @_; + + # If user did not supply a list, we punt. +! # (caller should probably use the list in $Config{perllibs}) + return ("", "", "", "") unless $potential_libs; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'perllibs'}; + my($libpth) = $Config{'libpth'}; + my($libext) = $Config{'lib_ext'} || ".lib"; + +*************** +*** 540,546 **** + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{libs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs> + as well as in C<$Config{libpth}>. For each library that is found, a +--- 540,546 ---- + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{perllibs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs> + as well as in C<$Config{libpth}>. For each library that is found, a +diff -rc perl5.004_01.orig/lib/ExtUtils/MM_Unix.pm perl5.004_01/lib/ExtUtils/MM_Unix.pm +*** perl5.004_01.orig/lib/ExtUtils/MM_Unix.pm Thu Jun 12 22:06:18 1997 +--- perl5.004_01/lib/ExtUtils/MM_Unix.pm Sun Nov 12 22:12:35 2000 +*************** +*** 2137,2143 **** + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{libs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { +--- 2137,2143 ---- + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{perllibs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { +diff -rc perl5.004_01.orig/myconfig perl5.004_01/myconfig +*** perl5.004_01.orig/myconfig Sat Dec 21 01:13:20 1996 +--- perl5.004_01/myconfig Sun Nov 12 22:12:35 2000 +*************** +*** 35,41 **** + Linker and Libraries: + ld='$ld', ldflags ='$ldflags' + libpth=$libpth +! libs=$libs + libc=$libc, so=$so + useshrplib=$useshrplib, libperl=$libperl + Dynamic Linking: +--- 35,41 ---- + Linker and Libraries: + ld='$ld', ldflags ='$ldflags' + libpth=$libpth +! libs=$perllibs + libc=$libc, so=$so + useshrplib=$useshrplib, libperl=$libperl + Dynamic Linking: +diff -rc perl5.004_01.orig/patchlevel.h perl5.004_01/patchlevel.h +*** perl5.004_01.orig/patchlevel.h Wed Jun 11 03:06:10 1997 +--- perl5.004_01/patchlevel.h Sun Nov 12 22:12:35 2000 +*************** +*** 38,43 **** +--- 38,44 ---- + */ + static char *local_patches[] = { + NULL ++ ,"NODB-1.0 - remove -ldb from core perl binary." + ,NULL + }; + diff --git a/db/perl.BerkeleyDB/patches/5.004_02 b/db/perl.BerkeleyDB/patches/5.004_02 new file mode 100644 index 000000000..238f87379 --- /dev/null +++ b/db/perl.BerkeleyDB/patches/5.004_02 @@ -0,0 +1,217 @@ +diff -rc perl5.004_02.orig/Configure perl5.004_02/Configure +*** perl5.004_02.orig/Configure Thu Aug 7 15:08:44 1997 +--- perl5.004_02/Configure Sun Nov 12 22:06:24 2000 +*************** +*** 188,193 **** +--- 188,194 ---- + mv='' + nroff='' + perl='' ++ perllibs='' + pg='' + pmake='' + pr='' +*************** +*** 9911,9916 **** +--- 9912,9925 ---- + shift + extensions="$*" + ++ : Remove libraries needed only for extensions ++ : The appropriate ext/Foo/Makefile.PL will add them back in, if ++ : necessary. ++ set X `echo " $libs " | ++ sed -e 's@ -lndbm @ @' -e 's@ -lgdbm @ @' -e 's@ -ldbm @ @' -e 's@ -ldb @ @'` ++ shift ++ perllibs="$*" ++ + : Remove build directory name from cppstdin so it can be used from + : either the present location or the final installed location. + echo " " +*************** +*** 10379,10384 **** +--- 10388,10394 ---- + patchlevel='$patchlevel' + path_sep='$path_sep' + perl='$perl' ++ perllibs='$perllibs' + perladmin='$perladmin' + perlpath='$perlpath' + pg='$pg' +diff -rc perl5.004_02.orig/Makefile.SH perl5.004_02/Makefile.SH +*** perl5.004_02.orig/Makefile.SH Thu Aug 7 13:10:53 1997 +--- perl5.004_02/Makefile.SH Sun Nov 12 22:06:24 2000 +*************** +*** 126,132 **** + ext = \$(dynamic_ext) \$(static_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $libs $cryptlib + + public = perl $suidperl utilities translators + +--- 126,132 ---- + ext = \$(dynamic_ext) \$(static_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $perllibs $cryptlib + + public = perl $suidperl utilities translators + +diff -rc perl5.004_02.orig/lib/ExtUtils/Embed.pm perl5.004_02/lib/ExtUtils/Embed.pm +*** perl5.004_02.orig/lib/ExtUtils/Embed.pm Fri Aug 1 15:08:44 1997 +--- perl5.004_02/lib/ExtUtils/Embed.pm Sun Nov 12 22:06:24 2000 +*************** +*** 178,184 **** + @path = $path ? split(/:/, $path) : @INC; + + push(@potential_libs, @link_args) if scalar @link_args; +! push(@potential_libs, $Config{libs}) if defined $std; + + push(@mods, static_ext()) if $std; + +--- 178,184 ---- + @path = $path ? split(/:/, $path) : @INC; + + push(@potential_libs, @link_args) if scalar @link_args; +! push(@potential_libs, $Config{perllibs}) if defined $std; + + push(@mods, static_ext()) if $std; + +diff -rc perl5.004_02.orig/lib/ExtUtils/Liblist.pm perl5.004_02/lib/ExtUtils/Liblist.pm +*** perl5.004_02.orig/lib/ExtUtils/Liblist.pm Fri Aug 1 19:36:58 1997 +--- perl5.004_02/lib/ExtUtils/Liblist.pm Sun Nov 12 22:06:24 2000 +*************** +*** 16,33 **** + + sub _unix_os2_ext { + my($self,$potential_libs, $verbose) = @_; +! if ($^O =~ 'os2' and $Config{libs}) { + # Dynamic libraries are not transitive, so we may need including + # the libraries linked against perl.dll again. + + $potential_libs .= " " if $potential_libs; +! $potential_libs .= $Config{libs}; + } + return ("", "", "", "") unless $potential_libs; + print STDOUT "Potential libraries are '$potential_libs':\n" if $verbose; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'libs'}; + my $Config_libext = $Config{lib_ext} || ".a"; + + +--- 16,33 ---- + + sub _unix_os2_ext { + my($self,$potential_libs, $verbose) = @_; +! if ($^O =~ 'os2' and $Config{perllibs}) { + # Dynamic libraries are not transitive, so we may need including + # the libraries linked against perl.dll again. + + $potential_libs .= " " if $potential_libs; +! $potential_libs .= $Config{perllibs}; + } + return ("", "", "", "") unless $potential_libs; + print STDOUT "Potential libraries are '$potential_libs':\n" if $verbose; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'perllibs'}; + my $Config_libext = $Config{lib_ext} || ".a"; + + +*************** +*** 186,196 **** + my($self, $potential_libs, $verbose) = @_; + + # If user did not supply a list, we punt. +! # (caller should probably use the list in $Config{libs}) + return ("", "", "", "") unless $potential_libs; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'libs'}; + my($libpth) = $Config{'libpth'}; + my($libext) = $Config{'lib_ext'} || ".lib"; + +--- 186,196 ---- + my($self, $potential_libs, $verbose) = @_; + + # If user did not supply a list, we punt. +! # (caller should probably use the list in $Config{perllibs}) + return ("", "", "", "") unless $potential_libs; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'perllibs'}; + my($libpth) = $Config{'libpth'}; + my($libext) = $Config{'lib_ext'} || ".lib"; + +*************** +*** 540,546 **** + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{libs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs> + as well as in C<$Config{libpth}>. For each library that is found, a +--- 540,546 ---- + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{perllibs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs> + as well as in C<$Config{libpth}>. For each library that is found, a +diff -rc perl5.004_02.orig/lib/ExtUtils/MM_Unix.pm perl5.004_02/lib/ExtUtils/MM_Unix.pm +*** perl5.004_02.orig/lib/ExtUtils/MM_Unix.pm Tue Aug 5 14:28:08 1997 +--- perl5.004_02/lib/ExtUtils/MM_Unix.pm Sun Nov 12 22:06:25 2000 +*************** +*** 2224,2230 **** + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{libs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { +--- 2224,2230 ---- + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{perllibs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { +diff -rc perl5.004_02.orig/myconfig perl5.004_02/myconfig +*** perl5.004_02.orig/myconfig Sat Dec 21 01:13:20 1996 +--- perl5.004_02/myconfig Sun Nov 12 22:06:25 2000 +*************** +*** 35,41 **** + Linker and Libraries: + ld='$ld', ldflags ='$ldflags' + libpth=$libpth +! libs=$libs + libc=$libc, so=$so + useshrplib=$useshrplib, libperl=$libperl + Dynamic Linking: +--- 35,41 ---- + Linker and Libraries: + ld='$ld', ldflags ='$ldflags' + libpth=$libpth +! libs=$perllibs + libc=$libc, so=$so + useshrplib=$useshrplib, libperl=$libperl + Dynamic Linking: +diff -rc perl5.004_02.orig/patchlevel.h perl5.004_02/patchlevel.h +*** perl5.004_02.orig/patchlevel.h Fri Aug 1 15:07:34 1997 +--- perl5.004_02/patchlevel.h Sun Nov 12 22:06:25 2000 +*************** +*** 38,43 **** +--- 38,44 ---- + */ + static char *local_patches[] = { + NULL ++ ,"NODB-1.0 - remove -ldb from core perl binary." + ,NULL + }; + diff --git a/db/perl.BerkeleyDB/patches/5.004_03 b/db/perl.BerkeleyDB/patches/5.004_03 new file mode 100644 index 000000000..06331eac9 --- /dev/null +++ b/db/perl.BerkeleyDB/patches/5.004_03 @@ -0,0 +1,223 @@ +diff -rc perl5.004_03.orig/Configure perl5.004_03/Configure +*** perl5.004_03.orig/Configure Wed Aug 13 16:09:46 1997 +--- perl5.004_03/Configure Sun Nov 12 21:56:18 2000 +*************** +*** 188,193 **** +--- 188,194 ---- + mv='' + nroff='' + perl='' ++ perllibs='' + pg='' + pmake='' + pr='' +*************** +*** 9911,9916 **** +--- 9912,9925 ---- + shift + extensions="$*" + ++ : Remove libraries needed only for extensions ++ : The appropriate ext/Foo/Makefile.PL will add them back in, if ++ : necessary. ++ set X `echo " $libs " | ++ sed -e 's@ -lndbm @ @' -e 's@ -lgdbm @ @' -e 's@ -ldbm @ @' -e 's@ -ldb @ @'` ++ shift ++ perllibs="$*" ++ + : Remove build directory name from cppstdin so it can be used from + : either the present location or the final installed location. + echo " " +*************** +*** 10379,10384 **** +--- 10388,10394 ---- + patchlevel='$patchlevel' + path_sep='$path_sep' + perl='$perl' ++ perllibs='$perllibs' + perladmin='$perladmin' + perlpath='$perlpath' + pg='$pg' +Only in perl5.004_03: Configure.orig +diff -rc perl5.004_03.orig/Makefile.SH perl5.004_03/Makefile.SH +*** perl5.004_03.orig/Makefile.SH Mon Aug 18 19:24:29 1997 +--- perl5.004_03/Makefile.SH Sun Nov 12 21:56:18 2000 +*************** +*** 126,132 **** + ext = \$(dynamic_ext) \$(static_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $libs $cryptlib + + public = perl $suidperl utilities translators + +--- 126,132 ---- + ext = \$(dynamic_ext) \$(static_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $perllibs $cryptlib + + public = perl $suidperl utilities translators + +Only in perl5.004_03: Makefile.SH.orig +diff -rc perl5.004_03.orig/lib/ExtUtils/Embed.pm perl5.004_03/lib/ExtUtils/Embed.pm +*** perl5.004_03.orig/lib/ExtUtils/Embed.pm Fri Aug 1 15:08:44 1997 +--- perl5.004_03/lib/ExtUtils/Embed.pm Sun Nov 12 21:56:18 2000 +*************** +*** 178,184 **** + @path = $path ? split(/:/, $path) : @INC; + + push(@potential_libs, @link_args) if scalar @link_args; +! push(@potential_libs, $Config{libs}) if defined $std; + + push(@mods, static_ext()) if $std; + +--- 178,184 ---- + @path = $path ? split(/:/, $path) : @INC; + + push(@potential_libs, @link_args) if scalar @link_args; +! push(@potential_libs, $Config{perllibs}) if defined $std; + + push(@mods, static_ext()) if $std; + +diff -rc perl5.004_03.orig/lib/ExtUtils/Liblist.pm perl5.004_03/lib/ExtUtils/Liblist.pm +*** perl5.004_03.orig/lib/ExtUtils/Liblist.pm Fri Aug 1 19:36:58 1997 +--- perl5.004_03/lib/ExtUtils/Liblist.pm Sun Nov 12 21:57:17 2000 +*************** +*** 16,33 **** + + sub _unix_os2_ext { + my($self,$potential_libs, $verbose) = @_; +! if ($^O =~ 'os2' and $Config{libs}) { + # Dynamic libraries are not transitive, so we may need including + # the libraries linked against perl.dll again. + + $potential_libs .= " " if $potential_libs; +! $potential_libs .= $Config{libs}; + } + return ("", "", "", "") unless $potential_libs; + print STDOUT "Potential libraries are '$potential_libs':\n" if $verbose; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'libs'}; + my $Config_libext = $Config{lib_ext} || ".a"; + + +--- 16,33 ---- + + sub _unix_os2_ext { + my($self,$potential_libs, $verbose) = @_; +! if ($^O =~ 'os2' and $Config{perllibs}) { + # Dynamic libraries are not transitive, so we may need including + # the libraries linked against perl.dll again. + + $potential_libs .= " " if $potential_libs; +! $potential_libs .= $Config{perllibs}; + } + return ("", "", "", "") unless $potential_libs; + print STDOUT "Potential libraries are '$potential_libs':\n" if $verbose; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'perllibs'}; + my $Config_libext = $Config{lib_ext} || ".a"; + + +*************** +*** 186,196 **** + my($self, $potential_libs, $verbose) = @_; + + # If user did not supply a list, we punt. +! # (caller should probably use the list in $Config{libs}) + return ("", "", "", "") unless $potential_libs; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'libs'}; + my($libpth) = $Config{'libpth'}; + my($libext) = $Config{'lib_ext'} || ".lib"; + +--- 186,196 ---- + my($self, $potential_libs, $verbose) = @_; + + # If user did not supply a list, we punt. +! # (caller should probably use the list in $Config{perllibs}) + return ("", "", "", "") unless $potential_libs; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'perllibs'}; + my($libpth) = $Config{'libpth'}; + my($libext) = $Config{'lib_ext'} || ".lib"; + +*************** +*** 540,546 **** + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{libs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs> + as well as in C<$Config{libpth}>. For each library that is found, a +--- 540,546 ---- + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{perllibs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs> + as well as in C<$Config{libpth}>. For each library that is found, a +Only in perl5.004_03/lib/ExtUtils: Liblist.pm.orig +Only in perl5.004_03/lib/ExtUtils: Liblist.pm.rej +diff -rc perl5.004_03.orig/lib/ExtUtils/MM_Unix.pm perl5.004_03/lib/ExtUtils/MM_Unix.pm +*** perl5.004_03.orig/lib/ExtUtils/MM_Unix.pm Mon Aug 18 19:16:12 1997 +--- perl5.004_03/lib/ExtUtils/MM_Unix.pm Sun Nov 12 21:56:19 2000 +*************** +*** 2224,2230 **** + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{libs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { +--- 2224,2230 ---- + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{perllibs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { +Only in perl5.004_03/lib/ExtUtils: MM_Unix.pm.orig +diff -rc perl5.004_03.orig/myconfig perl5.004_03/myconfig +*** perl5.004_03.orig/myconfig Sat Dec 21 01:13:20 1996 +--- perl5.004_03/myconfig Sun Nov 12 21:56:19 2000 +*************** +*** 35,41 **** + Linker and Libraries: + ld='$ld', ldflags ='$ldflags' + libpth=$libpth +! libs=$libs + libc=$libc, so=$so + useshrplib=$useshrplib, libperl=$libperl + Dynamic Linking: +--- 35,41 ---- + Linker and Libraries: + ld='$ld', ldflags ='$ldflags' + libpth=$libpth +! libs=$perllibs + libc=$libc, so=$so + useshrplib=$useshrplib, libperl=$libperl + Dynamic Linking: +diff -rc perl5.004_03.orig/patchlevel.h perl5.004_03/patchlevel.h +*** perl5.004_03.orig/patchlevel.h Wed Aug 13 11:42:01 1997 +--- perl5.004_03/patchlevel.h Sun Nov 12 21:56:19 2000 +*************** +*** 38,43 **** +--- 38,44 ---- + */ + static char *local_patches[] = { + NULL ++ ,"NODB-1.0 - remove -ldb from core perl binary." + ,NULL + }; + +Only in perl5.004_03: patchlevel.h.orig diff --git a/db/perl.BerkeleyDB/patches/5.004_04 b/db/perl.BerkeleyDB/patches/5.004_04 new file mode 100644 index 000000000..a227dc700 --- /dev/null +++ b/db/perl.BerkeleyDB/patches/5.004_04 @@ -0,0 +1,209 @@ +diff -rc perl5.004_04.orig/Configure perl5.004_04/Configure +*** perl5.004_04.orig/Configure Fri Oct 3 18:57:39 1997 +--- perl5.004_04/Configure Sun Nov 12 21:50:51 2000 +*************** +*** 188,193 **** +--- 188,194 ---- + mv='' + nroff='' + perl='' ++ perllibs='' + pg='' + pmake='' + pr='' +*************** +*** 9910,9915 **** +--- 9911,9924 ---- + shift + extensions="$*" + ++ : Remove libraries needed only for extensions ++ : The appropriate ext/Foo/Makefile.PL will add them back in, if ++ : necessary. ++ set X `echo " $libs " | ++ sed -e 's@ -lndbm @ @' -e 's@ -lgdbm @ @' -e 's@ -ldbm @ @' -e 's@ -ldb @ @'` ++ shift ++ perllibs="$*" ++ + : Remove build directory name from cppstdin so it can be used from + : either the present location or the final installed location. + echo " " +*************** +*** 10378,10383 **** +--- 10387,10393 ---- + patchlevel='$patchlevel' + path_sep='$path_sep' + perl='$perl' ++ perllibs='$perllibs' + perladmin='$perladmin' + perlpath='$perlpath' + pg='$pg' +diff -rc perl5.004_04.orig/Makefile.SH perl5.004_04/Makefile.SH +*** perl5.004_04.orig/Makefile.SH Wed Oct 15 10:33:16 1997 +--- perl5.004_04/Makefile.SH Sun Nov 12 21:50:51 2000 +*************** +*** 129,135 **** + ext = \$(dynamic_ext) \$(static_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $libs $cryptlib + + public = perl $suidperl utilities translators + +--- 129,135 ---- + ext = \$(dynamic_ext) \$(static_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $perllibs $cryptlib + + public = perl $suidperl utilities translators + +diff -rc perl5.004_04.orig/lib/ExtUtils/Embed.pm perl5.004_04/lib/ExtUtils/Embed.pm +*** perl5.004_04.orig/lib/ExtUtils/Embed.pm Fri Aug 1 15:08:44 1997 +--- perl5.004_04/lib/ExtUtils/Embed.pm Sun Nov 12 21:50:51 2000 +*************** +*** 178,184 **** + @path = $path ? split(/:/, $path) : @INC; + + push(@potential_libs, @link_args) if scalar @link_args; +! push(@potential_libs, $Config{libs}) if defined $std; + + push(@mods, static_ext()) if $std; + +--- 178,184 ---- + @path = $path ? split(/:/, $path) : @INC; + + push(@potential_libs, @link_args) if scalar @link_args; +! push(@potential_libs, $Config{perllibs}) if defined $std; + + push(@mods, static_ext()) if $std; + +diff -rc perl5.004_04.orig/lib/ExtUtils/Liblist.pm perl5.004_04/lib/ExtUtils/Liblist.pm +*** perl5.004_04.orig/lib/ExtUtils/Liblist.pm Tue Sep 9 17:41:32 1997 +--- perl5.004_04/lib/ExtUtils/Liblist.pm Sun Nov 12 21:51:33 2000 +*************** +*** 16,33 **** + + sub _unix_os2_ext { + my($self,$potential_libs, $verbose) = @_; +! if ($^O =~ 'os2' and $Config{libs}) { + # Dynamic libraries are not transitive, so we may need including + # the libraries linked against perl.dll again. + + $potential_libs .= " " if $potential_libs; +! $potential_libs .= $Config{libs}; + } + return ("", "", "", "") unless $potential_libs; + warn "Potential libraries are '$potential_libs':\n" if $verbose; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'libs'}; + my $Config_libext = $Config{lib_ext} || ".a"; + + +--- 16,33 ---- + + sub _unix_os2_ext { + my($self,$potential_libs, $verbose) = @_; +! if ($^O =~ 'os2' and $Config{perllibs}) { + # Dynamic libraries are not transitive, so we may need including + # the libraries linked against perl.dll again. + + $potential_libs .= " " if $potential_libs; +! $potential_libs .= $Config{perllibs}; + } + return ("", "", "", "") unless $potential_libs; + warn "Potential libraries are '$potential_libs':\n" if $verbose; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'perllibs'}; + my $Config_libext = $Config{lib_ext} || ".a"; + + +*************** +*** 189,195 **** + return ("", "", "", "") unless $potential_libs; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'libs'}; + my($libpth) = $Config{'libpth'}; + my($libext) = $Config{'lib_ext'} || ".lib"; + +--- 189,195 ---- + return ("", "", "", "") unless $potential_libs; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'perllibs'}; + my($libpth) = $Config{'libpth'}; + my($libext) = $Config{'lib_ext'} || ".lib"; + +*************** +*** 539,545 **** + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{libs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs> + as well as in C<$Config{libpth}>. For each library that is found, a +--- 539,545 ---- + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{perllibs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs> + as well as in C<$Config{libpth}>. For each library that is found, a +diff -rc perl5.004_04.orig/lib/ExtUtils/MM_Unix.pm perl5.004_04/lib/ExtUtils/MM_Unix.pm +*** perl5.004_04.orig/lib/ExtUtils/MM_Unix.pm Wed Oct 8 14:13:51 1997 +--- perl5.004_04/lib/ExtUtils/MM_Unix.pm Sun Nov 12 21:50:51 2000 +*************** +*** 2229,2235 **** + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{libs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { +--- 2229,2235 ---- + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{perllibs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { +diff -rc perl5.004_04.orig/myconfig perl5.004_04/myconfig +*** perl5.004_04.orig/myconfig Mon Oct 6 18:26:49 1997 +--- perl5.004_04/myconfig Sun Nov 12 21:50:51 2000 +*************** +*** 35,41 **** + Linker and Libraries: + ld='$ld', ldflags ='$ldflags' + libpth=$libpth +! libs=$libs + libc=$libc, so=$so + useshrplib=$useshrplib, libperl=$libperl + Dynamic Linking: +--- 35,41 ---- + Linker and Libraries: + ld='$ld', ldflags ='$ldflags' + libpth=$libpth +! libs=$perllibs + libc=$libc, so=$so + useshrplib=$useshrplib, libperl=$libperl + Dynamic Linking: +diff -rc perl5.004_04.orig/patchlevel.h perl5.004_04/patchlevel.h +*** perl5.004_04.orig/patchlevel.h Wed Oct 15 10:55:19 1997 +--- perl5.004_04/patchlevel.h Sun Nov 12 21:50:51 2000 +*************** +*** 39,44 **** +--- 39,45 ---- + /* The following line and terminating '};' are read by perlbug.PL. Don't alter. */ + static char *local_patches[] = { + NULL ++ ,"NODB-1.0 - remove -ldb from core perl binary." + ,NULL + }; + diff --git a/db/perl.BerkeleyDB/patches/5.004_05 b/db/perl.BerkeleyDB/patches/5.004_05 new file mode 100644 index 000000000..51c8bf350 --- /dev/null +++ b/db/perl.BerkeleyDB/patches/5.004_05 @@ -0,0 +1,209 @@ +diff -rc perl5.004_05.orig/Configure perl5.004_05/Configure +*** perl5.004_05.orig/Configure Thu Jan 6 22:05:49 2000 +--- perl5.004_05/Configure Sun Nov 12 21:36:25 2000 +*************** +*** 188,193 **** +--- 188,194 ---- + mv='' + nroff='' + perl='' ++ perllibs='' + pg='' + pmake='' + pr='' +*************** +*** 10164,10169 **** +--- 10165,10178 ---- + shift + extensions="$*" + ++ : Remove libraries needed only for extensions ++ : The appropriate ext/Foo/Makefile.PL will add them back in, if ++ : necessary. ++ set X `echo " $libs " | ++ sed -e 's@ -lndbm @ @' -e 's@ -lgdbm @ @' -e 's@ -ldbm @ @' -e 's@ -ldb @ @'` ++ shift ++ perllibs="$*" ++ + : Remove build directory name from cppstdin so it can be used from + : either the present location or the final installed location. + echo " " +*************** +*** 10648,10653 **** +--- 10657,10663 ---- + patchlevel='$patchlevel' + path_sep='$path_sep' + perl='$perl' ++ perllibs='$perllibs' + perladmin='$perladmin' + perlpath='$perlpath' + pg='$pg' +diff -rc perl5.004_05.orig/Makefile.SH perl5.004_05/Makefile.SH +*** perl5.004_05.orig/Makefile.SH Thu Jan 6 22:05:49 2000 +--- perl5.004_05/Makefile.SH Sun Nov 12 21:36:25 2000 +*************** +*** 151,157 **** + ext = \$(dynamic_ext) \$(static_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $libs $cryptlib + + public = perl $suidperl utilities translators + +--- 151,157 ---- + ext = \$(dynamic_ext) \$(static_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $perllibs $cryptlib + + public = perl $suidperl utilities translators + +diff -rc perl5.004_05.orig/lib/ExtUtils/Embed.pm perl5.004_05/lib/ExtUtils/Embed.pm +*** perl5.004_05.orig/lib/ExtUtils/Embed.pm Fri Aug 1 15:08:44 1997 +--- perl5.004_05/lib/ExtUtils/Embed.pm Sun Nov 12 21:36:25 2000 +*************** +*** 178,184 **** + @path = $path ? split(/:/, $path) : @INC; + + push(@potential_libs, @link_args) if scalar @link_args; +! push(@potential_libs, $Config{libs}) if defined $std; + + push(@mods, static_ext()) if $std; + +--- 178,184 ---- + @path = $path ? split(/:/, $path) : @INC; + + push(@potential_libs, @link_args) if scalar @link_args; +! push(@potential_libs, $Config{perllibs}) if defined $std; + + push(@mods, static_ext()) if $std; + +diff -rc perl5.004_05.orig/lib/ExtUtils/Liblist.pm perl5.004_05/lib/ExtUtils/Liblist.pm +*** perl5.004_05.orig/lib/ExtUtils/Liblist.pm Thu Jan 6 22:05:54 2000 +--- perl5.004_05/lib/ExtUtils/Liblist.pm Sun Nov 12 21:45:31 2000 +*************** +*** 16,33 **** + + sub _unix_os2_ext { + my($self,$potential_libs, $verbose) = @_; +! if ($^O =~ 'os2' and $Config{libs}) { + # Dynamic libraries are not transitive, so we may need including + # the libraries linked against perl.dll again. + + $potential_libs .= " " if $potential_libs; +! $potential_libs .= $Config{libs}; + } + return ("", "", "", "") unless $potential_libs; + warn "Potential libraries are '$potential_libs':\n" if $verbose; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'libs'}; + my $Config_libext = $Config{lib_ext} || ".a"; + + +--- 16,33 ---- + + sub _unix_os2_ext { + my($self,$potential_libs, $verbose) = @_; +! if ($^O =~ 'os2' and $Config{perllibs}) { + # Dynamic libraries are not transitive, so we may need including + # the libraries linked against perl.dll again. + + $potential_libs .= " " if $potential_libs; +! $potential_libs .= $Config{perllibs}; + } + return ("", "", "", "") unless $potential_libs; + warn "Potential libraries are '$potential_libs':\n" if $verbose; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'perllibs'}; + my $Config_libext = $Config{lib_ext} || ".a"; + + +*************** +*** 196,202 **** + my $BC = 1 if $cc =~ /^bcc/i; + my $GC = 1 if $cc =~ /^gcc/i; + my $so = $Config{'so'}; +! my $libs = $Config{'libs'}; + my $libpth = $Config{'libpth'}; + my $libext = $Config{'lib_ext'} || ".lib"; + +--- 196,202 ---- + my $BC = 1 if $cc =~ /^bcc/i; + my $GC = 1 if $cc =~ /^gcc/i; + my $so = $Config{'so'}; +! my $libs = $Config{'perllibs'}; + my $libpth = $Config{'libpth'}; + my $libext = $Config{'lib_ext'} || ".lib"; + +*************** +*** 590,596 **** + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{libs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs> + as well as in C<$Config{libpth}>. For each library that is found, a +--- 590,596 ---- + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{perllibs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs> + as well as in C<$Config{libpth}>. For each library that is found, a +diff -rc perl5.004_05.orig/lib/ExtUtils/MM_Unix.pm perl5.004_05/lib/ExtUtils/MM_Unix.pm +*** perl5.004_05.orig/lib/ExtUtils/MM_Unix.pm Thu Jan 6 22:05:54 2000 +--- perl5.004_05/lib/ExtUtils/MM_Unix.pm Sun Nov 12 21:36:25 2000 +*************** +*** 2246,2252 **** + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{libs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { +--- 2246,2252 ---- + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{perllibs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { +diff -rc perl5.004_05.orig/myconfig perl5.004_05/myconfig +*** perl5.004_05.orig/myconfig Thu Jan 6 22:05:55 2000 +--- perl5.004_05/myconfig Sun Nov 12 21:43:54 2000 +*************** +*** 34,40 **** + Linker and Libraries: + ld='$ld', ldflags ='$ldflags' + libpth=$libpth +! libs=$libs + libc=$libc, so=$so + useshrplib=$useshrplib, libperl=$libperl + Dynamic Linking: +--- 34,40 ---- + Linker and Libraries: + ld='$ld', ldflags ='$ldflags' + libpth=$libpth +! libs=$perllibs + libc=$libc, so=$so + useshrplib=$useshrplib, libperl=$libperl + Dynamic Linking: +diff -rc perl5.004_05.orig/patchlevel.h perl5.004_05/patchlevel.h +*** perl5.004_05.orig/patchlevel.h Thu Jan 6 22:05:48 2000 +--- perl5.004_05/patchlevel.h Sun Nov 12 21:36:25 2000 +*************** +*** 39,44 **** +--- 39,45 ---- + /* The following line and terminating '};' are read by perlbug.PL. Don't alter. */ + static char *local_patches[] = { + NULL ++ ,"NODB-1.0 - remove -ldb from core perl binary." + ,NULL + }; + diff --git a/db/perl.BerkeleyDB/patches/5.005 b/db/perl.BerkeleyDB/patches/5.005 new file mode 100644 index 000000000..effee3e82 --- /dev/null +++ b/db/perl.BerkeleyDB/patches/5.005 @@ -0,0 +1,209 @@ +diff -rc perl5.005.orig/Configure perl5.005/Configure +*** perl5.005.orig/Configure Wed Jul 15 08:05:44 1998 +--- perl5.005/Configure Sun Nov 12 21:30:40 2000 +*************** +*** 234,239 **** +--- 234,240 ---- + nm='' + nroff='' + perl='' ++ perllibs='' + pg='' + pmake='' + pr='' +*************** +*** 11279,11284 **** +--- 11280,11293 ---- + shift + extensions="$*" + ++ : Remove libraries needed only for extensions ++ : The appropriate ext/Foo/Makefile.PL will add them back in, if ++ : necessary. ++ set X `echo " $libs " | ++ sed -e 's@ -lndbm @ @' -e 's@ -lgdbm @ @' -e 's@ -ldbm @ @' -e 's@ -ldb @ @'` ++ shift ++ perllibs="$*" ++ + : Remove build directory name from cppstdin so it can be used from + : either the present location or the final installed location. + echo " " +*************** +*** 11804,11809 **** +--- 11813,11819 ---- + patchlevel='$patchlevel' + path_sep='$path_sep' + perl='$perl' ++ perllibs='$perllibs' + perladmin='$perladmin' + perlpath='$perlpath' + pg='$pg' +diff -rc perl5.005.orig/Makefile.SH perl5.005/Makefile.SH +*** perl5.005.orig/Makefile.SH Sun Jul 19 08:06:35 1998 +--- perl5.005/Makefile.SH Sun Nov 12 21:30:40 2000 +*************** +*** 150,156 **** + ext = \$(dynamic_ext) \$(static_ext) \$(nonxs_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $libs $cryptlib + + public = perl $suidperl utilities translators + +--- 150,156 ---- + ext = \$(dynamic_ext) \$(static_ext) \$(nonxs_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $perllibs $cryptlib + + public = perl $suidperl utilities translators + +diff -rc perl5.005.orig/lib/ExtUtils/Embed.pm perl5.005/lib/ExtUtils/Embed.pm +*** perl5.005.orig/lib/ExtUtils/Embed.pm Wed Jul 22 07:45:02 1998 +--- perl5.005/lib/ExtUtils/Embed.pm Sun Nov 12 21:30:40 2000 +*************** +*** 194,200 **** + @path = $path ? split(/:/, $path) : @INC; + + push(@potential_libs, @link_args) if scalar @link_args; +! push(@potential_libs, $Config{libs}) if defined $std; + + push(@mods, static_ext()) if $std; + +--- 194,200 ---- + @path = $path ? split(/:/, $path) : @INC; + + push(@potential_libs, @link_args) if scalar @link_args; +! push(@potential_libs, $Config{perllibs}) if defined $std; + + push(@mods, static_ext()) if $std; + +diff -rc perl5.005.orig/lib/ExtUtils/Liblist.pm perl5.005/lib/ExtUtils/Liblist.pm +*** perl5.005.orig/lib/ExtUtils/Liblist.pm Wed Jul 22 07:09:42 1998 +--- perl5.005/lib/ExtUtils/Liblist.pm Sun Nov 12 21:30:40 2000 +*************** +*** 16,33 **** + + sub _unix_os2_ext { + my($self,$potential_libs, $verbose) = @_; +! if ($^O =~ 'os2' and $Config{libs}) { + # Dynamic libraries are not transitive, so we may need including + # the libraries linked against perl.dll again. + + $potential_libs .= " " if $potential_libs; +! $potential_libs .= $Config{libs}; + } + return ("", "", "", "") unless $potential_libs; + warn "Potential libraries are '$potential_libs':\n" if $verbose; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'libs'}; + my $Config_libext = $Config{lib_ext} || ".a"; + + +--- 16,33 ---- + + sub _unix_os2_ext { + my($self,$potential_libs, $verbose) = @_; +! if ($^O =~ 'os2' and $Config{perllibs}) { + # Dynamic libraries are not transitive, so we may need including + # the libraries linked against perl.dll again. + + $potential_libs .= " " if $potential_libs; +! $potential_libs .= $Config{perllibs}; + } + return ("", "", "", "") unless $potential_libs; + warn "Potential libraries are '$potential_libs':\n" if $verbose; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'perllibs'}; + my $Config_libext = $Config{lib_ext} || ".a"; + + +*************** +*** 290,296 **** + $self->{CCFLAS} || $Config{'ccflags'}; + @crtls = ( ($dbgqual =~ m-/Debug-i ? $Config{'dbgprefix'} : '') + . 'PerlShr/Share' ); +! push(@crtls, grep { not /\(/ } split /\s+/, $Config{'libs'}); + push(@crtls, grep { not /\(/ } split /\s+/, $Config{'libc'}); + # In general, we pass through the basic libraries from %Config unchanged. + # The one exception is that if we're building in the Perl source tree, and +--- 290,296 ---- + $self->{CCFLAS} || $Config{'ccflags'}; + @crtls = ( ($dbgqual =~ m-/Debug-i ? $Config{'dbgprefix'} : '') + . 'PerlShr/Share' ); +! push(@crtls, grep { not /\(/ } split /\s+/, $Config{'perllibs'}); + push(@crtls, grep { not /\(/ } split /\s+/, $Config{'libc'}); + # In general, we pass through the basic libraries from %Config unchanged. + # The one exception is that if we're building in the Perl source tree, and +*************** +*** 598,604 **** + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{libs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs> + as well as in C<$Config{libpth}>. For each library that is found, a +--- 598,604 ---- + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{perllibs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs> + as well as in C<$Config{libpth}>. For each library that is found, a +diff -rc perl5.005.orig/lib/ExtUtils/MM_Unix.pm perl5.005/lib/ExtUtils/MM_Unix.pm +*** perl5.005.orig/lib/ExtUtils/MM_Unix.pm Tue Jul 14 04:39:12 1998 +--- perl5.005/lib/ExtUtils/MM_Unix.pm Sun Nov 12 21:30:41 2000 +*************** +*** 2281,2287 **** + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{libs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { +--- 2281,2287 ---- + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{perllibs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { +diff -rc perl5.005.orig/myconfig perl5.005/myconfig +*** perl5.005.orig/myconfig Fri Apr 3 01:20:35 1998 +--- perl5.005/myconfig Sun Nov 12 21:30:41 2000 +*************** +*** 34,40 **** + Linker and Libraries: + ld='$ld', ldflags ='$ldflags' + libpth=$libpth +! libs=$libs + libc=$libc, so=$so, useshrplib=$useshrplib, libperl=$libperl + Dynamic Linking: + dlsrc=$dlsrc, dlext=$dlext, d_dlsymun=$d_dlsymun, ccdlflags='$ccdlflags' +--- 34,40 ---- + Linker and Libraries: + ld='$ld', ldflags ='$ldflags' + libpth=$libpth +! libs=$perllibs + libc=$libc, so=$so, useshrplib=$useshrplib, libperl=$libperl + Dynamic Linking: + dlsrc=$dlsrc, dlext=$dlext, d_dlsymun=$d_dlsymun, ccdlflags='$ccdlflags' +diff -rc perl5.005.orig/patchlevel.h perl5.005/patchlevel.h +*** perl5.005.orig/patchlevel.h Wed Jul 22 19:22:01 1998 +--- perl5.005/patchlevel.h Sun Nov 12 21:30:41 2000 +*************** +*** 39,44 **** +--- 39,45 ---- + */ + static char *local_patches[] = { + NULL ++ ,"NODB-1.0 - remove -ldb from core perl binary." + ,NULL + }; + diff --git a/db/perl.BerkeleyDB/patches/5.005_01 b/db/perl.BerkeleyDB/patches/5.005_01 new file mode 100644 index 000000000..2a05dd545 --- /dev/null +++ b/db/perl.BerkeleyDB/patches/5.005_01 @@ -0,0 +1,209 @@ +diff -rc perl5.005_01.orig/Configure perl5.005_01/Configure +*** perl5.005_01.orig/Configure Wed Jul 15 08:05:44 1998 +--- perl5.005_01/Configure Sun Nov 12 20:55:58 2000 +*************** +*** 234,239 **** +--- 234,240 ---- + nm='' + nroff='' + perl='' ++ perllibs='' + pg='' + pmake='' + pr='' +*************** +*** 11279,11284 **** +--- 11280,11293 ---- + shift + extensions="$*" + ++ : Remove libraries needed only for extensions ++ : The appropriate ext/Foo/Makefile.PL will add them back in, if ++ : necessary. ++ set X `echo " $libs " | ++ sed -e 's@ -lndbm @ @' -e 's@ -lgdbm @ @' -e 's@ -ldbm @ @' -e 's@ -ldb @ @'` ++ shift ++ perllibs="$*" ++ + : Remove build directory name from cppstdin so it can be used from + : either the present location or the final installed location. + echo " " +*************** +*** 11804,11809 **** +--- 11813,11819 ---- + patchlevel='$patchlevel' + path_sep='$path_sep' + perl='$perl' ++ perllibs='$perllibs' + perladmin='$perladmin' + perlpath='$perlpath' + pg='$pg' +diff -rc perl5.005_01.orig/Makefile.SH perl5.005_01/Makefile.SH +*** perl5.005_01.orig/Makefile.SH Sun Jul 19 08:06:35 1998 +--- perl5.005_01/Makefile.SH Sun Nov 12 20:55:58 2000 +*************** +*** 150,156 **** + ext = \$(dynamic_ext) \$(static_ext) \$(nonxs_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $libs $cryptlib + + public = perl $suidperl utilities translators + +--- 150,156 ---- + ext = \$(dynamic_ext) \$(static_ext) \$(nonxs_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $perllibs $cryptlib + + public = perl $suidperl utilities translators + +diff -rc perl5.005_01.orig/lib/ExtUtils/Embed.pm perl5.005_01/lib/ExtUtils/Embed.pm +*** perl5.005_01.orig/lib/ExtUtils/Embed.pm Wed Jul 22 07:45:02 1998 +--- perl5.005_01/lib/ExtUtils/Embed.pm Sun Nov 12 20:55:58 2000 +*************** +*** 194,200 **** + @path = $path ? split(/:/, $path) : @INC; + + push(@potential_libs, @link_args) if scalar @link_args; +! push(@potential_libs, $Config{libs}) if defined $std; + + push(@mods, static_ext()) if $std; + +--- 194,200 ---- + @path = $path ? split(/:/, $path) : @INC; + + push(@potential_libs, @link_args) if scalar @link_args; +! push(@potential_libs, $Config{perllibs}) if defined $std; + + push(@mods, static_ext()) if $std; + +diff -rc perl5.005_01.orig/lib/ExtUtils/Liblist.pm perl5.005_01/lib/ExtUtils/Liblist.pm +*** perl5.005_01.orig/lib/ExtUtils/Liblist.pm Wed Jul 22 07:09:42 1998 +--- perl5.005_01/lib/ExtUtils/Liblist.pm Sun Nov 12 20:55:58 2000 +*************** +*** 16,33 **** + + sub _unix_os2_ext { + my($self,$potential_libs, $verbose) = @_; +! if ($^O =~ 'os2' and $Config{libs}) { + # Dynamic libraries are not transitive, so we may need including + # the libraries linked against perl.dll again. + + $potential_libs .= " " if $potential_libs; +! $potential_libs .= $Config{libs}; + } + return ("", "", "", "") unless $potential_libs; + warn "Potential libraries are '$potential_libs':\n" if $verbose; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'libs'}; + my $Config_libext = $Config{lib_ext} || ".a"; + + +--- 16,33 ---- + + sub _unix_os2_ext { + my($self,$potential_libs, $verbose) = @_; +! if ($^O =~ 'os2' and $Config{perllibs}) { + # Dynamic libraries are not transitive, so we may need including + # the libraries linked against perl.dll again. + + $potential_libs .= " " if $potential_libs; +! $potential_libs .= $Config{perllibs}; + } + return ("", "", "", "") unless $potential_libs; + warn "Potential libraries are '$potential_libs':\n" if $verbose; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'perllibs'}; + my $Config_libext = $Config{lib_ext} || ".a"; + + +*************** +*** 290,296 **** + $self->{CCFLAS} || $Config{'ccflags'}; + @crtls = ( ($dbgqual =~ m-/Debug-i ? $Config{'dbgprefix'} : '') + . 'PerlShr/Share' ); +! push(@crtls, grep { not /\(/ } split /\s+/, $Config{'libs'}); + push(@crtls, grep { not /\(/ } split /\s+/, $Config{'libc'}); + # In general, we pass through the basic libraries from %Config unchanged. + # The one exception is that if we're building in the Perl source tree, and +--- 290,296 ---- + $self->{CCFLAS} || $Config{'ccflags'}; + @crtls = ( ($dbgqual =~ m-/Debug-i ? $Config{'dbgprefix'} : '') + . 'PerlShr/Share' ); +! push(@crtls, grep { not /\(/ } split /\s+/, $Config{'perllibs'}); + push(@crtls, grep { not /\(/ } split /\s+/, $Config{'libc'}); + # In general, we pass through the basic libraries from %Config unchanged. + # The one exception is that if we're building in the Perl source tree, and +*************** +*** 598,604 **** + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{libs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs> + as well as in C<$Config{libpth}>. For each library that is found, a +--- 598,604 ---- + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{perllibs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs> + as well as in C<$Config{libpth}>. For each library that is found, a +diff -rc perl5.005_01.orig/lib/ExtUtils/MM_Unix.pm perl5.005_01/lib/ExtUtils/MM_Unix.pm +*** perl5.005_01.orig/lib/ExtUtils/MM_Unix.pm Tue Jul 14 04:39:12 1998 +--- perl5.005_01/lib/ExtUtils/MM_Unix.pm Sun Nov 12 20:55:58 2000 +*************** +*** 2281,2287 **** + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{libs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { +--- 2281,2287 ---- + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{perllibs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { +diff -rc perl5.005_01.orig/myconfig perl5.005_01/myconfig +*** perl5.005_01.orig/myconfig Fri Apr 3 01:20:35 1998 +--- perl5.005_01/myconfig Sun Nov 12 20:55:58 2000 +*************** +*** 34,40 **** + Linker and Libraries: + ld='$ld', ldflags ='$ldflags' + libpth=$libpth +! libs=$libs + libc=$libc, so=$so, useshrplib=$useshrplib, libperl=$libperl + Dynamic Linking: + dlsrc=$dlsrc, dlext=$dlext, d_dlsymun=$d_dlsymun, ccdlflags='$ccdlflags' +--- 34,40 ---- + Linker and Libraries: + ld='$ld', ldflags ='$ldflags' + libpth=$libpth +! libs=$perllibs + libc=$libc, so=$so, useshrplib=$useshrplib, libperl=$libperl + Dynamic Linking: + dlsrc=$dlsrc, dlext=$dlext, d_dlsymun=$d_dlsymun, ccdlflags='$ccdlflags' +diff -rc perl5.005_01.orig/patchlevel.h perl5.005_01/patchlevel.h +*** perl5.005_01.orig/patchlevel.h Mon Jan 3 11:07:45 2000 +--- perl5.005_01/patchlevel.h Sun Nov 12 20:55:58 2000 +*************** +*** 39,44 **** +--- 39,45 ---- + */ + static char *local_patches[] = { + NULL ++ ,"NODB-1.0 - remove -ldb from core perl binary." + ,NULL + }; + diff --git a/db/perl.BerkeleyDB/patches/5.005_02 b/db/perl.BerkeleyDB/patches/5.005_02 new file mode 100644 index 000000000..5dd57ddc0 --- /dev/null +++ b/db/perl.BerkeleyDB/patches/5.005_02 @@ -0,0 +1,264 @@ +diff -rc perl5.005_02.orig/Configure perl5.005_02/Configure +*** perl5.005_02.orig/Configure Mon Jan 3 11:12:20 2000 +--- perl5.005_02/Configure Sun Nov 12 20:50:51 2000 +*************** +*** 234,239 **** +--- 234,240 ---- + nm='' + nroff='' + perl='' ++ perllibs='' + pg='' + pmake='' + pr='' +*************** +*** 11334,11339 **** +--- 11335,11348 ---- + shift + extensions="$*" + ++ : Remove libraries needed only for extensions ++ : The appropriate ext/Foo/Makefile.PL will add them back in, if ++ : necessary. ++ set X `echo " $libs " | ++ sed -e 's@ -lndbm @ @' -e 's@ -lgdbm @ @' -e 's@ -ldbm @ @' -e 's@ -ldb @ @'` ++ shift ++ perllibs="$*" ++ + : Remove build directory name from cppstdin so it can be used from + : either the present location or the final installed location. + echo " " +*************** +*** 11859,11864 **** +--- 11868,11874 ---- + patchlevel='$patchlevel' + path_sep='$path_sep' + perl='$perl' ++ perllibs='$perllibs' + perladmin='$perladmin' + perlpath='$perlpath' + pg='$pg' +Only in perl5.005_02: Configure.orig +diff -rc perl5.005_02.orig/Makefile.SH perl5.005_02/Makefile.SH +*** perl5.005_02.orig/Makefile.SH Sun Jul 19 08:06:35 1998 +--- perl5.005_02/Makefile.SH Sun Nov 12 20:50:51 2000 +*************** +*** 150,156 **** + ext = \$(dynamic_ext) \$(static_ext) \$(nonxs_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $libs $cryptlib + + public = perl $suidperl utilities translators + +--- 150,156 ---- + ext = \$(dynamic_ext) \$(static_ext) \$(nonxs_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $perllibs $cryptlib + + public = perl $suidperl utilities translators + +Only in perl5.005_02: Makefile.SH.orig +diff -rc perl5.005_02.orig/lib/ExtUtils/Embed.pm perl5.005_02/lib/ExtUtils/Embed.pm +*** perl5.005_02.orig/lib/ExtUtils/Embed.pm Wed Jul 22 07:45:02 1998 +--- perl5.005_02/lib/ExtUtils/Embed.pm Sun Nov 12 20:50:51 2000 +*************** +*** 194,200 **** + @path = $path ? split(/:/, $path) : @INC; + + push(@potential_libs, @link_args) if scalar @link_args; +! push(@potential_libs, $Config{libs}) if defined $std; + + push(@mods, static_ext()) if $std; + +--- 194,200 ---- + @path = $path ? split(/:/, $path) : @INC; + + push(@potential_libs, @link_args) if scalar @link_args; +! push(@potential_libs, $Config{perllibs}) if defined $std; + + push(@mods, static_ext()) if $std; + +diff -rc perl5.005_02.orig/lib/ExtUtils/Liblist.pm perl5.005_02/lib/ExtUtils/Liblist.pm +*** perl5.005_02.orig/lib/ExtUtils/Liblist.pm Mon Jan 3 11:12:21 2000 +--- perl5.005_02/lib/ExtUtils/Liblist.pm Sun Nov 12 20:50:51 2000 +*************** +*** 16,33 **** + + sub _unix_os2_ext { + my($self,$potential_libs, $verbose) = @_; +! if ($^O =~ 'os2' and $Config{libs}) { + # Dynamic libraries are not transitive, so we may need including + # the libraries linked against perl.dll again. + + $potential_libs .= " " if $potential_libs; +! $potential_libs .= $Config{libs}; + } + return ("", "", "", "") unless $potential_libs; + warn "Potential libraries are '$potential_libs':\n" if $verbose; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'libs'}; + my $Config_libext = $Config{lib_ext} || ".a"; + + +--- 16,33 ---- + + sub _unix_os2_ext { + my($self,$potential_libs, $verbose) = @_; +! if ($^O =~ 'os2' and $Config{perllibs}) { + # Dynamic libraries are not transitive, so we may need including + # the libraries linked against perl.dll again. + + $potential_libs .= " " if $potential_libs; +! $potential_libs .= $Config{perllibs}; + } + return ("", "", "", "") unless $potential_libs; + warn "Potential libraries are '$potential_libs':\n" if $verbose; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'perllibs'}; + my $Config_libext = $Config{lib_ext} || ".a"; + + +*************** +*** 196,202 **** + my $BC = 1 if $cc =~ /^bcc/i; + my $GC = 1 if $cc =~ /^gcc/i; + my $so = $Config{'so'}; +! my $libs = $Config{'libs'}; + my $libpth = $Config{'libpth'}; + my $libext = $Config{'lib_ext'} || ".lib"; + +--- 196,202 ---- + my $BC = 1 if $cc =~ /^bcc/i; + my $GC = 1 if $cc =~ /^gcc/i; + my $so = $Config{'so'}; +! my $libs = $Config{'perllibs'}; + my $libpth = $Config{'libpth'}; + my $libext = $Config{'lib_ext'} || ".lib"; + +*************** +*** 333,339 **** + $self->{CCFLAS} || $Config{'ccflags'}; + @crtls = ( ($dbgqual =~ m-/Debug-i ? $Config{'dbgprefix'} : '') + . 'PerlShr/Share' ); +! push(@crtls, grep { not /\(/ } split /\s+/, $Config{'libs'}); + push(@crtls, grep { not /\(/ } split /\s+/, $Config{'libc'}); + # In general, we pass through the basic libraries from %Config unchanged. + # The one exception is that if we're building in the Perl source tree, and +--- 333,339 ---- + $self->{CCFLAS} || $Config{'ccflags'}; + @crtls = ( ($dbgqual =~ m-/Debug-i ? $Config{'dbgprefix'} : '') + . 'PerlShr/Share' ); +! push(@crtls, grep { not /\(/ } split /\s+/, $Config{'perllibs'}); + push(@crtls, grep { not /\(/ } split /\s+/, $Config{'libc'}); + # In general, we pass through the basic libraries from %Config unchanged. + # The one exception is that if we're building in the Perl source tree, and +*************** +*** 623,629 **** + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{libs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs> + as well as in C<$Config{libpth}>. For each library that is found, a +--- 623,629 ---- + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{perllibs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs> + as well as in C<$Config{libpth}>. For each library that is found, a +*************** +*** 666,672 **** + alphanumeric characters are treated as flags. Unknown flags will be ignored. + + An entry that matches C disables the appending of default +! libraries found in C<$Config{libs}> (this should be only needed very rarely). + + An entry that matches C disables all searching for + the libraries specified after it. Translation of C<-Lfoo> and +--- 666,672 ---- + alphanumeric characters are treated as flags. Unknown flags will be ignored. + + An entry that matches C disables the appending of default +! libraries found in C<$Config{perllibs}> (this should be only needed very rarely). + + An entry that matches C disables all searching for + the libraries specified after it. Translation of C<-Lfoo> and +*************** +*** 676,682 **** + + An entry that matches C reenables searching for + the libraries specified after it. You can put it at the end to +! enable searching for default libraries specified by C<$Config{libs}>. + + =item * + +--- 676,682 ---- + + An entry that matches C reenables searching for + the libraries specified after it. You can put it at the end to +! enable searching for default libraries specified by C<$Config{perllibs}>. + + =item * + +Only in perl5.005_02/lib/ExtUtils: Liblist.pm.orig +diff -rc perl5.005_02.orig/lib/ExtUtils/MM_Unix.pm perl5.005_02/lib/ExtUtils/MM_Unix.pm +*** perl5.005_02.orig/lib/ExtUtils/MM_Unix.pm Tue Jul 14 04:39:12 1998 +--- perl5.005_02/lib/ExtUtils/MM_Unix.pm Sun Nov 12 20:50:51 2000 +*************** +*** 2281,2287 **** + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{libs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { +--- 2281,2287 ---- + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{perllibs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { +Only in perl5.005_02/lib/ExtUtils: MM_Unix.pm.orig +diff -rc perl5.005_02.orig/myconfig perl5.005_02/myconfig +*** perl5.005_02.orig/myconfig Fri Apr 3 01:20:35 1998 +--- perl5.005_02/myconfig Sun Nov 12 20:50:51 2000 +*************** +*** 34,40 **** + Linker and Libraries: + ld='$ld', ldflags ='$ldflags' + libpth=$libpth +! libs=$libs + libc=$libc, so=$so, useshrplib=$useshrplib, libperl=$libperl + Dynamic Linking: + dlsrc=$dlsrc, dlext=$dlext, d_dlsymun=$d_dlsymun, ccdlflags='$ccdlflags' +--- 34,40 ---- + Linker and Libraries: + ld='$ld', ldflags ='$ldflags' + libpth=$libpth +! libs=$perllibs + libc=$libc, so=$so, useshrplib=$useshrplib, libperl=$libperl + Dynamic Linking: + dlsrc=$dlsrc, dlext=$dlext, d_dlsymun=$d_dlsymun, ccdlflags='$ccdlflags' +diff -rc perl5.005_02.orig/patchlevel.h perl5.005_02/patchlevel.h +*** perl5.005_02.orig/patchlevel.h Mon Jan 3 11:12:19 2000 +--- perl5.005_02/patchlevel.h Sun Nov 12 20:50:51 2000 +*************** +*** 40,45 **** +--- 40,46 ---- + */ + static char *local_patches[] = { + NULL ++ ,"NODB-1.0 - remove -ldb from core perl binary." + ,NULL + }; + diff --git a/db/perl.BerkeleyDB/patches/5.005_03 b/db/perl.BerkeleyDB/patches/5.005_03 new file mode 100644 index 000000000..115f9f5b9 --- /dev/null +++ b/db/perl.BerkeleyDB/patches/5.005_03 @@ -0,0 +1,250 @@ +diff -rc perl5.005_03.orig/Configure perl5.005_03/Configure +*** perl5.005_03.orig/Configure Sun Mar 28 17:12:57 1999 +--- perl5.005_03/Configure Sun Sep 17 22:19:16 2000 +*************** +*** 208,213 **** +--- 208,214 ---- + nm='' + nroff='' + perl='' ++ perllibs='' + pg='' + pmake='' + pr='' +*************** +*** 11642,11647 **** +--- 11643,11656 ---- + shift + extensions="$*" + ++ : Remove libraries needed only for extensions ++ : The appropriate ext/Foo/Makefile.PL will add them back in, if ++ : necessary. ++ set X `echo " $libs " | ++ sed -e 's@ -lndbm @ @' -e 's@ -lgdbm @ @' -e 's@ -ldbm @ @' -e 's@ -ldb @ @'` ++ shift ++ perllibs="$*" ++ + : Remove build directory name from cppstdin so it can be used from + : either the present location or the final installed location. + echo " " +*************** +*** 12183,12188 **** +--- 12192,12198 ---- + patchlevel='$patchlevel' + path_sep='$path_sep' + perl='$perl' ++ perllibs='$perllibs' + perladmin='$perladmin' + perlpath='$perlpath' + pg='$pg' +diff -rc perl5.005_03.orig/Makefile.SH perl5.005_03/Makefile.SH +*** perl5.005_03.orig/Makefile.SH Thu Mar 4 02:35:25 1999 +--- perl5.005_03/Makefile.SH Sun Sep 17 22:21:01 2000 +*************** +*** 58,67 **** + shrpldflags="-H512 -T512 -bhalt:4 -bM:SRE -bE:perl.exp" + case "$osvers" in + 3*) +! shrpldflags="$shrpldflags -e _nostart $ldflags $libs $cryptlib" + ;; + *) +! shrpldflags="$shrpldflags -b noentry $ldflags $libs $cryptlib" + ;; + esac + aixinstdir=`pwd | sed 's/\/UU$//'` +--- 58,67 ---- + shrpldflags="-H512 -T512 -bhalt:4 -bM:SRE -bE:perl.exp" + case "$osvers" in + 3*) +! shrpldflags="$shrpldflags -e _nostart $ldflags $perllibs $cryptlib" + ;; + *) +! shrpldflags="$shrpldflags -b noentry $ldflags $perllibs $cryptlib" + ;; + esac + aixinstdir=`pwd | sed 's/\/UU$//'` +*************** +*** 155,161 **** + ext = \$(dynamic_ext) \$(static_ext) \$(nonxs_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $libs $cryptlib + + public = perl $suidperl utilities translators + +--- 155,161 ---- + ext = \$(dynamic_ext) \$(static_ext) \$(nonxs_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $perllibs $cryptlib + + public = perl $suidperl utilities translators + +diff -rc perl5.005_03.orig/lib/ExtUtils/Embed.pm perl5.005_03/lib/ExtUtils/Embed.pm +*** perl5.005_03.orig/lib/ExtUtils/Embed.pm Wed Jan 6 02:17:50 1999 +--- perl5.005_03/lib/ExtUtils/Embed.pm Sun Sep 17 22:19:16 2000 +*************** +*** 194,200 **** + @path = $path ? split(/:/, $path) : @INC; + + push(@potential_libs, @link_args) if scalar @link_args; +! push(@potential_libs, $Config{libs}) if defined $std; + + push(@mods, static_ext()) if $std; + +--- 194,200 ---- + @path = $path ? split(/:/, $path) : @INC; + + push(@potential_libs, @link_args) if scalar @link_args; +! push(@potential_libs, $Config{perllibs}) if defined $std; + + push(@mods, static_ext()) if $std; + +diff -rc perl5.005_03.orig/lib/ExtUtils/Liblist.pm perl5.005_03/lib/ExtUtils/Liblist.pm +*** perl5.005_03.orig/lib/ExtUtils/Liblist.pm Wed Jan 6 02:17:47 1999 +--- perl5.005_03/lib/ExtUtils/Liblist.pm Sun Sep 17 22:19:16 2000 +*************** +*** 16,33 **** + + sub _unix_os2_ext { + my($self,$potential_libs, $verbose) = @_; +! if ($^O =~ 'os2' and $Config{libs}) { + # Dynamic libraries are not transitive, so we may need including + # the libraries linked against perl.dll again. + + $potential_libs .= " " if $potential_libs; +! $potential_libs .= $Config{libs}; + } + return ("", "", "", "") unless $potential_libs; + warn "Potential libraries are '$potential_libs':\n" if $verbose; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'libs'}; + my $Config_libext = $Config{lib_ext} || ".a"; + + +--- 16,33 ---- + + sub _unix_os2_ext { + my($self,$potential_libs, $verbose) = @_; +! if ($^O =~ 'os2' and $Config{perllibs}) { + # Dynamic libraries are not transitive, so we may need including + # the libraries linked against perl.dll again. + + $potential_libs .= " " if $potential_libs; +! $potential_libs .= $Config{perllibs}; + } + return ("", "", "", "") unless $potential_libs; + warn "Potential libraries are '$potential_libs':\n" if $verbose; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'perllibs'}; + my $Config_libext = $Config{lib_ext} || ".a"; + + +*************** +*** 196,202 **** + my $BC = 1 if $cc =~ /^bcc/i; + my $GC = 1 if $cc =~ /^gcc/i; + my $so = $Config{'so'}; +! my $libs = $Config{'libs'}; + my $libpth = $Config{'libpth'}; + my $libext = $Config{'lib_ext'} || ".lib"; + +--- 196,202 ---- + my $BC = 1 if $cc =~ /^bcc/i; + my $GC = 1 if $cc =~ /^gcc/i; + my $so = $Config{'so'}; +! my $libs = $Config{'perllibs'}; + my $libpth = $Config{'libpth'}; + my $libext = $Config{'lib_ext'} || ".lib"; + +*************** +*** 336,342 **** + $self->{CCFLAS} || $Config{'ccflags'}; + @crtls = ( ($dbgqual =~ m-/Debug-i ? $Config{'dbgprefix'} : '') + . 'PerlShr/Share' ); +! push(@crtls, grep { not /\(/ } split /\s+/, $Config{'libs'}); + push(@crtls, grep { not /\(/ } split /\s+/, $Config{'libc'}); + # In general, we pass through the basic libraries from %Config unchanged. + # The one exception is that if we're building in the Perl source tree, and +--- 336,342 ---- + $self->{CCFLAS} || $Config{'ccflags'}; + @crtls = ( ($dbgqual =~ m-/Debug-i ? $Config{'dbgprefix'} : '') + . 'PerlShr/Share' ); +! push(@crtls, grep { not /\(/ } split /\s+/, $Config{'perllibs'}); + push(@crtls, grep { not /\(/ } split /\s+/, $Config{'libc'}); + # In general, we pass through the basic libraries from %Config unchanged. + # The one exception is that if we're building in the Perl source tree, and +*************** +*** 626,632 **** + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{libs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs>, + C<$Config{libpth}>, and in C<$Config{installarchlib}/CORE>. +--- 626,632 ---- + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{perllibs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs>, + C<$Config{libpth}>, and in C<$Config{installarchlib}/CORE>. +*************** +*** 670,676 **** + alphanumeric characters are treated as flags. Unknown flags will be ignored. + + An entry that matches C disables the appending of default +! libraries found in C<$Config{libs}> (this should be only needed very rarely). + + An entry that matches C disables all searching for + the libraries specified after it. Translation of C<-Lfoo> and +--- 670,676 ---- + alphanumeric characters are treated as flags. Unknown flags will be ignored. + + An entry that matches C disables the appending of default +! libraries found in C<$Config{perllibs}> (this should be only needed very rarely). + + An entry that matches C disables all searching for + the libraries specified after it. Translation of C<-Lfoo> and +*************** +*** 680,686 **** + + An entry that matches C reenables searching for + the libraries specified after it. You can put it at the end to +! enable searching for default libraries specified by C<$Config{libs}>. + + =item * + +--- 680,686 ---- + + An entry that matches C reenables searching for + the libraries specified after it. You can put it at the end to +! enable searching for default libraries specified by C<$Config{perllibs}>. + + =item * + +diff -rc perl5.005_03.orig/lib/ExtUtils/MM_Unix.pm perl5.005_03/lib/ExtUtils/MM_Unix.pm +*** perl5.005_03.orig/lib/ExtUtils/MM_Unix.pm Fri Mar 5 00:34:20 1999 +--- perl5.005_03/lib/ExtUtils/MM_Unix.pm Sun Sep 17 22:19:16 2000 +*************** +*** 2284,2290 **** + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{libs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { +--- 2284,2290 ---- + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{perllibs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { diff --git a/db/perl.BerkeleyDB/patches/5.6.0 b/db/perl.BerkeleyDB/patches/5.6.0 new file mode 100644 index 000000000..1f9b3b620 --- /dev/null +++ b/db/perl.BerkeleyDB/patches/5.6.0 @@ -0,0 +1,294 @@ +diff -cr perl-5.6.0.orig/Configure perl-5.6.0/Configure +*** perl-5.6.0.orig/Configure Wed Mar 22 20:36:37 2000 +--- perl-5.6.0/Configure Sun Sep 17 23:40:15 2000 +*************** +*** 217,222 **** +--- 217,223 ---- + nm='' + nroff='' + perl='' ++ perllibs='' + pg='' + pmake='' + pr='' +*************** +*** 14971,14976 **** +--- 14972,14985 ---- + shift + extensions="$*" + ++ : Remove libraries needed only for extensions ++ : The appropriate ext/Foo/Makefile.PL will add them back in, if ++ : necessary. ++ set X `echo " $libs " | ++ sed -e 's@ -lndbm @ @' -e 's@ -lgdbm @ @' -e 's@ -ldbm @ @' -e 's@ -ldb @ @'` ++ shift ++ perllibs="$*" ++ + : Remove build directory name from cppstdin so it can be used from + : either the present location or the final installed location. + echo " " +*************** +*** 15640,15645 **** +--- 15649,15655 ---- + path_sep='$path_sep' + perl5='$perl5' + perl='$perl' ++ perllibs='$perllibs' + perladmin='$perladmin' + perlpath='$perlpath' + pg='$pg' +diff -cr perl-5.6.0.orig/Makefile.SH perl-5.6.0/Makefile.SH +*** perl-5.6.0.orig/Makefile.SH Sat Mar 11 16:05:24 2000 +--- perl-5.6.0/Makefile.SH Sun Sep 17 23:40:15 2000 +*************** +*** 70,76 **** + *) shrpldflags="$shrpldflags -b noentry" + ;; + esac +! shrpldflags="$shrpldflags $ldflags $libs $cryptlib" + linklibperl="-L $archlibexp/CORE -L `pwd | sed 's/\/UU$//'` -lperl" + ;; + hpux*) +--- 70,76 ---- + *) shrpldflags="$shrpldflags -b noentry" + ;; + esac +! shrpldflags="$shrpldflags $ldflags $perllibs $cryptlib" + linklibperl="-L $archlibexp/CORE -L `pwd | sed 's/\/UU$//'` -lperl" + ;; + hpux*) +*************** +*** 176,182 **** + ext = \$(dynamic_ext) \$(static_ext) \$(nonxs_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $libs $cryptlib + + public = perl $suidperl utilities translators + +--- 176,182 ---- + ext = \$(dynamic_ext) \$(static_ext) \$(nonxs_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $perllibs $cryptlib + + public = perl $suidperl utilities translators + +*************** +*** 333,339 **** + case "$osname" in + aix) + $spitshell >>Makefile <>Makefile <{CCFLAS} || $Config{'ccflags'}; + @crtls = ( ($dbgqual =~ m-/Debug-i ? $Config{'dbgprefix'} : '') + . 'PerlShr/Share' ); +! push(@crtls, grep { not /\(/ } split /\s+/, $Config{'libs'}); + push(@crtls, grep { not /\(/ } split /\s+/, $Config{'libc'}); + # In general, we pass through the basic libraries from %Config unchanged. + # The one exception is that if we're building in the Perl source tree, and +--- 338,344 ---- + $self->{CCFLAS} || $Config{'ccflags'}; + @crtls = ( ($dbgqual =~ m-/Debug-i ? $Config{'dbgprefix'} : '') + . 'PerlShr/Share' ); +! push(@crtls, grep { not /\(/ } split /\s+/, $Config{'perllibs'}); + push(@crtls, grep { not /\(/ } split /\s+/, $Config{'libc'}); + # In general, we pass through the basic libraries from %Config unchanged. + # The one exception is that if we're building in the Perl source tree, and +*************** +*** 624,630 **** + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{libs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs>, + C<$Config{libpth}>, and in C<$Config{installarchlib}/CORE>. +--- 624,630 ---- + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{perllibs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs>, + C<$Config{libpth}>, and in C<$Config{installarchlib}/CORE>. +*************** +*** 668,674 **** + alphanumeric characters are treated as flags. Unknown flags will be ignored. + + An entry that matches C disables the appending of default +! libraries found in C<$Config{libs}> (this should be only needed very rarely). + + An entry that matches C disables all searching for + the libraries specified after it. Translation of C<-Lfoo> and +--- 668,674 ---- + alphanumeric characters are treated as flags. Unknown flags will be ignored. + + An entry that matches C disables the appending of default +! libraries found in C<$Config{perllibs}> (this should be only needed very rarely). + + An entry that matches C disables all searching for + the libraries specified after it. Translation of C<-Lfoo> and +*************** +*** 678,684 **** + + An entry that matches C reenables searching for + the libraries specified after it. You can put it at the end to +! enable searching for default libraries specified by C<$Config{libs}>. + + =item * + +--- 678,684 ---- + + An entry that matches C reenables searching for + the libraries specified after it. You can put it at the end to +! enable searching for default libraries specified by C<$Config{perllibs}>. + + =item * + +diff -cr perl-5.6.0.orig/lib/ExtUtils/MM_Unix.pm perl-5.6.0/lib/ExtUtils/MM_Unix.pm +*** perl-5.6.0.orig/lib/ExtUtils/MM_Unix.pm Thu Mar 2 17:52:52 2000 +--- perl-5.6.0/lib/ExtUtils/MM_Unix.pm Sun Sep 17 23:40:15 2000 +*************** +*** 2450,2456 **** + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{libs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { +--- 2450,2456 ---- + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{perllibs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { +diff -cr perl-5.6.0.orig/myconfig.SH perl-5.6.0/myconfig.SH +*** perl-5.6.0.orig/myconfig.SH Sat Feb 26 06:34:49 2000 +--- perl-5.6.0/myconfig.SH Sun Sep 17 23:41:17 2000 +*************** +*** 48,54 **** + Linker and Libraries: + ld='$ld', ldflags ='$ldflags' + libpth=$libpth +! libs=$libs + libc=$libc, so=$so, useshrplib=$useshrplib, libperl=$libperl + Dynamic Linking: + dlsrc=$dlsrc, dlext=$dlext, d_dlsymun=$d_dlsymun, ccdlflags='$ccdlflags' +--- 48,54 ---- + Linker and Libraries: + ld='$ld', ldflags ='$ldflags' + libpth=$libpth +! libs=$perllibs + libc=$libc, so=$so, useshrplib=$useshrplib, libperl=$libperl + Dynamic Linking: + dlsrc=$dlsrc, dlext=$dlext, d_dlsymun=$d_dlsymun, ccdlflags='$ccdlflags' +diff -cr perl-5.6.0.orig/patchlevel.h perl-5.6.0/patchlevel.h +*** perl-5.6.0.orig/patchlevel.h Wed Mar 22 20:23:11 2000 +--- perl-5.6.0/patchlevel.h Sun Sep 17 23:40:15 2000 +*************** +*** 70,75 **** +--- 70,76 ---- + #if !defined(PERL_PATCHLEVEL_H_IMPLICIT) && !defined(LOCAL_PATCH_COUNT) + static char *local_patches[] = { + NULL ++ ,"NODB-1.0 - remove -ldb from core perl binary." + ,NULL + }; + diff --git a/db/perl.BerkeleyDB/t/btree.t b/db/perl.BerkeleyDB/t/btree.t new file mode 100644 index 000000000..97bb3257c --- /dev/null +++ b/db/perl.BerkeleyDB/t/btree.t @@ -0,0 +1,976 @@ +#!./perl -w + +# ID: %I%, %G% + +use strict ; + +BEGIN { + unless(grep /blib/, @INC) { + chdir 't' if -d 't'; + @INC = '../lib' if -d '../lib'; + } +} + +#use Config; +# +#BEGIN { +# if(-d "lib" && -f "TEST") { +# if ($Config{'extensions'} !~ /\bBerkeleyDB\b/ ) { +# print "1..74\n"; +# exit 0; +# } +# } +#} + +use BerkeleyDB; +use File::Path qw(rmtree); + +print "1..243\n"; + +my %DB_errors = ( + 'DB_INCOMPLETE' => "DB_INCOMPLETE: Sync was unable to complete", + 'DB_KEYEMPTY' => "DB_KEYEMPTY: Non-existent key/data pair", + 'DB_KEYEXIST' => "DB_KEYEXIST: Key/data pair already exists", + 'DB_LOCK_DEADLOCK' => "DB_LOCK_DEADLOCK: Locker killed to resolve a deadlock", + 'DB_LOCK_NOTGRANTED' => "DB_LOCK_NOTGRANTED: Lock not granted", + 'DB_NOTFOUND' => "DB_NOTFOUND: No matching key/data pair found", + 'DB_OLD_VERSION' => "DB_OLDVERSION: Database requires a version upgrade", + 'DB_RUNRECOVERY' => "DB_RUNRECOVERY: Fatal error, run database recovery", +) ; + +{ + package LexFile ; + + sub new + { + my $self = shift ; + unlink @_ ; + bless [ @_ ], $self ; + } + + sub DESTROY + { + my $self = shift ; + unlink @{ $self } ; + } +} + +sub ok +{ + my $no = shift ; + my $result = shift ; + + print "not " unless $result ; + print "ok $no\n" ; +} + +my $Dfile = "dbhash.tmp"; +my $Dfile2 = "dbhash2.tmp"; +my $Dfile3 = "dbhash3.tmp"; +unlink $Dfile; + +umask(0) ; + + +# Check for invalid parameters +{ + # Check for invalid parameters + my $db ; + eval ' $db = new BerkeleyDB::Btree -Stupid => 3 ; ' ; + ok 1, $@ =~ /unknown key value\(s\) Stupid/ ; + + eval ' $db = new BerkeleyDB::Btree -Bad => 2, -Mode => 0345, -Stupid => 3; ' ; + ok 2, $@ =~ /unknown key value\(s\) (Bad |Stupid ){2}/ ; + + eval ' $db = new BerkeleyDB::Btree -Env => 2 ' ; + ok 3, $@ =~ /^Env not of type BerkeleyDB::Env/ ; + + eval ' $db = new BerkeleyDB::Btree -Txn => "x" ' ; + ok 4, $@ =~ /^Txn not of type BerkeleyDB::Txn/ ; + + my $obj = bless [], "main" ; + eval ' $db = new BerkeleyDB::Btree -Env => $obj ' ; + ok 5, $@ =~ /^Env not of type BerkeleyDB::Env/ ; +} + +# Now check the interface to Btree + +{ + my $lex = new LexFile $Dfile ; + + ok 6, my $db = new BerkeleyDB::Btree -Filename => $Dfile, + -Flags => DB_CREATE ; + + # Add a k/v pair + my $value ; + my $status ; + ok 7, $db->db_put("some key", "some value") == 0 ; + ok 8, $db->status() == 0 ; + ok 9, $db->db_get("some key", $value) == 0 ; + ok 10, $value eq "some value" ; + ok 11, $db->db_put("key", "value") == 0 ; + ok 12, $db->db_get("key", $value) == 0 ; + ok 13, $value eq "value" ; + ok 14, $db->db_del("some key") == 0 ; + ok 15, ($status = $db->db_get("some key", $value)) == DB_NOTFOUND ; + ok 16, $db->status() == DB_NOTFOUND ; + ok 17, $db->status() eq $DB_errors{'DB_NOTFOUND'} ; + + ok 18, $db->db_sync() == 0 ; + + # Check NOOVERWRITE will make put fail when attempting to overwrite + # an existing record. + + ok 19, $db->db_put( 'key', 'x', DB_NOOVERWRITE) == DB_KEYEXIST ; + ok 20, $db->status() eq $DB_errors{'DB_KEYEXIST'} ; + ok 21, $db->status() == DB_KEYEXIST ; + + + # check that the value of the key has not been changed by the + # previous test + ok 22, $db->db_get("key", $value) == 0 ; + ok 23, $value eq "value" ; + + # test DB_GET_BOTH + my ($k, $v) = ("key", "value") ; + ok 24, $db->db_get($k, $v, DB_GET_BOTH) == 0 ; + + ($k, $v) = ("key", "fred") ; + ok 25, $db->db_get($k, $v, DB_GET_BOTH) == DB_NOTFOUND ; + + ($k, $v) = ("another", "value") ; + ok 26, $db->db_get($k, $v, DB_GET_BOTH) == DB_NOTFOUND ; + + +} + +{ + # Check simple env works with a hash. + my $lex = new LexFile $Dfile ; + + my $home = "./fred" ; + ok 27, -d $home ? chmod 0777, $home : mkdir($home, 0777) ; + + ok 28, my $env = new BerkeleyDB::Env -Flags => DB_CREATE|DB_INIT_MPOOL, + -Home => $home ; + ok 29, my $db = new BerkeleyDB::Btree -Filename => $Dfile, + -Env => $env, + -Flags => DB_CREATE ; + + # Add a k/v pair + my $value ; + ok 30, $db->db_put("some key", "some value") == 0 ; + ok 31, $db->db_get("some key", $value) == 0 ; + ok 32, $value eq "some value" ; + undef $db ; + undef $env ; + rmtree $home ; +} + + +{ + # cursors + + my $lex = new LexFile $Dfile ; + my %hash ; + my ($k, $v) ; + ok 33, my $db = new BerkeleyDB::Btree -Filename => $Dfile, + -Flags => DB_CREATE ; + + # create some data + my %data = ( + "red" => 2, + "green" => "house", + "blue" => "sea", + ) ; + + my $ret = 0 ; + while (($k, $v) = each %data) { + $ret += $db->db_put($k, $v) ; + } + ok 34, $ret == 0 ; + + # create the cursor + ok 35, my $cursor = $db->db_cursor() ; + + $k = $v = "" ; + my %copy = %data ; + my $extras = 0 ; + # sequence forwards + while ($cursor->c_get($k, $v, DB_NEXT) == 0) { + if ( $copy{$k} eq $v ) + { delete $copy{$k} } + else + { ++ $extras } + } + ok 36, $cursor->status() == DB_NOTFOUND ; + ok 37, $cursor->status() eq $DB_errors{'DB_NOTFOUND'}; + ok 38, keys %copy == 0 ; + ok 39, $extras == 0 ; + + # sequence backwards + %copy = %data ; + $extras = 0 ; + my $status ; + for ( $status = $cursor->c_get($k, $v, DB_LAST) ; + $status == 0 ; + $status = $cursor->c_get($k, $v, DB_PREV)) { + if ( $copy{$k} eq $v ) + { delete $copy{$k} } + else + { ++ $extras } + } + ok 40, $status == DB_NOTFOUND ; + ok 41, $status eq $DB_errors{'DB_NOTFOUND'}; + ok 42, $cursor->status() == $status ; + ok 43, $cursor->status() eq $status ; + ok 44, keys %copy == 0 ; + ok 45, $extras == 0 ; + + ($k, $v) = ("green", "house") ; + ok 46, $cursor->c_get($k, $v, DB_GET_BOTH) == 0 ; + + ($k, $v) = ("green", "door") ; + ok 47, $cursor->c_get($k, $v, DB_GET_BOTH) == DB_NOTFOUND ; + + ($k, $v) = ("black", "house") ; + ok 48, $cursor->c_get($k, $v, DB_GET_BOTH) == DB_NOTFOUND ; + +} + +{ + # Tied Hash interface + + my $lex = new LexFile $Dfile ; + my %hash ; + ok 49, tie %hash, 'BerkeleyDB::Btree', -Filename => $Dfile, + -Flags => DB_CREATE ; + + # check "each" with an empty database + my $count = 0 ; + while (my ($k, $v) = each %hash) { + ++ $count ; + } + ok 50, (tied %hash)->status() == DB_NOTFOUND ; + ok 51, $count == 0 ; + + # Add a k/v pair + my $value ; + $hash{"some key"} = "some value"; + ok 52, (tied %hash)->status() == 0 ; + ok 53, $hash{"some key"} eq "some value"; + ok 54, defined $hash{"some key"} ; + ok 55, (tied %hash)->status() == 0 ; + ok 56, exists $hash{"some key"} ; + ok 57, !defined $hash{"jimmy"} ; + ok 58, (tied %hash)->status() == DB_NOTFOUND ; + ok 59, !exists $hash{"jimmy"} ; + ok 60, (tied %hash)->status() == DB_NOTFOUND ; + + delete $hash{"some key"} ; + ok 61, (tied %hash)->status() == 0 ; + ok 62, ! defined $hash{"some key"} ; + ok 63, (tied %hash)->status() == DB_NOTFOUND ; + ok 64, ! exists $hash{"some key"} ; + ok 65, (tied %hash)->status() == DB_NOTFOUND ; + + $hash{1} = 2 ; + $hash{10} = 20 ; + $hash{1000} = 2000 ; + + my ($keys, $values) = (0,0); + $count = 0 ; + while (my ($k, $v) = each %hash) { + $keys += $k ; + $values += $v ; + ++ $count ; + } + ok 66, $count == 3 ; + ok 67, $keys == 1011 ; + ok 68, $values == 2022 ; + + # now clear the hash + %hash = () ; + ok 69, keys %hash == 0 ; + + untie %hash ; +} + +{ + # override default compare + my $lex = new LexFile $Dfile, $Dfile2, $Dfile3 ; + my $value ; + my (%h, %g, %k) ; + my @Keys = qw( 0123 12 -1234 9 987654321 def ) ; + ok 70, tie %h, "BerkeleyDB::Btree", -Filename => $Dfile, + -Compare => sub { $_[0] <=> $_[1] }, + -Flags => DB_CREATE ; + + ok 71, tie %g, 'BerkeleyDB::Btree', -Filename => $Dfile2, + -Compare => sub { $_[0] cmp $_[1] }, + -Flags => DB_CREATE ; + + ok 72, tie %k, 'BerkeleyDB::Btree', -Filename => $Dfile3, + -Compare => sub { length $_[0] <=> length $_[1] }, + -Flags => DB_CREATE ; + + my @srt_1 ; + { local $^W = 0 ; + @srt_1 = sort { $a <=> $b } @Keys ; + } + my @srt_2 = sort { $a cmp $b } @Keys ; + my @srt_3 = sort { length $a <=> length $b } @Keys ; + + foreach (@Keys) { + local $^W = 0 ; + $h{$_} = 1 ; + $g{$_} = 1 ; + $k{$_} = 1 ; + } + + sub ArrayCompare + { + my($a, $b) = @_ ; + + return 0 if @$a != @$b ; + + foreach (1 .. length @$a) + { + return 0 unless $$a[$_] eq $$b[$_] ; + } + + 1 ; + } + + ok 73, ArrayCompare (\@srt_1, [keys %h]); + ok 74, ArrayCompare (\@srt_2, [keys %g]); + ok 75, ArrayCompare (\@srt_3, [keys %k]); + +} + +{ + # override default compare, with duplicates, don't sort values + my $lex = new LexFile $Dfile, $Dfile2, $Dfile3 ; + my $value ; + my (%h, %g, %k) ; + my @Keys = qw( 0123 9 12 -1234 9 987654321 def ) ; + my @Values = qw( 1 0 3 dd x abc 0 ) ; + ok 76, tie %h, "BerkeleyDB::Btree", -Filename => $Dfile, + -Compare => sub { $_[0] <=> $_[1] }, + -Property => DB_DUP, + -Flags => DB_CREATE ; + + ok 77, tie %g, 'BerkeleyDB::Btree', -Filename => $Dfile2, + -Compare => sub { $_[0] cmp $_[1] }, + -Property => DB_DUP, + -Flags => DB_CREATE ; + + ok 78, tie %k, 'BerkeleyDB::Btree', -Filename => $Dfile3, + -Compare => sub { length $_[0] <=> length $_[1] }, + -Property => DB_DUP, + -Flags => DB_CREATE ; + + my @srt_1 ; + { local $^W = 0 ; + @srt_1 = sort { $a <=> $b } @Keys ; + } + my @srt_2 = sort { $a cmp $b } @Keys ; + my @srt_3 = sort { length $a <=> length $b } @Keys ; + + foreach (@Keys) { + local $^W = 0 ; + my $value = shift @Values ; + $h{$_} = $value ; + $g{$_} = $value ; + $k{$_} = $value ; + } + + sub getValues + { + my $hash = shift ; + my $db = tied %$hash ; + my $cursor = $db->db_cursor() ; + my @values = () ; + my ($k, $v) = (0,0) ; + while ($cursor->c_get($k, $v, DB_NEXT) == 0) { + push @values, $v ; + } + return @values ; + } + + ok 79, ArrayCompare (\@srt_1, [keys %h]); + ok 80, ArrayCompare (\@srt_2, [keys %g]); + ok 81, ArrayCompare (\@srt_3, [keys %k]); + ok 82, ArrayCompare ([qw(dd 0 0 x 3 1 abc)], [getValues \%h]); + ok 83, ArrayCompare ([qw(dd 1 0 3 x abc 0)], [getValues \%g]); + ok 84, ArrayCompare ([qw(0 x 3 0 1 dd abc)], [getValues \%k]); + + # test DB_DUP_NEXT + ok 85, my $cur = (tied %g)->db_cursor() ; + my ($k, $v) = (9, "") ; + ok 86, $cur->c_get($k, $v, DB_SET) == 0 ; + ok 87, $k == 9 && $v == 0 ; + ok 88, $cur->c_get($k, $v, DB_NEXT_DUP) == 0 ; + ok 89, $k == 9 && $v eq "x" ; + ok 90, $cur->c_get($k, $v, DB_NEXT_DUP) == DB_NOTFOUND ; +} + +{ + # override default compare, with duplicates, sort values + my $lex = new LexFile $Dfile, $Dfile2; + my $value ; + my (%h, %g) ; + my @Keys = qw( 0123 9 12 -1234 9 987654321 9 def ) ; + my @Values = qw( 1 11 3 dd x abc 2 0 ) ; + ok 91, tie %h, "BerkeleyDB::Btree", -Filename => $Dfile, + -Compare => sub { $_[0] <=> $_[1] }, + -DupCompare => sub { $_[0] cmp $_[1] }, + -Property => DB_DUP, + -Flags => DB_CREATE ; + + ok 92, tie %g, 'BerkeleyDB::Btree', -Filename => $Dfile2, + -Compare => sub { $_[0] cmp $_[1] }, + -DupCompare => sub { $_[0] <=> $_[1] }, + -Property => DB_DUP, + + + + -Flags => DB_CREATE ; + + my @srt_1 ; + { local $^W = 0 ; + @srt_1 = sort { $a <=> $b } @Keys ; + } + my @srt_2 = sort { $a cmp $b } @Keys ; + + foreach (@Keys) { + local $^W = 0 ; + my $value = shift @Values ; + $h{$_} = $value ; + $g{$_} = $value ; + } + + ok 93, ArrayCompare (\@srt_1, [keys %h]); + ok 94, ArrayCompare (\@srt_2, [keys %g]); + ok 95, ArrayCompare ([qw(dd 1 3 x 2 11 abc 0)], [getValues \%g]); + ok 96, ArrayCompare ([qw(dd 0 11 2 x 3 1 abc)], [getValues \%h]); + +} + +{ + # get_dup etc + my $lex = new LexFile $Dfile; + my %hh ; + + ok 97, my $YY = tie %hh, "BerkeleyDB::Btree", -Filename => $Dfile, + -DupCompare => sub { $_[0] cmp $_[1] }, + -Property => DB_DUP, + -Flags => DB_CREATE ; + + $hh{'Wall'} = 'Larry' ; + $hh{'Wall'} = 'Stone' ; # Note the duplicate key + $hh{'Wall'} = 'Brick' ; # Note the duplicate key + $hh{'Smith'} = 'John' ; + $hh{'mouse'} = 'mickey' ; + + # first work in scalar context + ok 98, scalar $YY->get_dup('Unknown') == 0 ; + ok 99, scalar $YY->get_dup('Smith') == 1 ; + ok 100, scalar $YY->get_dup('Wall') == 3 ; + + # now in list context + my @unknown = $YY->get_dup('Unknown') ; + ok 101, "@unknown" eq "" ; + + my @smith = $YY->get_dup('Smith') ; + ok 102, "@smith" eq "John" ; + + { + my @wall = $YY->get_dup('Wall') ; + my %wall ; + @wall{@wall} = @wall ; + ok 103, (@wall == 3 && $wall{'Larry'} && $wall{'Stone'} && $wall{'Brick'}); + } + + # hash + my %unknown = $YY->get_dup('Unknown', 1) ; + ok 104, keys %unknown == 0 ; + + my %smith = $YY->get_dup('Smith', 1) ; + ok 105, keys %smith == 1 && $smith{'John'} ; + + my %wall = $YY->get_dup('Wall', 1) ; + ok 106, keys %wall == 3 && $wall{'Larry'} == 1 && $wall{'Stone'} == 1 + && $wall{'Brick'} == 1 ; + + undef $YY ; + untie %hh ; + +} + +{ + # in-memory file + + my $lex = new LexFile $Dfile ; + my %hash ; + my $fd ; + my $value ; + ok 107, my $db = tie %hash, 'BerkeleyDB::Btree' ; + + ok 108, $db->db_put("some key", "some value") == 0 ; + ok 109, $db->db_get("some key", $value) == 0 ; + ok 110, $value eq "some value" ; + +} + +{ + # partial + # check works via API + + my $lex = new LexFile $Dfile ; + my $value ; + ok 111, my $db = new BerkeleyDB::Btree, -Filename => $Dfile, + -Flags => DB_CREATE ; + + # create some data + my %data = ( + "red" => "boat", + "green" => "house", + "blue" => "sea", + ) ; + + my $ret = 0 ; + while (my ($k, $v) = each %data) { + $ret += $db->db_put($k, $v) ; + } + ok 112, $ret == 0 ; + + + # do a partial get + my ($pon, $off, $len) = $db->partial_set(0,2) ; + ok 113, ! $pon && $off == 0 && $len == 0 ; + ok 114, $db->db_get("red", $value) == 0 && $value eq "bo" ; + ok 115, $db->db_get("green", $value) == 0 && $value eq "ho" ; + ok 116, $db->db_get("blue", $value) == 0 && $value eq "se" ; + + # do a partial get, off end of data + ($pon, $off, $len) = $db->partial_set(3,2) ; + ok 117, $pon ; + ok 118, $off == 0 ; + ok 119, $len == 2 ; + ok 120, $db->db_get("red", $value) == 0 && $value eq "t" ; + ok 121, $db->db_get("green", $value) == 0 && $value eq "se" ; + ok 122, $db->db_get("blue", $value) == 0 && $value eq "" ; + + # switch of partial mode + ($pon, $off, $len) = $db->partial_clear() ; + ok 123, $pon ; + ok 124, $off == 3 ; + ok 125, $len == 2 ; + ok 126, $db->db_get("red", $value) == 0 && $value eq "boat" ; + ok 127, $db->db_get("green", $value) == 0 && $value eq "house" ; + ok 128, $db->db_get("blue", $value) == 0 && $value eq "sea" ; + + # now partial put + $db->partial_set(0,2) ; + ok 129, $db->db_put("red", "") == 0 ; + ok 130, $db->db_put("green", "AB") == 0 ; + ok 131, $db->db_put("blue", "XYZ") == 0 ; + ok 132, $db->db_put("new", "KLM") == 0 ; + + ($pon, $off, $len) = $db->partial_clear() ; + ok 133, $pon ; + ok 134, $off == 0 ; + ok 135, $len == 2 ; + ok 136, $db->db_get("red", $value) == 0 && $value eq "at" ; + ok 137, $db->db_get("green", $value) == 0 && $value eq "ABuse" ; + ok 138, $db->db_get("blue", $value) == 0 && $value eq "XYZa" ; + ok 139, $db->db_get("new", $value) == 0 && $value eq "KLM" ; + + # now partial put + ($pon, $off, $len) = $db->partial_set(3,2) ; + ok 140, ! $pon ; + ok 141, $off == 0 ; + ok 142, $len == 0 ; + ok 143, $db->db_put("red", "PPP") == 0 ; + ok 144, $db->db_put("green", "Q") == 0 ; + ok 145, $db->db_put("blue", "XYZ") == 0 ; + ok 146, $db->db_put("new", "TU") == 0 ; + + $db->partial_clear() ; + ok 147, $db->db_get("red", $value) == 0 && $value eq "at\0PPP" ; + ok 148, $db->db_get("green", $value) == 0 && $value eq "ABuQ" ; + ok 149, $db->db_get("blue", $value) == 0 && $value eq "XYZXYZ" ; + ok 150, $db->db_get("new", $value) == 0 && $value eq "KLMTU" ; +} + +{ + # partial + # check works via tied hash + + my $lex = new LexFile $Dfile ; + my %hash ; + my $value ; + ok 151, my $db = tie %hash, 'BerkeleyDB::Btree', -Filename => $Dfile, + -Flags => DB_CREATE ; + + # create some data + my %data = ( + "red" => "boat", + "green" => "house", + "blue" => "sea", + ) ; + + while (my ($k, $v) = each %data) { + $hash{$k} = $v ; + } + + + # do a partial get + $db->partial_set(0,2) ; + ok 152, $hash{"red"} eq "bo" ; + ok 153, $hash{"green"} eq "ho" ; + ok 154, $hash{"blue"} eq "se" ; + + # do a partial get, off end of data + $db->partial_set(3,2) ; + ok 155, $hash{"red"} eq "t" ; + ok 156, $hash{"green"} eq "se" ; + ok 157, $hash{"blue"} eq "" ; + + # switch of partial mode + $db->partial_clear() ; + ok 158, $hash{"red"} eq "boat" ; + ok 159, $hash{"green"} eq "house" ; + ok 160, $hash{"blue"} eq "sea" ; + + # now partial put + $db->partial_set(0,2) ; + ok 161, $hash{"red"} = "" ; + ok 162, $hash{"green"} = "AB" ; + ok 163, $hash{"blue"} = "XYZ" ; + ok 164, $hash{"new"} = "KLM" ; + + $db->partial_clear() ; + ok 165, $hash{"red"} eq "at" ; + ok 166, $hash{"green"} eq "ABuse" ; + ok 167, $hash{"blue"} eq "XYZa" ; + ok 168, $hash{"new"} eq "KLM" ; + + # now partial put + $db->partial_set(3,2) ; + ok 169, $hash{"red"} = "PPP" ; + ok 170, $hash{"green"} = "Q" ; + ok 171, $hash{"blue"} = "XYZ" ; + ok 172, $hash{"new"} = "TU" ; + + $db->partial_clear() ; + ok 173, $hash{"red"} eq "at\0PPP" ; + ok 174, $hash{"green"} eq "ABuQ" ; + ok 175, $hash{"blue"} eq "XYZXYZ" ; + ok 176, $hash{"new"} eq "KLMTU" ; +} + +{ + # transaction + + my $lex = new LexFile $Dfile ; + my %hash ; + my $value ; + + my $home = "./fred" ; + rmtree $home if -e $home ; + ok 177, mkdir($home, 0777) ; + ok 178, my $env = new BerkeleyDB::Env -Home => $home, + -Flags => DB_CREATE|DB_INIT_TXN| + DB_INIT_MPOOL|DB_INIT_LOCK ; + ok 179, my $txn = $env->txn_begin() ; + ok 180, my $db1 = tie %hash, 'BerkeleyDB::Btree', -Filename => $Dfile, + -Flags => DB_CREATE , + -Env => $env, + -Txn => $txn ; + + + # create some data + my %data = ( + "red" => "boat", + "green" => "house", + "blue" => "sea", + ) ; + + my $ret = 0 ; + while (my ($k, $v) = each %data) { + $ret += $db1->db_put($k, $v) ; + } + ok 181, $ret == 0 ; + + # should be able to see all the records + + ok 182, my $cursor = $db1->db_cursor() ; + my ($k, $v) = ("", "") ; + my $count = 0 ; + # sequence forwards + while ($cursor->c_get($k, $v, DB_NEXT) == 0) { + ++ $count ; + } + ok 183, $count == 3 ; + undef $cursor ; + + # now abort the transaction + #ok 151, $txn->txn_abort() == 0 ; + ok 184, (my $Z = $txn->txn_abort()) == 0 ; + + # there shouldn't be any records in the database + $count = 0 ; + # sequence forwards + ok 185, $cursor = $db1->db_cursor() ; + while ($cursor->c_get($k, $v, DB_NEXT) == 0) { + ++ $count ; + } + ok 186, $count == 0 ; + + undef $txn ; + undef $cursor ; + undef $db1 ; + undef $env ; + untie %hash ; + rmtree $home ; +} + +{ + # DB_DUP + + my $lex = new LexFile $Dfile ; + my %hash ; + ok 187, my $db = tie %hash, 'BerkeleyDB::Btree', -Filename => $Dfile, + -Property => DB_DUP, + -Flags => DB_CREATE ; + + $hash{'Wall'} = 'Larry' ; + $hash{'Wall'} = 'Stone' ; + $hash{'Smith'} = 'John' ; + $hash{'Wall'} = 'Brick' ; + $hash{'Wall'} = 'Brick' ; + $hash{'mouse'} = 'mickey' ; + + ok 188, keys %hash == 6 ; + + # create a cursor + ok 189, my $cursor = $db->db_cursor() ; + + my $key = "Wall" ; + my $value ; + ok 190, $cursor->c_get($key, $value, DB_SET) == 0 ; + ok 191, $key eq "Wall" && $value eq "Larry" ; + ok 192, $cursor->c_get($key, $value, DB_NEXT) == 0 ; + ok 193, $key eq "Wall" && $value eq "Stone" ; + ok 194, $cursor->c_get($key, $value, DB_NEXT) == 0 ; + ok 195, $key eq "Wall" && $value eq "Brick" ; + ok 196, $cursor->c_get($key, $value, DB_NEXT) == 0 ; + ok 197, $key eq "Wall" && $value eq "Brick" ; + + my $ref = $db->db_stat() ; + ok 198, ($ref->{bt_flags} | DB_DUP) == DB_DUP ; + + undef $db ; + undef $cursor ; + untie %hash ; + +} + +{ + # db_stat + + my $lex = new LexFile $Dfile ; + my $recs = ($BerkeleyDB::db_version >= 3.1 ? "bt_ndata" : "bt_nrecs") ; + my %hash ; + my ($k, $v) ; + ok 199, my $db = new BerkeleyDB::Btree -Filename => $Dfile, + -Flags => DB_CREATE, + -Minkey =>3 , + -Pagesize => 2 **12 + ; + + my $ref = $db->db_stat() ; + ok 200, $ref->{$recs} == 0; + ok 201, $ref->{'bt_minkey'} == 3; + ok 202, $ref->{'bt_pagesize'} == 2 ** 12; + + # create some data + my %data = ( + "red" => 2, + "green" => "house", + "blue" => "sea", + ) ; + + my $ret = 0 ; + while (($k, $v) = each %data) { + $ret += $db->db_put($k, $v) ; + } + ok 203, $ret == 0 ; + + $ref = $db->db_stat() ; + ok 204, $ref->{$recs} == 3; +} + +{ + # sub-class test + + package Another ; + + use strict ; + + open(FILE, ">SubDB.pm") or die "Cannot open SubDB.pm: $!\n" ; + print FILE <<'EOM' ; + + package SubDB ; + + use strict ; + use vars qw( @ISA @EXPORT) ; + + require Exporter ; + use BerkeleyDB; + @ISA=qw(BerkeleyDB::Btree); + @EXPORT = @BerkeleyDB::EXPORT ; + + sub db_put { + my $self = shift ; + my $key = shift ; + my $value = shift ; + $self->SUPER::db_put($key, $value * 3) ; + } + + sub db_get { + my $self = shift ; + $self->SUPER::db_get($_[0], $_[1]) ; + $_[1] -= 2 ; + } + + sub A_new_method + { + my $self = shift ; + my $key = shift ; + my $value = $self->FETCH($key) ; + return "[[$value]]" ; + } + + 1 ; +EOM + + close FILE ; + + BEGIN { push @INC, '.'; } + eval 'use SubDB ; '; + main::ok 205, $@ eq "" ; + my %h ; + my $X ; + eval ' + $X = tie(%h, "SubDB", -Filename => "dbbtree.tmp", + -Flags => DB_CREATE, + -Mode => 0640 ); + ' ; + + main::ok 206, $@ eq "" ; + + my $ret = eval '$h{"fred"} = 3 ; return $h{"fred"} ' ; + main::ok 207, $@ eq "" ; + main::ok 208, $ret == 7 ; + + my $value = 0; + $ret = eval '$X->db_put("joe", 4) ; $X->db_get("joe", $value) ; return $value' ; + main::ok 209, $@ eq "" ; + main::ok 210, $ret == 10 ; + + $ret = eval ' DB_NEXT eq main::DB_NEXT ' ; + main::ok 211, $@ eq "" ; + main::ok 212, $ret == 1 ; + + $ret = eval '$X->A_new_method("joe") ' ; + main::ok 213, $@ eq "" ; + main::ok 214, $ret eq "[[10]]" ; + + unlink "SubDB.pm", "dbbtree.tmp" ; + +} + +{ + # DB_RECNUM, DB_SET_RECNO & DB_GET_RECNO + + my $lex = new LexFile $Dfile ; + my %hash ; + my ($k, $v) = ("", ""); + ok 215, my $db = new BerkeleyDB::Btree + -Filename => $Dfile, + -Flags => DB_CREATE, + -Property => DB_RECNUM ; + + + # create some data + my @data = ( + "A zero", + "B one", + "C two", + "D three", + "E four" + ) ; + + my $ix = 0 ; + my $ret = 0 ; + foreach (@data) { + $ret += $db->db_put($_, $ix) ; + ++ $ix ; + } + ok 216, $ret == 0 ; + + # db_get & DB_SET_RECNO + $k = 1 ; + ok 217, $db->db_get($k, $v, DB_SET_RECNO) == 0; + ok 218, $k eq "B one" && $v == 1 ; + + $k = 3 ; + ok 219, $db->db_get($k, $v, DB_SET_RECNO) == 0; + ok 220, $k eq "D three" && $v == 3 ; + + $k = 4 ; + ok 221, $db->db_get($k, $v, DB_SET_RECNO) == 0; + ok 222, $k eq "E four" && $v == 4 ; + + $k = 0 ; + ok 223, $db->db_get($k, $v, DB_SET_RECNO) == 0; + ok 224, $k eq "A zero" && $v == 0 ; + + # cursor & DB_SET_RECNO + + # create the cursor + ok 225, my $cursor = $db->db_cursor() ; + + $k = 2 ; + ok 226, $db->db_get($k, $v, DB_SET_RECNO) == 0; + ok 227, $k eq "C two" && $v == 2 ; + + $k = 0 ; + ok 228, $cursor->c_get($k, $v, DB_SET_RECNO) == 0; + ok 229, $k eq "A zero" && $v == 0 ; + + $k = 3 ; + ok 230, $db->db_get($k, $v, DB_SET_RECNO) == 0; + ok 231, $k eq "D three" && $v == 3 ; + + # cursor & DB_GET_RECNO + ok 232, $cursor->c_get($k, $v, DB_FIRST) == 0 ; + ok 233, $k eq "A zero" && $v == 0 ; + ok 234, $cursor->c_get($k, $v, DB_GET_RECNO) == 0; + ok 235, $v == 0 ; + + ok 236, $cursor->c_get($k, $v, DB_NEXT) == 0 ; + ok 237, $k eq "B one" && $v == 1 ; + ok 238, $cursor->c_get($k, $v, DB_GET_RECNO) == 0; + ok 239, $v == 1 ; + + ok 240, $cursor->c_get($k, $v, DB_LAST) == 0 ; + ok 241, $k eq "E four" && $v == 4 ; + ok 242, $cursor->c_get($k, $v, DB_GET_RECNO) == 0; + ok 243, $v == 4 ; + +} + diff --git a/db/perl.BerkeleyDB/t/db-3.0.t b/db/perl.BerkeleyDB/t/db-3.0.t new file mode 100644 index 000000000..9c324dc7b --- /dev/null +++ b/db/perl.BerkeleyDB/t/db-3.0.t @@ -0,0 +1,128 @@ +#!./perl -w + +# ID: 1.2, 7/17/97 + +use strict ; + +BEGIN { + unless(grep /blib/, @INC) { + chdir 't' if -d 't'; + @INC = '../lib' if -d '../lib'; + } +} + +use BerkeleyDB; +use File::Path qw(rmtree); + +BEGIN +{ + if ($BerkeleyDB::db_version < 3) { + print "1..0 # Skipped - this needs Berkeley DB 3.x or better\n" ; + exit 0 ; + } +} + +print "1..14\n"; + + +{ + package LexFile ; + + sub new + { + my $self = shift ; + unlink @_ ; + bless [ @_ ], $self ; + } + + sub DESTROY + { + my $self = shift ; + unlink @{ $self } ; + } +} + +sub ok +{ + my $no = shift ; + my $result = shift ; + + print "not " unless $result ; + print "ok $no\n" ; +} + +sub docat +{ + my $file = shift; + local $/ = undef; + open(CAT,$file) || die "Cannot open $file:$!"; + my $result = ; + close(CAT); + return $result; +} + + +my $Dfile = "dbhash.tmp"; + +umask(0); + +{ + # set_mutexlocks + + my $home = "./fred" ; + ok 1, -d $home ? chmod 0777, $home : mkdir($home, 0777) ; + mkdir "./fred", 0777 ; + chdir "./fred" ; + ok 2, my $env = new BerkeleyDB::Env -Flags => DB_CREATE ; + ok 3, $env->set_mutexlocks(0) == 0 ; + chdir ".." ; + undef $env ; + rmtree $home ; +} + +{ + # c_dup + + + my $lex = new LexFile $Dfile ; + my %hash ; + my ($k, $v) ; + ok 4, my $db = new BerkeleyDB::Hash -Filename => $Dfile, + -Flags => DB_CREATE ; + + # create some data + my %data = ( + "red" => 2, + "green" => "house", + "blue" => "sea", + ) ; + + my $ret = 0 ; + while (($k, $v) = each %data) { + $ret += $db->db_put($k, $v) ; + } + ok 5, $ret == 0 ; + + # create a cursor + ok 6, my $cursor = $db->db_cursor() ; + + # point to a specific k/v pair + $k = "green" ; + ok 7, $cursor->c_get($k, $v, DB_SET) == 0 ; + ok 8, $v eq "house" ; + + # duplicate the cursor + my $dup_cursor = $cursor->c_dup(DB_POSITION); + ok 9, $dup_cursor ; + + # move original cursor off green/house + $cursor->c_get($k, $v, DB_NEXT) ; + ok 10, $k ne "green" ; + ok 11, $v ne "house" ; + + # duplicate cursor should still be on green/house + ok 12, $dup_cursor->c_get($k, $v, DB_CURRENT) == 0; + ok 13, $k eq "green" ; + ok 14, $v eq "house" ; + +} diff --git a/db/perl.BerkeleyDB/t/db-3.1.t b/db/perl.BerkeleyDB/t/db-3.1.t new file mode 100644 index 000000000..35076b6cd --- /dev/null +++ b/db/perl.BerkeleyDB/t/db-3.1.t @@ -0,0 +1,172 @@ +#!./perl -w + +# ID: %I%, %G% + +use strict ; + +BEGIN { + unless(grep /blib/, @INC) { + chdir 't' if -d 't'; + @INC = '../lib' if -d '../lib'; + } +} + +#use Config; +# +#BEGIN { +# if(-d "lib" && -f "TEST") { +# if ($Config{'extensions'} !~ /\bBerkeleyDB\b/ ) { +# print "1..74\n"; +# exit 0; +# } +# } +#} + +use BerkeleyDB; +use File::Path qw(rmtree); + +BEGIN +{ + if ($BerkeleyDB::db_version < 3.1) { + print "1..0 # Skipping test, this needs Berkeley DB 3.1.x or better\n" ; + exit 0 ; + } +} + +print "1..25\n"; + +my %DB_errors = ( + 'DB_INCOMPLETE' => "DB_INCOMPLETE: Sync was unable to complete", + 'DB_KEYEMPTY' => "DB_KEYEMPTY: Non-existent key/data pair", + 'DB_KEYEXIST' => "DB_KEYEXIST: Key/data pair already exists", + 'DB_LOCK_DEADLOCK' => "DB_LOCK_DEADLOCK: Locker killed to resolve a deadlock", + 'DB_LOCK_NOTGRANTED' => "DB_LOCK_NOTGRANTED: Lock not granted", + 'DB_NOTFOUND' => "DB_NOTFOUND: No matching key/data pair found", + 'DB_OLD_VERSION' => "DB_OLDVERSION: Database requires a version upgrade", + 'DB_RUNRECOVERY' => "DB_RUNRECOVERY: Fatal error, run database recovery", +) ; + +{ + package LexFile ; + + sub new + { + my $self = shift ; + unlink @_ ; + bless [ @_ ], $self ; + } + + sub DESTROY + { + my $self = shift ; + unlink @{ $self } ; + } +} + + +sub ok +{ + my $no = shift ; + my $result = shift ; + + print "not " unless $result ; + print "ok $no\n" ; +} + +my $Dfile = "dbhash.tmp"; +my $Dfile2 = "dbhash2.tmp"; +my $Dfile3 = "dbhash3.tmp"; +unlink $Dfile; + +umask(0) ; + + + +{ + # c_count + + my $lex = new LexFile $Dfile ; + my %hash ; + ok 1, my $db = tie %hash, 'BerkeleyDB::Hash', -Filename => $Dfile, + -Property => DB_DUP, + -Flags => DB_CREATE ; + + $hash{'Wall'} = 'Larry' ; + $hash{'Wall'} = 'Stone' ; + $hash{'Smith'} = 'John' ; + $hash{'Wall'} = 'Brick' ; + $hash{'Wall'} = 'Brick' ; + $hash{'mouse'} = 'mickey' ; + + ok 2, keys %hash == 6 ; + + # create a cursor + ok 3, my $cursor = $db->db_cursor() ; + + my $key = "Wall" ; + my $value ; + ok 4, $cursor->c_get($key, $value, DB_SET) == 0 ; + ok 5, $key eq "Wall" && $value eq "Larry" ; + + my $count ; + ok 6, $cursor->c_count($count) == 0 ; + ok 7, $count == 4 ; + + $key = "Smith" ; + ok 8, $cursor->c_get($key, $value, DB_SET) == 0 ; + ok 9, $key eq "Smith" && $value eq "John" ; + + ok 10, $cursor->c_count($count) == 0 ; + ok 11, $count == 1 ; + + + undef $db ; + undef $cursor ; + untie %hash ; + +} + +{ + # db_key_range + + my $lex = new LexFile $Dfile ; + my %hash ; + ok 12, my $db = tie %hash, 'BerkeleyDB::Btree', -Filename => $Dfile, + -Property => DB_DUP, + -Flags => DB_CREATE ; + + $hash{'Wall'} = 'Larry' ; + $hash{'Wall'} = 'Stone' ; + $hash{'Smith'} = 'John' ; + $hash{'Wall'} = 'Brick' ; + $hash{'Wall'} = 'Brick' ; + $hash{'mouse'} = 'mickey' ; + + ok 13, keys %hash == 6 ; + + my $key = "Wall" ; + my ($less, $equal, $greater) ; + ok 14, $db->db_key_range($key, $less, $equal, $greater) == 0 ; + + ok 15, $less != 0 ; + ok 16, $equal != 0 ; + ok 17, $greater != 0 ; + + $key = "Smith" ; + ok 18, $db->db_key_range($key, $less, $equal, $greater) == 0 ; + + ok 19, $less == 0 ; + ok 20, $equal != 0 ; + ok 21, $greater != 0 ; + + $key = "NotThere" ; + ok 22, $db->db_key_range($key, $less, $equal, $greater) == 0 ; + + ok 23, $less == 0 ; + ok 24, $equal == 0 ; + ok 25, $greater == 1 ; + + undef $db ; + untie %hash ; + +} diff --git a/db/perl.BerkeleyDB/t/db-3.2.t b/db/perl.BerkeleyDB/t/db-3.2.t new file mode 100644 index 000000000..0cff24873 --- /dev/null +++ b/db/perl.BerkeleyDB/t/db-3.2.t @@ -0,0 +1,90 @@ +#!./perl -w + +# ID: %I%, %G% + +use strict ; + +BEGIN { + unless(grep /blib/, @INC) { + chdir 't' if -d 't'; + @INC = '../lib' if -d '../lib'; + } +} + +#use Config; +# +#BEGIN { +# if(-d "lib" && -f "TEST") { +# if ($Config{'extensions'} !~ /\bBerkeleyDB\b/ ) { +# print "1..74\n"; +# exit 0; +# } +# } +#} + +use BerkeleyDB; +use File::Path qw(rmtree); + +BEGIN +{ + if ($BerkeleyDB::db_version < 3.2) { + print "1..0 # Skipping test, this needs Berkeley DB 3.2.x or better\n" ; + exit 0 ; + } +} + +print "1..1\n"; + +my %DB_errors = ( + 'DB_INCOMPLETE' => "DB_INCOMPLETE: Sync was unable to complete", + 'DB_KEYEMPTY' => "DB_KEYEMPTY: Non-existent key/data pair", + 'DB_KEYEXIST' => "DB_KEYEXIST: Key/data pair already exists", + 'DB_LOCK_DEADLOCK' => "DB_LOCK_DEADLOCK: Locker killed to resolve a deadlock", + 'DB_LOCK_NOTGRANTED' => "DB_LOCK_NOTGRANTED: Lock not granted", + 'DB_NOTFOUND' => "DB_NOTFOUND: No matching key/data pair found", + 'DB_OLD_VERSION' => "DB_OLDVERSION: Database requires a version upgrade", + 'DB_RUNRECOVERY' => "DB_RUNRECOVERY: Fatal error, run database recovery", +) ; + +{ + package LexFile ; + + sub new + { + my $self = shift ; + unlink @_ ; + bless [ @_ ], $self ; + } + + sub DESTROY + { + my $self = shift ; + unlink @{ $self } ; + } +} + + +sub ok +{ + my $no = shift ; + my $result = shift ; + + print "not " unless $result ; + print "ok $no\n" ; +} + +my $Dfile = "dbhash.tmp"; +my $Dfile2 = "dbhash2.tmp"; +my $Dfile3 = "dbhash3.tmp"; +unlink $Dfile; + +umask(0) ; + + + +{ + # set_q_extentsize + + ok 1, 1 ; +} + diff --git a/db/perl.BerkeleyDB/t/destroy.t b/db/perl.BerkeleyDB/t/destroy.t new file mode 100644 index 000000000..e3a1e2a97 --- /dev/null +++ b/db/perl.BerkeleyDB/t/destroy.t @@ -0,0 +1,141 @@ +#!./perl -w + +use strict ; + +BEGIN { + unless(grep /blib/, @INC) { + chdir 't' if -d 't'; + @INC = '../lib' if -d '../lib'; + } +} + +use BerkeleyDB; +use File::Path qw(rmtree); + +print "1..13\n"; + + +{ + package LexFile ; + + sub new + { + my $self = shift ; + unlink @_ ; + bless [ @_ ], $self ; + } + + sub DESTROY + { + my $self = shift ; + unlink @{ $self } ; + } +} + +sub ok +{ + my $no = shift ; + my $result = shift ; + + print "not " unless $result ; + print "ok $no\n" ; +} + +sub docat +{ + my $file = shift; + local $/ = undef; + open(CAT,$file) || die "Cannot open $file:$!"; + my $result = ; + close(CAT); + return $result; +} + + +my $Dfile = "dbhash.tmp"; +my $home = "./fred" ; + +umask(0); + +{ + # let object destroction kill everything + + my $lex = new LexFile $Dfile ; + my %hash ; + my $value ; + + rmtree $home if -e $home ; + ok 1, mkdir($home, 0777) ; + ok 2, my $env = new BerkeleyDB::Env -Home => $home, + -Flags => DB_CREATE|DB_INIT_TXN| + DB_INIT_MPOOL|DB_INIT_LOCK ; + ok 3, my $txn = $env->txn_begin() ; + ok 4, my $db1 = tie %hash, 'BerkeleyDB::Hash', -Filename => $Dfile, + -Flags => DB_CREATE , + -Env => $env, + -Txn => $txn ; + + + # create some data + my %data = ( + "red" => "boat", + "green" => "house", + "blue" => "sea", + ) ; + + my $ret = 0 ; + while (my ($k, $v) = each %data) { + $ret += $db1->db_put($k, $v) ; + } + ok 5, $ret == 0 ; + + # should be able to see all the records + + ok 6, my $cursor = $db1->db_cursor() ; + my ($k, $v) = ("", "") ; + my $count = 0 ; + # sequence forwards + while ($cursor->c_get($k, $v, DB_NEXT) == 0) { + ++ $count ; + } + ok 7, $count == 3 ; + undef $cursor ; + + # now abort the transaction + ok 8, $txn->txn_abort() == 0 ; + + # there shouldn't be any records in the database + $count = 0 ; + # sequence forwards + ok 9, $cursor = $db1->db_cursor() ; + while ($cursor->c_get($k, $v, DB_NEXT) == 0) { + ++ $count ; + } + ok 10, $count == 0 ; + + #undef $txn ; + #undef $cursor ; + #undef $db1 ; + #undef $env ; + #untie %hash ; + +} +{ + my $lex = new LexFile $Dfile ; + my %hash ; + my $cursor ; + my ($k, $v) = ("", "") ; + ok 11, my $db1 = tie %hash, 'BerkeleyDB::Hash', + -Filename => $Dfile, + -Flags => DB_CREATE ; + my $count = 0 ; + # sequence forwards + ok 12, $cursor = $db1->db_cursor() ; + while ($cursor->c_get($k, $v, DB_NEXT) == 0) { + ++ $count ; + } + ok 13, $count == 0 ; +} + +rmtree $home ; + diff --git a/db/perl.BerkeleyDB/t/env.t b/db/perl.BerkeleyDB/t/env.t new file mode 100644 index 000000000..5d0197f85 --- /dev/null +++ b/db/perl.BerkeleyDB/t/env.t @@ -0,0 +1,279 @@ +#!./perl -w + +# ID: 1.2, 7/17/97 + +use strict ; + +BEGIN { + unless(grep /blib/, @INC) { + chdir 't' if -d 't'; + @INC = '../lib' if -d '../lib'; + } +} + +use BerkeleyDB; +use File::Path qw(rmtree); + +print "1..52\n"; + + +{ + package LexFile ; + + sub new + { + my $self = shift ; + unlink @_ ; + bless [ @_ ], $self ; + } + + sub DESTROY + { + my $self = shift ; + unlink @{ $self } ; + } +} + +sub ok +{ + my $no = shift ; + my $result = shift ; + + print "not " unless $result ; + print "ok $no\n" ; +} + +sub docat +{ + my $file = shift; + local $/ = undef; + open(CAT,$file) || die "Cannot open $file:$!"; + my $result = ; + close(CAT); + return $result; +} + + +my $Dfile = "dbhash.tmp"; + +umask(0); + +{ + # db version stuff + my ($major, $minor, $patch) = (0, 0, 0) ; + + ok 1, my $VER = BerkeleyDB::DB_VERSION_STRING ; + ok 2, my $ver = BerkeleyDB::db_version($major, $minor, $patch) ; + ok 3, $VER eq $ver ; + ok 4, $major > 1 ; + ok 5, defined $minor ; + ok 6, defined $patch ; +} + +{ + # Check for invalid parameters + my $env ; + eval ' $env = new BerkeleyDB::Env( -Stupid => 3) ; ' ; + ok 7, $@ =~ /unknown key value\(s\) Stupid/ ; + + eval ' $env = new BerkeleyDB::Env( -Bad => 2, -Home => "/tmp", -Stupid => 3) ; ' ; + ok 8, $@ =~ /unknown key value\(s\) (Bad |Stupid ){2}/ ; + + eval ' $env = new BerkeleyDB::Env (-Config => {"fred" => " "} ) ; ' ; + ok 9, !$env ; + ok 10, $BerkeleyDB::Error =~ /^illegal name-value pair/ ; +} + +{ + # create a very simple environment + my $home = "./fred" ; + ok 11, -d $home ? chmod 0777, $home : mkdir($home, 0777) ; + mkdir "./fred", 0777 ; + chdir "./fred" ; + ok 12, my $env = new BerkeleyDB::Env -Flags => DB_CREATE ; + chdir ".." ; + undef $env ; + rmtree $home ; +} + +{ + # create an environment with a Home + my $home = "./fred" ; + ok 13, -d $home ? chmod 0777, $home : mkdir($home, 0777) ; + ok 14, my $env = new BerkeleyDB::Env -Home => $home, + -Flags => DB_CREATE ; + + undef $env ; + rmtree $home ; +} + +{ + # make new fail. + my $home = "./not_there" ; + rmtree $home ; + ok 15, ! -d $home ; + my $env = new BerkeleyDB::Env -Home => $home, + -Flags => DB_INIT_LOCK ; + ok 16, ! $env ; + ok 17, $! != 0 ; + + rmtree $home ; +} + +{ + # Config + use Cwd ; + my $cwd = cwd() ; + my $home = "$cwd/fred" ; + my $data_dir = "$home/data_dir" ; + my $log_dir = "$home/log_dir" ; + my $data_file = "data.db" ; + ok 18, -d $home ? chmod 0777, $home : mkdir($home, 0777) ; + ok 19, -d $data_dir ? chmod 0777, $data_dir : mkdir($data_dir, 0777) ; + ok 20, -d $log_dir ? chmod 0777, $log_dir : mkdir($log_dir, 0777) ; + my $env = new BerkeleyDB::Env -Home => $home, + -Config => { DB_DATA_DIR => $data_dir, + DB_LOG_DIR => $log_dir + }, + -Flags => DB_CREATE|DB_INIT_TXN|DB_INIT_LOG| + DB_INIT_MPOOL|DB_INIT_LOCK ; + ok 21, $env ; + + ok 22, my $txn = $env->txn_begin() ; + + my %hash ; + ok 23, tie %hash, 'BerkeleyDB::Hash', -Filename => $data_file, + -Flags => DB_CREATE , + -Env => $env, + -Txn => $txn ; + + $hash{"abc"} = 123 ; + $hash{"def"} = 456 ; + + $txn->txn_commit() ; + + untie %hash ; + + undef $txn ; + undef $env ; + rmtree $home ; +} + +{ + # -ErrFile with a filename + my $errfile = "./errfile" ; + my $home = "./fred" ; + ok 24, -d $home ? chmod 0777, $home : mkdir($home, 0777) ; + my $lex = new LexFile $errfile ; + ok 25, my $env = new BerkeleyDB::Env( -ErrFile => $errfile, + -Flags => DB_CREATE, + -Home => $home) ; + my $db = new BerkeleyDB::Hash -Filename => $Dfile, + -Env => $env, + -Flags => -1; + ok 26, !$db ; + + ok 27, $BerkeleyDB::Error =~ /^illegal flag specified to (db_open|DB->open)/; + ok 28, -e $errfile ; + my $contents = docat($errfile) ; + chomp $contents ; + ok 29, $BerkeleyDB::Error eq $contents ; + + undef $env ; + rmtree $home ; +} + +{ + # -ErrFile with a filehandle + use IO ; + my $home = "./fred" ; + ok 30, -d $home ? chmod 0777, $home : mkdir($home, 0777) ; + my $errfile = "./errfile" ; + my $lex = new LexFile $errfile ; + ok 31, my $ef = new IO::File ">$errfile" ; + ok 32, my $env = new BerkeleyDB::Env( -ErrFile => $ef , + -Flags => DB_CREATE, + -Home => $home) ; + my $db = new BerkeleyDB::Hash -Filename => $Dfile, + -Env => $env, + -Flags => -1; + ok 33, !$db ; + + ok 34, $BerkeleyDB::Error =~ /^illegal flag specified to (db_open|DB->open)/; + $ef->close() ; + ok 35, -e $errfile ; + my $contents = "" ; + $contents = docat($errfile) ; + chomp $contents ; + ok 36, $BerkeleyDB::Error eq $contents ; + undef $env ; + rmtree $home ; +} + +{ + # -ErrPrefix + use IO ; + my $home = "./fred" ; + ok 37, -d $home ? chmod 0777, $home : mkdir($home, 0777) ; + my $errfile = "./errfile" ; + my $lex = new LexFile $errfile ; + ok 38, my $env = new BerkeleyDB::Env( -ErrFile => $errfile, + -ErrPrefix => "PREFIX", + -Flags => DB_CREATE, + -Home => $home) ; + my $db = new BerkeleyDB::Hash -Filename => $Dfile, + -Env => $env, + -Flags => -1; + ok 39, !$db ; + + ok 40, $BerkeleyDB::Error =~ /^PREFIX: illegal flag specified to (db_open|DB->open)/; + ok 41, -e $errfile ; + my $contents = docat($errfile) ; + chomp $contents ; + ok 42, $BerkeleyDB::Error eq $contents ; + + # change the prefix on the fly + my $old = $env->errPrefix("NEW ONE") ; + ok 43, $old eq "PREFIX" ; + + $db = new BerkeleyDB::Hash -Filename => $Dfile, + -Env => $env, + -Flags => -1; + ok 44, !$db ; + ok 45, $BerkeleyDB::Error =~ /^NEW ONE: illegal flag specified to (db_open|DB->open)/; + $contents = docat($errfile) ; + chomp $contents ; + ok 46, $contents =~ /$BerkeleyDB::Error$/ ; + undef $env ; + rmtree $home ; +} + +{ + # test db_appexit + use Cwd ; + my $cwd = cwd() ; + my $home = "$cwd/fred" ; + my $data_dir = "$home/data_dir" ; + my $log_dir = "$home/log_dir" ; + my $data_file = "data.db" ; + ok 47, -d $home ? chmod 0777, $home : mkdir($home, 0777) ; + ok 48, -d $data_dir ? chmod 0777, $data_dir : mkdir($data_dir, 0777) ; + ok 49, -d $log_dir ? chmod 0777, $log_dir : mkdir($log_dir, 0777) ; + my $env = new BerkeleyDB::Env -Home => $home, + -Config => { DB_DATA_DIR => $data_dir, + DB_LOG_DIR => $log_dir + }, + -Flags => DB_CREATE|DB_INIT_TXN|DB_INIT_LOG| + DB_INIT_MPOOL|DB_INIT_LOCK ; + ok 50, $env ; + + ok 51, my $txn_mgr = $env->TxnMgr() ; + + ok 52, $env->db_appexit() == 0 ; + + #rmtree $home ; +} + +# test -Verbose +# test -Flags +# db_value_set diff --git a/db/perl.BerkeleyDB/t/examples.t b/db/perl.BerkeleyDB/t/examples.t new file mode 100644 index 000000000..4b6702d54 --- /dev/null +++ b/db/perl.BerkeleyDB/t/examples.t @@ -0,0 +1,482 @@ +#!./perl -w + +use strict ; + +BEGIN { + unless(grep /blib/, @INC) { + chdir 't' if -d 't'; + @INC = '../lib' if -d '../lib'; + } +} + +use BerkeleyDB; +use File::Path qw(rmtree); + +print "1..7\n"; + +my $FA = 0 ; + +{ + sub try::TIEARRAY { bless [], "try" } + sub try::FETCHSIZE { $FA = 1 } + $FA = 0 ; + my @a ; + tie @a, 'try' ; + my $a = @a ; +} + +{ + package LexFile ; + + sub new + { + my $self = shift ; + unlink @_ ; + bless [ @_ ], $self ; + } + + sub DESTROY + { + my $self = shift ; + unlink @{ $self } ; + } +} + + +sub ok +{ + my $no = shift ; + my $result = shift ; + + print "not " unless $result ; + print "ok $no\n" ; +} + +{ + package Redirect ; + use Symbol ; + + sub new + { + my $class = shift ; + my $filename = shift ; + my $fh = gensym ; + open ($fh, ">$filename") || die "Cannot open $filename: $!" ; + my $real_stdout = select($fh) ; + return bless [$fh, $real_stdout ] ; + + } + sub DESTROY + { + my $self = shift ; + close $self->[0] ; + select($self->[1]) ; + } +} + +sub docat +{ + my $file = shift; + local $/ = undef; + open(CAT,$file) || die "Cannot open $file:$!"; + my $result = || "" ; + close(CAT); + return $result; +} + +sub docat_del +{ + my $file = shift; + local $/ = undef; + open(CAT,$file) || die "Cannot open $file: $!"; + my $result = || "" ; + close(CAT); + unlink $file ; + return $result; +} + +my $Dfile = "dbhash.tmp"; +my $Dfile2 = "dbhash2.tmp"; +my $Dfile3 = "dbhash3.tmp"; +unlink $Dfile; + +umask(0) ; + +my $redirect = "xyzt" ; + + +{ +my $x = $BerkeleyDB::Error; +my $redirect = "xyzt" ; + { + my $redirectObj = new Redirect $redirect ; + + use strict ; + use BerkeleyDB ; + use vars qw( %h $k $v ) ; + + my $filename = "fruit" ; + unlink $filename ; + tie %h, "BerkeleyDB::Hash", + -Filename => $filename, + -Flags => DB_CREATE + or die "Cannot open file $filename: $! $BerkeleyDB::Error\n" ; + + # Add a few key/value pairs to the file + $h{"apple"} = "red" ; + $h{"orange"} = "orange" ; + $h{"banana"} = "yellow" ; + $h{"tomato"} = "red" ; + + # Check for existence of a key + print "Banana Exists\n\n" if $h{"banana"} ; + + # Delete a key/value pair. + delete $h{"apple"} ; + + # print the contents of the file + while (($k, $v) = each %h) + { print "$k -> $v\n" } + + untie %h ; + unlink $filename ; + } + + #print "[" . docat($redirect) . "]" ; + ok(1, docat_del($redirect) eq <<'EOM') ; +Banana Exists + +orange -> orange +tomato -> red +banana -> yellow +EOM + + +} + +{ +my $redirect = "xyzt" ; + { + + my $redirectObj = new Redirect $redirect ; + + use strict ; + use BerkeleyDB ; + + my $filename = "fruit" ; + unlink $filename ; + my $db = new BerkeleyDB::Hash + -Filename => $filename, + -Flags => DB_CREATE + or die "Cannot open file $filename: $! $BerkeleyDB::Error\n" ; + + # Add a few key/value pairs to the file + $db->db_put("apple", "red") ; + $db->db_put("orange", "orange") ; + $db->db_put("banana", "yellow") ; + $db->db_put("tomato", "red") ; + + # Check for existence of a key + print "Banana Exists\n\n" if $db->db_get("banana", $v) == 0; + + # Delete a key/value pair. + $db->db_del("apple") ; + + # print the contents of the file + my ($k, $v) = ("", "") ; + my $cursor = $db->db_cursor() ; + while ($cursor->c_get($k, $v, DB_NEXT) == 0) + { print "$k -> $v\n" } + + undef $cursor ; + undef $db ; + unlink $filename ; + } + + #print "[" . docat($redirect) . "]" ; + ok(2, docat_del($redirect) eq <<'EOM') ; +Banana Exists + +orange -> orange +tomato -> red +banana -> yellow +EOM + +} + +{ +my $redirect = "xyzt" ; + { + + my $redirectObj = new Redirect $redirect ; + + use strict ; + use BerkeleyDB ; + + my $filename = "tree" ; + unlink $filename ; + my %h ; + tie %h, 'BerkeleyDB::Btree', + -Filename => $filename, + -Flags => DB_CREATE + or die "Cannot open $filename: $!\n" ; + + # Add a key/value pair to the file + $h{'Wall'} = 'Larry' ; + $h{'Smith'} = 'John' ; + $h{'mouse'} = 'mickey' ; + $h{'duck'} = 'donald' ; + + # Delete + delete $h{"duck"} ; + + # Cycle through the keys printing them in order. + # Note it is not necessary to sort the keys as + # the btree will have kept them in order automatically. + foreach (keys %h) + { print "$_\n" } + + untie %h ; + unlink $filename ; + } + + #print "[" . docat($redirect) . "]\n" ; + ok(3, docat_del($redirect) eq <<'EOM') ; +Smith +Wall +mouse +EOM + +} + +{ +my $redirect = "xyzt" ; + { + + my $redirectObj = new Redirect $redirect ; + + use strict ; + use BerkeleyDB ; + + my $filename = "tree" ; + unlink $filename ; + my %h ; + tie %h, 'BerkeleyDB::Btree', + -Filename => $filename, + -Flags => DB_CREATE, + -Compare => sub { lc $_[0] cmp lc $_[1] } + or die "Cannot open $filename: $!\n" ; + + # Add a key/value pair to the file + $h{'Wall'} = 'Larry' ; + $h{'Smith'} = 'John' ; + $h{'mouse'} = 'mickey' ; + $h{'duck'} = 'donald' ; + + # Delete + delete $h{"duck"} ; + + # Cycle through the keys printing them in order. + # Note it is not necessary to sort the keys as + # the btree will have kept them in order automatically. + foreach (keys %h) + { print "$_\n" } + + untie %h ; + unlink $filename ; + } + + #print "[" . docat($redirect) . "]\n" ; + ok(4, docat_del($redirect) eq <<'EOM') ; +mouse +Smith +Wall +EOM + +} + +{ +my $redirect = "xyzt" ; + { + + my $redirectObj = new Redirect $redirect ; + + use strict ; + use BerkeleyDB ; + + my %hash ; + my $filename = "filt.db" ; + unlink $filename ; + + my $db = tie %hash, 'BerkeleyDB::Hash', + -Filename => $filename, + -Flags => DB_CREATE + or die "Cannot open $filename: $!\n" ; + + # Install DBM Filters + $db->filter_fetch_key ( sub { s/\0$// } ) ; + $db->filter_store_key ( sub { $_ .= "\0" } ) ; + $db->filter_fetch_value( sub { s/\0$// } ) ; + $db->filter_store_value( sub { $_ .= "\0" } ) ; + + $hash{"abc"} = "def" ; + my $a = $hash{"ABC"} ; + # ... + undef $db ; + untie %hash ; + $db = tie %hash, 'BerkeleyDB::Hash', + -Filename => $filename, + -Flags => DB_CREATE + or die "Cannot open $filename: $!\n" ; + while (($k, $v) = each %hash) + { print "$k -> $v\n" } + undef $db ; + untie %hash ; + + unlink $filename ; + } + + #print "[" . docat($redirect) . "]\n" ; + ok(5, docat_del($redirect) eq <<"EOM") ; +abc\x00 -> def\x00 +EOM + +} + +{ +my $redirect = "xyzt" ; + { + + my $redirectObj = new Redirect $redirect ; + + use strict ; + use BerkeleyDB ; + my %hash ; + my $filename = "filt.db" ; + unlink $filename ; + + + my $db = tie %hash, 'BerkeleyDB::Btree', + -Filename => $filename, + -Flags => DB_CREATE + or die "Cannot open $filename: $!\n" ; + + $db->filter_fetch_key ( sub { $_ = unpack("i", $_) } ) ; + $db->filter_store_key ( sub { $_ = pack ("i", $_) } ) ; + $hash{123} = "def" ; + # ... + undef $db ; + untie %hash ; + $db = tie %hash, 'BerkeleyDB::Btree', + -Filename => $filename, + -Flags => DB_CREATE + or die "Cannot Open $filename: $!\n" ; + while (($k, $v) = each %hash) + { print "$k -> $v\n" } + undef $db ; + untie %hash ; + + unlink $filename ; + } + + my $val = pack("i", 123) ; + #print "[" . docat($redirect) . "]\n" ; + ok(6, docat_del($redirect) eq <<"EOM") ; +$val -> def +EOM + +} + +{ +my $redirect = "xyzt" ; + { + + my $redirectObj = new Redirect $redirect ; + + if ($FA) { + use strict ; + use BerkeleyDB ; + + my $filename = "text" ; + unlink $filename ; + + my @h ; + tie @h, 'BerkeleyDB::Recno', + -Filename => $filename, + -Flags => DB_CREATE, + -Property => DB_RENUMBER + or die "Cannot open $filename: $!\n" ; + + # Add a few key/value pairs to the file + $h[0] = "orange" ; + $h[1] = "blue" ; + $h[2] = "yellow" ; + + push @h, "green", "black" ; + + my $elements = scalar @h ; + print "The array contains $elements entries\n" ; + + my $last = pop @h ; + print "popped $last\n" ; + + unshift @h, "white" ; + my $first = shift @h ; + print "shifted $first\n" ; + + # Check for existence of a key + print "Element 1 Exists with value $h[1]\n" if $h[1] ; + + untie @h ; + unlink $filename ; + } else { + use strict ; + use BerkeleyDB ; + + my $filename = "text" ; + unlink $filename ; + + my @h ; + my $db = tie @h, 'BerkeleyDB::Recno', + -Filename => $filename, + -Flags => DB_CREATE, + -Property => DB_RENUMBER + or die "Cannot open $filename: $!\n" ; + + # Add a few key/value pairs to the file + $h[0] = "orange" ; + $h[1] = "blue" ; + $h[2] = "yellow" ; + + $db->push("green", "black") ; + + my $elements = $db->length() ; + print "The array contains $elements entries\n" ; + + my $last = $db->pop ; + print "popped $last\n" ; + + $db->unshift("white") ; + my $first = $db->shift ; + print "shifted $first\n" ; + + # Check for existence of a key + print "Element 1 Exists with value $h[1]\n" if $h[1] ; + + undef $db ; + untie @h ; + unlink $filename ; + } + + } + + #print "[" . docat($redirect) . "]\n" ; + ok(7, docat_del($redirect) eq <<"EOM") ; +The array contains 5 entries +popped black +shifted white +Element 1 Exists with value blue +EOM + +} + diff --git a/db/perl.BerkeleyDB/t/examples.t.T b/db/perl.BerkeleyDB/t/examples.t.T new file mode 100644 index 000000000..fe0922318 --- /dev/null +++ b/db/perl.BerkeleyDB/t/examples.t.T @@ -0,0 +1,496 @@ +#!./perl -w + +use strict ; + +BEGIN { + unless(grep /blib/, @INC) { + chdir 't' if -d 't'; + @INC = '../lib' if -d '../lib'; + } +} + +use BerkeleyDB; +use File::Path qw(rmtree); + +print "1..7\n"; + +my $FA = 0 ; + +{ + sub try::TIEARRAY { bless [], "try" } + sub try::FETCHSIZE { $FA = 1 } + $FA = 0 ; + my @a ; + tie @a, 'try' ; + my $a = @a ; +} + +{ + package LexFile ; + + sub new + { + my $self = shift ; + unlink @_ ; + bless [ @_ ], $self ; + } + + sub DESTROY + { + my $self = shift ; + unlink @{ $self } ; + } +} + + +sub ok +{ + my $no = shift ; + my $result = shift ; + + print "not " unless $result ; + print "ok $no\n" ; +} + +{ + package Redirect ; + use Symbol ; + + sub new + { + my $class = shift ; + my $filename = shift ; + my $fh = gensym ; + open ($fh, ">$filename") || die "Cannot open $filename: $!" ; + my $real_stdout = select($fh) ; + return bless [$fh, $real_stdout ] ; + + } + sub DESTROY + { + my $self = shift ; + close $self->[0] ; + select($self->[1]) ; + } +} + +sub docat +{ + my $file = shift; + local $/ = undef; + open(CAT,$file) || die "Cannot open $file:$!"; + my $result = || "" ; + close(CAT); + return $result; +} + +sub docat_del +{ + my $file = shift; + local $/ = undef; + open(CAT,$file) || die "Cannot open $file: $!"; + my $result = || "" ; + close(CAT); + unlink $file ; + return $result; +} + +my $Dfile = "dbhash.tmp"; +my $Dfile2 = "dbhash2.tmp"; +my $Dfile3 = "dbhash3.tmp"; +unlink $Dfile; + +umask(0) ; + +my $redirect = "xyzt" ; + + +{ +my $x = $BerkeleyDB::Error; +my $redirect = "xyzt" ; + { + my $redirectObj = new Redirect $redirect ; + +## BEGIN simpleHash + use strict ; + use BerkeleyDB ; + use vars qw( %h $k $v ) ; + + my $filename = "fruit" ; + unlink $filename ; + tie %h, "BerkeleyDB::Hash", + -Filename => $filename, + -Flags => DB_CREATE + or die "Cannot open file $filename: $! $BerkeleyDB::Error\n" ; + + # Add a few key/value pairs to the file + $h{"apple"} = "red" ; + $h{"orange"} = "orange" ; + $h{"banana"} = "yellow" ; + $h{"tomato"} = "red" ; + + # Check for existence of a key + print "Banana Exists\n\n" if $h{"banana"} ; + + # Delete a key/value pair. + delete $h{"apple"} ; + + # print the contents of the file + while (($k, $v) = each %h) + { print "$k -> $v\n" } + + untie %h ; +## END simpleHash + unlink $filename ; + } + + #print "[" . docat($redirect) . "]" ; + ok(1, docat_del($redirect) eq <<'EOM') ; +Banana Exists + +orange -> orange +tomato -> red +banana -> yellow +EOM + + +} + +{ +my $redirect = "xyzt" ; + { + + my $redirectObj = new Redirect $redirect ; + +## BEGIN simpleHash2 + use strict ; + use BerkeleyDB ; + + my $filename = "fruit" ; + unlink $filename ; + my $db = new BerkeleyDB::Hash + -Filename => $filename, + -Flags => DB_CREATE + or die "Cannot open file $filename: $! $BerkeleyDB::Error\n" ; + + # Add a few key/value pairs to the file + $db->db_put("apple", "red") ; + $db->db_put("orange", "orange") ; + $db->db_put("banana", "yellow") ; + $db->db_put("tomato", "red") ; + + # Check for existence of a key + print "Banana Exists\n\n" if $db->db_get("banana", $v) == 0; + + # Delete a key/value pair. + $db->db_del("apple") ; + + # print the contents of the file + my ($k, $v) = ("", "") ; + my $cursor = $db->db_cursor() ; + while ($cursor->c_get($k, $v, DB_NEXT) == 0) + { print "$k -> $v\n" } + + undef $cursor ; + undef $db ; +## END simpleHash2 + unlink $filename ; + } + + #print "[" . docat($redirect) . "]" ; + ok(2, docat_del($redirect) eq <<'EOM') ; +Banana Exists + +orange -> orange +tomato -> red +banana -> yellow +EOM + +} + +{ +my $redirect = "xyzt" ; + { + + my $redirectObj = new Redirect $redirect ; + +## BEGIN btreeSimple + use strict ; + use BerkeleyDB ; + + my $filename = "tree" ; + unlink $filename ; + my %h ; + tie %h, 'BerkeleyDB::Btree', + -Filename => $filename, + -Flags => DB_CREATE + or die "Cannot open $filename: $!\n" ; + + # Add a key/value pair to the file + $h{'Wall'} = 'Larry' ; + $h{'Smith'} = 'John' ; + $h{'mouse'} = 'mickey' ; + $h{'duck'} = 'donald' ; + + # Delete + delete $h{"duck"} ; + + # Cycle through the keys printing them in order. + # Note it is not necessary to sort the keys as + # the btree will have kept them in order automatically. + foreach (keys %h) + { print "$_\n" } + + untie %h ; +## END btreeSimple + unlink $filename ; + } + + #print "[" . docat($redirect) . "]\n" ; + ok(3, docat_del($redirect) eq <<'EOM') ; +Smith +Wall +mouse +EOM + +} + +{ +my $redirect = "xyzt" ; + { + + my $redirectObj = new Redirect $redirect ; + +## BEGIN btreeSortOrder + use strict ; + use BerkeleyDB ; + + my $filename = "tree" ; + unlink $filename ; + my %h ; + tie %h, 'BerkeleyDB::Btree', + -Filename => $filename, + -Flags => DB_CREATE, + -Compare => sub { lc $_[0] cmp lc $_[1] } + or die "Cannot open $filename: $!\n" ; + + # Add a key/value pair to the file + $h{'Wall'} = 'Larry' ; + $h{'Smith'} = 'John' ; + $h{'mouse'} = 'mickey' ; + $h{'duck'} = 'donald' ; + + # Delete + delete $h{"duck"} ; + + # Cycle through the keys printing them in order. + # Note it is not necessary to sort the keys as + # the btree will have kept them in order automatically. + foreach (keys %h) + { print "$_\n" } + + untie %h ; +## END btreeSortOrder + unlink $filename ; + } + + #print "[" . docat($redirect) . "]\n" ; + ok(4, docat_del($redirect) eq <<'EOM') ; +mouse +Smith +Wall +EOM + +} + +{ +my $redirect = "xyzt" ; + { + + my $redirectObj = new Redirect $redirect ; + +## BEGIN nullFilter + use strict ; + use BerkeleyDB ; + + my %hash ; + my $filename = "filt.db" ; + unlink $filename ; + + my $db = tie %hash, 'BerkeleyDB::Hash', + -Filename => $filename, + -Flags => DB_CREATE + or die "Cannot open $filename: $!\n" ; + + # Install DBM Filters + $db->filter_fetch_key ( sub { s/\0$// } ) ; + $db->filter_store_key ( sub { $_ .= "\0" } ) ; + $db->filter_fetch_value( sub { s/\0$// } ) ; + $db->filter_store_value( sub { $_ .= "\0" } ) ; + + $hash{"abc"} = "def" ; + my $a = $hash{"ABC"} ; + # ... + undef $db ; + untie %hash ; +## END nullFilter + $db = tie %hash, 'BerkeleyDB::Hash', + -Filename => $filename, + -Flags => DB_CREATE + or die "Cannot open $filename: $!\n" ; + while (($k, $v) = each %hash) + { print "$k -> $v\n" } + undef $db ; + untie %hash ; + + unlink $filename ; + } + + #print "[" . docat($redirect) . "]\n" ; + ok(5, docat_del($redirect) eq <<"EOM") ; +abc\x00 -> def\x00 +EOM + +} + +{ +my $redirect = "xyzt" ; + { + + my $redirectObj = new Redirect $redirect ; + +## BEGIN intFilter + use strict ; + use BerkeleyDB ; + my %hash ; + my $filename = "filt.db" ; + unlink $filename ; + + + my $db = tie %hash, 'BerkeleyDB::Btree', + -Filename => $filename, + -Flags => DB_CREATE + or die "Cannot open $filename: $!\n" ; + + $db->filter_fetch_key ( sub { $_ = unpack("i", $_) } ) ; + $db->filter_store_key ( sub { $_ = pack ("i", $_) } ) ; + $hash{123} = "def" ; + # ... + undef $db ; + untie %hash ; +## END intFilter + $db = tie %hash, 'BerkeleyDB::Btree', + -Filename => $filename, + -Flags => DB_CREATE + or die "Cannot Open $filename: $!\n" ; + while (($k, $v) = each %hash) + { print "$k -> $v\n" } + undef $db ; + untie %hash ; + + unlink $filename ; + } + + my $val = pack("i", 123) ; + #print "[" . docat($redirect) . "]\n" ; + ok(6, docat_del($redirect) eq <<"EOM") ; +$val -> def +EOM + +} + +{ +my $redirect = "xyzt" ; + { + + my $redirectObj = new Redirect $redirect ; + + if ($FA) { +## BEGIN simpleRecno + use strict ; + use BerkeleyDB ; + + my $filename = "text" ; + unlink $filename ; + + my @h ; + tie @h, 'BerkeleyDB::Recno', + -Filename => $filename, + -Flags => DB_CREATE, + -Property => DB_RENUMBER + or die "Cannot open $filename: $!\n" ; + + # Add a few key/value pairs to the file + $h[0] = "orange" ; + $h[1] = "blue" ; + $h[2] = "yellow" ; + + push @h, "green", "black" ; + + my $elements = scalar @h ; + print "The array contains $elements entries\n" ; + + my $last = pop @h ; + print "popped $last\n" ; + + unshift @h, "white" ; + my $first = shift @h ; + print "shifted $first\n" ; + + # Check for existence of a key + print "Element 1 Exists with value $h[1]\n" if $h[1] ; + + untie @h ; +## END simpleRecno + unlink $filename ; + } else { + use strict ; + use BerkeleyDB ; + + my $filename = "text" ; + unlink $filename ; + + my @h ; + my $db = tie @h, 'BerkeleyDB::Recno', + -Filename => $filename, + -Flags => DB_CREATE, + -Property => DB_RENUMBER + or die "Cannot open $filename: $!\n" ; + + # Add a few key/value pairs to the file + $h[0] = "orange" ; + $h[1] = "blue" ; + $h[2] = "yellow" ; + + $db->push("green", "black") ; + + my $elements = $db->length() ; + print "The array contains $elements entries\n" ; + + my $last = $db->pop ; + print "popped $last\n" ; + + $db->unshift("white") ; + my $first = $db->shift ; + print "shifted $first\n" ; + + # Check for existence of a key + print "Element 1 Exists with value $h[1]\n" if $h[1] ; + + undef $db ; + untie @h ; + unlink $filename ; + } + + } + + #print "[" . docat($redirect) . "]\n" ; + ok(7, docat_del($redirect) eq <<"EOM") ; +The array contains 5 entries +popped black +shifted white +Element 1 Exists with value blue +EOM + +} + diff --git a/db/perl.BerkeleyDB/t/examples3.t b/db/perl.BerkeleyDB/t/examples3.t new file mode 100644 index 000000000..9cc1fa72c --- /dev/null +++ b/db/perl.BerkeleyDB/t/examples3.t @@ -0,0 +1,213 @@ +#!./perl -w + +use strict ; + +BEGIN { + unless(grep /blib/, @INC) { + chdir 't' if -d 't'; + @INC = '../lib' if -d '../lib'; + } +} + +use BerkeleyDB; +use File::Path qw(rmtree); + +BEGIN +{ + if ($BerkeleyDB::db_version < 3) { + print "1..0 # Skipping test, this needs Berkeley DB 3.x or better\n" ; + exit 0 ; + } +} + + +print "1..2\n"; + +my $FA = 0 ; + +{ + sub try::TIEARRAY { bless [], "try" } + sub try::FETCHSIZE { $FA = 1 } + $FA = 0 ; + my @a ; + tie @a, 'try' ; + my $a = @a ; +} + +{ + package LexFile ; + + sub new + { + my $self = shift ; + unlink @_ ; + bless [ @_ ], $self ; + } + + sub DESTROY + { + my $self = shift ; + unlink @{ $self } ; + } +} + + +sub ok +{ + my $no = shift ; + my $result = shift ; + + print "not " unless $result ; + print "ok $no\n" ; +} + +{ + package Redirect ; + use Symbol ; + + sub new + { + my $class = shift ; + my $filename = shift ; + my $fh = gensym ; + open ($fh, ">$filename") || die "Cannot open $filename: $!" ; + my $real_stdout = select($fh) ; + return bless [$fh, $real_stdout ] ; + + } + sub DESTROY + { + my $self = shift ; + close $self->[0] ; + select($self->[1]) ; + } +} + +sub docat +{ + my $file = shift; + local $/ = undef; + open(CAT,$file) || die "Cannot open $file:$!"; + my $result = || "" ; + close(CAT); + return $result; +} + +sub docat_del +{ + my $file = shift; + local $/ = undef; + open(CAT,$file) || die "Cannot open $file: $!"; + my $result = || "" ; + close(CAT); + unlink $file ; + return $result; +} + +my $Dfile = "dbhash.tmp"; +my $Dfile2 = "dbhash2.tmp"; +my $Dfile3 = "dbhash3.tmp"; +unlink $Dfile; + +umask(0) ; + +my $redirect = "xyzt" ; + + +{ +my $redirect = "xyzt" ; + { + + my $redirectObj = new Redirect $redirect ; + + use strict ; + use BerkeleyDB ; + + my $filename = "fruit" ; + unlink $filename ; + my $db = new BerkeleyDB::Hash + -Filename => $filename, + -Flags => DB_CREATE, + -Property => DB_DUP + or die "Cannot open file $filename: $! $BerkeleyDB::Error\n" ; + + # Add a few key/value pairs to the file + $db->db_put("red", "apple") ; + $db->db_put("orange", "orange") ; + $db->db_put("green", "banana") ; + $db->db_put("yellow", "banana") ; + $db->db_put("red", "tomato") ; + $db->db_put("green", "apple") ; + + # print the contents of the file + my ($k, $v) = ("", "") ; + my $cursor = $db->db_cursor() ; + while ($cursor->c_get($k, $v, DB_NEXT) == 0) + { print "$k -> $v\n" } + + undef $cursor ; + undef $db ; + unlink $filename ; + } + + #print "[" . docat($redirect) . "]" ; + ok(1, docat_del($redirect) eq <<'EOM') ; +orange -> orange +yellow -> banana +red -> apple +red -> tomato +green -> banana +green -> apple +EOM + +} + +{ +my $redirect = "xyzt" ; + { + + my $redirectObj = new Redirect $redirect ; + + use strict ; + use BerkeleyDB ; + + my $filename = "fruit" ; + unlink $filename ; + my $db = new BerkeleyDB::Hash + -Filename => $filename, + -Flags => DB_CREATE, + -Property => DB_DUP | DB_DUPSORT + or die "Cannot open file $filename: $! $BerkeleyDB::Error\n" ; + + # Add a few key/value pairs to the file + $db->db_put("red", "apple") ; + $db->db_put("orange", "orange") ; + $db->db_put("green", "banana") ; + $db->db_put("yellow", "banana") ; + $db->db_put("red", "tomato") ; + $db->db_put("green", "apple") ; + + # print the contents of the file + my ($k, $v) = ("", "") ; + my $cursor = $db->db_cursor() ; + while ($cursor->c_get($k, $v, DB_NEXT) == 0) + { print "$k -> $v\n" } + + undef $cursor ; + undef $db ; + unlink $filename ; + } + + #print "[" . docat($redirect) . "]" ; + ok(2, docat_del($redirect) eq <<'EOM') ; +orange -> orange +yellow -> banana +red -> apple +red -> tomato +green -> apple +green -> banana +EOM + +} + + diff --git a/db/perl.BerkeleyDB/t/examples3.t.T b/db/perl.BerkeleyDB/t/examples3.t.T new file mode 100644 index 000000000..573c04903 --- /dev/null +++ b/db/perl.BerkeleyDB/t/examples3.t.T @@ -0,0 +1,217 @@ +#!./perl -w + +use strict ; + +BEGIN { + unless(grep /blib/, @INC) { + chdir 't' if -d 't'; + @INC = '../lib' if -d '../lib'; + } +} + +use BerkeleyDB; +use File::Path qw(rmtree); + +BEGIN +{ + if ($BerkeleyDB::db_version < 3) { + print "1..0 # Skipping test, this needs Berkeley DB 3.x or better\n" ; + exit 0 ; + } +} + + +print "1..2\n"; + +my $FA = 0 ; + +{ + sub try::TIEARRAY { bless [], "try" } + sub try::FETCHSIZE { $FA = 1 } + $FA = 0 ; + my @a ; + tie @a, 'try' ; + my $a = @a ; +} + +{ + package LexFile ; + + sub new + { + my $self = shift ; + unlink @_ ; + bless [ @_ ], $self ; + } + + sub DESTROY + { + my $self = shift ; + unlink @{ $self } ; + } +} + + +sub ok +{ + my $no = shift ; + my $result = shift ; + + print "not " unless $result ; + print "ok $no\n" ; +} + +{ + package Redirect ; + use Symbol ; + + sub new + { + my $class = shift ; + my $filename = shift ; + my $fh = gensym ; + open ($fh, ">$filename") || die "Cannot open $filename: $!" ; + my $real_stdout = select($fh) ; + return bless [$fh, $real_stdout ] ; + + } + sub DESTROY + { + my $self = shift ; + close $self->[0] ; + select($self->[1]) ; + } +} + +sub docat +{ + my $file = shift; + local $/ = undef; + open(CAT,$file) || die "Cannot open $file:$!"; + my $result = || "" ; + close(CAT); + return $result; +} + +sub docat_del +{ + my $file = shift; + local $/ = undef; + open(CAT,$file) || die "Cannot open $file: $!"; + my $result = || "" ; + close(CAT); + unlink $file ; + return $result; +} + +my $Dfile = "dbhash.tmp"; +my $Dfile2 = "dbhash2.tmp"; +my $Dfile3 = "dbhash3.tmp"; +unlink $Dfile; + +umask(0) ; + +my $redirect = "xyzt" ; + + +{ +my $redirect = "xyzt" ; + { + + my $redirectObj = new Redirect $redirect ; + +## BEGIN dupHash + use strict ; + use BerkeleyDB ; + + my $filename = "fruit" ; + unlink $filename ; + my $db = new BerkeleyDB::Hash + -Filename => $filename, + -Flags => DB_CREATE, + -Property => DB_DUP + or die "Cannot open file $filename: $! $BerkeleyDB::Error\n" ; + + # Add a few key/value pairs to the file + $db->db_put("red", "apple") ; + $db->db_put("orange", "orange") ; + $db->db_put("green", "banana") ; + $db->db_put("yellow", "banana") ; + $db->db_put("red", "tomato") ; + $db->db_put("green", "apple") ; + + # print the contents of the file + my ($k, $v) = ("", "") ; + my $cursor = $db->db_cursor() ; + while ($cursor->c_get($k, $v, DB_NEXT) == 0) + { print "$k -> $v\n" } + + undef $cursor ; + undef $db ; +## END dupHash + unlink $filename ; + } + + #print "[" . docat($redirect) . "]" ; + ok(1, docat_del($redirect) eq <<'EOM') ; +orange -> orange +yellow -> banana +red -> apple +red -> tomato +green -> banana +green -> apple +EOM + +} + +{ +my $redirect = "xyzt" ; + { + + my $redirectObj = new Redirect $redirect ; + +## BEGIN dupSortHash + use strict ; + use BerkeleyDB ; + + my $filename = "fruit" ; + unlink $filename ; + my $db = new BerkeleyDB::Hash + -Filename => $filename, + -Flags => DB_CREATE, + -Property => DB_DUP | DB_DUPSORT + or die "Cannot open file $filename: $! $BerkeleyDB::Error\n" ; + + # Add a few key/value pairs to the file + $db->db_put("red", "apple") ; + $db->db_put("orange", "orange") ; + $db->db_put("green", "banana") ; + $db->db_put("yellow", "banana") ; + $db->db_put("red", "tomato") ; + $db->db_put("green", "apple") ; + + # print the contents of the file + my ($k, $v) = ("", "") ; + my $cursor = $db->db_cursor() ; + while ($cursor->c_get($k, $v, DB_NEXT) == 0) + { print "$k -> $v\n" } + + undef $cursor ; + undef $db ; +## END dupSortHash + unlink $filename ; + } + + #print "[" . docat($redirect) . "]" ; + ok(2, docat_del($redirect) eq <<'EOM') ; +orange -> orange +yellow -> banana +red -> apple +red -> tomato +green -> apple +green -> banana +EOM + +} + + diff --git a/db/perl.BerkeleyDB/t/filter.t b/db/perl.BerkeleyDB/t/filter.t new file mode 100644 index 000000000..8bcdc7f3f --- /dev/null +++ b/db/perl.BerkeleyDB/t/filter.t @@ -0,0 +1,244 @@ +#!./perl -w + +# ID: %I%, %G% + +use strict ; + +BEGIN { + unless(grep /blib/, @INC) { + chdir 't' if -d 't'; + @INC = '../lib' if -d '../lib'; + } +} + +use BerkeleyDB; +use File::Path qw(rmtree); + +print "1..46\n"; + +{ + package LexFile ; + + sub new + { + my $self = shift ; + unlink @_ ; + bless [ @_ ], $self ; + } + + sub DESTROY + { + my $self = shift ; + unlink @{ $self } ; + } +} + + +sub ok +{ + my $no = shift ; + my $result = shift ; + + print "not " unless $result ; + print "ok $no\n" ; +} + +my $Dfile = "dbhash.tmp"; +unlink $Dfile; + +umask(0) ; + + +{ + # DBM Filter tests + use strict ; + my (%h, $db) ; + my ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + unlink $Dfile; + + sub checkOutput + { + my($fk, $sk, $fv, $sv) = @_ ; + return + $fetch_key eq $fk && $store_key eq $sk && + $fetch_value eq $fv && $store_value eq $sv && + $_ eq 'original' ; + } + + ok 1, $db = tie %h, 'BerkeleyDB::Hash', + -Filename => $Dfile, + -Flags => DB_CREATE; + + $db->filter_fetch_key (sub { $fetch_key = $_ }) ; + $db->filter_store_key (sub { $store_key = $_ }) ; + $db->filter_fetch_value (sub { $fetch_value = $_}) ; + $db->filter_store_value (sub { $store_value = $_ }) ; + + $_ = "original" ; + + $h{"fred"} = "joe" ; + # fk sk fv sv + ok 2, checkOutput( "", "fred", "", "joe") ; + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + ok 3, $h{"fred"} eq "joe"; + # fk sk fv sv + ok 4, checkOutput( "", "fred", "joe", "") ; + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + ok 5, $db->FIRSTKEY() eq "fred" ; + # fk sk fv sv + ok 6, checkOutput( "fred", "", "", "") ; + + # replace the filters, but remember the previous set + my ($old_fk) = $db->filter_fetch_key + (sub { $_ = uc $_ ; $fetch_key = $_ }) ; + my ($old_sk) = $db->filter_store_key + (sub { $_ = lc $_ ; $store_key = $_ }) ; + my ($old_fv) = $db->filter_fetch_value + (sub { $_ = "[$_]"; $fetch_value = $_ }) ; + my ($old_sv) = $db->filter_store_value + (sub { s/o/x/g; $store_value = $_ }) ; + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + $h{"Fred"} = "Joe" ; + # fk sk fv sv + ok 7, checkOutput( "", "fred", "", "Jxe") ; + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + ok 8, $h{"Fred"} eq "[Jxe]"; + # fk sk fv sv + ok 9, checkOutput( "", "fred", "[Jxe]", "") ; + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + ok 10, $db->FIRSTKEY() eq "FRED" ; + # fk sk fv sv + ok 11, checkOutput( "FRED", "", "", "") ; + + # put the original filters back + $db->filter_fetch_key ($old_fk); + $db->filter_store_key ($old_sk); + $db->filter_fetch_value ($old_fv); + $db->filter_store_value ($old_sv); + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + $h{"fred"} = "joe" ; + ok 12, checkOutput( "", "fred", "", "joe") ; + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + ok 13, $h{"fred"} eq "joe"; + ok 14, checkOutput( "", "fred", "joe", "") ; + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + ok 15, $db->FIRSTKEY() eq "fred" ; + ok 16, checkOutput( "fred", "", "", "") ; + + # delete the filters + $db->filter_fetch_key (undef); + $db->filter_store_key (undef); + $db->filter_fetch_value (undef); + $db->filter_store_value (undef); + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + $h{"fred"} = "joe" ; + ok 17, checkOutput( "", "", "", "") ; + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + ok 18, $h{"fred"} eq "joe"; + ok 19, checkOutput( "", "", "", "") ; + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + ok 20, $db->FIRSTKEY() eq "fred" ; + ok 21, checkOutput( "", "", "", "") ; + + undef $db ; + untie %h; + unlink $Dfile; +} + +{ + # DBM Filter with a closure + + use strict ; + my (%h, $db) ; + + unlink $Dfile; + ok 22, $db = tie %h, 'BerkeleyDB::Hash', + -Filename => $Dfile, + -Flags => DB_CREATE; + + my %result = () ; + + sub Closure + { + my ($name) = @_ ; + my $count = 0 ; + my @kept = () ; + + return sub { ++$count ; + push @kept, $_ ; + $result{$name} = "$name - $count: [@kept]" ; + } + } + + $db->filter_store_key(Closure("store key")) ; + $db->filter_store_value(Closure("store value")) ; + $db->filter_fetch_key(Closure("fetch key")) ; + $db->filter_fetch_value(Closure("fetch value")) ; + + $_ = "original" ; + + $h{"fred"} = "joe" ; + ok 23, $result{"store key"} eq "store key - 1: [fred]" ; + ok 24, $result{"store value"} eq "store value - 1: [joe]" ; + ok 25, ! defined $result{"fetch key"} ; + ok 26, ! defined $result{"fetch value"} ; + ok 27, $_ eq "original" ; + + ok 28, $db->FIRSTKEY() eq "fred" ; + ok 29, $result{"store key"} eq "store key - 1: [fred]" ; + ok 30, $result{"store value"} eq "store value - 1: [joe]" ; + ok 31, $result{"fetch key"} eq "fetch key - 1: [fred]" ; + ok 32, ! defined $result{"fetch value"} ; + ok 33, $_ eq "original" ; + + $h{"jim"} = "john" ; + ok 34, $result{"store key"} eq "store key - 2: [fred jim]" ; + ok 35, $result{"store value"} eq "store value - 2: [joe john]" ; + ok 36, $result{"fetch key"} eq "fetch key - 1: [fred]" ; + ok 37, ! defined $result{"fetch value"} ; + ok 38, $_ eq "original" ; + + ok 39, $h{"fred"} eq "joe" ; + ok 40, $result{"store key"} eq "store key - 3: [fred jim fred]" ; + ok 41, $result{"store value"} eq "store value - 2: [joe john]" ; + ok 42, $result{"fetch key"} eq "fetch key - 1: [fred]" ; + ok 43, $result{"fetch value"} eq "fetch value - 1: [joe]" ; + ok 44, $_ eq "original" ; + + undef $db ; + untie %h; + unlink $Dfile; +} + +{ + # DBM Filter recursion detection + use strict ; + my (%h, $db) ; + unlink $Dfile; + + ok 45, $db = tie %h, 'BerkeleyDB::Hash', + -Filename => $Dfile, + -Flags => DB_CREATE; + + $db->filter_store_key (sub { $_ = $h{$_} }) ; + + eval '$h{1} = 1234' ; + ok 46, $@ =~ /^BerkeleyDB Aborting: recursion detected in filter_store_key at/ ; + #print "[$@]\n" ; + + undef $db ; + untie %h; + unlink $Dfile; +} + diff --git a/db/perl.BerkeleyDB/t/hash.t b/db/perl.BerkeleyDB/t/hash.t new file mode 100644 index 000000000..1a42c60ac --- /dev/null +++ b/db/perl.BerkeleyDB/t/hash.t @@ -0,0 +1,777 @@ +#!./perl -w + +# ID: %I%, %G% + +use strict ; + +BEGIN { + unless(grep /blib/, @INC) { + chdir 't' if -d 't'; + @INC = '../lib' if -d '../lib'; + } +} + +#use Config; +# +#BEGIN { +# if(-d "lib" && -f "TEST") { +# if ($Config{'extensions'} !~ /\bBerkeleyDB\b/ ) { +# print "1..74\n"; +# exit 0; +# } +# } +#} + +use BerkeleyDB; +use File::Path qw(rmtree); + +print "1..210\n"; + +my %DB_errors = ( + 'DB_INCOMPLETE' => "DB_INCOMPLETE: Sync was unable to complete", + 'DB_KEYEMPTY' => "DB_KEYEMPTY: Non-existent key/data pair", + 'DB_KEYEXIST' => "DB_KEYEXIST: Key/data pair already exists", + 'DB_LOCK_DEADLOCK' => "DB_LOCK_DEADLOCK: Locker killed to resolve a deadlock", + 'DB_LOCK_NOTGRANTED' => "DB_LOCK_NOTGRANTED: Lock not granted", + 'DB_NOTFOUND' => "DB_NOTFOUND: No matching key/data pair found", + 'DB_OLD_VERSION' => "DB_OLDVERSION: Database requires a version upgrade", + 'DB_RUNRECOVERY' => "DB_RUNRECOVERY: Fatal error, run database recovery", +) ; + +{ + package LexFile ; + + sub new + { + my $self = shift ; + unlink @_ ; + bless [ @_ ], $self ; + } + + sub DESTROY + { + my $self = shift ; + unlink @{ $self } ; + } +} + + +sub ok +{ + my $no = shift ; + my $result = shift ; + + print "not " unless $result ; + print "ok $no\n" ; +} + +my $Dfile = "dbhash.tmp"; +my $Dfile2 = "dbhash2.tmp"; +my $Dfile3 = "dbhash3.tmp"; +unlink $Dfile; + +umask(0) ; + + +# Check for invalid parameters +{ + # Check for invalid parameters + my $db ; + eval ' $db = new BerkeleyDB::Hash -Stupid => 3 ; ' ; + ok 1, $@ =~ /unknown key value\(s\) Stupid/ ; + + eval ' $db = new BerkeleyDB::Hash -Bad => 2, -Mode => 0345, -Stupid => 3; ' ; + ok 2, $@ =~ /unknown key value\(s\) (Bad |Stupid ){2}/ ; + + eval ' $db = new BerkeleyDB::Hash -Env => 2 ' ; + ok 3, $@ =~ /^Env not of type BerkeleyDB::Env/ ; + + eval ' $db = new BerkeleyDB::Hash -Txn => "fred" ' ; + ok 4, $@ =~ /^Txn not of type BerkeleyDB::Txn/ ; + + my $obj = bless [], "main" ; + eval ' $db = new BerkeleyDB::Hash -Env => $obj ' ; + ok 5, $@ =~ /^Env not of type BerkeleyDB::Env/ ; +} + +# Now check the interface to HASH + +{ + my $lex = new LexFile $Dfile ; + + ok 6, my $db = new BerkeleyDB::Hash -Filename => $Dfile, + -Flags => DB_CREATE ; + + # Add a k/v pair + my $value ; + my $status ; + ok 7, $db->db_put("some key", "some value") == 0 ; + ok 8, $db->status() == 0 ; + ok 9, $db->db_get("some key", $value) == 0 ; + ok 10, $value eq "some value" ; + ok 11, $db->db_put("key", "value") == 0 ; + ok 12, $db->db_get("key", $value) == 0 ; + ok 13, $value eq "value" ; + ok 14, $db->db_del("some key") == 0 ; + ok 15, ($status = $db->db_get("some key", $value)) == DB_NOTFOUND ; + ok 16, $status eq $DB_errors{'DB_NOTFOUND'} ; + ok 17, $db->status() == DB_NOTFOUND ; + ok 18, $db->status() eq $DB_errors{'DB_NOTFOUND'}; + + ok 19, $db->db_sync() == 0 ; + + # Check NOOVERWRITE will make put fail when attempting to overwrite + # an existing record. + + ok 20, $db->db_put( 'key', 'x', DB_NOOVERWRITE) == DB_KEYEXIST ; + ok 21, $db->status() eq $DB_errors{'DB_KEYEXIST'}; + ok 22, $db->status() == DB_KEYEXIST ; + + # check that the value of the key has not been changed by the + # previous test + ok 23, $db->db_get("key", $value) == 0 ; + ok 24, $value eq "value" ; + + # test DB_GET_BOTH + my ($k, $v) = ("key", "value") ; + ok 25, $db->db_get($k, $v, DB_GET_BOTH) == 0 ; + + ($k, $v) = ("key", "fred") ; + ok 26, $db->db_get($k, $v, DB_GET_BOTH) == DB_NOTFOUND ; + + ($k, $v) = ("another", "value") ; + ok 27, $db->db_get($k, $v, DB_GET_BOTH) == DB_NOTFOUND ; + + +} + +{ + # Check simple env works with a hash. + my $lex = new LexFile $Dfile ; + + my $home = "./fred" ; + ok 28, -d $home ? chmod 0777, $home : mkdir($home, 0777) ; + + ok 29, my $env = new BerkeleyDB::Env -Flags => DB_CREATE| DB_INIT_MPOOL, + -Home => $home ; + ok 30, my $db = new BerkeleyDB::Hash -Filename => $Dfile, + -Env => $env, + -Flags => DB_CREATE ; + + # Add a k/v pair + my $value ; + ok 31, $db->db_put("some key", "some value") == 0 ; + ok 32, $db->db_get("some key", $value) == 0 ; + ok 33, $value eq "some value" ; + undef $db ; + undef $env ; + rmtree $home ; +} + +{ + # override default hash + my $lex = new LexFile $Dfile ; + my $value ; + $::count = 0 ; + ok 34, my $db = new BerkeleyDB::Hash -Filename => $Dfile, + -Hash => sub { ++$::count ; length $_[0] }, + -Flags => DB_CREATE ; + + ok 35, $db->db_put("some key", "some value") == 0 ; + ok 36, $db->db_get("some key", $value) == 0 ; + ok 37, $value eq "some value" ; + ok 38, $::count > 0 ; + +} + +{ + # cursors + + my $lex = new LexFile $Dfile ; + my %hash ; + my ($k, $v) ; + ok 39, my $db = new BerkeleyDB::Hash -Filename => $Dfile, + -Flags => DB_CREATE ; + + # create some data + my %data = ( + "red" => 2, + "green" => "house", + "blue" => "sea", + ) ; + + my $ret = 0 ; + while (($k, $v) = each %data) { + $ret += $db->db_put($k, $v) ; + } + ok 40, $ret == 0 ; + + # create the cursor + ok 41, my $cursor = $db->db_cursor() ; + + $k = $v = "" ; + my %copy = %data ; + my $extras = 0 ; + # sequence forwards + while ($cursor->c_get($k, $v, DB_NEXT) == 0) { + if ( $copy{$k} eq $v ) + { delete $copy{$k} } + else + { ++ $extras } + } + ok 42, $cursor->status() == DB_NOTFOUND ; + ok 43, $cursor->status() eq $DB_errors{'DB_NOTFOUND'} ; + ok 44, keys %copy == 0 ; + ok 45, $extras == 0 ; + + # sequence backwards + %copy = %data ; + $extras = 0 ; + my $status ; + for ( $status = $cursor->c_get($k, $v, DB_LAST) ; + $status == 0 ; + $status = $cursor->c_get($k, $v, DB_PREV)) { + if ( $copy{$k} eq $v ) + { delete $copy{$k} } + else + { ++ $extras } + } + ok 46, $status == DB_NOTFOUND ; + ok 47, $status eq $DB_errors{'DB_NOTFOUND'} ; + ok 48, $cursor->status() == $status ; + ok 49, $cursor->status() eq $status ; + ok 50, keys %copy == 0 ; + ok 51, $extras == 0 ; + + ($k, $v) = ("green", "house") ; + ok 52, $cursor->c_get($k, $v, DB_GET_BOTH) == 0 ; + + ($k, $v) = ("green", "door") ; + ok 53, $cursor->c_get($k, $v, DB_GET_BOTH) == DB_NOTFOUND ; + + ($k, $v) = ("black", "house") ; + ok 54, $cursor->c_get($k, $v, DB_GET_BOTH) == DB_NOTFOUND ; + +} + +{ + # Tied Hash interface + + my $lex = new LexFile $Dfile ; + my %hash ; + ok 55, tie %hash, 'BerkeleyDB::Hash', -Filename => $Dfile, + -Flags => DB_CREATE ; + + # check "each" with an empty database + my $count = 0 ; + while (my ($k, $v) = each %hash) { + ++ $count ; + } + ok 56, (tied %hash)->status() == DB_NOTFOUND ; + ok 57, $count == 0 ; + + # Add a k/v pair + my $value ; + $hash{"some key"} = "some value"; + ok 58, (tied %hash)->status() == 0 ; + ok 59, $hash{"some key"} eq "some value"; + ok 60, defined $hash{"some key"} ; + ok 61, (tied %hash)->status() == 0 ; + ok 62, exists $hash{"some key"} ; + ok 63, !defined $hash{"jimmy"} ; + ok 64, (tied %hash)->status() == DB_NOTFOUND ; + ok 65, !exists $hash{"jimmy"} ; + ok 66, (tied %hash)->status() == DB_NOTFOUND ; + + delete $hash{"some key"} ; + ok 67, (tied %hash)->status() == 0 ; + ok 68, ! defined $hash{"some key"} ; + ok 69, (tied %hash)->status() == DB_NOTFOUND ; + ok 70, ! exists $hash{"some key"} ; + ok 71, (tied %hash)->status() == DB_NOTFOUND ; + + $hash{1} = 2 ; + $hash{10} = 20 ; + $hash{1000} = 2000 ; + + my ($keys, $values) = (0,0); + $count = 0 ; + while (my ($k, $v) = each %hash) { + $keys += $k ; + $values += $v ; + ++ $count ; + } + ok 72, $count == 3 ; + ok 73, $keys == 1011 ; + ok 74, $values == 2022 ; + + # now clear the hash + %hash = () ; + ok 75, keys %hash == 0 ; + + untie %hash ; +} + +{ + # in-memory file + + my $lex = new LexFile $Dfile ; + my %hash ; + my $fd ; + my $value ; + ok 76, my $db = tie %hash, 'BerkeleyDB::Hash' ; + + ok 77, $db->db_put("some key", "some value") == 0 ; + ok 78, $db->db_get("some key", $value) == 0 ; + ok 79, $value eq "some value" ; + + undef $db ; + untie %hash ; +} + +{ + # partial + # check works via API + + my $lex = new LexFile $Dfile ; + my %hash ; + my $value ; + ok 80, my $db = tie %hash, 'BerkeleyDB::Hash', -Filename => $Dfile, + -Flags => DB_CREATE ; + + # create some data + my %data = ( + "red" => "boat", + "green" => "house", + "blue" => "sea", + ) ; + + my $ret = 0 ; + while (my ($k, $v) = each %data) { + $ret += $db->db_put($k, $v) ; + } + ok 81, $ret == 0 ; + + + # do a partial get + my($pon, $off, $len) = $db->partial_set(0,2) ; + ok 82, $pon == 0 && $off == 0 && $len == 0 ; + ok 83, ( $db->db_get("red", $value) == 0) && $value eq "bo" ; + ok 84, ( $db->db_get("green", $value) == 0) && $value eq "ho" ; + ok 85, ( $db->db_get("blue", $value) == 0) && $value eq "se" ; + + # do a partial get, off end of data + ($pon, $off, $len) = $db->partial_set(3,2) ; + ok 86, $pon ; + ok 87, $off == 0 ; + ok 88, $len == 2 ; + ok 89, $db->db_get("red", $value) == 0 && $value eq "t" ; + ok 90, $db->db_get("green", $value) == 0 && $value eq "se" ; + ok 91, $db->db_get("blue", $value) == 0 && $value eq "" ; + + # switch of partial mode + ($pon, $off, $len) = $db->partial_clear() ; + ok 92, $pon ; + ok 93, $off == 3 ; + ok 94, $len == 2 ; + ok 95, $db->db_get("red", $value) == 0 && $value eq "boat" ; + ok 96, $db->db_get("green", $value) == 0 && $value eq "house" ; + ok 97, $db->db_get("blue", $value) == 0 && $value eq "sea" ; + + # now partial put + ($pon, $off, $len) = $db->partial_set(0,2) ; + ok 98, ! $pon ; + ok 99, $off == 0 ; + ok 100, $len == 0 ; + ok 101, $db->db_put("red", "") == 0 ; + ok 102, $db->db_put("green", "AB") == 0 ; + ok 103, $db->db_put("blue", "XYZ") == 0 ; + ok 104, $db->db_put("new", "KLM") == 0 ; + + $db->partial_clear() ; + ok 105, $db->db_get("red", $value) == 0 && $value eq "at" ; + ok 106, $db->db_get("green", $value) == 0 && $value eq "ABuse" ; + ok 107, $db->db_get("blue", $value) == 0 && $value eq "XYZa" ; + ok 108, $db->db_get("new", $value) == 0 && $value eq "KLM" ; + + # now partial put + $db->partial_set(3,2) ; + ok 109, $db->db_put("red", "PPP") == 0 ; + ok 110, $db->db_put("green", "Q") == 0 ; + ok 111, $db->db_put("blue", "XYZ") == 0 ; + ok 112, $db->db_put("new", "--") == 0 ; + + ($pon, $off, $len) = $db->partial_clear() ; + ok 113, $pon ; + ok 114, $off == 3 ; + ok 115, $len == 2 ; + ok 116, $db->db_get("red", $value) == 0 && $value eq "at\0PPP" ; + ok 117, $db->db_get("green", $value) == 0 && $value eq "ABuQ" ; + ok 118, $db->db_get("blue", $value) == 0 && $value eq "XYZXYZ" ; + ok 119, $db->db_get("new", $value) == 0 && $value eq "KLM--" ; +} + +{ + # partial + # check works via tied hash + + my $lex = new LexFile $Dfile ; + my %hash ; + my $value ; + ok 120, my $db = tie %hash, 'BerkeleyDB::Hash', -Filename => $Dfile, + -Flags => DB_CREATE ; + + # create some data + my %data = ( + "red" => "boat", + "green" => "house", + "blue" => "sea", + ) ; + + while (my ($k, $v) = each %data) { + $hash{$k} = $v ; + } + + + # do a partial get + $db->partial_set(0,2) ; + ok 121, $hash{"red"} eq "bo" ; + ok 122, $hash{"green"} eq "ho" ; + ok 123, $hash{"blue"} eq "se" ; + + # do a partial get, off end of data + $db->partial_set(3,2) ; + ok 124, $hash{"red"} eq "t" ; + ok 125, $hash{"green"} eq "se" ; + ok 126, $hash{"blue"} eq "" ; + + # switch of partial mode + $db->partial_clear() ; + ok 127, $hash{"red"} eq "boat" ; + ok 128, $hash{"green"} eq "house" ; + ok 129, $hash{"blue"} eq "sea" ; + + # now partial put + $db->partial_set(0,2) ; + ok 130, $hash{"red"} = "" ; + ok 131, $hash{"green"} = "AB" ; + ok 132, $hash{"blue"} = "XYZ" ; + ok 133, $hash{"new"} = "KLM" ; + + $db->partial_clear() ; + ok 134, $hash{"red"} eq "at" ; + ok 135, $hash{"green"} eq "ABuse" ; + ok 136, $hash{"blue"} eq "XYZa" ; + ok 137, $hash{"new"} eq "KLM" ; + + # now partial put + $db->partial_set(3,2) ; + ok 138, $hash{"red"} = "PPP" ; + ok 139, $hash{"green"} = "Q" ; + ok 140, $hash{"blue"} = "XYZ" ; + ok 141, $hash{"new"} = "TU" ; + + $db->partial_clear() ; + ok 142, $hash{"red"} eq "at\0PPP" ; + ok 143, $hash{"green"} eq "ABuQ" ; + ok 144, $hash{"blue"} eq "XYZXYZ" ; + ok 145, $hash{"new"} eq "KLMTU" ; +} + +{ + # transaction + + my $lex = new LexFile $Dfile ; + my %hash ; + my $value ; + + my $home = "./fred" ; + rmtree $home if -e $home ; + ok 146, mkdir($home, 0777) ; + ok 147, my $env = new BerkeleyDB::Env -Home => $home, + -Flags => DB_CREATE|DB_INIT_TXN| + DB_INIT_MPOOL|DB_INIT_LOCK ; + ok 148, my $txn = $env->txn_begin() ; + ok 149, my $db1 = tie %hash, 'BerkeleyDB::Hash', -Filename => $Dfile, + -Flags => DB_CREATE , + -Env => $env, + -Txn => $txn ; + + + # create some data + my %data = ( + "red" => "boat", + "green" => "house", + "blue" => "sea", + ) ; + + my $ret = 0 ; + while (my ($k, $v) = each %data) { + $ret += $db1->db_put($k, $v) ; + } + ok 150, $ret == 0 ; + + # should be able to see all the records + + ok 151, my $cursor = $db1->db_cursor() ; + my ($k, $v) = ("", "") ; + my $count = 0 ; + # sequence forwards + while ($cursor->c_get($k, $v, DB_NEXT) == 0) { + ++ $count ; + } + ok 152, $count == 3 ; + undef $cursor ; + + # now abort the transaction + ok 153, $txn->txn_abort() == 0 ; + + # there shouldn't be any records in the database + $count = 0 ; + # sequence forwards + ok 154, $cursor = $db1->db_cursor() ; + while ($cursor->c_get($k, $v, DB_NEXT) == 0) { + ++ $count ; + } + ok 155, $count == 0 ; + + undef $txn ; + undef $cursor ; + undef $db1 ; + undef $env ; + untie %hash ; + rmtree $home ; +} + + +{ + # DB_DUP + + my $lex = new LexFile $Dfile ; + my %hash ; + ok 156, my $db = tie %hash, 'BerkeleyDB::Hash', -Filename => $Dfile, + -Property => DB_DUP, + -Flags => DB_CREATE ; + + $hash{'Wall'} = 'Larry' ; + $hash{'Wall'} = 'Stone' ; + $hash{'Smith'} = 'John' ; + $hash{'Wall'} = 'Brick' ; + $hash{'Wall'} = 'Brick' ; + $hash{'mouse'} = 'mickey' ; + + ok 157, keys %hash == 6 ; + + # create a cursor + ok 158, my $cursor = $db->db_cursor() ; + + my $key = "Wall" ; + my $value ; + ok 159, $cursor->c_get($key, $value, DB_SET) == 0 ; + ok 160, $key eq "Wall" && $value eq "Larry" ; + ok 161, $cursor->c_get($key, $value, DB_NEXT) == 0 ; + ok 162, $key eq "Wall" && $value eq "Stone" ; + ok 163, $cursor->c_get($key, $value, DB_NEXT) == 0 ; + ok 164, $key eq "Wall" && $value eq "Brick" ; + ok 165, $cursor->c_get($key, $value, DB_NEXT) == 0 ; + ok 166, $key eq "Wall" && $value eq "Brick" ; + + #my $ref = $db->db_stat() ; + #ok 143, $ref->{bt_flags} | DB_DUP ; + + # test DB_DUP_NEXT + my ($k, $v) = ("Wall", "") ; + ok 167, $cursor->c_get($k, $v, DB_SET) == 0 ; + ok 168, $k eq "Wall" && $v eq "Larry" ; + ok 169, $cursor->c_get($k, $v, DB_NEXT_DUP) == 0 ; + ok 170, $k eq "Wall" && $v eq "Stone" ; + ok 171, $cursor->c_get($k, $v, DB_NEXT_DUP) == 0 ; + ok 172, $k eq "Wall" && $v eq "Brick" ; + ok 173, $cursor->c_get($k, $v, DB_NEXT_DUP) == 0 ; + ok 174, $k eq "Wall" && $v eq "Brick" ; + ok 175, $cursor->c_get($k, $v, DB_NEXT_DUP) == DB_NOTFOUND ; + + + undef $db ; + undef $cursor ; + untie %hash ; + +} + +{ + # DB_DUP & DupCompare + my $lex = new LexFile $Dfile, $Dfile2; + my ($key, $value) ; + my (%h, %g) ; + my @Keys = qw( 0123 9 12 -1234 9 987654321 9 def ) ; + my @Values = qw( 1 11 3 dd x abc 2 0 ) ; + + ok 176, tie %h, "BerkeleyDB::Hash", -Filename => $Dfile, + -DupCompare => sub { $_[0] cmp $_[1] }, + -Property => DB_DUP|DB_DUPSORT, + -Flags => DB_CREATE ; + + ok 177, tie %g, 'BerkeleyDB::Hash', -Filename => $Dfile2, + -DupCompare => sub { $_[0] <=> $_[1] }, + -Property => DB_DUP|DB_DUPSORT, + -Flags => DB_CREATE ; + + foreach (@Keys) { + local $^W = 0 ; + my $value = shift @Values ; + $h{$_} = $value ; + $g{$_} = $value ; + } + + ok 178, my $cursor = (tied %h)->db_cursor() ; + $key = 9 ; $value = ""; + ok 179, $cursor->c_get($key, $value, DB_SET) == 0 ; + ok 180, $key == 9 && $value eq 11 ; + ok 181, $cursor->c_get($key, $value, DB_NEXT) == 0 ; + ok 182, $key == 9 && $value == 2 ; + ok 183, $cursor->c_get($key, $value, DB_NEXT) == 0 ; + ok 184, $key == 9 && $value eq "x" ; + + $cursor = (tied %g)->db_cursor() ; + $key = 9 ; + ok 185, $cursor->c_get($key, $value, DB_SET) == 0 ; + ok 186, $key == 9 && $value eq "x" ; + ok 187, $cursor->c_get($key, $value, DB_NEXT) == 0 ; + ok 188, $key == 9 && $value == 2 ; + ok 189, $cursor->c_get($key, $value, DB_NEXT) == 0 ; + ok 190, $key == 9 && $value == 11 ; + + +} + +{ + # get_dup etc + my $lex = new LexFile $Dfile; + my %hh ; + + ok 191, my $YY = tie %hh, "BerkeleyDB::Hash", -Filename => $Dfile, + -DupCompare => sub { $_[0] cmp $_[1] }, + -Property => DB_DUP, + -Flags => DB_CREATE ; + + $hh{'Wall'} = 'Larry' ; + $hh{'Wall'} = 'Stone' ; # Note the duplicate key + $hh{'Wall'} = 'Brick' ; # Note the duplicate key + $hh{'Smith'} = 'John' ; + $hh{'mouse'} = 'mickey' ; + + # first work in scalar context + ok 192, scalar $YY->get_dup('Unknown') == 0 ; + ok 193, scalar $YY->get_dup('Smith') == 1 ; + ok 194, scalar $YY->get_dup('Wall') == 3 ; + + # now in list context + my @unknown = $YY->get_dup('Unknown') ; + ok 195, "@unknown" eq "" ; + + my @smith = $YY->get_dup('Smith') ; + ok 196, "@smith" eq "John" ; + + { + my @wall = $YY->get_dup('Wall') ; + my %wall ; + @wall{@wall} = @wall ; + ok 197, (@wall == 3 && $wall{'Larry'} + && $wall{'Stone'} && $wall{'Brick'}); + } + + # hash + my %unknown = $YY->get_dup('Unknown', 1) ; + ok 198, keys %unknown == 0 ; + + my %smith = $YY->get_dup('Smith', 1) ; + ok 199, keys %smith == 1 && $smith{'John'} ; + + my %wall = $YY->get_dup('Wall', 1) ; + ok 200, keys %wall == 3 && $wall{'Larry'} == 1 && $wall{'Stone'} == 1 + && $wall{'Brick'} == 1 ; + + undef $YY ; + untie %hh ; + +} + +{ + # sub-class test + + package Another ; + + use strict ; + + open(FILE, ">SubDB.pm") or die "Cannot open SubDB.pm: $!\n" ; + print FILE <<'EOM' ; + + package SubDB ; + + use strict ; + use vars qw( @ISA @EXPORT) ; + + require Exporter ; + use BerkeleyDB; + @ISA=qw(BerkeleyDB::Hash); + @EXPORT = @BerkeleyDB::EXPORT ; + + sub db_put { + my $self = shift ; + my $key = shift ; + my $value = shift ; + $self->SUPER::db_put($key, $value * 3) ; + } + + sub db_get { + my $self = shift ; + $self->SUPER::db_get($_[0], $_[1]) ; + $_[1] -= 2 ; + } + + sub A_new_method + { + my $self = shift ; + my $key = shift ; + my $value = $self->FETCH($key) ; + return "[[$value]]" ; + } + + 1 ; +EOM + + close FILE ; + + BEGIN { push @INC, '.'; } + eval 'use SubDB ; '; + main::ok 201, $@ eq "" ; + my %h ; + my $X ; + eval ' + $X = tie(%h, "SubDB", -Filename => "dbhash.tmp", + -Flags => DB_CREATE, + -Mode => 0640 ); + ' ; + + main::ok 202, $@ eq "" ; + + my $ret = eval '$h{"fred"} = 3 ; return $h{"fred"} ' ; + main::ok 203, $@ eq "" ; + main::ok 204, $ret == 7 ; + + my $value = 0; + $ret = eval '$X->db_put("joe", 4) ; $X->db_get("joe", $value) ; return $value' ; + main::ok 205, $@ eq "" ; + main::ok 206, $ret == 10 ; + + $ret = eval ' DB_NEXT eq main::DB_NEXT ' ; + main::ok 207, $@ eq "" ; + main::ok 208, $ret == 1 ; + + $ret = eval '$X->A_new_method("joe") ' ; + main::ok 209, $@ eq "" ; + main::ok 210, $ret eq "[[10]]" ; + + unlink "SubDB.pm", "dbhash.tmp" ; + +} diff --git a/db/perl.BerkeleyDB/t/join.t b/db/perl.BerkeleyDB/t/join.t new file mode 100644 index 000000000..f986d76f7 --- /dev/null +++ b/db/perl.BerkeleyDB/t/join.t @@ -0,0 +1,270 @@ +#!./perl -w + +# ID: %I%, %G% + +use strict ; + +BEGIN { + unless(grep /blib/, @INC) { + chdir 't' if -d 't'; + @INC = '../lib' if -d '../lib'; + } +} + +use BerkeleyDB; +use File::Path qw(rmtree); + +if ($BerkeleyDB::db_ver < 2.005002) +{ + print "1..0 # Skip: join needs Berkeley DB 2.5.2 or later\n" ; + exit 0 ; +} + + +print "1..37\n"; + +{ + package LexFile ; + + sub new + { + my $self = shift ; + unlink @_ ; + bless [ @_ ], $self ; + } + + sub DESTROY + { + my $self = shift ; + unlink @{ $self } ; + } +} + + +sub ok +{ + my $no = shift ; + my $result = shift ; + + print "not " unless $result ; + print "ok $no\n" ; +} + +my $Dfile1 = "dbhash1.tmp"; +my $Dfile2 = "dbhash2.tmp"; +my $Dfile3 = "dbhash3.tmp"; +unlink $Dfile1, $Dfile2, $Dfile3 ; + +umask(0) ; + +sub addData +{ + my $db = shift ; + my @data = @_ ; + die "addData odd data\n" unless @data /2 != 0 ; + my ($k, $v) ; + my $ret = 0 ; + while (@data) { + $k = shift @data ; + $v = shift @data ; + $ret += $db->db_put($k, $v) ; + } + + return ($ret == 0) ; +} + +{ + # error cases + my $lex = new LexFile $Dfile1, $Dfile2, $Dfile3 ; + my %hash1 ; + my $value ; + my $status ; + my $cursor ; + + ok 1, my $db1 = tie %hash1, 'BerkeleyDB::Hash', + -Filename => $Dfile1, + -Flags => DB_CREATE, + -DupCompare => sub { $_[0] lt $_[1] }, + -Property => DB_DUP|DB_DUPSORT ; + + # no cursors supplied + eval '$cursor = $db1->db_join() ;' ; + ok 2, $@ =~ /Usage: \$db->BerkeleyDB::Common::db_join\Q([cursors], flags=0)/; + + # empty list + eval '$cursor = $db1->db_join([]) ;' ; + ok 3, $@ =~ /db_join: No cursors in parameter list/; + + # cursor list, isn't a [] + eval '$cursor = $db1->db_join({}) ;' ; + ok 4, $@ =~ /cursors is not an array reference at/ ; + + eval '$cursor = $db1->db_join(\1) ;' ; + ok 5, $@ =~ /cursors is not an array reference at/ ; + +} + +{ + # test a 2-way & 3-way join + + my $lex = new LexFile $Dfile1, $Dfile2, $Dfile3 ; + my %hash1 ; + my %hash2 ; + my %hash3 ; + my $value ; + my $status ; + + my $home = "./fred" ; + rmtree $home if -e $home ; + ok 6, mkdir($home, 0777) ; + ok 7, my $env = new BerkeleyDB::Env -Home => $home, + -Flags => DB_CREATE|DB_INIT_TXN + |DB_INIT_MPOOL; + #|DB_INIT_MPOOL| DB_INIT_LOCK; + ok 8, my $txn = $env->txn_begin() ; + ok 9, my $db1 = tie %hash1, 'BerkeleyDB::Hash', + -Filename => $Dfile1, + -Flags => DB_CREATE, + -DupCompare => sub { $_[0] cmp $_[1] }, + -Property => DB_DUP|DB_DUPSORT, + -Env => $env, + -Txn => $txn ; + ; + + ok 10, my $db2 = tie %hash2, 'BerkeleyDB::Hash', + -Filename => $Dfile2, + -Flags => DB_CREATE, + -DupCompare => sub { $_[0] cmp $_[1] }, + -Property => DB_DUP|DB_DUPSORT, + -Env => $env, + -Txn => $txn ; + + ok 11, my $db3 = tie %hash3, 'BerkeleyDB::Btree', + -Filename => $Dfile3, + -Flags => DB_CREATE, + -DupCompare => sub { $_[0] cmp $_[1] }, + -Property => DB_DUP|DB_DUPSORT, + -Env => $env, + -Txn => $txn ; + + + ok 12, addData($db1, qw( apple Convenience + peach Shopway + pear Farmer + raspberry Shopway + strawberry Shopway + gooseberry Farmer + blueberry Farmer + )); + + ok 13, addData($db2, qw( red apple + red raspberry + red strawberry + yellow peach + yellow pear + green gooseberry + blue blueberry)) ; + + ok 14, addData($db3, qw( expensive apple + reasonable raspberry + expensive strawberry + reasonable peach + reasonable pear + expensive gooseberry + reasonable blueberry)) ; + + ok 15, my $cursor2 = $db2->db_cursor() ; + my $k = "red" ; + my $v = "" ; + ok 16, $cursor2->c_get($k, $v, DB_SET) == 0 ; + + # Two way Join + ok 17, my $cursor1 = $db1->db_join([$cursor2]) ; + + my %expected = qw( apple Convenience + raspberry Shopway + strawberry Shopway + ) ; + + # sequence forwards + while ($cursor1->c_get($k, $v) == 0) { + delete $expected{$k} + if defined $expected{$k} && $expected{$k} eq $v ; + #print "[$k] [$v]\n" ; + } + ok 18, keys %expected == 0 ; + ok 19, $cursor1->status() == DB_NOTFOUND ; + + # Three way Join + ok 20, $cursor2 = $db2->db_cursor() ; + $k = "red" ; + $v = "" ; + ok 21, $cursor2->c_get($k, $v, DB_SET) == 0 ; + + ok 22, my $cursor3 = $db3->db_cursor() ; + $k = "expensive" ; + $v = "" ; + ok 23, $cursor3->c_get($k, $v, DB_SET) == 0 ; + ok 24, $cursor1 = $db1->db_join([$cursor2, $cursor3]) ; + + %expected = qw( apple Convenience + strawberry Shopway + ) ; + + # sequence forwards + while ($cursor1->c_get($k, $v) == 0) { + delete $expected{$k} + if defined $expected{$k} && $expected{$k} eq $v ; + #print "[$k] [$v]\n" ; + } + ok 25, keys %expected == 0 ; + ok 26, $cursor1->status() == DB_NOTFOUND ; + + # test DB_JOIN_ITEM + # ################# + ok 27, $cursor2 = $db2->db_cursor() ; + $k = "red" ; + $v = "" ; + ok 28, $cursor2->c_get($k, $v, DB_SET) == 0 ; + + ok 29, $cursor3 = $db3->db_cursor() ; + $k = "expensive" ; + $v = "" ; + ok 30, $cursor3->c_get($k, $v, DB_SET) == 0 ; + ok 31, $cursor1 = $db1->db_join([$cursor2, $cursor3]) ; + + %expected = qw( apple 1 + strawberry 1 + ) ; + + # sequence forwards + $k = "" ; + $v = "" ; + while ($cursor1->c_get($k, $v, DB_JOIN_ITEM) == 0) { + delete $expected{$k} + if defined $expected{$k} ; + #print "[$k]\n" ; + } + ok 32, keys %expected == 0 ; + ok 33, $cursor1->status() == DB_NOTFOUND ; + + ok 34, $cursor1->c_close() == 0 ; + ok 35, $cursor2->c_close() == 0 ; + ok 36, $cursor3->c_close() == 0 ; + + ok 37, ($status = $txn->txn_commit) == 0; + + undef $txn ; + #undef $cursor1; + #undef $cursor2; + #undef $cursor3; + undef $db1 ; + undef $db2 ; + undef $db3 ; + undef $env ; + untie %hash1 ; + untie %hash2 ; + untie %hash3 ; + rmtree $home ; +} + diff --git a/db/perl.BerkeleyDB/t/mldbm.t b/db/perl.BerkeleyDB/t/mldbm.t new file mode 100644 index 000000000..eb6673b35 --- /dev/null +++ b/db/perl.BerkeleyDB/t/mldbm.t @@ -0,0 +1,166 @@ +#!/usr/bin/perl -w + +BEGIN +{ + if ($] < 5.005) { + print "1..0 # This is Perl $], skipping test\n" ; + exit 0 ; + } + + eval { require Data::Dumper ; }; + if ($@) { + print "1..0 # Data::Dumper is not installed on this system.\n"; + exit 0 ; + } + if ($Data::Dumper::VERSION < 2.08) { + print "1..0 # Data::Dumper 2.08 or better required (found $Data::Dumper::VERSION).\n"; + exit 0 ; + } + eval { require MLDBM ; }; + if ($@) { + print "1..0 # MLDBM is not installed on this system.\n"; + exit 0 ; + } +} + +sub ok +{ + my $no = shift ; + my $result = shift ; + + print "not " unless $result ; + print "ok $no\n" ; +} + +print "1..12\n"; + +{ +package BTREE ; + +use BerkeleyDB ; +use MLDBM qw(BerkeleyDB::Btree) ; +use Data::Dumper; + +$filename = 'testmldbm' ; + +unlink $filename ; +$MLDBM::UseDB = "BerkeleyDB::Btree" ; +$db = tie %o, MLDBM, -Filename => $filename, + -Flags => DB_CREATE + or die $!; +::ok 1, $db ; +::ok 2, $db->type() == DB_BTREE ; + +$c = [\'c']; +$b = {}; +$a = [1, $b, $c]; +$b->{a} = $a; +$b->{b} = $a->[1]; +$b->{c} = $a->[2]; +@o{qw(a b c)} = ($a, $b, $c); +$o{d} = "{once upon a time}"; +$o{e} = 1024; +$o{f} = 1024.1024; +$first = Data::Dumper->new([@o{qw(a b c)}], [qw(a b c)])->Quotekeys(0)->Dump; +$second = <<'EOT'; +$a = [ + 1, + { + a => $a, + b => $a->[1], + c => [ + \'c' + ] + }, + $a->[1]{c} + ]; +$b = { + a => [ + 1, + $b, + [ + \'c' + ] + ], + b => $b, + c => $b->{a}[2] + }; +$c = [ + \'c' + ]; +EOT + +::ok 3, $first eq $second ; +::ok 4, $o{d} eq "{once upon a time}" ; +::ok 5, $o{e} == 1024 ; +::ok 6, $o{f} eq 1024.1024 ; + +unlink $filename ; +} + +{ + +package HASH ; + +use BerkeleyDB ; +use MLDBM qw(BerkeleyDB::Hash) ; +use Data::Dumper; + +$filename = 'testmldbm' ; + +unlink $filename ; +$MLDBM::UseDB = "BerkeleyDB::Hash" ; +$db = tie %o, MLDBM, -Filename => $filename, + -Flags => DB_CREATE + or die $!; +::ok 7, $db ; +::ok 8, $db->type() == DB_HASH ; + + +$c = [\'c']; +$b = {}; +$a = [1, $b, $c]; +$b->{a} = $a; +$b->{b} = $a->[1]; +$b->{c} = $a->[2]; +@o{qw(a b c)} = ($a, $b, $c); +$o{d} = "{once upon a time}"; +$o{e} = 1024; +$o{f} = 1024.1024; +$first = Data::Dumper->new([@o{qw(a b c)}], [qw(a b c)])->Quotekeys(0)->Dump; +$second = <<'EOT'; +$a = [ + 1, + { + a => $a, + b => $a->[1], + c => [ + \'c' + ] + }, + $a->[1]{c} + ]; +$b = { + a => [ + 1, + $b, + [ + \'c' + ] + ], + b => $b, + c => $b->{a}[2] + }; +$c = [ + \'c' + ]; +EOT + +::ok 9, $first eq $second ; +::ok 10, $o{d} eq "{once upon a time}" ; +::ok 11, $o{e} == 1024 ; +::ok 12, $o{f} eq 1024.1024 ; + +unlink $filename ; + +} diff --git a/db/perl.BerkeleyDB/t/queue.t b/db/perl.BerkeleyDB/t/queue.t new file mode 100644 index 000000000..0f459a43a --- /dev/null +++ b/db/perl.BerkeleyDB/t/queue.t @@ -0,0 +1,837 @@ +#!./perl -w + +# ID: %I%, %G% + +use strict ; + +BEGIN { + unless(grep /blib/, @INC) { + chdir 't' if -d 't'; + @INC = '../lib' if -d '../lib'; + } +} + +use BerkeleyDB; +use File::Path qw(rmtree); + +BEGIN +{ + if ($BerkeleyDB::db_version < 3) { + print "1..0 # Skipping test, Queue needs Berkeley DB 3.x or better\n" ; + exit 0 ; + } +} + +print "1..197\n"; + +my %DB_errors = ( + 'DB_INCOMPLETE' => "DB_INCOMPLETE: Sync was unable to complete", + 'DB_KEYEMPTY' => "DB_KEYEMPTY: Non-existent key/data pair", + 'DB_KEYEXIST' => "DB_KEYEXIST: Key/data pair already exists", + 'DB_LOCK_DEADLOCK' => "DB_LOCK_DEADLOCK: Locker killed to resolve a deadlock", + 'DB_LOCK_NOTGRANTED' => "DB_LOCK_NOTGRANTED: Lock not granted", + 'DB_NOTFOUND' => "DB_NOTFOUND: No matching key/data pair found", + 'DB_OLD_VERSION'=> "DB_OLDVERSION: Database requires a version upgrade", + 'DB_RUNRECOVERY'=> "DB_RUNRECOVERY: Fatal error, run database recovery", + ) ; + +{ + package LexFile ; + + sub new + { + my $self = shift ; + unlink @_ ; + bless [ @_ ], $self ; + } + + sub DESTROY + { + my $self = shift ; + unlink @{ $self } ; + } +} + + +sub ok +{ + my $no = shift ; + my $result = shift ; + + print "not " unless $result ; + print "ok $no\n" ; +} + +sub docat +{ + my $file = shift; + local $/ = undef; + open(CAT,$file) || die "Cannot open $file:$!"; + my $result = ; + close(CAT); + return $result; +} + +sub touch +{ + my $file = shift ; + open(CAT,">$file") || die "Cannot open $file:$!"; + close(CAT); +} + +sub joiner +{ + my $db = shift ; + my $sep = shift ; + my ($k, $v) = (0, "") ; + my @data = () ; + + my $cursor = $db->db_cursor() or return () ; + for ( my $status = $cursor->c_get($k, $v, DB_FIRST) ; + $status == 0 ; + $status = $cursor->c_get($k, $v, DB_NEXT)) { + push @data, $v ; + } + + (scalar(@data), join($sep, @data)) ; +} + +sub countRecords +{ + my $db = shift ; + my ($k, $v) = (0,0) ; + my ($count) = 0 ; + my ($cursor) = $db->db_cursor() ; + #for ($status = $cursor->c_get($k, $v, DB_FIRST) ; +# $status == 0 ; +# $status = $cursor->c_get($k, $v, DB_NEXT) ) + while ($cursor->c_get($k, $v, DB_NEXT) == 0) + { ++ $count } + + return $count ; +} + +sub fillout +{ + my $var = shift ; + my $length = shift ; + my $pad = shift || " " ; + my $template = $pad x $length ; + substr($template, 0, length($var)) = $var ; + return $template ; +} + +my $Dfile = "dbhash.tmp"; +my $Dfile2 = "dbhash2.tmp"; +my $Dfile3 = "dbhash3.tmp"; +unlink $Dfile; + +umask(0) ; + + +# Check for invalid parameters +{ + # Check for invalid parameters + my $db ; + eval ' $db = new BerkeleyDB::Queue -Stupid => 3 ; ' ; + ok 1, $@ =~ /unknown key value\(s\) Stupid/ ; + + eval ' $db = new BerkeleyDB::Queue -Bad => 2, -Mode => 0345, -Stupid => 3; ' ; + ok 2, $@ =~ /unknown key value\(s\) / ; + + eval ' $db = new BerkeleyDB::Queue -Env => 2 ' ; + ok 3, $@ =~ /^Env not of type BerkeleyDB::Env/ ; + + eval ' $db = new BerkeleyDB::Queue -Txn => "x" ' ; + ok 4, $@ =~ /^Txn not of type BerkeleyDB::Txn/ ; + + my $obj = bless [], "main" ; + eval ' $db = new BerkeleyDB::Queue -Env => $obj ' ; + ok 5, $@ =~ /^Env not of type BerkeleyDB::Env/ ; +} + +# Now check the interface to Queue + +{ + my $lex = new LexFile $Dfile ; + my $rec_len = 10 ; + my $pad = "x" ; + + ok 6, my $db = new BerkeleyDB::Queue -Filename => $Dfile, + -Flags => DB_CREATE, + -Len => $rec_len, + -Pad => $pad; + + # Add a k/v pair + my $value ; + my $status ; + ok 7, $db->db_put(1, "some value") == 0 ; + ok 8, $db->status() == 0 ; + ok 9, $db->db_get(1, $value) == 0 ; + ok 10, $value eq fillout("some value", $rec_len, $pad) ; + ok 11, $db->db_put(2, "value") == 0 ; + ok 12, $db->db_get(2, $value) == 0 ; + ok 13, $value eq fillout("value", $rec_len, $pad) ; + ok 14, $db->db_del(1) == 0 ; + ok 15, ($status = $db->db_get(1, $value)) == DB_KEYEMPTY ; + ok 16, $db->status() == DB_KEYEMPTY ; + ok 17, $db->status() eq $DB_errors{'DB_KEYEMPTY'} ; + + ok 18, ($status = $db->db_get(7, $value)) == DB_NOTFOUND ; + ok 19, $db->status() == DB_NOTFOUND ; + ok 20, $db->status() eq $DB_errors{'DB_NOTFOUND'} ; + + ok 21, $db->db_sync() == 0 ; + + # Check NOOVERWRITE will make put fail when attempting to overwrite + # an existing record. + + ok 22, $db->db_put( 2, 'x', DB_NOOVERWRITE) == DB_KEYEXIST ; + ok 23, $db->status() eq $DB_errors{'DB_KEYEXIST'} ; + ok 24, $db->status() == DB_KEYEXIST ; + + + # check that the value of the key has not been changed by the + # previous test + ok 25, $db->db_get(2, $value) == 0 ; + ok 26, $value eq fillout("value", $rec_len, $pad) ; + + +} + + +{ + # Check simple env works with a array. + # and pad defaults to space + my $lex = new LexFile $Dfile ; + + my $home = "./fred" ; + my $rec_len = 11 ; + ok 27, -d $home ? chmod 0777, $home : mkdir($home, 0777) ; + + ok 28, my $env = new BerkeleyDB::Env -Flags => DB_CREATE|DB_INIT_MPOOL, + -Home => $home ; + + ok 29, my $db = new BerkeleyDB::Queue -Filename => $Dfile, + -Env => $env, + -Flags => DB_CREATE, + -Len => $rec_len; + + # Add a k/v pair + my $value ; + ok 30, $db->db_put(1, "some value") == 0 ; + ok 31, $db->db_get(1, $value) == 0 ; + ok 32, $value eq fillout("some value", $rec_len) ; + undef $db ; + undef $env ; + rmtree $home ; +} + + +{ + # cursors + + my $lex = new LexFile $Dfile ; + my @array ; + my ($k, $v) ; + my $rec_len = 5 ; + ok 33, my $db = new BerkeleyDB::Queue -Filename => $Dfile, + -ArrayBase => 0, + -Flags => DB_CREATE , + -Len => $rec_len; + + # create some data + my @data = ( + "red" , + "green" , + "blue" , + ) ; + + my $i ; + my %data ; + my $ret = 0 ; + for ($i = 0 ; $i < @data ; ++$i) { + $ret += $db->db_put($i, $data[$i]) ; + $data{$i} = $data[$i] ; + } + ok 34, $ret == 0 ; + + # create the cursor + ok 35, my $cursor = $db->db_cursor() ; + + $k = 0 ; $v = "" ; + my %copy = %data; + my $extras = 0 ; + # sequence forwards + while ($cursor->c_get($k, $v, DB_NEXT) == 0) + { + if ( fillout($copy{$k}, $rec_len) eq $v ) + { delete $copy{$k} } + else + { ++ $extras } + } + + ok 36, $cursor->status() == DB_NOTFOUND ; + ok 37, $cursor->status() eq $DB_errors{'DB_NOTFOUND'} ; + ok 38, keys %copy == 0 ; + ok 39, $extras == 0 ; + + # sequence backwards + %copy = %data ; + $extras = 0 ; + my $status ; + for ( $status = $cursor->c_get($k, $v, DB_LAST) ; + $status == 0 ; + $status = $cursor->c_get($k, $v, DB_PREV)) { + if ( fillout($copy{$k}, $rec_len) eq $v ) + { delete $copy{$k} } + else + { ++ $extras } + } + ok 40, $status == DB_NOTFOUND ; + ok 41, $status eq $DB_errors{'DB_NOTFOUND'} ; + ok 42, $cursor->status() == $status ; + ok 43, $cursor->status() eq $status ; + ok 44, keys %copy == 0 ; + ok 45, $extras == 0 ; +} + +{ + # Tied Array interface + + # full tied array support started in Perl 5.004_57 + # just double check. + my $FA = 0 ; + { + sub try::TIEARRAY { bless [], "try" } + sub try::FETCHSIZE { $FA = 1 } + my @a ; + tie @a, 'try' ; + my $a = @a ; + } + + my $lex = new LexFile $Dfile ; + my @array ; + my $db ; + my $rec_len = 10 ; + ok 46, $db = tie @array, 'BerkeleyDB::Queue', -Filename => $Dfile, + -ArrayBase => 0, + -Flags => DB_CREATE , + -Len => $rec_len; + + ok 47, my $cursor = (tied @array)->db_cursor() ; + # check the database is empty + my $count = 0 ; + my ($k, $v) = (0,"") ; + while ($cursor->c_get($k, $v, DB_NEXT) == 0) { + ++ $count ; + } + ok 48, $cursor->status() == DB_NOTFOUND ; + ok 49, $count == 0 ; + + ok 50, @array == 0 ; + + # Add a k/v pair + my $value ; + $array[1] = "some value"; + ok 51, (tied @array)->status() == 0 ; + ok 52, $array[1] eq fillout("some value", $rec_len); + ok 53, defined $array[1]; + ok 54, (tied @array)->status() == 0 ; + ok 55, !defined $array[3]; + ok 56, (tied @array)->status() == DB_NOTFOUND ; + + ok 57, (tied @array)->db_del(1) == 0 ; + ok 58, (tied @array)->status() == 0 ; + ok 59, ! defined $array[1]; + ok 60, (tied @array)->status() == DB_KEYEMPTY ; + + $array[1] = 2 ; + $array[10] = 20 ; + $array[1000] = 2000 ; + + my ($keys, $values) = (0,0); + $count = 0 ; + for ( my $status = $cursor->c_get($k, $v, DB_FIRST) ; + $status == 0 ; + $status = $cursor->c_get($k, $v, DB_NEXT)) { + $keys += $k ; + $values += $v ; + ++ $count ; + } + ok 61, $count == 3 ; + ok 62, $keys == 1011 ; + ok 63, $values == 2022 ; + + # unshift isn't allowed +# eval { +# $FA ? unshift @array, "red", "green", "blue" +# : $db->unshift("red", "green", "blue" ) ; +# } ; +# ok 64, $@ =~ /^unshift is unsupported with Queue databases/ ; + $array[0] = "red" ; + $array[1] = "green" ; + $array[2] = "blue" ; + $array[4] = 2 ; + ok 64, $array[0] eq fillout("red", $rec_len) ; + ok 65, $cursor->c_get($k, $v, DB_FIRST) == 0 ; + ok 66, $k == 0 ; + ok 67, $v eq fillout("red", $rec_len) ; + ok 68, $array[1] eq fillout("green", $rec_len) ; + ok 69, $cursor->c_get($k, $v, DB_NEXT) == 0 ; + ok 70, $k == 1 ; + ok 71, $v eq fillout("green", $rec_len) ; + ok 72, $array[2] eq fillout("blue", $rec_len) ; + ok 73, $cursor->c_get($k, $v, DB_NEXT) == 0 ; + ok 74, $k == 2 ; + ok 75, $v eq fillout("blue", $rec_len) ; + ok 76, $array[4] == 2 ; + ok 77, $cursor->c_get($k, $v, DB_NEXT) == 0 ; + ok 78, $k == 4 ; + ok 79, $v == 2 ; + + # shift + ok 80, ($FA ? shift @array : $db->shift()) eq fillout("red", $rec_len) ; + ok 81, ($FA ? shift @array : $db->shift()) eq fillout("green", $rec_len) ; + ok 82, ($FA ? shift @array : $db->shift()) eq fillout("blue", $rec_len) ; + ok 83, ($FA ? shift @array : $db->shift()) == 2 ; + + # push + $FA ? push @array, "the", "end" + : $db->push("the", "end") ; + ok 84, $cursor->c_get($k, $v, DB_LAST) == 0 ; + ok 85, $k == 1002 ; + ok 86, $v eq fillout("end", $rec_len) ; + ok 87, $cursor->c_get($k, $v, DB_PREV) == 0 ; + ok 88, $k == 1001 ; + ok 89, $v eq fillout("the", $rec_len) ; + ok 90, $cursor->c_get($k, $v, DB_PREV) == 0 ; + ok 91, $k == 1000 ; + ok 92, $v == 2000 ; + + # pop + ok 93, ( $FA ? pop @array : $db->pop ) eq fillout("end", $rec_len) ; + ok 94, ( $FA ? pop @array : $db->pop ) eq fillout("the", $rec_len) ; + ok 95, ( $FA ? pop @array : $db->pop ) == 2000 ; + + # now clear the array + $FA ? @array = () + : $db->clear() ; + ok 96, $cursor->c_get($k, $v, DB_FIRST) == DB_NOTFOUND ; + + undef $cursor ; + undef $db ; + untie @array ; +} + +{ + # in-memory file + + my @array ; + my $fd ; + my $value ; + my $rec_len = 15 ; + ok 97, my $db = tie @array, 'BerkeleyDB::Queue', + -Len => $rec_len; + + ok 98, $db->db_put(1, "some value") == 0 ; + ok 99, $db->db_get(1, $value) == 0 ; + ok 100, $value eq fillout("some value", $rec_len) ; + +} + +{ + # partial + # check works via API + + my $lex = new LexFile $Dfile ; + my $value ; + my $rec_len = 8 ; + ok 101, my $db = new BerkeleyDB::Queue -Filename => $Dfile, + -Flags => DB_CREATE , + -Len => $rec_len, + -Pad => " " ; + + # create some data + my @data = ( + "", + "boat", + "house", + "sea", + ) ; + + my $ret = 0 ; + my $i ; + for ($i = 0 ; $i < @data ; ++$i) { + my $r = $db->db_put($i, $data[$i]) ; + $ret += $r ; + } + ok 102, $ret == 0 ; + + # do a partial get + my ($pon, $off, $len) = $db->partial_set(0,2) ; + ok 103, ! $pon && $off == 0 && $len == 0 ; + ok 104, $db->db_get(1, $value) == 0 && $value eq "bo" ; + ok 105, $db->db_get(2, $value) == 0 && $value eq "ho" ; + ok 106, $db->db_get(3, $value) == 0 && $value eq "se" ; + + # do a partial get, off end of data + ($pon, $off, $len) = $db->partial_set(3,2) ; + ok 107, $pon ; + ok 108, $off == 0 ; + ok 109, $len == 2 ; + ok 110, $db->db_get(1, $value) == 0 && $value eq fillout("t", 2) ; + ok 111, $db->db_get(2, $value) == 0 && $value eq "se" ; + ok 112, $db->db_get(3, $value) == 0 && $value eq " " ; + + # switch of partial mode + ($pon, $off, $len) = $db->partial_clear() ; + ok 113, $pon ; + ok 114, $off == 3 ; + ok 115, $len == 2 ; + ok 116, $db->db_get(1, $value) == 0 && $value eq fillout("boat", $rec_len) ; + ok 117, $db->db_get(2, $value) == 0 && $value eq fillout("house", $rec_len) ; + ok 118, $db->db_get(3, $value) == 0 && $value eq fillout("sea", $rec_len) ; + + # now partial put + $db->partial_set(0,2) ; + ok 119, $db->db_put(1, "") != 0 ; + ok 120, $db->db_put(2, "AB") == 0 ; + ok 121, $db->db_put(3, "XY") == 0 ; + ok 122, $db->db_put(4, "KLM") != 0 ; + ok 123, $db->db_put(4, "KL") == 0 ; + + ($pon, $off, $len) = $db->partial_clear() ; + ok 124, $pon ; + ok 125, $off == 0 ; + ok 126, $len == 2 ; + ok 127, $db->db_get(1, $value) == 0 && $value eq fillout("boat", $rec_len) ; + ok 128, $db->db_get(2, $value) == 0 && $value eq fillout("ABuse", $rec_len) ; + ok 129, $db->db_get(3, $value) == 0 && $value eq fillout("XYa", $rec_len) ; + ok 130, $db->db_get(4, $value) == 0 && $value eq fillout("KL", $rec_len) ; + + # now partial put + ($pon, $off, $len) = $db->partial_set(3,2) ; + ok 131, ! $pon ; + ok 132, $off == 0 ; + ok 133, $len == 0 ; + ok 134, $db->db_put(1, "PP") == 0 ; + ok 135, $db->db_put(2, "Q") != 0 ; + ok 136, $db->db_put(3, "XY") == 0 ; + ok 137, $db->db_put(4, "TU") == 0 ; + + $db->partial_clear() ; + ok 138, $db->db_get(1, $value) == 0 && $value eq fillout("boaPP", $rec_len) ; + ok 139, $db->db_get(2, $value) == 0 && $value eq fillout("ABuse",$rec_len) ; + ok 140, $db->db_get(3, $value) == 0 && $value eq fillout("XYaXY", $rec_len) ; + ok 141, $db->db_get(4, $value) == 0 && $value eq fillout("KL TU", $rec_len) ; +} + +{ + # partial + # check works via tied array + + my $lex = new LexFile $Dfile ; + my @array ; + my $value ; + my $rec_len = 8 ; + ok 142, my $db = tie @array, 'BerkeleyDB::Queue', -Filename => $Dfile, + -Flags => DB_CREATE , + -Len => $rec_len, + -Pad => " " ; + + # create some data + my @data = ( + "", + "boat", + "house", + "sea", + ) ; + + my $i ; + my $status = 0 ; + for ($i = 1 ; $i < @data ; ++$i) { + $array[$i] = $data[$i] ; + $status += $db->status() ; + } + + ok 143, $status == 0 ; + + # do a partial get + $db->partial_set(0,2) ; + ok 144, $array[1] eq fillout("bo", 2) ; + ok 145, $array[2] eq fillout("ho", 2) ; + ok 146, $array[3] eq fillout("se", 2) ; + + # do a partial get, off end of data + $db->partial_set(3,2) ; + ok 147, $array[1] eq fillout("t", 2) ; + ok 148, $array[2] eq fillout("se", 2) ; + ok 149, $array[3] eq fillout("", 2) ; + + # switch of partial mode + $db->partial_clear() ; + ok 150, $array[1] eq fillout("boat", $rec_len) ; + ok 151, $array[2] eq fillout("house", $rec_len) ; + ok 152, $array[3] eq fillout("sea", $rec_len) ; + + # now partial put + $db->partial_set(0,2) ; + $array[1] = "" ; + ok 153, $db->status() != 0 ; + $array[2] = "AB" ; + ok 154, $db->status() == 0 ; + $array[3] = "XY" ; + ok 155, $db->status() == 0 ; + $array[4] = "KL" ; + ok 156, $db->status() == 0 ; + + $db->partial_clear() ; + ok 157, $array[1] eq fillout("boat", $rec_len) ; + ok 158, $array[2] eq fillout("ABuse", $rec_len) ; + ok 159, $array[3] eq fillout("XYa", $rec_len) ; + ok 160, $array[4] eq fillout("KL", $rec_len) ; + + # now partial put + $db->partial_set(3,2) ; + $array[1] = "PP" ; + ok 161, $db->status() == 0 ; + $array[2] = "Q" ; + ok 162, $db->status() != 0 ; + $array[3] = "XY" ; + ok 163, $db->status() == 0 ; + $array[4] = "TU" ; + ok 164, $db->status() == 0 ; + + $db->partial_clear() ; + ok 165, $array[1] eq fillout("boaPP", $rec_len) ; + ok 166, $array[2] eq fillout("ABuse", $rec_len) ; + ok 167, $array[3] eq fillout("XYaXY", $rec_len) ; + ok 168, $array[4] eq fillout("KL TU", $rec_len) ; +} + +{ + # transaction + + my $lex = new LexFile $Dfile ; + my @array ; + my $value ; + + my $home = "./fred" ; + rmtree $home if -e $home ; + ok 169, mkdir($home, 0777) ; + my $rec_len = 9 ; + ok 170, my $env = new BerkeleyDB::Env -Home => $home, + -Flags => DB_CREATE|DB_INIT_TXN| + DB_INIT_MPOOL|DB_INIT_LOCK ; + ok 171, my $txn = $env->txn_begin() ; + ok 172, my $db1 = tie @array, 'BerkeleyDB::Queue', + -Filename => $Dfile, + -ArrayBase => 0, + -Flags => DB_CREATE , + -Env => $env, + -Txn => $txn , + -Len => $rec_len, + -Pad => " " ; + + + # create some data + my @data = ( + "boat", + "house", + "sea", + ) ; + + my $ret = 0 ; + my $i ; + for ($i = 0 ; $i < @data ; ++$i) { + $ret += $db1->db_put($i, $data[$i]) ; + } + ok 173, $ret == 0 ; + + # should be able to see all the records + + ok 174, my $cursor = $db1->db_cursor() ; + my ($k, $v) = (0, "") ; + my $count = 0 ; + # sequence forwards + while ($cursor->c_get($k, $v, DB_NEXT) == 0) { + ++ $count ; + } + ok 175, $count == 3 ; + undef $cursor ; + + # now abort the transaction + ok 176, $txn->txn_abort() == 0 ; + + # there shouldn't be any records in the database + $count = 0 ; + # sequence forwards + ok 177, $cursor = $db1->db_cursor() ; + while ($cursor->c_get($k, $v, DB_NEXT) == 0) { + ++ $count ; + } + ok 178, $count == 0 ; + + undef $txn ; + undef $cursor ; + undef $db1 ; + undef $env ; + untie @array ; + rmtree $home ; +} + + +{ + # db_stat + + my $lex = new LexFile $Dfile ; + my $recs = ($BerkeleyDB::db_version >= 3.1 ? "qs_ndata" : "qs_nrecs") ; + my @array ; + my ($k, $v) ; + my $rec_len = 7 ; + ok 179, my $db = new BerkeleyDB::Queue -Filename => $Dfile, + -Flags => DB_CREATE, + -Pagesize => 4 * 1024, + -Len => $rec_len, + -Pad => " " + ; + + my $ref = $db->db_stat() ; + ok 180, $ref->{$recs} == 0; + ok 181, $ref->{'qs_pagesize'} == 4 * 1024; + + # create some data + my @data = ( + 2, + "house", + "sea", + ) ; + + my $ret = 0 ; + my $i ; + for ($i = $db->ArrayOffset ; @data ; ++$i) { + $ret += $db->db_put($i, shift @data) ; + } + ok 182, $ret == 0 ; + + $ref = $db->db_stat() ; + ok 183, $ref->{$recs} == 3; +} + +{ + # sub-class test + + package Another ; + + use strict ; + + open(FILE, ">SubDB.pm") or die "Cannot open SubDB.pm: $!\n" ; + print FILE <<'EOM' ; + + package SubDB ; + + use strict ; + use vars qw( @ISA @EXPORT) ; + + require Exporter ; + use BerkeleyDB; + @ISA=qw(BerkeleyDB::Queue); + @EXPORT = @BerkeleyDB::EXPORT ; + + sub db_put { + my $self = shift ; + my $key = shift ; + my $value = shift ; + $self->SUPER::db_put($key, $value * 3) ; + } + + sub db_get { + my $self = shift ; + $self->SUPER::db_get($_[0], $_[1]) ; + $_[1] -= 2 ; + } + + sub A_new_method + { + my $self = shift ; + my $key = shift ; + my $value = $self->FETCH($key) ; + return "[[$value]]" ; + } + + 1 ; +EOM + + close FILE ; + + BEGIN { push @INC, '.'; } + eval 'use SubDB ; '; + main::ok 184, $@ eq "" ; + my @h ; + my $X ; + my $rec_len = 34 ; + eval ' + $X = tie(@h, "SubDB", -Filename => "dbbtree.tmp", + -Flags => DB_CREATE, + -Mode => 0640 , + -Len => $rec_len, + -Pad => " " + ); + ' ; + + main::ok 185, $@ eq "" ; + + my $ret = eval '$h[1] = 3 ; return $h[1] ' ; + main::ok 186, $@ eq "" ; + main::ok 187, $ret == 7 ; + + my $value = 0; + $ret = eval '$X->db_put(1, 4) ; $X->db_get(1, $value) ; return $value' ; + main::ok 188, $@ eq "" ; + main::ok 189, $ret == 10 ; + + $ret = eval ' DB_NEXT eq main::DB_NEXT ' ; + main::ok 190, $@ eq "" ; + main::ok 191, $ret == 1 ; + + $ret = eval '$X->A_new_method(1) ' ; + main::ok 192, $@ eq "" ; + main::ok 193, $ret eq "[[10]]" ; + + unlink "SubDB.pm", "dbbtree.tmp" ; + +} + +{ + # DB_APPEND + + my $lex = new LexFile $Dfile; + my @array ; + my $value ; + my $rec_len = 21 ; + ok 194, my $db = tie @array, 'BerkeleyDB::Queue', + -Filename => $Dfile, + -Flags => DB_CREATE , + -Len => $rec_len, + -Pad => " " ; + + # create a few records + $array[1] = "def" ; + $array[3] = "ghi" ; + + my $k = 0 ; + ok 195, $db->db_put($k, "fred", DB_APPEND) == 0 ; + ok 196, $k == 4 ; + ok 197, $array[4] eq fillout("fred", $rec_len) ; + + undef $db ; + untie @array ; +} + +__END__ + + +# TODO +# +# DB_DELIMETER DB_FIXEDLEN DB_PAD DB_SNAPSHOT with partial records diff --git a/db/perl.BerkeleyDB/t/recno.t b/db/perl.BerkeleyDB/t/recno.t new file mode 100644 index 000000000..0f210f540 --- /dev/null +++ b/db/perl.BerkeleyDB/t/recno.t @@ -0,0 +1,967 @@ +#!./perl -w + +# ID: %I%, %G% + +use strict ; + +BEGIN { + unless(grep /blib/, @INC) { + chdir 't' if -d 't'; + @INC = '../lib' if -d '../lib'; + } +} + +use BerkeleyDB; +use File::Path qw(rmtree); + +print "1..218\n"; + +my %DB_errors = ( + 'DB_INCOMPLETE' => "DB_INCOMPLETE: Sync was unable to complete", + 'DB_KEYEMPTY' => "DB_KEYEMPTY: Non-existent key/data pair", + 'DB_KEYEXIST' => "DB_KEYEXIST: Key/data pair already exists", + 'DB_LOCK_DEADLOCK' => "DB_LOCK_DEADLOCK: Locker killed to resolve a deadlock", + 'DB_LOCK_NOTGRANTED' => "DB_LOCK_NOTGRANTED: Lock not granted", + 'DB_NOTFOUND' => "DB_NOTFOUND: No matching key/data pair found", + 'DB_OLD_VERSION' => "DB_OLDVERSION: Database requires a version upgrade", + 'DB_RUNRECOVERY' => "DB_RUNRECOVERY: Fatal error, run database recovery", +) ; + +{ + package LexFile ; + + sub new + { + my $self = shift ; + unlink @_ ; + bless [ @_ ], $self ; + } + + sub DESTROY + { + my $self = shift ; + unlink @{ $self } ; + } +} + + +sub ok +{ + my $no = shift ; + my $result = shift ; + + print "not " unless $result ; + print "ok $no\n" ; +} + +sub docat +{ + my $file = shift; + local $/ = undef; + open(CAT,$file) || die "Cannot open $file:$!"; + my $result = ; + close(CAT); + return $result; +} + +sub touch +{ + my $file = shift ; + open(CAT,">$file") || die "Cannot open $file:$!"; + close(CAT); +} + +sub joiner +{ + my $db = shift ; + my $sep = shift ; + my ($k, $v) = (0, "") ; + my @data = () ; + + my $cursor = $db->db_cursor() or return () ; + for ( my $status = $cursor->c_get($k, $v, DB_FIRST) ; + $status == 0 ; + $status = $cursor->c_get($k, $v, DB_NEXT)) { + push @data, $v ; + } + + (scalar(@data), join($sep, @data)) ; +} + +sub countRecords +{ + my $db = shift ; + my ($k, $v) = (0,0) ; + my ($count) = 0 ; + my ($cursor) = $db->db_cursor() ; + #for ($status = $cursor->c_get($k, $v, DB_FIRST) ; +# $status == 0 ; +# $status = $cursor->c_get($k, $v, DB_NEXT) ) + while ($cursor->c_get($k, $v, DB_NEXT) == 0) + { ++ $count } + + return $count ; +} + +my $Dfile = "dbhash.tmp"; +my $Dfile2 = "dbhash2.tmp"; +my $Dfile3 = "dbhash3.tmp"; +unlink $Dfile; + +umask(0) ; + + +# Check for invalid parameters +{ + # Check for invalid parameters + my $db ; + eval ' $db = new BerkeleyDB::Recno -Stupid => 3 ; ' ; + ok 1, $@ =~ /unknown key value\(s\) Stupid/ ; + + eval ' $db = new BerkeleyDB::Recno -Bad => 2, -Mode => 0345, -Stupid => 3; ' ; + ok 2, $@ =~ /unknown key value\(s\) / ; + + eval ' $db = new BerkeleyDB::Recno -Env => 2 ' ; + ok 3, $@ =~ /^Env not of type BerkeleyDB::Env/ ; + + eval ' $db = new BerkeleyDB::Recno -Txn => "x" ' ; + ok 4, $@ =~ /^Txn not of type BerkeleyDB::Txn/ ; + + my $obj = bless [], "main" ; + eval ' $db = new BerkeleyDB::Recno -Env => $obj ' ; + ok 5, $@ =~ /^Env not of type BerkeleyDB::Env/ ; +} + +# Now check the interface to Recno + +{ + my $lex = new LexFile $Dfile ; + + ok 6, my $db = new BerkeleyDB::Recno -Filename => $Dfile, + -Flags => DB_CREATE ; + + # Add a k/v pair + my $value ; + my $status ; + ok 7, $db->db_put(1, "some value") == 0 ; + ok 8, $db->status() == 0 ; + ok 9, $db->db_get(1, $value) == 0 ; + ok 10, $value eq "some value" ; + ok 11, $db->db_put(2, "value") == 0 ; + ok 12, $db->db_get(2, $value) == 0 ; + ok 13, $value eq "value" ; + ok 14, $db->db_del(1) == 0 ; + ok 15, ($status = $db->db_get(1, $value)) == DB_KEYEMPTY ; + ok 16, $db->status() == DB_KEYEMPTY ; + ok 17, $db->status() eq $DB_errors{'DB_KEYEMPTY'} ; + + ok 18, ($status = $db->db_get(7, $value)) == DB_NOTFOUND ; + ok 19, $db->status() == DB_NOTFOUND ; + ok 20, $db->status() eq $DB_errors{'DB_NOTFOUND'} ; + + ok 21, $db->db_sync() == 0 ; + + # Check NOOVERWRITE will make put fail when attempting to overwrite + # an existing record. + + ok 22, $db->db_put( 2, 'x', DB_NOOVERWRITE) == DB_KEYEXIST ; + ok 23, $db->status() eq $DB_errors{'DB_KEYEXIST'} ; + ok 24, $db->status() == DB_KEYEXIST ; + + + # check that the value of the key has not been changed by the + # previous test + ok 25, $db->db_get(2, $value) == 0 ; + ok 26, $value eq "value" ; + + +} + + +{ + # Check simple env works with a array. + my $lex = new LexFile $Dfile ; + + my $home = "./fred" ; + ok 27, -d $home ? chmod 0777, $home : mkdir($home, 0777) ; + + ok 28, my $env = new BerkeleyDB::Env -Flags => DB_CREATE|DB_INIT_MPOOL, + -Home => $home ; + + ok 29, my $db = new BerkeleyDB::Recno -Filename => $Dfile, + -Env => $env, + -Flags => DB_CREATE ; + + # Add a k/v pair + my $value ; + ok 30, $db->db_put(1, "some value") == 0 ; + ok 31, $db->db_get(1, $value) == 0 ; + ok 32, $value eq "some value" ; + undef $db ; + undef $env ; + rmtree $home ; +} + + +{ + # cursors + + my $lex = new LexFile $Dfile ; + my @array ; + my ($k, $v) ; + ok 33, my $db = new BerkeleyDB::Recno -Filename => $Dfile, + -ArrayBase => 0, + -Flags => DB_CREATE ; + + # create some data + my @data = ( + "red" , + "green" , + "blue" , + ) ; + + my $i ; + my %data ; + my $ret = 0 ; + for ($i = 0 ; $i < @data ; ++$i) { + $ret += $db->db_put($i, $data[$i]) ; + $data{$i} = $data[$i] ; + } + ok 34, $ret == 0 ; + + # create the cursor + ok 35, my $cursor = $db->db_cursor() ; + + $k = 0 ; $v = "" ; + my %copy = %data; + my $extras = 0 ; + # sequence forwards + while ($cursor->c_get($k, $v, DB_NEXT) == 0) + { + if ( $copy{$k} eq $v ) + { delete $copy{$k} } + else + { ++ $extras } + } + + ok 36, $cursor->status() == DB_NOTFOUND ; + ok 37, $cursor->status() eq $DB_errors{'DB_NOTFOUND'} ; + ok 38, keys %copy == 0 ; + ok 39, $extras == 0 ; + + # sequence backwards + %copy = %data ; + $extras = 0 ; + my $status ; + for ( $status = $cursor->c_get($k, $v, DB_LAST) ; + $status == 0 ; + $status = $cursor->c_get($k, $v, DB_PREV)) { + if ( $copy{$k} eq $v ) + { delete $copy{$k} } + else + { ++ $extras } + } + ok 40, $status == DB_NOTFOUND ; + ok 41, $status eq $DB_errors{'DB_NOTFOUND'} ; + ok 42, $cursor->status() == $status ; + ok 43, $cursor->status() eq $status ; + ok 44, keys %copy == 0 ; + ok 45, $extras == 0 ; +} + +{ + # Tied Array interface + + # full tied array support started in Perl 5.004_57 + # just double check. + my $FA = 0 ; + { + sub try::TIEARRAY { bless [], "try" } + sub try::FETCHSIZE { $FA = 1 } + my @a ; + tie @a, 'try' ; + my $a = @a ; + } + + my $lex = new LexFile $Dfile ; + my @array ; + my $db ; + ok 46, $db = tie @array, 'BerkeleyDB::Recno', -Filename => $Dfile, + -Property => DB_RENUMBER, + -ArrayBase => 0, + -Flags => DB_CREATE ; + + ok 47, my $cursor = (tied @array)->db_cursor() ; + # check the database is empty + my $count = 0 ; + my ($k, $v) = (0,"") ; + while ($cursor->c_get($k, $v, DB_NEXT) == 0) { + ++ $count ; + } + ok 48, $cursor->status() == DB_NOTFOUND ; + ok 49, $count == 0 ; + + ok 50, @array == 0 ; + + # Add a k/v pair + my $value ; + $array[1] = "some value"; + ok 51, (tied @array)->status() == 0 ; + ok 52, $array[1] eq "some value"; + ok 53, defined $array[1]; + ok 54, (tied @array)->status() == 0 ; + ok 55, !defined $array[3]; + ok 56, (tied @array)->status() == DB_NOTFOUND ; + + ok 57, (tied @array)->db_del(1) == 0 ; + ok 58, (tied @array)->status() == 0 ; + ok 59, ! defined $array[1]; + ok 60, (tied @array)->status() == DB_NOTFOUND ; + + $array[1] = 2 ; + $array[10] = 20 ; + $array[1000] = 2000 ; + + my ($keys, $values) = (0,0); + $count = 0 ; + for ( my $status = $cursor->c_get($k, $v, DB_FIRST) ; + $status == 0 ; + $status = $cursor->c_get($k, $v, DB_NEXT)) { + $keys += $k ; + $values += $v ; + ++ $count ; + } + ok 61, $count == 3 ; + ok 62, $keys == 1011 ; + ok 63, $values == 2022 ; + + # unshift + $FA ? unshift @array, "red", "green", "blue" + : $db->unshift("red", "green", "blue" ) ; + ok 64, $array[1] eq "red" ; + ok 65, $cursor->c_get($k, $v, DB_FIRST) == 0 ; + ok 66, $k == 1 ; + ok 67, $v eq "red" ; + ok 68, $array[2] eq "green" ; + ok 69, $cursor->c_get($k, $v, DB_NEXT) == 0 ; + ok 70, $k == 2 ; + ok 71, $v eq "green" ; + ok 72, $array[3] eq "blue" ; + ok 73, $cursor->c_get($k, $v, DB_NEXT) == 0 ; + ok 74, $k == 3 ; + ok 75, $v eq "blue" ; + ok 76, $array[4] == 2 ; + ok 77, $cursor->c_get($k, $v, DB_NEXT) == 0 ; + ok 78, $k == 4 ; + ok 79, $v == 2 ; + + # shift + ok 80, ($FA ? shift @array : $db->shift()) eq "red" ; + ok 81, ($FA ? shift @array : $db->shift()) eq "green" ; + ok 82, ($FA ? shift @array : $db->shift()) eq "blue" ; + ok 83, ($FA ? shift @array : $db->shift()) == 2 ; + + # push + $FA ? push @array, "the", "end" + : $db->push("the", "end") ; + ok 84, $cursor->c_get($k, $v, DB_LAST) == 0 ; + ok 85, $k == 1001 ; + ok 86, $v eq "end" ; + ok 87, $cursor->c_get($k, $v, DB_PREV) == 0 ; + ok 88, $k == 1000 ; + ok 89, $v eq "the" ; + ok 90, $cursor->c_get($k, $v, DB_PREV) == 0 ; + ok 91, $k == 999 ; + ok 92, $v == 2000 ; + + # pop + ok 93, ( $FA ? pop @array : $db->pop ) eq "end" ; + ok 94, ( $FA ? pop @array : $db->pop ) eq "the" ; + ok 95, ( $FA ? pop @array : $db->pop ) == 2000 ; + + # now clear the array + $FA ? @array = () + : $db->clear() ; + ok 96, $cursor->c_get($k, $v, DB_FIRST) == DB_NOTFOUND ; + + undef $cursor ; + undef $db ; + untie @array ; +} + +{ + # in-memory file + + my @array ; + my $fd ; + my $value ; + ok 97, my $db = tie @array, 'BerkeleyDB::Recno' ; + + ok 98, $db->db_put(1, "some value") == 0 ; + ok 99, $db->db_get(1, $value) == 0 ; + ok 100, $value eq "some value" ; + +} + +{ + # partial + # check works via API + + my $lex = new LexFile $Dfile ; + my $value ; + ok 101, my $db = new BerkeleyDB::Recno, -Filename => $Dfile, + -Flags => DB_CREATE ; + + # create some data + my @data = ( + "", + "boat", + "house", + "sea", + ) ; + + my $ret = 0 ; + my $i ; + for ($i = 1 ; $i < @data ; ++$i) { + $ret += $db->db_put($i, $data[$i]) ; + } + ok 102, $ret == 0 ; + + + # do a partial get + my ($pon, $off, $len) = $db->partial_set(0,2) ; + ok 103, ! $pon && $off == 0 && $len == 0 ; + ok 104, $db->db_get(1, $value) == 0 && $value eq "bo" ; + ok 105, $db->db_get(2, $value) == 0 && $value eq "ho" ; + ok 106, $db->db_get(3, $value) == 0 && $value eq "se" ; + + # do a partial get, off end of data + ($pon, $off, $len) = $db->partial_set(3,2) ; + ok 107, $pon ; + ok 108, $off == 0 ; + ok 109, $len == 2 ; + ok 110, $db->db_get(1, $value) == 0 && $value eq "t" ; + ok 111, $db->db_get(2, $value) == 0 && $value eq "se" ; + ok 112, $db->db_get(3, $value) == 0 && $value eq "" ; + + # switch of partial mode + ($pon, $off, $len) = $db->partial_clear() ; + ok 113, $pon ; + ok 114, $off == 3 ; + ok 115, $len == 2 ; + ok 116, $db->db_get(1, $value) == 0 && $value eq "boat" ; + ok 117, $db->db_get(2, $value) == 0 && $value eq "house" ; + ok 118, $db->db_get(3, $value) == 0 && $value eq "sea" ; + + # now partial put + $db->partial_set(0,2) ; + ok 119, $db->db_put(1, "") == 0 ; + ok 120, $db->db_put(2, "AB") == 0 ; + ok 121, $db->db_put(3, "XYZ") == 0 ; + ok 122, $db->db_put(4, "KLM") == 0 ; + + ($pon, $off, $len) = $db->partial_clear() ; + ok 123, $pon ; + ok 124, $off == 0 ; + ok 125, $len == 2 ; + ok 126, $db->db_get(1, $value) == 0 && $value eq "at" ; + ok 127, $db->db_get(2, $value) == 0 && $value eq "ABuse" ; + ok 128, $db->db_get(3, $value) == 0 && $value eq "XYZa" ; + ok 129, $db->db_get(4, $value) == 0 && $value eq "KLM" ; + + # now partial put + ($pon, $off, $len) = $db->partial_set(3,2) ; + ok 130, ! $pon ; + ok 131, $off == 0 ; + ok 132, $len == 0 ; + ok 133, $db->db_put(1, "PPP") == 0 ; + ok 134, $db->db_put(2, "Q") == 0 ; + ok 135, $db->db_put(3, "XYZ") == 0 ; + ok 136, $db->db_put(4, "TU") == 0 ; + + $db->partial_clear() ; + ok 137, $db->db_get(1, $value) == 0 && $value eq "at\0PPP" ; + ok 138, $db->db_get(2, $value) == 0 && $value eq "ABuQ" ; + ok 139, $db->db_get(3, $value) == 0 && $value eq "XYZXYZ" ; + ok 140, $db->db_get(4, $value) == 0 && $value eq "KLMTU" ; +} + +{ + # partial + # check works via tied array + + my $lex = new LexFile $Dfile ; + my @array ; + my $value ; + ok 141, my $db = tie @array, 'BerkeleyDB::Recno', -Filename => $Dfile, + -Flags => DB_CREATE ; + + # create some data + my @data = ( + "", + "boat", + "house", + "sea", + ) ; + + my $i ; + for ($i = 1 ; $i < @data ; ++$i) { + $array[$i] = $data[$i] ; + } + + + # do a partial get + $db->partial_set(0,2) ; + ok 142, $array[1] eq "bo" ; + ok 143, $array[2] eq "ho" ; + ok 144, $array[3] eq "se" ; + + # do a partial get, off end of data + $db->partial_set(3,2) ; + ok 145, $array[1] eq "t" ; + ok 146, $array[2] eq "se" ; + ok 147, $array[3] eq "" ; + + # switch of partial mode + $db->partial_clear() ; + ok 148, $array[1] eq "boat" ; + ok 149, $array[2] eq "house" ; + ok 150, $array[3] eq "sea" ; + + # now partial put + $db->partial_set(0,2) ; + ok 151, $array[1] = "" ; + ok 152, $array[2] = "AB" ; + ok 153, $array[3] = "XYZ" ; + ok 154, $array[4] = "KLM" ; + + $db->partial_clear() ; + ok 155, $array[1] eq "at" ; + ok 156, $array[2] eq "ABuse" ; + ok 157, $array[3] eq "XYZa" ; + ok 158, $array[4] eq "KLM" ; + + # now partial put + $db->partial_set(3,2) ; + ok 159, $array[1] = "PPP" ; + ok 160, $array[2] = "Q" ; + ok 161, $array[3] = "XYZ" ; + ok 162, $array[4] = "TU" ; + + $db->partial_clear() ; + ok 163, $array[1] eq "at\0PPP" ; + ok 164, $array[2] eq "ABuQ" ; + ok 165, $array[3] eq "XYZXYZ" ; + ok 166, $array[4] eq "KLMTU" ; +} + +{ + # transaction + + my $lex = new LexFile $Dfile ; + my @array ; + my $value ; + + my $home = "./fred" ; + rmtree $home if -e $home ; + ok 167, mkdir($home, 0777) ; + ok 168, my $env = new BerkeleyDB::Env -Home => $home, + -Flags => DB_CREATE|DB_INIT_TXN| + DB_INIT_MPOOL|DB_INIT_LOCK ; + ok 169, my $txn = $env->txn_begin() ; + ok 170, my $db1 = tie @array, 'BerkeleyDB::Recno', + -Filename => $Dfile, + -ArrayBase => 0, + -Flags => DB_CREATE , + -Env => $env, + -Txn => $txn ; + + + # create some data + my @data = ( + "boat", + "house", + "sea", + ) ; + + my $ret = 0 ; + my $i ; + for ($i = 0 ; $i < @data ; ++$i) { + $ret += $db1->db_put($i, $data[$i]) ; + } + ok 171, $ret == 0 ; + + # should be able to see all the records + + ok 172, my $cursor = $db1->db_cursor() ; + my ($k, $v) = (0, "") ; + my $count = 0 ; + # sequence forwards + while ($cursor->c_get($k, $v, DB_NEXT) == 0) { + ++ $count ; + } + ok 173, $count == 3 ; + undef $cursor ; + + # now abort the transaction + ok 174, $txn->txn_abort() == 0 ; + + # there shouldn't be any records in the database + $count = 0 ; + # sequence forwards + ok 175, $cursor = $db1->db_cursor() ; + while ($cursor->c_get($k, $v, DB_NEXT) == 0) { + ++ $count ; + } + ok 176, $count == 0 ; + + undef $txn ; + undef $cursor ; + undef $db1 ; + undef $env ; + untie @array ; + rmtree $home ; +} + + +{ + # db_stat + + my $lex = new LexFile $Dfile ; + my $recs = ($BerkeleyDB::db_version >= 3.1 ? "bt_ndata" : "bt_nrecs") ; + my @array ; + my ($k, $v) ; + ok 177, my $db = new BerkeleyDB::Recno -Filename => $Dfile, + -Flags => DB_CREATE, + -Pagesize => 4 * 1024, + ; + + my $ref = $db->db_stat() ; + ok 178, $ref->{$recs} == 0; + ok 179, $ref->{'bt_pagesize'} == 4 * 1024; + + # create some data + my @data = ( + 2, + "house", + "sea", + ) ; + + my $ret = 0 ; + my $i ; + for ($i = $db->ArrayOffset ; @data ; ++$i) { + $ret += $db->db_put($i, shift @data) ; + } + ok 180, $ret == 0 ; + + $ref = $db->db_stat() ; + ok 181, $ref->{$recs} == 3; +} + +{ + # sub-class test + + package Another ; + + use strict ; + + open(FILE, ">SubDB.pm") or die "Cannot open SubDB.pm: $!\n" ; + print FILE <<'EOM' ; + + package SubDB ; + + use strict ; + use vars qw( @ISA @EXPORT) ; + + require Exporter ; + use BerkeleyDB; + @ISA=qw(BerkeleyDB::Recno); + @EXPORT = @BerkeleyDB::EXPORT ; + + sub db_put { + my $self = shift ; + my $key = shift ; + my $value = shift ; + $self->SUPER::db_put($key, $value * 3) ; + } + + sub db_get { + my $self = shift ; + $self->SUPER::db_get($_[0], $_[1]) ; + $_[1] -= 2 ; + } + + sub A_new_method + { + my $self = shift ; + my $key = shift ; + my $value = $self->FETCH($key) ; + return "[[$value]]" ; + } + + 1 ; +EOM + + close FILE ; + + BEGIN { push @INC, '.'; } + eval 'use SubDB ; '; + main::ok 182, $@ eq "" ; + my @h ; + my $X ; + eval ' + $X = tie(@h, "SubDB", -Filename => "dbbtree.tmp", + -Flags => DB_CREATE, + -Mode => 0640 ); + ' ; + + main::ok 183, $@ eq "" ; + + my $ret = eval '$h[1] = 3 ; return $h[1] ' ; + main::ok 184, $@ eq "" ; + main::ok 185, $ret == 7 ; + + my $value = 0; + $ret = eval '$X->db_put(1, 4) ; $X->db_get(1, $value) ; return $value' ; + main::ok 186, $@ eq "" ; + main::ok 187, $ret == 10 ; + + $ret = eval ' DB_NEXT eq main::DB_NEXT ' ; + main::ok 188, $@ eq "" ; + main::ok 189, $ret == 1 ; + + $ret = eval '$X->A_new_method(1) ' ; + main::ok 190, $@ eq "" ; + main::ok 191, $ret eq "[[10]]" ; + + unlink "SubDB.pm", "dbbtree.tmp" ; + +} + +{ + # variable length records, DB_DELIMETER -- defaults to \n + + my $lex = new LexFile $Dfile, $Dfile2 ; + touch $Dfile2 ; + my @array ; + my $value ; + ok 192, tie @array, 'BerkeleyDB::Recno', -Filename => $Dfile, + -ArrayBase => 0, + -Flags => DB_CREATE , + -Source => $Dfile2 ; + $array[0] = "abc" ; + $array[1] = "def" ; + $array[3] = "ghi" ; + untie @array ; + + my $x = docat($Dfile2) ; + ok 193, $x eq "abc\ndef\n\nghi\n" ; +} + +{ + # variable length records, change DB_DELIMETER + + my $lex = new LexFile $Dfile, $Dfile2 ; + touch $Dfile2 ; + my @array ; + my $value ; + ok 194, tie @array, 'BerkeleyDB::Recno', -Filename => $Dfile, + -ArrayBase => 0, + -Flags => DB_CREATE , + -Source => $Dfile2 , + -Delim => "-"; + $array[0] = "abc" ; + $array[1] = "def" ; + $array[3] = "ghi" ; + untie @array ; + + my $x = docat($Dfile2) ; + ok 195, $x eq "abc-def--ghi-"; +} + +{ + # fixed length records, default DB_PAD + + my $lex = new LexFile $Dfile, $Dfile2 ; + touch $Dfile2 ; + my @array ; + my $value ; + ok 196, tie @array, 'BerkeleyDB::Recno', -Filename => $Dfile, + -ArrayBase => 0, + -Flags => DB_CREATE , + -Len => 5, + -Source => $Dfile2 ; + $array[0] = "abc" ; + $array[1] = "def" ; + $array[3] = "ghi" ; + untie @array ; + + my $x = docat($Dfile2) ; + ok 197, $x eq "abc def ghi " ; +} + +{ + # fixed length records, change Pad + + my $lex = new LexFile $Dfile, $Dfile2 ; + touch $Dfile2 ; + my @array ; + my $value ; + ok 198, tie @array, 'BerkeleyDB::Recno', -Filename => $Dfile, + -ArrayBase => 0, + -Flags => DB_CREATE , + -Len => 5, + -Pad => "-", + -Source => $Dfile2 ; + $array[0] = "abc" ; + $array[1] = "def" ; + $array[3] = "ghi" ; + untie @array ; + + my $x = docat($Dfile2) ; + ok 199, $x eq "abc--def-------ghi--" ; +} + +{ + # DB_RENUMBER + + my $lex = new LexFile $Dfile; + my @array ; + my $value ; + ok 200, my $db = tie @array, 'BerkeleyDB::Recno', -Filename => $Dfile, + -Property => DB_RENUMBER, + -ArrayBase => 0, + -Flags => DB_CREATE ; + # create a few records + $array[0] = "abc" ; + $array[1] = "def" ; + $array[3] = "ghi" ; + + ok 201, my ($length, $joined) = joiner($db, "|") ; + ok 202, $length == 3 ; + ok 203, $joined eq "abc|def|ghi"; + + ok 204, $db->db_del(1) == 0 ; + ok 205, ($length, $joined) = joiner($db, "|") ; + ok 206, $length == 2 ; + ok 207, $joined eq "abc|ghi"; + + undef $db ; + untie @array ; + +} + +{ + # DB_APPEND + + my $lex = new LexFile $Dfile; + my @array ; + my $value ; + ok 208, my $db = tie @array, 'BerkeleyDB::Recno', + -Filename => $Dfile, + -Flags => DB_CREATE ; + + # create a few records + $array[1] = "def" ; + $array[3] = "ghi" ; + + my $k = 0 ; + ok 209, $db->db_put($k, "fred", DB_APPEND) == 0 ; + ok 210, $k == 4 ; + + undef $db ; + untie @array ; +} + +{ + # in-memory Btree with an associated text file + + my $lex = new LexFile $Dfile2 ; + touch $Dfile2 ; + my @array ; + my $value ; + ok 211, tie @array, 'BerkeleyDB::Recno', -Source => $Dfile2 , + -ArrayBase => 0, + -Property => DB_RENUMBER, + -Flags => DB_CREATE ; + $array[0] = "abc" ; + $array[1] = "def" ; + $array[3] = "ghi" ; + untie @array ; + + my $x = docat($Dfile2) ; + ok 212, $x eq "abc\ndef\n\nghi\n" ; +} + +{ + # in-memory, variable length records, change DB_DELIMETER + + my $lex = new LexFile $Dfile, $Dfile2 ; + touch $Dfile2 ; + my @array ; + my $value ; + ok 213, tie @array, 'BerkeleyDB::Recno', + -ArrayBase => 0, + -Flags => DB_CREATE , + -Source => $Dfile2 , + -Property => DB_RENUMBER, + -Delim => "-"; + $array[0] = "abc" ; + $array[1] = "def" ; + $array[3] = "ghi" ; + untie @array ; + + my $x = docat($Dfile2) ; + ok 214, $x eq "abc-def--ghi-"; +} + +{ + # in-memory, fixed length records, default DB_PAD + + my $lex = new LexFile $Dfile, $Dfile2 ; + touch $Dfile2 ; + my @array ; + my $value ; + ok 215, tie @array, 'BerkeleyDB::Recno', -ArrayBase => 0, + -Flags => DB_CREATE , + -Property => DB_RENUMBER, + -Len => 5, + -Source => $Dfile2 ; + $array[0] = "abc" ; + $array[1] = "def" ; + $array[3] = "ghi" ; + untie @array ; + + my $x = docat($Dfile2) ; + ok 216, $x eq "abc def ghi " ; +} + +{ + # in-memory, fixed length records, change Pad + + my $lex = new LexFile $Dfile, $Dfile2 ; + touch $Dfile2 ; + my @array ; + my $value ; + ok 217, tie @array, 'BerkeleyDB::Recno', + -ArrayBase => 0, + -Flags => DB_CREATE , + -Property => DB_RENUMBER, + -Len => 5, + -Pad => "-", + -Source => $Dfile2 ; + $array[0] = "abc" ; + $array[1] = "def" ; + $array[3] = "ghi" ; + untie @array ; + + my $x = docat($Dfile2) ; + ok 218, $x eq "abc--def-------ghi--" ; +} + +__END__ + + +# TODO +# +# DB_DELIMETER DB_FIXEDLEN DB_PAD DB_SNAPSHOT with partial records diff --git a/db/perl.BerkeleyDB/t/strict.t b/db/perl.BerkeleyDB/t/strict.t new file mode 100644 index 000000000..0a856bbb1 --- /dev/null +++ b/db/perl.BerkeleyDB/t/strict.t @@ -0,0 +1,220 @@ +#!./perl -w + +use strict ; + +BEGIN { + unless(grep /blib/, @INC) { + chdir 't' if -d 't'; + @INC = '../lib' if -d '../lib'; + } +} + +use BerkeleyDB; +use File::Path qw(rmtree); + +print "1..44\n"; + + +{ + package LexFile ; + + sub new + { + my $self = shift ; + unlink @_ ; + bless [ @_ ], $self ; + } + + sub DESTROY + { + my $self = shift ; + unlink @{ $self } ; + } +} + +sub ok +{ + my $no = shift ; + my $result = shift ; + + print "not " unless $result ; + print "ok $no\n" ; +} + +sub docat +{ + my $file = shift; + local $/ = undef; + open(CAT,$file) || die "Cannot open $file:$!"; + my $result = ; + close(CAT); + return $result; +} + + +my $Dfile = "dbhash.tmp"; +my $home = "./fred" ; + +umask(0); + +{ + # closing a database & an environment in the correct order. + my $lex = new LexFile $Dfile ; + my %hash ; + my $status ; + + rmtree $home if -e $home ; + ok 1, mkdir($home, 0777) ; + ok 2, my $env = new BerkeleyDB::Env -Home => $home, + -Flags => DB_CREATE|DB_INIT_TXN| + DB_INIT_MPOOL|DB_INIT_LOCK ; + + ok 3, my $db1 = tie %hash, 'BerkeleyDB::Hash', -Filename => $Dfile, + -Flags => DB_CREATE , + -Env => $env; + + ok 4, $db1->db_close() == 0 ; + + eval { $status = $env->db_appexit() ; } ; + ok 5, $status == 0 ; + ok 6, $@ eq "" ; + #print "[$@]\n" ; + + rmtree $home if -e $home ; +} + +{ + # closing an environment with an open database + my $lex = new LexFile $Dfile ; + my %hash ; + + rmtree $home if -e $home ; + ok 7, mkdir($home, 0777) ; + ok 8, my $env = new BerkeleyDB::Env -Home => $home, + -Flags => DB_CREATE|DB_INIT_TXN| + DB_INIT_MPOOL|DB_INIT_LOCK ; + + ok 9, my $db1 = tie %hash, 'BerkeleyDB::Hash', -Filename => $Dfile, + -Flags => DB_CREATE , + -Env => $env; + + eval { $env->db_appexit() ; } ; + ok 10, $@ =~ /BerkeleyDB Aborting: attempted to close an environment with 1 open database/ ; + #print "[$@]\n" ; + + undef $db1 ; + untie %hash ; + undef $env ; + rmtree $home if -e $home ; +} + +{ + # closing a transaction & a database + my $lex = new LexFile $Dfile ; + my %hash ; + my $status ; + + rmtree $home if -e $home ; + ok 11, mkdir($home, 0777) ; + ok 12, my $env = new BerkeleyDB::Env -Home => $home, + -Flags => DB_CREATE|DB_INIT_TXN| + DB_INIT_MPOOL|DB_INIT_LOCK ; + + ok 13, my $txn = $env->txn_begin() ; + ok 14, my $db = tie %hash, 'BerkeleyDB::Hash', -Filename => $Dfile, + -Flags => DB_CREATE , + -Env => $env, + -Txn => $txn ; + + ok 15, $txn->txn_commit() == 0 ; + eval { $status = $db->db_close() ; } ; + ok 16, $status == 0 ; + ok 17, $@ eq "" ; + eval { $status = $env->db_appexit() ; } ; + ok 18, $status == 0 ; + ok 19, $@ eq "" ; + #print "[$@]\n" ; +} + +{ + # closing a database with an open transaction + my $lex = new LexFile $Dfile ; + my %hash ; + + rmtree $home if -e $home ; + ok 20, mkdir($home, 0777) ; + ok 21, my $env = new BerkeleyDB::Env -Home => $home, + -Flags => DB_CREATE|DB_INIT_TXN| + DB_INIT_MPOOL|DB_INIT_LOCK ; + + ok 22, my $txn = $env->txn_begin() ; + ok 23, my $db = tie %hash, 'BerkeleyDB::Hash', -Filename => $Dfile, + -Flags => DB_CREATE , + -Env => $env, + -Txn => $txn ; + + eval { $db->db_close() ; } ; + ok 24, $@ =~ /BerkeleyDB Aborting: attempted to close a database while a transaction was still open at/ ; + #print "[$@]\n" ; +} + +{ + # closing a cursor & a database + my $lex = new LexFile $Dfile ; + my %hash ; + my $status ; + ok 25, my $db = tie %hash, 'BerkeleyDB::Hash', -Filename => $Dfile, + -Flags => DB_CREATE ; + ok 26, my $cursor = $db->db_cursor() ; + ok 27, $cursor->c_close() == 0 ; + eval { $status = $db->db_close() ; } ; + ok 28, $status == 0 ; + ok 29, $@ eq "" ; + #print "[$@]\n" ; + rmtree $home if -e $home ; +} + +{ + # closing a database with an open cursor + my $lex = new LexFile $Dfile ; + my %hash ; + ok 30, my $db = tie %hash, 'BerkeleyDB::Hash', -Filename => $Dfile, + -Flags => DB_CREATE ; + ok 31, my $cursor = $db->db_cursor() ; + eval { $db->db_close() ; } ; + ok 32, $@ =~ /\QBerkeleyDB Aborting: attempted to close a database with 1 open cursor(s) at/; + #print "[$@]\n" ; + rmtree $home if -e $home ; +} + +{ + # closing a transaction & a cursor + my $lex = new LexFile $Dfile ; + my %hash ; + my $status ; + + rmtree $home if -e $home ; + ok 33, mkdir($home, 0777) ; + ok 34, my $env = new BerkeleyDB::Env -Home => $home, + -Flags => DB_CREATE|DB_INIT_TXN| + DB_INIT_MPOOL|DB_INIT_LOCK ; + ok 35, my $txn = $env->txn_begin() ; + ok 36, my $db = tie %hash, 'BerkeleyDB::Hash', -Filename => $Dfile, + -Flags => DB_CREATE , + -Env => $env, + -Txn => $txn ; + ok 37, my $cursor = $db->db_cursor() ; + eval { $status = $cursor->c_close() ; } ; + ok 38, $status == 0 ; + ok 39, ($status = $txn->txn_commit()) == 0 ; + ok 40, $@ eq "" ; + eval { $status = $db->db_close() ; } ; + ok 41, $status == 0 ; + ok 42, $@ eq "" ; + eval { $status = $env->db_appexit() ; } ; + ok 43, $status == 0 ; + ok 44, $@ eq "" ; + #print "[$@]\n" ; + rmtree $home if -e $home ; +} + diff --git a/db/perl.BerkeleyDB/t/subdb.t b/db/perl.BerkeleyDB/t/subdb.t new file mode 100644 index 000000000..290e5d691 --- /dev/null +++ b/db/perl.BerkeleyDB/t/subdb.t @@ -0,0 +1,296 @@ +#!./perl -w + +use strict ; + +BEGIN { + unless(grep /blib/, @INC) { + chdir 't' if -d 't'; + @INC = '../lib' if -d '../lib'; + } +} + +use BerkeleyDB; +use File::Path qw(rmtree); + +BEGIN +{ + if ($BerkeleyDB::db_version < 3) { + print "1..0 # Skipping test, this needs Berkeley DB 3.x or better\n" ; + exit 0 ; + } +} + +print "1..43\n"; + +my %DB_errors = ( + 'DB_INCOMPLETE' => "DB_INCOMPLETE: Sync was unable to complete", + 'DB_KEYEMPTY' => "DB_KEYEMPTY: Non-existent key/data pair", + 'DB_KEYEXIST' => "DB_KEYEXIST: Key/data pair already exists", + 'DB_LOCK_DEADLOCK' => "DB_LOCK_DEADLOCK: Locker killed to resolve a deadlock", + 'DB_LOCK_NOTGRANTED' => "DB_LOCK_NOTGRANTED: Lock not granted", + 'DB_NOTFOUND' => "DB_NOTFOUND: No matching key/data pair found", + 'DB_OLD_VERSION' => "DB_OLDVERSION: Database requires a version upgrade", + 'DB_RUNRECOVERY' => "DB_RUNRECOVERY: Fatal error, run database recovery", + ) ; + +{ + package LexFile ; + + sub new + { + my $self = shift ; + unlink @_ ; + bless [ @_ ], $self ; + } + + sub DESTROY + { + my $self = shift ; + unlink @{ $self } ; + } +} + + +sub ok +{ + my $no = shift ; + my $result = shift ; + + print "not " unless $result ; + print "ok $no\n" ; +} + +sub addData +{ + my $db = shift ; + my @data = @_ ; + die "addData odd data\n" unless @data /2 != 0 ; + my ($k, $v) ; + my $ret = 0 ; + while (@data) { + $k = shift @data ; + $v = shift @data ; + $ret += $db->db_put($k, $v) ; + } + + return ($ret == 0) ; +} + +my $Dfile = "dbhash.tmp"; +my $Dfile2 = "dbhash2.tmp"; +my $Dfile3 = "dbhash3.tmp"; +unlink $Dfile; + +umask(0) ; + +# Berkeley DB 3.x specific functionality + +# Check for invalid parameters +{ + # Check for invalid parameters + my $db ; + eval ' BerkeleyDB::db_remove -Stupid => 3 ; ' ; + ok 1, $@ =~ /unknown key value\(s\) Stupid/ ; + + eval ' BerkeleyDB::db_remove -Bad => 2, -Filename => "fred", -Stupid => 3; ' ; + ok 2, $@ =~ /unknown key value\(s\) (Bad |Stupid ){2}/ ; + + eval ' BerkeleyDB::db_remove -Filename => "a", -Env => 2 ' ; + ok 3, $@ =~ /^Env not of type BerkeleyDB::Env/ ; + + eval ' BerkeleyDB::db_remove -Subname => "a"' ; + ok 4, $@ =~ /^Must specify a filename/ ; + + my $obj = bless [], "main" ; + eval ' BerkeleyDB::db_remove -Filename => "x", -Env => $obj ' ; + ok 5, $@ =~ /^Env not of type BerkeleyDB::Env/ ; +} + +{ + # subdatabases + + # opening a subdatabse in an exsiting database that doesn't have + # subdatabases at all should fail + + my $lex = new LexFile $Dfile ; + + ok 6, my $db = new BerkeleyDB::Hash -Filename => $Dfile, + -Flags => DB_CREATE ; + + # Add a k/v pair + my %data = qw( + red sky + blue sea + black heart + yellow belley + green grass + ) ; + + ok 7, addData($db, %data) ; + + undef $db ; + + $db = new BerkeleyDB::Hash -Filename => $Dfile, + -Subname => "fred" ; + ok 8, ! $db ; + + ok 9, -e $Dfile ; + ok 10, ! BerkeleyDB::db_remove(-Filename => $Dfile) ; +} + +{ + # subdatabases + + # opening a subdatabse in an exsiting database that does have + # subdatabases at all, but not this one + + my $lex = new LexFile $Dfile ; + + ok 11, my $db = new BerkeleyDB::Hash -Filename => $Dfile, + -Subname => "fred" , + -Flags => DB_CREATE ; + + # Add a k/v pair + my %data = qw( + red sky + blue sea + black heart + yellow belley + green grass + ) ; + + ok 12, addData($db, %data) ; + + undef $db ; + + $db = new BerkeleyDB::Hash -Filename => $Dfile, + -Subname => "joe" ; + + ok 13, !$db ; + +} + +{ + # subdatabases + + my $lex = new LexFile $Dfile ; + + ok 14, my $db = new BerkeleyDB::Hash -Filename => $Dfile, + -Subname => "fred" , + -Flags => DB_CREATE ; + + # Add a k/v pair + my %data = qw( + red sky + blue sea + black heart + yellow belley + green grass + ) ; + + ok 15, addData($db, %data) ; + + undef $db ; + + ok 16, $db = new BerkeleyDB::Hash -Filename => $Dfile, + -Subname => "fred" ; + + ok 17, my $cursor = $db->db_cursor() ; + my ($k, $v) = ("", "") ; + my $status ; + while (($status = $cursor->c_get($k, $v, DB_NEXT)) == 0) { + if ($data{$k} eq $v) { + delete $data{$k} ; + } + } + ok 18, $status == DB_NOTFOUND ; + ok 19, keys %data == 0 ; +} + +{ + # subdatabases + + # opening a database with multiple subdatabases - handle should be a list + # of the subdatabase names + + my $lex = new LexFile $Dfile ; + + ok 20, my $db1 = new BerkeleyDB::Hash -Filename => $Dfile, + -Subname => "fred" , + -Flags => DB_CREATE ; + + ok 21, my $db2 = new BerkeleyDB::Btree -Filename => $Dfile, + -Subname => "joe" , + -Flags => DB_CREATE ; + + # Add a k/v pair + my %data = qw( + red sky + blue sea + black heart + yellow belley + green grass + ) ; + + ok 22, addData($db1, %data) ; + ok 23, addData($db2, %data) ; + + undef $db1 ; + undef $db2 ; + + ok 24, my $db = new BerkeleyDB::Unknown -Filename => $Dfile , + -Flags => DB_RDONLY ; + + #my $type = $db->type() ; print "type $type\n" ; + ok 25, my $cursor = $db->db_cursor() ; + my ($k, $v) = ("", "") ; + my $status ; + my @dbnames = () ; + while (($status = $cursor->c_get($k, $v, DB_NEXT)) == 0) { + push @dbnames, $k ; + } + ok 26, $status == DB_NOTFOUND ; + ok 27, join(",", sort @dbnames) eq "fred,joe" ; + undef $db ; + + ok 28, BerkeleyDB::db_remove(-Filename => $Dfile, -Subname => "harry") != 0; + ok 29, BerkeleyDB::db_remove(-Filename => $Dfile, -Subname => "fred") == 0 ; + + # should only be one subdatabase + ok 30, $db = new BerkeleyDB::Unknown -Filename => $Dfile , + -Flags => DB_RDONLY ; + + ok 31, $cursor = $db->db_cursor() ; + @dbnames = () ; + while (($status = $cursor->c_get($k, $v, DB_NEXT)) == 0) { + push @dbnames, $k ; + } + ok 32, $status == DB_NOTFOUND ; + ok 33, join(",", sort @dbnames) eq "joe" ; + undef $db ; + + # can't delete an already deleted subdatabase + ok 34, BerkeleyDB::db_remove(-Filename => $Dfile, -Subname => "fred") != 0; + + ok 35, BerkeleyDB::db_remove(-Filename => $Dfile, -Subname => "joe") == 0 ; + + # should only be one subdatabase + ok 36, $db = new BerkeleyDB::Unknown -Filename => $Dfile , + -Flags => DB_RDONLY ; + + ok 37, $cursor = $db->db_cursor() ; + @dbnames = () ; + while (($status = $cursor->c_get($k, $v, DB_NEXT)) == 0) { + push @dbnames, $k ; + } + ok 38, $status == DB_NOTFOUND ; + ok 39, @dbnames == 0 ; + undef $db ; + + ok 40, -e $Dfile ; + ok 41, BerkeleyDB::db_remove(-Filename => $Dfile) == 0 ; + ok 42, ! -e $Dfile ; + ok 43, BerkeleyDB::db_remove(-Filename => $Dfile) != 0 ; +} + +# db_remove with env diff --git a/db/perl.BerkeleyDB/t/txn.t b/db/perl.BerkeleyDB/t/txn.t new file mode 100644 index 000000000..6bef1887e --- /dev/null +++ b/db/perl.BerkeleyDB/t/txn.t @@ -0,0 +1,354 @@ +#!./perl -w + +use strict ; + +BEGIN { + unless(grep /blib/, @INC) { + chdir 't' if -d 't'; + @INC = '../lib' if -d '../lib'; + } +} + +use BerkeleyDB; +use File::Path qw(rmtree); + +print "1..50\n"; + + +{ + package LexFile ; + + sub new + { + my $self = shift ; + unlink @_ ; + bless [ @_ ], $self ; + } + + sub DESTROY + { + my $self = shift ; + unlink @{ $self } ; + } +} + +sub ok +{ + my $no = shift ; + my $result = shift ; + + print "not " unless $result ; + print "ok $no\n" ; +} + +sub docat +{ + my $file = shift; + local $/ = undef; + open(CAT,$file) || die "Cannot open $file:$!"; + my $result = ; + close(CAT); + return $result; +} + + +my $Dfile = "dbhash.tmp"; + +umask(0); + +{ + # error cases + + my $lex = new LexFile $Dfile ; + my %hash ; + my $value ; + + my $home = "./fred" ; + rmtree $home if -e $home ; + ok 1, mkdir($home, 0777) ; + ok 2, my $env = new BerkeleyDB::Env -Home => $home, + -Flags => DB_CREATE| DB_INIT_MPOOL; + eval { $env->txn_begin() ; } ; + ok 3, $@ =~ /^BerkeleyDB Aborting: Transaction Manager not enabled at/ ; + + eval { my $txn_mgr = $env->TxnMgr() ; } ; + ok 4, $@ =~ /^BerkeleyDB Aborting: Transaction Manager not enabled at/ ; + undef $env ; + rmtree $home ; + +} + +{ + # transaction - abort works + + my $lex = new LexFile $Dfile ; + my %hash ; + my $value ; + + my $home = "./fred" ; + rmtree $home if -e $home ; + ok 5, mkdir($home, 0777) ; + ok 6, my $env = new BerkeleyDB::Env -Home => $home, + -Flags => DB_CREATE|DB_INIT_TXN| + DB_INIT_MPOOL|DB_INIT_LOCK ; + ok 7, my $txn = $env->txn_begin() ; + ok 8, my $db1 = tie %hash, 'BerkeleyDB::Hash', -Filename => $Dfile, + -Flags => DB_CREATE , + -Env => $env, + -Txn => $txn ; + + + # create some data + my %data = ( + "red" => "boat", + "green" => "house", + "blue" => "sea", + ) ; + + my $ret = 0 ; + while (my ($k, $v) = each %data) { + $ret += $db1->db_put($k, $v) ; + } + ok 9, $ret == 0 ; + + # should be able to see all the records + + ok 10, my $cursor = $db1->db_cursor() ; + my ($k, $v) = ("", "") ; + my $count = 0 ; + # sequence forwards + while ($cursor->c_get($k, $v, DB_NEXT) == 0) { + ++ $count ; + } + ok 11, $count == 3 ; + undef $cursor ; + + # now abort the transaction + ok 12, $txn->txn_abort() == 0 ; + + # there shouldn't be any records in the database + $count = 0 ; + # sequence forwards + ok 13, $cursor = $db1->db_cursor() ; + while ($cursor->c_get($k, $v, DB_NEXT) == 0) { + ++ $count ; + } + ok 14, $count == 0 ; + + my $stat = $env->txn_stat() ; + ok 15, $stat->{'st_naborts'} == 1 ; + + undef $txn ; + undef $cursor ; + undef $db1 ; + undef $env ; + untie %hash ; + rmtree $home ; +} + +{ + # transaction - abort works via txnmgr + + my $lex = new LexFile $Dfile ; + my %hash ; + my $value ; + + my $home = "./fred" ; + rmtree $home if -e $home ; + ok 16, mkdir($home, 0777) ; + ok 17, my $env = new BerkeleyDB::Env -Home => $home, + -Flags => DB_CREATE|DB_INIT_TXN| + DB_INIT_MPOOL|DB_INIT_LOCK ; + ok 18, my $txn_mgr = $env->TxnMgr() ; + ok 19, my $txn = $txn_mgr->txn_begin() ; + ok 20, my $db1 = tie %hash, 'BerkeleyDB::Hash', -Filename => $Dfile, + -Flags => DB_CREATE , + -Env => $env, + -Txn => $txn ; + + + # create some data + my %data = ( + "red" => "boat", + "green" => "house", + "blue" => "sea", + ) ; + + my $ret = 0 ; + while (my ($k, $v) = each %data) { + $ret += $db1->db_put($k, $v) ; + } + ok 21, $ret == 0 ; + + # should be able to see all the records + + ok 22, my $cursor = $db1->db_cursor() ; + my ($k, $v) = ("", "") ; + my $count = 0 ; + # sequence forwards + while ($cursor->c_get($k, $v, DB_NEXT) == 0) { + ++ $count ; + } + ok 23, $count == 3 ; + undef $cursor ; + + # now abort the transaction + ok 24, $txn->txn_abort() == 0 ; + + # there shouldn't be any records in the database + $count = 0 ; + # sequence forwards + ok 25, $cursor = $db1->db_cursor() ; + while ($cursor->c_get($k, $v, DB_NEXT) == 0) { + ++ $count ; + } + ok 26, $count == 0 ; + + my $stat = $txn_mgr->txn_stat() ; + ok 27, $stat->{'st_naborts'} == 1 ; + + undef $txn ; + undef $cursor ; + undef $db1 ; + undef $txn_mgr ; + undef $env ; + untie %hash ; + rmtree $home ; +} + +{ + # transaction - commit works + + my $lex = new LexFile $Dfile ; + my %hash ; + my $value ; + + my $home = "./fred" ; + rmtree $home if -e $home ; + ok 28, mkdir($home, 0777) ; + ok 29, my $env = new BerkeleyDB::Env -Home => $home, + -Flags => DB_CREATE|DB_INIT_TXN| + DB_INIT_MPOOL|DB_INIT_LOCK ; + ok 30, my $txn = $env->txn_begin() ; + ok 31, my $db1 = tie %hash, 'BerkeleyDB::Hash', -Filename => $Dfile, + -Flags => DB_CREATE , + -Env => $env, + -Txn => $txn ; + + + # create some data + my %data = ( + "red" => "boat", + "green" => "house", + "blue" => "sea", + ) ; + + my $ret = 0 ; + while (my ($k, $v) = each %data) { + $ret += $db1->db_put($k, $v) ; + } + ok 32, $ret == 0 ; + + # should be able to see all the records + + ok 33, my $cursor = $db1->db_cursor() ; + my ($k, $v) = ("", "") ; + my $count = 0 ; + # sequence forwards + while ($cursor->c_get($k, $v, DB_NEXT) == 0) { + ++ $count ; + } + ok 34, $count == 3 ; + undef $cursor ; + + # now commit the transaction + ok 35, $txn->txn_commit() == 0 ; + + $count = 0 ; + # sequence forwards + ok 36, $cursor = $db1->db_cursor() ; + while ($cursor->c_get($k, $v, DB_NEXT) == 0) { + ++ $count ; + } + ok 37, $count == 3 ; + + my $stat = $env->txn_stat() ; + ok 38, $stat->{'st_naborts'} == 0 ; + + undef $txn ; + undef $cursor ; + undef $db1 ; + undef $env ; + untie %hash ; + rmtree $home ; +} + +{ + # transaction - commit works via txnmgr + + my $lex = new LexFile $Dfile ; + my %hash ; + my $value ; + + my $home = "./fred" ; + rmtree $home if -e $home ; + ok 39, mkdir($home, 0777) ; + ok 40, my $env = new BerkeleyDB::Env -Home => $home, + -Flags => DB_CREATE|DB_INIT_TXN| + DB_INIT_MPOOL|DB_INIT_LOCK ; + ok 41, my $txn_mgr = $env->TxnMgr() ; + ok 42, my $txn = $txn_mgr->txn_begin() ; + ok 43, my $db1 = tie %hash, 'BerkeleyDB::Hash', -Filename => $Dfile, + -Flags => DB_CREATE , + -Env => $env, + -Txn => $txn ; + + + # create some data + my %data = ( + "red" => "boat", + "green" => "house", + "blue" => "sea", + ) ; + + my $ret = 0 ; + while (my ($k, $v) = each %data) { + $ret += $db1->db_put($k, $v) ; + } + ok 44, $ret == 0 ; + + # should be able to see all the records + + ok 45, my $cursor = $db1->db_cursor() ; + my ($k, $v) = ("", "") ; + my $count = 0 ; + # sequence forwards + while ($cursor->c_get($k, $v, DB_NEXT) == 0) { + ++ $count ; + } + ok 46, $count == 3 ; + undef $cursor ; + + # now commit the transaction + ok 47, $txn->txn_commit() == 0 ; + + $count = 0 ; + # sequence forwards + ok 48, $cursor = $db1->db_cursor() ; + while ($cursor->c_get($k, $v, DB_NEXT) == 0) { + ++ $count ; + } + ok 49, $count == 3 ; + + my $stat = $txn_mgr->txn_stat() ; + ok 50, $stat->{'st_naborts'} == 0 ; + + undef $txn ; + undef $cursor ; + undef $db1 ; + undef $txn_mgr ; + undef $env ; + untie %hash ; + rmtree $home ; +} + diff --git a/db/perl.BerkeleyDB/t/unknown.t b/db/perl.BerkeleyDB/t/unknown.t new file mode 100644 index 000000000..e72021f0b --- /dev/null +++ b/db/perl.BerkeleyDB/t/unknown.t @@ -0,0 +1,212 @@ +#!./perl -w + +# ID: %I%, %G% + +use strict ; + +BEGIN { + unless(grep /blib/, @INC) { + chdir 't' if -d 't'; + @INC = '../lib' if -d '../lib'; + } +} + +use BerkeleyDB; +use File::Path qw(rmtree); + +print "1..41\n"; + +{ + package LexFile ; + + sub new + { + my $self = shift ; + unlink @_ ; + bless [ @_ ], $self ; + } + + sub DESTROY + { + my $self = shift ; + unlink @{ $self } ; + } +} + + +sub ok +{ + my $no = shift ; + my $result = shift ; + + print "not " unless $result ; + print "ok $no\n" ; +} + +sub writeFile +{ + my $name = shift ; + open(FH, ">$name") or return 0 ; + print FH @_ ; + close FH ; + return 1 ; +} + +my $Dfile = "dbhash.tmp"; +unlink $Dfile; + +umask(0) ; + + +# Check for invalid parameters +{ + # Check for invalid parameters + my $db ; + eval ' $db = new BerkeleyDB::Unknown -Stupid => 3 ; ' ; + ok 1, $@ =~ /unknown key value\(s\) Stupid/ ; + + eval ' $db = new BerkeleyDB::Unknown -Bad => 2, -Mode => 0345, -Stupid => 3; ' ; + ok 2, $@ =~ /unknown key value\(s\) (Bad |Stupid ){2}/ ; + + eval ' $db = new BerkeleyDB::Unknown -Env => 2 ' ; + ok 3, $@ =~ /^Env not of type BerkeleyDB::Env/ ; + + eval ' $db = new BerkeleyDB::Unknown -Txn => "fred" ' ; + ok 4, $@ =~ /^Txn not of type BerkeleyDB::Txn/ ; + + my $obj = bless [], "main" ; + eval ' $db = new BerkeleyDB::Unknown -Env => $obj ' ; + ok 5, $@ =~ /^Env not of type BerkeleyDB::Env/ ; +} + +# check the interface to a rubbish database +{ + # first an empty file + my $lex = new LexFile $Dfile ; + ok 6, writeFile($Dfile, "") ; + + ok 7, ! (new BerkeleyDB::Unknown -Filename => $Dfile); + + # now a non-database file + writeFile($Dfile, "\x2af6") ; + ok 8, ! (new BerkeleyDB::Unknown -Filename => $Dfile); +} + +# check the interface to a Hash database + +{ + my $lex = new LexFile $Dfile ; + + # create a hash database + ok 9, my $db = new BerkeleyDB::Hash -Filename => $Dfile, + -Flags => DB_CREATE ; + + # Add a few k/v pairs + my $value ; + my $status ; + ok 10, $db->db_put("some key", "some value") == 0 ; + ok 11, $db->db_put("key", "value") == 0 ; + + # close the database + undef $db ; + + # now open it with Unknown + ok 12, $db = new BerkeleyDB::Unknown -Filename => $Dfile; + + ok 13, $db->type() == DB_HASH ; + ok 14, $db->db_get("some key", $value) == 0 ; + ok 15, $value eq "some value" ; + ok 16, $db->db_get("key", $value) == 0 ; + ok 17, $value eq "value" ; + + my @array ; + eval { $db->Tie(\@array)} ; + ok 18, $@ =~ /^Tie needs a reference to a hash/ ; + + my %hash ; + $db->Tie(\%hash) ; + ok 19, $hash{"some key"} eq "some value" ; + +} + +# check the interface to a Btree database + +{ + my $lex = new LexFile $Dfile ; + + # create a hash database + ok 20, my $db = new BerkeleyDB::Btree -Filename => $Dfile, + -Flags => DB_CREATE ; + + # Add a few k/v pairs + my $value ; + my $status ; + ok 21, $db->db_put("some key", "some value") == 0 ; + ok 22, $db->db_put("key", "value") == 0 ; + + # close the database + undef $db ; + + # now open it with Unknown + # create a hash database + ok 23, $db = new BerkeleyDB::Unknown -Filename => $Dfile; + + ok 24, $db->type() == DB_BTREE ; + ok 25, $db->db_get("some key", $value) == 0 ; + ok 26, $value eq "some value" ; + ok 27, $db->db_get("key", $value) == 0 ; + ok 28, $value eq "value" ; + + + my @array ; + eval { $db->Tie(\@array)} ; + ok 29, $@ =~ /^Tie needs a reference to a hash/ ; + + my %hash ; + $db->Tie(\%hash) ; + ok 30, $hash{"some key"} eq "some value" ; + + +} + +# check the interface to a Recno database + +{ + my $lex = new LexFile $Dfile ; + + # create a recno database + ok 31, my $db = new BerkeleyDB::Recno -Filename => $Dfile, + -Flags => DB_CREATE ; + + # Add a few k/v pairs + my $value ; + my $status ; + ok 32, $db->db_put(0, "some value") == 0 ; + ok 33, $db->db_put(1, "value") == 0 ; + + # close the database + undef $db ; + + # now open it with Unknown + # create a hash database + ok 34, $db = new BerkeleyDB::Unknown -Filename => $Dfile; + + ok 35, $db->type() == DB_RECNO ; + ok 36, $db->db_get(0, $value) == 0 ; + ok 37, $value eq "some value" ; + ok 38, $db->db_get(1, $value) == 0 ; + ok 39, $value eq "value" ; + + + my %hash ; + eval { $db->Tie(\%hash)} ; + ok 40, $@ =~ /^Tie needs a reference to an array/ ; + + my @array ; + $db->Tie(\@array) ; + ok 41, $array[1] eq "value" ; + + +} + +# check i/f to text diff --git a/db/perl.BerkeleyDB/typemap b/db/perl.BerkeleyDB/typemap new file mode 100644 index 000000000..d6c4c7647 --- /dev/null +++ b/db/perl.BerkeleyDB/typemap @@ -0,0 +1,275 @@ +# typemap for Perl 5 interface to Berkeley DB version 2 & 3 +# +# SCCS: %I%, %G% +# +# written by Paul Marquess +# +#################################### DB SECTION +# +# + +void * T_PV +u_int T_U_INT +u_int32_t T_U_INT +const char * T_PV_NULL +PV_or_NULL T_PV_NULL +IO_or_NULL T_IO_NULL + +AV * T_AV + +BerkeleyDB T_PTROBJ +BerkeleyDB::Common T_PTROBJ_AV +BerkeleyDB::Hash T_PTROBJ_AV +BerkeleyDB::Btree T_PTROBJ_AV +BerkeleyDB::Recno T_PTROBJ_AV +BerkeleyDB::Queue T_PTROBJ_AV +BerkeleyDB::Cursor T_PTROBJ_AV +BerkeleyDB::TxnMgr T_PTROBJ_AV +BerkeleyDB::Txn T_PTROBJ_AV +BerkeleyDB::Log T_PTROBJ_AV +BerkeleyDB::Lock T_PTROBJ_AV +BerkeleyDB::Env T_PTROBJ_AV + +BerkeleyDB::Raw T_RAW +BerkeleyDB::Common::Raw T_RAW +BerkeleyDB::Hash::Raw T_RAW +BerkeleyDB::Btree::Raw T_RAW +BerkeleyDB::Recno::Raw T_RAW +BerkeleyDB::Queue::Raw T_RAW +BerkeleyDB::Cursor::Raw T_RAW +BerkeleyDB::TxnMgr::Raw T_RAW +BerkeleyDB::Txn::Raw T_RAW +BerkeleyDB::Log::Raw T_RAW +BerkeleyDB::Lock::Raw T_RAW +BerkeleyDB::Env::Raw T_RAW + +BerkeleyDB::Env::Inner T_INNER +BerkeleyDB::Common::Inner T_INNER +BerkeleyDB::Txn::Inner T_INNER +BerkeleyDB::TxnMgr::Inner T_INNER +# BerkeleyDB__Env T_PTR +DBT T_dbtdatum +DBT_OPT T_dbtdatum_opt +DBT_B T_dbtdatum_btree +DBTKEY T_dbtkeydatum +DBTKEY_B T_dbtkeydatum_btree +DBTYPE T_U_INT +DualType T_DUAL +BerkeleyDB_type * T_IV +BerkeleyDB_ENV_type * T_IV +BerkeleyDB_TxnMgr_type * T_IV +BerkeleyDB_Txn_type * T_IV +BerkeleyDB__Cursor_type * T_IV +DB * T_IV + +INPUT + +T_AV + if (SvROK($arg) && SvTYPE(SvRV($arg)) == SVt_PVAV) + /* if (sv_isa($arg, \"${ntype}\")) */ + $var = (AV*)SvRV($arg); + else + croak(\"$var is not an array reference\") + +T_RAW + $var = ($type)SvIV($arg) + +T_U_INT + $var = SvUV($arg) + +T_SV_REF_NULL + if ($arg == &PL_sv_undef) + $var = NULL ; + else if (sv_derived_from($arg, \"${ntype}\")) { + IV tmp = SvIV((SV *)GetInternalObject($arg)); + $var = ($type) tmp; + } + else + croak(\"$var is not of type ${ntype}\") + +T_HV_REF_NULL + if ($arg == &PL_sv_undef) + $var = NULL ; + else if (sv_derived_from($arg, \"${ntype}\")) { + HV * hv = (HV *)GetInternalObject($arg); + SV ** svp = hv_fetch(hv, \"db\", 2, FALSE); + IV tmp = SvIV(*svp); + $var = ($type) tmp; + } + else + croak(\"$var is not of type ${ntype}\") + +T_HV_REF + if (sv_derived_from($arg, \"${ntype}\")) { + HV * hv = (HV *)GetInternalObject($arg); + SV ** svp = hv_fetch(hv, \"db\", 2, FALSE); + IV tmp = SvIV(*svp); + $var = ($type) tmp; + } + else + croak(\"$var is not of type ${ntype}\") + + +T_P_REF + if (sv_derived_from($arg, \"${ntype}\")) { + IV tmp = SvIV((SV*)SvRV($arg)); + $var = ($type) tmp; + } + else + croak(\"$var is not of type ${ntype}\") + + +T_INNER + { + HV * hv = (HV *)SvRV($arg); + SV ** svp = hv_fetch(hv, \"db\", 2, FALSE); + IV tmp = SvIV(*svp); + $var = ($type) tmp; + } + +T_PV_NULL + if ($arg == &PL_sv_undef) + $var = NULL ; + else { + $var = ($type)SvPV($arg,PL_na) ; + if (PL_na == 0) + $var = NULL ; + } + +T_IO_NULL + if ($arg == &PL_sv_undef) + $var = NULL ; + else + $var = IoOFP(sv_2io($arg)) + +T_PTROBJ_NULL + if ($arg == &PL_sv_undef) + $var = NULL ; + else if (sv_derived_from($arg, \"${ntype}\")) { + IV tmp = SvIV((SV*)SvRV($arg)); + $var = ($type) tmp; + } + else + croak(\"$var is not of type ${ntype}\") + +T_PTROBJ_SELF + if ($arg == &PL_sv_undef) + $var = NULL ; + else if (sv_derived_from($arg, \"${ntype}\")) { + IV tmp = SvIV((SV*)SvRV($arg)); + $var = ($type) tmp; + } + else + croak(\"$var is not of type ${ntype}\") + +T_PTROBJ_AV + if ($arg == &PL_sv_undef || $arg == NULL) + $var = NULL ; + else if (sv_derived_from($arg, \"${ntype}\")) { + IV tmp = getInnerObject($arg) ; + $var = ($type) tmp; + } + else + croak(\"$var is not of type ${ntype}\") + +T_dbtkeydatum + ckFilter($arg, filter_store_key, \"filter_store_key\"); + DBT_clear($var) ; + if (db->recno_or_queue) { + Value = GetRecnoKey(db, SvIV($arg)) ; + $var.data = & Value; + $var.size = (int)sizeof(db_recno_t); + } + else { + $var.data = SvPV($arg, PL_na); + $var.size = (int)PL_na; + } + +T_dbtkeydatum_btree + ckFilter($arg, filter_store_key, \"filter_store_key\"); + DBT_clear($var) ; + if (db->recno_or_queue || + (db->type == DB_BTREE && flagSet(DB_SET_RECNO))) { + Value = GetRecnoKey(db, SvIV($arg)) ; + $var.data = & Value; + $var.size = (int)sizeof(db_recno_t); + } + else { + $var.data = SvPV($arg, PL_na); + $var.size = (int)PL_na; + } + +T_dbtdatum + ckFilter($arg, filter_store_value, \"filter_store_value\"); + DBT_clear($var) ; + $var.data = SvPV($arg, PL_na); + $var.size = (int)PL_na; + $var.flags = db->partial ; + $var.dlen = db->dlen ; + $var.doff = db->doff ; + +T_dbtdatum_opt + DBT_clear($var) ; + if (flagSet(DB_GET_BOTH)) { + ckFilter($arg, filter_store_value, \"filter_store_value\"); + $var.data = SvPV($arg, PL_na); + $var.size = (int)PL_na; + $var.flags = db->partial ; + $var.dlen = db->dlen ; + $var.doff = db->doff ; + } + +T_dbtdatum_btree + DBT_clear($var) ; + if (flagSet(DB_GET_BOTH)) { + ckFilter($arg, filter_store_value, \"filter_store_value\"); + $var.data = SvPV($arg, PL_na); + $var.size = (int)PL_na; + $var.flags = db->partial ; + $var.dlen = db->dlen ; + $var.doff = db->doff ; + } + + +OUTPUT + +T_RAW + sv_setiv($arg, (IV)$var); + +T_SV_REF_NULL + sv_setiv($arg, (IV)$var); + +T_HV_REF_NULL + sv_setiv($arg, (IV)$var); + +T_HV_REF + sv_setiv($arg, (IV)$var); + +T_P_REF + sv_setiv($arg, (IV)$var); + +T_DUAL + setDUALerrno($arg, $var) ; + +T_U_INT + sv_setuv($arg, (UV)$var); + +T_PV_NULL + sv_setpv((SV*)$arg, $var); + +T_dbtkeydatum_btree + OutputKey_B($arg, $var) +T_dbtkeydatum + OutputKey($arg, $var) +T_dbtdatum + OutputValue($arg, $var) +T_dbtdatum_opt + OutputValue($arg, $var) +T_dbtdatum_btree + OutputValue_B($arg, $var) + +T_PTROBJ_NULL + sv_setref_pv($arg, \"${ntype}\", (void*)$var); + +T_PTROBJ_SELF + sv_setref_pv($arg, self, (void*)$var); diff --git a/db/perl.DB_File/Changes b/db/perl.DB_File/Changes new file mode 100644 index 000000000..b8684cac3 --- /dev/null +++ b/db/perl.DB_File/Changes @@ -0,0 +1,343 @@ + +0.1 + + First Release. + +0.2 + + When DB_File is opening a database file it no longer terminates the + process if dbopen returned an error. This allows file protection + errors to be caught at run time. Thanks to Judith Grass + for spotting the bug. + +0.3 + + Added prototype support for multiple btree compare callbacks. + +1.0 + + DB_File has been in use for over a year. To reflect that, the + version number has been incremented to 1.0. + + Added complete support for multiple concurrent callbacks. + + Using the push method on an empty list didn't work properly. This + has been fixed. + +1.01 + + Fixed a core dump problem with SunOS. + + The return value from TIEHASH wasn't set to NULL when dbopen + returned an error. + +1.02 + + Merged OS/2 specific code into DB_File.xs + + Removed some redundant code in DB_File.xs. + + Documentation update. + + Allow negative subscripts with RECNO interface. + + Changed the default flags from O_RDWR to O_CREAT|O_RDWR. + + The example code which showed how to lock a database needed a call + to sync added. Without it the resultant database file was empty. + + Added get_dup method. + +1.03 + + Documentation update. + + DB_File now imports the constants (O_RDWR, O_CREAT etc.) from Fcntl + automatically. + + The standard hash function exists is now supported. + + Modified the behavior of get_dup. When it returns an associative + array, the value is the count of the number of matching BTREE + values. + +1.04 + + Minor documentation changes. + + Fixed a bug in hash_cb. Patches supplied by Dave Hammen, + . + + Fixed a bug with the constructors for DB_File::HASHINFO, + DB_File::BTREEINFO and DB_File::RECNOINFO. Also tidied up the + constructors to make them -w clean. + + Reworked part of the test harness to be more locale friendly. + +1.05 + + Made all scripts in the documentation strict and -w clean. + + Added logic to DB_File.xs to allow the module to be built after + Perl is installed. + +1.06 + + Minor namespace cleanup: Localized PrintBtree. + +1.07 + + Fixed bug with RECNO, where bval wasn't defaulting to "\n". + +1.08 + + Documented operation of bval. + +1.09 + + Minor bug fix in DB_File::HASHINFO, DB_File::RECNOINFO and + DB_File::BTREEINFO. + + Changed default mode to 0666. + +1.10 + + Fixed fd method so that it still returns -1 for in-memory files + when db 1.86 is used. + +1.11 + + Documented the untie gotcha. + +1.12 + + Documented the incompatibility with version 2 of Berkeley DB. + +1.13 + + Minor changes to DB_FIle.xs and DB_File.pm + +1.14 + + Made it illegal to tie an associative array to a RECNO database and + an ordinary array to a HASH or BTREE database. + +1.15 + + Patch from Gisle Aas to suppress "use of undefined + value" warning with db_get and db_seq. + + Patch from Gisle Aas to make DB_File export only the + O_* constants from Fcntl. + + Removed the DESTROY method from the DB_File::HASHINFO module. + + Previously DB_File hard-wired the class name of any object that it + created to "DB_File". This makes sub-classing difficult. Now + DB_File creats objects in the namespace of the package it has been + inherited into. + + +1.16 + + A harmless looking tab was causing Makefile.PL to fail on AIX 3.2.5 + + Small fix for the AIX strict C compiler XLC which doesn't like + __attribute__ being defined via proto.h and redefined via db.h. Fix + courtesy of Jarkko Hietaniemi. + +1.50 + + DB_File can now build with either DB 1.x or 2.x, but not both at + the same time. + +1.51 + + Fixed the test harness so that it doesn't expect DB_File to have + been installed by the main Perl build. + + + Fixed a bug in mapping 1.x O_RDONLY flag to 2.x DB_RDONLY equivalent + +1.52 + + Patch from Nick Ing-Simmons now allows DB_File to build on NT. + Merged 1.15 patch. + +1.53 + + Added DB_RENUMBER to flags for recno. + +1.54 + + Fixed a small bug in the test harness when run under win32 + The emulation of fd when useing DB 2.x was busted. + +1.55 + Merged 1.16 changes. + +1.56 + Documented the Solaris 2.5 mutex bug + +1.57 + If Perl has been compiled with Threads support,the symbol op will be + defined. This clashes with a field name in db.h, so it needs to be + #undef'ed before db.h is included. + +1.58 + Tied Array support was enhanced in Perl 5.004_57. DB_File now + supports PUSH,POP,SHIFT,UNSHIFT & STORESIZE. + + Fixed a problem with the use of sv_setpvn. When the size is + specified as 0, it does a strlen on the data. This was ok for DB + 1.x, but isn't for DB 2.x. + +1.59 + Updated the license section. + + Berkeley DB 2.4.10 disallows zero length keys. Tests 32 & 42 in + db-btree.t and test 27 in db-hash.t failed because of this change. + Those tests have been zapped. + + Added dbinfo to the distribution. + +1.60 + Changed the test to check for full tied array support + +1.61 19th November 1998 + + Added a note to README about how to build Berkeley DB 2.x when + using HP-UX. + Minor modifications to get the module to build with DB 2.5.x + Fixed a typo in the definition of O_RDONLY, courtesy of Mark Kettenis. + +1.62 30th November 1998 + + Added hints/dynixptx.pl. + Fixed typemap -- 1.61 used PL_na instead of na + +1.63 19th December 1998 + + * Fix to allow DB 2.6.x to build with DB_File + * Documentation updated to use push,pop etc in the RECNO example & + to include the find_dup & del_dup methods. + +1.64 21st February 1999 + + * Tidied the 1.x to 2.x flag mapping code. + * Added a patch from Mark Kettenis to fix a flag + mapping problem with O_RDONLY on the Hurd + * Updated the message that db-recno.t prints when tests 51, 53 or 55 fail. + +1.65 6th March 1999 + + * Fixed a bug in the recno PUSH logic. + * The BOOT version check now needs 2.3.4 when using Berkeley DB version 2 + +1.66 15th March 1999 + + * Added DBM Filter code + +1.67 6th June 1999 + + * Added DBM Filter documentation to DB_File.pm + + * Fixed DBM Filter code to work with 5.004 + + * A few instances of newSVpvn were used in 1.66. This isn't available in + Perl 5.004_04 or earlier. Replaced with newSVpv. + +1.68 22nd July 1999 + + * Merged changes from 5.005_58 + + * Fixed a bug in R_IBEFORE & R_IAFTER procesing in Berkeley DB + 2 databases. + + * Added some of the examples in the POD into the test harness. + +1.69 3rd August 1999 + + * fixed a bug in push -- DB_APPEND wasn't working properly. + + * Fixed the R_SETCURSOR bug introduced in 1.68 + + * Added a new Perl variable $DB_File::db_ver + +1.70 4th August 1999 + + * Initialise $DB_File::db_ver and $DB_File::db_version with + GV_ADD|GV_ADDMULT -- bug spotted by Nick Ing-Simmons. + + * Added a BOOT check to test for equivalent versions of db.h & + libdb.a/so. + +1.71 7th September 1999 + + * Fixed a bug that prevented 1.70 from compiling under win32 + + * Updated to support Berkeley DB 3.x + + * Updated dbinfo for Berkeley DB 3.x file formats. + +1.72 16th January 2000 + + * Added hints/sco.pl + + * The module will now use XSLoader when it is available. When it + isn't it will use DynaLoader. + + * The locking section in DB_File.pm has been discredited. Many thanks + to David Harris for spotting the underlying problem, contributing + the updates to the documentation and writing DB_File::Lock (available + on CPAN). + +1.73 31st May 2000 + + * Added support in version.c for building with threaded Perl. + + * Berkeley DB 3.1 has reenabled support for null keys. The test + harness has been updated to reflect this. + +1.74 10th December 2000 + + * A "close" call in DB_File.xs needed parenthesised to stop win32 from + thinking it was one of its macros. + + * Updated dbinfo to support Berkeley DB 3.1 file format changes. + + * DB_File.pm & the test hasness now use the warnings pragma (when + available). + + * Included Perl core patch 7703 -- size argument for hash_cb is different + for Berkeley DB 3.x + + * Included Perl core patch 7801 -- Give __getBerkeleyDBInfo the ANSI C + treatment. + + * @a = () produced the warning 'Argument "" isn't numeric in entersub' + This has been fixed. Thanks to Edward Avis for spotting this bug. + + * Added note about building under Linux. Included patches. + + * Included Perl core patch 8068 -- fix for bug 20001013.009 + When run with warnings enabled "$hash{XX} = undef " produced an + "Uninitialized value" warning. This has been fixed. + +1.75 17th December 2000 + + * Fixed perl core patch 7703 + + * Added suppport to allow DB_File to be built with Berkeley DB 3.2 -- + btree_compare, btree_prefix and hash_cb needed to be changed. + + * Updated dbinfo to support Berkeley DB 3.2 file format changes. + + +1.76 15th January 2001 + + * Added instructions for using LD_PRELOAD to get Berkeley DB 2.x to work + with DB_File on Linux. Thanks to Norbert Bollow for sending details of + this approach. + + diff --git a/db/perl.DB_File/DB_File.pm b/db/perl.DB_File/DB_File.pm new file mode 100644 index 000000000..e9b6a40d7 --- /dev/null +++ b/db/perl.DB_File/DB_File.pm @@ -0,0 +1,2072 @@ +# DB_File.pm -- Perl 5 interface to Berkeley DB +# +# written by Paul Marquess (Paul.Marquess@btinternet.com) +# last modified 15th January 2001 +# version 1.76 +# +# Copyright (c) 1995-2001 Paul Marquess. All rights reserved. +# This program is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. + + +package DB_File::HASHINFO ; + +require 5.003 ; + +use warnings; +use strict; +use Carp; +require Tie::Hash; +@DB_File::HASHINFO::ISA = qw(Tie::Hash); + +sub new +{ + my $pkg = shift ; + my %x ; + tie %x, $pkg ; + bless \%x, $pkg ; +} + + +sub TIEHASH +{ + my $pkg = shift ; + + bless { VALID => { map {$_, 1} + qw( bsize ffactor nelem cachesize hash lorder) + }, + GOT => {} + }, $pkg ; +} + + +sub FETCH +{ + my $self = shift ; + my $key = shift ; + + return $self->{GOT}{$key} if exists $self->{VALID}{$key} ; + + my $pkg = ref $self ; + croak "${pkg}::FETCH - Unknown element '$key'" ; +} + + +sub STORE +{ + my $self = shift ; + my $key = shift ; + my $value = shift ; + + if ( exists $self->{VALID}{$key} ) + { + $self->{GOT}{$key} = $value ; + return ; + } + + my $pkg = ref $self ; + croak "${pkg}::STORE - Unknown element '$key'" ; +} + +sub DELETE +{ + my $self = shift ; + my $key = shift ; + + if ( exists $self->{VALID}{$key} ) + { + delete $self->{GOT}{$key} ; + return ; + } + + my $pkg = ref $self ; + croak "DB_File::HASHINFO::DELETE - Unknown element '$key'" ; +} + +sub EXISTS +{ + my $self = shift ; + my $key = shift ; + + exists $self->{VALID}{$key} ; +} + +sub NotHere +{ + my $self = shift ; + my $method = shift ; + + croak ref($self) . " does not define the method ${method}" ; +} + +sub FIRSTKEY { my $self = shift ; $self->NotHere("FIRSTKEY") } +sub NEXTKEY { my $self = shift ; $self->NotHere("NEXTKEY") } +sub CLEAR { my $self = shift ; $self->NotHere("CLEAR") } + +package DB_File::RECNOINFO ; + +use warnings; +use strict ; + +@DB_File::RECNOINFO::ISA = qw(DB_File::HASHINFO) ; + +sub TIEHASH +{ + my $pkg = shift ; + + bless { VALID => { map {$_, 1} + qw( bval cachesize psize flags lorder reclen bfname ) + }, + GOT => {}, + }, $pkg ; +} + +package DB_File::BTREEINFO ; + +use warnings; +use strict ; + +@DB_File::BTREEINFO::ISA = qw(DB_File::HASHINFO) ; + +sub TIEHASH +{ + my $pkg = shift ; + + bless { VALID => { map {$_, 1} + qw( flags cachesize maxkeypage minkeypage psize + compare prefix lorder ) + }, + GOT => {}, + }, $pkg ; +} + + +package DB_File ; + +use warnings; +use strict; +use vars qw($VERSION @ISA @EXPORT $AUTOLOAD $DB_BTREE $DB_HASH $DB_RECNO + $db_version $use_XSLoader + ) ; +use Carp; + + +$VERSION = "1.76" ; + +#typedef enum { DB_BTREE, DB_HASH, DB_RECNO } DBTYPE; +$DB_BTREE = new DB_File::BTREEINFO ; +$DB_HASH = new DB_File::HASHINFO ; +$DB_RECNO = new DB_File::RECNOINFO ; + +require Tie::Hash; +require Exporter; +use AutoLoader; +BEGIN { + $use_XSLoader = 1 ; + eval { require XSLoader } ; + + if ($@) { + $use_XSLoader = 0 ; + require DynaLoader; + @ISA = qw(DynaLoader); + } +} + +push @ISA, qw(Tie::Hash Exporter); +@EXPORT = qw( + $DB_BTREE $DB_HASH $DB_RECNO + + BTREEMAGIC + BTREEVERSION + DB_LOCK + DB_SHMEM + DB_TXN + HASHMAGIC + HASHVERSION + MAX_PAGE_NUMBER + MAX_PAGE_OFFSET + MAX_REC_NUMBER + RET_ERROR + RET_SPECIAL + RET_SUCCESS + R_CURSOR + R_DUP + R_FIRST + R_FIXEDLEN + R_IAFTER + R_IBEFORE + R_LAST + R_NEXT + R_NOKEY + R_NOOVERWRITE + R_PREV + R_RECNOSYNC + R_SETCURSOR + R_SNAPSHOT + __R_UNUSED + +); + +sub AUTOLOAD { + my($constname); + ($constname = $AUTOLOAD) =~ s/.*:://; + my $val = constant($constname, @_ ? $_[0] : 0); + if ($! != 0) { + if ($! =~ /Invalid/ || $!{EINVAL}) { + $AutoLoader::AUTOLOAD = $AUTOLOAD; + goto &AutoLoader::AUTOLOAD; + } + else { + my($pack,$file,$line) = caller; + croak "Your vendor has not defined DB macro $constname, used at $file line $line. +"; + } + } + eval "sub $AUTOLOAD { $val }"; + goto &$AUTOLOAD; +} + + +eval { + # Make all Fcntl O_XXX constants available for importing + require Fcntl; + my @O = grep /^O_/, @Fcntl::EXPORT; + Fcntl->import(@O); # first we import what we want to export + push(@EXPORT, @O); +}; + +if ($use_XSLoader) + { XSLoader::load("DB_File", $VERSION)} +else + { bootstrap DB_File $VERSION } + +# Preloaded methods go here. Autoload methods go after __END__, and are +# processed by the autosplit program. + +sub tie_hash_or_array +{ + my (@arg) = @_ ; + my $tieHASH = ( (caller(1))[3] =~ /TIEHASH/ ) ; + + $arg[4] = tied %{ $arg[4] } + if @arg >= 5 && ref $arg[4] && $arg[4] =~ /=HASH/ && tied %{ $arg[4] } ; + + # make recno in Berkeley DB version 2 work like recno in version 1. + if ($db_version > 1 and defined $arg[4] and $arg[4] =~ /RECNO/ and + $arg[1] and ! -e $arg[1]) { + open(FH, ">$arg[1]") or return undef ; + close FH ; + chmod $arg[3] ? $arg[3] : 0666 , $arg[1] ; + } + + DoTie_($tieHASH, @arg) ; +} + +sub TIEHASH +{ + tie_hash_or_array(@_) ; +} + +sub TIEARRAY +{ + tie_hash_or_array(@_) ; +} + +sub CLEAR +{ + my $self = shift; + my $key = 0 ; + my $value = "" ; + my $status = $self->seq($key, $value, R_FIRST()); + my @keys; + + while ($status == 0) { + push @keys, $key; + $status = $self->seq($key, $value, R_NEXT()); + } + foreach $key (reverse @keys) { + my $s = $self->del($key); + } +} + +sub EXTEND { } + +sub STORESIZE +{ + my $self = shift; + my $length = shift ; + my $current_length = $self->length() ; + + if ($length < $current_length) { + my $key ; + for ($key = $current_length - 1 ; $key >= $length ; -- $key) + { $self->del($key) } + } + elsif ($length > $current_length) { + $self->put($length-1, "") ; + } +} + +sub find_dup +{ + croak "Usage: \$db->find_dup(key,value)\n" + unless @_ == 3 ; + + my $db = shift ; + my ($origkey, $value_wanted) = @_ ; + my ($key, $value) = ($origkey, 0); + my ($status) = 0 ; + + for ($status = $db->seq($key, $value, R_CURSOR() ) ; + $status == 0 ; + $status = $db->seq($key, $value, R_NEXT() ) ) { + + return 0 if $key eq $origkey and $value eq $value_wanted ; + } + + return $status ; +} + +sub del_dup +{ + croak "Usage: \$db->del_dup(key,value)\n" + unless @_ == 3 ; + + my $db = shift ; + my ($key, $value) = @_ ; + my ($status) = $db->find_dup($key, $value) ; + return $status if $status != 0 ; + + $status = $db->del($key, R_CURSOR() ) ; + return $status ; +} + +sub get_dup +{ + croak "Usage: \$db->get_dup(key [,flag])\n" + unless @_ == 2 or @_ == 3 ; + + my $db = shift ; + my $key = shift ; + my $flag = shift ; + my $value = 0 ; + my $origkey = $key ; + my $wantarray = wantarray ; + my %values = () ; + my @values = () ; + my $counter = 0 ; + my $status = 0 ; + + # iterate through the database until either EOF ($status == 0) + # or a different key is encountered ($key ne $origkey). + for ($status = $db->seq($key, $value, R_CURSOR()) ; + $status == 0 and $key eq $origkey ; + $status = $db->seq($key, $value, R_NEXT()) ) { + + # save the value or count number of matches + if ($wantarray) { + if ($flag) + { ++ $values{$value} } + else + { push (@values, $value) } + } + else + { ++ $counter } + + } + + return ($wantarray ? ($flag ? %values : @values) : $counter) ; +} + + +1; +__END__ + +=head1 NAME + +DB_File - Perl5 access to Berkeley DB version 1.x + +=head1 SYNOPSIS + + use DB_File ; + + [$X =] tie %hash, 'DB_File', [$filename, $flags, $mode, $DB_HASH] ; + [$X =] tie %hash, 'DB_File', $filename, $flags, $mode, $DB_BTREE ; + [$X =] tie @array, 'DB_File', $filename, $flags, $mode, $DB_RECNO ; + + $status = $X->del($key [, $flags]) ; + $status = $X->put($key, $value [, $flags]) ; + $status = $X->get($key, $value [, $flags]) ; + $status = $X->seq($key, $value, $flags) ; + $status = $X->sync([$flags]) ; + $status = $X->fd ; + + # BTREE only + $count = $X->get_dup($key) ; + @list = $X->get_dup($key) ; + %list = $X->get_dup($key, 1) ; + $status = $X->find_dup($key, $value) ; + $status = $X->del_dup($key, $value) ; + + # RECNO only + $a = $X->length; + $a = $X->pop ; + $X->push(list); + $a = $X->shift; + $X->unshift(list); + + # DBM Filters + $old_filter = $db->filter_store_key ( sub { ... } ) ; + $old_filter = $db->filter_store_value( sub { ... } ) ; + $old_filter = $db->filter_fetch_key ( sub { ... } ) ; + $old_filter = $db->filter_fetch_value( sub { ... } ) ; + + untie %hash ; + untie @array ; + +=head1 DESCRIPTION + +B is a module which allows Perl programs to make use of the +facilities provided by Berkeley DB version 1.x (if you have a newer +version of DB, see L). +It is assumed that you have a copy of the Berkeley DB manual pages at +hand when reading this documentation. The interface defined here +mirrors the Berkeley DB interface closely. + +Berkeley DB is a C library which provides a consistent interface to a +number of database formats. B provides an interface to all +three of the database types currently supported by Berkeley DB. + +The file types are: + +=over 5 + +=item B + +This database type allows arbitrary key/value pairs to be stored in data +files. This is equivalent to the functionality provided by other +hashing packages like DBM, NDBM, ODBM, GDBM, and SDBM. Remember though, +the files created using DB_HASH are not compatible with any of the +other packages mentioned. + +A default hashing algorithm, which will be adequate for most +applications, is built into Berkeley DB. If you do need to use your own +hashing algorithm it is possible to write your own in Perl and have +B use it instead. + +=item B + +The btree format allows arbitrary key/value pairs to be stored in a +sorted, balanced binary tree. + +As with the DB_HASH format, it is possible to provide a user defined +Perl routine to perform the comparison of keys. By default, though, the +keys are stored in lexical order. + +=item B + +DB_RECNO allows both fixed-length and variable-length flat text files +to be manipulated using the same key/value pair interface as in DB_HASH +and DB_BTREE. In this case the key will consist of a record (line) +number. + +=back + +=head2 Using DB_File with Berkeley DB version 2 or 3 + +Although B is intended to be used with Berkeley DB version 1, +it can also be used with version 2.or 3 In this case the interface is +limited to the functionality provided by Berkeley DB 1.x. Anywhere the +version 2 or 3 interface differs, B arranges for it to work +like version 1. This feature allows B scripts that were built +with version 1 to be migrated to version 2 or 3 without any changes. + +If you want to make use of the new features available in Berkeley DB +2.x or greater, use the Perl module B instead. + +B The database file format has changed in both Berkeley DB +version 2 and 3. If you cannot recreate your databases, you must dump +any existing databases with the C utility that comes with +Berkeley DB. +Once you have rebuilt DB_File to use Berkeley DB version 2 or 3, your +databases can be recreated using C. Refer to the Berkeley DB +documentation for further details. + +Please read L<"COPYRIGHT"> before using version 2.x or 3.x of Berkeley +DB with DB_File. + +=head2 Interface to Berkeley DB + +B allows access to Berkeley DB files using the tie() mechanism +in Perl 5 (for full details, see L). This facility +allows B to access Berkeley DB files using either an +associative array (for DB_HASH & DB_BTREE file types) or an ordinary +array (for the DB_RECNO file type). + +In addition to the tie() interface, it is also possible to access most +of the functions provided in the Berkeley DB API directly. +See L. + +=head2 Opening a Berkeley DB Database File + +Berkeley DB uses the function dbopen() to open or create a database. +Here is the C prototype for dbopen(): + + DB* + dbopen (const char * file, int flags, int mode, + DBTYPE type, const void * openinfo) + +The parameter C is an enumeration which specifies which of the 3 +interface methods (DB_HASH, DB_BTREE or DB_RECNO) is to be used. +Depending on which of these is actually chosen, the final parameter, +I points to a data structure which allows tailoring of the +specific interface method. + +This interface is handled slightly differently in B. Here is +an equivalent call using B: + + tie %array, 'DB_File', $filename, $flags, $mode, $DB_HASH ; + +The C, C and C parameters are the direct +equivalent of their dbopen() counterparts. The final parameter $DB_HASH +performs the function of both the C and C parameters in +dbopen(). + +In the example above $DB_HASH is actually a pre-defined reference to a +hash object. B has three of these pre-defined references. +Apart from $DB_HASH, there is also $DB_BTREE and $DB_RECNO. + +The keys allowed in each of these pre-defined references is limited to +the names used in the equivalent C structure. So, for example, the +$DB_HASH reference will only allow keys called C, C, +C, C, C and C. + +To change one of these elements, just assign to it like this: + + $DB_HASH->{'cachesize'} = 10000 ; + +The three predefined variables $DB_HASH, $DB_BTREE and $DB_RECNO are +usually adequate for most applications. If you do need to create extra +instances of these objects, constructors are available for each file +type. + +Here are examples of the constructors and the valid options available +for DB_HASH, DB_BTREE and DB_RECNO respectively. + + $a = new DB_File::HASHINFO ; + $a->{'bsize'} ; + $a->{'cachesize'} ; + $a->{'ffactor'}; + $a->{'hash'} ; + $a->{'lorder'} ; + $a->{'nelem'} ; + + $b = new DB_File::BTREEINFO ; + $b->{'flags'} ; + $b->{'cachesize'} ; + $b->{'maxkeypage'} ; + $b->{'minkeypage'} ; + $b->{'psize'} ; + $b->{'compare'} ; + $b->{'prefix'} ; + $b->{'lorder'} ; + + $c = new DB_File::RECNOINFO ; + $c->{'bval'} ; + $c->{'cachesize'} ; + $c->{'psize'} ; + $c->{'flags'} ; + $c->{'lorder'} ; + $c->{'reclen'} ; + $c->{'bfname'} ; + +The values stored in the hashes above are mostly the direct equivalent +of their C counterpart. Like their C counterparts, all are set to a +default values - that means you don't have to set I of the +values when you only want to change one. Here is an example: + + $a = new DB_File::HASHINFO ; + $a->{'cachesize'} = 12345 ; + tie %y, 'DB_File', "filename", $flags, 0777, $a ; + +A few of the options need extra discussion here. When used, the C +equivalent of the keys C, C and C store pointers +to C functions. In B these keys are used to store references +to Perl subs. Below are templates for each of the subs: + + sub hash + { + my ($data) = @_ ; + ... + # return the hash value for $data + return $hash ; + } + + sub compare + { + my ($key, $key2) = @_ ; + ... + # return 0 if $key1 eq $key2 + # -1 if $key1 lt $key2 + # 1 if $key1 gt $key2 + return (-1 , 0 or 1) ; + } + + sub prefix + { + my ($key, $key2) = @_ ; + ... + # return number of bytes of $key2 which are + # necessary to determine that it is greater than $key1 + return $bytes ; + } + +See L for an example of using the +C template. + +If you are using the DB_RECNO interface and you intend making use of +C, you should check out L. + +=head2 Default Parameters + +It is possible to omit some or all of the final 4 parameters in the +call to C and let them take default values. As DB_HASH is the most +common file format used, the call: + + tie %A, "DB_File", "filename" ; + +is equivalent to: + + tie %A, "DB_File", "filename", O_CREAT|O_RDWR, 0666, $DB_HASH ; + +It is also possible to omit the filename parameter as well, so the +call: + + tie %A, "DB_File" ; + +is equivalent to: + + tie %A, "DB_File", undef, O_CREAT|O_RDWR, 0666, $DB_HASH ; + +See L for a discussion on the use of C +in place of a filename. + +=head2 In Memory Databases + +Berkeley DB allows the creation of in-memory databases by using NULL +(that is, a C<(char *)0> in C) in place of the filename. B +uses C instead of NULL to provide this functionality. + +=head1 DB_HASH + +The DB_HASH file format is probably the most commonly used of the three +file formats that B supports. It is also very straightforward +to use. + +=head2 A Simple Example + +This example shows how to create a database, add key/value pairs to the +database, delete keys/value pairs and finally how to enumerate the +contents of the database. + + use warnings ; + use strict ; + use DB_File ; + use vars qw( %h $k $v ) ; + + unlink "fruit" ; + tie %h, "DB_File", "fruit", O_RDWR|O_CREAT, 0640, $DB_HASH + or die "Cannot open file 'fruit': $!\n"; + + # Add a few key/value pairs to the file + $h{"apple"} = "red" ; + $h{"orange"} = "orange" ; + $h{"banana"} = "yellow" ; + $h{"tomato"} = "red" ; + + # Check for existence of a key + print "Banana Exists\n\n" if $h{"banana"} ; + + # Delete a key/value pair. + delete $h{"apple"} ; + + # print the contents of the file + while (($k, $v) = each %h) + { print "$k -> $v\n" } + + untie %h ; + +here is the output: + + Banana Exists + + orange -> orange + tomato -> red + banana -> yellow + +Note that the like ordinary associative arrays, the order of the keys +retrieved is in an apparently random order. + +=head1 DB_BTREE + +The DB_BTREE format is useful when you want to store data in a given +order. By default the keys will be stored in lexical order, but as you +will see from the example shown in the next section, it is very easy to +define your own sorting function. + +=head2 Changing the BTREE sort order + +This script shows how to override the default sorting algorithm that +BTREE uses. Instead of using the normal lexical ordering, a case +insensitive compare function will be used. + + use warnings ; + use strict ; + use DB_File ; + + my %h ; + + sub Compare + { + my ($key1, $key2) = @_ ; + "\L$key1" cmp "\L$key2" ; + } + + # specify the Perl sub that will do the comparison + $DB_BTREE->{'compare'} = \&Compare ; + + unlink "tree" ; + tie %h, "DB_File", "tree", O_RDWR|O_CREAT, 0640, $DB_BTREE + or die "Cannot open file 'tree': $!\n" ; + + # Add a key/value pair to the file + $h{'Wall'} = 'Larry' ; + $h{'Smith'} = 'John' ; + $h{'mouse'} = 'mickey' ; + $h{'duck'} = 'donald' ; + + # Delete + delete $h{"duck"} ; + + # Cycle through the keys printing them in order. + # Note it is not necessary to sort the keys as + # the btree will have kept them in order automatically. + foreach (keys %h) + { print "$_\n" } + + untie %h ; + +Here is the output from the code above. + + mouse + Smith + Wall + +There are a few point to bear in mind if you want to change the +ordering in a BTREE database: + +=over 5 + +=item 1. + +The new compare function must be specified when you create the database. + +=item 2. + +You cannot change the ordering once the database has been created. Thus +you must use the same compare function every time you access the +database. + +=back + +=head2 Handling Duplicate Keys + +The BTREE file type optionally allows a single key to be associated +with an arbitrary number of values. This option is enabled by setting +the flags element of C<$DB_BTREE> to R_DUP when creating the database. + +There are some difficulties in using the tied hash interface if you +want to manipulate a BTREE database with duplicate keys. Consider this +code: + + use warnings ; + use strict ; + use DB_File ; + + use vars qw($filename %h ) ; + + $filename = "tree" ; + unlink $filename ; + + # Enable duplicate records + $DB_BTREE->{'flags'} = R_DUP ; + + tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0640, $DB_BTREE + or die "Cannot open $filename: $!\n"; + + # Add some key/value pairs to the file + $h{'Wall'} = 'Larry' ; + $h{'Wall'} = 'Brick' ; # Note the duplicate key + $h{'Wall'} = 'Brick' ; # Note the duplicate key and value + $h{'Smith'} = 'John' ; + $h{'mouse'} = 'mickey' ; + + # iterate through the associative array + # and print each key/value pair. + foreach (sort keys %h) + { print "$_ -> $h{$_}\n" } + + untie %h ; + +Here is the output: + + Smith -> John + Wall -> Larry + Wall -> Larry + Wall -> Larry + mouse -> mickey + +As you can see 3 records have been successfully created with key C +- the only thing is, when they are retrieved from the database they +I to have the same value, namely C. The problem is caused +by the way that the associative array interface works. Basically, when +the associative array interface is used to fetch the value associated +with a given key, it will only ever retrieve the first value. + +Although it may not be immediately obvious from the code above, the +associative array interface can be used to write values with duplicate +keys, but it cannot be used to read them back from the database. + +The way to get around this problem is to use the Berkeley DB API method +called C. This method allows sequential access to key/value +pairs. See L for details of both the C method +and the API in general. + +Here is the script above rewritten using the C API method. + + use warnings ; + use strict ; + use DB_File ; + + use vars qw($filename $x %h $status $key $value) ; + + $filename = "tree" ; + unlink $filename ; + + # Enable duplicate records + $DB_BTREE->{'flags'} = R_DUP ; + + $x = tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0640, $DB_BTREE + or die "Cannot open $filename: $!\n"; + + # Add some key/value pairs to the file + $h{'Wall'} = 'Larry' ; + $h{'Wall'} = 'Brick' ; # Note the duplicate key + $h{'Wall'} = 'Brick' ; # Note the duplicate key and value + $h{'Smith'} = 'John' ; + $h{'mouse'} = 'mickey' ; + + # iterate through the btree using seq + # and print each key/value pair. + $key = $value = 0 ; + for ($status = $x->seq($key, $value, R_FIRST) ; + $status == 0 ; + $status = $x->seq($key, $value, R_NEXT) ) + { print "$key -> $value\n" } + + undef $x ; + untie %h ; + +that prints: + + Smith -> John + Wall -> Brick + Wall -> Brick + Wall -> Larry + mouse -> mickey + +This time we have got all the key/value pairs, including the multiple +values associated with the key C. + +To make life easier when dealing with duplicate keys, B comes with +a few utility methods. + +=head2 The get_dup() Method + +The C method assists in +reading duplicate values from BTREE databases. The method can take the +following forms: + + $count = $x->get_dup($key) ; + @list = $x->get_dup($key) ; + %list = $x->get_dup($key, 1) ; + +In a scalar context the method returns the number of values associated +with the key, C<$key>. + +In list context, it returns all the values which match C<$key>. Note +that the values will be returned in an apparently random order. + +In list context, if the second parameter is present and evaluates +TRUE, the method returns an associative array. The keys of the +associative array correspond to the values that matched in the BTREE +and the values of the array are a count of the number of times that +particular value occurred in the BTREE. + +So assuming the database created above, we can use C like +this: + + use warnings ; + use strict ; + use DB_File ; + + use vars qw($filename $x %h ) ; + + $filename = "tree" ; + + # Enable duplicate records + $DB_BTREE->{'flags'} = R_DUP ; + + $x = tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0640, $DB_BTREE + or die "Cannot open $filename: $!\n"; + + my $cnt = $x->get_dup("Wall") ; + print "Wall occurred $cnt times\n" ; + + my %hash = $x->get_dup("Wall", 1) ; + print "Larry is there\n" if $hash{'Larry'} ; + print "There are $hash{'Brick'} Brick Walls\n" ; + + my @list = sort $x->get_dup("Wall") ; + print "Wall => [@list]\n" ; + + @list = $x->get_dup("Smith") ; + print "Smith => [@list]\n" ; + + @list = $x->get_dup("Dog") ; + print "Dog => [@list]\n" ; + + +and it will print: + + Wall occurred 3 times + Larry is there + There are 2 Brick Walls + Wall => [Brick Brick Larry] + Smith => [John] + Dog => [] + +=head2 The find_dup() Method + + $status = $X->find_dup($key, $value) ; + +This method checks for the existence of a specific key/value pair. If the +pair exists, the cursor is left pointing to the pair and the method +returns 0. Otherwise the method returns a non-zero value. + +Assuming the database from the previous example: + + use warnings ; + use strict ; + use DB_File ; + + use vars qw($filename $x %h $found) ; + + my $filename = "tree" ; + + # Enable duplicate records + $DB_BTREE->{'flags'} = R_DUP ; + + $x = tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0640, $DB_BTREE + or die "Cannot open $filename: $!\n"; + + $found = ( $x->find_dup("Wall", "Larry") == 0 ? "" : "not") ; + print "Larry Wall is $found there\n" ; + + $found = ( $x->find_dup("Wall", "Harry") == 0 ? "" : "not") ; + print "Harry Wall is $found there\n" ; + + undef $x ; + untie %h ; + +prints this + + Larry Wall is there + Harry Wall is not there + + +=head2 The del_dup() Method + + $status = $X->del_dup($key, $value) ; + +This method deletes a specific key/value pair. It returns +0 if they exist and have been deleted successfully. +Otherwise the method returns a non-zero value. + +Again assuming the existence of the C database + + use warnings ; + use strict ; + use DB_File ; + + use vars qw($filename $x %h $found) ; + + my $filename = "tree" ; + + # Enable duplicate records + $DB_BTREE->{'flags'} = R_DUP ; + + $x = tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0640, $DB_BTREE + or die "Cannot open $filename: $!\n"; + + $x->del_dup("Wall", "Larry") ; + + $found = ( $x->find_dup("Wall", "Larry") == 0 ? "" : "not") ; + print "Larry Wall is $found there\n" ; + + undef $x ; + untie %h ; + +prints this + + Larry Wall is not there + +=head2 Matching Partial Keys + +The BTREE interface has a feature which allows partial keys to be +matched. This functionality is I available when the C method +is used along with the R_CURSOR flag. + + $x->seq($key, $value, R_CURSOR) ; + +Here is the relevant quote from the dbopen man page where it defines +the use of the R_CURSOR flag with seq: + + Note, for the DB_BTREE access method, the returned key is not + necessarily an exact match for the specified key. The returned key + is the smallest key greater than or equal to the specified key, + permitting partial key matches and range searches. + +In the example script below, the C sub uses this feature to find +and print the first matching key/value pair given a partial key. + + use warnings ; + use strict ; + use DB_File ; + use Fcntl ; + + use vars qw($filename $x %h $st $key $value) ; + + sub match + { + my $key = shift ; + my $value = 0; + my $orig_key = $key ; + $x->seq($key, $value, R_CURSOR) ; + print "$orig_key\t-> $key\t-> $value\n" ; + } + + $filename = "tree" ; + unlink $filename ; + + $x = tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0640, $DB_BTREE + or die "Cannot open $filename: $!\n"; + + # Add some key/value pairs to the file + $h{'mouse'} = 'mickey' ; + $h{'Wall'} = 'Larry' ; + $h{'Walls'} = 'Brick' ; + $h{'Smith'} = 'John' ; + + + $key = $value = 0 ; + print "IN ORDER\n" ; + for ($st = $x->seq($key, $value, R_FIRST) ; + $st == 0 ; + $st = $x->seq($key, $value, R_NEXT) ) + + { print "$key -> $value\n" } + + print "\nPARTIAL MATCH\n" ; + + match "Wa" ; + match "A" ; + match "a" ; + + undef $x ; + untie %h ; + +Here is the output: + + IN ORDER + Smith -> John + Wall -> Larry + Walls -> Brick + mouse -> mickey + + PARTIAL MATCH + Wa -> Wall -> Larry + A -> Smith -> John + a -> mouse -> mickey + +=head1 DB_RECNO + +DB_RECNO provides an interface to flat text files. Both variable and +fixed length records are supported. + +In order to make RECNO more compatible with Perl, the array offset for +all RECNO arrays begins at 0 rather than 1 as in Berkeley DB. + +As with normal Perl arrays, a RECNO array can be accessed using +negative indexes. The index -1 refers to the last element of the array, +-2 the second last, and so on. Attempting to access an element before +the start of the array will raise a fatal run-time error. + +=head2 The 'bval' Option + +The operation of the bval option warrants some discussion. Here is the +definition of bval from the Berkeley DB 1.85 recno manual page: + + The delimiting byte to be used to mark the end of a + record for variable-length records, and the pad charac- + ter for fixed-length records. If no value is speci- + fied, newlines (``\n'') are used to mark the end of + variable-length records and fixed-length records are + padded with spaces. + +The second sentence is wrong. In actual fact bval will only default to +C<"\n"> when the openinfo parameter in dbopen is NULL. If a non-NULL +openinfo parameter is used at all, the value that happens to be in bval +will be used. That means you always have to specify bval when making +use of any of the options in the openinfo parameter. This documentation +error will be fixed in the next release of Berkeley DB. + +That clarifies the situation with regards Berkeley DB itself. What +about B? Well, the behavior defined in the quote above is +quite useful, so B conforms to it. + +That means that you can specify other options (e.g. cachesize) and +still have bval default to C<"\n"> for variable length records, and +space for fixed length records. + +=head2 A Simple Example + +Here is a simple example that uses RECNO (if you are using a version +of Perl earlier than 5.004_57 this example won't work -- see +L for a workaround). + + use warnings ; + use strict ; + use DB_File ; + + my $filename = "text" ; + unlink $filename ; + + my @h ; + tie @h, "DB_File", $filename, O_RDWR|O_CREAT, 0640, $DB_RECNO + or die "Cannot open file 'text': $!\n" ; + + # Add a few key/value pairs to the file + $h[0] = "orange" ; + $h[1] = "blue" ; + $h[2] = "yellow" ; + + push @h, "green", "black" ; + + my $elements = scalar @h ; + print "The array contains $elements entries\n" ; + + my $last = pop @h ; + print "popped $last\n" ; + + unshift @h, "white" ; + my $first = shift @h ; + print "shifted $first\n" ; + + # Check for existence of a key + print "Element 1 Exists with value $h[1]\n" if $h[1] ; + + # use a negative index + print "The last element is $h[-1]\n" ; + print "The 2nd last element is $h[-2]\n" ; + + untie @h ; + +Here is the output from the script: + + The array contains 5 entries + popped black + shifted white + Element 1 Exists with value blue + The last element is green + The 2nd last element is yellow + +=head2 Extra RECNO Methods + +If you are using a version of Perl earlier than 5.004_57, the tied +array interface is quite limited. In the example script above +C, C, C, C +or determining the array length will not work with a tied array. + +To make the interface more useful for older versions of Perl, a number +of methods are supplied with B to simulate the missing array +operations. All these methods are accessed via the object returned from +the tie call. + +Here are the methods: + +=over 5 + +=item B<$X-Epush(list) ;> + +Pushes the elements of C to the end of the array. + +=item B<$value = $X-Epop ;> + +Removes and returns the last element of the array. + +=item B<$X-Eshift> + +Removes and returns the first element of the array. + +=item B<$X-Eunshift(list) ;> + +Pushes the elements of C to the start of the array. + +=item B<$X-Elength> + +Returns the number of elements in the array. + +=back + +=head2 Another Example + +Here is a more complete example that makes use of some of the methods +described above. It also makes use of the API interface directly (see +L). + + use warnings ; + use strict ; + use vars qw(@h $H $file $i) ; + use DB_File ; + use Fcntl ; + + $file = "text" ; + + unlink $file ; + + $H = tie @h, "DB_File", $file, O_RDWR|O_CREAT, 0640, $DB_RECNO + or die "Cannot open file $file: $!\n" ; + + # first create a text file to play with + $h[0] = "zero" ; + $h[1] = "one" ; + $h[2] = "two" ; + $h[3] = "three" ; + $h[4] = "four" ; + + + # Print the records in order. + # + # The length method is needed here because evaluating a tied + # array in a scalar context does not return the number of + # elements in the array. + + print "\nORIGINAL\n" ; + foreach $i (0 .. $H->length - 1) { + print "$i: $h[$i]\n" ; + } + + # use the push & pop methods + $a = $H->pop ; + $H->push("last") ; + print "\nThe last record was [$a]\n" ; + + # and the shift & unshift methods + $a = $H->shift ; + $H->unshift("first") ; + print "The first record was [$a]\n" ; + + # Use the API to add a new record after record 2. + $i = 2 ; + $H->put($i, "Newbie", R_IAFTER) ; + + # and a new record before record 1. + $i = 1 ; + $H->put($i, "New One", R_IBEFORE) ; + + # delete record 3 + $H->del(3) ; + + # now print the records in reverse order + print "\nREVERSE\n" ; + for ($i = $H->length - 1 ; $i >= 0 ; -- $i) + { print "$i: $h[$i]\n" } + + # same again, but use the API functions instead + print "\nREVERSE again\n" ; + my ($s, $k, $v) = (0, 0, 0) ; + for ($s = $H->seq($k, $v, R_LAST) ; + $s == 0 ; + $s = $H->seq($k, $v, R_PREV)) + { print "$k: $v\n" } + + undef $H ; + untie @h ; + +and this is what it outputs: + + ORIGINAL + 0: zero + 1: one + 2: two + 3: three + 4: four + + The last record was [four] + The first record was [zero] + + REVERSE + 5: last + 4: three + 3: Newbie + 2: one + 1: New One + 0: first + + REVERSE again + 5: last + 4: three + 3: Newbie + 2: one + 1: New One + 0: first + +Notes: + +=over 5 + +=item 1. + +Rather than iterating through the array, C<@h> like this: + + foreach $i (@h) + +it is necessary to use either this: + + foreach $i (0 .. $H->length - 1) + +or this: + + for ($a = $H->get($k, $v, R_FIRST) ; + $a == 0 ; + $a = $H->get($k, $v, R_NEXT) ) + +=item 2. + +Notice that both times the C method was used the record index was +specified using a variable, C<$i>, rather than the literal value +itself. This is because C will return the record number of the +inserted line via that parameter. + +=back + +=head1 THE API INTERFACE + +As well as accessing Berkeley DB using a tied hash or array, it is also +possible to make direct use of most of the API functions defined in the +Berkeley DB documentation. + +To do this you need to store a copy of the object returned from the tie. + + $db = tie %hash, "DB_File", "filename" ; + +Once you have done that, you can access the Berkeley DB API functions +as B methods directly like this: + + $db->put($key, $value, R_NOOVERWRITE) ; + +B If you have saved a copy of the object returned from +C, the underlying database file will I be closed until both +the tied variable is untied and all copies of the saved object are +destroyed. + + use DB_File ; + $db = tie %hash, "DB_File", "filename" + or die "Cannot tie filename: $!" ; + ... + undef $db ; + untie %hash ; + +See L for more details. + +All the functions defined in L are available except for +close() and dbopen() itself. The B method interface to the +supported functions have been implemented to mirror the way Berkeley DB +works whenever possible. In particular note that: + +=over 5 + +=item * + +The methods return a status value. All return 0 on success. +All return -1 to signify an error and set C<$!> to the exact +error code. The return code 1 generally (but not always) means that the +key specified did not exist in the database. + +Other return codes are defined. See below and in the Berkeley DB +documentation for details. The Berkeley DB documentation should be used +as the definitive source. + +=item * + +Whenever a Berkeley DB function returns data via one of its parameters, +the equivalent B method does exactly the same. + +=item * + +If you are careful, it is possible to mix API calls with the tied +hash/array interface in the same piece of code. Although only a few of +the methods used to implement the tied interface currently make use of +the cursor, you should always assume that the cursor has been changed +any time the tied hash/array interface is used. As an example, this +code will probably not do what you expect: + + $X = tie %x, 'DB_File', $filename, O_RDWR|O_CREAT, 0777, $DB_BTREE + or die "Cannot tie $filename: $!" ; + + # Get the first key/value pair and set the cursor + $X->seq($key, $value, R_FIRST) ; + + # this line will modify the cursor + $count = scalar keys %x ; + + # Get the second key/value pair. + # oops, it didn't, it got the last key/value pair! + $X->seq($key, $value, R_NEXT) ; + +The code above can be rearranged to get around the problem, like this: + + $X = tie %x, 'DB_File', $filename, O_RDWR|O_CREAT, 0777, $DB_BTREE + or die "Cannot tie $filename: $!" ; + + # this line will modify the cursor + $count = scalar keys %x ; + + # Get the first key/value pair and set the cursor + $X->seq($key, $value, R_FIRST) ; + + # Get the second key/value pair. + # worked this time. + $X->seq($key, $value, R_NEXT) ; + +=back + +All the constants defined in L for use in the flags parameters +in the methods defined below are also available. Refer to the Berkeley +DB documentation for the precise meaning of the flags values. + +Below is a list of the methods available. + +=over 5 + +=item B<$status = $X-Eget($key, $value [, $flags]) ;> + +Given a key (C<$key>) this method reads the value associated with it +from the database. The value read from the database is returned in the +C<$value> parameter. + +If the key does not exist the method returns 1. + +No flags are currently defined for this method. + +=item B<$status = $X-Eput($key, $value [, $flags]) ;> + +Stores the key/value pair in the database. + +If you use either the R_IAFTER or R_IBEFORE flags, the C<$key> parameter +will have the record number of the inserted key/value pair set. + +Valid flags are R_CURSOR, R_IAFTER, R_IBEFORE, R_NOOVERWRITE and +R_SETCURSOR. + +=item B<$status = $X-Edel($key [, $flags]) ;> + +Removes all key/value pairs with key C<$key> from the database. + +A return code of 1 means that the requested key was not in the +database. + +R_CURSOR is the only valid flag at present. + +=item B<$status = $X-Efd ;> + +Returns the file descriptor for the underlying database. + +See L for an explanation for why you should +not use C to lock your database. + +=item B<$status = $X-Eseq($key, $value, $flags) ;> + +This interface allows sequential retrieval from the database. See +L for full details. + +Both the C<$key> and C<$value> parameters will be set to the key/value +pair read from the database. + +The flags parameter is mandatory. The valid flag values are R_CURSOR, +R_FIRST, R_LAST, R_NEXT and R_PREV. + +=item B<$status = $X-Esync([$flags]) ;> + +Flushes any cached buffers to disk. + +R_RECNOSYNC is the only valid flag at present. + +=back + +=head1 DBM FILTERS + +A DBM Filter is a piece of code that is be used when you I +want to make the same transformation to all keys and/or values in a +DBM database. + +There are four methods associated with DBM Filters. All work identically, +and each is used to install (or uninstall) a single DBM Filter. Each +expects a single parameter, namely a reference to a sub. The only +difference between them is the place that the filter is installed. + +To summarise: + +=over 5 + +=item B + +If a filter has been installed with this method, it will be invoked +every time you write a key to a DBM database. + +=item B + +If a filter has been installed with this method, it will be invoked +every time you write a value to a DBM database. + + +=item B + +If a filter has been installed with this method, it will be invoked +every time you read a key from a DBM database. + +=item B + +If a filter has been installed with this method, it will be invoked +every time you read a value from a DBM database. + +=back + +You can use any combination of the methods, from none, to all four. + +All filter methods return the existing filter, if present, or C +in not. + +To delete a filter pass C to it. + +=head2 The Filter + +When each filter is called by Perl, a local copy of C<$_> will contain +the key or value to be filtered. Filtering is achieved by modifying +the contents of C<$_>. The return code from the filter is ignored. + +=head2 An Example -- the NULL termination problem. + +Consider the following scenario. You have a DBM database +that you need to share with a third-party C application. The C application +assumes that I keys and values are NULL terminated. Unfortunately +when Perl writes to DBM databases it doesn't use NULL termination, so +your Perl application will have to manage NULL termination itself. When +you write to the database you will have to use something like this: + + $hash{"$key\0"} = "$value\0" ; + +Similarly the NULL needs to be taken into account when you are considering +the length of existing keys/values. + +It would be much better if you could ignore the NULL terminations issue +in the main application code and have a mechanism that automatically +added the terminating NULL to all keys and values whenever you write to +the database and have them removed when you read from the database. As I'm +sure you have already guessed, this is a problem that DBM Filters can +fix very easily. + + use warnings ; + use strict ; + use DB_File ; + + my %hash ; + my $filename = "/tmp/filt" ; + unlink $filename ; + + my $db = tie %hash, 'DB_File', $filename, O_CREAT|O_RDWR, 0666, $DB_HASH + or die "Cannot open $filename: $!\n" ; + + # Install DBM Filters + $db->filter_fetch_key ( sub { s/\0$// } ) ; + $db->filter_store_key ( sub { $_ .= "\0" } ) ; + $db->filter_fetch_value( sub { s/\0$// } ) ; + $db->filter_store_value( sub { $_ .= "\0" } ) ; + + $hash{"abc"} = "def" ; + my $a = $hash{"ABC"} ; + # ... + undef $db ; + untie %hash ; + +Hopefully the contents of each of the filters should be +self-explanatory. Both "fetch" filters remove the terminating NULL, +and both "store" filters add a terminating NULL. + + +=head2 Another Example -- Key is a C int. + +Here is another real-life example. By default, whenever Perl writes to +a DBM database it always writes the key and value as strings. So when +you use this: + + $hash{12345} = "soemthing" ; + +the key 12345 will get stored in the DBM database as the 5 byte string +"12345". If you actually want the key to be stored in the DBM database +as a C int, you will have to use C when writing, and C +when reading. + +Here is a DBM Filter that does it: + + use warnings ; + use strict ; + use DB_File ; + my %hash ; + my $filename = "/tmp/filt" ; + unlink $filename ; + + + my $db = tie %hash, 'DB_File', $filename, O_CREAT|O_RDWR, 0666, $DB_HASH + or die "Cannot open $filename: $!\n" ; + + $db->filter_fetch_key ( sub { $_ = unpack("i", $_) } ) ; + $db->filter_store_key ( sub { $_ = pack ("i", $_) } ) ; + $hash{123} = "def" ; + # ... + undef $db ; + untie %hash ; + +This time only two filters have been used -- we only need to manipulate +the contents of the key, so it wasn't necessary to install any value +filters. + +=head1 HINTS AND TIPS + + +=head2 Locking: The Trouble with fd + +Until version 1.72 of this module, the recommended technique for locking +B databases was to flock the filehandle returned from the "fd" +function. Unfortunately this technique has been shown to be fundamentally +flawed (Kudos to David Harris for tracking this down). Use it at your own +peril! + +The locking technique went like this. + + $db = tie(%db, 'DB_File', '/tmp/foo.db', O_CREAT|O_RDWR, 0644) + || die "dbcreat /tmp/foo.db $!"; + $fd = $db->fd; + open(DB_FH, "+<&=$fd") || die "dup $!"; + flock (DB_FH, LOCK_EX) || die "flock: $!"; + ... + $db{"Tom"} = "Jerry" ; + ... + flock(DB_FH, LOCK_UN); + undef $db; + untie %db; + close(DB_FH); + +In simple terms, this is what happens: + +=over 5 + +=item 1. + +Use "tie" to open the database. + +=item 2. + +Lock the database with fd & flock. + +=item 3. + +Read & Write to the database. + +=item 4. + +Unlock and close the database. + +=back + +Here is the crux of the problem. A side-effect of opening the B +database in step 2 is that an initial block from the database will get +read from disk and cached in memory. + +To see why this is a problem, consider what can happen when two processes, +say "A" and "B", both want to update the same B database +using the locking steps outlined above. Assume process "A" has already +opened the database and has a write lock, but it hasn't actually updated +the database yet (it has finished step 2, but not started step 3 yet). Now +process "B" tries to open the same database - step 1 will succeed, +but it will block on step 2 until process "A" releases the lock. The +important thing to notice here is that at this point in time both +processes will have cached identical initial blocks from the database. + +Now process "A" updates the database and happens to change some of the +data held in the initial buffer. Process "A" terminates, flushing +all cached data to disk and releasing the database lock. At this point +the database on disk will correctly reflect the changes made by process +"A". + +With the lock released, process "B" can now continue. It also updates the +database and unfortunately it too modifies the data that was in its +initial buffer. Once that data gets flushed to disk it will overwrite +some/all of the changes process "A" made to the database. + +The result of this scenario is at best a database that doesn't contain +what you expect. At worst the database will corrupt. + +The above won't happen every time competing process update the same +B database, but it does illustrate why the technique should +not be used. + +=head2 Safe ways to lock a database + +Starting with version 2.x, Berkeley DB has internal support for locking. +The companion module to this one, B, provides an interface +to this locking functionality. If you are serious about locking +Berkeley DB databases, I strongly recommend using B. + +If using B isn't an option, there are a number of modules +available on CPAN that can be used to implement locking. Each one +implements locking differently and has different goals in mind. It is +therefore worth knowing the difference, so that you can pick the right +one for your application. Here are the three locking wrappers: + +=over 5 + +=item B + +A B wrapper which creates copies of the database file for +read access, so that you have a kind of a multiversioning concurrent read +system. However, updates are still serial. Use for databases where reads +may be lengthy and consistency problems may occur. + +=item B + +A B wrapper that has the ability to lock and unlock the database +while it is being used. Avoids the tie-before-flock problem by simply +re-tie-ing the database when you get or drop a lock. Because of the +flexibility in dropping and re-acquiring the lock in the middle of a +session, this can be massaged into a system that will work with long +updates and/or reads if the application follows the hints in the POD +documentation. + +=item B + +An extremely lightweight B wrapper that simply flocks a lockfile +before tie-ing the database and drops the lock after the untie. Allows +one to use the same lockfile for multiple databases to avoid deadlock +problems, if desired. Use for databases where updates are reads are +quick and simple flock locking semantics are enough. + +=back + +=head2 Sharing Databases With C Applications + +There is no technical reason why a Berkeley DB database cannot be +shared by both a Perl and a C application. + +The vast majority of problems that are reported in this area boil down +to the fact that C strings are NULL terminated, whilst Perl strings are +not. See L for a generic way to work around this problem. + +Here is a real example. Netscape 2.0 keeps a record of the locations you +visit along with the time you last visited them in a DB_HASH database. +This is usually stored in the file F<~/.netscape/history.db>. The key +field in the database is the location string and the value field is the +time the location was last visited stored as a 4 byte binary value. + +If you haven't already guessed, the location string is stored with a +terminating NULL. This means you need to be careful when accessing the +database. + +Here is a snippet of code that is loosely based on Tom Christiansen's +I script (available from your nearest CPAN archive in +F). + + use warnings ; + use strict ; + use DB_File ; + use Fcntl ; + + use vars qw( $dotdir $HISTORY %hist_db $href $binary_time $date ) ; + $dotdir = $ENV{HOME} || $ENV{LOGNAME}; + + $HISTORY = "$dotdir/.netscape/history.db"; + + tie %hist_db, 'DB_File', $HISTORY + or die "Cannot open $HISTORY: $!\n" ;; + + # Dump the complete database + while ( ($href, $binary_time) = each %hist_db ) { + + # remove the terminating NULL + $href =~ s/\x00$// ; + + # convert the binary time into a user friendly string + $date = localtime unpack("V", $binary_time); + print "$date $href\n" ; + } + + # check for the existence of a specific key + # remember to add the NULL + if ( $binary_time = $hist_db{"http://mox.perl.com/\x00"} ) { + $date = localtime unpack("V", $binary_time) ; + print "Last visited mox.perl.com on $date\n" ; + } + else { + print "Never visited mox.perl.com\n" + } + + untie %hist_db ; + +=head2 The untie() Gotcha + +If you make use of the Berkeley DB API, it is I strongly +recommended that you read L. + +Even if you don't currently make use of the API interface, it is still +worth reading it. + +Here is an example which illustrates the problem from a B +perspective: + + use DB_File ; + use Fcntl ; + + my %x ; + my $X ; + + $X = tie %x, 'DB_File', 'tst.fil' , O_RDWR|O_TRUNC + or die "Cannot tie first time: $!" ; + + $x{123} = 456 ; + + untie %x ; + + tie %x, 'DB_File', 'tst.fil' , O_RDWR|O_CREAT + or die "Cannot tie second time: $!" ; + + untie %x ; + +When run, the script will produce this error message: + + Cannot tie second time: Invalid argument at bad.file line 14. + +Although the error message above refers to the second tie() statement +in the script, the source of the problem is really with the untie() +statement that precedes it. + +Having read L you will probably have already guessed that the +error is caused by the extra copy of the tied object stored in C<$X>. +If you haven't, then the problem boils down to the fact that the +B destructor, DESTROY, will not be called until I +references to the tied object are destroyed. Both the tied variable, +C<%x>, and C<$X> above hold a reference to the object. The call to +untie() will destroy the first, but C<$X> still holds a valid +reference, so the destructor will not get called and the database file +F will remain open. The fact that Berkeley DB then reports the +attempt to open a database that is already open via the catch-all +"Invalid argument" doesn't help. + +If you run the script with the C<-w> flag the error message becomes: + + untie attempted while 1 inner references still exist at bad.file line 12. + Cannot tie second time: Invalid argument at bad.file line 14. + +which pinpoints the real problem. Finally the script can now be +modified to fix the original problem by destroying the API object +before the untie: + + ... + $x{123} = 456 ; + + undef $X ; + untie %x ; + + $X = tie %x, 'DB_File', 'tst.fil' , O_RDWR|O_CREAT + ... + + +=head1 COMMON QUESTIONS + +=head2 Why is there Perl source in my database? + +If you look at the contents of a database file created by DB_File, +there can sometimes be part of a Perl script included in it. + +This happens because Berkeley DB uses dynamic memory to allocate +buffers which will subsequently be written to the database file. Being +dynamic, the memory could have been used for anything before DB +malloced it. As Berkeley DB doesn't clear the memory once it has been +allocated, the unused portions will contain random junk. In the case +where a Perl script gets written to the database, the random junk will +correspond to an area of dynamic memory that happened to be used during +the compilation of the script. + +Unless you don't like the possibility of there being part of your Perl +scripts embedded in a database file, this is nothing to worry about. + +=head2 How do I store complex data structures with DB_File? + +Although B cannot do this directly, there is a module which +can layer transparently over B to accomplish this feat. + +Check out the MLDBM module, available on CPAN in the directory +F. + +=head2 What does "Invalid Argument" mean? + +You will get this error message when one of the parameters in the +C call is wrong. Unfortunately there are quite a few parameters to +get wrong, so it can be difficult to figure out which one it is. + +Here are a couple of possibilities: + +=over 5 + +=item 1. + +Attempting to reopen a database without closing it. + +=item 2. + +Using the O_WRONLY flag. + +=back + +=head2 What does "Bareword 'DB_File' not allowed" mean? + +You will encounter this particular error message when you have the +C pragma (or the full strict pragma) in your script. +Consider this script: + + use warnings ; + use strict ; + use DB_File ; + use vars qw(%x) ; + tie %x, DB_File, "filename" ; + +Running it produces the error in question: + + Bareword "DB_File" not allowed while "strict subs" in use + +To get around the error, place the word C in either single or +double quotes, like this: + + tie %x, "DB_File", "filename" ; + +Although it might seem like a real pain, it is really worth the effort +of having a C in all your scripts. + +=head1 REFERENCES + +Articles that are either about B or make use of it. + +=over 5 + +=item 1. + +I, Tim Kientzle (tkientzle@ddj.com), +Dr. Dobb's Journal, Issue 295, January 1999, pp 34-41 + +=back + +=head1 HISTORY + +Moved to the Changes file. + +=head1 BUGS + +Some older versions of Berkeley DB had problems with fixed length +records using the RECNO file format. This problem has been fixed since +version 1.85 of Berkeley DB. + +I am sure there are bugs in the code. If you do find any, or can +suggest any enhancements, I would welcome your comments. + +=head1 AVAILABILITY + +B comes with the standard Perl source distribution. Look in +the directory F. Given the amount of time between releases +of Perl the version that ships with Perl is quite likely to be out of +date, so the most recent version can always be found on CPAN (see +L for details), in the directory +F. + +This version of B will work with either version 1.x, 2.x or +3.x of Berkeley DB, but is limited to the functionality provided by +version 1. + +The official web site for Berkeley DB is F. +All versions of Berkeley DB are available there. + +Alternatively, Berkeley DB version 1 is available at your nearest CPAN +archive in F. + +If you are running IRIX, then get Berkeley DB version 1 from +F. It has the patches necessary to +compile properly on IRIX 5.3. + +=head1 COPYRIGHT + +Copyright (c) 1995-1999 Paul Marquess. All rights reserved. This program +is free software; you can redistribute it and/or modify it under the +same terms as Perl itself. + +Although B is covered by the Perl license, the library it +makes use of, namely Berkeley DB, is not. Berkeley DB has its own +copyright and its own license. Please take the time to read it. + +Here are are few words taken from the Berkeley DB FAQ (at +F) regarding the license: + + Do I have to license DB to use it in Perl scripts? + + No. The Berkeley DB license requires that software that uses + Berkeley DB be freely redistributable. In the case of Perl, that + software is Perl, and not your scripts. Any Perl scripts that you + write are your property, including scripts that make use of + Berkeley DB. Neither the Perl license nor the Berkeley DB license + place any restriction on what you may do with them. + +If you are in any doubt about the license situation, contact either the +Berkeley DB authors or the author of DB_File. See L<"AUTHOR"> for details. + + +=head1 SEE ALSO + +L, L, L, L, L, +L + +=head1 AUTHOR + +The DB_File interface was written by Paul Marquess +EPaul.Marquess@btinternet.comE. +Questions about the DB system itself may be addressed to +Edb@sleepycat.com. + +=cut diff --git a/db/perl.DB_File/DB_File.xs b/db/perl.DB_File/DB_File.xs new file mode 100644 index 000000000..681134206 --- /dev/null +++ b/db/perl.DB_File/DB_File.xs @@ -0,0 +1,2072 @@ +/* + + DB_File.xs -- Perl 5 interface to Berkeley DB + + written by Paul Marquess + last modified 15th January 2001 + version 1.76 + + All comments/suggestions/problems are welcome + + Copyright (c) 1995-2001 Paul Marquess. All rights reserved. + This program is free software; you can redistribute it and/or + modify it under the same terms as Perl itself. + + Changes: + 0.1 - Initial Release + 0.2 - No longer bombs out if dbopen returns an error. + 0.3 - Added some support for multiple btree compares + 1.0 - Complete support for multiple callbacks added. + Fixed a problem with pushing a value onto an empty list. + 1.01 - Fixed a SunOS core dump problem. + The return value from TIEHASH wasn't set to NULL when + dbopen returned an error. + 1.02 - Use ALIAS to define TIEARRAY. + Removed some redundant commented code. + Merged OS2 code into the main distribution. + Allow negative subscripts with RECNO interface. + Changed the default flags to O_CREAT|O_RDWR + 1.03 - Added EXISTS + 1.04 - fixed a couple of bugs in hash_cb. Patches supplied by + Dave Hammen, hammen@gothamcity.jsc.nasa.gov + 1.05 - Added logic to allow prefix & hash types to be specified via + Makefile.PL + 1.06 - Minor namespace cleanup: Localized PrintBtree. + 1.07 - Fixed bug with RECNO, where bval wasn't defaulting to "\n". + 1.08 - No change to DB_File.xs + 1.09 - Default mode for dbopen changed to 0666 + 1.10 - Fixed fd method so that it still returns -1 for + in-memory files when db 1.86 is used. + 1.11 - No change to DB_File.xs + 1.12 - No change to DB_File.xs + 1.13 - Tidied up a few casts. + 1.14 - Made it illegal to tie an associative array to a RECNO + database and an ordinary array to a HASH or BTREE database. + 1.50 - Make work with both DB 1.x or DB 2.x + 1.51 - Fixed a bug in mapping 1.x O_RDONLY flag to 2.x DB_RDONLY equivalent + 1.52 - Patch from Gisle Aas to suppress "use of + undefined value" warning with db_get and db_seq. + 1.53 - Added DB_RENUMBER to flags for recno. + 1.54 - Fixed bug in the fd method + 1.55 - Fix for AIX from Jarkko Hietaniemi + 1.56 - No change to DB_File.xs + 1.57 - added the #undef op to allow building with Threads support. + 1.58 - Fixed a problem with the use of sv_setpvn. When the + size is specified as 0, it does a strlen on the data. + This was ok for DB 1.x, but isn't for DB 2.x. + 1.59 - No change to DB_File.xs + 1.60 - Some code tidy up + 1.61 - added flagSet macro for DB 2.5.x + fixed typo in O_RDONLY test. + 1.62 - No change to DB_File.xs + 1.63 - Fix to alllow DB 2.6.x to build. + 1.64 - Tidied up the 1.x to 2.x flags mapping code. + Added a patch from Mark Kettenis + to fix a flag mapping problem with O_RDONLY on the Hurd + 1.65 - Fixed a bug in the PUSH logic. + Added BOOT check that using 2.3.4 or greater + 1.66 - Added DBM filter code + 1.67 - Backed off the use of newSVpvn. + Fixed DBM Filter code for Perl 5.004. + Fixed a small memory leak in the filter code. + 1.68 - fixed backward compatability bug with R_IAFTER & R_IBEFORE + merged in the 5.005_58 changes + 1.69 - fixed a bug in push -- DB_APPEND wasn't working properly. + Fixed the R_SETCURSOR bug introduced in 1.68 + Added a new Perl variable $DB_File::db_ver + 1.70 - Initialise $DB_File::db_ver and $DB_File::db_version with + GV_ADD|GV_ADDMULT -- bug spotted by Nick Ing-Simmons. + Added a BOOT check to test for equivalent versions of db.h & + libdb.a/so. + 1.71 - Support for Berkeley DB version 3. + Support for Berkeley DB 2/3's backward compatability mode. + Rewrote push + 1.72 - No change to DB_File.xs + 1.73 - No change to DB_File.xs + 1.74 - A call to open needed parenthesised to stop it clashing + with a win32 macro. + Added Perl core patches 7703 & 7801. + 1.75 - Fixed Perl core patch 7703. + Added suppport to allow DB_File to be built with + Berkeley DB 3.2 -- btree_compare, btree_prefix and hash_cb + needed to be changed. + 1.76 - No change to DB_File.xs + +*/ + +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" + +#ifndef PERL_VERSION +# include "patchlevel.h" +# define PERL_REVISION 5 +# define PERL_VERSION PATCHLEVEL +# define PERL_SUBVERSION SUBVERSION +#endif + +#if PERL_REVISION == 5 && (PERL_VERSION < 4 || (PERL_VERSION == 4 && PERL_SUBVERSION <= 75 )) + +# define PL_sv_undef sv_undef +# define PL_na na + +#endif + +/* DEFSV appears first in 5.004_56 */ +#ifndef DEFSV +# define DEFSV GvSV(defgv) +#endif + +/* Being the Berkeley DB we prefer the (which will be + * shortly #included by the ) __attribute__ to the possibly + * already defined __attribute__, for example by GNUC or by Perl. */ + +#undef __attribute__ + +/* If Perl has been compiled with Threads support,the symbol op will + be defined here. This clashes with a field name in db.h, so get rid of it. + */ +#ifdef op +# undef op +#endif + +#ifdef COMPAT185 +# include +#else +# include +#endif + +#ifdef CAN_PROTOTYPE +extern void __getBerkeleyDBInfo(void); +#endif + +#ifndef pTHX +# define pTHX +# define pTHX_ +# define aTHX +# define aTHX_ +#endif + +#ifndef newSVpvn +# define newSVpvn(a,b) newSVpv(a,b) +#endif + +#include + +/* #define TRACE */ +#define DBM_FILTERING + +#ifdef TRACE +# define Trace(x) printf x +#else +# define Trace(x) +#endif + + +#define DBT_clear(x) Zero(&x, 1, DBT) ; + +#ifdef DB_VERSION_MAJOR + +#if DB_VERSION_MAJOR == 2 +# define BERKELEY_DB_1_OR_2 +#endif + +#if DB_VERSION_MAJOR > 3 || (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR >= 2) +# define AT_LEAST_DB_3_2 +#endif + +/* map version 2 features & constants onto their version 1 equivalent */ + +#ifdef DB_Prefix_t +# undef DB_Prefix_t +#endif +#define DB_Prefix_t size_t + +#ifdef DB_Hash_t +# undef DB_Hash_t +#endif +#define DB_Hash_t u_int32_t + +/* DBTYPE stays the same */ +/* HASHINFO, RECNOINFO and BTREEINFO map to DB_INFO */ +#if DB_VERSION_MAJOR == 2 + typedef DB_INFO INFO ; +#else /* DB_VERSION_MAJOR > 2 */ +# define DB_FIXEDLEN (0x8000) +#endif /* DB_VERSION_MAJOR == 2 */ + +/* version 2 has db_recno_t in place of recno_t */ +typedef db_recno_t recno_t; + + +#define R_CURSOR DB_SET_RANGE +#define R_FIRST DB_FIRST +#define R_IAFTER DB_AFTER +#define R_IBEFORE DB_BEFORE +#define R_LAST DB_LAST +#define R_NEXT DB_NEXT +#define R_NOOVERWRITE DB_NOOVERWRITE +#define R_PREV DB_PREV + +#if DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR < 5 +# define R_SETCURSOR 0x800000 +#else +# define R_SETCURSOR (-100) +#endif + +#define R_RECNOSYNC 0 +#define R_FIXEDLEN DB_FIXEDLEN +#define R_DUP DB_DUP + + +#define db_HA_hash h_hash +#define db_HA_ffactor h_ffactor +#define db_HA_nelem h_nelem +#define db_HA_bsize db_pagesize +#define db_HA_cachesize db_cachesize +#define db_HA_lorder db_lorder + +#define db_BT_compare bt_compare +#define db_BT_prefix bt_prefix +#define db_BT_flags flags +#define db_BT_psize db_pagesize +#define db_BT_cachesize db_cachesize +#define db_BT_lorder db_lorder +#define db_BT_maxkeypage +#define db_BT_minkeypage + + +#define db_RE_reclen re_len +#define db_RE_flags flags +#define db_RE_bval re_pad +#define db_RE_bfname re_source +#define db_RE_psize db_pagesize +#define db_RE_cachesize db_cachesize +#define db_RE_lorder db_lorder + +#define TXN NULL, + +#define do_SEQ(db, key, value, flag) (db->cursor->c_get)(db->cursor, &key, &value, flag) + + +#define DBT_flags(x) x.flags = 0 +#define DB_flags(x, v) x |= v + +#if DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR < 5 +# define flagSet(flags, bitmask) ((flags) & (bitmask)) +#else +# define flagSet(flags, bitmask) (((flags) & DB_OPFLAGS_MASK) == (bitmask)) +#endif + +#else /* db version 1.x */ + +#define BERKELEY_DB_1 +#define BERKELEY_DB_1_OR_2 + +typedef union INFO { + HASHINFO hash ; + RECNOINFO recno ; + BTREEINFO btree ; + } INFO ; + + +#ifdef mDB_Prefix_t +# ifdef DB_Prefix_t +# undef DB_Prefix_t +# endif +# define DB_Prefix_t mDB_Prefix_t +#endif + +#ifdef mDB_Hash_t +# ifdef DB_Hash_t +# undef DB_Hash_t +# endif +# define DB_Hash_t mDB_Hash_t +#endif + +#define db_HA_hash hash.hash +#define db_HA_ffactor hash.ffactor +#define db_HA_nelem hash.nelem +#define db_HA_bsize hash.bsize +#define db_HA_cachesize hash.cachesize +#define db_HA_lorder hash.lorder + +#define db_BT_compare btree.compare +#define db_BT_prefix btree.prefix +#define db_BT_flags btree.flags +#define db_BT_psize btree.psize +#define db_BT_cachesize btree.cachesize +#define db_BT_lorder btree.lorder +#define db_BT_maxkeypage btree.maxkeypage +#define db_BT_minkeypage btree.minkeypage + +#define db_RE_reclen recno.reclen +#define db_RE_flags recno.flags +#define db_RE_bval recno.bval +#define db_RE_bfname recno.bfname +#define db_RE_psize recno.psize +#define db_RE_cachesize recno.cachesize +#define db_RE_lorder recno.lorder + +#define TXN + +#define do_SEQ(db, key, value, flag) (db->dbp->seq)(db->dbp, &key, &value, flag) +#define DBT_flags(x) +#define DB_flags(x, v) +#define flagSet(flags, bitmask) ((flags) & (bitmask)) + +#endif /* db version 1 */ + + + +#define db_DELETE(db, key, flags) ((db->dbp)->del)(db->dbp, TXN &key, flags) +#define db_STORE(db, key, value, flags) ((db->dbp)->put)(db->dbp, TXN &key, &value, flags) +#define db_FETCH(db, key, flags) ((db->dbp)->get)(db->dbp, TXN &key, &value, flags) + +#define db_sync(db, flags) ((db->dbp)->sync)(db->dbp, flags) +#define db_get(db, key, value, flags) ((db->dbp)->get)(db->dbp, TXN &key, &value, flags) + +#ifdef DB_VERSION_MAJOR +#define db_DESTROY(db) ( db->cursor->c_close(db->cursor),\ + (db->dbp->close)(db->dbp, 0) ) +#define db_close(db) ((db->dbp)->close)(db->dbp, 0) +#define db_del(db, key, flags) (flagSet(flags, R_CURSOR) \ + ? ((db->cursor)->c_del)(db->cursor, 0) \ + : ((db->dbp)->del)(db->dbp, NULL, &key, flags) ) + +#else /* ! DB_VERSION_MAJOR */ + +#define db_DESTROY(db) ((db->dbp)->close)(db->dbp) +#define db_close(db) ((db->dbp)->close)(db->dbp) +#define db_del(db, key, flags) ((db->dbp)->del)(db->dbp, &key, flags) +#define db_put(db, key, value, flags) ((db->dbp)->put)(db->dbp, &key, &value, flags) + +#endif /* ! DB_VERSION_MAJOR */ + + +#define db_seq(db, key, value, flags) do_SEQ(db, key, value, flags) + +typedef struct { + DBTYPE type ; + DB * dbp ; + SV * compare ; + SV * prefix ; + SV * hash ; + int in_memory ; +#ifdef BERKELEY_DB_1_OR_2 + INFO info ; +#endif +#ifdef DB_VERSION_MAJOR + DBC * cursor ; +#endif +#ifdef DBM_FILTERING + SV * filter_fetch_key ; + SV * filter_store_key ; + SV * filter_fetch_value ; + SV * filter_store_value ; + int filtering ; +#endif /* DBM_FILTERING */ + + } DB_File_type; + +typedef DB_File_type * DB_File ; +typedef DBT DBTKEY ; + +#ifdef DBM_FILTERING + +#define ckFilter(arg,type,name) \ + if (db->type) { \ + SV * save_defsv ; \ + /* printf("filtering %s\n", name) ;*/ \ + if (db->filtering) \ + croak("recursion detected in %s", name) ; \ + db->filtering = TRUE ; \ + save_defsv = newSVsv(DEFSV) ; \ + sv_setsv(DEFSV, arg) ; \ + PUSHMARK(sp) ; \ + (void) perl_call_sv(db->type, G_DISCARD|G_NOARGS); \ + sv_setsv(arg, DEFSV) ; \ + sv_setsv(DEFSV, save_defsv) ; \ + SvREFCNT_dec(save_defsv) ; \ + db->filtering = FALSE ; \ + /*printf("end of filtering %s\n", name) ;*/ \ + } + +#else + +#define ckFilter(arg,type, name) + +#endif /* DBM_FILTERING */ + +#define my_sv_setpvn(sv, d, s) sv_setpvn(sv, (s ? d : (void*)""), s) + +#define OutputValue(arg, name) \ + { if (RETVAL == 0) { \ + my_sv_setpvn(arg, name.data, name.size) ; \ + ckFilter(arg, filter_fetch_value,"filter_fetch_value") ; \ + } \ + } + +#define OutputKey(arg, name) \ + { if (RETVAL == 0) \ + { \ + if (db->type != DB_RECNO) { \ + my_sv_setpvn(arg, name.data, name.size); \ + } \ + else \ + sv_setiv(arg, (I32)*(I32*)name.data - 1); \ + ckFilter(arg, filter_fetch_key,"filter_fetch_key") ; \ + } \ + } + + +/* Internal Global Data */ +static recno_t Value ; +static recno_t zero = 0 ; +static DB_File CurrentDB ; +static DBTKEY empty ; + +#ifdef DB_VERSION_MAJOR + +static int +#ifdef CAN_PROTOTYPE +db_put(DB_File db, DBTKEY key, DBT value, u_int flags) +#else +db_put(db, key, value, flags) +DB_File db ; +DBTKEY key ; +DBT value ; +u_int flags ; +#endif +{ + int status ; + + if (flagSet(flags, R_IAFTER) || flagSet(flags, R_IBEFORE)) { + DBC * temp_cursor ; + DBT l_key, l_value; + +#if DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR < 6 + if (((db->dbp)->cursor)(db->dbp, NULL, &temp_cursor) != 0) +#else + if (((db->dbp)->cursor)(db->dbp, NULL, &temp_cursor, 0) != 0) +#endif + return (-1) ; + + memset(&l_key, 0, sizeof(l_key)); + l_key.data = key.data; + l_key.size = key.size; + memset(&l_value, 0, sizeof(l_value)); + l_value.data = value.data; + l_value.size = value.size; + + if ( temp_cursor->c_get(temp_cursor, &l_key, &l_value, DB_SET) != 0) { + (void)temp_cursor->c_close(temp_cursor); + return (-1); + } + + status = temp_cursor->c_put(temp_cursor, &key, &value, flags); + (void)temp_cursor->c_close(temp_cursor); + + return (status) ; + } + + + if (flagSet(flags, R_CURSOR)) { + return ((db->cursor)->c_put)(db->cursor, &key, &value, DB_CURRENT); + } + + if (flagSet(flags, R_SETCURSOR)) { + if ((db->dbp)->put(db->dbp, NULL, &key, &value, 0) != 0) + return -1 ; + return ((db->cursor)->c_get)(db->cursor, &key, &value, DB_SET_RANGE); + + } + + return ((db->dbp)->put)(db->dbp, NULL, &key, &value, flags) ; + +} + +#endif /* DB_VERSION_MAJOR */ + + +static int +#ifdef AT_LEAST_DB_3_2 + +#ifdef CAN_PROTOTYPE +btree_compare(DB * db, const DBT *key1, const DBT *key2) +#else +btree_compare(db, key1, key2) +DB * db ; +const DBT * key1 ; +const DBT * key2 ; +#endif /* CAN_PROTOTYPE */ + +#else /* Berkeley DB < 3.2 */ + +#ifdef CAN_PROTOTYPE +btree_compare(const DBT *key1, const DBT *key2) +#else +btree_compare(key1, key2) +const DBT * key1 ; +const DBT * key2 ; +#endif + +#endif + +{ +#ifdef dTHX + dTHX; +#endif + dSP ; + void * data1, * data2 ; + int retval ; + int count ; + + data1 = key1->data ; + data2 = key2->data ; + +#ifndef newSVpvn + /* As newSVpv will assume that the data pointer is a null terminated C + string if the size parameter is 0, make sure that data points to an + empty string if the length is 0 + */ + if (key1->size == 0) + data1 = "" ; + if (key2->size == 0) + data2 = "" ; +#endif + + ENTER ; + SAVETMPS; + + PUSHMARK(SP) ; + EXTEND(SP,2) ; + PUSHs(sv_2mortal(newSVpvn(data1,key1->size))); + PUSHs(sv_2mortal(newSVpvn(data2,key2->size))); + PUTBACK ; + + count = perl_call_sv(CurrentDB->compare, G_SCALAR); + + SPAGAIN ; + + if (count != 1) + croak ("DB_File btree_compare: expected 1 return value from compare sub, got %d\n", count) ; + + retval = POPi ; + + PUTBACK ; + FREETMPS ; + LEAVE ; + return (retval) ; + +} + +static DB_Prefix_t +#ifdef AT_LEAST_DB_3_2 + +#ifdef CAN_PROTOTYPE +btree_prefix(DB * db, const DBT *key1, const DBT *key2) +#else +btree_prefix(db, key1, key2) +Db * db ; +const DBT * key1 ; +const DBT * key2 ; +#endif + +#else /* Berkeley DB < 3.2 */ + +#ifdef CAN_PROTOTYPE +btree_prefix(const DBT *key1, const DBT *key2) +#else +btree_prefix(key1, key2) +const DBT * key1 ; +const DBT * key2 ; +#endif + +#endif +{ +#ifdef dTHX + dTHX; +#endif + dSP ; + void * data1, * data2 ; + int retval ; + int count ; + + data1 = key1->data ; + data2 = key2->data ; + +#ifndef newSVpvn + /* As newSVpv will assume that the data pointer is a null terminated C + string if the size parameter is 0, make sure that data points to an + empty string if the length is 0 + */ + if (key1->size == 0) + data1 = "" ; + if (key2->size == 0) + data2 = "" ; +#endif + + ENTER ; + SAVETMPS; + + PUSHMARK(SP) ; + EXTEND(SP,2) ; + PUSHs(sv_2mortal(newSVpvn(data1,key1->size))); + PUSHs(sv_2mortal(newSVpvn(data2,key2->size))); + PUTBACK ; + + count = perl_call_sv(CurrentDB->prefix, G_SCALAR); + + SPAGAIN ; + + if (count != 1) + croak ("DB_File btree_prefix: expected 1 return value from prefix sub, got %d\n", count) ; + + retval = POPi ; + + PUTBACK ; + FREETMPS ; + LEAVE ; + + return (retval) ; +} + + +#ifdef BERKELEY_DB_1 +# define HASH_CB_SIZE_TYPE size_t +#else +# define HASH_CB_SIZE_TYPE u_int32_t +#endif + +static DB_Hash_t +#ifdef AT_LEAST_DB_3_2 + +#ifdef CAN_PROTOTYPE +hash_cb(DB * db, const void *data, u_int32_t size) +#else +hash_cb(db, data, size) +DB * db ; +const void * data ; +HASH_CB_SIZE_TYPE size ; +#endif + +#else /* Berkeley DB < 3.2 */ + +#ifdef CAN_PROTOTYPE +hash_cb(const void *data, HASH_CB_SIZE_TYPE size) +#else +hash_cb(data, size) +const void * data ; +HASH_CB_SIZE_TYPE size ; +#endif + +#endif +{ +#ifdef dTHX + dTHX; +#endif + dSP ; + int retval ; + int count ; + +#ifndef newSVpvn + if (size == 0) + data = "" ; +#endif + + /* DGH - Next two lines added to fix corrupted stack problem */ + ENTER ; + SAVETMPS; + + PUSHMARK(SP) ; + + XPUSHs(sv_2mortal(newSVpvn((char*)data,size))); + PUTBACK ; + + count = perl_call_sv(CurrentDB->hash, G_SCALAR); + + SPAGAIN ; + + if (count != 1) + croak ("DB_File hash_cb: expected 1 return value from hash sub, got %d\n", count) ; + + retval = POPi ; + + PUTBACK ; + FREETMPS ; + LEAVE ; + + return (retval) ; +} + + +#if defined(TRACE) && defined(BERKELEY_DB_1_OR_2) + +static void +#ifdef CAN_PROTOTYPE +PrintHash(INFO *hash) +#else +PrintHash(hash) +INFO * hash ; +#endif +{ + printf ("HASH Info\n") ; + printf (" hash = %s\n", + (hash->db_HA_hash != NULL ? "redefined" : "default")) ; + printf (" bsize = %d\n", hash->db_HA_bsize) ; + printf (" ffactor = %d\n", hash->db_HA_ffactor) ; + printf (" nelem = %d\n", hash->db_HA_nelem) ; + printf (" cachesize = %d\n", hash->db_HA_cachesize) ; + printf (" lorder = %d\n", hash->db_HA_lorder) ; + +} + +static void +#ifdef CAN_PROTOTYPE +PrintRecno(INFO *recno) +#else +PrintRecno(recno) +INFO * recno ; +#endif +{ + printf ("RECNO Info\n") ; + printf (" flags = %d\n", recno->db_RE_flags) ; + printf (" cachesize = %d\n", recno->db_RE_cachesize) ; + printf (" psize = %d\n", recno->db_RE_psize) ; + printf (" lorder = %d\n", recno->db_RE_lorder) ; + printf (" reclen = %ul\n", (unsigned long)recno->db_RE_reclen) ; + printf (" bval = %d 0x%x\n", recno->db_RE_bval, recno->db_RE_bval) ; + printf (" bfname = %d [%s]\n", recno->db_RE_bfname, recno->db_RE_bfname) ; +} + +static void +#ifdef CAN_PROTOTYPE +PrintBtree(INFO *btree) +#else +PrintBtree(btree) +INFO * btree ; +#endif +{ + printf ("BTREE Info\n") ; + printf (" compare = %s\n", + (btree->db_BT_compare ? "redefined" : "default")) ; + printf (" prefix = %s\n", + (btree->db_BT_prefix ? "redefined" : "default")) ; + printf (" flags = %d\n", btree->db_BT_flags) ; + printf (" cachesize = %d\n", btree->db_BT_cachesize) ; + printf (" psize = %d\n", btree->db_BT_psize) ; +#ifndef DB_VERSION_MAJOR + printf (" maxkeypage = %d\n", btree->db_BT_maxkeypage) ; + printf (" minkeypage = %d\n", btree->db_BT_minkeypage) ; +#endif + printf (" lorder = %d\n", btree->db_BT_lorder) ; +} + +#else + +#define PrintRecno(recno) +#define PrintHash(hash) +#define PrintBtree(btree) + +#endif /* TRACE */ + + +static I32 +#ifdef CAN_PROTOTYPE +GetArrayLength(pTHX_ DB_File db) +#else +GetArrayLength(db) +DB_File db ; +#endif +{ + DBT key ; + DBT value ; + int RETVAL ; + + DBT_clear(key) ; + DBT_clear(value) ; + RETVAL = do_SEQ(db, key, value, R_LAST) ; + if (RETVAL == 0) + RETVAL = *(I32 *)key.data ; + else /* No key means empty file */ + RETVAL = 0 ; + + return ((I32)RETVAL) ; +} + +static recno_t +#ifdef CAN_PROTOTYPE +GetRecnoKey(pTHX_ DB_File db, I32 value) +#else +GetRecnoKey(db, value) +DB_File db ; +I32 value ; +#endif +{ + if (value < 0) { + /* Get the length of the array */ + I32 length = GetArrayLength(aTHX_ db) ; + + /* check for attempt to write before start of array */ + if (length + value + 1 <= 0) + croak("Modification of non-creatable array value attempted, subscript %ld", (long)value) ; + + value = length + value + 1 ; + } + else + ++ value ; + + return value ; +} + + +static DB_File +#ifdef CAN_PROTOTYPE +ParseOpenInfo(pTHX_ int isHASH, char *name, int flags, int mode, SV *sv) +#else +ParseOpenInfo(isHASH, name, flags, mode, sv) +int isHASH ; +char * name ; +int flags ; +int mode ; +SV * sv ; +#endif +{ + +#ifdef BERKELEY_DB_1_OR_2 /* Berkeley DB Version 1 or 2 */ + + SV ** svp; + HV * action ; + DB_File RETVAL = (DB_File)safemalloc(sizeof(DB_File_type)) ; + void * openinfo = NULL ; + INFO * info = &RETVAL->info ; + STRLEN n_a; + +/* printf("In ParseOpenInfo name=[%s] flags=[%d] mode = [%d]\n", name, flags, mode) ; */ + Zero(RETVAL, 1, DB_File_type) ; + + /* Default to HASH */ +#ifdef DBM_FILTERING + RETVAL->filtering = 0 ; + RETVAL->filter_fetch_key = RETVAL->filter_store_key = + RETVAL->filter_fetch_value = RETVAL->filter_store_value = +#endif /* DBM_FILTERING */ + RETVAL->hash = RETVAL->compare = RETVAL->prefix = NULL ; + RETVAL->type = DB_HASH ; + + /* DGH - Next line added to avoid SEGV on existing hash DB */ + CurrentDB = RETVAL; + + /* fd for 1.86 hash in memory files doesn't return -1 like 1.85 */ + RETVAL->in_memory = (name == NULL) ; + + if (sv) + { + if (! SvROK(sv) ) + croak ("type parameter is not a reference") ; + + svp = hv_fetch( (HV*)SvRV(sv), "GOT", 3, FALSE) ; + if (svp && SvOK(*svp)) + action = (HV*) SvRV(*svp) ; + else + croak("internal error") ; + + if (sv_isa(sv, "DB_File::HASHINFO")) + { + + if (!isHASH) + croak("DB_File can only tie an associative array to a DB_HASH database") ; + + RETVAL->type = DB_HASH ; + openinfo = (void*)info ; + + svp = hv_fetch(action, "hash", 4, FALSE); + + if (svp && SvOK(*svp)) + { + info->db_HA_hash = hash_cb ; + RETVAL->hash = newSVsv(*svp) ; + } + else + info->db_HA_hash = NULL ; + + svp = hv_fetch(action, "ffactor", 7, FALSE); + info->db_HA_ffactor = svp ? SvIV(*svp) : 0; + + svp = hv_fetch(action, "nelem", 5, FALSE); + info->db_HA_nelem = svp ? SvIV(*svp) : 0; + + svp = hv_fetch(action, "bsize", 5, FALSE); + info->db_HA_bsize = svp ? SvIV(*svp) : 0; + + svp = hv_fetch(action, "cachesize", 9, FALSE); + info->db_HA_cachesize = svp ? SvIV(*svp) : 0; + + svp = hv_fetch(action, "lorder", 6, FALSE); + info->db_HA_lorder = svp ? SvIV(*svp) : 0; + + PrintHash(info) ; + } + else if (sv_isa(sv, "DB_File::BTREEINFO")) + { + if (!isHASH) + croak("DB_File can only tie an associative array to a DB_BTREE database"); + + RETVAL->type = DB_BTREE ; + openinfo = (void*)info ; + + svp = hv_fetch(action, "compare", 7, FALSE); + if (svp && SvOK(*svp)) + { + info->db_BT_compare = btree_compare ; + RETVAL->compare = newSVsv(*svp) ; + } + else + info->db_BT_compare = NULL ; + + svp = hv_fetch(action, "prefix", 6, FALSE); + if (svp && SvOK(*svp)) + { + info->db_BT_prefix = btree_prefix ; + RETVAL->prefix = newSVsv(*svp) ; + } + else + info->db_BT_prefix = NULL ; + + svp = hv_fetch(action, "flags", 5, FALSE); + info->db_BT_flags = svp ? SvIV(*svp) : 0; + + svp = hv_fetch(action, "cachesize", 9, FALSE); + info->db_BT_cachesize = svp ? SvIV(*svp) : 0; + +#ifndef DB_VERSION_MAJOR + svp = hv_fetch(action, "minkeypage", 10, FALSE); + info->btree.minkeypage = svp ? SvIV(*svp) : 0; + + svp = hv_fetch(action, "maxkeypage", 10, FALSE); + info->btree.maxkeypage = svp ? SvIV(*svp) : 0; +#endif + + svp = hv_fetch(action, "psize", 5, FALSE); + info->db_BT_psize = svp ? SvIV(*svp) : 0; + + svp = hv_fetch(action, "lorder", 6, FALSE); + info->db_BT_lorder = svp ? SvIV(*svp) : 0; + + PrintBtree(info) ; + + } + else if (sv_isa(sv, "DB_File::RECNOINFO")) + { + if (isHASH) + croak("DB_File can only tie an array to a DB_RECNO database"); + + RETVAL->type = DB_RECNO ; + openinfo = (void *)info ; + + info->db_RE_flags = 0 ; + + svp = hv_fetch(action, "flags", 5, FALSE); + info->db_RE_flags = (u_long) (svp ? SvIV(*svp) : 0); + + svp = hv_fetch(action, "reclen", 6, FALSE); + info->db_RE_reclen = (size_t) (svp ? SvIV(*svp) : 0); + + svp = hv_fetch(action, "cachesize", 9, FALSE); + info->db_RE_cachesize = (u_int) (svp ? SvIV(*svp) : 0); + + svp = hv_fetch(action, "psize", 5, FALSE); + info->db_RE_psize = (u_int) (svp ? SvIV(*svp) : 0); + + svp = hv_fetch(action, "lorder", 6, FALSE); + info->db_RE_lorder = (int) (svp ? SvIV(*svp) : 0); + +#ifdef DB_VERSION_MAJOR + info->re_source = name ; + name = NULL ; +#endif + svp = hv_fetch(action, "bfname", 6, FALSE); + if (svp && SvOK(*svp)) { + char * ptr = SvPV(*svp,n_a) ; +#ifdef DB_VERSION_MAJOR + name = (char*) n_a ? ptr : NULL ; +#else + info->db_RE_bfname = (char*) (n_a ? ptr : NULL) ; +#endif + } + else +#ifdef DB_VERSION_MAJOR + name = NULL ; +#else + info->db_RE_bfname = NULL ; +#endif + + svp = hv_fetch(action, "bval", 4, FALSE); +#ifdef DB_VERSION_MAJOR + if (svp && SvOK(*svp)) + { + int value ; + if (SvPOK(*svp)) + value = (int)*SvPV(*svp, n_a) ; + else + value = SvIV(*svp) ; + + if (info->flags & DB_FIXEDLEN) { + info->re_pad = value ; + info->flags |= DB_PAD ; + } + else { + info->re_delim = value ; + info->flags |= DB_DELIMITER ; + } + + } +#else + if (svp && SvOK(*svp)) + { + if (SvPOK(*svp)) + info->db_RE_bval = (u_char)*SvPV(*svp, n_a) ; + else + info->db_RE_bval = (u_char)(unsigned long) SvIV(*svp) ; + DB_flags(info->flags, DB_DELIMITER) ; + + } + else + { + if (info->db_RE_flags & R_FIXEDLEN) + info->db_RE_bval = (u_char) ' ' ; + else + info->db_RE_bval = (u_char) '\n' ; + DB_flags(info->flags, DB_DELIMITER) ; + } +#endif + +#ifdef DB_RENUMBER + info->flags |= DB_RENUMBER ; +#endif + + PrintRecno(info) ; + } + else + croak("type is not of type DB_File::HASHINFO, DB_File::BTREEINFO or DB_File::RECNOINFO"); + } + + + /* OS2 Specific Code */ +#ifdef OS2 +#ifdef __EMX__ + flags |= O_BINARY; +#endif /* __EMX__ */ +#endif /* OS2 */ + +#ifdef DB_VERSION_MAJOR + + { + int Flags = 0 ; + int status ; + + /* Map 1.x flags to 2.x flags */ + if ((flags & O_CREAT) == O_CREAT) + Flags |= DB_CREATE ; + +#if O_RDONLY == 0 + if (flags == O_RDONLY) +#else + if ((flags & O_RDONLY) == O_RDONLY && (flags & O_RDWR) != O_RDWR) +#endif + Flags |= DB_RDONLY ; + +#ifdef O_TRUNC + if ((flags & O_TRUNC) == O_TRUNC) + Flags |= DB_TRUNCATE ; +#endif + + status = db_open(name, RETVAL->type, Flags, mode, NULL, openinfo, &RETVAL->dbp) ; + if (status == 0) +#if DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR < 6 + status = (RETVAL->dbp->cursor)(RETVAL->dbp, NULL, &RETVAL->cursor) ; +#else + status = (RETVAL->dbp->cursor)(RETVAL->dbp, NULL, &RETVAL->cursor, + 0) ; +#endif + + if (status) + RETVAL->dbp = NULL ; + + } +#else + +#if defined(DB_LIBRARY_COMPATIBILITY_API) && DB_VERSION_MAJOR > 2 + RETVAL->dbp = __db185_open(name, flags, mode, RETVAL->type, openinfo) ; +#else + RETVAL->dbp = dbopen(name, flags, mode, RETVAL->type, openinfo) ; +#endif /* DB_LIBRARY_COMPATIBILITY_API */ + +#endif + + return (RETVAL) ; + +#else /* Berkeley DB Version > 2 */ + + SV ** svp; + HV * action ; + DB_File RETVAL = (DB_File)safemalloc(sizeof(DB_File_type)) ; + DB * dbp ; + STRLEN n_a; + int status ; + +/* printf("In ParseOpenInfo name=[%s] flags=[%d] mode = [%d]\n", name, flags, mode) ; */ + Zero(RETVAL, 1, DB_File_type) ; + + /* Default to HASH */ +#ifdef DBM_FILTERING + RETVAL->filtering = 0 ; + RETVAL->filter_fetch_key = RETVAL->filter_store_key = + RETVAL->filter_fetch_value = RETVAL->filter_store_value = +#endif /* DBM_FILTERING */ + RETVAL->hash = RETVAL->compare = RETVAL->prefix = NULL ; + RETVAL->type = DB_HASH ; + + /* DGH - Next line added to avoid SEGV on existing hash DB */ + CurrentDB = RETVAL; + + /* fd for 1.86 hash in memory files doesn't return -1 like 1.85 */ + RETVAL->in_memory = (name == NULL) ; + + status = db_create(&RETVAL->dbp, NULL,0) ; + /* printf("db_create returned %d %s\n", status, db_strerror(status)) ; */ + if (status) { + RETVAL->dbp = NULL ; + return (RETVAL) ; + } + dbp = RETVAL->dbp ; + + if (sv) + { + if (! SvROK(sv) ) + croak ("type parameter is not a reference") ; + + svp = hv_fetch( (HV*)SvRV(sv), "GOT", 3, FALSE) ; + if (svp && SvOK(*svp)) + action = (HV*) SvRV(*svp) ; + else + croak("internal error") ; + + if (sv_isa(sv, "DB_File::HASHINFO")) + { + + if (!isHASH) + croak("DB_File can only tie an associative array to a DB_HASH database") ; + + RETVAL->type = DB_HASH ; + + svp = hv_fetch(action, "hash", 4, FALSE); + + if (svp && SvOK(*svp)) + { + (void)dbp->set_h_hash(dbp, hash_cb) ; + RETVAL->hash = newSVsv(*svp) ; + } + + svp = hv_fetch(action, "ffactor", 7, FALSE); + if (svp) + (void)dbp->set_h_ffactor(dbp, SvIV(*svp)) ; + + svp = hv_fetch(action, "nelem", 5, FALSE); + if (svp) + (void)dbp->set_h_nelem(dbp, SvIV(*svp)) ; + + svp = hv_fetch(action, "bsize", 5, FALSE); + if (svp) + (void)dbp->set_pagesize(dbp, SvIV(*svp)); + + svp = hv_fetch(action, "cachesize", 9, FALSE); + if (svp) + (void)dbp->set_cachesize(dbp, 0, SvIV(*svp), 0) ; + + svp = hv_fetch(action, "lorder", 6, FALSE); + if (svp) + (void)dbp->set_lorder(dbp, SvIV(*svp)) ; + + PrintHash(info) ; + } + else if (sv_isa(sv, "DB_File::BTREEINFO")) + { + if (!isHASH) + croak("DB_File can only tie an associative array to a DB_BTREE database"); + + RETVAL->type = DB_BTREE ; + + svp = hv_fetch(action, "compare", 7, FALSE); + if (svp && SvOK(*svp)) + { + (void)dbp->set_bt_compare(dbp, btree_compare) ; + RETVAL->compare = newSVsv(*svp) ; + } + + svp = hv_fetch(action, "prefix", 6, FALSE); + if (svp && SvOK(*svp)) + { + (void)dbp->set_bt_prefix(dbp, btree_prefix) ; + RETVAL->prefix = newSVsv(*svp) ; + } + + svp = hv_fetch(action, "flags", 5, FALSE); + if (svp) + (void)dbp->set_flags(dbp, SvIV(*svp)) ; + + svp = hv_fetch(action, "cachesize", 9, FALSE); + if (svp) + (void)dbp->set_cachesize(dbp, 0, SvIV(*svp), 0) ; + + svp = hv_fetch(action, "psize", 5, FALSE); + if (svp) + (void)dbp->set_pagesize(dbp, SvIV(*svp)) ; + + svp = hv_fetch(action, "lorder", 6, FALSE); + if (svp) + (void)dbp->set_lorder(dbp, SvIV(*svp)) ; + + PrintBtree(info) ; + + } + else if (sv_isa(sv, "DB_File::RECNOINFO")) + { + int fixed = FALSE ; + + if (isHASH) + croak("DB_File can only tie an array to a DB_RECNO database"); + + RETVAL->type = DB_RECNO ; + + svp = hv_fetch(action, "flags", 5, FALSE); + if (svp) { + int flags = SvIV(*svp) ; + /* remove FIXDLEN, if present */ + if (flags & DB_FIXEDLEN) { + fixed = TRUE ; + flags &= ~DB_FIXEDLEN ; + } + } + + svp = hv_fetch(action, "cachesize", 9, FALSE); + if (svp) { + status = dbp->set_cachesize(dbp, 0, SvIV(*svp), 0) ; + } + + svp = hv_fetch(action, "psize", 5, FALSE); + if (svp) { + status = dbp->set_pagesize(dbp, SvIV(*svp)) ; + } + + svp = hv_fetch(action, "lorder", 6, FALSE); + if (svp) { + status = dbp->set_lorder(dbp, SvIV(*svp)) ; + } + + svp = hv_fetch(action, "bval", 4, FALSE); + if (svp && SvOK(*svp)) + { + int value ; + if (SvPOK(*svp)) + value = (int)*SvPV(*svp, n_a) ; + else + value = SvIV(*svp) ; + + if (fixed) { + status = dbp->set_re_pad(dbp, value) ; + } + else { + status = dbp->set_re_delim(dbp, value) ; + } + + } + + if (fixed) { + svp = hv_fetch(action, "reclen", 6, FALSE); + if (svp) { + u_int32_t len = (u_int32_t)SvIV(*svp) ; + status = dbp->set_re_len(dbp, len) ; + } + } + + if (name != NULL) { + status = dbp->set_re_source(dbp, name) ; + name = NULL ; + } + + svp = hv_fetch(action, "bfname", 6, FALSE); + if (svp && SvOK(*svp)) { + char * ptr = SvPV(*svp,n_a) ; + name = (char*) n_a ? ptr : NULL ; + } + else + name = NULL ; + + + status = dbp->set_flags(dbp, DB_RENUMBER) ; + + if (flags){ + (void)dbp->set_flags(dbp, flags) ; + } + PrintRecno(info) ; + } + else + croak("type is not of type DB_File::HASHINFO, DB_File::BTREEINFO or DB_File::RECNOINFO"); + } + + { + int Flags = 0 ; + int status ; + + /* Map 1.x flags to 3.x flags */ + if ((flags & O_CREAT) == O_CREAT) + Flags |= DB_CREATE ; + +#if O_RDONLY == 0 + if (flags == O_RDONLY) +#else + if ((flags & O_RDONLY) == O_RDONLY && (flags & O_RDWR) != O_RDWR) +#endif + Flags |= DB_RDONLY ; + +#ifdef O_TRUNC + if ((flags & O_TRUNC) == O_TRUNC) + Flags |= DB_TRUNCATE ; +#endif + + status = (RETVAL->dbp->open)(RETVAL->dbp, name, NULL, RETVAL->type, + Flags, mode) ; + /* printf("open returned %d %s\n", status, db_strerror(status)) ; */ + + if (status == 0) + status = (RETVAL->dbp->cursor)(RETVAL->dbp, NULL, &RETVAL->cursor, + 0) ; + /* printf("cursor returned %d %s\n", status, db_strerror(status)) ; */ + + if (status) + RETVAL->dbp = NULL ; + + } + + return (RETVAL) ; + +#endif /* Berkeley DB Version > 2 */ + +} /* ParseOpenInfo */ + + +static double +#ifdef CAN_PROTOTYPE +constant(char *name, int arg) +#else +constant(name, arg) +char *name; +int arg; +#endif +{ + errno = 0; + switch (*name) { + case 'A': + break; + case 'B': + if (strEQ(name, "BTREEMAGIC")) +#ifdef BTREEMAGIC + return BTREEMAGIC; +#else + goto not_there; +#endif + if (strEQ(name, "BTREEVERSION")) +#ifdef BTREEVERSION + return BTREEVERSION; +#else + goto not_there; +#endif + break; + case 'C': + break; + case 'D': + if (strEQ(name, "DB_LOCK")) +#ifdef DB_LOCK + return DB_LOCK; +#else + goto not_there; +#endif + if (strEQ(name, "DB_SHMEM")) +#ifdef DB_SHMEM + return DB_SHMEM; +#else + goto not_there; +#endif + if (strEQ(name, "DB_TXN")) +#ifdef DB_TXN + return (U32)DB_TXN; +#else + goto not_there; +#endif + break; + case 'E': + break; + case 'F': + break; + case 'G': + break; + case 'H': + if (strEQ(name, "HASHMAGIC")) +#ifdef HASHMAGIC + return HASHMAGIC; +#else + goto not_there; +#endif + if (strEQ(name, "HASHVERSION")) +#ifdef HASHVERSION + return HASHVERSION; +#else + goto not_there; +#endif + break; + case 'I': + break; + case 'J': + break; + case 'K': + break; + case 'L': + break; + case 'M': + if (strEQ(name, "MAX_PAGE_NUMBER")) +#ifdef MAX_PAGE_NUMBER + return (U32)MAX_PAGE_NUMBER; +#else + goto not_there; +#endif + if (strEQ(name, "MAX_PAGE_OFFSET")) +#ifdef MAX_PAGE_OFFSET + return MAX_PAGE_OFFSET; +#else + goto not_there; +#endif + if (strEQ(name, "MAX_REC_NUMBER")) +#ifdef MAX_REC_NUMBER + return (U32)MAX_REC_NUMBER; +#else + goto not_there; +#endif + break; + case 'N': + break; + case 'O': + break; + case 'P': + break; + case 'Q': + break; + case 'R': + if (strEQ(name, "RET_ERROR")) +#ifdef RET_ERROR + return RET_ERROR; +#else + goto not_there; +#endif + if (strEQ(name, "RET_SPECIAL")) +#ifdef RET_SPECIAL + return RET_SPECIAL; +#else + goto not_there; +#endif + if (strEQ(name, "RET_SUCCESS")) +#ifdef RET_SUCCESS + return RET_SUCCESS; +#else + goto not_there; +#endif + if (strEQ(name, "R_CURSOR")) +#ifdef R_CURSOR + return R_CURSOR; +#else + goto not_there; +#endif + if (strEQ(name, "R_DUP")) +#ifdef R_DUP + return R_DUP; +#else + goto not_there; +#endif + if (strEQ(name, "R_FIRST")) +#ifdef R_FIRST + return R_FIRST; +#else + goto not_there; +#endif + if (strEQ(name, "R_FIXEDLEN")) +#ifdef R_FIXEDLEN + return R_FIXEDLEN; +#else + goto not_there; +#endif + if (strEQ(name, "R_IAFTER")) +#ifdef R_IAFTER + return R_IAFTER; +#else + goto not_there; +#endif + if (strEQ(name, "R_IBEFORE")) +#ifdef R_IBEFORE + return R_IBEFORE; +#else + goto not_there; +#endif + if (strEQ(name, "R_LAST")) +#ifdef R_LAST + return R_LAST; +#else + goto not_there; +#endif + if (strEQ(name, "R_NEXT")) +#ifdef R_NEXT + return R_NEXT; +#else + goto not_there; +#endif + if (strEQ(name, "R_NOKEY")) +#ifdef R_NOKEY + return R_NOKEY; +#else + goto not_there; +#endif + if (strEQ(name, "R_NOOVERWRITE")) +#ifdef R_NOOVERWRITE + return R_NOOVERWRITE; +#else + goto not_there; +#endif + if (strEQ(name, "R_PREV")) +#ifdef R_PREV + return R_PREV; +#else + goto not_there; +#endif + if (strEQ(name, "R_RECNOSYNC")) +#ifdef R_RECNOSYNC + return R_RECNOSYNC; +#else + goto not_there; +#endif + if (strEQ(name, "R_SETCURSOR")) +#ifdef R_SETCURSOR + return R_SETCURSOR; +#else + goto not_there; +#endif + if (strEQ(name, "R_SNAPSHOT")) +#ifdef R_SNAPSHOT + return R_SNAPSHOT; +#else + goto not_there; +#endif + break; + case 'S': + break; + case 'T': + break; + case 'U': + break; + case 'V': + break; + case 'W': + break; + case 'X': + break; + case 'Y': + break; + case 'Z': + break; + case '_': + break; + } + errno = EINVAL; + return 0; + +not_there: + errno = ENOENT; + return 0; +} + +MODULE = DB_File PACKAGE = DB_File PREFIX = db_ + +BOOT: + { + __getBerkeleyDBInfo() ; + + DBT_clear(empty) ; + empty.data = &zero ; + empty.size = sizeof(recno_t) ; + } + +double +constant(name,arg) + char * name + int arg + + +DB_File +db_DoTie_(isHASH, dbtype, name=undef, flags=O_CREAT|O_RDWR, mode=0666, type=DB_HASH) + int isHASH + char * dbtype + int flags + int mode + CODE: + { + char * name = (char *) NULL ; + SV * sv = (SV *) NULL ; + STRLEN n_a; + + if (items >= 3 && SvOK(ST(2))) + name = (char*) SvPV(ST(2), n_a) ; + + if (items == 6) + sv = ST(5) ; + + RETVAL = ParseOpenInfo(aTHX_ isHASH, name, flags, mode, sv) ; + if (RETVAL->dbp == NULL) + RETVAL = NULL ; + } + OUTPUT: + RETVAL + +int +db_DESTROY(db) + DB_File db + INIT: + CurrentDB = db ; + CLEANUP: + if (db->hash) + SvREFCNT_dec(db->hash) ; + if (db->compare) + SvREFCNT_dec(db->compare) ; + if (db->prefix) + SvREFCNT_dec(db->prefix) ; +#ifdef DBM_FILTERING + if (db->filter_fetch_key) + SvREFCNT_dec(db->filter_fetch_key) ; + if (db->filter_store_key) + SvREFCNT_dec(db->filter_store_key) ; + if (db->filter_fetch_value) + SvREFCNT_dec(db->filter_fetch_value) ; + if (db->filter_store_value) + SvREFCNT_dec(db->filter_store_value) ; +#endif /* DBM_FILTERING */ + safefree(db) ; +#ifdef DB_VERSION_MAJOR + if (RETVAL > 0) + RETVAL = -1 ; +#endif + + +int +db_DELETE(db, key, flags=0) + DB_File db + DBTKEY key + u_int flags + INIT: + CurrentDB = db ; + + +int +db_EXISTS(db, key) + DB_File db + DBTKEY key + CODE: + { + DBT value ; + + DBT_clear(value) ; + CurrentDB = db ; + RETVAL = (((db->dbp)->get)(db->dbp, TXN &key, &value, 0) == 0) ; + } + OUTPUT: + RETVAL + +int +db_FETCH(db, key, flags=0) + DB_File db + DBTKEY key + u_int flags + CODE: + { + DBT value ; + + DBT_clear(value) ; + CurrentDB = db ; + /* RETVAL = ((db->dbp)->get)(db->dbp, TXN &key, &value, flags) ; */ + RETVAL = db_get(db, key, value, flags) ; + ST(0) = sv_newmortal(); + OutputValue(ST(0), value) + } + +int +db_STORE(db, key, value, flags=0) + DB_File db + DBTKEY key + DBT value + u_int flags + INIT: + CurrentDB = db ; + + +int +db_FIRSTKEY(db) + DB_File db + CODE: + { + DBTKEY key ; + DBT value ; + + DBT_clear(key) ; + DBT_clear(value) ; + CurrentDB = db ; + RETVAL = do_SEQ(db, key, value, R_FIRST) ; + ST(0) = sv_newmortal(); + OutputKey(ST(0), key) ; + } + +int +db_NEXTKEY(db, key) + DB_File db + DBTKEY key + CODE: + { + DBT value ; + + DBT_clear(value) ; + CurrentDB = db ; + RETVAL = do_SEQ(db, key, value, R_NEXT) ; + ST(0) = sv_newmortal(); + OutputKey(ST(0), key) ; + } + +# +# These would be nice for RECNO +# + +int +unshift(db, ...) + DB_File db + ALIAS: UNSHIFT = 1 + CODE: + { + DBTKEY key ; + DBT value ; + int i ; + int One ; + DB * Db = db->dbp ; + STRLEN n_a; + + DBT_clear(key) ; + DBT_clear(value) ; + CurrentDB = db ; +#ifdef DB_VERSION_MAJOR + /* get the first value */ + RETVAL = do_SEQ(db, key, value, DB_FIRST) ; + RETVAL = 0 ; +#else + RETVAL = -1 ; +#endif + for (i = items-1 ; i > 0 ; --i) + { + value.data = SvPV(ST(i), n_a) ; + value.size = n_a ; + One = 1 ; + key.data = &One ; + key.size = sizeof(int) ; +#ifdef DB_VERSION_MAJOR + RETVAL = (db->cursor->c_put)(db->cursor, &key, &value, DB_BEFORE) ; +#else + RETVAL = (Db->put)(Db, &key, &value, R_IBEFORE) ; +#endif + if (RETVAL != 0) + break; + } + } + OUTPUT: + RETVAL + +I32 +pop(db) + DB_File db + ALIAS: POP = 1 + CODE: + { + DBTKEY key ; + DBT value ; + + DBT_clear(key) ; + DBT_clear(value) ; + CurrentDB = db ; + + /* First get the final value */ + RETVAL = do_SEQ(db, key, value, R_LAST) ; + ST(0) = sv_newmortal(); + /* Now delete it */ + if (RETVAL == 0) + { + /* the call to del will trash value, so take a copy now */ + OutputValue(ST(0), value) ; + RETVAL = db_del(db, key, R_CURSOR) ; + if (RETVAL != 0) + sv_setsv(ST(0), &PL_sv_undef); + } + } + +I32 +shift(db) + DB_File db + ALIAS: SHIFT = 1 + CODE: + { + DBT value ; + DBTKEY key ; + + DBT_clear(key) ; + DBT_clear(value) ; + CurrentDB = db ; + /* get the first value */ + RETVAL = do_SEQ(db, key, value, R_FIRST) ; + ST(0) = sv_newmortal(); + /* Now delete it */ + if (RETVAL == 0) + { + /* the call to del will trash value, so take a copy now */ + OutputValue(ST(0), value) ; + RETVAL = db_del(db, key, R_CURSOR) ; + if (RETVAL != 0) + sv_setsv (ST(0), &PL_sv_undef) ; + } + } + + +I32 +push(db, ...) + DB_File db + ALIAS: PUSH = 1 + CODE: + { + DBTKEY key ; + DBT value ; + DB * Db = db->dbp ; + int i ; + STRLEN n_a; + int keyval ; + + DBT_flags(key) ; + DBT_flags(value) ; + CurrentDB = db ; + /* Set the Cursor to the Last element */ + RETVAL = do_SEQ(db, key, value, R_LAST) ; +#ifndef DB_VERSION_MAJOR + if (RETVAL >= 0) +#endif + { + if (RETVAL == 0) + keyval = *(int*)key.data ; + else + keyval = 0 ; + for (i = 1 ; i < items ; ++i) + { + value.data = SvPV(ST(i), n_a) ; + value.size = n_a ; + ++ keyval ; + key.data = &keyval ; + key.size = sizeof(int) ; + RETVAL = (Db->put)(Db, TXN &key, &value, 0) ; + if (RETVAL != 0) + break; + } + } + } + OUTPUT: + RETVAL + +I32 +length(db) + DB_File db + ALIAS: FETCHSIZE = 1 + CODE: + CurrentDB = db ; + RETVAL = GetArrayLength(aTHX_ db) ; + OUTPUT: + RETVAL + + +# +# Now provide an interface to the rest of the DB functionality +# + +int +db_del(db, key, flags=0) + DB_File db + DBTKEY key + u_int flags + CODE: + CurrentDB = db ; + RETVAL = db_del(db, key, flags) ; +#ifdef DB_VERSION_MAJOR + if (RETVAL > 0) + RETVAL = -1 ; + else if (RETVAL == DB_NOTFOUND) + RETVAL = 1 ; +#endif + OUTPUT: + RETVAL + + +int +db_get(db, key, value, flags=0) + DB_File db + DBTKEY key + DBT value = NO_INIT + u_int flags + CODE: + CurrentDB = db ; + DBT_clear(value) ; + RETVAL = db_get(db, key, value, flags) ; +#ifdef DB_VERSION_MAJOR + if (RETVAL > 0) + RETVAL = -1 ; + else if (RETVAL == DB_NOTFOUND) + RETVAL = 1 ; +#endif + OUTPUT: + RETVAL + value + +int +db_put(db, key, value, flags=0) + DB_File db + DBTKEY key + DBT value + u_int flags + CODE: + CurrentDB = db ; + RETVAL = db_put(db, key, value, flags) ; +#ifdef DB_VERSION_MAJOR + if (RETVAL > 0) + RETVAL = -1 ; + else if (RETVAL == DB_KEYEXIST) + RETVAL = 1 ; +#endif + OUTPUT: + RETVAL + key if (flagSet(flags, R_IAFTER) || flagSet(flags, R_IBEFORE)) OutputKey(ST(1), key); + +int +db_fd(db) + DB_File db + int status = 0 ; + CODE: + CurrentDB = db ; +#ifdef DB_VERSION_MAJOR + RETVAL = -1 ; + status = (db->in_memory + ? -1 + : ((db->dbp)->fd)(db->dbp, &RETVAL) ) ; + if (status != 0) + RETVAL = -1 ; +#else + RETVAL = (db->in_memory + ? -1 + : ((db->dbp)->fd)(db->dbp) ) ; +#endif + OUTPUT: + RETVAL + +int +db_sync(db, flags=0) + DB_File db + u_int flags + CODE: + CurrentDB = db ; + RETVAL = db_sync(db, flags) ; +#ifdef DB_VERSION_MAJOR + if (RETVAL > 0) + RETVAL = -1 ; +#endif + OUTPUT: + RETVAL + + +int +db_seq(db, key, value, flags) + DB_File db + DBTKEY key + DBT value = NO_INIT + u_int flags + CODE: + CurrentDB = db ; + DBT_clear(value) ; + RETVAL = db_seq(db, key, value, flags); +#ifdef DB_VERSION_MAJOR + if (RETVAL > 0) + RETVAL = -1 ; + else if (RETVAL == DB_NOTFOUND) + RETVAL = 1 ; +#endif + OUTPUT: + RETVAL + key + value + +#ifdef DBM_FILTERING + +#define setFilter(type) \ + { \ + if (db->type) \ + RETVAL = sv_mortalcopy(db->type) ; \ + ST(0) = RETVAL ; \ + if (db->type && (code == &PL_sv_undef)) { \ + SvREFCNT_dec(db->type) ; \ + db->type = NULL ; \ + } \ + else if (code) { \ + if (db->type) \ + sv_setsv(db->type, code) ; \ + else \ + db->type = newSVsv(code) ; \ + } \ + } + + +SV * +filter_fetch_key(db, code) + DB_File db + SV * code + SV * RETVAL = &PL_sv_undef ; + CODE: + setFilter(filter_fetch_key) ; + +SV * +filter_store_key(db, code) + DB_File db + SV * code + SV * RETVAL = &PL_sv_undef ; + CODE: + setFilter(filter_store_key) ; + +SV * +filter_fetch_value(db, code) + DB_File db + SV * code + SV * RETVAL = &PL_sv_undef ; + CODE: + setFilter(filter_fetch_value) ; + +SV * +filter_store_value(db, code) + DB_File db + SV * code + SV * RETVAL = &PL_sv_undef ; + CODE: + setFilter(filter_store_value) ; + +#endif /* DBM_FILTERING */ diff --git a/db/perl.DB_File/DB_File_BS b/db/perl.DB_File/DB_File_BS new file mode 100644 index 000000000..9282c4988 --- /dev/null +++ b/db/perl.DB_File/DB_File_BS @@ -0,0 +1,6 @@ +# NeXT needs /usr/lib/libposix.a to load along with DB_File.so +if ( $dlsrc eq "dl_next.xs" ) { + @DynaLoader::dl_resolve_using = ( '/usr/lib/libposix.a' ); +} + +1; diff --git a/db/perl.DB_File/MANIFEST b/db/perl.DB_File/MANIFEST new file mode 100644 index 000000000..0cc30dbfb --- /dev/null +++ b/db/perl.DB_File/MANIFEST @@ -0,0 +1,27 @@ +Makefile.PL +DB_File.pm +DB_File.xs +DB_File_BS +Changes +config.in +dbinfo +hints/dynixptx.pl +hints/sco.pl +MANIFEST +README +typemap +t/db-btree.t +t/db-hash.t +t/db-recno.t +version.c +patches/5.004 +patches/5.004_01 +patches/5.004_02 +patches/5.004_03 +patches/5.004_04 +patches/5.004_05 +patches/5.005 +patches/5.005_01 +patches/5.005_02 +patches/5.005_03 +patches/5.6.0 diff --git a/db/perl.DB_File/Makefile.PL b/db/perl.DB_File/Makefile.PL new file mode 100644 index 000000000..25e707df6 --- /dev/null +++ b/db/perl.DB_File/Makefile.PL @@ -0,0 +1,187 @@ +#! perl -w +use strict ; +use ExtUtils::MakeMaker 5.16 ; +use Config ; + +my $VER_INFO ; +my $LIB_DIR ; +my $INC_DIR ; +my $DB_NAME ; +my $LIBS ; +my $COMPAT185 = "" ; + +my @files = ('DB_File.pm', glob "t/*.t") ; +# See if warnings is available +eval 'use warnings;'; +if ($@) { + # not there, so write a dummy warnings.pm + oldWarnings(@files) ; +} else { + # is there, + newWarnings(@files) ; +} + +ParseCONFIG() ; + +if (defined $DB_NAME) + { $LIBS = $DB_NAME } +else { + if ($^O eq 'MSWin32') + { $LIBS = '-llibdb' } + else + { $LIBS = '-ldb' } +} + +# Solaris is special. +#$LIBS .= " -lthread" if $^O eq 'solaris' ; + +# OS2 is a special case, so check for it now. +my $OS2 = "" ; +$OS2 = "-DOS2" if $Config{'osname'} eq 'os2' ; + +WriteMakefile( + NAME => 'DB_File', + LIBS => ["-L${LIB_DIR} $LIBS"], + MAN3PODS => ' ', # Pods will be built by installman. + INC => "-I$INC_DIR", + VERSION_FROM => 'DB_File.pm', + XSPROTOARG => '-noprototypes', + DEFINE => "$OS2 $VER_INFO $COMPAT185", + OBJECT => 'version$(OBJ_EXT) DB_File$(OBJ_EXT)', + OPTIMIZE => '-g', + 'macro' => { INSTALLDIRS => 'perl' }, + 'dist' => {COMPRESS=>'gzip', SUFFIX=>'gz'}, + ); + + +sub MY::postamble { + ' +version$(OBJ_EXT): version.c + +$(NAME).xs: typemap + @$(TOUCH) $(NAME).xs + +Makefile: config.in + +' ; +} + + +sub ParseCONFIG +{ + my ($k, $v) ; + my @badkey = () ; + my %Info = () ; + my @Options = qw( INCLUDE LIB PREFIX HASH DBNAME COMPAT185 ) ; + my %ValidOption = map {$_, 1} @Options ; + my %Parsed = %ValidOption ; + my $CONFIG = 'config.in' ; + + print "Parsing $CONFIG...\n" ; + + # DBNAME & COMPAT185 are optional, so pretend they have + # been parsed. + delete $Parsed{'DBNAME'} ; + delete $Parsed{'COMPAT185'} ; + $Info{COMPAT185} = "No" ; + + + open(F, "$CONFIG") or die "Cannot open file $CONFIG: $!\n" ; + while () { + s/^\s*|\s*$//g ; + next if /^\s*$/ or /^\s*#/ ; + s/\s*#\s*$// ; + + ($k, $v) = split(/\s+=\s+/, $_, 2) ; + $k = uc $k ; + if ($ValidOption{$k}) { + delete $Parsed{$k} ; + $Info{$k} = $v ; + } + else { + push(@badkey, $k) ; + } + } + close F ; + + print "Unknown keys in $CONFIG ignored [@badkey]\n" + if @badkey ; + + # check parsed values + my @missing = () ; + die "The following keys are missing from $CONFIG file: [@missing]\n" + if @missing = keys %Parsed ; + + $INC_DIR = $ENV{'DB_FILE_INCLUDE'} || $Info{'INCLUDE'} ; + $LIB_DIR = $ENV{'DB_FILE_LIB'} || $Info{'LIB'} ; + $DB_NAME = $Info{'DBNAME'} if defined $Info{'DBNAME'} ; + $COMPAT185 = "-DCOMPAT185 -DDB_LIBRARY_COMPATIBILITY_API" + if (defined $ENV{'DB_FILE_COMPAT185'} && + $ENV{'DB_FILE_COMPAT185'} =~ /^\s*(on|true|1)\s*$/i) || + $Info{'COMPAT185'} =~ /^\s*(on|true|1)\s*$/i ; + my $PREFIX = $Info{'PREFIX'} ; + my $HASH = $Info{'HASH'} ; + + $VER_INFO = "-DmDB_Prefix_t=${PREFIX} -DmDB_Hash_t=${HASH}" ; + + print <) + { + if (/^__END__/) + { + print ; + my $this = $ARGV ; + while (<>) + { + last if $ARGV ne $this ; + print ; + } + } + + s/^(\s*)(no\s+warnings)/${1}local (\$^W) = 0; #$2/ ; + s/^(\s*)(use\s+warnings)/${1}local (\$^W) = 1; #$2/ ; + print ; + } +} + +sub newWarnings +{ + local ($^I) = ".bak" ; + local (@ARGV) = @_ ; + + while (<>) + { + if (/^__END__/) + { + my $this = $ARGV ; + print ; + while (<>) + { + last if $ARGV ne $this ; + print ; + } + } + + s/^(\s*)local\s*\(\$\^W\)\s*=\s*\d+\s*;\s*#\s*((no|use)\s+warnings.*)/$1$2/ ; + print ; + } +} + +# end of file Makefile.PL diff --git a/db/perl.DB_File/README b/db/perl.DB_File/README new file mode 100644 index 000000000..e780111b2 --- /dev/null +++ b/db/perl.DB_File/README @@ -0,0 +1,396 @@ + DB_File + + Version 1.76 + + 15th January 2001 + + Copyright (c) 1995-2001 Paul Marquess. All rights reserved. This + program is free software; you can redistribute it and/or modify + it under the same terms as Perl itself. + + +IMPORTANT NOTICE +================ + +If are using the locking technique described in older versions of +DB_File, please read the section called "Locking: The Trouble with fd" +in DB_File.pm immediately. The locking method has been found to be +unsafe. You risk corrupting your data if you continue to use it. + +DESCRIPTION +----------- + +DB_File is a module which allows Perl programs to make use of the +facilities provided by Berkeley DB version 1. (DB_File can be built +version 2 or 3 of Berkeley DB, but it will only support the 1.x +features), + +If you want to make use of the new features available in Berkeley DB +2.x or 3.x, use the Perl module BerkeleyDB instead. + +Berkeley DB is a C library which provides a consistent interface to a +number of database formats. DB_File provides an interface to all three +of the database types (hash, btree and recno) currently supported by +Berkeley DB. + +For further details see the documentation included at the end of the +file DB_File.pm. + +PREREQUISITES +------------- + +Before you can build DB_File you must have the following installed on +your system: + + * Perl 5.004 or greater. + + * Berkeley DB. + + The official web site for Berkeley DB is http://www.sleepycat.com. + The latest version of Berkeley DB is always available there. It + is recommended that you use the most recent version available at + the Sleepycat site. + + The one exception to this advice is where you want to use DB_File + to access database files created by a third-party application, like + Sendmail or Netscape. In these cases you must build DB_File with a + compatible version of Berkeley DB. + + If you want to use Berkeley DB 2.x, you must have version 2.3.4 + or greater. If you want to use Berkeley DB 3.x, any version will + do. For Berkeley DB 1.x, use either version 1.85 or 1.86. + + +BUILDING THE MODULE +------------------- + +Assuming you have met all the prerequisites, building the module should +be relatively straightforward. + +Step 1 : If you are running either Solaris 2.5 or HP-UX 10 and want + to use Berkeley DB version 2 or 3, read either the Solaris Notes + or HP-UX Notes sections below. If you are running Linux please + read the Linux Notes section before proceeding. + +Step 2 : Edit the file config.in to suit you local installation. + Instructions are given in the file. + +Step 3 : Build and test the module using this sequence of commands: + + perl Makefile.PL + make + make test + + + NOTE: + If you have a very old version of Berkeley DB (i.e. pre 1.85), + three of the tests in the recno test harness may fail (tests 51, + 53 and 55). You can safely ignore the errors if you're never + going to use the broken functionality (recno databases with a + modified bval). Otherwise you'll have to upgrade your DB + library. + + +INSTALLATION +------------ + + make install + + +TROUBLESHOOTING +=============== + +Here are some of the common problems people encounter when building +DB_File. + +Missing db.h or libdb.a +----------------------- + +If you get an error like this: + + cc -c -I/usr/local/include -Dbool=char -DHAS_BOOL + -O2 -DVERSION=\"1.64\" -DXS_VERSION=\"1.64\" -fpic + -I/usr/local/lib/perl5/i586-linux/5.00404/CORE -DmDB_Prefix_t=size_t + -DmDB_Hash_t=u_int32_t DB_File.c + DB_File.xs:101: db.h: No such file or directory + +or this: + + LD_RUN_PATH="/lib" cc -o blib/arch/auto/DB_File/DB_File.so -shared + -L/usr/local/lib DB_File.o -L/usr/local/lib -ldb + ld: cannot open -ldb: No such file or directory + +This symptom can imply: + + 1. You don't have Berkeley DB installed on your system at all. + Solution: get & install Berkeley DB. + + 2. You do have Berkeley DB installed, but it isn't in a standard place. + Solution: Edit config.in and set the LIB and INCLUDE variables to point + to the directories where libdb.a and db.h are installed. + + +Undefined symbol db_version +--------------------------- + +DB_File seems to have built correctly, but you get an error like this +when you run the test harness: + + $ make test + PERL_DL_NONLAZY=1 /usr/bin/perl5.00404 -I./blib/arch -I./blib/lib + -I/usr/local/lib/perl5/i586-linux/5.00404 -I/usr/local/lib/perl5 -e 'use + Test::Harness qw(&runtests $verbose); $verbose=0; runtests @ARGV;' t/*.t + t/db-btree..........Can't load './blib/arch/auto/DB_File/DB_File.so' for + module DB_File: ./blib/arch/auto/DB_File/DB_File.so: undefined symbol: + db_version at /usr/local/lib/perl5/i586-linux/5.00404/DynaLoader.pm + line 166. + + at t/db-btree.t line 21 + BEGIN failed--compilation aborted at t/db-btree.t line 21. + dubious Test returned status 2 (wstat 512, 0x200) + +This error usually happens when you have both version 1 and version +2 of Berkeley DB installed on your system and DB_File attempts to +build using the db.h for Berkeley DB version 2 and the version 1 +library. Unfortunately the two versions aren't compatible with each +other. The undefined symbol error is actually caused because Berkeley +DB version 1 doesn't have the symbol db_version. + +Solution: Setting the LIB & INCLUDE variables in config.in to point to the + correct directories can sometimes be enough to fix this + problem. If that doesn't work the easiest way to fix the + problem is to either delete or temporarily rename the copies + of db.h and libdb.a that you don't want DB_File to use. + +Incompatible versions of db.h and libdb +--------------------------------------- + +BerkeleyDB seems to have built correctly, but you get an error like this +when you run the test harness: + + $ make test + PERL_DL_NONLAZY=1 /home/paul/perl/install/bin/perl5.00560 -Iblib/arch + -Iblib/lib -I/home/paul/perl/install/5.005_60/lib/5.00560/i586-linux + -I/home/paul/perl/install/5.005_60/lib/5.00560 -e 'use Test::Harness + qw(&runtests $verbose); $verbose=0; runtests @ARGV;' t/*.t + t/db-btree.......... + DB_File needs compatible versions of libdb & db.h + you have db.h version 2.3.7 and libdb version 2.7.5 + BEGIN failed--compilation aborted at t/db-btree.t line 21. + ... + +Another variation on the theme of having two versions of Berkeley DB on +your system. + +Solution: Setting the LIB & INCLUDE variables in config.in to point to the + correct directories can sometimes be enough to fix this + problem. If that doesn't work the easiest way to fix the + problem is to either delete or temporarily rename the copies + of db.h and libdb.a that you don't want BerkeleyDB to use. + If you are running Linux, please read the Linux Notes section + below. + + +Linux Notes +----------- + +Newer versions of Linux (e.g. RedHat 6, SuSe 6) ship with a C library +that has version 2.x of Berkeley DB linked into it. This makes it +difficult to build this module with anything other than the version of +Berkeley DB that shipped with your Linux release. If you do try to use +a different version of Berkeley DB you will most likely get the error +described in the "Incompatible versions of db.h and libdb" section of +this file. + +To make matters worse, prior to Perl 5.6.1, the perl binary itself +*always* included the Berkeley DB library. + +If you want to use a newer version of Berkeley DB with this module, the +easiest solution is to use Perl 5.6.1 (or better) and Berkeley DB 3.x +(or better). + +There are two approaches you can use to get older versions of Perl to +work with specific versions of Berkeley DB. Both have their advantages +and disadvantages. + +The first approach will only work when you want to build a version of +Perl older than 5.6.1 along with Berkeley DB 3.x. If you want to use +Berkeley DB 2.x, you must use the next approach. This approach involves +rebuilding your existing version of Perl after applying an unofficial +patch. The "patches" directory in the this module's source distribution +contains a number of patch files. There is one patch file for every +stable version of Perl since 5.004. Apply the appropriate patch to your +Perl source tree before re-building and installing Perl from scratch. +For example, assuming you are in the top-level source directory for +Perl 5.6.0, the command below will apply the necessary patch. Remember +to replace the path shown below with one that points to this module's +patches directory. + + patch -p1 -N diff --git a/db/perl.DB_File/config.in b/db/perl.DB_File/config.in new file mode 100644 index 000000000..5bda4a667 --- /dev/null +++ b/db/perl.DB_File/config.in @@ -0,0 +1,99 @@ +# Filename: config.in +# +# written by Paul Marquess +# last modified 9th Sept 1997 +# version 1.55 + +# 1. Where is the file db.h? +# +# Change the path below to point to the directory where db.h is +# installed on your system. + +#INCLUDE = /usr/local/include +#INCLUDE = /usr/local/BerkeleyDB/include +#INCLUDE = /usr/include +INCLUDE = ./libraries/3.2.7 + +# 2. Where is libdb? +# +# Change the path below to point to the directory where libdb is +# installed on your system. + +#LIB = /usr/local/lib +#LIB = /usr/local/BerkeleyDB/lib +#LIB = /usr/lib +LIB = ./libraries/3.2.7 + +# 3. What version of Berkely DB have you got? +# +# If you have version 2.0 or greater, you can skip this question. +# +# If you have Berkeley DB 1.78 or greater you shouldn't have to +# change the definitions for PREFIX and HASH below. +# +# For older versions of Berkeley DB change both PREFIX and HASH to int. +# Version 1.71, 1.72 and 1.73 are known to need this change. +# +# If you don't know what version you have have a look in the file db.h. +# +# Search for the string "DB_VERSION_MAJOR". If it is present, you +# have Berkeley DB version 2 (or greater). +# +# If that didn't work, find the definition of the BTREEINFO typedef. +# Check the return type from the prefix element. It should look like +# this in an older copy of db.h: +# +# int (*prefix) __P((const DBT *, const DBT *)); +# +# and like this in a more recent copy: +# +# size_t (*prefix) /* prefix function */ +# __P((const DBT *, const DBT *)); +# +# Change the definition of PREFIX, below, to reflect the return type +# of the prefix function in your db.h. +# +# Now find the definition of the HASHINFO typedef. Check the return +# type of the hash element. Older versions look like this: +# +# int (*hash) __P((const void *, size_t)); +# +# newer like this: +# +# u_int32_t /* hash function */ +# (*hash) __P((const void *, size_t)); +# +# Change the definition of HASH, below, to reflect the return type of +# the hash function in your db.h. +# + +PREFIX = size_t +HASH = u_int32_t + +# 4. Is the library called libdb? +# +# If you have copies of both 1.x and 2.x Berkeley DB installed on +# your system it can sometimes be tricky to make sure you are using +# the correct one. Renaming one (or creating a symbolic link) to +# include the version number of the library can help. +# +# For example, if you have both Berkeley DB 2.3.12 and 1.85 on your +# system and you want to use the Berkeley DB version 2 library you +# could rename the version 2 library from libdb.a to libdb-2.3.12.a and +# change the DBNAME line below to look like this: +# +# DBNAME = -ldb-2.3.12 +# +# That will ensure you are linking the correct version of the DB +# library. +# +# Note: If you are building this module with Win32, -llibdb will be +# used by default. +# +# If you have changed the name of the library, uncomment the line +# below (by removing the leading #) and edit the line to use the name +# you have picked. + +#DBNAME = -ldb-2.4.10 + +# end of file config.in diff --git a/db/perl.DB_File/dbinfo b/db/perl.DB_File/dbinfo new file mode 100644 index 000000000..5a4df1590 --- /dev/null +++ b/db/perl.DB_File/dbinfo @@ -0,0 +1,109 @@ +#!/usr/local/bin/perl + +# Name: dbinfo -- identify berkeley DB version used to create +# a database file +# +# Author: Paul Marquess +# Version: 1.03 +# Date 17th September 2000 +# +# Copyright (c) 1998-2000 Paul Marquess. All rights reserved. +# This program is free software; you can redistribute it and/or +# modify it under the same terms as Perl itself. + +# Todo: Print more stats on a db file, e.g. no of records +# add log/txn/lock files + +use strict ; + +my %Data = + ( + 0x053162 => { + Type => "Btree", + Versions => + { + 1 => "Unknown (older than 1.71)", + 2 => "Unknown (older than 1.71)", + 3 => "1.71 -> 1.85, 1.86", + 4 => "Unknown", + 5 => "2.0.0 -> 2.3.0", + 6 => "2.3.1 -> 2.7.7", + 7 => "3.0.x", + 8 => "3.1.x or greater", + } + }, + 0x061561 => { + Type => "Hash", + Versions => + { + 1 => "Unknown (older than 1.71)", + 2 => "1.71 -> 1.85", + 3 => "1.86", + 4 => "2.0.0 -> 2.1.0", + 5 => "2.2.6 -> 2.7.7", + 6 => "3.0.x", + 7 => "3.1.x or greater", + } + }, + 0x042253 => { + Type => "Queue", + Versions => + { + 1 => "3.0.x", + 2 => "3.1.x", + 3 => "3.2.x or greater", + } + }, + ) ; + +die "Usage: dbinfo file\n" unless @ARGV == 1 ; + +print "testing file $ARGV[0]...\n\n" ; +open (F, "<$ARGV[0]") or die "Cannot open file $ARGV[0]: $!\n" ; + +my $buff ; +read F, $buff, 20 ; + +my (@info) = unpack("NNNNN", $buff) ; +my (@info1) = unpack("VVVVV", $buff) ; +my ($magic, $version, $endian) ; + +if ($Data{$info[0]}) # first try DB 1.x format +{ + $magic = $info[0] ; + $version = $info[1] ; + $endian = "Unknown" ; +} +elsif ($Data{$info[3]}) # next DB 2.x big endian +{ + $magic = $info[3] ; + $version = $info[4] ; + $endian = "Big Endian" ; +} +elsif ($Data{$info1[3]}) # next DB 2.x little endian +{ + $magic = $info1[3] ; + $version = $info1[4] ; + $endian = "Little Endian" ; +} +else + { die "not a Berkeley DB database file.\n" } + +my $type = $Data{$magic} ; +$magic = sprintf "%06X", $magic ; + +my $ver_string = "Unknown" ; +$ver_string = $type->{Versions}{$version} + if defined $type->{Versions}{$version} ; + +print <{Type} file. +File Version ID: $version +Built with Berkeley DB: $ver_string +Byte Order: $endian +Magic: $magic +EOM + +close F ; + +exit ; diff --git a/db/perl.DB_File/hints/dynixptx.pl b/db/perl.DB_File/hints/dynixptx.pl new file mode 100644 index 000000000..bb5ffa56e --- /dev/null +++ b/db/perl.DB_File/hints/dynixptx.pl @@ -0,0 +1,3 @@ +# Need to add an extra '-lc' to the end to work around a DYNIX/ptx bug + +$self->{LIBS} = ['-lm -lc']; diff --git a/db/perl.DB_File/hints/sco.pl b/db/perl.DB_File/hints/sco.pl new file mode 100644 index 000000000..ff6044094 --- /dev/null +++ b/db/perl.DB_File/hints/sco.pl @@ -0,0 +1,2 @@ +# osr5 needs to explicitly link against libc to pull in some static symbols +$self->{LIBS} = ['-ldb -lc'] if $Config{'osvers'} =~ '3\.2v5\.0\..' ; diff --git a/db/perl.DB_File/patches/5.004 b/db/perl.DB_File/patches/5.004 new file mode 100644 index 000000000..143ec95af --- /dev/null +++ b/db/perl.DB_File/patches/5.004 @@ -0,0 +1,44 @@ +diff perl5.004.orig/Configure perl5.004/Configure +190a191 +> perllibs='' +9904a9906,9913 +> : Remove libraries needed only for extensions +> : The appropriate ext/Foo/Makefile.PL will add them back in, if +> : necessary. +> set X `echo " $libs " | +> sed -e 's@ -lndbm @ @' -e 's@ -lgdbm @ @' -e 's@ -ldbm @ @' -e 's@ -ldb @ @'` +> shift +> perllibs="$*" +> +10372a10382 +> perllibs='$perllibs' +diff perl5.004.orig/Makefile.SH perl5.004/Makefile.SH +122c122 +< libs = $libs $cryptlib +--- +> libs = $perllibs $cryptlib +Common subdirectories: perl5.004.orig/Porting and perl5.004/Porting +Common subdirectories: perl5.004.orig/cygwin32 and perl5.004/cygwin32 +Common subdirectories: perl5.004.orig/eg and perl5.004/eg +Common subdirectories: perl5.004.orig/emacs and perl5.004/emacs +Common subdirectories: perl5.004.orig/ext and perl5.004/ext +Common subdirectories: perl5.004.orig/h2pl and perl5.004/h2pl +Common subdirectories: perl5.004.orig/hints and perl5.004/hints +Common subdirectories: perl5.004.orig/lib and perl5.004/lib +diff perl5.004.orig/myconfig perl5.004/myconfig +38c38 +< libs=$libs +--- +> libs=$perllibs +Common subdirectories: perl5.004.orig/os2 and perl5.004/os2 +diff perl5.004.orig/patchlevel.h perl5.004/patchlevel.h +40a41 +> ,"NODB-1.0 - remove -ldb from core perl binary." +Common subdirectories: perl5.004.orig/plan9 and perl5.004/plan9 +Common subdirectories: perl5.004.orig/pod and perl5.004/pod +Common subdirectories: perl5.004.orig/qnx and perl5.004/qnx +Common subdirectories: perl5.004.orig/t and perl5.004/t +Common subdirectories: perl5.004.orig/utils and perl5.004/utils +Common subdirectories: perl5.004.orig/vms and perl5.004/vms +Common subdirectories: perl5.004.orig/win32 and perl5.004/win32 +Common subdirectories: perl5.004.orig/x2p and perl5.004/x2p diff --git a/db/perl.DB_File/patches/5.004_01 b/db/perl.DB_File/patches/5.004_01 new file mode 100644 index 000000000..1b05eb4e0 --- /dev/null +++ b/db/perl.DB_File/patches/5.004_01 @@ -0,0 +1,217 @@ +diff -rc perl5.004_01.orig/Configure perl5.004_01/Configure +*** perl5.004_01.orig/Configure Wed Jun 11 00:28:03 1997 +--- perl5.004_01/Configure Sun Nov 12 22:12:35 2000 +*************** +*** 188,193 **** +--- 188,194 ---- + mv='' + nroff='' + perl='' ++ perllibs='' + pg='' + pmake='' + pr='' +*************** +*** 9907,9912 **** +--- 9908,9921 ---- + shift + extensions="$*" + ++ : Remove libraries needed only for extensions ++ : The appropriate ext/Foo/Makefile.PL will add them back in, if ++ : necessary. ++ set X `echo " $libs " | ++ sed -e 's@ -lndbm @ @' -e 's@ -lgdbm @ @' -e 's@ -ldbm @ @' -e 's@ -ldb @ @'` ++ shift ++ perllibs="$*" ++ + : Remove build directory name from cppstdin so it can be used from + : either the present location or the final installed location. + echo " " +*************** +*** 10375,10380 **** +--- 10384,10390 ---- + patchlevel='$patchlevel' + path_sep='$path_sep' + perl='$perl' ++ perllibs='$perllibs' + perladmin='$perladmin' + perlpath='$perlpath' + pg='$pg' +diff -rc perl5.004_01.orig/Makefile.SH perl5.004_01/Makefile.SH +*** perl5.004_01.orig/Makefile.SH Thu Jun 12 23:27:56 1997 +--- perl5.004_01/Makefile.SH Sun Nov 12 22:12:35 2000 +*************** +*** 126,132 **** + ext = \$(dynamic_ext) \$(static_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $libs $cryptlib + + public = perl $suidperl utilities translators + +--- 126,132 ---- + ext = \$(dynamic_ext) \$(static_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $perllibs $cryptlib + + public = perl $suidperl utilities translators + +diff -rc perl5.004_01.orig/lib/ExtUtils/Embed.pm perl5.004_01/lib/ExtUtils/Embed.pm +*** perl5.004_01.orig/lib/ExtUtils/Embed.pm Wed Apr 2 22:12:04 1997 +--- perl5.004_01/lib/ExtUtils/Embed.pm Sun Nov 12 22:12:35 2000 +*************** +*** 170,176 **** + @path = $path ? split(/:/, $path) : @INC; + + push(@potential_libs, @link_args) if scalar @link_args; +! push(@potential_libs, $Config{libs}) if defined $std; + + push(@mods, static_ext()) if $std; + +--- 170,176 ---- + @path = $path ? split(/:/, $path) : @INC; + + push(@potential_libs, @link_args) if scalar @link_args; +! push(@potential_libs, $Config{perllibs}) if defined $std; + + push(@mods, static_ext()) if $std; + +diff -rc perl5.004_01.orig/lib/ExtUtils/Liblist.pm perl5.004_01/lib/ExtUtils/Liblist.pm +*** perl5.004_01.orig/lib/ExtUtils/Liblist.pm Sat Jun 7 01:19:44 1997 +--- perl5.004_01/lib/ExtUtils/Liblist.pm Sun Nov 12 22:13:27 2000 +*************** +*** 16,33 **** + + sub _unix_os2_ext { + my($self,$potential_libs, $Verbose) = @_; +! if ($^O =~ 'os2' and $Config{libs}) { + # Dynamic libraries are not transitive, so we may need including + # the libraries linked against perl.dll again. + + $potential_libs .= " " if $potential_libs; +! $potential_libs .= $Config{libs}; + } + return ("", "", "", "") unless $potential_libs; + print STDOUT "Potential libraries are '$potential_libs':\n" if $Verbose; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'libs'}; + my $Config_libext = $Config{lib_ext} || ".a"; + + +--- 16,33 ---- + + sub _unix_os2_ext { + my($self,$potential_libs, $Verbose) = @_; +! if ($^O =~ 'os2' and $Config{perllibs}) { + # Dynamic libraries are not transitive, so we may need including + # the libraries linked against perl.dll again. + + $potential_libs .= " " if $potential_libs; +! $potential_libs .= $Config{perllibs}; + } + return ("", "", "", "") unless $potential_libs; + print STDOUT "Potential libraries are '$potential_libs':\n" if $Verbose; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'perllibs'}; + my $Config_libext = $Config{lib_ext} || ".a"; + + +*************** +*** 186,196 **** + my($self, $potential_libs, $Verbose) = @_; + + # If user did not supply a list, we punt. +! # (caller should probably use the list in $Config{libs}) + return ("", "", "", "") unless $potential_libs; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'libs'}; + my($libpth) = $Config{'libpth'}; + my($libext) = $Config{'lib_ext'} || ".lib"; + +--- 186,196 ---- + my($self, $potential_libs, $Verbose) = @_; + + # If user did not supply a list, we punt. +! # (caller should probably use the list in $Config{perllibs}) + return ("", "", "", "") unless $potential_libs; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'perllibs'}; + my($libpth) = $Config{'libpth'}; + my($libext) = $Config{'lib_ext'} || ".lib"; + +*************** +*** 540,546 **** + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{libs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs> + as well as in C<$Config{libpth}>. For each library that is found, a +--- 540,546 ---- + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{perllibs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs> + as well as in C<$Config{libpth}>. For each library that is found, a +diff -rc perl5.004_01.orig/lib/ExtUtils/MM_Unix.pm perl5.004_01/lib/ExtUtils/MM_Unix.pm +*** perl5.004_01.orig/lib/ExtUtils/MM_Unix.pm Thu Jun 12 22:06:18 1997 +--- perl5.004_01/lib/ExtUtils/MM_Unix.pm Sun Nov 12 22:12:35 2000 +*************** +*** 2137,2143 **** + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{libs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { +--- 2137,2143 ---- + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{perllibs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { +diff -rc perl5.004_01.orig/myconfig perl5.004_01/myconfig +*** perl5.004_01.orig/myconfig Sat Dec 21 01:13:20 1996 +--- perl5.004_01/myconfig Sun Nov 12 22:12:35 2000 +*************** +*** 35,41 **** + Linker and Libraries: + ld='$ld', ldflags ='$ldflags' + libpth=$libpth +! libs=$libs + libc=$libc, so=$so + useshrplib=$useshrplib, libperl=$libperl + Dynamic Linking: +--- 35,41 ---- + Linker and Libraries: + ld='$ld', ldflags ='$ldflags' + libpth=$libpth +! libs=$perllibs + libc=$libc, so=$so + useshrplib=$useshrplib, libperl=$libperl + Dynamic Linking: +diff -rc perl5.004_01.orig/patchlevel.h perl5.004_01/patchlevel.h +*** perl5.004_01.orig/patchlevel.h Wed Jun 11 03:06:10 1997 +--- perl5.004_01/patchlevel.h Sun Nov 12 22:12:35 2000 +*************** +*** 38,43 **** +--- 38,44 ---- + */ + static char *local_patches[] = { + NULL ++ ,"NODB-1.0 - remove -ldb from core perl binary." + ,NULL + }; + diff --git a/db/perl.DB_File/patches/5.004_02 b/db/perl.DB_File/patches/5.004_02 new file mode 100644 index 000000000..238f87379 --- /dev/null +++ b/db/perl.DB_File/patches/5.004_02 @@ -0,0 +1,217 @@ +diff -rc perl5.004_02.orig/Configure perl5.004_02/Configure +*** perl5.004_02.orig/Configure Thu Aug 7 15:08:44 1997 +--- perl5.004_02/Configure Sun Nov 12 22:06:24 2000 +*************** +*** 188,193 **** +--- 188,194 ---- + mv='' + nroff='' + perl='' ++ perllibs='' + pg='' + pmake='' + pr='' +*************** +*** 9911,9916 **** +--- 9912,9925 ---- + shift + extensions="$*" + ++ : Remove libraries needed only for extensions ++ : The appropriate ext/Foo/Makefile.PL will add them back in, if ++ : necessary. ++ set X `echo " $libs " | ++ sed -e 's@ -lndbm @ @' -e 's@ -lgdbm @ @' -e 's@ -ldbm @ @' -e 's@ -ldb @ @'` ++ shift ++ perllibs="$*" ++ + : Remove build directory name from cppstdin so it can be used from + : either the present location or the final installed location. + echo " " +*************** +*** 10379,10384 **** +--- 10388,10394 ---- + patchlevel='$patchlevel' + path_sep='$path_sep' + perl='$perl' ++ perllibs='$perllibs' + perladmin='$perladmin' + perlpath='$perlpath' + pg='$pg' +diff -rc perl5.004_02.orig/Makefile.SH perl5.004_02/Makefile.SH +*** perl5.004_02.orig/Makefile.SH Thu Aug 7 13:10:53 1997 +--- perl5.004_02/Makefile.SH Sun Nov 12 22:06:24 2000 +*************** +*** 126,132 **** + ext = \$(dynamic_ext) \$(static_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $libs $cryptlib + + public = perl $suidperl utilities translators + +--- 126,132 ---- + ext = \$(dynamic_ext) \$(static_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $perllibs $cryptlib + + public = perl $suidperl utilities translators + +diff -rc perl5.004_02.orig/lib/ExtUtils/Embed.pm perl5.004_02/lib/ExtUtils/Embed.pm +*** perl5.004_02.orig/lib/ExtUtils/Embed.pm Fri Aug 1 15:08:44 1997 +--- perl5.004_02/lib/ExtUtils/Embed.pm Sun Nov 12 22:06:24 2000 +*************** +*** 178,184 **** + @path = $path ? split(/:/, $path) : @INC; + + push(@potential_libs, @link_args) if scalar @link_args; +! push(@potential_libs, $Config{libs}) if defined $std; + + push(@mods, static_ext()) if $std; + +--- 178,184 ---- + @path = $path ? split(/:/, $path) : @INC; + + push(@potential_libs, @link_args) if scalar @link_args; +! push(@potential_libs, $Config{perllibs}) if defined $std; + + push(@mods, static_ext()) if $std; + +diff -rc perl5.004_02.orig/lib/ExtUtils/Liblist.pm perl5.004_02/lib/ExtUtils/Liblist.pm +*** perl5.004_02.orig/lib/ExtUtils/Liblist.pm Fri Aug 1 19:36:58 1997 +--- perl5.004_02/lib/ExtUtils/Liblist.pm Sun Nov 12 22:06:24 2000 +*************** +*** 16,33 **** + + sub _unix_os2_ext { + my($self,$potential_libs, $verbose) = @_; +! if ($^O =~ 'os2' and $Config{libs}) { + # Dynamic libraries are not transitive, so we may need including + # the libraries linked against perl.dll again. + + $potential_libs .= " " if $potential_libs; +! $potential_libs .= $Config{libs}; + } + return ("", "", "", "") unless $potential_libs; + print STDOUT "Potential libraries are '$potential_libs':\n" if $verbose; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'libs'}; + my $Config_libext = $Config{lib_ext} || ".a"; + + +--- 16,33 ---- + + sub _unix_os2_ext { + my($self,$potential_libs, $verbose) = @_; +! if ($^O =~ 'os2' and $Config{perllibs}) { + # Dynamic libraries are not transitive, so we may need including + # the libraries linked against perl.dll again. + + $potential_libs .= " " if $potential_libs; +! $potential_libs .= $Config{perllibs}; + } + return ("", "", "", "") unless $potential_libs; + print STDOUT "Potential libraries are '$potential_libs':\n" if $verbose; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'perllibs'}; + my $Config_libext = $Config{lib_ext} || ".a"; + + +*************** +*** 186,196 **** + my($self, $potential_libs, $verbose) = @_; + + # If user did not supply a list, we punt. +! # (caller should probably use the list in $Config{libs}) + return ("", "", "", "") unless $potential_libs; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'libs'}; + my($libpth) = $Config{'libpth'}; + my($libext) = $Config{'lib_ext'} || ".lib"; + +--- 186,196 ---- + my($self, $potential_libs, $verbose) = @_; + + # If user did not supply a list, we punt. +! # (caller should probably use the list in $Config{perllibs}) + return ("", "", "", "") unless $potential_libs; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'perllibs'}; + my($libpth) = $Config{'libpth'}; + my($libext) = $Config{'lib_ext'} || ".lib"; + +*************** +*** 540,546 **** + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{libs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs> + as well as in C<$Config{libpth}>. For each library that is found, a +--- 540,546 ---- + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{perllibs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs> + as well as in C<$Config{libpth}>. For each library that is found, a +diff -rc perl5.004_02.orig/lib/ExtUtils/MM_Unix.pm perl5.004_02/lib/ExtUtils/MM_Unix.pm +*** perl5.004_02.orig/lib/ExtUtils/MM_Unix.pm Tue Aug 5 14:28:08 1997 +--- perl5.004_02/lib/ExtUtils/MM_Unix.pm Sun Nov 12 22:06:25 2000 +*************** +*** 2224,2230 **** + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{libs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { +--- 2224,2230 ---- + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{perllibs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { +diff -rc perl5.004_02.orig/myconfig perl5.004_02/myconfig +*** perl5.004_02.orig/myconfig Sat Dec 21 01:13:20 1996 +--- perl5.004_02/myconfig Sun Nov 12 22:06:25 2000 +*************** +*** 35,41 **** + Linker and Libraries: + ld='$ld', ldflags ='$ldflags' + libpth=$libpth +! libs=$libs + libc=$libc, so=$so + useshrplib=$useshrplib, libperl=$libperl + Dynamic Linking: +--- 35,41 ---- + Linker and Libraries: + ld='$ld', ldflags ='$ldflags' + libpth=$libpth +! libs=$perllibs + libc=$libc, so=$so + useshrplib=$useshrplib, libperl=$libperl + Dynamic Linking: +diff -rc perl5.004_02.orig/patchlevel.h perl5.004_02/patchlevel.h +*** perl5.004_02.orig/patchlevel.h Fri Aug 1 15:07:34 1997 +--- perl5.004_02/patchlevel.h Sun Nov 12 22:06:25 2000 +*************** +*** 38,43 **** +--- 38,44 ---- + */ + static char *local_patches[] = { + NULL ++ ,"NODB-1.0 - remove -ldb from core perl binary." + ,NULL + }; + diff --git a/db/perl.DB_File/patches/5.004_03 b/db/perl.DB_File/patches/5.004_03 new file mode 100644 index 000000000..06331eac9 --- /dev/null +++ b/db/perl.DB_File/patches/5.004_03 @@ -0,0 +1,223 @@ +diff -rc perl5.004_03.orig/Configure perl5.004_03/Configure +*** perl5.004_03.orig/Configure Wed Aug 13 16:09:46 1997 +--- perl5.004_03/Configure Sun Nov 12 21:56:18 2000 +*************** +*** 188,193 **** +--- 188,194 ---- + mv='' + nroff='' + perl='' ++ perllibs='' + pg='' + pmake='' + pr='' +*************** +*** 9911,9916 **** +--- 9912,9925 ---- + shift + extensions="$*" + ++ : Remove libraries needed only for extensions ++ : The appropriate ext/Foo/Makefile.PL will add them back in, if ++ : necessary. ++ set X `echo " $libs " | ++ sed -e 's@ -lndbm @ @' -e 's@ -lgdbm @ @' -e 's@ -ldbm @ @' -e 's@ -ldb @ @'` ++ shift ++ perllibs="$*" ++ + : Remove build directory name from cppstdin so it can be used from + : either the present location or the final installed location. + echo " " +*************** +*** 10379,10384 **** +--- 10388,10394 ---- + patchlevel='$patchlevel' + path_sep='$path_sep' + perl='$perl' ++ perllibs='$perllibs' + perladmin='$perladmin' + perlpath='$perlpath' + pg='$pg' +Only in perl5.004_03: Configure.orig +diff -rc perl5.004_03.orig/Makefile.SH perl5.004_03/Makefile.SH +*** perl5.004_03.orig/Makefile.SH Mon Aug 18 19:24:29 1997 +--- perl5.004_03/Makefile.SH Sun Nov 12 21:56:18 2000 +*************** +*** 126,132 **** + ext = \$(dynamic_ext) \$(static_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $libs $cryptlib + + public = perl $suidperl utilities translators + +--- 126,132 ---- + ext = \$(dynamic_ext) \$(static_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $perllibs $cryptlib + + public = perl $suidperl utilities translators + +Only in perl5.004_03: Makefile.SH.orig +diff -rc perl5.004_03.orig/lib/ExtUtils/Embed.pm perl5.004_03/lib/ExtUtils/Embed.pm +*** perl5.004_03.orig/lib/ExtUtils/Embed.pm Fri Aug 1 15:08:44 1997 +--- perl5.004_03/lib/ExtUtils/Embed.pm Sun Nov 12 21:56:18 2000 +*************** +*** 178,184 **** + @path = $path ? split(/:/, $path) : @INC; + + push(@potential_libs, @link_args) if scalar @link_args; +! push(@potential_libs, $Config{libs}) if defined $std; + + push(@mods, static_ext()) if $std; + +--- 178,184 ---- + @path = $path ? split(/:/, $path) : @INC; + + push(@potential_libs, @link_args) if scalar @link_args; +! push(@potential_libs, $Config{perllibs}) if defined $std; + + push(@mods, static_ext()) if $std; + +diff -rc perl5.004_03.orig/lib/ExtUtils/Liblist.pm perl5.004_03/lib/ExtUtils/Liblist.pm +*** perl5.004_03.orig/lib/ExtUtils/Liblist.pm Fri Aug 1 19:36:58 1997 +--- perl5.004_03/lib/ExtUtils/Liblist.pm Sun Nov 12 21:57:17 2000 +*************** +*** 16,33 **** + + sub _unix_os2_ext { + my($self,$potential_libs, $verbose) = @_; +! if ($^O =~ 'os2' and $Config{libs}) { + # Dynamic libraries are not transitive, so we may need including + # the libraries linked against perl.dll again. + + $potential_libs .= " " if $potential_libs; +! $potential_libs .= $Config{libs}; + } + return ("", "", "", "") unless $potential_libs; + print STDOUT "Potential libraries are '$potential_libs':\n" if $verbose; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'libs'}; + my $Config_libext = $Config{lib_ext} || ".a"; + + +--- 16,33 ---- + + sub _unix_os2_ext { + my($self,$potential_libs, $verbose) = @_; +! if ($^O =~ 'os2' and $Config{perllibs}) { + # Dynamic libraries are not transitive, so we may need including + # the libraries linked against perl.dll again. + + $potential_libs .= " " if $potential_libs; +! $potential_libs .= $Config{perllibs}; + } + return ("", "", "", "") unless $potential_libs; + print STDOUT "Potential libraries are '$potential_libs':\n" if $verbose; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'perllibs'}; + my $Config_libext = $Config{lib_ext} || ".a"; + + +*************** +*** 186,196 **** + my($self, $potential_libs, $verbose) = @_; + + # If user did not supply a list, we punt. +! # (caller should probably use the list in $Config{libs}) + return ("", "", "", "") unless $potential_libs; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'libs'}; + my($libpth) = $Config{'libpth'}; + my($libext) = $Config{'lib_ext'} || ".lib"; + +--- 186,196 ---- + my($self, $potential_libs, $verbose) = @_; + + # If user did not supply a list, we punt. +! # (caller should probably use the list in $Config{perllibs}) + return ("", "", "", "") unless $potential_libs; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'perllibs'}; + my($libpth) = $Config{'libpth'}; + my($libext) = $Config{'lib_ext'} || ".lib"; + +*************** +*** 540,546 **** + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{libs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs> + as well as in C<$Config{libpth}>. For each library that is found, a +--- 540,546 ---- + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{perllibs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs> + as well as in C<$Config{libpth}>. For each library that is found, a +Only in perl5.004_03/lib/ExtUtils: Liblist.pm.orig +Only in perl5.004_03/lib/ExtUtils: Liblist.pm.rej +diff -rc perl5.004_03.orig/lib/ExtUtils/MM_Unix.pm perl5.004_03/lib/ExtUtils/MM_Unix.pm +*** perl5.004_03.orig/lib/ExtUtils/MM_Unix.pm Mon Aug 18 19:16:12 1997 +--- perl5.004_03/lib/ExtUtils/MM_Unix.pm Sun Nov 12 21:56:19 2000 +*************** +*** 2224,2230 **** + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{libs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { +--- 2224,2230 ---- + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{perllibs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { +Only in perl5.004_03/lib/ExtUtils: MM_Unix.pm.orig +diff -rc perl5.004_03.orig/myconfig perl5.004_03/myconfig +*** perl5.004_03.orig/myconfig Sat Dec 21 01:13:20 1996 +--- perl5.004_03/myconfig Sun Nov 12 21:56:19 2000 +*************** +*** 35,41 **** + Linker and Libraries: + ld='$ld', ldflags ='$ldflags' + libpth=$libpth +! libs=$libs + libc=$libc, so=$so + useshrplib=$useshrplib, libperl=$libperl + Dynamic Linking: +--- 35,41 ---- + Linker and Libraries: + ld='$ld', ldflags ='$ldflags' + libpth=$libpth +! libs=$perllibs + libc=$libc, so=$so + useshrplib=$useshrplib, libperl=$libperl + Dynamic Linking: +diff -rc perl5.004_03.orig/patchlevel.h perl5.004_03/patchlevel.h +*** perl5.004_03.orig/patchlevel.h Wed Aug 13 11:42:01 1997 +--- perl5.004_03/patchlevel.h Sun Nov 12 21:56:19 2000 +*************** +*** 38,43 **** +--- 38,44 ---- + */ + static char *local_patches[] = { + NULL ++ ,"NODB-1.0 - remove -ldb from core perl binary." + ,NULL + }; + +Only in perl5.004_03: patchlevel.h.orig diff --git a/db/perl.DB_File/patches/5.004_04 b/db/perl.DB_File/patches/5.004_04 new file mode 100644 index 000000000..a227dc700 --- /dev/null +++ b/db/perl.DB_File/patches/5.004_04 @@ -0,0 +1,209 @@ +diff -rc perl5.004_04.orig/Configure perl5.004_04/Configure +*** perl5.004_04.orig/Configure Fri Oct 3 18:57:39 1997 +--- perl5.004_04/Configure Sun Nov 12 21:50:51 2000 +*************** +*** 188,193 **** +--- 188,194 ---- + mv='' + nroff='' + perl='' ++ perllibs='' + pg='' + pmake='' + pr='' +*************** +*** 9910,9915 **** +--- 9911,9924 ---- + shift + extensions="$*" + ++ : Remove libraries needed only for extensions ++ : The appropriate ext/Foo/Makefile.PL will add them back in, if ++ : necessary. ++ set X `echo " $libs " | ++ sed -e 's@ -lndbm @ @' -e 's@ -lgdbm @ @' -e 's@ -ldbm @ @' -e 's@ -ldb @ @'` ++ shift ++ perllibs="$*" ++ + : Remove build directory name from cppstdin so it can be used from + : either the present location or the final installed location. + echo " " +*************** +*** 10378,10383 **** +--- 10387,10393 ---- + patchlevel='$patchlevel' + path_sep='$path_sep' + perl='$perl' ++ perllibs='$perllibs' + perladmin='$perladmin' + perlpath='$perlpath' + pg='$pg' +diff -rc perl5.004_04.orig/Makefile.SH perl5.004_04/Makefile.SH +*** perl5.004_04.orig/Makefile.SH Wed Oct 15 10:33:16 1997 +--- perl5.004_04/Makefile.SH Sun Nov 12 21:50:51 2000 +*************** +*** 129,135 **** + ext = \$(dynamic_ext) \$(static_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $libs $cryptlib + + public = perl $suidperl utilities translators + +--- 129,135 ---- + ext = \$(dynamic_ext) \$(static_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $perllibs $cryptlib + + public = perl $suidperl utilities translators + +diff -rc perl5.004_04.orig/lib/ExtUtils/Embed.pm perl5.004_04/lib/ExtUtils/Embed.pm +*** perl5.004_04.orig/lib/ExtUtils/Embed.pm Fri Aug 1 15:08:44 1997 +--- perl5.004_04/lib/ExtUtils/Embed.pm Sun Nov 12 21:50:51 2000 +*************** +*** 178,184 **** + @path = $path ? split(/:/, $path) : @INC; + + push(@potential_libs, @link_args) if scalar @link_args; +! push(@potential_libs, $Config{libs}) if defined $std; + + push(@mods, static_ext()) if $std; + +--- 178,184 ---- + @path = $path ? split(/:/, $path) : @INC; + + push(@potential_libs, @link_args) if scalar @link_args; +! push(@potential_libs, $Config{perllibs}) if defined $std; + + push(@mods, static_ext()) if $std; + +diff -rc perl5.004_04.orig/lib/ExtUtils/Liblist.pm perl5.004_04/lib/ExtUtils/Liblist.pm +*** perl5.004_04.orig/lib/ExtUtils/Liblist.pm Tue Sep 9 17:41:32 1997 +--- perl5.004_04/lib/ExtUtils/Liblist.pm Sun Nov 12 21:51:33 2000 +*************** +*** 16,33 **** + + sub _unix_os2_ext { + my($self,$potential_libs, $verbose) = @_; +! if ($^O =~ 'os2' and $Config{libs}) { + # Dynamic libraries are not transitive, so we may need including + # the libraries linked against perl.dll again. + + $potential_libs .= " " if $potential_libs; +! $potential_libs .= $Config{libs}; + } + return ("", "", "", "") unless $potential_libs; + warn "Potential libraries are '$potential_libs':\n" if $verbose; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'libs'}; + my $Config_libext = $Config{lib_ext} || ".a"; + + +--- 16,33 ---- + + sub _unix_os2_ext { + my($self,$potential_libs, $verbose) = @_; +! if ($^O =~ 'os2' and $Config{perllibs}) { + # Dynamic libraries are not transitive, so we may need including + # the libraries linked against perl.dll again. + + $potential_libs .= " " if $potential_libs; +! $potential_libs .= $Config{perllibs}; + } + return ("", "", "", "") unless $potential_libs; + warn "Potential libraries are '$potential_libs':\n" if $verbose; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'perllibs'}; + my $Config_libext = $Config{lib_ext} || ".a"; + + +*************** +*** 189,195 **** + return ("", "", "", "") unless $potential_libs; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'libs'}; + my($libpth) = $Config{'libpth'}; + my($libext) = $Config{'lib_ext'} || ".lib"; + +--- 189,195 ---- + return ("", "", "", "") unless $potential_libs; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'perllibs'}; + my($libpth) = $Config{'libpth'}; + my($libext) = $Config{'lib_ext'} || ".lib"; + +*************** +*** 539,545 **** + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{libs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs> + as well as in C<$Config{libpth}>. For each library that is found, a +--- 539,545 ---- + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{perllibs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs> + as well as in C<$Config{libpth}>. For each library that is found, a +diff -rc perl5.004_04.orig/lib/ExtUtils/MM_Unix.pm perl5.004_04/lib/ExtUtils/MM_Unix.pm +*** perl5.004_04.orig/lib/ExtUtils/MM_Unix.pm Wed Oct 8 14:13:51 1997 +--- perl5.004_04/lib/ExtUtils/MM_Unix.pm Sun Nov 12 21:50:51 2000 +*************** +*** 2229,2235 **** + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{libs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { +--- 2229,2235 ---- + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{perllibs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { +diff -rc perl5.004_04.orig/myconfig perl5.004_04/myconfig +*** perl5.004_04.orig/myconfig Mon Oct 6 18:26:49 1997 +--- perl5.004_04/myconfig Sun Nov 12 21:50:51 2000 +*************** +*** 35,41 **** + Linker and Libraries: + ld='$ld', ldflags ='$ldflags' + libpth=$libpth +! libs=$libs + libc=$libc, so=$so + useshrplib=$useshrplib, libperl=$libperl + Dynamic Linking: +--- 35,41 ---- + Linker and Libraries: + ld='$ld', ldflags ='$ldflags' + libpth=$libpth +! libs=$perllibs + libc=$libc, so=$so + useshrplib=$useshrplib, libperl=$libperl + Dynamic Linking: +diff -rc perl5.004_04.orig/patchlevel.h perl5.004_04/patchlevel.h +*** perl5.004_04.orig/patchlevel.h Wed Oct 15 10:55:19 1997 +--- perl5.004_04/patchlevel.h Sun Nov 12 21:50:51 2000 +*************** +*** 39,44 **** +--- 39,45 ---- + /* The following line and terminating '};' are read by perlbug.PL. Don't alter. */ + static char *local_patches[] = { + NULL ++ ,"NODB-1.0 - remove -ldb from core perl binary." + ,NULL + }; + diff --git a/db/perl.DB_File/patches/5.004_05 b/db/perl.DB_File/patches/5.004_05 new file mode 100644 index 000000000..51c8bf350 --- /dev/null +++ b/db/perl.DB_File/patches/5.004_05 @@ -0,0 +1,209 @@ +diff -rc perl5.004_05.orig/Configure perl5.004_05/Configure +*** perl5.004_05.orig/Configure Thu Jan 6 22:05:49 2000 +--- perl5.004_05/Configure Sun Nov 12 21:36:25 2000 +*************** +*** 188,193 **** +--- 188,194 ---- + mv='' + nroff='' + perl='' ++ perllibs='' + pg='' + pmake='' + pr='' +*************** +*** 10164,10169 **** +--- 10165,10178 ---- + shift + extensions="$*" + ++ : Remove libraries needed only for extensions ++ : The appropriate ext/Foo/Makefile.PL will add them back in, if ++ : necessary. ++ set X `echo " $libs " | ++ sed -e 's@ -lndbm @ @' -e 's@ -lgdbm @ @' -e 's@ -ldbm @ @' -e 's@ -ldb @ @'` ++ shift ++ perllibs="$*" ++ + : Remove build directory name from cppstdin so it can be used from + : either the present location or the final installed location. + echo " " +*************** +*** 10648,10653 **** +--- 10657,10663 ---- + patchlevel='$patchlevel' + path_sep='$path_sep' + perl='$perl' ++ perllibs='$perllibs' + perladmin='$perladmin' + perlpath='$perlpath' + pg='$pg' +diff -rc perl5.004_05.orig/Makefile.SH perl5.004_05/Makefile.SH +*** perl5.004_05.orig/Makefile.SH Thu Jan 6 22:05:49 2000 +--- perl5.004_05/Makefile.SH Sun Nov 12 21:36:25 2000 +*************** +*** 151,157 **** + ext = \$(dynamic_ext) \$(static_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $libs $cryptlib + + public = perl $suidperl utilities translators + +--- 151,157 ---- + ext = \$(dynamic_ext) \$(static_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $perllibs $cryptlib + + public = perl $suidperl utilities translators + +diff -rc perl5.004_05.orig/lib/ExtUtils/Embed.pm perl5.004_05/lib/ExtUtils/Embed.pm +*** perl5.004_05.orig/lib/ExtUtils/Embed.pm Fri Aug 1 15:08:44 1997 +--- perl5.004_05/lib/ExtUtils/Embed.pm Sun Nov 12 21:36:25 2000 +*************** +*** 178,184 **** + @path = $path ? split(/:/, $path) : @INC; + + push(@potential_libs, @link_args) if scalar @link_args; +! push(@potential_libs, $Config{libs}) if defined $std; + + push(@mods, static_ext()) if $std; + +--- 178,184 ---- + @path = $path ? split(/:/, $path) : @INC; + + push(@potential_libs, @link_args) if scalar @link_args; +! push(@potential_libs, $Config{perllibs}) if defined $std; + + push(@mods, static_ext()) if $std; + +diff -rc perl5.004_05.orig/lib/ExtUtils/Liblist.pm perl5.004_05/lib/ExtUtils/Liblist.pm +*** perl5.004_05.orig/lib/ExtUtils/Liblist.pm Thu Jan 6 22:05:54 2000 +--- perl5.004_05/lib/ExtUtils/Liblist.pm Sun Nov 12 21:45:31 2000 +*************** +*** 16,33 **** + + sub _unix_os2_ext { + my($self,$potential_libs, $verbose) = @_; +! if ($^O =~ 'os2' and $Config{libs}) { + # Dynamic libraries are not transitive, so we may need including + # the libraries linked against perl.dll again. + + $potential_libs .= " " if $potential_libs; +! $potential_libs .= $Config{libs}; + } + return ("", "", "", "") unless $potential_libs; + warn "Potential libraries are '$potential_libs':\n" if $verbose; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'libs'}; + my $Config_libext = $Config{lib_ext} || ".a"; + + +--- 16,33 ---- + + sub _unix_os2_ext { + my($self,$potential_libs, $verbose) = @_; +! if ($^O =~ 'os2' and $Config{perllibs}) { + # Dynamic libraries are not transitive, so we may need including + # the libraries linked against perl.dll again. + + $potential_libs .= " " if $potential_libs; +! $potential_libs .= $Config{perllibs}; + } + return ("", "", "", "") unless $potential_libs; + warn "Potential libraries are '$potential_libs':\n" if $verbose; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'perllibs'}; + my $Config_libext = $Config{lib_ext} || ".a"; + + +*************** +*** 196,202 **** + my $BC = 1 if $cc =~ /^bcc/i; + my $GC = 1 if $cc =~ /^gcc/i; + my $so = $Config{'so'}; +! my $libs = $Config{'libs'}; + my $libpth = $Config{'libpth'}; + my $libext = $Config{'lib_ext'} || ".lib"; + +--- 196,202 ---- + my $BC = 1 if $cc =~ /^bcc/i; + my $GC = 1 if $cc =~ /^gcc/i; + my $so = $Config{'so'}; +! my $libs = $Config{'perllibs'}; + my $libpth = $Config{'libpth'}; + my $libext = $Config{'lib_ext'} || ".lib"; + +*************** +*** 590,596 **** + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{libs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs> + as well as in C<$Config{libpth}>. For each library that is found, a +--- 590,596 ---- + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{perllibs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs> + as well as in C<$Config{libpth}>. For each library that is found, a +diff -rc perl5.004_05.orig/lib/ExtUtils/MM_Unix.pm perl5.004_05/lib/ExtUtils/MM_Unix.pm +*** perl5.004_05.orig/lib/ExtUtils/MM_Unix.pm Thu Jan 6 22:05:54 2000 +--- perl5.004_05/lib/ExtUtils/MM_Unix.pm Sun Nov 12 21:36:25 2000 +*************** +*** 2246,2252 **** + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{libs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { +--- 2246,2252 ---- + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{perllibs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { +diff -rc perl5.004_05.orig/myconfig perl5.004_05/myconfig +*** perl5.004_05.orig/myconfig Thu Jan 6 22:05:55 2000 +--- perl5.004_05/myconfig Sun Nov 12 21:43:54 2000 +*************** +*** 34,40 **** + Linker and Libraries: + ld='$ld', ldflags ='$ldflags' + libpth=$libpth +! libs=$libs + libc=$libc, so=$so + useshrplib=$useshrplib, libperl=$libperl + Dynamic Linking: +--- 34,40 ---- + Linker and Libraries: + ld='$ld', ldflags ='$ldflags' + libpth=$libpth +! libs=$perllibs + libc=$libc, so=$so + useshrplib=$useshrplib, libperl=$libperl + Dynamic Linking: +diff -rc perl5.004_05.orig/patchlevel.h perl5.004_05/patchlevel.h +*** perl5.004_05.orig/patchlevel.h Thu Jan 6 22:05:48 2000 +--- perl5.004_05/patchlevel.h Sun Nov 12 21:36:25 2000 +*************** +*** 39,44 **** +--- 39,45 ---- + /* The following line and terminating '};' are read by perlbug.PL. Don't alter. */ + static char *local_patches[] = { + NULL ++ ,"NODB-1.0 - remove -ldb from core perl binary." + ,NULL + }; + diff --git a/db/perl.DB_File/patches/5.005 b/db/perl.DB_File/patches/5.005 new file mode 100644 index 000000000..effee3e82 --- /dev/null +++ b/db/perl.DB_File/patches/5.005 @@ -0,0 +1,209 @@ +diff -rc perl5.005.orig/Configure perl5.005/Configure +*** perl5.005.orig/Configure Wed Jul 15 08:05:44 1998 +--- perl5.005/Configure Sun Nov 12 21:30:40 2000 +*************** +*** 234,239 **** +--- 234,240 ---- + nm='' + nroff='' + perl='' ++ perllibs='' + pg='' + pmake='' + pr='' +*************** +*** 11279,11284 **** +--- 11280,11293 ---- + shift + extensions="$*" + ++ : Remove libraries needed only for extensions ++ : The appropriate ext/Foo/Makefile.PL will add them back in, if ++ : necessary. ++ set X `echo " $libs " | ++ sed -e 's@ -lndbm @ @' -e 's@ -lgdbm @ @' -e 's@ -ldbm @ @' -e 's@ -ldb @ @'` ++ shift ++ perllibs="$*" ++ + : Remove build directory name from cppstdin so it can be used from + : either the present location or the final installed location. + echo " " +*************** +*** 11804,11809 **** +--- 11813,11819 ---- + patchlevel='$patchlevel' + path_sep='$path_sep' + perl='$perl' ++ perllibs='$perllibs' + perladmin='$perladmin' + perlpath='$perlpath' + pg='$pg' +diff -rc perl5.005.orig/Makefile.SH perl5.005/Makefile.SH +*** perl5.005.orig/Makefile.SH Sun Jul 19 08:06:35 1998 +--- perl5.005/Makefile.SH Sun Nov 12 21:30:40 2000 +*************** +*** 150,156 **** + ext = \$(dynamic_ext) \$(static_ext) \$(nonxs_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $libs $cryptlib + + public = perl $suidperl utilities translators + +--- 150,156 ---- + ext = \$(dynamic_ext) \$(static_ext) \$(nonxs_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $perllibs $cryptlib + + public = perl $suidperl utilities translators + +diff -rc perl5.005.orig/lib/ExtUtils/Embed.pm perl5.005/lib/ExtUtils/Embed.pm +*** perl5.005.orig/lib/ExtUtils/Embed.pm Wed Jul 22 07:45:02 1998 +--- perl5.005/lib/ExtUtils/Embed.pm Sun Nov 12 21:30:40 2000 +*************** +*** 194,200 **** + @path = $path ? split(/:/, $path) : @INC; + + push(@potential_libs, @link_args) if scalar @link_args; +! push(@potential_libs, $Config{libs}) if defined $std; + + push(@mods, static_ext()) if $std; + +--- 194,200 ---- + @path = $path ? split(/:/, $path) : @INC; + + push(@potential_libs, @link_args) if scalar @link_args; +! push(@potential_libs, $Config{perllibs}) if defined $std; + + push(@mods, static_ext()) if $std; + +diff -rc perl5.005.orig/lib/ExtUtils/Liblist.pm perl5.005/lib/ExtUtils/Liblist.pm +*** perl5.005.orig/lib/ExtUtils/Liblist.pm Wed Jul 22 07:09:42 1998 +--- perl5.005/lib/ExtUtils/Liblist.pm Sun Nov 12 21:30:40 2000 +*************** +*** 16,33 **** + + sub _unix_os2_ext { + my($self,$potential_libs, $verbose) = @_; +! if ($^O =~ 'os2' and $Config{libs}) { + # Dynamic libraries are not transitive, so we may need including + # the libraries linked against perl.dll again. + + $potential_libs .= " " if $potential_libs; +! $potential_libs .= $Config{libs}; + } + return ("", "", "", "") unless $potential_libs; + warn "Potential libraries are '$potential_libs':\n" if $verbose; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'libs'}; + my $Config_libext = $Config{lib_ext} || ".a"; + + +--- 16,33 ---- + + sub _unix_os2_ext { + my($self,$potential_libs, $verbose) = @_; +! if ($^O =~ 'os2' and $Config{perllibs}) { + # Dynamic libraries are not transitive, so we may need including + # the libraries linked against perl.dll again. + + $potential_libs .= " " if $potential_libs; +! $potential_libs .= $Config{perllibs}; + } + return ("", "", "", "") unless $potential_libs; + warn "Potential libraries are '$potential_libs':\n" if $verbose; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'perllibs'}; + my $Config_libext = $Config{lib_ext} || ".a"; + + +*************** +*** 290,296 **** + $self->{CCFLAS} || $Config{'ccflags'}; + @crtls = ( ($dbgqual =~ m-/Debug-i ? $Config{'dbgprefix'} : '') + . 'PerlShr/Share' ); +! push(@crtls, grep { not /\(/ } split /\s+/, $Config{'libs'}); + push(@crtls, grep { not /\(/ } split /\s+/, $Config{'libc'}); + # In general, we pass through the basic libraries from %Config unchanged. + # The one exception is that if we're building in the Perl source tree, and +--- 290,296 ---- + $self->{CCFLAS} || $Config{'ccflags'}; + @crtls = ( ($dbgqual =~ m-/Debug-i ? $Config{'dbgprefix'} : '') + . 'PerlShr/Share' ); +! push(@crtls, grep { not /\(/ } split /\s+/, $Config{'perllibs'}); + push(@crtls, grep { not /\(/ } split /\s+/, $Config{'libc'}); + # In general, we pass through the basic libraries from %Config unchanged. + # The one exception is that if we're building in the Perl source tree, and +*************** +*** 598,604 **** + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{libs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs> + as well as in C<$Config{libpth}>. For each library that is found, a +--- 598,604 ---- + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{perllibs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs> + as well as in C<$Config{libpth}>. For each library that is found, a +diff -rc perl5.005.orig/lib/ExtUtils/MM_Unix.pm perl5.005/lib/ExtUtils/MM_Unix.pm +*** perl5.005.orig/lib/ExtUtils/MM_Unix.pm Tue Jul 14 04:39:12 1998 +--- perl5.005/lib/ExtUtils/MM_Unix.pm Sun Nov 12 21:30:41 2000 +*************** +*** 2281,2287 **** + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{libs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { +--- 2281,2287 ---- + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{perllibs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { +diff -rc perl5.005.orig/myconfig perl5.005/myconfig +*** perl5.005.orig/myconfig Fri Apr 3 01:20:35 1998 +--- perl5.005/myconfig Sun Nov 12 21:30:41 2000 +*************** +*** 34,40 **** + Linker and Libraries: + ld='$ld', ldflags ='$ldflags' + libpth=$libpth +! libs=$libs + libc=$libc, so=$so, useshrplib=$useshrplib, libperl=$libperl + Dynamic Linking: + dlsrc=$dlsrc, dlext=$dlext, d_dlsymun=$d_dlsymun, ccdlflags='$ccdlflags' +--- 34,40 ---- + Linker and Libraries: + ld='$ld', ldflags ='$ldflags' + libpth=$libpth +! libs=$perllibs + libc=$libc, so=$so, useshrplib=$useshrplib, libperl=$libperl + Dynamic Linking: + dlsrc=$dlsrc, dlext=$dlext, d_dlsymun=$d_dlsymun, ccdlflags='$ccdlflags' +diff -rc perl5.005.orig/patchlevel.h perl5.005/patchlevel.h +*** perl5.005.orig/patchlevel.h Wed Jul 22 19:22:01 1998 +--- perl5.005/patchlevel.h Sun Nov 12 21:30:41 2000 +*************** +*** 39,44 **** +--- 39,45 ---- + */ + static char *local_patches[] = { + NULL ++ ,"NODB-1.0 - remove -ldb from core perl binary." + ,NULL + }; + diff --git a/db/perl.DB_File/patches/5.005_01 b/db/perl.DB_File/patches/5.005_01 new file mode 100644 index 000000000..2a05dd545 --- /dev/null +++ b/db/perl.DB_File/patches/5.005_01 @@ -0,0 +1,209 @@ +diff -rc perl5.005_01.orig/Configure perl5.005_01/Configure +*** perl5.005_01.orig/Configure Wed Jul 15 08:05:44 1998 +--- perl5.005_01/Configure Sun Nov 12 20:55:58 2000 +*************** +*** 234,239 **** +--- 234,240 ---- + nm='' + nroff='' + perl='' ++ perllibs='' + pg='' + pmake='' + pr='' +*************** +*** 11279,11284 **** +--- 11280,11293 ---- + shift + extensions="$*" + ++ : Remove libraries needed only for extensions ++ : The appropriate ext/Foo/Makefile.PL will add them back in, if ++ : necessary. ++ set X `echo " $libs " | ++ sed -e 's@ -lndbm @ @' -e 's@ -lgdbm @ @' -e 's@ -ldbm @ @' -e 's@ -ldb @ @'` ++ shift ++ perllibs="$*" ++ + : Remove build directory name from cppstdin so it can be used from + : either the present location or the final installed location. + echo " " +*************** +*** 11804,11809 **** +--- 11813,11819 ---- + patchlevel='$patchlevel' + path_sep='$path_sep' + perl='$perl' ++ perllibs='$perllibs' + perladmin='$perladmin' + perlpath='$perlpath' + pg='$pg' +diff -rc perl5.005_01.orig/Makefile.SH perl5.005_01/Makefile.SH +*** perl5.005_01.orig/Makefile.SH Sun Jul 19 08:06:35 1998 +--- perl5.005_01/Makefile.SH Sun Nov 12 20:55:58 2000 +*************** +*** 150,156 **** + ext = \$(dynamic_ext) \$(static_ext) \$(nonxs_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $libs $cryptlib + + public = perl $suidperl utilities translators + +--- 150,156 ---- + ext = \$(dynamic_ext) \$(static_ext) \$(nonxs_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $perllibs $cryptlib + + public = perl $suidperl utilities translators + +diff -rc perl5.005_01.orig/lib/ExtUtils/Embed.pm perl5.005_01/lib/ExtUtils/Embed.pm +*** perl5.005_01.orig/lib/ExtUtils/Embed.pm Wed Jul 22 07:45:02 1998 +--- perl5.005_01/lib/ExtUtils/Embed.pm Sun Nov 12 20:55:58 2000 +*************** +*** 194,200 **** + @path = $path ? split(/:/, $path) : @INC; + + push(@potential_libs, @link_args) if scalar @link_args; +! push(@potential_libs, $Config{libs}) if defined $std; + + push(@mods, static_ext()) if $std; + +--- 194,200 ---- + @path = $path ? split(/:/, $path) : @INC; + + push(@potential_libs, @link_args) if scalar @link_args; +! push(@potential_libs, $Config{perllibs}) if defined $std; + + push(@mods, static_ext()) if $std; + +diff -rc perl5.005_01.orig/lib/ExtUtils/Liblist.pm perl5.005_01/lib/ExtUtils/Liblist.pm +*** perl5.005_01.orig/lib/ExtUtils/Liblist.pm Wed Jul 22 07:09:42 1998 +--- perl5.005_01/lib/ExtUtils/Liblist.pm Sun Nov 12 20:55:58 2000 +*************** +*** 16,33 **** + + sub _unix_os2_ext { + my($self,$potential_libs, $verbose) = @_; +! if ($^O =~ 'os2' and $Config{libs}) { + # Dynamic libraries are not transitive, so we may need including + # the libraries linked against perl.dll again. + + $potential_libs .= " " if $potential_libs; +! $potential_libs .= $Config{libs}; + } + return ("", "", "", "") unless $potential_libs; + warn "Potential libraries are '$potential_libs':\n" if $verbose; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'libs'}; + my $Config_libext = $Config{lib_ext} || ".a"; + + +--- 16,33 ---- + + sub _unix_os2_ext { + my($self,$potential_libs, $verbose) = @_; +! if ($^O =~ 'os2' and $Config{perllibs}) { + # Dynamic libraries are not transitive, so we may need including + # the libraries linked against perl.dll again. + + $potential_libs .= " " if $potential_libs; +! $potential_libs .= $Config{perllibs}; + } + return ("", "", "", "") unless $potential_libs; + warn "Potential libraries are '$potential_libs':\n" if $verbose; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'perllibs'}; + my $Config_libext = $Config{lib_ext} || ".a"; + + +*************** +*** 290,296 **** + $self->{CCFLAS} || $Config{'ccflags'}; + @crtls = ( ($dbgqual =~ m-/Debug-i ? $Config{'dbgprefix'} : '') + . 'PerlShr/Share' ); +! push(@crtls, grep { not /\(/ } split /\s+/, $Config{'libs'}); + push(@crtls, grep { not /\(/ } split /\s+/, $Config{'libc'}); + # In general, we pass through the basic libraries from %Config unchanged. + # The one exception is that if we're building in the Perl source tree, and +--- 290,296 ---- + $self->{CCFLAS} || $Config{'ccflags'}; + @crtls = ( ($dbgqual =~ m-/Debug-i ? $Config{'dbgprefix'} : '') + . 'PerlShr/Share' ); +! push(@crtls, grep { not /\(/ } split /\s+/, $Config{'perllibs'}); + push(@crtls, grep { not /\(/ } split /\s+/, $Config{'libc'}); + # In general, we pass through the basic libraries from %Config unchanged. + # The one exception is that if we're building in the Perl source tree, and +*************** +*** 598,604 **** + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{libs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs> + as well as in C<$Config{libpth}>. For each library that is found, a +--- 598,604 ---- + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{perllibs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs> + as well as in C<$Config{libpth}>. For each library that is found, a +diff -rc perl5.005_01.orig/lib/ExtUtils/MM_Unix.pm perl5.005_01/lib/ExtUtils/MM_Unix.pm +*** perl5.005_01.orig/lib/ExtUtils/MM_Unix.pm Tue Jul 14 04:39:12 1998 +--- perl5.005_01/lib/ExtUtils/MM_Unix.pm Sun Nov 12 20:55:58 2000 +*************** +*** 2281,2287 **** + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{libs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { +--- 2281,2287 ---- + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{perllibs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { +diff -rc perl5.005_01.orig/myconfig perl5.005_01/myconfig +*** perl5.005_01.orig/myconfig Fri Apr 3 01:20:35 1998 +--- perl5.005_01/myconfig Sun Nov 12 20:55:58 2000 +*************** +*** 34,40 **** + Linker and Libraries: + ld='$ld', ldflags ='$ldflags' + libpth=$libpth +! libs=$libs + libc=$libc, so=$so, useshrplib=$useshrplib, libperl=$libperl + Dynamic Linking: + dlsrc=$dlsrc, dlext=$dlext, d_dlsymun=$d_dlsymun, ccdlflags='$ccdlflags' +--- 34,40 ---- + Linker and Libraries: + ld='$ld', ldflags ='$ldflags' + libpth=$libpth +! libs=$perllibs + libc=$libc, so=$so, useshrplib=$useshrplib, libperl=$libperl + Dynamic Linking: + dlsrc=$dlsrc, dlext=$dlext, d_dlsymun=$d_dlsymun, ccdlflags='$ccdlflags' +diff -rc perl5.005_01.orig/patchlevel.h perl5.005_01/patchlevel.h +*** perl5.005_01.orig/patchlevel.h Mon Jan 3 11:07:45 2000 +--- perl5.005_01/patchlevel.h Sun Nov 12 20:55:58 2000 +*************** +*** 39,44 **** +--- 39,45 ---- + */ + static char *local_patches[] = { + NULL ++ ,"NODB-1.0 - remove -ldb from core perl binary." + ,NULL + }; + diff --git a/db/perl.DB_File/patches/5.005_02 b/db/perl.DB_File/patches/5.005_02 new file mode 100644 index 000000000..5dd57ddc0 --- /dev/null +++ b/db/perl.DB_File/patches/5.005_02 @@ -0,0 +1,264 @@ +diff -rc perl5.005_02.orig/Configure perl5.005_02/Configure +*** perl5.005_02.orig/Configure Mon Jan 3 11:12:20 2000 +--- perl5.005_02/Configure Sun Nov 12 20:50:51 2000 +*************** +*** 234,239 **** +--- 234,240 ---- + nm='' + nroff='' + perl='' ++ perllibs='' + pg='' + pmake='' + pr='' +*************** +*** 11334,11339 **** +--- 11335,11348 ---- + shift + extensions="$*" + ++ : Remove libraries needed only for extensions ++ : The appropriate ext/Foo/Makefile.PL will add them back in, if ++ : necessary. ++ set X `echo " $libs " | ++ sed -e 's@ -lndbm @ @' -e 's@ -lgdbm @ @' -e 's@ -ldbm @ @' -e 's@ -ldb @ @'` ++ shift ++ perllibs="$*" ++ + : Remove build directory name from cppstdin so it can be used from + : either the present location or the final installed location. + echo " " +*************** +*** 11859,11864 **** +--- 11868,11874 ---- + patchlevel='$patchlevel' + path_sep='$path_sep' + perl='$perl' ++ perllibs='$perllibs' + perladmin='$perladmin' + perlpath='$perlpath' + pg='$pg' +Only in perl5.005_02: Configure.orig +diff -rc perl5.005_02.orig/Makefile.SH perl5.005_02/Makefile.SH +*** perl5.005_02.orig/Makefile.SH Sun Jul 19 08:06:35 1998 +--- perl5.005_02/Makefile.SH Sun Nov 12 20:50:51 2000 +*************** +*** 150,156 **** + ext = \$(dynamic_ext) \$(static_ext) \$(nonxs_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $libs $cryptlib + + public = perl $suidperl utilities translators + +--- 150,156 ---- + ext = \$(dynamic_ext) \$(static_ext) \$(nonxs_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $perllibs $cryptlib + + public = perl $suidperl utilities translators + +Only in perl5.005_02: Makefile.SH.orig +diff -rc perl5.005_02.orig/lib/ExtUtils/Embed.pm perl5.005_02/lib/ExtUtils/Embed.pm +*** perl5.005_02.orig/lib/ExtUtils/Embed.pm Wed Jul 22 07:45:02 1998 +--- perl5.005_02/lib/ExtUtils/Embed.pm Sun Nov 12 20:50:51 2000 +*************** +*** 194,200 **** + @path = $path ? split(/:/, $path) : @INC; + + push(@potential_libs, @link_args) if scalar @link_args; +! push(@potential_libs, $Config{libs}) if defined $std; + + push(@mods, static_ext()) if $std; + +--- 194,200 ---- + @path = $path ? split(/:/, $path) : @INC; + + push(@potential_libs, @link_args) if scalar @link_args; +! push(@potential_libs, $Config{perllibs}) if defined $std; + + push(@mods, static_ext()) if $std; + +diff -rc perl5.005_02.orig/lib/ExtUtils/Liblist.pm perl5.005_02/lib/ExtUtils/Liblist.pm +*** perl5.005_02.orig/lib/ExtUtils/Liblist.pm Mon Jan 3 11:12:21 2000 +--- perl5.005_02/lib/ExtUtils/Liblist.pm Sun Nov 12 20:50:51 2000 +*************** +*** 16,33 **** + + sub _unix_os2_ext { + my($self,$potential_libs, $verbose) = @_; +! if ($^O =~ 'os2' and $Config{libs}) { + # Dynamic libraries are not transitive, so we may need including + # the libraries linked against perl.dll again. + + $potential_libs .= " " if $potential_libs; +! $potential_libs .= $Config{libs}; + } + return ("", "", "", "") unless $potential_libs; + warn "Potential libraries are '$potential_libs':\n" if $verbose; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'libs'}; + my $Config_libext = $Config{lib_ext} || ".a"; + + +--- 16,33 ---- + + sub _unix_os2_ext { + my($self,$potential_libs, $verbose) = @_; +! if ($^O =~ 'os2' and $Config{perllibs}) { + # Dynamic libraries are not transitive, so we may need including + # the libraries linked against perl.dll again. + + $potential_libs .= " " if $potential_libs; +! $potential_libs .= $Config{perllibs}; + } + return ("", "", "", "") unless $potential_libs; + warn "Potential libraries are '$potential_libs':\n" if $verbose; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'perllibs'}; + my $Config_libext = $Config{lib_ext} || ".a"; + + +*************** +*** 196,202 **** + my $BC = 1 if $cc =~ /^bcc/i; + my $GC = 1 if $cc =~ /^gcc/i; + my $so = $Config{'so'}; +! my $libs = $Config{'libs'}; + my $libpth = $Config{'libpth'}; + my $libext = $Config{'lib_ext'} || ".lib"; + +--- 196,202 ---- + my $BC = 1 if $cc =~ /^bcc/i; + my $GC = 1 if $cc =~ /^gcc/i; + my $so = $Config{'so'}; +! my $libs = $Config{'perllibs'}; + my $libpth = $Config{'libpth'}; + my $libext = $Config{'lib_ext'} || ".lib"; + +*************** +*** 333,339 **** + $self->{CCFLAS} || $Config{'ccflags'}; + @crtls = ( ($dbgqual =~ m-/Debug-i ? $Config{'dbgprefix'} : '') + . 'PerlShr/Share' ); +! push(@crtls, grep { not /\(/ } split /\s+/, $Config{'libs'}); + push(@crtls, grep { not /\(/ } split /\s+/, $Config{'libc'}); + # In general, we pass through the basic libraries from %Config unchanged. + # The one exception is that if we're building in the Perl source tree, and +--- 333,339 ---- + $self->{CCFLAS} || $Config{'ccflags'}; + @crtls = ( ($dbgqual =~ m-/Debug-i ? $Config{'dbgprefix'} : '') + . 'PerlShr/Share' ); +! push(@crtls, grep { not /\(/ } split /\s+/, $Config{'perllibs'}); + push(@crtls, grep { not /\(/ } split /\s+/, $Config{'libc'}); + # In general, we pass through the basic libraries from %Config unchanged. + # The one exception is that if we're building in the Perl source tree, and +*************** +*** 623,629 **** + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{libs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs> + as well as in C<$Config{libpth}>. For each library that is found, a +--- 623,629 ---- + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{perllibs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs> + as well as in C<$Config{libpth}>. For each library that is found, a +*************** +*** 666,672 **** + alphanumeric characters are treated as flags. Unknown flags will be ignored. + + An entry that matches C disables the appending of default +! libraries found in C<$Config{libs}> (this should be only needed very rarely). + + An entry that matches C disables all searching for + the libraries specified after it. Translation of C<-Lfoo> and +--- 666,672 ---- + alphanumeric characters are treated as flags. Unknown flags will be ignored. + + An entry that matches C disables the appending of default +! libraries found in C<$Config{perllibs}> (this should be only needed very rarely). + + An entry that matches C disables all searching for + the libraries specified after it. Translation of C<-Lfoo> and +*************** +*** 676,682 **** + + An entry that matches C reenables searching for + the libraries specified after it. You can put it at the end to +! enable searching for default libraries specified by C<$Config{libs}>. + + =item * + +--- 676,682 ---- + + An entry that matches C reenables searching for + the libraries specified after it. You can put it at the end to +! enable searching for default libraries specified by C<$Config{perllibs}>. + + =item * + +Only in perl5.005_02/lib/ExtUtils: Liblist.pm.orig +diff -rc perl5.005_02.orig/lib/ExtUtils/MM_Unix.pm perl5.005_02/lib/ExtUtils/MM_Unix.pm +*** perl5.005_02.orig/lib/ExtUtils/MM_Unix.pm Tue Jul 14 04:39:12 1998 +--- perl5.005_02/lib/ExtUtils/MM_Unix.pm Sun Nov 12 20:50:51 2000 +*************** +*** 2281,2287 **** + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{libs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { +--- 2281,2287 ---- + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{perllibs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { +Only in perl5.005_02/lib/ExtUtils: MM_Unix.pm.orig +diff -rc perl5.005_02.orig/myconfig perl5.005_02/myconfig +*** perl5.005_02.orig/myconfig Fri Apr 3 01:20:35 1998 +--- perl5.005_02/myconfig Sun Nov 12 20:50:51 2000 +*************** +*** 34,40 **** + Linker and Libraries: + ld='$ld', ldflags ='$ldflags' + libpth=$libpth +! libs=$libs + libc=$libc, so=$so, useshrplib=$useshrplib, libperl=$libperl + Dynamic Linking: + dlsrc=$dlsrc, dlext=$dlext, d_dlsymun=$d_dlsymun, ccdlflags='$ccdlflags' +--- 34,40 ---- + Linker and Libraries: + ld='$ld', ldflags ='$ldflags' + libpth=$libpth +! libs=$perllibs + libc=$libc, so=$so, useshrplib=$useshrplib, libperl=$libperl + Dynamic Linking: + dlsrc=$dlsrc, dlext=$dlext, d_dlsymun=$d_dlsymun, ccdlflags='$ccdlflags' +diff -rc perl5.005_02.orig/patchlevel.h perl5.005_02/patchlevel.h +*** perl5.005_02.orig/patchlevel.h Mon Jan 3 11:12:19 2000 +--- perl5.005_02/patchlevel.h Sun Nov 12 20:50:51 2000 +*************** +*** 40,45 **** +--- 40,46 ---- + */ + static char *local_patches[] = { + NULL ++ ,"NODB-1.0 - remove -ldb from core perl binary." + ,NULL + }; + diff --git a/db/perl.DB_File/patches/5.005_03 b/db/perl.DB_File/patches/5.005_03 new file mode 100644 index 000000000..115f9f5b9 --- /dev/null +++ b/db/perl.DB_File/patches/5.005_03 @@ -0,0 +1,250 @@ +diff -rc perl5.005_03.orig/Configure perl5.005_03/Configure +*** perl5.005_03.orig/Configure Sun Mar 28 17:12:57 1999 +--- perl5.005_03/Configure Sun Sep 17 22:19:16 2000 +*************** +*** 208,213 **** +--- 208,214 ---- + nm='' + nroff='' + perl='' ++ perllibs='' + pg='' + pmake='' + pr='' +*************** +*** 11642,11647 **** +--- 11643,11656 ---- + shift + extensions="$*" + ++ : Remove libraries needed only for extensions ++ : The appropriate ext/Foo/Makefile.PL will add them back in, if ++ : necessary. ++ set X `echo " $libs " | ++ sed -e 's@ -lndbm @ @' -e 's@ -lgdbm @ @' -e 's@ -ldbm @ @' -e 's@ -ldb @ @'` ++ shift ++ perllibs="$*" ++ + : Remove build directory name from cppstdin so it can be used from + : either the present location or the final installed location. + echo " " +*************** +*** 12183,12188 **** +--- 12192,12198 ---- + patchlevel='$patchlevel' + path_sep='$path_sep' + perl='$perl' ++ perllibs='$perllibs' + perladmin='$perladmin' + perlpath='$perlpath' + pg='$pg' +diff -rc perl5.005_03.orig/Makefile.SH perl5.005_03/Makefile.SH +*** perl5.005_03.orig/Makefile.SH Thu Mar 4 02:35:25 1999 +--- perl5.005_03/Makefile.SH Sun Sep 17 22:21:01 2000 +*************** +*** 58,67 **** + shrpldflags="-H512 -T512 -bhalt:4 -bM:SRE -bE:perl.exp" + case "$osvers" in + 3*) +! shrpldflags="$shrpldflags -e _nostart $ldflags $libs $cryptlib" + ;; + *) +! shrpldflags="$shrpldflags -b noentry $ldflags $libs $cryptlib" + ;; + esac + aixinstdir=`pwd | sed 's/\/UU$//'` +--- 58,67 ---- + shrpldflags="-H512 -T512 -bhalt:4 -bM:SRE -bE:perl.exp" + case "$osvers" in + 3*) +! shrpldflags="$shrpldflags -e _nostart $ldflags $perllibs $cryptlib" + ;; + *) +! shrpldflags="$shrpldflags -b noentry $ldflags $perllibs $cryptlib" + ;; + esac + aixinstdir=`pwd | sed 's/\/UU$//'` +*************** +*** 155,161 **** + ext = \$(dynamic_ext) \$(static_ext) \$(nonxs_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $libs $cryptlib + + public = perl $suidperl utilities translators + +--- 155,161 ---- + ext = \$(dynamic_ext) \$(static_ext) \$(nonxs_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $perllibs $cryptlib + + public = perl $suidperl utilities translators + +diff -rc perl5.005_03.orig/lib/ExtUtils/Embed.pm perl5.005_03/lib/ExtUtils/Embed.pm +*** perl5.005_03.orig/lib/ExtUtils/Embed.pm Wed Jan 6 02:17:50 1999 +--- perl5.005_03/lib/ExtUtils/Embed.pm Sun Sep 17 22:19:16 2000 +*************** +*** 194,200 **** + @path = $path ? split(/:/, $path) : @INC; + + push(@potential_libs, @link_args) if scalar @link_args; +! push(@potential_libs, $Config{libs}) if defined $std; + + push(@mods, static_ext()) if $std; + +--- 194,200 ---- + @path = $path ? split(/:/, $path) : @INC; + + push(@potential_libs, @link_args) if scalar @link_args; +! push(@potential_libs, $Config{perllibs}) if defined $std; + + push(@mods, static_ext()) if $std; + +diff -rc perl5.005_03.orig/lib/ExtUtils/Liblist.pm perl5.005_03/lib/ExtUtils/Liblist.pm +*** perl5.005_03.orig/lib/ExtUtils/Liblist.pm Wed Jan 6 02:17:47 1999 +--- perl5.005_03/lib/ExtUtils/Liblist.pm Sun Sep 17 22:19:16 2000 +*************** +*** 16,33 **** + + sub _unix_os2_ext { + my($self,$potential_libs, $verbose) = @_; +! if ($^O =~ 'os2' and $Config{libs}) { + # Dynamic libraries are not transitive, so we may need including + # the libraries linked against perl.dll again. + + $potential_libs .= " " if $potential_libs; +! $potential_libs .= $Config{libs}; + } + return ("", "", "", "") unless $potential_libs; + warn "Potential libraries are '$potential_libs':\n" if $verbose; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'libs'}; + my $Config_libext = $Config{lib_ext} || ".a"; + + +--- 16,33 ---- + + sub _unix_os2_ext { + my($self,$potential_libs, $verbose) = @_; +! if ($^O =~ 'os2' and $Config{perllibs}) { + # Dynamic libraries are not transitive, so we may need including + # the libraries linked against perl.dll again. + + $potential_libs .= " " if $potential_libs; +! $potential_libs .= $Config{perllibs}; + } + return ("", "", "", "") unless $potential_libs; + warn "Potential libraries are '$potential_libs':\n" if $verbose; + + my($so) = $Config{'so'}; +! my($libs) = $Config{'perllibs'}; + my $Config_libext = $Config{lib_ext} || ".a"; + + +*************** +*** 196,202 **** + my $BC = 1 if $cc =~ /^bcc/i; + my $GC = 1 if $cc =~ /^gcc/i; + my $so = $Config{'so'}; +! my $libs = $Config{'libs'}; + my $libpth = $Config{'libpth'}; + my $libext = $Config{'lib_ext'} || ".lib"; + +--- 196,202 ---- + my $BC = 1 if $cc =~ /^bcc/i; + my $GC = 1 if $cc =~ /^gcc/i; + my $so = $Config{'so'}; +! my $libs = $Config{'perllibs'}; + my $libpth = $Config{'libpth'}; + my $libext = $Config{'lib_ext'} || ".lib"; + +*************** +*** 336,342 **** + $self->{CCFLAS} || $Config{'ccflags'}; + @crtls = ( ($dbgqual =~ m-/Debug-i ? $Config{'dbgprefix'} : '') + . 'PerlShr/Share' ); +! push(@crtls, grep { not /\(/ } split /\s+/, $Config{'libs'}); + push(@crtls, grep { not /\(/ } split /\s+/, $Config{'libc'}); + # In general, we pass through the basic libraries from %Config unchanged. + # The one exception is that if we're building in the Perl source tree, and +--- 336,342 ---- + $self->{CCFLAS} || $Config{'ccflags'}; + @crtls = ( ($dbgqual =~ m-/Debug-i ? $Config{'dbgprefix'} : '') + . 'PerlShr/Share' ); +! push(@crtls, grep { not /\(/ } split /\s+/, $Config{'perllibs'}); + push(@crtls, grep { not /\(/ } split /\s+/, $Config{'libc'}); + # In general, we pass through the basic libraries from %Config unchanged. + # The one exception is that if we're building in the Perl source tree, and +*************** +*** 626,632 **** + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{libs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs>, + C<$Config{libpth}>, and in C<$Config{installarchlib}/CORE>. +--- 626,632 ---- + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{perllibs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs>, + C<$Config{libpth}>, and in C<$Config{installarchlib}/CORE>. +*************** +*** 670,676 **** + alphanumeric characters are treated as flags. Unknown flags will be ignored. + + An entry that matches C disables the appending of default +! libraries found in C<$Config{libs}> (this should be only needed very rarely). + + An entry that matches C disables all searching for + the libraries specified after it. Translation of C<-Lfoo> and +--- 670,676 ---- + alphanumeric characters are treated as flags. Unknown flags will be ignored. + + An entry that matches C disables the appending of default +! libraries found in C<$Config{perllibs}> (this should be only needed very rarely). + + An entry that matches C disables all searching for + the libraries specified after it. Translation of C<-Lfoo> and +*************** +*** 680,686 **** + + An entry that matches C reenables searching for + the libraries specified after it. You can put it at the end to +! enable searching for default libraries specified by C<$Config{libs}>. + + =item * + +--- 680,686 ---- + + An entry that matches C reenables searching for + the libraries specified after it. You can put it at the end to +! enable searching for default libraries specified by C<$Config{perllibs}>. + + =item * + +diff -rc perl5.005_03.orig/lib/ExtUtils/MM_Unix.pm perl5.005_03/lib/ExtUtils/MM_Unix.pm +*** perl5.005_03.orig/lib/ExtUtils/MM_Unix.pm Fri Mar 5 00:34:20 1999 +--- perl5.005_03/lib/ExtUtils/MM_Unix.pm Sun Sep 17 22:19:16 2000 +*************** +*** 2284,2290 **** + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{libs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { +--- 2284,2290 ---- + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{perllibs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { diff --git a/db/perl.DB_File/patches/5.6.0 b/db/perl.DB_File/patches/5.6.0 new file mode 100644 index 000000000..1f9b3b620 --- /dev/null +++ b/db/perl.DB_File/patches/5.6.0 @@ -0,0 +1,294 @@ +diff -cr perl-5.6.0.orig/Configure perl-5.6.0/Configure +*** perl-5.6.0.orig/Configure Wed Mar 22 20:36:37 2000 +--- perl-5.6.0/Configure Sun Sep 17 23:40:15 2000 +*************** +*** 217,222 **** +--- 217,223 ---- + nm='' + nroff='' + perl='' ++ perllibs='' + pg='' + pmake='' + pr='' +*************** +*** 14971,14976 **** +--- 14972,14985 ---- + shift + extensions="$*" + ++ : Remove libraries needed only for extensions ++ : The appropriate ext/Foo/Makefile.PL will add them back in, if ++ : necessary. ++ set X `echo " $libs " | ++ sed -e 's@ -lndbm @ @' -e 's@ -lgdbm @ @' -e 's@ -ldbm @ @' -e 's@ -ldb @ @'` ++ shift ++ perllibs="$*" ++ + : Remove build directory name from cppstdin so it can be used from + : either the present location or the final installed location. + echo " " +*************** +*** 15640,15645 **** +--- 15649,15655 ---- + path_sep='$path_sep' + perl5='$perl5' + perl='$perl' ++ perllibs='$perllibs' + perladmin='$perladmin' + perlpath='$perlpath' + pg='$pg' +diff -cr perl-5.6.0.orig/Makefile.SH perl-5.6.0/Makefile.SH +*** perl-5.6.0.orig/Makefile.SH Sat Mar 11 16:05:24 2000 +--- perl-5.6.0/Makefile.SH Sun Sep 17 23:40:15 2000 +*************** +*** 70,76 **** + *) shrpldflags="$shrpldflags -b noentry" + ;; + esac +! shrpldflags="$shrpldflags $ldflags $libs $cryptlib" + linklibperl="-L $archlibexp/CORE -L `pwd | sed 's/\/UU$//'` -lperl" + ;; + hpux*) +--- 70,76 ---- + *) shrpldflags="$shrpldflags -b noentry" + ;; + esac +! shrpldflags="$shrpldflags $ldflags $perllibs $cryptlib" + linklibperl="-L $archlibexp/CORE -L `pwd | sed 's/\/UU$//'` -lperl" + ;; + hpux*) +*************** +*** 176,182 **** + ext = \$(dynamic_ext) \$(static_ext) \$(nonxs_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $libs $cryptlib + + public = perl $suidperl utilities translators + +--- 176,182 ---- + ext = \$(dynamic_ext) \$(static_ext) \$(nonxs_ext) + DYNALOADER = lib/auto/DynaLoader/DynaLoader\$(LIB_EXT) + +! libs = $perllibs $cryptlib + + public = perl $suidperl utilities translators + +*************** +*** 333,339 **** + case "$osname" in + aix) + $spitshell >>Makefile <>Makefile <{CCFLAS} || $Config{'ccflags'}; + @crtls = ( ($dbgqual =~ m-/Debug-i ? $Config{'dbgprefix'} : '') + . 'PerlShr/Share' ); +! push(@crtls, grep { not /\(/ } split /\s+/, $Config{'libs'}); + push(@crtls, grep { not /\(/ } split /\s+/, $Config{'libc'}); + # In general, we pass through the basic libraries from %Config unchanged. + # The one exception is that if we're building in the Perl source tree, and +--- 338,344 ---- + $self->{CCFLAS} || $Config{'ccflags'}; + @crtls = ( ($dbgqual =~ m-/Debug-i ? $Config{'dbgprefix'} : '') + . 'PerlShr/Share' ); +! push(@crtls, grep { not /\(/ } split /\s+/, $Config{'perllibs'}); + push(@crtls, grep { not /\(/ } split /\s+/, $Config{'libc'}); + # In general, we pass through the basic libraries from %Config unchanged. + # The one exception is that if we're building in the Perl source tree, and +*************** +*** 624,630 **** + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{libs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs>, + C<$Config{libpth}>, and in C<$Config{installarchlib}/CORE>. +--- 624,630 ---- + =item * + + If C<$potential_libs> is empty, the return value will be empty. +! Otherwise, the libraries specified by C<$Config{perllibs}> (see Config.pm) + will be appended to the list of C<$potential_libs>. The libraries + will be searched for in the directories specified in C<$potential_libs>, + C<$Config{libpth}>, and in C<$Config{installarchlib}/CORE>. +*************** +*** 668,674 **** + alphanumeric characters are treated as flags. Unknown flags will be ignored. + + An entry that matches C disables the appending of default +! libraries found in C<$Config{libs}> (this should be only needed very rarely). + + An entry that matches C disables all searching for + the libraries specified after it. Translation of C<-Lfoo> and +--- 668,674 ---- + alphanumeric characters are treated as flags. Unknown flags will be ignored. + + An entry that matches C disables the appending of default +! libraries found in C<$Config{perllibs}> (this should be only needed very rarely). + + An entry that matches C disables all searching for + the libraries specified after it. Translation of C<-Lfoo> and +*************** +*** 678,684 **** + + An entry that matches C reenables searching for + the libraries specified after it. You can put it at the end to +! enable searching for default libraries specified by C<$Config{libs}>. + + =item * + +--- 678,684 ---- + + An entry that matches C reenables searching for + the libraries specified after it. You can put it at the end to +! enable searching for default libraries specified by C<$Config{perllibs}>. + + =item * + +diff -cr perl-5.6.0.orig/lib/ExtUtils/MM_Unix.pm perl-5.6.0/lib/ExtUtils/MM_Unix.pm +*** perl-5.6.0.orig/lib/ExtUtils/MM_Unix.pm Thu Mar 2 17:52:52 2000 +--- perl-5.6.0/lib/ExtUtils/MM_Unix.pm Sun Sep 17 23:40:15 2000 +*************** +*** 2450,2456 **** + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{libs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { +--- 2450,2456 ---- + MAP_STATIC = ", + join(" \\\n\t", reverse sort keys %static), " + +! MAP_PRELIBS = $Config::Config{perllibs} $Config::Config{cryptlib} + "; + + if (defined $libperl) { +diff -cr perl-5.6.0.orig/myconfig.SH perl-5.6.0/myconfig.SH +*** perl-5.6.0.orig/myconfig.SH Sat Feb 26 06:34:49 2000 +--- perl-5.6.0/myconfig.SH Sun Sep 17 23:41:17 2000 +*************** +*** 48,54 **** + Linker and Libraries: + ld='$ld', ldflags ='$ldflags' + libpth=$libpth +! libs=$libs + libc=$libc, so=$so, useshrplib=$useshrplib, libperl=$libperl + Dynamic Linking: + dlsrc=$dlsrc, dlext=$dlext, d_dlsymun=$d_dlsymun, ccdlflags='$ccdlflags' +--- 48,54 ---- + Linker and Libraries: + ld='$ld', ldflags ='$ldflags' + libpth=$libpth +! libs=$perllibs + libc=$libc, so=$so, useshrplib=$useshrplib, libperl=$libperl + Dynamic Linking: + dlsrc=$dlsrc, dlext=$dlext, d_dlsymun=$d_dlsymun, ccdlflags='$ccdlflags' +diff -cr perl-5.6.0.orig/patchlevel.h perl-5.6.0/patchlevel.h +*** perl-5.6.0.orig/patchlevel.h Wed Mar 22 20:23:11 2000 +--- perl-5.6.0/patchlevel.h Sun Sep 17 23:40:15 2000 +*************** +*** 70,75 **** +--- 70,76 ---- + #if !defined(PERL_PATCHLEVEL_H_IMPLICIT) && !defined(LOCAL_PATCH_COUNT) + static char *local_patches[] = { + NULL ++ ,"NODB-1.0 - remove -ldb from core perl binary." + ,NULL + }; + diff --git a/db/perl.DB_File/t/db-btree.t b/db/perl.DB_File/t/db-btree.t new file mode 100644 index 000000000..377cfe45c --- /dev/null +++ b/db/perl.DB_File/t/db-btree.t @@ -0,0 +1,1306 @@ +#!./perl -w + +use warnings; +use strict; + +BEGIN { + unless(grep /blib/, @INC) { + chdir 't' if -d 't'; + @INC = '../lib' if -d '../lib'; + } +} + +use Config; + +BEGIN { + if(-d "lib" && -f "TEST") { + if ($Config{'extensions'} !~ /\bDB_File\b/ ) { + print "1..157\n"; + exit 0; + } + } +} + +use DB_File; +use Fcntl; + +print "1..157\n"; + +sub ok +{ + my $no = shift ; + my $result = shift ; + + print "not " unless $result ; + print "ok $no\n" ; +} + +sub lexical +{ + my(@a) = unpack ("C*", $a) ; + my(@b) = unpack ("C*", $b) ; + + my $len = (@a > @b ? @b : @a) ; + my $i = 0 ; + + foreach $i ( 0 .. $len -1) { + return $a[$i] - $b[$i] if $a[$i] != $b[$i] ; + } + + return @a - @b ; +} + +{ + package Redirect ; + use Symbol ; + + sub new + { + my $class = shift ; + my $filename = shift ; + my $fh = gensym ; + open ($fh, ">$filename") || die "Cannot open $filename: $!" ; + my $real_stdout = select($fh) ; + return bless [$fh, $real_stdout ] ; + + } + sub DESTROY + { + my $self = shift ; + close $self->[0] ; + select($self->[1]) ; + } +} + +sub docat +{ + my $file = shift; + #local $/ = undef unless wantarray ; + open(CAT,$file) || die "Cannot open $file: $!"; + my @result = ; + close(CAT); + wantarray ? @result : join("", @result) ; +} + +sub docat_del +{ + my $file = shift; + #local $/ = undef unless wantarray ; + open(CAT,$file) || die "Cannot open $file: $!"; + my @result = ; + close(CAT); + unlink $file ; + wantarray ? @result : join("", @result) ; +} + + +my $db185mode = ($DB_File::db_version == 1 && ! $DB_File::db_185_compat) ; +my $null_keys_allowed = ($DB_File::db_ver < 2.004010 + || $DB_File::db_ver >= 3.1 ); + +my $Dfile = "dbbtree.tmp"; +unlink $Dfile; + +umask(0); + +# Check the interface to BTREEINFO + +my $dbh = new DB_File::BTREEINFO ; +ok(1, ! defined $dbh->{flags}) ; +ok(2, ! defined $dbh->{cachesize}) ; +ok(3, ! defined $dbh->{psize}) ; +ok(4, ! defined $dbh->{lorder}) ; +ok(5, ! defined $dbh->{minkeypage}) ; +ok(6, ! defined $dbh->{maxkeypage}) ; +ok(7, ! defined $dbh->{compare}) ; +ok(8, ! defined $dbh->{prefix}) ; + +$dbh->{flags} = 3000 ; +ok(9, $dbh->{flags} == 3000) ; + +$dbh->{cachesize} = 9000 ; +ok(10, $dbh->{cachesize} == 9000); + +$dbh->{psize} = 400 ; +ok(11, $dbh->{psize} == 400) ; + +$dbh->{lorder} = 65 ; +ok(12, $dbh->{lorder} == 65) ; + +$dbh->{minkeypage} = 123 ; +ok(13, $dbh->{minkeypage} == 123) ; + +$dbh->{maxkeypage} = 1234 ; +ok(14, $dbh->{maxkeypage} == 1234 ); + +$dbh->{compare} = 1234 ; +ok(15, $dbh->{compare} == 1234) ; + +$dbh->{prefix} = 1234 ; +ok(16, $dbh->{prefix} == 1234 ); + +# Check that an invalid entry is caught both for store & fetch +eval '$dbh->{fred} = 1234' ; +ok(17, $@ =~ /^DB_File::BTREEINFO::STORE - Unknown element 'fred' at/ ) ; +eval 'my $q = $dbh->{fred}' ; +ok(18, $@ =~ /^DB_File::BTREEINFO::FETCH - Unknown element 'fred' at/ ) ; + +# Now check the interface to BTREE + +my ($X, %h) ; +ok(19, $X = tie(%h, 'DB_File',$Dfile, O_RDWR|O_CREAT, 0640, $DB_BTREE )) ; + +my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime, + $blksize,$blocks) = stat($Dfile); +ok(20, ($mode & 0777) == ($^O eq 'os2' ? 0666 : 0640) || $^O eq 'amigaos' || $^O eq 'MSWin32'); + +my ($key, $value, $i); +while (($key,$value) = each(%h)) { + $i++; +} +ok(21, !$i ) ; + +$h{'goner1'} = 'snork'; + +$h{'abc'} = 'ABC'; +ok(22, $h{'abc'} eq 'ABC' ); +ok(23, ! defined $h{'jimmy'} ) ; +ok(24, ! exists $h{'jimmy'} ) ; +ok(25, defined $h{'abc'} ) ; + +$h{'def'} = 'DEF'; +$h{'jkl','mno'} = "JKL\034MNO"; +$h{'a',2,3,4,5} = join("\034",'A',2,3,4,5); +$h{'a'} = 'A'; + +#$h{'b'} = 'B'; +$X->STORE('b', 'B') ; + +$h{'c'} = 'C'; + +#$h{'d'} = 'D'; +$X->put('d', 'D') ; + +$h{'e'} = 'E'; +$h{'f'} = 'F'; +$h{'g'} = 'X'; +$h{'h'} = 'H'; +$h{'i'} = 'I'; + +$h{'goner2'} = 'snork'; +delete $h{'goner2'}; + + +# IMPORTANT - $X must be undefined before the untie otherwise the +# underlying DB close routine will not get called. +undef $X ; +untie(%h); + +# tie to the same file again +ok(26, $X = tie(%h,'DB_File',$Dfile, O_RDWR, 0640, $DB_BTREE)) ; + +# Modify an entry from the previous tie +$h{'g'} = 'G'; + +$h{'j'} = 'J'; +$h{'k'} = 'K'; +$h{'l'} = 'L'; +$h{'m'} = 'M'; +$h{'n'} = 'N'; +$h{'o'} = 'O'; +$h{'p'} = 'P'; +$h{'q'} = 'Q'; +$h{'r'} = 'R'; +$h{'s'} = 'S'; +$h{'t'} = 'T'; +$h{'u'} = 'U'; +$h{'v'} = 'V'; +$h{'w'} = 'W'; +$h{'x'} = 'X'; +$h{'y'} = 'Y'; +$h{'z'} = 'Z'; + +$h{'goner3'} = 'snork'; + +delete $h{'goner1'}; +$X->DELETE('goner3'); + +my @keys = keys(%h); +my @values = values(%h); + +ok(27, $#keys == 29 && $#values == 29) ; + +$i = 0 ; +while (($key,$value) = each(%h)) { + if ($key eq $keys[$i] && $value eq $values[$i] && $key eq lc($value)) { + $key =~ y/a-z/A-Z/; + $i++ if $key eq $value; + } +} + +ok(28, $i == 30) ; + +@keys = ('blurfl', keys(%h), 'dyick'); +ok(29, $#keys == 31) ; + +#Check that the keys can be retrieved in order +my @b = keys %h ; +my @c = sort lexical @b ; +ok(30, ArrayCompare(\@b, \@c)) ; + +$h{'foo'} = ''; +ok(31, $h{'foo'} eq '' ) ; + +# Berkeley DB from version 2.4.10 to 3.0 does not allow null keys. +# This feature was reenabled in version 3.1 of Berkeley DB. +my $result = 0 ; +if ($null_keys_allowed) { + $h{''} = 'bar'; + $result = ( $h{''} eq 'bar' ); +} +else + { $result = 1 } +ok(32, $result) ; + +# check cache overflow and numeric keys and contents +my $ok = 1; +for ($i = 1; $i < 200; $i++) { $h{$i + 0} = $i + 0; } +for ($i = 1; $i < 200; $i++) { $ok = 0 unless $h{$i} == $i; } +ok(33, $ok); + +($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime, + $blksize,$blocks) = stat($Dfile); +ok(34, $size > 0 ); + +@h{0..200} = 200..400; +my @foo = @h{0..200}; +ok(35, join(':',200..400) eq join(':',@foo) ); + +# Now check all the non-tie specific stuff + + +# Check R_NOOVERWRITE flag will make put fail when attempting to overwrite +# an existing record. + +my $status = $X->put( 'x', 'newvalue', R_NOOVERWRITE) ; +ok(36, $status == 1 ); + +# check that the value of the key 'x' has not been changed by the +# previous test +ok(37, $h{'x'} eq 'X' ); + +# standard put +$status = $X->put('key', 'value') ; +ok(38, $status == 0 ); + +#check that previous put can be retrieved +$value = 0 ; +$status = $X->get('key', $value) ; +ok(39, $status == 0 ); +ok(40, $value eq 'value' ); + +# Attempting to delete an existing key should work + +$status = $X->del('q') ; +ok(41, $status == 0 ); +if ($null_keys_allowed) { + $status = $X->del('') ; +} else { + $status = 0 ; +} +ok(42, $status == 0 ); + +# Make sure that the key deleted, cannot be retrieved +ok(43, ! defined $h{'q'}) ; +ok(44, ! defined $h{''}) ; + +undef $X ; +untie %h ; + +ok(45, $X = tie(%h, 'DB_File',$Dfile, O_RDWR, 0640, $DB_BTREE )); + +# Attempting to delete a non-existant key should fail + +$status = $X->del('joe') ; +ok(46, $status == 1 ); + +# Check the get interface + +# First a non-existing key +$status = $X->get('aaaa', $value) ; +ok(47, $status == 1 ); + +# Next an existing key +$status = $X->get('a', $value) ; +ok(48, $status == 0 ); +ok(49, $value eq 'A' ); + +# seq +# ### + +# use seq to find an approximate match +$key = 'ke' ; +$value = '' ; +$status = $X->seq($key, $value, R_CURSOR) ; +ok(50, $status == 0 ); +ok(51, $key eq 'key' ); +ok(52, $value eq 'value' ); + +# seq when the key does not match +$key = 'zzz' ; +$value = '' ; +$status = $X->seq($key, $value, R_CURSOR) ; +ok(53, $status == 1 ); + + +# use seq to set the cursor, then delete the record @ the cursor. + +$key = 'x' ; +$value = '' ; +$status = $X->seq($key, $value, R_CURSOR) ; +ok(54, $status == 0 ); +ok(55, $key eq 'x' ); +ok(56, $value eq 'X' ); +$status = $X->del(0, R_CURSOR) ; +ok(57, $status == 0 ); +$status = $X->get('x', $value) ; +ok(58, $status == 1 ); + +# ditto, but use put to replace the key/value pair. +$key = 'y' ; +$value = '' ; +$status = $X->seq($key, $value, R_CURSOR) ; +ok(59, $status == 0 ); +ok(60, $key eq 'y' ); +ok(61, $value eq 'Y' ); + +$key = "replace key" ; +$value = "replace value" ; +$status = $X->put($key, $value, R_CURSOR) ; +ok(62, $status == 0 ); +ok(63, $key eq 'replace key' ); +ok(64, $value eq 'replace value' ); +$status = $X->get('y', $value) ; +ok(65, 1) ; # hard-wire to always pass. the previous test ($status == 1) + # only worked because of a bug in 1.85/6 + +# use seq to walk forwards through a file + +$status = $X->seq($key, $value, R_FIRST) ; +ok(66, $status == 0 ); +my $previous = $key ; + +$ok = 1 ; +while (($status = $X->seq($key, $value, R_NEXT)) == 0) +{ + ($ok = 0), last if ($previous cmp $key) == 1 ; +} + +ok(67, $status == 1 ); +ok(68, $ok == 1 ); + +# use seq to walk backwards through a file +$status = $X->seq($key, $value, R_LAST) ; +ok(69, $status == 0 ); +$previous = $key ; + +$ok = 1 ; +while (($status = $X->seq($key, $value, R_PREV)) == 0) +{ + ($ok = 0), last if ($previous cmp $key) == -1 ; + #print "key = [$key] value = [$value]\n" ; +} + +ok(70, $status == 1 ); +ok(71, $ok == 1 ); + + +# check seq FIRST/LAST + +# sync +# #### + +$status = $X->sync ; +ok(72, $status == 0 ); + + +# fd +# ## + +$status = $X->fd ; +ok(73, $status != 0 ); + + +undef $X ; +untie %h ; + +unlink $Dfile; + +# Now try an in memory file +my $Y; +ok(74, $Y = tie(%h, 'DB_File',undef, O_RDWR|O_CREAT, 0640, $DB_BTREE )); + +# fd with an in memory file should return failure +$status = $Y->fd ; +ok(75, $status == -1 ); + + +undef $Y ; +untie %h ; + +# Duplicate keys +my $bt = new DB_File::BTREEINFO ; +$bt->{flags} = R_DUP ; +my ($YY, %hh); +ok(76, $YY = tie(%hh, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $bt )) ; + +$hh{'Wall'} = 'Larry' ; +$hh{'Wall'} = 'Stone' ; # Note the duplicate key +$hh{'Wall'} = 'Brick' ; # Note the duplicate key +$hh{'Wall'} = 'Brick' ; # Note the duplicate key and value +$hh{'Smith'} = 'John' ; +$hh{'mouse'} = 'mickey' ; + +# first work in scalar context +ok(77, scalar $YY->get_dup('Unknown') == 0 ); +ok(78, scalar $YY->get_dup('Smith') == 1 ); +ok(79, scalar $YY->get_dup('Wall') == 4 ); + +# now in list context +my @unknown = $YY->get_dup('Unknown') ; +ok(80, "@unknown" eq "" ); + +my @smith = $YY->get_dup('Smith') ; +ok(81, "@smith" eq "John" ); + +{ +my @wall = $YY->get_dup('Wall') ; +my %wall ; +@wall{@wall} = @wall ; +ok(82, (@wall == 4 && $wall{'Larry'} && $wall{'Stone'} && $wall{'Brick'}) ); +} + +# hash +my %unknown = $YY->get_dup('Unknown', 1) ; +ok(83, keys %unknown == 0 ); + +my %smith = $YY->get_dup('Smith', 1) ; +ok(84, keys %smith == 1 && $smith{'John'}) ; + +my %wall = $YY->get_dup('Wall', 1) ; +ok(85, keys %wall == 3 && $wall{'Larry'} == 1 && $wall{'Stone'} == 1 + && $wall{'Brick'} == 2); + +undef $YY ; +untie %hh ; +unlink $Dfile; + + +# test multiple callbacks +my $Dfile1 = "btree1" ; +my $Dfile2 = "btree2" ; +my $Dfile3 = "btree3" ; + +my $dbh1 = new DB_File::BTREEINFO ; +$dbh1->{compare} = sub { + no warnings 'numeric' ; + $_[0] <=> $_[1] } ; + +my $dbh2 = new DB_File::BTREEINFO ; +$dbh2->{compare} = sub { $_[0] cmp $_[1] } ; + +my $dbh3 = new DB_File::BTREEINFO ; +$dbh3->{compare} = sub { length $_[0] <=> length $_[1] } ; + + +my (%g, %k); +tie(%h, 'DB_File',$Dfile1, O_RDWR|O_CREAT, 0640, $dbh1 ) ; +tie(%g, 'DB_File',$Dfile2, O_RDWR|O_CREAT, 0640, $dbh2 ) ; +tie(%k, 'DB_File',$Dfile3, O_RDWR|O_CREAT, 0640, $dbh3 ) ; + +my @Keys = qw( 0123 12 -1234 9 987654321 def ) ; +my (@srt_1, @srt_2, @srt_3); +{ + no warnings 'numeric' ; + @srt_1 = sort { $a <=> $b } @Keys ; +} +@srt_2 = sort { $a cmp $b } @Keys ; +@srt_3 = sort { length $a <=> length $b } @Keys ; + +foreach (@Keys) { + $h{$_} = 1 ; + $g{$_} = 1 ; + $k{$_} = 1 ; +} + +sub ArrayCompare +{ + my($a, $b) = @_ ; + + return 0 if @$a != @$b ; + + foreach (1 .. length @$a) + { + return 0 unless $$a[$_] eq $$b[$_] ; + } + + 1 ; +} + +ok(86, ArrayCompare (\@srt_1, [keys %h]) ); +ok(87, ArrayCompare (\@srt_2, [keys %g]) ); +ok(88, ArrayCompare (\@srt_3, [keys %k]) ); + +untie %h ; +untie %g ; +untie %k ; +unlink $Dfile1, $Dfile2, $Dfile3 ; + +# clear +# ##### + +ok(89, tie(%h, 'DB_File', $Dfile1, O_RDWR|O_CREAT, 0640, $DB_BTREE ) ); +foreach (1 .. 10) + { $h{$_} = $_ * 100 } + +# check that there are 10 elements in the hash +$i = 0 ; +while (($key,$value) = each(%h)) { + $i++; +} +ok(90, $i == 10); + +# now clear the hash +%h = () ; + +# check it is empty +$i = 0 ; +while (($key,$value) = each(%h)) { + $i++; +} +ok(91, $i == 0); + +untie %h ; +unlink $Dfile1 ; + +{ + # check that attempting to tie an array to a DB_BTREE will fail + + my $filename = "xyz" ; + my @x ; + eval { tie @x, 'DB_File', $filename, O_RDWR|O_CREAT, 0640, $DB_BTREE ; } ; + ok(92, $@ =~ /^DB_File can only tie an associative array to a DB_BTREE database/) ; + unlink $filename ; +} + +{ + # sub-class test + + package Another ; + + use warnings ; + use strict ; + + open(FILE, ">SubDB.pm") or die "Cannot open SubDB.pm: $!\n" ; + print FILE <<'EOM' ; + + package SubDB ; + + use warnings ; + use strict ; + use vars qw( @ISA @EXPORT) ; + + require Exporter ; + use DB_File; + @ISA=qw(DB_File); + @EXPORT = @DB_File::EXPORT ; + + sub STORE { + my $self = shift ; + my $key = shift ; + my $value = shift ; + $self->SUPER::STORE($key, $value * 2) ; + } + + sub FETCH { + my $self = shift ; + my $key = shift ; + $self->SUPER::FETCH($key) - 1 ; + } + + sub put { + my $self = shift ; + my $key = shift ; + my $value = shift ; + $self->SUPER::put($key, $value * 3) ; + } + + sub get { + my $self = shift ; + $self->SUPER::get($_[0], $_[1]) ; + $_[1] -= 2 ; + } + + sub A_new_method + { + my $self = shift ; + my $key = shift ; + my $value = $self->FETCH($key) ; + return "[[$value]]" ; + } + + 1 ; +EOM + + close FILE ; + + BEGIN { push @INC, '.'; } + eval 'use SubDB ; '; + main::ok(93, $@ eq "") ; + my %h ; + my $X ; + eval ' + $X = tie(%h, "SubDB","dbbtree.tmp", O_RDWR|O_CREAT, 0640, $DB_BTREE ); + ' ; + + main::ok(94, $@ eq "") ; + + my $ret = eval '$h{"fred"} = 3 ; return $h{"fred"} ' ; + main::ok(95, $@ eq "") ; + main::ok(96, $ret == 5) ; + + my $value = 0; + $ret = eval '$X->put("joe", 4) ; $X->get("joe", $value) ; return $value' ; + main::ok(97, $@ eq "") ; + main::ok(98, $ret == 10) ; + + $ret = eval ' R_NEXT eq main::R_NEXT ' ; + main::ok(99, $@ eq "" ) ; + main::ok(100, $ret == 1) ; + + $ret = eval '$X->A_new_method("joe") ' ; + main::ok(101, $@ eq "") ; + main::ok(102, $ret eq "[[11]]") ; + + undef $X; + untie(%h); + unlink "SubDB.pm", "dbbtree.tmp" ; + +} + +{ + # DBM Filter tests + use warnings ; + use strict ; + my (%h, $db) ; + my ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + unlink $Dfile; + + sub checkOutput + { + my($fk, $sk, $fv, $sv) = @_ ; + return + $fetch_key eq $fk && $store_key eq $sk && + $fetch_value eq $fv && $store_value eq $sv && + $_ eq 'original' ; + } + + ok(103, $db = tie(%h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_BTREE ) ); + + $db->filter_fetch_key (sub { $fetch_key = $_ }) ; + $db->filter_store_key (sub { $store_key = $_ }) ; + $db->filter_fetch_value (sub { $fetch_value = $_}) ; + $db->filter_store_value (sub { $store_value = $_ }) ; + + $_ = "original" ; + + $h{"fred"} = "joe" ; + # fk sk fv sv + ok(104, checkOutput( "", "fred", "", "joe")) ; + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + ok(105, $h{"fred"} eq "joe"); + # fk sk fv sv + ok(106, checkOutput( "", "fred", "joe", "")) ; + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + ok(107, $db->FIRSTKEY() eq "fred") ; + # fk sk fv sv + ok(108, checkOutput( "fred", "", "", "")) ; + + # replace the filters, but remember the previous set + my ($old_fk) = $db->filter_fetch_key + (sub { $_ = uc $_ ; $fetch_key = $_ }) ; + my ($old_sk) = $db->filter_store_key + (sub { $_ = lc $_ ; $store_key = $_ }) ; + my ($old_fv) = $db->filter_fetch_value + (sub { $_ = "[$_]"; $fetch_value = $_ }) ; + my ($old_sv) = $db->filter_store_value + (sub { s/o/x/g; $store_value = $_ }) ; + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + $h{"Fred"} = "Joe" ; + # fk sk fv sv + ok(109, checkOutput( "", "fred", "", "Jxe")) ; + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + ok(110, $h{"Fred"} eq "[Jxe]"); + # fk sk fv sv + ok(111, checkOutput( "", "fred", "[Jxe]", "")) ; + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + ok(112, $db->FIRSTKEY() eq "FRED") ; + # fk sk fv sv + ok(113, checkOutput( "FRED", "", "", "")) ; + + # put the original filters back + $db->filter_fetch_key ($old_fk); + $db->filter_store_key ($old_sk); + $db->filter_fetch_value ($old_fv); + $db->filter_store_value ($old_sv); + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + $h{"fred"} = "joe" ; + ok(114, checkOutput( "", "fred", "", "joe")) ; + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + ok(115, $h{"fred"} eq "joe"); + ok(116, checkOutput( "", "fred", "joe", "")) ; + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + ok(117, $db->FIRSTKEY() eq "fred") ; + ok(118, checkOutput( "fred", "", "", "")) ; + + # delete the filters + $db->filter_fetch_key (undef); + $db->filter_store_key (undef); + $db->filter_fetch_value (undef); + $db->filter_store_value (undef); + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + $h{"fred"} = "joe" ; + ok(119, checkOutput( "", "", "", "")) ; + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + ok(120, $h{"fred"} eq "joe"); + ok(121, checkOutput( "", "", "", "")) ; + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + ok(122, $db->FIRSTKEY() eq "fred") ; + ok(123, checkOutput( "", "", "", "")) ; + + undef $db ; + untie %h; + unlink $Dfile; +} + +{ + # DBM Filter with a closure + + use warnings ; + use strict ; + my (%h, $db) ; + + unlink $Dfile; + ok(124, $db = tie(%h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_BTREE ) ); + + my %result = () ; + + sub Closure + { + my ($name) = @_ ; + my $count = 0 ; + my @kept = () ; + + return sub { ++$count ; + push @kept, $_ ; + $result{$name} = "$name - $count: [@kept]" ; + } + } + + $db->filter_store_key(Closure("store key")) ; + $db->filter_store_value(Closure("store value")) ; + $db->filter_fetch_key(Closure("fetch key")) ; + $db->filter_fetch_value(Closure("fetch value")) ; + + $_ = "original" ; + + $h{"fred"} = "joe" ; + ok(125, $result{"store key"} eq "store key - 1: [fred]"); + ok(126, $result{"store value"} eq "store value - 1: [joe]"); + ok(127, ! defined $result{"fetch key"} ); + ok(128, ! defined $result{"fetch value"} ); + ok(129, $_ eq "original") ; + + ok(130, $db->FIRSTKEY() eq "fred") ; + ok(131, $result{"store key"} eq "store key - 1: [fred]"); + ok(132, $result{"store value"} eq "store value - 1: [joe]"); + ok(133, $result{"fetch key"} eq "fetch key - 1: [fred]"); + ok(134, ! defined $result{"fetch value"} ); + ok(135, $_ eq "original") ; + + $h{"jim"} = "john" ; + ok(136, $result{"store key"} eq "store key - 2: [fred jim]"); + ok(137, $result{"store value"} eq "store value - 2: [joe john]"); + ok(138, $result{"fetch key"} eq "fetch key - 1: [fred]"); + ok(139, ! defined $result{"fetch value"} ); + ok(140, $_ eq "original") ; + + ok(141, $h{"fred"} eq "joe"); + ok(142, $result{"store key"} eq "store key - 3: [fred jim fred]"); + ok(143, $result{"store value"} eq "store value - 2: [joe john]"); + ok(144, $result{"fetch key"} eq "fetch key - 1: [fred]"); + ok(145, $result{"fetch value"} eq "fetch value - 1: [joe]"); + ok(146, $_ eq "original") ; + + undef $db ; + untie %h; + unlink $Dfile; +} + +{ + # DBM Filter recursion detection + use warnings ; + use strict ; + my (%h, $db) ; + unlink $Dfile; + + ok(147, $db = tie(%h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_BTREE ) ); + + $db->filter_store_key (sub { $_ = $h{$_} }) ; + + eval '$h{1} = 1234' ; + ok(148, $@ =~ /^recursion detected in filter_store_key at/ ); + + undef $db ; + untie %h; + unlink $Dfile; +} + + +{ + # Examples from the POD + + + my $file = "xyzt" ; + { + my $redirect = new Redirect $file ; + + # BTREE example 1 + ### + + use warnings FATAL => qw(all) ; + use strict ; + use DB_File ; + + my %h ; + + sub Compare + { + my ($key1, $key2) = @_ ; + "\L$key1" cmp "\L$key2" ; + } + + # specify the Perl sub that will do the comparison + $DB_BTREE->{'compare'} = \&Compare ; + + unlink "tree" ; + tie %h, "DB_File", "tree", O_RDWR|O_CREAT, 0640, $DB_BTREE + or die "Cannot open file 'tree': $!\n" ; + + # Add a key/value pair to the file + $h{'Wall'} = 'Larry' ; + $h{'Smith'} = 'John' ; + $h{'mouse'} = 'mickey' ; + $h{'duck'} = 'donald' ; + + # Delete + delete $h{"duck"} ; + + # Cycle through the keys printing them in order. + # Note it is not necessary to sort the keys as + # the btree will have kept them in order automatically. + foreach (keys %h) + { print "$_\n" } + + untie %h ; + + unlink "tree" ; + } + + delete $DB_BTREE->{'compare'} ; + + ok(149, docat_del($file) eq <<'EOM') ; +mouse +Smith +Wall +EOM + + { + my $redirect = new Redirect $file ; + + # BTREE example 2 + ### + + use warnings FATAL => qw(all) ; + use strict ; + use DB_File ; + + use vars qw($filename %h ) ; + + $filename = "tree" ; + unlink $filename ; + + # Enable duplicate records + $DB_BTREE->{'flags'} = R_DUP ; + + tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0640, $DB_BTREE + or die "Cannot open $filename: $!\n"; + + # Add some key/value pairs to the file + $h{'Wall'} = 'Larry' ; + $h{'Wall'} = 'Brick' ; # Note the duplicate key + $h{'Wall'} = 'Brick' ; # Note the duplicate key and value + $h{'Smith'} = 'John' ; + $h{'mouse'} = 'mickey' ; + + # iterate through the associative array + # and print each key/value pair. + foreach (keys %h) + { print "$_ -> $h{$_}\n" } + + untie %h ; + + unlink $filename ; + } + + ok(150, docat_del($file) eq ($db185mode ? <<'EOM' : <<'EOM') ) ; +Smith -> John +Wall -> Brick +Wall -> Brick +Wall -> Brick +mouse -> mickey +EOM +Smith -> John +Wall -> Larry +Wall -> Larry +Wall -> Larry +mouse -> mickey +EOM + + { + my $redirect = new Redirect $file ; + + # BTREE example 3 + ### + + use warnings FATAL => qw(all) ; + use strict ; + use DB_File ; + + use vars qw($filename $x %h $status $key $value) ; + + $filename = "tree" ; + unlink $filename ; + + # Enable duplicate records + $DB_BTREE->{'flags'} = R_DUP ; + + $x = tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0640, $DB_BTREE + or die "Cannot open $filename: $!\n"; + + # Add some key/value pairs to the file + $h{'Wall'} = 'Larry' ; + $h{'Wall'} = 'Brick' ; # Note the duplicate key + $h{'Wall'} = 'Brick' ; # Note the duplicate key and value + $h{'Smith'} = 'John' ; + $h{'mouse'} = 'mickey' ; + + # iterate through the btree using seq + # and print each key/value pair. + $key = $value = 0 ; + for ($status = $x->seq($key, $value, R_FIRST) ; + $status == 0 ; + $status = $x->seq($key, $value, R_NEXT) ) + { print "$key -> $value\n" } + + + undef $x ; + untie %h ; + } + + ok(151, docat_del($file) eq ($db185mode == 1 ? <<'EOM' : <<'EOM') ) ; +Smith -> John +Wall -> Brick +Wall -> Brick +Wall -> Larry +mouse -> mickey +EOM +Smith -> John +Wall -> Larry +Wall -> Brick +Wall -> Brick +mouse -> mickey +EOM + + + { + my $redirect = new Redirect $file ; + + # BTREE example 4 + ### + + use warnings FATAL => qw(all) ; + use strict ; + use DB_File ; + + use vars qw($filename $x %h ) ; + + $filename = "tree" ; + + # Enable duplicate records + $DB_BTREE->{'flags'} = R_DUP ; + + $x = tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0640, $DB_BTREE + or die "Cannot open $filename: $!\n"; + + my $cnt = $x->get_dup("Wall") ; + print "Wall occurred $cnt times\n" ; + + my %hash = $x->get_dup("Wall", 1) ; + print "Larry is there\n" if $hash{'Larry'} ; + print "There are $hash{'Brick'} Brick Walls\n" ; + + my @list = sort $x->get_dup("Wall") ; + print "Wall => [@list]\n" ; + + @list = $x->get_dup("Smith") ; + print "Smith => [@list]\n" ; + + @list = $x->get_dup("Dog") ; + print "Dog => [@list]\n" ; + + undef $x ; + untie %h ; + } + + ok(152, docat_del($file) eq <<'EOM') ; +Wall occurred 3 times +Larry is there +There are 2 Brick Walls +Wall => [Brick Brick Larry] +Smith => [John] +Dog => [] +EOM + + { + my $redirect = new Redirect $file ; + + # BTREE example 5 + ### + + use warnings FATAL => qw(all) ; + use strict ; + use DB_File ; + + use vars qw($filename $x %h $found) ; + + my $filename = "tree" ; + + # Enable duplicate records + $DB_BTREE->{'flags'} = R_DUP ; + + $x = tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0640, $DB_BTREE + or die "Cannot open $filename: $!\n"; + + $found = ( $x->find_dup("Wall", "Larry") == 0 ? "" : "not") ; + print "Larry Wall is $found there\n" ; + + $found = ( $x->find_dup("Wall", "Harry") == 0 ? "" : "not") ; + print "Harry Wall is $found there\n" ; + + undef $x ; + untie %h ; + } + + ok(153, docat_del($file) eq <<'EOM') ; +Larry Wall is there +Harry Wall is not there +EOM + + { + my $redirect = new Redirect $file ; + + # BTREE example 6 + ### + + use warnings FATAL => qw(all) ; + use strict ; + use DB_File ; + + use vars qw($filename $x %h $found) ; + + my $filename = "tree" ; + + # Enable duplicate records + $DB_BTREE->{'flags'} = R_DUP ; + + $x = tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0640, $DB_BTREE + or die "Cannot open $filename: $!\n"; + + $x->del_dup("Wall", "Larry") ; + + $found = ( $x->find_dup("Wall", "Larry") == 0 ? "" : "not") ; + print "Larry Wall is $found there\n" ; + + undef $x ; + untie %h ; + + unlink $filename ; + } + + ok(154, docat_del($file) eq <<'EOM') ; +Larry Wall is not there +EOM + + { + my $redirect = new Redirect $file ; + + # BTREE example 7 + ### + + use warnings FATAL => qw(all) ; + use strict ; + use DB_File ; + use Fcntl ; + + use vars qw($filename $x %h $st $key $value) ; + + sub match + { + my $key = shift ; + my $value = 0; + my $orig_key = $key ; + $x->seq($key, $value, R_CURSOR) ; + print "$orig_key\t-> $key\t-> $value\n" ; + } + + $filename = "tree" ; + unlink $filename ; + + $x = tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0640, $DB_BTREE + or die "Cannot open $filename: $!\n"; + + # Add some key/value pairs to the file + $h{'mouse'} = 'mickey' ; + $h{'Wall'} = 'Larry' ; + $h{'Walls'} = 'Brick' ; + $h{'Smith'} = 'John' ; + + + $key = $value = 0 ; + print "IN ORDER\n" ; + for ($st = $x->seq($key, $value, R_FIRST) ; + $st == 0 ; + $st = $x->seq($key, $value, R_NEXT) ) + + { print "$key -> $value\n" } + + print "\nPARTIAL MATCH\n" ; + + match "Wa" ; + match "A" ; + match "a" ; + + undef $x ; + untie %h ; + + unlink $filename ; + + } + + ok(155, docat_del($file) eq <<'EOM') ; +IN ORDER +Smith -> John +Wall -> Larry +Walls -> Brick +mouse -> mickey + +PARTIAL MATCH +Wa -> Wall -> Larry +A -> Smith -> John +a -> mouse -> mickey +EOM + +} + +#{ +# # R_SETCURSOR +# use strict ; +# my (%h, $db) ; +# unlink $Dfile; +# +# ok(156, $db = tie(%h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_BTREE ) ); +# +# $h{abc} = 33 ; +# my $k = "newest" ; +# my $v = 44 ; +# my $status = $db->put($k, $v, R_SETCURSOR) ; +# print "status = [$status]\n" ; +# ok(157, $status == 0) ; +# $status = $db->del($k, R_CURSOR) ; +# print "status = [$status]\n" ; +# ok(158, $status == 0) ; +# $k = "newest" ; +# ok(159, $db->get($k, $v, R_CURSOR)) ; +# +# ok(160, keys %h == 1) ; +# +# undef $db ; +# untie %h; +# unlink $Dfile; +#} + +{ + # Bug ID 20001013.009 + # + # test that $hash{KEY} = undef doesn't produce the warning + # Use of uninitialized value in null operation + use warnings ; + use strict ; + use DB_File ; + + unlink $Dfile; + my %h ; + my $a = ""; + local $SIG{__WARN__} = sub {$a = $_[0]} ; + + tie %h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0664, $DB_BTREE + or die "Can't open file: $!\n" ; + $h{ABC} = undef; + ok(156, $a eq "") ; + untie %h ; + unlink $Dfile; +} + +{ + # test that %hash = () doesn't produce the warning + # Argument "" isn't numeric in entersub + use warnings ; + use strict ; + use DB_File ; + + unlink $Dfile; + my %h ; + my $a = ""; + local $SIG{__WARN__} = sub {$a = $_[0]} ; + + tie %h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0664, $DB_BTREE + or die "Can't open file: $!\n" ; + %h = (); ; + ok(157, $a eq "") ; + untie %h ; + unlink $Dfile; +} + +exit ; diff --git a/db/perl.DB_File/t/db-hash.t b/db/perl.DB_File/t/db-hash.t new file mode 100644 index 000000000..a6efd9810 --- /dev/null +++ b/db/perl.DB_File/t/db-hash.t @@ -0,0 +1,753 @@ +#!./perl + +use warnings ; +use strict ; + +BEGIN { + unless(grep /blib/, @INC) { + chdir 't' if -d 't'; + @INC = '../lib' if -d '../lib'; + } +} + +use Config; + +BEGIN { + if(-d "lib" && -f "TEST") { + if ($Config{'extensions'} !~ /\bDB_File\b/ ) { + print "1..111\n"; + exit 0; + } + } +} + +use DB_File; +use Fcntl; + +print "1..111\n"; + +sub ok +{ + my $no = shift ; + my $result = shift ; + + print "not " unless $result ; + print "ok $no\n" ; +} + +{ + package Redirect ; + use Symbol ; + + sub new + { + my $class = shift ; + my $filename = shift ; + my $fh = gensym ; + open ($fh, ">$filename") || die "Cannot open $filename: $!" ; + my $real_stdout = select($fh) ; + return bless [$fh, $real_stdout ] ; + + } + sub DESTROY + { + my $self = shift ; + close $self->[0] ; + select($self->[1]) ; + } +} + +sub docat_del +{ + my $file = shift; + local $/ = undef; + open(CAT,$file) || die "Cannot open $file: $!"; + my $result = ; + close(CAT); + unlink $file ; + return $result; +} + +my $Dfile = "dbhash.tmp"; +my $null_keys_allowed = ($DB_File::db_ver < 2.004010 + || $DB_File::db_ver >= 3.1 ); + +unlink $Dfile; + +umask(0); + +# Check the interface to HASHINFO + +my $dbh = new DB_File::HASHINFO ; + +ok(1, ! defined $dbh->{bsize}) ; +ok(2, ! defined $dbh->{ffactor}) ; +ok(3, ! defined $dbh->{nelem}) ; +ok(4, ! defined $dbh->{cachesize}) ; +ok(5, ! defined $dbh->{hash}) ; +ok(6, ! defined $dbh->{lorder}) ; + +$dbh->{bsize} = 3000 ; +ok(7, $dbh->{bsize} == 3000 ); + +$dbh->{ffactor} = 9000 ; +ok(8, $dbh->{ffactor} == 9000 ); + +$dbh->{nelem} = 400 ; +ok(9, $dbh->{nelem} == 400 ); + +$dbh->{cachesize} = 65 ; +ok(10, $dbh->{cachesize} == 65 ); + +$dbh->{hash} = "abc" ; +ok(11, $dbh->{hash} eq "abc" ); + +$dbh->{lorder} = 1234 ; +ok(12, $dbh->{lorder} == 1234 ); + +# Check that an invalid entry is caught both for store & fetch +eval '$dbh->{fred} = 1234' ; +ok(13, $@ =~ /^DB_File::HASHINFO::STORE - Unknown element 'fred' at/ ); +eval 'my $q = $dbh->{fred}' ; +ok(14, $@ =~ /^DB_File::HASHINFO::FETCH - Unknown element 'fred' at/ ); + + +# Now check the interface to HASH +my ($X, %h); +ok(15, $X = tie(%h, 'DB_File',$Dfile, O_RDWR|O_CREAT, 0640, $DB_HASH ) ); + +my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime, + $blksize,$blocks) = stat($Dfile); +ok(16, ($mode & 0777) == ($^O eq 'os2' ? 0666 : 0640) || $^O eq 'amigaos' || $^O eq 'MSWin32'); + +my ($key, $value, $i); +while (($key,$value) = each(%h)) { + $i++; +} +ok(17, !$i ); + +$h{'goner1'} = 'snork'; + +$h{'abc'} = 'ABC'; +ok(18, $h{'abc'} eq 'ABC' ); +ok(19, !defined $h{'jimmy'} ); +ok(20, !exists $h{'jimmy'} ); +ok(21, exists $h{'abc'} ); + +$h{'def'} = 'DEF'; +$h{'jkl','mno'} = "JKL\034MNO"; +$h{'a',2,3,4,5} = join("\034",'A',2,3,4,5); +$h{'a'} = 'A'; + +#$h{'b'} = 'B'; +$X->STORE('b', 'B') ; + +$h{'c'} = 'C'; + +#$h{'d'} = 'D'; +$X->put('d', 'D') ; + +$h{'e'} = 'E'; +$h{'f'} = 'F'; +$h{'g'} = 'X'; +$h{'h'} = 'H'; +$h{'i'} = 'I'; + +$h{'goner2'} = 'snork'; +delete $h{'goner2'}; + + +# IMPORTANT - $X must be undefined before the untie otherwise the +# underlying DB close routine will not get called. +undef $X ; +untie(%h); + + +# tie to the same file again, do not supply a type - should default to HASH +ok(22, $X = tie(%h,'DB_File',$Dfile, O_RDWR, 0640) ); + +# Modify an entry from the previous tie +$h{'g'} = 'G'; + +$h{'j'} = 'J'; +$h{'k'} = 'K'; +$h{'l'} = 'L'; +$h{'m'} = 'M'; +$h{'n'} = 'N'; +$h{'o'} = 'O'; +$h{'p'} = 'P'; +$h{'q'} = 'Q'; +$h{'r'} = 'R'; +$h{'s'} = 'S'; +$h{'t'} = 'T'; +$h{'u'} = 'U'; +$h{'v'} = 'V'; +$h{'w'} = 'W'; +$h{'x'} = 'X'; +$h{'y'} = 'Y'; +$h{'z'} = 'Z'; + +$h{'goner3'} = 'snork'; + +delete $h{'goner1'}; +$X->DELETE('goner3'); + +my @keys = keys(%h); +my @values = values(%h); + +ok(23, $#keys == 29 && $#values == 29) ; + +$i = 0 ; +while (($key,$value) = each(%h)) { + if ($key eq $keys[$i] && $value eq $values[$i] && $key eq lc($value)) { + $key =~ y/a-z/A-Z/; + $i++ if $key eq $value; + } +} + +ok(24, $i == 30) ; + +@keys = ('blurfl', keys(%h), 'dyick'); +ok(25, $#keys == 31) ; + +$h{'foo'} = ''; +ok(26, $h{'foo'} eq '' ); + +# Berkeley DB from version 2.4.10 to 3.0 does not allow null keys. +# This feature was reenabled in version 3.1 of Berkeley DB. +my $result = 0 ; +if ($null_keys_allowed) { + $h{''} = 'bar'; + $result = ( $h{''} eq 'bar' ); +} +else + { $result = 1 } +ok(27, $result) ; + +# check cache overflow and numeric keys and contents +my $ok = 1; +for ($i = 1; $i < 200; $i++) { $h{$i + 0} = $i + 0; } +for ($i = 1; $i < 200; $i++) { $ok = 0 unless $h{$i} == $i; } +ok(28, $ok ); + +($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime, + $blksize,$blocks) = stat($Dfile); +ok(29, $size > 0 ); + +@h{0..200} = 200..400; +my @foo = @h{0..200}; +ok(30, join(':',200..400) eq join(':',@foo) ); + + +# Now check all the non-tie specific stuff + +# Check NOOVERWRITE will make put fail when attempting to overwrite +# an existing record. + +my $status = $X->put( 'x', 'newvalue', R_NOOVERWRITE) ; +ok(31, $status == 1 ); + +# check that the value of the key 'x' has not been changed by the +# previous test +ok(32, $h{'x'} eq 'X' ); + +# standard put +$status = $X->put('key', 'value') ; +ok(33, $status == 0 ); + +#check that previous put can be retrieved +$value = 0 ; +$status = $X->get('key', $value) ; +ok(34, $status == 0 ); +ok(35, $value eq 'value' ); + +# Attempting to delete an existing key should work + +$status = $X->del('q') ; +ok(36, $status == 0 ); + +# Make sure that the key deleted, cannot be retrieved +{ + no warnings 'uninitialized' ; + ok(37, $h{'q'} eq undef ); +} + +# Attempting to delete a non-existant key should fail + +$status = $X->del('joe') ; +ok(38, $status == 1 ); + +# Check the get interface + +# First a non-existing key +$status = $X->get('aaaa', $value) ; +ok(39, $status == 1 ); + +# Next an existing key +$status = $X->get('a', $value) ; +ok(40, $status == 0 ); +ok(41, $value eq 'A' ); + +# seq +# ### + +# ditto, but use put to replace the key/value pair. + +# use seq to walk backwards through a file - check that this reversed is + +# check seq FIRST/LAST + +# sync +# #### + +$status = $X->sync ; +ok(42, $status == 0 ); + + +# fd +# ## + +$status = $X->fd ; +ok(43, $status != 0 ); + +undef $X ; +untie %h ; + +unlink $Dfile; + +# clear +# ##### + +ok(44, tie(%h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_HASH ) ); +foreach (1 .. 10) + { $h{$_} = $_ * 100 } + +# check that there are 10 elements in the hash +$i = 0 ; +while (($key,$value) = each(%h)) { + $i++; +} +ok(45, $i == 10); + +# now clear the hash +%h = () ; + +# check it is empty +$i = 0 ; +while (($key,$value) = each(%h)) { + $i++; +} +ok(46, $i == 0); + +untie %h ; +unlink $Dfile ; + + +# Now try an in memory file +ok(47, $X = tie(%h, 'DB_File',undef, O_RDWR|O_CREAT, 0640, $DB_HASH ) ); + +# fd with an in memory file should return fail +$status = $X->fd ; +ok(48, $status == -1 ); + +undef $X ; +untie %h ; + +{ + # check ability to override the default hashing + my %x ; + my $filename = "xyz" ; + my $hi = new DB_File::HASHINFO ; + $::count = 0 ; + $hi->{hash} = sub { ++$::count ; length $_[0] } ; + ok(49, tie %x, 'DB_File', $filename, O_RDWR|O_CREAT, 0640, $hi ) ; + $h{"abc"} = 123 ; + ok(50, $h{"abc"} == 123) ; + untie %x ; + unlink $filename ; + ok(51, $::count >0) ; +} + +{ + # check that attempting to tie an array to a DB_HASH will fail + + my $filename = "xyz" ; + my @x ; + eval { tie @x, 'DB_File', $filename, O_RDWR|O_CREAT, 0640, $DB_HASH ; } ; + ok(52, $@ =~ /^DB_File can only tie an associative array to a DB_HASH database/) ; + unlink $filename ; +} + +{ + # sub-class test + + package Another ; + + use warnings ; + use strict ; + + open(FILE, ">SubDB.pm") or die "Cannot open SubDB.pm: $!\n" ; + print FILE <<'EOM' ; + + package SubDB ; + + use warnings ; + use strict ; + use vars qw( @ISA @EXPORT) ; + + require Exporter ; + use DB_File; + @ISA=qw(DB_File); + @EXPORT = @DB_File::EXPORT ; + + sub STORE { + my $self = shift ; + my $key = shift ; + my $value = shift ; + $self->SUPER::STORE($key, $value * 2) ; + } + + sub FETCH { + my $self = shift ; + my $key = shift ; + $self->SUPER::FETCH($key) - 1 ; + } + + sub put { + my $self = shift ; + my $key = shift ; + my $value = shift ; + $self->SUPER::put($key, $value * 3) ; + } + + sub get { + my $self = shift ; + $self->SUPER::get($_[0], $_[1]) ; + $_[1] -= 2 ; + } + + sub A_new_method + { + my $self = shift ; + my $key = shift ; + my $value = $self->FETCH($key) ; + return "[[$value]]" ; + } + + 1 ; +EOM + + close FILE ; + + BEGIN { push @INC, '.'; } + eval 'use SubDB ; '; + main::ok(53, $@ eq "") ; + my %h ; + my $X ; + eval ' + $X = tie(%h, "SubDB","dbhash.tmp", O_RDWR|O_CREAT, 0640, $DB_HASH ); + ' ; + + main::ok(54, $@ eq "") ; + + my $ret = eval '$h{"fred"} = 3 ; return $h{"fred"} ' ; + main::ok(55, $@ eq "") ; + main::ok(56, $ret == 5) ; + + my $value = 0; + $ret = eval '$X->put("joe", 4) ; $X->get("joe", $value) ; return $value' ; + main::ok(57, $@ eq "") ; + main::ok(58, $ret == 10) ; + + $ret = eval ' R_NEXT eq main::R_NEXT ' ; + main::ok(59, $@ eq "" ) ; + main::ok(60, $ret == 1) ; + + $ret = eval '$X->A_new_method("joe") ' ; + main::ok(61, $@ eq "") ; + main::ok(62, $ret eq "[[11]]") ; + + undef $X; + untie(%h); + unlink "SubDB.pm", "dbhash.tmp" ; + +} + +{ + # DBM Filter tests + use warnings ; + use strict ; + my (%h, $db) ; + my ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + unlink $Dfile; + + sub checkOutput + { + my($fk, $sk, $fv, $sv) = @_ ; + return + $fetch_key eq $fk && $store_key eq $sk && + $fetch_value eq $fv && $store_value eq $sv && + $_ eq 'original' ; + } + + ok(63, $db = tie(%h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_HASH ) ); + + $db->filter_fetch_key (sub { $fetch_key = $_ }) ; + $db->filter_store_key (sub { $store_key = $_ }) ; + $db->filter_fetch_value (sub { $fetch_value = $_}) ; + $db->filter_store_value (sub { $store_value = $_ }) ; + + $_ = "original" ; + + $h{"fred"} = "joe" ; + # fk sk fv sv + ok(64, checkOutput( "", "fred", "", "joe")) ; + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + ok(65, $h{"fred"} eq "joe"); + # fk sk fv sv + ok(66, checkOutput( "", "fred", "joe", "")) ; + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + ok(67, $db->FIRSTKEY() eq "fred") ; + # fk sk fv sv + ok(68, checkOutput( "fred", "", "", "")) ; + + # replace the filters, but remember the previous set + my ($old_fk) = $db->filter_fetch_key + (sub { $_ = uc $_ ; $fetch_key = $_ }) ; + my ($old_sk) = $db->filter_store_key + (sub { $_ = lc $_ ; $store_key = $_ }) ; + my ($old_fv) = $db->filter_fetch_value + (sub { $_ = "[$_]"; $fetch_value = $_ }) ; + my ($old_sv) = $db->filter_store_value + (sub { s/o/x/g; $store_value = $_ }) ; + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + $h{"Fred"} = "Joe" ; + # fk sk fv sv + ok(69, checkOutput( "", "fred", "", "Jxe")) ; + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + ok(70, $h{"Fred"} eq "[Jxe]"); + # fk sk fv sv + ok(71, checkOutput( "", "fred", "[Jxe]", "")) ; + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + ok(72, $db->FIRSTKEY() eq "FRED") ; + # fk sk fv sv + ok(73, checkOutput( "FRED", "", "", "")) ; + + # put the original filters back + $db->filter_fetch_key ($old_fk); + $db->filter_store_key ($old_sk); + $db->filter_fetch_value ($old_fv); + $db->filter_store_value ($old_sv); + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + $h{"fred"} = "joe" ; + ok(74, checkOutput( "", "fred", "", "joe")) ; + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + ok(75, $h{"fred"} eq "joe"); + ok(76, checkOutput( "", "fred", "joe", "")) ; + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + ok(77, $db->FIRSTKEY() eq "fred") ; + ok(78, checkOutput( "fred", "", "", "")) ; + + # delete the filters + $db->filter_fetch_key (undef); + $db->filter_store_key (undef); + $db->filter_fetch_value (undef); + $db->filter_store_value (undef); + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + $h{"fred"} = "joe" ; + ok(79, checkOutput( "", "", "", "")) ; + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + ok(80, $h{"fred"} eq "joe"); + ok(81, checkOutput( "", "", "", "")) ; + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + ok(82, $db->FIRSTKEY() eq "fred") ; + ok(83, checkOutput( "", "", "", "")) ; + + undef $db ; + untie %h; + unlink $Dfile; +} + +{ + # DBM Filter with a closure + + use warnings ; + use strict ; + my (%h, $db) ; + + unlink $Dfile; + ok(84, $db = tie(%h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_HASH ) ); + + my %result = () ; + + sub Closure + { + my ($name) = @_ ; + my $count = 0 ; + my @kept = () ; + + return sub { ++$count ; + push @kept, $_ ; + $result{$name} = "$name - $count: [@kept]" ; + } + } + + $db->filter_store_key(Closure("store key")) ; + $db->filter_store_value(Closure("store value")) ; + $db->filter_fetch_key(Closure("fetch key")) ; + $db->filter_fetch_value(Closure("fetch value")) ; + + $_ = "original" ; + + $h{"fred"} = "joe" ; + ok(85, $result{"store key"} eq "store key - 1: [fred]"); + ok(86, $result{"store value"} eq "store value - 1: [joe]"); + ok(87, ! defined $result{"fetch key"} ); + ok(88, ! defined $result{"fetch value"} ); + ok(89, $_ eq "original") ; + + ok(90, $db->FIRSTKEY() eq "fred") ; + ok(91, $result{"store key"} eq "store key - 1: [fred]"); + ok(92, $result{"store value"} eq "store value - 1: [joe]"); + ok(93, $result{"fetch key"} eq "fetch key - 1: [fred]"); + ok(94, ! defined $result{"fetch value"} ); + ok(95, $_ eq "original") ; + + $h{"jim"} = "john" ; + ok(96, $result{"store key"} eq "store key - 2: [fred jim]"); + ok(97, $result{"store value"} eq "store value - 2: [joe john]"); + ok(98, $result{"fetch key"} eq "fetch key - 1: [fred]"); + ok(99, ! defined $result{"fetch value"} ); + ok(100, $_ eq "original") ; + + ok(101, $h{"fred"} eq "joe"); + ok(102, $result{"store key"} eq "store key - 3: [fred jim fred]"); + ok(103, $result{"store value"} eq "store value - 2: [joe john]"); + ok(104, $result{"fetch key"} eq "fetch key - 1: [fred]"); + ok(105, $result{"fetch value"} eq "fetch value - 1: [joe]"); + ok(106, $_ eq "original") ; + + undef $db ; + untie %h; + unlink $Dfile; +} + +{ + # DBM Filter recursion detection + use warnings ; + use strict ; + my (%h, $db) ; + unlink $Dfile; + + ok(107, $db = tie(%h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_HASH ) ); + + $db->filter_store_key (sub { $_ = $h{$_} }) ; + + eval '$h{1} = 1234' ; + ok(108, $@ =~ /^recursion detected in filter_store_key at/ ); + + undef $db ; + untie %h; + unlink $Dfile; +} + + +{ + # Examples from the POD + + my $file = "xyzt" ; + { + my $redirect = new Redirect $file ; + + use warnings FATAL => qw(all); + use strict ; + use DB_File ; + use vars qw( %h $k $v ) ; + + unlink "fruit" ; + tie %h, "DB_File", "fruit", O_RDWR|O_CREAT, 0640, $DB_HASH + or die "Cannot open file 'fruit': $!\n"; + + # Add a few key/value pairs to the file + $h{"apple"} = "red" ; + $h{"orange"} = "orange" ; + $h{"banana"} = "yellow" ; + $h{"tomato"} = "red" ; + + # Check for existence of a key + print "Banana Exists\n\n" if $h{"banana"} ; + + # Delete a key/value pair. + delete $h{"apple"} ; + + # print the contents of the file + while (($k, $v) = each %h) + { print "$k -> $v\n" } + + untie %h ; + + unlink "fruit" ; + } + + ok(109, docat_del($file) eq <<'EOM') ; +Banana Exists + +orange -> orange +tomato -> red +banana -> yellow +EOM + +} + +{ + # Bug ID 20001013.009 + # + # test that $hash{KEY} = undef doesn't produce the warning + # Use of uninitialized value in null operation + use warnings ; + use strict ; + use DB_File ; + + unlink $Dfile; + my %h ; + my $a = ""; + local $SIG{__WARN__} = sub {$a = $_[0]} ; + + tie %h, 'DB_File', $Dfile or die "Can't open file: $!\n" ; + $h{ABC} = undef; + ok(110, $a eq "") ; + untie %h ; + unlink $Dfile; +} + +{ + # test that %hash = () doesn't produce the warning + # Argument "" isn't numeric in entersub + use warnings ; + use strict ; + use DB_File ; + + unlink $Dfile; + my %h ; + my $a = ""; + local $SIG{__WARN__} = sub {$a = $_[0]} ; + + tie %h, 'DB_File', $Dfile or die "Can't open file: $!\n" ; + %h = (); ; + ok(111, $a eq "") ; + untie %h ; + unlink $Dfile; +} + +exit ; diff --git a/db/perl.DB_File/t/db-recno.t b/db/perl.DB_File/t/db-recno.t new file mode 100644 index 000000000..c64d83b59 --- /dev/null +++ b/db/perl.DB_File/t/db-recno.t @@ -0,0 +1,899 @@ +#!./perl -w + +use warnings; +use strict ; + +BEGIN { + unless(grep /blib/, @INC) { + chdir 't' if -d 't'; + @INC = '../lib' if -d '../lib'; + } +} + +use Config; + +BEGIN { + if(-d "lib" && -f "TEST") { + if ($Config{'extensions'} !~ /\bDB_File\b/ ) { + print "1..128\n"; + exit 0; + } + } +} + +use DB_File; +use Fcntl; +use vars qw($dbh $Dfile $bad_ones $FA) ; + +# full tied array support started in Perl 5.004_57 +# Double check to see if it is available. + +{ + sub try::TIEARRAY { bless [], "try" } + sub try::FETCHSIZE { $FA = 1 } + $FA = 0 ; + my @a ; + tie @a, 'try' ; + my $a = @a ; +} + + +sub ok +{ + my $no = shift ; + my $result = shift ; + + print "not " unless $result ; + print "ok $no\n" ; + + return $result ; +} + +{ + package Redirect ; + use Symbol ; + + sub new + { + my $class = shift ; + my $filename = shift ; + my $fh = gensym ; + open ($fh, ">$filename") || die "Cannot open $filename: $!" ; + my $real_stdout = select($fh) ; + return bless [$fh, $real_stdout ] ; + + } + sub DESTROY + { + my $self = shift ; + close $self->[0] ; + select($self->[1]) ; + } +} + +sub docat +{ + my $file = shift; + local $/ = undef; + open(CAT,$file) || die "Cannot open $file:$!"; + my $result = ; + close(CAT); + return $result; +} + +sub docat_del +{ + my $file = shift; + local $/ = undef; + open(CAT,$file) || die "Cannot open $file: $!"; + my $result = ; + close(CAT); + unlink $file ; + return $result; +} + +sub bad_one +{ + print STDERR <{bval}) ; +ok(2, ! defined $dbh->{cachesize}) ; +ok(3, ! defined $dbh->{psize}) ; +ok(4, ! defined $dbh->{flags}) ; +ok(5, ! defined $dbh->{lorder}) ; +ok(6, ! defined $dbh->{reclen}) ; +ok(7, ! defined $dbh->{bfname}) ; + +$dbh->{bval} = 3000 ; +ok(8, $dbh->{bval} == 3000 ); + +$dbh->{cachesize} = 9000 ; +ok(9, $dbh->{cachesize} == 9000 ); + +$dbh->{psize} = 400 ; +ok(10, $dbh->{psize} == 400 ); + +$dbh->{flags} = 65 ; +ok(11, $dbh->{flags} == 65 ); + +$dbh->{lorder} = 123 ; +ok(12, $dbh->{lorder} == 123 ); + +$dbh->{reclen} = 1234 ; +ok(13, $dbh->{reclen} == 1234 ); + +$dbh->{bfname} = 1234 ; +ok(14, $dbh->{bfname} == 1234 ); + + +# Check that an invalid entry is caught both for store & fetch +eval '$dbh->{fred} = 1234' ; +ok(15, $@ =~ /^DB_File::RECNOINFO::STORE - Unknown element 'fred' at/ ); +eval 'my $q = $dbh->{fred}' ; +ok(16, $@ =~ /^DB_File::RECNOINFO::FETCH - Unknown element 'fred' at/ ); + +# Now check the interface to RECNOINFO + +my $X ; +my @h ; +ok(17, $X = tie @h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_RECNO ) ; + +ok(18, ((stat($Dfile))[2] & 0777) == ($^O eq 'os2' ? 0666 : 0640) + || $^O eq 'MSWin32' || $^O eq 'amigaos') ; + +#my $l = @h ; +my $l = $X->length ; +ok(19, ($FA ? @h == 0 : !$l) ); + +my @data = qw( a b c d ever f g h i j k longername m n o p) ; + +$h[0] = shift @data ; +ok(20, $h[0] eq 'a' ); + +my $ i; +foreach (@data) + { $h[++$i] = $_ } + +unshift (@data, 'a') ; + +ok(21, defined $h[1] ); +ok(22, ! defined $h[16] ); +ok(23, $FA ? @h == @data : $X->length == @data ); + + +# Overwrite an entry & check fetch it +$h[3] = 'replaced' ; +$data[3] = 'replaced' ; +ok(24, $h[3] eq 'replaced' ); + +#PUSH +my @push_data = qw(added to the end) ; +($FA ? push(@h, @push_data) : $X->push(@push_data)) ; +push (@data, @push_data) ; +ok(25, $h[++$i] eq 'added' ); +ok(26, $h[++$i] eq 'to' ); +ok(27, $h[++$i] eq 'the' ); +ok(28, $h[++$i] eq 'end' ); + +# POP +my $popped = pop (@data) ; +my $value = ($FA ? pop @h : $X->pop) ; +ok(29, $value eq $popped) ; + +# SHIFT +$value = ($FA ? shift @h : $X->shift) ; +my $shifted = shift @data ; +ok(30, $value eq $shifted ); + +# UNSHIFT + +# empty list +($FA ? unshift @h : $X->unshift) ; +ok(31, ($FA ? @h == @data : $X->length == @data )); + +my @new_data = qw(add this to the start of the array) ; +$FA ? unshift (@h, @new_data) : $X->unshift (@new_data) ; +unshift (@data, @new_data) ; +ok(32, $FA ? @h == @data : $X->length == @data ); +ok(33, $h[0] eq "add") ; +ok(34, $h[1] eq "this") ; +ok(35, $h[2] eq "to") ; +ok(36, $h[3] eq "the") ; +ok(37, $h[4] eq "start") ; +ok(38, $h[5] eq "of") ; +ok(39, $h[6] eq "the") ; +ok(40, $h[7] eq "array") ; +ok(41, $h[8] eq $data[8]) ; + +# SPLICE + +# Now both arrays should be identical + +my $ok = 1 ; +my $j = 0 ; +foreach (@data) +{ + $ok = 0, last if $_ ne $h[$j ++] ; +} +ok(42, $ok ); + +# Neagtive subscripts + +# get the last element of the array +ok(43, $h[-1] eq $data[-1] ); +ok(44, $h[-1] eq $h[ ($FA ? @h : $X->length) -1] ); + +# get the first element using a negative subscript +eval '$h[ - ( $FA ? @h : $X->length)] = "abcd"' ; +ok(45, $@ eq "" ); +ok(46, $h[0] eq "abcd" ); + +# now try to read before the start of the array +eval '$h[ - (1 + ($FA ? @h : $X->length))] = 1234' ; +ok(47, $@ =~ '^Modification of non-creatable array value attempted' ); + +# IMPORTANT - $X must be undefined before the untie otherwise the +# underlying DB close routine will not get called. +undef $X ; +untie(@h); + +unlink $Dfile; + + +{ + # Check bval defaults to \n + + my @h = () ; + my $dbh = new DB_File::RECNOINFO ; + ok(48, tie @h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $dbh ) ; + $h[0] = "abc" ; + $h[1] = "def" ; + $h[3] = "ghi" ; + untie @h ; + my $x = docat($Dfile) ; + unlink $Dfile; + ok(49, $x eq "abc\ndef\n\nghi\n") ; +} + +{ + # Change bval + + my @h = () ; + my $dbh = new DB_File::RECNOINFO ; + $dbh->{bval} = "-" ; + ok(50, tie @h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $dbh ) ; + $h[0] = "abc" ; + $h[1] = "def" ; + $h[3] = "ghi" ; + untie @h ; + my $x = docat($Dfile) ; + unlink $Dfile; + my $ok = ($x eq "abc-def--ghi-") ; + bad_one() unless $ok ; + ok(51, $ok) ; +} + +{ + # Check R_FIXEDLEN with default bval (space) + + my @h = () ; + my $dbh = new DB_File::RECNOINFO ; + $dbh->{flags} = R_FIXEDLEN ; + $dbh->{reclen} = 5 ; + ok(52, tie @h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $dbh ) ; + $h[0] = "abc" ; + $h[1] = "def" ; + $h[3] = "ghi" ; + untie @h ; + my $x = docat($Dfile) ; + unlink $Dfile; + my $ok = ($x eq "abc def ghi ") ; + bad_one() unless $ok ; + ok(53, $ok) ; +} + +{ + # Check R_FIXEDLEN with user-defined bval + + my @h = () ; + my $dbh = new DB_File::RECNOINFO ; + $dbh->{flags} = R_FIXEDLEN ; + $dbh->{bval} = "-" ; + $dbh->{reclen} = 5 ; + ok(54, tie @h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $dbh ) ; + $h[0] = "abc" ; + $h[1] = "def" ; + $h[3] = "ghi" ; + untie @h ; + my $x = docat($Dfile) ; + unlink $Dfile; + my $ok = ($x eq "abc--def-------ghi--") ; + bad_one() unless $ok ; + ok(55, $ok) ; +} + +{ + # check that attempting to tie an associative array to a DB_RECNO will fail + + my $filename = "xyz" ; + my %x ; + eval { tie %x, 'DB_File', $filename, O_RDWR|O_CREAT, 0640, $DB_RECNO ; } ; + ok(56, $@ =~ /^DB_File can only tie an array to a DB_RECNO database/) ; + unlink $filename ; +} + +{ + # sub-class test + + package Another ; + + use warnings ; + use strict ; + + open(FILE, ">SubDB.pm") or die "Cannot open SubDB.pm: $!\n" ; + print FILE <<'EOM' ; + + package SubDB ; + + use warnings ; + use strict ; + use vars qw( @ISA @EXPORT) ; + + require Exporter ; + use DB_File; + @ISA=qw(DB_File); + @EXPORT = @DB_File::EXPORT ; + + sub STORE { + my $self = shift ; + my $key = shift ; + my $value = shift ; + $self->SUPER::STORE($key, $value * 2) ; + } + + sub FETCH { + my $self = shift ; + my $key = shift ; + $self->SUPER::FETCH($key) - 1 ; + } + + sub put { + my $self = shift ; + my $key = shift ; + my $value = shift ; + $self->SUPER::put($key, $value * 3) ; + } + + sub get { + my $self = shift ; + $self->SUPER::get($_[0], $_[1]) ; + $_[1] -= 2 ; + } + + sub A_new_method + { + my $self = shift ; + my $key = shift ; + my $value = $self->FETCH($key) ; + return "[[$value]]" ; + } + + 1 ; +EOM + + close FILE ; + + BEGIN { push @INC, '.'; } + eval 'use SubDB ; '; + main::ok(57, $@ eq "") ; + my @h ; + my $X ; + eval ' + $X = tie(@h, "SubDB","recno.tmp", O_RDWR|O_CREAT, 0640, $DB_RECNO ); + ' ; + + main::ok(58, $@ eq "") ; + + my $ret = eval '$h[3] = 3 ; return $h[3] ' ; + main::ok(59, $@ eq "") ; + main::ok(60, $ret == 5) ; + + my $value = 0; + $ret = eval '$X->put(1, 4) ; $X->get(1, $value) ; return $value' ; + main::ok(61, $@ eq "") ; + main::ok(62, $ret == 10) ; + + $ret = eval ' R_NEXT eq main::R_NEXT ' ; + main::ok(63, $@ eq "" ) ; + main::ok(64, $ret == 1) ; + + $ret = eval '$X->A_new_method(1) ' ; + main::ok(65, $@ eq "") ; + main::ok(66, $ret eq "[[11]]") ; + + undef $X; + untie(@h); + unlink "SubDB.pm", "recno.tmp" ; + +} + +{ + + # test $# + my $self ; + unlink $Dfile; + ok(67, $self = tie @h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_RECNO ) ; + $h[0] = "abc" ; + $h[1] = "def" ; + $h[2] = "ghi" ; + $h[3] = "jkl" ; + ok(68, $FA ? $#h == 3 : $self->length() == 4) ; + undef $self ; + untie @h ; + my $x = docat($Dfile) ; + ok(69, $x eq "abc\ndef\nghi\njkl\n") ; + + # $# sets array to same length + ok(70, $self = tie @h, 'DB_File', $Dfile, O_RDWR, 0640, $DB_RECNO ) ; + if ($FA) + { $#h = 3 } + else + { $self->STORESIZE(4) } + ok(71, $FA ? $#h == 3 : $self->length() == 4) ; + undef $self ; + untie @h ; + $x = docat($Dfile) ; + ok(72, $x eq "abc\ndef\nghi\njkl\n") ; + + # $# sets array to bigger + ok(73, $self = tie @h, 'DB_File', $Dfile, O_RDWR, 0640, $DB_RECNO ) ; + if ($FA) + { $#h = 6 } + else + { $self->STORESIZE(7) } + ok(74, $FA ? $#h == 6 : $self->length() == 7) ; + undef $self ; + untie @h ; + $x = docat($Dfile) ; + ok(75, $x eq "abc\ndef\nghi\njkl\n\n\n\n") ; + + # $# sets array smaller + ok(76, $self = tie @h, 'DB_File', $Dfile, O_RDWR, 0640, $DB_RECNO ) ; + if ($FA) + { $#h = 2 } + else + { $self->STORESIZE(3) } + ok(77, $FA ? $#h == 2 : $self->length() == 3) ; + undef $self ; + untie @h ; + $x = docat($Dfile) ; + ok(78, $x eq "abc\ndef\nghi\n") ; + + unlink $Dfile; + + +} + +{ + # DBM Filter tests + use warnings ; + use strict ; + my (@h, $db) ; + my ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + unlink $Dfile; + + sub checkOutput + { + my($fk, $sk, $fv, $sv) = @_ ; + return + $fetch_key eq $fk && $store_key eq $sk && + $fetch_value eq $fv && $store_value eq $sv && + $_ eq 'original' ; + } + + ok(79, $db = tie(@h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_RECNO ) ); + + $db->filter_fetch_key (sub { $fetch_key = $_ }) ; + $db->filter_store_key (sub { $store_key = $_ }) ; + $db->filter_fetch_value (sub { $fetch_value = $_}) ; + $db->filter_store_value (sub { $store_value = $_ }) ; + + $_ = "original" ; + + $h[0] = "joe" ; + # fk sk fv sv + ok(80, checkOutput( "", 0, "", "joe")) ; + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + ok(81, $h[0] eq "joe"); + # fk sk fv sv + ok(82, checkOutput( "", 0, "joe", "")) ; + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + ok(83, $db->FIRSTKEY() == 0) ; + # fk sk fv sv + ok(84, checkOutput( 0, "", "", "")) ; + + # replace the filters, but remember the previous set + my ($old_fk) = $db->filter_fetch_key + (sub { ++ $_ ; $fetch_key = $_ }) ; + my ($old_sk) = $db->filter_store_key + (sub { $_ *= 2 ; $store_key = $_ }) ; + my ($old_fv) = $db->filter_fetch_value + (sub { $_ = "[$_]"; $fetch_value = $_ }) ; + my ($old_sv) = $db->filter_store_value + (sub { s/o/x/g; $store_value = $_ }) ; + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + $h[1] = "Joe" ; + # fk sk fv sv + ok(85, checkOutput( "", 2, "", "Jxe")) ; + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + ok(86, $h[1] eq "[Jxe]"); + # fk sk fv sv + ok(87, checkOutput( "", 2, "[Jxe]", "")) ; + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + ok(88, $db->FIRSTKEY() == 1) ; + # fk sk fv sv + ok(89, checkOutput( 1, "", "", "")) ; + + # put the original filters back + $db->filter_fetch_key ($old_fk); + $db->filter_store_key ($old_sk); + $db->filter_fetch_value ($old_fv); + $db->filter_store_value ($old_sv); + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + $h[0] = "joe" ; + ok(90, checkOutput( "", 0, "", "joe")) ; + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + ok(91, $h[0] eq "joe"); + ok(92, checkOutput( "", 0, "joe", "")) ; + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + ok(93, $db->FIRSTKEY() == 0) ; + ok(94, checkOutput( 0, "", "", "")) ; + + # delete the filters + $db->filter_fetch_key (undef); + $db->filter_store_key (undef); + $db->filter_fetch_value (undef); + $db->filter_store_value (undef); + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + $h[0] = "joe" ; + ok(95, checkOutput( "", "", "", "")) ; + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + ok(96, $h[0] eq "joe"); + ok(97, checkOutput( "", "", "", "")) ; + + ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ; + ok(98, $db->FIRSTKEY() == 0) ; + ok(99, checkOutput( "", "", "", "")) ; + + undef $db ; + untie @h; + unlink $Dfile; +} + +{ + # DBM Filter with a closure + + use warnings ; + use strict ; + my (@h, $db) ; + + unlink $Dfile; + ok(100, $db = tie(@h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_RECNO ) ); + + my %result = () ; + + sub Closure + { + my ($name) = @_ ; + my $count = 0 ; + my @kept = () ; + + return sub { ++$count ; + push @kept, $_ ; + $result{$name} = "$name - $count: [@kept]" ; + } + } + + $db->filter_store_key(Closure("store key")) ; + $db->filter_store_value(Closure("store value")) ; + $db->filter_fetch_key(Closure("fetch key")) ; + $db->filter_fetch_value(Closure("fetch value")) ; + + $_ = "original" ; + + $h[0] = "joe" ; + ok(101, $result{"store key"} eq "store key - 1: [0]"); + ok(102, $result{"store value"} eq "store value - 1: [joe]"); + ok(103, ! defined $result{"fetch key"} ); + ok(104, ! defined $result{"fetch value"} ); + ok(105, $_ eq "original") ; + + ok(106, $db->FIRSTKEY() == 0 ) ; + ok(107, $result{"store key"} eq "store key - 1: [0]"); + ok(108, $result{"store value"} eq "store value - 1: [joe]"); + ok(109, $result{"fetch key"} eq "fetch key - 1: [0]"); + ok(110, ! defined $result{"fetch value"} ); + ok(111, $_ eq "original") ; + + $h[7] = "john" ; + ok(112, $result{"store key"} eq "store key - 2: [0 7]"); + ok(113, $result{"store value"} eq "store value - 2: [joe john]"); + ok(114, $result{"fetch key"} eq "fetch key - 1: [0]"); + ok(115, ! defined $result{"fetch value"} ); + ok(116, $_ eq "original") ; + + ok(117, $h[0] eq "joe"); + ok(118, $result{"store key"} eq "store key - 3: [0 7 0]"); + ok(119, $result{"store value"} eq "store value - 2: [joe john]"); + ok(120, $result{"fetch key"} eq "fetch key - 1: [0]"); + ok(121, $result{"fetch value"} eq "fetch value - 1: [joe]"); + ok(122, $_ eq "original") ; + + undef $db ; + untie @h; + unlink $Dfile; +} + +{ + # DBM Filter recursion detection + use warnings ; + use strict ; + my (@h, $db) ; + unlink $Dfile; + + ok(123, $db = tie(@h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_RECNO ) ); + + $db->filter_store_key (sub { $_ = $h[0] }) ; + + eval '$h[1] = 1234' ; + ok(124, $@ =~ /^recursion detected in filter_store_key at/ ); + + undef $db ; + untie @h; + unlink $Dfile; +} + + +{ + # Examples from the POD + + my $file = "xyzt" ; + { + my $redirect = new Redirect $file ; + + use warnings FATAL => qw(all); + use strict ; + use DB_File ; + + my $filename = "text" ; + unlink $filename ; + + my @h ; + my $x = tie @h, "DB_File", $filename, O_RDWR|O_CREAT, 0640, $DB_RECNO + or die "Cannot open file 'text': $!\n" ; + + # Add a few key/value pairs to the file + $h[0] = "orange" ; + $h[1] = "blue" ; + $h[2] = "yellow" ; + + $FA ? push @h, "green", "black" + : $x->push("green", "black") ; + + my $elements = $FA ? scalar @h : $x->length ; + print "The array contains $elements entries\n" ; + + my $last = $FA ? pop @h : $x->pop ; + print "popped $last\n" ; + + $FA ? unshift @h, "white" + : $x->unshift("white") ; + my $first = $FA ? shift @h : $x->shift ; + print "shifted $first\n" ; + + # Check for existence of a key + print "Element 1 Exists with value $h[1]\n" if $h[1] ; + + # use a negative index + print "The last element is $h[-1]\n" ; + print "The 2nd last element is $h[-2]\n" ; + + undef $x ; + untie @h ; + + unlink $filename ; + } + + ok(125, docat_del($file) eq <<'EOM') ; +The array contains 5 entries +popped black +shifted white +Element 1 Exists with value blue +The last element is green +The 2nd last element is yellow +EOM + + my $save_output = "xyzt" ; + { + my $redirect = new Redirect $save_output ; + + use warnings FATAL => qw(all); + use strict ; + use vars qw(@h $H $file $i) ; + use DB_File ; + use Fcntl ; + + $file = "text" ; + + unlink $file ; + + $H = tie @h, "DB_File", $file, O_RDWR|O_CREAT, 0640, $DB_RECNO + or die "Cannot open file $file: $!\n" ; + + # first create a text file to play with + $h[0] = "zero" ; + $h[1] = "one" ; + $h[2] = "two" ; + $h[3] = "three" ; + $h[4] = "four" ; + + + # Print the records in order. + # + # The length method is needed here because evaluating a tied + # array in a scalar context does not return the number of + # elements in the array. + + print "\nORIGINAL\n" ; + foreach $i (0 .. $H->length - 1) { + print "$i: $h[$i]\n" ; + } + + # use the push & pop methods + $a = $H->pop ; + $H->push("last") ; + print "\nThe last record was [$a]\n" ; + + # and the shift & unshift methods + $a = $H->shift ; + $H->unshift("first") ; + print "The first record was [$a]\n" ; + + # Use the API to add a new record after record 2. + $i = 2 ; + $H->put($i, "Newbie", R_IAFTER) ; + + # and a new record before record 1. + $i = 1 ; + $H->put($i, "New One", R_IBEFORE) ; + + # delete record 3 + $H->del(3) ; + + # now print the records in reverse order + print "\nREVERSE\n" ; + for ($i = $H->length - 1 ; $i >= 0 ; -- $i) + { print "$i: $h[$i]\n" } + + # same again, but use the API functions instead + print "\nREVERSE again\n" ; + my ($s, $k, $v) = (0, 0, 0) ; + for ($s = $H->seq($k, $v, R_LAST) ; + $s == 0 ; + $s = $H->seq($k, $v, R_PREV)) + { print "$k: $v\n" } + + undef $H ; + untie @h ; + + unlink $file ; + } + + ok(126, docat_del($save_output) eq <<'EOM') ; + +ORIGINAL +0: zero +1: one +2: two +3: three +4: four + +The last record was [four] +The first record was [zero] + +REVERSE +5: last +4: three +3: Newbie +2: one +1: New One +0: first + +REVERSE again +5: last +4: three +3: Newbie +2: one +1: New One +0: first +EOM + +} + +{ + # Bug ID 20001013.009 + # + # test that $hash{KEY} = undef doesn't produce the warning + # Use of uninitialized value in null operation + use warnings ; + use strict ; + use DB_File ; + + unlink $Dfile; + my @h ; + my $a = ""; + local $SIG{__WARN__} = sub {$a = $_[0]} ; + + tie @h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0664, $DB_RECNO + or die "Can't open file: $!\n" ; + $h[0] = undef; + ok(127, $a eq "") ; + untie @h ; + unlink $Dfile; +} + +{ + # test that %hash = () doesn't produce the warning + # Argument "" isn't numeric in entersub + use warnings ; + use strict ; + use DB_File ; + my $a = ""; + local $SIG{__WARN__} = sub {$a = $_[0]} ; + + unlink $Dfile; + my @h ; + + tie @h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0664, $DB_RECNO + or die "Can't open file: $!\n" ; + @h = (); ; + ok(128, $a eq "") ; + untie @h ; + unlink $Dfile; +} + +exit ; diff --git a/db/perl.DB_File/typemap b/db/perl.DB_File/typemap new file mode 100644 index 000000000..55439ee76 --- /dev/null +++ b/db/perl.DB_File/typemap @@ -0,0 +1,44 @@ +# typemap for Perl 5 interface to Berkeley +# +# written by Paul Marquess +# last modified 10th December 2000 +# version 1.74 +# +#################################### DB SECTION +# +# + +u_int T_U_INT +DB_File T_PTROBJ +DBT T_dbtdatum +DBTKEY T_dbtkeydatum + +INPUT +T_dbtkeydatum + ckFilter($arg, filter_store_key, \"filter_store_key\"); + DBT_clear($var) ; + if (db->type != DB_RECNO) { + $var.data = SvPV($arg, PL_na); + $var.size = (int)PL_na; + } + else { + Value = GetRecnoKey(aTHX_ db, SvIV($arg)) ; + $var.data = & Value; + $var.size = (int)sizeof(recno_t); + } +T_dbtdatum + ckFilter($arg, filter_store_value, \"filter_store_value\"); + DBT_clear($var) ; + if (SvOK($arg)) { + $var.data = SvPV($arg, PL_na); + $var.size = (int)PL_na; + } + +OUTPUT + +T_dbtkeydatum + OutputKey($arg, $var) +T_dbtdatum + OutputValue($arg, $var) +T_PTROBJ + sv_setref_pv($arg, dbtype, (void*)$var); diff --git a/db/perl.DB_File/version.c b/db/perl.DB_File/version.c new file mode 100644 index 000000000..82b3e8b27 --- /dev/null +++ b/db/perl.DB_File/version.c @@ -0,0 +1,81 @@ +/* + + version.c -- Perl 5 interface to Berkeley DB + + written by Paul Marquess + last modified 16th January 2000 + version 1.73 + + All comments/suggestions/problems are welcome + + Copyright (c) 1995-2001 Paul Marquess. All rights reserved. + This program is free software; you can redistribute it and/or + modify it under the same terms as Perl itself. + + Changes: + 1.71 - Support for Berkeley DB version 3. + Support for Berkeley DB 2/3's backward compatability mode. + 1.72 - No change. + 1.73 - Added support for threading + 1.74 - Added Perl core patch 7801. + + +*/ + +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" + +#include + +void +#ifdef CAN_PROTOTYPE +__getBerkeleyDBInfo(void) +#else +__getBerkeleyDBInfo() +#endif +{ +#ifdef dTHX + dTHX; +#endif + SV * version_sv = perl_get_sv("DB_File::db_version", GV_ADD|GV_ADDMULTI) ; + SV * ver_sv = perl_get_sv("DB_File::db_ver", GV_ADD|GV_ADDMULTI) ; + SV * compat_sv = perl_get_sv("DB_File::db_185_compat", GV_ADD|GV_ADDMULTI) ; + +#ifdef DB_VERSION_MAJOR + int Major, Minor, Patch ; + + (void)db_version(&Major, &Minor, &Patch) ; + + /* Check that the versions of db.h and libdb.a are the same */ + if (Major != DB_VERSION_MAJOR || Minor != DB_VERSION_MINOR + || Patch != DB_VERSION_PATCH) + croak("\nDB_File needs compatible versions of libdb & db.h\n\tyou have db.h version %d.%d.%d and libdb version %d.%d.%d\n", + DB_VERSION_MAJOR, DB_VERSION_MINOR, DB_VERSION_PATCH, + Major, Minor, Patch) ; + + /* check that libdb is recent enough -- we need 2.3.4 or greater */ + if (Major == 2 && (Minor < 3 || (Minor == 3 && Patch < 4))) + croak("DB_File needs Berkeley DB 2.3.4 or greater, you have %d.%d.%d\n", + Major, Minor, Patch) ; + + { + char buffer[40] ; + sprintf(buffer, "%d.%d", Major, Minor) ; + sv_setpv(version_sv, buffer) ; + sprintf(buffer, "%d.%03d%03d", Major, Minor, Patch) ; + sv_setpv(ver_sv, buffer) ; + } + +#else /* ! DB_VERSION_MAJOR */ + sv_setiv(version_sv, 1) ; + sv_setiv(ver_sv, 1) ; +#endif /* ! DB_VERSION_MAJOR */ + +#ifdef COMPAT185 + sv_setiv(compat_sv, 1) ; +#else /* ! COMPAT185 */ + sv_setiv(compat_sv, 0) ; +#endif /* ! COMPAT185 */ + +} diff --git a/db/qam/qam.c b/db/qam/qam.c new file mode 100644 index 000000000..0c9f45304 --- /dev/null +++ b/db/qam/qam.c @@ -0,0 +1,1357 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: qam.c,v 11.72 2001/01/16 20:10:55 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_shash.h" +#include "db_am.h" +#include "mp.h" +#include "lock.h" +#include "log.h" +#include "btree.h" +#include "qam.h" + +static int __qam_c_close __P((DBC *, db_pgno_t, int *)); +static int __qam_c_del __P((DBC *)); +static int __qam_c_destroy __P((DBC *)); +static int __qam_c_get __P((DBC *, DBT *, DBT *, u_int32_t, db_pgno_t *)); +static int __qam_c_put __P((DBC *, DBT *, DBT *, u_int32_t, db_pgno_t *)); +static int __qam_getno __P((DB *, const DBT *, db_recno_t *)); + +/* + * __qam_position -- + * Position a queued access method cursor at a record. This returns + * the page locked. *exactp will be set if the record is valid. + * PUBLIC: int __qam_position + * PUBLIC: __P((DBC *, db_recno_t *, qam_position_mode, int *)); + */ +int +__qam_position(dbc, recnop, mode, exactp) + DBC *dbc; /* open cursor */ + db_recno_t *recnop; /* pointer to recno to find */ + qam_position_mode mode;/* locking: read or write */ + int *exactp; /* indicate if it was found */ +{ + QUEUE_CURSOR *cp; + DB *dbp; + QAMDATA *qp; + db_pgno_t pg; + int ret; + + dbp = dbc->dbp; + cp = (QUEUE_CURSOR *)dbc->internal; + + /* Fetch the page for this recno. */ + pg = QAM_RECNO_PAGE(dbp, *recnop); + + if ((ret = __db_lget(dbc, 0, pg, mode == QAM_READ ? + DB_LOCK_READ : DB_LOCK_WRITE, 0, &cp->lock)) != 0) + return (ret); + cp->page = NULL; + *exactp = 0; + if ((ret = __qam_fget(dbp, &pg, + mode == QAM_WRITE ? DB_MPOOL_CREATE : 0, + &cp->page)) != 0) { + /* We did not fetch it, we can release the lock. */ + (void)__LPUT(dbc, cp->lock); + cp->lock.off = LOCK_INVALID; + if (mode != QAM_WRITE && (ret == EINVAL || ret == ENOENT)) + return (0); + return (ret); + } + cp->pgno = pg; + cp->indx = QAM_RECNO_INDEX(dbp, pg, *recnop); + + if (PGNO(cp->page) == 0) { + if (F_ISSET(dbp, DB_AM_RDONLY)) { + *exactp = 0; + return (0); + } + PGNO(cp->page) = pg; + TYPE(cp->page) = P_QAMDATA; + } + + qp = QAM_GET_RECORD(dbp, cp->page, cp->indx); + *exactp = F_ISSET(qp, QAM_VALID); + + return (ret); +} + +/* + * __qam_pitem -- + * Put an item on a queue page. Copy the data to the page and set the + * VALID and SET bits. If logging and the record was previously set, + * log that data, otherwise just log the new data. + * + * pagep must be write locked + * + * PUBLIC: int __qam_pitem + * PUBLIC: __P((DBC *, QPAGE *, u_int32_t, db_recno_t, DBT *)); + */ +int +__qam_pitem(dbc, pagep, indx, recno, data) + DBC *dbc; + QPAGE *pagep; + u_int32_t indx; + db_recno_t recno; + DBT *data; +{ + DB *dbp; + DBT olddata, pdata, *datap; + QAMDATA *qp; + QUEUE *t; + u_int32_t size; + u_int8_t *dest, *p; + int alloced, ret; + + alloced = ret = 0; + + dbp = dbc->dbp; + t = (QUEUE *)dbp->q_internal; + + if (data->size > t->re_len) + goto len_err; + + qp = QAM_GET_RECORD(dbp, pagep, indx); + + p = qp->data; + size = data->size; + datap = data; + if (F_ISSET(data, DB_DBT_PARTIAL)) { + if (data->doff + data->dlen > t->re_len) { + alloced = data->dlen; + goto len_err; + } + if (data->size != data->dlen) { +len_err: __db_err(dbp->dbenv, + "Length improper for fixed length record %lu", + (u_long)(alloced ? alloced : data->size)); + return (EINVAL); + } + if (data->size == t->re_len) + goto no_partial; + + /* + * If we are logging, then we have to build the record + * first, otherwise, we can simply drop the change + * directly on the page. After this clause, make + * sure that datap and p are set up correctly so that + * copying datap into p does the right thing. + * + * Note, I am changing this so that if the existing + * record is not valid, we create a complete record + * to log so that both this and the recovery code is simpler. + */ + + if (DB_LOGGING(dbc) || !F_ISSET(qp, QAM_VALID)) { + datap = &pdata; + memset(datap, 0, sizeof(*datap)); + + if ((ret = __os_malloc(dbp->dbenv, + t->re_len, NULL, &datap->data)) != 0) + return (ret); + alloced = 1; + datap->size = t->re_len; + + /* + * Construct the record if it's valid, otherwise set it + * all to the pad character. + */ + dest = datap->data; + if (F_ISSET(qp, QAM_VALID)) + memcpy(dest, p, t->re_len); + else + memset(dest, t->re_pad, t->re_len); + + dest += data->doff; + memcpy(dest, data->data, data->size); + } else { + datap = data; + p += data->doff; + } + } + +no_partial: + if (DB_LOGGING(dbc)) { + olddata.size = 0; + if (F_ISSET(qp, QAM_SET)) { + olddata.data = qp->data; + olddata.size = t->re_len; + } + if ((ret = __qam_add_log(dbp->dbenv, dbc->txn, &LSN(pagep), + 0, dbp->log_fileid, &LSN(pagep), pagep->pgno, + indx, recno, datap, qp->flags, + olddata.size == 0 ? NULL : &olddata)) != 0) + goto err; + } + + F_SET(qp, QAM_VALID | QAM_SET); + memcpy(p, datap->data, datap->size); + if (!F_ISSET(data, DB_DBT_PARTIAL)) + memset(p + datap->size, t->re_pad, t->re_len - datap->size); + +err: if (alloced) + __os_free(datap->data, t->re_len); + + return (ret); +} +/* + * __qam_c_put + * Cursor put for queued access method. + * BEFORE and AFTER cannot be specified. + */ +static int +__qam_c_put(dbc, key, data, flags, pgnop) + DBC *dbc; + DBT *key, *data; + u_int32_t flags; + db_pgno_t *pgnop; +{ + QUEUE_CURSOR *cp; + DB *dbp; + DB_LOCK lock; + QMETA *meta; + db_pgno_t pg; + db_recno_t new_cur, new_first; + u_int32_t opcode; + int exact, ret, t_ret; + + COMPQUIET(key, NULL); + + dbp = dbc->dbp; + if (pgnop != NULL) + *pgnop = PGNO_INVALID; + + cp = (QUEUE_CURSOR *)dbc->internal; + + /* Write lock the record. */ + if ((ret = __db_lget(dbc, + 0, cp->recno, DB_LOCK_WRITE, DB_LOCK_RECORD, &lock)) != 0) + return (ret); + + if ((ret = __qam_position(dbc, + &cp->recno, QAM_WRITE, &exact)) != 0) { + /* We could not get the page, we can release the record lock. */ + __LPUT(dbc, lock); + return (ret); + } + + if (exact && flags == DB_NOOVERWRITE) { + ret = __TLPUT(dbc, lock); + /* Doing record locking, release the page lock */ + if ((t_ret = __LPUT(dbc, cp->lock)) == 0) + cp->lock.off = LOCK_INVALID; + else + if (ret == 0) + ret = t_ret; + if ((t_ret = + __qam_fput(dbp, cp->pgno, cp->page, 0)) != 0 && ret == 0) + ret = t_ret; + cp->page = NULL; + return (ret == 0 ? DB_KEYEXIST : ret); + } + + /* Put the item on the page. */ + ret = __qam_pitem(dbc, (QPAGE *)cp->page, cp->indx, cp->recno, data); + + /* Doing record locking, release the page lock */ + if ((t_ret = __LPUT(dbc, cp->lock)) != 0 && ret == 0) + ret = t_ret; + if ((t_ret = + __qam_fput(dbp, cp->pgno, cp->page, DB_MPOOL_DIRTY)) && ret == 0) + ret = t_ret; + cp->page = NULL; + cp->lock = lock; + cp->lock_mode = DB_LOCK_WRITE; + if (ret != 0) + return (ret); + + /* We may need to reset the head or tail of the queue. */ + pg = ((QUEUE *)dbp->q_internal)->q_meta; + if ((ret = __db_lget(dbc, 0, pg, DB_LOCK_WRITE, 0, &lock)) != 0) + return (ret); + if ((ret = memp_fget(dbp->mpf, &pg, 0, &meta)) != 0) { + /* We did not fetch it, we can release the lock. */ + (void)__LPUT(dbc, lock); + return (ret); + } + + opcode = 0; + new_cur = new_first = 0; + + /* + * If the put address is outside the queue, adjust the head and + * tail of the queue. If the order is inverted we move + * the one which is closer. The first case is when the + * queue is empty, move first and current to where the new + * insert is. + */ + + if (meta->first_recno == meta->cur_recno) { + new_first = cp->recno; + new_cur = cp->recno + 1; + if (new_cur == RECNO_OOB) + new_cur++; + opcode |= QAM_SETFIRST; + opcode |= QAM_SETCUR; + } else { + if (QAM_BEFORE_FIRST(meta, cp->recno) && + (meta->first_recno <= meta->cur_recno || + meta->first_recno - cp->recno < cp->recno - meta->cur_recno)) { + new_first = cp->recno; + opcode |= QAM_SETFIRST; + } + + if (meta->cur_recno == cp->recno || + (QAM_AFTER_CURRENT(meta, cp->recno) && + (meta->first_recno <= meta->cur_recno || + cp->recno - meta->cur_recno <= meta->first_recno - cp->recno))) { + new_cur = cp->recno + 1; + if (new_cur == RECNO_OOB) + new_cur++; + opcode |= QAM_SETCUR; + } + } + + if (opcode != 0 && DB_LOGGING(dbc)) { + ret = __qam_mvptr_log(dbp->dbenv, dbc->txn, &meta->dbmeta.lsn, + 0, opcode, dbp->log_fileid, meta->first_recno, new_first, + meta->cur_recno, new_cur, &meta->dbmeta.lsn); + } + + if (opcode & QAM_SETCUR) + meta->cur_recno = new_cur; + if (opcode & QAM_SETFIRST) + meta->first_recno = new_first; + + if ((t_ret = + memp_fput(dbp->mpf, meta, opcode != 0 ? DB_MPOOL_DIRTY : 0)) != 0 && + ret == 0) + ret = t_ret; + + /* Don't hold the meta page long term. */ + if ((t_ret = __LPUT(dbc, lock)) != 0 && ret == 0) + ret = t_ret; + return (ret); +} + +/* + * __qam_put -- + * Add a record to the queue. + * If we are doing anything but appending, just call qam_c_put to do the + * work. Otherwise we fast path things here. + * + * PUBLIC: int __qam_put __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t)); + */ +int +__qam_put(dbp, txn, key, data, flags) + DB *dbp; + DB_TXN *txn; + DBT *key, *data; + u_int32_t flags; +{ + QUEUE_CURSOR *cp; + DBC *dbc; + DB_LOCK lock; + QMETA *meta; + QPAGE *page; + QUEUE *qp; + db_pgno_t pg; + db_recno_t recno; + int ret, t_ret; + + PANIC_CHECK(dbp->dbenv); + DB_CHECK_TXN(dbp, txn); + + /* Allocate a cursor. */ + if ((ret = dbp->cursor(dbp, txn, &dbc, DB_WRITELOCK)) != 0) + return (ret); + + DEBUG_LWRITE(dbc, dbc->txn, "qam_put", key, data, flags); + + cp = (QUEUE_CURSOR *)dbc->internal; + + /* Check for invalid flags. */ + if ((ret = __db_putchk(dbp, + key, data, flags, F_ISSET(dbp, DB_AM_RDONLY), 0)) != 0) + goto done; + + /* If not appending, then just call the cursor routine */ + if (flags != DB_APPEND) { + if ((ret = __qam_getno(dbp, key, &cp->recno)) != 0) + goto done; + + ret = __qam_c_put(dbc, NULL, data, flags, NULL); + goto done; + } + + /* Write lock the meta page. */ + pg = ((QUEUE *)dbp->q_internal)->q_meta; + if ((ret = __db_lget(dbc, 0, pg, DB_LOCK_WRITE, 0, &lock)) != 0) + goto done; + if ((ret = memp_fget(dbp->mpf, &pg, 0, &meta)) != 0) { + /* We did not fetch it, we can release the lock. */ + (void)__LPUT(dbc, lock); + goto done; + } + + /* Record that we are going to allocate a record. */ + if (DB_LOGGING(dbc)) { + __qam_inc_log(dbp->dbenv, + dbc->txn, &meta->dbmeta.lsn, + 0, dbp->log_fileid, &meta->dbmeta.lsn); + } + + /* Get the next record number. */ + recno = meta->cur_recno; + meta->cur_recno++; + if (meta->cur_recno == RECNO_OOB) + meta->cur_recno++; + if (meta->cur_recno == meta->first_recno) { + meta->cur_recno--; + if (meta->cur_recno == RECNO_OOB) + meta->cur_recno--; + (void)__LPUT(dbc, lock); + ret = EFBIG; + goto err; + } + + if (QAM_BEFORE_FIRST(meta, recno)) + meta->first_recno = recno; + + /* Lock the record and release meta page lock. */ + if ((ret = __db_lget(dbc, + 1, recno, DB_LOCK_WRITE, DB_LOCK_RECORD, &lock)) != 0) + goto err; + + /* + * The application may modify the data based on the selected record + * number. + */ + if (flags == DB_APPEND && dbc->dbp->db_append_recno != NULL && + (ret = dbc->dbp->db_append_recno(dbc->dbp, data, recno)) != 0) { + (void)__LPUT(dbc, lock); + goto err; + } + + cp->lock = lock; + cp->lock_mode = DB_LOCK_WRITE; + + pg = QAM_RECNO_PAGE(dbp, recno); + + /* Fetch and write lock the data page. */ + if ((ret = __db_lget(dbc, 0, pg, DB_LOCK_WRITE, 0, &lock)) != 0) + goto err; + if ((ret = __qam_fget(dbp, &pg, DB_MPOOL_CREATE, &page)) != 0) { + /* We did not fetch it, we can release the lock. */ + (void)__LPUT(dbc, lock); + goto err; + } + + /* See if this is a new page. */ + if (page->pgno == 0) { + page->pgno = pg; + page->type = P_QAMDATA; + } + + /* Put the item on the page and log it. */ + ret = __qam_pitem(dbc, page, + QAM_RECNO_INDEX(dbp, pg, recno), recno, data); + + /* Doing record locking, release the page lock */ + if ((t_ret = __LPUT(dbc, lock)) != 0 && ret == 0) + ret = t_ret; + + if ((t_ret + = __qam_fput(dbp, pg, page, DB_MPOOL_DIRTY)) != 0 && ret == 0) + ret = t_ret; + + /* Return the record number to the user. */ + if (ret == 0) + ret = __db_retcopy(dbp, key, + &recno, sizeof(recno), &dbc->rkey.data, &dbc->rkey.ulen); + + /* See if we are leaving the extent. */ + qp = (QUEUE *) dbp->q_internal; + if (qp->page_ext != 0 + && (recno % (qp->page_ext * qp->rec_page) == 0 + || recno == UINT32_T_MAX)) { + if ((ret = + __db_lget(dbc, 0, pg, DB_LOCK_WRITE, 0, &lock)) != 0) + goto err; + if (!QAM_AFTER_CURRENT(meta, recno)) + ret = __qam_fclose(dbp, pg); + (void)__LPUT(dbc, lock); + } + +err: + /* Release the meta page. */ + if ((t_ret + = memp_fput(dbp->mpf, meta, DB_MPOOL_DIRTY)) != 0 && ret == 0) + ret = t_ret; + +done: + /* Discard the cursor. */ + if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0) + ret = t_ret; + + return (ret); +} + +/* + * __qam_c_del -- + * Qam cursor->am_del function + */ +static int +__qam_c_del(dbc) + DBC *dbc; +{ + QUEUE_CURSOR *cp; + DB *dbp; + DBT data; + DB_LOCK lock; + PAGE *pagep; + QAMDATA *qp; + QMETA *meta; + db_pgno_t pg; + int exact, ret, t_ret; + + dbp = dbc->dbp; + cp = (QUEUE_CURSOR *)dbc->internal; + + pg = ((QUEUE *)dbp->q_internal)->q_meta; + if ((ret = __db_lget(dbc, 0, pg, DB_LOCK_READ, 0, &lock)) != 0) + return (ret); + if ((ret = memp_fget(dbp->mpf, &pg, 0, &meta)) != 0) { + /* We did not fetch it, we can release the lock. */ + (void)__LPUT(dbc, lock); + return (ret); + } + + if (QAM_NOT_VALID(meta, cp->recno)) + ret = DB_NOTFOUND; + + /* Don't hold the meta page long term. */ + if ((t_ret = __LPUT(dbc, lock)) != 0 && ret == 0) + ret = t_ret; + if ((t_ret = memp_fput(dbp->mpf, meta, 0)) != 0 && ret == 0) + ret = t_ret; + + if (ret != 0) + return (ret); + + if ((ret = __db_lget(dbc, + 0, cp->recno, DB_LOCK_WRITE, DB_LOCK_RECORD, &lock)) != 0) + return (ret); + + cp->lock_mode = DB_LOCK_WRITE; + /* Find the record ; delete only deletes exact matches. */ + if ((ret = __qam_position(dbc, + &cp->recno, QAM_WRITE, &exact)) != 0) { + cp->lock = lock; + return (ret); + } + if (!exact) { + ret = DB_NOTFOUND; + goto err1; + } + + pagep = cp->page; + qp = QAM_GET_RECORD(dbp, pagep, cp->indx); + + if (DB_LOGGING(dbc)) { + if (((QUEUE *)dbp->q_internal)->page_ext == 0 + || ((QUEUE *)dbp->q_internal)->re_len == 0) { + if ((ret = + __qam_del_log(dbp->dbenv, + dbc->txn, &LSN(pagep), 0, + dbp->log_fileid, &LSN(pagep), + pagep->pgno, cp->indx, cp->recno)) != 0) + goto err1; + } else { + data.size = ((QUEUE *)dbp->q_internal)->re_len; + data.data = qp->data; + if ((ret = + __qam_delext_log(dbp->dbenv, dbc->txn, + &LSN(pagep), 0, dbp->log_fileid, &LSN(pagep), + pagep->pgno, cp->indx, cp->recno, &data)) != 0) + goto err1; + } + } + + F_CLR(qp, QAM_VALID); + +err1: + if ((t_ret = __qam_fput( + dbp, cp->pgno, cp->page, ret == 0 ? DB_MPOOL_DIRTY : 0)) != 0) + return (ret ? ret : t_ret); + cp->page = NULL; + /* Doing record locking, release the page lock */ + if ((t_ret = __LPUT(dbc, cp->lock)) != 0) { + cp->lock = lock; + return (ret ? ret : t_ret); + } + cp->lock = lock; + return (ret); +} + +/* + * __qam_delete -- + * Queue db->del function. + * + * PUBLIC: int __qam_delete __P((DB *, DB_TXN *, DBT *, u_int32_t)); + */ +int +__qam_delete(dbp, txn, key, flags) + DB *dbp; + DB_TXN *txn; + DBT *key; + u_int32_t flags; +{ + QUEUE_CURSOR *cp; + DBC *dbc; + int ret, t_ret; + + PANIC_CHECK(dbp->dbenv); + DB_CHECK_TXN(dbp, txn); + + /* Check for invalid flags. */ + if ((ret = + __db_delchk(dbp, key, flags, F_ISSET(dbp, DB_AM_RDONLY))) != 0) + return (ret); + + /* Acquire a cursor. */ + if ((ret = dbp->cursor(dbp, txn, &dbc, DB_WRITELOCK)) != 0) + return (ret); + + DEBUG_LWRITE(dbc, txn, "qam_delete", key, NULL, flags); + + cp = (QUEUE_CURSOR *)dbc->internal; + if ((ret = __qam_getno(dbp, key, &cp->recno)) != 0) + goto err; + + ret = __qam_c_del(dbc); + + /* Release the cursor. */ +err: if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0) + ret = t_ret; + + return (ret); +} + +#ifdef DEBUG_WOP +#define QDEBUG +#endif + +/* + * __qam_c_get -- + * Queue cursor->c_get function. + */ +static int +__qam_c_get(dbc, key, data, flags, pgnop) + DBC *dbc; + DBT *key, *data; + u_int32_t flags; + db_pgno_t *pgnop; +{ + DB *dbp; + DB_LOCK lock, pglock, metalock, save_lock; + DBT tmp; + PAGE *pg; + QAMDATA *qp; + QMETA *meta; + QUEUE *t; + QUEUE_CURSOR *cp; + db_indx_t save_indx; + db_lockmode_t lock_mode; + db_pgno_t metapno, save_page; + db_recno_t current, first, save_recno; + qam_position_mode mode; + u_int32_t rec_extent; + int exact, is_first, locked, ret, t_ret, wait, with_delete; + int put_mode, meta_dirty, retrying, skip_again, wrapped; + + cp = (QUEUE_CURSOR *)dbc->internal; + dbp = dbc->dbp; + + PANIC_CHECK(dbp->dbenv); + + wait = 0; + with_delete = 0; + retrying = 0; + rec_extent = 0; + lock_mode = DB_LOCK_READ; + mode = QAM_READ; + put_mode = 0; + t_ret = 0; + *pgnop = 0; + pg = NULL; + skip_again = 0; + + if (F_ISSET(dbc, DBC_RMW)) { + lock_mode = DB_LOCK_WRITE; + mode = QAM_WRITE; + } + + if (flags == DB_CONSUME_WAIT) { + wait = 1; + flags = DB_CONSUME; + } + if (flags == DB_CONSUME) { + DB_CHECK_TXN(dbp, dbc->txn); + with_delete = 1; + flags = DB_FIRST; + lock_mode = DB_LOCK_WRITE; + mode = QAM_CONSUME; + } + + DEBUG_LREAD(dbc, dbc->txn, "qam_c_get", + flags == DB_SET || flags == DB_SET_RANGE ? key : NULL, NULL, flags); + + is_first = 0; + + t = (QUEUE *)dbp->q_internal; + /* get the meta page */ + metapno = t->q_meta; + if ((ret = __db_lget(dbc, 0, metapno, lock_mode, 0, &metalock)) != 0) + return (ret); + locked = 1; + if ((ret = memp_fget(dbp->mpf, &metapno, 0, &meta)) != 0) { + /* We did not fetch it, we can release the lock. */ + (void)__LPUT(dbc, metalock); + return (ret); + } + + first = 0; + + /* Make lint and friends happy. */ + meta_dirty = 0; + + /* Release any previous lock if not in a transaction. */ + if (cp->lock.off != LOCK_INVALID) { + (void)__TLPUT(dbc, cp->lock); + cp->lock.off = LOCK_INVALID; + } + +retry: /* Update the record number. */ + switch (flags) { + case DB_CURRENT: + break; + case DB_NEXT_DUP: + ret = DB_NOTFOUND; + goto err; + /* NOTREACHED */ + case DB_NEXT: + case DB_NEXT_NODUP: + if (cp->recno != RECNO_OOB) { + ++cp->recno; + /* Wrap around, skipping zero. */ + if (cp->recno == RECNO_OOB) + cp->recno++; + break; + } + /* FALLTHROUGH */ + case DB_FIRST: + flags = DB_NEXT; + is_first = 1; + + /* get the first record number */ + cp->recno = first = meta->first_recno; + + break; + case DB_PREV: + case DB_PREV_NODUP: + if (cp->recno != RECNO_OOB) { + if (QAM_BEFORE_FIRST(meta, cp->recno) + || cp->recno == meta->first_recno) { + ret = DB_NOTFOUND; + goto err; + } + --cp->recno; + /* Wrap around, skipping zero. */ + if (cp->recno == RECNO_OOB) + --cp->recno; + break; + } + /* FALLTHROUGH */ + case DB_LAST: + if (meta->first_recno == meta->cur_recno) { + ret = DB_NOTFOUND; + goto err; + } + cp->recno = meta->cur_recno - 1; + if (cp->recno == RECNO_OOB) + cp->recno--; + break; + case DB_GET_BOTH: + case DB_SET: + case DB_SET_RANGE: + if ((ret = __qam_getno(dbp, key, &cp->recno)) != 0) + goto err; + break; + default: + ret = __db_unknown_flag(dbp->dbenv, "__qam_c_get", flags); + goto err; + } + + /* + * Check to see if we are out of data. Current points to + * the first free slot. + */ + if (cp->recno == meta->cur_recno || + QAM_AFTER_CURRENT(meta, cp->recno)) { + ret = DB_NOTFOUND; + pg = NULL; + if (wait) { + flags = DB_FIRST; + /* + * If first is not set, then we skipped a + * locked record, go back and find it. + * If we find a locked record again + * wait for it. + */ + if (first == 0) { + retrying = 1; + goto retry; + } + if (CDB_LOCKING(dbp->dbenv)) { + if ((ret = lock_get(dbp->dbenv, dbc->locker, + DB_LOCK_SWITCH, &dbc->lock_dbt, + DB_LOCK_WAIT, &dbc->mylock)) != 0) + goto err; + if ((ret = lock_get(dbp->dbenv, dbc->locker, + DB_LOCK_UPGRADE, &dbc->lock_dbt, DB_LOCK_WRITE, + &dbc->mylock)) != 0) + goto err; + goto retry; + } + /* + * Wait for someone to update the meta page. + * This will probably mean there is something + * in the queue. We then go back up and + * try again. + */ + if (locked == 0) { + if ((ret = __db_lget( dbc, + 0, metapno, lock_mode, 0, &metalock)) != 0) + goto err; + locked = 1; + if (cp->recno != RECNO_OOB && + !QAM_AFTER_CURRENT(meta, cp->recno)) + goto retry; + } + if ((ret = __db_lget(dbc, 0, metapno, + DB_LOCK_WAIT, DB_LOCK_SWITCH, &metalock)) != 0) + goto err; + if ((ret = lock_get(dbp->dbenv, dbc->locker, + DB_LOCK_UPGRADE, &dbc->lock_dbt, DB_LOCK_WRITE, + &metalock)) != 0) + goto err; + locked = 1; + goto retry; + } + + goto err; + } + + /* Don't hold the meta page long term. */ + if (locked) { + if ((ret = __LPUT(dbc, metalock)) != 0) + goto err; + locked = 0; + } + + /* Lock the record. */ + if ((ret = __db_lget(dbc, 0, cp->recno, lock_mode, + (with_delete && !retrying) ? + DB_LOCK_NOWAIT | DB_LOCK_RECORD : DB_LOCK_RECORD, + &lock)) == DB_LOCK_NOTGRANTED && with_delete) { +#ifdef QDEBUG + __db_logmsg(dbp->dbenv, + dbc->txn, "Queue S", 0, "%x %d %d %d", + dbc->locker, cp->recno, first, meta->first_recno); +#endif + first = 0; + goto retry; + } + + if (ret != 0) + goto err; + + /* + * In the DB_FIRST or DB_LAST cases we must wait and then start over + * since the first/last may have moved while we slept. + * We release our locks and try again. + */ + if ((!with_delete && is_first) || flags == DB_LAST) { + if ((ret = + __db_lget(dbc, 0, metapno, lock_mode, 0, &metalock)) != 0) + goto err; + if (cp->recno != + (is_first ? meta->first_recno : (meta->cur_recno - 1))) { + __LPUT(dbc, lock); + if (is_first) + flags = DB_FIRST; + locked = 1; + goto retry; + } + /* Don't hold the meta page long term. */ + if ((ret = __LPUT(dbc, metalock)) != 0) + goto err; + } + + /* Position the cursor on the record. */ + if ((ret = __qam_position(dbc, &cp->recno, mode, &exact)) != 0) { + /* We cannot get the page, release the record lock. */ + (void)__LPUT(dbc, lock); + goto err; + } + + pg = cp->page; + pglock = cp->lock; + cp->lock = lock; + cp->lock_mode = lock_mode; + + if (!exact) { + if (flags == DB_NEXT || flags == DB_NEXT_NODUP + || flags == DB_PREV || flags == DB_PREV_NODUP + || flags == DB_LAST) { + /* Release locks and try again. */ + if (pg != NULL) + (void)__qam_fput(dbp, cp->pgno, pg, 0); + cp->page = pg = NULL; + (void)__LPUT(dbc, pglock); + (void)__LPUT(dbc, cp->lock); + if (flags == DB_LAST) + flags = DB_PREV; + if (!with_delete) + is_first = 0; + retrying = 0; + goto retry; + } + /* this is for the SET and SET_RANGE cases */ + ret = DB_KEYEMPTY; + goto err1; + } + + /* Return the key if the user didn't give us one. */ + if (key != NULL && flags != DB_SET && flags != DB_GET_BOTH && + (ret = __db_retcopy(dbp, key, &cp->recno, sizeof(cp->recno), + &dbc->rkey.data, &dbc->rkey.ulen)) != 0) + goto err1; + + if (key != NULL) + F_SET(key, DB_DBT_ISSET); + + qp = QAM_GET_RECORD(dbp, pg, cp->indx); + + /* Return the data item. */ + if (flags == DB_GET_BOTH) { + /* + * Need to compare + */ + tmp.data = qp->data; + tmp.size = t->re_len; + if ((ret = __bam_defcmp(dbp, data, &tmp)) != 0) { + ret = DB_NOTFOUND; + goto err1; + } + } + if (data != NULL && (ret = __db_retcopy(dbp, data, + qp->data, t->re_len, &dbc->rdata.data, &dbc->rdata.ulen)) != 0) + goto err1; + + if (data != NULL) + F_SET(data, DB_DBT_ISSET); + + /* Finally, if we are doing DB_CONSUME mark the record. */ + if (with_delete) { + if (DB_LOGGING(dbc)) { + if (t->page_ext == 0 || t->re_len == 0) { + if ((ret = __qam_del_log(dbp->dbenv, dbc->txn, + &LSN(pg), 0, dbp->log_fileid, &LSN(pg), + pg->pgno, cp->indx, cp->recno)) != 0) + goto err1; + } else { + tmp.data = qp->data; + tmp.size = t->re_len; + if ((ret = + __qam_delext_log(dbp->dbenv, dbc->txn, + &LSN(pg), 0, dbp->log_fileid, &LSN(pg), + pg->pgno, cp->indx, cp->recno, &tmp)) != 0) + goto err1; + } + } + + F_CLR(qp, QAM_VALID); + put_mode = DB_MPOOL_DIRTY; + + if ((ret = __LPUT(dbc, pglock)) != 0) + goto err; + + /* + * Now we need to update the metapage + * first pointer. If we have deleted + * the record that is pointed to by + * first_recno then we move it as far + * forward as we can without blocking. + * The metapage lock must be held for + * the whole scan otherwise someone could + * do a random insert behind where we are + * looking. + */ + + if (locked == 0 && (ret = __db_lget( + dbc, 0, metapno, lock_mode, 0, &metalock)) != 0) + goto err1; + locked = 1; +#ifdef QDEBUG + __db_logmsg(dbp->dbenv, + dbc->txn, "Queue D", 0, "%x %d %d %d", + dbc->locker, cp->recno, first, meta->first_recno); +#endif + /* + * See if we deleted the "first" record. If + * first is zero then we skipped something, + * see if first_recno has been move passed + * that to the record that we deleted. + */ + if (first == 0) + first = cp->recno; + if (first != meta->first_recno) + goto done; + + save_page = cp->pgno; + save_indx = cp->indx; + save_recno = cp->recno; + save_lock = cp->lock; + + /* + * If we skipped some deleted records, we need to + * reposition on the first one. Get a lock + * in case someone is trying to put it back. + */ + if (first != cp->recno) { + ret = __db_lget(dbc, 0, first, DB_LOCK_READ, + DB_LOCK_NOWAIT | DB_LOCK_RECORD, &lock); + if (ret == DB_LOCK_NOTGRANTED) { + ret = 0; + goto done; + } + if (ret != 0) + goto err1; + if ((ret = + __qam_fput(dbp, cp->pgno, cp->page, put_mode)) != 0) + goto err1; + cp->page = NULL; + put_mode = 0; + if ((ret = __qam_position(dbc, + &first, QAM_READ, &exact)) != 0 || exact != 0) { + (void)__LPUT(dbc, lock); + goto err1; + } + if ((ret =__LPUT(dbc, lock)) != 0) + goto err1; + if ((ret = __LPUT(dbc, cp->lock)) != 0) + goto err1; + } + + current = meta->cur_recno; + wrapped = 0; + if (first > current) + wrapped = 1; + rec_extent = meta->page_ext * meta->rec_page; + + /* Loop until we find a record or hit current */ + for (;;) { + /* + * Check to see if we are moving off the extent + * and remove the extent. + * If we are moving off a page we need to + * get rid of the buffer. + * Wait for the lagging readers to move off the + * page. + */ + if (rec_extent != 0 + && ((exact = first % rec_extent == 0) + || first % meta->rec_page == 0 + || first == UINT32_T_MAX)) { + if (exact == 1 && (ret = __db_lget(dbc, + 0, cp->pgno, DB_LOCK_WRITE, 0, &cp->lock)) != 0) + break; + +#ifdef QDEBUG + __db_logmsg(dbp->dbenv, + dbc->txn, "Queue R", 0, "%x %d %d %d", + dbc->locker, cp->pgno, first, meta->first_recno); +#endif + put_mode |= DB_MPOOL_DISCARD; + if ((ret = __qam_fput(dbp, + cp->pgno, cp->page, put_mode)) != 0) + break; + cp->page = NULL; + + if (exact == 1) { + ret = __qam_fremove(dbp, cp->pgno); + t_ret = __LPUT(dbc, cp->lock); + } + if (ret != 0) + break; + if (t_ret != 0) { + ret = t_ret; + break; + } + } else if ((ret = + __qam_fput(dbp, cp->pgno, cp->page, put_mode)) != 0) + break; + cp->page = NULL; + first++; + if (first == RECNO_OOB) { + wrapped = 0; + first++; + } + + /* + * LOOP EXIT when we come move to the current + * pointer. + */ + if (!wrapped && first >= current) + break; + + ret = __db_lget(dbc, 0, first, DB_LOCK_READ, + DB_LOCK_NOWAIT | DB_LOCK_RECORD, &lock); + if (ret == DB_LOCK_NOTGRANTED) { + ret = 0; + break; + } + if (ret != 0) + break; + + if ((ret = __qam_position(dbc, + &first, QAM_READ, &exact)) != 0) { + (void)__LPUT(dbc, lock); + break; + } + put_mode = 0; + if ((ret =__LPUT(dbc, lock)) != 0 + || (ret = __LPUT(dbc, cp->lock)) != 0 ||exact) { + if ((t_ret = __qam_fput(dbp, cp->pgno, + cp->page, put_mode)) != 0 && ret == 0) + ret = t_ret; + cp->page = NULL; + break; + } + } + + cp->pgno = save_page; + cp->indx = save_indx; + cp->recno = save_recno; + cp->lock = save_lock; + + /* + * We have advanced as far as we can. + * Advance first_recno to this point. + */ + if (meta->first_recno != first) { +#ifdef QDEBUG + __db_logmsg(dbp->dbenv, dbc->txn, "Queue M", + 0, "%x %d %d %d", dbc->locker, cp->recno, + first, meta->first_recno); +#endif + if (DB_LOGGING(dbc)) + if ((ret = + __qam_incfirst_log(dbp->dbenv, + dbc->txn, &meta->dbmeta.lsn, 0, + dbp->log_fileid, cp->recno)) != 0) + goto err; + meta->first_recno = first; + meta_dirty = 1; + } + } + +done: +err1: if (cp->page != NULL) { + t_ret = __qam_fput(dbp, cp->pgno, cp->page, put_mode); + + if (!ret) + ret = t_ret; + /* Doing record locking, release the page lock */ + t_ret = __LPUT(dbc, pglock); + cp->page = NULL; + } + +err: if (!ret) + ret = t_ret; + if (meta) { + + /* release the meta page */ + t_ret = memp_fput( + dbp->mpf, meta, meta_dirty ? DB_MPOOL_DIRTY : 0); + + if (!ret) + ret = t_ret; + + /* Don't hold the meta page long term. */ + if (locked) + t_ret = __LPUT(dbc, metalock); + } + DB_ASSERT(metalock.off == LOCK_INVALID); + + /* + * There is no need to keep the record locked if we are + * not in a transaction. + */ + if (t_ret == 0) + t_ret = __TLPUT(dbc, cp->lock); + + return (ret ? ret : t_ret); +} + +/* + * __qam_c_close -- + * Close down the cursor from a single use. + */ +static int +__qam_c_close(dbc, root_pgno, rmroot) + DBC *dbc; + db_pgno_t root_pgno; + int *rmroot; +{ + QUEUE_CURSOR *cp; + + COMPQUIET(root_pgno, 0); + COMPQUIET(rmroot, NULL); + + cp = (QUEUE_CURSOR *)dbc->internal; + + /* Discard any locks not acquired inside of a transaction. */ + if (cp->lock.off != LOCK_INVALID) { + (void)__TLPUT(dbc, cp->lock); + cp->lock.off = LOCK_INVALID; + } + + cp->page = NULL; + cp->pgno = PGNO_INVALID; + cp->indx = 0; + cp->lock.off = LOCK_INVALID; + cp->lock_mode = DB_LOCK_NG; + cp->recno = RECNO_OOB; + cp->flags = 0; + + return (0); +} + +/* + * __qam_c_dup -- + * Duplicate a queue cursor, such that the new one holds appropriate + * locks for the position of the original. + * + * PUBLIC: int __qam_c_dup __P((DBC *, DBC *)); + */ +int +__qam_c_dup(orig_dbc, new_dbc) + DBC *orig_dbc, *new_dbc; +{ + QUEUE_CURSOR *orig, *new; + + orig = (QUEUE_CURSOR *)orig_dbc->internal; + new = (QUEUE_CURSOR *)new_dbc->internal; + + new->recno = orig->recno; + + /* reget the long term lock if we are not in a xact */ + if (orig_dbc->txn != NULL || + !STD_LOCKING(orig_dbc) || orig->lock.off == LOCK_INVALID) + return (0); + + return (__db_lget(new_dbc, + 0, new->recno, new->lock_mode, DB_LOCK_RECORD, &new->lock)); +} + +/* + * __qam_c_init + * + * PUBLIC: int __qam_c_init __P((DBC *)); + */ +int +__qam_c_init(dbc) + DBC *dbc; +{ + QUEUE_CURSOR *cp; + DB *dbp; + int ret; + + dbp = dbc->dbp; + + /* Allocate the internal structure. */ + cp = (QUEUE_CURSOR *)dbc->internal; + if (cp == NULL) { + if ((ret = + __os_calloc(dbp->dbenv, 1, sizeof(QUEUE_CURSOR), &cp)) != 0) + return (ret); + dbc->internal = (DBC_INTERNAL *)cp; + } + + /* Initialize methods. */ + dbc->c_close = __db_c_close; + dbc->c_count = __db_c_count; + dbc->c_del = __db_c_del; + dbc->c_dup = __db_c_dup; + dbc->c_get = __db_c_get; + dbc->c_put = __db_c_put; + dbc->c_am_close = __qam_c_close; + dbc->c_am_del = __qam_c_del; + dbc->c_am_destroy = __qam_c_destroy; + dbc->c_am_get = __qam_c_get; + dbc->c_am_put = __qam_c_put; + dbc->c_am_writelock = NULL; + + return (0); +} + +/* + * __qam_c_destroy -- + * Close a single cursor -- internal version. + */ +static int +__qam_c_destroy(dbc) + DBC *dbc; +{ + /* Discard the structures. */ + __os_free(dbc->internal, sizeof(QUEUE_CURSOR)); + + return (0); +} + +/* + * __qam_getno -- + * Check the user's record number. + */ +static int +__qam_getno(dbp, key, rep) + DB *dbp; + const DBT *key; + db_recno_t *rep; +{ + if ((*rep = *(db_recno_t *)key->data) == 0) { + __db_err(dbp->dbenv, "illegal record number of 0"); + return (EINVAL); + } + return (0); +} diff --git a/db/qam/qam.src b/db/qam/qam.src new file mode 100644 index 000000000..507d7a652 --- /dev/null +++ b/db/qam/qam.src @@ -0,0 +1,124 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: qam.src,v 11.15 2001/01/16 20:10:55 ubell Exp $ + */ + +PREFIX qam + +INCLUDE #include "db_config.h" +INCLUDE +INCLUDE #ifndef NO_SYSTEM_INCLUDES +INCLUDE #include +INCLUDE +INCLUDE #include +INCLUDE #include +INCLUDE #include +INCLUDE #endif +INCLUDE +INCLUDE #include "db_int.h" +INCLUDE #include "db_page.h" +INCLUDE #include "db_dispatch.h" +INCLUDE #include "db_am.h" +INCLUDE #include "qam.h" +INCLUDE #include "txn.h" +INCLUDE + +/* + * inc + * Used when we increment a record number. These do not actually + * tell you what record number you got, just that you incremented + * the record number. These operations are never undone. + */ +BEGIN inc 76 +ARG fileid int32_t ld +POINTER lsn DB_LSN * lu +END + +/* + * incfirst + * Used when we increment first_recno. + */ +BEGIN incfirst 77 +ARG fileid int32_t ld +ARG recno db_recno_t lu +END + +/* + * mvptr + * Used when we change one or both of cur_recno and first_recno. + */ +BEGIN mvptr 78 +ARG opcode u_int32_t lu +ARG fileid int32_t ld +ARG old_first db_recno_t lu +ARG new_first db_recno_t lu +ARG old_cur db_recno_t lu +ARG new_cur db_recno_t lu +POINTER metalsn DB_LSN * lu +END + +/* + * del + * Used when we delete a record. + * recno is the record that is being deleted. + */ +BEGIN del 79 +ARG fileid int32_t ld +POINTER lsn DB_LSN * lu +ARG pgno db_pgno_t lu +ARG indx u_int32_t lu +ARG recno db_recno_t lu +END + +/* + * add + * Used when we put a record on a page. + * recno is the record being added. + * data is the record itself. + */ +BEGIN add 80 +ARG fileid int32_t ld +POINTER lsn DB_LSN * lu +ARG pgno db_pgno_t lu +ARG indx u_int32_t lu +ARG recno db_recno_t lu +DBT data DBT s +ARG vflag u_int32_t lu +DBT olddata DBT s +END + +/* + * delete + * Used when we remove a Queue extent file. + */ +BEGIN delete 81 +DBT name DBT s +POINTER lsn DB_LSN * lu +END + +/* + * rename + * Used when we rename a Queue extent file. + */ +BEGIN rename 82 +DBT name DBT s +DBT newname DBT s +END + +/* + * delext + * Used when we delete a record in extent based queue. + * recno is the record that is being deleted. + */ +BEGIN delext 83 +ARG fileid int32_t ld +POINTER lsn DB_LSN * lu +ARG pgno db_pgno_t lu +ARG indx u_int32_t lu +ARG recno db_recno_t lu +DBT data DBT s +END diff --git a/db/qam/qam_auto.c b/db/qam/qam_auto.c new file mode 100644 index 000000000..cfdba3195 --- /dev/null +++ b/db/qam/qam_auto.c @@ -0,0 +1,1282 @@ +/* Do not edit: automatically built by gen_rec.awk. */ +#include "db_config.h" + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_dispatch.h" +#include "db_am.h" +#include "qam.h" +#include "txn.h" + +int +__qam_inc_log(dbenv, txnid, ret_lsnp, flags, + fileid, lsn) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + int32_t fileid; + DB_LSN * lsn; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_qam_inc; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(fileid) + + sizeof(*lsn); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &fileid, sizeof(fileid)); + bp += sizeof(fileid); + if (lsn != NULL) + memcpy(bp, lsn, sizeof(*lsn)); + else + memset(bp, 0, sizeof(*lsn)); + bp += sizeof(*lsn); + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__qam_inc_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __qam_inc_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __qam_inc_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]qam_inc: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tlsn: [%lu][%lu]\n", + (u_long)argp->lsn.file, (u_long)argp->lsn.offset); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__qam_inc_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __qam_inc_args **argpp; +{ + __qam_inc_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__qam_inc_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->lsn, bp, sizeof(argp->lsn)); + bp += sizeof(argp->lsn); + *argpp = argp; + return (0); +} + +int +__qam_incfirst_log(dbenv, txnid, ret_lsnp, flags, + fileid, recno) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + int32_t fileid; + db_recno_t recno; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_qam_incfirst; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(fileid) + + sizeof(recno); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &fileid, sizeof(fileid)); + bp += sizeof(fileid); + memcpy(bp, &recno, sizeof(recno)); + bp += sizeof(recno); + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__qam_incfirst_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __qam_incfirst_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __qam_incfirst_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]qam_incfirst: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\trecno: %lu\n", (u_long)argp->recno); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__qam_incfirst_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __qam_incfirst_args **argpp; +{ + __qam_incfirst_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__qam_incfirst_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->recno, bp, sizeof(argp->recno)); + bp += sizeof(argp->recno); + *argpp = argp; + return (0); +} + +int +__qam_mvptr_log(dbenv, txnid, ret_lsnp, flags, + opcode, fileid, old_first, new_first, old_cur, new_cur, + metalsn) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + u_int32_t opcode; + int32_t fileid; + db_recno_t old_first; + db_recno_t new_first; + db_recno_t old_cur; + db_recno_t new_cur; + DB_LSN * metalsn; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_qam_mvptr; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(opcode) + + sizeof(fileid) + + sizeof(old_first) + + sizeof(new_first) + + sizeof(old_cur) + + sizeof(new_cur) + + sizeof(*metalsn); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &opcode, sizeof(opcode)); + bp += sizeof(opcode); + memcpy(bp, &fileid, sizeof(fileid)); + bp += sizeof(fileid); + memcpy(bp, &old_first, sizeof(old_first)); + bp += sizeof(old_first); + memcpy(bp, &new_first, sizeof(new_first)); + bp += sizeof(new_first); + memcpy(bp, &old_cur, sizeof(old_cur)); + bp += sizeof(old_cur); + memcpy(bp, &new_cur, sizeof(new_cur)); + bp += sizeof(new_cur); + if (metalsn != NULL) + memcpy(bp, metalsn, sizeof(*metalsn)); + else + memset(bp, 0, sizeof(*metalsn)); + bp += sizeof(*metalsn); + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__qam_mvptr_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __qam_mvptr_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __qam_mvptr_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]qam_mvptr: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\topcode: %lu\n", (u_long)argp->opcode); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\told_first: %lu\n", (u_long)argp->old_first); + printf("\tnew_first: %lu\n", (u_long)argp->new_first); + printf("\told_cur: %lu\n", (u_long)argp->old_cur); + printf("\tnew_cur: %lu\n", (u_long)argp->new_cur); + printf("\tmetalsn: [%lu][%lu]\n", + (u_long)argp->metalsn.file, (u_long)argp->metalsn.offset); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__qam_mvptr_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __qam_mvptr_args **argpp; +{ + __qam_mvptr_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__qam_mvptr_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->opcode, bp, sizeof(argp->opcode)); + bp += sizeof(argp->opcode); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->old_first, bp, sizeof(argp->old_first)); + bp += sizeof(argp->old_first); + memcpy(&argp->new_first, bp, sizeof(argp->new_first)); + bp += sizeof(argp->new_first); + memcpy(&argp->old_cur, bp, sizeof(argp->old_cur)); + bp += sizeof(argp->old_cur); + memcpy(&argp->new_cur, bp, sizeof(argp->new_cur)); + bp += sizeof(argp->new_cur); + memcpy(&argp->metalsn, bp, sizeof(argp->metalsn)); + bp += sizeof(argp->metalsn); + *argpp = argp; + return (0); +} + +int +__qam_del_log(dbenv, txnid, ret_lsnp, flags, + fileid, lsn, pgno, indx, recno) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + int32_t fileid; + DB_LSN * lsn; + db_pgno_t pgno; + u_int32_t indx; + db_recno_t recno; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_qam_del; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(fileid) + + sizeof(*lsn) + + sizeof(pgno) + + sizeof(indx) + + sizeof(recno); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &fileid, sizeof(fileid)); + bp += sizeof(fileid); + if (lsn != NULL) + memcpy(bp, lsn, sizeof(*lsn)); + else + memset(bp, 0, sizeof(*lsn)); + bp += sizeof(*lsn); + memcpy(bp, &pgno, sizeof(pgno)); + bp += sizeof(pgno); + memcpy(bp, &indx, sizeof(indx)); + bp += sizeof(indx); + memcpy(bp, &recno, sizeof(recno)); + bp += sizeof(recno); + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__qam_del_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __qam_del_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __qam_del_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]qam_del: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tlsn: [%lu][%lu]\n", + (u_long)argp->lsn.file, (u_long)argp->lsn.offset); + printf("\tpgno: %lu\n", (u_long)argp->pgno); + printf("\tindx: %lu\n", (u_long)argp->indx); + printf("\trecno: %lu\n", (u_long)argp->recno); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__qam_del_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __qam_del_args **argpp; +{ + __qam_del_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__qam_del_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->lsn, bp, sizeof(argp->lsn)); + bp += sizeof(argp->lsn); + memcpy(&argp->pgno, bp, sizeof(argp->pgno)); + bp += sizeof(argp->pgno); + memcpy(&argp->indx, bp, sizeof(argp->indx)); + bp += sizeof(argp->indx); + memcpy(&argp->recno, bp, sizeof(argp->recno)); + bp += sizeof(argp->recno); + *argpp = argp; + return (0); +} + +int +__qam_add_log(dbenv, txnid, ret_lsnp, flags, + fileid, lsn, pgno, indx, recno, data, + vflag, olddata) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + int32_t fileid; + DB_LSN * lsn; + db_pgno_t pgno; + u_int32_t indx; + db_recno_t recno; + const DBT *data; + u_int32_t vflag; + const DBT *olddata; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t zero; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_qam_add; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(fileid) + + sizeof(*lsn) + + sizeof(pgno) + + sizeof(indx) + + sizeof(recno) + + sizeof(u_int32_t) + (data == NULL ? 0 : data->size) + + sizeof(vflag) + + sizeof(u_int32_t) + (olddata == NULL ? 0 : olddata->size); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &fileid, sizeof(fileid)); + bp += sizeof(fileid); + if (lsn != NULL) + memcpy(bp, lsn, sizeof(*lsn)); + else + memset(bp, 0, sizeof(*lsn)); + bp += sizeof(*lsn); + memcpy(bp, &pgno, sizeof(pgno)); + bp += sizeof(pgno); + memcpy(bp, &indx, sizeof(indx)); + bp += sizeof(indx); + memcpy(bp, &recno, sizeof(recno)); + bp += sizeof(recno); + if (data == NULL) { + zero = 0; + memcpy(bp, &zero, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + } else { + memcpy(bp, &data->size, sizeof(data->size)); + bp += sizeof(data->size); + memcpy(bp, data->data, data->size); + bp += data->size; + } + memcpy(bp, &vflag, sizeof(vflag)); + bp += sizeof(vflag); + if (olddata == NULL) { + zero = 0; + memcpy(bp, &zero, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + } else { + memcpy(bp, &olddata->size, sizeof(olddata->size)); + bp += sizeof(olddata->size); + memcpy(bp, olddata->data, olddata->size); + bp += olddata->size; + } + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__qam_add_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __qam_add_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __qam_add_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]qam_add: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tlsn: [%lu][%lu]\n", + (u_long)argp->lsn.file, (u_long)argp->lsn.offset); + printf("\tpgno: %lu\n", (u_long)argp->pgno); + printf("\tindx: %lu\n", (u_long)argp->indx); + printf("\trecno: %lu\n", (u_long)argp->recno); + printf("\tdata: "); + for (i = 0; i < argp->data.size; i++) { + ch = ((u_int8_t *)argp->data.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\tvflag: %lu\n", (u_long)argp->vflag); + printf("\tolddata: "); + for (i = 0; i < argp->olddata.size; i++) { + ch = ((u_int8_t *)argp->olddata.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__qam_add_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __qam_add_args **argpp; +{ + __qam_add_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__qam_add_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->lsn, bp, sizeof(argp->lsn)); + bp += sizeof(argp->lsn); + memcpy(&argp->pgno, bp, sizeof(argp->pgno)); + bp += sizeof(argp->pgno); + memcpy(&argp->indx, bp, sizeof(argp->indx)); + bp += sizeof(argp->indx); + memcpy(&argp->recno, bp, sizeof(argp->recno)); + bp += sizeof(argp->recno); + memset(&argp->data, 0, sizeof(argp->data)); + memcpy(&argp->data.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->data.data = bp; + bp += argp->data.size; + memcpy(&argp->vflag, bp, sizeof(argp->vflag)); + bp += sizeof(argp->vflag); + memset(&argp->olddata, 0, sizeof(argp->olddata)); + memcpy(&argp->olddata.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->olddata.data = bp; + bp += argp->olddata.size; + *argpp = argp; + return (0); +} + +int +__qam_delete_log(dbenv, txnid, ret_lsnp, flags, + name, lsn) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + const DBT *name; + DB_LSN * lsn; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t zero; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_qam_delete; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(u_int32_t) + (name == NULL ? 0 : name->size) + + sizeof(*lsn); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + if (name == NULL) { + zero = 0; + memcpy(bp, &zero, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + } else { + memcpy(bp, &name->size, sizeof(name->size)); + bp += sizeof(name->size); + memcpy(bp, name->data, name->size); + bp += name->size; + } + if (lsn != NULL) + memcpy(bp, lsn, sizeof(*lsn)); + else + memset(bp, 0, sizeof(*lsn)); + bp += sizeof(*lsn); + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__qam_delete_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __qam_delete_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __qam_delete_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]qam_delete: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tname: "); + for (i = 0; i < argp->name.size; i++) { + ch = ((u_int8_t *)argp->name.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\tlsn: [%lu][%lu]\n", + (u_long)argp->lsn.file, (u_long)argp->lsn.offset); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__qam_delete_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __qam_delete_args **argpp; +{ + __qam_delete_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__qam_delete_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memset(&argp->name, 0, sizeof(argp->name)); + memcpy(&argp->name.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->name.data = bp; + bp += argp->name.size; + memcpy(&argp->lsn, bp, sizeof(argp->lsn)); + bp += sizeof(argp->lsn); + *argpp = argp; + return (0); +} + +int +__qam_rename_log(dbenv, txnid, ret_lsnp, flags, + name, newname) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + const DBT *name; + const DBT *newname; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t zero; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_qam_rename; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(u_int32_t) + (name == NULL ? 0 : name->size) + + sizeof(u_int32_t) + (newname == NULL ? 0 : newname->size); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + if (name == NULL) { + zero = 0; + memcpy(bp, &zero, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + } else { + memcpy(bp, &name->size, sizeof(name->size)); + bp += sizeof(name->size); + memcpy(bp, name->data, name->size); + bp += name->size; + } + if (newname == NULL) { + zero = 0; + memcpy(bp, &zero, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + } else { + memcpy(bp, &newname->size, sizeof(newname->size)); + bp += sizeof(newname->size); + memcpy(bp, newname->data, newname->size); + bp += newname->size; + } + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__qam_rename_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __qam_rename_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __qam_rename_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]qam_rename: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tname: "); + for (i = 0; i < argp->name.size; i++) { + ch = ((u_int8_t *)argp->name.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\tnewname: "); + for (i = 0; i < argp->newname.size; i++) { + ch = ((u_int8_t *)argp->newname.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__qam_rename_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __qam_rename_args **argpp; +{ + __qam_rename_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__qam_rename_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memset(&argp->name, 0, sizeof(argp->name)); + memcpy(&argp->name.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->name.data = bp; + bp += argp->name.size; + memset(&argp->newname, 0, sizeof(argp->newname)); + memcpy(&argp->newname.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->newname.data = bp; + bp += argp->newname.size; + *argpp = argp; + return (0); +} + +int +__qam_delext_log(dbenv, txnid, ret_lsnp, flags, + fileid, lsn, pgno, indx, recno, data) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + int32_t fileid; + DB_LSN * lsn; + db_pgno_t pgno; + u_int32_t indx; + db_recno_t recno; + const DBT *data; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t zero; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_qam_delext; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(fileid) + + sizeof(*lsn) + + sizeof(pgno) + + sizeof(indx) + + sizeof(recno) + + sizeof(u_int32_t) + (data == NULL ? 0 : data->size); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &fileid, sizeof(fileid)); + bp += sizeof(fileid); + if (lsn != NULL) + memcpy(bp, lsn, sizeof(*lsn)); + else + memset(bp, 0, sizeof(*lsn)); + bp += sizeof(*lsn); + memcpy(bp, &pgno, sizeof(pgno)); + bp += sizeof(pgno); + memcpy(bp, &indx, sizeof(indx)); + bp += sizeof(indx); + memcpy(bp, &recno, sizeof(recno)); + bp += sizeof(recno); + if (data == NULL) { + zero = 0; + memcpy(bp, &zero, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + } else { + memcpy(bp, &data->size, sizeof(data->size)); + bp += sizeof(data->size); + memcpy(bp, data->data, data->size); + bp += data->size; + } + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__qam_delext_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __qam_delext_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __qam_delext_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]qam_delext: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tfileid: %ld\n", (long)argp->fileid); + printf("\tlsn: [%lu][%lu]\n", + (u_long)argp->lsn.file, (u_long)argp->lsn.offset); + printf("\tpgno: %lu\n", (u_long)argp->pgno); + printf("\tindx: %lu\n", (u_long)argp->indx); + printf("\trecno: %lu\n", (u_long)argp->recno); + printf("\tdata: "); + for (i = 0; i < argp->data.size; i++) { + ch = ((u_int8_t *)argp->data.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__qam_delext_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __qam_delext_args **argpp; +{ + __qam_delext_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__qam_delext_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->fileid, bp, sizeof(argp->fileid)); + bp += sizeof(argp->fileid); + memcpy(&argp->lsn, bp, sizeof(argp->lsn)); + bp += sizeof(argp->lsn); + memcpy(&argp->pgno, bp, sizeof(argp->pgno)); + bp += sizeof(argp->pgno); + memcpy(&argp->indx, bp, sizeof(argp->indx)); + bp += sizeof(argp->indx); + memcpy(&argp->recno, bp, sizeof(argp->recno)); + bp += sizeof(argp->recno); + memset(&argp->data, 0, sizeof(argp->data)); + memcpy(&argp->data.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->data.data = bp; + bp += argp->data.size; + *argpp = argp; + return (0); +} + +int +__qam_init_print(dbenv) + DB_ENV *dbenv; +{ + int ret; + + if ((ret = __db_add_recovery(dbenv, + __qam_inc_print, DB_qam_inc)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __qam_incfirst_print, DB_qam_incfirst)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __qam_mvptr_print, DB_qam_mvptr)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __qam_del_print, DB_qam_del)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __qam_add_print, DB_qam_add)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __qam_delete_print, DB_qam_delete)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __qam_rename_print, DB_qam_rename)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __qam_delext_print, DB_qam_delext)) != 0) + return (ret); + return (0); +} + +int +__qam_init_recover(dbenv) + DB_ENV *dbenv; +{ + int ret; + + if ((ret = __db_add_recovery(dbenv, + __qam_inc_recover, DB_qam_inc)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __qam_incfirst_recover, DB_qam_incfirst)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __qam_mvptr_recover, DB_qam_mvptr)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __qam_del_recover, DB_qam_del)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __qam_add_recover, DB_qam_add)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __qam_delete_recover, DB_qam_delete)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __qam_rename_recover, DB_qam_rename)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __qam_delext_recover, DB_qam_delext)) != 0) + return (ret); + return (0); +} + diff --git a/db/qam/qam_conv.c b/db/qam/qam_conv.c new file mode 100644 index 000000000..2eb1c7227 --- /dev/null +++ b/db/qam/qam_conv.c @@ -0,0 +1,83 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: qam_conv.c,v 11.6 2000/11/16 23:40:57 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "qam.h" +#include "db_swap.h" +#include "db_am.h" + +/* + * __qam_mswap -- + * Swap the bytes on the queue metadata page. + * + * PUBLIC: int __qam_mswap __P((PAGE *)); + */ +int +__qam_mswap(pg) + PAGE *pg; +{ + u_int8_t *p; + + __db_metaswap(pg); + + p = (u_int8_t *)pg + sizeof(DBMETA); + + SWAP32(p); /* first_recno */ + SWAP32(p); /* cur_recno */ + SWAP32(p); /* re_len */ + SWAP32(p); /* re_pad */ + SWAP32(p); /* rec_page */ + SWAP32(p); /* page_ext */ + + return (0); +} + +/* + * __qam_pgin_out -- + * Convert host-specific page layout to/from the host-independent format + * stored on disk. + * We only need to fix up a few fields in the header + * + * PUBLIC: int __qam_pgin_out __P((DB_ENV *, db_pgno_t, void *, DBT *)); + */ +int +__qam_pgin_out(dbenv, pg, pp, cookie) + DB_ENV *dbenv; + db_pgno_t pg; + void *pp; + DBT *cookie; +{ + DB_PGINFO *pginfo; + QPAGE *h; + + COMPQUIET(pg, 0); + COMPQUIET(dbenv, NULL); + pginfo = (DB_PGINFO *)cookie->data; + if (!pginfo->needswap) + return (0); + + h = pp; + if (h->type == P_QAMMETA) + return (__qam_mswap(pp)); + + M_32_SWAP(h->lsn.file); + M_32_SWAP(h->lsn.offset); + M_32_SWAP(h->pgno); + + return (0); +} diff --git a/db/qam/qam_files.c b/db/qam/qam_files.c new file mode 100644 index 000000000..e53a3bf24 --- /dev/null +++ b/db/qam/qam_files.c @@ -0,0 +1,503 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: qam_files.c,v 1.16 2001/01/19 18:01:59 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_shash.h" +#include "db_am.h" +#include "lock.h" +#include "btree.h" +#include "qam.h" +#include "mp.h" + +/* + * __qam_fprobe -- calcluate and open extent + * + * Calculate which extent the page is in, open and create + * if necessary. + * + * PUBLIC: int __qam_fprobe __P((DB *, db_pgno_t, void *, qam_probe_mode, int)); + */ + +int +__qam_fprobe(dbp, pgno, addrp, mode, flags) + DB *dbp; + db_pgno_t pgno; + void *addrp; + qam_probe_mode mode; + int flags; +{ + DB_ENV *dbenv; + DB_MPOOLFILE *mpf; + MPFARRAY *array; + QUEUE *qp; + u_int32_t extid, maxext; + char buf[256]; + int numext, offset, oldext, openflags, ret; + + qp = (QUEUE *)dbp->q_internal; + if (qp->page_ext == 0) { + mpf = dbp->mpf; + if (mode == QAM_PROBE_GET) + return (memp_fget(mpf, &pgno, flags, addrp)); + return (memp_fput(mpf, addrp, flags)); + } + + dbenv = dbp->dbenv; + mpf = NULL; + ret = 0; + + /* + * Need to lock long enough to find the mpf or create the file. + * The file cannot go away because we must have a record locked + * in that file. + */ + MUTEX_THREAD_LOCK(dbenv, dbp->mutexp); + extid = (pgno - 1) / qp->page_ext; + + /* Array1 will always be in use if array2 is in use. */ + array = &qp->array1; + if (array->n_extent == 0) { + /* Start with 4 extents */ + oldext = 0; + array->n_extent = 4; + array->low_extent = extid; + offset = 0; + numext = 0; + goto alloc; + } + + offset = extid - qp->array1.low_extent; + if (qp->array2.n_extent != 0 && + abs(offset) > abs(extid - qp->array2.low_extent)) { + array = &qp->array2; + offset = extid - array->low_extent; + } + + /* + * Check to see if the requested extent is outside the range of + * extents in the array. This is true by defualt if there are + * no extents here yet. + */ + if (offset < 0 || (unsigned) offset >= array->n_extent) { + oldext = array->n_extent; + numext = array->hi_extent - array->low_extent + 1; + if (offset < 0 + && (unsigned) -offset + numext <= array->n_extent) { + /* If we can fit this one in, move the array up */ + memmove(&array->mpfarray[-offset], + array->mpfarray, numext + * sizeof(array->mpfarray[0])); + memset(array->mpfarray, 0, -offset + * sizeof(array->mpfarray[0])); + offset = 0; + } else if ((u_int32_t)offset == array->n_extent && + mode != QAM_PROBE_MPF && array->mpfarray[0].pinref == 0) { + /* We can close the bottom extent. */ + mpf = array->mpfarray[0].mpf; + if (mpf != NULL && (ret = memp_fclose(mpf)) != 0) + goto err; + memmove(&array->mpfarray[0], &array->mpfarray[1], + (array->n_extent - 1) * sizeof (array->mpfarray[0])); + array->low_extent++; + array->hi_extent++; + offset--; + array->mpfarray[offset].mpf = NULL; + array->mpfarray[offset].pinref = 0; + } else { + /* See if we have wrapped around the queue. */ + maxext = (u_int32_t) UINT32_T_MAX + / (qp->page_ext * qp->rec_page); + if ((u_int32_t) abs(offset) >= maxext/2) { + array = &qp->array2; + DB_ASSERT(array->n_extent == 0); + oldext = 0; + array->n_extent = 4; + array->low_extent = extid; + offset = 0; + numext = 0; + } else { + /* + * Increase the size to at least include + * the new one and double it. + */ + array->n_extent += abs(offset); + array->n_extent <<= 2; + } + alloc: + if ((ret = __os_realloc(dbenv, + array->n_extent * sizeof(struct __qmpf), + NULL, &array->mpfarray)) != 0) + goto err; + + if (offset < 0) { + offset = -offset; + memmove(&array->mpfarray[offset], array->mpfarray, + numext * sizeof(array->mpfarray[0])); + memset(array->mpfarray, 0, + offset * sizeof(array->mpfarray[0])); + memset(&array->mpfarray[numext + offset], 0, + (array->n_extent - (numext + offset)) + * sizeof(array->mpfarray[0])); + offset = 0; + } + else + memset(&array->mpfarray[oldext], 0, + (array->n_extent - oldext) * + sizeof(array->mpfarray[0])); + } + } + + if (extid < array->low_extent) + array->low_extent = extid; + if (extid > array->hi_extent) + array->hi_extent = extid; + if (array->mpfarray[offset].mpf == NULL) { + snprintf(buf, + sizeof(buf), QUEUE_EXTENT, qp->dir, qp->name, extid); + openflags = DB_EXTENT; + if (LF_ISSET(DB_MPOOL_CREATE)) + openflags |= DB_CREATE; + if (F_ISSET(dbp, DB_AM_RDONLY)) + openflags |= DB_RDONLY; + qp->finfo.fileid = NULL; + if ((ret = __memp_fopen(dbenv->mp_handle, + NULL, buf, openflags, qp->mode, dbp->pgsize, + 1, &qp->finfo, &array->mpfarray[offset].mpf)) != 0) + goto err; + } + + mpf = array->mpfarray[offset].mpf; + if (mode == QAM_PROBE_GET) + array->mpfarray[offset].pinref++; + if (LF_ISSET(DB_MPOOL_CREATE)) + __memp_clear_unlink(mpf); + +err: + MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp); + + if (ret == 0) { + if (mode == QAM_PROBE_MPF) { + *(DB_MPOOLFILE **)addrp = mpf; + return (0); + } + pgno--; + pgno %= qp->page_ext; + if (mode == QAM_PROBE_GET) + return (memp_fget(mpf, + &pgno, flags | DB_MPOOL_EXTENT, addrp)); + ret = memp_fput(mpf, addrp, flags); + MUTEX_THREAD_LOCK(dbenv, dbp->mutexp); + array->mpfarray[offset].pinref--; + MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp); + } + return (ret); +} + +/* + * __qam_fclose -- close an extent. + * + * Calculate which extent the page is in and close it. + * We assume the mpf entry is present. + * + * PUBLIC: int __qam_fclose __P((DB *, db_pgno_t)); + */ + +int +__qam_fclose(dbp, pgnoaddr) + DB *dbp; + db_pgno_t pgnoaddr; +{ + DB_ENV *dbenv; + DB_MPOOLFILE *mpf; + MPFARRAY *array; + QUEUE *qp; + u_int32_t extid; + int offset, ret; + + ret = 0; + dbenv = dbp->dbenv; + qp = (QUEUE *)dbp->q_internal; + + MUTEX_THREAD_LOCK(dbenv, dbp->mutexp); + + extid = (pgnoaddr - 1) / qp->page_ext; + array = &qp->array1; + if (array->low_extent > extid || array->hi_extent < extid) + array = &qp->array2; + offset = extid - array->low_extent; + + DB_ASSERT(offset >= 0 && (unsigned) offset < array->n_extent); + + /* If other threads are still using this file, leave it. */ + if (array->mpfarray[offset].pinref != 0) + goto done; + + mpf = array->mpfarray[offset].mpf; + array->mpfarray[offset].mpf = NULL; + ret = memp_fclose(mpf); + +done: + MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp); + return (ret); +} +/* + * __qam_fremove -- remove an extent. + * + * Calculate which extent the page is in and remove it. There is no way + * to remove an extent without probing it first and seeing that is is empty + * so we assume the mpf entry is present. + * + * PUBLIC: int __qam_fremove __P((DB *, db_pgno_t)); + */ + +int +__qam_fremove(dbp, pgnoaddr) + DB *dbp; + db_pgno_t pgnoaddr; +{ + DB_ENV *dbenv; + DB_MPOOLFILE *mpf; + MPFARRAY *array; + QUEUE *qp; + u_int32_t extid; +#if CONFIG_TEST + char buf[256], *real_name; +#endif + int offset, ret; + + qp = (QUEUE *)dbp->q_internal; + dbenv = dbp->dbenv; + ret = 0; + + MUTEX_THREAD_LOCK(dbenv, dbp->mutexp); + + extid = (pgnoaddr - 1) / qp->page_ext; + array = &qp->array1; + if (array->low_extent > extid || array->hi_extent < extid) + array = &qp->array2; + offset = extid - array->low_extent; + + DB_ASSERT(offset >= 0 && (unsigned) offset < array->n_extent); + +#if CONFIG_TEST + real_name = NULL; + /* Find the real name of the file. */ + snprintf(buf, sizeof(buf), + QUEUE_EXTENT, qp->dir, qp->name, extid); + if ((ret = __db_appname(dbenv, + DB_APP_DATA, NULL, buf, 0, NULL, &real_name)) != 0) + goto err; +#endif + mpf = array->mpfarray[offset].mpf; + array->mpfarray[offset].mpf = NULL; + __memp_set_unlink(mpf); + if ((ret = memp_fclose(mpf)) != 0) + goto err; + + if (offset == 0) { + memmove(array->mpfarray, &array->mpfarray[1], + (array->hi_extent - array->low_extent) + * sizeof(array->mpfarray[0])); + array->mpfarray[array->hi_extent - array->low_extent].mpf = NULL; + if (array->low_extent != array->hi_extent) + array->low_extent++; + } else { + if (extid == array->hi_extent) + array->hi_extent--; + } + +err: + MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp); +#if CONFIG_TEST + if (real_name != NULL) + __os_freestr(real_name); +#endif + return (ret); +} + +/* + * __qam_sync -- + * Flush the database cache. + * + * PUBLIC: int __qam_sync __P((DB *, u_int32_t)); + */ +int +__qam_sync(dbp, flags) + DB *dbp; + u_int32_t flags; +{ + DB_ENV *dbenv; + DB_MPOOLFILE *mpf; + MPFARRAY *array; + QUEUE *qp; + QUEUE_FILELIST *filelist; + struct __qmpf *mpfp; + u_int32_t i; + int done, ret; + + dbenv = dbp->dbenv; + + PANIC_CHECK(dbenv); + DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->sync"); + + if ((ret = __db_syncchk(dbp, flags)) != 0) + return (ret); + + /* Read-only trees never need to be sync'd. */ + if (F_ISSET(dbp, DB_AM_RDONLY)) + return (0); + + /* If the tree was never backed by a database file, we're done. */ + if (F_ISSET(dbp, DB_AM_INMEM)) + return (0); + + /* Flush any dirty pages from the cache to the backing file. */ + if ((ret = memp_fsync(dbp->mpf)) != 0) + return (ret); + + qp = (QUEUE *)dbp->q_internal; + if (qp->page_ext == 0) + return (0); + + /* We do this for the side effect of opening all active extents. */ + if ((ret = __qam_gen_filelist(dbp, &filelist)) != 0) + return (ret); + + if (filelist == NULL) + return (0); + + __os_free(filelist, 0); + + done = 0; + qp = (QUEUE *)dbp->q_internal; + array = &qp->array1; + + MUTEX_THREAD_LOCK(dbenv, dbp->mutexp); +again: + mpfp = array->mpfarray; + for (i = array->low_extent; i <= array->hi_extent; i++, mpfp++) + if ((mpf = mpfp->mpf) != NULL) { + if ((ret = memp_fsync(mpf)) != 0) + goto err; + /* + * If we are the only ones with this file open + * then close it so it might be removed. + */ + if (mpfp->pinref == 0) { + mpfp->mpf = NULL; + if ((ret = memp_fclose(mpf)) != 0) + goto err; + } + } + + if (done == 0 && qp->array2.n_extent != 0) { + array = &qp->array2; + done = 1; + goto again; + } + +err: + MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp); + return (ret); +} + +/* + * __qam_gen_filelist -- generate a list of extent files. + * Another thread may close the handle so this should only + * be used single threaded or with care. + * + * PUBLIC: int __qam_gen_filelist __P(( DB *, QUEUE_FILELIST **)); + */ +int +__qam_gen_filelist(dbp, filelistp) + DB *dbp; + QUEUE_FILELIST **filelistp; +{ + DB_ENV *dbenv; + QUEUE *qp; + QMETA *meta; + db_pgno_t i, last, start, stop; + db_recno_t current, first; + QUEUE_FILELIST *fp; + int ret; + + dbenv = dbp->dbenv; + qp = (QUEUE *)dbp->q_internal; + *filelistp = NULL; + if (qp->page_ext == 0) + return (0); + + /* This may happen during metapage recovery. */ + if (qp->name == NULL) + return (0); + + /* Find out the page number of the last page in the database. */ + i = PGNO_BASE_MD; + if ((ret = memp_fget(dbp->mpf, &i, 0, &meta)) != 0) { + (void)dbp->close(dbp, 0); + return (ret); + } + + current = meta->cur_recno; + first = meta->first_recno; + + if ((ret = memp_fput(dbp->mpf, meta, 0)) != 0) { + (void)dbp->close(dbp, 0); + return (ret); + } + + last = QAM_RECNO_PAGE(dbp, current); + start = QAM_RECNO_PAGE(dbp, first); + + /* Allocate the worst case plus 1 for null termination. */ + if (last >= start) + ret = last - start + 2; + else + ret = last + (QAM_RECNO_PAGE(dbp, UINT32_T_MAX) - start) + 1; + if ((ret = __os_calloc(dbenv, + ret, sizeof(QUEUE_FILELIST), filelistp)) != 0) + return (ret); + fp = *filelistp; + i = start; + if (last >= start) + stop = last; + else + stop = QAM_RECNO_PAGE(dbp, UINT32_T_MAX); +again: + for (; i <= last; i += qp->page_ext) { + if ((ret = __qam_fprobe(dbp, + i, &fp->mpf, QAM_PROBE_MPF, 0)) != 0) { + if (ret == ENOENT) + continue; + return (ret); + } + fp->id = (i - 1) / qp->page_ext; + fp++; + } + + if (last < start) { + i = 1; + stop = last; + start = 0; + goto again; + } + + return (0); +} diff --git a/db/qam/qam_method.c b/db/qam/qam_method.c new file mode 100644 index 000000000..1c94f4b8d --- /dev/null +++ b/db/qam/qam_method.c @@ -0,0 +1,472 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: qam_method.c,v 11.17 2001/01/10 04:50:54 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_int.h" +#include "db_shash.h" +#include "db_am.h" +#include "qam.h" +#include "db.h" +#include "mp.h" +#include "lock.h" +#include "log.h" + +static int __qam_set_extentsize __P((DB *, u_int32_t)); +static int __qam_remove_callback __P((DB *, void *)); + +struct __qam_cookie { + DB_LSN lsn; + QUEUE_FILELIST *filelist; +}; + +/* + * __qam_db_create -- + * Queue specific initialization of the DB structure. + * + * PUBLIC: int __qam_db_create __P((DB *)); + */ +int +__qam_db_create(dbp) + DB *dbp; +{ + QUEUE *t; + int ret; + + /* Allocate and initialize the private queue structure. */ + if ((ret = __os_calloc(dbp->dbenv, 1, sizeof(QUEUE), &t)) != 0) + return (ret); + dbp->q_internal = t; + dbp->set_q_extentsize = __qam_set_extentsize; + + t->re_pad = ' '; + + return (0); +} + +/* + * __qam_db_close -- + * Queue specific discard of the DB structure. + * + * PUBLIC: int __qam_db_close __P((DB *)); + */ +int +__qam_db_close(dbp) + DB *dbp; +{ + DB_MPOOLFILE *mpf; + MPFARRAY *array; + QUEUE *t; + struct __qmpf *mpfp; + u_int32_t i; + int ret, t_ret; + + ret = 0; + t = dbp->q_internal; + + array = &t->array1; +again: + mpfp = array->mpfarray; + if (mpfp != NULL) { + for (i = array->low_extent; + i <= array->hi_extent; i++, mpfp++) { + mpf = mpfp->mpf; + mpfp->mpf = NULL; + if (mpf != NULL && + (t_ret = memp_fclose(mpf)) != 0 && ret == 0) + ret = t_ret; + } + __os_free(array->mpfarray, 0); + } + if (t->array2.n_extent != 0) { + array = &t->array2; + array->n_extent = 0; + goto again; + } + + if (t->path != NULL) + __os_free(t->path, 0); + __os_free(t, sizeof(QUEUE)); + dbp->q_internal = NULL; + + return (ret); +} + +static int +__qam_set_extentsize(dbp, extentsize) + DB *dbp; + u_int32_t extentsize; +{ + DB_ILLEGAL_AFTER_OPEN(dbp, "set_extentsize"); + + if (extentsize < 1) { + __db_err(dbp->dbenv, "Extent size must be at least 1."); + return (EINVAL); + } + + ((QUEUE*)dbp->q_internal)->page_ext = extentsize; + + return (0); +} + +/* + * __db_prqueue -- + * Print out a queue + * + * PUBLIC: int __db_prqueue __P((DB *, u_int32_t)); + */ +int +__db_prqueue(dbp, flags) + DB *dbp; + u_int32_t flags; +{ + PAGE *h; + QMETA *meta; + db_pgno_t first, i, last, pg_ext, stop; + int ret; + + /* Find out the page number of the last page in the database. */ + i = PGNO_BASE_MD; + if ((ret = memp_fget(dbp->mpf, &i, 0, &meta)) != 0) + return (ret); + + first = QAM_RECNO_PAGE(dbp, meta->first_recno); + last = QAM_RECNO_PAGE(dbp, meta->cur_recno); + + if ((ret = __db_prpage(dbp, (PAGE *)meta, flags)) != 0) + return (ret); + if ((ret = memp_fput(dbp->mpf, meta, 0)) != 0) + return (ret); + + i = first; + if (first > last) + stop = QAM_RECNO_PAGE(dbp, UINT32_T_MAX); + else + stop = last; + + /* Dump each page. */ +begin: + for (; i <= stop; ++i) { + if ((ret = __qam_fget(dbp, &i, DB_MPOOL_EXTENT, &h)) != 0) { + pg_ext = ((QUEUE *)dbp->q_internal)->page_ext; + if (pg_ext == 0) { + if (ret == EINVAL && first == last) + return (0); + return (ret); + } + if (ret == ENOENT || ret == EINVAL) { + i += pg_ext - ((i - 1) % pg_ext) - 1; + continue; + } + return (ret); + } + (void)__db_prpage(dbp, h, flags); + if ((ret = __qam_fput(dbp, i, h, 0)) != 0) + return (ret); + } + + if (first > last) { + i = 1; + stop = last; + first = last; + goto begin; + } + return (0); +} + +/* + * __qam_remove + * Remove method for a Queue. + * + * PUBLIC: int __qam_remove __P((DB *, const char *, + * PUBLIC: const char *, DB_LSN *, int (**)(DB *, void*), void **)); + */ +int +__qam_remove(dbp, name, subdb, lsnp, callbackp, cookiep) + DB *dbp; + const char *name, *subdb; + DB_LSN *lsnp; + int (**callbackp) __P((DB *, void *)); + void **cookiep; +{ + DBT namedbt; + DB_ENV *dbenv; + DB_LSN lsn; + MPFARRAY *ap; + QUEUE *qp; + int ret; + char *backup, buf[256], *real_back, *real_name; + QUEUE_FILELIST *filelist, *fp; + struct __qam_cookie *qam_cookie; + + dbenv = dbp->dbenv; + ret = 0; + backup = real_back = real_name = NULL; + filelist = NULL; + + PANIC_CHECK(dbenv); + + /* + * Subdatabases. + */ + if (subdb != NULL) { + __db_err(dbenv, + "Queue does not support multiple databases per file."); + ret = EINVAL; + goto done; + } + + qp = (QUEUE *)dbp->q_internal; + + if (qp->page_ext != 0 && + (ret = __qam_gen_filelist(dbp, &filelist)) != 0) + goto done; + + if (filelist == NULL) + goto done; + + for (fp = filelist; fp->mpf != NULL; fp++) { + snprintf(buf, + sizeof(buf), QUEUE_EXTENT, qp->dir, qp->name, fp->id); + if ((ret = __db_appname(dbenv, + DB_APP_DATA, NULL, buf, 0, NULL, &real_name)) != 0) + goto done; + if (LOGGING_ON(dbenv)) { + memset(&namedbt, 0, sizeof(namedbt)); + namedbt.data = (char *)buf; + namedbt.size = strlen(buf) + 1; + + if ((ret = + __qam_delete_log(dbenv, dbp->open_txn, + &lsn, DB_FLUSH, &namedbt, lsnp)) != 0) { + __db_err(dbenv, + "%s: %s", name, db_strerror(ret)); + goto done; + } + } + (void)__memp_fremove(fp->mpf); + if ((ret = memp_fclose(fp->mpf)) != 0) + goto done; + if (qp->array2.n_extent == 0 || qp->array2.low_extent > fp->id) + ap = &qp->array1; + else + ap = &qp->array2; + ap->mpfarray[fp->id - ap->low_extent].mpf = NULL; + + /* Create name for backup file. */ + if (TXN_ON(dbenv)) { + if ((ret = __db_backup_name(dbenv, + buf, &backup, lsnp)) != 0) + goto done; + if ((ret = __db_appname(dbenv, DB_APP_DATA, + NULL, backup, 0, NULL, &real_back)) != 0) + goto done; + if ((ret = __os_rename(dbenv, + real_name, real_back)) != 0) + goto done; + __os_freestr(real_back); + real_back = NULL; + } + else + if ((ret = __os_unlink(dbenv, real_name)) != 0) + goto done; + __os_freestr(real_name); + real_name = NULL; + } + if ((ret= __os_malloc(dbenv, + sizeof(struct __qam_cookie), NULL, &qam_cookie)) != 0) + goto done; + qam_cookie->lsn = *lsnp; + qam_cookie->filelist = filelist; + *cookiep = qam_cookie; + *callbackp = __qam_remove_callback; + +done: + if (ret != 0 && filelist != NULL) + __os_free(filelist, 0); + if (real_back != NULL) + __os_freestr(real_back); + if (real_name != NULL) + __os_freestr(real_name); + if (backup != NULL) + __os_freestr(backup); + + return (ret); +} + +static int +__qam_remove_callback(dbp, cookie) + DB *dbp; + void *cookie; +{ + DB_ENV *dbenv; + DB_LSN *lsnp; + QUEUE *qp; + QUEUE_FILELIST *filelist, *fp; + char *backup, buf[256], *real_back; + int ret; + + qp = (QUEUE *)dbp->q_internal; + if (qp->page_ext == 0) + return (__os_unlink(dbp->dbenv, cookie)); + + dbenv = dbp->dbenv; + lsnp = &((struct __qam_cookie *)cookie)->lsn; + filelist = fp = ((struct __qam_cookie *)cookie)->filelist; + real_back = backup = NULL; + if ((ret = + __db_backup_name(dbenv, qp->name, &backup, lsnp)) != 0) + goto err; + if ((ret = __db_appname(dbenv, + DB_APP_DATA, NULL, backup, 0, NULL, &real_back)) != 0) + goto err; + if ((ret = __os_unlink(dbp->dbenv, real_back)) != 0) + goto err; + + __os_freestr(backup); + __os_freestr(real_back); + + if (fp == NULL) + return (0); + + for (; fp->mpf != NULL; fp++) { + snprintf(buf, + sizeof(buf), QUEUE_EXTENT, qp->dir, qp->name, fp->id); + real_back = backup = NULL; + if ((ret = __db_backup_name(dbenv, buf, &backup, lsnp)) != 0) + goto err; + if ((ret = __db_appname(dbenv, + DB_APP_DATA, NULL, backup, 0, NULL, &real_back)) != 0) + goto err; + ret = __os_unlink(dbenv, real_back); + __os_freestr(real_back); + __os_freestr(backup); + } + __os_free(filelist, 0); + __os_free(cookie, sizeof (struct __qam_cookie)); + + return (0); + +err: + if (backup != NULL) + __os_freestr(backup); + + if (real_back != NULL) + __os_freestr(real_back); + + return (ret); +} + +/* + * __qam_rename + * Rename method for Queue. + * + * PUBLIC: int __qam_rename __P((DB *, + * PUBLIC: const char *, const char *, const char *)); + */ +int +__qam_rename(dbp, filename, subdb, newname) + DB *dbp; + const char *filename, *subdb, *newname; +{ + DBT namedbt, newnamedbt; + DB_ENV *dbenv; + DB_LSN newlsn; + MPFARRAY *ap; + QUEUE *qp; + QUEUE_FILELIST *fp, *filelist; + char buf[256], nbuf[256], *namep, *real_name, *real_newname; + int ret; + + dbenv = dbp->dbenv; + ret = 0; + real_name = real_newname = NULL; + filelist = NULL; + + qp = (QUEUE *)dbp->q_internal; + + if (subdb != NULL) { + __db_err(dbenv, + "Queue does not support multiple databases per file."); + ret = EINVAL; + goto err; + } + if (qp->page_ext != 0 && + (ret = __qam_gen_filelist(dbp, &filelist)) != 0) + goto err; + if ((namep = __db_rpath(newname)) != NULL) + newname = namep + 1; + + for (fp = filelist; fp != NULL && fp->mpf != NULL; fp++) { + if ((ret = __memp_fremove(fp->mpf)) != 0) + goto err; + if ((ret = memp_fclose(fp->mpf)) != 0) + goto err; + if (qp->array2.n_extent == 0 || qp->array2.low_extent > fp->id) + ap = &qp->array1; + else + ap = &qp->array2; + ap->mpfarray[fp->id - ap->low_extent].mpf = NULL; + snprintf(buf, + sizeof(buf), QUEUE_EXTENT, qp->dir, qp->name, fp->id); + if ((ret = __db_appname(dbenv, + DB_APP_DATA, NULL, buf, 0, NULL, &real_name)) != 0) + goto err; + snprintf(nbuf, + sizeof(nbuf), QUEUE_EXTENT, qp->dir, newname, fp->id); + if ((ret = __db_appname(dbenv, + DB_APP_DATA, NULL, nbuf, 0, NULL, &real_newname)) != 0) + goto err; + if (LOGGING_ON(dbenv)) { + memset(&namedbt, 0, sizeof(namedbt)); + namedbt.data = (char *)buf; + namedbt.size = strlen(buf) + 1; + + memset(&newnamedbt, 0, sizeof(namedbt)); + newnamedbt.data = (char *)nbuf; + newnamedbt.size = strlen(nbuf) + 1; + + if ((ret = + __qam_rename_log(dbenv, + dbp->open_txn, &newlsn, 0, + &namedbt, &newnamedbt)) != 0) { + __db_err(dbenv, "%s: %s", filename, db_strerror(ret)); + goto err; + } + + if ((ret = __log_filelist_update(dbenv, dbp, + dbp->log_fileid, newname, NULL)) != 0) + goto err; + } + if ((ret = __os_rename(dbenv, real_name, real_newname)) != 0) + goto err; + __os_freestr(real_name); + __os_freestr(real_newname); + real_name = real_newname = NULL; + } + +err: + if (real_name != NULL) + __os_freestr(real_name); + if (real_newname != NULL) + __os_freestr(real_newname); + if (filelist != NULL) + __os_free(filelist, 0); + + return (ret); +} diff --git a/db/qam/qam_open.c b/db/qam/qam_open.c new file mode 100644 index 000000000..73346439f --- /dev/null +++ b/db/qam/qam_open.c @@ -0,0 +1,268 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: qam_open.c,v 11.31 2000/12/20 17:59:29 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_shash.h" +#include "db_swap.h" +#include "db_am.h" +#include "lock.h" +#include "qam.h" + +/* + * __qam_open + * + * PUBLIC: int __qam_open __P((DB *, const char *, db_pgno_t, int, u_int32_t)); + */ +int +__qam_open(dbp, name, base_pgno, mode, flags) + DB *dbp; + const char *name; + db_pgno_t base_pgno; + int mode; + u_int32_t flags; +{ + QUEUE *t; + DBC *dbc; + DB_LOCK metalock; + DB_LSN orig_lsn; + QMETA *qmeta; + int locked; + int ret, t_ret; + + ret = 0; + locked = 0; + t = dbp->q_internal; + + if (name == NULL && t->page_ext != 0) { + __db_err(dbp->dbenv, + "Extent size may not be specified for in-memory queue database."); + return (EINVAL); + } + /* Initialize the remaining fields/methods of the DB. */ + dbp->del = __qam_delete; + dbp->put = __qam_put; + dbp->stat = __qam_stat; + dbp->sync = __qam_sync; + dbp->db_am_remove = __qam_remove; + dbp->db_am_rename = __qam_rename; + + metalock.off = LOCK_INVALID; + + /* + * Get a cursor. If DB_CREATE is specified, we may be creating + * pages, and to do that safely in CDB we need a write cursor. + * In STD_LOCKING mode, we'll synchronize using the meta page + * lock instead. + */ + if ((ret = dbp->cursor(dbp, dbp->open_txn, + &dbc, LF_ISSET(DB_CREATE) && CDB_LOCKING(dbp->dbenv) ? + DB_WRITECURSOR : 0)) != 0) + return (ret); + + /* Get, and optionally create the metadata page. */ + if ((ret = + __db_lget(dbc, 0, base_pgno, DB_LOCK_READ, 0, &metalock)) != 0) + goto err; + if ((ret = memp_fget( + dbp->mpf, &base_pgno, DB_MPOOL_CREATE, (PAGE **)&qmeta)) != 0) + goto err; + + /* + * If the magic number is correct, we're not creating the tree. + * Correct any fields that may not be right. Note, all of the + * local flags were set by DB->open. + */ +again: if (qmeta->dbmeta.magic == DB_QAMMAGIC) { + t->re_pad = qmeta->re_pad; + t->re_len = qmeta->re_len; + t->rec_page = qmeta->rec_page; + t->page_ext = qmeta->page_ext; + + (void)memp_fput(dbp->mpf, (PAGE *)qmeta, 0); + goto done; + } + + /* If we're doing CDB; we now have to get the write lock. */ + if (CDB_LOCKING(dbp->dbenv)) { + DB_ASSERT(LF_ISSET(DB_CREATE)); + if ((ret = lock_get(dbp->dbenv, dbc->locker, DB_LOCK_UPGRADE, + &dbc->lock_dbt, DB_LOCK_WRITE, &dbc->mylock)) != 0) + goto err; + } + + /* + * If we are doing locking, relase the read lock + * and get a write lock. We want to avoid deadlock. + */ + if (locked == 0 && STD_LOCKING(dbc)) { + if ((ret = __LPUT(dbc, metalock)) != 0) + goto err; + if ((ret = __db_lget(dbc, + 0, base_pgno, DB_LOCK_WRITE, 0, &metalock)) != 0) + goto err; + locked = 1; + goto again; + } + /* Initialize the tree structure metadata information. */ + orig_lsn = qmeta->dbmeta.lsn; + memset(qmeta, 0, sizeof(QMETA)); + ZERO_LSN(qmeta->dbmeta.lsn); + qmeta->dbmeta.pgno = base_pgno; + qmeta->dbmeta.magic = DB_QAMMAGIC; + qmeta->dbmeta.version = DB_QAMVERSION; + qmeta->dbmeta.pagesize = dbp->pgsize; + qmeta->dbmeta.type = P_QAMMETA; + qmeta->re_pad = t->re_pad; + qmeta->re_len = t->re_len; + qmeta->rec_page = CALC_QAM_RECNO_PER_PAGE(dbp); + qmeta->cur_recno = 1; + qmeta->first_recno = 1; + qmeta->page_ext = t->page_ext; + t->rec_page = qmeta->rec_page; + memcpy(qmeta->dbmeta.uid, dbp->fileid, DB_FILE_ID_LEN); + + /* Verify that we can fit at least one record per page. */ + if (QAM_RECNO_PER_PAGE(dbp) < 1) { + __db_err(dbp->dbenv, + "Record size of %lu too large for page size of %lu", + (u_long)t->re_len, (u_long)dbp->pgsize); + (void)memp_fput(dbp->mpf, (PAGE *)qmeta, 0); + ret = EINVAL; + goto err; + } + + if ((ret = __db_log_page(dbp, + name, &orig_lsn, base_pgno, (PAGE *)qmeta)) != 0) + goto err; + + /* Release the metadata page. */ + if ((ret = memp_fput(dbp->mpf, (PAGE *)qmeta, DB_MPOOL_DIRTY)) != 0) + goto err; + DB_TEST_RECOVERY(dbp, DB_TEST_POSTLOG, ret, name); + + /* + * Flush the metadata page to disk. + * + * !!! + * It's not useful to return not-yet-flushed here -- convert it to + * an error. + */ + if ((ret = memp_fsync(dbp->mpf)) == DB_INCOMPLETE) { + __db_err(dbp->dbenv, "Flush of metapage failed"); + ret = EINVAL; + } + DB_TEST_RECOVERY(dbp, DB_TEST_POSTSYNC, ret, name); + +done: t->q_meta = base_pgno; + t->q_root = base_pgno + 1; + + /* Setup information needed to open extents. */ + if (t->page_ext != 0) { + t->finfo.pgcookie = &t->pgcookie; + t->finfo.fileid = NULL; + t->finfo.lsn_offset = 0; + + t->pginfo.db_pagesize = dbp->pgsize; + t->pginfo.needswap = F_ISSET(dbp, DB_AM_SWAP); + t->pgcookie.data = &t->pginfo; + t->pgcookie.size = sizeof(DB_PGINFO); + + if ((ret = __os_strdup(dbp->dbenv, name, &t->path)) != 0) + goto err; + t->dir = t->path; + if ((t->name = __db_rpath(t->path)) == NULL) { + t->name = t->path; + t->dir = PATH_DOT; + } else + *t->name++ = '\0'; + + if (mode == 0) + mode = __db_omode("rwrw--"); + t->mode = mode; + } + +err: +DB_TEST_RECOVERY_LABEL + /* Don't hold the meta page long term. */ + (void)__LPUT(dbc, metalock); + + if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0) + ret = t_ret; + + return (ret); +} + +/* + * __qam_metachk -- + * + * PUBLIC: int __qam_metachk __P((DB *, const char *, QMETA *)); + */ +int +__qam_metachk(dbp, name, qmeta) + DB *dbp; + const char *name; + QMETA *qmeta; +{ + DB_ENV *dbenv; + u_int32_t vers; + int ret; + + dbenv = dbp->dbenv; + + /* + * At this point, all we know is that the magic number is for a Queue. + * Check the version, the database may be out of date. + */ + vers = qmeta->dbmeta.version; + if (F_ISSET(dbp, DB_AM_SWAP)) + M_32_SWAP(vers); + switch (vers) { + case 1: + case 2: + __db_err(dbenv, + "%s: queue version %lu requires a version upgrade", + name, (u_long)vers); + return (DB_OLD_VERSION); + case 3: + break; + default: + __db_err(dbenv, + "%s: unsupported qam version: %lu", name, (u_long)vers); + return (EINVAL); + } + + /* Swap the page if we need to. */ + if (F_ISSET(dbp, DB_AM_SWAP) && (ret = __qam_mswap((PAGE *)qmeta)) != 0) + return (ret); + + /* Check the type. */ + if (dbp->type != DB_QUEUE && dbp->type != DB_UNKNOWN) + return (EINVAL); + dbp->type = DB_QUEUE; + DB_ILLEGAL_METHOD(dbp, DB_OK_QUEUE); + + /* Set the page size. */ + dbp->pgsize = qmeta->dbmeta.pagesize; + + /* Copy the file's ID. */ + memcpy(dbp->fileid, qmeta->dbmeta.uid, DB_FILE_ID_LEN); + + return (0); +} diff --git a/db/qam/qam_rec.c b/db/qam/qam_rec.c new file mode 100644 index 000000000..4d330f586 --- /dev/null +++ b/db/qam/qam_rec.c @@ -0,0 +1,732 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: qam_rec.c,v 11.34 2001/01/19 18:01:59 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_shash.h" +#include "lock.h" +#include "db_am.h" +#include "qam.h" +#include "log.h" + +/* + * __qam_inc_recover -- + * Recovery function for inc. + * + * PUBLIC: int __qam_inc_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__qam_inc_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __qam_inc_args *argp; + DB *file_dbp; + DBC *dbc; + DB_LOCK lock; + DB_MPOOLFILE *mpf; + QMETA *meta; + db_pgno_t metapg; + int cmp_p, modified, ret; + + COMPQUIET(info, NULL); + REC_PRINT(__qam_inc_print); + REC_INTRO(__qam_inc_read, 1); + + metapg = ((QUEUE *)file_dbp->q_internal)->q_meta; + + if ((ret = __db_lget(dbc, + LCK_ROLLBACK, metapg, DB_LOCK_WRITE, 0, &lock)) != 0) + goto done; + if ((ret = memp_fget(mpf, &metapg, 0, &meta)) != 0) { + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &metapg, DB_MPOOL_CREATE, &meta)) != 0) { + (void)__LPUT(dbc, lock); + goto out; + } + meta->dbmeta.pgno = metapg; + meta->dbmeta.type = P_QAMMETA; + + } else { + *lsnp = argp->prev_lsn; + ret = 0; + (void)__LPUT(dbc, lock); + goto out; + } + } + + modified = 0; + cmp_p = log_compare(&LSN(meta), &argp->lsn); + CHECK_LSN(op, cmp_p, &LSN(meta), &argp->lsn); + + /* + * The cur_recno never goes backwards. It is a point of + * contention among appenders. If one fails cur_recno will + * most likely be beyond that one when it aborts. + * We move it ahead on either an abort or a commit + * and make the LSN reflect that fact. + */ + if (cmp_p == 0) { + modified = 1; + meta->cur_recno++; + if (meta->cur_recno == RECNO_OOB) + meta->cur_recno++; + meta->dbmeta.lsn = *lsnp; + } + if ((ret = memp_fput(mpf, meta, modified ? DB_MPOOL_DIRTY : 0))) + goto out; + + (void)__LPUT(dbc, lock); + +done: *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __qam_incfirst_recover -- + * Recovery function for incfirst. + * + * PUBLIC: int __qam_incfirst_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__qam_incfirst_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __qam_incfirst_args *argp; + DB *file_dbp; + DBC *dbc; + DB_LOCK lock; + DB_MPOOLFILE *mpf; + QMETA *meta; + QUEUE_CURSOR *cp; + db_pgno_t metapg; + int exact, modified, ret, rec_ext; + + COMPQUIET(info, NULL); + REC_PRINT(__qam_incfirst_print); + REC_INTRO(__qam_incfirst_read, 1); + + metapg = ((QUEUE *)file_dbp->q_internal)->q_meta; + + if ((ret = __db_lget(dbc, + LCK_ROLLBACK, metapg, DB_LOCK_WRITE, 0, &lock)) != 0) + goto done; + if ((ret = memp_fget(mpf, &metapg, 0, &meta)) != 0) { + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &metapg, DB_MPOOL_CREATE, &meta)) != 0) { + (void)__LPUT(dbc, lock); + goto out; + } + meta->dbmeta.pgno = metapg; + meta->dbmeta.type = P_QAMMETA; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + (void)__LPUT(dbc, lock); + goto out; + } + } + + modified = 0; + + /* + * Only move first_recno backwards so we pick up the aborted delete. + * When going forward we need to be careful since + * we may have bumped over a locked record. + */ + if (DB_UNDO(op)) { + if (QAM_BEFORE_FIRST(meta, argp->recno)) { + meta->first_recno = argp->recno; + modified = 1; + } + } else { + if (log_compare(&LSN(meta), lsnp) < 0) { + LSN(meta) = *lsnp; + modified = 1; + } + rec_ext = 0; + if (meta->page_ext != 0) + rec_ext = meta->page_ext * meta->rec_page; + cp = (QUEUE_CURSOR *)dbc->internal; + if (meta->first_recno == RECNO_OOB) + meta->first_recno++; + while (meta->first_recno != meta->cur_recno + && !QAM_BEFORE_FIRST(meta, argp->recno + 1)) { + if ((ret = __qam_position(dbc, + &meta->first_recno, QAM_READ, &exact)) != 0) + goto out; + if (cp->page != NULL) + __qam_fput(file_dbp, cp->pgno, cp->page, 0); + + if (exact == 1) + break; + if (cp->page != NULL && + rec_ext != 0 && meta->first_recno % rec_ext == 0) + if ((ret = + __qam_fremove(file_dbp, cp->pgno)) != 0) + goto out; + meta->first_recno++; + if (meta->first_recno == RECNO_OOB) + meta->first_recno++; + modified = 1; + } + } + + if ((ret = memp_fput(mpf, meta, modified ? DB_MPOOL_DIRTY : 0))) + goto out; + + (void)__LPUT(dbc, lock); + +done: *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __qam_mvptr_recover -- + * Recovery function for mvptr. + * + * PUBLIC: int __qam_mvptr_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__qam_mvptr_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __qam_mvptr_args *argp; + DB *file_dbp; + DBC *dbc; + DB_LOCK lock; + DB_MPOOLFILE *mpf; + QMETA *meta; + db_pgno_t metapg; + int cmp_p, modified, ret; + + COMPQUIET(info, NULL); + REC_PRINT(__qam_mvptr_print); + REC_INTRO(__qam_mvptr_read, 1); + + metapg = ((QUEUE *)file_dbp->q_internal)->q_meta; + + if ((ret = __db_lget(dbc, + LCK_ROLLBACK, metapg, DB_LOCK_WRITE, 0, &lock)) != 0) + goto done; + if ((ret = memp_fget(mpf, &metapg, 0, &meta)) != 0) { + if (DB_REDO(op)) { + if ((ret = memp_fget(mpf, + &metapg, DB_MPOOL_CREATE, &meta)) != 0) { + (void)__LPUT(dbc, lock); + goto out; + } + meta->dbmeta.pgno = metapg; + meta->dbmeta.type = P_QAMMETA; + } else { + *lsnp = argp->prev_lsn; + ret = 0; + (void)__LPUT(dbc, lock); + goto out; + } + } + + modified = 0; + cmp_p = log_compare(&meta->dbmeta.lsn, &argp->metalsn); + + /* + * We never undo a movement of one of the pointers. + * Just move them along regardless of abort/commit. + */ + if (cmp_p == 0) { + if (argp->opcode & QAM_SETFIRST) + meta->first_recno = argp->new_first; + + if (argp->opcode & QAM_SETCUR) + meta->cur_recno = argp->new_cur; + + modified = 1; + meta->dbmeta.lsn = *lsnp; + } + + if ((ret = memp_fput(mpf, meta, modified ? DB_MPOOL_DIRTY : 0))) + goto out; + + (void)__LPUT(dbc, lock); + +done: *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} +/* + * __qam_del_recover -- + * Recovery function for del. + * Non-extent version or if there is no data (zero len). + * + * PUBLIC: int __qam_del_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__qam_del_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __qam_del_args *argp; + DB *file_dbp; + DBC *dbc; + DB_LOCK lock; + DB_MPOOLFILE *mpf; + QAMDATA *qp; + QMETA *meta; + QPAGE *pagep; + db_pgno_t metapg; + int cmp_n, modified, ret; + + COMPQUIET(info, NULL); + REC_PRINT(__qam_del_print); + REC_INTRO(__qam_del_read, 1); + + if ((ret = __qam_fget(file_dbp, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + + modified = 0; + if (pagep->pgno == PGNO_INVALID) { + pagep->pgno = argp->pgno; + pagep->type = P_QAMDATA; + modified = 1; + } + + cmp_n = log_compare(lsnp, &LSN(pagep)); + + if (DB_UNDO(op)) { + /* make sure first is behind us */ + metapg = ((QUEUE *)file_dbp->q_internal)->q_meta; + if ((ret = __db_lget(dbc, + LCK_ROLLBACK, metapg, DB_LOCK_WRITE, 0, &lock)) != 0) + return (ret); + if ((ret = memp_fget(file_dbp->mpf, &metapg, 0, &meta)) != 0) { + (void)__LPUT(dbc, lock); + goto done; + } + if (meta->first_recno == RECNO_OOB || + (QAM_BEFORE_FIRST(meta, argp->recno) + && (meta->first_recno <= meta->cur_recno + || meta->first_recno - + argp->recno < argp->recno - meta->cur_recno))) { + meta->first_recno = argp->recno; + (void)memp_fput(file_dbp->mpf, meta, DB_MPOOL_DIRTY); + } else + (void)memp_fput(file_dbp->mpf, meta, 0); + (void)__LPUT(dbc, lock); + + /* Need to undo delete - mark the record as present */ + qp = QAM_GET_RECORD(file_dbp, pagep, argp->indx); + F_SET(qp, QAM_VALID); + + /* + * Move the LSN back to this point; do not move it forward. + * Only move it back if we're in recovery. If we're in + * an abort, because we don't hold a page lock, we could + * foul up a concurrent put. Having too late an LSN + * is harmless in queue except when we're determining + * what we need to roll forward during recovery. [#2588] + */ + if (op == DB_TXN_BACKWARD_ROLL && cmp_n < 0) + LSN(pagep) = argp->lsn; + modified = 1; + } else if (cmp_n > 0 && DB_REDO(op)) { + /* Need to redo delete - clear the valid bit */ + qp = QAM_GET_RECORD(file_dbp, pagep, argp->indx); + F_CLR(qp, QAM_VALID); + LSN(pagep) = *lsnp; + modified = 1; + } + if ((ret = __qam_fput(file_dbp, + argp->pgno, pagep, modified ? DB_MPOOL_DIRTY : 0))) + goto out; + +done: *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} +/* + * __qam_delext_recover -- + * Recovery function for del in an extent based queue. + * + * PUBLIC: int __qam_delext_recover __P((DB_ENV *, + * PUBLIC: DBT *, DB_LSN *, db_recops, void *)); + */ +int +__qam_delext_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __qam_delext_args *argp; + DB *file_dbp; + DBC *dbc; + DB_LOCK lock; + DB_MPOOLFILE *mpf; + QAMDATA *qp; + QMETA *meta; + QPAGE *pagep; + db_pgno_t metapg; + int cmp_n, modified, ret; + + COMPQUIET(info, NULL); + REC_PRINT(__qam_delext_print); + REC_INTRO(__qam_delext_read, 1); + + if ((ret = __qam_fget(file_dbp, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + + modified = 0; + if (pagep->pgno == PGNO_INVALID) { + pagep->pgno = argp->pgno; + pagep->type = P_QAMDATA; + modified = 1; + } + + cmp_n = log_compare(lsnp, &LSN(pagep)); + + if (DB_UNDO(op)) { + /* make sure first is behind us */ + metapg = ((QUEUE *)file_dbp->q_internal)->q_meta; + if ((ret = __db_lget(dbc, + LCK_ROLLBACK, metapg, DB_LOCK_WRITE, 0, &lock)) != 0) + return (ret); + if ((ret = memp_fget(file_dbp->mpf, &metapg, 0, &meta)) != 0) { + (void)__LPUT(dbc, lock); + goto done; + } + if (meta->first_recno == RECNO_OOB || + (QAM_BEFORE_FIRST(meta, argp->recno) + && (meta->first_recno <= meta->cur_recno + || meta->first_recno - + argp->recno < argp->recno - meta->cur_recno))) { + meta->first_recno = argp->recno; + (void)memp_fput(file_dbp->mpf, meta, DB_MPOOL_DIRTY); + } else + (void)memp_fput(file_dbp->mpf, meta, 0); + (void)__LPUT(dbc, lock); + + if ((ret = __qam_pitem(dbc, pagep, + argp->indx, argp->recno, &argp->data)) != 0) + goto done; + + /* + * Move the LSN back to this point; do not move it forward. + * Only move it back if we're in recovery. If we're in + * an abort, because we don't hold a page lock, we could + * foul up a concurrent put. Having too late an LSN + * is harmless in queue except when we're determining + * what we need to roll forward during recovery. [#2588] + */ + if (op == DB_TXN_BACKWARD_ROLL && cmp_n < 0) + LSN(pagep) = argp->lsn; + modified = 1; + } else if (cmp_n > 0 && DB_REDO(op)) { + /* Need to redo delete - clear the valid bit */ + qp = QAM_GET_RECORD(file_dbp, pagep, argp->indx); + F_CLR(qp, QAM_VALID); + LSN(pagep) = *lsnp; + modified = 1; + } + if ((ret = __qam_fput(file_dbp, + argp->pgno, pagep, modified ? DB_MPOOL_DIRTY : 0))) + goto out; + +done: *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} + +/* + * __qam_add_recover -- + * Recovery function for add. + * + * PUBLIC: int __qam_add_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__qam_add_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __qam_add_args *argp; + DB *file_dbp; + DBC *dbc; + DB_MPOOLFILE *mpf; + QAMDATA *qp; + QMETA *meta; + QPAGE *pagep; + db_pgno_t metapg; + int cmp_n, modified, ret; + + COMPQUIET(info, NULL); + REC_PRINT(__qam_add_print); + REC_INTRO(__qam_add_read, 1); + + modified = 0; + if ((ret = __qam_fget(file_dbp, + &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) + goto out; + + if (pagep->pgno == PGNO_INVALID) { + pagep->pgno = argp->pgno; + pagep->type = P_QAMDATA; + modified = 1; + } + + cmp_n = log_compare(lsnp, &LSN(pagep)); + + if (cmp_n > 0 && DB_REDO(op)) { + /* Need to redo add - put the record on page */ + if ((ret = __qam_pitem(dbc, pagep, argp->indx, argp->recno, + &argp->data)) != 0) + goto err; + LSN(pagep) = *lsnp; + modified = 1; + /* Make sure first pointer includes this record. */ + metapg = ((QUEUE *)file_dbp->q_internal)->q_meta; + if ((ret = memp_fget(mpf, &metapg, 0, &meta)) != 0) + goto err; + if (QAM_BEFORE_FIRST(meta, argp->recno)) { + meta->first_recno = argp->recno; + if ((ret = memp_fput(mpf, meta, DB_MPOOL_DIRTY)) != 0) + goto err; + } else + if ((ret = memp_fput(mpf, meta, 0)) != 0) + goto err; + + } else if (DB_UNDO(op)) { + /* + * Need to undo add + * If this was an overwrite, put old record back. + * Otherwise just clear the valid bit + */ + if (argp->olddata.size != 0) { + if ((ret = __qam_pitem(dbc, pagep, + argp->indx, argp->recno, &argp->olddata)) != 0) + goto err; + + if (!(argp->vflag & QAM_VALID)) { + qp = QAM_GET_RECORD( + file_dbp, pagep, argp->indx); + F_CLR(qp, QAM_VALID); + } + modified = 1; + } else { + qp = QAM_GET_RECORD(file_dbp, pagep, argp->indx); + qp->flags = 0; + modified = 1; + } + + /* + * Move the LSN back to this point; do not move it forward. + * Only move it back if we're in recovery. If we're in + * an abort, because we don't hold a page lock, we could + * foul up a concurrent put. Having too late an LSN + * is harmless in queue except when we're determining + * what we need to roll forward during recovery. [#2588] + */ + if (op == DB_TXN_BACKWARD_ROLL && cmp_n < 0) + LSN(pagep) = argp->lsn; + } + +err: if ((ret = __qam_fput(file_dbp, + argp->pgno, pagep, modified ? DB_MPOOL_DIRTY : 0))) + goto out; + +done: *lsnp = argp->prev_lsn; + ret = 0; + +out: REC_CLOSE; +} +/* + * __qam_delete_recover -- + * Recovery function for delete of an extent. + * + * PUBLIC: int __qam_delete_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__qam_delete_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __qam_delete_args *argp; + int ret; + char *backup, *real_back, *real_name; + + COMPQUIET(info, NULL); + + REC_PRINT(__qam_delete_print); + + backup = real_back = real_name = NULL; + if ((ret = __qam_delete_read(dbenv, dbtp->data, &argp)) != 0) + goto out; + + if (DB_REDO(op)) { + /* + * On a recovery, as we recreate what was going on, we + * recreate the creation of the file. And so, even though + * it committed, we need to delete it. Try to delete it, + * but it is not an error if that delete fails. + */ + if ((ret = __db_appname(dbenv, DB_APP_DATA, + NULL, argp->name.data, 0, NULL, &real_name)) != 0) + goto out; + if (__os_exists(real_name, NULL) == 0) { + if ((ret = __os_unlink(dbenv, real_name)) != 0) + goto out; + } + } else if (DB_UNDO(op)) { + /* + * Trying to undo. File may or may not have been deleted. + * Try to move the backup to the original. If the backup + * exists, then this is right. If it doesn't exist, then + * nothing will happen and that's OK. + */ + if ((ret = __db_backup_name(dbenv, argp->name.data, + &backup, &argp->lsn)) != 0) + goto out; + if ((ret = __db_appname(dbenv, + DB_APP_DATA, NULL, backup, 0, NULL, &real_back)) != 0) + goto out; + if ((ret = __db_appname(dbenv, DB_APP_DATA, + NULL, argp->name.data, 0, NULL, &real_name)) != 0) + goto out; + if (__os_exists(real_back, NULL) == 0) + if ((ret = + __os_rename(dbenv, real_back, real_name)) != 0) + goto out; + } + *lsnp = argp->prev_lsn; + ret = 0; + +out: if (argp != NULL) + __os_free(argp, 0); + if (backup != NULL) + __os_freestr(backup); + if (real_back != NULL) + __os_freestr(real_back); + if (real_name != NULL) + __os_freestr(real_name); + return (ret); +} +/* + * __qam_rename_recover -- + * Recovery function for rename. + * + * PUBLIC: int __qam_rename_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__qam_rename_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __qam_rename_args *argp; + char *new_name, *real_name; + int ret; + + COMPQUIET(info, NULL); + + REC_PRINT(__qam_rename_print); + + new_name = real_name = NULL; + + if ((ret = __qam_rename_read(dbenv, dbtp->data, &argp)) != 0) + goto out; + + if (DB_REDO(op)) { + if ((ret = __db_appname(dbenv, DB_APP_DATA, + NULL, argp->name.data, 0, NULL, &real_name)) != 0) + goto out; + if (__os_exists(real_name, NULL) == 0) { + if ((ret = __db_appname(dbenv, + DB_APP_DATA, NULL, argp->newname.data, + 0, NULL, &new_name)) != 0) + goto out; + if ((ret = __os_rename(dbenv, + real_name, new_name)) != 0) + goto out; + } + } else { + if ((ret = __db_appname(dbenv, DB_APP_DATA, + NULL, argp->newname.data, 0, NULL, &new_name)) != 0) + goto out; + if (__os_exists(new_name, NULL) == 0) { + if ((ret = __db_appname(dbenv, + DB_APP_DATA, NULL, argp->name.data, + 0, NULL, &real_name)) != 0) + goto out; + if ((ret = __os_rename(dbenv, + new_name, real_name)) != 0) + goto out; + } + } + + *lsnp = argp->prev_lsn; + ret = 0; + +out: if (argp != NULL) + __os_free(argp, 0); + + if (new_name != NULL) + __os_free(new_name, 0); + + if (real_name != NULL) + __os_free(real_name, 0); + + return (ret); +} diff --git a/db/qam/qam_stat.c b/db/qam/qam_stat.c new file mode 100644 index 000000000..865f477c1 --- /dev/null +++ b/db/qam/qam_stat.c @@ -0,0 +1,201 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: qam_stat.c,v 11.16 2001/01/10 04:50:54 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_shash.h" +#include "db_am.h" +#include "lock.h" +#include "qam.h" + +/* + * __qam_stat -- + * Gather/print the qam statistics + * + * PUBLIC: int __qam_stat __P((DB *, void *, void *(*)(size_t), u_int32_t)); + */ +int +__qam_stat(dbp, spp, db_malloc, flags) + DB *dbp; + void *spp; + void *(*db_malloc) __P((size_t)); + u_int32_t flags; +{ + QUEUE *t; + DBC *dbc; + DB_LOCK lock; + DB_QUEUE_STAT *sp; + PAGE *h; + QAMDATA *qp, *ep; + QMETA *meta; + db_indx_t indx; + db_pgno_t first, last, pgno, pg_ext, stop; + u_int32_t re_len; + int ret, t_ret; + + PANIC_CHECK(dbp->dbenv); + DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->stat"); + + t = dbp->q_internal; + sp = NULL; + lock.off = LOCK_INVALID; + + /* Check for invalid flags. */ + if ((ret = __db_statchk(dbp, flags)) != 0) + return (ret); + + if (spp == NULL) + return (0); + + /* Acquire a cursor. */ + if ((ret = dbp->cursor(dbp, NULL, &dbc, 0)) != 0) + return (ret); + + DEBUG_LWRITE(dbc, NULL, "qam_stat", NULL, NULL, flags); + + /* Allocate and clear the structure. */ + if ((ret = __os_malloc(dbp->dbenv, sizeof(*sp), db_malloc, &sp)) != 0) + goto err; + memset(sp, 0, sizeof(*sp)); + + re_len = ((QUEUE *)dbp->q_internal)->re_len; + if (flags == DB_CACHED_COUNTS) { + if ((ret = __db_lget(dbc, + 0, t->q_meta, DB_LOCK_READ, 0, &lock)) != 0) + goto err; + if ((ret = + memp_fget(dbp->mpf, &t->q_meta, 0, (PAGE **)&meta)) != 0) + goto err; + sp->qs_nkeys = meta->dbmeta.key_count; + sp->qs_ndata = meta->dbmeta.record_count; + + goto done; + } + + /* Determine the last page of the database. */ + if ((ret = __db_lget(dbc, + 0, t->q_meta, DB_LOCK_READ, 0, &lock)) != 0) + goto err; + if ((ret = memp_fget(dbp->mpf, &t->q_meta, 0, (PAGE **)&meta)) != 0) + goto err; + + first = QAM_RECNO_PAGE(dbp, meta->first_recno); + last = QAM_RECNO_PAGE(dbp, meta->cur_recno); + + if ((ret = memp_fput(dbp->mpf, meta, 0)) != 0) + goto err; + (void)__LPUT(dbc, lock); + + pgno = first; + if (first > last) + stop = QAM_RECNO_PAGE(dbp, UINT32_T_MAX); + else + stop = last; + + /* Dump each page. */ + pg_ext = ((QUEUE *)dbp->q_internal)->page_ext; +begin: + /* Walk through the pages and count. */ + for (; pgno <= stop; ++pgno) { + if ((ret = + __db_lget(dbc, + 0, pgno, DB_LOCK_READ, 0, &lock)) != 0) + goto err; + ret = __qam_fget(dbp, &pgno, DB_MPOOL_EXTENT, &h); + if (ret == ENOENT) { + pgno += pg_ext - 1; + continue; + } + if (ret == EINVAL) { + pgno += pg_ext - ((pgno - 1) % pg_ext) - 1; + continue; + } + if (ret == EIO && first == last && pg_ext == 0) + break; + if (ret != 0) + goto err; + + ++sp->qs_pages; + + ep = (QAMDATA *)((u_int8_t *)h + dbp->pgsize - re_len); + for (indx = 0, qp = QAM_GET_RECORD(dbp, h, indx); + qp <= ep; + ++indx, qp = QAM_GET_RECORD(dbp, h, indx)) { + if (F_ISSET(qp, QAM_VALID)) + sp->qs_ndata++; + else + sp->qs_pgfree += re_len; + } + + if ((ret = __qam_fput(dbp, pgno, h, 0)) != 0) + goto err; + (void)__LPUT(dbc, lock); + } + if (first > last) { + pgno = 1; + stop = last; + first = last; + goto begin; + } + + /* Get the meta-data page. */ + if ((ret = __db_lget(dbc, + 0, t->q_meta, F_ISSET(dbp, DB_AM_RDONLY) ? + DB_LOCK_READ : DB_LOCK_WRITE, 0, &lock)) != 0) + goto err; + if ((ret = memp_fget(dbp->mpf, &t->q_meta, 0, (PAGE **)&meta)) != 0) + goto err; + + /* Get the metadata fields. */ + sp->qs_magic = meta->dbmeta.magic; + sp->qs_version = meta->dbmeta.version; + sp->qs_metaflags = meta->dbmeta.flags; + sp->qs_pagesize = meta->dbmeta.pagesize; + sp->qs_re_len = meta->re_len; + sp->qs_re_pad = meta->re_pad; + sp->qs_first_recno = meta->first_recno; + sp->qs_cur_recno = meta->cur_recno; + sp->qs_nkeys = sp->qs_ndata; + if (!F_ISSET(dbp, DB_AM_RDONLY)) + meta->dbmeta.key_count = + meta->dbmeta.record_count = sp->qs_ndata; + +done: + /* Discard the meta-data page. */ + if ((ret = memp_fput(dbp->mpf, + meta, F_ISSET(dbp, DB_AM_RDONLY) ? 0 : DB_MPOOL_DIRTY)) != 0) + goto err; + (void)__LPUT(dbc, lock); + + *(DB_QUEUE_STAT **)spp = sp; + ret = 0; + + if (0) { +err: if (sp != NULL) + __os_free(sp, sizeof(*sp)); + } + + if (lock.off != LOCK_INVALID) + (void)__LPUT(dbc, lock); + + if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0) + ret = t_ret; + + return (ret); +} diff --git a/db/qam/qam_upgrade.c b/db/qam/qam_upgrade.c new file mode 100644 index 000000000..f49bfe88d --- /dev/null +++ b/db/qam/qam_upgrade.c @@ -0,0 +1,111 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: qam_upgrade.c,v 11.7 2000/11/30 00:58:44 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_swap.h" +#include "db_am.h" +#include "db_upgrade.h" + +/* + * __qam_31_qammeta -- + * Upgrade the database from version 1 to version 2. + * + * PUBLIC: int __qam_31_qammeta __P((DB *, char *, u_int8_t *)); + */ +int +__qam_31_qammeta(dbp, real_name, buf) + DB *dbp; + char *real_name; + u_int8_t *buf; +{ + QMETA31 *newmeta; + QMETA30 *oldmeta; + + COMPQUIET(dbp, NULL); + COMPQUIET(real_name, NULL); + + newmeta = (QMETA31 *)buf; + oldmeta = (QMETA30 *)buf; + + /* + * Copy the fields to their new locations. + * They may overlap so start at the bottom and use memmove(). + */ + newmeta->rec_page = oldmeta->rec_page; + newmeta->re_pad = oldmeta->re_pad; + newmeta->re_len = oldmeta->re_len; + newmeta->cur_recno = oldmeta->cur_recno; + newmeta->first_recno = oldmeta->first_recno; + newmeta->start = oldmeta->start; + memmove(newmeta->dbmeta.uid, + oldmeta->dbmeta.uid, sizeof(oldmeta->dbmeta.uid)); + newmeta->dbmeta.flags = oldmeta->dbmeta.flags; + newmeta->dbmeta.record_count = 0; + newmeta->dbmeta.key_count = 0; + ZERO_LSN(newmeta->dbmeta.unused3); + + /* Update the version. */ + newmeta->dbmeta.version = 2; + + return (0); +} + +/* + * __qam_32_qammeta -- + * Upgrade the database from version 2 to version 3. + * + * PUBLIC: int __qam_32_qammeta __P((DB *, char *, u_int8_t *)); + */ +int +__qam_32_qammeta(dbp, real_name, buf) + DB *dbp; + char *real_name; + u_int8_t *buf; +{ + QMETA32 *newmeta; + QMETA31 *oldmeta; + + COMPQUIET(dbp, NULL); + COMPQUIET(real_name, NULL); + + newmeta = (QMETA32 *)buf; + oldmeta = (QMETA31 *)buf; + + /* + * Copy the fields to their new locations. + * We are dropping the first field so move + * from the top. + */ + newmeta->first_recno = oldmeta->first_recno; + newmeta->cur_recno = oldmeta->cur_recno; + newmeta->re_len = oldmeta->re_len; + newmeta->re_pad = oldmeta->re_pad; + newmeta->rec_page = oldmeta->rec_page; + newmeta->page_ext = 0; + /* cur_recno now points to the first free slot. */ + newmeta->cur_recno++; + if (newmeta->first_recno == 0) + newmeta->first_recno = 1; + + /* Update the version. */ + newmeta->dbmeta.version = 3; + + return (0); +} diff --git a/db/qam/qam_verify.c b/db/qam/qam_verify.c new file mode 100644 index 000000000..a9a467d67 --- /dev/null +++ b/db/qam/qam_verify.c @@ -0,0 +1,194 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: qam_verify.c,v 1.17 2000/12/12 17:39:35 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_verify.h" +#include "qam.h" +#include "db_ext.h" + +/* + * __qam_vrfy_meta -- + * Verify the queue-specific part of a metadata page. + * + * PUBLIC: int __qam_vrfy_meta __P((DB *, VRFY_DBINFO *, QMETA *, + * PUBLIC: db_pgno_t, u_int32_t)); + */ +int +__qam_vrfy_meta(dbp, vdp, meta, pgno, flags) + DB *dbp; + VRFY_DBINFO *vdp; + QMETA *meta; + db_pgno_t pgno; + u_int32_t flags; +{ + VRFY_PAGEINFO *pip; + int isbad, ret, t_ret; + + if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) + return (ret); + isbad = 0; + + /* + * Queue can't be used in subdatabases, so if this isn't set + * something very odd is going on. + */ + if (!F_ISSET(pip, VRFY_INCOMPLETE)) + EPRINT((dbp->dbenv, "Queue databases must be one-per-file.")); + + /* + * cur_recno/rec_page + * Cur_recno may be one beyond the end of the page and + * we start numbering from 1. + */ + if (vdp->last_pgno > 0 && meta->cur_recno > 0 && + meta->cur_recno - 1 > meta->rec_page * vdp->last_pgno) { + EPRINT((dbp->dbenv, + "Current recno %lu references record past last page number %lu", + meta->cur_recno, vdp->last_pgno)); + isbad = 1; + } + + /* + * re_len: If this is bad, we can't safely verify queue data pages, so + * return DB_VERIFY_FATAL + */ + if (ALIGN(meta->re_len + sizeof(QAMDATA) - 1, sizeof(u_int32_t)) * + meta->rec_page + sizeof(QPAGE) > dbp->pgsize) { + EPRINT((dbp->dbenv, + "Queue record length %lu impossibly high for page size and records per page", + meta->re_len)); + ret = DB_VERIFY_FATAL; + goto err; + } else { + vdp->re_len = meta->re_len; + vdp->rec_page = meta->rec_page; + } + +err: if ((t_ret = __db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0) + ret = t_ret; + return (ret == 0 && isbad == 1 ? DB_VERIFY_BAD : ret); +} + +/* + * __qam_vrfy_data -- + * Verify a queue data page. + * + * PUBLIC: int __qam_vrfy_data __P((DB *, VRFY_DBINFO *, QPAGE *, + * PUBLIC: db_pgno_t, u_int32_t)); + */ +int +__qam_vrfy_data(dbp, vdp, h, pgno, flags) + DB *dbp; + VRFY_DBINFO *vdp; + QPAGE *h; + db_pgno_t pgno; + u_int32_t flags; +{ + DB fakedb; + struct __queue fakeq; + QAMDATA *qp; + db_recno_t i; + u_int8_t qflags; + + /* + * Not much to do here, except make sure that flags are reasonable. + * + * QAM_GET_RECORD assumes a properly initialized q_internal + * structure, however, and we don't have one, so we play + * some gross games to fake it out. + */ + fakedb.q_internal = &fakeq; + fakeq.re_len = vdp->re_len; + + for (i = 0; i < vdp->rec_page; i++) { + qp = QAM_GET_RECORD(&fakedb, h, i); + if ((u_int8_t *)qp >= (u_int8_t *)h + dbp->pgsize) { + EPRINT((dbp->dbenv, + "Queue record %lu extends past end of page %lu", + i, pgno)); + return (DB_VERIFY_BAD); + } + + qflags = qp->flags; + qflags &= !(QAM_VALID | QAM_SET); + if (qflags != 0) { + EPRINT((dbp->dbenv, + "Queue record %lu on page %lu has bad flags", + i, pgno)); + return (DB_VERIFY_BAD); + } + } + + return (0); +} + +/* + * __qam_vrfy_structure -- + * Verify a queue database structure, such as it is. + * + * PUBLIC: int __qam_vrfy_structure __P((DB *, VRFY_DBINFO *, u_int32_t)); + */ +int +__qam_vrfy_structure(dbp, vdp, flags) + DB *dbp; + VRFY_DBINFO *vdp; + u_int32_t flags; +{ + VRFY_PAGEINFO *pip; + db_pgno_t i; + int ret, isbad; + + isbad = 0; + + if ((ret = __db_vrfy_getpageinfo(vdp, PGNO_BASE_MD, &pip)) != 0) + return (ret); + + if (pip->type != P_QAMMETA) { + EPRINT((dbp->dbenv, + "Queue database has no meta page")); + isbad = 1; + goto err; + } + + if ((ret = __db_vrfy_pgset_inc(vdp->pgset, 0)) != 0) + goto err; + + for (i = 1; i <= vdp->last_pgno; i++) { + /* Send feedback to the application about our progress. */ + if (!LF_ISSET(DB_SALVAGE)) + __db_vrfy_struct_feedback(dbp, vdp); + + if ((ret = __db_vrfy_putpageinfo(vdp, pip)) != 0 || + (ret = __db_vrfy_getpageinfo(vdp, i, &pip)) != 0) + return (ret); + if (!F_ISSET(pip, VRFY_IS_ALLZEROES) && + pip->type != P_QAMDATA) { + EPRINT((dbp->dbenv, + "Queue database page %lu of incorrect type %lu", + i, pip->type)); + isbad = 1; + goto err; + } else if ((ret = __db_vrfy_pgset_inc(vdp->pgset, i)) != 0) + goto err; + } + +err: if ((ret = __db_vrfy_putpageinfo(vdp, pip)) != 0) + return (ret); + return (isbad == 1 ? DB_VERIFY_BAD : 0); +} diff --git a/db/rpc_client/client.c b/db/rpc_client/client.c new file mode 100644 index 000000000..70744f54b --- /dev/null +++ b/db/rpc_client/client.c @@ -0,0 +1,371 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: client.c,v 1.21 2000/11/30 00:58:44 ubell Exp $"; +#endif /* not lint */ + +#ifdef HAVE_RPC +#ifndef NO_SYSTEM_INCLUDES +#include + +#include + +#include +#include +#include +#include +#endif +#include "db_server.h" + +#include "db_int.h" +#include "txn.h" +#include "gen_client_ext.h" +#include "rpc_client_ext.h" + +/* + * __dbclenv_server -- + * Initialize an environment's server. + * + * PUBLIC: int __dbcl_envserver __P((DB_ENV *, char *, long, long, u_int32_t)); + */ +int +__dbcl_envserver(dbenv, host, tsec, ssec, flags) + DB_ENV *dbenv; + char *host; + long tsec, ssec; + u_int32_t flags; +{ + CLIENT *cl; + __env_create_msg req; + __env_create_reply *replyp; + struct timeval tp; + int ret; + + COMPQUIET(flags, 0); + +#ifdef HAVE_VXWORKS + if ((ret = rpcTaskInit()) != 0) { + __db_err(dbenv, "Could not initialize VxWorks RPC"); + return (ERROR); + } +#endif + if ((cl = + clnt_create(host, DB_SERVERPROG, DB_SERVERVERS, "tcp")) == NULL) { + __db_err(dbenv, clnt_spcreateerror(host)); + return (DB_NOSERVER); + } + dbenv->cl_handle = cl; + + if (tsec != 0) { + tp.tv_sec = tsec; + tp.tv_usec = 0; + (void)clnt_control(cl, CLSET_TIMEOUT, (char *)&tp); + } + + req.timeout = ssec; + /* + * CALL THE SERVER + */ + if ((replyp = __db_env_create_1(&req, cl)) == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + return (DB_NOSERVER); + } + + /* + * Process reply and free up our space from request + * SUCCESS: Store ID from server. + */ + if ((ret = replyp->status) != 0) + return (ret); + + dbenv->cl_id = replyp->envcl_id; + return (0); +} + +/* + * __dbcl_refresh -- + * Clean up an environment. + * + * PUBLIC: int __dbcl_refresh __P((DB_ENV *)); + */ +int +__dbcl_refresh(dbenv) + DB_ENV *dbenv; +{ + CLIENT *cl; + int ret; + + cl = (CLIENT *)dbenv->cl_handle; + + ret = 0; + if (dbenv->tx_handle != NULL) { + /* + * We only need to free up our stuff, the caller + * of this function will call the server who will + * do all the real work. + */ + ret = __dbcl_txn_close(dbenv); + dbenv->tx_handle = NULL; + } + if (cl != NULL) + clnt_destroy(cl); + dbenv->cl_handle = NULL; + return (ret); +} + +/* + * __dbcl_txn_close -- + * Clean up an environment's transactions. + * + * PUBLIC: int __dbcl_txn_close __P((DB_ENV *)); + */ +int +__dbcl_txn_close(dbenv) + DB_ENV *dbenv; +{ + DB_TXN *txnp; + DB_TXNMGR *tmgrp; + int ret; + + ret = 0; + tmgrp = dbenv->tx_handle; + + /* + * This function can only be called once per process (i.e., not + * once per thread), so no synchronization is required. + * Also this function is called *after* the server has been called, + * so the server has already closed/aborted any transactions that + * were open on its side. We only need to do local cleanup. + */ + while ((txnp = TAILQ_FIRST(&tmgrp->txn_chain)) != NULL) + __dbcl_txn_end(txnp); + + __os_free(tmgrp, sizeof(*tmgrp)); + return (ret); + +} + +/* + * __dbcl_txn_end -- + * Clean up an transaction. + * RECURSIVE FUNCTION: Clean up nested transactions. + * + * PUBLIC: void __dbcl_txn_end __P((DB_TXN *)); + */ +void +__dbcl_txn_end(txnp) + DB_TXN *txnp; +{ + DB_ENV *dbenv; + DB_TXN *kids; + DB_TXNMGR *mgr; + + mgr = txnp->mgrp; + dbenv = mgr->dbenv; + + /* + * First take care of any kids we have + */ + for (kids = TAILQ_FIRST(&txnp->kids); + kids != NULL; + kids = TAILQ_FIRST(&txnp->kids)) + __dbcl_txn_end(kids); + + /* + * We are ending this transaction no matter what the parent + * may eventually do, if we have a parent. All those details + * are taken care of by the server. We only need to make sure + * that we properly release resources. + */ + if (txnp->parent != NULL) + TAILQ_REMOVE(&txnp->parent->kids, txnp, klinks); + TAILQ_REMOVE(&mgr->txn_chain, txnp, links); + __os_free(txnp, sizeof(*txnp)); + + return; +} + +/* + * __dbcl_c_destroy -- + * Destroy a cursor. + * + * PUBLIC: int __dbcl_c_destroy __P((DBC *)); + */ +int +__dbcl_c_destroy(dbc) + DBC *dbc; +{ + DB *dbp; + + dbp = dbc->dbp; + + TAILQ_REMOVE(&dbp->free_queue, dbc, links); + __os_free(dbc, sizeof(*dbc)); + + return (0); +} + +/* + * __dbcl_c_refresh -- + * Refresh a cursor. Move it from the active queue to the free queue. + * + * PUBLIC: void __dbcl_c_refresh __P((DBC *)); + */ +void +__dbcl_c_refresh(dbcp) + DBC *dbcp; +{ + DB *dbp; + + dbp = dbcp->dbp; + dbcp->flags = 0; + dbcp->cl_id = 0; + + /* + * If dbp->cursor fails locally, we use a local dbc so that + * we can close it. In that case, dbp will be NULL. + */ + if (dbp != NULL) { + TAILQ_REMOVE(&dbp->active_queue, dbcp, links); + TAILQ_INSERT_TAIL(&dbp->free_queue, dbcp, links); + } + return; +} + +/* + * __dbcl_c_setup -- + * Allocate a cursor. + * + * PUBLIC: int __dbcl_c_setup __P((long, DB *, DBC **)); + */ +int +__dbcl_c_setup(cl_id, dbp, dbcpp) + long cl_id; + DB *dbp; + DBC **dbcpp; +{ + DBC *dbc, tmpdbc; + int ret, t_ret; + + if ((dbc = TAILQ_FIRST(&dbp->free_queue)) != NULL) + TAILQ_REMOVE(&dbp->free_queue, dbc, links); + else { + if ((ret = + __os_calloc(dbp->dbenv, 1, sizeof(DBC), &dbc)) != 0) { + /* + * If we die here, set up a tmp dbc to call the + * server to shut down that cursor. + */ + tmpdbc.dbp = NULL; + tmpdbc.cl_id = cl_id; + t_ret = __dbcl_dbc_close(&tmpdbc); + return (ret); + } + dbc->c_close = __dbcl_dbc_close; + dbc->c_count = __dbcl_dbc_count; + dbc->c_del = __dbcl_dbc_del; + dbc->c_dup = __dbcl_dbc_dup; + dbc->c_get = __dbcl_dbc_get; + dbc->c_put = __dbcl_dbc_put; + dbc->c_am_destroy = __dbcl_c_destroy; + } + dbc->cl_id = cl_id; + dbc->dbp = dbp; + TAILQ_INSERT_TAIL(&dbp->active_queue, dbc, links); + *dbcpp = dbc; + return (0); +} + +/* + * __dbcl_retcopy -- + * Copy the returned data into the user's DBT, handling special flags + * as they apply to a client. Modeled after __db_retcopy(). + * + * PUBLIC: int __dbcl_retcopy __P((DB_ENV *, DBT *, void *, u_int32_t)); + */ +int +__dbcl_retcopy(dbenv, dbt, data, len) + DB_ENV *dbenv; + DBT *dbt; + void *data; + u_int32_t len; +{ + int ret; + + /* + * No need to handle DB_DBT_PARTIAL here, server already did. + */ + dbt->size = len; + + /* + * Allocate memory to be owned by the application: DB_DBT_MALLOC + * and DB_DBT_REALLOC. Always allocate even if we're copying 0 bytes. + * Or use memory specified by application: DB_DBT_USERMEM. + */ + if (F_ISSET(dbt, DB_DBT_MALLOC)) { + if ((ret = __os_malloc(dbenv, len, NULL, &dbt->data)) != 0) + return (ret); + } else if (F_ISSET(dbt, DB_DBT_REALLOC)) { + if ((ret = __os_realloc(dbenv, len, NULL, &dbt->data)) != 0) + return (ret); + } else if (F_ISSET(dbt, DB_DBT_USERMEM)) { + if (len != 0 && (dbt->data == NULL || dbt->ulen < len)) + return (ENOMEM); + } else { + /* + * If no user flags, then set the DBT to point to the + * returned data pointer and return. + */ + dbt->data = data; + return (0); + } + + if (len != 0) + memcpy(dbt->data, data, len); + return (0); +} + +/* + * __dbcl_dbclose_common -- + * Common code for closing/cleaning a dbp. + * + * PUBLIC: int __dbcl_dbclose_common __P((DB *)); + */ +int +__dbcl_dbclose_common(dbp) + DB *dbp; +{ + int ret, t_ret; + DBC *dbc; + + /* + * Go through the active cursors and call the cursor recycle routine, + * which resolves pending operations and moves the cursors onto the + * free list. Then, walk the free list and call the cursor destroy + * routine. + * + * NOTE: We do not need to use the join_queue for join cursors. + * See comment in __dbcl_dbjoin_ret. + */ + ret = 0; + while ((dbc = TAILQ_FIRST(&dbp->active_queue)) != NULL) + __dbcl_c_refresh(dbc); + while ((dbc = TAILQ_FIRST(&dbp->free_queue)) != NULL) + if ((t_ret = __dbcl_c_destroy(dbc)) != 0 && ret == 0) + ret = t_ret; + + TAILQ_INIT(&dbp->free_queue); + TAILQ_INIT(&dbp->active_queue); + + memset(dbp, CLEAR_BYTE, sizeof(*dbp)); + __os_free(dbp, sizeof(*dbp)); + return (ret); +} +#endif /* HAVE_RPC */ diff --git a/db/rpc_client/db_server_clnt.c b/db/rpc_client/db_server_clnt.c new file mode 100644 index 000000000..680a26144 --- /dev/null +++ b/db/rpc_client/db_server_clnt.c @@ -0,0 +1,692 @@ +#include "db_config.h" +#ifdef HAVE_RPC +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#include "db_server.h" + +/* Default timeout can be changed using clnt_control() */ +static struct timeval TIMEOUT = { 25, 0 }; + +__env_cachesize_reply * +__db_env_cachesize_1(argp, clnt) + __env_cachesize_msg *argp; + CLIENT *clnt; +{ + static __env_cachesize_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_env_cachesize, + (xdrproc_t) xdr___env_cachesize_msg, (caddr_t) argp, + (xdrproc_t) xdr___env_cachesize_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__env_close_reply * +__db_env_close_1(argp, clnt) + __env_close_msg *argp; + CLIENT *clnt; +{ + static __env_close_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_env_close, + (xdrproc_t) xdr___env_close_msg, (caddr_t) argp, + (xdrproc_t) xdr___env_close_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__env_create_reply * +__db_env_create_1(argp, clnt) + __env_create_msg *argp; + CLIENT *clnt; +{ + static __env_create_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_env_create, + (xdrproc_t) xdr___env_create_msg, (caddr_t) argp, + (xdrproc_t) xdr___env_create_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__env_flags_reply * +__db_env_flags_1(argp, clnt) + __env_flags_msg *argp; + CLIENT *clnt; +{ + static __env_flags_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_env_flags, + (xdrproc_t) xdr___env_flags_msg, (caddr_t) argp, + (xdrproc_t) xdr___env_flags_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__env_open_reply * +__db_env_open_1(argp, clnt) + __env_open_msg *argp; + CLIENT *clnt; +{ + static __env_open_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_env_open, + (xdrproc_t) xdr___env_open_msg, (caddr_t) argp, + (xdrproc_t) xdr___env_open_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__env_remove_reply * +__db_env_remove_1(argp, clnt) + __env_remove_msg *argp; + CLIENT *clnt; +{ + static __env_remove_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_env_remove, + (xdrproc_t) xdr___env_remove_msg, (caddr_t) argp, + (xdrproc_t) xdr___env_remove_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__txn_abort_reply * +__db_txn_abort_1(argp, clnt) + __txn_abort_msg *argp; + CLIENT *clnt; +{ + static __txn_abort_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_txn_abort, + (xdrproc_t) xdr___txn_abort_msg, (caddr_t) argp, + (xdrproc_t) xdr___txn_abort_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__txn_begin_reply * +__db_txn_begin_1(argp, clnt) + __txn_begin_msg *argp; + CLIENT *clnt; +{ + static __txn_begin_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_txn_begin, + (xdrproc_t) xdr___txn_begin_msg, (caddr_t) argp, + (xdrproc_t) xdr___txn_begin_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__txn_commit_reply * +__db_txn_commit_1(argp, clnt) + __txn_commit_msg *argp; + CLIENT *clnt; +{ + static __txn_commit_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_txn_commit, + (xdrproc_t) xdr___txn_commit_msg, (caddr_t) argp, + (xdrproc_t) xdr___txn_commit_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__db_bt_maxkey_reply * +__db_db_bt_maxkey_1(argp, clnt) + __db_bt_maxkey_msg *argp; + CLIENT *clnt; +{ + static __db_bt_maxkey_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_db_bt_maxkey, + (xdrproc_t) xdr___db_bt_maxkey_msg, (caddr_t) argp, + (xdrproc_t) xdr___db_bt_maxkey_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__db_bt_minkey_reply * +__db_db_bt_minkey_1(argp, clnt) + __db_bt_minkey_msg *argp; + CLIENT *clnt; +{ + static __db_bt_minkey_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_db_bt_minkey, + (xdrproc_t) xdr___db_bt_minkey_msg, (caddr_t) argp, + (xdrproc_t) xdr___db_bt_minkey_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__db_close_reply * +__db_db_close_1(argp, clnt) + __db_close_msg *argp; + CLIENT *clnt; +{ + static __db_close_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_db_close, + (xdrproc_t) xdr___db_close_msg, (caddr_t) argp, + (xdrproc_t) xdr___db_close_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__db_create_reply * +__db_db_create_1(argp, clnt) + __db_create_msg *argp; + CLIENT *clnt; +{ + static __db_create_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_db_create, + (xdrproc_t) xdr___db_create_msg, (caddr_t) argp, + (xdrproc_t) xdr___db_create_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__db_del_reply * +__db_db_del_1(argp, clnt) + __db_del_msg *argp; + CLIENT *clnt; +{ + static __db_del_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_db_del, + (xdrproc_t) xdr___db_del_msg, (caddr_t) argp, + (xdrproc_t) xdr___db_del_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__db_extentsize_reply * +__db_db_extentsize_1(argp, clnt) + __db_extentsize_msg *argp; + CLIENT *clnt; +{ + static __db_extentsize_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_db_extentsize, + (xdrproc_t) xdr___db_extentsize_msg, (caddr_t) argp, + (xdrproc_t) xdr___db_extentsize_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__db_flags_reply * +__db_db_flags_1(argp, clnt) + __db_flags_msg *argp; + CLIENT *clnt; +{ + static __db_flags_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_db_flags, + (xdrproc_t) xdr___db_flags_msg, (caddr_t) argp, + (xdrproc_t) xdr___db_flags_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__db_get_reply * +__db_db_get_1(argp, clnt) + __db_get_msg *argp; + CLIENT *clnt; +{ + static __db_get_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_db_get, + (xdrproc_t) xdr___db_get_msg, (caddr_t) argp, + (xdrproc_t) xdr___db_get_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__db_h_ffactor_reply * +__db_db_h_ffactor_1(argp, clnt) + __db_h_ffactor_msg *argp; + CLIENT *clnt; +{ + static __db_h_ffactor_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_db_h_ffactor, + (xdrproc_t) xdr___db_h_ffactor_msg, (caddr_t) argp, + (xdrproc_t) xdr___db_h_ffactor_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__db_h_nelem_reply * +__db_db_h_nelem_1(argp, clnt) + __db_h_nelem_msg *argp; + CLIENT *clnt; +{ + static __db_h_nelem_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_db_h_nelem, + (xdrproc_t) xdr___db_h_nelem_msg, (caddr_t) argp, + (xdrproc_t) xdr___db_h_nelem_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__db_key_range_reply * +__db_db_key_range_1(argp, clnt) + __db_key_range_msg *argp; + CLIENT *clnt; +{ + static __db_key_range_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_db_key_range, + (xdrproc_t) xdr___db_key_range_msg, (caddr_t) argp, + (xdrproc_t) xdr___db_key_range_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__db_lorder_reply * +__db_db_lorder_1(argp, clnt) + __db_lorder_msg *argp; + CLIENT *clnt; +{ + static __db_lorder_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_db_lorder, + (xdrproc_t) xdr___db_lorder_msg, (caddr_t) argp, + (xdrproc_t) xdr___db_lorder_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__db_open_reply * +__db_db_open_1(argp, clnt) + __db_open_msg *argp; + CLIENT *clnt; +{ + static __db_open_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_db_open, + (xdrproc_t) xdr___db_open_msg, (caddr_t) argp, + (xdrproc_t) xdr___db_open_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__db_pagesize_reply * +__db_db_pagesize_1(argp, clnt) + __db_pagesize_msg *argp; + CLIENT *clnt; +{ + static __db_pagesize_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_db_pagesize, + (xdrproc_t) xdr___db_pagesize_msg, (caddr_t) argp, + (xdrproc_t) xdr___db_pagesize_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__db_put_reply * +__db_db_put_1(argp, clnt) + __db_put_msg *argp; + CLIENT *clnt; +{ + static __db_put_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_db_put, + (xdrproc_t) xdr___db_put_msg, (caddr_t) argp, + (xdrproc_t) xdr___db_put_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__db_re_delim_reply * +__db_db_re_delim_1(argp, clnt) + __db_re_delim_msg *argp; + CLIENT *clnt; +{ + static __db_re_delim_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_db_re_delim, + (xdrproc_t) xdr___db_re_delim_msg, (caddr_t) argp, + (xdrproc_t) xdr___db_re_delim_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__db_re_len_reply * +__db_db_re_len_1(argp, clnt) + __db_re_len_msg *argp; + CLIENT *clnt; +{ + static __db_re_len_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_db_re_len, + (xdrproc_t) xdr___db_re_len_msg, (caddr_t) argp, + (xdrproc_t) xdr___db_re_len_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__db_re_pad_reply * +__db_db_re_pad_1(argp, clnt) + __db_re_pad_msg *argp; + CLIENT *clnt; +{ + static __db_re_pad_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_db_re_pad, + (xdrproc_t) xdr___db_re_pad_msg, (caddr_t) argp, + (xdrproc_t) xdr___db_re_pad_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__db_remove_reply * +__db_db_remove_1(argp, clnt) + __db_remove_msg *argp; + CLIENT *clnt; +{ + static __db_remove_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_db_remove, + (xdrproc_t) xdr___db_remove_msg, (caddr_t) argp, + (xdrproc_t) xdr___db_remove_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__db_rename_reply * +__db_db_rename_1(argp, clnt) + __db_rename_msg *argp; + CLIENT *clnt; +{ + static __db_rename_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_db_rename, + (xdrproc_t) xdr___db_rename_msg, (caddr_t) argp, + (xdrproc_t) xdr___db_rename_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__db_stat_reply * +__db_db_stat_1(argp, clnt) + __db_stat_msg *argp; + CLIENT *clnt; +{ + static __db_stat_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_db_stat, + (xdrproc_t) xdr___db_stat_msg, (caddr_t) argp, + (xdrproc_t) xdr___db_stat_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__db_swapped_reply * +__db_db_swapped_1(argp, clnt) + __db_swapped_msg *argp; + CLIENT *clnt; +{ + static __db_swapped_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_db_swapped, + (xdrproc_t) xdr___db_swapped_msg, (caddr_t) argp, + (xdrproc_t) xdr___db_swapped_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__db_sync_reply * +__db_db_sync_1(argp, clnt) + __db_sync_msg *argp; + CLIENT *clnt; +{ + static __db_sync_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_db_sync, + (xdrproc_t) xdr___db_sync_msg, (caddr_t) argp, + (xdrproc_t) xdr___db_sync_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__db_cursor_reply * +__db_db_cursor_1(argp, clnt) + __db_cursor_msg *argp; + CLIENT *clnt; +{ + static __db_cursor_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_db_cursor, + (xdrproc_t) xdr___db_cursor_msg, (caddr_t) argp, + (xdrproc_t) xdr___db_cursor_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__db_join_reply * +__db_db_join_1(argp, clnt) + __db_join_msg *argp; + CLIENT *clnt; +{ + static __db_join_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_db_join, + (xdrproc_t) xdr___db_join_msg, (caddr_t) argp, + (xdrproc_t) xdr___db_join_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__dbc_close_reply * +__db_dbc_close_1(argp, clnt) + __dbc_close_msg *argp; + CLIENT *clnt; +{ + static __dbc_close_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_dbc_close, + (xdrproc_t) xdr___dbc_close_msg, (caddr_t) argp, + (xdrproc_t) xdr___dbc_close_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__dbc_count_reply * +__db_dbc_count_1(argp, clnt) + __dbc_count_msg *argp; + CLIENT *clnt; +{ + static __dbc_count_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_dbc_count, + (xdrproc_t) xdr___dbc_count_msg, (caddr_t) argp, + (xdrproc_t) xdr___dbc_count_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__dbc_del_reply * +__db_dbc_del_1(argp, clnt) + __dbc_del_msg *argp; + CLIENT *clnt; +{ + static __dbc_del_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_dbc_del, + (xdrproc_t) xdr___dbc_del_msg, (caddr_t) argp, + (xdrproc_t) xdr___dbc_del_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__dbc_dup_reply * +__db_dbc_dup_1(argp, clnt) + __dbc_dup_msg *argp; + CLIENT *clnt; +{ + static __dbc_dup_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_dbc_dup, + (xdrproc_t) xdr___dbc_dup_msg, (caddr_t) argp, + (xdrproc_t) xdr___dbc_dup_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__dbc_get_reply * +__db_dbc_get_1(argp, clnt) + __dbc_get_msg *argp; + CLIENT *clnt; +{ + static __dbc_get_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_dbc_get, + (xdrproc_t) xdr___dbc_get_msg, (caddr_t) argp, + (xdrproc_t) xdr___dbc_get_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +__dbc_put_reply * +__db_dbc_put_1(argp, clnt) + __dbc_put_msg *argp; + CLIENT *clnt; +{ + static __dbc_put_reply clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, __DB_dbc_put, + (xdrproc_t) xdr___dbc_put_msg, (caddr_t) argp, + (xdrproc_t) xdr___dbc_put_reply, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} +#endif /* HAVE_RPC */ diff --git a/db/rpc_client/gen_client.c b/db/rpc_client/gen_client.c new file mode 100644 index 000000000..7cc598e7d --- /dev/null +++ b/db/rpc_client/gen_client.c @@ -0,0 +1,2494 @@ +/* Do not edit: automatically built by gen_rpc.awk. */ +#include "db_config.h" + +#ifdef HAVE_RPC +#ifndef NO_SYSTEM_INCLUDES +#include +#include +#include + +#include +#include +#endif +#include "db_server.h" + +#include "db_int.h" +#include "db_page.h" +#include "db_ext.h" +#include "mp.h" +#include "rpc_client_ext.h" +#include "txn.h" + +#include "gen_client_ext.h" + +int +__dbcl_env_cachesize(dbenv, gbytes, bytes, ncache) + DB_ENV * dbenv; + u_int32_t gbytes; + u_int32_t bytes; + int ncache; +{ + CLIENT *cl; + __env_cachesize_msg req; + static __env_cachesize_reply *replyp = NULL; + int ret; + + ret = 0; + if (dbenv == NULL || dbenv->cl_handle == NULL) { + __db_err(dbenv, "No server environment."); + return (DB_NOSERVER); + } + + if (replyp != NULL) { + xdr_free((xdrproc_t)xdr___env_cachesize_reply, (void *)replyp); + replyp = NULL; + } + cl = (CLIENT *)dbenv->cl_handle; + + if (dbenv == NULL) + req.dbenvcl_id = 0; + else + req.dbenvcl_id = dbenv->cl_id; + req.gbytes = gbytes; + req.bytes = bytes; + req.ncache = ncache; + + replyp = __db_env_cachesize_1(&req, cl); + if (replyp == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + ret = DB_NOSERVER; + goto out; + } + ret = replyp->status; +out: + return (ret); +} + +int +__dbcl_env_close(dbenv, flags) + DB_ENV * dbenv; + u_int32_t flags; +{ + CLIENT *cl; + __env_close_msg req; + static __env_close_reply *replyp = NULL; + int ret; + + ret = 0; + if (dbenv == NULL || dbenv->cl_handle == NULL) { + __db_err(dbenv, "No server environment."); + return (DB_NOSERVER); + } + + if (replyp != NULL) { + xdr_free((xdrproc_t)xdr___env_close_reply, (void *)replyp); + replyp = NULL; + } + cl = (CLIENT *)dbenv->cl_handle; + + if (dbenv == NULL) + req.dbenvcl_id = 0; + else + req.dbenvcl_id = dbenv->cl_id; + req.flags = flags; + + replyp = __db_env_close_1(&req, cl); + if (replyp == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + ret = DB_NOSERVER; + goto out; + } + return (__dbcl_env_close_ret(dbenv, flags, replyp)); +out: + return (ret); +} + +int +__dbcl_rpc_illegal(dbenv, name) + DB_ENV *dbenv; + char *name; +{ + __db_err(dbenv, + "%s method meaningless in RPC environment", name); + return (__db_eopnotsup(dbenv)); +} + +int +__dbcl_set_data_dir(dbenv, dir) + DB_ENV * dbenv; + const char * dir; +{ + COMPQUIET(dir, NULL); + return (__dbcl_rpc_illegal(dbenv, "set_data_dir")); +} + +int +__dbcl_env_set_feedback(dbenv, func0) + DB_ENV * dbenv; + void (*func0) __P((DB_ENV *, int, int)); +{ + COMPQUIET(func0, 0); + return (__dbcl_rpc_illegal(dbenv, "env_set_feedback")); +} + +int +__dbcl_env_flags(dbenv, flags, onoff) + DB_ENV * dbenv; + u_int32_t flags; + int onoff; +{ + CLIENT *cl; + __env_flags_msg req; + static __env_flags_reply *replyp = NULL; + int ret; + + ret = 0; + if (dbenv == NULL || dbenv->cl_handle == NULL) { + __db_err(dbenv, "No server environment."); + return (DB_NOSERVER); + } + + if (replyp != NULL) { + xdr_free((xdrproc_t)xdr___env_flags_reply, (void *)replyp); + replyp = NULL; + } + cl = (CLIENT *)dbenv->cl_handle; + + if (dbenv == NULL) + req.dbenvcl_id = 0; + else + req.dbenvcl_id = dbenv->cl_id; + req.flags = flags; + req.onoff = onoff; + + replyp = __db_env_flags_1(&req, cl); + if (replyp == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + ret = DB_NOSERVER; + goto out; + } + ret = replyp->status; +out: + return (ret); +} + +int +__dbcl_set_lg_bsize(dbenv, bsize) + DB_ENV * dbenv; + u_int32_t bsize; +{ + COMPQUIET(bsize, 0); + return (__dbcl_rpc_illegal(dbenv, "set_lg_bsize")); +} + +int +__dbcl_set_lg_dir(dbenv, dir) + DB_ENV * dbenv; + const char * dir; +{ + COMPQUIET(dir, NULL); + return (__dbcl_rpc_illegal(dbenv, "set_lg_dir")); +} + +int +__dbcl_set_lg_max(dbenv, max) + DB_ENV * dbenv; + u_int32_t max; +{ + COMPQUIET(max, 0); + return (__dbcl_rpc_illegal(dbenv, "set_lg_max")); +} + +int +__dbcl_set_lk_conflict(dbenv, conflicts, modes) + DB_ENV * dbenv; + u_int8_t * conflicts; + int modes; +{ + COMPQUIET(conflicts, 0); + COMPQUIET(modes, 0); + return (__dbcl_rpc_illegal(dbenv, "set_lk_conflict")); +} + +int +__dbcl_set_lk_detect(dbenv, detect) + DB_ENV * dbenv; + u_int32_t detect; +{ + COMPQUIET(detect, 0); + return (__dbcl_rpc_illegal(dbenv, "set_lk_detect")); +} + +int +__dbcl_set_lk_max(dbenv, max) + DB_ENV * dbenv; + u_int32_t max; +{ + COMPQUIET(max, 0); + return (__dbcl_rpc_illegal(dbenv, "set_lk_max")); +} + +int +__dbcl_set_lk_max_locks(dbenv, max) + DB_ENV * dbenv; + u_int32_t max; +{ + COMPQUIET(max, 0); + return (__dbcl_rpc_illegal(dbenv, "set_lk_max_locks")); +} + +int +__dbcl_set_lk_max_lockers(dbenv, max) + DB_ENV * dbenv; + u_int32_t max; +{ + COMPQUIET(max, 0); + return (__dbcl_rpc_illegal(dbenv, "set_lk_max_lockers")); +} + +int +__dbcl_set_lk_max_objects(dbenv, max) + DB_ENV * dbenv; + u_int32_t max; +{ + COMPQUIET(max, 0); + return (__dbcl_rpc_illegal(dbenv, "set_lk_max_objects")); +} + +int +__dbcl_set_mp_mmapsize(dbenv, mmapsize) + DB_ENV * dbenv; + size_t mmapsize; +{ + COMPQUIET(mmapsize, 0); + return (__dbcl_rpc_illegal(dbenv, "set_mp_mmapsize")); +} + +int +__dbcl_set_mutex_locks(dbenv, do_lock) + DB_ENV * dbenv; + int do_lock; +{ + COMPQUIET(do_lock, 0); + return (__dbcl_rpc_illegal(dbenv, "set_mutex_locks")); +} + +int +__dbcl_env_open(dbenv, home, flags, mode) + DB_ENV * dbenv; + const char * home; + u_int32_t flags; + int mode; +{ + CLIENT *cl; + __env_open_msg req; + static __env_open_reply *replyp = NULL; + int ret; + + ret = 0; + if (dbenv == NULL || dbenv->cl_handle == NULL) { + __db_err(dbenv, "No server environment."); + return (DB_NOSERVER); + } + + if (replyp != NULL) { + xdr_free((xdrproc_t)xdr___env_open_reply, (void *)replyp); + replyp = NULL; + } + cl = (CLIENT *)dbenv->cl_handle; + + if (dbenv == NULL) + req.dbenvcl_id = 0; + else + req.dbenvcl_id = dbenv->cl_id; + if (home == NULL) + req.home = ""; + else + req.home = (char *)home; + req.flags = flags; + req.mode = mode; + + replyp = __db_env_open_1(&req, cl); + if (replyp == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + ret = DB_NOSERVER; + goto out; + } + return (__dbcl_env_open_ret(dbenv, home, flags, mode, replyp)); +out: + return (ret); +} + +int +__dbcl_env_paniccall(dbenv, func0) + DB_ENV * dbenv; + void (*func0) __P((DB_ENV *, int)); +{ + COMPQUIET(func0, 0); + return (__dbcl_rpc_illegal(dbenv, "env_paniccall")); +} + +int +__dbcl_set_recovery_init(dbenv, func0) + DB_ENV * dbenv; + int (*func0) __P((DB_ENV *)); +{ + COMPQUIET(func0, 0); + return (__dbcl_rpc_illegal(dbenv, "set_recovery_init")); +} + +int +__dbcl_env_remove(dbenv, home, flags) + DB_ENV * dbenv; + const char * home; + u_int32_t flags; +{ + CLIENT *cl; + __env_remove_msg req; + static __env_remove_reply *replyp = NULL; + int ret; + + ret = 0; + if (dbenv == NULL || dbenv->cl_handle == NULL) { + __db_err(dbenv, "No server environment."); + return (DB_NOSERVER); + } + + if (replyp != NULL) { + xdr_free((xdrproc_t)xdr___env_remove_reply, (void *)replyp); + replyp = NULL; + } + cl = (CLIENT *)dbenv->cl_handle; + + if (dbenv == NULL) + req.dbenvcl_id = 0; + else + req.dbenvcl_id = dbenv->cl_id; + if (home == NULL) + req.home = ""; + else + req.home = (char *)home; + req.flags = flags; + + replyp = __db_env_remove_1(&req, cl); + if (replyp == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + ret = DB_NOSERVER; + goto out; + } + return (__dbcl_env_remove_ret(dbenv, home, flags, replyp)); +out: + return (ret); +} + +int +__dbcl_set_shm_key(dbenv, shm_key) + DB_ENV * dbenv; + long shm_key; +{ + COMPQUIET(shm_key, 0); + return (__dbcl_rpc_illegal(dbenv, "set_shm_key")); +} + +int +__dbcl_set_tmp_dir(dbenv, dir) + DB_ENV * dbenv; + const char * dir; +{ + COMPQUIET(dir, NULL); + return (__dbcl_rpc_illegal(dbenv, "set_tmp_dir")); +} + +int +__dbcl_set_tx_recover(dbenv, func0) + DB_ENV * dbenv; + int (*func0) __P((DB_ENV *, DBT *, DB_LSN *, db_recops)); +{ + COMPQUIET(func0, 0); + return (__dbcl_rpc_illegal(dbenv, "set_tx_recover")); +} + +int +__dbcl_set_tx_max(dbenv, max) + DB_ENV * dbenv; + u_int32_t max; +{ + COMPQUIET(max, 0); + return (__dbcl_rpc_illegal(dbenv, "set_tx_max")); +} + +int +__dbcl_set_tx_timestamp(dbenv, max) + DB_ENV * dbenv; + time_t * max; +{ + COMPQUIET(max, 0); + return (__dbcl_rpc_illegal(dbenv, "set_tx_timestamp")); +} + +int +__dbcl_set_verbose(dbenv, which, onoff) + DB_ENV * dbenv; + u_int32_t which; + int onoff; +{ + COMPQUIET(which, 0); + COMPQUIET(onoff, 0); + return (__dbcl_rpc_illegal(dbenv, "set_verbose")); +} + +int +__dbcl_txn_abort(txnp) + DB_TXN * txnp; +{ + CLIENT *cl; + __txn_abort_msg req; + static __txn_abort_reply *replyp = NULL; + int ret; + DB_ENV *dbenv; + + ret = 0; + dbenv = NULL; + dbenv = txnp->mgrp->dbenv; + if (dbenv == NULL || dbenv->cl_handle == NULL) { + __db_err(dbenv, "No server environment."); + return (DB_NOSERVER); + } + + if (replyp != NULL) { + xdr_free((xdrproc_t)xdr___txn_abort_reply, (void *)replyp); + replyp = NULL; + } + cl = (CLIENT *)dbenv->cl_handle; + + if (txnp == NULL) + req.txnpcl_id = 0; + else + req.txnpcl_id = txnp->txnid; + + replyp = __db_txn_abort_1(&req, cl); + if (replyp == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + ret = DB_NOSERVER; + goto out; + } + return (__dbcl_txn_abort_ret(txnp, replyp)); +out: + return (ret); +} + +int +__dbcl_txn_begin(envp, parent, txnpp, flags) + DB_ENV * envp; + DB_TXN * parent; + DB_TXN ** txnpp; + u_int32_t flags; +{ + CLIENT *cl; + __txn_begin_msg req; + static __txn_begin_reply *replyp = NULL; + int ret; + + ret = 0; + if (envp == NULL || envp->cl_handle == NULL) { + __db_err(envp, "No server environment."); + return (DB_NOSERVER); + } + + if (replyp != NULL) { + xdr_free((xdrproc_t)xdr___txn_begin_reply, (void *)replyp); + replyp = NULL; + } + cl = (CLIENT *)envp->cl_handle; + + if (envp == NULL) + req.envpcl_id = 0; + else + req.envpcl_id = envp->cl_id; + if (parent == NULL) + req.parentcl_id = 0; + else + req.parentcl_id = parent->txnid; + req.flags = flags; + + replyp = __db_txn_begin_1(&req, cl); + if (replyp == NULL) { + __db_err(envp, clnt_sperror(cl, "Berkeley DB")); + ret = DB_NOSERVER; + goto out; + } + return (__dbcl_txn_begin_ret(envp, parent, txnpp, flags, replyp)); +out: + return (ret); +} + +int +__dbcl_txn_checkpoint(dbenv, kbyte, min) + DB_ENV * dbenv; + u_int32_t kbyte; + u_int32_t min; +{ + COMPQUIET(kbyte, 0); + COMPQUIET(min, 0); + return (__dbcl_rpc_illegal(dbenv, "txn_checkpoint")); +} + +int +__dbcl_txn_commit(txnp, flags) + DB_TXN * txnp; + u_int32_t flags; +{ + CLIENT *cl; + __txn_commit_msg req; + static __txn_commit_reply *replyp = NULL; + int ret; + DB_ENV *dbenv; + + ret = 0; + dbenv = NULL; + dbenv = txnp->mgrp->dbenv; + if (dbenv == NULL || dbenv->cl_handle == NULL) { + __db_err(dbenv, "No server environment."); + return (DB_NOSERVER); + } + + if (replyp != NULL) { + xdr_free((xdrproc_t)xdr___txn_commit_reply, (void *)replyp); + replyp = NULL; + } + cl = (CLIENT *)dbenv->cl_handle; + + if (txnp == NULL) + req.txnpcl_id = 0; + else + req.txnpcl_id = txnp->txnid; + req.flags = flags; + + replyp = __db_txn_commit_1(&req, cl); + if (replyp == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + ret = DB_NOSERVER; + goto out; + } + return (__dbcl_txn_commit_ret(txnp, flags, replyp)); +out: + return (ret); +} + +int +__dbcl_txn_prepare(txnp) + DB_TXN * txnp; +{ + DB_ENV *dbenv; + + dbenv = txnp->mgrp->dbenv; + return (__dbcl_rpc_illegal(dbenv, "txn_prepare")); +} + +int +__dbcl_txn_stat(dbenv, statp, func0) + DB_ENV * dbenv; + DB_TXN_STAT ** statp; + void *(*func0) __P((size_t)); +{ + COMPQUIET(statp, 0); + COMPQUIET(func0, 0); + return (__dbcl_rpc_illegal(dbenv, "txn_stat")); +} + +int +__dbcl_db_bt_compare(dbp, func0) + DB * dbp; + int (*func0) __P((DB *, const DBT *, const DBT *)); +{ + DB_ENV *dbenv; + + dbenv = dbp->dbenv; + COMPQUIET(func0, 0); + return (__dbcl_rpc_illegal(dbenv, "db_bt_compare")); +} + +int +__dbcl_db_bt_maxkey(dbp, maxkey) + DB * dbp; + u_int32_t maxkey; +{ + CLIENT *cl; + __db_bt_maxkey_msg req; + static __db_bt_maxkey_reply *replyp = NULL; + int ret; + DB_ENV *dbenv; + + ret = 0; + dbenv = NULL; + dbenv = dbp->dbenv; + if (dbenv == NULL || dbenv->cl_handle == NULL) { + __db_err(dbenv, "No server environment."); + return (DB_NOSERVER); + } + + if (replyp != NULL) { + xdr_free((xdrproc_t)xdr___db_bt_maxkey_reply, (void *)replyp); + replyp = NULL; + } + cl = (CLIENT *)dbenv->cl_handle; + + if (dbp == NULL) + req.dbpcl_id = 0; + else + req.dbpcl_id = dbp->cl_id; + req.maxkey = maxkey; + + replyp = __db_db_bt_maxkey_1(&req, cl); + if (replyp == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + ret = DB_NOSERVER; + goto out; + } + ret = replyp->status; +out: + return (ret); +} + +int +__dbcl_db_bt_minkey(dbp, minkey) + DB * dbp; + u_int32_t minkey; +{ + CLIENT *cl; + __db_bt_minkey_msg req; + static __db_bt_minkey_reply *replyp = NULL; + int ret; + DB_ENV *dbenv; + + ret = 0; + dbenv = NULL; + dbenv = dbp->dbenv; + if (dbenv == NULL || dbenv->cl_handle == NULL) { + __db_err(dbenv, "No server environment."); + return (DB_NOSERVER); + } + + if (replyp != NULL) { + xdr_free((xdrproc_t)xdr___db_bt_minkey_reply, (void *)replyp); + replyp = NULL; + } + cl = (CLIENT *)dbenv->cl_handle; + + if (dbp == NULL) + req.dbpcl_id = 0; + else + req.dbpcl_id = dbp->cl_id; + req.minkey = minkey; + + replyp = __db_db_bt_minkey_1(&req, cl); + if (replyp == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + ret = DB_NOSERVER; + goto out; + } + ret = replyp->status; +out: + return (ret); +} + +int +__dbcl_db_bt_prefix(dbp, func0) + DB * dbp; + size_t (*func0) __P((DB *, const DBT *, const DBT *)); +{ + DB_ENV *dbenv; + + dbenv = dbp->dbenv; + COMPQUIET(func0, 0); + return (__dbcl_rpc_illegal(dbenv, "db_bt_prefix")); +} + +int +__dbcl_db_set_append_recno(dbp, func0) + DB * dbp; + int (*func0) __P((DB *, DBT *, db_recno_t)); +{ + DB_ENV *dbenv; + + dbenv = dbp->dbenv; + COMPQUIET(func0, 0); + return (__dbcl_rpc_illegal(dbenv, "db_set_append_recno")); +} + +int +__dbcl_db_cachesize(dbp, gbytes, bytes, ncache) + DB * dbp; + u_int32_t gbytes; + u_int32_t bytes; + int ncache; +{ + DB_ENV *dbenv; + + dbenv = dbp->dbenv; + COMPQUIET(gbytes, 0); + COMPQUIET(bytes, 0); + COMPQUIET(ncache, 0); + return (__dbcl_rpc_illegal(dbenv, "db_cachesize")); +} + +int +__dbcl_db_close(dbp, flags) + DB * dbp; + u_int32_t flags; +{ + CLIENT *cl; + __db_close_msg req; + static __db_close_reply *replyp = NULL; + int ret; + DB_ENV *dbenv; + + ret = 0; + dbenv = NULL; + dbenv = dbp->dbenv; + if (dbenv == NULL || dbenv->cl_handle == NULL) { + __db_err(dbenv, "No server environment."); + return (DB_NOSERVER); + } + + if (replyp != NULL) { + xdr_free((xdrproc_t)xdr___db_close_reply, (void *)replyp); + replyp = NULL; + } + cl = (CLIENT *)dbenv->cl_handle; + + if (dbp == NULL) + req.dbpcl_id = 0; + else + req.dbpcl_id = dbp->cl_id; + req.flags = flags; + + replyp = __db_db_close_1(&req, cl); + if (replyp == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + ret = DB_NOSERVER; + goto out; + } + return (__dbcl_db_close_ret(dbp, flags, replyp)); +out: + return (ret); +} + +int +__dbcl_db_del(dbp, txnp, key, flags) + DB * dbp; + DB_TXN * txnp; + DBT * key; + u_int32_t flags; +{ + CLIENT *cl; + __db_del_msg req; + static __db_del_reply *replyp = NULL; + int ret; + DB_ENV *dbenv; + + ret = 0; + dbenv = NULL; + dbenv = dbp->dbenv; + if (dbenv == NULL || dbenv->cl_handle == NULL) { + __db_err(dbenv, "No server environment."); + return (DB_NOSERVER); + } + + if (replyp != NULL) { + xdr_free((xdrproc_t)xdr___db_del_reply, (void *)replyp); + replyp = NULL; + } + cl = (CLIENT *)dbenv->cl_handle; + + if (dbp == NULL) + req.dbpcl_id = 0; + else + req.dbpcl_id = dbp->cl_id; + if (txnp == NULL) + req.txnpcl_id = 0; + else + req.txnpcl_id = txnp->txnid; + req.keydlen = key->dlen; + req.keydoff = key->doff; + req.keyflags = key->flags; + req.keydata.keydata_val = key->data; + req.keydata.keydata_len = key->size; + req.flags = flags; + + replyp = __db_db_del_1(&req, cl); + if (replyp == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + ret = DB_NOSERVER; + goto out; + } + ret = replyp->status; +out: + return (ret); +} + +int +__dbcl_db_extentsize(dbp, extentsize) + DB * dbp; + u_int32_t extentsize; +{ + CLIENT *cl; + __db_extentsize_msg req; + static __db_extentsize_reply *replyp = NULL; + int ret; + DB_ENV *dbenv; + + ret = 0; + dbenv = NULL; + dbenv = dbp->dbenv; + if (dbenv == NULL || dbenv->cl_handle == NULL) { + __db_err(dbenv, "No server environment."); + return (DB_NOSERVER); + } + + if (replyp != NULL) { + xdr_free((xdrproc_t)xdr___db_extentsize_reply, (void *)replyp); + replyp = NULL; + } + cl = (CLIENT *)dbenv->cl_handle; + + if (dbp == NULL) + req.dbpcl_id = 0; + else + req.dbpcl_id = dbp->cl_id; + req.extentsize = extentsize; + + replyp = __db_db_extentsize_1(&req, cl); + if (replyp == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + ret = DB_NOSERVER; + goto out; + } + ret = replyp->status; +out: + return (ret); +} + +int +__dbcl_db_fd(dbp, fdp) + DB * dbp; + int * fdp; +{ + DB_ENV *dbenv; + + dbenv = dbp->dbenv; + COMPQUIET(fdp, 0); + return (__dbcl_rpc_illegal(dbenv, "db_fd")); +} + +int +__dbcl_db_feedback(dbp, func0) + DB * dbp; + void (*func0) __P((DB *, int, int)); +{ + DB_ENV *dbenv; + + dbenv = dbp->dbenv; + COMPQUIET(func0, 0); + return (__dbcl_rpc_illegal(dbenv, "db_feedback")); +} + +int +__dbcl_db_flags(dbp, flags) + DB * dbp; + u_int32_t flags; +{ + CLIENT *cl; + __db_flags_msg req; + static __db_flags_reply *replyp = NULL; + int ret; + DB_ENV *dbenv; + + ret = 0; + dbenv = NULL; + dbenv = dbp->dbenv; + if (dbenv == NULL || dbenv->cl_handle == NULL) { + __db_err(dbenv, "No server environment."); + return (DB_NOSERVER); + } + + if (replyp != NULL) { + xdr_free((xdrproc_t)xdr___db_flags_reply, (void *)replyp); + replyp = NULL; + } + cl = (CLIENT *)dbenv->cl_handle; + + if (dbp == NULL) + req.dbpcl_id = 0; + else + req.dbpcl_id = dbp->cl_id; + req.flags = flags; + + replyp = __db_db_flags_1(&req, cl); + if (replyp == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + ret = DB_NOSERVER; + goto out; + } + ret = replyp->status; +out: + return (ret); +} + +int +__dbcl_db_get(dbp, txnp, key, data, flags) + DB * dbp; + DB_TXN * txnp; + DBT * key; + DBT * data; + u_int32_t flags; +{ + CLIENT *cl; + __db_get_msg req; + static __db_get_reply *replyp = NULL; + int ret; + DB_ENV *dbenv; + + ret = 0; + dbenv = NULL; + dbenv = dbp->dbenv; + if (dbenv == NULL || dbenv->cl_handle == NULL) { + __db_err(dbenv, "No server environment."); + return (DB_NOSERVER); + } + + if (replyp != NULL) { + xdr_free((xdrproc_t)xdr___db_get_reply, (void *)replyp); + replyp = NULL; + } + cl = (CLIENT *)dbenv->cl_handle; + + if (dbp == NULL) + req.dbpcl_id = 0; + else + req.dbpcl_id = dbp->cl_id; + if (txnp == NULL) + req.txnpcl_id = 0; + else + req.txnpcl_id = txnp->txnid; + req.keydlen = key->dlen; + req.keydoff = key->doff; + req.keyflags = key->flags; + req.keydata.keydata_val = key->data; + req.keydata.keydata_len = key->size; + req.datadlen = data->dlen; + req.datadoff = data->doff; + req.dataflags = data->flags; + req.datadata.datadata_val = data->data; + req.datadata.datadata_len = data->size; + req.flags = flags; + + replyp = __db_db_get_1(&req, cl); + if (replyp == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + ret = DB_NOSERVER; + goto out; + } + return (__dbcl_db_get_ret(dbp, txnp, key, data, flags, replyp)); +out: + return (ret); +} + +int +__dbcl_db_h_ffactor(dbp, ffactor) + DB * dbp; + u_int32_t ffactor; +{ + CLIENT *cl; + __db_h_ffactor_msg req; + static __db_h_ffactor_reply *replyp = NULL; + int ret; + DB_ENV *dbenv; + + ret = 0; + dbenv = NULL; + dbenv = dbp->dbenv; + if (dbenv == NULL || dbenv->cl_handle == NULL) { + __db_err(dbenv, "No server environment."); + return (DB_NOSERVER); + } + + if (replyp != NULL) { + xdr_free((xdrproc_t)xdr___db_h_ffactor_reply, (void *)replyp); + replyp = NULL; + } + cl = (CLIENT *)dbenv->cl_handle; + + if (dbp == NULL) + req.dbpcl_id = 0; + else + req.dbpcl_id = dbp->cl_id; + req.ffactor = ffactor; + + replyp = __db_db_h_ffactor_1(&req, cl); + if (replyp == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + ret = DB_NOSERVER; + goto out; + } + ret = replyp->status; +out: + return (ret); +} + +int +__dbcl_db_h_hash(dbp, func0) + DB * dbp; + u_int32_t (*func0) __P((DB *, const void *, u_int32_t)); +{ + DB_ENV *dbenv; + + dbenv = dbp->dbenv; + COMPQUIET(func0, 0); + return (__dbcl_rpc_illegal(dbenv, "db_h_hash")); +} + +int +__dbcl_db_h_nelem(dbp, nelem) + DB * dbp; + u_int32_t nelem; +{ + CLIENT *cl; + __db_h_nelem_msg req; + static __db_h_nelem_reply *replyp = NULL; + int ret; + DB_ENV *dbenv; + + ret = 0; + dbenv = NULL; + dbenv = dbp->dbenv; + if (dbenv == NULL || dbenv->cl_handle == NULL) { + __db_err(dbenv, "No server environment."); + return (DB_NOSERVER); + } + + if (replyp != NULL) { + xdr_free((xdrproc_t)xdr___db_h_nelem_reply, (void *)replyp); + replyp = NULL; + } + cl = (CLIENT *)dbenv->cl_handle; + + if (dbp == NULL) + req.dbpcl_id = 0; + else + req.dbpcl_id = dbp->cl_id; + req.nelem = nelem; + + replyp = __db_db_h_nelem_1(&req, cl); + if (replyp == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + ret = DB_NOSERVER; + goto out; + } + ret = replyp->status; +out: + return (ret); +} + +int +__dbcl_db_key_range(dbp, txnp, key, range, flags) + DB * dbp; + DB_TXN * txnp; + DBT * key; + DB_KEY_RANGE * range; + u_int32_t flags; +{ + CLIENT *cl; + __db_key_range_msg req; + static __db_key_range_reply *replyp = NULL; + int ret; + DB_ENV *dbenv; + + ret = 0; + dbenv = NULL; + dbenv = dbp->dbenv; + if (dbenv == NULL || dbenv->cl_handle == NULL) { + __db_err(dbenv, "No server environment."); + return (DB_NOSERVER); + } + + if (replyp != NULL) { + xdr_free((xdrproc_t)xdr___db_key_range_reply, (void *)replyp); + replyp = NULL; + } + cl = (CLIENT *)dbenv->cl_handle; + + if (dbp == NULL) + req.dbpcl_id = 0; + else + req.dbpcl_id = dbp->cl_id; + if (txnp == NULL) + req.txnpcl_id = 0; + else + req.txnpcl_id = txnp->txnid; + req.keydlen = key->dlen; + req.keydoff = key->doff; + req.keyflags = key->flags; + req.keydata.keydata_val = key->data; + req.keydata.keydata_len = key->size; + req.flags = flags; + + replyp = __db_db_key_range_1(&req, cl); + if (replyp == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + ret = DB_NOSERVER; + goto out; + } + return (__dbcl_db_key_range_ret(dbp, txnp, key, range, flags, replyp)); +out: + return (ret); +} + +int +__dbcl_db_lorder(dbp, lorder) + DB * dbp; + int lorder; +{ + CLIENT *cl; + __db_lorder_msg req; + static __db_lorder_reply *replyp = NULL; + int ret; + DB_ENV *dbenv; + + ret = 0; + dbenv = NULL; + dbenv = dbp->dbenv; + if (dbenv == NULL || dbenv->cl_handle == NULL) { + __db_err(dbenv, "No server environment."); + return (DB_NOSERVER); + } + + if (replyp != NULL) { + xdr_free((xdrproc_t)xdr___db_lorder_reply, (void *)replyp); + replyp = NULL; + } + cl = (CLIENT *)dbenv->cl_handle; + + if (dbp == NULL) + req.dbpcl_id = 0; + else + req.dbpcl_id = dbp->cl_id; + req.lorder = lorder; + + replyp = __db_db_lorder_1(&req, cl); + if (replyp == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + ret = DB_NOSERVER; + goto out; + } + ret = replyp->status; +out: + return (ret); +} + +int +__dbcl_db_malloc(dbp, func0) + DB * dbp; + void *(*func0) __P((size_t)); +{ + DB_ENV *dbenv; + + dbenv = dbp->dbenv; + COMPQUIET(func0, 0); + return (__dbcl_rpc_illegal(dbenv, "db_malloc")); +} + +int +__dbcl_db_open(dbp, name, subdb, type, flags, mode) + DB * dbp; + const char * name; + const char * subdb; + DBTYPE type; + u_int32_t flags; + int mode; +{ + CLIENT *cl; + __db_open_msg req; + static __db_open_reply *replyp = NULL; + int ret; + DB_ENV *dbenv; + + ret = 0; + dbenv = NULL; + dbenv = dbp->dbenv; + if (dbenv == NULL || dbenv->cl_handle == NULL) { + __db_err(dbenv, "No server environment."); + return (DB_NOSERVER); + } + + if (replyp != NULL) { + xdr_free((xdrproc_t)xdr___db_open_reply, (void *)replyp); + replyp = NULL; + } + cl = (CLIENT *)dbenv->cl_handle; + + if (dbp == NULL) + req.dbpcl_id = 0; + else + req.dbpcl_id = dbp->cl_id; + if (name == NULL) + req.name = ""; + else + req.name = (char *)name; + if (subdb == NULL) + req.subdb = ""; + else + req.subdb = (char *)subdb; + req.type = type; + req.flags = flags; + req.mode = mode; + + replyp = __db_db_open_1(&req, cl); + if (replyp == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + ret = DB_NOSERVER; + goto out; + } + return (__dbcl_db_open_ret(dbp, name, subdb, type, flags, mode, replyp)); +out: + return (ret); +} + +int +__dbcl_db_pagesize(dbp, pagesize) + DB * dbp; + u_int32_t pagesize; +{ + CLIENT *cl; + __db_pagesize_msg req; + static __db_pagesize_reply *replyp = NULL; + int ret; + DB_ENV *dbenv; + + ret = 0; + dbenv = NULL; + dbenv = dbp->dbenv; + if (dbenv == NULL || dbenv->cl_handle == NULL) { + __db_err(dbenv, "No server environment."); + return (DB_NOSERVER); + } + + if (replyp != NULL) { + xdr_free((xdrproc_t)xdr___db_pagesize_reply, (void *)replyp); + replyp = NULL; + } + cl = (CLIENT *)dbenv->cl_handle; + + if (dbp == NULL) + req.dbpcl_id = 0; + else + req.dbpcl_id = dbp->cl_id; + req.pagesize = pagesize; + + replyp = __db_db_pagesize_1(&req, cl); + if (replyp == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + ret = DB_NOSERVER; + goto out; + } + ret = replyp->status; +out: + return (ret); +} + +int +__dbcl_db_panic(dbp, func0) + DB * dbp; + void (*func0) __P((DB_ENV *, int)); +{ + DB_ENV *dbenv; + + dbenv = dbp->dbenv; + COMPQUIET(func0, 0); + return (__dbcl_rpc_illegal(dbenv, "db_panic")); +} + +int +__dbcl_db_put(dbp, txnp, key, data, flags) + DB * dbp; + DB_TXN * txnp; + DBT * key; + DBT * data; + u_int32_t flags; +{ + CLIENT *cl; + __db_put_msg req; + static __db_put_reply *replyp = NULL; + int ret; + DB_ENV *dbenv; + + ret = 0; + dbenv = NULL; + dbenv = dbp->dbenv; + if (dbenv == NULL || dbenv->cl_handle == NULL) { + __db_err(dbenv, "No server environment."); + return (DB_NOSERVER); + } + + if (replyp != NULL) { + xdr_free((xdrproc_t)xdr___db_put_reply, (void *)replyp); + replyp = NULL; + } + cl = (CLIENT *)dbenv->cl_handle; + + if (dbp == NULL) + req.dbpcl_id = 0; + else + req.dbpcl_id = dbp->cl_id; + if (txnp == NULL) + req.txnpcl_id = 0; + else + req.txnpcl_id = txnp->txnid; + req.keydlen = key->dlen; + req.keydoff = key->doff; + req.keyflags = key->flags; + req.keydata.keydata_val = key->data; + req.keydata.keydata_len = key->size; + req.datadlen = data->dlen; + req.datadoff = data->doff; + req.dataflags = data->flags; + req.datadata.datadata_val = data->data; + req.datadata.datadata_len = data->size; + req.flags = flags; + + replyp = __db_db_put_1(&req, cl); + if (replyp == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + ret = DB_NOSERVER; + goto out; + } + return (__dbcl_db_put_ret(dbp, txnp, key, data, flags, replyp)); +out: + return (ret); +} + +int +__dbcl_db_realloc(dbp, func0) + DB * dbp; + void *(*func0) __P((void *, size_t)); +{ + DB_ENV *dbenv; + + dbenv = dbp->dbenv; + COMPQUIET(func0, 0); + return (__dbcl_rpc_illegal(dbenv, "db_realloc")); +} + +int +__dbcl_db_re_delim(dbp, delim) + DB * dbp; + int delim; +{ + CLIENT *cl; + __db_re_delim_msg req; + static __db_re_delim_reply *replyp = NULL; + int ret; + DB_ENV *dbenv; + + ret = 0; + dbenv = NULL; + dbenv = dbp->dbenv; + if (dbenv == NULL || dbenv->cl_handle == NULL) { + __db_err(dbenv, "No server environment."); + return (DB_NOSERVER); + } + + if (replyp != NULL) { + xdr_free((xdrproc_t)xdr___db_re_delim_reply, (void *)replyp); + replyp = NULL; + } + cl = (CLIENT *)dbenv->cl_handle; + + if (dbp == NULL) + req.dbpcl_id = 0; + else + req.dbpcl_id = dbp->cl_id; + req.delim = delim; + + replyp = __db_db_re_delim_1(&req, cl); + if (replyp == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + ret = DB_NOSERVER; + goto out; + } + ret = replyp->status; +out: + return (ret); +} + +int +__dbcl_db_re_len(dbp, len) + DB * dbp; + u_int32_t len; +{ + CLIENT *cl; + __db_re_len_msg req; + static __db_re_len_reply *replyp = NULL; + int ret; + DB_ENV *dbenv; + + ret = 0; + dbenv = NULL; + dbenv = dbp->dbenv; + if (dbenv == NULL || dbenv->cl_handle == NULL) { + __db_err(dbenv, "No server environment."); + return (DB_NOSERVER); + } + + if (replyp != NULL) { + xdr_free((xdrproc_t)xdr___db_re_len_reply, (void *)replyp); + replyp = NULL; + } + cl = (CLIENT *)dbenv->cl_handle; + + if (dbp == NULL) + req.dbpcl_id = 0; + else + req.dbpcl_id = dbp->cl_id; + req.len = len; + + replyp = __db_db_re_len_1(&req, cl); + if (replyp == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + ret = DB_NOSERVER; + goto out; + } + ret = replyp->status; +out: + return (ret); +} + +int +__dbcl_db_re_pad(dbp, pad) + DB * dbp; + int pad; +{ + CLIENT *cl; + __db_re_pad_msg req; + static __db_re_pad_reply *replyp = NULL; + int ret; + DB_ENV *dbenv; + + ret = 0; + dbenv = NULL; + dbenv = dbp->dbenv; + if (dbenv == NULL || dbenv->cl_handle == NULL) { + __db_err(dbenv, "No server environment."); + return (DB_NOSERVER); + } + + if (replyp != NULL) { + xdr_free((xdrproc_t)xdr___db_re_pad_reply, (void *)replyp); + replyp = NULL; + } + cl = (CLIENT *)dbenv->cl_handle; + + if (dbp == NULL) + req.dbpcl_id = 0; + else + req.dbpcl_id = dbp->cl_id; + req.pad = pad; + + replyp = __db_db_re_pad_1(&req, cl); + if (replyp == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + ret = DB_NOSERVER; + goto out; + } + ret = replyp->status; +out: + return (ret); +} + +int +__dbcl_db_re_source(dbp, re_source) + DB * dbp; + const char * re_source; +{ + DB_ENV *dbenv; + + dbenv = dbp->dbenv; + COMPQUIET(re_source, NULL); + return (__dbcl_rpc_illegal(dbenv, "db_re_source")); +} + +int +__dbcl_db_remove(dbp, name, subdb, flags) + DB * dbp; + const char * name; + const char * subdb; + u_int32_t flags; +{ + CLIENT *cl; + __db_remove_msg req; + static __db_remove_reply *replyp = NULL; + int ret; + DB_ENV *dbenv; + + ret = 0; + dbenv = NULL; + dbenv = dbp->dbenv; + if (dbenv == NULL || dbenv->cl_handle == NULL) { + __db_err(dbenv, "No server environment."); + return (DB_NOSERVER); + } + + if (replyp != NULL) { + xdr_free((xdrproc_t)xdr___db_remove_reply, (void *)replyp); + replyp = NULL; + } + cl = (CLIENT *)dbenv->cl_handle; + + if (dbp == NULL) + req.dbpcl_id = 0; + else + req.dbpcl_id = dbp->cl_id; + if (name == NULL) + req.name = ""; + else + req.name = (char *)name; + if (subdb == NULL) + req.subdb = ""; + else + req.subdb = (char *)subdb; + req.flags = flags; + + replyp = __db_db_remove_1(&req, cl); + if (replyp == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + ret = DB_NOSERVER; + goto out; + } + return (__dbcl_db_remove_ret(dbp, name, subdb, flags, replyp)); +out: + return (ret); +} + +int +__dbcl_db_rename(dbp, name, subdb, newname, flags) + DB * dbp; + const char * name; + const char * subdb; + const char * newname; + u_int32_t flags; +{ + CLIENT *cl; + __db_rename_msg req; + static __db_rename_reply *replyp = NULL; + int ret; + DB_ENV *dbenv; + + ret = 0; + dbenv = NULL; + dbenv = dbp->dbenv; + if (dbenv == NULL || dbenv->cl_handle == NULL) { + __db_err(dbenv, "No server environment."); + return (DB_NOSERVER); + } + + if (replyp != NULL) { + xdr_free((xdrproc_t)xdr___db_rename_reply, (void *)replyp); + replyp = NULL; + } + cl = (CLIENT *)dbenv->cl_handle; + + if (dbp == NULL) + req.dbpcl_id = 0; + else + req.dbpcl_id = dbp->cl_id; + if (name == NULL) + req.name = ""; + else + req.name = (char *)name; + if (subdb == NULL) + req.subdb = ""; + else + req.subdb = (char *)subdb; + if (newname == NULL) + req.newname = ""; + else + req.newname = (char *)newname; + req.flags = flags; + + replyp = __db_db_rename_1(&req, cl); + if (replyp == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + ret = DB_NOSERVER; + goto out; + } + return (__dbcl_db_rename_ret(dbp, name, subdb, newname, flags, replyp)); +out: + return (ret); +} + +int +__dbcl_db_stat(dbp, sp, func0, flags) + DB * dbp; + void * sp; + void *(*func0) __P((size_t)); + u_int32_t flags; +{ + CLIENT *cl; + __db_stat_msg req; + static __db_stat_reply *replyp = NULL; + int ret; + DB_ENV *dbenv; + + ret = 0; + dbenv = NULL; + dbenv = dbp->dbenv; + if (dbenv == NULL || dbenv->cl_handle == NULL) { + __db_err(dbenv, "No server environment."); + return (DB_NOSERVER); + } + + if (replyp != NULL) { + xdr_free((xdrproc_t)xdr___db_stat_reply, (void *)replyp); + replyp = NULL; + } + cl = (CLIENT *)dbenv->cl_handle; + + if (func0 != NULL) { + __db_err(sp, "User functions not supported in RPC."); + return (EINVAL); + } + if (dbp == NULL) + req.dbpcl_id = 0; + else + req.dbpcl_id = dbp->cl_id; + req.flags = flags; + + replyp = __db_db_stat_1(&req, cl); + if (replyp == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + ret = DB_NOSERVER; + goto out; + } + return (__dbcl_db_stat_ret(dbp, sp, func0, flags, replyp)); +out: + return (ret); +} + +int +__dbcl_db_swapped(dbp) + DB * dbp; +{ + CLIENT *cl; + __db_swapped_msg req; + static __db_swapped_reply *replyp = NULL; + int ret; + DB_ENV *dbenv; + + ret = 0; + dbenv = NULL; + dbenv = dbp->dbenv; + if (dbenv == NULL || dbenv->cl_handle == NULL) { + __db_err(dbenv, "No server environment."); + return (DB_NOSERVER); + } + + if (replyp != NULL) { + xdr_free((xdrproc_t)xdr___db_swapped_reply, (void *)replyp); + replyp = NULL; + } + cl = (CLIENT *)dbenv->cl_handle; + + if (dbp == NULL) + req.dbpcl_id = 0; + else + req.dbpcl_id = dbp->cl_id; + + replyp = __db_db_swapped_1(&req, cl); + if (replyp == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + ret = DB_NOSERVER; + goto out; + } + ret = replyp->status; +out: + return (ret); +} + +int +__dbcl_db_sync(dbp, flags) + DB * dbp; + u_int32_t flags; +{ + CLIENT *cl; + __db_sync_msg req; + static __db_sync_reply *replyp = NULL; + int ret; + DB_ENV *dbenv; + + ret = 0; + dbenv = NULL; + dbenv = dbp->dbenv; + if (dbenv == NULL || dbenv->cl_handle == NULL) { + __db_err(dbenv, "No server environment."); + return (DB_NOSERVER); + } + + if (replyp != NULL) { + xdr_free((xdrproc_t)xdr___db_sync_reply, (void *)replyp); + replyp = NULL; + } + cl = (CLIENT *)dbenv->cl_handle; + + if (dbp == NULL) + req.dbpcl_id = 0; + else + req.dbpcl_id = dbp->cl_id; + req.flags = flags; + + replyp = __db_db_sync_1(&req, cl); + if (replyp == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + ret = DB_NOSERVER; + goto out; + } + ret = replyp->status; +out: + return (ret); +} + +int +__dbcl_db_upgrade(dbp, fname, flags) + DB * dbp; + const char * fname; + u_int32_t flags; +{ + DB_ENV *dbenv; + + dbenv = dbp->dbenv; + COMPQUIET(fname, NULL); + COMPQUIET(flags, 0); + return (__dbcl_rpc_illegal(dbenv, "db_upgrade")); +} + +int +__dbcl_db_cursor(dbp, txnp, dbcpp, flags) + DB * dbp; + DB_TXN * txnp; + DBC ** dbcpp; + u_int32_t flags; +{ + CLIENT *cl; + __db_cursor_msg req; + static __db_cursor_reply *replyp = NULL; + int ret; + DB_ENV *dbenv; + + ret = 0; + dbenv = NULL; + dbenv = dbp->dbenv; + if (dbenv == NULL || dbenv->cl_handle == NULL) { + __db_err(dbenv, "No server environment."); + return (DB_NOSERVER); + } + + if (replyp != NULL) { + xdr_free((xdrproc_t)xdr___db_cursor_reply, (void *)replyp); + replyp = NULL; + } + cl = (CLIENT *)dbenv->cl_handle; + + if (dbp == NULL) + req.dbpcl_id = 0; + else + req.dbpcl_id = dbp->cl_id; + if (txnp == NULL) + req.txnpcl_id = 0; + else + req.txnpcl_id = txnp->txnid; + req.flags = flags; + + replyp = __db_db_cursor_1(&req, cl); + if (replyp == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + ret = DB_NOSERVER; + goto out; + } + return (__dbcl_db_cursor_ret(dbp, txnp, dbcpp, flags, replyp)); +out: + return (ret); +} + +static int __dbcl_db_join_curslist __P((__db_join_curslist **, DBC **)); +static void __dbcl_db_join_cursfree __P((__db_join_curslist **)); +int +__dbcl_db_join(dbp, curs, dbcp, flags) + DB * dbp; + DBC ** curs; + DBC ** dbcp; + u_int32_t flags; +{ + CLIENT *cl; + __db_join_msg req; + static __db_join_reply *replyp = NULL; + int ret; + DB_ENV *dbenv; + + ret = 0; + dbenv = NULL; + dbenv = dbp->dbenv; + if (dbenv == NULL || dbenv->cl_handle == NULL) { + __db_err(dbenv, "No server environment."); + return (DB_NOSERVER); + } + + if (replyp != NULL) { + xdr_free((xdrproc_t)xdr___db_join_reply, (void *)replyp); + replyp = NULL; + } + cl = (CLIENT *)dbenv->cl_handle; + + if (dbp == NULL) + req.dbpcl_id = 0; + else + req.dbpcl_id = dbp->cl_id; + if ((ret = __dbcl_db_join_curslist(&req.curslist, curs)) != 0) + goto out; + req.flags = flags; + + replyp = __db_db_join_1(&req, cl); + if (replyp == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + ret = DB_NOSERVER; + goto out; + } + __dbcl_db_join_cursfree(&req.curslist); + return (__dbcl_db_join_ret(dbp, curs, dbcp, flags, replyp)); +out: + __dbcl_db_join_cursfree(&req.curslist); + return (ret); +} + +int +__dbcl_db_join_curslist(locp, pp) + __db_join_curslist **locp; + DBC ** pp; +{ + DBC ** p; + u_int32_t *q; + int ret; + __db_join_curslist *nl, **nlp; + + *locp = NULL; + if (pp == NULL) + return (0); + nlp = locp; + for (p = pp; *p != 0; p++) { + if ((ret = __os_malloc(NULL, sizeof(*nl), NULL, nlp)) != 0) + goto out; + nl = *nlp; + nl->next = NULL; + nl->ent.ent_val = NULL; + nl->ent.ent_len = 0; + if ((ret = __os_malloc(NULL, sizeof(u_int32_t), NULL, &nl->ent.ent_val)) != 0) + goto out; + q = (u_int32_t *)nl->ent.ent_val; + *q = (*p)->cl_id; + nl->ent.ent_len = sizeof(u_int32_t); + nlp = &nl->next; + } + return (0); +out: + __dbcl_db_join_cursfree(locp); + return (ret); +} + +void +__dbcl_db_join_cursfree(locp) + __db_join_curslist **locp; +{ + __db_join_curslist *nl, *nl1; + + if (locp == NULL) + return; + for (nl = *locp; nl != NULL; nl = nl1) { + nl1 = nl->next; + if (nl->ent.ent_val) + __os_free(nl->ent.ent_val, nl->ent.ent_len); + __os_free(nl, sizeof(*nl)); + } +} + +int +__dbcl_dbc_close(dbc) + DBC * dbc; +{ + CLIENT *cl; + __dbc_close_msg req; + static __dbc_close_reply *replyp = NULL; + int ret; + DB_ENV *dbenv; + + ret = 0; + dbenv = NULL; + dbenv = dbc->dbp->dbenv; + if (dbenv == NULL || dbenv->cl_handle == NULL) { + __db_err(dbenv, "No server environment."); + return (DB_NOSERVER); + } + + if (replyp != NULL) { + xdr_free((xdrproc_t)xdr___dbc_close_reply, (void *)replyp); + replyp = NULL; + } + cl = (CLIENT *)dbenv->cl_handle; + + if (dbc == NULL) + req.dbccl_id = 0; + else + req.dbccl_id = dbc->cl_id; + + replyp = __db_dbc_close_1(&req, cl); + if (replyp == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + ret = DB_NOSERVER; + goto out; + } + return (__dbcl_dbc_close_ret(dbc, replyp)); +out: + return (ret); +} + +int +__dbcl_dbc_count(dbc, countp, flags) + DBC * dbc; + db_recno_t * countp; + u_int32_t flags; +{ + CLIENT *cl; + __dbc_count_msg req; + static __dbc_count_reply *replyp = NULL; + int ret; + DB_ENV *dbenv; + + ret = 0; + dbenv = NULL; + dbenv = dbc->dbp->dbenv; + if (dbenv == NULL || dbenv->cl_handle == NULL) { + __db_err(dbenv, "No server environment."); + return (DB_NOSERVER); + } + + if (replyp != NULL) { + xdr_free((xdrproc_t)xdr___dbc_count_reply, (void *)replyp); + replyp = NULL; + } + cl = (CLIENT *)dbenv->cl_handle; + + if (dbc == NULL) + req.dbccl_id = 0; + else + req.dbccl_id = dbc->cl_id; + req.flags = flags; + + replyp = __db_dbc_count_1(&req, cl); + if (replyp == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + ret = DB_NOSERVER; + goto out; + } + return (__dbcl_dbc_count_ret(dbc, countp, flags, replyp)); +out: + return (ret); +} + +int +__dbcl_dbc_del(dbc, flags) + DBC * dbc; + u_int32_t flags; +{ + CLIENT *cl; + __dbc_del_msg req; + static __dbc_del_reply *replyp = NULL; + int ret; + DB_ENV *dbenv; + + ret = 0; + dbenv = NULL; + dbenv = dbc->dbp->dbenv; + if (dbenv == NULL || dbenv->cl_handle == NULL) { + __db_err(dbenv, "No server environment."); + return (DB_NOSERVER); + } + + if (replyp != NULL) { + xdr_free((xdrproc_t)xdr___dbc_del_reply, (void *)replyp); + replyp = NULL; + } + cl = (CLIENT *)dbenv->cl_handle; + + if (dbc == NULL) + req.dbccl_id = 0; + else + req.dbccl_id = dbc->cl_id; + req.flags = flags; + + replyp = __db_dbc_del_1(&req, cl); + if (replyp == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + ret = DB_NOSERVER; + goto out; + } + ret = replyp->status; +out: + return (ret); +} + +int +__dbcl_dbc_dup(dbc, dbcp, flags) + DBC * dbc; + DBC ** dbcp; + u_int32_t flags; +{ + CLIENT *cl; + __dbc_dup_msg req; + static __dbc_dup_reply *replyp = NULL; + int ret; + DB_ENV *dbenv; + + ret = 0; + dbenv = NULL; + dbenv = dbc->dbp->dbenv; + if (dbenv == NULL || dbenv->cl_handle == NULL) { + __db_err(dbenv, "No server environment."); + return (DB_NOSERVER); + } + + if (replyp != NULL) { + xdr_free((xdrproc_t)xdr___dbc_dup_reply, (void *)replyp); + replyp = NULL; + } + cl = (CLIENT *)dbenv->cl_handle; + + if (dbc == NULL) + req.dbccl_id = 0; + else + req.dbccl_id = dbc->cl_id; + req.flags = flags; + + replyp = __db_dbc_dup_1(&req, cl); + if (replyp == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + ret = DB_NOSERVER; + goto out; + } + return (__dbcl_dbc_dup_ret(dbc, dbcp, flags, replyp)); +out: + return (ret); +} + +int +__dbcl_dbc_get(dbc, key, data, flags) + DBC * dbc; + DBT * key; + DBT * data; + u_int32_t flags; +{ + CLIENT *cl; + __dbc_get_msg req; + static __dbc_get_reply *replyp = NULL; + int ret; + DB_ENV *dbenv; + + ret = 0; + dbenv = NULL; + dbenv = dbc->dbp->dbenv; + if (dbenv == NULL || dbenv->cl_handle == NULL) { + __db_err(dbenv, "No server environment."); + return (DB_NOSERVER); + } + + if (replyp != NULL) { + xdr_free((xdrproc_t)xdr___dbc_get_reply, (void *)replyp); + replyp = NULL; + } + cl = (CLIENT *)dbenv->cl_handle; + + if (dbc == NULL) + req.dbccl_id = 0; + else + req.dbccl_id = dbc->cl_id; + req.keydlen = key->dlen; + req.keydoff = key->doff; + req.keyflags = key->flags; + req.keydata.keydata_val = key->data; + req.keydata.keydata_len = key->size; + req.datadlen = data->dlen; + req.datadoff = data->doff; + req.dataflags = data->flags; + req.datadata.datadata_val = data->data; + req.datadata.datadata_len = data->size; + req.flags = flags; + + replyp = __db_dbc_get_1(&req, cl); + if (replyp == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + ret = DB_NOSERVER; + goto out; + } + return (__dbcl_dbc_get_ret(dbc, key, data, flags, replyp)); +out: + return (ret); +} + +int +__dbcl_dbc_put(dbc, key, data, flags) + DBC * dbc; + DBT * key; + DBT * data; + u_int32_t flags; +{ + CLIENT *cl; + __dbc_put_msg req; + static __dbc_put_reply *replyp = NULL; + int ret; + DB_ENV *dbenv; + + ret = 0; + dbenv = NULL; + dbenv = dbc->dbp->dbenv; + if (dbenv == NULL || dbenv->cl_handle == NULL) { + __db_err(dbenv, "No server environment."); + return (DB_NOSERVER); + } + + if (replyp != NULL) { + xdr_free((xdrproc_t)xdr___dbc_put_reply, (void *)replyp); + replyp = NULL; + } + cl = (CLIENT *)dbenv->cl_handle; + + if (dbc == NULL) + req.dbccl_id = 0; + else + req.dbccl_id = dbc->cl_id; + req.keydlen = key->dlen; + req.keydoff = key->doff; + req.keyflags = key->flags; + req.keydata.keydata_val = key->data; + req.keydata.keydata_len = key->size; + req.datadlen = data->dlen; + req.datadoff = data->doff; + req.dataflags = data->flags; + req.datadata.datadata_val = data->data; + req.datadata.datadata_len = data->size; + req.flags = flags; + + replyp = __db_dbc_put_1(&req, cl); + if (replyp == NULL) { + __db_err(dbenv, clnt_sperror(cl, "Berkeley DB")); + ret = DB_NOSERVER; + goto out; + } + return (__dbcl_dbc_put_ret(dbc, key, data, flags, replyp)); +out: + return (ret); +} + +int +__dbcl_lock_detect(dbenv, flags, atype, aborted) + DB_ENV * dbenv; + u_int32_t flags; + u_int32_t atype; + int * aborted; +{ + COMPQUIET(flags, 0); + COMPQUIET(atype, 0); + COMPQUIET(aborted, 0); + return (__dbcl_rpc_illegal(dbenv, "lock_detect")); +} + +int +__dbcl_lock_get(dbenv, locker, flags, obj, mode, lock) + DB_ENV * dbenv; + u_int32_t locker; + u_int32_t flags; + const DBT * obj; + db_lockmode_t mode; + DB_LOCK * lock; +{ + COMPQUIET(locker, 0); + COMPQUIET(flags, 0); + COMPQUIET(obj, NULL); + COMPQUIET(mode, 0); + COMPQUIET(lock, 0); + return (__dbcl_rpc_illegal(dbenv, "lock_get")); +} + +int +__dbcl_lock_id(dbenv, idp) + DB_ENV * dbenv; + u_int32_t * idp; +{ + COMPQUIET(idp, 0); + return (__dbcl_rpc_illegal(dbenv, "lock_id")); +} + +int +__dbcl_lock_put(dbenv, lock) + DB_ENV * dbenv; + DB_LOCK * lock; +{ + COMPQUIET(lock, 0); + return (__dbcl_rpc_illegal(dbenv, "lock_put")); +} + +int +__dbcl_lock_stat(dbenv, statp, func0) + DB_ENV * dbenv; + DB_LOCK_STAT ** statp; + void *(*func0) __P((size_t)); +{ + COMPQUIET(statp, 0); + COMPQUIET(func0, 0); + return (__dbcl_rpc_illegal(dbenv, "lock_stat")); +} + +int +__dbcl_lock_vec(dbenv, locker, flags, list, nlist, elistp) + DB_ENV * dbenv; + u_int32_t locker; + u_int32_t flags; + DB_LOCKREQ * list; + int nlist; + DB_LOCKREQ ** elistp; +{ + COMPQUIET(locker, 0); + COMPQUIET(flags, 0); + COMPQUIET(list, 0); + COMPQUIET(nlist, 0); + COMPQUIET(elistp, 0); + return (__dbcl_rpc_illegal(dbenv, "lock_vec")); +} + +int +__dbcl_log_archive(dbenv, listp, flags, func0) + DB_ENV * dbenv; + char *** listp; + u_int32_t flags; + void *(*func0) __P((size_t)); +{ + COMPQUIET(listp, 0); + COMPQUIET(flags, 0); + COMPQUIET(func0, 0); + return (__dbcl_rpc_illegal(dbenv, "log_archive")); +} + +int +__dbcl_log_file(dbenv, lsn, namep, len) + DB_ENV * dbenv; + const DB_LSN * lsn; + char * namep; + size_t len; +{ + COMPQUIET(lsn, NULL); + COMPQUIET(namep, NULL); + COMPQUIET(len, 0); + return (__dbcl_rpc_illegal(dbenv, "log_file")); +} + +int +__dbcl_log_flush(dbenv, lsn) + DB_ENV * dbenv; + const DB_LSN * lsn; +{ + COMPQUIET(lsn, NULL); + return (__dbcl_rpc_illegal(dbenv, "log_flush")); +} + +int +__dbcl_log_get(dbenv, lsn, data, flags) + DB_ENV * dbenv; + DB_LSN * lsn; + DBT * data; + u_int32_t flags; +{ + COMPQUIET(lsn, 0); + COMPQUIET(data, NULL); + COMPQUIET(flags, 0); + return (__dbcl_rpc_illegal(dbenv, "log_get")); +} + +int +__dbcl_log_put(dbenv, lsn, data, flags) + DB_ENV * dbenv; + DB_LSN * lsn; + const DBT * data; + u_int32_t flags; +{ + COMPQUIET(lsn, 0); + COMPQUIET(data, NULL); + COMPQUIET(flags, 0); + return (__dbcl_rpc_illegal(dbenv, "log_put")); +} + +int +__dbcl_log_register(dbenv, dbp, namep) + DB_ENV * dbenv; + DB * dbp; + const char * namep; +{ + COMPQUIET(dbp, 0); + COMPQUIET(namep, NULL); + return (__dbcl_rpc_illegal(dbenv, "log_register")); +} + +int +__dbcl_log_stat(dbenv, statp, func0) + DB_ENV * dbenv; + DB_LOG_STAT ** statp; + void *(*func0) __P((size_t)); +{ + COMPQUIET(statp, 0); + COMPQUIET(func0, 0); + return (__dbcl_rpc_illegal(dbenv, "log_stat")); +} + +int +__dbcl_log_unregister(dbenv, dbp) + DB_ENV * dbenv; + DB * dbp; +{ + COMPQUIET(dbp, 0); + return (__dbcl_rpc_illegal(dbenv, "log_unregister")); +} + +int +__dbcl_memp_fclose(mpf) + DB_MPOOLFILE * mpf; +{ + DB_ENV *dbenv; + + dbenv = mpf->dbmp->dbenv; + return (__dbcl_rpc_illegal(dbenv, "memp_fclose")); +} + +int +__dbcl_memp_fget(mpf, pgno, flags, pagep) + DB_MPOOLFILE * mpf; + db_pgno_t * pgno; + u_int32_t flags; + void ** pagep; +{ + DB_ENV *dbenv; + + dbenv = mpf->dbmp->dbenv; + COMPQUIET(pgno, 0); + COMPQUIET(flags, 0); + COMPQUIET(pagep, 0); + return (__dbcl_rpc_illegal(dbenv, "memp_fget")); +} + +int +__dbcl_memp_fopen(dbenv, file, flags, mode, pagesize, finfop, mpf) + DB_ENV * dbenv; + const char * file; + u_int32_t flags; + int mode; + size_t pagesize; + DB_MPOOL_FINFO * finfop; + DB_MPOOLFILE ** mpf; +{ + COMPQUIET(file, NULL); + COMPQUIET(flags, 0); + COMPQUIET(mode, 0); + COMPQUIET(pagesize, 0); + COMPQUIET(finfop, 0); + COMPQUIET(mpf, 0); + return (__dbcl_rpc_illegal(dbenv, "memp_fopen")); +} + +int +__dbcl_memp_fput(mpf, pgaddr, flags) + DB_MPOOLFILE * mpf; + void * pgaddr; + u_int32_t flags; +{ + DB_ENV *dbenv; + + dbenv = mpf->dbmp->dbenv; + COMPQUIET(pgaddr, 0); + COMPQUIET(flags, 0); + return (__dbcl_rpc_illegal(dbenv, "memp_fput")); +} + +int +__dbcl_memp_fset(mpf, pgaddr, flags) + DB_MPOOLFILE * mpf; + void * pgaddr; + u_int32_t flags; +{ + DB_ENV *dbenv; + + dbenv = mpf->dbmp->dbenv; + COMPQUIET(pgaddr, 0); + COMPQUIET(flags, 0); + return (__dbcl_rpc_illegal(dbenv, "memp_fset")); +} + +int +__dbcl_memp_fsync(mpf) + DB_MPOOLFILE * mpf; +{ + DB_ENV *dbenv; + + dbenv = mpf->dbmp->dbenv; + return (__dbcl_rpc_illegal(dbenv, "memp_fsync")); +} + +int +__dbcl_memp_register(dbenv, ftype, func0, func1) + DB_ENV * dbenv; + int ftype; + int (*func0) __P((DB_ENV *, db_pgno_t, void *, DBT *)); + int (*func1) __P((DB_ENV *, db_pgno_t, void *, DBT *)); +{ + COMPQUIET(ftype, 0); + COMPQUIET(func0, 0); + COMPQUIET(func1, 0); + return (__dbcl_rpc_illegal(dbenv, "memp_register")); +} + +int +__dbcl_memp_stat(dbenv, gstatp, fstatp, func0) + DB_ENV * dbenv; + DB_MPOOL_STAT ** gstatp; + DB_MPOOL_FSTAT *** fstatp; + void *(*func0) __P((size_t)); +{ + COMPQUIET(gstatp, 0); + COMPQUIET(fstatp, 0); + COMPQUIET(func0, 0); + return (__dbcl_rpc_illegal(dbenv, "memp_stat")); +} + +int +__dbcl_memp_sync(dbenv, lsn) + DB_ENV * dbenv; + DB_LSN * lsn; +{ + COMPQUIET(lsn, 0); + return (__dbcl_rpc_illegal(dbenv, "memp_sync")); +} + +int +__dbcl_memp_trickle(dbenv, pct, nwrotep) + DB_ENV * dbenv; + int pct; + int * nwrotep; +{ + COMPQUIET(pct, 0); + COMPQUIET(nwrotep, 0); + return (__dbcl_rpc_illegal(dbenv, "memp_trickle")); +} + +#endif /* HAVE_RPC */ diff --git a/db/rpc_client/gen_client_ret.c b/db/rpc_client/gen_client_ret.c new file mode 100644 index 000000000..17e3f195f --- /dev/null +++ b/db/rpc_client/gen_client_ret.c @@ -0,0 +1,542 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: gen_client_ret.c,v 1.29 2000/12/31 19:26:23 bostic Exp $"; +#endif /* not lint */ + +#ifdef HAVE_RPC +#ifndef NO_SYSTEM_INCLUDES +#include + +#include + +#include +#endif +#include "db_server.h" + +#include "db_int.h" +#include "db_page.h" +#include "txn.h" +#include "db_ext.h" +#include "rpc_client_ext.h" + +static void __db_db_stat_statsfree __P((u_int32_t *)); +static int __db_db_stat_statslist __P((__db_stat_statsreplist *, u_int32_t **)); + +int +__dbcl_env_close_ret(dbenv, flags, replyp) + DB_ENV *dbenv; + u_int32_t flags; + __env_close_reply *replyp; +{ + int ret; + + COMPQUIET(flags, 0); + + ret = __dbcl_refresh(dbenv); + __os_free(dbenv, sizeof(*dbenv)); + if (replyp->status == 0 && ret != 0) + return (ret); + else + return (replyp->status); +} + +int +__dbcl_env_open_ret(dbenv, home, flags, mode, replyp) + DB_ENV *dbenv; + const char *home; + u_int32_t flags; + int mode; + __env_open_reply *replyp; +{ + DB_TXNMGR *tmgrp; + int ret; + + COMPQUIET(home, NULL); + COMPQUIET(mode, 0); + + /* + * If error, return it. + */ + if (replyp->status != 0) + return (replyp->status); + + /* + * If the user requested transactions, then we have some + * local client-side setup to do also. + */ + if (LF_ISSET(DB_INIT_TXN)) { + if ((ret = __os_calloc(dbenv, + 1, sizeof(DB_TXNMGR), &tmgrp)) != 0) + return (ret); + TAILQ_INIT(&tmgrp->txn_chain); + tmgrp->dbenv = dbenv; + dbenv->tx_handle = tmgrp; + } + + return (replyp->status); +} + +int +__dbcl_env_remove_ret(dbenv, home, flags, replyp) + DB_ENV *dbenv; + const char *home; + u_int32_t flags; + __env_remove_reply *replyp; +{ + int ret; + + COMPQUIET(home, NULL); + COMPQUIET(flags, 0); + + ret = __dbcl_refresh(dbenv); + __os_free(dbenv, sizeof(*dbenv)); + if (replyp->status == 0 && ret != 0) + return (ret); + else + return (replyp->status); +} + +int +__dbcl_txn_abort_ret(txnp, replyp) + DB_TXN *txnp; + __txn_abort_reply *replyp; +{ + __dbcl_txn_end(txnp); + return (replyp->status); +} + +int +__dbcl_txn_begin_ret(envp, parent, txnpp, flags, replyp) + DB_ENV *envp; + DB_TXN *parent, **txnpp; + u_int32_t flags; + __txn_begin_reply *replyp; +{ + DB_TXN *txn; + int ret; + + COMPQUIET(flags, 0); + + if (replyp->status != 0) + return (replyp->status); + + if ((ret = __os_calloc(envp, 1, sizeof(DB_TXN), &txn)) != 0) + return (ret); + txn->txnid = replyp->txnidcl_id; + txn->mgrp = envp->tx_handle; + txn->parent = parent; + TAILQ_INIT(&txn->kids); + txn->flags = TXN_MALLOC; + if (parent != NULL) + TAILQ_INSERT_HEAD(&parent->kids, txn, klinks); + + /* + * XXX + * In DB library the txn_chain is protected by the mgrp->mutexp. + * However, that mutex is implemented in the environments shared + * memory region. The client library does not support all of the + * region - that just get forwarded to the server. Therefore, + * the chain is unprotected here, but properly protected on the + * server. + */ + TAILQ_INSERT_TAIL(&txn->mgrp->txn_chain, txn, links); + + *txnpp = txn; + return (replyp->status); +} + +int +__dbcl_txn_commit_ret(txnp, flags, replyp) + DB_TXN *txnp; + u_int32_t flags; + __txn_commit_reply *replyp; +{ + COMPQUIET(flags, 0); + + __dbcl_txn_end(txnp); + return (replyp->status); +} + +int +__dbcl_db_close_ret(dbp, flags, replyp) + DB *dbp; + u_int32_t flags; + __db_close_reply *replyp; +{ + int ret; + + COMPQUIET(flags, 0); + + ret = __dbcl_dbclose_common(dbp); + + if (replyp->status != 0) + return (replyp->status); + else + return (ret); +} + +int +__dbcl_db_get_ret(dbp, txnp, key, data, flags, replyp) + DB *dbp; + DB_TXN *txnp; + DBT *key, *data; + u_int32_t flags; + __db_get_reply *replyp; +{ + DB_ENV *dbenv; + int ret; + void *oldkey; + + COMPQUIET(txnp, NULL); + COMPQUIET(flags, 0); + + ret = 0; + if (replyp->status != 0) + return (replyp->status); + + dbenv = dbp->dbenv; + + oldkey = key->data; + ret = __dbcl_retcopy(dbenv, key, replyp->keydata.keydata_val, + replyp->keydata.keydata_len); + if (ret) + return (ret); + ret = __dbcl_retcopy(dbenv, data, replyp->datadata.datadata_val, + replyp->datadata.datadata_len); + /* + * If an error on copying 'data' and we allocated for 'key' + * free it before returning the error. + */ + if (ret && oldkey != NULL) + __os_free(key->data, key->size); + return (ret); +} + +int +__dbcl_db_key_range_ret(dbp, txnp, key, range, flags, replyp) + DB *dbp; + DB_TXN *txnp; + DBT *key; + DB_KEY_RANGE *range; + u_int32_t flags; + __db_key_range_reply *replyp; +{ + COMPQUIET(dbp, NULL); + COMPQUIET(txnp, NULL); + COMPQUIET(key, NULL); + COMPQUIET(flags, 0); + + if (replyp->status != 0) + return (replyp->status); + range->less = replyp->less; + range->equal = replyp->equal; + range->greater = replyp->greater; + return (replyp->status); +} + +int +__dbcl_db_open_ret(dbp, name, subdb, type, flags, mode, replyp) + DB *dbp; + const char *name, *subdb; + DBTYPE type; + u_int32_t flags; + int mode; + __db_open_reply *replyp; +{ + COMPQUIET(name, NULL); + COMPQUIET(subdb, NULL); + COMPQUIET(type, 0); + COMPQUIET(flags, 0); + COMPQUIET(mode, 0); + + dbp->type = replyp->type; + + /* + * XXX + * This is only for Tcl which peeks at the dbp flags. + * When dbp->get_flags exists, this should go away. + */ + dbp->flags = replyp->dbflags; + return (replyp->status); +} + +int +__dbcl_db_put_ret(dbp, txnp, key, data, flags, replyp) + DB *dbp; + DB_TXN *txnp; + DBT *key, *data; + u_int32_t flags; + __db_put_reply *replyp; +{ + int ret; + + COMPQUIET(dbp, NULL); + COMPQUIET(txnp, NULL); + COMPQUIET(data, NULL); + + ret = replyp->status; + if (replyp->status == 0 && (flags == DB_APPEND)) + *(db_recno_t *)key->data = + *(db_recno_t *)replyp->keydata.keydata_val; + return (ret); +} + +int +__dbcl_db_remove_ret(dbp, name, subdb, flags, replyp) + DB *dbp; + const char *name, *subdb; + u_int32_t flags; + __db_remove_reply *replyp; +{ + int ret; + + COMPQUIET(name, 0); + COMPQUIET(subdb, 0); + COMPQUIET(flags, 0); + + ret = __dbcl_dbclose_common(dbp); + + if (replyp->status != 0) + return (replyp->status); + else + return (ret); +} + +int +__dbcl_db_rename_ret(dbp, name, subdb, newname, flags, replyp) + DB *dbp; + const char *name, *subdb, *newname; + u_int32_t flags; + __db_remove_reply *replyp; +{ + int ret; + + COMPQUIET(name, 0); + COMPQUIET(subdb, 0); + COMPQUIET(newname, 0); + COMPQUIET(flags, 0); + + ret = __dbcl_dbclose_common(dbp); + + if (replyp->status != 0) + return (replyp->status); + else + return (ret); +} + +int +__dbcl_db_stat_ret(dbp, sp, func, flags, replyp) + DB *dbp; + void *sp; + void *(*func) __P((size_t)); + u_int32_t flags; + __db_stat_reply *replyp; +{ + int ret; + u_int32_t *__db_statslist; + + COMPQUIET(dbp, NULL); + COMPQUIET(func, NULL); + COMPQUIET(flags, 0); + + if (replyp->status != 0) + return (replyp->status); + + if ((ret = + __db_db_stat_statslist(replyp->statslist, &__db_statslist)) != 0) + return (ret); + + if (sp == NULL) + __db_db_stat_statsfree(__db_statslist); + else + *(u_int32_t **)sp = __db_statslist; + return (replyp->status); +} + +static int +__db_db_stat_statslist(locp, ppp) + __db_stat_statsreplist *locp; + u_int32_t **ppp; +{ + u_int32_t *pp; + int cnt, ret, size; + __db_stat_statsreplist *nl; + + for (cnt = 0, nl = locp; nl != NULL; cnt++, nl = nl->next) + ; + + if (cnt == 0) { + *ppp = NULL; + return (0); + } + size = sizeof(*pp) * cnt; + if ((ret = __os_malloc(NULL, size, NULL, ppp)) != 0) + return (ret); + memset(*ppp, 0, size); + for (pp = *ppp, nl = locp; nl != NULL; nl = nl->next, pp++) { + *pp = *(u_int32_t *)nl->ent.ent_val; + } + return (0); +} + +static void +__db_db_stat_statsfree(pp) + u_int32_t *pp; +{ + size_t size; + u_int32_t *p; + + if (pp == NULL) + return; + size = sizeof(*p); + for (p = pp; *p != 0; p++) + size += sizeof(*p); + + __os_free(pp, size); +} + +int +__dbcl_db_cursor_ret(dbp, txnp, dbcpp, flags, replyp) + DB *dbp; + DB_TXN *txnp; + DBC **dbcpp; + u_int32_t flags; + __db_cursor_reply *replyp; +{ + COMPQUIET(txnp, NULL); + COMPQUIET(flags, 0); + + if (replyp->status != 0) + return (replyp->status); + + return (__dbcl_c_setup(replyp->dbcidcl_id, dbp, dbcpp)); +} + +int +__dbcl_db_join_ret(dbp, curs, dbcpp, flags, replyp) + DB *dbp; + DBC **curs, **dbcpp; + u_int32_t flags; + __db_join_reply *replyp; +{ + COMPQUIET(curs, NULL); + COMPQUIET(flags, 0); + + if (replyp->status != 0) + return (replyp->status); + + /* + * We set this up as a normal cursor. We do not need + * to treat a join cursor any differently than a normal + * cursor, even though DB itself must. We only need the + * client-side cursor/db relationship to know what cursors + * are open in the db, and to store their ID. Nothing else. + */ + return (__dbcl_c_setup(replyp->dbcidcl_id, dbp, dbcpp)); +} + +int +__dbcl_dbc_close_ret(dbcp, replyp) + DBC *dbcp; + __dbc_close_reply *replyp; +{ + DB *dbp; + + dbp = dbcp->dbp; + __dbcl_c_refresh(dbcp); + return (replyp->status); +} + +int +__dbcl_dbc_count_ret(dbc, countp, flags, replyp) + DBC *dbc; + db_recno_t *countp; + u_int32_t flags; + __dbc_count_reply *replyp; +{ + COMPQUIET(dbc, NULL); + COMPQUIET(flags, 0); + + if (replyp->status != 0) + return (replyp->status); + *countp = replyp->dupcount; + + return (replyp->status); +} + +int +__dbcl_dbc_dup_ret(dbcp, dbcpp, flags, replyp) + DBC *dbcp, **dbcpp; + u_int32_t flags; + __dbc_dup_reply *replyp; +{ + COMPQUIET(flags, 0); + + if (replyp->status != 0) + return (replyp->status); + + return (__dbcl_c_setup(replyp->dbcidcl_id, dbcp->dbp, dbcpp)); +} + +int +__dbcl_dbc_get_ret(dbcp, key, data, flags, replyp) + DBC *dbcp; + DBT *key, *data; + u_int32_t flags; + __dbc_get_reply *replyp; +{ + DB_ENV *dbenv; + int ret; + void *oldkey; + + COMPQUIET(flags, 0); + + ret = 0; + if (replyp->status != 0) + return (replyp->status); + + dbenv = dbcp->dbp->dbenv; + oldkey = key->data; + ret = __dbcl_retcopy(dbenv, key, replyp->keydata.keydata_val, + replyp->keydata.keydata_len); + if (ret) + return (ret); + ret = __dbcl_retcopy(dbenv, data, replyp->datadata.datadata_val, + replyp->datadata.datadata_len); + + /* + * If an error on copying 'data' and we allocated for 'key' + * free it before returning the error. + */ + if (ret && oldkey != NULL) + __os_free(key->data, key->size); + return (ret); +} + +int +__dbcl_dbc_put_ret(dbcp, key, data, flags, replyp) + DBC *dbcp; + DBT *key, *data; + u_int32_t flags; + __dbc_put_reply *replyp; +{ + COMPQUIET(data, NULL); + + if (replyp->status != 0) + return (replyp->status); + + if (replyp->status == 0 && dbcp->dbp->type == DB_RECNO && + (flags == DB_AFTER || flags == DB_BEFORE)) + *(db_recno_t *)key->data = + *(db_recno_t *)replyp->keydata.keydata_val; + return (replyp->status); +} +#endif /* HAVE_RPC */ diff --git a/db/rpc_server/clsrv.html b/db/rpc_server/clsrv.html new file mode 100644 index 000000000..ae089c4b3 --- /dev/null +++ b/db/rpc_server/clsrv.html @@ -0,0 +1,453 @@ + + + + + + + + +

+

+Client/Server Interface for Berkeley DB

+ +
Susan LoVerso +
sue@sleepycat.com +
Rev 1.3 +
1999 Nov 29
+ +

We provide an interface allowing client/server access to Berkeley DB.   +Our goal is to provide a client and server library to allow users to separate +the functionality of their applications yet still have access to the full +benefits of Berkeley DB.  The goal is to provide a totally seamless +interface with minimal modification to existing applications as well. +

The client/server interface for Berkeley DB can be broken up into several +layers.  At the lowest level there is the transport mechanism to send +out the messages over the network.  Above that layer is the messaging +layer to interpret what comes over the wire, and bundle/unbundle message +contents.  The next layer is Berkeley DB itself. +

The transport layer uses ONC RPC (RFC 1831) and XDR (RFC 1832).  +We declare our message types and operations supported by our program and +the RPC library and utilities pretty much take care of the rest.  +The +rpcgen program generates all of the low level code needed.  +We need to define both sides of the RPC. +
  +

+DB Modifications

+To achieve the goal of a seamless interface, it is necessary to impose +a constraint on the application. That constraint is simply that all database +access must be done through an open environment.  I.e. this model +does not support standalone databases.  The reason for this constraint +is so that we have an environment structure internally to store our connection +to the server.  Imposing this constraint means that we can provide +the seamless interface just by adding a single environment method: DBENV->set_server(). +

The planned interface for this method is: +

DBENV->set_server(dbenv,      /* DB_ENV structure */
+                  hostname    /* Host of server */
+                  cl_timeout, /* Client timeout (sec) */
+                  srv_timeout,/* Server timeout (sec) */
+                  flags);     /* Flags: unused */
+This new method takes the hostname of the server, establishes our connection +and an environment on the server.  If a server timeout is specified, +then we send that to the server as well (and the server may or may not +choose to use that value).  This timeout is how long the server will +allow the environment to remain idle before declaring it dead and releasing +resources on the server.  The pointer to the connection is stored +on the client in the DBENV structure and is used by all other methods to +figure out with whom to communicate.  If a client timeout is specified, +it indicates how long the client is willing to wait for a reply from the +server.  If the values are 0, then defaults are used.  Flags +is currently unused, but exists because we always need to have a placeholder +for flags and it would be used for specifying authentication desired (were +we to provide an authentication scheme at some point) or other uses not +thought of yet! +

This client code is part of the monolithic DB library.  The user +accesses the client functions via a new flag to db_env_create().  +That flag is DB_CLIENT.  By using this flag the user indicates they +want to have the client methods rather than the standard methods for the +environment.  Also by issuing this flag, the user needs to connect +to the server via the DBENV->set_server() +method. +

We need two new fields in the DB_ENV structure.  One is +the socket descriptor to communicate to the server, the other field is +the client identifier the server gives to us.  The DB, and +DBC only need one additional field, the client identifier.  The +DB_TXN +structure does not need modification, we are overloading the txn_id +field. +

+Issues

+We need to figure out what to do in case of client and server crashes.  +Both the client library and the server program are stateful.  They +both consume local resources during the lifetime of the connection.  +Should one end drop that connection, the other side needs to release those +resources. +

If the server crashes, then the client will get an error back.  +I have chosen to implement time-outs on the client side, using a default +or allowing the application to specify one through the DBENV->set_server() +method.  Either the current operation will time-out waiting for the +reply or the next operation called will time out (or get back some other +kind of error regarding the server's non-existence).  In any case, +if the client application gets back such an error, it should abort any +open transactions locally, close any databases, and close its environment.  +It may then decide to retry to connect to the server periodically or whenever +it comes back.  If the last operation a client did was a transaction +commit that did not return or timed out from the server, the client cannot +determine if the transaction was committed or not but must release the +local transaction resources. Once the server is back up, recovery must +be run on the server.   If the transaction commit completed on +the server before the crash, then the operation is redone, if the transaction +commit did not get to the server, the pieces of the transaction are undone +on recover.  The client can then re-establish its connection and begin +again.  This is effectively like beginning over.  The client +cannot use ID's from its previous connection to the server.  However, +if recovery is run, then consistency is assured. +

If the client crashes, the server needs to somehow figure this out.  +The server is just sitting there waiting for a request to come in.  +A server must be able to time-out a client.  Similar to ftpd, if a +connection is idle for N seconds, then the server decides the client is +dead and releases that client's resources, aborting any open transactions, +closing any open databases and environments.   The server timing +out a client is not a trivial issue however.  The generated function +for the server just calls svc_run().  The server code I write +contains procedures to do specific things.  We do not have access +to the code calling select().  Timing out the select is not +good enough even if we could do so.  We want to time-out idle environments, +not simply cause a time-out if the server is idle a while.  See the +discussion of the server program for +a description of how we accomplish this. +

Since rpcgen generates the main() function of the server, I do not yet +know how we are going to have the server multi-threaded or multi-process +without changing the generated code.  The RPC book indicates that +the only way to accomplish this is through modifying the generated code +in the server.  For the moment we will ignore this issue while +we get the core server working, as it is only a performance issue. +

We do not do any security or authentication.  Someone could get +the code and modify it to spoof messages, trick the server, etc.  +RPC has some amount of authentication built into it.  I haven't yet +looked into it much to know if we want to use it or just point a user at +it.  The changes to the client code are fairly minor, the changes +to our server procs are fairly minor.  We would have to add code to +a sed script or awk script to change the generated server +code (yet again) in the dispatch routine to perform authentication. +

We will need to get an official program number from Sun.  We can +get this by sending mail to rpc@sun.com and presumably at some point +they will send us back a program number that we will encode into our XDR +description file.  Until we release this we can use a program number +in the "user defined" number space. +
  +

+The Server Program

+The server is a standalone program that the user builds and runs, probably +as a daemon like process.  This program is linked against the Berkeley +DB library and the RPC library (which is part of the C library on my FreeBSD +machine, others may have/need -lrpclib).  The server basically +is a slave to the client process.  All messages from the client are +synchronous and two-way.  The server handles messages one at a time, +and sends a reply back before getting another message.  There are +no asynchronous messages generated by the server to the client. +

We have made a choice to modify the generated code for the server.  +The changes will be minimal, generally calling functions we write, that +are in other source files.  The first change is adding a call to our +time-out function as described below.  The second change is changing +the name of the generated main() function to __dbsrv_main(), +and adding our own main() function so that we can parse options, +and set up other initialization we require.  I have a sed script +that is run from the distribution scripts that massages the generated code +to make these minor changes. +

Primarily the code needed for the server is the collection of the specified +RPC functions.  Each function receives the structure indicated, and +our code takes out what it needs and passes the information into DB itself.  +The server needs to maintain a translation table for identifiers that we +pass back to the client for the environment, transaction and database handles. +

The table that the server maintains, assuming one client per server +process/thread, should contain the handle to the environment, database +or transaction, a link to maintain parent/child relationships between transactions, +or databases and cursors, this handle's identifier, a type so that we can +error if the client passes us a bad id for this call, and a link to this +handle's environment entry (for time out/activity purposes).  The +table contains, in entries used by environments, a time-out value and an +activity time stamp.  Its use is described below for timing out idle +clients. +

Here is how we time out clients in the server.  We have to modify +the generated server code, but only to add one line during the dispatch +function to run the time-out function.  The call is made right before +the return of the dispatch function, after the reply is sent to the client, +so that client's aren't kept waiting for server bookkeeping activities.  +This time-out function then runs every time the server processes a request.  +In the time-out function we maintain a time-out hint that is the youngest +environment to time-out.  If the current time is less than the hint +we know we do not need to run through the list of open handles.  If +the hint is expired, then we go through the list of open environment handles, +and if they are past their expiration, then we close them and clean up.  +If they are not, we set up the hint for the next time. +

Each entry in the open handle table has a pointer back to its environment's +entry.  Every operation within this environment can then update the +single environment activity record.  Every environment can have a +different time-out.  The DBENV->set_server +call +takes a server time-out value.  If this value is 0 then a default +(currently 5 minutes) is used.  This time-out value is only a hint +to the server.  It may choose to disregard this value or set the time-out +based on its own implementation. +

For completeness, the flaws of this time-out implementation should be +pointed out.  First, it is possible that a client could crash with +open handles, and no other requests come in to the server.  Therefore +the time-out function never gets run and those resources are not released +(until a request does come in).  Similarly, this time-out is not exact.  +The time-out function uses its hint and if it computes a hint on one run, +an earlier time-out might be created before that time-out expires.  +This issue simply yields a handle that doesn't get released until that +original hint expires.  To illustrate, consider that at the time that +the time-out function is run, the youngest time-out is 5 minutes in the +future.  Soon after, a new environment is opened that has a time-out +of 1 minute.  If this environment becomes idle (and other operations +are going on), the time-out function will not release that environment +until the original 5 minute hint expires.  This is not a problem since +the resources will eventually be released. +

On a similar note, if a client crashes during an RPC, our reply generates +a SIGPIPE, and our server crashes unless we catch it.  Using signal(SIGPIPE, +SIG_IGN) we can ignore it, and the server will go on.  This is +a call  in our main() function that we write.  Eventually +this client's handles would be timed out as described above.  We need +this only for the unfortunate window of a client crashing during the RPC. +

The options below are primarily for control of the program itself,.  +Details relating to databases and environments should be passed from the +client to the server, since the server can serve many clients, many environments +and many databases.  Therefore it makes more sense for the client +to set the cache size of its own environment, rather than setting a default +cachesize on the server that applies as a blanket to any environment it +may be called upon to open.  Options are: +

    +
  • +-t  to set the default time-out given to an environment.
  • + +
  • +-T to set the maximum time-out allowed for the server.
  • + +
  • +-L to log the execution of the server process to a specified file.
  • + +
  • +-v to run in verbose mode.
  • + +
  • +-M  to specify the maximum number of outstanding child server +processes/threads we can have at any given time.  The default is 10. +[We +are not yet doing multiple threads/processes.]
  • +
+ +

+The Client Code

+The client code contains all of the supported functions and methods used +in this model.  There are several methods in the __db_env +and +__db +structures that currently do not apply, such as the callbacks.  Those +fields that are not applicable to the client model point to NULL to notify +the user of their error.  Some method functions remain unchanged, +as well such as the error calls. +

The client code contains each method function that goes along with the +RPC +calls described elsewhere.  The client library also contains its +own version of db_env_create(), +which does not result in any messages going over to the server (since we +do not yet know what server we are talking to).  This function sets +up the pointers to the correct client functions. +

All of the method functions that handle the messaging have a basic flow +similar to this: +

    +
  • +Local arg parsing that may be needed
  • + +
  • +Marshalling the message header and the arguments we need to send to the +server
  • + +
  • +Sending the message
  • + +
  • +Receiving a reply
  • + +
  • +Unmarshalling the reply
  • + +
  • +Local results processing that may be needed
  • +
+ +

+Generated Code

+Almost all of the code is generated from a source file describing the interface +and an awk script.   This awk script generates six (6) +files for us.  It also modifies one.  The files are: +
    +
  1. +Client file - The C source file created containing the client code.
  2. + +
  3. +Client template file - The C template source file created containing interfaces +for handling client-local issues such as resource allocation, but with +a consistent interface with the client code generated.
  4. + +
  5. +Server file - The C source file created containing the server code.
  6. + +
  7. +Server template file - The C template source file created containing interfaces +for handling server-local issues such as resource allocation, calling into +the DB library but with a consistent interface with the server code generated.
  8. + +
  9. +XDR file - The XDR message description file created.
  10. + +
  11. +Server sed file - A sed script that contains commands to apply to the server +procedure file (i.e. the real source file that the server template file +becomes) so that minor interface changes can be consistently and easily +applied to the real code.
  12. + +
  13. +Server procedure file - This is the file that is modified by the sed script +generated.  It originated from the server template file.
  14. +
+The awk script reads a source file, db_server/rpc.src that describes +each operation and what sorts of arguments it takes and what it returns +from the server.  The syntax of the source file describes the interface +to that operation.  There are four (4) parts to the syntax: +
    +
  1. +BEGIN function version# codetype - begins a new functional +interface for the given function.  Each function has +a version number, currently all of them are at version number +one (1).  The code type indicates to the awk script +what kind of code to generate.  The choices are:
  2. + +
      +
    • +CODE - Generate all code, and return a status value.  If specified, +the client code will simply return the status to the user upon completion +of the RPC call.
    • + +
    • +RETCODE - Generate all code and call a return function in the client +template file to deal with client issues or with other returned items.  +If specified, the client code generated will call a function of the form +__dbcl_<name>_ret() +where +<name> is replaced with the function name given here.  This function +is placed in the template file because this indicates that something special +must occur on return.  The arguments to this function are the same +as those for the client function, with the addition of the reply message +structure.
    • + +
    • +NOCLNTCODE - Generate XDR and server code, but no corresponding +client code. (This is used for functions that are not named the same thing +on both sides.  The only use of this at the moment is db_env_create +and db_create.  The environment create call to the server is actually +called from the DBENV->set_server() +method.  The db_create code exists elsewhere in the library and we +modify that code for the client call.)
    • +
    + +
  3. +ARG RPC-type C-type varname [list-type]- each line of this +describes an argument to the function.  The argument is called varname.  +The C-type given is what it should look like in the C code +generated, such as DB *, u_int32_t, const char *.  The +RPC-type +is an indication about how the RPC request message should be constructed.  +The RPC-types allowed are described below.
  4. + +
  5. +RET RPC-type C-type varname [list-type]- each line of this +describes what the server should return from this procedure call (in addition +to a status, which is always returned and should not be specified).  +The argument is called varname.  The C-type +given is what it should look like in the C code generated, such as DB +*, u_int32_t, const char *.  The RPC-type is an +indication about how the RPC reply message should be constructed.  +The RPC-types are described below.
  6. + +
  7. +END - End the description of this function.  The result is +that when the awk script encounters the END tag, it now has all +the information it needs to construct the generated code for this function.
  8. +
+The RPC-type must be one of the following: +
    +
  • +IGNORE - This argument is not passed to the server and should be +ignored when constructing the XDR code.  Only allowed for an ARG +specfication.
  • + +
  • +STRING - This argument is a string.
  • + +
  • +INT - This argument is an integer of some sort.
  • + +
  • +DBT - This argument is a DBT, resulting in its decomposition into +the request message.
  • + +
  • +LIST - This argument is an opaque list passed to the server (NULL-terminated).  +If an argument of this type is given, it must have a list-type +specified that is one of:
  • + +
      +
    • +STRING
    • + +
    • +INT
    • + +
    • +ID.
    • +
    + +
  • +ID - This argument is an identifier.
  • +
+So, for example, the source for the DB->join RPC call looks like: +
BEGIN   dbjoin          1       RETCODE
+ARG     ID      DB *            dbp 
+ARG     LIST    DBC **          curs    ID
+ARG     IGNORE  DBC **          dbcpp 
+ARG     INT     u_int32_t       flags
+RET     ID      long            dbcid
+END
+Our first line tells us we are writing the dbjoin function.  It requires +special code on the client so we indicate that with the RETCODE.  +This method takes four arguments.  For the RPC request we need the +database ID from the dbp, we construct a NULL-terminated list of IDs for +the cursor list, we ignore the argument to return the cursor handle to +the user, and we pass along the flags.  On the return, the reply contains +a status, by default, and additionally, it contains the ID of the newly +created cursor. +

+Building and Installing

+I need to verify with Don Anderson, but I believe we should just build +the server program, just like we do for db_stat, db_checkpoint, etc.  +Basically it can be treated as a utility program from the building and +installation perspective. +

As mentioned early on, in the section on DB +Modifications, we have a single library, but allowing the user to access +the client portion by sending a flag to db_env_create().  +The Makefile is modified to include the new files. +

Testing is performed in two ways.  First I have a new example program, +that should become part of the example directory.  It is basically +a merging of ex_access.c and ex_env.c.  This example is adequate to +test basic functionality, as it does just does database put/get calls and +appropriate open and close calls.  However, in order to test the full +set of functions a more generalized scheme is required.  For the moment, +I am going to modify the Tcl interface to accept the server information.  +Nothing else should need to change in Tcl.  Then we can either write +our own test modules or use a subset of the existing ones to test functionality +on a regular basis. + + diff --git a/db/rpc_server/db_server.sed b/db/rpc_server/db_server.sed new file mode 100644 index 000000000..f028f778e --- /dev/null +++ b/db/rpc_server/db_server.sed @@ -0,0 +1,5 @@ +1i\ +\#include "db_config.h"\ +\#ifdef HAVE_RPC +$a\ +\#endif /* HAVE_RPC */ diff --git a/db/rpc_server/db_server.x b/db/rpc_server/db_server.x new file mode 100644 index 000000000..6bdff201f --- /dev/null +++ b/db/rpc_server/db_server.x @@ -0,0 +1,492 @@ +/* Do not edit: automatically built by gen_rpc.awk. */ + +struct __env_cachesize_msg { + unsigned int dbenvcl_id; + unsigned int gbytes; + unsigned int bytes; + unsigned int ncache; +}; + +struct __env_cachesize_reply { + unsigned int status; +}; + +struct __env_close_msg { + unsigned int dbenvcl_id; + unsigned int flags; +}; + +struct __env_close_reply { + unsigned int status; +}; + +struct __env_create_msg { + unsigned int timeout; +}; + +struct __env_create_reply { + unsigned int status; + unsigned int envcl_id; +}; + +struct __env_flags_msg { + unsigned int dbenvcl_id; + unsigned int flags; + unsigned int onoff; +}; + +struct __env_flags_reply { + unsigned int status; +}; + +struct __env_open_msg { + unsigned int dbenvcl_id; + string home<>; + unsigned int flags; + unsigned int mode; +}; + +struct __env_open_reply { + unsigned int status; +}; + +struct __env_remove_msg { + unsigned int dbenvcl_id; + string home<>; + unsigned int flags; +}; + +struct __env_remove_reply { + unsigned int status; +}; + +struct __txn_abort_msg { + unsigned int txnpcl_id; +}; + +struct __txn_abort_reply { + unsigned int status; +}; + +struct __txn_begin_msg { + unsigned int envpcl_id; + unsigned int parentcl_id; + unsigned int flags; +}; + +struct __txn_begin_reply { + unsigned int status; + unsigned int txnidcl_id; +}; + +struct __txn_commit_msg { + unsigned int txnpcl_id; + unsigned int flags; +}; + +struct __txn_commit_reply { + unsigned int status; +}; + +struct __db_bt_maxkey_msg { + unsigned int dbpcl_id; + unsigned int maxkey; +}; + +struct __db_bt_maxkey_reply { + unsigned int status; +}; + +struct __db_bt_minkey_msg { + unsigned int dbpcl_id; + unsigned int minkey; +}; + +struct __db_bt_minkey_reply { + unsigned int status; +}; + +struct __db_close_msg { + unsigned int dbpcl_id; + unsigned int flags; +}; + +struct __db_close_reply { + unsigned int status; +}; + +struct __db_create_msg { + unsigned int flags; + unsigned int envpcl_id; +}; + +struct __db_create_reply { + unsigned int status; + unsigned int dbpcl_id; +}; + +struct __db_del_msg { + unsigned int dbpcl_id; + unsigned int txnpcl_id; + unsigned int keydlen; + unsigned int keydoff; + unsigned int keyflags; + opaque keydata<>; + unsigned int flags; +}; + +struct __db_del_reply { + unsigned int status; +}; + +struct __db_extentsize_msg { + unsigned int dbpcl_id; + unsigned int extentsize; +}; + +struct __db_extentsize_reply { + unsigned int status; +}; + +struct __db_flags_msg { + unsigned int dbpcl_id; + unsigned int flags; +}; + +struct __db_flags_reply { + unsigned int status; +}; + +struct __db_get_msg { + unsigned int dbpcl_id; + unsigned int txnpcl_id; + unsigned int keydlen; + unsigned int keydoff; + unsigned int keyflags; + opaque keydata<>; + unsigned int datadlen; + unsigned int datadoff; + unsigned int dataflags; + opaque datadata<>; + unsigned int flags; +}; + +struct __db_get_reply { + unsigned int status; + opaque keydata<>; + opaque datadata<>; +}; + +struct __db_h_ffactor_msg { + unsigned int dbpcl_id; + unsigned int ffactor; +}; + +struct __db_h_ffactor_reply { + unsigned int status; +}; + +struct __db_h_nelem_msg { + unsigned int dbpcl_id; + unsigned int nelem; +}; + +struct __db_h_nelem_reply { + unsigned int status; +}; + +struct __db_key_range_msg { + unsigned int dbpcl_id; + unsigned int txnpcl_id; + unsigned int keydlen; + unsigned int keydoff; + unsigned int keyflags; + opaque keydata<>; + unsigned int flags; +}; + +struct __db_key_range_reply { + unsigned int status; + double less; + double equal; + double greater; +}; + +struct __db_lorder_msg { + unsigned int dbpcl_id; + unsigned int lorder; +}; + +struct __db_lorder_reply { + unsigned int status; +}; + +struct __db_open_msg { + unsigned int dbpcl_id; + string name<>; + string subdb<>; + unsigned int type; + unsigned int flags; + unsigned int mode; +}; + +struct __db_open_reply { + unsigned int status; + unsigned int type; + unsigned int dbflags; +}; + +struct __db_pagesize_msg { + unsigned int dbpcl_id; + unsigned int pagesize; +}; + +struct __db_pagesize_reply { + unsigned int status; +}; + +struct __db_put_msg { + unsigned int dbpcl_id; + unsigned int txnpcl_id; + unsigned int keydlen; + unsigned int keydoff; + unsigned int keyflags; + opaque keydata<>; + unsigned int datadlen; + unsigned int datadoff; + unsigned int dataflags; + opaque datadata<>; + unsigned int flags; +}; + +struct __db_put_reply { + unsigned int status; + opaque keydata<>; +}; + +struct __db_re_delim_msg { + unsigned int dbpcl_id; + unsigned int delim; +}; + +struct __db_re_delim_reply { + unsigned int status; +}; + +struct __db_re_len_msg { + unsigned int dbpcl_id; + unsigned int len; +}; + +struct __db_re_len_reply { + unsigned int status; +}; + +struct __db_re_pad_msg { + unsigned int dbpcl_id; + unsigned int pad; +}; + +struct __db_re_pad_reply { + unsigned int status; +}; + +struct __db_remove_msg { + unsigned int dbpcl_id; + string name<>; + string subdb<>; + unsigned int flags; +}; + +struct __db_remove_reply { + unsigned int status; +}; + +struct __db_rename_msg { + unsigned int dbpcl_id; + string name<>; + string subdb<>; + string newname<>; + unsigned int flags; +}; + +struct __db_rename_reply { + unsigned int status; +}; + +struct __db_stat_msg { + unsigned int dbpcl_id; + unsigned int flags; +}; + +struct __db_stat_statsreplist { + opaque ent<>; + __db_stat_statsreplist *next; +}; + +struct __db_stat_reply { + unsigned int status; + __db_stat_statsreplist *statslist; +}; + +struct __db_swapped_msg { + unsigned int dbpcl_id; +}; + +struct __db_swapped_reply { + unsigned int status; +}; + +struct __db_sync_msg { + unsigned int dbpcl_id; + unsigned int flags; +}; + +struct __db_sync_reply { + unsigned int status; +}; + +struct __db_cursor_msg { + unsigned int dbpcl_id; + unsigned int txnpcl_id; + unsigned int flags; +}; + +struct __db_cursor_reply { + unsigned int status; + unsigned int dbcidcl_id; +}; + +struct __db_join_curslist { + opaque ent<>; + __db_join_curslist *next; +}; + +struct __db_join_msg { + unsigned int dbpcl_id; + __db_join_curslist *curslist; + unsigned int flags; +}; + +struct __db_join_reply { + unsigned int status; + unsigned int dbcidcl_id; +}; + +struct __dbc_close_msg { + unsigned int dbccl_id; +}; + +struct __dbc_close_reply { + unsigned int status; +}; + +struct __dbc_count_msg { + unsigned int dbccl_id; + unsigned int flags; +}; + +struct __dbc_count_reply { + unsigned int status; + unsigned int dupcount; +}; + +struct __dbc_del_msg { + unsigned int dbccl_id; + unsigned int flags; +}; + +struct __dbc_del_reply { + unsigned int status; +}; + +struct __dbc_dup_msg { + unsigned int dbccl_id; + unsigned int flags; +}; + +struct __dbc_dup_reply { + unsigned int status; + unsigned int dbcidcl_id; +}; + +struct __dbc_get_msg { + unsigned int dbccl_id; + unsigned int keydlen; + unsigned int keydoff; + unsigned int keyflags; + opaque keydata<>; + unsigned int datadlen; + unsigned int datadoff; + unsigned int dataflags; + opaque datadata<>; + unsigned int flags; +}; + +struct __dbc_get_reply { + unsigned int status; + opaque keydata<>; + opaque datadata<>; +}; + +struct __dbc_put_msg { + unsigned int dbccl_id; + unsigned int keydlen; + unsigned int keydoff; + unsigned int keyflags; + opaque keydata<>; + unsigned int datadlen; + unsigned int datadoff; + unsigned int dataflags; + opaque datadata<>; + unsigned int flags; +}; + +struct __dbc_put_reply { + unsigned int status; + opaque keydata<>; +}; +program DB_SERVERPROG { + version DB_SERVERVERS { + __env_cachesize_reply __DB_env_cachesize(__env_cachesize_msg) = 1; + __env_close_reply __DB_env_close(__env_close_msg) = 2; + __env_create_reply __DB_env_create(__env_create_msg) = 3; + __env_flags_reply __DB_env_flags(__env_flags_msg) = 4; + __env_open_reply __DB_env_open(__env_open_msg) = 5; + __env_remove_reply __DB_env_remove(__env_remove_msg) = 6; + __txn_abort_reply __DB_txn_abort(__txn_abort_msg) = 7; + __txn_begin_reply __DB_txn_begin(__txn_begin_msg) = 8; + __txn_commit_reply __DB_txn_commit(__txn_commit_msg) = 9; + __db_bt_maxkey_reply __DB_db_bt_maxkey(__db_bt_maxkey_msg) = 10; + __db_bt_minkey_reply __DB_db_bt_minkey(__db_bt_minkey_msg) = 11; + __db_close_reply __DB_db_close(__db_close_msg) = 12; + __db_create_reply __DB_db_create(__db_create_msg) = 13; + __db_del_reply __DB_db_del(__db_del_msg) = 14; + __db_extentsize_reply __DB_db_extentsize(__db_extentsize_msg) = 15; + __db_flags_reply __DB_db_flags(__db_flags_msg) = 16; + __db_get_reply __DB_db_get(__db_get_msg) = 17; + __db_h_ffactor_reply __DB_db_h_ffactor(__db_h_ffactor_msg) = 18; + __db_h_nelem_reply __DB_db_h_nelem(__db_h_nelem_msg) = 19; + __db_key_range_reply __DB_db_key_range(__db_key_range_msg) = 20; + __db_lorder_reply __DB_db_lorder(__db_lorder_msg) = 21; + __db_open_reply __DB_db_open(__db_open_msg) = 22; + __db_pagesize_reply __DB_db_pagesize(__db_pagesize_msg) = 23; + __db_put_reply __DB_db_put(__db_put_msg) = 24; + __db_re_delim_reply __DB_db_re_delim(__db_re_delim_msg) = 25; + __db_re_len_reply __DB_db_re_len(__db_re_len_msg) = 26; + __db_re_pad_reply __DB_db_re_pad(__db_re_pad_msg) = 27; + __db_remove_reply __DB_db_remove(__db_remove_msg) = 28; + __db_rename_reply __DB_db_rename(__db_rename_msg) = 29; + __db_stat_reply __DB_db_stat(__db_stat_msg) = 30; + __db_swapped_reply __DB_db_swapped(__db_swapped_msg) = 31; + __db_sync_reply __DB_db_sync(__db_sync_msg) = 32; + __db_cursor_reply __DB_db_cursor(__db_cursor_msg) = 33; + __db_join_reply __DB_db_join(__db_join_msg) = 34; + __dbc_close_reply __DB_dbc_close(__dbc_close_msg) = 35; + __dbc_count_reply __DB_dbc_count(__dbc_count_msg) = 36; + __dbc_del_reply __DB_dbc_del(__dbc_del_msg) = 37; + __dbc_dup_reply __DB_dbc_dup(__dbc_dup_msg) = 38; + __dbc_get_reply __DB_dbc_get(__dbc_get_msg) = 39; + __dbc_put_reply __DB_dbc_put(__dbc_put_msg) = 40; + } = 1; +} = 351457; diff --git a/db/rpc_server/db_server_proc.c b/db/rpc_server/db_server_proc.c new file mode 100644 index 000000000..108a00fb3 --- /dev/null +++ b/db/rpc_server/db_server_proc.c @@ -0,0 +1,1546 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifdef HAVE_RPC +#ifndef lint +static const char revid[] = "$Id: db_server_proc.c,v 1.48 2001/01/06 16:08:01 sue Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include + +#include +#endif +#include "db_server.h" + +#include "db_int.h" +#include "db_server_int.h" +#include "rpc_server_ext.h" + +static int __db_stats_list __P((DB_ENV *, + __db_stat_statsreplist **, u_int32_t *, int)); + +/* BEGIN __env_cachesize_1_proc */ +void +__env_cachesize_1_proc(dbenvcl_id, gbytes, bytes, + ncache, replyp) + long dbenvcl_id; + u_int32_t gbytes; + u_int32_t bytes; + u_int32_t ncache; + __env_cachesize_reply *replyp; +/* END __env_cachesize_1_proc */ +{ + int ret; + DB_ENV * dbenv; + ct_entry *dbenv_ctp; + + ACTIVATE_CTP(dbenv_ctp, dbenvcl_id, CT_ENV); + dbenv = (DB_ENV *)dbenv_ctp->ct_anyp; + + ret = dbenv->set_cachesize(dbenv, gbytes, bytes, ncache); + + replyp->status = ret; + return; +} + +/* BEGIN __env_close_1_proc */ +void +__env_close_1_proc(dbenvcl_id, flags, replyp) + long dbenvcl_id; + u_int32_t flags; + __env_close_reply *replyp; +/* END __env_close_1_proc */ +{ + replyp->status = __dbenv_close_int(dbenvcl_id, flags); + return; +} + +/* BEGIN __env_create_1_proc */ +void +__env_create_1_proc(timeout, replyp) + u_int32_t timeout; + __env_create_reply *replyp; +/* END __env_create_1_proc */ +{ + int ret; + DB_ENV *dbenv; + ct_entry *ctp; + + ctp = new_ct_ent(&replyp->status); + if (ctp == NULL) + return; + if ((ret = db_env_create(&dbenv, 0)) == 0) { + ctp->ct_envp = dbenv; + ctp->ct_type = CT_ENV; + ctp->ct_parent = NULL; + ctp->ct_envparent = ctp; + __dbsrv_settimeout(ctp, timeout); + __dbsrv_active(ctp); + replyp->envcl_id = ctp->ct_id; + } else + __dbclear_ctp(ctp); + + replyp->status = ret; + return; +} + +/* BEGIN __env_flags_1_proc */ +void +__env_flags_1_proc(dbenvcl_id, flags, onoff, replyp) + long dbenvcl_id; + u_int32_t flags; + u_int32_t onoff; + __env_flags_reply *replyp; +/* END __env_flags_1_proc */ +{ + int ret; + DB_ENV * dbenv; + ct_entry *dbenv_ctp; + + ACTIVATE_CTP(dbenv_ctp, dbenvcl_id, CT_ENV); + dbenv = (DB_ENV *)dbenv_ctp->ct_anyp; + + ret = dbenv->set_flags(dbenv, flags, onoff); + + replyp->status = ret; + return; +} +/* BEGIN __env_open_1_proc */ +void +__env_open_1_proc(dbenvcl_id, home, flags, + mode, replyp) + long dbenvcl_id; + char *home; + u_int32_t flags; + u_int32_t mode; + __env_open_reply *replyp; +/* END __env_open_1_proc */ +{ + int ret; + DB_ENV * dbenv; + ct_entry *dbenv_ctp; + char *fullhome; + + ACTIVATE_CTP(dbenv_ctp, dbenvcl_id, CT_ENV); + dbenv = (DB_ENV *)dbenv_ctp->ct_anyp; + fullhome = get_home(home); + if (fullhome == NULL) { + replyp->status = DB_NOSERVER_HOME; + return; + } + + ret = dbenv->open(dbenv, fullhome, flags, mode); + replyp->status = ret; + return; +} + +/* BEGIN __env_remove_1_proc */ +void +__env_remove_1_proc(dbenvcl_id, home, flags, replyp) + long dbenvcl_id; + char *home; + u_int32_t flags; + __env_remove_reply *replyp; +/* END __env_remove_1_proc */ +{ + int ret; + DB_ENV * dbenv; + ct_entry *dbenv_ctp; + char *fullhome; + + ACTIVATE_CTP(dbenv_ctp, dbenvcl_id, CT_ENV); + dbenv = (DB_ENV *)dbenv_ctp->ct_anyp; + fullhome = get_home(home); + if (fullhome == NULL) { + replyp->status = DB_NOSERVER_HOME; + return; + } + + ret = dbenv->remove(dbenv, fullhome, flags); + __dbdel_ctp(dbenv_ctp); + replyp->status = ret; + return; +} + +/* BEGIN __txn_abort_1_proc */ +void +__txn_abort_1_proc(txnpcl_id, replyp) + long txnpcl_id; + __txn_abort_reply *replyp; +/* END __txn_abort_1_proc */ +{ + DB_TXN * txnp; + ct_entry *txnp_ctp; + int ret; + + ACTIVATE_CTP(txnp_ctp, txnpcl_id, CT_TXN); + txnp = (DB_TXN *)txnp_ctp->ct_anyp; + + ret = txn_abort(txnp); + __dbdel_ctp(txnp_ctp); + replyp->status = ret; + return; +} + +/* BEGIN __txn_begin_1_proc */ +void +__txn_begin_1_proc(envpcl_id, parentcl_id, + flags, replyp) + long envpcl_id; + long parentcl_id; + u_int32_t flags; + __txn_begin_reply *replyp; +/* END __txn_begin_1_proc */ +{ + int ret; + DB_ENV * envp; + ct_entry *envp_ctp; + DB_TXN * parent; + ct_entry *parent_ctp; + DB_TXN *txnp; + ct_entry *ctp; + + ACTIVATE_CTP(envp_ctp, envpcl_id, CT_ENV); + envp = (DB_ENV *)envp_ctp->ct_anyp; + parent_ctp = NULL; + + ctp = new_ct_ent(&replyp->status); + if (ctp == NULL) + return; + + if (parentcl_id != 0) { + ACTIVATE_CTP(parent_ctp, parentcl_id, CT_TXN); + parent = (DB_TXN *)parent_ctp->ct_anyp; + ctp->ct_activep = parent_ctp->ct_activep; + } else + parent = NULL; + + ret = txn_begin(envp, parent, &txnp, flags); + if (ret == 0) { + ctp->ct_txnp = txnp; + ctp->ct_type = CT_TXN; + ctp->ct_parent = parent_ctp; + ctp->ct_envparent = envp_ctp; + replyp->txnidcl_id = ctp->ct_id; + __dbsrv_settimeout(ctp, envp_ctp->ct_timeout); + __dbsrv_active(ctp); + } else + __dbclear_ctp(ctp); + + replyp->status = ret; + return; +} + +/* BEGIN __txn_commit_1_proc */ +void +__txn_commit_1_proc(txnpcl_id, flags, replyp) + long txnpcl_id; + u_int32_t flags; + __txn_commit_reply *replyp; +/* END __txn_commit_1_proc */ +{ + int ret; + DB_TXN * txnp; + ct_entry *txnp_ctp; + + ACTIVATE_CTP(txnp_ctp, txnpcl_id, CT_TXN); + txnp = (DB_TXN *)txnp_ctp->ct_anyp; + + ret = txn_commit(txnp, flags); + __dbdel_ctp(txnp_ctp); + + replyp->status = ret; + return; +} + +/* BEGIN __db_bt_maxkey_1_proc */ +void +__db_bt_maxkey_1_proc(dbpcl_id, maxkey, replyp) + long dbpcl_id; + u_int32_t maxkey; + __db_bt_maxkey_reply *replyp; +/* END __db_bt_maxkey_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + + ret = dbp->set_bt_maxkey(dbp, maxkey); + + replyp->status = ret; + return; +} + +/* BEGIN __db_bt_minkey_1_proc */ +void +__db_bt_minkey_1_proc(dbpcl_id, minkey, replyp) + long dbpcl_id; + u_int32_t minkey; + __db_bt_minkey_reply *replyp; +/* END __db_bt_minkey_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + + ret = dbp->set_bt_minkey(dbp, minkey); + + replyp->status = ret; + return; +} + +/* BEGIN __db_close_1_proc */ +void +__db_close_1_proc(dbpcl_id, flags, replyp) + long dbpcl_id; + u_int32_t flags; + __db_close_reply *replyp; +/* END __db_close_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + + ret = dbp->close(dbp, flags); + __dbdel_ctp(dbp_ctp); + + replyp-> status= ret; + return; +} + +/* BEGIN __db_create_1_proc */ +void +__db_create_1_proc(flags, envpcl_id, replyp) + u_int32_t flags; + long envpcl_id; + __db_create_reply *replyp; +/* END __db_create_1_proc */ +{ + int ret; + DB_ENV * envp; + DB *dbp; + ct_entry *envp_ctp, *dbp_ctp; + + ACTIVATE_CTP(envp_ctp, envpcl_id, CT_ENV); + envp = (DB_ENV *)envp_ctp->ct_anyp; + + dbp_ctp = new_ct_ent(&replyp->status); + if (dbp_ctp == NULL) + return ; + /* + * We actually require env's for databases. The client should + * have caught it, but just in case. + */ + DB_ASSERT(envp != NULL); + if ((ret = db_create(&dbp, envp, flags)) == 0) { + dbp_ctp->ct_dbp = dbp; + dbp_ctp->ct_type = CT_DB; + dbp_ctp->ct_parent = envp_ctp; + dbp_ctp->ct_envparent = envp_ctp; + replyp->dbpcl_id = dbp_ctp->ct_id; + } else + __dbclear_ctp(dbp_ctp); + replyp->status = ret; + return; +} + +/* BEGIN __db_del_1_proc */ +void +__db_del_1_proc(dbpcl_id, txnpcl_id, keydlen, + keydoff, keyflags, keydata, keysize, + flags, replyp) + long dbpcl_id; + long txnpcl_id; + u_int32_t keydlen; + u_int32_t keydoff; + u_int32_t keyflags; + void *keydata; + u_int32_t keysize; + u_int32_t flags; + __db_del_reply *replyp; +/* END __db_del_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + DB_TXN * txnp; + ct_entry *txnp_ctp; + DBT key; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + if (txnpcl_id != 0) { + ACTIVATE_CTP(txnp_ctp, txnpcl_id, CT_TXN); + txnp = (DB_TXN *)txnp_ctp->ct_anyp; + } else + txnp = NULL; + + memset(&key, 0, sizeof(key)); + + /* Set up key DBT */ + key.dlen = keydlen; + key.doff = keydoff; + key.flags = keyflags; + key.size = keysize; + key.data = keydata; + + ret = dbp->del(dbp, txnp, &key, flags); + + replyp->status = ret; + return; +} + +/* BEGIN __db_extentsize_1_proc */ +void +__db_extentsize_1_proc(dbpcl_id, extentsize, replyp) + long dbpcl_id; + u_int32_t extentsize; + __db_extentsize_reply *replyp; +/* END __db_extentsize_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + + ret = dbp->set_q_extentsize(dbp, extentsize); + + replyp->status = ret; + return; +} + +/* BEGIN __db_flags_1_proc */ +void +__db_flags_1_proc(dbpcl_id, flags, replyp) + long dbpcl_id; + u_int32_t flags; + __db_flags_reply *replyp; +/* END __db_flags_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + + ret = dbp->set_flags(dbp, flags); + + replyp->status = ret; + return; +} + +/* BEGIN __db_get_1_proc */ +void +__db_get_1_proc(dbpcl_id, txnpcl_id, keydlen, + keydoff, keyflags, keydata, keysize, + datadlen, datadoff, dataflags, datadata, + datasize, flags, replyp, freep) + long dbpcl_id; + long txnpcl_id; + u_int32_t keydlen; + u_int32_t keydoff; + u_int32_t keyflags; + void *keydata; + u_int32_t keysize; + u_int32_t datadlen; + u_int32_t datadoff; + u_int32_t dataflags; + void *datadata; + u_int32_t datasize; + u_int32_t flags; + __db_get_reply *replyp; + int * freep; +/* END __db_get_1_proc */ +{ + int key_alloc, ret; + DB * dbp; + ct_entry *dbp_ctp; + DB_TXN * txnp; + ct_entry *txnp_ctp; + DBT key, data; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + if (txnpcl_id != 0) { + ACTIVATE_CTP(txnp_ctp, txnpcl_id, CT_TXN); + txnp = (DB_TXN *)txnp_ctp->ct_anyp; + } else + txnp = NULL; + + *freep = 0; + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + + /* Set up key and data DBT */ + key.dlen = keydlen; + key.doff = keydoff; + /* + * Ignore memory related flags on server. + */ + key.flags = DB_DBT_MALLOC; + if (keyflags & DB_DBT_PARTIAL) + key.flags |= DB_DBT_PARTIAL; + key.size = keysize; + key.data = keydata; + + data.dlen = datadlen; + data.doff = datadoff; + /* + * Ignore memory related flags on server. + */ + data.flags = DB_DBT_MALLOC; + if (dataflags & DB_DBT_PARTIAL) + data.flags |= DB_DBT_PARTIAL; + data.size = datasize; + data.data = datadata; + + /* Got all our stuff, now do the get */ + ret = dbp->get(dbp, txnp, &key, &data, flags); + /* + * Otherwise just status. + */ + if (ret == 0) { + /* + * XXX + * We need to xdr_free whatever we are returning, next time. + * However, DB does not allocate a new key if one was given + * and we'd be free'ing up space allocated in the request. + * So, allocate a new key/data pointer if it is the same one + * as in the request. + */ + *freep = 1; + /* + * Key + */ + key_alloc = 0; + if (key.data == keydata) { + ret = __os_malloc(dbp->dbenv, + key.size, NULL, &replyp->keydata.keydata_val); + if (ret != 0) { + __os_free(key.data, key.size); + __os_free(data.data, data.size); + goto err; + } + key_alloc = 1; + memcpy(replyp->keydata.keydata_val, key.data, key.size); + } else + replyp->keydata.keydata_val = key.data; + + replyp->keydata.keydata_len = key.size; + + /* + * Data + */ + if (data.data == datadata) { + ret = __os_malloc(dbp->dbenv, + data.size, NULL, &replyp->datadata.datadata_val); + if (ret != 0) { + __os_free(key.data, key.size); + __os_free(data.data, data.size); + if (key_alloc) + __os_free(replyp->keydata.keydata_val, + key.size); + goto err; + } + memcpy(replyp->datadata.datadata_val, data.data, + data.size); + } else + replyp->datadata.datadata_val = data.data; + replyp->datadata.datadata_len = data.size; + } else { +err: replyp->keydata.keydata_val = NULL; + replyp->keydata.keydata_len = 0; + replyp->datadata.datadata_val = NULL; + replyp->datadata.datadata_len = 0; + *freep = 0; + } + replyp->status = ret; + return; +} + +/* BEGIN __db_h_ffactor_1_proc */ +void +__db_h_ffactor_1_proc(dbpcl_id, ffactor, replyp) + long dbpcl_id; + u_int32_t ffactor; + __db_h_ffactor_reply *replyp; +/* END __db_h_ffactor_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + + ret = dbp->set_h_ffactor(dbp, ffactor); + + replyp->status = ret; + return; +} + +/* BEGIN __db_h_nelem_1_proc */ +void +__db_h_nelem_1_proc(dbpcl_id, nelem, replyp) + long dbpcl_id; + u_int32_t nelem; + __db_h_nelem_reply *replyp; +/* END __db_h_nelem_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + + ret = dbp->set_h_nelem(dbp, nelem); + + replyp->status = ret; + return; +} + +/* BEGIN __db_key_range_1_proc */ +void +__db_key_range_1_proc(dbpcl_id, txnpcl_id, keydlen, + keydoff, keyflags, keydata, keysize, + flags, replyp) + long dbpcl_id; + long txnpcl_id; + u_int32_t keydlen; + u_int32_t keydoff; + u_int32_t keyflags; + void *keydata; + u_int32_t keysize; + u_int32_t flags; + __db_key_range_reply *replyp; +/* END __db_key_range_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + DB_TXN * txnp; + ct_entry *txnp_ctp; + DBT key; + DB_KEY_RANGE range; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + if (txnpcl_id != 0) { + ACTIVATE_CTP(txnp_ctp, txnpcl_id, CT_TXN); + txnp = (DB_TXN *)txnp_ctp->ct_anyp; + } else + txnp = NULL; + + memset(&key, 0, sizeof(key)); + /* Set up key and data DBT */ + key.dlen = keydlen; + key.doff = keydoff; + key.size = keysize; + key.data = keydata; + key.flags = keyflags; + + ret = dbp->key_range(dbp, txnp, &key, &range, flags); + + replyp->status = ret; + replyp->less = range.less; + replyp->equal = range.equal; + replyp->greater = range.greater; + return; +} + +/* BEGIN __db_lorder_1_proc */ +void +__db_lorder_1_proc(dbpcl_id, lorder, replyp) + long dbpcl_id; + u_int32_t lorder; + __db_lorder_reply *replyp; +/* END __db_lorder_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + + ret = dbp->set_lorder(dbp, lorder); + + replyp->status = ret; + return; +} + +/* BEGIN __dbopen_1_proc */ +void +__db_open_1_proc(dbpcl_id, name, subdb, + type, flags, mode, replyp) + long dbpcl_id; + char *name; + char *subdb; + u_int32_t type; + u_int32_t flags; + u_int32_t mode; + __db_open_reply *replyp; +/* END __db_open_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + + ret = dbp->open(dbp, name, subdb, (DBTYPE)type, flags, mode); + if (ret == 0) { + replyp->type = (int) dbp->get_type(dbp); + /* XXX + * Tcl needs to peek at dbp->flags for DB_AM_DUP. Send + * this dbp's flags back. + */ + replyp->dbflags = (int) dbp->flags; + } + replyp->status = ret; + return; +} + +/* BEGIN __db_pagesize_1_proc */ +void +__db_pagesize_1_proc(dbpcl_id, pagesize, replyp) + long dbpcl_id; + u_int32_t pagesize; + __db_pagesize_reply *replyp; +/* END __db_pagesize_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + + ret = dbp->set_pagesize(dbp, pagesize); + + replyp->status = ret; + return; +} + +/* BEGIN __db_put_1_proc */ +void +__db_put_1_proc(dbpcl_id, txnpcl_id, keydlen, + keydoff, keyflags, keydata, keysize, + datadlen, datadoff, dataflags, datadata, + datasize, flags, replyp, freep) + long dbpcl_id; + long txnpcl_id; + u_int32_t keydlen; + u_int32_t keydoff; + u_int32_t keyflags; + void *keydata; + u_int32_t keysize; + u_int32_t datadlen; + u_int32_t datadoff; + u_int32_t dataflags; + void *datadata; + u_int32_t datasize; + u_int32_t flags; + __db_put_reply *replyp; + int * freep; +/* END __db_put_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + DB_TXN * txnp; + ct_entry *txnp_ctp; + DBT key, data; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + if (txnpcl_id != 0) { + ACTIVATE_CTP(txnp_ctp, txnpcl_id, CT_TXN); + txnp = (DB_TXN *)txnp_ctp->ct_anyp; + } else + txnp = NULL; + + *freep = 0; + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + + /* Set up key and data DBT */ + key.dlen = keydlen; + key.doff = keydoff; + /* + * Ignore memory related flags on server. + */ + key.flags = DB_DBT_MALLOC; + if (keyflags & DB_DBT_PARTIAL) + key.flags |= DB_DBT_PARTIAL; + key.size = keysize; + key.data = keydata; + + data.dlen = datadlen; + data.doff = datadoff; + data.flags = dataflags; + data.size = datasize; + data.data = datadata; + + /* Got all our stuff, now do the put */ + ret = dbp->put(dbp, txnp, &key, &data, flags); + /* + * If the client did a DB_APPEND, set up key in reply. + * Otherwise just status. + */ + if (ret == 0 && (flags == DB_APPEND)) { + /* + * XXX + * We need to xdr_free whatever we are returning, next time. + * However, DB does not allocate a new key if one was given + * and we'd be free'ing up space allocated in the request. + * So, allocate a new key/data pointer if it is the same one + * as in the request. + */ + *freep = 1; + /* + * Key + */ + if (key.data == keydata) { + ret = __os_malloc(dbp->dbenv, + key.size, NULL, &replyp->keydata.keydata_val); + if (ret != 0) { + __os_free(key.data, key.size); + goto err; + } + memcpy(replyp->keydata.keydata_val, key.data, key.size); + } else + replyp->keydata.keydata_val = key.data; + + replyp->keydata.keydata_len = key.size; + } else { +err: replyp->keydata.keydata_val = NULL; + replyp->keydata.keydata_len = 0; + *freep = 0; + } + replyp->status = ret; + return; +} + +/* BEGIN __db_re_delim_1_proc */ +void +__db_re_delim_1_proc(dbpcl_id, delim, replyp) + long dbpcl_id; + u_int32_t delim; + __db_re_delim_reply *replyp; +/* END __db_re_delim_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + + ret = dbp->set_re_delim(dbp, delim); + + replyp->status = ret; + return; +} + +/* BEGIN __db_re_len_1_proc */ +void +__db_re_len_1_proc(dbpcl_id, len, replyp) + long dbpcl_id; + u_int32_t len; + __db_re_len_reply *replyp; +/* END __db_re_len_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + + ret = dbp->set_re_len(dbp, len); + + replyp->status = ret; + return; +} + +/* BEGIN __db_re_pad_1_proc */ +void +__db_re_pad_1_proc(dbpcl_id, pad, replyp) + long dbpcl_id; + u_int32_t pad; + __db_re_pad_reply *replyp; +/* END __db_re_pad_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + + ret = dbp->set_re_pad(dbp, pad); + + replyp->status = ret; + return; +} + +/* BEGIN __db_remove_1_proc */ +void +__db_remove_1_proc(dbpcl_id, name, subdb, + flags, replyp) + long dbpcl_id; + char *name; + char *subdb; + u_int32_t flags; + __db_remove_reply *replyp; +/* END __db_remove_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + + ret = dbp->remove(dbp, name, subdb, flags); + __dbdel_ctp(dbp_ctp); + + replyp->status = ret; + return; +} + +/* BEGIN __db_rename_1_proc */ +void +__db_rename_1_proc(dbpcl_id, name, subdb, + newname, flags, replyp) + long dbpcl_id; + char *name; + char *subdb; + char *newname; + u_int32_t flags; + __db_rename_reply *replyp; +/* END __db_rename_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + + ret = dbp->rename(dbp, name, subdb, newname, flags); + __dbdel_ctp(dbp_ctp); + + replyp->status = ret; + return; +} + +/* BEGIN __db_stat_1_proc */ +void +__db_stat_1_proc(dbpcl_id, + flags, replyp, freep) + long dbpcl_id; + u_int32_t flags; + __db_stat_reply *replyp; + int * freep; +/* END __db_stat_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + DBTYPE type; + void *sp; + int len; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + + ret = dbp->stat(dbp, &sp, NULL, flags); + replyp->status = ret; + if (ret != 0) + return; + /* + * We get here, we have success. Allocate an array so that + * we can use the list generator. Generate the reply, free + * up the space. + */ + /* + * XXX This assumes that all elements of all stat structures + * are u_int32_t fields. They are, currently. + */ + type = dbp->get_type(dbp); + if (type == DB_HASH) + len = sizeof(DB_HASH_STAT) / sizeof(u_int32_t); + else if (type == DB_QUEUE) + len = sizeof(DB_QUEUE_STAT) / sizeof(u_int32_t); + else /* BTREE or RECNO are same stats */ + len = sizeof(DB_BTREE_STAT) / sizeof(u_int32_t); + /* + * Set up our list of stats. + */ + ret = __db_stats_list(dbp->dbenv, + &replyp->statslist, (u_int32_t*)sp, len); + + __os_free(sp, 0); + if (ret == 0) + *freep = 1; + replyp->status = ret; + return; +} + +int +__db_stats_list(dbenv, locp, pp, len) + DB_ENV *dbenv; + __db_stat_statsreplist **locp; + u_int32_t *pp; + int len; +{ + u_int32_t *p, *q; + int i, ret; + __db_stat_statsreplist *nl, **nlp; + + nlp = locp; + for (i = 0; i < len; i++) { + p = pp+i; + if ((ret = __os_malloc(dbenv, sizeof(*nl), NULL, nlp)) != 0) + goto out; + nl = *nlp; + nl->next = NULL; + if ((ret = __os_malloc(dbenv, + sizeof(u_int32_t), NULL, &nl->ent.ent_val)) != 0) + goto out; + q = (u_int32_t *)nl->ent.ent_val; + *q = *p; + nl->ent.ent_len = sizeof(u_int32_t); + nlp = &nl->next; + } + return (0); +out: + __db_stats_freelist(locp); + return (ret); +} + +/* + * PUBLIC: void __db_stats_freelist __P((__db_stat_statsreplist **)); + */ +void +__db_stats_freelist(locp) + __db_stat_statsreplist **locp; +{ + __db_stat_statsreplist *nl, *nl1; + + for (nl = *locp; nl != NULL; nl = nl1) { + nl1 = nl->next; + if (nl->ent.ent_val) + __os_free(nl->ent.ent_val, nl->ent.ent_len); + __os_free(nl, sizeof(*nl)); + } + *locp = NULL; +} + +/* BEGIN __db_swapped_1_proc */ +void +__db_swapped_1_proc(dbpcl_id, replyp) + long dbpcl_id; + __db_swapped_reply *replyp; +/* END __db_swapped_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + + ret = dbp->get_byteswapped(dbp); + + replyp->status = ret; + return; +} + +/* BEGIN __db_sync_1_proc */ +void +__db_sync_1_proc(dbpcl_id, flags, replyp) + long dbpcl_id; + u_int32_t flags; + __db_sync_reply *replyp; +/* END __db_sync_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + + ret = dbp->sync(dbp, flags); + + replyp->status = ret; + return; +} + +/* BEGIN __db_cursor_1_proc */ +void +__db_cursor_1_proc(dbpcl_id, txnpcl_id, + flags, replyp) + long dbpcl_id; + long txnpcl_id; + u_int32_t flags; + __db_cursor_reply *replyp; +/* END __db_cursor_1_proc */ +{ + int ret; + DB * dbp; + ct_entry *dbp_ctp; + DB_TXN * txnp; + ct_entry *txnp_ctp; + DBC *dbc; + ct_entry *dbc_ctp, *env_ctp; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + dbc_ctp = new_ct_ent(&replyp->status); + if (dbc_ctp == NULL) + return; + + if (txnpcl_id != 0) { + ACTIVATE_CTP(txnp_ctp, txnpcl_id, CT_TXN); + txnp = (DB_TXN *)txnp_ctp->ct_anyp; + dbc_ctp->ct_activep = txnp_ctp->ct_activep; + } else + txnp = NULL; + + if ((ret = dbp->cursor(dbp, txnp, &dbc, flags)) == 0) { + dbc_ctp->ct_dbc = dbc; + dbc_ctp->ct_type = CT_CURSOR; + dbc_ctp->ct_parent = dbp_ctp; + env_ctp = dbp_ctp->ct_envparent; + dbc_ctp->ct_envparent = env_ctp; + __dbsrv_settimeout(dbc_ctp, env_ctp->ct_timeout); + __dbsrv_active(dbc_ctp); + replyp->dbcidcl_id = dbc_ctp->ct_id; + } else + __dbclear_ctp(dbc_ctp); + + replyp->status = ret; + return; +} + +/* BEGIN __db_join_1_proc */ +void +__db_join_1_proc(dbpcl_id, curslist, + flags, replyp) + long dbpcl_id; + u_int32_t * curslist; + u_int32_t flags; + __db_join_reply *replyp; +/* END __db_join_1_proc */ +{ + DB * dbp; + ct_entry *dbp_ctp; + DBC *dbc; + DBC **jcurs, **c; + ct_entry *dbc_ctp, *ctp; + size_t size; + int ret; + u_int32_t *cl; + + ACTIVATE_CTP(dbp_ctp, dbpcl_id, CT_DB); + dbp = (DB *)dbp_ctp->ct_anyp; + + dbc_ctp = new_ct_ent(&replyp->status); + if (dbc_ctp == NULL) + return; + + for (size = sizeof(DBC *), cl = curslist; *cl != 0; size += sizeof(DBC *), cl++) + ; + if ((ret = __os_malloc(dbp->dbenv, size, NULL, &jcurs)) != 0) { + replyp->status = ret; + __dbclear_ctp(dbc_ctp); + return; + } + /* + * If our curslist has a parent txn, we need to use it too + * for the activity timeout. All cursors must be part of + * the same transaction, so just check the first. + */ + ctp = get_tableent(*curslist); + DB_ASSERT(ctp->ct_type == CT_CURSOR); + /* + * If we are using a transaction, set the join activity timer + * to point to the parent transaction. + */ + if (ctp->ct_activep != &ctp->ct_active) + dbc_ctp->ct_activep = ctp->ct_activep; + for (cl = curslist, c = jcurs; *cl != 0; cl++, c++) { + ctp = get_tableent(*cl); + if (ctp == NULL) { + replyp->status = DB_NOSERVER_ID; + goto out; + } + /* + * If we are using a txn, the join cursor points to the + * transaction timeout. If we are not using a transaction, + * then all the curslist cursors must point to the join + * cursor's timeout so that we do not timeout any of the + * curlist cursors while the join cursor is active. + * Change the type of the curslist ctps to CT_JOIN so that + * we know they are part of a join list and we can distinguish + * them and later restore them when the join cursor is closed. + */ + DB_ASSERT(ctp->ct_type == CT_CURSOR); + ctp->ct_type |= CT_JOIN; + ctp->ct_origp = ctp->ct_activep; + /* + * Setting this to the ct_active field of the dbc_ctp is + * really just a way to distinguish which join dbc this + * cursor is part of. The ct_activep of this cursor is + * not used at all during its lifetime as part of a join + * cursor. + */ + ctp->ct_activep = &dbc_ctp->ct_active; + *c = ctp->ct_dbc; + } + *c = NULL; + if ((ret = dbp->join(dbp, jcurs, &dbc, flags)) == 0) { + dbc_ctp->ct_dbc = dbc; + dbc_ctp->ct_type = (CT_JOINCUR | CT_CURSOR); + dbc_ctp->ct_parent = dbp_ctp; + dbc_ctp->ct_envparent = dbp_ctp->ct_envparent; + __dbsrv_settimeout(dbc_ctp, dbp_ctp->ct_envparent->ct_timeout); + __dbsrv_active(dbc_ctp); + replyp->dbcidcl_id = dbc_ctp->ct_id; + } else { + __dbclear_ctp(dbc_ctp); + /* + * If we get an error, undo what we did above to any cursors. + */ + for (cl = curslist; *cl != 0; cl++) { + ctp = get_tableent(*cl); + ctp->ct_type = CT_CURSOR; + ctp->ct_activep = ctp->ct_origp; + } + } + + replyp->status = ret; +out: + __os_free(jcurs, size); + return; +} + +/* BEGIN __dbc_close_1_proc */ +void +__dbc_close_1_proc(dbccl_id, replyp) + long dbccl_id; + __dbc_close_reply *replyp; +/* END __dbc_close_1_proc */ +{ + ct_entry *dbc_ctp; + + ACTIVATE_CTP(dbc_ctp, dbccl_id, CT_CURSOR); + replyp->status = __dbc_close_int(dbc_ctp); + return; +} + +/* BEGIN __dbc_count_1_proc */ +void +__dbc_count_1_proc(dbccl_id, flags, replyp) + long dbccl_id; + u_int32_t flags; + __dbc_count_reply *replyp; +/* END __dbc_count_1_proc */ +{ + int ret; + DBC * dbc; + ct_entry *dbc_ctp; + db_recno_t num; + + ACTIVATE_CTP(dbc_ctp, dbccl_id, CT_CURSOR); + dbc = (DBC *)dbc_ctp->ct_anyp; + + ret = dbc->c_count(dbc, &num, flags); + replyp->status = ret; + if (ret == 0) + replyp->dupcount = num; + return; +} + +/* BEGIN __dbc_del_1_proc */ +void +__dbc_del_1_proc(dbccl_id, flags, replyp) + long dbccl_id; + u_int32_t flags; + __dbc_del_reply *replyp; +/* END __dbc_del_1_proc */ +{ + int ret; + DBC * dbc; + ct_entry *dbc_ctp; + + ACTIVATE_CTP(dbc_ctp, dbccl_id, CT_CURSOR); + dbc = (DBC *)dbc_ctp->ct_anyp; + + ret = dbc->c_del(dbc, flags); + + replyp->status = ret; + return; +} + +/* BEGIN __dbc_dup_1_proc */ +void +__dbc_dup_1_proc(dbccl_id, flags, replyp) + long dbccl_id; + u_int32_t flags; + __dbc_dup_reply *replyp; +/* END __dbc_dup_1_proc */ +{ + int ret; + DBC * dbc; + ct_entry *dbc_ctp; + DBC *newdbc; + ct_entry *new_ctp; + + ACTIVATE_CTP(dbc_ctp, dbccl_id, CT_CURSOR); + dbc = (DBC *)dbc_ctp->ct_anyp; + + new_ctp = new_ct_ent(&replyp->status); + if (new_ctp == NULL) + return; + + if ((ret = dbc->c_dup(dbc, &newdbc, flags)) == 0) { + new_ctp->ct_dbc = newdbc; + new_ctp->ct_type = CT_CURSOR; + new_ctp->ct_parent = dbc_ctp->ct_parent; + new_ctp->ct_envparent = dbc_ctp->ct_envparent; + /* + * If our cursor has a parent txn, we need to use it too. + */ + if (dbc_ctp->ct_activep != &dbc_ctp->ct_active) + new_ctp->ct_activep = dbc_ctp->ct_activep; + __dbsrv_settimeout(new_ctp, dbc_ctp->ct_timeout); + __dbsrv_active(new_ctp); + replyp->dbcidcl_id = new_ctp->ct_id; + } else + __dbclear_ctp(new_ctp); + + replyp->status = ret; + return; +} + +/* BEGIN __dbc_get_1_proc */ +void +__dbc_get_1_proc(dbccl_id, keydlen, keydoff, + keyflags, keydata, keysize, datadlen, + datadoff, dataflags, datadata, datasize, + flags, replyp, freep) + long dbccl_id; + u_int32_t keydlen; + u_int32_t keydoff; + u_int32_t keyflags; + void *keydata; + u_int32_t keysize; + u_int32_t datadlen; + u_int32_t datadoff; + u_int32_t dataflags; + void *datadata; + u_int32_t datasize; + u_int32_t flags; + __dbc_get_reply *replyp; + int * freep; +/* END __dbc_get_1_proc */ +{ + DB_ENV *dbenv; + DBC *dbc; + DBT key, data; + ct_entry *dbc_ctp; + int key_alloc, ret; + + ACTIVATE_CTP(dbc_ctp, dbccl_id, CT_CURSOR); + dbc = (DBC *)dbc_ctp->ct_anyp; + dbenv = dbc->dbp->dbenv; + + *freep = 0; + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + + /* Set up key and data DBT */ + key.dlen = keydlen; + key.doff = keydoff; + /* + * Ignore memory related flags on server. + */ + key.flags = DB_DBT_MALLOC; + if (keyflags & DB_DBT_PARTIAL) + key.flags |= DB_DBT_PARTIAL; + key.size = keysize; + key.data = keydata; + + data.dlen = datadlen; + data.doff = datadoff; + data.flags = DB_DBT_MALLOC; + if (dataflags & DB_DBT_PARTIAL) + data.flags |= DB_DBT_PARTIAL; + data.size = datasize; + data.data = datadata; + + /* Got all our stuff, now do the get */ + ret = dbc->c_get(dbc, &key, &data, flags); + + /* + * Otherwise just status. + */ + if (ret == 0) { + /* + * XXX + * We need to xdr_free whatever we are returning, next time. + * However, DB does not allocate a new key if one was given + * and we'd be free'ing up space allocated in the request. + * So, allocate a new key/data pointer if it is the same one + * as in the request. + */ + *freep = 1; + /* + * Key + */ + key_alloc = 0; + if (key.data == keydata) { + ret = __os_malloc(dbenv, key.size, NULL, + &replyp->keydata.keydata_val); + if (ret != 0) { + __os_free(key.data, key.size); + __os_free(data.data, data.size); + goto err; + } + key_alloc = 1; + memcpy(replyp->keydata.keydata_val, key.data, key.size); + } else + replyp->keydata.keydata_val = key.data; + + replyp->keydata.keydata_len = key.size; + + /* + * Data + */ + if (data.data == datadata) { + ret = __os_malloc(dbenv, data.size, NULL, + &replyp->datadata.datadata_val); + if (ret != 0) { + __os_free(key.data, key.size); + __os_free(data.data, data.size); + if (key_alloc) + __os_free(replyp->keydata.keydata_val, + key.size); + goto err; + } + memcpy(replyp->datadata.datadata_val, data.data, + data.size); + } else + replyp->datadata.datadata_val = data.data; + replyp->datadata.datadata_len = data.size; + } else { +err: replyp->keydata.keydata_val = NULL; + replyp->keydata.keydata_len = 0; + replyp->datadata.datadata_val = NULL; + replyp->datadata.datadata_len = 0; + *freep = 0; + } + replyp->status = ret; + return; +} + +/* BEGIN __dbc_put_1_proc */ +void +__dbc_put_1_proc(dbccl_id, keydlen, keydoff, + keyflags, keydata, keysize, datadlen, + datadoff, dataflags, datadata, datasize, + flags, replyp, freep) + long dbccl_id; + u_int32_t keydlen; + u_int32_t keydoff; + u_int32_t keyflags; + void *keydata; + u_int32_t keysize; + u_int32_t datadlen; + u_int32_t datadoff; + u_int32_t dataflags; + void *datadata; + u_int32_t datasize; + u_int32_t flags; + __dbc_put_reply *replyp; + int * freep; +/* END __dbc_put_1_proc */ +{ + int ret; + DBC * dbc; + DB *dbp; + ct_entry *dbc_ctp; + DBT key, data; + + ACTIVATE_CTP(dbc_ctp, dbccl_id, CT_CURSOR); + dbc = (DBC *)dbc_ctp->ct_anyp; + dbp = (DB *)dbc_ctp->ct_parent->ct_anyp; + + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + + /* Set up key and data DBT */ + key.dlen = keydlen; + key.doff = keydoff; + /* + * Ignore memory related flags on server. + */ + key.flags = 0; + if (keyflags & DB_DBT_PARTIAL) + key.flags |= DB_DBT_PARTIAL; + key.size = keysize; + key.data = keydata; + + data.dlen = datadlen; + data.doff = datadoff; + data.flags = dataflags; + data.size = datasize; + data.data = datadata; + + /* Got all our stuff, now do the put */ + ret = dbc->c_put(dbc, &key, &data, flags); + + *freep = 0; + if (ret == 0 && (flags == DB_AFTER || flags == DB_BEFORE) && + dbp->type == DB_RECNO) { + /* + * We need to xdr_free whatever we are returning, next time. + */ + replyp->keydata.keydata_val = key.data; + replyp->keydata.keydata_len = key.size; + } else { + replyp->keydata.keydata_val = NULL; + replyp->keydata.keydata_len = 0; + } + replyp->status = ret; + return; +} +#endif /* HAVE_RPC */ diff --git a/db/rpc_server/db_server_proc.sed b/db/rpc_server/db_server_proc.sed new file mode 100644 index 000000000..7266275b2 --- /dev/null +++ b/db/rpc_server/db_server_proc.sed @@ -0,0 +1,418 @@ +/^\/\* BEGIN __env_cachesize_1_proc/,/^\/\* END __env_cachesize_1_proc/c\ +/* BEGIN __env_cachesize_1_proc */\ +void\ +__env_cachesize_1_proc(dbenvcl_id, gbytes, bytes,\ +\ \ ncache, replyp)\ +\ long dbenvcl_id;\ +\ u_int32_t gbytes;\ +\ u_int32_t bytes;\ +\ u_int32_t ncache;\ +\ __env_cachesize_reply *replyp;\ +/* END __env_cachesize_1_proc */ +/^\/\* BEGIN __env_close_1_proc/,/^\/\* END __env_close_1_proc/c\ +/* BEGIN __env_close_1_proc */\ +void\ +__env_close_1_proc(dbenvcl_id, flags, replyp)\ +\ long dbenvcl_id;\ +\ u_int32_t flags;\ +\ __env_close_reply *replyp;\ +/* END __env_close_1_proc */ +/^\/\* BEGIN __env_create_1_proc/,/^\/\* END __env_create_1_proc/c\ +/* BEGIN __env_create_1_proc */\ +void\ +__env_create_1_proc(timeout, replyp)\ +\ u_int32_t timeout;\ +\ __env_create_reply *replyp;\ +/* END __env_create_1_proc */ +/^\/\* BEGIN __env_flags_1_proc/,/^\/\* END __env_flags_1_proc/c\ +/* BEGIN __env_flags_1_proc */\ +void\ +__env_flags_1_proc(dbenvcl_id, flags, onoff, replyp)\ +\ long dbenvcl_id;\ +\ u_int32_t flags;\ +\ u_int32_t onoff;\ +\ __env_flags_reply *replyp;\ +/* END __env_flags_1_proc */ +/^\/\* BEGIN __env_open_1_proc/,/^\/\* END __env_open_1_proc/c\ +/* BEGIN __env_open_1_proc */\ +void\ +__env_open_1_proc(dbenvcl_id, home, flags,\ +\ \ mode, replyp)\ +\ long dbenvcl_id;\ +\ char *home;\ +\ u_int32_t flags;\ +\ u_int32_t mode;\ +\ __env_open_reply *replyp;\ +/* END __env_open_1_proc */ +/^\/\* BEGIN __env_remove_1_proc/,/^\/\* END __env_remove_1_proc/c\ +/* BEGIN __env_remove_1_proc */\ +void\ +__env_remove_1_proc(dbenvcl_id, home, flags, replyp)\ +\ long dbenvcl_id;\ +\ char *home;\ +\ u_int32_t flags;\ +\ __env_remove_reply *replyp;\ +/* END __env_remove_1_proc */ +/^\/\* BEGIN __txn_abort_1_proc/,/^\/\* END __txn_abort_1_proc/c\ +/* BEGIN __txn_abort_1_proc */\ +void\ +__txn_abort_1_proc(txnpcl_id, replyp)\ +\ long txnpcl_id;\ +\ __txn_abort_reply *replyp;\ +/* END __txn_abort_1_proc */ +/^\/\* BEGIN __txn_begin_1_proc/,/^\/\* END __txn_begin_1_proc/c\ +/* BEGIN __txn_begin_1_proc */\ +void\ +__txn_begin_1_proc(envpcl_id, parentcl_id,\ +\ \ flags, replyp)\ +\ long envpcl_id;\ +\ long parentcl_id;\ +\ u_int32_t flags;\ +\ __txn_begin_reply *replyp;\ +/* END __txn_begin_1_proc */ +/^\/\* BEGIN __txn_commit_1_proc/,/^\/\* END __txn_commit_1_proc/c\ +/* BEGIN __txn_commit_1_proc */\ +void\ +__txn_commit_1_proc(txnpcl_id, flags, replyp)\ +\ long txnpcl_id;\ +\ u_int32_t flags;\ +\ __txn_commit_reply *replyp;\ +/* END __txn_commit_1_proc */ +/^\/\* BEGIN __db_bt_maxkey_1_proc/,/^\/\* END __db_bt_maxkey_1_proc/c\ +/* BEGIN __db_bt_maxkey_1_proc */\ +void\ +__db_bt_maxkey_1_proc(dbpcl_id, maxkey, replyp)\ +\ long dbpcl_id;\ +\ u_int32_t maxkey;\ +\ __db_bt_maxkey_reply *replyp;\ +/* END __db_bt_maxkey_1_proc */ +/^\/\* BEGIN __db_bt_minkey_1_proc/,/^\/\* END __db_bt_minkey_1_proc/c\ +/* BEGIN __db_bt_minkey_1_proc */\ +void\ +__db_bt_minkey_1_proc(dbpcl_id, minkey, replyp)\ +\ long dbpcl_id;\ +\ u_int32_t minkey;\ +\ __db_bt_minkey_reply *replyp;\ +/* END __db_bt_minkey_1_proc */ +/^\/\* BEGIN __db_close_1_proc/,/^\/\* END __db_close_1_proc/c\ +/* BEGIN __db_close_1_proc */\ +void\ +__db_close_1_proc(dbpcl_id, flags, replyp)\ +\ long dbpcl_id;\ +\ u_int32_t flags;\ +\ __db_close_reply *replyp;\ +/* END __db_close_1_proc */ +/^\/\* BEGIN __db_create_1_proc/,/^\/\* END __db_create_1_proc/c\ +/* BEGIN __db_create_1_proc */\ +void\ +__db_create_1_proc(flags, envpcl_id, replyp)\ +\ u_int32_t flags;\ +\ long envpcl_id;\ +\ __db_create_reply *replyp;\ +/* END __db_create_1_proc */ +/^\/\* BEGIN __db_del_1_proc/,/^\/\* END __db_del_1_proc/c\ +/* BEGIN __db_del_1_proc */\ +void\ +__db_del_1_proc(dbpcl_id, txnpcl_id, keydlen,\ +\ \ keydoff, keyflags, keydata, keysize,\ +\ \ flags, replyp)\ +\ long dbpcl_id;\ +\ long txnpcl_id;\ +\ u_int32_t keydlen;\ +\ u_int32_t keydoff;\ +\ u_int32_t keyflags;\ +\ void *keydata;\ +\ u_int32_t keysize;\ +\ u_int32_t flags;\ +\ __db_del_reply *replyp;\ +/* END __db_del_1_proc */ +/^\/\* BEGIN __db_extentsize_1_proc/,/^\/\* END __db_extentsize_1_proc/c\ +/* BEGIN __db_extentsize_1_proc */\ +void\ +__db_extentsize_1_proc(dbpcl_id, extentsize, replyp)\ +\ long dbpcl_id;\ +\ u_int32_t extentsize;\ +\ __db_extentsize_reply *replyp;\ +/* END __db_extentsize_1_proc */ +/^\/\* BEGIN __db_flags_1_proc/,/^\/\* END __db_flags_1_proc/c\ +/* BEGIN __db_flags_1_proc */\ +void\ +__db_flags_1_proc(dbpcl_id, flags, replyp)\ +\ long dbpcl_id;\ +\ u_int32_t flags;\ +\ __db_flags_reply *replyp;\ +/* END __db_flags_1_proc */ +/^\/\* BEGIN __db_get_1_proc/,/^\/\* END __db_get_1_proc/c\ +/* BEGIN __db_get_1_proc */\ +void\ +__db_get_1_proc(dbpcl_id, txnpcl_id, keydlen,\ +\ \ keydoff, keyflags, keydata, keysize,\ +\ \ datadlen, datadoff, dataflags, datadata,\ +\ \ datasize, flags, replyp, freep)\ +\ long dbpcl_id;\ +\ long txnpcl_id;\ +\ u_int32_t keydlen;\ +\ u_int32_t keydoff;\ +\ u_int32_t keyflags;\ +\ void *keydata;\ +\ u_int32_t keysize;\ +\ u_int32_t datadlen;\ +\ u_int32_t datadoff;\ +\ u_int32_t dataflags;\ +\ void *datadata;\ +\ u_int32_t datasize;\ +\ u_int32_t flags;\ +\ __db_get_reply *replyp;\ +\ int * freep;\ +/* END __db_get_1_proc */ +/^\/\* BEGIN __db_h_ffactor_1_proc/,/^\/\* END __db_h_ffactor_1_proc/c\ +/* BEGIN __db_h_ffactor_1_proc */\ +void\ +__db_h_ffactor_1_proc(dbpcl_id, ffactor, replyp)\ +\ long dbpcl_id;\ +\ u_int32_t ffactor;\ +\ __db_h_ffactor_reply *replyp;\ +/* END __db_h_ffactor_1_proc */ +/^\/\* BEGIN __db_h_nelem_1_proc/,/^\/\* END __db_h_nelem_1_proc/c\ +/* BEGIN __db_h_nelem_1_proc */\ +void\ +__db_h_nelem_1_proc(dbpcl_id, nelem, replyp)\ +\ long dbpcl_id;\ +\ u_int32_t nelem;\ +\ __db_h_nelem_reply *replyp;\ +/* END __db_h_nelem_1_proc */ +/^\/\* BEGIN __db_key_range_1_proc/,/^\/\* END __db_key_range_1_proc/c\ +/* BEGIN __db_key_range_1_proc */\ +void\ +__db_key_range_1_proc(dbpcl_id, txnpcl_id, keydlen,\ +\ \ keydoff, keyflags, keydata, keysize,\ +\ \ flags, replyp)\ +\ long dbpcl_id;\ +\ long txnpcl_id;\ +\ u_int32_t keydlen;\ +\ u_int32_t keydoff;\ +\ u_int32_t keyflags;\ +\ void *keydata;\ +\ u_int32_t keysize;\ +\ u_int32_t flags;\ +\ __db_key_range_reply *replyp;\ +/* END __db_key_range_1_proc */ +/^\/\* BEGIN __db_lorder_1_proc/,/^\/\* END __db_lorder_1_proc/c\ +/* BEGIN __db_lorder_1_proc */\ +void\ +__db_lorder_1_proc(dbpcl_id, lorder, replyp)\ +\ long dbpcl_id;\ +\ u_int32_t lorder;\ +\ __db_lorder_reply *replyp;\ +/* END __db_lorder_1_proc */ +/^\/\* BEGIN __db_open_1_proc/,/^\/\* END __db_open_1_proc/c\ +/* BEGIN __db_open_1_proc */\ +void\ +__db_open_1_proc(dbpcl_id, name, subdb,\ +\ \ type, flags, mode, replyp)\ +\ long dbpcl_id;\ +\ char *name;\ +\ char *subdb;\ +\ u_int32_t type;\ +\ u_int32_t flags;\ +\ u_int32_t mode;\ +\ __db_open_reply *replyp;\ +/* END __db_open_1_proc */ +/^\/\* BEGIN __db_pagesize_1_proc/,/^\/\* END __db_pagesize_1_proc/c\ +/* BEGIN __db_pagesize_1_proc */\ +void\ +__db_pagesize_1_proc(dbpcl_id, pagesize, replyp)\ +\ long dbpcl_id;\ +\ u_int32_t pagesize;\ +\ __db_pagesize_reply *replyp;\ +/* END __db_pagesize_1_proc */ +/^\/\* BEGIN __db_put_1_proc/,/^\/\* END __db_put_1_proc/c\ +/* BEGIN __db_put_1_proc */\ +void\ +__db_put_1_proc(dbpcl_id, txnpcl_id, keydlen,\ +\ \ keydoff, keyflags, keydata, keysize,\ +\ \ datadlen, datadoff, dataflags, datadata,\ +\ \ datasize, flags, replyp, freep)\ +\ long dbpcl_id;\ +\ long txnpcl_id;\ +\ u_int32_t keydlen;\ +\ u_int32_t keydoff;\ +\ u_int32_t keyflags;\ +\ void *keydata;\ +\ u_int32_t keysize;\ +\ u_int32_t datadlen;\ +\ u_int32_t datadoff;\ +\ u_int32_t dataflags;\ +\ void *datadata;\ +\ u_int32_t datasize;\ +\ u_int32_t flags;\ +\ __db_put_reply *replyp;\ +\ int * freep;\ +/* END __db_put_1_proc */ +/^\/\* BEGIN __db_re_delim_1_proc/,/^\/\* END __db_re_delim_1_proc/c\ +/* BEGIN __db_re_delim_1_proc */\ +void\ +__db_re_delim_1_proc(dbpcl_id, delim, replyp)\ +\ long dbpcl_id;\ +\ u_int32_t delim;\ +\ __db_re_delim_reply *replyp;\ +/* END __db_re_delim_1_proc */ +/^\/\* BEGIN __db_re_len_1_proc/,/^\/\* END __db_re_len_1_proc/c\ +/* BEGIN __db_re_len_1_proc */\ +void\ +__db_re_len_1_proc(dbpcl_id, len, replyp)\ +\ long dbpcl_id;\ +\ u_int32_t len;\ +\ __db_re_len_reply *replyp;\ +/* END __db_re_len_1_proc */ +/^\/\* BEGIN __db_re_pad_1_proc/,/^\/\* END __db_re_pad_1_proc/c\ +/* BEGIN __db_re_pad_1_proc */\ +void\ +__db_re_pad_1_proc(dbpcl_id, pad, replyp)\ +\ long dbpcl_id;\ +\ u_int32_t pad;\ +\ __db_re_pad_reply *replyp;\ +/* END __db_re_pad_1_proc */ +/^\/\* BEGIN __db_remove_1_proc/,/^\/\* END __db_remove_1_proc/c\ +/* BEGIN __db_remove_1_proc */\ +void\ +__db_remove_1_proc(dbpcl_id, name, subdb,\ +\ \ flags, replyp)\ +\ long dbpcl_id;\ +\ char *name;\ +\ char *subdb;\ +\ u_int32_t flags;\ +\ __db_remove_reply *replyp;\ +/* END __db_remove_1_proc */ +/^\/\* BEGIN __db_rename_1_proc/,/^\/\* END __db_rename_1_proc/c\ +/* BEGIN __db_rename_1_proc */\ +void\ +__db_rename_1_proc(dbpcl_id, name, subdb,\ +\ \ newname, flags, replyp)\ +\ long dbpcl_id;\ +\ char *name;\ +\ char *subdb;\ +\ char *newname;\ +\ u_int32_t flags;\ +\ __db_rename_reply *replyp;\ +/* END __db_rename_1_proc */ +/^\/\* BEGIN __db_stat_1_proc/,/^\/\* END __db_stat_1_proc/c\ +/* BEGIN __db_stat_1_proc */\ +void\ +__db_stat_1_proc(dbpcl_id,\ +\ \ flags, replyp, freep)\ +\ long dbpcl_id;\ +\ u_int32_t flags;\ +\ __db_stat_reply *replyp;\ +\ int * freep;\ +/* END __db_stat_1_proc */ +/^\/\* BEGIN __db_swapped_1_proc/,/^\/\* END __db_swapped_1_proc/c\ +/* BEGIN __db_swapped_1_proc */\ +void\ +__db_swapped_1_proc(dbpcl_id, replyp)\ +\ long dbpcl_id;\ +\ __db_swapped_reply *replyp;\ +/* END __db_swapped_1_proc */ +/^\/\* BEGIN __db_sync_1_proc/,/^\/\* END __db_sync_1_proc/c\ +/* BEGIN __db_sync_1_proc */\ +void\ +__db_sync_1_proc(dbpcl_id, flags, replyp)\ +\ long dbpcl_id;\ +\ u_int32_t flags;\ +\ __db_sync_reply *replyp;\ +/* END __db_sync_1_proc */ +/^\/\* BEGIN __db_cursor_1_proc/,/^\/\* END __db_cursor_1_proc/c\ +/* BEGIN __db_cursor_1_proc */\ +void\ +__db_cursor_1_proc(dbpcl_id, txnpcl_id,\ +\ \ flags, replyp)\ +\ long dbpcl_id;\ +\ long txnpcl_id;\ +\ u_int32_t flags;\ +\ __db_cursor_reply *replyp;\ +/* END __db_cursor_1_proc */ +/^\/\* BEGIN __db_join_1_proc/,/^\/\* END __db_join_1_proc/c\ +/* BEGIN __db_join_1_proc */\ +void\ +__db_join_1_proc(dbpcl_id, curslist,\ +\ \ flags, replyp)\ +\ long dbpcl_id;\ +\ u_int32_t * curslist;\ +\ u_int32_t flags;\ +\ __db_join_reply *replyp;\ +/* END __db_join_1_proc */ +/^\/\* BEGIN __dbc_close_1_proc/,/^\/\* END __dbc_close_1_proc/c\ +/* BEGIN __dbc_close_1_proc */\ +void\ +__dbc_close_1_proc(dbccl_id, replyp)\ +\ long dbccl_id;\ +\ __dbc_close_reply *replyp;\ +/* END __dbc_close_1_proc */ +/^\/\* BEGIN __dbc_count_1_proc/,/^\/\* END __dbc_count_1_proc/c\ +/* BEGIN __dbc_count_1_proc */\ +void\ +__dbc_count_1_proc(dbccl_id, flags, replyp)\ +\ long dbccl_id;\ +\ u_int32_t flags;\ +\ __dbc_count_reply *replyp;\ +/* END __dbc_count_1_proc */ +/^\/\* BEGIN __dbc_del_1_proc/,/^\/\* END __dbc_del_1_proc/c\ +/* BEGIN __dbc_del_1_proc */\ +void\ +__dbc_del_1_proc(dbccl_id, flags, replyp)\ +\ long dbccl_id;\ +\ u_int32_t flags;\ +\ __dbc_del_reply *replyp;\ +/* END __dbc_del_1_proc */ +/^\/\* BEGIN __dbc_dup_1_proc/,/^\/\* END __dbc_dup_1_proc/c\ +/* BEGIN __dbc_dup_1_proc */\ +void\ +__dbc_dup_1_proc(dbccl_id, flags, replyp)\ +\ long dbccl_id;\ +\ u_int32_t flags;\ +\ __dbc_dup_reply *replyp;\ +/* END __dbc_dup_1_proc */ +/^\/\* BEGIN __dbc_get_1_proc/,/^\/\* END __dbc_get_1_proc/c\ +/* BEGIN __dbc_get_1_proc */\ +void\ +__dbc_get_1_proc(dbccl_id, keydlen, keydoff,\ +\ \ keyflags, keydata, keysize, datadlen,\ +\ \ datadoff, dataflags, datadata, datasize,\ +\ \ flags, replyp, freep)\ +\ long dbccl_id;\ +\ u_int32_t keydlen;\ +\ u_int32_t keydoff;\ +\ u_int32_t keyflags;\ +\ void *keydata;\ +\ u_int32_t keysize;\ +\ u_int32_t datadlen;\ +\ u_int32_t datadoff;\ +\ u_int32_t dataflags;\ +\ void *datadata;\ +\ u_int32_t datasize;\ +\ u_int32_t flags;\ +\ __dbc_get_reply *replyp;\ +\ int * freep;\ +/* END __dbc_get_1_proc */ +/^\/\* BEGIN __dbc_put_1_proc/,/^\/\* END __dbc_put_1_proc/c\ +/* BEGIN __dbc_put_1_proc */\ +void\ +__dbc_put_1_proc(dbccl_id, keydlen, keydoff,\ +\ \ keyflags, keydata, keysize, datadlen,\ +\ \ datadoff, dataflags, datadata, datasize,\ +\ \ flags, replyp, freep)\ +\ long dbccl_id;\ +\ u_int32_t keydlen;\ +\ u_int32_t keydoff;\ +\ u_int32_t keyflags;\ +\ void *keydata;\ +\ u_int32_t keysize;\ +\ u_int32_t datadlen;\ +\ u_int32_t datadoff;\ +\ u_int32_t dataflags;\ +\ void *datadata;\ +\ u_int32_t datasize;\ +\ u_int32_t flags;\ +\ __dbc_put_reply *replyp;\ +\ int * freep;\ +/* END __dbc_put_1_proc */ diff --git a/db/rpc_server/db_server_svc.c b/db/rpc_server/db_server_svc.c new file mode 100644 index 000000000..96d8a4a5d --- /dev/null +++ b/db/rpc_server/db_server_svc.c @@ -0,0 +1,359 @@ +#include "db_config.h" +#ifdef HAVE_RPC +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#include "db_server.h" +#include +#include /* getenv, exit */ +#include +#include +#include +extern void __dbsrv_timeout(); + +#ifdef DEBUG +#define RPC_SVC_FG +#endif + +static void +db_serverprog_1(rqstp, transp) + struct svc_req *rqstp; + register SVCXPRT *transp; +{ + union { + __env_cachesize_msg __db_env_cachesize_1_arg; + __env_close_msg __db_env_close_1_arg; + __env_create_msg __db_env_create_1_arg; + __env_flags_msg __db_env_flags_1_arg; + __env_open_msg __db_env_open_1_arg; + __env_remove_msg __db_env_remove_1_arg; + __txn_abort_msg __db_txn_abort_1_arg; + __txn_begin_msg __db_txn_begin_1_arg; + __txn_commit_msg __db_txn_commit_1_arg; + __db_bt_maxkey_msg __db_db_bt_maxkey_1_arg; + __db_bt_minkey_msg __db_db_bt_minkey_1_arg; + __db_close_msg __db_db_close_1_arg; + __db_create_msg __db_db_create_1_arg; + __db_del_msg __db_db_del_1_arg; + __db_extentsize_msg __db_db_extentsize_1_arg; + __db_flags_msg __db_db_flags_1_arg; + __db_get_msg __db_db_get_1_arg; + __db_h_ffactor_msg __db_db_h_ffactor_1_arg; + __db_h_nelem_msg __db_db_h_nelem_1_arg; + __db_key_range_msg __db_db_key_range_1_arg; + __db_lorder_msg __db_db_lorder_1_arg; + __db_open_msg __db_db_open_1_arg; + __db_pagesize_msg __db_db_pagesize_1_arg; + __db_put_msg __db_db_put_1_arg; + __db_re_delim_msg __db_db_re_delim_1_arg; + __db_re_len_msg __db_db_re_len_1_arg; + __db_re_pad_msg __db_db_re_pad_1_arg; + __db_remove_msg __db_db_remove_1_arg; + __db_rename_msg __db_db_rename_1_arg; + __db_stat_msg __db_db_stat_1_arg; + __db_swapped_msg __db_db_swapped_1_arg; + __db_sync_msg __db_db_sync_1_arg; + __db_cursor_msg __db_db_cursor_1_arg; + __db_join_msg __db_db_join_1_arg; + __dbc_close_msg __db_dbc_close_1_arg; + __dbc_count_msg __db_dbc_count_1_arg; + __dbc_del_msg __db_dbc_del_1_arg; + __dbc_dup_msg __db_dbc_dup_1_arg; + __dbc_get_msg __db_dbc_get_1_arg; + __dbc_put_msg __db_dbc_put_1_arg; + } argument; + char *result; + bool_t (*xdr_argument)(), (*xdr_result)(); + char *(*local)(); + + switch (rqstp->rq_proc) { + case NULLPROC: + (void) svc_sendreply(transp, xdr_void, + (char *)NULL); + return; + + case __DB_env_cachesize: + xdr_argument = xdr___env_cachesize_msg; + xdr_result = xdr___env_cachesize_reply; + local = (char *(*)()) __db_env_cachesize_1; + break; + + case __DB_env_close: + xdr_argument = xdr___env_close_msg; + xdr_result = xdr___env_close_reply; + local = (char *(*)()) __db_env_close_1; + break; + + case __DB_env_create: + xdr_argument = xdr___env_create_msg; + xdr_result = xdr___env_create_reply; + local = (char *(*)()) __db_env_create_1; + break; + + case __DB_env_flags: + xdr_argument = xdr___env_flags_msg; + xdr_result = xdr___env_flags_reply; + local = (char *(*)()) __db_env_flags_1; + break; + + case __DB_env_open: + xdr_argument = xdr___env_open_msg; + xdr_result = xdr___env_open_reply; + local = (char *(*)()) __db_env_open_1; + break; + + case __DB_env_remove: + xdr_argument = xdr___env_remove_msg; + xdr_result = xdr___env_remove_reply; + local = (char *(*)()) __db_env_remove_1; + break; + + case __DB_txn_abort: + xdr_argument = xdr___txn_abort_msg; + xdr_result = xdr___txn_abort_reply; + local = (char *(*)()) __db_txn_abort_1; + break; + + case __DB_txn_begin: + xdr_argument = xdr___txn_begin_msg; + xdr_result = xdr___txn_begin_reply; + local = (char *(*)()) __db_txn_begin_1; + break; + + case __DB_txn_commit: + xdr_argument = xdr___txn_commit_msg; + xdr_result = xdr___txn_commit_reply; + local = (char *(*)()) __db_txn_commit_1; + break; + + case __DB_db_bt_maxkey: + xdr_argument = xdr___db_bt_maxkey_msg; + xdr_result = xdr___db_bt_maxkey_reply; + local = (char *(*)()) __db_db_bt_maxkey_1; + break; + + case __DB_db_bt_minkey: + xdr_argument = xdr___db_bt_minkey_msg; + xdr_result = xdr___db_bt_minkey_reply; + local = (char *(*)()) __db_db_bt_minkey_1; + break; + + case __DB_db_close: + xdr_argument = xdr___db_close_msg; + xdr_result = xdr___db_close_reply; + local = (char *(*)()) __db_db_close_1; + break; + + case __DB_db_create: + xdr_argument = xdr___db_create_msg; + xdr_result = xdr___db_create_reply; + local = (char *(*)()) __db_db_create_1; + break; + + case __DB_db_del: + xdr_argument = xdr___db_del_msg; + xdr_result = xdr___db_del_reply; + local = (char *(*)()) __db_db_del_1; + break; + + case __DB_db_extentsize: + xdr_argument = xdr___db_extentsize_msg; + xdr_result = xdr___db_extentsize_reply; + local = (char *(*)()) __db_db_extentsize_1; + break; + + case __DB_db_flags: + xdr_argument = xdr___db_flags_msg; + xdr_result = xdr___db_flags_reply; + local = (char *(*)()) __db_db_flags_1; + break; + + case __DB_db_get: + xdr_argument = xdr___db_get_msg; + xdr_result = xdr___db_get_reply; + local = (char *(*)()) __db_db_get_1; + break; + + case __DB_db_h_ffactor: + xdr_argument = xdr___db_h_ffactor_msg; + xdr_result = xdr___db_h_ffactor_reply; + local = (char *(*)()) __db_db_h_ffactor_1; + break; + + case __DB_db_h_nelem: + xdr_argument = xdr___db_h_nelem_msg; + xdr_result = xdr___db_h_nelem_reply; + local = (char *(*)()) __db_db_h_nelem_1; + break; + + case __DB_db_key_range: + xdr_argument = xdr___db_key_range_msg; + xdr_result = xdr___db_key_range_reply; + local = (char *(*)()) __db_db_key_range_1; + break; + + case __DB_db_lorder: + xdr_argument = xdr___db_lorder_msg; + xdr_result = xdr___db_lorder_reply; + local = (char *(*)()) __db_db_lorder_1; + break; + + case __DB_db_open: + xdr_argument = xdr___db_open_msg; + xdr_result = xdr___db_open_reply; + local = (char *(*)()) __db_db_open_1; + break; + + case __DB_db_pagesize: + xdr_argument = xdr___db_pagesize_msg; + xdr_result = xdr___db_pagesize_reply; + local = (char *(*)()) __db_db_pagesize_1; + break; + + case __DB_db_put: + xdr_argument = xdr___db_put_msg; + xdr_result = xdr___db_put_reply; + local = (char *(*)()) __db_db_put_1; + break; + + case __DB_db_re_delim: + xdr_argument = xdr___db_re_delim_msg; + xdr_result = xdr___db_re_delim_reply; + local = (char *(*)()) __db_db_re_delim_1; + break; + + case __DB_db_re_len: + xdr_argument = xdr___db_re_len_msg; + xdr_result = xdr___db_re_len_reply; + local = (char *(*)()) __db_db_re_len_1; + break; + + case __DB_db_re_pad: + xdr_argument = xdr___db_re_pad_msg; + xdr_result = xdr___db_re_pad_reply; + local = (char *(*)()) __db_db_re_pad_1; + break; + + case __DB_db_remove: + xdr_argument = xdr___db_remove_msg; + xdr_result = xdr___db_remove_reply; + local = (char *(*)()) __db_db_remove_1; + break; + + case __DB_db_rename: + xdr_argument = xdr___db_rename_msg; + xdr_result = xdr___db_rename_reply; + local = (char *(*)()) __db_db_rename_1; + break; + + case __DB_db_stat: + xdr_argument = xdr___db_stat_msg; + xdr_result = xdr___db_stat_reply; + local = (char *(*)()) __db_db_stat_1; + break; + + case __DB_db_swapped: + xdr_argument = xdr___db_swapped_msg; + xdr_result = xdr___db_swapped_reply; + local = (char *(*)()) __db_db_swapped_1; + break; + + case __DB_db_sync: + xdr_argument = xdr___db_sync_msg; + xdr_result = xdr___db_sync_reply; + local = (char *(*)()) __db_db_sync_1; + break; + + case __DB_db_cursor: + xdr_argument = xdr___db_cursor_msg; + xdr_result = xdr___db_cursor_reply; + local = (char *(*)()) __db_db_cursor_1; + break; + + case __DB_db_join: + xdr_argument = xdr___db_join_msg; + xdr_result = xdr___db_join_reply; + local = (char *(*)()) __db_db_join_1; + break; + + case __DB_dbc_close: + xdr_argument = xdr___dbc_close_msg; + xdr_result = xdr___dbc_close_reply; + local = (char *(*)()) __db_dbc_close_1; + break; + + case __DB_dbc_count: + xdr_argument = xdr___dbc_count_msg; + xdr_result = xdr___dbc_count_reply; + local = (char *(*)()) __db_dbc_count_1; + break; + + case __DB_dbc_del: + xdr_argument = xdr___dbc_del_msg; + xdr_result = xdr___dbc_del_reply; + local = (char *(*)()) __db_dbc_del_1; + break; + + case __DB_dbc_dup: + xdr_argument = xdr___dbc_dup_msg; + xdr_result = xdr___dbc_dup_reply; + local = (char *(*)()) __db_dbc_dup_1; + break; + + case __DB_dbc_get: + xdr_argument = xdr___dbc_get_msg; + xdr_result = xdr___dbc_get_reply; + local = (char *(*)()) __db_dbc_get_1; + break; + + case __DB_dbc_put: + xdr_argument = xdr___dbc_put_msg; + xdr_result = xdr___dbc_put_reply; + local = (char *(*)()) __db_dbc_put_1; + break; + + default: + svcerr_noproc(transp); + return; + } + (void) memset((char *)&argument, 0, sizeof (argument)); + if (!svc_getargs(transp, xdr_argument, &argument)) { + svcerr_decode(transp); + return; + } + result = (*local)(&argument, rqstp); + if (result != NULL && !svc_sendreply(transp, xdr_result, result)) { + svcerr_systemerr(transp); + } + if (!svc_freeargs(transp, xdr_argument, &argument)) { + fprintf(stderr, "unable to free arguments"); + exit(1); + } + __dbsrv_timeout(0); + return; +} + +void __dbsrv_main() +{ + register SVCXPRT *transp; + + (void) pmap_unset(DB_SERVERPROG, DB_SERVERVERS); + + transp = svctcp_create(RPC_ANYSOCK, 0, 0); + if (transp == NULL) { + fprintf(stderr, "cannot create tcp service."); + exit(1); + } + if (!svc_register(transp, DB_SERVERPROG, DB_SERVERVERS, db_serverprog_1, IPPROTO_TCP)) { + fprintf(stderr, "unable to register (DB_SERVERPROG, DB_SERVERVERS, tcp)."); + exit(1); + } + + svc_run(); + fprintf(stderr, "svc_run returned"); + exit(1); + /* NOTREACHED */ +} +#endif /* HAVE_RPC */ diff --git a/db/rpc_server/db_server_svc.sed b/db/rpc_server/db_server_svc.sed new file mode 100644 index 000000000..9d540e51a --- /dev/null +++ b/db/rpc_server/db_server_svc.sed @@ -0,0 +1,5 @@ +/^#include /a\ +\extern void __dbsrv_timeout(); +/^ return;/i\ +\ __dbsrv_timeout(0); +s/^main/void __dbsrv_main/ diff --git a/db/rpc_server/db_server_util.c b/db/rpc_server/db_server_util.c new file mode 100644 index 000000000..862bbd05e --- /dev/null +++ b/db/rpc_server/db_server_util.c @@ -0,0 +1,612 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: db_server_util.c,v 1.32 2001/01/18 18:36:59 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#if TIME_WITH_SYS_TIME +#include +#include +#else +#if HAVE_SYS_TIME_H +#include +#else +#include +#endif +#endif + +#include + +#include +#include +#include +#include +#include +#include +#endif +#include "db_server.h" + +#include "db_int.h" +#include "clib_ext.h" +#include "db_server_int.h" +#include "rpc_server_ext.h" +#include "common_ext.h" + +extern int __dbsrv_main __P((void)); +static int add_home __P((char *)); +static int env_recover __P((char *)); +static void __dbclear_child __P((ct_entry *)); + +static LIST_HEAD(cthead, ct_entry) __dbsrv_head; +static LIST_HEAD(homehead, home_entry) __dbsrv_home; +static long __dbsrv_defto = DB_SERVER_TIMEOUT; +static long __dbsrv_maxto = DB_SERVER_MAXTIMEOUT; +static long __dbsrv_idleto = DB_SERVER_IDLETIMEOUT; +static char *logfile = NULL; +static char *prog; + +static void usage __P((char *)); +static void version_check __P((void)); + +int __dbsrv_verbose = 0; + +int +main(argc, argv) + int argc; + char **argv; +{ + extern char *optarg; + extern int optind; + CLIENT *cl; + int ch, ret; + + prog = argv[0]; + + version_check(); + + /* + * Check whether another server is running or not. There + * is a race condition where two servers could be racing to + * register with the portmapper. The goal of this check is to + * forbid running additional servers (like those started from + * the test suite) if the user is already running one. + * + * XXX + * This does not solve nor prevent two servers from being + * started at the same time and running recovery at the same + * time on the same environments. + */ + if ((cl = clnt_create("localhost", + DB_SERVERPROG, DB_SERVERVERS, "tcp")) != NULL) { + fprintf(stderr, + "%s: Berkeley DB RPC server already running.\n", prog); + clnt_destroy(cl); + exit(1); + } + + LIST_INIT(&__dbsrv_home); + while ((ch = getopt(argc, argv, "h:I:L:t:T:Vv")) != EOF) + switch (ch) { + case 'h': + (void)add_home(optarg); + break; + case 'I': + (void)__db_getlong(NULL, prog, optarg, 1, + LONG_MAX, &__dbsrv_idleto); + break; + case 'L': + logfile = optarg; + break; + case 't': + (void)__db_getlong(NULL, prog, optarg, 1, + LONG_MAX, &__dbsrv_defto); + break; + case 'T': + (void)__db_getlong(NULL, prog, optarg, 1, + LONG_MAX, &__dbsrv_maxto); + break; + case 'V': + printf("%s\n", db_version(NULL, NULL, NULL)); + exit(0); + case 'v': + __dbsrv_verbose = 1; + break; + default: + usage(prog); + } + /* + * Check default timeout against maximum timeout + */ + if (__dbsrv_defto > __dbsrv_maxto) + __dbsrv_defto = __dbsrv_maxto; + + /* + * Check default timeout against idle timeout + * It would be bad to timeout environments sooner than txns. + */ + if (__dbsrv_defto > __dbsrv_idleto) +printf("%s: WARNING: Idle timeout %ld is less than resource timeout %ld\n", + prog, __dbsrv_idleto, __dbsrv_defto); + + LIST_INIT(&__dbsrv_head); + + /* + * If a client crashes during an RPC, our reply to it + * generates a SIGPIPE. Ignore SIGPIPE so we don't exit unnecessarily. + */ +#ifdef SIGPIPE + signal(SIGPIPE, SIG_IGN); +#endif + + if (logfile != NULL && __db_util_logset("berkeley_db_svc", logfile)) + exit(1); + + /* + * Now that we are ready to start, run recovery on all the + * environments specified. + */ + if ((ret = env_recover(prog)) != 0) + exit(1); + + /* + * We've done our setup, now call the generated server loop + */ + if (__dbsrv_verbose) + printf("%s: Ready to receive requests\n", prog); + __dbsrv_main(); + + /* NOTREACHED */ + abort(); +} + +static void +usage(prog) + char *prog; +{ + fprintf(stderr, "usage: %s %s\n\t%s\n", prog, + "[-Vv] [-h home]", + "[-I idletimeout] [-L logfile] [-t def_timeout] [-T maxtimeout]"); + exit(1); +} + +static void +version_check() +{ + int v_major, v_minor, v_patch; + + /* Make sure we're loaded with the right version of the DB library. */ + (void)db_version(&v_major, &v_minor, &v_patch); + if (v_major != DB_VERSION_MAJOR || + v_minor != DB_VERSION_MINOR || v_patch != DB_VERSION_PATCH) { + fprintf(stderr, + "%s: version %d.%d.%d doesn't match library version %d.%d.%d\n", + prog, DB_VERSION_MAJOR, DB_VERSION_MINOR, + DB_VERSION_PATCH, v_major, v_minor, v_patch); + exit (1); + } +} + +/* + * PUBLIC: void __dbsrv_settimeout __P((ct_entry *, u_int32_t)); + */ +void +__dbsrv_settimeout(ctp, to) + ct_entry *ctp; + u_int32_t to; +{ + if (to > (u_int32_t)__dbsrv_maxto) + ctp->ct_timeout = __dbsrv_maxto; + else if (to <= 0) + ctp->ct_timeout = __dbsrv_defto; + else + ctp->ct_timeout = to; +} + +/* + * PUBLIC: void __dbsrv_timeout __P((int)); + */ +void +__dbsrv_timeout(force) + int force; +{ + static long to_hint = -1; + DBC *dbcp; + time_t t; + long to; + ct_entry *ctp, *nextctp; + + if ((t = time(NULL)) == -1) + return; + + /* + * Check hint. If hint is further in the future + * than now, no work to do. + */ + if (!force && to_hint > 0 && t < to_hint) + return; + to_hint = -1; + /* + * Timeout transactions or cursors holding DB resources. + * Do this before timing out envs to properly release resources. + * + * !!! + * We can just loop through this list looking for cursors and txns. + * We do not need to verify txn and cursor relationships at this + * point because we maintain the list in LIFO order *and* we + * maintain activity in the ultimate txn parent of any cursor + * so either everything in a txn is timing out, or nothing. + * So, since we are LIFO, we will correctly close/abort all the + * appropriate handles, in the correct order. + */ + for (ctp = LIST_FIRST(&__dbsrv_head); ctp != NULL; ctp = nextctp) { + nextctp = LIST_NEXT(ctp, entries); + switch (ctp->ct_type) { + case CT_TXN: + to = *(ctp->ct_activep) + ctp->ct_timeout; + /* TIMEOUT */ + if (to < t) { + if (__dbsrv_verbose) + printf("Timing out txn id %ld\n", + ctp->ct_id); + (void)txn_abort((DB_TXN *)ctp->ct_anyp); + __dbdel_ctp(ctp); + /* + * If we timed out an txn, we may have closed + * all sorts of ctp's. + * So start over with a guaranteed good ctp. + */ + nextctp = LIST_FIRST(&__dbsrv_head); + } else if ((to_hint > 0 && to_hint > to) || + to_hint == -1) + to_hint = to; + break; + case CT_CURSOR: + case (CT_JOINCUR | CT_CURSOR): + to = *(ctp->ct_activep) + ctp->ct_timeout; + /* TIMEOUT */ + if (to < t) { + if (__dbsrv_verbose) + printf("Timing out cursor %ld\n", + ctp->ct_id); + dbcp = (DBC *)ctp->ct_anyp; + (void)__dbc_close_int(ctp); + /* + * Start over with a guaranteed good ctp. + */ + nextctp = LIST_FIRST(&__dbsrv_head); + } else if ((to_hint > 0 && to_hint > to) || + to_hint == -1) + to_hint = to; + break; + default: + break; + } + } + /* + * Timeout idle handles. + * If we are forcing a timeout, we'll close all env handles. + */ + for (ctp = LIST_FIRST(&__dbsrv_head); ctp != NULL; ctp = nextctp) { + nextctp = LIST_NEXT(ctp, entries); + if (ctp->ct_type != CT_ENV) + continue; + to = *(ctp->ct_activep) + ctp->ct_idle; + /* TIMEOUT */ + if (to < t || force) { + if (__dbsrv_verbose) + printf("Timing out env id %ld\n", ctp->ct_id); + (void)__dbenv_close_int(ctp->ct_id, 0); + /* + * If we timed out an env, we may have closed + * all sorts of ctp's (maybe even all of them. + * So start over with a guaranteed good ctp. + */ + nextctp = LIST_FIRST(&__dbsrv_head); + } + } +} + +/* + * RECURSIVE FUNCTION. We need to clear/free any number of levels of nested + * layers. + */ +static void +__dbclear_child(parent) + ct_entry *parent; +{ + ct_entry *ctp, *nextctp; + + for (ctp = LIST_FIRST(&__dbsrv_head); ctp != NULL; + ctp = nextctp) { + nextctp = LIST_NEXT(ctp, entries); + if (ctp->ct_type == 0) + continue; + if (ctp->ct_parent == parent) { + __dbclear_child(ctp); + /* + * Need to do this here because le_next may + * have changed with the recursive call and we + * don't want to point to a removed entry. + */ + nextctp = LIST_NEXT(ctp, entries); + __dbclear_ctp(ctp); + } + } +} + +/* + * PUBLIC: void __dbclear_ctp __P((ct_entry *)); + */ +void +__dbclear_ctp(ctp) + ct_entry *ctp; +{ + LIST_REMOVE(ctp, entries); + __os_free(ctp, sizeof(ct_entry)); +} + +/* + * PUBLIC: void __dbdel_ctp __P((ct_entry *)); + */ +void +__dbdel_ctp(parent) + ct_entry *parent; +{ + __dbclear_child(parent); + __dbclear_ctp(parent); +} + +/* + * PUBLIC: ct_entry *new_ct_ent __P((u_int32_t *)); + */ +ct_entry * +new_ct_ent(errp) + u_int32_t *errp; +{ + time_t t; + ct_entry *ctp, *octp; + int ret; + + if ((ret = __os_malloc(NULL, sizeof(ct_entry), NULL, &ctp)) != 0) { + *errp = ret; + return (NULL); + } + /* + * Get the time as ID. We may service more than one request per + * second however. If we are, then increment id value until we + * find an unused one. We insert entries in LRU fashion at the + * head of the list. So, if the first entry doesn't match, then + * we know for certain that we can use our entry. + */ + if ((t = time(NULL)) == -1) { + *errp = t; + __os_free(ctp, sizeof(ct_entry)); + return (NULL); + } + octp = LIST_FIRST(&__dbsrv_head); + if (octp != NULL && octp->ct_id >= t) + t = octp->ct_id + 1; + ctp->ct_id = t; + ctp->ct_idle = __dbsrv_idleto; + ctp->ct_activep = &ctp->ct_active; + ctp->ct_origp = NULL; + + LIST_INSERT_HEAD(&__dbsrv_head, ctp, entries); + return (ctp); +} + +/* + * PUBLIC: ct_entry *get_tableent __P((long)); + */ +ct_entry * +get_tableent(id) + long id; +{ + ct_entry *ctp; + + for (ctp = LIST_FIRST(&__dbsrv_head); ctp != NULL; + ctp = LIST_NEXT(ctp, entries)) + if (ctp->ct_id == id) + return (ctp); + return (NULL); +} + +/* + * PUBLIC: void __dbsrv_active __P((ct_entry *)); + */ +void +__dbsrv_active(ctp) + ct_entry *ctp; +{ + time_t t; + ct_entry *envctp; + + if (ctp == NULL) + return; + if ((t = time(NULL)) == -1) + return; + *(ctp->ct_activep) = t; + if ((envctp = ctp->ct_envparent) == NULL) + return; + *(envctp->ct_activep) = t; + return; +} + +/* + * PUBLIC: int __dbc_close_int __P((ct_entry *)); + */ +int +__dbc_close_int(dbc_ctp) + ct_entry *dbc_ctp; +{ + DBC *dbc; + int ret; + ct_entry *ctp; + + dbc = (DBC *)dbc_ctp->ct_anyp; + + ret = dbc->c_close(dbc); + /* + * If this cursor is a join cursor then we need to fix up the + * cursors that it was joined from so that they are independent again. + */ + if (dbc_ctp->ct_type & CT_JOINCUR) + for (ctp = LIST_FIRST(&__dbsrv_head); ctp != NULL; + ctp = LIST_NEXT(ctp, entries)) { + /* + * Test if it is a join cursor, and if it is part + * of this one. + */ + if ((ctp->ct_type & CT_JOIN) && + ctp->ct_activep == &dbc_ctp->ct_active) { + ctp->ct_type &= ~CT_JOIN; + ctp->ct_activep = ctp->ct_origp; + __dbsrv_active(ctp); + } + } + __dbclear_ctp(dbc_ctp); + return (ret); + +} + +/* + * PUBLIC: int __dbenv_close_int __P((long, int)); + */ +int +__dbenv_close_int(id, flags) + long id; + int flags; +{ + DB_ENV *dbenv; + int ret; + ct_entry *ctp; + + ctp = get_tableent(id); + if (ctp == NULL) + return (DB_NOSERVER_ID); + DB_ASSERT(ctp->ct_type == CT_ENV); + dbenv = ctp->ct_envp; + + ret = dbenv->close(dbenv, flags); + __dbdel_ctp(ctp); + return (ret); +} + +static int +add_home(home) + char *home; +{ + home_entry *hp, *homep; + int ret; + + if ((ret = __os_malloc(NULL, sizeof(home_entry), NULL, &hp)) != 0) + return (ret); + if ((ret = __os_malloc(NULL, strlen(home)+1, NULL, &hp->home)) != 0) + return (ret); + memcpy(hp->home, home, strlen(home)+1); + hp->dir = home; + /* + * This loop is to remove any trailing path separators, + * to assure hp->name points to the last component. + */ + hp->name = __db_rpath(home); + *(hp->name) = '\0'; + hp->name++; + while (*(hp->name) == '\0') { + hp->name = __db_rpath(home); + *(hp->name) = '\0'; + hp->name++; + } + /* + * Now we have successfully added it. Make sure there are no + * identical names. + */ + for (homep = LIST_FIRST(&__dbsrv_home); homep != NULL; + homep = LIST_NEXT(homep, entries)) + if (strcmp(homep->name, hp->name) == 0) { + printf("Already added home name %s, at directory %s\n", + hp->name, homep->dir); + return (-1); + } + LIST_INSERT_HEAD(&__dbsrv_home, hp, entries); + if (__dbsrv_verbose) + printf("Added home %s in dir %s\n", hp->name, hp->dir); + return (0); +} + +/* + * PUBLIC: char *get_home __P((char *)); + */ +char * +get_home(name) + char *name; +{ + home_entry *hp; + + for (hp = LIST_FIRST(&__dbsrv_home); hp != NULL; + hp = LIST_NEXT(hp, entries)) + if (strcmp(name, hp->name) == 0) + return (hp->home); + return (NULL); +} + +static int +env_recover(progname) + char *progname; +{ + DB_ENV *dbenv; + home_entry *hp; + u_int32_t flags; + int exitval, ret; + + for (hp = LIST_FIRST(&__dbsrv_home); hp != NULL; + hp = LIST_NEXT(hp, entries)) { + exitval = 0; + if ((ret = db_env_create(&dbenv, 0)) != 0) { + fprintf(stderr, "%s: db_env_create: %s\n", + progname, db_strerror(ret)); + exit(1); + } + if (__dbsrv_verbose == 1) { + (void)dbenv->set_verbose(dbenv, DB_VERB_RECOVERY, 1); + (void)dbenv->set_verbose(dbenv, DB_VERB_CHKPOINT, 1); + } + dbenv->set_errfile(dbenv, stderr); + dbenv->set_errpfx(dbenv, progname); + + /* + * Initialize the env with DB_RECOVER. That is all we + * have to do to run recovery. + */ + if (__dbsrv_verbose) + printf("Running recovery on %s\n", hp->home); + flags = DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | + DB_INIT_TXN | DB_PRIVATE | DB_USE_ENVIRON | DB_RECOVER; + if ((ret = dbenv->open(dbenv, hp->home, flags, 0)) != 0) { + dbenv->err(dbenv, ret, "DBENV->open"); + goto error; + } + + if (0) { +error: exitval = 1; + } + if ((ret = dbenv->close(dbenv, 0)) != 0) { + exitval = 1; + fprintf(stderr, "%s: dbenv->close: %s\n", + progname, db_strerror(ret)); + } + if (exitval) + return (exitval); + } + return (0); +} diff --git a/db/rpc_server/db_server_xdr.c b/db/rpc_server/db_server_xdr.c new file mode 100644 index 000000000..f403f862e --- /dev/null +++ b/db/rpc_server/db_server_xdr.c @@ -0,0 +1,1149 @@ +#include "db_config.h" +#ifdef HAVE_RPC +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#include "db_server.h" + +bool_t +xdr___env_cachesize_msg(xdrs, objp) + register XDR *xdrs; + __env_cachesize_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->dbenvcl_id)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->gbytes)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->bytes)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->ncache)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___env_cachesize_reply(xdrs, objp) + register XDR *xdrs; + __env_cachesize_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___env_close_msg(xdrs, objp) + register XDR *xdrs; + __env_close_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->dbenvcl_id)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->flags)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___env_close_reply(xdrs, objp) + register XDR *xdrs; + __env_close_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___env_create_msg(xdrs, objp) + register XDR *xdrs; + __env_create_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->timeout)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___env_create_reply(xdrs, objp) + register XDR *xdrs; + __env_create_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->envcl_id)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___env_flags_msg(xdrs, objp) + register XDR *xdrs; + __env_flags_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->dbenvcl_id)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->flags)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->onoff)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___env_flags_reply(xdrs, objp) + register XDR *xdrs; + __env_flags_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___env_open_msg(xdrs, objp) + register XDR *xdrs; + __env_open_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->dbenvcl_id)) + return (FALSE); + if (!xdr_string(xdrs, &objp->home, ~0)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->flags)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->mode)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___env_open_reply(xdrs, objp) + register XDR *xdrs; + __env_open_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___env_remove_msg(xdrs, objp) + register XDR *xdrs; + __env_remove_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->dbenvcl_id)) + return (FALSE); + if (!xdr_string(xdrs, &objp->home, ~0)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->flags)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___env_remove_reply(xdrs, objp) + register XDR *xdrs; + __env_remove_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___txn_abort_msg(xdrs, objp) + register XDR *xdrs; + __txn_abort_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->txnpcl_id)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___txn_abort_reply(xdrs, objp) + register XDR *xdrs; + __txn_abort_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___txn_begin_msg(xdrs, objp) + register XDR *xdrs; + __txn_begin_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->envpcl_id)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->parentcl_id)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->flags)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___txn_begin_reply(xdrs, objp) + register XDR *xdrs; + __txn_begin_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->txnidcl_id)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___txn_commit_msg(xdrs, objp) + register XDR *xdrs; + __txn_commit_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->txnpcl_id)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->flags)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___txn_commit_reply(xdrs, objp) + register XDR *xdrs; + __txn_commit_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_bt_maxkey_msg(xdrs, objp) + register XDR *xdrs; + __db_bt_maxkey_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->dbpcl_id)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->maxkey)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_bt_maxkey_reply(xdrs, objp) + register XDR *xdrs; + __db_bt_maxkey_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_bt_minkey_msg(xdrs, objp) + register XDR *xdrs; + __db_bt_minkey_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->dbpcl_id)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->minkey)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_bt_minkey_reply(xdrs, objp) + register XDR *xdrs; + __db_bt_minkey_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_close_msg(xdrs, objp) + register XDR *xdrs; + __db_close_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->dbpcl_id)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->flags)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_close_reply(xdrs, objp) + register XDR *xdrs; + __db_close_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_create_msg(xdrs, objp) + register XDR *xdrs; + __db_create_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->flags)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->envpcl_id)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_create_reply(xdrs, objp) + register XDR *xdrs; + __db_create_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->dbpcl_id)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_del_msg(xdrs, objp) + register XDR *xdrs; + __db_del_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->dbpcl_id)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->txnpcl_id)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->keydlen)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->keydoff)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->keyflags)) + return (FALSE); + if (!xdr_bytes(xdrs, (char **)&objp->keydata.keydata_val, (u_int *) &objp->keydata.keydata_len, ~0)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->flags)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_del_reply(xdrs, objp) + register XDR *xdrs; + __db_del_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_extentsize_msg(xdrs, objp) + register XDR *xdrs; + __db_extentsize_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->dbpcl_id)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->extentsize)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_extentsize_reply(xdrs, objp) + register XDR *xdrs; + __db_extentsize_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_flags_msg(xdrs, objp) + register XDR *xdrs; + __db_flags_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->dbpcl_id)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->flags)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_flags_reply(xdrs, objp) + register XDR *xdrs; + __db_flags_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_get_msg(xdrs, objp) + register XDR *xdrs; + __db_get_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->dbpcl_id)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->txnpcl_id)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->keydlen)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->keydoff)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->keyflags)) + return (FALSE); + if (!xdr_bytes(xdrs, (char **)&objp->keydata.keydata_val, (u_int *) &objp->keydata.keydata_len, ~0)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->datadlen)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->datadoff)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->dataflags)) + return (FALSE); + if (!xdr_bytes(xdrs, (char **)&objp->datadata.datadata_val, (u_int *) &objp->datadata.datadata_len, ~0)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->flags)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_get_reply(xdrs, objp) + register XDR *xdrs; + __db_get_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + if (!xdr_bytes(xdrs, (char **)&objp->keydata.keydata_val, (u_int *) &objp->keydata.keydata_len, ~0)) + return (FALSE); + if (!xdr_bytes(xdrs, (char **)&objp->datadata.datadata_val, (u_int *) &objp->datadata.datadata_len, ~0)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_h_ffactor_msg(xdrs, objp) + register XDR *xdrs; + __db_h_ffactor_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->dbpcl_id)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->ffactor)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_h_ffactor_reply(xdrs, objp) + register XDR *xdrs; + __db_h_ffactor_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_h_nelem_msg(xdrs, objp) + register XDR *xdrs; + __db_h_nelem_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->dbpcl_id)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->nelem)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_h_nelem_reply(xdrs, objp) + register XDR *xdrs; + __db_h_nelem_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_key_range_msg(xdrs, objp) + register XDR *xdrs; + __db_key_range_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->dbpcl_id)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->txnpcl_id)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->keydlen)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->keydoff)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->keyflags)) + return (FALSE); + if (!xdr_bytes(xdrs, (char **)&objp->keydata.keydata_val, (u_int *) &objp->keydata.keydata_len, ~0)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->flags)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_key_range_reply(xdrs, objp) + register XDR *xdrs; + __db_key_range_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + if (!xdr_double(xdrs, &objp->less)) + return (FALSE); + if (!xdr_double(xdrs, &objp->equal)) + return (FALSE); + if (!xdr_double(xdrs, &objp->greater)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_lorder_msg(xdrs, objp) + register XDR *xdrs; + __db_lorder_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->dbpcl_id)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->lorder)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_lorder_reply(xdrs, objp) + register XDR *xdrs; + __db_lorder_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_open_msg(xdrs, objp) + register XDR *xdrs; + __db_open_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->dbpcl_id)) + return (FALSE); + if (!xdr_string(xdrs, &objp->name, ~0)) + return (FALSE); + if (!xdr_string(xdrs, &objp->subdb, ~0)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->type)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->flags)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->mode)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_open_reply(xdrs, objp) + register XDR *xdrs; + __db_open_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->type)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->dbflags)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_pagesize_msg(xdrs, objp) + register XDR *xdrs; + __db_pagesize_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->dbpcl_id)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->pagesize)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_pagesize_reply(xdrs, objp) + register XDR *xdrs; + __db_pagesize_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_put_msg(xdrs, objp) + register XDR *xdrs; + __db_put_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->dbpcl_id)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->txnpcl_id)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->keydlen)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->keydoff)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->keyflags)) + return (FALSE); + if (!xdr_bytes(xdrs, (char **)&objp->keydata.keydata_val, (u_int *) &objp->keydata.keydata_len, ~0)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->datadlen)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->datadoff)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->dataflags)) + return (FALSE); + if (!xdr_bytes(xdrs, (char **)&objp->datadata.datadata_val, (u_int *) &objp->datadata.datadata_len, ~0)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->flags)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_put_reply(xdrs, objp) + register XDR *xdrs; + __db_put_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + if (!xdr_bytes(xdrs, (char **)&objp->keydata.keydata_val, (u_int *) &objp->keydata.keydata_len, ~0)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_re_delim_msg(xdrs, objp) + register XDR *xdrs; + __db_re_delim_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->dbpcl_id)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->delim)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_re_delim_reply(xdrs, objp) + register XDR *xdrs; + __db_re_delim_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_re_len_msg(xdrs, objp) + register XDR *xdrs; + __db_re_len_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->dbpcl_id)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->len)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_re_len_reply(xdrs, objp) + register XDR *xdrs; + __db_re_len_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_re_pad_msg(xdrs, objp) + register XDR *xdrs; + __db_re_pad_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->dbpcl_id)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->pad)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_re_pad_reply(xdrs, objp) + register XDR *xdrs; + __db_re_pad_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_remove_msg(xdrs, objp) + register XDR *xdrs; + __db_remove_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->dbpcl_id)) + return (FALSE); + if (!xdr_string(xdrs, &objp->name, ~0)) + return (FALSE); + if (!xdr_string(xdrs, &objp->subdb, ~0)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->flags)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_remove_reply(xdrs, objp) + register XDR *xdrs; + __db_remove_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_rename_msg(xdrs, objp) + register XDR *xdrs; + __db_rename_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->dbpcl_id)) + return (FALSE); + if (!xdr_string(xdrs, &objp->name, ~0)) + return (FALSE); + if (!xdr_string(xdrs, &objp->subdb, ~0)) + return (FALSE); + if (!xdr_string(xdrs, &objp->newname, ~0)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->flags)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_rename_reply(xdrs, objp) + register XDR *xdrs; + __db_rename_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_stat_msg(xdrs, objp) + register XDR *xdrs; + __db_stat_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->dbpcl_id)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->flags)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_stat_statsreplist(xdrs, objp) + register XDR *xdrs; + __db_stat_statsreplist *objp; +{ + + if (!xdr_bytes(xdrs, (char **)&objp->ent.ent_val, (u_int *) &objp->ent.ent_len, ~0)) + return (FALSE); + if (!xdr_pointer(xdrs, (char **)&objp->next, sizeof (__db_stat_statsreplist), (xdrproc_t) xdr___db_stat_statsreplist)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_stat_reply(xdrs, objp) + register XDR *xdrs; + __db_stat_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + if (!xdr_pointer(xdrs, (char **)&objp->statslist, sizeof (__db_stat_statsreplist), (xdrproc_t) xdr___db_stat_statsreplist)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_swapped_msg(xdrs, objp) + register XDR *xdrs; + __db_swapped_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->dbpcl_id)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_swapped_reply(xdrs, objp) + register XDR *xdrs; + __db_swapped_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_sync_msg(xdrs, objp) + register XDR *xdrs; + __db_sync_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->dbpcl_id)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->flags)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_sync_reply(xdrs, objp) + register XDR *xdrs; + __db_sync_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_cursor_msg(xdrs, objp) + register XDR *xdrs; + __db_cursor_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->dbpcl_id)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->txnpcl_id)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->flags)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_cursor_reply(xdrs, objp) + register XDR *xdrs; + __db_cursor_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->dbcidcl_id)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_join_curslist(xdrs, objp) + register XDR *xdrs; + __db_join_curslist *objp; +{ + + if (!xdr_bytes(xdrs, (char **)&objp->ent.ent_val, (u_int *) &objp->ent.ent_len, ~0)) + return (FALSE); + if (!xdr_pointer(xdrs, (char **)&objp->next, sizeof (__db_join_curslist), (xdrproc_t) xdr___db_join_curslist)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_join_msg(xdrs, objp) + register XDR *xdrs; + __db_join_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->dbpcl_id)) + return (FALSE); + if (!xdr_pointer(xdrs, (char **)&objp->curslist, sizeof (__db_join_curslist), (xdrproc_t) xdr___db_join_curslist)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->flags)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___db_join_reply(xdrs, objp) + register XDR *xdrs; + __db_join_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->dbcidcl_id)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___dbc_close_msg(xdrs, objp) + register XDR *xdrs; + __dbc_close_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->dbccl_id)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___dbc_close_reply(xdrs, objp) + register XDR *xdrs; + __dbc_close_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___dbc_count_msg(xdrs, objp) + register XDR *xdrs; + __dbc_count_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->dbccl_id)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->flags)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___dbc_count_reply(xdrs, objp) + register XDR *xdrs; + __dbc_count_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->dupcount)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___dbc_del_msg(xdrs, objp) + register XDR *xdrs; + __dbc_del_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->dbccl_id)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->flags)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___dbc_del_reply(xdrs, objp) + register XDR *xdrs; + __dbc_del_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___dbc_dup_msg(xdrs, objp) + register XDR *xdrs; + __dbc_dup_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->dbccl_id)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->flags)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___dbc_dup_reply(xdrs, objp) + register XDR *xdrs; + __dbc_dup_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->dbcidcl_id)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___dbc_get_msg(xdrs, objp) + register XDR *xdrs; + __dbc_get_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->dbccl_id)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->keydlen)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->keydoff)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->keyflags)) + return (FALSE); + if (!xdr_bytes(xdrs, (char **)&objp->keydata.keydata_val, (u_int *) &objp->keydata.keydata_len, ~0)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->datadlen)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->datadoff)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->dataflags)) + return (FALSE); + if (!xdr_bytes(xdrs, (char **)&objp->datadata.datadata_val, (u_int *) &objp->datadata.datadata_len, ~0)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->flags)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___dbc_get_reply(xdrs, objp) + register XDR *xdrs; + __dbc_get_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + if (!xdr_bytes(xdrs, (char **)&objp->keydata.keydata_val, (u_int *) &objp->keydata.keydata_len, ~0)) + return (FALSE); + if (!xdr_bytes(xdrs, (char **)&objp->datadata.datadata_val, (u_int *) &objp->datadata.datadata_len, ~0)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___dbc_put_msg(xdrs, objp) + register XDR *xdrs; + __dbc_put_msg *objp; +{ + + if (!xdr_u_int(xdrs, &objp->dbccl_id)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->keydlen)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->keydoff)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->keyflags)) + return (FALSE); + if (!xdr_bytes(xdrs, (char **)&objp->keydata.keydata_val, (u_int *) &objp->keydata.keydata_len, ~0)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->datadlen)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->datadoff)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->dataflags)) + return (FALSE); + if (!xdr_bytes(xdrs, (char **)&objp->datadata.datadata_val, (u_int *) &objp->datadata.datadata_len, ~0)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->flags)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr___dbc_put_reply(xdrs, objp) + register XDR *xdrs; + __dbc_put_reply *objp; +{ + + if (!xdr_u_int(xdrs, &objp->status)) + return (FALSE); + if (!xdr_bytes(xdrs, (char **)&objp->keydata.keydata_val, (u_int *) &objp->keydata.keydata_len, ~0)) + return (FALSE); + return (TRUE); +} +#endif /* HAVE_RPC */ diff --git a/db/rpc_server/gen_db_server.c b/db/rpc_server/gen_db_server.c new file mode 100644 index 000000000..20da69c4b --- /dev/null +++ b/db/rpc_server/gen_db_server.c @@ -0,0 +1,703 @@ +/* Do not edit: automatically built by gen_rpc.awk. */ +#include "db_config.h" + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include + +#include +#include +#endif +#include "db_server.h" + +#include "db_int.h" +#include "db_server_int.h" +#include "rpc_server_ext.h" + +#include "gen_server_ext.h" + +__env_cachesize_reply * +__db_env_cachesize_1(req) + __env_cachesize_msg *req; +{ + static __env_cachesize_reply reply; /* must be static */ + + __env_cachesize_1_proc(req->dbenvcl_id, + req->gbytes, + req->bytes, + req->ncache, + &reply); + + return (&reply); +} + +__env_close_reply * +__db_env_close_1(req) + __env_close_msg *req; +{ + static __env_close_reply reply; /* must be static */ + + __env_close_1_proc(req->dbenvcl_id, + req->flags, + &reply); + + return (&reply); +} + +__env_create_reply * +__db_env_create_1(req) + __env_create_msg *req; +{ + static __env_create_reply reply; /* must be static */ + + __env_create_1_proc(req->timeout, + &reply); + + return (&reply); +} + +__env_flags_reply * +__db_env_flags_1(req) + __env_flags_msg *req; +{ + static __env_flags_reply reply; /* must be static */ + + __env_flags_1_proc(req->dbenvcl_id, + req->flags, + req->onoff, + &reply); + + return (&reply); +} + +__env_open_reply * +__db_env_open_1(req) + __env_open_msg *req; +{ + static __env_open_reply reply; /* must be static */ + + __env_open_1_proc(req->dbenvcl_id, + (*req->home == '\0') ? NULL : req->home, + req->flags, + req->mode, + &reply); + + return (&reply); +} + +__env_remove_reply * +__db_env_remove_1(req) + __env_remove_msg *req; +{ + static __env_remove_reply reply; /* must be static */ + + __env_remove_1_proc(req->dbenvcl_id, + (*req->home == '\0') ? NULL : req->home, + req->flags, + &reply); + + return (&reply); +} + +__txn_abort_reply * +__db_txn_abort_1(req) + __txn_abort_msg *req; +{ + static __txn_abort_reply reply; /* must be static */ + + __txn_abort_1_proc(req->txnpcl_id, + &reply); + + return (&reply); +} + +__txn_begin_reply * +__db_txn_begin_1(req) + __txn_begin_msg *req; +{ + static __txn_begin_reply reply; /* must be static */ + + __txn_begin_1_proc(req->envpcl_id, + req->parentcl_id, + req->flags, + &reply); + + return (&reply); +} + +__txn_commit_reply * +__db_txn_commit_1(req) + __txn_commit_msg *req; +{ + static __txn_commit_reply reply; /* must be static */ + + __txn_commit_1_proc(req->txnpcl_id, + req->flags, + &reply); + + return (&reply); +} + +__db_bt_maxkey_reply * +__db_db_bt_maxkey_1(req) + __db_bt_maxkey_msg *req; +{ + static __db_bt_maxkey_reply reply; /* must be static */ + + __db_bt_maxkey_1_proc(req->dbpcl_id, + req->maxkey, + &reply); + + return (&reply); +} + +__db_bt_minkey_reply * +__db_db_bt_minkey_1(req) + __db_bt_minkey_msg *req; +{ + static __db_bt_minkey_reply reply; /* must be static */ + + __db_bt_minkey_1_proc(req->dbpcl_id, + req->minkey, + &reply); + + return (&reply); +} + +__db_close_reply * +__db_db_close_1(req) + __db_close_msg *req; +{ + static __db_close_reply reply; /* must be static */ + + __db_close_1_proc(req->dbpcl_id, + req->flags, + &reply); + + return (&reply); +} + +__db_create_reply * +__db_db_create_1(req) + __db_create_msg *req; +{ + static __db_create_reply reply; /* must be static */ + + __db_create_1_proc(req->flags, + req->envpcl_id, + &reply); + + return (&reply); +} + +__db_del_reply * +__db_db_del_1(req) + __db_del_msg *req; +{ + static __db_del_reply reply; /* must be static */ + + __db_del_1_proc(req->dbpcl_id, + req->txnpcl_id, + req->keydlen, + req->keydoff, + req->keyflags, + req->keydata.keydata_val, + req->keydata.keydata_len, + req->flags, + &reply); + + return (&reply); +} + +__db_extentsize_reply * +__db_db_extentsize_1(req) + __db_extentsize_msg *req; +{ + static __db_extentsize_reply reply; /* must be static */ + + __db_extentsize_1_proc(req->dbpcl_id, + req->extentsize, + &reply); + + return (&reply); +} + +__db_flags_reply * +__db_db_flags_1(req) + __db_flags_msg *req; +{ + static __db_flags_reply reply; /* must be static */ + + __db_flags_1_proc(req->dbpcl_id, + req->flags, + &reply); + + return (&reply); +} + +__db_get_reply * +__db_db_get_1(req) + __db_get_msg *req; +{ + static __db_get_reply reply; /* must be static */ + static int __db_get_free = 0; /* must be static */ + + if (__db_get_free) + xdr_free((xdrproc_t)xdr___db_get_reply, (void *)&reply); + __db_get_free = 0; + + /* Reinitialize allocated fields */ + reply.keydata.keydata_val = NULL; + reply.datadata.datadata_val = NULL; + + __db_get_1_proc(req->dbpcl_id, + req->txnpcl_id, + req->keydlen, + req->keydoff, + req->keyflags, + req->keydata.keydata_val, + req->keydata.keydata_len, + req->datadlen, + req->datadoff, + req->dataflags, + req->datadata.datadata_val, + req->datadata.datadata_len, + req->flags, + &reply, + &__db_get_free); + return (&reply); +} + +__db_h_ffactor_reply * +__db_db_h_ffactor_1(req) + __db_h_ffactor_msg *req; +{ + static __db_h_ffactor_reply reply; /* must be static */ + + __db_h_ffactor_1_proc(req->dbpcl_id, + req->ffactor, + &reply); + + return (&reply); +} + +__db_h_nelem_reply * +__db_db_h_nelem_1(req) + __db_h_nelem_msg *req; +{ + static __db_h_nelem_reply reply; /* must be static */ + + __db_h_nelem_1_proc(req->dbpcl_id, + req->nelem, + &reply); + + return (&reply); +} + +__db_key_range_reply * +__db_db_key_range_1(req) + __db_key_range_msg *req; +{ + static __db_key_range_reply reply; /* must be static */ + + __db_key_range_1_proc(req->dbpcl_id, + req->txnpcl_id, + req->keydlen, + req->keydoff, + req->keyflags, + req->keydata.keydata_val, + req->keydata.keydata_len, + req->flags, + &reply); + + return (&reply); +} + +__db_lorder_reply * +__db_db_lorder_1(req) + __db_lorder_msg *req; +{ + static __db_lorder_reply reply; /* must be static */ + + __db_lorder_1_proc(req->dbpcl_id, + req->lorder, + &reply); + + return (&reply); +} + +__db_open_reply * +__db_db_open_1(req) + __db_open_msg *req; +{ + static __db_open_reply reply; /* must be static */ + + __db_open_1_proc(req->dbpcl_id, + (*req->name == '\0') ? NULL : req->name, + (*req->subdb == '\0') ? NULL : req->subdb, + req->type, + req->flags, + req->mode, + &reply); + + return (&reply); +} + +__db_pagesize_reply * +__db_db_pagesize_1(req) + __db_pagesize_msg *req; +{ + static __db_pagesize_reply reply; /* must be static */ + + __db_pagesize_1_proc(req->dbpcl_id, + req->pagesize, + &reply); + + return (&reply); +} + +__db_put_reply * +__db_db_put_1(req) + __db_put_msg *req; +{ + static __db_put_reply reply; /* must be static */ + static int __db_put_free = 0; /* must be static */ + + if (__db_put_free) + xdr_free((xdrproc_t)xdr___db_put_reply, (void *)&reply); + __db_put_free = 0; + + /* Reinitialize allocated fields */ + reply.keydata.keydata_val = NULL; + + __db_put_1_proc(req->dbpcl_id, + req->txnpcl_id, + req->keydlen, + req->keydoff, + req->keyflags, + req->keydata.keydata_val, + req->keydata.keydata_len, + req->datadlen, + req->datadoff, + req->dataflags, + req->datadata.datadata_val, + req->datadata.datadata_len, + req->flags, + &reply, + &__db_put_free); + return (&reply); +} + +__db_re_delim_reply * +__db_db_re_delim_1(req) + __db_re_delim_msg *req; +{ + static __db_re_delim_reply reply; /* must be static */ + + __db_re_delim_1_proc(req->dbpcl_id, + req->delim, + &reply); + + return (&reply); +} + +__db_re_len_reply * +__db_db_re_len_1(req) + __db_re_len_msg *req; +{ + static __db_re_len_reply reply; /* must be static */ + + __db_re_len_1_proc(req->dbpcl_id, + req->len, + &reply); + + return (&reply); +} + +__db_re_pad_reply * +__db_db_re_pad_1(req) + __db_re_pad_msg *req; +{ + static __db_re_pad_reply reply; /* must be static */ + + __db_re_pad_1_proc(req->dbpcl_id, + req->pad, + &reply); + + return (&reply); +} + +__db_remove_reply * +__db_db_remove_1(req) + __db_remove_msg *req; +{ + static __db_remove_reply reply; /* must be static */ + + __db_remove_1_proc(req->dbpcl_id, + (*req->name == '\0') ? NULL : req->name, + (*req->subdb == '\0') ? NULL : req->subdb, + req->flags, + &reply); + + return (&reply); +} + +__db_rename_reply * +__db_db_rename_1(req) + __db_rename_msg *req; +{ + static __db_rename_reply reply; /* must be static */ + + __db_rename_1_proc(req->dbpcl_id, + (*req->name == '\0') ? NULL : req->name, + (*req->subdb == '\0') ? NULL : req->subdb, + (*req->newname == '\0') ? NULL : req->newname, + req->flags, + &reply); + + return (&reply); +} + +__db_stat_reply * +__db_db_stat_1(req) + __db_stat_msg *req; +{ + static __db_stat_reply reply; /* must be static */ + static int __db_stat_free = 0; /* must be static */ + + if (__db_stat_free) + xdr_free((xdrproc_t)xdr___db_stat_reply, (void *)&reply); + __db_stat_free = 0; + + /* Reinitialize allocated fields */ + reply.statslist = NULL; + + __db_stat_1_proc(req->dbpcl_id, + req->flags, + &reply, + &__db_stat_free); + return (&reply); +} + +__db_swapped_reply * +__db_db_swapped_1(req) + __db_swapped_msg *req; +{ + static __db_swapped_reply reply; /* must be static */ + + __db_swapped_1_proc(req->dbpcl_id, + &reply); + + return (&reply); +} + +__db_sync_reply * +__db_db_sync_1(req) + __db_sync_msg *req; +{ + static __db_sync_reply reply; /* must be static */ + + __db_sync_1_proc(req->dbpcl_id, + req->flags, + &reply); + + return (&reply); +} + +__db_cursor_reply * +__db_db_cursor_1(req) + __db_cursor_msg *req; +{ + static __db_cursor_reply reply; /* must be static */ + + __db_cursor_1_proc(req->dbpcl_id, + req->txnpcl_id, + req->flags, + &reply); + + return (&reply); +} + +int __db_db_join_curslist __P((__db_join_curslist *, u_int32_t **)); +void __db_db_join_cursfree __P((u_int32_t *)); + +__db_join_reply * +__db_db_join_1(req) + __db_join_msg *req; +{ + u_int32_t *__db_curslist; + int ret; + static __db_join_reply reply; /* must be static */ + + if ((ret = __db_db_join_curslist(req->curslist, &__db_curslist)) != 0) + goto out; + + __db_join_1_proc(req->dbpcl_id, + __db_curslist, + req->flags, + &reply); + + __db_db_join_cursfree(__db_curslist); + +out: + return (&reply); +} + +int +__db_db_join_curslist(locp, ppp) + __db_join_curslist *locp; + u_int32_t **ppp; +{ + u_int32_t *pp; + int cnt, ret, size; + __db_join_curslist *nl; + + for (cnt = 0, nl = locp; nl != NULL; cnt++, nl = nl->next) + ; + + if (cnt == 0) { + *ppp = NULL; + return (0); + } + size = sizeof(*pp) * (cnt + 1); + if ((ret = __os_malloc(NULL, size, NULL, ppp)) != 0) + return (ret); + memset(*ppp, 0, size); + for (pp = *ppp, nl = locp; nl != NULL; nl = nl->next, pp++) { + *pp = *(u_int32_t *)nl->ent.ent_val; + } + return (0); +} + +void +__db_db_join_cursfree(pp) + u_int32_t *pp; +{ + size_t size; + u_int32_t *p; + + if (pp == NULL) + return; + size = sizeof(*p); + for (p = pp; *p != 0; p++) { + size += sizeof(*p); + } + __os_free(pp, size); +} + +__dbc_close_reply * +__db_dbc_close_1(req) + __dbc_close_msg *req; +{ + static __dbc_close_reply reply; /* must be static */ + + __dbc_close_1_proc(req->dbccl_id, + &reply); + + return (&reply); +} + +__dbc_count_reply * +__db_dbc_count_1(req) + __dbc_count_msg *req; +{ + static __dbc_count_reply reply; /* must be static */ + + __dbc_count_1_proc(req->dbccl_id, + req->flags, + &reply); + + return (&reply); +} + +__dbc_del_reply * +__db_dbc_del_1(req) + __dbc_del_msg *req; +{ + static __dbc_del_reply reply; /* must be static */ + + __dbc_del_1_proc(req->dbccl_id, + req->flags, + &reply); + + return (&reply); +} + +__dbc_dup_reply * +__db_dbc_dup_1(req) + __dbc_dup_msg *req; +{ + static __dbc_dup_reply reply; /* must be static */ + + __dbc_dup_1_proc(req->dbccl_id, + req->flags, + &reply); + + return (&reply); +} + +__dbc_get_reply * +__db_dbc_get_1(req) + __dbc_get_msg *req; +{ + static __dbc_get_reply reply; /* must be static */ + static int __dbc_get_free = 0; /* must be static */ + + if (__dbc_get_free) + xdr_free((xdrproc_t)xdr___dbc_get_reply, (void *)&reply); + __dbc_get_free = 0; + + /* Reinitialize allocated fields */ + reply.keydata.keydata_val = NULL; + reply.datadata.datadata_val = NULL; + + __dbc_get_1_proc(req->dbccl_id, + req->keydlen, + req->keydoff, + req->keyflags, + req->keydata.keydata_val, + req->keydata.keydata_len, + req->datadlen, + req->datadoff, + req->dataflags, + req->datadata.datadata_val, + req->datadata.datadata_len, + req->flags, + &reply, + &__dbc_get_free); + return (&reply); +} + +__dbc_put_reply * +__db_dbc_put_1(req) + __dbc_put_msg *req; +{ + static __dbc_put_reply reply; /* must be static */ + static int __dbc_put_free = 0; /* must be static */ + + if (__dbc_put_free) + xdr_free((xdrproc_t)xdr___dbc_put_reply, (void *)&reply); + __dbc_put_free = 0; + + /* Reinitialize allocated fields */ + reply.keydata.keydata_val = NULL; + + __dbc_put_1_proc(req->dbccl_id, + req->keydlen, + req->keydoff, + req->keyflags, + req->keydata.keydata_val, + req->keydata.keydata_len, + req->datadlen, + req->datadoff, + req->dataflags, + req->datadata.datadata_val, + req->datadata.datadata_len, + req->flags, + &reply, + &__dbc_put_free); + return (&reply); +} + diff --git a/db/rpc_server/rpc.src b/db/rpc_server/rpc.src new file mode 100644 index 000000000..5dd252051 --- /dev/null +++ b/db/rpc_server/rpc.src @@ -0,0 +1,599 @@ +# +# $Id: rpc.src,v 1.30 2000/12/20 21:53:05 ubell Exp $ +# Syntax: +# BEGIN function_name RPC # {CODE | NOCLNTCODE | RETCODE | NOFUNC} +# CODE: generate XDR and client code, return status +# Used for functions that just return a status and nothing else. +# RETCODE:generate XDR and client code, call return function +# (generate template return function) +# Used for functions that returns data. +# NOCLNTCODE: generate only XDR and server functions +# Used for functions that are "different" on the client. +# Primarily used for envcreate (which is called from +# the dbenv->set_server method on the client side) and +# dbcreate, which is called from non-generated code. +# NOFUNC: generate a client "unsupported function" with right args +# Used for unsupported functions. +# +# ARG {IGNORE | STRING | INT | DBT | LIST | ID | CONST} C-type varname +# IGNORE: not passed to server +# STRING: string passed to server +# DBT: DBT arg passed to server +# LIST: opaque list passed to server (NULL-terminated opaque list) +# INT: integer passed to server +# ID: cl_id from arg passed to server +# CONST: do not generate COMPQUIET (for NOFUNC only) +# FUNCPROT prototype +# FUNCARG functiontype +# These two *MUST* go together and FUNCPROT *MUST* be first. These +# are for the tricky user-supplied functions to some methods. They +# are not supported in RPC, so will be ignored, but the complicated +# syntax of their argument requires we have a special flag for them +# that contains the verbatim text to use in the prototype and the +# c-type, respectively. The FUNCARG must include the function, and +# must call it 'funcN', where N is the count of functions. Almost +# always it must be func0. A *very* few methods have more than one +# user-supplied functions, in those cases, it must be func0, func1, etc. +# +# All messages automatically return "status" and return that from +# the call to the function. RET's are additional things the server +# may return. RET is like ARG but does not need the IGNORE option. +# RET {STRING | INT | DBT | LIST | ID} varname [STRING | INT | ID] +# STRING: string from server +# DBT: DBT arg from server +# LIST: opaque list from server (NULL-terminated opaque list) +# Must have list type of STRING, ID or INT specified +# INT: integer from server +# ID: id from server stored in cl_id +# END function end. + +# +# Environment functions +# +BEGIN env_cachesize 1 CODE +ARG ID DB_ENV * dbenv +ARG INT u_int32_t gbytes +ARG INT u_int32_t bytes +ARG INT int ncache +END +BEGIN env_close 1 RETCODE +ARG ID DB_ENV * dbenv +ARG INT u_int32_t flags +END +BEGIN env_create 1 NOCLNTCODE +ARG INT long timeout +RET ID long env +END +BEGIN set_data_dir 1 NOFUNC +ARG ID DB_ENV * dbenv +ARG STRING const char * dir +END +BEGIN env_set_feedback 1 NOFUNC +ARG ID DB_ENV * dbenv +FUNCPROT void (*)(DB_ENV *, int, int) +FUNCARG void (*func0) __P((DB_ENV *, int, int)) +END +BEGIN env_flags 1 CODE +ARG ID DB_ENV * dbenv +ARG INT u_int32_t flags +ARG INT int onoff +END +BEGIN set_lg_bsize 1 NOFUNC +ARG ID DB_ENV * dbenv +ARG INT u_int32_t bsize +END +BEGIN set_lg_dir 1 NOFUNC +ARG ID DB_ENV * dbenv +ARG STRING const char * dir +END +BEGIN set_lg_max 1 NOFUNC +ARG ID DB_ENV * dbenv +ARG INT u_int32_t max +END +BEGIN set_lk_conflict 1 NOFUNC +ARG ID DB_ENV * dbenv +ARG INT u_int8_t * conflicts +ARG INT int modes +END +BEGIN set_lk_detect 1 NOFUNC +ARG ID DB_ENV * dbenv +ARG INT u_int32_t detect +END +BEGIN set_lk_max 1 NOFUNC +ARG ID DB_ENV * dbenv +ARG INT u_int32_t max +END +BEGIN set_lk_max_locks 1 NOFUNC +ARG ID DB_ENV * dbenv +ARG INT u_int32_t max +END +BEGIN set_lk_max_lockers 1 NOFUNC +ARG ID DB_ENV * dbenv +ARG INT u_int32_t max +END +BEGIN set_lk_max_objects 1 NOFUNC +ARG ID DB_ENV * dbenv +ARG INT u_int32_t max +END +BEGIN set_mp_mmapsize 1 NOFUNC +ARG ID DB_ENV * dbenv +ARG INT size_t mmapsize +END +BEGIN set_mutex_locks 1 NOFUNC +ARG ID DB_ENV * dbenv +ARG INT int do_lock +END +BEGIN env_open 1 RETCODE +ARG ID DB_ENV * dbenv +ARG STRING const char * home +ARG INT u_int32_t flags +ARG INT int mode +END +BEGIN env_paniccall 1 NOFUNC +ARG ID DB_ENV * dbenv +FUNCPROT void (*)(DB_ENV *, int) +FUNCARG void (*func0) __P((DB_ENV *, int)) +END +BEGIN set_recovery_init 1 NOFUNC +ARG ID DB_ENV * dbenv +FUNCPROT int (*)(DB_ENV *) +FUNCARG int (*func0) __P((DB_ENV *)) +END +BEGIN env_remove 1 RETCODE +ARG ID DB_ENV * dbenv +ARG STRING const char * home +ARG INT u_int32_t flags +END +BEGIN set_shm_key 1 NOFUNC +ARG ID DB_ENV * dbenv +ARG INT long shm_key +END +BEGIN set_tmp_dir 1 NOFUNC +ARG ID DB_ENV * dbenv +ARG STRING const char * dir +END +BEGIN set_tx_recover 1 NOFUNC +ARG ID DB_ENV * dbenv +FUNCPROT int (*)(DB_ENV *, DBT *, DB_LSN *, db_recops) +FUNCARG int (*func0) __P((DB_ENV *, DBT *, DB_LSN *, db_recops)) +END +BEGIN set_tx_max 1 NOFUNC +ARG ID DB_ENV * dbenv +ARG INT u_int32_t max +END +BEGIN set_tx_timestamp 1 NOFUNC +ARG ID DB_ENV * dbenv +ARG INT time_t * max +END +BEGIN set_verbose 1 NOFUNC +ARG ID DB_ENV * dbenv +ARG INT u_int32_t which +ARG INT int onoff +END +# +# Transaction functions +# +BEGIN txn_abort 1 RETCODE +ARG ID DB_TXN * txnp +END +BEGIN txn_begin 1 RETCODE +ARG ID DB_ENV * envp +ARG ID DB_TXN * parent +ARG IGNORE DB_TXN ** txnpp +ARG INT u_int32_t flags +RET ID long txnid +END +BEGIN txn_checkpoint 1 NOFUNC +ARG ID DB_ENV * dbenv +ARG INT u_int32_t kbyte +ARG INT u_int32_t min +END +BEGIN txn_commit 1 RETCODE +ARG ID DB_TXN * txnp +ARG INT u_int32_t flags +END +BEGIN txn_prepare 1 NOFUNC +ARG ID DB_TXN * txnp +END +BEGIN txn_stat 1 NOFUNC +ARG ID DB_ENV * dbenv +ARG IGNORE DB_TXN_STAT ** statp +FUNCPROT void *(*)(size_t) +FUNCARG void *(*func0) __P((size_t)) +END + +# +# Database functions +# +BEGIN db_bt_compare 1 NOFUNC +ARG ID DB * dbp +FUNCPROT int (*)(DB *, const DBT *, const DBT *) +FUNCARG int (*func0) __P((DB *, const DBT *, const DBT *)) +END +BEGIN db_bt_maxkey 1 CODE +ARG ID DB * dbp +ARG INT u_int32_t maxkey +END +BEGIN db_bt_minkey 1 CODE +ARG ID DB * dbp +ARG INT u_int32_t minkey +END +BEGIN db_bt_prefix 1 NOFUNC +ARG ID DB * dbp +FUNCPROT size_t(*)(DB *, const DBT *, const DBT *) +FUNCARG size_t (*func0) __P((DB *, const DBT *, const DBT *)) +END +BEGIN db_set_append_recno 1 NOFUNC +ARG ID DB * dbp +FUNCPROT int (*)(DB *, DBT *, db_recno_t) +FUNCARG int (*func0) __P((DB *, DBT *, db_recno_t)) +END +BEGIN db_cachesize 1 NOFUNC +ARG ID DB * dbp +ARG INT u_int32_t gbytes +ARG INT u_int32_t bytes +ARG INT int ncache +END +BEGIN db_close 1 RETCODE +ARG ID DB * dbp +ARG INT u_int32_t flags +END +BEGIN db_create 1 NOCLNTCODE +ARG INT u_int32_t flags +ARG ID DB_ENV * envp +RET ID long dbp +END +BEGIN db_del 1 CODE +ARG ID DB * dbp +ARG ID DB_TXN * txnp +ARG DBT DBT * key +ARG INT u_int32_t flags +END +BEGIN db_extentsize 1 CODE +ARG ID DB * dbp +ARG INT u_int32_t extentsize +END +BEGIN db_fd 1 NOFUNC +ARG ID DB * dbp +ARG IGNORE int * fdp +END +BEGIN db_feedback 1 NOFUNC +ARG ID DB * dbp +FUNCPROT void (*)(DB *, int, int) +FUNCARG void (*func0) __P((DB *, int, int)) +END +BEGIN db_flags 1 CODE +ARG ID DB * dbp +ARG INT u_int32_t flags +END +BEGIN db_get 1 RETCODE +ARG ID DB * dbp +ARG ID DB_TXN * txnp +ARG DBT DBT * key +ARG DBT DBT * data +ARG INT u_int32_t flags +RET DBT DBT * key +RET DBT DBT * data +END +BEGIN db_h_ffactor 1 CODE +ARG ID DB * dbp +ARG INT u_int32_t ffactor +END +BEGIN db_h_hash 1 NOFUNC +ARG ID DB * dbp +FUNCPROT u_int32_t(*)(DB *, const void *, u_int32_t) +FUNCARG u_int32_t (*func0) __P((DB *, const void *, u_int32_t)) +END +BEGIN db_h_nelem 1 CODE +ARG ID DB * dbp +ARG INT u_int32_t nelem +END +BEGIN db_key_range 1 RETCODE +ARG ID DB * dbp +ARG ID DB_TXN * txnp +ARG DBT DBT * key +ARG IGNORE DB_KEY_RANGE * range +ARG INT u_int32_t flags +RET DBL double less +RET DBL double equal +RET DBL double greater +END +BEGIN db_lorder 1 CODE +ARG ID DB * dbp +ARG INT int lorder +END +BEGIN db_malloc 1 NOFUNC +ARG ID DB * dbp +FUNCPROT void *(*)(size_t) +FUNCARG void *(*func0) __P((size_t)) +END +# XXX +# The line: +# RET INT u_int32_t dbflags +# should go away when a get_flags method exists. It is +# needed now because Tcl looks at dbp->flags. +# +BEGIN db_open 1 RETCODE +ARG ID DB * dbp +ARG STRING const char * name +ARG STRING const char * subdb +ARG INT DBTYPE type +ARG INT u_int32_t flags +ARG INT int mode +RET INT DBTYPE type +RET INT u_int32_t dbflags +END +BEGIN db_pagesize 1 CODE +ARG ID DB * dbp +ARG INT u_int32_t pagesize +END +BEGIN db_panic 1 NOFUNC +ARG ID DB * dbp +FUNCPROT void (*)(DB_ENV *, int) +FUNCARG void (*func0) __P((DB_ENV *, int)) +END +BEGIN db_put 1 RETCODE +ARG ID DB * dbp +ARG ID DB_TXN * txnp +ARG DBT DBT * key +ARG DBT DBT * data +ARG INT u_int32_t flags +RET DBT DBT * key +END +BEGIN db_realloc 1 NOFUNC +ARG ID DB * dbp +FUNCPROT void *(*)(void *, size_t) +FUNCARG void *(*func0) __P((void *, size_t)) +END +BEGIN db_re_delim 1 CODE +ARG ID DB * dbp +ARG INT int delim +END +BEGIN db_re_len 1 CODE +ARG ID DB * dbp +ARG INT u_int32_t len +END +BEGIN db_re_pad 1 CODE +ARG ID DB * dbp +ARG INT int pad +END +BEGIN db_re_source 1 NOFUNC +ARG ID DB * dbp +ARG STRING const char * re_source +END +BEGIN db_remove 1 RETCODE +ARG ID DB * dbp +ARG STRING const char * name +ARG STRING const char * subdb +ARG INT u_int32_t flags +END +BEGIN db_rename 1 RETCODE +ARG ID DB * dbp +ARG STRING const char * name +ARG STRING const char * subdb +ARG STRING const char * newname +ARG INT u_int32_t flags +END +BEGIN db_stat 1 RETCODE +ARG ID DB * dbp +ARG IGNORE void * sp +FUNCPROT void *(*)(size_t) +FUNCARG void *(*func0) __P((size_t)) +ARG INT u_int32_t flags +RET LIST u_int32_t * stats INT +END +BEGIN db_swapped 1 CODE +ARG ID DB * dbp +END +BEGIN db_sync 1 CODE +ARG ID DB * dbp +ARG INT u_int32_t flags +END +BEGIN db_upgrade 1 NOFUNC +ARG ID DB * dbp +ARG STRING const char * fname +ARG INT u_int32_t flags +END +# +# Cursor functions +# +BEGIN db_cursor 1 RETCODE +ARG ID DB * dbp +ARG ID DB_TXN * txnp +ARG IGNORE DBC ** dbcpp +ARG INT u_int32_t flags +RET ID long dbcid +END +BEGIN db_join 1 RETCODE +ARG ID DB * dbp +ARG LIST DBC ** curs ID +ARG IGNORE DBC ** dbcp +ARG INT u_int32_t flags +RET ID long dbcid +END +BEGIN dbc_close 1 RETCODE +ARG ID DBC * dbc +END +BEGIN dbc_count 1 RETCODE +ARG ID DBC * dbc +ARG IGNORE db_recno_t * countp +ARG INT u_int32_t flags +RET INT db_recno_t dupcount +END +BEGIN dbc_del 1 CODE +ARG ID DBC * dbc +ARG INT u_int32_t flags +END +BEGIN dbc_dup 1 RETCODE +ARG ID DBC * dbc +ARG IGNORE DBC ** dbcp +ARG INT u_int32_t flags +RET ID long dbcid +END +BEGIN dbc_get 1 RETCODE +ARG ID DBC * dbc +ARG DBT DBT * key +ARG DBT DBT * data +ARG INT u_int32_t flags +RET DBT DBT * key +RET DBT DBT * data +END +BEGIN dbc_put 1 RETCODE +ARG ID DBC * dbc +ARG DBT DBT * key +ARG DBT DBT * data +ARG INT u_int32_t flags +RET DBT DBT * key +END + +# +# Unsupported environment subsystems +# +# +# Locking subsystem +# +BEGIN lock_detect 1 NOFUNC +ARG ID DB_ENV * dbenv +ARG INT u_int32_t flags +ARG INT u_int32_t atype +ARG IGNORE int * aborted +END +BEGIN lock_get 1 NOFUNC +ARG ID DB_ENV * dbenv +ARG INT u_int32_t locker +ARG INT u_int32_t flags +ARG CONST const DBT * obj +ARG INT db_lockmode_t mode +ARG IGNORE DB_LOCK * lock +END +BEGIN lock_id 1 NOFUNC +ARG ID DB_ENV * dbenv +ARG INT u_int32_t * idp +END +BEGIN lock_put 1 NOFUNC +ARG ID DB_ENV * dbenv +ARG ID DB_LOCK * lock +END +BEGIN lock_stat 1 NOFUNC +ARG ID DB_ENV * dbenv +ARG IGNORE DB_LOCK_STAT ** statp +FUNCPROT void *(*)(size_t) +FUNCARG void *(*func0) __P((size_t)) +END +BEGIN lock_vec 1 NOFUNC +ARG ID DB_ENV * dbenv +ARG INT u_int32_t locker +ARG INT u_int32_t flags +ARG IGNORE DB_LOCKREQ * list +ARG INT int nlist +ARG IGNORE DB_LOCKREQ ** elistp +END +# +# Logging subsystem +# +BEGIN log_archive 1 NOFUNC +ARG ID DB_ENV * dbenv +ARG IGNORE char *** listp +ARG INT u_int32_t flags +FUNCPROT void *(*)(size_t) +FUNCARG void *(*func0) __P((size_t)) +END +# +# Don't do log_compare. It doesn't have an env we can get at, +# and it doesn't manipulate DB internal information. +# +BEGIN log_file 1 NOFUNC +ARG ID DB_ENV * dbenv +ARG CONST const DB_LSN * lsn +ARG STRING char * namep +ARG INT size_t len +END +BEGIN log_flush 1 NOFUNC +ARG ID DB_ENV * dbenv +ARG CONST const DB_LSN * lsn +END +BEGIN log_get 1 NOFUNC +ARG ID DB_ENV * dbenv +ARG IGNORE DB_LSN * lsn +ARG DBT DBT * data +ARG INT u_int32_t flags +END +BEGIN log_put 1 NOFUNC +ARG ID DB_ENV * dbenv +ARG IGNORE DB_LSN * lsn +ARG CONST const DBT * data +ARG INT u_int32_t flags +END +BEGIN log_register 1 NOFUNC +ARG ID DB_ENV * dbenv +ARG ID DB * dbp +ARG CONST const char * namep +END +BEGIN log_stat 1 NOFUNC +ARG ID DB_ENV * dbenv +ARG IGNORE DB_LOG_STAT ** statp +FUNCPROT void *(*)(size_t) +FUNCARG void *(*func0) __P((size_t)) +END +BEGIN log_unregister 1 NOFUNC +ARG ID DB_ENV * dbenv +ARG ID DB * dbp +END +# +# Mpool Subsystem +# +BEGIN memp_fclose 1 NOFUNC +ARG ID DB_MPOOLFILE * mpf +END +BEGIN memp_fget 1 NOFUNC +ARG ID DB_MPOOLFILE * mpf +ARG IGNORE db_pgno_t * pgno +ARG INT u_int32_t flags +ARG IGNORE void ** pagep +END +BEGIN memp_fopen 1 NOFUNC +ARG ID DB_ENV * dbenv +ARG CONST const char * file +ARG INT u_int32_t flags +ARG INT int mode +ARG INT size_t pagesize +ARG IGNORE DB_MPOOL_FINFO * finfop +ARG IGNORE DB_MPOOLFILE ** mpf +END +BEGIN memp_fput 1 NOFUNC +ARG ID DB_MPOOLFILE * mpf +ARG IGNORE void * pgaddr +ARG INT u_int32_t flags +END +BEGIN memp_fset 1 NOFUNC +ARG ID DB_MPOOLFILE * mpf +ARG IGNORE void * pgaddr +ARG INT u_int32_t flags +END +BEGIN memp_fsync 1 NOFUNC +ARG ID DB_MPOOLFILE * mpf +END +BEGIN memp_register 1 NOFUNC +ARG ID DB_ENV * dbenv +ARG INT int ftype +FUNCPROT int (*)(DB_ENV *, db_pgno_t, void *, DBT *) +FUNCARG int (*func0) __P((DB_ENV *, db_pgno_t, void *, DBT *)) +FUNCPROT int (*)(DB_ENV *, db_pgno_t, void *, DBT *) +FUNCARG int (*func1) __P((DB_ENV *, db_pgno_t, void *, DBT *)) +END +BEGIN memp_stat 1 NOFUNC +ARG ID DB_ENV * dbenv +ARG IGNORE DB_MPOOL_STAT ** gstatp +ARG IGNORE DB_MPOOL_FSTAT *** fstatp +FUNCPROT void *(*)(size_t) +FUNCARG void *(*func0) __P((size_t)) +END +BEGIN memp_sync 1 NOFUNC +ARG ID DB_ENV * dbenv +ARG IGNORE DB_LSN * lsn +END +BEGIN memp_trickle 1 NOFUNC +ARG ID DB_ENV * dbenv +ARG INT int pct +ARG IGNORE int * nwrotep +END diff --git a/db/tcl/docs/db.html b/db/tcl/docs/db.html new file mode 100644 index 000000000..c75ab6ecf --- /dev/null +++ b/db/tcl/docs/db.html @@ -0,0 +1,266 @@ + + + + + + + + +

+Database Commands

+The database commands provide a conduit into the DB method functions.  +They are all fairly straightforward and I describe them in terms of their +DB functions briefly here, with a link to the DB page where appropriate.  +The first set of commands are those I believe will be the primary functions +used by most databases.  Some are directly related to their DB counterparts, +and some are higher level functions that are useful to provide the user. +

> berkdb open [-env env] +
    [-btree|-hash|-recno|-queue|-unknown] +
    [-create] [-excl] [-nommap] [-rdonly] [-truncate] +[-mode +mode] [-errfile filename] +
    [-dup] [-dupsort] [-recnum] [-renumber] [-revsplitoff] +[-snapshot] +
    [-extent size] +
    [-ffactor density] +
    [-nelem size] +
    [-lorder order] +
    [-delim delim] +
    [-len len] +
    [-pad pad] +
    [-source file] +
    [-minkey minkey] +
    [-cachesize {gbytes bytes ncaches}] +
    [-pagesize pagesize] +
    [--] +
    [filename [subdbname]] +

This command will invoke the db_create +function.  If the command is given the -env option, then we +will accordingly creating the database within the context of that environment.  +After it successfully gets a handle to a database, we bind it to a new +Tcl command of the form dbX, where X is an integer starting +at 0 (e.g. db0, db1, etc).  We use the Tcl_CreateObjCommand()  +to create the top level database function.  It is through this handle +that the user can access all of the commands described in the Database +Commands section.  Internally, the database handle is sent as +the ClientData portion of the new command set so that all future +database calls access the appropriate handle. +

After parsing all of the optional arguments affecting the setup of the +database and making the appropriate calls to DB to manipulate those values, +we open the database for the user. It  translates to the +DB->open +method call after parsing all of the various optional arguments.  +We automatically set the DB_THREAD flag.  The arguments are: +

    +
  • +-- - Terminate the list of options and use remaining arguments as +the file or subdb names (thus allowing the use of filenames beginning with +a dash '-')
  • + +
  • +-btree - DB_BTREE database
  • + +
  • +-hash -  DB_HASH database
  • + +
  • +-recno  - DB_RECNO database
  • + +
  • +-queue - DB_QUEUE database
  • + +
  • +-create selects the DB_CREATE flag  to create underlying files
  • + +
  • +-excl selects the DB_EXCL flag  to exclusively create underlying +files
  • + +
  • +-nommap selects the DB_NOMMAP flag to forbid mmaping of files
  • + +
  • +-rdonly selects the DB_RDONLY flag for opening in read-only mode
  • + +
  • +-truncate selects the DB_TRUNCATE flag to truncate the database
  • + +
  • +-mode mode specifies the mode for created files
  • + +
  • +-errfile specifies the error file to use for this environment to +filename +by calling DB->set_errfile. +If +the file already exists then we will append to the end of the file
  • + +
  • +-dup selects the DB_DUP flag to permit duplicates in the database
  • + +
  • +-dupsort selects the DB_DUPSORT flag to support sorted duplicates
  • + +
  • +-recnum selects the DB_RECNUM flag to support record numbers in +btrees
  • + +
  • +-renumber selects the DB_RENUMBER flag to support mutable record +numbers
  • + +
  • +-revsplitoff selects the DB_REVSPLITOFF flag to suppress reverse +splitting of pages on deletion
  • + +
  • +-snapshot selects the DB_SNAPSHOT flag to support database snapshots
  • + +
  • +-extent sets the size of a Queue database extent to the given size +using +the DB->set_q_extentsize +method
  • + +
  • +-ffactor sets the hash table key density to the given density +using +the DB->set_h_ffactor +method
  • + +
  • +-nelem sets the hash table size estimate to the given size +using +the DB->set_h_nelem +method
  • + +
  • +-lorder sets the byte order for integers stored in the database +meta-data to the given order using the DB->set_lorder +method
  • + +
  • +-delim sets the delimiting byte for variable length records to +delim +using the DB->set_re_delim +method
  • + +
  • +-len sets the length of fixed-length records to len +using the DB->set_re_len +method
  • + +
  • +-pad sets the pad character used for fixed length records to +pad  +using the DB->set_re_pad method
  • + +
  • +-source sets the backing source file name to file +using the DB->set_re_source +method
  • + +
  • +-minkey sets the minimum number of keys per Btree page to minkey +using the DB->set_bt_minkey +method
  • + +
  • +-cachesize sets the size of the database cache to the size  +specified by gbytes and bytes, broken up into +ncaches +number of caches using the DB->set_cachesize +method
  • + +
  • +-pagesize sets the size of the database page to pagesize using +the DB->set_pagesize +method
  • + +
  • +filename indicates the name of the database
  • + +
  • +subdbname indicate the name of the sub-database
  • +
+ +
+
 berkdb upgrade [-dupsort] [-env env] [--] [filename] +

This command will invoke the DB->upgrade +function.  If the command is given the -env option, then we +will accordingly upgrade the database filename within the context of that +environment. The -dupsort option selects the DB_DUPSORT flag for +upgrading. The use of -- terminates the list of options, thus allowing +filenames beginning with a dash. +

+


> berkdb verify [-env env] [--] [filename] +

This command will invoke the DB->verify +function.  If the command is given the -env option, then we +will accordingly verify the database filename within the context of that +environment.  The use of -- terminates the list of options, +thus allowing filenames beginning with a dash. +

+


> db join [-nosort] db0.c0 db1.c0 ... +

This command will invoke the db_join +function.  After it successfully joins a database, we bind it to a +new Tcl command of the form dbN.cX, where X is an integer +starting at 0 (e.g. db2.c0, db3.c0, etc).  We use the Tcl_CreateObjCommand()  +to create the top level database function.  It is through this cursor +handle that the user can access the joined data items. +

The options are: +

    +
  • +-nosort - This flag causes DB not to sort the cursors based on the +number of data items they reference.  It results in the DB_JOIN_NOSORT +flag being set.
  • +
+ +
> db get_join [-nosort] {db key} {db key} ... +

This command performs a join operation on the keys specified and returns +a list of the joined {key data} pairs. +

The options are: +

    +
  • +-nosort This flag causes DB not to sort the cursors based on the +number of data items they reference.  It results in the DB_JOIN_NOSORT +flag being set.
  • +
+ +
> db keyrange [-txn id] key +

This command returns the range for the given key.  It returns +a list of 3 double elements of the form {less equal greater} +where less is the percentage of keys less than the given +key, equal is the percentage equal to the given key and greater +is the percentage greater than the given key.  If the -txn option +is specified it performs this operation under transaction protection. +
+


> db put +

The undocumented options are: +

    +
  • +-nodupdata This flag causes DB not to insert the key/data pair if +it already exists, that is, both the key and data items are already in +the database. The -nodupdata flag may only be specified if the underlying +database has been configured to support sorted duplicates.
  • +
+ +
> db stat +

The undocumented options are: +

    +
  • +-cachedcounts This flag causes DB to return the cached key/record +counts, similar to the DB_CACHED_COUNTS flags to DB->stat.
  • +
+ +
> dbc put +

The undocumented options are: +

    +
  • +-nodupdata This flag causes DB not to insert the key/data pair if +it already exists, that is, both the key and data items are already in +the database. The -nodupdata flag may only be specified if the underlying +database has been configured to support sorted duplicates.
  • +
+ + + diff --git a/db/tcl/docs/env.html b/db/tcl/docs/env.html new file mode 100644 index 000000000..a1bd08fd1 --- /dev/null +++ b/db/tcl/docs/env.html @@ -0,0 +1,303 @@ + + + + + + + + +

+Environment Commands

+Environments provide a structure for creating a consistent environment +for processes using one or more of the features of Berkeley DB.  Unlike +some of the database commands, the environment commands are very low level. +
+
+

The user may create and open a new DB environment  by invoking: +

> berkdb env +
    [-cdb] [-cdb_alldb] [-lock] [-log] [-txn [nosync]] +
    [-create] [-home directory] [-mode mode] +
    [-data_dir directory] [-log_dir directory] +[-tmp_dir directory] +
    [-nommap] [-private] [-recover] [-recover_fatal] +[-system_mem] [-errfile filename] +
    [-use_environ] [-use_environ_root] [-verbose +{which on|off}] +
    [-region_init] +
    [-cachesize {gbytes bytes ncaches}] +
    [-mmapsize size] +
    [-log_max max] +
    [-log_buffer size] +
    [-lock_conflict {nmodes {matrix}}] +
    [-lock_detect default|oldest|random|youngest] +
    [-lock_max max] +
    [-lock_max_locks max] +
    [-lock_max_lockers max] +
    [-lock_max_objects max] +
    [-txn_max max] +
    [-client_timeout seconds] +
    [-server_timeout seconds] +
    [-server hostname] +
  +

This command opens up an environment.   We automatically set +the DB_THREAD and the DB_INIT_MPOOL flags.  The arguments are: +

    +
  • +-cdb selects the DB_INIT_CDB flag for Concurrent Data Store
  • + +
  • +-cdb_alldb selects the DB_CDB_ALLDB flag for Concurrent Data Store
  • + +
  • +-lock selects the DB_INIT_LOCK flag for the locking subsystem
  • + +
  • +-log selects the DB_INIT_LOG flag for the logging subsystem
  • + +
  • +-txn selects the DB_INIT_TXN, DB_INIT_LOCK and DB_INIT_LOG flags +for the transaction subsystem.  If nosync is specified, then +it will also select DB_TXN_NOSYNC to indicate no flushes of log on commits
  • + +
  • +-create selects the DB_CREATE flag to create underlying files
  • + +
  • +-home directory selects the home directory of the environment
  • + +
  • +-data_dir directory selects the data file directory of the +environment by calling DBENV->set_data_dir.
  • + +
  • +-log_dir directory selects the log file directory of the +environment  by calling DBENV->set_lg_dir.
  • + +
  • +-tmp_dir directory selects the temporary file directory of +the environment  by calling DBENV->set_tmp_dir.
  • + +
  • +-mode mode sets the permissions of created files to mode
  • + +
  • +-nommap selects the DB_NOMMAP flag to disallow using mmap'ed files
  • + +
  • +-private selects the DB_PRIVATE flag for a private environment
  • + +
  • +-recover selects the DB_RECOVER flag for recovery
  • + +
  • +-recover_fatal selects the DB_RECOVER_FATAL flag for catastrophic +recovery
  • + +
  • +-system_mem selects the DB_SYSTEM_MEM flag to use system memory
  • + +
  • +-errfile specifies the error file to use for this environment to +filename +by calling DBENV->set_errfile. +If +the file already exists then we will append to the end of the file
  • + +
  • +-use_environ selects the DB_USE_ENVIRON flag to affect file naming
  • + +
  • +-use_environ_root selects the DB_USE_ENVIRON_ROOT flag to have the +root environment affect file naming
  • + +
  • +-verbose produces verbose error output for the given which subsystem, +using the DBENV->set_verbose +method.   See the description of verbose +below for valid which values
  • + +
  • +-region_init specifies that the user wants to page fault the region +in on startup using the DBENV->set_region_init +method call
  • + +
  • +-cachesize sets the size of the database cache to the size  +specified by gbytes and bytes, broken up into +ncaches +number of caches using the DBENV->set_cachesize +method
  • + +
  • +-mmapsize sets the size of the database page to size using +the DBENV->set_mp_mmapsize +method
  • + +
  • +-log_max sets the maximum size of the log file to max +using the DBENV->set_lg_max +call
  • + +
  • +-log_buffer sets the size of the log file in bytes to size +using the DBENV->set_lg_bsize +call
  • + +
  • +-lock_conflict sets the number of lock modes to nmodes +and sets the locking policy for those modes to the conflict_matrix +given using the DBENV->set_lk_conflict +method call
  • + +
  • +-lock_detect sets the deadlock detection policy to the given policy +using the DBENV->set_lk_detect +method call.  The policy choices are:
  • + +
      +
    • +default selects the DB_LOCK_DEFAULT policy for default detection
    • + +
    • +oldest selects DB_LOCK_OLDEST to abort the oldest locker on a deadlock
    • + +
    • +random selects DB_LOCK_RANDOM to abort a random locker on a deadlock
    • + +
    • +youngest selects DB_LOCK_YOUNGEST to abort the youngest locker on +a deadlock
    • +
    + +
  • +-lock_max sets the maximum size of the lock table to max using +the DBENV->set_lk_max +method call
  • + +
  • +-lock_max_locks sets the maximum number of locks to max using +the DBENV->set_lk_max_locks +method call
  • + +
  • +-lock_max_lockers sets the maximum number of locking entities to +max using the DBENV->set_lk_max_lockers +method call
  • + +
  • +-lock_max_objects sets the maximum number of simultaneously locked +objects to max using the DBENV->set_lk_max_objects +method call
  • + +
  • +-txn_max sets the maximum size of the transaction table to max +using the DBENV->set_txn_max +method call
  • + +
  • +-client_timeout sets the timeout value for the client waiting for +a reply from the server for RPC operations to seconds.
  • + +
  • +-server_timeout sets the timeout value for the server to determine +an idle client is gone to seconds.
  • + +
  • + -server specifies the hostname of the server +to connect to in the DBENV->set_server +call.
  • +
+This command will invoke the db_env_create +function.  After it successfully gets a handle to an environment, +we bind it to a new Tcl command of the form envX, where X +is an integer starting at  0 (e.g. env0, env1, etc).  +We use the Tcl_CreateObjCommand() to create the top level environment +command function.  It is through this handle that the user can access +all the commands described in the Environment +Commands section.  Internally, the handle we get back from DB +will be stored as the ClientData portion of the new command set +so that all future environment calls will have that handle readily available.  +Then we call the DBENV->open +method call and possibly some number of setup calls as described above. +

+


+
> <env> verbose which +on|off +

This command controls the use of debugging output for the environment.  +This command directly translates to a call to the DBENV->set_verbose +method call.  It returns either a 0 (for success), a DB error message +or it throws a Tcl error with a system message.  The user specifies +which +subsystem to control, and indicates whether debug messages should be turned +on +or off for that subsystem.  The value of which +must be one of the following: +

    +
  • +chkpt - Chooses the checkpointing code by using the DB_VERB_CHKPOINT +value
  • + +
  • +deadlock - Chooses the deadlocking code by using the DB_VERB_DEADLOCK +value
  • + +
  • +recovery - Chooses the recovery code by using the DB_VERB_RECOVERY +value
  • + +
  • +wait - Chooses the waitsfor code by using the DB_VERB_WAITSFOR value
  • +
+ +
+

> <env> close +

This command closes an environment and deletes the handle.  This +command directly translates to a call to the DBENV->close +method call.  It returns either a 0 (for success), a DB error message +or it throws a Tcl error with a system message. +

Additionally, since the handle is no longer valid, we will call Tcl_DeleteCommand() +so +that further uses of the handle will be dealt with properly by Tcl itself. +

Also, the close command will automatically abort any transactions +and close any mpool memory files.  As such +we must maintain a list of open transaction and mpool handles so that we +can call Tcl_DeleteCommand on those as well. +

+


+
> berkdb envremove [-data_dir directory] [-force] [-home +directory] +-log_dir directory] [-tmp_dir directory] [-use_environ] [-use_environ_root] +

This command removes the environment if it is not in use and deletes +the handle.  This command directly translates to a call to the DBENV->remove +method call.  It returns either a 0 (for success), a DB error message +or it throws a Tcl error with a system message.  The arguments are: +

    +
  • +-force selects the DB_FORCE flag to remove even if other processes +have the environment open
  • + +
  • +-home directory specifies the home directory of the environment
  • + +
  • +-data_dir directory selects the data file directory of the +environment by calling DBENV->set_data_dir.
  • + +
  • +-log_dir directory selects the log file directory of the +environment  by calling DBENV->set_lg_dir.
  • + +
  • +-tmp_dir directory selects the temporary file directory of +the environment  by calling DBENV->set_tmp_dir.
  • + +
  • +-use_environ selects the DB_USE_ENVIRON flag to affect file naming
  • + +
  • +-use_environ_root selects the DB_USE_ENVIRON_ROOT flag to affect +file naming
  • +
+ + + diff --git a/db/tcl/docs/historic.html b/db/tcl/docs/historic.html new file mode 100644 index 000000000..216dc456b --- /dev/null +++ b/db/tcl/docs/historic.html @@ -0,0 +1,168 @@ + + + + + + + + +

+Compatibility Commands

+The compatibility commands for old Dbm and Ndbm are described in the dbm +manpage. +

> berkdb dbminit filename +

This command will invoke the dbminit function.   Filename +is used as the name of the database. +

+


> berkdb dbmclose +

This command will invoke the dbmclose function. +

+


> berkdb fetch key +

This command will invoke the fetch function.   It will return +the data associated with the given key or a Tcl error. +

+


> berkdb store key data +

This command will invoke the store function.   It will store +the key/data pair.  It will return a 0 on success or +throw a Tcl error. +

+


> berkdb delete key +

This command will invoke the deletet function.   It will delete +the key from the database.  It will return a 0 on success +or throw a Tcl error. +

+


> berkdb firstkey +

This command will invoke the firstkey function.   It will +return the first key in the database or a Tcl error. +

+


> berkdb nextkey key +

This command will invoke the nextkey function.   It will return +the next key after the given key or a Tcl error. +

+


> berkdb hcreate nelem +

This command will invoke the hcreate function with nelem +elements.  It will return a 0 on success or a Tcl error. +

+


> berkdb hsearch key data action +

This command will invoke the hsearch function with key +and data.  The action must be either find +or enter.  If it is find, it will return the resultant +data.  If it is enter, it will return a 0 on success or a Tcl +error. +

+


> berkdb hdestroy +

This command will invoke the hdestroy function.  It will return +a 0. +


> berkdb ndbm_open [-create] [-rdonly] [-truncate] +[-mode +mode] [--] filename +

This command will invoke the dbm_open function.    After +it successfully gets a handle to a database, we bind it to a new Tcl command +of the form ndbmX, where X is an integer starting at 0 (e.g. +ndbm0, +ndbm1, etc).  We use the Tcl_CreateObjCommand()  to +create the top level database function.  It is through this handle +that the user can access all of the commands described below.  Internally, +the database handle is sent as the ClientData portion of the new +command set so that all future database calls access the appropriate handle. +

The arguments are: +

    +
  • +-- - Terminate the list of options and use remaining arguments as +the file or subdb names (thus allowing the use of filenames beginning with +a dash '-')
  • + +
  • +-create selects the O_CREAT flag  to create underlying files
  • + +
  • +-rdonly selects the O_RDONLY flag for opening in read-only mode
  • + +
  • +-truncate selects the O_TRUNC flag to truncate the database
  • + +
  • +-mode mode specifies the mode for created files
  • + +
  • +filename indicates the name of the database
  • +
+ +


+


+
> <ndbm> close +

This command closes the database and renders the handle invalid.   +This command directly translates to the dbm_close function call.  +It returns either a 0 (for success),  or it throws a Tcl error with +a system message. +

Additionally, since the handle is no longer valid, we will call Tcl_DeleteCommand() +so +that further uses of the handle will be dealt with properly by Tcl itself.  +


+
> <ndbm> clearerr +

This command clears errors  the database.   This command +directly translates to the dbm_clearerr function call.  It returns +either a 0 (for success),  or it throws a Tcl error with a system +message. +

+


+
> <ndbm> delete key +

This command deletes the key from thedatabase.   +This command directly translates to the dbm_delete function call.  +It returns either a 0 (for success),  or it throws a Tcl error with +a system message. +

+


+
> <ndbm> dirfno +

This command directly translates to the dbm_dirfno function call.  +It returns either resultts,  or it throws a Tcl error with a system +message. +

+


+
> <ndbm> error +

This command returns the last error.   This command directly +translates to the dbm_error function call.  It returns an error string.. +

+


+
> <ndbm> fetch key +

This command gets the given key from the database.   +This command directly translates to the dbm_fetch function call.  +It returns either the data,  or it throws a Tcl error with a system +message. +

+


+
> <ndbm> firstkey +

This command returns the first key in the database.   This +command directly translates to the dbm_firstkey function call.  It +returns either the key,  or it throws a Tcl error with a system message. +

+


+
> <ndbm> nextkey +

This command returns the next key in the database.   This +command directly translates to the dbm_nextkey function call.  It +returns either the key,  or it throws a Tcl error with a system message. +

+


+
> <ndbm> pagfno +

This command directly translates to the dbm_pagfno function call.  +It returns either resultts,  or it throws a Tcl error with a system +message. +
+


+
> <ndbm> rdonly +

This command changes the database to readonly.   This command +directly translates to the dbm_rdonly function call.  It returns either +a 0 (for success),  or it throws a Tcl error with a system message. +

+


+
> <ndbm> store key data insert|replace +

This command puts the given key and data +pair into the database.   This command directly translates to +the dbm_store function call.  It will either insert or replace +the data based on the action given in the third argument.  It returns +either a 0 (for success),  or it throws a Tcl error with a system +message. +
+


+ + diff --git a/db/tcl/docs/index.html b/db/tcl/docs/index.html new file mode 100644 index 000000000..2866c1e23 --- /dev/null +++ b/db/tcl/docs/index.html @@ -0,0 +1,47 @@ + + + + + + + + +
+

+Complete Tcl Interface for Berkeley DB

+ + + + + + diff --git a/db/tcl/docs/library.html b/db/tcl/docs/library.html new file mode 100644 index 000000000..abd656d8e --- /dev/null +++ b/db/tcl/docs/library.html @@ -0,0 +1,26 @@ + + + + + + + +
+

+Convenience Commands

+The convenience commands are provided for ease of use with the DB test +suite. +

> berkdb rand +

This command will invoke the rand function and return the random number. +

+


> berkdb random_int low high +

This command will invoke the rand function and return a number between +low +and high. +

+


+

> berkdb srand seed +

This command will invoke the srand function with the given seed +and return 0. +

+


diff --git a/db/tcl/docs/lock.html b/db/tcl/docs/lock.html new file mode 100644 index 000000000..87a20e9a6 --- /dev/null +++ b/db/tcl/docs/lock.html @@ -0,0 +1,187 @@ + + + + + + + + +

+Locking Commands

+Most locking commands work with the environment handle.  However, +when a user gets a lock we create a new lock handle that they then use +with in a similar manner to all the other handles to release the lock.  +We present the general locking functions first, and then those that manipulate +locks. +

> <env> lock_detect [-lock_conflict] [default|oldest|youngest|random] +

This command runs the deadlock detector.  It directly translates +to the lock_detect DB call.  +It returns either a 0 (for success), a DB error message or it throws a +Tcl error with a system message.  The first argument sets the policy +for deadlock as follows: +

    +
  • +default selects the DB_LOCK_DEFAULT policy for default detection +(default if not specified)
  • + +
  • +oldest selects DB_LOCK_OLDEST to abort the oldest locker on a deadlock
  • + +
  • +random selects DB_LOCK_RANDOM to abort a random locker on a deadlock
  • + +
  • +youngest selects DB_LOCK_YOUNGEST to abort the youngest locker on +a deadlock
  • +
+The second argument, -lock_conflict, selects the DB_LOCK_CONFLICT +flag to only run the detector if a lock conflict has occurred since the +last time the detector was run. +
+
> <env> lock_stat +

This command returns a list of name/value pairs where the names correspond +to the C-structure field names of DB_LOCK_STAT and the values are the data +returned.  This command is a direct translation of the lock_stat +DB call. +


+
> <env> lock_id +

This command returns a unique locker ID value.  It directly translates +to the lock_id DB call. +


+
> <env> lock_get [-nowait]lockmode +locker obj +

This command gets a lock. It will invoke the lock_get +function.  After it successfully gets a handle to a lock, we bind +it to a new Tcl command of the form $env.lockX, where X is +an integer starting at  0 (e.g. $env.lock0, $env.lock1, etc).  +We use the Tcl_CreateObjCommand() to create the top level locking +command function.  It is through this handle that the user can release +the lock.  Internally, the handle we get back from DB will be stored +as the ClientData portion of the new command set so that future +locking calls will have that handle readily available. +

The arguments are: +

    +
  • +locker specifies the locker ID returned from the lock_id +command
  • + +
  • +obj specifies an object to lock
  • + +
  • +the lock mode is specified as one of the following:
  • + +
      +
    • +ng specifies DB_LOCK_NG for not granted (always 0)
    • + +
    • +read specifies DB_LOCK_READ for a read (shared) lock
    • + +
    • +write specifies DB_LOCK_WRITE for an exclusive write lock
    • + +
    • +iwrite specifies DB_LOCK_IWRITE for intent for exclusive write lock
    • + +
    • +iread specifies DB_LOCK_IREAD for intent for shared read lock
    • + +
    • +iwr specifies DB_LOCK_IWR for intent for eread and write lock
    • +
    + +
  • +-nowait selects the DB_LOCK_NOWAIT to indicate that we do not want +to wait on the lock
  • +
+ +
+
> <lock> put +

This command releases the lock referenced by the command.  It is +a direct translation of the lock_put +function.  It returns either a 0 (for success), a DB error message +or it throws a Tcl error with a system message.  Additionally, since +the handle is no longer valid, we will call +Tcl_DeleteCommand() +so +that further uses of the handle will be dealt with properly by Tcl itself. +
+


+
> <env> lock_vec [-nowait] locker +{get|put|put_all|put_obj +[obj] [lockmode] [lock]} ... +

This command performs a series of lock calls.  It is a direct translation +of the lock_vec function.  +This command will return a list of the return values from each operation +specified in the argument list.  For the 'put' operations the entry +in the return value list is either a 0 (for success) or an error.  +For the 'get' operation, the entry is the lock widget handle, $env.lockN +(as described above in <env> lock_get) +or an error.  If an error occurs, the return list will contain the +return values for all the successful operations up the erroneous one and +the error code for that operation.  Subsequent operations will be +ignored. +

As for the other operations, if we are doing a 'get' we will create +the commands and if we are doing a 'put' we will have to delete the commands.  +Additionally, we will have to do this after the call to the DB lock_vec +and iterate over the results, creating and/or deleting Tcl commands.  +It is possible that we may return a lock widget from a get operation that +is considered invalid, if, for instance, there was a put_all operation +performed later in the vector of operations.  The arguments are: +

    +
  • +locker specifies the locker ID returned from the lock_id +command
  • + +
  • +-nowait selects the DB_LOCK_NOWAIT to indicate that we do not want +to wait on the lock
  • + +
  • +the lock vectors are tuple consisting of {an operation, lock object, lock +mode, lock handle} where what is required is based on the operation desired:
  • + +
      +
    • +get specifes DB_LOCK_GET to get a lock.  Requires a tuple {get +obj +mode} +where +mode +is:
    • + +
        +
      • +ng specifies DB_LOCK_NG for not granted (always 0)
      • + +
      • +read specifies DB_LOCK_READ for a read (shared) lock
      • + +
      • +write specifies DB_LOCK_WRITE for an exclusive write lock
      • + +
      • +iwrite specifies DB_LOCK_IWRITE for intent for exclusive write lock
      • + +
      • +iread specifies DB_LOCK_IREAD for intent for shared read lock
      • + +
      • +iwr specifies DB_LOCK_IWR for intent for eread and write lock
      • +
      + +
    • +put specifies DB_LOCK_PUT to release a lock.  +Requires a tuple {put lock}
    • + +
    • +put_all specifies DB_LOCK_PUT_ALL to release all locks held by locker.  +Requires a tuple {put_all}
    • + +
    • +put_obj specifies DB_LOCK_PUT_OBJ to release all locks held by locker +associated with the given obj.  Requires a tuple {put_obj +obj}
    • +
    +
diff --git a/db/tcl/docs/log.html b/db/tcl/docs/log.html new file mode 100644 index 000000000..35ecfc2f5 --- /dev/null +++ b/db/tcl/docs/log.html @@ -0,0 +1,142 @@ + + + + + + + + +

+Logging Commands

+Logging commands work from the environment handle to control the use of +the log files.  Log files are opened when the environment is opened +and closed when the environment is closed.  In all of the commands +in the logging subsystem that take or return a log sequence number, it +is of the form: +
{fileid offset} +
where the fileid is an identifier of the log file, as +returned from the log_get call. +

> <env> log_archive [-arch_abs] [-arch_data] [-arch_log] +

This command returns  a list of log files that are no longer in +use.  It is a direct call to the log_archive +function. The arguments are: +

    +
  • +-arch_abs selects DB_ARCH_ABS to return all pathnames as absolute +pathnames
  • + +
  • +-arch_data selects DB_ARCH_DATA to return a list of database files
  • + +
  • +-arch_log selects DB_ARCH_LOG to return a list of log files
  • +
+ +
+
> <env> log_compare lsn1 lsn2 +

This command compares two log sequence numbers, given as lsn1 +and lsn2.  It is a direct call to the log_compare +function.  It will return a -1, 0, 1 to indicate if lsn1 +is less than, equal to or greater than lsn2 respectively. +
+


+
> <env> log_file lsn +

This command returns  the file name associated with the given lsn.  +It is a direct call to the log_file +function. +
+


+
> <env> log_flush [lsn] +

This command  flushes the log up to the specified lsn +or flushes all records if none is given  It is a direct call to the +log_flush +function.  It returns either a 0 (for success), a DB error message +or it throws a Tcl error with a system message. +
+


+
> <env> log_get [-checkpoint] +[-current] [-first] [-last] [-next] [-prev] [-set lsn] +

This command retrieves a record from the log according to the lsn +given and returns it and the data.  It is a direct call to the log_get +function.  It is a way of implementing a manner of log iteration similar +to cursors.   +The information we return is similar to database information.  We +return a list where the first item is the LSN (which is a list itself) +and the second item is the data.  So it looks like, fully expanded, +{{fileid +offset} +data}.  +In the case where DB_NOTFOUND is returned, we return an empty list {}.  +All other errors return a Tcl error.  The arguments are: +

    +
  • +-checkpoint selects the DB_CHECKPOINT flag to return the LSN/data +pair of the last record written through log_put +with DB_CHECKPOINT specified
  • + +
  • +-current selects the DB_CURRENT flag to return the current record
  • + +
  • +-first selects the DB_FIRST flag to return the first record in the +log.
  • + +
  • +-last selects the DB_LAST flag to return the last record in the +log.
  • + +
  • +-next selects the DB_NEXT flag to return the next record in the +log.
  • + +
  • +-prev selects the DB_PREV flag to return the  previous record +in the log.
  • + +
  • +-set selects the DB_SET flag to return the record specified by the +given lsn
  • +
+ +
+
> <env> log_put [-checkpoint] +[-curlsn] [-flush] record +

This command stores a record into the log and returns +the LSN of the log record.  It is a direct call to the log_put +function.  It returns either an LSN or it throws a Tcl error with +a system message.  The arguments are: +

    +
  • +-checkpoint selects the DB_CHECKPOINT flag
  • + +
  • +-curlsn selects the DB_CURLSN flag to return the LSN of the next +record
  • + +
  • +-flush selects the DB_FLUSH flag to flush the log to disk.
  • +
+ +
+
> <env> log_register db +file +

This command registers a file and db with +the log manager.  It is a direct call to the log_register +function.  It returns either a 0 (for success), a DB error message +or it throws a Tcl error with a system message. +
+


+
> <env> log_unregister db +

This command unregisters the file specified by the database handle db +from the log manager.  It is a direct call to the log_unregister +function.  It returns either a 0 (for success), a DB error message +or it throws a Tcl error with a system message. +
+


+
> <env> log_stat +

This command returns  the statistics associated with the logging +subsystem.  It is a direct call to the log_stat +function.  It returns a list of name/value pairs of the DB_LOG_STAT +structure. + + diff --git a/db/tcl/docs/mpool.html b/db/tcl/docs/mpool.html new file mode 100644 index 000000000..666219306 --- /dev/null +++ b/db/tcl/docs/mpool.html @@ -0,0 +1,189 @@ + + + + + + + + +

+Memory Pool Commands

+Memory pools are used in a manner similar to the other subsystems.  +We create a handle to the pool and  then use it for a variety of operations.  +Some of the memory pool commands use the environment instead. Those are +presented first. +

> <env> mpool_stat +

This command returns  the statistics associated with the memory +pool subsystem.  It is a direct call to the memp_stat +function.  It returns a list of name/value pairs of the DB_MPOOL_STAT +structure. +
+


+
> <env> mpool_sync lsn +

This command flushes the memory pool for all pages with a log sequence +number less than lsn.  It is a direct call to the memp_sync  +function.  It returns either a 0 (for success), a DB error message +or it throws a Tcl error with a system message. +
+


+
> <env> mpool_trickle percent +

This command tells DB to ensure that at least percent +percent of the pages are clean by writing out enough to dirty pages to +achieve that percentage.  It is a direct call to the memp_trickle +function.  The command will return the number of pages actually written.  +It returns either the number of pages on success, or it throws a Tcl error +with a system message. +
+


+

> <env> mpool [-create] [-nommap] [-rdonly] [-mode mode] +-pagesize size [file] +

This command creates a new memory pool.  It invokes the memp_fopen +function.  After it successfully gets a handle to a memory pool, we +bind it to a new Tcl command of the form $env.mpX, where +X is an integer starting at  0 (e.g. $env.mp0, $env.mp1, etc).  +We use the Tcl_CreateObjCommand() to create the top level memory +pool functions.  It is through this handle that the user can manipulate +the pool.  Internally, the handle we get back from DB will be stored +as the ClientData portion of the new command set so that future +memory pool calls will have that handle readily available.  Additionally, +we need to maintain this handle in relation to the environment so that +if the user calls <env> close without closing +the memory pool we can properly clean up.  The arguments are: +

    +
  • +file is the name of the file to open
  • + +
  • +-create selects the DB_CREATE flag to create underlying file
  • + +
  • +-mode mode sets the permissions of created file to mode
  • + +
  • +-nommap selects the DB_NOMMAP flag to disallow using mmap'ed files
  • + +
  • +-pagesize sets the underlying file page size to size
  • + +
  • +-rdonly selects the DB_RDONLY flag for read only access
  • +
+ +
+
> <mp> close +

This command closes the memory pool.  It is a direct call to the +memp_close +function.  It returns either a 0 (for success), a DB error message +or it throws a Tcl error with a system message. +

Additionally, since the handle is no longer valid, we will call +Tcl_DeleteCommand() +so +that further uses of the handle will be dealt with properly by Tcl itself.  +We must also remove the reference to this handle from the environment.  +We will go through the list of pinned pages that were acquired by the get +command and +put them back. +


+
> <mp> fsync +

This command flushes all of the file's dirty pages to disk.  It +is a direct call to the memp_fsync +function.  It returns either a 0 (for success), a DB error message +or it throws a Tcl error with a system message. +


+
> <mp> get [-create] [-last] [-new] +[pgno] +

This command gets the  pgno page from the memory +pool.  It invokes the memp_fget +function and possibly the memp_fset +function if any options are chosen to set the page characteristics.  +After it successfully gets a handle to a page,  we bind it to and +return a new Tcl command of the form $env.mpN.pX, where X +is an integer starting at  0 (e.g. $env.mp0.p0, $env.mp1.p0, etc).  +We use the Tcl_CreateObjCommand() to create the top level page functions.  +It is through this handle that the user can manipulate the page.  +Internally, the handle we get back from DB will be stored as the ClientData +portion of the new command set.  We need to store this handle in  +relation to the memory pool handle so that if the memory pool is closed, +we will put back the pages (setting the discard +flag) and delete that set of commands. +

The arguments are: +

    +
  • +-create selects the DB_MPOOL_CREATE flag  to create the page +if it does not exist.
  • + +
  • +-last selects the DB_MPOOL_LAST flag to return the last page in +the file
  • + +
  • +-new selects the DB_MPOOL_NEW flag to create a new page
  • +
+ +
+
> <pg> pgnum +

This command returns the page number associated with this memory pool +page.  Primarily it will be used after an <mp> +get call. +
+


> <pg> pgsize +

This command returns the page size associated with this memory pool +page.  Primarily it will be used after an <mp> +get call. +
+


> <pg> set [-clean] [-dirty] [-discard] +

This command sets the characteristics of the page.  It is a direct +call to the memp_fset function.  +It returns either a 0 (for success), a DB error message or it throws a +Tcl error with a system message.  The arguments are: +

    +
  • +-clean selects the DB_MPOOL_CLEAN flag to indicate this is a clean +page
  • + +
  • +-dirty selects the DB_MPOOL_DIRTY flag to indicate this page should +be flushed before eviction
  • + +
  • +-discard selects the DB_MPOOL_DISCARD flag to indicate this page +is unimportant
  • +
+ +
+
> <pg> put [-clean] [-dirty] [-discard] +

This command will put back the page to the memory pool.  It is +a direct call to the memp_fput +function.  It returns either a 0 (for success), a DB error message +or it throws a Tcl error with a system message. Additionally, since the +handle is no longer valid, we will call +Tcl_DeleteCommand() +so that +further uses of the handle will be dealt with properly by Tcl itself.  +We must also remove the reference to this handle from the memory pool. +

The arguments are: +

    +
  • +-clean selects the DB_MPOOL_CLEAN flag to indicate this is a clean +page
  • + +
  • +-dirty selects the DB_MPOOL_DIRTY flag to indicate this page should +be flushed before eviction
  • + +
  • +-discard selects the DB_MPOOL_DISCARD flag to indicate this page +is unimportant
  • +
+ +
+
> <pg> init val|string +

This command initializes the page to the val given or +places the string given at the beginning of the page.  +It returns a 0 for success or it throws a Tcl error with an error message. +

+


+
> <pg> is_setto val|string +

This command verifies the page contains the val given +or checks that the string given is at the beginning of the page.  +It returns a 1 if the page is correctly set to the value and a 0 otherwise. diff --git a/db/tcl/docs/test.html b/db/tcl/docs/test.html new file mode 100644 index 000000000..10cf09efb --- /dev/null +++ b/db/tcl/docs/test.html @@ -0,0 +1,149 @@ + + + + + + + + +

+Debugging and Testing

+We have imported the debugging system from the old test suite into the +new interface to aid in debugging problems.  There are several variables +that are available both in gdb as globals to the C code, and variables +in Tcl that the user can set.  These variables are linked together +so that changes in one venue are reflected in the other.  The names +of the variables have been modified a bit to reduce the likelihood +
of namespace trampling.  We have added a double underscore to +all the names. +

The variables are all initialized to zero (0) thus resulting in debugging +being turned off.  The purpose of the debugging, fundamentally, is +to allow the user to set a breakpoint prior to making a DB call.  +This breakpoint is set in the __db_loadme() function.  The +user may selectively turn on various debugging areas each controlled by +a separate variable (note they all have two (2) underscores prepended to +the name): +

    +
  • +__debug_on - Turns on the debugging system.  This must be on +for any debugging to occur
  • + +
  • +__debug_print - Turns on printing a debug count statement on each +call
  • + +
  • +__debug_test - Hits the breakpoint in __db_loadme on the +specific iteration
  • + +
  • +__debug_stop - Hits the breakpoint in __db_loadme on every +(or the next) iteration
  • +
+Note to developers:  Anyone extending this interface must place +a call to _debug_check() (no arguments) before every call into the +DB library. +

There is also a command available that will force a call to the _debug_check +function. +

> berkdb debug_check +

+


+
For testing purposes we have added several hooks into the DB library +and a small interface into the environment and/or database commands to +manipulate the hooks.  This command interface and the hooks and everything +that goes with it is only enabled when the test option is configured into +DB. +

> <env> test copy location +
> <db> test copy location +
> <env> test abort location +
> <db> test abort location +

In order to test recovery we need to be able to abort the creation or +deletion process at various points.  Also we want to invoke a copy +function to copy the database file(s)  at various points as well so +that we can obtain before/after snapshots of the databases.  The interface +provides the test command to specify a location where we +wish to invoke a copy or an abort.  The command is available +from either the environment or the database for convenience.  The +location +can be one of the following: +

    +
  • +none - Clears the location
  • + +
  • +preopen - Sets the location prior to the __os_open call in the creation +process
  • + +
  • +postopen - Sets the location to immediately following the __os_open +call in creation
  • + +
  • +postlogmeta - Sets the location to immediately following the __db_log_page +call to log the meta data in creation.  Only valid for Btree.
  • + +
  • +postlog - Sets the location to immediately following the last (or +only) __db_log_page call in creation.
  • + +
  • +postsync - Sets the location to immediately following the sync of +the log page in creation.
  • + +
  • +prerename - Sets the location prior to the __os_rename call in the +deletion process.
  • + +
  • +postrename - Sets the location to immediately following the __os_rename +call in deletion
  • +
+ +
+
> <env> mutex mode nitems +

This command creates a mutex region for testing.  It sets the mode +of the region to mode and sets up for nitems +number of mutex entries.  After we successfully get a handle to a +mutex we create a command of the form $env.mutexX, where +X is an integer starting at  0 (e.g. $env.mutex0, $env.mutex1, +etc).   +We use the Tcl_CreateObjCommand()  to create the top level +mutex function.  It is through this handle that the user can access +all of the commands described below.  Internally, the mutex handle +is sent as the ClientData portion of the new command set so that +all future mutex calls access the appropriate handle. +

+


> <mutex> close +

This command closes the mutex and renders the handle invalid.   +This command directly translates to the __db_r_detach function call.  +It returns either a 0 (for success),  or it throws a Tcl error with +a system message. +

Additionally, since the handle is no longer valid, we will call Tcl_DeleteCommand() +so +that further uses of the handle will be dealt with properly by Tcl itself.  +


> <mutex> get id +

This command locks the mutex identified by id.  It +returns either a 0 (for success),  or it throws a Tcl error with a +system message. +
+


> <mutex> release id +

This command releases the mutex identified by id.  +It returns either a 0 (for success),  or it throws a Tcl error with +a system message. +
+


> <mutex> getval id +

This command gets the value stored for the mutex identified by id.  +It returns either the value,  or it throws a Tcl error with a system +message. +
+


> <mutex> setval id val +

This command sets the value stored for the mutex identified by id +to +val.  +It returns either a 0 (for success),  or it throws a Tcl error with +a system message. +
+


+
  + + diff --git a/db/tcl/docs/txn.html b/db/tcl/docs/txn.html new file mode 100644 index 000000000..863c9a875 --- /dev/null +++ b/db/tcl/docs/txn.html @@ -0,0 +1,56 @@ + + + + + + + + +

+Transaction Commands

+Transactions are used in a manner similar to the other subsystems.  +We create a handle to the transaction and  then use it for a variety +of operations.  Some of the transaction commands use the environment +instead.  Those are presented first.  The transaction command +handle returned is the handle used by the various commands that can be +transaction protected, such as cursors.
+ +
+

> <env> txn_checkpoint [-kbyte kb] [-min min] +

This command causes a checkpoint of the transaction region.  It +is a direct translation of the txn_checkpoint +function.  +It returns either a 0 (for success), a DB error message or it throws a +Tcl error with a system message.  The arguments are: +

    +
  • +-kbyte causes the checkpoint to occur only if kb kilobytes +of log data has been written since the last checkpoint
  • + +
  • +-min causes the checkpoint to occur only if min minutes +have passed since the last checkpoint
  • +
+ +
+
> <env> txn_stat +

This command returns transaction statistics.  It is a direct translation +of the txn_stat function.  +It will return a list of name/value pairs that correspond to the DB_TXN_STAT +structure. +


+
>  <txn> id +

This command returns the transaction id.  It is a direct call to +the txn_id function.  The +typical use of this identifier is as the locker value for +the lock_get and lock_vec +calls. +


+
> <txn> prepare +

This command initiates a two-phase commit.  It is a direct call +to the txn_prepare function.  +It returns either a 0 (for success), a DB error message or it throws a +Tcl error with a system message. +


+ + diff --git a/db/tcl/tcl_compat.c b/db/tcl/tcl_compat.c new file mode 100644 index 000000000..41caee95c --- /dev/null +++ b/db/tcl/tcl_compat.c @@ -0,0 +1,1055 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: tcl_compat.c,v 11.22 2001/01/11 18:19:55 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#include +#endif + +#define DB_DBM_HSEARCH 1 + +#include "db_int.h" +#include "tcl_db.h" + +/* + * Prototypes for procedures defined later in this file: + */ +static int mutex_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*)); + +/* + * bdb_HCommand -- + * Implements h* functions. + * + * PUBLIC: int bdb_HCommand __P((Tcl_Interp *, int, Tcl_Obj * CONST*)); + */ +int +bdb_HCommand(interp, objc, objv) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ +{ + static char *hcmds[] = { + "hcreate", + "hdestroy", + "hsearch", + NULL + }; + enum hcmds { + HHCREATE, + HHDESTROY, + HHSEARCH + }; + static char *srchacts[] = { + "enter", + "find", + NULL + }; + enum srchacts { + ACT_ENTER, + ACT_FIND + }; + ENTRY item, *hres; + ACTION action; + int actindex, cmdindex, nelem, result, ret; + Tcl_Obj *res; + + result = TCL_OK; + /* + * Get the command name index from the object based on the cmds + * defined above. This SHOULD NOT fail because we already checked + * in the 'berkdb' command. + */ + if (Tcl_GetIndexFromObj(interp, + objv[1], hcmds, "command", TCL_EXACT, &cmdindex) != TCL_OK) + return (IS_HELP(objv[1])); + + res = NULL; + switch ((enum hcmds)cmdindex) { + case HHCREATE: + /* + * Must be 1 arg, nelem. Error if not. + */ + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "nelem"); + return (TCL_ERROR); + } + result = Tcl_GetIntFromObj(interp, objv[2], &nelem); + if (result == TCL_OK) { + _debug_check(); + ret = hcreate(nelem) == 0 ? 1: 0; + _ReturnSetup(interp, ret, "hcreate"); + } + break; + case HHSEARCH: + /* + * 3 args for this. Error if different. + */ + if (objc != 5) { + Tcl_WrongNumArgs(interp, 2, objv, "key data action"); + return (TCL_ERROR); + } + item.key = Tcl_GetStringFromObj(objv[2], NULL); + item.data = Tcl_GetStringFromObj(objv[3], NULL); + action = 0; + if (Tcl_GetIndexFromObj(interp, objv[4], srchacts, + "action", TCL_EXACT, &actindex) != TCL_OK) + return (IS_HELP(objv[4])); + switch ((enum srchacts)actindex) { + case ACT_FIND: + action = FIND; + break; + case ACT_ENTER: + action = ENTER; + break; + } + _debug_check(); + hres = hsearch(item, action); + if (hres == NULL) + Tcl_SetResult(interp, "-1", TCL_STATIC); + else if (action == FIND) + Tcl_SetResult(interp, (char *)hres->data, TCL_STATIC); + else + /* action is ENTER */ + Tcl_SetResult(interp, "0", TCL_STATIC); + + break; + case HHDESTROY: + /* + * No args for this. Error if there are some. + */ + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + _debug_check(); + (void)hdestroy(); + res = Tcl_NewIntObj(0); + break; + } + /* + * Only set result if we have a res. Otherwise, lower + * functions have already done so. + */ + if (result == TCL_OK && res) + Tcl_SetObjResult(interp, res); + return (result); +} + +/* + * + * bdb_NdbmOpen -- + * Opens an ndbm database. + * + * PUBLIC: #if DB_DBM_HSEARCH != 0 + * PUBLIC: int bdb_NdbmOpen __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DBM **)); + * PUBLIC: #endif + */ +int +bdb_NdbmOpen(interp, objc, objv, dbpp) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DBM **dbpp; /* Dbm pointer */ +{ + static char *ndbopen[] = { + "-create", + "-mode", + "-rdonly", + "-truncate", + "--", + NULL + }; + enum ndbopen { + NDB_CREATE, + NDB_MODE, + NDB_RDONLY, + NDB_TRUNC, + NDB_ENDARG + }; + + u_int32_t open_flags; + int endarg, i, mode, optindex, read_only, result; + char *arg, *db; + + result = TCL_OK; + open_flags = 0; + endarg = mode = 0; + read_only = 0; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 2, objv, "?args?"); + return (TCL_ERROR); + } + + /* + * Get the option name index from the object based on the args + * defined above. + */ + i = 2; + while (i < objc) { + if (Tcl_GetIndexFromObj(interp, objv[i], ndbopen, "option", + TCL_EXACT, &optindex) != TCL_OK) { + arg = Tcl_GetStringFromObj(objv[i], NULL); + if (arg[0] == '-') { + result = IS_HELP(objv[i]); + goto error; + } else + Tcl_ResetResult(interp); + break; + } + i++; + switch ((enum ndbopen)optindex) { + case NDB_CREATE: + open_flags |= O_CREAT; + break; + case NDB_RDONLY: + read_only = 1; + break; + case NDB_TRUNC: + open_flags |= O_TRUNC; + break; + case NDB_MODE: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-mode mode?"); + result = TCL_ERROR; + break; + } + /* + * Don't need to check result here because + * if TCL_ERROR, the error message is already + * set up, and we'll bail out below. If ok, + * the mode is set and we go on. + */ + result = Tcl_GetIntFromObj(interp, objv[i++], &mode); + break; + case NDB_ENDARG: + endarg = 1; + break; + } /* switch */ + + /* + * If, at any time, parsing the args we get an error, + * bail out and return. + */ + if (result != TCL_OK) + goto error; + if (endarg) + break; + } + if (result != TCL_OK) + goto error; + + /* + * Any args we have left, (better be 0, or 1 left) is a + * file name. If we have 0, then an in-memory db. If + * there is 1, a db name. + */ + db = NULL; + if (i != objc && i != objc - 1) { + Tcl_WrongNumArgs(interp, 2, objv, "?args? ?file?"); + result = TCL_ERROR; + goto error; + } + if (i != objc) + db = Tcl_GetStringFromObj(objv[objc - 1], NULL); + + /* + * When we get here, we have already parsed all of our args + * and made all our calls to set up the database. Everything + * is okay so far, no errors, if we get here. + * + * Now open the database. + */ + if (read_only) + open_flags |= O_RDONLY; + else + open_flags |= O_RDWR; + _debug_check(); + if ((*dbpp = dbm_open(db, open_flags, mode)) == NULL) { + result = _ReturnSetup(interp, Tcl_GetErrno(), "db open"); + goto error; + } + return (TCL_OK); + +error: + *dbpp = NULL; + return (result); +} + +/* + * bdb_DbmCommand -- + * Implements "dbm" commands. + * + * PUBLIC: #if DB_DBM_HSEARCH != 0 + * PUBLIC: int bdb_DbmCommand + * PUBLIC: __P((Tcl_Interp *, int, Tcl_Obj * CONST*, int, DBM *)); + * PUBLIC: #endif + */ +int +bdb_DbmCommand(interp, objc, objv, flag, dbm) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + int flag; /* Which db interface */ + DBM *dbm; /* DBM pointer */ +{ + static char *dbmcmds[] = { + "dbmclose", + "dbminit", + "delete", + "fetch", + "firstkey", + "nextkey", + "store", + NULL + }; + enum dbmcmds { + DBMCLOSE, + DBMINIT, + DBMDELETE, + DBMFETCH, + DBMFIRST, + DBMNEXT, + DBMSTORE + }; + static char *stflag[] = { + "insert", "replace", + NULL + }; + enum stflag { + STINSERT, STREPLACE + }; + datum key, data; + int cmdindex, stindex, result, ret; + char *name, *t; + + result = TCL_OK; + /* + * Get the command name index from the object based on the cmds + * defined above. This SHOULD NOT fail because we already checked + * in the 'berkdb' command. + */ + if (Tcl_GetIndexFromObj(interp, + objv[1], dbmcmds, "command", TCL_EXACT, &cmdindex) != TCL_OK) + return (IS_HELP(objv[1])); + + switch ((enum dbmcmds)cmdindex) { + case DBMCLOSE: + /* + * No arg for this. Error if different. + */ + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + _debug_check(); + if (flag == DBTCL_DBM) + ret = dbmclose(); + else { + Tcl_SetResult(interp, + "Bad interface flag for command", TCL_STATIC); + return (TCL_ERROR); + } + _ReturnSetup(interp, ret, "dbmclose"); + break; + case DBMINIT: + /* + * Must be 1 arg - file. + */ + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "file"); + return (TCL_ERROR); + } + name = Tcl_GetStringFromObj(objv[2], NULL); + if (flag == DBTCL_DBM) + ret = dbminit(name); + else { + Tcl_SetResult(interp, "Bad interface flag for command", + TCL_STATIC); + return (TCL_ERROR); + } + _ReturnSetup(interp, ret, "dbminit"); + break; + case DBMFETCH: + /* + * 1 arg for this. Error if different. + */ + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "key"); + return (TCL_ERROR); + } + key.dptr = (char *)Tcl_GetByteArrayFromObj(objv[2], &key.dsize); + _debug_check(); + if (flag == DBTCL_DBM) + data = fetch(key); + else if (flag == DBTCL_NDBM) + data = dbm_fetch(dbm, key); + else { + Tcl_SetResult(interp, + "Bad interface flag for command", TCL_STATIC); + return (TCL_ERROR); + } + if (data.dptr == NULL || + (ret = __os_malloc(NULL, data.dsize + 1, NULL, &t)) != 0) + Tcl_SetResult(interp, "-1", TCL_STATIC); + else { + memcpy(t, data.dptr, data.dsize); + t[data.dsize] = '\0'; + Tcl_SetResult(interp, t, TCL_VOLATILE); + __os_free(t, data.dsize + 1); + } + break; + case DBMSTORE: + /* + * 2 args for this. Error if different. + */ + if (objc != 4 && flag == DBTCL_DBM) { + Tcl_WrongNumArgs(interp, 2, objv, "key data"); + return (TCL_ERROR); + } + if (objc != 5 && flag == DBTCL_NDBM) { + Tcl_WrongNumArgs(interp, 2, objv, "key data action"); + return (TCL_ERROR); + } + key.dptr = (char *)Tcl_GetByteArrayFromObj(objv[2], &key.dsize); + data.dptr = + (char *)Tcl_GetByteArrayFromObj(objv[3], &data.dsize); + _debug_check(); + if (flag == DBTCL_DBM) + ret = store(key, data); + else if (flag == DBTCL_NDBM) { + if (Tcl_GetIndexFromObj(interp, objv[4], stflag, + "flag", TCL_EXACT, &stindex) != TCL_OK) + return (IS_HELP(objv[4])); + switch ((enum stflag)stindex) { + case STINSERT: + flag = DBM_INSERT; + break; + case STREPLACE: + flag = DBM_REPLACE; + break; + } + ret = dbm_store(dbm, key, data, flag); + } else { + Tcl_SetResult(interp, + "Bad interface flag for command", TCL_STATIC); + return (TCL_ERROR); + } + _ReturnSetup(interp, ret, "store"); + break; + case DBMDELETE: + /* + * 1 arg for this. Error if different. + */ + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "key"); + return (TCL_ERROR); + } + key.dptr = (char *)Tcl_GetByteArrayFromObj(objv[2], &key.dsize); + _debug_check(); + if (flag == DBTCL_DBM) + ret = delete(key); + else if (flag == DBTCL_NDBM) + ret = dbm_delete(dbm, key); + else { + Tcl_SetResult(interp, + "Bad interface flag for command", TCL_STATIC); + return (TCL_ERROR); + } + _ReturnSetup(interp, ret, "delete"); + break; + case DBMFIRST: + /* + * No arg for this. Error if different. + */ + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + _debug_check(); + if (flag == DBTCL_DBM) + key = firstkey(); + else if (flag == DBTCL_NDBM) + key = dbm_firstkey(dbm); + else { + Tcl_SetResult(interp, + "Bad interface flag for command", TCL_STATIC); + return (TCL_ERROR); + } + if (key.dptr == NULL || + (ret = __os_malloc(NULL, key.dsize + 1, NULL, &t)) != 0) + Tcl_SetResult(interp, "-1", TCL_STATIC); + else { + memcpy(t, key.dptr, key.dsize); + t[key.dsize] = '\0'; + Tcl_SetResult(interp, t, TCL_VOLATILE); + __os_free(t, key.dsize + 1); + } + break; + case DBMNEXT: + /* + * 0 or 1 arg for this. Error if different. + */ + _debug_check(); + if (flag == DBTCL_DBM) { + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + key.dptr = (char *) + Tcl_GetByteArrayFromObj(objv[2], &key.dsize); + data = nextkey(key); + } else if (flag == DBTCL_NDBM) { + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + data = dbm_nextkey(dbm); + } else { + Tcl_SetResult(interp, + "Bad interface flag for command", TCL_STATIC); + return (TCL_ERROR); + } + if (data.dptr == NULL || + (ret = __os_malloc(NULL, data.dsize + 1, NULL, &t)) != 0) + Tcl_SetResult(interp, "-1", TCL_STATIC); + else { + memcpy(t, data.dptr, data.dsize); + t[data.dsize] = '\0'; + Tcl_SetResult(interp, t, TCL_VOLATILE); + __os_free(t, data.dsize + 1); + } + break; + } + return (result); +} + +/* + * ndbm_Cmd -- + * Implements the "ndbm" widget. + * + * PUBLIC: int ndbm_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*)); + */ +int +ndbm_Cmd(clientData, interp, objc, objv) + ClientData clientData; /* DB handle */ + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ +{ + static char *ndbcmds[] = { + "clearerr", + "close", + "delete", + "dirfno", + "error", + "fetch", + "firstkey", + "nextkey", + "pagfno", + "rdonly", + "store", + NULL + }; + enum ndbcmds { + NDBCLRERR, + NDBCLOSE, + NDBDELETE, + NDBDIRFNO, + NDBERR, + NDBFETCH, + NDBFIRST, + NDBNEXT, + NDBPAGFNO, + NDBRDONLY, + NDBSTORE + }; + DBM *dbp; + DBTCL_INFO *dbip; + Tcl_Obj *res; + int cmdindex, result, ret; + + Tcl_ResetResult(interp); + dbp = (DBM *)clientData; + dbip = _PtrToInfo((void *)dbp); + result = TCL_OK; + if (objc <= 1) { + Tcl_WrongNumArgs(interp, 1, objv, "command cmdargs"); + return (TCL_ERROR); + } + if (dbp == NULL) { + Tcl_SetResult(interp, "NULL db pointer", TCL_STATIC); + return (TCL_ERROR); + } + if (dbip == NULL) { + Tcl_SetResult(interp, "NULL db info pointer", TCL_STATIC); + return (TCL_ERROR); + } + + /* + * Get the command name index from the object based on the dbcmds + * defined above. + */ + if (Tcl_GetIndexFromObj(interp, + objv[1], ndbcmds, "command", TCL_EXACT, &cmdindex) != TCL_OK) + return (IS_HELP(objv[1])); + + res = NULL; + switch ((enum ndbcmds)cmdindex) { + case NDBCLOSE: + _debug_check(); + dbm_close(dbp); + (void)Tcl_DeleteCommand(interp, dbip->i_name); + _DeleteInfo(dbip); + res = Tcl_NewIntObj(0); + break; + case NDBDELETE: + case NDBFETCH: + case NDBFIRST: + case NDBNEXT: + case NDBSTORE: + result = bdb_DbmCommand(interp, objc, objv, DBTCL_NDBM, dbp); + break; + case NDBCLRERR: + /* + * No args for this. Error if there are some. + */ + if (objc > 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + _debug_check(); + ret = dbm_clearerr(dbp); + if (ret) + _ReturnSetup(interp, ret, "clearerr"); + else + res = Tcl_NewIntObj(ret); + break; + case NDBDIRFNO: + /* + * No args for this. Error if there are some. + */ + if (objc > 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + _debug_check(); + ret = dbm_dirfno(dbp); + res = Tcl_NewIntObj(ret); + break; + case NDBPAGFNO: + /* + * No args for this. Error if there are some. + */ + if (objc > 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + _debug_check(); + ret = dbm_pagfno(dbp); + res = Tcl_NewIntObj(ret); + break; + case NDBERR: + /* + * No args for this. Error if there are some. + */ + if (objc > 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + _debug_check(); + ret = dbm_error(dbp); + Tcl_SetErrno(ret); + Tcl_SetResult(interp, Tcl_PosixError(interp), TCL_STATIC); + break; + case NDBRDONLY: + /* + * No args for this. Error if there are some. + */ + if (objc > 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + _debug_check(); + ret = dbm_rdonly(dbp); + if (ret) + _ReturnSetup(interp, ret, "rdonly"); + else + res = Tcl_NewIntObj(ret); + break; + } + /* + * Only set result if we have a res. Otherwise, lower + * functions have already done so. + */ + if (result == TCL_OK && res) + Tcl_SetObjResult(interp, res); + return (result); +} + +/* + * bdb_RandCommand -- + * Implements rand* functions. + * + * PUBLIC: int bdb_RandCommand __P((Tcl_Interp *, int, Tcl_Obj * CONST*)); + */ +int +bdb_RandCommand(interp, objc, objv) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ +{ + static char *rcmds[] = { + "rand", "random_int", "srand", + NULL + }; + enum rcmds { + RRAND, RRAND_INT, RSRAND + }; + long t; + int cmdindex, hi, lo, result, ret; + Tcl_Obj *res; + char msg[MSG_SIZE]; + + result = TCL_OK; + /* + * Get the command name index from the object based on the cmds + * defined above. This SHOULD NOT fail because we already checked + * in the 'berkdb' command. + */ + if (Tcl_GetIndexFromObj(interp, + objv[1], rcmds, "command", TCL_EXACT, &cmdindex) != TCL_OK) + return (IS_HELP(objv[1])); + + res = NULL; + switch ((enum rcmds)cmdindex) { + case RRAND: + /* + * Must be 0 args. Error if different. + */ + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + ret = rand(); + res = Tcl_NewIntObj(ret); + break; + case RRAND_INT: + /* + * Must be 4 args. Error if different. + */ + if (objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "lo hi"); + return (TCL_ERROR); + } + result = Tcl_GetIntFromObj(interp, objv[2], &lo); + if (result != TCL_OK) + break; + result = Tcl_GetIntFromObj(interp, objv[3], &hi); + if (result == TCL_OK) { +#ifndef RAND_MAX +#define RAND_MAX 0x7fffffff +#endif + t = rand(); + if (t > RAND_MAX) { + snprintf(msg, MSG_SIZE, + "Max random is higher than %ld\n", + (long)RAND_MAX); + Tcl_SetResult(interp, msg, TCL_VOLATILE); + result = TCL_ERROR; + break; + } + _debug_check(); + ret = (int)(((double)t / ((double)(RAND_MAX) + 1)) * + (hi - lo + 1)); + ret += lo; + res = Tcl_NewIntObj(ret); + } + break; + case RSRAND: + /* + * Must be 1 arg. Error if different. + */ + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "seed"); + return (TCL_ERROR); + } + result = Tcl_GetIntFromObj(interp, objv[2], &lo); + if (result == TCL_OK) { + srand((u_int)lo); + res = Tcl_NewIntObj(0); + } + break; + } + /* + * Only set result if we have a res. Otherwise, lower + * functions have already done so. + */ + if (result == TCL_OK && res) + Tcl_SetObjResult(interp, res); + return (result); +} + +/* + * + * tcl_Mutex -- + * Opens an env mutex. + * + * PUBLIC: int tcl_Mutex __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *, + * PUBLIC: DBTCL_INFO *)); + */ +int +tcl_Mutex(interp, objc, objv, envp, envip) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB_ENV *envp; /* Environment pointer */ + DBTCL_INFO *envip; /* Info pointer */ +{ + DBTCL_INFO *ip; + Tcl_Obj *res; + _MUTEX_DATA *md; + int i, mode, nitems, result, ret; + char newname[MSG_SIZE]; + + md = NULL; + result = TCL_OK; + mode = nitems = ret = 0; + memset(newname, 0, MSG_SIZE); + + if (objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "mode nitems"); + return (TCL_ERROR); + } + result = Tcl_GetIntFromObj(interp, objv[2], &mode); + if (result != TCL_OK) + return (TCL_ERROR); + result = Tcl_GetIntFromObj(interp, objv[3], &nitems); + if (result != TCL_OK) + return (TCL_ERROR); + + snprintf(newname, sizeof(newname), + "%s.mutex%d", envip->i_name, envip->i_envmutexid); + ip = _NewInfo(interp, NULL, newname, I_MUTEX); + if (ip == NULL) { + Tcl_SetResult(interp, "Could not set up info", + TCL_STATIC); + return (TCL_ERROR); + } + /* + * Set up mutex. + */ + /* + * Map in the region. + * + * XXX + * We don't bother doing this "right", i.e., using the shalloc + * functions, just grab some memory knowing that it's correctly + * aligned. + */ + _debug_check(); + if (__os_calloc(NULL, 1, sizeof(_MUTEX_DATA), &md) != 0) + goto posixout; + md->env = envp; + md->n_mutex = nitems; + md->size = sizeof(_MUTEX_ENTRY) * nitems; + + md->reginfo.type = REGION_TYPE_MUTEX; + md->reginfo.id = INVALID_REGION_TYPE; + md->reginfo.mode = mode; + md->reginfo.flags = REGION_CREATE_OK | REGION_JOIN_OK; + if ((ret = __db_r_attach(envp, &md->reginfo, md->size)) != 0) + goto posixout; + md->marray = md->reginfo.addr; + + /* Initialize a created region. */ + if (F_ISSET(&md->reginfo, REGION_CREATE)) + for (i = 0; i < nitems; i++) { + md->marray[i].val = 0; + if ((ret = + __db_mutex_init(envp, &md->marray[i].m, i, 0)) != 0) + goto posixout; + } + R_UNLOCK(envp, &md->reginfo); + + /* + * Success. Set up return. Set up new info + * and command widget for this mutex. + */ + envip->i_envmutexid++; + ip->i_parent = envip; + _SetInfoData(ip, md); + Tcl_CreateObjCommand(interp, newname, + (Tcl_ObjCmdProc *)mutex_Cmd, (ClientData)md, NULL); + res = Tcl_NewStringObj(newname, strlen(newname)); + Tcl_SetObjResult(interp, res); + + return (TCL_OK); + +posixout: + if (ret > 0) + Tcl_PosixError(interp); + result = _ReturnSetup(interp, ret, "mutex"); + _DeleteInfo(ip); + + if (md != NULL) { + if (md->reginfo.addr != NULL) + (void)__db_r_detach(md->env, + &md->reginfo, F_ISSET(&md->reginfo, REGION_CREATE)); + __os_free(md, sizeof(*md)); + } + return (result); +} + +/* + * mutex_Cmd -- + * Implements the "mutex" widget. + */ +static int +mutex_Cmd(clientData, interp, objc, objv) + ClientData clientData; /* Mutex handle */ + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ +{ + static char *mxcmds[] = { + "close", + "get", + "getval", + "release", + "setval", + NULL + }; + enum mxcmds { + MXCLOSE, + MXGET, + MXGETVAL, + MXRELE, + MXSETVAL + }; + DB_ENV *dbenv; + DBTCL_INFO *envip, *mpip; + _MUTEX_DATA *mp; + Tcl_Obj *res; + int cmdindex, id, result, newval; + + Tcl_ResetResult(interp); + mp = (_MUTEX_DATA *)clientData; + mpip = _PtrToInfo((void *)mp); + envip = mpip->i_parent; + dbenv = envip->i_envp; + result = TCL_OK; + + if (mp == NULL) { + Tcl_SetResult(interp, "NULL mp pointer", TCL_STATIC); + return (TCL_ERROR); + } + if (mpip == NULL) { + Tcl_SetResult(interp, "NULL mp info pointer", TCL_STATIC); + return (TCL_ERROR); + } + + /* + * Get the command name index from the object based on the dbcmds + * defined above. + */ + if (Tcl_GetIndexFromObj(interp, + objv[1], mxcmds, "command", TCL_EXACT, &cmdindex) != TCL_OK) + return (IS_HELP(objv[1])); + + res = NULL; + switch ((enum mxcmds)cmdindex) { + case MXCLOSE: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return (TCL_ERROR); + } + _debug_check(); + (void)__db_r_detach(mp->env, &mp->reginfo, 0); + res = Tcl_NewIntObj(0); + (void)Tcl_DeleteCommand(interp, mpip->i_name); + _DeleteInfo(mpip); + __os_free(mp, sizeof(*mp)); + break; + case MXRELE: + /* + * Check for 1 arg. Error if different. + */ + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "id"); + return (TCL_ERROR); + } + result = Tcl_GetIntFromObj(interp, objv[2], &id); + if (result != TCL_OK) + break; + MUTEX_UNLOCK(dbenv, &mp->marray[id].m); + res = Tcl_NewIntObj(0); + break; + case MXGET: + /* + * Check for 1 arg. Error if different. + */ + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "id"); + return (TCL_ERROR); + } + result = Tcl_GetIntFromObj(interp, objv[2], &id); + if (result != TCL_OK) + break; + MUTEX_LOCK(dbenv, &mp->marray[id].m, mp->env->lockfhp); + res = Tcl_NewIntObj(0); + break; + case MXGETVAL: + /* + * Check for 1 arg. Error if different. + */ + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "id"); + return (TCL_ERROR); + } + result = Tcl_GetIntFromObj(interp, objv[2], &id); + if (result != TCL_OK) + break; + res = Tcl_NewIntObj(mp->marray[id].val); + break; + case MXSETVAL: + /* + * Check for 2 args. Error if different. + */ + if (objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "id val"); + return (TCL_ERROR); + } + result = Tcl_GetIntFromObj(interp, objv[2], &id); + if (result != TCL_OK) + break; + result = Tcl_GetIntFromObj(interp, objv[3], &newval); + if (result != TCL_OK) + break; + mp->marray[id].val = newval; + res = Tcl_NewIntObj(0); + break; + } + /* + * Only set result if we have a res. Otherwise, lower + * functions have already done so. + */ + if (result == TCL_OK && res) + Tcl_SetObjResult(interp, res); + return (result); +} diff --git a/db/tcl/tcl_db.c b/db/tcl/tcl_db.c new file mode 100644 index 000000000..8e7215a27 --- /dev/null +++ b/db/tcl/tcl_db.c @@ -0,0 +1,1771 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: tcl_db.c,v 11.55 2000/11/28 20:12:31 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#endif + +#include "db_int.h" +#include "tcl_db.h" + +/* + * Prototypes for procedures defined later in this file: + */ +static int tcl_DbClose __P((Tcl_Interp *, + int, Tcl_Obj * CONST*, DB *, DBTCL_INFO *)); +static int tcl_DbDelete __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB *)); +static int tcl_DbGet __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB *)); +static int tcl_DbKeyRange __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB *)); +static int tcl_DbPut __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB *)); +static int tcl_DbStat __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB *)); +static int tcl_DbCursor __P((Tcl_Interp *, + int, Tcl_Obj * CONST*, DB *, DBC **)); +static int tcl_DbJoin __P((Tcl_Interp *, + int, Tcl_Obj * CONST*, DB *, DBC **)); +static int tcl_DbGetjoin __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB *)); +static int tcl_DbCount __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB *)); + +/* + * + * PUBLIC: int db_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*)); + * + * db_Cmd -- + * Implements the "db" widget. + */ +int +db_Cmd(clientData, interp, objc, objv) + ClientData clientData; /* DB handle */ + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ +{ + static char *dbcmds[] = { + "close", + "count", + "cursor", + "del", + "get", + "get_join", + "get_type", + "is_byteswapped", + "join", + "keyrange", + "put", + "stat", + "sync", +#if CONFIG_TEST + "test", +#endif + NULL + }; + enum dbcmds { + DBCLOSE, + DBCOUNT, + DBCURSOR, + DBDELETE, + DBGET, + DBGETJOIN, + DBGETTYPE, + DBSWAPPED, + DBJOIN, + DBKEYRANGE, + DBPUT, + DBSTAT, + DBSYNC +#if CONFIG_TEST + , DBTEST +#endif + }; + DB *dbp; + DBC *dbc; + DBTCL_INFO *dbip; + DBTCL_INFO *ip; + Tcl_Obj *res; + int cmdindex, result, ret; + char newname[MSG_SIZE]; + + Tcl_ResetResult(interp); + dbp = (DB *)clientData; + dbip = _PtrToInfo((void *)dbp); + memset(newname, 0, MSG_SIZE); + result = TCL_OK; + if (objc <= 1) { + Tcl_WrongNumArgs(interp, 1, objv, "command cmdargs"); + return (TCL_ERROR); + } + if (dbp == NULL) { + Tcl_SetResult(interp, "NULL db pointer", TCL_STATIC); + return (TCL_ERROR); + } + if (dbip == NULL) { + Tcl_SetResult(interp, "NULL db info pointer", TCL_STATIC); + return (TCL_ERROR); + } + + /* + * Get the command name index from the object based on the dbcmds + * defined above. + */ + if (Tcl_GetIndexFromObj(interp, + objv[1], dbcmds, "command", TCL_EXACT, &cmdindex) != TCL_OK) + return (IS_HELP(objv[1])); + + res = NULL; + switch ((enum dbcmds)cmdindex) { + case DBCLOSE: + result = tcl_DbClose(interp, objc, objv, dbp, dbip); + break; + case DBDELETE: + result = tcl_DbDelete(interp, objc, objv, dbp); + break; + case DBGET: + result = tcl_DbGet(interp, objc, objv, dbp); + break; + case DBKEYRANGE: + result = tcl_DbKeyRange(interp, objc, objv, dbp); + break; + case DBPUT: + result = tcl_DbPut(interp, objc, objv, dbp); + break; + case DBCOUNT: + result = tcl_DbCount(interp, objc, objv, dbp); + break; + case DBSWAPPED: + /* + * No args for this. Error if there are some. + */ + if (objc > 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + _debug_check(); + ret = dbp->get_byteswapped(dbp); + res = Tcl_NewIntObj(ret); + break; + case DBGETTYPE: + /* + * No args for this. Error if there are some. + */ + if (objc > 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + _debug_check(); + ret = dbp->get_type(dbp); + if (ret == DB_BTREE) + res = Tcl_NewStringObj("btree", strlen("btree")); + else if (ret == DB_HASH) + res = Tcl_NewStringObj("hash", strlen("hash")); + else if (ret == DB_RECNO) + res = Tcl_NewStringObj("recno", strlen("recno")); + else if (ret == DB_QUEUE) + res = Tcl_NewStringObj("queue", strlen("queue")); + else { + Tcl_SetResult(interp, + "db gettype: Returned unknown type\n", TCL_STATIC); + result = TCL_ERROR; + } + break; + case DBSTAT: + result = tcl_DbStat(interp, objc, objv, dbp); + break; + case DBSYNC: + /* + * No args for this. Error if there are some. + */ + if (objc > 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + _debug_check(); + ret = dbp->sync(dbp, 0); + res = Tcl_NewIntObj(ret); + if (ret != 0) { + Tcl_SetObjResult(interp, res); + result = TCL_ERROR; + } + break; + case DBCURSOR: + snprintf(newname, sizeof(newname), + "%s.c%d", dbip->i_name, dbip->i_dbdbcid); + ip = _NewInfo(interp, NULL, newname, I_DBC); + if (ip != NULL) { + result = tcl_DbCursor(interp, objc, objv, dbp, &dbc); + if (result == TCL_OK) { + dbip->i_dbdbcid++; + ip->i_parent = dbip; + Tcl_CreateObjCommand(interp, newname, + (Tcl_ObjCmdProc *)dbc_Cmd, + (ClientData)dbc, NULL); + res = + Tcl_NewStringObj(newname, strlen(newname)); + _SetInfoData(ip, dbc); + } else + _DeleteInfo(ip); + } else { + Tcl_SetResult(interp, + "Could not set up info", TCL_STATIC); + result = TCL_ERROR; + } + break; + case DBJOIN: + snprintf(newname, sizeof(newname), + "%s.c%d", dbip->i_name, dbip->i_dbdbcid); + ip = _NewInfo(interp, NULL, newname, I_DBC); + if (ip != NULL) { + result = tcl_DbJoin(interp, objc, objv, dbp, &dbc); + if (result == TCL_OK) { + dbip->i_dbdbcid++; + ip->i_parent = dbip; + Tcl_CreateObjCommand(interp, newname, + (Tcl_ObjCmdProc *)dbc_Cmd, + (ClientData)dbc, NULL); + res = + Tcl_NewStringObj(newname, strlen(newname)); + _SetInfoData(ip, dbc); + } else + _DeleteInfo(ip); + } else { + Tcl_SetResult(interp, + "Could not set up info", TCL_STATIC); + result = TCL_ERROR; + } + break; + case DBGETJOIN: + result = tcl_DbGetjoin(interp, objc, objv, dbp); + break; +#if CONFIG_TEST + case DBTEST: + result = tcl_EnvTest(interp, objc, objv, dbp->dbenv); + break; +#endif + } + /* + * Only set result if we have a res. Otherwise, lower + * functions have already done so. + */ + if (result == TCL_OK && res) + Tcl_SetObjResult(interp, res); + return (result); +} + +/* + * tcl_db_stat -- + */ +static int +tcl_DbStat(interp, objc, objv, dbp) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB *dbp; /* Database pointer */ +{ + DB_BTREE_STAT *bsp; + DB_HASH_STAT *hsp; + DB_QUEUE_STAT *qsp; + void *sp; + Tcl_Obj *res; + DBTYPE type; + u_int32_t flag; + int result, ret; + char *arg; + + result = TCL_OK; + flag = 0; + + if (objc > 3) { + Tcl_WrongNumArgs(interp, 2, objv, "?-recordcount?"); + return (TCL_ERROR); + } + + if (objc == 3) { + arg = Tcl_GetStringFromObj(objv[2], NULL); + if (strcmp(arg, "-recordcount") == 0) + flag = DB_RECORDCOUNT; + else if (strcmp(arg, "-cachedcounts") == 0) + flag = DB_CACHED_COUNTS; + else { + Tcl_SetResult(interp, + "db stat: unknown arg", TCL_STATIC); + return (TCL_ERROR); + } + } + + _debug_check(); + ret = dbp->stat(dbp, &sp, NULL, flag); + result = _ReturnSetup(interp, ret, "db stat"); + if (result == TCL_ERROR) + return (result); + + type = dbp->get_type(dbp); + /* + * Have our stats, now construct the name value + * list pairs and free up the memory. + */ + res = Tcl_NewObj(); + /* + * MAKE_STAT_LIST assumes 'res' and 'error' label. + */ + if (type == DB_HASH) { + hsp = (DB_HASH_STAT *)sp; + MAKE_STAT_LIST("Magic", hsp->hash_magic); + MAKE_STAT_LIST("Version", hsp->hash_version); + MAKE_STAT_LIST("Page size", hsp->hash_pagesize); + MAKE_STAT_LIST("Number of keys", hsp->hash_nkeys); + MAKE_STAT_LIST("Number of records", hsp->hash_ndata); + MAKE_STAT_LIST("Estim. number of elements", hsp->hash_nelem); + MAKE_STAT_LIST("Fill factor", hsp->hash_ffactor); + MAKE_STAT_LIST("Buckets", hsp->hash_buckets); + MAKE_STAT_LIST("Free pages", hsp->hash_free); + MAKE_STAT_LIST("Bytes free", hsp->hash_bfree); + MAKE_STAT_LIST("Number of big pages", hsp->hash_bigpages); + MAKE_STAT_LIST("Big pages bytes free", hsp->hash_big_bfree); + MAKE_STAT_LIST("Overflow pages", hsp->hash_overflows); + MAKE_STAT_LIST("Overflow bytes free", hsp->hash_ovfl_free); + MAKE_STAT_LIST("Duplicate pages", hsp->hash_dup); + MAKE_STAT_LIST("Duplicate pages bytes free", + hsp->hash_dup_free); + } else if (type == DB_QUEUE) { + qsp = (DB_QUEUE_STAT *)sp; + MAKE_STAT_LIST("Magic", qsp->qs_magic); + MAKE_STAT_LIST("Version", qsp->qs_version); + MAKE_STAT_LIST("Page size", qsp->qs_pagesize); + MAKE_STAT_LIST("Number of records", qsp->qs_ndata); + MAKE_STAT_LIST("Number of pages", qsp->qs_pages); + MAKE_STAT_LIST("Bytes free", qsp->qs_pgfree); + MAKE_STAT_LIST("Record length", qsp->qs_re_len); + MAKE_STAT_LIST("Record pad", qsp->qs_re_pad); + MAKE_STAT_LIST("First record number", qsp->qs_first_recno); + MAKE_STAT_LIST("Last record number", qsp->qs_cur_recno); + } else { /* BTREE and RECNO are same stats */ + bsp = (DB_BTREE_STAT *)sp; + MAKE_STAT_LIST("Number of keys", bsp->bt_nkeys); + MAKE_STAT_LIST("Number of records", bsp->bt_ndata); + if (flag != DB_RECORDCOUNT) { + MAKE_STAT_LIST("Magic", bsp->bt_magic); + MAKE_STAT_LIST("Version", bsp->bt_version); + MAKE_STAT_LIST("Flags", bsp->bt_metaflags); + MAKE_STAT_LIST("Minimum keys per page", bsp->bt_minkey); + MAKE_STAT_LIST("Fixed record length", bsp->bt_re_len); + MAKE_STAT_LIST("Record pad", bsp->bt_re_pad); + MAKE_STAT_LIST("Page size", bsp->bt_pagesize); + MAKE_STAT_LIST("Levels", bsp->bt_levels); + MAKE_STAT_LIST("Internal pages", bsp->bt_int_pg); + MAKE_STAT_LIST("Leaf pages", bsp->bt_leaf_pg); + MAKE_STAT_LIST("Duplicate pages", bsp->bt_dup_pg); + MAKE_STAT_LIST("Overflow pages", bsp->bt_over_pg); + MAKE_STAT_LIST("Pages on freelist", bsp->bt_free); + MAKE_STAT_LIST("Internal pages bytes free", + bsp->bt_int_pgfree); + MAKE_STAT_LIST("Leaf pages bytes free", + bsp->bt_leaf_pgfree); + MAKE_STAT_LIST("Duplicate pages bytes free", + bsp->bt_dup_pgfree); + MAKE_STAT_LIST("Bytes free in overflow pages", + bsp->bt_over_pgfree); + } + } + Tcl_SetObjResult(interp, res); +error: + __os_free(sp, 0); + return (result); +} + +/* + * tcl_db_close -- + */ +static int +tcl_DbClose(interp, objc, objv, dbp, dbip) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB *dbp; /* Database pointer */ + DBTCL_INFO *dbip; /* Info pointer */ +{ + DBTCL_INFO *p, *nextp; + u_int32_t flag; + int result, ret; + char *arg; + + result = TCL_OK; + flag = 0; + if (objc > 3) { + Tcl_WrongNumArgs(interp, 2, objv, "?-nosync?"); + return (TCL_ERROR); + } + + if (objc == 3) { + arg = Tcl_GetStringFromObj(objv[2], NULL); + if (strcmp(arg, "-nosync") == 0) + flag = DB_NOSYNC; + else { + Tcl_SetResult(interp, + "dbclose: unknown arg", TCL_STATIC); + return (TCL_ERROR); + } + } + + /* + * First we have to close any open cursors. Then we close + * our db. + */ + for (p = LIST_FIRST(&__db_infohead); p != NULL; p = nextp) { + nextp = LIST_NEXT(p, entries); + /* + * Check if this is a cursor info structure and if + * it is, if it belongs to this DB. If so, remove + * its commands and info structure. + */ + if (p->i_parent == dbip && p->i_type == I_DBC) { + (void)Tcl_DeleteCommand(interp, p->i_name); + _DeleteInfo(p); + } + } + (void)Tcl_DeleteCommand(interp, dbip->i_name); + _DeleteInfo(dbip); + _debug_check(); + ret = (dbp)->close(dbp, flag); + result = _ReturnSetup(interp, ret, "db close"); + return (result); +} + +/* + * tcl_db_put -- + */ +static int +tcl_DbPut(interp, objc, objv, dbp) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB *dbp; /* Database pointer */ +{ + static char *dbputopts[] = { + "-append", + "-nodupdata", + "-nooverwrite", + "-partial", + "-txn", + NULL + }; + enum dbputopts { + DBPUT_APPEND, + DBGET_NODUPDATA, + DBPUT_NOOVER, + DBPUT_PART, + DBPUT_TXN + }; + static char *dbputapp[] = { + "-append", NULL + }; + enum dbputapp { DBPUT_APPEND0 }; + DBT key, data; + DBTYPE type; + DB_TXN *txn; + Tcl_Obj **elemv, *res; + db_recno_t recno; + u_int32_t flag; + int elemc, end, i, itmp, optindex, result, ret; + char *arg, msg[MSG_SIZE]; + + txn = NULL; + result = TCL_OK; + flag = 0; + if (objc <= 3) { + Tcl_WrongNumArgs(interp, 2, objv, "?-args? key data"); + return (TCL_ERROR); + } + + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + + /* + * If it is a QUEUE or RECNO database, the key is a record number + * and must be setup up to contain a db_recno_t. Otherwise the + * key is a "string". + */ + type = dbp->get_type(dbp); + + /* + * We need to determine where the end of required args are. If we + * are using a QUEUE/RECNO db and -append, then there is just one + * req arg (data). Otherwise there are two (key data). + * + * We preparse the list to determine this since we need to know + * to properly check # of args for other options below. + */ + end = objc - 2; + if (type == DB_QUEUE || type == DB_RECNO) { + i = 2; + while (i < objc - 1) { + if (Tcl_GetIndexFromObj(interp, objv[i++], dbputapp, + "option", TCL_EXACT, &optindex) != TCL_OK) + continue; + switch ((enum dbputapp)optindex) { + case DBPUT_APPEND0: + end = objc - 1; + break; + } + } + } + Tcl_ResetResult(interp); + + /* + * Get the command name index from the object based on the options + * defined above. + */ + i = 2; + while (i < end) { + if (Tcl_GetIndexFromObj(interp, objv[i], + dbputopts, "option", TCL_EXACT, &optindex) != TCL_OK) + return (IS_HELP(objv[i])); + i++; + switch ((enum dbputopts)optindex) { + case DBPUT_TXN: + if (i > (end - 1)) { + Tcl_WrongNumArgs(interp, 2, objv, "?-txn id?"); + result = TCL_ERROR; + break; + } + arg = Tcl_GetStringFromObj(objv[i++], NULL); + txn = NAME_TO_TXN(arg); + if (txn == NULL) { + snprintf(msg, MSG_SIZE, + "Put: Invalid txn: %s\n", arg); + Tcl_SetResult(interp, msg, TCL_VOLATILE); + result = TCL_ERROR; + } + break; + case DBPUT_APPEND: + FLAG_CHECK(flag); + flag = DB_APPEND; + break; + case DBGET_NODUPDATA: + FLAG_CHECK(flag); + flag = DB_NODUPDATA; + break; + case DBPUT_NOOVER: + FLAG_CHECK(flag); + flag = DB_NOOVERWRITE; + break; + case DBPUT_PART: + if (i > (end - 1)) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-partial {offset length}?"); + result = TCL_ERROR; + break; + } + /* + * Get sublist as {offset length} + */ + result = Tcl_ListObjGetElements(interp, objv[i++], + &elemc, &elemv); + if (elemc != 2) { + Tcl_SetResult(interp, + "List must be {offset length}", TCL_STATIC); + result = TCL_ERROR; + break; + } + data.flags = DB_DBT_PARTIAL; + result = Tcl_GetIntFromObj(interp, elemv[0], &itmp); + data.doff = itmp; + if (result != TCL_OK) + break; + result = Tcl_GetIntFromObj(interp, elemv[1], &itmp); + data.dlen = itmp; + /* + * NOTE: We don't check result here because all we'd + * do is break anyway, and we are doing that. If you + * add code here, you WILL need to add the check + * for result. (See the check for save.doff, a few + * lines above and copy that.) + */ + break; + } + if (result != TCL_OK) + break; + } + + if (result == TCL_ERROR) + return (result); + + /* + * If we are a recno db and we are NOT using append, then the 2nd + * last arg is the key. + */ + if (type == DB_QUEUE || type == DB_RECNO) { + key.data = &recno; + key.ulen = key.size = sizeof(db_recno_t); + key.flags = DB_DBT_USERMEM; + if (flag == DB_APPEND) + recno = 0; + else { + result = Tcl_GetIntFromObj(interp, objv[objc-2], &itmp); + recno = itmp; + if (result != TCL_OK) + return (result); + } + } else { + key.data = Tcl_GetByteArrayFromObj(objv[objc-2], &itmp); + key.size = itmp; + } + /* + * XXX + * Tcl 8.1 Tcl_GetByteArrayFromObj/Tcl_GetIntFromObj bug. + * + * This line (and the line for key.data above) were moved from + * the beginning of the function to here. + * + * There is a bug in Tcl 8.1 and byte arrays in that if it happens + * to use an object as both a byte array and something else like + * an int, and you've done a Tcl_GetByteArrayFromObj, then you + * do a Tcl_GetIntFromObj, your memory is deleted. + * + * Workaround is to make sure all Tcl_GetByteArrayFromObj calls + * are done last. + */ + data.data = Tcl_GetByteArrayFromObj(objv[objc-1], &itmp); + data.size = itmp; + _debug_check(); + ret = dbp->put(dbp, txn, &key, &data, flag); + result = _ReturnSetup(interp, ret, "db put"); + if (ret == 0 && + (type == DB_RECNO || type == DB_QUEUE) && flag == DB_APPEND) { + res = Tcl_NewIntObj(recno); + Tcl_SetObjResult(interp, res); + } + return (result); +} + +/* + * tcl_db_get -- + */ +static int +tcl_DbGet(interp, objc, objv, dbp) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB *dbp; /* Database pointer */ +{ + static char *dbgetopts[] = { + "-consume", + "-consume_wait", + "-get_both", + "-glob", + "-partial", + "-recno", + "-rmw", + "-txn", + NULL + }; + enum dbgetopts { + DBGET_CONSUME, + DBGET_CONSUME_WAIT, + DBGET_BOTH, + DBGET_GLOB, + DBGET_PART, + DBGET_RECNO, + DBGET_RMW, + DBGET_TXN + }; + DBC *dbc; + DBT key, data, save; + DBTYPE type; + DB_TXN *txn; + Tcl_Obj **elemv, *retlist; + db_recno_t recno; + u_int32_t flag, cflag, isdup, rmw; + int elemc, end, i, itmp, optindex, result, ret, useglob, userecno; + char *arg, *pattern, *prefix, msg[MSG_SIZE]; + + result = TCL_OK; + cflag = flag = rmw = 0; + useglob = userecno = 0; + txn = NULL; + pattern = prefix = NULL; + + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, "?-args? key"); + return (TCL_ERROR); + } + + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + memset(&save, 0, sizeof(save)); + + /* + * Get the command name index from the object based on the options + * defined above. + */ + i = 2; + type = dbp->get_type(dbp); + end = objc; + while (i < end) { + if (Tcl_GetIndexFromObj(interp, objv[i], dbgetopts, "option", + TCL_EXACT, &optindex) != TCL_OK) { + if (IS_HELP(objv[i]) == TCL_OK) + return (TCL_OK); + Tcl_ResetResult(interp); + break; + } + i++; + switch ((enum dbgetopts)optindex) { + case DBGET_BOTH: + /* + * Change 'end' and make sure we aren't already past + * the new end. + */ + if (i > objc - 2) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-get_both key data?"); + result = TCL_ERROR; + break; + } + end = objc - 2; + FLAG_CHECK(flag); + flag = DB_GET_BOTH; + break; + case DBGET_TXN: + if (i == end - 1) { + Tcl_WrongNumArgs(interp, 2, objv, "?-txn id?"); + result = TCL_ERROR; + break; + } + arg = Tcl_GetStringFromObj(objv[i++], NULL); + txn = NAME_TO_TXN(arg); + if (txn == NULL) { + snprintf(msg, MSG_SIZE, + "Get: Invalid txn: %s\n", arg); + Tcl_SetResult(interp, msg, TCL_VOLATILE); + result = TCL_ERROR; + } + break; + case DBGET_GLOB: + useglob = 1; + end = objc - 1; + break; + case DBGET_CONSUME: + FLAG_CHECK(flag); + flag = DB_CONSUME; + break; + case DBGET_CONSUME_WAIT: + FLAG_CHECK(flag); + flag = DB_CONSUME_WAIT; + break; + case DBGET_RECNO: + end = objc - 1; + userecno = 1; + if (type != DB_RECNO && type != DB_QUEUE) { + FLAG_CHECK(flag); + flag = DB_SET_RECNO; + } + break; + case DBGET_RMW: + rmw = DB_RMW; + break; + case DBGET_PART: + end = objc - 1; + if (i == end) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-partial {offset length}?"); + result = TCL_ERROR; + break; + } + /* + * Get sublist as {offset length} + */ + result = Tcl_ListObjGetElements(interp, objv[i++], + &elemc, &elemv); + if (elemc != 2) { + Tcl_SetResult(interp, + "List must be {offset length}", TCL_STATIC); + result = TCL_ERROR; + break; + } + save.flags = DB_DBT_PARTIAL; + result = Tcl_GetIntFromObj(interp, elemv[0], &itmp); + save.doff = itmp; + if (result != TCL_OK) + break; + result = Tcl_GetIntFromObj(interp, elemv[1], &itmp); + save.dlen = itmp; + /* + * NOTE: We don't check result here because all we'd + * do is break anyway, and we are doing that. If you + * add code here, you WILL need to add the check + * for result. (See the check for save.doff, a few + * lines above and copy that.) + */ + break; + } + if (result != TCL_OK) + break; + } + if (result != TCL_OK) + goto out; + + if (type == DB_RECNO || type == DB_QUEUE) + userecno = 1; + /* + * Check for illegal combos of options. + */ + if (useglob && (userecno || flag == DB_SET_RECNO || + type == DB_RECNO || type == DB_QUEUE)) { + Tcl_SetResult(interp, + "Cannot use -glob and record numbers.\n", + TCL_STATIC); + result = TCL_ERROR; + goto out; + } + if (useglob && flag == DB_GET_BOTH) { + Tcl_SetResult(interp, + "Only one of -glob or -get_both can be specified.\n", + TCL_STATIC); + result = TCL_ERROR; + goto out; + } + + if (useglob) + pattern = Tcl_GetStringFromObj(objv[objc - 1], NULL); + + /* + * This is the list we return + */ + retlist = Tcl_NewListObj(0, NULL); + save.flags |= DB_DBT_MALLOC; + + /* + * isdup is used to know if we support duplicates. If not, we + * can just do a db->get call and avoid using cursors. + * XXX + * When there is a db->get_flags method, it should be used. + * isdup = dbp->get_flags(dbp) & DB_DUP; + * For now we illegally peek. + * XXX + */ + isdup = dbp->flags & DB_AM_DUP; + + /* + * If the database doesn't support duplicates or we're performing + * ops that don't require returning multiple items, use DB->get + * instead of a cursor operation. + */ + if (pattern == NULL && (isdup == 0 || + flag == DB_SET_RECNO || flag == DB_GET_BOTH || + flag == DB_CONSUME || flag == DB_CONSUME_WAIT)) { + if (flag == DB_GET_BOTH) { + if (userecno) { + result = Tcl_GetIntFromObj(interp, + objv[(objc - 2)], &itmp); + recno = itmp; + if (result == TCL_OK) { + key.data = &recno; + key.size = sizeof(db_recno_t); + } else + return (result); + } else { + key.data = + Tcl_GetByteArrayFromObj(objv[objc-2], + &itmp); + key.size = itmp; + } + /* + * Already checked args above. Fill in key and save. + * Save is used in the dbp->get call below to fill in + * data. + */ + save.data = + Tcl_GetByteArrayFromObj(objv[objc-1], &itmp); + save.size = itmp; + } else if (flag != DB_CONSUME && flag != DB_CONSUME_WAIT) { + if (userecno) { + result = Tcl_GetIntFromObj( + interp, objv[(objc - 1)], &itmp); + recno = itmp; + if (result == TCL_OK) { + key.data = &recno; + key.size = sizeof(db_recno_t); + } else + return (result); + } else { + key.data = Tcl_GetByteArrayFromObj(objv[objc-1], &itmp); + key.size = itmp; + } + } + + memset(&data, 0, sizeof(data)); + data = save; + + _debug_check(); + + ret = dbp->get(dbp, txn, &key, &data, flag | rmw); + result = _ReturnSetup(interp, ret, "db get"); + if (ret == 0) { + /* + * Success. Return a list of the form {name value} + * If it was a recno in key.data, we need to convert + * into a string/object representation of that recno. + */ + if (type == DB_RECNO || type == DB_QUEUE) + result = _SetListRecnoElem(interp, retlist, + *(db_recno_t *)key.data, data.data, + data.size); + else + result = _SetListElem(interp, retlist, + key.data, key.size, data.data, data.size); + /* + * Free space from DB_DBT_MALLOC + */ + __os_free(data.data, data.size); + } + if (result == TCL_OK) + Tcl_SetObjResult(interp, retlist); + goto out; + } + + if (userecno) { + result = Tcl_GetIntFromObj(interp, objv[(objc - 1)], &itmp); + recno = itmp; + if (result == TCL_OK) { + key.data = &recno; + key.size = sizeof(db_recno_t); + } else + return (result); + } else { + key.data = Tcl_GetByteArrayFromObj(objv[objc-1], &itmp); + key.size = itmp; + } + ret = dbp->cursor(dbp, txn, &dbc, 0); + result = _ReturnSetup(interp, ret, "db cursor"); + if (result == TCL_ERROR) + goto out; + + /* + * At this point, we have a cursor, if we have a pattern, + * we go to the nearest one and step forward until we don't + * have any more that match the pattern prefix. If we have + * an exact key, we go to that key position, and step through + * all the duplicates. In either case we build up a list of + * the form {{key data} {key data}...} along the way. + */ + memset(&data, 0, sizeof(data)); + /* + * Restore any "partial" info we have saved. + */ + data = save; + if (pattern) { + /* + * Note, prefix is returned in new space. Must free it. + */ + ret = _GetGlobPrefix(pattern, &prefix); + if (ret) { + result = TCL_ERROR; + Tcl_SetResult(interp, + "Unable to allocate pattern space", TCL_STATIC); + goto out1; + } + key.data = prefix; + key.size = strlen(prefix); + /* + * If they give us an empty pattern string + * (i.e. -glob *), go through entire DB. + */ + if (strlen(prefix) == 0) + cflag = DB_FIRST; + else + cflag = DB_SET_RANGE; + } else + cflag = DB_SET; + _debug_check(); + ret = dbc->c_get(dbc, &key, &data, cflag | rmw); + result = _ReturnSetup(interp, ret, "db get (cursor)"); + if (result == TCL_ERROR) + goto out1; + if (pattern) + cflag = DB_NEXT; + else + cflag = DB_NEXT_DUP; + + while (ret == 0 && result == TCL_OK) { + /* + * Build up our {name value} sublist + */ + result = _SetListElem(interp, retlist, + key.data, key.size, + data.data, data.size); + /* + * Free space from DB_DBT_MALLOC + */ + __os_free(data.data, data.size); + if (result != TCL_OK) + break; + /* + * Append {name value} to return list + */ + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + /* + * Restore any "partial" info we have saved. + */ + data = save; + ret = dbc->c_get(dbc, &key, &data, cflag | rmw); + if (ret == 0 && pattern && + memcmp(key.data, prefix, strlen(prefix)) != 0) { + /* + * Free space from DB_DBT_MALLOC + */ + __os_free(data.data, data.size); + break; + } + } + dbc->c_close(dbc); +out1: + if (result == TCL_OK) + Tcl_SetObjResult(interp, retlist); +out: + /* + * _GetGlobPrefix(), the function which allocates prefix, works + * by copying and condensing another string. Thus prefix may + * have multiple nuls at the end, so we free using __os_free(). + */ + if (prefix != NULL) + __os_free(prefix,0); + return (result); +} + +/* + * tcl_db_delete -- + */ +static int +tcl_DbDelete(interp, objc, objv, dbp) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB *dbp; /* Database pointer */ +{ + static char *dbdelopts[] = { + "-glob", + "-txn", + NULL + }; + enum dbdelopts { + DBDEL_GLOB, + DBDEL_TXN + }; + DBC *dbc; + DBT key, data; + DBTYPE type; + DB_TXN *txn; + db_recno_t recno; + int i, itmp, optindex, result, ret; + u_int32_t flag; + char *arg, *pattern, *prefix, msg[MSG_SIZE]; + + result = TCL_OK; + flag = 0; + pattern = prefix = NULL; + txn = NULL; + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, "?-args? key"); + return (TCL_ERROR); + } + + memset(&key, 0, sizeof(key)); + /* + * The first arg must be -txn, -glob or a list of keys. + */ + i = 2; + while (i < objc) { + if (Tcl_GetIndexFromObj(interp, objv[i], dbdelopts, "option", + TCL_EXACT, &optindex) != TCL_OK) { + /* + * If we don't have a -glob or -txn, then the + * remaining args must be exact keys. + * Reset the result so we don't get + * an errant error message if there is another error. + */ + if (IS_HELP(objv[i]) == TCL_OK) + return (TCL_OK); + Tcl_ResetResult(interp); + break; + } + i++; + switch ((enum dbdelopts)optindex) { + case DBDEL_TXN: + if (i == objc) { + /* + * Someone could conceivably have a key of + * the same name. So just break and use it. + */ + i--; + break; + } + arg = Tcl_GetStringFromObj(objv[i++], NULL); + txn = NAME_TO_TXN(arg); + if (txn == NULL) { + snprintf(msg, MSG_SIZE, + "Delete: Invalid txn: %s\n", arg); + Tcl_SetResult(interp, msg, TCL_VOLATILE); + result = TCL_ERROR; + } + break; + case DBDEL_GLOB: + /* + * Get the pattern. Get the prefix and use cursors to + * get all the data items. + */ + if (i == objc) { + /* + * Someone could conceivably have a key of + * the same name. So just break and use it. + */ + i--; + break; + } + pattern = Tcl_GetStringFromObj(objv[i++], NULL); + break; + } + if (result != TCL_OK) + break; + } + + if (result != TCL_OK) + goto out; + + /* + * If we have a pattern AND more keys to process, then there + * is an error. Either we have some number of exact keys, + * or we have a pattern. + */ + if (pattern != NULL && i != objc) { + Tcl_WrongNumArgs(interp, 2, objv, "?args? -glob pattern | key"); + result = TCL_ERROR; + goto out; + } + /* + * XXX + * For consistency with get, we have decided for the moment, to + * allow -glob, or one key, not many. The code was originally + * written to take many keys and we'll leave it that way, because + * tcl_DbGet may one day accept many disjoint keys to get, rather + * than one, and at that time we'd make delete be consistent. In + * any case, the code is already here and there is no need to remove, + * just check that we only have one arg left. + */ + if (pattern == NULL && i != (objc - 1)) { + Tcl_WrongNumArgs(interp, 2, objv, "?args? -glob pattern | key"); + result = TCL_ERROR; + goto out; + } + + /* + * If we have remaining args, they are all exact keys. Call + * DB->del on each of those keys. + * + * If it is a RECNO database, the key is a record number and must be + * setup up to contain a db_recno_t. Otherwise the key is a "string". + */ + type = dbp->get_type(dbp); + ret = 0; + while (i < objc && ret == 0) { + memset(&key, 0, sizeof(key)); + if (type == DB_RECNO || type == DB_QUEUE) { + result = Tcl_GetIntFromObj(interp, objv[i++], &itmp); + recno = itmp; + if (result == TCL_OK) { + key.data = &recno; + key.size = sizeof(db_recno_t); + } else + return (result); + } else { + key.data = Tcl_GetByteArrayFromObj(objv[i++], &itmp); + key.size = itmp; + } + _debug_check(); + ret = dbp->del(dbp, txn, &key, 0); + /* + * If we have any error, set up return result and stop + * processing keys. + */ + if (ret != 0) + break; + } + result = _ReturnSetup(interp, ret, "db del"); + + /* + * At this point we've either finished or, if we have a pattern, + * we go to the nearest one and step forward until we don't + * have any more that match the pattern prefix. + */ + if (pattern) { + ret = dbp->cursor(dbp, txn, &dbc, 0); + if (ret != 0) { + result = _ReturnSetup(interp, ret, "db cursor"); + goto out; + } + /* + * Note, prefix is returned in new space. Must free it. + */ + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + ret = _GetGlobPrefix(pattern, &prefix); + if (ret) { + result = TCL_ERROR; + Tcl_SetResult(interp, + "Unable to allocate pattern space", TCL_STATIC); + goto out; + } + key.data = prefix; + key.size = strlen(prefix); + if (strlen(prefix) == 0) + flag = DB_FIRST; + else + flag = DB_SET_RANGE; + ret = dbc->c_get(dbc, &key, &data, flag); + while (ret == 0 && + memcmp(key.data, prefix, strlen(prefix)) == 0) { + /* + * Each time through here the cursor is pointing + * at the current valid item. Delete it and + * move ahead. + */ + _debug_check(); + ret = dbc->c_del(dbc, 0); + if (ret != 0) { + result = _ReturnSetup(interp, ret, "db c_del"); + break; + } + /* + * Deleted the current, now move to the next item + * in the list, check if it matches the prefix pattern. + */ + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + ret = dbc->c_get(dbc, &key, &data, DB_NEXT); + } + if (ret == DB_NOTFOUND) + ret = 0; + /* + * _GetGlobPrefix(), the function which allocates prefix, works + * by copying and condensing another string. Thus prefix may + * have multiple nuls at the end, so we free using __os_free(). + */ + __os_free(prefix,0); + dbc->c_close(dbc); + result = _ReturnSetup(interp, ret, "db del"); + } +out: + return (result); +} + +/* + * tcl_db_cursor -- + */ +static int +tcl_DbCursor(interp, objc, objv, dbp, dbcp) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB *dbp; /* Database pointer */ + DBC **dbcp; /* Return cursor pointer */ +{ + static char *dbcuropts[] = { + "-txn", "-update", + NULL + }; + enum dbcuropts { + DBCUR_TXN, DBCUR_UPDATE + }; + DB_TXN *txn; + u_int32_t flag; + int i, optindex, result, ret; + char *arg, msg[MSG_SIZE]; + + result = TCL_OK; + flag = 0; + txn = NULL; + /* + * If the user asks for -glob or -recno, it MUST be the second + * last arg given. If it isn't given, then we must check if + * they gave us a correct key. + */ + i = 2; + while (i < objc) { + if (Tcl_GetIndexFromObj(interp, objv[i], dbcuropts, "option", + TCL_EXACT, &optindex) != TCL_OK) { + result = IS_HELP(objv[i]); + goto out; + } + i++; + switch ((enum dbcuropts)optindex) { + case DBCUR_TXN: + if (i == objc) { + Tcl_WrongNumArgs(interp, 2, objv, "?-txn id?"); + result = TCL_ERROR; + break; + } + arg = Tcl_GetStringFromObj(objv[i++], NULL); + txn = NAME_TO_TXN(arg); + if (txn == NULL) { + snprintf(msg, MSG_SIZE, + "Cursor: Invalid txn: %s\n", arg); + Tcl_SetResult(interp, msg, TCL_VOLATILE); + result = TCL_ERROR; + } + break; + case DBCUR_UPDATE: + flag = DB_WRITECURSOR; + break; + } + if (result != TCL_OK) + break; + } + if (result != TCL_OK) + goto out; + + _debug_check(); + ret = dbp->cursor(dbp, txn, dbcp, flag); + if (ret != 0) + result = _ErrorSetup(interp, ret, "db cursor"); +out: + return (result); +} + +/* + * tcl_db_join -- + */ +static int +tcl_DbJoin(interp, objc, objv, dbp, dbcp) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB *dbp; /* Database pointer */ + DBC **dbcp; /* Cursor pointer */ +{ + static char *dbjopts[] = { + "-nosort", + NULL + }; + enum dbjopts { + DBJ_NOSORT + }; + DBC **listp; + u_int32_t flag; + int adj, i, j, optindex, size, result, ret; + char *arg, msg[MSG_SIZE]; + + result = TCL_OK; + flag = 0; + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, "curs1 curs2 ..."); + return (TCL_ERROR); + } + + i = 2; + adj = i; + while (i < objc) { + if (Tcl_GetIndexFromObj(interp, objv[i], dbjopts, "option", + TCL_EXACT, &optindex) != TCL_OK) { + result = IS_HELP(objv[i]); + if (result == TCL_OK) + return (result); + result = TCL_OK; + Tcl_ResetResult(interp); + break; + } + i++; + switch ((enum dbjopts)optindex) { + case DBJ_NOSORT: + flag |= DB_JOIN_NOSORT; + adj++; + break; + } + } + if (result != TCL_OK) + return (result); + /* + * Allocate one more for NULL ptr at end of list. + */ + size = sizeof(DBC *) * ((objc - adj) + 1); + ret = __os_malloc(dbp->dbenv, size, NULL, &listp); + if (ret != 0) { + Tcl_SetResult(interp, db_strerror(ret), TCL_STATIC); + return (TCL_ERROR); + } + + memset(listp, 0, size); + for (j = 0, i = adj; i < objc; i++, j++) { + arg = Tcl_GetStringFromObj(objv[i], NULL); + listp[j] = NAME_TO_DBC(arg); + if (listp[j] == NULL) { + snprintf(msg, MSG_SIZE, + "Join: Invalid cursor: %s\n", arg); + Tcl_SetResult(interp, msg, TCL_VOLATILE); + result = TCL_ERROR; + goto out; + } + } + listp[j] = NULL; + _debug_check(); + ret = dbp->join(dbp, listp, dbcp, flag); + result = _ReturnSetup(interp, ret, "db join"); + +out: + __os_free(listp, size); + return (result); +} + +/* + * tcl_db_getjoin -- + */ +static int +tcl_DbGetjoin(interp, objc, objv, dbp) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB *dbp; /* Database pointer */ +{ + static char *dbgetjopts[] = { + "-nosort", + "-txn", + NULL + }; + enum dbgetjopts { + DBGETJ_NOSORT, + DBGETJ_TXN + }; + DB_TXN *txn; + DB *elemdbp; + DBC **listp; + DBC *dbc; + DBT key, data; + Tcl_Obj **elemv, *retlist; + u_int32_t flag; + int adj, elemc, i, itmp, j, optindex, result, ret, size; + char *arg, msg[MSG_SIZE]; + + result = TCL_OK; + flag = 0; + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, "{db1 key1} {db2 key2} ..."); + return (TCL_ERROR); + } + + txn = NULL; + i = 2; + adj = i; + while (i < objc) { + if (Tcl_GetIndexFromObj(interp, objv[i], dbgetjopts, "option", + TCL_EXACT, &optindex) != TCL_OK) { + result = IS_HELP(objv[i]); + if (result == TCL_OK) + return (result); + result = TCL_OK; + Tcl_ResetResult(interp); + break; + } + i++; + switch ((enum dbgetjopts)optindex) { + case DBGETJ_NOSORT: + flag |= DB_JOIN_NOSORT; + adj++; + break; + case DBGETJ_TXN: + if (i == objc) { + Tcl_WrongNumArgs(interp, 2, objv, "?-txn id?"); + result = TCL_ERROR; + break; + } + arg = Tcl_GetStringFromObj(objv[i++], NULL); + txn = NAME_TO_TXN(arg); + adj += 2; + if (txn == NULL) { + snprintf(msg, MSG_SIZE, + "GetJoin: Invalid txn: %s\n", arg); + Tcl_SetResult(interp, msg, TCL_VOLATILE); + result = TCL_ERROR; + } + break; + } + } + if (result != TCL_OK) + return (result); + size = sizeof(DBC *) * ((objc - adj) + 1); + ret = __os_malloc(NULL, size, NULL, &listp); + if (ret != 0) { + Tcl_SetResult(interp, db_strerror(ret), TCL_STATIC); + return (TCL_ERROR); + } + + memset(listp, 0, size); + for (j = 0, i = adj; i < objc; i++, j++) { + /* + * Get each sublist as {db key} + */ + result = Tcl_ListObjGetElements(interp, objv[i], + &elemc, &elemv); + if (elemc != 2) { + Tcl_SetResult(interp, "Lists must be {db key}", + TCL_STATIC); + result = TCL_ERROR; + goto out; + } + /* + * Get a pointer to that open db. Then, open a cursor in + * that db, and go to the "key" place. + */ + elemdbp = NAME_TO_DB(Tcl_GetStringFromObj(elemv[0], NULL)); + if (elemdbp == NULL) { + snprintf(msg, MSG_SIZE, "Get_join: Invalid db: %s\n", + Tcl_GetStringFromObj(elemv[0], NULL)); + Tcl_SetResult(interp, msg, TCL_VOLATILE); + result = TCL_ERROR; + goto out; + } + ret = elemdbp->cursor(elemdbp, txn, &listp[j], 0); + if ((result = _ReturnSetup(interp, ret, "db cursor")) == + TCL_ERROR) + goto out; + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = Tcl_GetByteArrayFromObj(elemv[elemc-1], &itmp); + key.size = itmp; + ret = (listp[j])->c_get(listp[j], &key, &data, DB_SET); + if ((result = _ReturnSetup(interp, ret, "db cget")) == + TCL_ERROR) + goto out; + } + listp[j] = NULL; + _debug_check(); + ret = dbp->join(dbp, listp, &dbc, flag); + result = _ReturnSetup(interp, ret, "db join"); + if (result == TCL_ERROR) + goto out; + + retlist = Tcl_NewListObj(0, NULL); + while (ret == 0 && result == TCL_OK) { + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.flags |= DB_DBT_MALLOC; + data.flags |= DB_DBT_MALLOC; + ret = dbc->c_get(dbc, &key, &data, 0); + /* + * Build up our {name value} sublist + */ + if (ret == 0) { + result = _SetListElem(interp, retlist, + key.data, key.size, + data.data, data.size); + __os_free(key.data, key.size); + __os_free(data.data, data.size); + } + } + dbc->c_close(dbc); + if (result == TCL_OK) + Tcl_SetObjResult(interp, retlist); +out: + while (j) { + if (listp[j]) + (listp[j])->c_close(listp[j]); + j--; + } + __os_free(listp, size); + return (result); +} + +/* + * tcl_DbCount -- + */ +static int +tcl_DbCount(interp, objc, objv, dbp) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB *dbp; /* Database pointer */ +{ + Tcl_Obj *res; + DBC *dbc; + DBT key, data; + db_recno_t count, recno; + int itmp, len, result, ret; + + result = TCL_OK; + count = 0; + res = NULL; + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "key"); + return (TCL_ERROR); + } + + memset(&key, 0, sizeof(key)); + + /* + * Get the count for our key. + * We do this by getting a cursor for this DB. Moving the cursor + * to the set location, and getting a count on that cursor. + */ + ret = 0; + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + /* + * If it's a queue or recno database, we must make sure to + * treat the key as a recno rather than as a byte string. + */ + if (dbp->type == DB_RECNO || dbp->type == DB_QUEUE) { + result = Tcl_GetIntFromObj(interp, objv[2], &itmp); + recno = itmp; + if (result == TCL_OK) { + key.data = &recno; + key.size = sizeof(db_recno_t); + } else + return (result); + } else { + key.data = Tcl_GetByteArrayFromObj(objv[2], &len); + key.size = len; + } + _debug_check(); + ret = dbp->cursor(dbp, NULL, &dbc, 0); + if (ret != 0) { + result = _ReturnSetup(interp, ret, "db cursor"); + goto out; + } + /* + * Move our cursor to the key. + */ + ret = dbc->c_get(dbc, &key, &data, DB_SET); + if (ret == DB_NOTFOUND) + count = 0; + else { + ret = dbc->c_count(dbc, &count, 0); + if (ret != 0) { + result = _ReturnSetup(interp, ret, "db cursor"); + goto out; + } + } + res = Tcl_NewIntObj(count); + Tcl_SetObjResult(interp, res); +out: + return (result); +} + +/* + * tcl_DbKeyRange -- + */ +static int +tcl_DbKeyRange(interp, objc, objv, dbp) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB *dbp; /* Database pointer */ +{ + static char *dbkeyropts[] = { + "-txn", + NULL + }; + enum dbkeyropts { + DBKEYR_TXN + }; + DB_TXN *txn; + DB_KEY_RANGE range; + DBT key; + DBTYPE type; + Tcl_Obj *myobjv[3], *retlist; + db_recno_t recno; + u_int32_t flag; + int i, itmp, myobjc, optindex, result, ret; + char *arg, msg[MSG_SIZE]; + + result = TCL_OK; + flag = 0; + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, "?-txn id? key"); + return (TCL_ERROR); + } + + txn = NULL; + i = 2; + while (i < objc) { + if (Tcl_GetIndexFromObj(interp, objv[i], dbkeyropts, "option", + TCL_EXACT, &optindex) != TCL_OK) { + result = IS_HELP(objv[i]); + if (result == TCL_OK) + return (result); + result = TCL_OK; + Tcl_ResetResult(interp); + break; + } + i++; + switch ((enum dbkeyropts)optindex) { + case DBKEYR_TXN: + if (i == objc) { + Tcl_WrongNumArgs(interp, 2, objv, "?-txn id?"); + result = TCL_ERROR; + break; + } + arg = Tcl_GetStringFromObj(objv[i++], NULL); + txn = NAME_TO_TXN(arg); + if (txn == NULL) { + snprintf(msg, MSG_SIZE, + "KeyRange: Invalid txn: %s\n", arg); + Tcl_SetResult(interp, msg, TCL_VOLATILE); + result = TCL_ERROR; + } + break; + } + } + if (result != TCL_OK) + return (result); + type = dbp->get_type(dbp); + ret = 0; + /* + * Make sure we have a key. + */ + if (i != (objc - 1)) { + Tcl_WrongNumArgs(interp, 2, objv, "?args? key"); + result = TCL_ERROR; + goto out; + } + memset(&key, 0, sizeof(key)); + if (type == DB_RECNO || type == DB_QUEUE) { + result = Tcl_GetIntFromObj(interp, objv[i], &itmp); + recno = itmp; + if (result == TCL_OK) { + key.data = &recno; + key.size = sizeof(db_recno_t); + } else + return (result); + } else { + key.data = Tcl_GetByteArrayFromObj(objv[i++], &itmp); + key.size = itmp; + } + _debug_check(); + ret = dbp->key_range(dbp, txn, &key, &range, flag); + result = _ReturnSetup(interp, ret, "db join"); + if (result == TCL_ERROR) + goto out; + + /* + * If we succeeded, set up return list. + */ + myobjc = 3; + myobjv[0] = Tcl_NewDoubleObj(range.less); + myobjv[1] = Tcl_NewDoubleObj(range.equal); + myobjv[2] = Tcl_NewDoubleObj(range.greater); + retlist = Tcl_NewListObj(myobjc, myobjv); + if (result == TCL_OK) + Tcl_SetObjResult(interp, retlist); +out: + return (result); +} diff --git a/db/tcl/tcl_db_pkg.c b/db/tcl/tcl_db_pkg.c new file mode 100644 index 000000000..f83b5a7d2 --- /dev/null +++ b/db/tcl/tcl_db_pkg.c @@ -0,0 +1,2246 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: tcl_db_pkg.c,v 11.76 2001/01/19 18:02:36 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#endif + +#define DB_DBM_HSEARCH 1 + +#include "db_int.h" +#include "tcl_db.h" + +/* + * Prototypes for procedures defined later in this file: + */ +static int berkdb_Cmd __P((ClientData, Tcl_Interp *, int, + Tcl_Obj * CONST*)); +static int bdb_EnvOpen __P((Tcl_Interp *, int, Tcl_Obj * CONST*, + DBTCL_INFO *, DB_ENV **)); +static int bdb_DbOpen __P((Tcl_Interp *, int, Tcl_Obj * CONST*, + DBTCL_INFO *, DB **)); +static int bdb_DbRemove __P((Tcl_Interp *, int, Tcl_Obj * CONST*)); +static int bdb_DbRename __P((Tcl_Interp *, int, Tcl_Obj * CONST*)); +static int bdb_DbUpgrade __P((Tcl_Interp *, int, Tcl_Obj * CONST*)); +static int bdb_DbVerify __P((Tcl_Interp *, int, Tcl_Obj * CONST*)); +static int bdb_Version __P((Tcl_Interp *, int, Tcl_Obj * CONST*)); +static int bdb_Handles __P((Tcl_Interp *, int, Tcl_Obj * CONST*)); + +/* + * Db_tcl_Init -- + * + * This is a package initialization procedure, which is called by Tcl when + * this package is to be added to an interpreter. The name is based on the + * name of the shared library, currently libdb_tcl-X.Y.so, which Tcl uses + * to determine the name of this function. + */ +int +Db_tcl_Init(interp) + Tcl_Interp *interp; /* Interpreter in which the package is + * to be made available. */ +{ + int code; + + code = Tcl_PkgProvide(interp, "Db_tcl", "1.0"); + if (code != TCL_OK) + return (code); + + Tcl_CreateObjCommand(interp, "berkdb", (Tcl_ObjCmdProc *)berkdb_Cmd, + (ClientData)0, NULL); + /* + * Create shared global debugging variables + */ + Tcl_LinkVar(interp, "__debug_on", (char *)&__debug_on, TCL_LINK_INT); + Tcl_LinkVar(interp, "__debug_print", (char *)&__debug_print, + TCL_LINK_INT); + Tcl_LinkVar(interp, "__debug_stop", (char *)&__debug_stop, + TCL_LINK_INT); + Tcl_LinkVar(interp, "__debug_test", (char *)&__debug_test, + TCL_LINK_INT); + LIST_INIT(&__db_infohead); + return (TCL_OK); +} + +/* + * berkdb_cmd -- + * Implements the "berkdb" command. + * This command supports three sub commands: + * berkdb version - Returns a list {major minor patch} + * berkdb env - Creates a new DB_ENV and returns a binding + * to a new command of the form dbenvX, where X is an + * integer starting at 0 (dbenv0, dbenv1, ...) + * berkdb open - Creates a new DB (optionally within + * the given environment. Returns a binding to a new + * command of the form dbX, where X is an integer + * starting at 0 (db0, db1, ...) + */ +static int +berkdb_Cmd(notused, interp, objc, objv) + ClientData notused; /* Not used. */ + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ +{ + static char *berkdbcmds[] = { + "dbremove", + "dbrename", + "dbverify", + "env", + "envremove", + "handles", + "open", + "upgrade", + "version", + /* All below are compatibility functions */ + "hcreate", "hsearch", "hdestroy", + "dbminit", "fetch", "store", + "delete", "firstkey", "nextkey", + "ndbm_open", "dbmclose", + /* All below are convenience functions */ + "rand", "random_int", "srand", + "debug_check", + NULL + }; + /* + * All commands enums below ending in X are compatibility + */ + enum berkdbcmds { + BDB_DBREMOVE, + BDB_DBRENAME, + BDB_DBVERIFY, + BDB_ENV, + BDB_ENVREMOVE, + BDB_HANDLES, + BDB_OPEN, + BDB_UPGRADE, + BDB_VERSION, + BDB_HCREATEX, BDB_HSEARCHX, BDB_HDESTROYX, + BDB_DBMINITX, BDB_FETCHX, BDB_STOREX, + BDB_DELETEX, BDB_FIRSTKEYX, BDB_NEXTKEYX, + BDB_NDBMOPENX, BDB_DBMCLOSEX, + BDB_RANDX, BDB_RAND_INTX, BDB_SRANDX, + BDB_DBGCKX + }; + static int env_id = 0; + static int db_id = 0; + static int ndbm_id = 0; + + DB *dbp; + DBM *ndbmp; + DBTCL_INFO *ip; + DB_ENV *envp; + Tcl_Obj *res; + int cmdindex, result; + char newname[MSG_SIZE]; + + COMPQUIET(notused, NULL); + + Tcl_ResetResult(interp); + memset(newname, 0, MSG_SIZE); + result = TCL_OK; + if (objc <= 1) { + Tcl_WrongNumArgs(interp, 1, objv, "command cmdargs"); + return (TCL_ERROR); + } + + /* + * Get the command name index from the object based on the berkdbcmds + * defined above. + */ + if (Tcl_GetIndexFromObj(interp, + objv[1], berkdbcmds, "command", TCL_EXACT, &cmdindex) != TCL_OK) + return (IS_HELP(objv[1])); + res = NULL; + switch ((enum berkdbcmds)cmdindex) { + case BDB_VERSION: + _debug_check(); + result = bdb_Version(interp, objc, objv); + break; + case BDB_HANDLES: + result = bdb_Handles(interp, objc, objv); + break; + case BDB_ENV: + snprintf(newname, sizeof(newname), "env%d", env_id); + ip = _NewInfo(interp, NULL, newname, I_ENV); + if (ip != NULL) { + result = bdb_EnvOpen(interp, objc, objv, ip, &envp); + if (result == TCL_OK && envp != NULL) { + env_id++; + Tcl_CreateObjCommand(interp, newname, + (Tcl_ObjCmdProc *)env_Cmd, + (ClientData)envp, NULL); + /* Use ip->i_name - newname is overwritten */ + res = + Tcl_NewStringObj(newname, strlen(newname)); + _SetInfoData(ip, envp); + } else + _DeleteInfo(ip); + } else { + Tcl_SetResult(interp, "Could not set up info", + TCL_STATIC); + result = TCL_ERROR; + } + break; + case BDB_DBREMOVE: + result = bdb_DbRemove(interp, objc, objv); + break; + case BDB_DBRENAME: + result = bdb_DbRename(interp, objc, objv); + break; + case BDB_UPGRADE: + result = bdb_DbUpgrade(interp, objc, objv); + break; + case BDB_DBVERIFY: + result = bdb_DbVerify(interp, objc, objv); + break; + case BDB_ENVREMOVE: + result = tcl_EnvRemove(interp, objc, objv, NULL, NULL); + break; + case BDB_OPEN: + snprintf(newname, sizeof(newname), "db%d", db_id); + ip = _NewInfo(interp, NULL, newname, I_DB); + if (ip != NULL) { + result = bdb_DbOpen(interp, objc, objv, ip, &dbp); + if (result == TCL_OK && dbp != NULL) { + db_id++; + Tcl_CreateObjCommand(interp, newname, + (Tcl_ObjCmdProc *)db_Cmd, + (ClientData)dbp, NULL); + /* Use ip->i_name - newname is overwritten */ + res = + Tcl_NewStringObj(newname, strlen(newname)); + _SetInfoData(ip, dbp); + } else + _DeleteInfo(ip); + } else { + Tcl_SetResult(interp, "Could not set up info", + TCL_STATIC); + result = TCL_ERROR; + } + break; + case BDB_HCREATEX: + case BDB_HSEARCHX: + case BDB_HDESTROYX: + result = bdb_HCommand(interp, objc, objv); + break; + case BDB_DBMINITX: + case BDB_DBMCLOSEX: + case BDB_FETCHX: + case BDB_STOREX: + case BDB_DELETEX: + case BDB_FIRSTKEYX: + case BDB_NEXTKEYX: + result = bdb_DbmCommand(interp, objc, objv, DBTCL_DBM, NULL); + break; + case BDB_NDBMOPENX: + snprintf(newname, sizeof(newname), "ndbm%d", ndbm_id); + ip = _NewInfo(interp, NULL, newname, I_NDBM); + if (ip != NULL) { + result = bdb_NdbmOpen(interp, objc, objv, &ndbmp); + if (result == TCL_OK) { + ndbm_id++; + Tcl_CreateObjCommand(interp, newname, + (Tcl_ObjCmdProc *)ndbm_Cmd, + (ClientData)ndbmp, NULL); + /* Use ip->i_name - newname is overwritten */ + res = + Tcl_NewStringObj(newname, strlen(newname)); + _SetInfoData(ip, ndbmp); + } else + _DeleteInfo(ip); + } else { + Tcl_SetResult(interp, "Could not set up info", + TCL_STATIC); + result = TCL_ERROR; + } + break; + case BDB_RANDX: + case BDB_RAND_INTX: + case BDB_SRANDX: + result = bdb_RandCommand(interp, objc, objv); + break; + case BDB_DBGCKX: + _debug_check(); + res = Tcl_NewIntObj(0); + break; + } + /* + * For each different arg call different function to create + * new commands (or if version, get/return it). + */ + if (result == TCL_OK && res != NULL) + Tcl_SetObjResult(interp, res); + return (result); +} + +/* + * bdb_EnvOpen - + * Implements the environment open command. + * There are many, many options to the open command. + * Here is the general flow: + * + * 1. Call db_env_create to create the env handle. + * 2. Parse args tracking options. + * 3. Make any pre-open setup calls necessary. + * 4. Call DBENV->open to open the env. + * 5. Return env widget handle to user. + */ +static int +bdb_EnvOpen(interp, objc, objv, ip, env) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DBTCL_INFO *ip; /* Our internal info */ + DB_ENV **env; /* Environment pointer */ +{ + static char *envopen[] = { + "-cachesize", + "-cdb", + "-cdb_alldb", + "-client_timeout", + "-create", + "-data_dir", + "-errfile", + "-errpfx", + "-home", + "-lock", + "-lock_conflict", + "-lock_detect", + "-lock_max", + "-lock_max_locks", + "-lock_max_lockers", + "-lock_max_objects", + "-log", + "-log_buffer", + "-log_dir", + "-log_max", + "-mmapsize", + "-mode", + "-nommap", + "-private", + "-recover", + "-recover_fatal", + "-region_init", + "-server", + "-server_timeout", + "-shm_key", + "-system_mem", + "-tmp_dir", + "-txn", + "-txn_max", + "-txn_timestamp", + "-use_environ", + "-use_environ_root", + "-verbose", + NULL + }; + /* + * !!! + * These have to be in the same order as the above, + * which is close to but not quite alphabetical. + */ + enum envopen { + ENV_CACHESIZE, + ENV_CDB, + ENV_CDB_ALLDB, + ENV_CLIENT_TO, + ENV_CREATE, + ENV_DATA_DIR, + ENV_ERRFILE, + ENV_ERRPFX, + ENV_HOME, + ENV_LOCK, + ENV_CONFLICT, + ENV_DETECT, + ENV_LOCK_MAX, + ENV_LOCK_MAX_LOCKS, + ENV_LOCK_MAX_LOCKERS, + ENV_LOCK_MAX_OBJECTS, + ENV_LOG, + ENV_LOG_BUFFER, + ENV_LOG_DIR, + ENV_LOG_MAX, + ENV_MMAPSIZE, + ENV_MODE, + ENV_NOMMAP, + ENV_PRIVATE, + ENV_RECOVER, + ENV_RECOVER_FATAL, + ENV_REGION_INIT, + ENV_SERVER, + ENV_SERVER_TO, + ENV_SHM_KEY, + ENV_SYSTEM_MEM, + ENV_TMP_DIR, + ENV_TXN, + ENV_TXN_MAX, + ENV_TXN_TIME, + ENV_USE_ENVIRON, + ENV_USE_ENVIRON_ROOT, + ENV_VERBOSE + }; + Tcl_Obj **myobjv, **myobjv1; + time_t time; + u_int32_t detect, gbytes, bytes, ncaches, open_flags, set_flag, size; + u_int8_t *conflicts; + int i, intarg, itmp, j, logbufset, logmaxset; + int mode, myobjc, nmodes, optindex, result, ret, temp; + long client_to, server_to, shm; + char *arg, *home, *server; + + result = TCL_OK; + mode = 0; + set_flag = 0; + home = NULL; + /* + * XXX + * If/when our Tcl interface becomes thread-safe, we should enable + * DB_THREAD here. Note that DB_THREAD currently does not work + * with log_get -next, -prev; if we wish to enable DB_THREAD, + * those must either be made thread-safe first or we must come up with + * a workaround. (We used to specify DB_THREAD if and only if + * logging was not configured.) + */ + open_flags = DB_JOINENV; + logmaxset = logbufset = 0; + + if (objc <= 2) { + Tcl_WrongNumArgs(interp, 2, objv, "?args?"); + return (TCL_ERROR); + } + + /* + * Server code must go before the call to db_env_create. + */ + server = NULL; + server_to = client_to = 0; + i = 2; + while (i < objc) { + if (Tcl_GetIndexFromObj(interp, objv[i++], envopen, "option", + TCL_EXACT, &optindex) != TCL_OK) { + Tcl_ResetResult(interp); + continue; + } + switch ((enum envopen)optindex) { + case ENV_SERVER: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-server hostname"); + result = TCL_ERROR; + break; + } + server = Tcl_GetStringFromObj(objv[i++], NULL); + break; + case ENV_SERVER_TO: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-server_to secs"); + result = TCL_ERROR; + break; + } + result = Tcl_GetLongFromObj(interp, objv[i++], + &server_to); + break; + case ENV_CLIENT_TO: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-client_to secs"); + result = TCL_ERROR; + break; + } + result = Tcl_GetLongFromObj(interp, objv[i++], + &client_to); + break; + default: + break; + } + } + if (server != NULL) { + ret = db_env_create(env, DB_CLIENT); + if (ret) + return (_ReturnSetup(interp, ret, "db_env_create")); + (*env)->set_errpfx((*env), ip->i_name); + (*env)->set_errcall((*env), _ErrorFunc); + if ((ret = (*env)->set_server((*env), server, + client_to, server_to, 0)) != 0) { + result = TCL_ERROR; + goto error; + } + } else { + /* + * Create the environment handle before parsing the args + * since we'll be modifying the environment as we parse. + */ + ret = db_env_create(env, 0); + if (ret) + return (_ReturnSetup(interp, ret, "db_env_create")); + (*env)->set_errpfx((*env), ip->i_name); + (*env)->set_errcall((*env), _ErrorFunc); + } + + /* + * Get the command name index from the object based on the bdbcmds + * defined above. + */ + i = 2; + while (i < objc) { + if (Tcl_GetIndexFromObj(interp, objv[i], envopen, "option", + TCL_EXACT, &optindex) != TCL_OK) { + result = IS_HELP(objv[i]); + goto error; + } + i++; + switch ((enum envopen)optindex) { + case ENV_SERVER: + case ENV_SERVER_TO: + case ENV_CLIENT_TO: + /* + * Already handled these, skip them and their arg. + */ + i++; + break; + case ENV_CDB: + FLD_SET(open_flags, DB_INIT_CDB | DB_INIT_MPOOL); + FLD_CLR(open_flags, DB_JOINENV); + break; + case ENV_CDB_ALLDB: + FLD_SET(set_flag, DB_CDB_ALLDB); + break; + case ENV_LOCK: + FLD_SET(open_flags, DB_INIT_LOCK | DB_INIT_MPOOL); + FLD_CLR(open_flags, DB_JOINENV); + break; + case ENV_LOG: + FLD_SET(open_flags, DB_INIT_LOG | DB_INIT_MPOOL); + FLD_CLR(open_flags, DB_JOINENV); + break; + case ENV_TXN: + FLD_SET(open_flags, DB_INIT_LOCK | + DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN); + FLD_CLR(open_flags, DB_JOINENV); + /* Make sure we have an arg to check against! */ + if (i < objc) { + arg = Tcl_GetStringFromObj(objv[i], NULL); + if (strcmp(arg, "nosync") == 0) { + FLD_SET(set_flag, DB_TXN_NOSYNC); + i++; + } + } + break; + case ENV_CREATE: + FLD_SET(open_flags, DB_CREATE | DB_INIT_MPOOL); + FLD_CLR(open_flags, DB_JOINENV); + break; + case ENV_HOME: + /* Make sure we have an arg to check against! */ + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-home dir?"); + result = TCL_ERROR; + break; + } + home = Tcl_GetStringFromObj(objv[i++], NULL); + break; + case ENV_MODE: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-mode mode?"); + result = TCL_ERROR; + break; + } + /* + * Don't need to check result here because + * if TCL_ERROR, the error message is already + * set up, and we'll bail out below. If ok, + * the mode is set and we go on. + */ + result = Tcl_GetIntFromObj(interp, objv[i++], &mode); + break; + case ENV_NOMMAP: + FLD_SET(set_flag, DB_NOMMAP); + break; + case ENV_PRIVATE: + FLD_SET(open_flags, DB_PRIVATE | DB_INIT_MPOOL); + FLD_CLR(open_flags, DB_JOINENV); + break; + case ENV_RECOVER: + FLD_SET(open_flags, DB_RECOVER); + break; + case ENV_RECOVER_FATAL: + FLD_SET(open_flags, DB_RECOVER_FATAL); + break; + case ENV_SYSTEM_MEM: + FLD_SET(open_flags, DB_SYSTEM_MEM); + break; + case ENV_USE_ENVIRON_ROOT: + FLD_SET(open_flags, DB_USE_ENVIRON_ROOT); + break; + case ENV_USE_ENVIRON: + FLD_SET(open_flags, DB_USE_ENVIRON); + break; + case ENV_VERBOSE: + result = Tcl_ListObjGetElements(interp, objv[i], + &myobjc, &myobjv); + if (result == TCL_OK) + i++; + else + break; + if (myobjc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-verbose {which on|off}?"); + result = TCL_ERROR; + break; + } + result = tcl_EnvVerbose(interp, *env, + myobjv[0], myobjv[1]); + break; + case ENV_REGION_INIT: + _debug_check(); + ret = db_env_set_region_init(1); + result = _ReturnSetup(interp, ret, "region_init"); + break; + case ENV_CACHESIZE: + result = Tcl_ListObjGetElements(interp, objv[i], + &myobjc, &myobjv); + if (result == TCL_OK) + i++; + else + break; + j = 0; + if (myobjc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-cachesize {gbytes bytes ncaches}?"); + result = TCL_ERROR; + break; + } + result = Tcl_GetIntFromObj(interp, myobjv[0], &itmp); + gbytes = itmp; + if (result != TCL_OK) + break; + result = Tcl_GetIntFromObj(interp, myobjv[1], &itmp); + bytes = itmp; + if (result != TCL_OK) + break; + result = Tcl_GetIntFromObj(interp, myobjv[2], &itmp); + ncaches = itmp; + if (result != TCL_OK) + break; + _debug_check(); + ret = (*env)->set_cachesize(*env, gbytes, bytes, + ncaches); + result = _ReturnSetup(interp, ret, "set_cachesize"); + break; + case ENV_MMAPSIZE: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-mmapsize size?"); + result = TCL_ERROR; + break; + } + result = Tcl_GetIntFromObj(interp, objv[i++], &intarg); + if (result == TCL_OK) { + _debug_check(); + ret = (*env)->set_mp_mmapsize(*env, + (size_t)intarg); + result = _ReturnSetup(interp, ret, "mmapsize"); + } + break; + case ENV_SHM_KEY: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-shm_key key?"); + result = TCL_ERROR; + break; + } + result = Tcl_GetLongFromObj(interp, objv[i++], &shm); + if (result == TCL_OK) { + _debug_check(); + ret = (*env)->set_shm_key(*env, shm); + result = _ReturnSetup(interp, ret, "shm_key"); + } + break; + case ENV_LOG_MAX: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-log_max max?"); + result = TCL_ERROR; + break; + } + result = Tcl_GetIntFromObj(interp, objv[i++], &intarg); + if (result == TCL_OK && logbufset) { + _debug_check(); + ret = (*env)->set_lg_max(*env, + (u_int32_t)intarg); + result = _ReturnSetup(interp, ret, "log_max"); + logbufset = 0; + } else + logmaxset = intarg; + break; + case ENV_LOG_BUFFER: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-log_buffer size?"); + result = TCL_ERROR; + break; + } + result = Tcl_GetIntFromObj(interp, objv[i++], &intarg); + if (result == TCL_OK) { + _debug_check(); + ret = (*env)->set_lg_bsize(*env, + (u_int32_t)intarg); + result = _ReturnSetup(interp, ret, "log_bsize"); + logbufset = 1; + if (logmaxset) { + _debug_check(); + ret = (*env)->set_lg_max(*env, + (u_int32_t)logmaxset); + result = _ReturnSetup(interp, ret, + "log_max"); + logmaxset = 0; + logbufset = 0; + } + } + break; + case ENV_CONFLICT: + /* + * Get conflict list. List is: + * {nmodes {matrix}} + * + * Where matrix must be nmodes*nmodes big. + * Set up conflicts array to pass. + */ + result = Tcl_ListObjGetElements(interp, objv[i], + &myobjc, &myobjv); + if (result == TCL_OK) + i++; + else + break; + if (myobjc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-lock_conflict {nmodes {matrix}}?"); + result = TCL_ERROR; + break; + } + result = Tcl_GetIntFromObj(interp, myobjv[0], &nmodes); + if (result != TCL_OK) + break; + result = Tcl_ListObjGetElements(interp, myobjv[1], + &myobjc, &myobjv1); + if (myobjc != (nmodes * nmodes)) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-lock_conflict {nmodes {matrix}}?"); + result = TCL_ERROR; + break; + } + size = sizeof(u_int8_t) * nmodes*nmodes; + ret = __os_malloc(*env, size, NULL, &conflicts); + if (ret != 0) { + result = TCL_ERROR; + break; + } + for (j = 0; j < myobjc; j++) { + result = Tcl_GetIntFromObj(interp, myobjv1[j], + &temp); + conflicts[j] = temp; + if (result != TCL_OK) { + __os_free(conflicts, size); + break; + } + } + _debug_check(); + ret = (*env)->set_lk_conflicts(*env, + (u_int8_t *)conflicts, nmodes); + __os_free(conflicts, size); + result = _ReturnSetup(interp, ret, "set_lk_conflicts"); + break; + case ENV_DETECT: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-lock_detect policy?"); + result = TCL_ERROR; + break; + } + arg = Tcl_GetStringFromObj(objv[i++], NULL); + if (strcmp(arg, "default") == 0) + detect = DB_LOCK_DEFAULT; + else if (strcmp(arg, "oldest") == 0) + detect = DB_LOCK_OLDEST; + else if (strcmp(arg, "youngest") == 0) + detect = DB_LOCK_YOUNGEST; + else if (strcmp(arg, "random") == 0) + detect = DB_LOCK_RANDOM; + else { + Tcl_AddErrorInfo(interp, + "lock_detect: illegal policy"); + result = TCL_ERROR; + break; + } + _debug_check(); + ret = (*env)->set_lk_detect(*env, detect); + result = _ReturnSetup(interp, ret, "lock_detect"); + break; + case ENV_LOCK_MAX: + case ENV_LOCK_MAX_LOCKS: + case ENV_LOCK_MAX_LOCKERS: + case ENV_LOCK_MAX_OBJECTS: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-lock_max max?"); + result = TCL_ERROR; + break; + } + result = Tcl_GetIntFromObj(interp, objv[i++], &intarg); + if (result == TCL_OK) { + _debug_check(); + switch ((enum envopen)optindex) { + case ENV_LOCK_MAX: + ret = (*env)->set_lk_max(*env, + (u_int32_t)intarg); + break; + case ENV_LOCK_MAX_LOCKS: + ret = (*env)->set_lk_max_locks(*env, + (u_int32_t)intarg); + break; + case ENV_LOCK_MAX_LOCKERS: + ret = (*env)->set_lk_max_lockers(*env, + (u_int32_t)intarg); + break; + case ENV_LOCK_MAX_OBJECTS: + ret = (*env)->set_lk_max_objects(*env, + (u_int32_t)intarg); + break; + default: + break; + } + result = _ReturnSetup(interp, ret, "lock_max"); + } + break; + case ENV_TXN_MAX: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-txn_max max?"); + result = TCL_ERROR; + break; + } + result = Tcl_GetIntFromObj(interp, objv[i++], &intarg); + if (result == TCL_OK) { + _debug_check(); + ret = (*env)->set_tx_max(*env, + (u_int32_t)intarg); + result = _ReturnSetup(interp, ret, "txn_max"); + } + break; + case ENV_TXN_TIME: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-txn_timestamp time?"); + result = TCL_ERROR; + break; + } + result = Tcl_GetLongFromObj(interp, objv[i++], + (long *)&time); + if (result == TCL_OK) { + _debug_check(); + ret = (*env)->set_tx_timestamp(*env, &time); + result = _ReturnSetup(interp, ret, + "txn_timestamp"); + } + break; + case ENV_ERRFILE: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "-errfile file"); + result = TCL_ERROR; + break; + } + arg = Tcl_GetStringFromObj(objv[i++], NULL); + /* + * If the user already set one, close it. + */ + if (ip->i_err != NULL) + fclose(ip->i_err); + ip->i_err = fopen(arg, "a"); + if (ip->i_err != NULL) { + _debug_check(); + (*env)->set_errfile(*env, ip->i_err); + } + break; + case ENV_ERRPFX: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "-errpfx prefix"); + result = TCL_ERROR; + break; + } + arg = Tcl_GetStringFromObj(objv[i++], NULL); + /* + * If the user already set one, free it. + */ + if (ip->i_errpfx != NULL) + __os_freestr(ip->i_errpfx); + if ((ret = + __os_strdup(*env, arg, &ip->i_errpfx)) != 0) { + result = _ReturnSetup(interp, ret, + "__os_strdup"); + break; + } + if (ip->i_errpfx != NULL) { + _debug_check(); + (*env)->set_errpfx(*env, ip->i_errpfx); + } + break; + case ENV_DATA_DIR: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "-data_dir dir"); + result = TCL_ERROR; + break; + } + arg = Tcl_GetStringFromObj(objv[i++], NULL); + _debug_check(); + ret = (*env)->set_data_dir(*env, arg); + result = _ReturnSetup(interp, ret, "set_data_dir"); + break; + case ENV_LOG_DIR: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "-log_dir dir"); + result = TCL_ERROR; + break; + } + arg = Tcl_GetStringFromObj(objv[i++], NULL); + _debug_check(); + ret = (*env)->set_lg_dir(*env, arg); + result = _ReturnSetup(interp, ret, "set_lg_dir"); + break; + case ENV_TMP_DIR: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "-tmp_dir dir"); + result = TCL_ERROR; + break; + } + arg = Tcl_GetStringFromObj(objv[i++], NULL); + _debug_check(); + ret = (*env)->set_tmp_dir(*env, arg); + result = _ReturnSetup(interp, ret, "set_tmp_dir"); + break; + } + /* + * If, at any time, parsing the args we get an error, + * bail out and return. + */ + if (result != TCL_OK) + goto error; + } + + /* + * We have to check this here. We want to set the log buffer + * size first, if it is specified. So if the user did so, + * then we took care of it above. But, if we get out here and + * logmaxset is non-zero, then they set the log_max without + * resetting the log buffer size, so we now have to do the + * call to set_lg_max, since we didn't do it above. + */ + if (logmaxset) { + _debug_check(); + ret = (*env)->set_lg_max(*env, (u_int32_t)logmaxset); + result = _ReturnSetup(interp, ret, "log_max"); + } + + if (result != TCL_OK) + goto error; + + if (set_flag) { + ret = (*env)->set_flags(*env, set_flag, 1); + result = _ReturnSetup(interp, ret, "set_flags"); + if (result == TCL_ERROR) + goto error; + /* + * If we are successful, clear the result so that the + * return from set_flags isn't part of the result. + */ + Tcl_ResetResult(interp); + } + /* + * When we get here, we have already parsed all of our args + * and made all our calls to set up the environment. Everything + * is okay so far, no errors, if we get here. + * + * Now open the environment. + */ + _debug_check(); + ret = (*env)->open(*env, home, open_flags, mode); + result = _ReturnSetup(interp, ret, "env open"); + +error: + if (result == TCL_ERROR) { + if (ip->i_err) { + fclose(ip->i_err); + ip->i_err = NULL; + } + (void)(*env)->close(*env, 0); + *env = NULL; + } + return (result); +} + +/* + * bdb_DbOpen -- + * Implements the "db_create/db_open" command. + * There are many, many options to the open command. + * Here is the general flow: + * + * 0. Preparse args to determine if we have -env. + * 1. Call db_create to create the db handle. + * 2. Parse args tracking options. + * 3. Make any pre-open setup calls necessary. + * 4. Call DB->open to open the database. + * 5. Return db widget handle to user. + */ +static int +bdb_DbOpen(interp, objc, objv, ip, dbp) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DBTCL_INFO *ip; /* Our internal info */ + DB **dbp; /* DB handle */ +{ + static char *bdbenvopen[] = { + "-env", NULL + }; + enum bdbenvopen { + TCL_DB_ENV0 + }; + static char *bdbopen[] = { + "-btree", + "-cachesize", + "-create", + "-delim", + "-dup", + "-dupsort", + "-env", + "-errfile", + "-errpfx", + "-excl", + "-extent", + "-ffactor", + "-hash", + "-len", + "-lorder", + "-minkey", + "-mode", + "-nelem", + "-nommap", + "-pad", + "-pagesize", + "-queue", + "-rdonly", + "-recno", + "-recnum", + "-renumber", + "-revsplitoff", + "-snapshot", + "-source", + "-truncate", + "-test", + "-unknown", + "--", + NULL + }; + enum bdbopen { + TCL_DB_BTREE, + TCL_DB_CACHESIZE, + TCL_DB_CREATE, + TCL_DB_DELIM, + TCL_DB_DUP, + TCL_DB_DUPSORT, + TCL_DB_ENV, + TCL_DB_ERRFILE, + TCL_DB_ERRPFX, + TCL_DB_EXCL, + TCL_DB_EXTENT, + TCL_DB_FFACTOR, + TCL_DB_HASH, + TCL_DB_LEN, + TCL_DB_LORDER, + TCL_DB_MINKEY, + TCL_DB_MODE, + TCL_DB_NELEM, + TCL_DB_NOMMAP, + TCL_DB_PAD, + TCL_DB_PAGESIZE, + TCL_DB_QUEUE, + TCL_DB_RDONLY, + TCL_DB_RECNO, + TCL_DB_RECNUM, + TCL_DB_RENUMBER, + TCL_DB_REVSPLIT, + TCL_DB_SNAPSHOT, + TCL_DB_SOURCE, + TCL_DB_TRUNCATE, + TCL_DB_TEST, + TCL_DB_UNKNOWN, + TCL_DB_ENDARG + }; + + DBTCL_INFO *envip, *errip; + DBTYPE type; + DB_ENV *envp; + Tcl_Obj **myobjv; + u_int32_t gbytes, bytes, ncaches, open_flags; + int endarg, i, intarg, itmp, j, mode, myobjc; + int optindex, result, ret, set_err, set_flag, set_pfx, subdblen; + u_char *subdbtmp; + char *arg, *db, *subdb; + extern u_int32_t __ham_test __P((DB *, const void *, u_int32_t)); + + type = DB_UNKNOWN; + endarg = mode = set_err = set_flag = set_pfx = 0; + result = TCL_OK; + subdbtmp = NULL; + db = subdb = NULL; + + /* + * XXX + * If/when our Tcl interface becomes thread-safe, we should enable + * DB_THREAD here. See comment in bdb_EnvOpen(). + */ + open_flags = 0; + envp = NULL; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 2, objv, "?args?"); + return (TCL_ERROR); + } + + /* + * We must first parse for the environment flag, since that + * is needed for db_create. Then create the db handle. + */ + i = 2; + while (i < objc) { + if (Tcl_GetIndexFromObj(interp, objv[i++], bdbenvopen, + "option", TCL_EXACT, &optindex) != TCL_OK) { + /* + * Reset the result so we don't get + * an errant error message if there is another error. + */ + Tcl_ResetResult(interp); + continue; + } + switch ((enum bdbenvopen)optindex) { + case TCL_DB_ENV0: + arg = Tcl_GetStringFromObj(objv[i], NULL); + envp = NAME_TO_ENV(arg); + if (envp == NULL) { + Tcl_SetResult(interp, + "db open: illegal environment", TCL_STATIC); + return (TCL_ERROR); + } + } + break; + } + + /* + * Create the db handle before parsing the args + * since we'll be modifying the database options as we parse. + */ + ret = db_create(dbp, envp, 0); + if (ret) + return (_ReturnSetup(interp, ret, "db_create")); + + /* + * XXX Remove restriction when err stuff is not tied to env. + * + * The DB->set_err* functions actually overwrite in the + * environment. So, if we are explicitly using an env, + * don't overwrite what we have already set up. If we are + * not using one, then we set up since we get a private + * default env. + */ + /* XXX - remove this conditional if/when err is not tied to env */ + if (envp == NULL) { + (*dbp)->set_errpfx((*dbp), ip->i_name); + (*dbp)->set_errcall((*dbp), _ErrorFunc); + } + envip = _PtrToInfo(envp); /* XXX */ + /* + * If we are using an env, we keep track of err info in the env's ip. + * Otherwise use the DB's ip. + */ + if (envip) + errip = envip; + else + errip = ip; + /* + * Get the option name index from the object based on the args + * defined above. + */ + i = 2; + while (i < objc) { + if (Tcl_GetIndexFromObj(interp, objv[i], bdbopen, "option", + TCL_EXACT, &optindex) != TCL_OK) { + arg = Tcl_GetStringFromObj(objv[i], NULL); + if (arg[0] == '-') { + result = IS_HELP(objv[i]); + goto error; + } else + Tcl_ResetResult(interp); + break; + } + i++; + switch ((enum bdbopen)optindex) { + case TCL_DB_ENV: + /* + * Already parsed this, skip it and the env pointer. + */ + i++; + continue; + case TCL_DB_BTREE: + if (type != DB_UNKNOWN) { + Tcl_SetResult(interp, + "Too many DB types specified", TCL_STATIC); + result = TCL_ERROR; + goto error; + } + type = DB_BTREE; + break; + case TCL_DB_HASH: + if (type != DB_UNKNOWN) { + Tcl_SetResult(interp, + "Too many DB types specified", TCL_STATIC); + result = TCL_ERROR; + goto error; + } + type = DB_HASH; + break; + case TCL_DB_RECNO: + if (type != DB_UNKNOWN) { + Tcl_SetResult(interp, + "Too many DB types specified", TCL_STATIC); + result = TCL_ERROR; + goto error; + } + type = DB_RECNO; + break; + case TCL_DB_QUEUE: + if (type != DB_UNKNOWN) { + Tcl_SetResult(interp, + "Too many DB types specified", TCL_STATIC); + result = TCL_ERROR; + goto error; + } + type = DB_QUEUE; + break; + case TCL_DB_UNKNOWN: + if (type != DB_UNKNOWN) { + Tcl_SetResult(interp, + "Too many DB types specified", TCL_STATIC); + result = TCL_ERROR; + goto error; + } + break; + case TCL_DB_CREATE: + open_flags |= DB_CREATE; + break; + case TCL_DB_EXCL: + open_flags |= DB_EXCL; + break; + case TCL_DB_RDONLY: + open_flags |= DB_RDONLY; + break; + case TCL_DB_TRUNCATE: + open_flags |= DB_TRUNCATE; + break; + case TCL_DB_TEST: + (*dbp)->set_h_hash(*dbp, __ham_test); + break; + case TCL_DB_MODE: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-mode mode?"); + result = TCL_ERROR; + break; + } + /* + * Don't need to check result here because + * if TCL_ERROR, the error message is already + * set up, and we'll bail out below. If ok, + * the mode is set and we go on. + */ + result = Tcl_GetIntFromObj(interp, objv[i++], &mode); + break; + case TCL_DB_NOMMAP: + open_flags |= DB_NOMMAP; + break; + case TCL_DB_DUP: + set_flag |= DB_DUP; + break; + case TCL_DB_DUPSORT: + set_flag |= DB_DUPSORT; + break; + case TCL_DB_RECNUM: + set_flag |= DB_RECNUM; + break; + case TCL_DB_RENUMBER: + set_flag |= DB_RENUMBER; + break; + case TCL_DB_REVSPLIT: + set_flag |= DB_REVSPLITOFF; + break; + case TCL_DB_SNAPSHOT: + set_flag |= DB_SNAPSHOT; + break; + case TCL_DB_FFACTOR: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "-ffactor density"); + result = TCL_ERROR; + break; + } + result = Tcl_GetIntFromObj(interp, objv[i++], &intarg); + if (result == TCL_OK) { + _debug_check(); + ret = (*dbp)->set_h_ffactor(*dbp, + (u_int32_t)intarg); + result = _ReturnSetup(interp, ret, + "set_h_ffactor"); + } + break; + case TCL_DB_NELEM: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "-nelem nelem"); + result = TCL_ERROR; + break; + } + result = Tcl_GetIntFromObj(interp, objv[i++], &intarg); + if (result == TCL_OK) { + _debug_check(); + ret = (*dbp)->set_h_nelem(*dbp, + (u_int32_t)intarg); + result = _ReturnSetup(interp, ret, + "set_h_nelem"); + } + break; + case TCL_DB_LORDER: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "-lorder 1234|4321"); + result = TCL_ERROR; + break; + } + result = Tcl_GetIntFromObj(interp, objv[i++], &intarg); + if (result == TCL_OK) { + _debug_check(); + ret = (*dbp)->set_lorder(*dbp, + (u_int32_t)intarg); + result = _ReturnSetup(interp, ret, + "set_lorder"); + } + break; + case TCL_DB_DELIM: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "-delim delim"); + result = TCL_ERROR; + break; + } + result = Tcl_GetIntFromObj(interp, objv[i++], &intarg); + if (result == TCL_OK) { + _debug_check(); + ret = (*dbp)->set_re_delim(*dbp, intarg); + result = _ReturnSetup(interp, ret, + "set_re_delim"); + } + break; + case TCL_DB_LEN: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "-len length"); + result = TCL_ERROR; + break; + } + result = Tcl_GetIntFromObj(interp, objv[i++], &intarg); + if (result == TCL_OK) { + _debug_check(); + ret = (*dbp)->set_re_len(*dbp, + (u_int32_t)intarg); + result = _ReturnSetup(interp, ret, + "set_re_len"); + } + break; + case TCL_DB_PAD: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "-pad pad"); + result = TCL_ERROR; + break; + } + result = Tcl_GetIntFromObj(interp, objv[i++], &intarg); + if (result == TCL_OK) { + _debug_check(); + ret = (*dbp)->set_re_pad(*dbp, intarg); + result = _ReturnSetup(interp, ret, + "set_re_pad"); + } + break; + case TCL_DB_SOURCE: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "-source file"); + result = TCL_ERROR; + break; + } + arg = Tcl_GetStringFromObj(objv[i++], NULL); + _debug_check(); + ret = (*dbp)->set_re_source(*dbp, arg); + result = _ReturnSetup(interp, ret, "set_re_source"); + break; + case TCL_DB_EXTENT: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "-extent size"); + result = TCL_ERROR; + break; + } + result = Tcl_GetIntFromObj(interp, objv[i++], &intarg); + if (result == TCL_OK) { + _debug_check(); + ret = (*dbp)->set_q_extentsize(*dbp, + (u_int32_t)intarg); + result = _ReturnSetup(interp, ret, + "set_q_extentsize"); + } + break; + case TCL_DB_MINKEY: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "-minkey minkey"); + result = TCL_ERROR; + break; + } + result = Tcl_GetIntFromObj(interp, objv[i++], &intarg); + if (result == TCL_OK) { + _debug_check(); + ret = (*dbp)->set_bt_minkey(*dbp, intarg); + result = _ReturnSetup(interp, ret, + "set_bt_minkey"); + } + break; + case TCL_DB_CACHESIZE: + result = Tcl_ListObjGetElements(interp, objv[i++], + &myobjc, &myobjv); + if (result != TCL_OK) + break; + j = 0; + if (myobjc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-cachesize {gbytes bytes ncaches}?"); + result = TCL_ERROR; + break; + } + result = Tcl_GetIntFromObj(interp, myobjv[0], &itmp); + gbytes = itmp; + if (result != TCL_OK) + break; + result = Tcl_GetIntFromObj(interp, myobjv[1], &itmp); + bytes = itmp; + if (result != TCL_OK) + break; + result = Tcl_GetIntFromObj(interp, myobjv[2], &itmp); + ncaches = itmp; + if (result != TCL_OK) + break; + _debug_check(); + ret = (*dbp)->set_cachesize(*dbp, gbytes, bytes, + ncaches); + result = _ReturnSetup(interp, ret, + "set_cachesize"); + break; + case TCL_DB_PAGESIZE: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-pagesize size?"); + result = TCL_ERROR; + break; + } + result = Tcl_GetIntFromObj(interp, objv[i++], &intarg); + if (result == TCL_OK) { + _debug_check(); + ret = (*dbp)->set_pagesize(*dbp, + (size_t)intarg); + result = _ReturnSetup(interp, ret, + "set pagesize"); + } + break; + case TCL_DB_ERRFILE: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "-errfile file"); + result = TCL_ERROR; + break; + } + arg = Tcl_GetStringFromObj(objv[i++], NULL); + /* + * If the user already set one, close it. + */ + if (errip->i_err != NULL) + fclose(errip->i_err); + errip->i_err = fopen(arg, "a"); + if (errip->i_err != NULL) { + _debug_check(); + (*dbp)->set_errfile(*dbp, errip->i_err); + set_err = 1; + } + break; + case TCL_DB_ERRPFX: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "-errpfx prefix"); + result = TCL_ERROR; + break; + } + arg = Tcl_GetStringFromObj(objv[i++], NULL); + /* + * If the user already set one, free it. + */ + if (errip->i_errpfx != NULL) + __os_freestr(errip->i_errpfx); + if ((ret = __os_strdup((*dbp)->dbenv, + arg, &errip->i_errpfx)) != 0) { + result = _ReturnSetup(interp, ret, + "__os_strdup"); + break; + } + if (errip->i_errpfx != NULL) { + _debug_check(); + (*dbp)->set_errpfx(*dbp, errip->i_errpfx); + set_pfx = 1; + } + break; + case TCL_DB_ENDARG: + endarg = 1; + break; + } /* switch */ + + /* + * If, at any time, parsing the args we get an error, + * bail out and return. + */ + if (result != TCL_OK) + goto error; + if (endarg) + break; + } + if (result != TCL_OK) + goto error; + + /* + * Any args we have left, (better be 0, 1 or 2 left) are + * file names. If we have 0, then an in-memory db. If + * there is 1, a db name, if 2 a db and subdb name. + */ + if (i != objc) { + /* + * Dbs must be NULL terminated file names, but subdbs can + * be anything. Use Strings for the db name and byte + * arrays for the subdb. + */ + db = Tcl_GetStringFromObj(objv[i++], NULL); + if (i != objc) { + subdbtmp = + Tcl_GetByteArrayFromObj(objv[i++], &subdblen); + if ((ret = __os_malloc(envp, + subdblen + 1, NULL, &subdb)) != 0) { + Tcl_SetResult(interp, db_strerror(ret), + TCL_STATIC); + return (0); + } + memcpy(subdb, subdbtmp, subdblen); + subdb[subdblen] = '\0'; + } + } + if (set_flag) { + ret = (*dbp)->set_flags(*dbp, set_flag); + result = _ReturnSetup(interp, ret, "set_flags"); + if (result == TCL_ERROR) + goto error; + /* + * If we are successful, clear the result so that the + * return from set_flags isn't part of the result. + */ + Tcl_ResetResult(interp); + } + + /* + * When we get here, we have already parsed all of our args and made + * all our calls to set up the database. Everything is okay so far, + * no errors, if we get here. + */ + _debug_check(); + + /* Open the database. */ + ret = (*dbp)->open(*dbp, db, subdb, type, open_flags, mode); + result = _ReturnSetup(interp, ret, "db open"); + +error: + if (subdb) + __os_free(subdb, subdblen + 1); + if (result == TCL_ERROR) { + /* + * If we opened and set up the error file in the environment + * on this open, but we failed for some other reason, clean + * up and close the file. + * + * XXX when err stuff isn't tied to env, change to use ip, + * instead of envip. Also, set_err is irrelevant when that + * happens. It will just read: + * if (ip->i_err) + * fclose(ip->i_err); + */ + if (set_err && errip && errip->i_err != NULL) { + fclose(errip->i_err); + errip->i_err = NULL; + } + if (set_pfx && errip && errip->i_errpfx != NULL) { + __os_freestr(errip->i_errpfx); + errip->i_errpfx = NULL; + } + (void)(*dbp)->close(*dbp, 0); + *dbp = NULL; + } + return (result); +} + +/* + * bdb_DbRemove -- + * Implements the DB->remove command. + */ +static int +bdb_DbRemove(interp, objc, objv) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ +{ + static char *bdbrem[] = { + "-env", "--", NULL + }; + enum bdbrem { + TCL_DBREM_ENV, + TCL_DBREM_ENDARG + }; + DB_ENV *envp; + DB *dbp; + int endarg, i, optindex, result, ret, subdblen; + u_char *subdbtmp; + char *arg, *db, *subdb; + + envp = NULL; + dbp = NULL; + result = TCL_OK; + subdbtmp = NULL; + db = subdb = NULL; + endarg = 0; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 2, objv, "?args? filename ?database?"); + return (TCL_ERROR); + } + + /* + * We must first parse for the environment flag, since that + * is needed for db_create. Then create the db handle. + */ + i = 2; + while (i < objc) { + if (Tcl_GetIndexFromObj(interp, objv[i], bdbrem, + "option", TCL_EXACT, &optindex) != TCL_OK) { + arg = Tcl_GetStringFromObj(objv[i], NULL); + if (arg[0] == '-') { + result = IS_HELP(objv[i]); + goto error; + } else + Tcl_ResetResult(interp); + break; + } + i++; + switch ((enum bdbrem)optindex) { + case TCL_DBREM_ENV: + arg = Tcl_GetStringFromObj(objv[i++], NULL); + envp = NAME_TO_ENV(arg); + if (envp == NULL) { + Tcl_SetResult(interp, + "db remove: illegal environment", + TCL_STATIC); + return (TCL_ERROR); + } + break; + case TCL_DBREM_ENDARG: + endarg = 1; + break; + } + /* + * If, at any time, parsing the args we get an error, + * bail out and return. + */ + if (result != TCL_OK) + goto error; + if (endarg) + break; + } + if (result != TCL_OK) + goto error; + /* + * Any args we have left, (better be 1 or 2 left) are + * file names. If there is 1, a db name, if 2 a db and subdb name. + */ + if ((i != (objc - 1)) || (i != (objc - 2))) { + /* + * Dbs must be NULL terminated file names, but subdbs can + * be anything. Use Strings for the db name and byte + * arrays for the subdb. + */ + db = Tcl_GetStringFromObj(objv[i++], NULL); + if (i != objc) { + subdbtmp = + Tcl_GetByteArrayFromObj(objv[i++], &subdblen); + if ((ret = __os_malloc(envp, subdblen + 1, + NULL, &subdb)) != 0) { Tcl_SetResult(interp, + db_strerror(ret), TCL_STATIC); + return (0); + } + memcpy(subdb, subdbtmp, subdblen); + subdb[subdblen] = '\0'; + } + } else { + Tcl_WrongNumArgs(interp, 2, objv, "?args? filename ?database?"); + result = TCL_ERROR; + goto error; + } + ret = db_create(&dbp, envp, 0); + if (ret) { + result = _ReturnSetup(interp, ret, "db_create"); + goto error; + } + /* + * No matter what, we NULL out dbp after this call. + */ + ret = dbp->remove(dbp, db, subdb, 0); + result = _ReturnSetup(interp, ret, "db remove"); + dbp = NULL; +error: + if (subdb) + __os_free(subdb, subdblen + 1); + if (result == TCL_ERROR && dbp) + (void)dbp->close(dbp, 0); + return (result); +} + +/* + * bdb_DbRename -- + * Implements the DB->rename command. + */ +static int +bdb_DbRename(interp, objc, objv) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ +{ + static char *bdbmv[] = { + "-env", "--", NULL + }; + enum bdbmv { + TCL_DBMV_ENV, + TCL_DBMV_ENDARG + }; + DB_ENV *envp; + DB *dbp; + int endarg, i, newlen, optindex, result, ret, subdblen; + u_char *subdbtmp; + char *arg, *db, *newname, *subdb; + + envp = NULL; + dbp = NULL; + result = TCL_OK; + subdbtmp = NULL; + db = newname = subdb = NULL; + endarg = 0; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, + 3, objv, "?args? filename ?database? ?newname?"); + return (TCL_ERROR); + } + + /* + * We must first parse for the environment flag, since that + * is needed for db_create. Then create the db handle. + */ + i = 2; + while (i < objc) { + if (Tcl_GetIndexFromObj(interp, objv[i], bdbmv, + "option", TCL_EXACT, &optindex) != TCL_OK) { + arg = Tcl_GetStringFromObj(objv[i], NULL); + if (arg[0] == '-') { + result = IS_HELP(objv[i]); + goto error; + } else + Tcl_ResetResult(interp); + break; + } + i++; + switch ((enum bdbmv)optindex) { + case TCL_DBMV_ENV: + arg = Tcl_GetStringFromObj(objv[i++], NULL); + envp = NAME_TO_ENV(arg); + if (envp == NULL) { + Tcl_SetResult(interp, + "db rename: illegal environment", + TCL_STATIC); + return (TCL_ERROR); + } + break; + case TCL_DBMV_ENDARG: + endarg = 1; + break; + } + /* + * If, at any time, parsing the args we get an error, + * bail out and return. + */ + if (result != TCL_OK) + goto error; + if (endarg) + break; + } + if (result != TCL_OK) + goto error; + /* + * Any args we have left, (better be 2 or 3 left) are + * file names. If there is 2, a file name, if 3 a file and db name. + */ + if ((i != (objc - 2)) || (i != (objc - 3))) { + /* + * Dbs must be NULL terminated file names, but subdbs can + * be anything. Use Strings for the db name and byte + * arrays for the subdb. + */ + db = Tcl_GetStringFromObj(objv[i++], NULL); + if (i == objc - 2) { + subdbtmp = + Tcl_GetByteArrayFromObj(objv[i++], &subdblen); + if ((ret = __os_malloc(envp, subdblen + 1, + NULL, &subdb)) != 0) { + Tcl_SetResult(interp, + db_strerror(ret), TCL_STATIC); + return (0); + } + memcpy(subdb, subdbtmp, subdblen); + subdb[subdblen] = '\0'; + } + subdbtmp = + Tcl_GetByteArrayFromObj(objv[i++], &newlen); + if ((ret = __os_malloc(envp, newlen + 1, + NULL, &newname)) != 0) { + Tcl_SetResult(interp, + db_strerror(ret), TCL_STATIC); + return (0); + } + memcpy(newname, subdbtmp, newlen); + newname[newlen] = '\0'; + } else { + Tcl_WrongNumArgs(interp, 3, objv, "?args? filename ?database? ?newname?"); + result = TCL_ERROR; + goto error; + } + ret = db_create(&dbp, envp, 0); + if (ret) { + result = _ReturnSetup(interp, ret, "db_create"); + goto error; + } + /* + * No matter what, we NULL out dbp after this call. + */ + ret = dbp->rename(dbp, db, subdb, newname, 0); + result = _ReturnSetup(interp, ret, "db rename"); + dbp = NULL; +error: + if (subdb) + __os_free(subdb, subdblen + 1); + if (newname) + __os_free(newname, newlen + 1); + if (result == TCL_ERROR && dbp) + (void)dbp->close(dbp, 0); + return (result); +} + +/* + * bdb_DbVerify -- + * Implements the DB->verify command. + */ +static int +bdb_DbVerify(interp, objc, objv) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ +{ + static char *bdbverify[] = { + "-env", "-errfile", "-errpfx", "--", NULL + }; + enum bdbvrfy { + TCL_DBVRFY_ENV, + TCL_DBVRFY_ERRFILE, + TCL_DBVRFY_ERRPFX, + TCL_DBVRFY_ENDARG + }; + DB_ENV *envp; + DB *dbp; + FILE *errf; + int endarg, i, optindex, result, ret, flags; + char *arg, *db, *errpfx; + + envp = NULL; + dbp = NULL; + result = TCL_OK; + db = errpfx = NULL; + errf = NULL; + flags = endarg = 0; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 2, objv, "?args? filename"); + return (TCL_ERROR); + } + + /* + * We must first parse for the environment flag, since that + * is needed for db_create. Then create the db handle. + */ + i = 2; + while (i < objc) { + if (Tcl_GetIndexFromObj(interp, objv[i], bdbverify, + "option", TCL_EXACT, &optindex) != TCL_OK) { + arg = Tcl_GetStringFromObj(objv[i], NULL); + if (arg[0] == '-') { + result = IS_HELP(objv[i]); + goto error; + } else + Tcl_ResetResult(interp); + break; + } + i++; + switch ((enum bdbvrfy)optindex) { + case TCL_DBVRFY_ENV: + arg = Tcl_GetStringFromObj(objv[i++], NULL); + envp = NAME_TO_ENV(arg); + if (envp == NULL) { + Tcl_SetResult(interp, + "db verify: illegal environment", + TCL_STATIC); + result = TCL_ERROR; + break; + } + break; + case TCL_DBVRFY_ERRFILE: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "-errfile file"); + result = TCL_ERROR; + break; + } + arg = Tcl_GetStringFromObj(objv[i++], NULL); + /* + * If the user already set one, close it. + */ + if (errf != NULL) + fclose(errf); + errf = fopen(arg, "a"); + break; + case TCL_DBVRFY_ERRPFX: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "-errpfx prefix"); + result = TCL_ERROR; + break; + } + arg = Tcl_GetStringFromObj(objv[i++], NULL); + /* + * If the user already set one, free it. + */ + if (errpfx != NULL) + __os_freestr(errpfx); + if ((ret = __os_strdup(NULL, arg, &errpfx)) != 0) { + result = _ReturnSetup(interp, ret, + "__os_strdup"); + break; + } + break; + case TCL_DBVRFY_ENDARG: + endarg = 1; + break; + } + /* + * If, at any time, parsing the args we get an error, + * bail out and return. + */ + if (result != TCL_OK) + goto error; + if (endarg) + break; + } + if (result != TCL_OK) + goto error; + /* + * The remaining arg is the db filename. + */ + if (i == (objc - 1)) + db = Tcl_GetStringFromObj(objv[i++], NULL); + else { + Tcl_WrongNumArgs(interp, 2, objv, "?args? filename"); + result = TCL_ERROR; + goto error; + } + ret = db_create(&dbp, envp, 0); + if (ret) { + result = _ReturnSetup(interp, ret, "db_create"); + goto error; + } + + if (errf != NULL) + dbp->set_errfile(dbp, errf); + if (errpfx != NULL) + dbp->set_errpfx(dbp, errpfx); + + ret = dbp->verify(dbp, db, NULL, NULL, flags); + result = _ReturnSetup(interp, ret, "db verify"); +error: + if (errf != NULL) + fclose(errf); + if (errpfx != NULL) + __os_freestr(errpfx); + if (dbp) + (void)dbp->close(dbp, 0); + return (result); +} + +/* + * bdb_Version -- + * Implements the version command. + */ +static int +bdb_Version(interp, objc, objv) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ +{ + static char *bdbver[] = { + "-string", NULL + }; + enum bdbver { + TCL_VERSTRING + }; + int i, optindex, maj, min, patch, result, string, verobjc; + char *arg, *v; + Tcl_Obj *res, *verobjv[3]; + + result = TCL_OK; + string = 0; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 2, objv, "?args?"); + return (TCL_ERROR); + } + + /* + * We must first parse for the environment flag, since that + * is needed for db_create. Then create the db handle. + */ + i = 2; + while (i < objc) { + if (Tcl_GetIndexFromObj(interp, objv[i], bdbver, + "option", TCL_EXACT, &optindex) != TCL_OK) { + arg = Tcl_GetStringFromObj(objv[i], NULL); + if (arg[0] == '-') { + result = IS_HELP(objv[i]); + goto error; + } else + Tcl_ResetResult(interp); + break; + } + i++; + switch ((enum bdbver)optindex) { + case TCL_VERSTRING: + string = 1; + break; + } + /* + * If, at any time, parsing the args we get an error, + * bail out and return. + */ + if (result != TCL_OK) + goto error; + } + if (result != TCL_OK) + goto error; + + v = db_version(&maj, &min, &patch); + if (string) + res = Tcl_NewStringObj(v, strlen(v)); + else { + verobjc = 3; + verobjv[0] = Tcl_NewIntObj(maj); + verobjv[1] = Tcl_NewIntObj(min); + verobjv[2] = Tcl_NewIntObj(patch); + res = Tcl_NewListObj(verobjc, verobjv); + } + Tcl_SetObjResult(interp, res); +error: + return (result); +} + +/* + * bdb_Handles -- + * Implements the handles command. + */ +static int +bdb_Handles(interp, objc, objv) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ +{ + DBTCL_INFO *p; + Tcl_Obj *res, *handle; + + /* + * No args. Error if we have some + */ + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, ""); + return (TCL_ERROR); + } + res = Tcl_NewListObj(0, NULL); + + for (p = LIST_FIRST(&__db_infohead); p != NULL; + p = LIST_NEXT(p, entries)) { + handle = Tcl_NewStringObj(p->i_name, strlen(p->i_name)); + if (Tcl_ListObjAppendElement(interp, res, handle) != TCL_OK) + return (TCL_ERROR); + } + Tcl_SetObjResult(interp, res); + return (TCL_OK); +} + +/* + * bdb_DbUpgrade -- + * Implements the DB->upgrade command. + */ +static int +bdb_DbUpgrade(interp, objc, objv) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ +{ + static char *bdbupg[] = { + "-dupsort", "-env", "--", NULL + }; + enum bdbupg { + TCL_DBUPG_DUPSORT, + TCL_DBUPG_ENV, + TCL_DBUPG_ENDARG + }; + DB_ENV *envp; + DB *dbp; + int endarg, i, optindex, result, ret, flags; + char *arg, *db; + + envp = NULL; + dbp = NULL; + result = TCL_OK; + db = NULL; + flags = endarg = 0; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 2, objv, "?args? filename"); + return (TCL_ERROR); + } + + i = 2; + while (i < objc) { + if (Tcl_GetIndexFromObj(interp, objv[i], bdbupg, + "option", TCL_EXACT, &optindex) != TCL_OK) { + arg = Tcl_GetStringFromObj(objv[i], NULL); + if (arg[0] == '-') { + result = IS_HELP(objv[i]); + goto error; + } else + Tcl_ResetResult(interp); + break; + } + i++; + switch ((enum bdbupg)optindex) { + case TCL_DBUPG_DUPSORT: + flags |= DB_DUPSORT; + break; + case TCL_DBUPG_ENV: + arg = Tcl_GetStringFromObj(objv[i++], NULL); + envp = NAME_TO_ENV(arg); + if (envp == NULL) { + Tcl_SetResult(interp, + "db upgrade: illegal environment", + TCL_STATIC); + return (TCL_ERROR); + } + break; + case TCL_DBUPG_ENDARG: + endarg = 1; + break; + } + /* + * If, at any time, parsing the args we get an error, + * bail out and return. + */ + if (result != TCL_OK) + goto error; + if (endarg) + break; + } + if (result != TCL_OK) + goto error; + /* + * The remaining arg is the db filename. + */ + if (i == (objc - 1)) + db = Tcl_GetStringFromObj(objv[i++], NULL); + else { + Tcl_WrongNumArgs(interp, 2, objv, "?args? filename"); + result = TCL_ERROR; + goto error; + } + ret = db_create(&dbp, envp, 0); + if (ret) { + result = _ReturnSetup(interp, ret, "db_create"); + goto error; + } + + ret = dbp->upgrade(dbp, db, flags); + result = _ReturnSetup(interp, ret, "db upgrade"); +error: + if (dbp) + (void)dbp->close(dbp, 0); + return (result); +} diff --git a/db/tcl/tcl_dbcursor.c b/db/tcl/tcl_dbcursor.c new file mode 100644 index 000000000..26e7b58c6 --- /dev/null +++ b/db/tcl/tcl_dbcursor.c @@ -0,0 +1,744 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: tcl_dbcursor.c,v 11.26 2001/01/11 18:19:55 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#endif + +#include "db_int.h" +#include "tcl_db.h" + +/* + * Prototypes for procedures defined later in this file: + */ +static int tcl_DbcDup __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DBC *)); +static int tcl_DbcGet __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DBC *)); +static int tcl_DbcPut __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DBC *)); + +/* + * PUBLIC: int dbc_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*)); + * + * dbc_cmd -- + * Implements the cursor command. + */ +int +dbc_Cmd(clientData, interp, objc, objv) + ClientData clientData; /* Cursor handle */ + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ +{ + static char *dbccmds[] = { + "close", + "del", + "dup", + "get", + "put", + NULL + }; + enum dbccmds { + DBCCLOSE, + DBCDELETE, + DBCDUP, + DBCGET, + DBCPUT + }; + DBC *dbc; + DBTCL_INFO *dbip; + int cmdindex, result, ret; + + Tcl_ResetResult(interp); + dbc = (DBC *)clientData; + dbip = _PtrToInfo((void *)dbc); + result = TCL_OK; + + if (objc <= 1) { + Tcl_WrongNumArgs(interp, 1, objv, "command cmdargs"); + return (TCL_ERROR); + } + if (dbc == NULL) { + Tcl_SetResult(interp, "NULL dbc pointer", TCL_STATIC); + return (TCL_ERROR); + } + if (dbip == NULL) { + Tcl_SetResult(interp, "NULL dbc info pointer", TCL_STATIC); + return (TCL_ERROR); + } + + /* + * Get the command name index from the object based on the berkdbcmds + * defined above. + */ + if (Tcl_GetIndexFromObj(interp, objv[1], dbccmds, "command", + TCL_EXACT, &cmdindex) != TCL_OK) + return (IS_HELP(objv[1])); + switch ((enum dbccmds)cmdindex) { + case DBCCLOSE: + /* + * No args for this. Error if there are some. + */ + if (objc > 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + _debug_check(); + ret = dbc->c_close(dbc); + result = _ReturnSetup(interp, ret, "dbc close"); + if (result == TCL_OK) { + (void)Tcl_DeleteCommand(interp, dbip->i_name); + _DeleteInfo(dbip); + } + break; + case DBCDELETE: + /* + * No args for this. Error if there are some. + */ + if (objc > 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + _debug_check(); + ret = dbc->c_del(dbc, 0); + result = _ReturnSetup(interp, ret, "dbc delete"); + break; + case DBCDUP: + result = tcl_DbcDup(interp, objc, objv, dbc); + break; + case DBCGET: + result = tcl_DbcGet(interp, objc, objv, dbc); + break; + case DBCPUT: + result = tcl_DbcPut(interp, objc, objv, dbc); + break; + } + return (result); +} + +/* + * tcl_DbcPut -- + */ +static int +tcl_DbcPut(interp, objc, objv, dbc) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DBC *dbc; /* Cursor pointer */ +{ + static char *dbcutopts[] = { + "-after", "-before", "-current", + "-keyfirst", "-keylast", "-nodupdata", + "-partial", + NULL + }; + enum dbcutopts { + DBCPUT_AFTER, DBCPUT_BEFORE, DBCPUT_CURRENT, + DBCPUT_KEYFIRST,DBCPUT_KEYLAST, DBCPUT_NODUPDATA, + DBCPUT_PART + }; + DB *thisdbp; + DBT key, data; + DBTCL_INFO *dbcip, *dbip; + DBTYPE type; + Tcl_Obj **elemv, *res; + db_recno_t recno; + u_int32_t flag; + int elemc, i, itmp, optindex, result, ret; + + result = TCL_OK; + flag = 0; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 2, objv, "?-args? ?key?"); + return (TCL_ERROR); + } + + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + + /* + * Get the command name index from the object based on the options + * defined above. + */ + i = 2; + while (i < (objc - 1)) { + if (Tcl_GetIndexFromObj(interp, objv[i], dbcutopts, "option", + TCL_EXACT, &optindex) != TCL_OK) { + /* + * Reset the result so we don't get + * an errant error message if there is another error. + */ + if (IS_HELP(objv[i]) == TCL_OK) { + result = TCL_OK; + goto out; + } + Tcl_ResetResult(interp); + break; + } + i++; + switch ((enum dbcutopts)optindex) { + case DBCPUT_AFTER: + FLAG_CHECK(flag); + flag = DB_AFTER; + break; + case DBCPUT_BEFORE: + FLAG_CHECK(flag); + flag = DB_BEFORE; + break; + case DBCPUT_CURRENT: + FLAG_CHECK(flag); + flag = DB_CURRENT; + break; + case DBCPUT_KEYFIRST: + FLAG_CHECK(flag); + flag = DB_KEYFIRST; + break; + case DBCPUT_KEYLAST: + FLAG_CHECK(flag); + flag = DB_KEYLAST; + break; + case DBCPUT_NODUPDATA: + FLAG_CHECK(flag); + flag = DB_NODUPDATA; + break; + case DBCPUT_PART: + if (i > (objc - 2)) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-partial {offset length}?"); + result = TCL_ERROR; + break; + } + /* + * Get sublist as {offset length} + */ + result = Tcl_ListObjGetElements(interp, objv[i++], + &elemc, &elemv); + if (elemc != 2) { + Tcl_SetResult(interp, + "List must be {offset length}", TCL_STATIC); + result = TCL_ERROR; + break; + } + data.flags |= DB_DBT_PARTIAL; + result = Tcl_GetIntFromObj(interp, elemv[0], &itmp); + data.doff = itmp; + if (result != TCL_OK) + break; + result = Tcl_GetIntFromObj(interp, elemv[1], &itmp); + data.dlen = itmp; + /* + * NOTE: We don't check result here because all we'd + * do is break anyway, and we are doing that. If you + * add code here, you WILL need to add the check + * for result. (See the check for save.doff, a few + * lines above and copy that.) + */ + } + if (result != TCL_OK) + break; + } + if (result != TCL_OK) + goto out; + + /* + * We need to determine if we are a recno database or not. If we are, + * then key.data is a recno, not a string. + */ + dbcip = _PtrToInfo(dbc); + if (dbcip == NULL) + type = DB_UNKNOWN; + else { + dbip = dbcip->i_parent; + if (dbip == NULL) { + Tcl_SetResult(interp, "Cursor without parent database", + TCL_STATIC); + result = TCL_ERROR; + return (result); + } + thisdbp = dbip->i_dbp; + type = thisdbp->get_type(thisdbp); + } + /* + * When we get here, we better have: + * 1 arg if -after, -before or -current + * 2 args in all other cases + */ + if (flag == DB_AFTER || flag == DB_BEFORE || flag == DB_CURRENT) { + if (i != (objc - 1)) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-args? data"); + result = TCL_ERROR; + goto out; + } + /* + * We want to get the key back, so we need to set + * up the location to get it back in. + */ + if (type == DB_RECNO || type == DB_QUEUE) { + recno = 0; + key.data = &recno; + key.size = sizeof(db_recno_t); + } + } else { + if (i != (objc - 2)) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-args? key data"); + result = TCL_ERROR; + goto out; + } + if (type == DB_RECNO || type == DB_QUEUE) { + result = Tcl_GetIntFromObj(interp, objv[objc-2], &itmp); + recno = itmp; + if (result == TCL_OK) { + key.data = &recno; + key.size = sizeof(db_recno_t); + } else + return (result); + } else { + key.data = Tcl_GetByteArrayFromObj(objv[objc-2], &itmp); + key.size = itmp; + } + } + data.data = Tcl_GetByteArrayFromObj(objv[objc-1], &itmp); + data.size = itmp; + _debug_check(); + ret = dbc->c_put(dbc, &key, &data, flag); + result = _ReturnSetup(interp, ret, "dbc put"); + if (ret == 0 && (flag == DB_AFTER || flag == DB_BEFORE) + && type == DB_RECNO) { + res = Tcl_NewIntObj(*(db_recno_t *)key.data); + Tcl_SetObjResult(interp, res); + } +out: + return (result); +} + +/* + * tcl_dbc_get -- + */ +static int +tcl_DbcGet(interp, objc, objv, dbc) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DBC *dbc; /* Cursor pointer */ +{ + static char *dbcgetopts[] = { + "-current", + "-first", + "-get_both", + "-get_recno", + "-join_item", + "-last", + "-next", + "-nextdup", + "-nextnodup", + "-partial", + "-prev", + "-prevnodup", + "-rmw", + "-set", + "-set_range", + "-set_recno", + NULL + }; + enum dbcgetopts { + DBCGET_CURRENT, + DBCGET_FIRST, + DBCGET_BOTH, + DBCGET_RECNO, + DBCGET_JOIN, + DBCGET_LAST, + DBCGET_NEXT, + DBCGET_NEXTDUP, + DBCGET_NEXTNODUP, + DBCGET_PART, + DBCGET_PREV, + DBCGET_PREVNODUP, + DBCGET_RMW, + DBCGET_SET, + DBCGET_SETRANGE, + DBCGET_SETRECNO + }; + DB *thisdbp; + DBT key, data; + DBTCL_INFO *dbcip, *dbip; + DBTYPE type; + Tcl_Obj **elemv, *myobj, *retlist; + db_recno_t recno; + u_int32_t flag; + int elemc, i, itmp, optindex, result, ret; + + result = TCL_OK; + flag = 0; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 2, objv, "?-args? ?key?"); + return (TCL_ERROR); + } + + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + /* + * Get the command name index from the object based on the options + * defined above. + */ + i = 2; + while (i < objc) { + if (Tcl_GetIndexFromObj(interp, objv[i], dbcgetopts, + "option", TCL_EXACT, &optindex) != TCL_OK) { + /* + * Reset the result so we don't get + * an errant error message if there is another error. + */ + if (IS_HELP(objv[i]) == TCL_OK) { + result = TCL_OK; + goto out; + } + Tcl_ResetResult(interp); + break; + } + i++; + switch ((enum dbcgetopts)optindex) { + case DBCGET_RMW: + flag |= DB_RMW; + break; + case DBCGET_CURRENT: + FLAG_CHECK2(flag, DB_RMW); + flag |= DB_CURRENT; + break; + case DBCGET_FIRST: + FLAG_CHECK2(flag, DB_RMW); + flag |= DB_FIRST; + break; + case DBCGET_LAST: + FLAG_CHECK2(flag, DB_RMW); + flag |= DB_LAST; + break; + case DBCGET_NEXT: + FLAG_CHECK2(flag, DB_RMW); + flag |= DB_NEXT; + break; + case DBCGET_PREV: + FLAG_CHECK2(flag, DB_RMW); + flag |= DB_PREV; + break; + case DBCGET_PREVNODUP: + FLAG_CHECK2(flag, DB_RMW); + flag |= DB_PREV_NODUP; + break; + case DBCGET_NEXTNODUP: + FLAG_CHECK2(flag, DB_RMW); + flag |= DB_NEXT_NODUP; + break; + case DBCGET_NEXTDUP: + FLAG_CHECK2(flag, DB_RMW); + flag |= DB_NEXT_DUP; + break; + case DBCGET_BOTH: + FLAG_CHECK2(flag, DB_RMW); + flag |= DB_GET_BOTH; + break; + case DBCGET_RECNO: + FLAG_CHECK2(flag, DB_RMW); + flag |= DB_GET_RECNO; + break; + case DBCGET_JOIN: + FLAG_CHECK2(flag, DB_RMW); + flag |= DB_JOIN_ITEM; + break; + case DBCGET_SET: + FLAG_CHECK2(flag, DB_RMW); + flag |= DB_SET; + break; + case DBCGET_SETRANGE: + FLAG_CHECK2(flag, DB_RMW); + flag |= DB_SET_RANGE; + break; + case DBCGET_SETRECNO: + FLAG_CHECK2(flag, DB_RMW); + flag |= DB_SET_RECNO; + break; + case DBCGET_PART: + if (i == objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-partial {offset length}?"); + result = TCL_ERROR; + break; + } + /* + * Get sublist as {offset length} + */ + result = Tcl_ListObjGetElements(interp, objv[i++], + &elemc, &elemv); + if (elemc != 2) { + Tcl_SetResult(interp, + "List must be {offset length}", TCL_STATIC); + result = TCL_ERROR; + break; + } + data.flags |= DB_DBT_PARTIAL; + result = Tcl_GetIntFromObj(interp, elemv[0], &itmp); + data.doff = itmp; + if (result != TCL_OK) + break; + result = Tcl_GetIntFromObj(interp, elemv[1], &itmp); + data.dlen = itmp; + /* + * NOTE: We don't check result here because all we'd + * do is break anyway, and we are doing that. If you + * add code here, you WILL need to add the check + * for result. (See the check for save.doff, a few + * lines above and copy that.) + */ + break; + } + if (result != TCL_OK) + break; + } + if (result != TCL_OK) + goto out; + + /* + * We need to determine if we are a recno database + * or not. If we are, then key.data is a recno, not + * a string. + */ + dbcip = _PtrToInfo(dbc); + if (dbcip == NULL) + type = DB_UNKNOWN; + else { + dbip = dbcip->i_parent; + if (dbip == NULL) { + Tcl_SetResult(interp, "Cursor without parent database", + TCL_STATIC); + result = TCL_ERROR; + goto out; + } + thisdbp = dbip->i_dbp; + type = thisdbp->get_type(thisdbp); + } + /* + * When we get here, we better have: + * 2 args, key and data if GET_BOTH was specified. + * 1 arg if -set, -set_range or -set_recno + * 0 in all other cases. + */ + if ((flag & DB_OPFLAGS_MASK) == DB_GET_BOTH) { + if (i != (objc - 2)) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-args? -get_both key data"); + result = TCL_ERROR; + goto out; + } else { + if (type == DB_RECNO || type == DB_QUEUE) { + result = Tcl_GetIntFromObj( + interp, objv[objc-2], &itmp); + recno = itmp; + if (result == TCL_OK) { + key.data = &recno; + key.size = sizeof(db_recno_t); + } else + goto out; + } else { + key.data = Tcl_GetByteArrayFromObj( + objv[objc - 2], &itmp); + key.size = itmp; + } + data.data = + Tcl_GetByteArrayFromObj(objv[objc - 1], &itmp); + data.size = itmp; + } + } else if ((flag & DB_OPFLAGS_MASK) == DB_SET || + (flag & DB_OPFLAGS_MASK) == DB_SET_RANGE || + (flag & DB_OPFLAGS_MASK) == DB_SET_RECNO) { + if (i != (objc - 1)) { + Tcl_WrongNumArgs(interp, 2, objv, "?-args? key"); + result = TCL_ERROR; + goto out; + } + data.flags |= DB_DBT_MALLOC; + if ((flag & DB_OPFLAGS_MASK) == DB_SET_RECNO || + type == DB_RECNO || type == DB_QUEUE) { + result = Tcl_GetIntFromObj(interp, + objv[objc - 1], (int *)&recno); + key.data = &recno; + key.size = sizeof(db_recno_t); + } else { + key.data = + Tcl_GetByteArrayFromObj(objv[objc - 1], &itmp); + key.size = itmp; + } + } else { + if (i != objc) { + Tcl_WrongNumArgs(interp, 2, objv, "?-args?"); + result = TCL_ERROR; + goto out; + } + key.flags |= DB_DBT_MALLOC; + data.flags |= DB_DBT_MALLOC; + } + + _debug_check(); + ret = dbc->c_get(dbc, &key, &data, flag); + result = _ReturnSetup(interp, ret, "dbc get"); + if (result == TCL_ERROR) + goto out; + + retlist = Tcl_NewListObj(0, NULL); + if (ret == DB_NOTFOUND) + goto out1; + if ((flag & DB_OPFLAGS_MASK) == DB_GET_RECNO) { + recno = *((db_recno_t *)data.data); + myobj = Tcl_NewIntObj((int)recno); + result = Tcl_ListObjAppendElement(interp, retlist, myobj); + } else { + if ((type == DB_RECNO || type == DB_QUEUE) && key.data != NULL) + result = _SetListRecnoElem(interp, retlist, + *(db_recno_t *)key.data, data.data, data.size); + else + result = _SetListElem(interp, retlist, + key.data, key.size, data.data, data.size); + } + if (key.flags & DB_DBT_MALLOC) + __os_free(key.data, key.size); + if (data.flags & DB_DBT_MALLOC) + __os_free(data.data, data.size); +out1: + if (result == TCL_OK) + Tcl_SetObjResult(interp, retlist); +out: + return (result); + +} + +/* + * tcl_DbcDup -- + */ +static int +tcl_DbcDup(interp, objc, objv, dbc) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DBC *dbc; /* Cursor pointer */ +{ + static char *dbcdupopts[] = { + "-position", + NULL + }; + enum dbcdupopts { + DBCDUP_POS + }; + DB *thisdbp; + DBC *newdbc; + DBTCL_INFO *dbcip, *newdbcip, *dbip; + Tcl_Obj *res; + u_int32_t flag; + int i, optindex, result, ret; + char newname[MSG_SIZE]; + + result = TCL_OK; + flag = 0; + res = NULL; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 2, objv, "?-args?"); + return (TCL_ERROR); + } + + /* + * Get the command name index from the object based on the options + * defined above. + */ + i = 2; + while (i < objc) { + if (Tcl_GetIndexFromObj(interp, objv[i], dbcdupopts, + "option", TCL_EXACT, &optindex) != TCL_OK) { + /* + * Reset the result so we don't get + * an errant error message if there is another error. + */ + if (IS_HELP(objv[i]) == TCL_OK) { + result = TCL_OK; + goto out; + } + Tcl_ResetResult(interp); + break; + } + i++; + switch ((enum dbcdupopts)optindex) { + case DBCDUP_POS: + flag = DB_POSITION; + break; + } + if (result != TCL_OK) + break; + } + if (result != TCL_OK) + goto out; + + /* + * We need to determine if we are a recno database + * or not. If we are, then key.data is a recno, not + * a string. + */ + dbcip = _PtrToInfo(dbc); + if (dbcip == NULL) { + Tcl_SetResult(interp, "Cursor without info structure", + TCL_STATIC); + result = TCL_ERROR; + goto out; + } else { + dbip = dbcip->i_parent; + if (dbip == NULL) { + Tcl_SetResult(interp, "Cursor without parent database", + TCL_STATIC); + result = TCL_ERROR; + goto out; + } + thisdbp = dbip->i_dbp; + } + /* + * Now duplicate the cursor. If successful, we need to create + * a new cursor command. + */ + + snprintf(newname, sizeof(newname), + "%s.c%d", dbip->i_name, dbip->i_dbdbcid); + newdbcip = _NewInfo(interp, NULL, newname, I_DBC); + if (newdbcip != NULL) { + ret = dbc->c_dup(dbc, &newdbc, flag); + if (ret == 0) { + dbip->i_dbdbcid++; + newdbcip->i_parent = dbip; + Tcl_CreateObjCommand(interp, newname, + (Tcl_ObjCmdProc *)dbc_Cmd, + (ClientData)newdbc, NULL); + res = Tcl_NewStringObj(newname, strlen(newname)); + _SetInfoData(newdbcip, newdbc); + Tcl_SetObjResult(interp, res); + } else { + result = _ReturnSetup(interp, ret, "db dup"); + _DeleteInfo(newdbcip); + } + } else { + Tcl_SetResult(interp, "Could not set up info", TCL_STATIC); + result = TCL_ERROR; + } +out: + return (result); + +} diff --git a/db/tcl/tcl_env.c b/db/tcl/tcl_env.c new file mode 100644 index 000000000..cb7b0d974 --- /dev/null +++ b/db/tcl/tcl_env.c @@ -0,0 +1,678 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: tcl_env.c,v 11.33 2001/01/11 18:19:55 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#endif + +#include "db_int.h" +#include "tcl_db.h" + +/* + * Prototypes for procedures defined later in this file: + */ +static void _EnvInfoDelete __P((Tcl_Interp *, DBTCL_INFO *)); + +/* + * PUBLIC: int env_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*)); + * + * env_Cmd -- + * Implements the "env" command. + */ +int +env_Cmd(clientData, interp, objc, objv) + ClientData clientData; /* Env handle */ + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ +{ + static char *envcmds[] = { + "close", + "lock_detect", + "lock_id", + "lock_get", + "lock_stat", + "lock_vec", + "log_archive", + "log_compare", + "log_file", + "log_flush", + "log_get", + "log_put", + "log_register", + "log_stat", + "log_unregister", + "mpool", + "mpool_stat", + "mpool_sync", + "mpool_trickle", + "mutex", +#if CONFIG_TEST + "test", +#endif + "txn", + "txn_checkpoint", + "txn_stat", + "verbose", + NULL + }; + enum envcmds { + ENVCLOSE, + ENVLKDETECT, + ENVLKID, + ENVLKGET, + ENVLKSTAT, + ENVLKVEC, + ENVLOGARCH, + ENVLOGCMP, + ENVLOGFILE, + ENVLOGFLUSH, + ENVLOGGET, + ENVLOGPUT, + ENVLOGREG, + ENVLOGSTAT, + ENVLOGUNREG, + ENVMP, + ENVMPSTAT, + ENVMPSYNC, + ENVTRICKLE, + ENVMUTEX, +#if CONFIG_TEST + ENVTEST, +#endif + ENVTXN, + ENVTXNCKP, + ENVTXNSTAT, + ENVVERB + }; + DBTCL_INFO *envip; + DB_ENV *envp; + Tcl_Obj *res; + u_int32_t newval; + int cmdindex, result, ret; + + Tcl_ResetResult(interp); + envp = (DB_ENV *)clientData; + envip = _PtrToInfo((void *)envp); + result = TCL_OK; + + if (objc <= 1) { + Tcl_WrongNumArgs(interp, 1, objv, "command cmdargs"); + return (TCL_ERROR); + } + if (envp == NULL) { + Tcl_SetResult(interp, "NULL env pointer", TCL_STATIC); + return (TCL_ERROR); + } + if (envip == NULL) { + Tcl_SetResult(interp, "NULL env info pointer", TCL_STATIC); + return (TCL_ERROR); + } + + /* + * Get the command name index from the object based on the berkdbcmds + * defined above. + */ + if (Tcl_GetIndexFromObj(interp, objv[1], envcmds, "command", + TCL_EXACT, &cmdindex) != TCL_OK) + return (IS_HELP(objv[1])); + res = NULL; + switch ((enum envcmds)cmdindex) { + case ENVCLOSE: + /* + * No args for this. Error if there are some. + */ + if (objc > 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + /* + * Any transactions will be aborted, and an mpools + * closed automatically. We must delete any txn + * and mp widgets we have here too for this env. + * NOTE: envip is freed when we come back from + * this function. Set it to NULL to make sure no + * one tries to use it later. + */ + _EnvInfoDelete(interp, envip); + envip = NULL; + _debug_check(); + ret = envp->close(envp, 0); + result = _ReturnSetup(interp, ret, "env close"); + break; + case ENVLKDETECT: + result = tcl_LockDetect(interp, objc, objv, envp); + break; + case ENVLKSTAT: + result = tcl_LockStat(interp, objc, objv, envp); + break; + case ENVLKID: + /* + * No args for this. Error if there are some. + */ + if (objc > 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + _debug_check(); + ret = lock_id(envp, &newval); + result = _ReturnSetup(interp, ret, "lock_id"); + if (result == TCL_OK) + res = Tcl_NewIntObj((int)newval); + break; + case ENVLKGET: + result = tcl_LockGet(interp, objc, objv, envp); + break; + case ENVLKVEC: + result = tcl_LockVec(interp, objc, objv, envp); + break; + case ENVLOGARCH: + result = tcl_LogArchive(interp, objc, objv, envp); + break; + case ENVLOGCMP: + result = tcl_LogCompare(interp, objc, objv); + break; + case ENVLOGFILE: + result = tcl_LogFile(interp, objc, objv, envp); + break; + case ENVLOGFLUSH: + result = tcl_LogFlush(interp, objc, objv, envp); + break; + case ENVLOGGET: + result = tcl_LogGet(interp, objc, objv, envp); + break; + case ENVLOGPUT: + result = tcl_LogPut(interp, objc, objv, envp); + break; + case ENVLOGREG: + result = tcl_LogRegister(interp, objc, objv, envp); + break; + case ENVLOGUNREG: + result = tcl_LogUnregister(interp, objc, objv, envp); + break; + case ENVLOGSTAT: + result = tcl_LogStat(interp, objc, objv, envp); + break; + case ENVMPSTAT: + result = tcl_MpStat(interp, objc, objv, envp); + break; + case ENVMPSYNC: + result = tcl_MpSync(interp, objc, objv, envp); + break; + case ENVTRICKLE: + result = tcl_MpTrickle(interp, objc, objv, envp); + break; + case ENVMP: + result = tcl_Mp(interp, objc, objv, envp, envip); + break; + case ENVTXNCKP: + result = tcl_TxnCheckpoint(interp, objc, objv, envp); + break; + case ENVTXNSTAT: + result = tcl_TxnStat(interp, objc, objv, envp); + break; + case ENVTXN: + result = tcl_Txn(interp, objc, objv, envp, envip); + break; + case ENVMUTEX: + result = tcl_Mutex(interp, objc, objv, envp, envip); + break; +#if CONFIG_TEST + case ENVTEST: + result = tcl_EnvTest(interp, objc, objv, envp); + break; +#endif + case ENVVERB: + /* + * Two args for this. Error if different. + */ + if (objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + result = tcl_EnvVerbose(interp, envp, objv[2], objv[3]); + break; + } + /* + * Only set result if we have a res. Otherwise, lower + * functions have already done so. + */ + if (result == TCL_OK && res) + Tcl_SetObjResult(interp, res); + return (result); +} + +/* + * PUBLIC: int tcl_EnvRemove __P((Tcl_Interp *, int, Tcl_Obj * CONST*, + * PUBLIC: DB_ENV *, DBTCL_INFO *)); + * + * tcl_EnvRemove -- + */ +int +tcl_EnvRemove(interp, objc, objv, envp, envip) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB_ENV *envp; /* Env pointer */ + DBTCL_INFO *envip; /* Info pointer */ +{ + static char *envremopts[] = { + "-data_dir", + "-force", + "-home", + "-log_dir", + "-server", + "-tmp_dir", + "-use_environ", + "-use_environ_root", + NULL + }; + enum envremopts { + ENVREM_DATADIR, + ENVREM_FORCE, + ENVREM_HOME, + ENVREM_LOGDIR, + ENVREM_SERVER, + ENVREM_TMPDIR, + ENVREM_USE_ENVIRON, + ENVREM_USE_ENVIRON_ROOT + }; + DB_ENV *e; + u_int32_t cflag, flag, forceflag; + int i, optindex, result, ret; + char *datadir, *home, *logdir, *server, *tmpdir; + + result = TCL_OK; + cflag = flag = forceflag = 0; + home = NULL; + datadir = logdir = tmpdir = NULL; + server = NULL; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 2, objv, "?args?"); + return (TCL_ERROR); + } + + i = 2; + while (i < objc) { + if (Tcl_GetIndexFromObj(interp, objv[i], envremopts, "option", + TCL_EXACT, &optindex) != TCL_OK) { + result = IS_HELP(objv[i]); + goto error; + } + i++; + switch ((enum envremopts)optindex) { + case ENVREM_FORCE: + forceflag |= DB_FORCE; + break; + case ENVREM_HOME: + /* Make sure we have an arg to check against! */ + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-home dir?"); + result = TCL_ERROR; + break; + } + home = Tcl_GetStringFromObj(objv[i++], NULL); + break; + case ENVREM_SERVER: + /* Make sure we have an arg to check against! */ + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-server name?"); + result = TCL_ERROR; + break; + } + server = Tcl_GetStringFromObj(objv[i++], NULL); + cflag = DB_CLIENT; + break; + case ENVREM_USE_ENVIRON: + flag |= DB_USE_ENVIRON; + break; + case ENVREM_USE_ENVIRON_ROOT: + flag |= DB_USE_ENVIRON_ROOT; + break; + case ENVREM_DATADIR: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "-data_dir dir"); + result = TCL_ERROR; + break; + } + datadir = Tcl_GetStringFromObj(objv[i++], NULL); + break; + case ENVREM_LOGDIR: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "-log_dir dir"); + result = TCL_ERROR; + break; + } + logdir = Tcl_GetStringFromObj(objv[i++], NULL); + break; + case ENVREM_TMPDIR: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "-tmp_dir dir"); + result = TCL_ERROR; + break; + } + tmpdir = Tcl_GetStringFromObj(objv[i++], NULL); + break; + } + /* + * If, at any time, parsing the args we get an error, + * bail out and return. + */ + if (result != TCL_OK) + goto error; + } + + /* + * If envp is NULL, we don't have an open env and we need to open + * one of the user. Don't bother with the info stuff. + */ + if (envp == NULL) { + if ((ret = db_env_create(&e, cflag)) != 0) { + result = _ReturnSetup(interp, ret, "db_env_create"); + goto error; + } + if (server != NULL) { + ret = e->set_server(e, server, 0, 0, 0); + result = _ReturnSetup(interp, ret, "set_server"); + if (result != TCL_OK) + goto error; + } + if (datadir != NULL) { + _debug_check(); + ret = e->set_data_dir(e, datadir); + result = _ReturnSetup(interp, ret, "set_data_dir"); + if (result != TCL_OK) + goto error; + } + if (logdir != NULL) { + _debug_check(); + ret = e->set_lg_dir(e, logdir); + result = _ReturnSetup(interp, ret, "set_log_dir"); + if (result != TCL_OK) + goto error; + } + if (tmpdir != NULL) { + _debug_check(); + ret = e->set_tmp_dir(e, tmpdir); + result = _ReturnSetup(interp, ret, "set_tmp_dir"); + if (result != TCL_OK) + goto error; + } + } else { + /* + * We have to clean up any info associated with this env, + * regardless of the result of the remove so do it first. + * NOTE: envip is freed when we come back from this function. + */ + _EnvInfoDelete(interp, envip); + envip = NULL; + e = envp; + } + + flag |= forceflag; + /* + * When we get here we have parsed all the args. Now remove + * the environment. + */ + _debug_check(); + ret = e->remove(e, home, flag); + result = _ReturnSetup(interp, ret, "env remove"); +error: + return (result); +} + +static void +_EnvInfoDelete(interp, envip) + Tcl_Interp *interp; /* Tcl Interpreter */ + DBTCL_INFO *envip; /* Info for env */ +{ + DBTCL_INFO *nextp, *p; + + /* + * Before we can delete the environment info, we must close + * any open subsystems in this env. We will: + * 1. Abort any transactions (which aborts any nested txns). + * 2. Close any mpools (which will put any pages itself). + * 3. Put any locks. + * 4. Close the error file. + */ + for (p = LIST_FIRST(&__db_infohead); p != NULL; p = nextp) { + /* + * Check if this info structure "belongs" to this + * env. If so, remove its commands and info structure. + * We do not close/abort/whatever here, because we + * don't want to replicate DB behavior. + */ + if (p->i_parent == envip) { + switch (p->i_type) { + case I_TXN: + _TxnInfoDelete(interp, p); + break; + case I_MP: + _MpInfoDelete(interp, p); + break; + default: + Tcl_SetResult(interp, + "_EnvInfoDelete: bad info type", + TCL_STATIC); + break; + } + nextp = LIST_NEXT(p, entries); + (void)Tcl_DeleteCommand(interp, p->i_name); + _DeleteInfo(p); + } else + nextp = LIST_NEXT(p, entries); + } + (void)Tcl_DeleteCommand(interp, envip->i_name); + _DeleteInfo(envip); +} + +/* + * PUBLIC: int tcl_EnvVerbose __P((Tcl_Interp *, DB_ENV *, Tcl_Obj *, + * PUBLIC: Tcl_Obj *)); + * + * tcl_EnvVerbose -- + */ +int +tcl_EnvVerbose(interp, envp, which, onoff) + Tcl_Interp *interp; /* Interpreter */ + DB_ENV *envp; /* Env pointer */ + Tcl_Obj *which; /* Which subsystem */ + Tcl_Obj *onoff; /* On or off */ +{ + static char *verbwhich[] = { + "chkpt", + "deadlock", + "recovery", + "wait", + NULL + }; + enum verbwhich { + ENVVERB_CHK, + ENVVERB_DEAD, + ENVVERB_REC, + ENVVERB_WAIT + }; + static char *verbonoff[] = { + "off", + "on", + NULL + }; + enum verbonoff { + ENVVERB_OFF, + ENVVERB_ON + }; + int on, optindex, ret; + u_int32_t wh; + + if (Tcl_GetIndexFromObj(interp, which, verbwhich, "option", + TCL_EXACT, &optindex) != TCL_OK) + return (IS_HELP(which)); + + switch ((enum verbwhich)optindex) { + case ENVVERB_CHK: + wh = DB_VERB_CHKPOINT; + break; + case ENVVERB_DEAD: + wh = DB_VERB_DEADLOCK; + break; + case ENVVERB_REC: + wh = DB_VERB_RECOVERY; + break; + case ENVVERB_WAIT: + wh = DB_VERB_WAITSFOR; + break; + default: + return (TCL_ERROR); + } + if (Tcl_GetIndexFromObj(interp, onoff, verbonoff, "option", + TCL_EXACT, &optindex) != TCL_OK) + return (IS_HELP(onoff)); + switch ((enum verbonoff)optindex) { + case ENVVERB_OFF: + on = 0; + break; + case ENVVERB_ON: + on = 1; + break; + default: + return (TCL_ERROR); + } + ret = envp->set_verbose(envp, wh, on); + return (_ReturnSetup(interp, ret, "env set verbose")); +} + +#if CONFIG_TEST +/* + * PUBLIC: int tcl_EnvTest __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *)); + * + * tcl_EnvTest -- + */ +int +tcl_EnvTest(interp, objc, objv, envp) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB_ENV *envp; /* Env pointer */ +{ + static char *envtestcmd[] = { + "abort", + "copy", + NULL + }; + enum envtestcmd { + ENVTEST_ABORT, + ENVTEST_COPY + }; + static char *envtestat[] = { + "none", + "preopen", + "prerename", + "postlog", + "postlogmeta", + "postopen", + "postrename", + "postsync", + NULL + }; + enum envtestat { + ENVTEST_NONE, + ENVTEST_PREOPEN, + ENVTEST_PRERENAME, + ENVTEST_POSTLOG, + ENVTEST_POSTLOGMETA, + ENVTEST_POSTOPEN, + ENVTEST_POSTRENAME, + ENVTEST_POSTSYNC + }; + int *loc, optindex, result, testval; + + result = TCL_OK; + + if (objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "abort|copy location"); + return (TCL_ERROR); + } + + /* + * This must be the "copy" or "abort" portion of the command. + */ + if (Tcl_GetIndexFromObj(interp, objv[2], envtestcmd, "command", + TCL_EXACT, &optindex) != TCL_OK) { + result = IS_HELP(objv[2]); + return (result); + } + switch ((enum envtestcmd)optindex) { + case ENVTEST_ABORT: + loc = &envp->test_abort; + break; + case ENVTEST_COPY: + loc = &envp->test_copy; + break; + default: + Tcl_SetResult(interp, "Illegal store location", TCL_STATIC); + return (TCL_ERROR); + } + + /* + * This must be the location portion of the command. + */ + if (Tcl_GetIndexFromObj(interp, objv[3], envtestat, "location", + TCL_EXACT, &optindex) != TCL_OK) { + result = IS_HELP(objv[3]); + return (result); + } + switch ((enum envtestat)optindex) { + case ENVTEST_NONE: + testval = 0; + break; + case ENVTEST_PREOPEN: + testval = DB_TEST_PREOPEN; + break; + case ENVTEST_PRERENAME: + testval = DB_TEST_PRERENAME; + break; + case ENVTEST_POSTLOG: + testval = DB_TEST_POSTLOG; + break; + case ENVTEST_POSTLOGMETA: + testval = DB_TEST_POSTLOGMETA; + break; + case ENVTEST_POSTOPEN: + testval = DB_TEST_POSTOPEN; + break; + case ENVTEST_POSTRENAME: + testval = DB_TEST_POSTRENAME; + break; + case ENVTEST_POSTSYNC: + testval = DB_TEST_POSTSYNC; + break; + default: + Tcl_SetResult(interp, "Illegal test location", TCL_STATIC); + return (TCL_ERROR); + } + + *loc = testval; + Tcl_SetResult(interp, "0", TCL_STATIC); + return (result); +} +#endif diff --git a/db/tcl/tcl_internal.c b/db/tcl/tcl_internal.c new file mode 100644 index 000000000..bdab60f4a --- /dev/null +++ b/db/tcl/tcl_internal.c @@ -0,0 +1,440 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: tcl_internal.c,v 11.27 2000/05/22 18:36:51 sue Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#endif + +#include "db_int.h" +#include "tcl_db.h" +#include "db_page.h" +#include "db_am.h" +#include "db_ext.h" + +/* + * + * internal.c -- + * + * This file contains internal functions we need to maintain + * state for our Tcl interface. + * + * NOTE: This all uses a linear linked list. If we end up with + * too many info structs such that this is a performance hit, it + * should be redone using hashes or a list per type. The assumption + * is that the user won't have more than a few dozen info structs + * in operation at any given point in time. Even a complicated + * application with a few environments, nested transactions, locking, + * and several databases open, using cursors should not have a + * negative performance impact, in terms of searching the list to + * get/manipulate the info structure. + */ + +/* + * Prototypes for procedures defined later in this file: + */ + +#define GLOB_CHAR(c) ((c) == '*' || (c) == '?') + +/* + * PUBLIC: DBTCL_INFO *_NewInfo __P((Tcl_Interp *, + * PUBLIC: void *, char *, enum INFOTYPE)); + * + * _NewInfo -- + * + * This function will create a new info structure and fill it in + * with the name and pointer, id and type. + */ +DBTCL_INFO * +_NewInfo(interp, anyp, name, type) + Tcl_Interp *interp; + void *anyp; + char *name; + enum INFOTYPE type; +{ + DBTCL_INFO *p; + int i, ret; + + if ((ret = __os_malloc(NULL, sizeof(DBTCL_INFO), NULL, &p)) != 0) { + Tcl_SetResult(interp, db_strerror(ret), TCL_STATIC); + return (NULL); + } + + if ((ret = __os_strdup(NULL, name, &p->i_name)) != 0) { + Tcl_SetResult(interp, db_strerror(ret), TCL_STATIC); + __os_free(p, sizeof(DBTCL_INFO)); + return (NULL); + } + p->i_interp = interp; + p->i_anyp = anyp; + p->i_data = 0; + p->i_data2 = 0; + p->i_type = type; + p->i_parent = NULL; + p->i_err = NULL; + p->i_errpfx = NULL; + p->i_lockobj.data = NULL; + for (i = 0; i < MAX_ID; i++) + p->i_otherid[i] = 0; + + LIST_INSERT_HEAD(&__db_infohead, p, entries); + return (p); +} + +/* + * PUBLIC: void *_NameToPtr __P((CONST char *)); + */ +void * +_NameToPtr(name) + CONST char *name; +{ + DBTCL_INFO *p; + + for (p = LIST_FIRST(&__db_infohead); p != NULL; + p = LIST_NEXT(p, entries)) + if (strcmp(name, p->i_name) == 0) + return (p->i_anyp); + return (NULL); +} + +/* + * PUBLIC: char *_PtrToName __P((CONST void *)); + */ +char * +_PtrToName(ptr) + CONST void *ptr; +{ + DBTCL_INFO *p; + + for (p = LIST_FIRST(&__db_infohead); p != NULL; + p = LIST_NEXT(p, entries)) + if (p->i_anyp == ptr) + return (p->i_name); + return (NULL); +} + +/* + * PUBLIC: DBTCL_INFO *_PtrToInfo __P((CONST void *)); + */ +DBTCL_INFO * +_PtrToInfo(ptr) + CONST void *ptr; +{ + DBTCL_INFO *p; + + for (p = LIST_FIRST(&__db_infohead); p != NULL; + p = LIST_NEXT(p, entries)) + if (p->i_anyp == ptr) + return (p); + return (NULL); +} + +/* + * PUBLIC: DBTCL_INFO *_NameToInfo __P((CONST char *)); + */ +DBTCL_INFO * +_NameToInfo(name) + CONST char *name; +{ + DBTCL_INFO *p; + + for (p = LIST_FIRST(&__db_infohead); p != NULL; + p = LIST_NEXT(p, entries)) + if (strcmp(name, p->i_name) == 0) + return (p); + return (NULL); +} + +/* + * PUBLIC: void _SetInfoData __P((DBTCL_INFO *, void *)); + */ +void +_SetInfoData(p, data) + DBTCL_INFO *p; + void *data; +{ + if (p == NULL) + return; + p->i_anyp = data; + return; +} + +/* + * PUBLIC: void _DeleteInfo __P((DBTCL_INFO *)); + */ +void +_DeleteInfo(p) + DBTCL_INFO *p; +{ + if (p == NULL) + return; + LIST_REMOVE(p, entries); + if (p->i_lockobj.data != NULL) + __os_free(p->i_lockobj.data, p->i_lockobj.size); + if (p->i_err != NULL) { + fclose(p->i_err); + p->i_err = NULL; + } + if (p->i_errpfx != NULL) + __os_freestr(p->i_errpfx); + __os_freestr(p->i_name); + __os_free(p, sizeof(DBTCL_INFO)); + + return; +} + +/* + * PUBLIC: int _SetListElem __P((Tcl_Interp *, + * PUBLIC: Tcl_Obj *, void *, int, void *, int)); + */ +int +_SetListElem(interp, list, elem1, e1cnt, elem2, e2cnt) + Tcl_Interp *interp; + Tcl_Obj *list; + void *elem1, *elem2; + int e1cnt, e2cnt; +{ + Tcl_Obj *myobjv[2], *thislist; + int myobjc; + + myobjc = 2; + myobjv[0] = Tcl_NewByteArrayObj((u_char *)elem1, e1cnt); + myobjv[1] = Tcl_NewByteArrayObj((u_char *)elem2, e2cnt); + thislist = Tcl_NewListObj(myobjc, myobjv); + if (thislist == NULL) + return (TCL_ERROR); + return (Tcl_ListObjAppendElement(interp, list, thislist)); + +} + +/* + * PUBLIC: int _SetListElemInt __P((Tcl_Interp *, Tcl_Obj *, void *, int)); + */ +int +_SetListElemInt(interp, list, elem1, elem2) + Tcl_Interp *interp; + Tcl_Obj *list; + void *elem1; + int elem2; +{ + Tcl_Obj *myobjv[2], *thislist; + int myobjc; + + myobjc = 2; + myobjv[0] = Tcl_NewByteArrayObj((u_char *)elem1, strlen((char *)elem1)); + myobjv[1] = Tcl_NewIntObj(elem2); + thislist = Tcl_NewListObj(myobjc, myobjv); + if (thislist == NULL) + return (TCL_ERROR); + return (Tcl_ListObjAppendElement(interp, list, thislist)); +} + +/* + * PUBLIC: int _SetListRecnoElem __P((Tcl_Interp *, Tcl_Obj *, + * PUBLIC: db_recno_t, u_char *, int)); + */ +int +_SetListRecnoElem(interp, list, elem1, elem2, e2size) + Tcl_Interp *interp; + Tcl_Obj *list; + db_recno_t elem1; + u_char *elem2; + int e2size; +{ + Tcl_Obj *myobjv[2], *thislist; + int myobjc; + + myobjc = 2; + myobjv[0] = Tcl_NewIntObj(elem1); + myobjv[1] = Tcl_NewByteArrayObj(elem2, e2size); + thislist = Tcl_NewListObj(myobjc, myobjv); + if (thislist == NULL) + return (TCL_ERROR); + return (Tcl_ListObjAppendElement(interp, list, thislist)); + +} + +/* + * PUBLIC: int _GetGlobPrefix __P((char *, char **)); + */ +int +_GetGlobPrefix(pattern, prefix) + char *pattern; + char **prefix; +{ + int i, j; + char *p; + + /* + * Duplicate it, we get enough space and most of the work is done. + */ + if (__os_strdup(NULL, pattern, prefix) != 0) + return (1); + + p = *prefix; + for (i = 0, j = 0; p[i] && !GLOB_CHAR(p[i]); i++, j++) + /* + * Check for an escaped character and adjust + */ + if (p[i] == '\\' && p[i+1]) { + p[j] = p[i+1]; + i++; + } else + p[j] = p[i]; + p[j] = 0; + return (0); +} + +/* + * PUBLIC: int _ReturnSetup __P((Tcl_Interp *, int, char *)); + */ +int +_ReturnSetup(interp, ret, errmsg) + Tcl_Interp *interp; + int ret; + char *errmsg; +{ + char *msg; + + if (ret > 0) + return (_ErrorSetup(interp, ret, errmsg)); + + /* + * We either have success or a DB error. If a DB error, set up the + * string. We return an error if not one of the errors we catch. + * If anyone wants to reset the result to return anything different, + * then the calling function is responsible for doing so via + * Tcl_ResetResult or another Tcl_SetObjResult. + */ + if (ret == 0) { + Tcl_SetResult(interp, "0", TCL_STATIC); + return (TCL_OK); + } + + msg = db_strerror(ret); + Tcl_AppendResult(interp, msg, NULL); + + switch (ret) { + case DB_NOTFOUND: + case DB_KEYEXIST: + case DB_KEYEMPTY: + return (TCL_OK); + default: + Tcl_SetErrorCode(interp, "BerkeleyDB", msg, NULL); + return (TCL_ERROR); + } +} + +/* + * PUBLIC: int _ErrorSetup __P((Tcl_Interp *, int, char *)); + */ +int +_ErrorSetup(interp, ret, errmsg) + Tcl_Interp *interp; + int ret; + char *errmsg; +{ + Tcl_SetErrno(ret); + Tcl_AppendResult(interp, errmsg, ":", Tcl_PosixError(interp), NULL); + return (TCL_ERROR); +} + +/* + * PUBLIC: void _ErrorFunc __P((CONST char *, char *)); + */ +void +_ErrorFunc(pfx, msg) + CONST char *pfx; + char *msg; +{ + DBTCL_INFO *p; + Tcl_Interp *interp; + int size; + char *err; + + p = _NameToInfo(pfx); + if (p == NULL) + return; + interp = p->i_interp; + + size = strlen(pfx) + strlen(msg) + 4; + /* + * If we cannot allocate enough to put together the prefix + * and message then give them just the message. + */ + if (__os_malloc(NULL, size, NULL, &err) != 0) { + Tcl_AddErrorInfo(interp, msg); + Tcl_AppendResult(interp, msg, "\n", NULL); + return; + } + snprintf(err, size, "%s: %s", pfx, msg); + Tcl_AddErrorInfo(interp, err); + Tcl_AppendResult(interp, err, "\n", NULL); + __os_free(err, size); + return; +} + +#define INVALID_LSNMSG "Invalid LSN with %d parts. Should have 2.\n" + +/* + * PUBLIC: int _GetLsn __P((Tcl_Interp *, Tcl_Obj *, DB_LSN *)); + */ +int +_GetLsn(interp, obj, lsn) + Tcl_Interp *interp; + Tcl_Obj *obj; + DB_LSN *lsn; +{ + Tcl_Obj **myobjv; + int itmp, myobjc, result; + char msg[MSG_SIZE]; + + result = Tcl_ListObjGetElements(interp, obj, &myobjc, &myobjv); + if (result == TCL_ERROR) + return (result); + if (myobjc != 2) { + result = TCL_ERROR; + snprintf(msg, MSG_SIZE, INVALID_LSNMSG, myobjc); + Tcl_SetResult(interp, msg, TCL_VOLATILE); + return (result); + } + result = Tcl_GetIntFromObj(interp, myobjv[0], &itmp); + if (result == TCL_ERROR) + return (result); + lsn->file = itmp; + result = Tcl_GetIntFromObj(interp, myobjv[1], &itmp); + lsn->offset = itmp; + return (result); +} + +int __debug_stop, __debug_on, __debug_print, __debug_test; + +/* + * PUBLIC: void _debug_check __P((void)); + */ +void +_debug_check() +{ + if (__debug_on == 0) + return; + + if (__debug_print != 0) { + printf("\r%6d:", __debug_on); + fflush(stdout); + } + if (__debug_on++ == __debug_test || __debug_stop) + __db_loadme(); +} diff --git a/db/tcl/tcl_lock.c b/db/tcl/tcl_lock.c new file mode 100644 index 000000000..89f6eeb2b --- /dev/null +++ b/db/tcl/tcl_lock.c @@ -0,0 +1,655 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: tcl_lock.c,v 11.21 2001/01/11 18:19:55 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#endif + +#include "db_int.h" +#include "tcl_db.h" + +/* + * Prototypes for procedures defined later in this file: + */ +static int lock_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*)); +static int _LockMode __P((Tcl_Interp *, Tcl_Obj *, db_lockmode_t *)); +static int _GetThisLock __P((Tcl_Interp *, DB_ENV *, u_int32_t, + u_int32_t, DBT *, db_lockmode_t, char *)); +static void _LockPutInfo __P((Tcl_Interp *, db_lockop_t, DB_LOCK *, + u_int32_t, DBT *)); + +static char *lkmode[] = { + "ng", "read", "write", + "iwrite", "iread", "iwr", + NULL +}; +enum lkmode { + LK_NG, LK_READ, LK_WRITE, + LK_IWRITE, LK_IREAD, LK_IWR +}; + +/* + * tcl_LockDetect -- + * + * PUBLIC: int tcl_LockDetect __P((Tcl_Interp *, int, + * PUBLIC: Tcl_Obj * CONST*, DB_ENV *)); + */ +int +tcl_LockDetect(interp, objc, objv, envp) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB_ENV *envp; /* Environment pointer */ +{ + static char *ldopts[] = { + "-lock_conflict", + "default", + "oldest", + "random", + "youngest", + NULL + }; + enum ldopts { + LD_CONFLICT, + LD_DEFAULT, + LD_OLDEST, + LD_RANDOM, + LD_YOUNGEST + }; + u_int32_t flag, policy; + int i, optindex, result, ret; + + result = TCL_OK; + flag = policy = 0; + i = 2; + while (i < objc) { + if (Tcl_GetIndexFromObj(interp, objv[i], + ldopts, "option", TCL_EXACT, &optindex) != TCL_OK) + return (IS_HELP(objv[i])); + i++; + switch ((enum ldopts)optindex) { + case LD_DEFAULT: + FLAG_CHECK(policy); + policy = DB_LOCK_DEFAULT; + break; + case LD_OLDEST: + FLAG_CHECK(policy); + policy = DB_LOCK_OLDEST; + break; + case LD_YOUNGEST: + FLAG_CHECK(policy); + policy = DB_LOCK_YOUNGEST; + break; + case LD_RANDOM: + FLAG_CHECK(policy); + policy = DB_LOCK_RANDOM; + break; + case LD_CONFLICT: + flag |= DB_LOCK_CONFLICT; + break; + } + } + + _debug_check(); + ret = lock_detect(envp, flag, policy, NULL); + result = _ReturnSetup(interp, ret, "lock detect"); + return (result); +} + +/* + * tcl_LockGet -- + * + * PUBLIC: int tcl_LockGet __P((Tcl_Interp *, int, + * PUBLIC: Tcl_Obj * CONST*, DB_ENV *)); + */ +int +tcl_LockGet(interp, objc, objv, envp) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB_ENV *envp; /* Environment pointer */ +{ + static char *lgopts[] = { + "-nowait", + NULL + }; + enum lgopts { + LGNOWAIT + }; + DBT obj; + Tcl_Obj *res; + db_lockmode_t mode; + u_int32_t flag, lockid; + int itmp, optindex, result; + char newname[MSG_SIZE]; + + result = TCL_OK; + memset(newname, 0, MSG_SIZE); + if (objc != 5 && objc != 6) { + Tcl_WrongNumArgs(interp, 2, objv, "?-nowait? mode id obj"); + return (TCL_ERROR); + } + /* + * Work back from required args. + * Last arg is obj. + * Second last is lock id. + * Third last is lock mode. + */ + memset(&obj, 0, sizeof(obj)); + + if ((result = + Tcl_GetIntFromObj(interp, objv[objc-2], &itmp)) != TCL_OK) + return (result); + lockid = itmp; + + /* + * XXX + * Tcl 8.1 Tcl_GetByteArrayFromObj/Tcl_GetIntFromObj bug. + * + * The line below was originally before the Tcl_GetIntFromObj. + * + * There is a bug in Tcl 8.1 and byte arrays in that if it happens + * to use an object as both a byte array and something else like + * an int, and you've done a Tcl_GetByteArrayFromObj, then you + * do a Tcl_GetIntFromObj, your memory is deleted. + * + * Workaround is to make sure all Tcl_GetByteArrayFromObj calls + * are done last. + */ + obj.data = Tcl_GetByteArrayFromObj(objv[objc-1], &itmp); + obj.size = itmp; + if ((result = _LockMode(interp, objv[(objc - 3)], &mode)) != TCL_OK) + return (result); + + /* + * Any left over arg is the flag. + */ + flag = 0; + if (objc == 6) { + if (Tcl_GetIndexFromObj(interp, objv[(objc - 4)], + lgopts, "option", TCL_EXACT, &optindex) != TCL_OK) + return (IS_HELP(objv[(objc - 4)])); + switch ((enum lgopts)optindex) { + case LGNOWAIT: + flag |= DB_LOCK_NOWAIT; + break; + } + } + + result = _GetThisLock(interp, envp, lockid, flag, &obj, mode, newname); + if (result == TCL_OK) { + res = Tcl_NewStringObj(newname, strlen(newname)); + Tcl_SetObjResult(interp, res); + } + return (result); +} + +/* + * tcl_LockStat -- + * + * PUBLIC: int tcl_LockStat __P((Tcl_Interp *, int, + * PUBLIC: Tcl_Obj * CONST*, DB_ENV *)); + */ +int +tcl_LockStat(interp, objc, objv, envp) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB_ENV *envp; /* Environment pointer */ +{ + DB_LOCK_STAT *sp; + Tcl_Obj *res; + int result, ret; + + result = TCL_OK; + /* + * No args for this. Error if there are some. + */ + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + _debug_check(); + ret = lock_stat(envp, &sp, NULL); + result = _ReturnSetup(interp, ret, "lock stat"); + if (result == TCL_ERROR) + return (result); + /* + * Have our stats, now construct the name value + * list pairs and free up the memory. + */ + res = Tcl_NewObj(); + /* + * MAKE_STAT_LIST assumes 'res' and 'error' label. + */ + MAKE_STAT_LIST("Region size", sp->st_regsize); + MAKE_STAT_LIST("Max locks", sp->st_maxlocks); + MAKE_STAT_LIST("Max lockers", sp->st_maxlockers); + MAKE_STAT_LIST("Max objects", sp->st_maxobjects); + MAKE_STAT_LIST("Lock modes", sp->st_nmodes); + MAKE_STAT_LIST("Current number of locks", sp->st_nlocks); + MAKE_STAT_LIST("Maximum number of locks so far", sp->st_maxnlocks); + MAKE_STAT_LIST("Current number of lockers", sp->st_nlockers); + MAKE_STAT_LIST("Maximum number of lockers so far", sp->st_maxnlockers); + MAKE_STAT_LIST("Current number of objects", sp->st_nobjects); + MAKE_STAT_LIST("Maximum number of objects so far", sp->st_maxnobjects); + MAKE_STAT_LIST("Number of conflicts", sp->st_nconflicts); + MAKE_STAT_LIST("Lock requests", sp->st_nrequests); + MAKE_STAT_LIST("Lock releases", sp->st_nreleases); + MAKE_STAT_LIST("Deadlocks detected", sp->st_ndeadlocks); + MAKE_STAT_LIST("Number of region lock waits", sp->st_region_wait); + MAKE_STAT_LIST("Number of region lock nowaits", sp->st_region_nowait); + Tcl_SetObjResult(interp, res); +error: + __os_free(sp, sizeof(*sp)); + return (result); +} + +/* + * lock_Cmd -- + * Implements the "lock" widget. + */ +static int +lock_Cmd(clientData, interp, objc, objv) + ClientData clientData; /* Lock handle */ + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ +{ + static char *lkcmds[] = { + "put", + NULL + }; + enum lkcmds { + LKPUT + }; + DB_ENV *env; + DB_LOCK *lock; + DBTCL_INFO *lkip; + int cmdindex, result, ret; + + Tcl_ResetResult(interp); + lock = (DB_LOCK *)clientData; + lkip = _PtrToInfo((void *)lock); + result = TCL_OK; + + if (lock == NULL) { + Tcl_SetResult(interp, "NULL lock", TCL_STATIC); + return (TCL_ERROR); + } + if (lkip == NULL) { + Tcl_SetResult(interp, "NULL lock info pointer", TCL_STATIC); + return (TCL_ERROR); + } + + env = NAME_TO_ENV(lkip->i_parent->i_name); + /* + * No args for this. Error if there are some. + */ + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + /* + * Get the command name index from the object based on the dbcmds + * defined above. + */ + if (Tcl_GetIndexFromObj(interp, + objv[1], lkcmds, "command", TCL_EXACT, &cmdindex) != TCL_OK) + return (IS_HELP(objv[1])); + + switch ((enum lkcmds)cmdindex) { + case LKPUT: + _debug_check(); + ret = lock_put(env, lock); + result = _ReturnSetup(interp, ret, "lock put"); + (void)Tcl_DeleteCommand(interp, lkip->i_name); + _DeleteInfo(lkip); + __os_free(lock, sizeof(DB_LOCK)); + break; + } + return (result); +} + +/* + * tcl_LockVec -- + * + * PUBLIC: int tcl_LockVec __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *)); + */ +int +tcl_LockVec(interp, objc, objv, envp) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB_ENV *envp; /* environment pointer */ +{ + static char *lvopts[] = { + "-nowait", + NULL + }; + enum lvopts { + LVNOWAIT + }; + static char *lkops[] = { + "get", "put", "put_all", "put_obj", + NULL + }; + enum lkops { + LKGET, LKPUT, LKPUTALL, LKPUTOBJ + }; + DB_LOCK *lock; + DB_LOCKREQ list; + DBT obj; + Tcl_Obj **myobjv, *res, *thisop; + db_lockmode_t mode; + u_int32_t flag, lockid; + int i, itmp, myobjc, optindex, result, ret; + char *lockname, msg[MSG_SIZE], newname[MSG_SIZE]; + + result = TCL_OK; + memset(newname, 0, MSG_SIZE); + flag = 0; + mode = 0; + /* + * If -nowait is given, it MUST be first arg. + */ + if (Tcl_GetIndexFromObj(interp, objv[2], + lvopts, "option", TCL_EXACT, &optindex) == TCL_OK) { + switch ((enum lvopts)optindex) { + case LVNOWAIT: + flag |= DB_LOCK_NOWAIT; + break; + } + i = 3; + } else { + if (IS_HELP(objv[2]) == TCL_OK) + return (TCL_OK); + Tcl_ResetResult(interp); + i = 2; + } + + /* + * Our next arg MUST be the locker ID. + */ + result = Tcl_GetIntFromObj(interp, objv[i++], &itmp); + if (result != TCL_OK) + return (result); + lockid = itmp; + + /* + * All other remaining args are operation tuples. + * Go through sequentially to decode, execute and build + * up list of return values. + */ + res = Tcl_NewListObj(0, NULL); + while (i < objc) { + /* + * Get the list of the tuple. + */ + lock = NULL; + result = Tcl_ListObjGetElements(interp, objv[i], + &myobjc, &myobjv); + if (result == TCL_OK) + i++; + else + break; + /* + * First we will set up the list of requests. + * We will make a "second pass" after we get back + * the results from the lock_vec call to create + * the return list. + */ + if (Tcl_GetIndexFromObj(interp, myobjv[0], + lkops, "option", TCL_EXACT, &optindex) != TCL_OK) { + result = IS_HELP(myobjv[0]); + goto error; + } + switch ((enum lkops)optindex) { + case LKGET: + if (myobjc != 3) { + Tcl_WrongNumArgs(interp, 1, myobjv, + "{get obj mode}"); + result = TCL_ERROR; + goto error; + } + result = _LockMode(interp, myobjv[2], &list.mode); + if (result != TCL_OK) + goto error; + /* + * XXX + * Tcl 8.1 Tcl_GetByteArrayFromObj/Tcl_GetIntFromObj + * bug. + * + * There is a bug in Tcl 8.1 and byte arrays in that if + * it happens to use an object as both a byte array and + * something else like an int, and you've done a + * Tcl_GetByteArrayFromObj, then you do a + * Tcl_GetIntFromObj, your memory is deleted. + * + * Workaround is to make sure all + * Tcl_GetByteArrayFromObj calls are done last. + */ + obj.data = Tcl_GetByteArrayFromObj(myobjv[1], &itmp); + obj.size = itmp; + ret = _GetThisLock(interp, envp, lockid, flag, + &obj, list.mode, newname); + if (ret != 0) { + result = _ReturnSetup(interp, ret, "lock vec"); + thisop = Tcl_NewIntObj(ret); + (void)Tcl_ListObjAppendElement(interp, res, + thisop); + goto error; + } + thisop = Tcl_NewStringObj(newname, strlen(newname)); + (void)Tcl_ListObjAppendElement(interp, res, thisop); + continue; + case LKPUT: + if (myobjc != 2) { + Tcl_WrongNumArgs(interp, 1, myobjv, + "{put lock}"); + result = TCL_ERROR; + goto error; + } + list.op = DB_LOCK_PUT; + lockname = Tcl_GetStringFromObj(myobjv[1], NULL); + lock = NAME_TO_LOCK(lockname); + if (lock == NULL) { + snprintf(msg, MSG_SIZE, "Invalid lock: %s\n", + lockname); + Tcl_SetResult(interp, msg, TCL_VOLATILE); + result = TCL_ERROR; + goto error; + } + list.lock = *lock; + break; + case LKPUTALL: + if (myobjc != 1) { + Tcl_WrongNumArgs(interp, 1, myobjv, + "{put_all}"); + result = TCL_ERROR; + goto error; + } + list.op = DB_LOCK_PUT_ALL; + break; + case LKPUTOBJ: + if (myobjc != 2) { + Tcl_WrongNumArgs(interp, 1, myobjv, + "{put_obj obj}"); + result = TCL_ERROR; + goto error; + } + list.op = DB_LOCK_PUT_OBJ; + obj.data = Tcl_GetByteArrayFromObj(myobjv[1], &itmp); + obj.size = itmp; + list.obj = &obj; + break; + } + /* + * We get here, we have set up our request, now call + * lock_vec. + */ + _debug_check(); + ret = lock_vec(envp, lockid, flag, &list, 1, NULL); + /* + * Now deal with whether or not the operation succeeded. + * Get's were done above, all these are only puts. + */ + thisop = Tcl_NewIntObj(ret); + result = Tcl_ListObjAppendElement(interp, res, thisop); + if (ret != 0 && result == TCL_OK) + result = _ReturnSetup(interp, ret, "lock put"); + /* + * We did a put of some kind. Since we did that, + * we have to delete the commands associated with + * any of the locks we just put. + */ + _LockPutInfo(interp, list.op, lock, lockid, &obj); + } + + if (result == TCL_OK && res) + Tcl_SetObjResult(interp, res); +error: + return (result); +} + +static int +_LockMode(interp, obj, mode) + Tcl_Interp *interp; + Tcl_Obj *obj; + db_lockmode_t *mode; +{ + int optindex; + + if (Tcl_GetIndexFromObj(interp, obj, lkmode, "option", + TCL_EXACT, &optindex) != TCL_OK) + return (IS_HELP(obj)); + switch ((enum lkmode)optindex) { + case LK_NG: + *mode = DB_LOCK_NG; + break; + case LK_READ: + *mode = DB_LOCK_READ; + break; + case LK_WRITE: + *mode = DB_LOCK_WRITE; + break; + case LK_IREAD: + *mode = DB_LOCK_IREAD; + break; + case LK_IWRITE: + *mode = DB_LOCK_IWRITE; + break; + case LK_IWR: + *mode = DB_LOCK_IWR; + break; + } + return (TCL_OK); +} + +static void +_LockPutInfo(interp, op, lock, lockid, objp) + Tcl_Interp *interp; + db_lockop_t op; + DB_LOCK *lock; + u_int32_t lockid; + DBT *objp; +{ + DBTCL_INFO *p, *nextp; + int found; + + for (p = LIST_FIRST(&__db_infohead); p != NULL; p = nextp) { + found = 0; + nextp = LIST_NEXT(p, entries); + if ((op == DB_LOCK_PUT && (p->i_lock == lock)) || + (op == DB_LOCK_PUT_ALL && p->i_locker == lockid) || + (op == DB_LOCK_PUT_OBJ && p->i_lockobj.data && + memcmp(p->i_lockobj.data, objp->data, objp->size) == 0)) + found = 1; + if (found) { + (void)Tcl_DeleteCommand(interp, p->i_name); + __os_free(p->i_lock, sizeof(DB_LOCK)); + _DeleteInfo(p); + } + } +} + +static int +_GetThisLock(interp, envp, lockid, flag, objp, mode, newname) + Tcl_Interp *interp; /* Interpreter */ + DB_ENV *envp; /* Env handle */ + u_int32_t lockid; /* Locker ID */ + u_int32_t flag; /* Lock flag */ + DBT *objp; /* Object to lock */ + db_lockmode_t mode; /* Lock mode */ + char *newname; /* New command name */ +{ + DB_LOCK *lock; + DBTCL_INFO *envip, *ip; + int result, ret; + + result = TCL_OK; + envip = _PtrToInfo((void *)envp); + if (envip == NULL) { + Tcl_SetResult(interp, "Could not find env info\n", TCL_STATIC); + return (TCL_ERROR); + } + snprintf(newname, MSG_SIZE, "%s.lock%d", + envip->i_name, envip->i_envlockid); + ip = _NewInfo(interp, NULL, newname, I_LOCK); + if (ip == NULL) { + Tcl_SetResult(interp, "Could not set up info", + TCL_STATIC); + return (TCL_ERROR); + } + ret = __os_malloc(envp, sizeof(DB_LOCK), NULL, &lock); + if (ret != 0) { + Tcl_SetResult(interp, db_strerror(ret), TCL_STATIC); + return (TCL_ERROR); + } + _debug_check(); + ret = lock_get(envp, lockid, flag, objp, mode, lock); + result = _ReturnSetup(interp, ret, "lock get"); + if (result == TCL_ERROR) { + __os_free(lock, sizeof(DB_LOCK)); + _DeleteInfo(ip); + return (result); + } + /* + * Success. Set up return. Set up new info + * and command widget for this lock. + */ + ret = __os_malloc(envp, objp->size, NULL, &ip->i_lockobj.data); + if (ret != 0) { + Tcl_SetResult(interp, "Could not duplicate obj", + TCL_STATIC); + (void)lock_put(envp, lock); + __os_free(lock, sizeof(DB_LOCK)); + _DeleteInfo(ip); + result = TCL_ERROR; + goto error; + } + memcpy(ip->i_lockobj.data, objp->data, objp->size); + ip->i_lockobj.size = objp->size; + envip->i_envlockid++; + ip->i_parent = envip; + ip->i_locker = lockid; + _SetInfoData(ip, lock); + Tcl_CreateObjCommand(interp, newname, + (Tcl_ObjCmdProc *)lock_Cmd, (ClientData)lock, NULL); +error: + return (result); +} diff --git a/db/tcl/tcl_log.c b/db/tcl/tcl_log.c new file mode 100644 index 000000000..20f8e8c02 --- /dev/null +++ b/db/tcl/tcl_log.c @@ -0,0 +1,581 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: tcl_log.c,v 11.21 2000/11/30 00:58:45 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#endif + +#include "db_int.h" +#include "tcl_db.h" + +/* + * tcl_LogArchive -- + * + * PUBLIC: int tcl_LogArchive __P((Tcl_Interp *, int, + * PUBLIC: Tcl_Obj * CONST*, DB_ENV *)); + */ +int +tcl_LogArchive(interp, objc, objv, envp) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB_ENV *envp; /* Environment pointer */ +{ + static char *archopts[] = { + "-arch_abs", "-arch_data", "-arch_log", + NULL + }; + enum archopts { + ARCH_ABS, ARCH_DATA, ARCH_LOG + }; + Tcl_Obj *fileobj, *res; + u_int32_t flag; + int i, optindex, result, ret; + char **file, **list; + + result = TCL_OK; + flag = 0; + /* + * Get the flag index from the object based on the options + * defined above. + */ + i = 2; + while (i < objc) { + if (Tcl_GetIndexFromObj(interp, objv[i], + archopts, "option", TCL_EXACT, &optindex) != TCL_OK) + return (IS_HELP(objv[i])); + i++; + switch ((enum archopts)optindex) { + case ARCH_ABS: + flag |= DB_ARCH_ABS; + break; + case ARCH_DATA: + flag |= DB_ARCH_DATA; + break; + case ARCH_LOG: + flag |= DB_ARCH_LOG; + break; + } + } + _debug_check(); + list = NULL; + ret = log_archive(envp, &list, flag, NULL); + result = _ReturnSetup(interp, ret, "log archive"); + if (result == TCL_OK) { + res = Tcl_NewListObj(0, NULL); + for (file = list; file != NULL && *file != NULL; file++) { + fileobj = Tcl_NewStringObj(*file, strlen(*file)); + result = Tcl_ListObjAppendElement(interp, res, fileobj); + if (result != TCL_OK) + break; + } + Tcl_SetObjResult(interp, res); + } + if (list != NULL) + __os_free(list, 0); + return (result); +} + +/* + * tcl_LogCompare -- + * + * PUBLIC: int tcl_LogCompare __P((Tcl_Interp *, int, + * PUBLIC: Tcl_Obj * CONST*)); + */ +int +tcl_LogCompare(interp, objc, objv) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ +{ + DB_LSN lsn0, lsn1; + Tcl_Obj *res; + int result, ret; + + result = TCL_OK; + /* + * No flags, must be 4 args. + */ + if (objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "lsn1 lsn2"); + return (TCL_ERROR); + } + + result = _GetLsn(interp, objv[2], &lsn0); + if (result == TCL_ERROR) + return (result); + result = _GetLsn(interp, objv[3], &lsn1); + if (result == TCL_ERROR) + return (result); + + _debug_check(); + ret = log_compare(&lsn0, &lsn1); + res = Tcl_NewIntObj(ret); + Tcl_SetObjResult(interp, res); + return (result); +} + +/* + * tcl_LogFile -- + * + * PUBLIC: int tcl_LogFile __P((Tcl_Interp *, int, + * PUBLIC: Tcl_Obj * CONST*, DB_ENV *)); + */ +int +tcl_LogFile(interp, objc, objv, envp) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB_ENV *envp; /* Environment pointer */ +{ + DB_LSN lsn; + Tcl_Obj *res; + size_t len; + int result, ret; + char *name; + + result = TCL_OK; + /* + * No flags, must be 3 args. + */ + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "lsn"); + return (TCL_ERROR); + } + + result = _GetLsn(interp, objv[2], &lsn); + if (result == TCL_ERROR) + return (result); + + len = MSG_SIZE; + ret = ENOMEM; + name = NULL; + while (ret == ENOMEM) { + if (name != NULL) + __os_free(name, len/2); + ret = __os_malloc(envp, len, NULL, &name); + if (ret != 0) { + Tcl_SetResult(interp, db_strerror(ret), TCL_STATIC); + break; + } + _debug_check(); + ret = log_file(envp, &lsn, name, len); + len *= 2; + } + result = _ReturnSetup(interp, ret, "log_file"); + if (ret == 0) { + res = Tcl_NewStringObj(name, strlen(name)); + Tcl_SetObjResult(interp, res); + } + + if (name != NULL) + __os_free(name, len/2); + + return (result); +} + +/* + * tcl_LogFlush -- + * + * PUBLIC: int tcl_LogFlush __P((Tcl_Interp *, int, + * PUBLIC: Tcl_Obj * CONST*, DB_ENV *)); + */ +int +tcl_LogFlush(interp, objc, objv, envp) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB_ENV *envp; /* Environment pointer */ +{ + DB_LSN lsn, *lsnp; + int result, ret; + + result = TCL_OK; + /* + * No flags, must be 2 or 3 args. + */ + if (objc > 3) { + Tcl_WrongNumArgs(interp, 2, objv, "?lsn?"); + return (TCL_ERROR); + } + + if (objc == 3) { + lsnp = &lsn; + result = _GetLsn(interp, objv[2], &lsn); + if (result == TCL_ERROR) + return (result); + } else + lsnp = NULL; + + _debug_check(); + ret = log_flush(envp, lsnp); + result = _ReturnSetup(interp, ret, "log_flush"); + return (result); +} + +/* + * tcl_LogGet -- + * + * PUBLIC: int tcl_LogGet __P((Tcl_Interp *, int, + * PUBLIC: Tcl_Obj * CONST*, DB_ENV *)); + */ +int +tcl_LogGet(interp, objc, objv, envp) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB_ENV *envp; /* Environment pointer */ +{ + static char *loggetopts[] = { + "-checkpoint", "-current", "-first", + "-last", "-next", "-prev", + "-set", + NULL + }; + enum loggetopts { + LOGGET_CKP, LOGGET_CUR, LOGGET_FIRST, + LOGGET_LAST, LOGGET_NEXT, LOGGET_PREV, + LOGGET_SET + }; + DB_LSN lsn; + DBT data; + Tcl_Obj *dataobj, *lsnlist, *myobjv[2], *res; + u_int32_t flag; + int i, myobjc, optindex, result, ret; + + result = TCL_OK; + flag = 0; + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, "?-args? lsn"); + return (TCL_ERROR); + } + + /* + * Get the command name index from the object based on the options + * defined above. + */ + i = 2; + while (i < objc) { + if (Tcl_GetIndexFromObj(interp, objv[i], + loggetopts, "option", TCL_EXACT, &optindex) != TCL_OK) + return (IS_HELP(objv[i])); + i++; + switch ((enum loggetopts)optindex) { + case LOGGET_CKP: + FLAG_CHECK(flag); + flag |= DB_CHECKPOINT; + break; + case LOGGET_CUR: + FLAG_CHECK(flag); + flag |= DB_CURRENT; + break; + case LOGGET_FIRST: + FLAG_CHECK(flag); + flag |= DB_FIRST; + break; + case LOGGET_LAST: + FLAG_CHECK(flag); + flag |= DB_LAST; + break; + case LOGGET_NEXT: + FLAG_CHECK(flag); + flag |= DB_NEXT; + break; + case LOGGET_PREV: + FLAG_CHECK(flag); + flag |= DB_PREV; + break; + case LOGGET_SET: + FLAG_CHECK(flag); + flag |= DB_SET; + if (i == objc) { + Tcl_WrongNumArgs(interp, 2, objv, "?-set lsn?"); + result = TCL_ERROR; + break; + } + result = _GetLsn(interp, objv[i++], &lsn); + break; + } + } + + if (result == TCL_ERROR) + return (result); + + memset(&data, 0, sizeof(data)); + data.flags |= DB_DBT_MALLOC; + _debug_check(); + ret = log_get(envp, &lsn, &data, flag); + res = Tcl_NewListObj(0, NULL); + result = _ReturnSetup(interp, ret, "log_get"); + if (ret == 0) { + /* + * Success. Set up return list as {LSN data} where LSN + * is a sublist {file offset}. + */ + myobjc = 2; + myobjv[0] = Tcl_NewIntObj(lsn.file); + myobjv[1] = Tcl_NewIntObj(lsn.offset); + lsnlist = Tcl_NewListObj(myobjc, myobjv); + if (lsnlist == NULL) { + if (data.data != NULL) + __os_free(data.data, data.size); + return (TCL_ERROR); + } + result = Tcl_ListObjAppendElement(interp, res, lsnlist); + dataobj = Tcl_NewStringObj(data.data, data.size); + result = Tcl_ListObjAppendElement(interp, res, dataobj); + } + if (data.data != NULL) + __os_free(data.data, data.size); + + if (result == TCL_OK) + Tcl_SetObjResult(interp, res); + return (result); +} + +/* + * tcl_LogPut -- + * + * PUBLIC: int tcl_LogPut __P((Tcl_Interp *, int, + * PUBLIC: Tcl_Obj * CONST*, DB_ENV *)); + */ +int +tcl_LogPut(interp, objc, objv, envp) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB_ENV *envp; /* Environment pointer */ +{ + static char *logputopts[] = { + "-checkpoint", "-curlsn", "-flush", + NULL + }; + enum logputopts { + LOGPUT_CKP, LOGPUT_CUR, LOGPUT_FLUSH + }; + DB_LSN lsn; + DBT data; + Tcl_Obj *intobj, *res; + u_int32_t flag; + int itmp, optindex, result, ret; + + result = TCL_OK; + flag = 0; + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, "?-args? record"); + return (TCL_ERROR); + } + + /* + * Data/record must be the last arg. + */ + memset(&data, 0, sizeof(data)); + data.data = Tcl_GetByteArrayFromObj(objv[objc-1], &itmp); + data.size = itmp; + + /* + * Get the command name index from the object based on the options + * defined above. + */ + if (objc == 4) { + if (Tcl_GetIndexFromObj(interp, objv[2], + logputopts, "option", TCL_EXACT, &optindex) != TCL_OK) { + return (IS_HELP(objv[2])); + } + switch ((enum logputopts)optindex) { + case LOGPUT_CKP: + flag = DB_CHECKPOINT; + break; + case LOGPUT_CUR: + flag = DB_CURLSN; + break; + case LOGPUT_FLUSH: + flag = DB_FLUSH; + break; + } + } + + if (result == TCL_ERROR) + return (result); + + _debug_check(); + ret = log_put(envp, &lsn, &data, flag); + result = _ReturnSetup(interp, ret, "log_put"); + if (result == TCL_ERROR) + return (result); + res = Tcl_NewListObj(0, NULL); + intobj = Tcl_NewIntObj(lsn.file); + result = Tcl_ListObjAppendElement(interp, res, intobj); + intobj = Tcl_NewIntObj(lsn.offset); + result = Tcl_ListObjAppendElement(interp, res, intobj); + Tcl_SetObjResult(interp, res); + return (result); +} + +/* + * tcl_LogRegister -- + * + * PUBLIC: int tcl_LogRegister __P((Tcl_Interp *, int, + * PUBLIC: Tcl_Obj * CONST*, DB_ENV *)); + */ +int +tcl_LogRegister(interp, objc, objv, envp) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB_ENV *envp; /* Environment pointer */ +{ + DB *dbp; + Tcl_Obj *res; + int result, ret; + char *arg, msg[MSG_SIZE]; + + result = TCL_OK; + if (objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "db filename"); + return (TCL_ERROR); + } + /* + * First comes the DB. + */ + arg = Tcl_GetStringFromObj(objv[2], NULL); + dbp = NAME_TO_DB(arg); + if (dbp == NULL) { + snprintf(msg, MSG_SIZE, + "LogRegister: Invalid db: %s\n", arg); + Tcl_SetResult(interp, msg, TCL_VOLATILE); + return (TCL_ERROR); + } + + /* + * Next is the filename. + */ + arg = Tcl_GetStringFromObj(objv[3], NULL); + + _debug_check(); + ret = log_register(envp, dbp, arg); + result = _ReturnSetup(interp, ret, "log_register"); + if (result == TCL_OK) { + res = Tcl_NewIntObj((int)dbp->log_fileid); + Tcl_SetObjResult(interp, res); + } + return (result); +} + +/* + * tcl_LogStat -- + * + * PUBLIC: int tcl_LogStat __P((Tcl_Interp *, int, + * PUBLIC: Tcl_Obj * CONST*, DB_ENV *)); + */ +int +tcl_LogStat(interp, objc, objv, envp) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB_ENV *envp; /* Environment pointer */ +{ + DB_LOG_STAT *sp; + Tcl_Obj *res; + int result, ret; + + result = TCL_OK; + /* + * No args for this. Error if there are some. + */ + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + _debug_check(); + ret = log_stat(envp, &sp, NULL); + result = _ReturnSetup(interp, ret, "log stat"); + if (result == TCL_ERROR) + return (result); + + /* + * Have our stats, now construct the name value + * list pairs and free up the memory. + */ + res = Tcl_NewObj(); + /* + * MAKE_STAT_LIST assumes 'res' and 'error' label. + */ + MAKE_STAT_LIST("Magic", sp->st_magic); + MAKE_STAT_LIST("Log file Version", sp->st_version); + MAKE_STAT_LIST("Region size", sp->st_regsize); + MAKE_STAT_LIST("Log file mode", sp->st_mode); + MAKE_STAT_LIST("Log record cache size", sp->st_lg_bsize); + MAKE_STAT_LIST("Maximum log file size", sp->st_lg_max); + MAKE_STAT_LIST("Mbytes written", sp->st_w_mbytes); + MAKE_STAT_LIST("Bytes written (over Mb)", sp->st_w_bytes); + MAKE_STAT_LIST("Mbytes written since checkpoint", sp->st_wc_mbytes); + MAKE_STAT_LIST("Bytes written (over Mb) since checkpoint", + sp->st_wc_bytes); + MAKE_STAT_LIST("Times log written", sp->st_wcount); + MAKE_STAT_LIST("Times log written because cache filled up", + sp->st_wcount_fill); + MAKE_STAT_LIST("Times log flushed", sp->st_scount); + MAKE_STAT_LIST("Current log file number", sp->st_cur_file); + MAKE_STAT_LIST("Current log file offset", sp->st_cur_offset); + MAKE_STAT_LIST("Number of region lock waits", sp->st_region_wait); + MAKE_STAT_LIST("Number of region lock nowaits", sp->st_region_nowait); + Tcl_SetObjResult(interp, res); +error: + __os_free(sp, sizeof(*sp)); + return (result); +} + +/* + * tcl_LogUnregister -- + * + * PUBLIC: int tcl_LogUnregister __P((Tcl_Interp *, int, + * PUBLIC: Tcl_Obj * CONST*, DB_ENV *)); + */ +int +tcl_LogUnregister(interp, objc, objv, envp) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB_ENV *envp; /* Environment pointer */ +{ + DB *dbp; + char *arg, msg[MSG_SIZE]; + int result, ret; + + result = TCL_OK; + /* + * 1 arg for this. Error if more or less. + */ + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + arg = Tcl_GetStringFromObj(objv[2], NULL); + dbp = NAME_TO_DB(arg); + if (dbp == NULL) { + snprintf(msg, MSG_SIZE, + "log_unregister: Invalid db identifier: %s\n", arg); + Tcl_SetResult(interp, msg, TCL_VOLATILE); + return (TCL_ERROR); + } + _debug_check(); + ret = log_unregister(envp, dbp); + result = _ReturnSetup(interp, ret, "log_unregister"); + + return (result); +} diff --git a/db/tcl/tcl_mp.c b/db/tcl/tcl_mp.c new file mode 100644 index 000000000..b424deea2 --- /dev/null +++ b/db/tcl/tcl_mp.c @@ -0,0 +1,822 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: tcl_mp.c,v 11.24 2001/01/09 16:13:59 sue Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#endif + +#include "db_int.h" +#include "tcl_db.h" + +/* + * Prototypes for procedures defined later in this file: + */ +static int mp_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*)); +static int pg_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*)); +static int tcl_MpGet __P((Tcl_Interp *, int, Tcl_Obj * CONST*, + DB_MPOOLFILE *, DBTCL_INFO *)); +static int tcl_Pg __P((Tcl_Interp *, int, Tcl_Obj * CONST*, + void *, DB_MPOOLFILE *, DBTCL_INFO *, int)); +static int tcl_PgInit __P((Tcl_Interp *, int, Tcl_Obj * CONST*, + void *, DBTCL_INFO *)); +static int tcl_PgIsset __P((Tcl_Interp *, int, Tcl_Obj * CONST*, + void *, DBTCL_INFO *)); + +/* + * _MpInfoDelete -- + * Removes "sub" mp page info structures that are children + * of this mp. + * + * PUBLIC: void _MpInfoDelete __P((Tcl_Interp *, DBTCL_INFO *)); + */ +void +_MpInfoDelete(interp, mpip) + Tcl_Interp *interp; /* Interpreter */ + DBTCL_INFO *mpip; /* Info for mp */ +{ + DBTCL_INFO *nextp, *p; + + for (p = LIST_FIRST(&__db_infohead); p != NULL; p = nextp) { + /* + * Check if this info structure "belongs" to this + * mp. Remove its commands and info structure. + */ + nextp = LIST_NEXT(p, entries); + if (p->i_parent == mpip && p->i_type == I_PG) { + (void)Tcl_DeleteCommand(interp, p->i_name); + _DeleteInfo(p); + } + } +} + +/* + * tcl_MpSync -- + * + * PUBLIC: int tcl_MpSync __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *)); + */ +int +tcl_MpSync(interp, objc, objv, envp) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB_ENV *envp; /* Environment pointer */ +{ + + DB_LSN lsn; + int result, ret; + + result = TCL_OK; + /* + * No flags, must be 3 args. + */ + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "lsn"); + return (TCL_ERROR); + } + + result = _GetLsn(interp, objv[2], &lsn); + if (result == TCL_ERROR) + return (result); + + _debug_check(); + ret = memp_sync(envp, &lsn); + result = _ReturnSetup(interp, ret, "memp sync"); + return (result); +} + +/* + * tcl_MpTrickle -- + * + * PUBLIC: int tcl_MpTrickle __P((Tcl_Interp *, int, + * PUBLIC: Tcl_Obj * CONST*, DB_ENV *)); + */ +int +tcl_MpTrickle(interp, objc, objv, envp) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB_ENV *envp; /* Environment pointer */ +{ + + int pages; + int percent; + int result; + int ret; + Tcl_Obj *res; + + result = TCL_OK; + /* + * No flags, must be 3 args. + */ + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "percent"); + return (TCL_ERROR); + } + + result = Tcl_GetIntFromObj(interp, objv[2], &percent); + if (result == TCL_ERROR) + return (result); + + _debug_check(); + ret = memp_trickle(envp, percent, &pages); + result = _ReturnSetup(interp, ret, "memp trickle"); + if (result == TCL_ERROR) + return (result); + + res = Tcl_NewIntObj(pages); + Tcl_SetObjResult(interp, res); + return (result); + +} + +/* + * tcl_Mp -- + * + * PUBLIC: int tcl_Mp __P((Tcl_Interp *, int, + * PUBLIC: Tcl_Obj * CONST*, DB_ENV *, DBTCL_INFO *)); + */ +int +tcl_Mp(interp, objc, objv, envp, envip) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB_ENV *envp; /* Environment pointer */ + DBTCL_INFO *envip; /* Info pointer */ +{ + static char *mpopts[] = { + "-create", + "-mode", + "-nommap", + "-pagesize", + "-rdonly", + NULL + }; + enum mpopts { + MPCREATE, + MPMODE, + MPNOMMAP, + MPPAGE, + MPRDONLY + }; + DBTCL_INFO *ip; + DB_MPOOLFILE *mpf; + Tcl_Obj *res; + u_int32_t flag; + int i, pgsize, mode, optindex, result, ret; + char *file, newname[MSG_SIZE]; + + result = TCL_OK; + i = 2; + flag = 0; + mode = 0; + pgsize = 0; + memset(newname, 0, MSG_SIZE); + while (i < objc) { + if (Tcl_GetIndexFromObj(interp, objv[i], + mpopts, "option", TCL_EXACT, &optindex) != TCL_OK) { + /* + * Reset the result so we don't get an errant + * error message if there is another error. + * This arg is the file name. + */ + if (IS_HELP(objv[i]) == TCL_OK) + return (TCL_OK); + Tcl_ResetResult(interp); + break; + } + i++; + switch ((enum mpopts)optindex) { + case MPCREATE: + flag |= DB_CREATE; + break; + case MPNOMMAP: + flag |= DB_NOMMAP; + break; + case MPPAGE: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-pagesize size?"); + result = TCL_ERROR; + break; + } + /* + * Don't need to check result here because + * if TCL_ERROR, the error message is already + * set up, and we'll bail out below. If ok, + * the mode is set and we go on. + */ + result = Tcl_GetIntFromObj(interp, objv[i++], &pgsize); + break; + case MPRDONLY: + flag |= DB_RDONLY; + break; + case MPMODE: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-mode mode?"); + result = TCL_ERROR; + break; + } + /* + * Don't need to check result here because + * if TCL_ERROR, the error message is already + * set up, and we'll bail out below. If ok, + * the mode is set and we go on. + */ + result = Tcl_GetIntFromObj(interp, objv[i++], &mode); + break; + } + if (result != TCL_OK) + goto error; + } + /* + * Any left over arg is a file name. It better be the last arg. + */ + file = NULL; + if (i != objc) { + if (i != objc - 1) { + Tcl_WrongNumArgs(interp, 2, objv, "?args? ?file?"); + result = TCL_ERROR; + goto error; + } + file = Tcl_GetStringFromObj(objv[i++], NULL); + } + + snprintf(newname, sizeof(newname), "%s.mp%d", + envip->i_name, envip->i_envmpid); + ip = _NewInfo(interp, NULL, newname, I_MP); + if (ip == NULL) { + Tcl_SetResult(interp, "Could not set up info", + TCL_STATIC); + return (TCL_ERROR); + } + /* + * XXX finfop is NULL here. Interface currently doesn't + * have all the stuff. Should expand interface. + */ + _debug_check(); + ret = memp_fopen(envp, file, flag, mode, (size_t)pgsize, NULL, &mpf); + if (ret != 0) { + result = _ReturnSetup(interp, ret, "mpool"); + _DeleteInfo(ip); + } else { + /* + * Success. Set up return. Set up new info + * and command widget for this mpool. + */ + envip->i_envmpid++; + ip->i_parent = envip; + ip->i_pgsz = pgsize; + _SetInfoData(ip, mpf); + Tcl_CreateObjCommand(interp, newname, + (Tcl_ObjCmdProc *)mp_Cmd, (ClientData)mpf, NULL); + res = Tcl_NewStringObj(newname, strlen(newname)); + Tcl_SetObjResult(interp, res); + } +error: + return (result); +} + +/* + * tcl_MpStat -- + * + * PUBLIC: int tcl_MpStat __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *)); + */ +int +tcl_MpStat(interp, objc, objv, envp) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB_ENV *envp; /* Environment pointer */ +{ + DB_MPOOL_STAT *sp; + DB_MPOOL_FSTAT **fsp, **savefsp; + int result; + int ret; + Tcl_Obj *res; + Tcl_Obj *res1; + + result = TCL_OK; + savefsp = NULL; + /* + * No args for this. Error if there are some. + */ + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + _debug_check(); + ret = memp_stat(envp, &sp, &fsp, NULL); + result = _ReturnSetup(interp, ret, "memp stat"); + if (result == TCL_ERROR) + return (result); + + /* + * Have our stats, now construct the name value + * list pairs and free up the memory. + */ + res = Tcl_NewObj(); + /* + * MAKE_STAT_LIST assumes 'res' and 'error' label. + */ + MAKE_STAT_LIST("Region size", sp->st_regsize); + MAKE_STAT_LIST("Cache size (gbytes)", sp->st_gbytes); + MAKE_STAT_LIST("Cache size (bytes)", sp->st_bytes); + MAKE_STAT_LIST("Cache hits", sp->st_cache_hit); + MAKE_STAT_LIST("Cache misses", sp->st_cache_miss); + MAKE_STAT_LIST("Number of caches", sp->st_ncache); + MAKE_STAT_LIST("Pages mapped into address space", sp->st_map); + MAKE_STAT_LIST("Pages created", sp->st_page_create); + MAKE_STAT_LIST("Pages read in", sp->st_page_in); + MAKE_STAT_LIST("Pages written", sp->st_page_out); + MAKE_STAT_LIST("Clean page evictions", sp->st_ro_evict); + MAKE_STAT_LIST("Dirty page evictions", sp->st_rw_evict); + MAKE_STAT_LIST("Hash buckets", sp->st_hash_buckets); + MAKE_STAT_LIST("Hash lookups", sp->st_hash_searches); + MAKE_STAT_LIST("Longest hash chain found", sp->st_hash_longest); + MAKE_STAT_LIST("Hash elements examined", sp->st_hash_examined); + MAKE_STAT_LIST("Cached clean pages", sp->st_page_clean); + MAKE_STAT_LIST("Cached dirty pages", sp->st_page_dirty); + MAKE_STAT_LIST("Dirty pages trickled", sp->st_page_trickle); + MAKE_STAT_LIST("Number of region lock waits", sp->st_region_wait); + MAKE_STAT_LIST("Number of region lock nowaits", sp->st_region_nowait); + /* + * Save global stat list as res1. The MAKE_STAT_LIST + * macro assumes 'res' so we'll use that to build up + * our per-file sublist. + */ + res1 = res; + savefsp = fsp; + for (; fsp != NULL && *fsp != NULL; fsp++) { + res = Tcl_NewObj(); + result = _SetListElem(interp, res, "File Name", + strlen("File Name"), (*fsp)->file_name, + strlen((*fsp)->file_name)); + if (result != TCL_OK) + goto error; + MAKE_STAT_LIST("Page size", (*fsp)->st_pagesize); + MAKE_STAT_LIST("Cache Hits", (*fsp)->st_cache_hit); + MAKE_STAT_LIST("Cache Misses", (*fsp)->st_cache_miss); + MAKE_STAT_LIST("Pages mapped into address space", + (*fsp)->st_map); + MAKE_STAT_LIST("Pages created", (*fsp)->st_page_create); + MAKE_STAT_LIST("Pages read in", (*fsp)->st_page_in); + MAKE_STAT_LIST("Pages written", (*fsp)->st_page_out); + /* + * Now that we have a complete "per-file" stat + * list, append that to the other list. + */ + result = Tcl_ListObjAppendElement(interp, res1, res); + if (result != TCL_OK) + goto error; + } + Tcl_SetObjResult(interp, res1); +error: + __os_free(sp, sizeof(*sp)); + if (savefsp != NULL) + __os_free(savefsp, 0); + return (result); +} + +/* + * mp_Cmd -- + * Implements the "mp" widget. + */ +static int +mp_Cmd(clientData, interp, objc, objv) + ClientData clientData; /* Mp handle */ + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ +{ + static char *mpcmds[] = { + "close", "fsync", "get", + NULL + }; + enum mpcmds { + MPCLOSE, MPFSYNC, MPGET + }; + DB_MPOOLFILE *mp; + int cmdindex, length, result, ret; + DBTCL_INFO *mpip; + Tcl_Obj *res; + char *obj_name; + + Tcl_ResetResult(interp); + mp = (DB_MPOOLFILE *)clientData; + obj_name = Tcl_GetStringFromObj(objv[0], &length); + mpip = _NameToInfo(obj_name); + result = TCL_OK; + + if (mp == NULL) { + Tcl_SetResult(interp, "NULL mp pointer", TCL_STATIC); + return (TCL_ERROR); + } + if (mpip == NULL) { + Tcl_SetResult(interp, "NULL mp info pointer", TCL_STATIC); + return (TCL_ERROR); + } + + /* + * Get the command name index from the object based on the dbcmds + * defined above. + */ + if (Tcl_GetIndexFromObj(interp, + objv[1], mpcmds, "command", TCL_EXACT, &cmdindex) != TCL_OK) + return (IS_HELP(objv[1])); + + res = NULL; + switch ((enum mpcmds)cmdindex) { + case MPCLOSE: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return (TCL_ERROR); + } + _debug_check(); + ret = memp_fclose(mp); + result = _ReturnSetup(interp, ret, "mp close"); + _MpInfoDelete(interp, mpip); + (void)Tcl_DeleteCommand(interp, mpip->i_name); + _DeleteInfo(mpip); + break; + case MPFSYNC: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return (TCL_ERROR); + } + _debug_check(); + ret = memp_fsync(mp); + res = Tcl_NewIntObj(ret); + break; + case MPGET: + result = tcl_MpGet(interp, objc, objv, mp, mpip); + break; + } + /* + * Only set result if we have a res. Otherwise, lower + * functions have already done so. + */ + if (result == TCL_OK && res) + Tcl_SetObjResult(interp, res); + return (result); +} + +/* + * tcl_MpGet -- + */ +static int +tcl_MpGet(interp, objc, objv, mp, mpip) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB_MPOOLFILE *mp; /* mp pointer */ + DBTCL_INFO *mpip; /* mp info pointer */ +{ + static char *mpget[] = { + "-create", "-last", "-new", + NULL + }; + enum mpget { + MPGET_CREATE, MPGET_LAST, MPGET_NEW + }; + + DBTCL_INFO *ip; + Tcl_Obj *res; + db_pgno_t pgno; + u_int32_t flag; + int i, ipgno, optindex, result, ret; + char newname[MSG_SIZE]; + void *page; + + result = TCL_OK; + memset(newname, 0, MSG_SIZE); + i = 2; + flag = 0; + while (i < objc) { + if (Tcl_GetIndexFromObj(interp, objv[i], + mpget, "option", TCL_EXACT, &optindex) != TCL_OK) { + /* + * Reset the result so we don't get an errant + * error message if there is another error. + * This arg is the page number. + */ + if (IS_HELP(objv[i]) == TCL_OK) + return (TCL_OK); + Tcl_ResetResult(interp); + break; + } + i++; + switch ((enum mpget)optindex) { + case MPGET_CREATE: + flag |= DB_MPOOL_CREATE; + break; + case MPGET_LAST: + flag |= DB_MPOOL_LAST; + break; + case MPGET_NEW: + flag |= DB_MPOOL_NEW; + break; + } + if (result != TCL_OK) + goto error; + } + /* + * Any left over arg is a page number. It better be the last arg. + */ + ipgno = 0; + if (i != objc) { + if (i != objc - 1) { + Tcl_WrongNumArgs(interp, 2, objv, "?args? ?pgno?"); + result = TCL_ERROR; + goto error; + } + result = Tcl_GetIntFromObj(interp, objv[i++], &ipgno); + if (result != TCL_OK) + goto error; + } + + snprintf(newname, sizeof(newname), "%s.pg%d", + mpip->i_name, mpip->i_mppgid); + ip = _NewInfo(interp, NULL, newname, I_PG); + if (ip == NULL) { + Tcl_SetResult(interp, "Could not set up info", + TCL_STATIC); + return (TCL_ERROR); + } + _debug_check(); + pgno = ipgno; + ret = memp_fget(mp, &pgno, flag, &page); + result = _ReturnSetup(interp, ret, "mpool get"); + if (result == TCL_ERROR) + _DeleteInfo(ip); + else { + /* + * Success. Set up return. Set up new info + * and command widget for this mpool. + */ + mpip->i_mppgid++; + ip->i_parent = mpip; + ip->i_pgno = pgno; + ip->i_pgsz = mpip->i_pgsz; + _SetInfoData(ip, page); + Tcl_CreateObjCommand(interp, newname, + (Tcl_ObjCmdProc *)pg_Cmd, (ClientData)page, NULL); + res = Tcl_NewStringObj(newname, strlen(newname)); + Tcl_SetObjResult(interp, res); + } +error: + return (result); +} + +/* + * pg_Cmd -- + * Implements the "pg" widget. + */ +static int +pg_Cmd(clientData, interp, objc, objv) + ClientData clientData; /* Page handle */ + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ +{ + static char *pgcmds[] = { + "init", + "is_setto", + "pgnum", + "pgsize", + "put", + "set", + NULL + }; + enum pgcmds { + PGINIT, + PGISSET, + PGNUM, + PGSIZE, + PGPUT, + PGSET + }; + DB_MPOOLFILE *mp; + int cmdindex, length, result; + char *obj_name; + void *page; + DBTCL_INFO *pgip; + Tcl_Obj *res; + + Tcl_ResetResult(interp); + page = (void *)clientData; + obj_name = Tcl_GetStringFromObj(objv[0], &length); + pgip = _NameToInfo(obj_name); + mp = NAME_TO_MP(pgip->i_parent->i_name); + result = TCL_OK; + + if (page == NULL) { + Tcl_SetResult(interp, "NULL page pointer", TCL_STATIC); + return (TCL_ERROR); + } + if (mp == NULL) { + Tcl_SetResult(interp, "NULL mp pointer", TCL_STATIC); + return (TCL_ERROR); + } + if (pgip == NULL) { + Tcl_SetResult(interp, "NULL page info pointer", TCL_STATIC); + return (TCL_ERROR); + } + + /* + * Get the command name index from the object based on the dbcmds + * defined above. + */ + if (Tcl_GetIndexFromObj(interp, + objv[1], pgcmds, "command", TCL_EXACT, &cmdindex) != TCL_OK) + return (IS_HELP(objv[1])); + + res = NULL; + switch ((enum pgcmds)cmdindex) { + case PGNUM: + res = Tcl_NewIntObj(pgip->i_pgno); + break; + case PGSIZE: + res = Tcl_NewLongObj(pgip->i_pgsz); + break; + case PGSET: + case PGPUT: + result = tcl_Pg(interp, objc, objv, page, mp, pgip, + cmdindex == PGSET ? 0 : 1); + break; + case PGINIT: + result = tcl_PgInit(interp, objc, objv, page, pgip); + break; + case PGISSET: + result = tcl_PgIsset(interp, objc, objv, page, pgip); + break; + } + /* + * Only set result if we have a res. Otherwise, lower + * functions have already done so. + */ + if (result == TCL_OK && res) + Tcl_SetObjResult(interp, res); + return (result); +} + +static int +tcl_Pg(interp, objc, objv, page, mp, pgip, putop) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + void *page; /* Page pointer */ + DB_MPOOLFILE *mp; /* Mpool pointer */ + DBTCL_INFO *pgip; /* Info pointer */ + int putop; /* Operation */ +{ + static char *pgopt[] = { + "-clean", "-dirty", "-discard", + NULL + }; + enum pgopt { + PGCLEAN, PGDIRTY, PGDISCARD + }; + u_int32_t flag; + int i, optindex, result, ret; + + result = TCL_OK; + i = 2; + flag = 0; + while (i < objc) { + if (Tcl_GetIndexFromObj(interp, objv[i], + pgopt, "option", TCL_EXACT, &optindex) != TCL_OK) + return (IS_HELP(objv[i])); + i++; + switch ((enum pgopt)optindex) { + case PGCLEAN: + flag |= DB_MPOOL_CLEAN; + break; + case PGDIRTY: + flag |= DB_MPOOL_DIRTY; + break; + case PGDISCARD: + flag |= DB_MPOOL_DISCARD; + break; + } + } + + _debug_check(); + if (putop) + ret = memp_fput(mp, page, flag); + else + ret = memp_fset(mp, page, flag); + + result = _ReturnSetup(interp, ret, "page"); + + if (putop) { + (void)Tcl_DeleteCommand(interp, pgip->i_name); + _DeleteInfo(pgip); + } + return (result); +} + +static int +tcl_PgInit(interp, objc, objv, page, pgip) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + void *page; /* Page pointer */ + DBTCL_INFO *pgip; /* Info pointer */ +{ + Tcl_Obj *res; + size_t pgsz; + long *p, *endp, newval; + int length, result; + u_char *s; + + result = TCL_OK; + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "val"); + return (TCL_ERROR); + } + + pgsz = pgip->i_pgsz; + result = Tcl_GetLongFromObj(interp, objv[2], &newval); + if (result != TCL_OK) { + s = Tcl_GetByteArrayFromObj(objv[2], &length); + if (s == NULL) + return (TCL_ERROR); + memcpy(page, s, ((size_t)length < pgsz) ? length : pgsz); + result = TCL_OK; + } else { + p = (long *)page; + for (endp = p + (pgsz / sizeof(long)); p < endp; p++) + *p = newval; + } + res = Tcl_NewIntObj(0); + Tcl_SetObjResult(interp, res); + return (result); +} + +static int +tcl_PgIsset(interp, objc, objv, page, pgip) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + void *page; /* Page pointer */ + DBTCL_INFO *pgip; /* Info pointer */ +{ + Tcl_Obj *res; + size_t pgsz; + long *p, *endp, newval; + int length, result; + u_char *s; + + result = TCL_OK; + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "val"); + return (TCL_ERROR); + } + + pgsz = pgip->i_pgsz; + result = Tcl_GetLongFromObj(interp, objv[2], &newval); + if (result != TCL_OK) { + if ((s = Tcl_GetByteArrayFromObj(objv[2], &length)) == NULL) + return (TCL_ERROR); + result = TCL_OK; + + if (memcmp(page, + s, ((size_t)length < pgsz) ? length : pgsz ) != 0) { + res = Tcl_NewIntObj(0); + Tcl_SetObjResult(interp, res); + return (result); + } + } else { + p = (long *)page; + /* + * If any value is not the same, return 0 (is not set to + * this value). Otherwise, if we finish the loop, we return 1 + * (is set to this value). + */ + for (endp = p + (pgsz/sizeof(long)); p < endp; p++) + if (*p != newval) { + res = Tcl_NewIntObj(0); + Tcl_SetObjResult(interp, res); + return (result); + } + } + + res = Tcl_NewIntObj(1); + Tcl_SetObjResult(interp, res); + return (result); +} diff --git a/db/tcl/tcl_txn.c b/db/tcl/tcl_txn.c new file mode 100644 index 000000000..dfe6b6cf6 --- /dev/null +++ b/db/tcl/tcl_txn.c @@ -0,0 +1,473 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: tcl_txn.c,v 11.24 2000/12/31 19:26:23 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#endif + +#include "db_int.h" +#include "tcl_db.h" + +/* + * Prototypes for procedures defined later in this file: + */ +static int tcl_TxnCommit __P((Tcl_Interp *, int, Tcl_Obj * CONST*, + DB_TXN *, DBTCL_INFO *)); + +/* + * _TxnInfoDelete -- + * Removes nested txn info structures that are children + * of this txn. + * RECURSIVE: Transactions can be arbitrarily nested, so we + * must recurse down until we get them all. + * + * PUBLIC: void _TxnInfoDelete __P((Tcl_Interp *, DBTCL_INFO *)); + */ +void +_TxnInfoDelete(interp, txnip) + Tcl_Interp *interp; /* Interpreter */ + DBTCL_INFO *txnip; /* Info for txn */ +{ + DBTCL_INFO *nextp, *p; + + for (p = LIST_FIRST(&__db_infohead); p != NULL; p = nextp) { + /* + * Check if this info structure "belongs" to this + * txn. Remove its commands and info structure. + */ + nextp = LIST_NEXT(p, entries); + if (p->i_parent == txnip && p->i_type == I_TXN) { + _TxnInfoDelete(interp, p); + (void)Tcl_DeleteCommand(interp, p->i_name); + _DeleteInfo(p); + } + } +} + +/* + * tcl_TxnCheckpoint -- + * + * PUBLIC: int tcl_TxnCheckpoint __P((Tcl_Interp *, int, + * PUBLIC: Tcl_Obj * CONST*, DB_ENV *)); + */ +int +tcl_TxnCheckpoint(interp, objc, objv, envp) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB_ENV *envp; /* Environment pointer */ +{ + static char *txnckpopts[] = { + "-kbyte", "-min", + NULL + }; + enum txnckpopts { + TXNCKP_KB, TXNCKP_MIN + }; + int i, kb, min, optindex, result, ret; + + result = TCL_OK; + kb = min = 0; + + /* + * Get the flag index from the object based on the options + * defined above. + */ + i = 2; + while (i < objc) { + if (Tcl_GetIndexFromObj(interp, objv[i], + txnckpopts, "option", TCL_EXACT, &optindex) != TCL_OK) { + return (IS_HELP(objv[i])); + } + i++; + switch ((enum txnckpopts)optindex) { + case TXNCKP_KB: + if (i == objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-kbyte kb?"); + result = TCL_ERROR; + break; + } + result = Tcl_GetIntFromObj(interp, objv[i++], &kb); + break; + case TXNCKP_MIN: + if (i == objc) { + Tcl_WrongNumArgs(interp, 2, objv, "?-min min?"); + result = TCL_ERROR; + break; + } + result = Tcl_GetIntFromObj(interp, objv[i++], &min); + break; + } + } + _debug_check(); + ret = txn_checkpoint(envp, (u_int32_t)kb, (u_int32_t)min, 0); + result = _ReturnSetup(interp, ret, "txn checkpoint"); + return (result); +} + +/* + * tcl_Txn -- + * + * PUBLIC: int tcl_Txn __P((Tcl_Interp *, int, + * PUBLIC: Tcl_Obj * CONST*, DB_ENV *, DBTCL_INFO *)); + */ +int +tcl_Txn(interp, objc, objv, envp, envip) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB_ENV *envp; /* Environment pointer */ + DBTCL_INFO *envip; /* Info pointer */ +{ + static char *txnopts[] = { + "-nosync", + "-nowait", + "-parent", + "-sync", + NULL + }; + enum txnopts { + TXN_NOSYNC, + TXN_NOWAIT, + TXN_PARENT, + TXN_SYNC + }; + DBTCL_INFO *ip; + DB_TXN *parent; + DB_TXN *txn; + Tcl_Obj *res; + u_int32_t flag; + int i, optindex, result, ret; + char *arg, msg[MSG_SIZE], newname[MSG_SIZE]; + + result = TCL_OK; + memset(newname, 0, MSG_SIZE); + + parent = NULL; + flag = 0; + i = 2; + while (i < objc) { + if (Tcl_GetIndexFromObj(interp, objv[i], + txnopts, "option", TCL_EXACT, &optindex) != TCL_OK) { + return (IS_HELP(objv[i])); + } + i++; + switch ((enum txnopts)optindex) { + case TXN_PARENT: + if (i == objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-parent txn?"); + result = TCL_ERROR; + break; + } + arg = Tcl_GetStringFromObj(objv[i++], NULL); + parent = NAME_TO_TXN(arg); + if (parent == NULL) { + snprintf(msg, MSG_SIZE, + "Invalid parent txn: %s\n", + arg); + Tcl_SetResult(interp, msg, TCL_VOLATILE); + return (TCL_ERROR); + } + break; + case TXN_NOWAIT: + FLAG_CHECK(flag); + flag |= DB_TXN_NOWAIT; + break; + case TXN_SYNC: + FLAG_CHECK(flag); + flag |= DB_TXN_SYNC; + break; + case TXN_NOSYNC: + FLAG_CHECK(flag); + flag |= DB_TXN_NOSYNC; + break; + } + } + snprintf(newname, sizeof(newname), "%s.txn%d", + envip->i_name, envip->i_envtxnid); + ip = _NewInfo(interp, NULL, newname, I_TXN); + if (ip == NULL) { + Tcl_SetResult(interp, "Could not set up info", + TCL_STATIC); + return (TCL_ERROR); + } + _debug_check(); + ret = txn_begin(envp, parent, &txn, flag); + result = _ReturnSetup(interp, ret, "txn"); + if (result == TCL_ERROR) + _DeleteInfo(ip); + else { + /* + * Success. Set up return. Set up new info + * and command widget for this txn. + */ + envip->i_envtxnid++; + if (parent) + ip->i_parent = _PtrToInfo(parent); + else + ip->i_parent = envip; + _SetInfoData(ip, txn); + Tcl_CreateObjCommand(interp, newname, + (Tcl_ObjCmdProc *)txn_Cmd, (ClientData)txn, NULL); + res = Tcl_NewStringObj(newname, strlen(newname)); + Tcl_SetObjResult(interp, res); + } + return (result); +} + +/* + * tcl_TxnStat -- + * + * PUBLIC: int tcl_TxnStat __P((Tcl_Interp *, int, + * PUBLIC: Tcl_Obj * CONST*, DB_ENV *)); + */ +int +tcl_TxnStat(interp, objc, objv, envp) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB_ENV *envp; /* Environment pointer */ +{ +#define MAKE_STAT_LSN(s, lsn) \ +do { \ + myobjc = 2; \ + myobjv[0] = Tcl_NewIntObj((lsn)->file); \ + myobjv[1] = Tcl_NewIntObj((lsn)->offset); \ + lsnlist = Tcl_NewListObj(myobjc, myobjv); \ + myobjc = 2; \ + myobjv[0] = Tcl_NewStringObj((s), strlen(s)); \ + myobjv[1] = lsnlist; \ + thislist = Tcl_NewListObj(myobjc, myobjv); \ + result = Tcl_ListObjAppendElement(interp, res, thislist); \ + if (result != TCL_OK) \ + goto error; \ +} while (0); + + DBTCL_INFO *ip; + DB_TXN_ACTIVE *p; + DB_TXN_STAT *sp; + Tcl_Obj *myobjv[2], *res, *thislist, *lsnlist; + u_int32_t i; + int myobjc, result, ret; + + result = TCL_OK; + /* + * No args for this. Error if there are some. + */ + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + _debug_check(); + ret = txn_stat(envp, &sp, NULL); + result = _ReturnSetup(interp, ret, "txn stat"); + if (result == TCL_ERROR) + return (result); + + /* + * Have our stats, now construct the name value + * list pairs and free up the memory. + */ + res = Tcl_NewObj(); + /* + * MAKE_STAT_LIST assumes 'res' and 'error' label. + */ + MAKE_STAT_LIST("Region size", sp->st_regsize); + MAKE_STAT_LSN("LSN of last checkpoint", &sp->st_last_ckp); + MAKE_STAT_LSN("LSN of pending checkpoint", &sp->st_pending_ckp); + MAKE_STAT_LIST("Time of last checkpoint", sp->st_time_ckp); + MAKE_STAT_LIST("Last txn ID allocated", sp->st_last_txnid); + MAKE_STAT_LIST("Max Txns", sp->st_maxtxns); + MAKE_STAT_LIST("Number aborted txns", sp->st_naborts); + MAKE_STAT_LIST("Number active txns", sp->st_nactive); + MAKE_STAT_LIST("Number txns begun", sp->st_nbegins); + MAKE_STAT_LIST("Number committed txns", sp->st_ncommits); + MAKE_STAT_LIST("Number of region lock waits", sp->st_region_wait); + MAKE_STAT_LIST("Number of region lock nowaits", sp->st_region_nowait); + for (i = 0, p = sp->st_txnarray; i < sp->st_nactive; i++, p++) + for (ip = LIST_FIRST(&__db_infohead); ip != NULL; + ip = LIST_NEXT(ip, entries)) { + if (ip->i_type != I_TXN) + continue; + if (ip->i_type == I_TXN && + (txn_id(ip->i_txnp) == p->txnid)) { + MAKE_STAT_LSN(ip->i_name, &p->lsn); + if (p->parentid != 0) + MAKE_STAT_STRLIST("Parent", + ip->i_parent->i_name); + else + MAKE_STAT_LIST("Parent", 0); + break; + } + } + Tcl_SetObjResult(interp, res); +error: + __os_free(sp, sizeof(*sp)); + return (result); +} + +/* + * txn_Cmd -- + * Implements the "txn" widget. + * + * PUBLIC: int txn_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*)); + */ +int +txn_Cmd(clientData, interp, objc, objv) + ClientData clientData; /* Txn handle */ + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ +{ + static char *txncmds[] = { + "abort", + "commit", + "id", + "prepare", + NULL + }; + enum txncmds { + TXNABORT, + TXNCOMMIT, + TXNID, + TXNPREPARE + }; + DBTCL_INFO *txnip; + DB_TXN *txnp; + Tcl_Obj *res; + int cmdindex, result, ret; + + Tcl_ResetResult(interp); + txnp = (DB_TXN *)clientData; + txnip = _PtrToInfo((void *)txnp); + result = TCL_OK; + if (txnp == NULL) { + Tcl_SetResult(interp, "NULL txn pointer", TCL_STATIC); + return (TCL_ERROR); + } + if (txnip == NULL) { + Tcl_SetResult(interp, "NULL txn info pointer", TCL_STATIC); + return (TCL_ERROR); + } + + /* + * Get the command name index from the object based on the dbcmds + * defined above. + */ + if (Tcl_GetIndexFromObj(interp, + objv[1], txncmds, "command", TCL_EXACT, &cmdindex) != TCL_OK) + return (IS_HELP(objv[1])); + + res = NULL; + switch ((enum txncmds)cmdindex) { + case TXNID: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return (TCL_ERROR); + } + _debug_check(); + ret = txn_id(txnp); + res = Tcl_NewIntObj(ret); + break; + case TXNPREPARE: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return (TCL_ERROR); + } + _debug_check(); + ret = txn_prepare(txnp); + result = _ReturnSetup(interp, ret, "txn prepare"); + break; + case TXNCOMMIT: + result = tcl_TxnCommit(interp, objc, objv, txnp, txnip); + _TxnInfoDelete(interp, txnip); + (void)Tcl_DeleteCommand(interp, txnip->i_name); + _DeleteInfo(txnip); + break; + case TXNABORT: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return (TCL_ERROR); + } + _debug_check(); + ret = txn_abort(txnp); + result = _ReturnSetup(interp, ret, "txn abort"); + _TxnInfoDelete(interp, txnip); + (void)Tcl_DeleteCommand(interp, txnip->i_name); + _DeleteInfo(txnip); + break; + } + /* + * Only set result if we have a res. Otherwise, lower + * functions have already done so. + */ + if (result == TCL_OK && res) + Tcl_SetObjResult(interp, res); + return (result); +} + +static int +tcl_TxnCommit(interp, objc, objv, txnp, txnip) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB_TXN *txnp; /* Transaction pointer */ + DBTCL_INFO *txnip; /* Info pointer */ +{ + static char *commitopt[] = { + "-nosync", + "-sync", + NULL + }; + enum commitopt { + COMSYNC, + COMNOSYNC + }; + u_int32_t flag; + int optindex, result, ret; + + COMPQUIET(txnip, NULL); + + result = TCL_OK; + flag = 0; + if (objc != 2 && objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return (TCL_ERROR); + } + if (objc == 3) { + if (Tcl_GetIndexFromObj(interp, objv[2], commitopt, + "option", TCL_EXACT, &optindex) != TCL_OK) + return (IS_HELP(objv[2])); + switch ((enum commitopt)optindex) { + case COMSYNC: + FLAG_CHECK(flag); + flag = DB_TXN_SYNC; + break; + case COMNOSYNC: + FLAG_CHECK(flag); + flag = DB_TXN_NOSYNC; + break; + } + } + + _debug_check(); + ret = txn_commit(txnp, flag); + result = _ReturnSetup(interp, ret, "txn commit"); + return (result); +} diff --git a/db/test/TESTS b/db/test/TESTS new file mode 100644 index 000000000..a585bdddc --- /dev/null +++ b/db/test/TESTS @@ -0,0 +1,448 @@ +# $Id: TESTS,v 11.34 2000/11/06 19:31:56 sue Exp $ + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +Access method tests +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +test001 Small keys/data + Put/get per key + Dump file + Close, reopen + Dump file + +test002 Small keys/medium data + Put/get per key + Dump file + Close, reopen + Dump file + +test003 Small keys/large data + Put/get per key + Dump file + Close, reopen + Dump file + +test004 Small keys/medium data + Put/get per key + Sequential (cursor) get/delete + +test005 Small keys/medium data + Put/get per key + Close, reopen + Sequential (cursor) get/delete + +test006 Small keys/medium data + Put/get per key + Keyed delete and verify + +test007 Small keys/medium data + Put/get per key + Close, reopen + Keyed delete + +test008 Small keys/large data + Put/get per key + Loop through keys by steps (which change) + ... delete each key at step + ... add each key back + ... change step + Confirm that overflow pages are getting reused + +test009 Small keys/large data + Same as test008; close and reopen database + +test010 Duplicate test + Small key/data pairs. + +test011 Duplicate test + Small key/data pairs. + Test DB_KEYFIRST, DB_KEYLAST, DB_BEFORE and DB_AFTER. + To test off-page duplicates, run with small pagesize. + +test012 Large keys/small data + Same as test003 except use big keys (source files and + executables) and small data (the file/executable names). + +test013 Partial put test + Overwrite entire records using partial puts. Make sure + that NOOVERWRITE flag works. + +test014 Exercise partial puts on short data + Run 5 combinations of numbers of characters to replace, + and number of times to increase the size by. + +test015 Partial put test + Partial put test where the key does not initially exist. + +test016 Partial put test + Partial put where the datum gets shorter as a result of + the put. + +test017 Basic offpage duplicate test. + +test018 Offpage duplicate test + Key_{first,last,before,after} offpage duplicates. + +test019 Partial get test. + +test020 In-Memory database tests. + +test021 Btree range tests. + +test022 Test of DB->getbyteswapped(). + +test023 Duplicate test + Exercise deletes and cursor operations within a + duplicate set. + +test024 Record number retrieval test. + +test025 DB_APPEND flag test. + +test026 Small keys/medium data w/duplicates + Put/get per key. + Loop through keys -- delete each key + ... test that cursors delete duplicates correctly + +test027 Off-page duplicate test + Test026 with parameters to force off-page duplicates. + +test028 Cursor delete test + Test put operations after deleting through a cursor. + +test029 Record renumbering + +test030 DB_NEXT_DUP functionality + +test031 Duplicate sorting functionality + Make sure DB_NODUPDATA works. + +test032 DB_GET_BOTH + +test033 DB_GET_BOTH without comparison function + +test034 Test032 with off-page duplicates + +test035 Test033 with off-page duplicates + +test036 Test KEYFIRST and KEYLAST when the key doesn't exist + +test037 Test DB_RMW + +test038 DB_GET_BOTH on deleted items + +test039 DB_GET_BOTH on deleted items without comparison function + +test040 Test038 with off-page duplicates + +test041 Test039 with off-page duplicates + +test042 Concurrent Data Store test + +test043 Recno renumbering and implicit creation test + +test044 Small system integration tests + Test proper functioning of the checkpoint daemon, + recovery, transactions, etc. + +test045 Small random tester + Runs a number of random add/delete/retrieve operations. + Tests both successful conditions and error conditions. + +test046 Overwrite test of small/big key/data with cursor checks. + +test047 Cursor get test with SET_RANGE option. + +test048 Cursor stability across Btree splits. + +test049 Cursor operations on unitialized cursors. + +test050 Cursor overwrite test for Recno. + +test051 Fixed-length record Recno test. + +test052 Renumbering record Recno test. + +test053 DB_REVSPLITOFF flag test + +test054 Cursor maintenance during key/data deletion. + +test054 Basic cursor operations. + +test055 Cursor maintenance during key deletes. + +test056 Cursor maintenance during deletes. + +test057 Cursor maintenance during key deletes. + +test058 Verify that deleting and reading duplicates results in + correct ordering. + +test059 Cursor ops work with a partial length of 0. + +test060 Test of the DB_EXCL flag to DB->open(). + +test061 Test of txn abort and commit for in-memory databases. + +test062 Test of partial puts (using DB_CURRENT) onto duplicate pages. + +test063 Test of the DB_RDONLY flag to DB->open + +test064 Test of DB->get_type + +test065 Test of DB->stat(DB_RECORDCOUNT) + +test066 Test of cursor overwrites of DB_CURRENT w/ duplicates. + +test067 Test of DB_CURRENT partial puts onto almost empty duplicate + pages, with and without DB_DUP_SORT. + +test068 Test of DB_BEFORE and DB_AFTER with partial puts. + +test069 Test of DB_CURRENT partial puts without duplicates-- + test067 w/ small ndups. + +test070 Test of DB_CONSUME (Four consumers, 1000 items.) + +test071 Test of DB_CONSUME (One consumer, 10000 items.) + +test072 Cursor stability test when dups are moved off-page + +test073 Test of cursor stability on duplicate pages. + +test074 Test of DB_NEXT_NODUP. + +test075 Test of DB->rename(). + (formerly test of DB_TRUNCATE cached page invalidation [#1487]) + +test076 Test creation of many small databases in a single environment. + [#1528]. + +test077 Test of DB_GET_RECNO [#1206]. + +test078 Test of DBC->c_count(). + +test079 Test of deletes in large trees. (test006 w/ sm. pagesize). + +test080 Test of DB->remove() + +test081 Test off-page duplicates and overflow pages together with + very large keys (key/data as file contents). + +test082 Test of DB_PREV_NODUP (uses test074). + +test083 Test of DB->key_range. + +test084 Sanity test of large (64K) pages. + +test085 Test of cursor behavior when a cursor is pointing to a deleted + btree key which then has duplicates added. [#2473] + +test086 Test of cursor stability across btree splits/rsplits with + subtransaction aborts (a variant of test048). [#2373] + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +Cursor Join. +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +jointest Test duplicate assisted joins. + Executes 1, 2, 3 and 4-way joins with differing + index orders and selectivity. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +Deadlock detection. +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +dead001 Use two different configurations to test deadlock + detection among a variable number of processes. One + configuration has the processes deadlocked in a ring. + The other has the processes all deadlocked on a single + resource. + +dead002 Same test as dead001, but use "detect on every collision" + instead of separate deadlock detector. + +dead003 Same test as dead002, but explicitly specify oldest or + youngest. Verify the correct lock was aborted/granted. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +Lock tests +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +lock001 Basic lock test, gets/puts. Contention without waiting. + +lock002 Multi-process lock tests. + +lock003 Multiprocess random lock test. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +Logging test +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +log001 Read/write log records. + +log002 Tests multiple logs + Log truncation + lsn comparison and file functionality. + +log003 Verify that log_flush is flushing records correctly. + +log004 Prev on log when beginning of log has been truncated. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +Mpool test +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +memp001 Randomly updates pages. + +memp002 Tests multiple processes accessing and modifying the same + files. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +Recovery +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +recd001 Per-operation recovery tests for non-duplicate, non-split + messages. Makes sure that we exercise redo, undo, and + do-nothing condition. Any test that appears with the + message (change state) indicates that we've already run + the particular test, but we are running it again so that + we can change the state of the data base to prepare for + the next test (this applies to all other recovery tests + as well). + +recd002 Split recovery tests. For every known split log message, + makes sure that we exercise redo, undo, and do-nothing + condition. + +recd003 Duplicate recovery tests. For every known duplicate log + message, makes sure that we exercise redo, undo, and + do-nothing condition. + +recd004 Big key test where big key gets elevated to internal page. + +recd005 Verify reuse of file ids works on catastrophic recovery. + +recd006 Nested transactions. + +recd007 File create/delete tests. + +recd008 Test deeply nested transactions. + +recd009 Verify record numbering across split/reverse splits + and recovery. + +recd010 Verify duplicates across split/reverse splits + and recovery. + +recd011 Verify that recovery to a specific timestamp works. + +recd012 Test of log file ID management. [#2288] + +recd013 Test of cursor adjustment on child transaction aborts. [#2373] + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +Subdatabase tests +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +subdb001 Tests mixing db and subdb operations + Create a db, add data, try to create a subdb. + Test naming db and subdb with a leading - for + correct parsing + Existence check -- test use of -excl with subdbs + +subdb002 Tests basic subdb functionality + Small keys, small data + Put/get per key + Dump file + Close, reopen + Dump file + +subdb003 Tests many subdbs + Creates many subdbs and puts a small amount of + data in each (many defaults to 2000) + +subdb004 Tests large subdb names + subdb name = filecontents, + key = filename, data = filecontents + Put/get per key + Dump file + Dump subdbs, verify data and subdb name match + +subdb005 Tests cursor operations in subdbs + Put/get per key + Verify cursor operations work within subdb + Verify cursor operations do not work across subdbs + +subdb006 Tests intra-subdb join + +subdb007 Tests page size differences between subdbs + Open several subdbs, each with a different pagesize + Small keys, small data + Put/get per key per subdb + Dump file, verify per subdb + Close, reopen per subdb + Dump file, verify per subdb + +subdb008 Tests lorder differences between subdbs + Open several subdbs, each with a different/random lorder + Small keys, small data + Put/get per key per subdb + Dump file, verify per subdb + Close, reopen per subdb + Dump file, verify per subdb + +subdb009 Test DB->rename() method for subdbs + +subdb010 Test DB->remove() method for subdbs + +subdbtest001 Tests multiple access methods in one subdb + Open several subdbs, each with a different access method + Small keys, small data + Put/get per key per subdb + Dump file, verify per subdb + Close, reopen per subdb + Dump file, verify per subdb + +subdbtest002 Tests multiple access methods in one subdb access by + multiple processes + Open several subdbs, each with a different access method + Small keys, small data + Put/get per key per subdb + Fork off several child procs to each delete selected + data from their subdb and then exit + Dump file, verify contents of each subdb is correct + Close, reopen per subdb + Dump file, verify per subdb + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +Transaction tests +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +txn001 Begin, commit, abort testing. + +txn002 Verify that read-only transactions do not write log records. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +Environment tests +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +env001 Test of env remove interface (formerly env_remove). + +env002 Test of DB_LOG_DIR and env name resolution. + +env003 Test of DB_TMP_DIR and env name resolution. + +env004 Multiple data directories test. + +env005 Test for using subsystems without initializing them correctly. + +env006 Smoke test that the utilities all run. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +RPC tests +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +[RPC tests also include running all Access Method tests for all methods +via an RPC server] + +rpc001 Test RPC server timeouts for cursor, txn and env handles. + +rpc002 Test unsupported functions + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +Recno backing file tests +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +rsrc001 Basic backing file test (put/get) + +rsrc002 Test of set_re_delim diff --git a/db/test/archive.tcl b/db/test/archive.tcl new file mode 100644 index 000000000..9fdbe82d1 --- /dev/null +++ b/db/test/archive.tcl @@ -0,0 +1,232 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: archive.tcl,v 11.14 2000/10/27 13:23:55 sue Exp $ +# +# Options are: +# -checkrec +# -maxfilesize +# -stat +proc archive_usage {} { + puts "archive -checkrec -dir \ + -maxfilesize " +} +proc archive_command { args } { + source ./include.tcl + + # Catch a list of files output by db_archive. + catch { eval exec $util_path/db_archive $args } output + + if { $is_windows_test == 1 || 1 } { + # On Windows, convert all filenames to use forward slashes. + regsub -all {[\\]} $output / output + } + + # Output the [possibly-transformed] list. + return $output +} +proc archive { args } { + global alphabet + source ./include.tcl + + # Set defaults + set maxbsize [expr 8 * 1024] + set maxfile [expr 32 * 1024] + set dostat 0 + set checkrec 500 + for { set i 0 } { $i < [llength $args] } {incr i} { + switch -regexp -- [lindex $args $i] { + -c.* { incr i; set checkrec [lindex $args $i] } + -d.* { incr i; set testdir [lindex $args $i] } + -m.* { incr i; set maxfile [lindex $args $i] } + -s.* { set dostat 1 } + default { + puts -nonewline "FAIL:[timestamp] Usage: " + archive_usage + return + } + + } + } + + # Clean out old log if it existed + puts "Unlinking log: error message OK" + env_cleanup $testdir + + # Now run the various functionality tests + set eflags "-create -txn -home $testdir \ + -log_buffer $maxbsize -log_max $maxfile" + set dbenv [eval {berkdb env} $eflags] + error_check_bad dbenv $dbenv NULL + error_check_good dbenv [is_substr $dbenv env] 1 + + # The basic test structure here is that we write a lot of log + # records (enough to fill up 100 log files; each log file it + # small). We take periodic checkpoints. Between each pair + # of checkpoints, we refer to 2 files, overlapping them each + # checkpoint. We also start transactions and let them overlap + # checkpoints as well. The pattern that we try to create is: + # ---- write log records----|||||--- write log records --- + # -T1 T2 T3 --- D1 D2 ------CHECK--- CT1 --- D2 D3 CD1 ----CHECK + # where TX is begin transaction, CTx is commit transaction, DX is + # open data file and CDx is close datafile. + + set baserec "1:$alphabet:2:$alphabet:3:$alphabet:4:$alphabet" + puts "Archive.a: Writing log records; checkpoint every $checkrec records" + set nrecs $maxfile + set rec 0:$baserec + + # Begin transaction and write a log record + set t1 [$dbenv txn] + error_check_good t1:txn_begin [is_substr $t1 "txn"] 1 + + set l1 [$dbenv log_put $rec] + error_check_bad l1:log_put [llength $l1] 0 + + set lsnlist [list [lindex $l1 0]] + + set t2 [$dbenv txn] + error_check_good t2:txn_begin [is_substr $t2 "txn"] 1 + + set l1 [$dbenv log_put $rec] + lappend lsnlist [lindex $l1 0] + + set t3 [$dbenv txn] + set l1 [$dbenv log_put $rec] + lappend lsnlist [lindex $l1 0] + + set txnlist [list $t1 $t2 $t3] + set db1 [eval {berkdb_open} "-create -mode 0644 -hash -env $dbenv ar1"] + set db2 [eval {berkdb_open} "-create -mode 0644 -btree -env $dbenv ar2"] + set dbcount 3 + set dblist [list $db1 $db2] + + for { set i 1 } { $i <= $nrecs } { incr i } { + set rec $i:$baserec + set lsn [$dbenv log_put $rec] + error_check_bad log_put [llength $lsn] 0 + if { [expr $i % $checkrec] == 0 } { + # Take a checkpoint + $dbenv txn_checkpoint + set ckp_file [lindex [lindex [$dbenv log_get -last] 0] 0] + catch { archive_command -h $testdir -a } res_log_full + if { [string first db_archive $res_log_full] == 0 } { + set res_log_full "" + } + catch { archive_command -h $testdir } res_log + if { [string first db_archive $res_log] == 0 } { + set res_log "" + } + catch { archive_command -h $testdir -l } res_alllog + catch { archive_command -h $testdir -a -s } \ + res_data_full + catch { archive_command -h $testdir -s } res_data + error_check_good nlogfiles [llength $res_alllog] \ + [lindex [lindex [$dbenv log_get -last] 0] 0] + error_check_good logs_match [llength $res_log_full] \ + [llength $res_log] + error_check_good data_match [llength $res_data_full] \ + [llength $res_data] + + # Check right number of log files + error_check_good nlogs [llength $res_log] \ + [expr [lindex $lsnlist 0] - 1] + + # Check that the relative names are a subset of the + # full names + set n 0 + foreach x $res_log { + error_check_bad log_name_match:$res_log \ + [string first $x \ + [lindex $res_log_full $n]] -1 + incr n + } + + set n 0 + foreach x $res_data { + error_check_bad log_name_match:$res_data \ + [string first $x \ + [lindex $res_data_full $n]] -1 + incr n + } + + # Begin/commit any transactions + set t [lindex $txnlist 0] + if { [string length $t] != 0 } { + error_check_good txn_commit:$t [$t commit] 0 + set txnlist [lrange $txnlist 1 end] + } + set lsnlist [lrange $lsnlist 1 end] + + if { [llength $txnlist] == 0 } { + set t1 [$dbenv txn] + error_check_bad tx_begin $t1 NULL + error_check_good \ + tx_begin [is_substr $t1 $dbenv] 1 + set l1 [lindex [$dbenv log_put $rec] 0] + lappend lsnlist [min $l1 $ckp_file] + + set t2 [$dbenv txn] + error_check_bad tx_begin $t2 NULL + error_check_good \ + tx_begin [is_substr $t2 $dbenv] 1 + set l1 [lindex [$dbenv log_put $rec] 0] + lappend lsnlist [min $l1 $ckp_file] + + set t3 [$dbenv txn] + error_check_bad tx_begin $t3 NULL + error_check_good \ + tx_begin [is_substr $t3 $dbenv] 1 + set l1 [lindex [$dbenv log_put $rec] 0] + lappend lsnlist [min $l1 $ckp_file] + + set txnlist [list $t1 $t2 $t3] + } + + # Open/close some DB files + if { [expr $dbcount % 2] == 0 } { + set type "-hash" + } else { + set type "-btree" + } + set db [eval {berkdb_open} \ + "-create -mode 0644 $type -env $dbenv ar$dbcount"] + error_check_bad db_open:$dbcount $db NULL + error_check_good db_open:$dbcount [is_substr $db db] 1 + incr dbcount + + lappend dblist $db + set db [lindex $dblist 0] + error_check_good db_close:$db [$db close] 0 + set dblist [lrange $dblist 1 end] + + } + } + # Commit any transactions still running. + puts "Archive: Commit any transactions still running." + foreach t $txnlist { + error_check_good txn_commit:$t [$t commit] 0 + } + + # Close any files that are still open. + puts "Archive: Close open files." + foreach d $dblist { + error_check_good db_close:$db [$d close] 0 + } + + # Close and unlink the file + reset_env $dbenv + + puts "Archive: Complete." +} + +proc min { a b } { + if {$a < $b} { + return $a + } else { + return $b + } +} diff --git a/db/test/byteorder.tcl b/db/test/byteorder.tcl new file mode 100644 index 000000000..d9e44e1d2 --- /dev/null +++ b/db/test/byteorder.tcl @@ -0,0 +1,23 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: byteorder.tcl,v 11.7 2000/11/16 23:56:18 ubell Exp $ +# +# Byte Order Test +# Use existing tests and run with both byte orders. +proc byteorder { method {nentries 1000} } { + puts "Byteorder: $method $nentries" + + eval {test001 $method $nentries 0 "01" -lorder 1234} + eval {test001 $method $nentries 0 "01" -lorder 4321} + eval {test003 $method -lorder 1234} + eval {test003 $method -lorder 4321} + eval {test010 $method $nentries 5 10 -lorder 1234} + eval {test010 $method $nentries 5 10 -lorder 4321} + eval {test011 $method $nentries 5 11 -lorder 1234} + eval {test011 $method $nentries 5 11 -lorder 4321} + eval {test018 $method $nentries -lorder 1234} + eval {test018 $method $nentries -lorder 4321} +} diff --git a/db/test/conscript.tcl b/db/test/conscript.tcl new file mode 100644 index 000000000..11d0eb58e --- /dev/null +++ b/db/test/conscript.tcl @@ -0,0 +1,123 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: conscript.tcl,v 11.12 2000/12/01 04:28:36 ubell Exp $ +# +# Script for DB_CONSUME test (test070.tcl). +# Usage: conscript dir file runtype nitems outputfile tnum args +# dir: DBHOME directory +# file: db file on which to operate +# runtype: PRODUCE or CONSUME--which am I? +# nitems: number of items to put or get +# outputfile: where to log consumer results +# tnum: test number + +proc consumescript_produce { db_cmd nitems tnum args } { + source ./include.tcl + global mydata + + set pid [pid] + puts "\tTest0$tnum: Producer $pid starting, producing $nitems items." + + set db [eval $db_cmd] + error_check_good db_open:$pid [is_valid_db $db] TRUE + + set oret -1 + set ret 0 + for { set ndx 0 } { $ndx < $nitems } { incr ndx } { + set oret $ret + set ret [$db put -append [chop_data q $mydata]] + error_check_good db_put \ + [expr $ret > 0 ? $oret < $ret : \ + $oret < 0 ? $oret < $ret : $oret > $ret] 1 + + } + # XXX: We permit incomplete syncs because they seem to + # be unavoidable and not damaging. + set ret [catch {$db close} res] + error_check_good db_close:$pid [expr ($ret == 0) ||\ + ([is_substr $res DB_INCOMPLETE] == 1)] 1 + puts "\t\tTest0$tnum: Producer $pid finished." +} + +proc consumescript_consume { db_cmd nitems tnum outputfile mode args } { + source ./include.tcl + global mydata + set pid [pid] + puts "\tTest0$tnum: Consumer $pid starting, seeking $nitems items." + + set db [eval $db_cmd] + error_check_good db_open:$pid [is_valid_db $db] TRUE + + set oid [open $outputfile w] + + for { set ndx 0 } { $ndx < $nitems } { } { + set ret [$db get $mode] + if { [llength $ret] > 0 } { + error_check_good correct_data:$pid \ + [lindex [lindex $ret 0] 1] [pad_data q $mydata] + set rno [lindex [lindex $ret 0] 0] + puts $oid $rno + incr ndx + } else { + # No data to consume; wait. + } + } + + error_check_good output_close:$pid [close $oid] "" + # XXX: see above note. + set ret [catch {$db close} res] + error_check_good db_close:$pid [expr ($ret == 0) ||\ + ([is_substr $res DB_INCOMPLETE] == 1)] 1 + puts "\t\tTest0$tnum: Consumer $pid finished." +} + +source ./include.tcl +source $test_path/test.tcl + +# Verify usage +if { $argc < 6 } { + puts stderr "FAIL:[timestamp] Usage: $usage" + exit +} + +set usage "conscript.tcl dir file runtype nitems outputfile tnum" + +# Initialize arguments +set dir [lindex $argv 0] +set file [lindex $argv 1] +set runtype [lindex $argv 2] +set nitems [lindex $argv 3] +set outputfile [lindex $argv 4] +set tnum [lindex $argv 5] +# args is the string "{ -len 20 -pad 0}", so we need to extract the +# " -len 20 -pad 0" part. +set args [lindex [lrange $argv 6 end] 0] + +set mydata "consumer data" + +# Open env +set dbenv [berkdb env -home $dir ] +error_check_good db_env_create [is_valid_env $dbenv] TRUE + +# Figure out db opening command. +set db_cmd [concat {berkdb_open -create -mode 0644 -queue -env}\ + $dbenv $args $file] + +# Invoke consumescript_produce or consumescript_consume based on $runtype +if { $runtype == "PRODUCE" } { + # Producers have nothing to log; make sure outputfile is null. + error_check_good no_producer_outputfile $outputfile "" + consumescript_produce $db_cmd $nitems $tnum $args +} elseif { $runtype == "CONSUME" } { + consumescript_consume $db_cmd $nitems $tnum $outputfile -consume $args +} elseif { $runtype == "WAIT" } { + consumescript_consume $db_cmd $nitems $tnum $outputfile -consume_wait \ + $args +} else { + error_check_good bad_args $runtype "either PRODUCE, CONSUME or WAIT" +} +error_check_good env_close [$dbenv close] 0 +exit diff --git a/db/test/dbm.tcl b/db/test/dbm.tcl new file mode 100644 index 000000000..41a5da1f1 --- /dev/null +++ b/db/test/dbm.tcl @@ -0,0 +1,128 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: dbm.tcl,v 11.12 2000/08/25 14:21:50 sue Exp $ +# +# Historic DBM interface test. +# Use the first 1000 entries from the dictionary. +# Insert each with self as key and data; retrieve each. +# After all are entered, retrieve all; compare output to original. +# Then reopen the file, re-retrieve everything. +# Finally, delete everything. +proc dbm { { nentries 1000 } } { + source ./include.tcl + + puts "DBM interfaces test: $nentries" + + # Create the database and open the dictionary + set testfile $testdir/dbmtest + set t1 $testdir/t1 + set t2 $testdir/t2 + set t3 $testdir/t3 + cleanup $testdir NULL + + error_check_good dbminit [berkdb dbminit $testfile] 0 + set did [open $dict] + + set flags "" + set txn "" + set count 0 + set skippednullkey 0 + + puts "\tDBM.a: put/get loop" + # Here is the loop where we put and get each key/data pair + while { [gets $did str] != -1 && $count < $nentries } { + # DBM can't handle zero-length keys + if { [string length $str] == 0 } { + set skippednullkey 1 + continue + } + + set ret [berkdb store $str $str] + error_check_good dbm_store $ret 0 + + set d [berkdb fetch $str] + error_check_good dbm_fetch $d $str + incr count + } + close $did + + # Now we will get each key from the DB and compare the results + # to the original. + puts "\tDBM.b: dump file" + set oid [open $t1 w] + for { set key [berkdb firstkey] } { $key != -1 } {\ + set key [berkdb nextkey $key] } { + puts $oid $key + set d [berkdb fetch $key] + error_check_good dbm_refetch $d $key + } + + # If we had to skip a zero-length key, juggle things to cover up + # this fact in the dump. + if { $skippednullkey == 1 } { + puts $oid "" + incr nentries 1 + } + + close $oid + + # Now compare the keys to see if they match the dictionary (or ints) + set q q + filehead $nentries $dict $t3 + filesort $t3 $t2 + filesort $t1 $t3 + + error_check_good DBM:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 + + puts "\tDBM.c: close, open, and dump file" + + # Now, reopen the file and run the last test again. + error_check_good dbminit2 [berkdb dbminit $testfile] 0 + set oid [open $t1 w] + + for { set key [berkdb firstkey] } { $key != -1 } {\ + set key [berkdb nextkey $key] } { + puts $oid $key + set d [berkdb fetch $key] + error_check_good dbm_refetch $d $key + } + if { $skippednullkey == 1 } { + puts $oid "" + } + close $oid + + # Now compare the keys to see if they match the dictionary (or ints) + filesort $t1 $t3 + + error_check_good DBM:diff($t2,$t3) \ + [filecmp $t2 $t3] 0 + + # Now, reopen the file and delete each entry + puts "\tDBM.d: sequential scan and delete" + + error_check_good dbminit3 [berkdb dbminit $testfile] 0 + set oid [open $t1 w] + + for { set key [berkdb firstkey] } { $key != -1 } {\ + set key [berkdb nextkey $key] } { + puts $oid $key + set ret [berkdb delete $key] + error_check_good dbm_delete $ret 0 + } + if { $skippednullkey == 1 } { + puts $oid "" + } + close $oid + + # Now compare the keys to see if they match the dictionary (or ints) + filesort $t1 $t3 + + error_check_good DBM:diff($t2,$t3) \ + [filecmp $t2 $t3] 0 + + error_check_good "dbm_close" [berkdb dbmclose] 0 +} diff --git a/db/test/dbscript.tcl b/db/test/dbscript.tcl new file mode 100644 index 000000000..3a51b4363 --- /dev/null +++ b/db/test/dbscript.tcl @@ -0,0 +1,357 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: dbscript.tcl,v 11.10 2000/04/21 18:36:21 krinsky Exp $ +# +# Random db tester. +# Usage: dbscript file numops min_del max_add key_avg data_avgdups +# file: db file on which to operate +# numops: number of operations to do +# ncurs: number of cursors +# min_del: minimum number of keys before you disable deletes. +# max_add: maximum number of keys before you disable adds. +# key_avg: average key size +# data_avg: average data size +# dups: 1 indicates dups allowed, 0 indicates no dups +# errpct: What percent of operations should generate errors +# seed: Random number generator seed (-1 means use pid) + +source ./include.tcl +source $test_path/test.tcl +source $test_path/testutils.tcl + +set alphabet "abcdefghijklmnopqrstuvwxyz" + +set usage "dbscript file numops ncurs min_del max_add key_avg data_avg dups errpcnt" + +# Verify usage +if { $argc != 9 } { + puts stderr "FAIL:[timestamp] Usage: $usage" + exit +} + +# Initialize arguments +set file [lindex $argv 0] +set numops [ lindex $argv 1 ] +set ncurs [ lindex $argv 2 ] +set min_del [ lindex $argv 3 ] +set max_add [ lindex $argv 4 ] +set key_avg [ lindex $argv 5 ] +set data_avg [ lindex $argv 6 ] +set dups [ lindex $argv 7 ] +set errpct [ lindex $argv 8 ] + +berkdb srand $rand_init + +puts "Beginning execution for [pid]" +puts "$file database" +puts "$numops Operations" +puts "$ncurs cursors" +puts "$min_del keys before deletes allowed" +puts "$max_add or fewer keys to add" +puts "$key_avg average key length" +puts "$data_avg average data length" +if { $dups != 1 } { + puts "No dups" +} else { + puts "Dups allowed" +} +puts "$errpct % Errors" + +flush stdout + +set db [berkdb_open $file] +set cerr [catch {error_check_good dbopen [is_substr $db db] 1} cret] +if {$cerr != 0} { + puts $cret + return +} +set method [$db get_type] +set record_based [is_record_based $method] + +# Initialize globals including data +global nkeys +global l_keys +global a_keys + +set nkeys [db_init $db 1] +puts "Initial number of keys: $nkeys" + +set pflags "" +set gflags "" +set txn "" + +# Open the cursors +set curslist {} +for { set i 0 } { $i < $ncurs } { incr i } { + set dbc [$db cursor] + set cerr [catch {error_check_good dbopen [is_substr $dbc $db.c] 1} cret] + if {$cerr != 0} { + puts $cret + return + } + set cerr [catch {error_check_bad cursor_create $dbc NULL} cret] + if {$cerr != 0} { + puts $cret + return + } + lappend curslist $dbc + +} + +# On each iteration we're going to generate random keys and +# data. We'll select either a get/put/delete operation unless +# we have fewer than min_del keys in which case, delete is not +# an option or more than max_add in which case, add is not +# an option. The tcl global arrays a_keys and l_keys keep track +# of key-data pairs indexed by key and a list of keys, accessed +# by integer. +set adds 0 +set puts 0 +set gets 0 +set dels 0 +set bad_adds 0 +set bad_puts 0 +set bad_gets 0 +set bad_dels 0 + +for { set iter 0 } { $iter < $numops } { incr iter } { + set op [pick_op $min_del $max_add $nkeys] + set err [is_err $errpct] + + # The op0's indicate that there aren't any duplicates, so we + # exercise regular operations. If dups is 1, then we'll use + # cursor ops. + switch $op$dups$err { + add00 { + incr adds + + set k [random_data $key_avg 1 a_keys $record_based] + set data [random_data $data_avg 0 0] + set data [chop_data $method $data] + set ret [eval {$db put} $txn $pflags \ + {-nooverwrite $k $data}] + set cerr [catch {error_check_good put $ret 0} cret] + if {$cerr != 0} { + puts $cret + return + } + newpair $k [pad_data $method $data] + } + add01 { + incr bad_adds + set k [random_key] + set data [random_data $data_avg 0 0] + set data [chop_data $method $data] + set ret [eval {$db put} $txn $pflags \ + {-nooverwrite $k $data}] + set cerr [catch {error_check_good put $ret 0} cret] + if {$cerr != 0} { + puts $cret + return + } + # Error case so no change to data state + } + add10 { + incr adds + set dbcinfo [random_cursor $curslist] + set dbc [lindex $dbcinfo 0] + if { [berkdb random_int 1 2] == 1 } { + # Add a new key + set k [random_data $key_avg 1 a_keys \ + $record_based] + set data [random_data $data_avg 0 0] + set data [chop_data $method $data] + set ret [eval {$dbc put} $txn \ + {-keyfirst $k $data}] + newpair $k [pad_data $method $data] + } else { + # Add a new duplicate + set dbc [lindex $dbcinfo 0] + set k [lindex $dbcinfo 1] + set data [random_data $data_avg 0 0] + + set op [pick_cursput] + set data [chop_data $method $data] + set ret [eval {$dbc put} $txn {$op $k $data}] + adddup $k [lindex $dbcinfo 2] $data + } + } + add11 { + # TODO + incr bad_adds + set ret 1 + } + put00 { + incr puts + set k [random_key] + set data [random_data $data_avg 0 0] + set data [chop_data $method $data] + set ret [eval {$db put} $txn {$k $data}] + changepair $k [pad_data $method $data] + } + put01 { + incr bad_puts + set k [random_key] + set data [random_data $data_avg 0 0] + set data [chop_data $method $data] + set ret [eval {$db put} $txn $pflags \ + {-nooverwrite $k $data}] + set cerr [catch {error_check_good put $ret 0} cret] + if {$cerr != 0} { + puts $cret + return + } + # Error case so no change to data state + } + put10 { + incr puts + set dbcinfo [random_cursor $curslist] + set dbc [lindex $dbcinfo 0] + set k [lindex $dbcinfo 1] + set data [random_data $data_avg 0 0] + set data [chop_data $method $data] + + set ret [eval {$dbc put} $txn {-current $data}] + changedup $k [lindex $dbcinfo 2] $data + } + put11 { + incr bad_puts + set k [random_key] + set data [random_data $data_avg 0 0] + set data [chop_data $method $data] + set dbc [$db cursor] + set ret [eval {$dbc put} $txn {-current $data}] + set cerr [catch {error_check_good curs_close \ + [$dbc close] 0} cret] + if {$cerr != 0} { + puts $cret + return + } + # Error case so no change to data state + } + get00 { + incr gets + set k [random_key] + set val [eval {$db get} $txn {$k}] + set data [pad_data $method [lindex [lindex $val 0] 1]] + if { $data == $a_keys($k) } { + set ret 0 + } else { + set ret "FAIL: Error got |$data| expected |$a_keys($k)|" + } + # Get command requires no state change + } + get01 { + incr bad_gets + set k [random_data $key_avg 1 a_keys $record_based] + set ret [eval {$db get} $txn {$k}] + # Error case so no change to data state + } + get10 { + incr gets + set dbcinfo [random_cursor $curslist] + if { [llength $dbcinfo] == 3 } { + set ret 0 + else + set ret 0 + } + # Get command requires no state change + } + get11 { + incr bad_gets + set k [random_key] + set dbc [$db cursor] + if { [berkdb random_int 1 2] == 1 } { + set dir -next + } else { + set dir -prev + } + set ret [eval {$dbc get} $txn {-next $k}] + set cerr [catch {error_check_good curs_close \ + [$dbc close] 0} cret] + if {$cerr != 0} { + puts $cret + return + } + # Error and get case so no change to data state + } + del00 { + incr dels + set k [random_key] + set ret [eval {$db del} $txn {$k}] + rempair $k + } + del01 { + incr bad_dels + set k [random_data $key_avg 1 a_keys $record_based] + set ret [eval {$db del} $txn {$k}] + # Error case so no change to data state + } + del10 { + incr dels + set dbcinfo [random_cursor $curslist] + set dbc [lindex $dbcinfo 0] + set ret [eval {$dbc del} $txn] + remdup [lindex dbcinfo 1] [lindex dbcinfo 2] + } + del11 { + incr bad_dels + set c [$db cursor] + set ret [eval {$c del} $txn] + set cerr [catch {error_check_good curs_close \ + [$c close] 0} cret] + if {$cerr != 0} { + puts $cret + return + } + # Error case so no change to data state + } + } + if { $err == 1 } { + # Verify failure. + set cerr [catch {error_check_good $op$dups$err:$k \ + [is_substr Error $ret] 1} cret] + if {$cerr != 0} { + puts $cret + return + } + } else { + # Verify success + set cerr [catch {error_check_good $op$dups$err:$k $ret 0} cret] + if {$cerr != 0} { + puts $cret + return + } + } + + flush stdout +} + +# Close cursors and file +foreach i $curslist { + set r [$i close] + set cerr [catch {error_check_good cursor_close:$i $r 0} cret] + if {$cerr != 0} { + puts $cret + return + } +} + +set r [$db close] +set cerr [catch {error_check_good db_close:$db $r 0} cret] +if {$cerr != 0} { + puts $cret + return +} + +puts "[timestamp] [pid] Complete" +puts "Successful ops: $adds adds $gets gets $puts puts $dels dels" +puts "Error ops: $bad_adds adds $bad_gets gets $bad_puts puts $bad_dels dels" +flush stdout + +filecheck $file $txn + +exit diff --git a/db/test/ddscript.tcl b/db/test/ddscript.tcl new file mode 100644 index 000000000..9b139a4cb --- /dev/null +++ b/db/test/ddscript.tcl @@ -0,0 +1,43 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: ddscript.tcl,v 11.7 2000/05/08 19:26:37 sue Exp $ +# +# Deadlock detector script tester. +# Usage: ddscript dir test lockerid objid numprocs +# dir: DBHOME directory +# test: Which test to run +# lockerid: Lock id for this locker +# objid: Object id to lock. +# numprocs: Total number of processes running + +source ./include.tcl +source $test_path/test.tcl +source $test_path/testutils.tcl + +set usage "ddscript dir test lockerid objid numprocs" + +# Verify usage +if { $argc != 5 } { + puts stderr "FAIL:[timestamp] Usage: $usage" + exit +} + +# Initialize arguments +set dir [lindex $argv 0] +set tnum [ lindex $argv 1 ] +set lockerid [ lindex $argv 2 ] +set objid [ lindex $argv 3 ] +set numprocs [ lindex $argv 4 ] + +set myenv [berkdb env -lock -home $dir -create -mode 0644] +error_check_bad lock_open $myenv NULL +error_check_good lock_open [is_substr $myenv "env"] 1 + +puts [eval $tnum $myenv $lockerid $objid $numprocs] + +error_check_good envclose [$myenv close] 0 + +exit diff --git a/db/test/dead001.tcl b/db/test/dead001.tcl new file mode 100644 index 000000000..9e7c71f6a --- /dev/null +++ b/db/test/dead001.tcl @@ -0,0 +1,76 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: dead001.tcl,v 11.17 2000/11/05 14:23:55 dda Exp $ +# +# Deadlock Test 1. +# We create various deadlock scenarios for different numbers of lockers +# and see if we can get the world cleaned up suitably. +proc dead001 { { procs "2 4 10" } {tests "ring clump" } } { + source ./include.tcl + + puts "Dead001: Deadlock detector tests" + + env_cleanup $testdir + + # Create the environment. + puts "\tDead001.a: creating environment" + set env [berkdb env -create -mode 0644 -lock -home $testdir] + error_check_good lock_env:open [is_valid_env $env] TRUE + + error_check_good lock_env:close [$env close] 0 + + set dpid [exec $util_path/db_deadlock -vw -h $testdir \ + >& $testdir/dd.out &] + + foreach t $tests { + set pidlist "" + foreach n $procs { + + sentinel_init + + # Fire off the tests + puts "\tDead001: $n procs of test $t" + for { set i 0 } { $i < $n } { incr i } { + puts "$tclsh_path $test_path/wrap.tcl \ + $testdir/dead001.log.$i \ + ddscript.tcl $testdir $t $i $i $n" + set p [exec $tclsh_path \ + $test_path/wrap.tcl \ + ddscript.tcl $testdir/dead001.log.$i \ + $testdir $t $i $i $n &] + lappend pidlist $p + } + watch_procs 5 + + # Now check output + set dead 0 + set clean 0 + set other 0 + for { set i 0 } { $i < $n } { incr i } { + set did [open $testdir/dead001.log.$i] + while { [gets $did val] != -1 } { + switch $val { + DEADLOCK { incr dead } + 1 { incr clean } + default { incr other } + } + } + close $did + } + puts "dead check..." + dead_check $t $n $dead $clean $other + } + } + + exec $KILL $dpid + # Windows needs files closed before deleting files, so pause a little + tclsleep 2 + fileremove -f $testdir/dd.out + # Remove log files + for { set i 0 } { $i < $n } { incr i } { + fileremove -f $testdir/dead001.log.$i + } +} diff --git a/db/test/dead002.tcl b/db/test/dead002.tcl new file mode 100644 index 000000000..83cc6c7d5 --- /dev/null +++ b/db/test/dead002.tcl @@ -0,0 +1,68 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: dead002.tcl,v 11.15 2000/08/25 14:21:50 sue Exp $ +# +# Deadlock Test 2. +# Identical to Test 1 except that instead of running a standalone deadlock +# detector, we create the region with "detect on every wait" +proc dead002 { { procs "2 4 10" } {tests "ring clump" } } { + source ./include.tcl + + puts "Dead002: Deadlock detector tests" + + env_cleanup $testdir + + # Create the environment. + puts "\tDead002.a: creating environment" + set env [berkdb env \ + -create -mode 0644 -home $testdir -lock -lock_detect default] + error_check_good lock_env:open [is_valid_env $env] TRUE + error_check_good lock_env:close [$env close] 0 + + foreach t $tests { + set pidlist "" + foreach n $procs { + sentinel_init + + # Fire off the tests + puts "\tDead002: $n procs of test $t" + for { set i 0 } { $i < $n } { incr i } { + puts "$tclsh_path $test_path/wrap.tcl \ + $testdir/dead002.log.$i \ + ddscript.tcl $testdir $t $i $i $n" + set p [exec $tclsh_path \ + $test_path/wrap.tcl \ + ddscript.tcl $testdir/dead002.log.$i \ + $testdir $t $i $i $n &] + lappend pidlist $p + } + watch_procs 5 + + # Now check output + set dead 0 + set clean 0 + set other 0 + for { set i 0 } { $i < $n } { incr i } { + set did [open $testdir/dead002.log.$i] + while { [gets $did val] != -1 } { + switch $val { + DEADLOCK { incr dead } + 1 { incr clean } + default { incr other } + } + } + close $did + } + dead_check $t $n $dead $clean $other + } + } + + fileremove -f $testdir/dd.out + # Remove log files + for { set i 0 } { $i < $n } { incr i } { + fileremove -f $testdir/dead002.log.$i + } +} diff --git a/db/test/dead003.tcl b/db/test/dead003.tcl new file mode 100644 index 000000000..4075eb44f --- /dev/null +++ b/db/test/dead003.tcl @@ -0,0 +1,92 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: dead003.tcl,v 1.8 2000/08/25 14:21:50 sue Exp $ +# +# Deadlock Test 3. +# Test DB_LOCK_OLDEST and DB_LOCK_YOUNGEST +# Identical to Test 2 except that we create the region with "detect on +# every wait" with first the "oldest" and then "youngest". +proc dead003 { { procs "2 4 10" } {tests "ring clump" } } { + source ./include.tcl + + set detects { oldest youngest } + puts "Dead003: Deadlock detector tests: $detects" + + # Create the environment. + foreach d $detects { + env_cleanup $testdir + puts "\tDead003.a: creating environment for $d" + set env [berkdb env \ + -create -mode 0644 -home $testdir -lock -lock_detect $d] + error_check_good lock_env:open [is_valid_env $env] TRUE + error_check_good lock_env:close [$env close] 0 + + foreach t $tests { + set pidlist "" + foreach n $procs { + sentinel_init + + # Fire off the tests + puts "\tDead003: $n procs of test $t" + for { set i 0 } { $i < $n } { incr i } { + puts "$tclsh_path\ + test_path/ddscript.tcl $testdir \ + $t $i $i $n >& \ + $testdir/dead003.log.$i" + set p [exec $tclsh_path \ + $test_path/wrap.tcl \ + ddscript.tcl \ + $testdir/dead003.log.$i $testdir \ + $t $i $i $n &] + lappend pidlist $p + } + watch_procs 5 + + # Now check output + set dead 0 + set clean 0 + set other 0 + for { set i 0 } { $i < $n } { incr i } { + set did [open $testdir/dead003.log.$i] + while { [gets $did val] != -1 } { + switch $val { + DEADLOCK { incr dead } + 1 { incr clean } + default { incr other } + } + } + close $did + } + dead_check $t $n $dead $clean $other + # + # If we get here we know we have the + # correct number of dead/clean procs, as + # checked by dead_check above. Now verify + # that the right process was the one. + puts "\tDead003: Verify $d locks were aborted" + set l "" + if { $d == "oldest" } { + set l [expr $n - 1] + } + if { $d == "youngest" } { + set l 0 + } + set did [open $testdir/dead003.log.$l] + while { [gets $did val] != -1 } { + error_check_good check_abort \ + $val 1 + } + close $did + } + } + + fileremove -f $testdir/dd.out + # Remove log files + for { set i 0 } { $i < $n } { incr i } { + fileremove -f $testdir/dead003.log.$i + } + } +} diff --git a/db/test/env001.tcl b/db/test/env001.tcl new file mode 100644 index 000000000..008373301 --- /dev/null +++ b/db/test/env001.tcl @@ -0,0 +1,147 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: env001.tcl,v 11.21 2000/11/09 19:24:08 sue Exp $ +# +# Test of env remove interface. +proc env001 { } { + global errorInfo + global errorCode + + source ./include.tcl + + set testfile $testdir/env.db + set t1 $testdir/t1 + + puts "Env001: Test of environment remove interface." + env_cleanup $testdir + + # Try opening without Create flag should error + puts "\tEnv001.a: Open without create (should fail)." + catch {set env [berkdb env -home $testdir]} ret + error_check_good env:fail [is_substr $ret "no such file"] 1 + + # Now try opening with create + puts "\tEnv001.b: Open with create." + set env [berkdb env -create -mode 0644 -home $testdir] + error_check_bad env:$testdir $env NULL + error_check_good env:$testdir [is_substr $env "env"] 1 + + # Make sure that close works. + puts "\tEnv001.c: Verify close." + error_check_good env:close:$env [$env close] 0 + + # Make sure we can reopen -- this doesn't work on Windows + # because if there is only one opener, the region disappears + # when it is closed. We can't do a second opener, because + # that will fail on HP-UX. + puts "\tEnv001.d: Remove on closed environments." + if { $is_windows_test != 1 } { + puts "\t\tEnv001.d.1: Verify re-open." + set env [berkdb env -home $testdir] + error_check_bad env:$testdir $env NULL + error_check_good env:$testdir [is_substr $env "env"] 1 + + # remove environment + puts "\t\tEnv001.d.2: Close environment." + error_check_good env:close [$env close] 0 + puts "\t\tEnv001.d.3: Try remove with force (should succeed)." + error_check_good \ + envremove [berkdb envremove -force -home $testdir] 0 + } + + if { $is_windows_test != 1 && $is_hp_test != 1 } { + puts "\tEnv001.e: Remove on open environments." + puts "\t\tEnv001.e.1: Env is open by single proc,\ + remove no force." + set env [berkdb env -create -mode 0644 -home $testdir] + error_check_bad env:$testdir $env NULL + error_check_good env:$testdir [is_substr $env "env"] 1 + set stat [catch {berkdb envremove -home $testdir} ret] + error_check_good env:remove $stat 1 + error_check_good env:close [$env close] 0 + } + + puts \ + "\t\tEnv001.e.2: Env is open by single proc, remove with force." + # Now that envremove doesn't do a close, this won't work on Windows. + if { $is_windows_test != 1 && $is_hp_test != 1} { + set env [berkdb env -create -mode 0644 -home $testdir] + error_check_bad env:$testdir $env NULL + error_check_good env:$testdir [is_substr $env "env"] 1 + set stat [catch {berkdb envremove -force -home $testdir} ret] + error_check_good env:remove(force) $ret 0 + # + # Even though the underlying env is gone, we need to close + # the handle. + # + catch {$env close} + } + + puts "\t\tEnv001.e.3: Env is open by 2 procs, remove no force." + # should fail + set env [berkdb env -create -mode 0644 -home $testdir] + error_check_bad env:$testdir $env NULL + error_check_good env:$testdir [is_substr $env "env"] 1 + + set f1 [open |$tclsh_path r+] + puts $f1 "source $test_path/test.tcl" + + set remote_env [send_cmd $f1 "berkdb env -home $testdir"] + error_check_good remote:env_open [is_valid_env $remote_env] TRUE + # First close our env, but leave remote open + error_check_good env:close [$env close] 0 + catch {berkdb envremove -home $testdir} ret + error_check_good envremove:2procs:noforce [is_substr $errorCode EBUSY] 1 + # + # even though it failed, $env is no longer valid, so remove it in + # the remote process + set remote_close [send_cmd $f1 "$remote_env close"] + error_check_good remote_close $remote_close 0 + + # exit remote process + set err [catch { close $f1 } result] + error_check_good close_remote_process $err 0 + + puts "\t\tEnv001.e.4: Env is open by 2 procs, remove with force." + # You cannot do this on windows because you can't remove files that + # are open, so we skip this test for Windows. On UNIX, it should + # succeed + if { $is_windows_test != 1 && $is_hp_test != 1 } { + set env [berkdb env -create -mode 0644 -home $testdir] + error_check_bad env:$testdir $env NULL + error_check_good env:$testdir [is_substr $env "env"] 1 + set f1 [open |$tclsh_path r+] + puts $f1 "source $test_path/test.tcl" + + set remote_env [send_cmd $f1 "berkdb env -home $testdir"] + error_check_good remote:env_open [is_valid_env $remote_env] TRUE + + catch {berkdb envremove -force -home $testdir} ret + error_check_good envremove:2procs:force $ret 0 + # + # We still need to close our handle. + # + catch {$env close} ret + + # Close down remote process + set err [catch { close $f1 } result] + error_check_good close_remote_process $err 0 + } + + # Try opening in a different dir + puts "\tEnv001.f: Try opening env in another directory." + if { [file exists $testdir/NEWDIR] != 1 } { + file mkdir $testdir/NEWDIR + } + set eflags "-create -home $testdir/NEWDIR -mode 0644" + set env [eval {berkdb env} $eflags] + error_check_bad env:open $env NULL + error_check_good env:close [$env close] 0 + error_check_good berkdb:envremove \ + [berkdb envremove -home $testdir/NEWDIR] 0 + + puts "\tEnv001 complete." +} diff --git a/db/test/env002.tcl b/db/test/env002.tcl new file mode 100644 index 000000000..a37ddea17 --- /dev/null +++ b/db/test/env002.tcl @@ -0,0 +1,156 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: env002.tcl,v 11.11 2000/08/25 14:21:50 sue Exp $ +# +# Env Test 002 +# Test set_lg_dir and env name resolution +# With an environment path specified using -home, and then again +# with it specified by the environment variable DB_HOME: +# 1) Make sure that the set_lg_dir option is respected +# a) as a relative pathname. +# b) as an absolute pathname. +# 2) Make sure that the DB_LOG_DIR db_config argument is respected, +# again as relative and absolute pathnames. +# 3) Make sure that if -both- db_config and a file are present, +# only the file is respected (see doc/env/naming.html). +proc env002 { } { + # env002 is essentially just a small driver that runs + # env002_body--formerly the entire test--twice; once, it + # supplies a "home" argument to use with environment opens, + # and the second time it sets DB_HOME instead. + # Note that env002_body itself calls env002_run_test to run + # the body of the actual test and check for the presence + # of logs. The nesting, I hope, makes this test's structure simpler. + + global env + source ./include.tcl + + puts "Env002: set_lg_dir test." + + puts "\tEnv002: Running with -home argument to berkdb env." + env002_body "-home $testdir" + + puts "\tEnv002: Running with environment variable DB_HOME set." + set env(DB_HOME) $testdir + env002_body "-use_environ" + + unset env(DB_HOME) + + puts "\tEnv002: Running with both DB_HOME and -home set." + # Should respect -only- -home, so we give it a bogus + # environment variable setting. + set env(DB_HOME) $testdir/bogus_home + env002_body "-use_environ -home $testdir" + unset env(DB_HOME) + +} + +proc env002_body { home_arg } { + source ./include.tcl + + env_cleanup $testdir + set logdir "logs_in_here" + + file mkdir $testdir/$logdir + + # Set up full path to $logdir for when we test absolute paths. + set curdir [pwd] + cd $testdir/$logdir + set fulllogdir [pwd] + cd $curdir + + env002_make_config $logdir + + # Run the meat of the test. + env002_run_test a 1 "relative path, config file" $home_arg \ + $testdir/$logdir + + env_cleanup $testdir + + file mkdir $fulllogdir + env002_make_config $fulllogdir + + # Run the test again + env002_run_test a 2 "absolute path, config file" $home_arg \ + $fulllogdir + + env_cleanup $testdir + + # Now we try without a config file, but instead with db_config + # relative paths + file mkdir $testdir/$logdir + env002_run_test b 1 "relative path, db_config" "$home_arg \ + -log_dir $logdir -data_dir ." \ + $testdir/$logdir + + env_cleanup $testdir + + # absolute + file mkdir $fulllogdir + env002_run_test b 2 "absolute path, db_config" "$home_arg \ + -log_dir $fulllogdir -data_dir ." \ + $fulllogdir + + env_cleanup $testdir + + # Now, set db_config -and- have a # DB_CONFIG file, and make + # sure only the latter is honored. + + file mkdir $testdir/$logdir + env002_make_config $logdir + + # note that we supply a -nonexistent- log dir to db_config + env002_run_test c 1 "relative path, both db_config and file" \ + "$home_arg -log_dir $testdir/bogus \ + -data_dir ." $testdir/$logdir + env_cleanup $testdir + + file mkdir $fulllogdir + env002_make_config $fulllogdir + + # note that we supply a -nonexistent- log dir to db_config + env002_run_test c 2 "relative path, both db_config and file" \ + "$home_arg -log_dir $fulllogdir/bogus \ + -data_dir ." $fulllogdir +} + +proc env002_run_test { major minor msg env_args log_path} { + global testdir + set testfile "env002.db" + + puts "\t\tEnv002.$major.$minor: $msg" + + # Create an environment, with logging, and scribble some + # stuff in a [btree] database in it. + # puts [concat {berkdb env -create -log -private} $env_args] + set dbenv [eval {berkdb env -create -log -private} $env_args] + error_check_good env_open [is_valid_env $dbenv] TRUE + set db [berkdb_open -env $dbenv -create -btree -mode 0644 $testfile] + error_check_good db_open [is_valid_db $db] TRUE + + set key "some_key" + set data "some_data" + + error_check_good db_put \ + [$db put $key [chop_data btree $data]] 0 + + error_check_good db_close [$db close] 0 + error_check_good env_close [$dbenv close] 0 + + # Now make sure the log file is where we want it to be. + error_check_good db_exists [file exists $testdir/$testfile] 1 + error_check_good log_exists \ + [file exists $log_path/log.0000000001] 1 +} + +proc env002_make_config { logdir } { + global testdir + + set cid [open $testdir/DB_CONFIG w] + puts $cid "set_data_dir ." + puts $cid "set_lg_dir $logdir" + close $cid +} diff --git a/db/test/env003.tcl b/db/test/env003.tcl new file mode 100644 index 000000000..01e0b6188 --- /dev/null +++ b/db/test/env003.tcl @@ -0,0 +1,177 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: env003.tcl,v 11.12 2000/08/25 14:21:50 sue Exp $ +# +# Env Test 003 +# Test DB_TMP_DIR and env name resolution +# With an environment path specified using -home, and then again +# with it specified by the environment variable DB_HOME: +# 1) Make sure that the DB_TMP_DIR config file option is respected +# a) as a relative pathname. +# b) as an absolute pathname. +# 2) Make sure that the DB_TMP_DIR db_config argument is respected, +# again as relative and absolute pathnames. +# 3) Make sure that if -both- db_config and a file are present, +# only the file is respected (see doc/env/naming.html). +proc env003 { } { + # env003 is essentially just a small driver that runs + # env003_body twice. First, it supplies a "home" argument + # to use with environment opens, and the second time it sets + # DB_HOME instead. + # Note that env003_body itself calls env003_run_test to run + # the body of the actual test. + + global env + source ./include.tcl + + puts "Env003: DB_TMP_DIR test." + + puts "\tEnv003: Running with -home argument to berkdb env." + env003_body "-home $testdir" + + puts "\tEnv003: Running with environment variable DB_HOME set." + set env(DB_HOME) $testdir + env003_body "-use_environ" + + unset env(DB_HOME) + + puts "\tEnv003: Running with both DB_HOME and -home set." + # Should respect -only- -home, so we give it a bogus + # environment variable setting. + set env(DB_HOME) $testdir/bogus_home + env003_body "-use_environ -home $testdir" + unset env(DB_HOME) + +} + +proc env003_body { home_arg } { + source ./include.tcl + + env_cleanup $testdir + set tmpdir "tmpfiles_in_here" + + file mkdir $testdir/$tmpdir + + # Set up full path to $tmpdir for when we test absolute paths. + set curdir [pwd] + cd $testdir/$tmpdir + set fulltmpdir [pwd] + cd $curdir + + # Run test with the temp dir. nonexistent--it checks for failure. + env_cleanup $testdir + + env003_make_config $tmpdir + + # Run the meat of the test. + env003_run_test a 1 "relative path, config file" $home_arg \ + $testdir/$tmpdir + + env_cleanup $testdir + + env003_make_config $fulltmpdir + + # Run the test again + env003_run_test a 2 "absolute path, config file" $home_arg \ + $fulltmpdir + + env_cleanup $testdir + + # Now we try without a config file, but instead with db_config + # relative paths + env003_run_test b 1 "relative path, db_config" "$home_arg \ + -tmp_dir $tmpdir -data_dir ." \ + $testdir/$tmpdir + + env_cleanup $testdir + + # absolute + env003_run_test b 2 "absolute path, db_config" "$home_arg \ + -tmp_dir $fulltmpdir -data_dir ." \ + $fulltmpdir + + env_cleanup $testdir + + # Now, set db_config -and- have a # DB_CONFIG file, and make + # sure only the latter is honored. + + # Make a temp directory that actually does exist to supply + # as a bogus argument--the test checks for -nonexistent- temp + # dirs., as success is harder to detect. + file mkdir $testdir/bogus + env003_make_config $tmpdir + + # note that we supply an -existent- tmp dir to db_config as + # a red herring + env003_run_test c 1 "relative path, both db_config and file" \ + "$home_arg -tmp_dir $testdir/bogus -data_dir ." \ + $testdir/$tmpdir + env_cleanup $testdir + + file mkdir $fulltmpdir + file mkdir $fulltmpdir/bogus + env003_make_config $fulltmpdir/nonexistent + + # note that we supply an -existent- tmp dir to db_config as + # a red herring + env003_run_test c 2 "relative path, both db_config and file" \ + "$home_arg -tmp_dir $fulltmpdir/bogus -data_dir ." \ + $fulltmpdir +} + +proc env003_run_test { major minor msg env_args tmp_path} { + global testdir + global alphabet + global errorCode + + puts "\t\tEnv003.$major.$minor: $msg" + + # Create an environment and small-cached in-memory database to + # use. + set dbenv [eval {berkdb env -create -home $testdir} $env_args \ + {-cachesize {0 40960 1}}] + error_check_good env_open [is_valid_env $dbenv] TRUE + set db [berkdb_open_noerr -env $dbenv -create -btree] + error_check_good db_open [is_valid_db $db] TRUE + + # Fill the database with more than its cache can fit. + # !!! + # This is actually trickier than it sounds. The tempfile + # gets unlinked as soon as it's created, so there's no straightforward + # way to check for its existence. Instead, we make sure + # DB_TMP_DIR points somewhere bogus, and make sure that the temp + # dir. does -not- exist. But to do this, we have to know + # which call to DB->put is going to fail--the temp file is + # created lazily, so the failure only occurs when the cache finally + # overflows. + # The data we've conjured up will fit nicely once, but the second + # call will overflow the cache. Thus we check for success once, + # then failure. + # + set key1 "key1" + set key2 "key2" + set data [repeat $alphabet 1000] + + # First put should succeed. + error_check_good db_put_1 [$db put $key1 $data] 0 + + # Second one should return ENOENT. + set errorCode NONE + catch {$db put $key2 $data} res + error_check_good db_put_2 [is_substr $errorCode ENOENT] 1 + + error_check_good db_close [$db close] 0 + error_check_good env_close [$dbenv close] 0 +} + +proc env003_make_config { tmpdir } { + global testdir + + set cid [open $testdir/DB_CONFIG w] + puts $cid "set_data_dir ." + puts $cid "set_tmp_dir $tmpdir" + close $cid +} diff --git a/db/test/env004.tcl b/db/test/env004.tcl new file mode 100644 index 000000000..82cc8dd25 --- /dev/null +++ b/db/test/env004.tcl @@ -0,0 +1,103 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: env004.tcl,v 11.14 2000/08/25 14:21:50 sue Exp $ +# +# Env Test 4 +# Test multiple data directories. Do a bunch of different opens +# to make sure that the files are detected in different directories. +proc env004 { } { + source ./include.tcl + + set method "hash" + set omethod [convert_method $method] + set args [convert_args $method ""] + + puts "Env004: Multiple data directory test." + + env_cleanup $testdir + file mkdir $testdir/data1 + file mkdir $testdir/data2 + file mkdir $testdir/data3 + + puts "\tEnv004.a: Multiple data directories in DB_CONFIG file" + + # Create a config file + set cid [open $testdir/DB_CONFIG w] + puts $cid "set_data_dir ." + puts $cid "set_data_dir data1" + puts $cid "set_data_dir data2" + puts $cid "set_data_dir data3" + close $cid + + # Now get pathnames + set curdir [pwd] + cd $testdir + set fulldir [pwd] + cd $curdir + + set e [berkdb env -create -private -home $testdir] + error_check_good dbenv [is_valid_env $e] TRUE + ddir_test $fulldir $method $e $args + error_check_good env_close [$e close] 0 + + puts "\tEnv004.b: Multiple data directories in berkdb env call." + env_cleanup $testdir + file mkdir $testdir/data1 + file mkdir $testdir/data2 + file mkdir $testdir/data3 + + # Now call dbenv with config specified + set e [berkdb env -create -private \ + -data_dir . -data_dir data1 -data_dir data2 \ + -data_dir data3 -home $testdir] + error_check_good dbenv [is_valid_env $e] TRUE + ddir_test $fulldir $method $e $args + error_check_good env_close [$e close] 0 + + env_cleanup $testdir +} + +proc ddir_test { fulldir method e args } { + source ./include.tcl + + set args [convert_args $args] + set omethod [convert_method $method] + + # Now create one file in each directory + set db1 [eval {berkdb_open -create \ + -truncate -mode 0644 $omethod -env $e} $args {data1/datafile1.db}] + error_check_good dbopen1 [is_valid_db $db1] TRUE + + set db2 [eval {berkdb_open -create \ + -truncate -mode 0644 $omethod -env $e} $args {data2/datafile2.db}] + error_check_good dbopen2 [is_valid_db $db2] TRUE + + set db3 [eval {berkdb_open -create \ + -truncate -mode 0644 $omethod -env $e} $args {data3/datafile3.db}] + error_check_good dbopen3 [is_valid_db $db3] TRUE + + # Close the files + error_check_good db_close1 [$db1 close] 0 + error_check_good db_close2 [$db2 close] 0 + error_check_good db_close3 [$db3 close] 0 + + # Now, reopen the files without complete pathnames and make + # sure that we find them. + + set db1 [berkdb_open -env $e $fulldir/data1/datafile1.db] + error_check_good dbopen1 [is_valid_db $db1] TRUE + + set db2 [berkdb_open -env $e $fulldir/data2/datafile2.db] + error_check_good dbopen2 [is_valid_db $db2] TRUE + + set db3 [berkdb_open -env $e $fulldir/data3/datafile3.db] + error_check_good dbopen3 [is_valid_db $db3] TRUE + + # Finally close all the files + error_check_good db_close1 [$db1 close] 0 + error_check_good db_close2 [$db2 close] 0 + error_check_good db_close3 [$db3 close] 0 +} diff --git a/db/test/env005.tcl b/db/test/env005.tcl new file mode 100644 index 000000000..4ad941993 --- /dev/null +++ b/db/test/env005.tcl @@ -0,0 +1,53 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: env005.tcl,v 11.8 2000/08/25 14:21:50 sue Exp $ +# +# Env Test 5 +# Test that using subsystems without initializing them correctly +# returns an error. Cannot test mpool, because it is assumed +# in the Tcl code. +proc env005 { } { + source ./include.tcl + + puts "Env005: Uninitialized env subsystems test." + + env_cleanup $testdir + puts "\tEnv005.a: Creating env with no subsystems." + + set e [berkdb env -create -home $testdir] + error_check_good dbenv [is_valid_env $e] TRUE + set db [berkdb_open -create -btree $testdir/env005.db] + error_check_good dbopen [is_valid_db $db] TRUE + + set rlist { + { "lock_detect" "Env005.b0"} + { "lock_get read 1 1" "Env005.b1"} + { "lock_id" "Env005.b2"} + { "lock_stat" "Env005.b3"} + { "log_archive" "Env005.c0"} + { "log_file {1 1}" "Env005.c1"} + { "log_flush" "Env005.c2"} + { "log_get -first" "Env005.c3"} + { "log_put record" "Env005.c4"} + { "log_register $db xxx" "Env005.c5"} + { "log_stat" "Env005.c6"} + { "log_unregister $db" "Env005.c7"} + { "txn" "Env005.d0"} + { "txn_checkpoint" "Env005.d1"} + { "txn_stat" "Env005.d2"} + } + + foreach pair $rlist { + set cmd [lindex $pair 0] + set msg [lindex $pair 1] + puts "\t$msg: $cmd" + set stat [catch {eval $e $cmd} ret] + error_check_good $cmd $stat 1 + error_check_good $cmd.err [is_substr $ret invalid] 1 + } + error_check_good dbclose [$db close] 0 + error_check_good envclose [$e close] 0 +} diff --git a/db/test/env006.tcl b/db/test/env006.tcl new file mode 100644 index 000000000..1a39886ca --- /dev/null +++ b/db/test/env006.tcl @@ -0,0 +1,42 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: env006.tcl,v 11.5 2000/10/27 13:23:55 sue Exp $ +# +# Env Test 6 +# DB Utility Check +# Make sure that all the utilities exist and run. +# +proc env006 { } { + source ./include.tcl + + puts "Env006: Run underlying utilities." + + set rlist { + { "db_archive" "Env006.a"} + { "db_checkpoint" "Env006.b"} + { "db_deadlock" "Env006.c"} + { "db_dump" "Env006.d"} + { "db_load" "Env006.e"} + { "db_printlog" "Env006.f"} + { "db_recover" "Env006.g"} + { "db_stat" "Env006.h"} + } + foreach pair $rlist { + set cmd [lindex $pair 0] + set msg [lindex $pair 1] + + puts "\t$msg: $cmd" + + set stat [catch {exec $util_path/$cmd -?} ret] + error_check_good $cmd $stat 1 + + # + # Check for "usage", but only check "sage" so that + # we can handle either Usage or usage. + # + error_check_good $cmd.err [is_substr $ret sage] 1 + } +} diff --git a/db/test/env007.tcl b/db/test/env007.tcl new file mode 100644 index 000000000..b8ddea75c --- /dev/null +++ b/db/test/env007.tcl @@ -0,0 +1,100 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: env007.tcl,v 11.5 2000/08/25 14:21:50 sue Exp $ +# +# Env Test 007 +# Test various config file options. +# 1) Make sure command line option is respected +# 2) Make sure that config file option is respected +# 3) Make sure that if -both- DB_CONFIG and the set_ +# method is used, only the file is respected. +proc env007 { } { + # env007 is essentially just a small driver that runs + # env007_body twice. First, it supplies a "set" argument + # to use with environment opens, and the second time it sets + # DB_CONFIG instead. + # Note that env007_body itself calls env007_run_test to run + # the body of the actual test. + + source ./include.tcl + + puts "Env007: DB_CONFIG test." + + # + # Test only those options we can easily check via stat + # + set rlist { + { " -txn_max " "set_tx_max" "19" "31" "Env007.a: Txn Max" + "txn_stat" "Max Txns"} + { " -lock_max " "set_lk_max" "19" "31" "Env007.b: Lock Max" + "lock_stat" "Max locks"} + { " -log_buffer " "set_lg_bsize" "65536" "131072" "Env007.c: Log Bsize" + "log_stat" "Log record cache size"} + { " -log_max " "set_lg_max" "8388608" "9437184" "Env007.d: Log Max" + "log_stat" "Maximum log file size"} + } + + set e "berkdb env -create -mode 0644 -home $testdir -log -lock -txn " + foreach item $rlist { + set envarg [lindex $item 0] + set configarg [lindex $item 1] + set envval [lindex $item 2] + set configval [lindex $item 3] + set msg [lindex $item 4] + set statcmd [lindex $item 5] + set statstr [lindex $item 6] + + env_cleanup $testdir + # First verify using just env args + puts "\t$msg Environment argument only" + set env [eval $e $envarg $envval] + error_check_good envopen:0 [is_valid_env $env] TRUE + env007_check $env $statcmd $statstr $envval + error_check_good envclose:0 [$env close] 0 + + env_cleanup $testdir + env007_make_config $configarg $configval + + # verify using just config file + puts "\t$msg Config file only" + set env [eval $e] + error_check_good envopen:1 [is_valid_env $env] TRUE + env007_check $env $statcmd $statstr $configval + error_check_good envclose:1 [$env close] 0 + + # First verify using just env args + puts "\t$msg Environment arg and config file" + set env [eval $e $envarg $envval] + error_check_good envopen:2 [is_valid_env $env] TRUE + env007_check $env $statcmd $statstr $configval + error_check_good envclose:2 [$env close] 0 + } +} + +proc env007_check { env statcmd statstr testval } { + set stat [$env $statcmd] + set checked 0 + foreach statpair $stat { + if {$checked == 1} { + break + } + set statmsg [lindex $statpair 0] + set statval [lindex $statpair 1] + if {[is_substr $statmsg $statstr] != 0} { + set checked 1 + error_check_good $statstr:ck $statval $testval + } + } + error_check_good $statstr:test $checked 1 +} + +proc env007_make_config { carg cval } { + global testdir + + set cid [open $testdir/DB_CONFIG w] + puts $cid "$carg $cval" + close $cid +} diff --git a/db/test/env008.tcl b/db/test/env008.tcl new file mode 100644 index 000000000..645f07f63 --- /dev/null +++ b/db/test/env008.tcl @@ -0,0 +1,73 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: env008.tcl,v 11.2 2000/10/30 19:00:38 sue Exp $ +# +# Test of env and subdirs. +proc env008 { } { + global errorInfo + global errorCode + + source ./include.tcl + + env_cleanup $testdir + + set subdir 1/1 + set subdir1 1/2 + file mkdir $testdir/$subdir $testdir/$subdir1 + set testfile $subdir/env.db + + puts "Env008: Test of environments and subdirectories." + + # Try opening without Create flag should error + puts "\tEnv008.a: Create env and db." + set env [berkdb env -create -mode 0644 -home $testdir -txn] + error_check_good env [is_valid_env $env] TRUE + + puts "\tEnv008.b: Remove db in subdir." + env008_db $env $testfile + error_check_good dbremove:$testfile \ + [berkdb dbremove -env $env $testfile] 0 + + # + # Rather than remaking the db every time for the renames + # just move around the new file name to another new file + # name. + # + puts "\tEnv008.c: Rename db in subdir." + env008_db $env $testfile + set newfile $subdir/new.db + error_check_good dbrename:$testfile/.. \ + [berkdb dbrename -env $env $testfile $newfile] 0 + set testfile $newfile + + puts "\tEnv008.d: Rename db to parent dir." + set newfile $subdir/../new.db + error_check_good dbrename:$testfile/.. \ + [berkdb dbrename -env $env $testfile $newfile] 0 + set testfile $newfile + + puts "\tEnv008.e: Rename db to child dir." + set newfile $subdir/env.db + error_check_good dbrename:$testfile/.. \ + [berkdb dbrename -env $env $testfile $newfile] 0 + set testfile $newfile + + puts "\tEnv008.f: Rename db to another dir." + set newfile $subdir1/env.db + error_check_good dbrename:$testfile/.. \ + [berkdb dbrename -env $env $testfile $newfile] 0 + + error_check_good envclose [$env close] 0 + puts "\tEnv008 complete." +} + +proc env008_db { env testfile } { + set db [berkdb_open -env $env -create -btree $testfile] + error_check_good dbopen [is_valid_db $db] TRUE + set ret [$db put key data] + error_check_good dbput $ret 0 + error_check_good dbclose [$db close] 0 +} diff --git a/db/test/hsearch.tcl b/db/test/hsearch.tcl new file mode 100644 index 000000000..0afee7fb2 --- /dev/null +++ b/db/test/hsearch.tcl @@ -0,0 +1,51 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: hsearch.tcl,v 11.7 2000/08/25 14:21:50 sue Exp $ +# +# Historic Hsearch interface test. +# Use the first 1000 entries from the dictionary. +# Insert each with self as key and data; retrieve each. +# After all are entered, retrieve all; compare output to original. +# Then reopen the file, re-retrieve everything. +# Finally, delete everything. +proc hsearch { { nentries 1000 } } { + source ./include.tcl + + puts "HSEARCH interfaces test: $nentries" + + # Create the database and open the dictionary + set t1 $testdir/t1 + set t2 $testdir/t2 + set t3 $testdir/t3 + cleanup $testdir NULL + + error_check_good hcreate [berkdb hcreate $nentries] 0 + set did [open $dict] + set count 0 + + puts "\tHSEARCH.a: put/get loop" + # Here is the loop where we put and get each key/data pair + while { [gets $did str] != -1 && $count < $nentries } { + set ret [berkdb hsearch $str $str enter] + error_check_good hsearch:enter $ret 0 + + set d [berkdb hsearch $str 0 find] + error_check_good hsearch:find $d $str + incr count + } + close $did + + puts "\tHSEARCH.b: re-get loop" + set did [open $dict] + # Here is the loop where we retrieve each key + while { [gets $did str] != -1 && $count < $nentries } { + set d [berkdb hsearch $str 0 find] + error_check_good hsearch:find $d $str + incr count + } + close $did + error_check_good hdestroy [berkdb hdestroy] 0 +} diff --git a/db/test/include.tcl b/db/test/include.tcl new file mode 100644 index 000000000..e5084d650 --- /dev/null +++ b/db/test/include.tcl @@ -0,0 +1,19 @@ +set tclsh_path @TCL_TCLSH@ +set tcllib .libs/libdb_tcl-@DB_VERSION_MAJOR@.@DB_VERSION_MINOR@.@SOSUFFIX@ +set rpc_server localhost +set rpc_path . +set test_path @srcdir@/../test + +set KILL "@db_cv_path_kill@" + +# DO NOT EDIT BELOW THIS LINE: automatically built by dist/s_tcl. + +global dict +global testdir +global util_path +set testdir ./TESTDIR +set rpc_testdir $rpc_path/TESTDIR + +global is_hp_test +global is_qnx_test +global is_windows_test diff --git a/db/test/join.tcl b/db/test/join.tcl new file mode 100644 index 000000000..ebf33b8cd --- /dev/null +++ b/db/test/join.tcl @@ -0,0 +1,451 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: join.tcl,v 11.17 2000/08/25 14:21:51 sue Exp $ +# +# We'll test 2-way, 3-way, and 4-way joins and figure that if those work, +# everything else does as well. We'll create test databases called +# join1.db, join2.db, join3.db, and join4.db. The number on the database +# describes the duplication -- duplicates are of the form 0, N, 2N, 3N, ... +# where N is the number of the database. Primary.db is the primary database, +# and null.db is the database that has no matching duplicates. +# +# We should test this on all btrees, all hash, and a combination thereof +# Join test. +proc jointest { {psize 8192} {with_dup_dups 0} {flags 0} } { + global testdir + global rand_init + source ./include.tcl + + env_cleanup $testdir + berkdb srand $rand_init + + # Use one environment for all database opens so we don't + # need oodles of regions. + set env [berkdb env -create -home $testdir] + error_check_good env_open [is_valid_env $env] TRUE + + # With the new offpage duplicate code, we don't support + # duplicate duplicates in sorted dup sets. Thus, if with_dup_dups + # is greater than one, run only with "-dup". + if { $with_dup_dups > 1 } { + set doptarray {"-dup"} + } else { + set doptarray {"-dup -dupsort" "-dup" RANDOMMIX RANDOMMIX } + } + + # NB: these flags are internal only, ok + foreach m "DB_BTREE DB_HASH DB_BOTH" { + # run with two different random mixes. + foreach dopt $doptarray { + set opt [list "-env" $env $dopt] + + puts "Join test: ($m $dopt) psize $psize,\ + $with_dup_dups dup\ + dups, flags $flags." + + build_all $m $psize $opt oa $with_dup_dups + + # null.db is db_built fifth but is referenced by + # zero; set up the option array appropriately. + set oa(0) $oa(5) + + # Build the primary + puts "\tBuilding the primary database $m" + set oflags "-create -truncate -mode 0644 -env $env\ + [conv $m [berkdb random_int 1 2]]" + set db [eval {berkdb_open} $oflags primary.db] + error_check_good dbopen [is_valid_db $db] TRUE + for { set i 0 } { $i < 1000 } { incr i } { + set key [format "%04d" $i] + set ret [$db put $key stub] + error_check_good "primary put" $ret 0 + } + error_check_good "primary close" [$db close] 0 + set did [open $dict] + gets $did str + do_join primary.db "1 0" $str oa $flags\ + $with_dup_dups + gets $did str + do_join primary.db "2 0" $str oa $flags\ + $with_dup_dups + gets $did str + do_join primary.db "3 0" $str oa $flags\ + $with_dup_dups + gets $did str + do_join primary.db "4 0" $str oa $flags\ + $with_dup_dups + gets $did str + do_join primary.db "1" $str oa $flags $with_dup_dups + gets $did str + do_join primary.db "2" $str oa $flags $with_dup_dups + gets $did str + do_join primary.db "3" $str oa $flags $with_dup_dups + gets $did str + do_join primary.db "4" $str oa $flags $with_dup_dups + gets $did str + do_join primary.db "1 2" $str oa $flags\ + $with_dup_dups + gets $did str + do_join primary.db "1 2 3" $str oa $flags\ + $with_dup_dups + gets $did str + do_join primary.db "1 2 3 4" $str oa $flags\ + $with_dup_dups + gets $did str + do_join primary.db "2 1" $str oa $flags\ + $with_dup_dups + gets $did str + do_join primary.db "3 2 1" $str oa $flags\ + $with_dup_dups + gets $did str + do_join primary.db "4 3 2 1" $str oa $flags\ + $with_dup_dups + gets $did str + do_join primary.db "1 3" $str oa $flags $with_dup_dups + gets $did str + do_join primary.db "3 1" $str oa $flags $with_dup_dups + gets $did str + do_join primary.db "1 4" $str oa $flags $with_dup_dups + gets $did str + do_join primary.db "4 1" $str oa $flags $with_dup_dups + gets $did str + do_join primary.db "2 3" $str oa $flags $with_dup_dups + gets $did str + do_join primary.db "3 2" $str oa $flags $with_dup_dups + gets $did str + do_join primary.db "2 4" $str oa $flags $with_dup_dups + gets $did str + do_join primary.db "4 2" $str oa $flags $with_dup_dups + gets $did str + do_join primary.db "3 4" $str oa $flags $with_dup_dups + gets $did str + do_join primary.db "4 3" $str oa $flags $with_dup_dups + gets $did str + do_join primary.db "2 3 4" $str oa $flags\ + $with_dup_dups + gets $did str + do_join primary.db "3 4 1" $str oa $flags\ + $with_dup_dups + gets $did str + do_join primary.db "4 2 1" $str oa $flags\ + $with_dup_dups + gets $did str + do_join primary.db "0 2 1" $str oa $flags\ + $with_dup_dups + gets $did str + do_join primary.db "3 2 0" $str oa $flags\ + $with_dup_dups + gets $did str + do_join primary.db "4 3 2 1" $str oa $flags\ + $with_dup_dups + gets $did str + do_join primary.db "4 3 0 1" $str oa $flags\ + $with_dup_dups + gets $did str + do_join primary.db "3 3 3" $str oa $flags\ + $with_dup_dups + gets $did str + do_join primary.db "2 2 3 3" $str oa $flags\ + $with_dup_dups + gets $did str2 + gets $did str + do_join primary.db "1 2" $str oa $flags\ + $with_dup_dups "3" $str2 + + # You really don't want to run this section + # with $with_dup_dups > 2. + if { $with_dup_dups <= 2 } { + gets $did str2 + gets $did str + do_join primary.db "1 2 3" $str\ + oa $flags $with_dup_dups "3 3 1" $str2 + gets $did str2 + gets $did str + do_join primary.db "4 0 2" $str\ + oa $flags $with_dup_dups "4 3 3" $str2 + gets $did str2 + gets $did str + do_join primary.db "3 2 1" $str\ + oa $flags $with_dup_dups "0 2" $str2 + gets $did str2 + gets $did str + do_join primary.db "2 2 3 3" $str\ + oa $flags $with_dup_dups "1 4 4" $str2 + gets $did str2 + gets $did str + do_join primary.db "2 2 3 3" $str\ + oa $flags $with_dup_dups "0 0 4 4" $str2 + gets $did str2 + gets $did str + do_join primary.db "2 2 3 3" $str2\ + oa $flags $with_dup_dups "2 4 4" $str + gets $did str2 + gets $did str + do_join primary.db "2 2 3 3" $str2\ + oa $flags $with_dup_dups "0 0 4 4" $str + } + close $did + } + } + + error_check_good env_close [$env close] 0 +} + +proc build_all { method psize opt oaname with_dup_dups {nentries 100} } { + global testdir + db_build join1.db $nentries 50 1 [conv $method 1]\ + $psize $opt $oaname $with_dup_dups + db_build join2.db $nentries 25 2 [conv $method 2]\ + $psize $opt $oaname $with_dup_dups + db_build join3.db $nentries 16 3 [conv $method 3]\ + $psize $opt $oaname $with_dup_dups + db_build join4.db $nentries 12 4 [conv $method 4]\ + $psize $opt $oaname $with_dup_dups + db_build null.db $nentries 0 5 [conv $method 5]\ + $psize $opt $oaname $with_dup_dups +} + +proc conv { m i } { + switch -- $m { + DB_HASH { return "-hash"} + "-hash" { return "-hash"} + DB_BTREE { return "-btree"} + "-btree" { return "-btree"} + DB_BOTH { + if { [expr $i % 2] == 0 } { + return "-hash"; + } else { + return "-btree"; + } + } + } +} + +proc random_opts { } { + set j [berkdb random_int 0 1] + if { $j == 0 } { + return " -dup" + } else { + return " -dup -dupsort" + } +} + +proc db_build { name nkeys ndups dup_interval method psize lopt oaname \ + with_dup_dups } { + source ./include.tcl + + # Get array of arg names (from two levels up the call stack) + upvar 2 $oaname oa + + # Search for "RANDOMMIX" in $opt, and if present, replace + # with " -dup" or " -dup -dupsort" at random. + set i [lsearch $lopt RANDOMMIX] + if { $i != -1 } { + set lopt [lreplace $lopt $i $i [random_opts]] + } + + # Save off db_open arguments for this database. + set opt [eval concat $lopt] + set oa($dup_interval) $opt + + # Create the database and open the dictionary + set oflags "-create -truncate -mode 0644 $method\ + -pagesize $psize" + set db [eval {berkdb_open} $oflags $opt $name] + error_check_good dbopen [is_valid_db $db] TRUE + set did [open $dict] + set count 0 + puts -nonewline "\tBuilding $name: $nkeys keys " + puts -nonewline "with $ndups duplicates at interval of $dup_interval" + if { $with_dup_dups > 0 } { + puts "" + puts "\t\tand $with_dup_dups duplicate duplicates." + } else { + puts "." + } + for { set count 0 } { [gets $did str] != -1 && $count < $nkeys } { + incr count} { + set str $str$name + # We need to make sure that the dups are inserted in a + # random, or near random, order. Do this by generating + # them and putting each in a list, then sorting the list + # at random. + set duplist {} + for { set i 0 } { $i < $ndups } { incr i } { + set data [format "%04d" [expr $i * $dup_interval]] + lappend duplist $data + } + # randomize the list + for { set i 0 } { $i < $ndups } {incr i } { + # set j [berkdb random_int $i [expr $ndups - 1]] + set j [expr ($i % 2) + $i] + if { $j >= $ndups } { set j $i } + set dupi [lindex $duplist $i] + set dupj [lindex $duplist $j] + set duplist [lreplace $duplist $i $i $dupj] + set duplist [lreplace $duplist $j $j $dupi] + } + foreach data $duplist { + if { $with_dup_dups != 0 } { + for { set j 0 }\ + { $j < $with_dup_dups }\ + {incr j} { + set ret [$db put $str $data] + error_check_good put$j $ret 0 + } + } else { + set ret [$db put $str $data] + error_check_good put $ret 0 + } + } + + if { $ndups == 0 } { + set ret [$db put $str NODUP] + error_check_good put $ret 0 + } + } + close $did + error_check_good close:$name [$db close] 0 +} + +proc do_join { primary dbs key oanm flags with_dup_dups {dbs2 ""} {key2 ""} } { + global testdir + source ./include.tcl + + upvar $oanm oa + + puts -nonewline "\tJoining: $dbs on $key" + if { $dbs2 == "" } { + puts "" + } else { + puts " with $dbs2 on $key2" + } + + # Open all the databases + set p [berkdb_open -unknown $testdir/$primary] + error_check_good "primary open" [is_valid_db $p] TRUE + + set dblist "" + set curslist "" + + set ndx [llength $dbs] + + foreach i [concat $dbs $dbs2] { + set opt $oa($i) + set db [eval {berkdb_open -unknown} $opt [n_to_name $i]] + error_check_good "[n_to_name $i] open" [is_valid_db $db] TRUE + set curs [$db cursor] + error_check_good "$db cursor" \ + [is_substr $curs "$db.c"] 1 + lappend dblist $db + lappend curslist $curs + + if { $ndx > 0 } { + set realkey [concat $key[n_to_name $i]] + } else { + set realkey [concat $key2[n_to_name $i]] + } + + set pair [$curs get -set $realkey] + error_check_good cursor_set:$realkey:$pair \ + [llength [lindex $pair 0]] 2 + + incr ndx -1 + } + + set join_curs [eval {$p join} $curslist] + error_check_good join_cursor \ + [is_substr $join_curs "$p.c"] 1 + + # Calculate how many dups we expect. + # We go through the list of indices. If we find a 0, then we + # expect 0 dups. For everything else, we look at pairs of numbers, + # if the are relatively prime, multiply them and figure out how + # many times that goes into 50. If they aren't relatively prime, + # take the number of times the larger goes into 50. + set expected 50 + set last 1 + foreach n [concat $dbs $dbs2] { + if { $n == 0 } { + set expected 0 + break + } + if { $last == $n } { + continue + } + + if { [expr $last % $n] == 0 || [expr $n % $last] == 0 } { + if { $n > $last } { + set last $n + set expected [expr 50 / $last] + } + } else { + set last [expr $n * $last / [gcd $n $last]] + set expected [expr 50 / $last] + } + } + + # If $with_dup_dups is greater than zero, each datum has + # been inserted $with_dup_dups times. So we expect the number + # of dups to go up by a factor of ($with_dup_dups)^(number of databases) + + if { $with_dup_dups > 0 } { + foreach n [concat $dbs $dbs2] { + set expected [expr $expected * $with_dup_dups] + } + } + + set ndups 0 + if { $flags == " -join_item"} { + set l 1 + } else { + set flags "" + set l 2 + } + for { set pair [eval {$join_curs get} $flags] } { \ + [llength [lindex $pair 0]] == $l } { + set pair [eval {$join_curs get} $flags] } { + set k [lindex [lindex $pair 0] 0] + foreach i $dbs { + error_check_bad valid_dup:$i:$dbs $i 0 + set kval [string trimleft $k 0] + if { [string length $kval] == 0 } { + set kval 0 + } + error_check_good valid_dup:$i:$dbs [expr $kval % $i] 0 + } + incr ndups + } + error_check_good number_of_dups:$dbs $ndups $expected + + error_check_good close_primary [$p close] 0 + foreach i $curslist { + error_check_good close_cursor:$i [$i close] 0 + } + foreach i $dblist { + error_check_good close_index:$i [$i close] 0 + } +} + +proc n_to_name { n } { +global testdir + if { $n == 0 } { + return null.db; + } else { + return join$n.db; + } +} + +proc gcd { a b } { + set g 1 + + for { set i 2 } { $i <= $a } { incr i } { + if { [expr $a % $i] == 0 && [expr $b % $i] == 0 } { + set g $i + } + } + return $g +} diff --git a/db/test/lock001.tcl b/db/test/lock001.tcl new file mode 100644 index 000000000..d571a9872 --- /dev/null +++ b/db/test/lock001.tcl @@ -0,0 +1,170 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: lock001.tcl,v 11.11 2000/08/25 14:21:51 sue Exp $ +# +# Test driver for lock tests. +# General Multi Random +# Options are: +# -dir Y Y Y +# -iterations Y N Y +# -ldegree N N Y +# -maxlocks Y Y Y +# -objs N N Y +# -procs N N Y +# -reads N N Y +# -seeds N N Y +# -wait N N Y +# -conflicts Y Y Y +proc lock_usage {} { + puts stderr "randomlock\n\t-dir \n\t-iterations " + puts stderr "\t-conflicts " + puts stderr "\t-ldegree \n\t-maxlocks " + puts stderr "\t-objs \n\t-procs \n\t-reads <%reads>" + puts stderr "\t-seeds \n\t-wait " + return +} + +proc locktest { args } { + source ./include.tcl + + # Set defaults + # Adjusted to make exact match of isqrt + #set conflicts { 3 0 0 0 0 0 1 0 1 1} + #set conflicts { 3 0 0 0 0 1 0 1 1} + set conflicts { 0 0 0 0 0 1 0 1 1} + set iterations 1000 + set ldegree 5 + set maxlocks 1000 + set objs 75 + set procs 5 + set reads 65 + set seeds {} + set wait 5 + for { set i 0 } { $i < [llength $args] } {incr i} { + switch -regexp -- [lindex $args $i] { + -c.* { incr i; set conflicts [linkdex $args $i] } + -d.* { incr i; set testdir [lindex $args $i] } + -i.* { incr i; set iterations [lindex $args $i] } + -l.* { incr i; set ldegree [lindex $args $i] } + -m.* { incr i; set maxlocks [lindex $args $i] } + -o.* { incr i; set objs [lindex $args $i] } + -p.* { incr i; set procs [lindex $args $i] } + -r.* { incr i; set reads [lindex $args $i] } + -s.* { incr i; set seeds [lindex $args $i] } + -w.* { incr i; set wait [lindex $args $i] } + default { + puts -nonewline "FAIL:[timestamp] Usage: " + lock_usage + return + } + } + } + set nmodes [isqrt [llength $conflicts]] + + # Cleanup + env_cleanup $testdir + + # Open the region we'll use for testing. + set eflags "-create -lock -home $testdir -mode 0644 \ + -lock_max $maxlocks -lock_conflict {$nmodes {$conflicts}}" + set env [eval {berkdb env} $eflags] + lock001 $env $iterations $nmodes + reset_env $env + env_cleanup $testdir + + lock002 $maxlocks $conflicts + + lock003 $testdir $iterations \ + $maxlocks $procs $ldegree $objs $reads $wait $conflicts $seeds +} + +# Make sure that the basic lock tests work. Do some simple gets and puts for +# a single locker. +proc lock001 {env iter nmodes} { + source ./include.tcl + + puts "Lock001: test basic lock operations" + set locker 999 + # Get and release each type of lock + puts "Lock001.a: get and release each type of lock" + foreach m {ng write read} { + set obj obj$m + set lockp [$env lock_get $m $locker $obj] + error_check_good lock_get:a [is_blocked $lockp] 0 + error_check_good lock_get:a [is_substr $lockp $env] 1 + set ret [ $lockp put ] + error_check_good lock_put $ret 0 + } + + # Get a bunch of locks for the same locker; these should work + set obj OBJECT + puts "Lock001.b: Get a bunch of locks for the same locker" + foreach m {ng write read} { + set lockp [$env lock_get $m $locker $obj ] + lappend locklist $lockp + error_check_good lock_get:b [is_blocked $lockp] 0 + error_check_good lock_get:b [is_substr $lockp $env] 1 + } + release_list $locklist + + set locklist {} + # Check that reference counted locks work + puts "Lock001.c: reference counted locks." + for {set i 0} { $i < 10 } {incr i} { + set lockp [$env lock_get -nowait write $locker $obj] + error_check_good lock_get:c [is_blocked $lockp] 0 + error_check_good lock_get:c [is_substr $lockp $env] 1 + lappend locklist $lockp + } + release_list $locklist + + # Finally try some failing locks + set locklist {} + foreach i {ng write read} { + set lockp [$env lock_get $i $locker $obj] + lappend locklist $lockp + error_check_good lock_get:d [is_blocked $lockp] 0 + error_check_good lock_get:d [is_substr $lockp $env] 1 + } + + # Change the locker + set locker [incr locker] + set blocklist {} + # Skip NO_LOCK lock. + puts "Lock001.e: Change the locker, acquire read and write." + foreach i {write read} { + catch {$env lock_get -nowait $i $locker $obj} ret + error_check_good lock_get:e [is_substr $ret "not granted"] 1 + #error_check_good lock_get:e [is_substr $lockp $env] 1 + #error_check_good lock_get:e [is_blocked $lockp] 0 + } + # Now release original locks + release_list $locklist + + # Now re-acquire blocking locks + set locklist {} + puts "Lock001.f: Re-acquire blocking locks." + foreach i {write read} { + set lockp [$env lock_get -nowait $i $locker $obj ] + error_check_good lock_get:f [is_substr $lockp $env] 1 + error_check_good lock_get:f [is_blocked $lockp] 0 + lappend locklist $lockp + } + + # Now release new locks + release_list $locklist + + puts "Lock001 Complete." +} + +# Blocked locks appear as lockmgrN.lockM\nBLOCKED +proc is_blocked { l } { + if { [string compare $l BLOCKED ] == 0 } { + return 1 + } else { + return 0 + } +} diff --git a/db/test/lock002.tcl b/db/test/lock002.tcl new file mode 100644 index 000000000..b433730b1 --- /dev/null +++ b/db/test/lock002.tcl @@ -0,0 +1,151 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: lock002.tcl,v 11.10 2000/08/25 14:21:51 sue Exp $ +# +# Exercise basic multi-process aspects of lock. +proc lock002 { {maxlocks 1000} {conflicts {0 0 0 0 0 1 0 1 1} } } { + source ./include.tcl + + puts "Lock002: Basic multi-process lock tests." + + env_cleanup $testdir + + set nmodes [isqrt [llength $conflicts]] + + # Open the lock + mlock_open $maxlocks $nmodes $conflicts + mlock_wait +} + +# Make sure that we can create a region; destroy it, attach to it, +# detach from it, etc. +proc mlock_open { maxl nmodes conflicts } { + source ./include.tcl + + puts "Lock002.a multi-process open/close test" + + # Open/Create region here. Then close it and try to open from + # other test process. + set env_cmd [concat "berkdb env -create -mode 0644 \ + -lock -lock_max $maxl -lock_conflict" \ + [list [list $nmodes $conflicts]] "-home $testdir"] + set local_env [eval $env_cmd] + error_check_good env_open [is_valid_env $local_env] TRUE + + set ret [$local_env close] + error_check_good env_close $ret 0 + + # Open from other test process + set env_cmd "berkdb env -mode 0644 -home $testdir" + + set f1 [open |$tclsh_path r+] + puts $f1 "source $test_path/test.tcl" + + set remote_env [send_cmd $f1 $env_cmd] + error_check_good remote:env_open [is_valid_env $remote_env] TRUE + + # Now make sure that we can reopen the region. + set local_env [eval $env_cmd] + error_check_good env_open [is_valid_env $local_env] TRUE + set ret [$local_env close] + error_check_good env_close $ret 0 + + # Try closing the remote region + set ret [send_cmd $f1 "$remote_env close"] + error_check_good remote:lock_close $ret 0 + + # Try opening for create. Will succeed because region exists. + set env_cmd [concat "berkdb env -create -mode 0644 \ + -lock -lock_max $maxl -lock_conflict" \ + [list [list $nmodes $conflicts]] "-home $testdir"] + set local_env [eval $env_cmd] + error_check_good remote:env_open [is_valid_env $local_env] TRUE + + # close locally + reset_env $local_env + + # Close and exit remote + set ret [send_cmd $f1 "reset_env $remote_env"] + + catch { close $f1 } result +} + +proc mlock_wait { } { + source ./include.tcl + + puts "Lock002.b multi-process get/put wait test" + + # Open region locally + set env_cmd "berkdb env -lock -home $testdir" + set local_env [eval $env_cmd] + error_check_good env_open [is_valid_env $local_env] TRUE + + # Open region remotely + set f1 [open |$tclsh_path r+] + + puts $f1 "source $test_path/test.tcl" + + set remote_env [send_cmd $f1 $env_cmd] + error_check_good remote:env_open [is_valid_env $remote_env] TRUE + + # Get a write lock locally; try for the read lock + # remotely. We hold the locks for several seconds + # so that we can use timestamps to figure out if the + # other process waited. + set locker 1 + set local_lock [$local_env lock_get write $locker object1] + error_check_good lock_get [is_valid_lock $local_lock $local_env] TRUE + + # Now request a lock that we expect to hang; generate + # timestamps so we can tell if it actually hangs. + set locker 2 + set remote_lock [send_timed_cmd $f1 1 \ + "set lock \[$remote_env lock_get write $locker object1\]"] + + # Now sleep before releasing lock + tclsleep 5 + set result [$local_lock put] + error_check_good lock_put $result 0 + + # Now get the result from the other script + set result [rcv_result $f1] + error_check_good lock_get:remote_time [expr $result > 4] 1 + + # Now get the remote lock + set remote_lock [send_cmd $f1 "puts \$lock"] + error_check_good remote:lock_get \ + [is_valid_lock $remote_lock $remote_env] TRUE + + # Now make the other guy wait 5 second and then release his + # lock while we try to get a write lock on it + set start [timestamp -r] + + set ret [send_cmd $f1 "tclsleep 5"] + + set ret [send_cmd $f1 "$remote_lock put"] + + set locker 1 + set local_lock [$local_env lock_get write $locker object1] + error_check_good lock_get:time \ + [expr [expr [timestamp -r] - $start] > 2] 1 + error_check_good lock_get:local \ + [is_valid_lock $local_lock $local_env] TRUE + + # Now check remote's result + set result [rcv_result $f1] + error_check_good lock_put:remote $result 0 + + # Clean up remote + set ret [send_cmd $f1 "reset_env $remote_env"] + + close $f1 + + # Now close up locally + set ret [$local_lock put] + error_check_good lock_put $ret 0 + + reset_env $local_env +} diff --git a/db/test/lock003.tcl b/db/test/lock003.tcl new file mode 100644 index 000000000..539b6d0ff --- /dev/null +++ b/db/test/lock003.tcl @@ -0,0 +1,48 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: lock003.tcl,v 11.16 2000/08/25 14:21:51 sue Exp $ +# +# Exercise multi-process aspects of lock. Generate a bunch of parallel +# testers that try to randomly obtain locks. +proc lock003 { dir {iter 500} {max 1000} {procs 5} {ldegree 5} {objs 75} \ + {reads 65} {wait 1} {conflicts { 3 0 0 0 0 0 1 0 1 1}} {seeds {}} } { + source ./include.tcl + + puts "Lock003: Multi-process random lock test" + + # Clean up after previous runs + env_cleanup $dir + + # Open/create the lock region + set e [berkdb env -create -lock -home $dir] + error_check_good env_open [is_substr $e env] 1 + + set ret [$e close] + error_check_good env_close $ret 0 + + # Now spawn off processes + set pidlist {} + for { set i 0 } {$i < $procs} {incr i} { + if { [llength $seeds] == $procs } { + set s [lindex $seeds $i] + } + puts "$tclsh_path\ + $test_path/wrap.tcl \ + lockscript.tcl $dir/$i.lockout\ + $dir $iter $objs $wait $ldegree $reads &" + set p [exec $tclsh_path $test_path/wrap.tcl \ + lockscript.tcl $testdir/lock003.$i.out \ + $dir $iter $objs $wait $ldegree $reads &] + lappend pidlist $p + } + + puts "Lock003: $procs independent processes now running" + watch_procs 30 10800 + # Remove log files + for { set i 0 } {$i < $procs} {incr i} { + fileremove -f $dir/$i.lockout + } +} diff --git a/db/test/lockscript.tcl b/db/test/lockscript.tcl new file mode 100644 index 000000000..bd07d80b5 --- /dev/null +++ b/db/test/lockscript.tcl @@ -0,0 +1,88 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: lockscript.tcl,v 11.11 2000/03/24 19:53:39 krinsky Exp $ +# +# Random lock tester. +# Usage: lockscript dir numiters numobjs sleepint degree readratio +# dir: lock directory. +# numiters: Total number of iterations. +# numobjs: Number of objects on which to lock. +# sleepint: Maximum sleep interval. +# degree: Maximum number of locks to acquire at once +# readratio: Percent of locks that should be reads. + +source ./include.tcl +source $test_path/test.tcl + +set usage "lockscript dir numiters numobjs sleepint degree readratio" + +# Verify usage +if { $argc != 6 } { + puts stderr "FAIL:[timestamp] Usage: $usage" + exit +} + +# Initialize arguments +set dir [lindex $argv 0] +set numiters [ lindex $argv 1 ] +set numobjs [ lindex $argv 2 ] +set sleepint [ lindex $argv 3 ] +set degree [ lindex $argv 4 ] +set readratio [ lindex $argv 5 ] +set locker [pid] + +# Initialize random number generator +global rand_init +berkdb srand $rand_init + +puts -nonewline "Beginning execution for $locker: $numiters $numobjs " +puts "$sleepint $degree $readratio" +flush stdout + +set e [berkdb env -create -lock -home $dir] +error_check_good env_open [is_substr $e env] 1 + +for { set iter 0 } { $iter < $numiters } { incr iter } { + set nlocks [berkdb random_int 1 $degree] + # We will always lock objects in ascending order to avoid + # deadlocks. + set lastobj 1 + set locklist {} + for { set lnum 0 } { $lnum < $nlocks } { incr lnum } { + # Pick lock parameters + set obj [berkdb random_int $lastobj $numobjs] + set lastobj [expr $obj + 1] + set x [berkdb random_int 1 100 ] + if { $x <= $readratio } { + set rw read + } else { + set rw write + } + puts "[timestamp] $locker $lnum: $rw $obj" + + # Do get; add to list + set lockp [$e lock_get $rw $locker $obj] + lappend locklist $lockp + if {$lastobj > $numobjs} { + break + } + } + # Pick sleep interval + tclsleep [berkdb random_int 1 $sleepint] + + # Now release locks + puts "[timestamp] $locker released locks" + release_list $locklist + flush stdout +} + +set ret [$e close] +error_check_good env_close $ret 0 + +puts "[timestamp] $locker Complete" +flush stdout + +exit diff --git a/db/test/log.tcl b/db/test/log.tcl new file mode 100644 index 000000000..c3802d0f9 --- /dev/null +++ b/db/test/log.tcl @@ -0,0 +1,337 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: log.tcl,v 11.17 2000/11/30 20:09:19 dda Exp $ +# +# Options are: +# -dir +# -maxfilesize +# -iterations +# -stat +proc log_usage {} { + puts "log -dir -iterations \ + -maxfilesize -stat" +} +proc logtest { args } { + source ./include.tcl + global rand_init + + # Set defaults + set iterations 1000 + set maxfile [expr 1024 * 128] + set dostat 0 + for { set i 0 } { $i < [llength $args] } {incr i} { + switch -regexp -- [lindex $args $i] { + -d.* { incr i; set testdir [lindex $args $i] } + -i.* { incr i; set iterations [lindex $args $i] } + -m.* { incr i; set maxfile [lindex $args $i] } + -s.* { set dostat 1 } + default { + puts -nonewline "FAIL:[timestamp] Usage: " + log_usage + return + } + } + } + set multi_log [expr 3 * $iterations] + + # Clean out old log if it existed + puts "Unlinking log: error message OK" + env_cleanup $testdir + + # Now run the various functionality tests + berkdb srand $rand_init + + log001 $testdir $maxfile $iterations + log001 $testdir $maxfile $multi_log + log002 $testdir $maxfile + log003 $testdir $maxfile + log004 $testdir +} + +proc log001 { dir max nrecs } { + source ./include.tcl + + puts "Log001: Basic put/get test" + + env_cleanup $dir + + set env [berkdb env -log -create -home $dir \ + -mode 0644 -log_max $max] + error_check_bad log_env:$dir $env NULL + error_check_good log:$dir [is_substr $env "env"] 1 + + # We will write records to the log and make sure we can + # read them back correctly. We'll use a standard pattern + # repeated some number of times for each record. + + set lsn_list {} + set rec_list {} + puts "Log001.a: Writing $nrecs log records" + for { set i 0 } { $i < $nrecs } { incr i } { + set rec "" + for { set j 0 } { $j < [expr $i % 10 + 1] } {incr j} { + set rec $rec$i:logrec:$i + } + set lsn [$env log_put $rec] + error_check_bad log_put [is_substr $lsn log_cmd] 1 + lappend lsn_list $lsn + lappend rec_list $rec + } + puts "Log001.b: Retrieving log records sequentially (forward)" + set i 0 + for { set grec [$env log_get -first] } { [llength $grec] != 0 } { + set grec [$env log_get -next]} { + error_check_good log_get:seq [lindex $grec 1] \ + [lindex $rec_list $i] + incr i + } + + puts "Log001.c: Retrieving log records sequentially (backward)" + set i [llength $rec_list] + for { set grec [$env log_get -last] } { [llength $grec] != 0 } { + set grec [$env log_get -prev] } { + incr i -1 + error_check_good \ + log_get:seq [lindex $grec 1] [lindex $rec_list $i] + } + + puts "Log001.d: Retrieving log records sequentially by LSN" + set i 0 + foreach lsn $lsn_list { + set grec [$env log_get -set $lsn] + error_check_good \ + log_get:seq [lindex $grec 1] [lindex $rec_list $i] + incr i + } + + puts "Log001.e: Retrieving log records randomly by LSN" + set m [expr [llength $lsn_list] - 1] + for { set i 0 } { $i < $nrecs } { incr i } { + set recno [berkdb random_int 0 $m ] + set lsn [lindex $lsn_list $recno] + set grec [$env log_get -set $lsn] + error_check_good \ + log_get:seq [lindex $grec 1] [lindex $rec_list $recno] + } + + # Close and unlink the file + error_check_good env:close:$env [$env close] 0 + error_check_good envremove:$dir [berkdb envremove -home $dir] 0 + + puts "Log001 Complete" +} + +proc log002 { dir {max 32768} } { + source ./include.tcl + + puts "Log002: Multiple log test w/trunc, file, compare functionality" + + env_cleanup $dir + + set env [berkdb env -create -home $dir -mode 0644 -log -log_max $max] + error_check_bad log_env:$dir $env NULL + error_check_good log:$dir [is_substr $env "env"] 1 + + # We'll record every hundred'th record for later use + set info_list {} + + set i 0 + puts "Log002.a: Writing log records" + + for {set s 0} { $s < [expr 3 * $max] } { incr s $len } { + set rec [random_data 120 0 0] + set len [string length $rec] + set lsn [$env log_put $rec] + + if { [expr $i % 100 ] == 0 } { + lappend info_list [list $lsn $rec] + } + incr i + } + + puts "Log002.b: Checking log_compare" + set last {0 0} + foreach p $info_list { + set l [lindex $p 0] + if { [llength $last] != 0 } { + error_check_good \ + log_compare [$env log_compare $l $last] 1 + error_check_good \ + log_compare [$env log_compare $last $l] -1 + error_check_good \ + log_compare [$env log_compare $l $l] 0 + } + set last $l + } + + puts "Log002.c: Checking log_file" + set flist [glob $dir/log*] + foreach p $info_list { + + set lsn [lindex $p 0] + set f [$env log_file $lsn] + + # Change all backslash separators on Windows to forward slash + # separators, which is what the rest of the test suite expects. + regsub -all {\\} $f {/} f + + error_check_bad log_file:$f [lsearch $flist $f] -1 + } + + puts "Log002.d: Verifying records" + for {set i [expr [llength $info_list] - 1] } { $i >= 0 } { incr i -1} { + set p [lindex $info_list $i] + set grec [$env log_get -set [lindex $p 0]] + error_check_good log_get:$env [lindex $grec 1] [lindex $p 1] + } + + # Close and unlink the file + error_check_good env:close:$env [$env close] 0 + error_check_good envremove:$dir [berkdb envremove -home $dir] 0 + + puts "Log002 Complete" +} + +proc log003 { dir {max 32768} } { + source ./include.tcl + + puts "Log003: Verify log_flush behavior" + + env_cleanup $dir + set short_rec "abcdefghijklmnopqrstuvwxyz" + set long_rec [repeat $short_rec 200] + set very_long_rec [repeat $long_rec 4] + + foreach rec "$short_rec $long_rec $very_long_rec" { + puts "Log003.a: Verify flush on [string length $rec] byte rec" + + set env [berkdb env -log -home $dir \ + -create -mode 0644 -log_max $max] + error_check_bad log_env:$dir $env NULL + error_check_good log:$dir [is_substr $env "env"] 1 + + set lsn [$env log_put $rec] + error_check_bad log_put [lindex $lsn 0] "ERROR:" + set ret [$env log_flush $lsn] + error_check_good log_flush $ret 0 + + # Now, we want to crash the region and recheck. Closing the + # log does not flush any records, so we'll use a close to + # do the "crash" + set ret [$env close] + error_check_good log_env:close $ret 0 + + # Now, remove the log region + #set ret [berkdb envremove -home $dir] + #error_check_good env:remove $ret 0 + + # Re-open the log and try to read the record. + set env [berkdb env -create -home $dir \ + -log -mode 0644 -log_max $max] + error_check_bad log_env:$dir $env NULL + error_check_good log:$dir [is_substr $env "env"] 1 + + set gotrec [$env log_get -first] + error_check_good lp_get [lindex $gotrec 1] $rec + + # Close and unlink the file + error_check_good env:close:$env [$env close] 0 + error_check_good envremove:$dir [berkdb envremove -home $dir] 0 + log_cleanup $dir + } + + foreach rec "$short_rec $long_rec $very_long_rec" { + puts "Log003.b: \ + Verify flush on non-last record [string length $rec]" + set env [berkdb env \ + -create -log -home $dir -mode 0644 -log_max $max] + error_check_bad log_env:$dir $env NULL + error_check_good log:$dir [is_substr $env "env"] 1 + + # Put 10 random records + for { set i 0 } { $i < 10 } { incr i} { + set r [random_data 450 0 0] + set lsn [$env log_put $r] + error_check_bad log_put [lindex $lsn 0] "ERROR:" + } + + # Put the record we are interested in + set save_lsn [$env log_put $rec] + error_check_bad log_put [lindex $save_lsn 0] "ERROR:" + + # Put 10 more random records + for { set i 0 } { $i < 10 } { incr i} { + set r [random_data 450 0 0] + set lsn [$env log_put $r] + error_check_bad log_put [lindex $lsn 0] "ERROR:" + } + + # Now check the flush + set ret [$env log_flush $save_lsn] + error_check_good log_flush $ret 0 + + # Now, we want to crash the region and recheck. Closing the + # log does not flush any records, so we'll use a close to + # do the "crash" + + # + # Now, close and remove the log region + error_check_good env:close:$env [$env close] 0 + set ret [berkdb envremove -home $dir] + error_check_good env:remove $ret 0 + + # Re-open the log and try to read the record. + set env [berkdb env \ + -home $dir -create -log -mode 0644 -log_max $max] + error_check_bad log_env:$dir $env NULL + error_check_good log:$dir [is_substr $env "env"] 1 + + set gotrec [$env log_get -set $save_lsn] + error_check_good lp_get [lindex $gotrec 1] $rec + + # Close and unlink the file + error_check_good env:close:$env [$env close] 0 + error_check_good envremove:$dir [berkdb envremove -home $dir] 0 + log_cleanup $dir + } + + puts "Log003 Complete" +} + +# Make sure that if we do PREVs on a log, but the beginning of the +# log has been truncated, we do the right thing. +proc log004 { dir } { + source ./include.tcl + + puts "Log004: Prev on log when beginning of log has been truncated." + # Use archive test to populate log + env_cleanup $dir + puts "Log004.a: Call archive to populate log." + archive + + # Delete all log files under 100 + puts "Log004.b: Delete all log files under 100." + set ret [catch { glob $dir/log.00000000* } result] + if { $ret == 0 } { + eval fileremove -f $result + } + + # Now open the log and get the first record and try a prev + puts "Log004.c: Open truncated log, attempt to access missing portion." + set myenv [berkdb env -create -log -home $dir] + error_check_good log_open [is_substr $myenv "env"] 1 + + set ret [$myenv log_get -first] + error_check_bad log_get [llength $ret] 0 + + # This should give DB_NOTFOUND which is a ret of length 0 + catch {$myenv log_get -prev} ret + error_check_good log_get_prev [string length $ret] 0 + + puts "Log004.d: Close log and environment." + error_check_good log_close [$myenv close] 0 + puts "Log004 complete." +} diff --git a/db/test/logtrack.list b/db/test/logtrack.list new file mode 100644 index 000000000..ba7f34a6d --- /dev/null +++ b/db/test/logtrack.list @@ -0,0 +1,68 @@ +PREFIX crdel +BEGIN fileopen 141 +BEGIN metasub 142 +BEGIN metapage 143 +DEPRECATED old_delete 144 +BEGIN rename 145 +BEGIN delete 146 +PREFIX db +BEGIN addrem 41 +DEPRECATED split 42 +BEGIN big 43 +BEGIN ovref 44 +BEGIN relink 45 +DEPRECATED addpage 46 +BEGIN debug 47 +BEGIN noop 48 +PREFIX bam +BEGIN pg_alloc 51 +DEPRECATED pg_alloc1 60 +BEGIN pg_free 52 +DEPRECATED pg_free1 61 +DEPRECATED split1 53 +BEGIN split 62 +DEPRECATED rsplit1 54 +BEGIN rsplit 63 +BEGIN adj 55 +BEGIN cadjust 56 +BEGIN cdel 57 +BEGIN repl 58 +BEGIN root 59 +BEGIN curadj 64 +BEGIN rcuradj 65 +PREFIX ham +BEGIN insdel 21 +BEGIN newpage 22 +DEPRECATED splitmeta 23 +BEGIN splitdata 24 +BEGIN replace 25 +DEPRECATED newpgno 26 +DEPRECATED ovfl 27 +BEGIN copypage 28 +BEGIN metagroup 29 +DEPRECATED groupalloc1 30 +DEPRECATED groupalloc2 31 +BEGIN groupalloc 32 +BEGIN curadj 33 +BEGIN chgpg 34 +PREFIX log +DEPRECATED register1 1 +BEGIN register 2 +PREFIX qam +BEGIN inc 76 +BEGIN incfirst 77 +BEGIN mvptr 78 +BEGIN del 79 +BEGIN add 80 +BEGIN delete 81 +BEGIN rename 82 +BEGIN delext 83 +PREFIX txn +DEPRECATED old_regop 6 +BEGIN regop 10 +DEPRECATED old_ckp 7 +BEGIN ckp 11 +DEPRECATED xa_regop_old 8 +BEGIN xa_regop 13 +DEPRECATED child_old 9 +BEGIN child 12 diff --git a/db/test/logtrack.tcl b/db/test/logtrack.tcl new file mode 100644 index 000000000..cea4912e6 --- /dev/null +++ b/db/test/logtrack.tcl @@ -0,0 +1,130 @@ +# See the file LICENSE for redistribution information +# +# Copyright (c) 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: logtrack.tcl,v 11.6 2000/10/27 15:30:39 krinsky Exp $ +# +# logtrack.tcl: A collection of routines, formerly implemented in Perl +# as log.pl, to track which log record types the test suite hits. + +set ltsname "logtrack_seen.db" +set ltlist $test_path/logtrack.list +set tmpname "logtrack_tmp" + +proc logtrack_clean { } { + global ltsname + + file delete -force $ltsname + + return +} + +proc logtrack_init { } { + global ltsname + + logtrack_clean + + # Create an empty tracking database. + [berkdb_open -create -truncate -btree $ltsname] close + + return +} + +# Dump the logs for directory dirname and record which log +# records were seen. +proc logtrack_read { dirname } { + global ltsname tmpname util_path + + set seendb [berkdb_open $ltsname] + error_check_good seendb_open [is_valid_db $seendb] TRUE + + file delete -force $tmpname + set ret [catch {exec $util_path/db_printlog -N \ + -h "$dirname" > $tmpname} res] + error_check_good printlog $ret 0 + error_check_good tmpfile_exists [file exists $tmpname] 1 + + set f [open $tmpname r] + while { [gets $f record] >= 0 } { + regexp {\[[^\]]*\]\[[^\]]*\]([^\:]*)\:} $record whl name + error_check_good seendb_put [$seendb put $name ""] 0 + } + close $f + file delete -force $tmpname + + error_check_good seendb_close [$seendb close] 0 +} + +# Print the log record types that were seen but should not have been +# seen and the log record types that were not seen but should have been seen. +proc logtrack_summary { } { + global ltsname ltlist testdir + + set seendb [berkdb_open $ltsname] + error_check_good seendb_open [is_valid_db $seendb] TRUE + set existdb [berkdb_open -create -btree] + error_check_good existdb_open [is_valid_db $existdb] TRUE + set deprecdb [berkdb_open -create -btree] + error_check_good deprecdb_open [is_valid_db $deprecdb] TRUE + + error_check_good ltlist_exists [file exists $ltlist] 1 + set f [open $ltlist r] + set pref "" + while { [gets $f line] >= 0 } { + # Get the keyword, the first thing on the line: + # BEGIN/DEPRECATED/PREFIX + set keyword [lindex $line 0] + + if { [string compare $keyword PREFIX] == 0 } { + # New prefix. + set pref [lindex $line 1] + } elseif { [string compare $keyword BEGIN] == 0 } { + # A log type we care about; put it on our list. + + # Skip noop and debug. + if { [string compare [lindex $line 1] noop] == 0 } { + continue + } + if { [string compare [lindex $line 1] debug] == 0 } { + continue + } + + error_check_good exist_put [$existdb put \ + ${pref}_[lindex $line 1] ""] 0 + } elseif { [string compare $keyword DEPRECATED] == 0 } { + error_check_good deprec_put [$deprecdb put \ + ${pref}_[lindex $line 1] ""] 0 + } + } + + error_check_good exist_curs \ + [is_valid_cursor [set ec [$existdb cursor]] $existdb] TRUE + while { [llength [set dbt [$ec get -next]]] != 0 } { + set rec [lindex [lindex $dbt 0] 0] + if { [$seendb count $rec] == 0 } { + puts "FAIL: log record type $rec not seen" + } + } + error_check_good exist_curs_close [$ec close] 0 + + error_check_good seen_curs \ + [is_valid_cursor [set sc [$existdb cursor]] $existdb] TRUE + while { [llength [set dbt [$sc get -next]]] != 0 } { + set rec [lindex [lindex $dbt 0] 0] + if { [$existdb count $rec] == 0 } { + if { [$deprecdb count $rec] == 0 } { + puts "FAIL: unknown log record type $rec seen" + } else { + puts "FAIL: deprecated log record type $rec seen" + } + } + } + error_check_good seen_curs_close [$sc close] 0 + + error_check_good seendb_close [$seendb close] 0 + error_check_good existdb_close [$existdb close] 0 + error_check_good deprecdb_close [$deprecdb close] 0 + + logtrack_clean +} diff --git a/db/test/mdbscript.tcl b/db/test/mdbscript.tcl new file mode 100644 index 000000000..368aad371 --- /dev/null +++ b/db/test/mdbscript.tcl @@ -0,0 +1,381 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: mdbscript.tcl,v 11.23 2000/10/09 02:26:11 krinsky Exp $ +# +# Process script for the multi-process db tester. + +source ./include.tcl +source $test_path/test.tcl +source $test_path/testutils.tcl + +global dbenv +global klock +global l_keys +global procid +global alphabet + +# In Tcl, when there are multiple catch handlers, *all* handlers +# are called, so we have to resort to this hack. +# +global exception_handled + +set exception_handled 0 + +set datastr $alphabet$alphabet + +# Usage: mdbscript dir file nentries iter procid procs seed +# dir: DBHOME directory +# file: db file on which to operate +# nentries: number of entries taken from dictionary +# iter: number of operations to run +# procid: this processes' id number +# procs: total number of processes running +set usage "mdbscript method dir file nentries iter procid procs" + +# Verify usage +if { $argc != 7 } { + puts "FAIL:[timestamp] test042: Usage: $usage" + exit +} + +# Initialize arguments +set method [lindex $argv 0] +set dir [lindex $argv 1] +set file [lindex $argv 2] +set nentries [ lindex $argv 3 ] +set iter [ lindex $argv 4 ] +set procid [ lindex $argv 5 ] +set procs [ lindex $argv 6 ] + +set pflags "" +set gflags "" +set txn "" + +set renum [is_rrecno $method] +set omethod [convert_method $method] + +if { [is_record_based $method] == 1 } { + append gflags " -recno" +} + +# Initialize seed +global rand_init + +# We want repeatable results, but we also want each instance of mdbscript +# to do something different. So we add the procid to the fixed seed. +# (Note that this is a serial number given by the caller, not a pid.) +berkdb srand [expr $rand_init + $procid] + +puts "Beginning execution for [pid] $method" +puts "$dir db_home" +puts "$file database" +puts "$nentries data elements" +puts "$iter iterations" +puts "$procid process id" +puts "$procs processes" + +set klock NOLOCK +flush stdout + +set dbenv [berkdb env -create -cdb -home $dir] +#set dbenv [berkdb env -create -cdb -log -home $dir] +error_check_good dbenv [is_valid_env $dbenv] TRUE + +set db [berkdb_open -env $dbenv -create -mode 0644 $omethod $file] +error_check_good dbopen [is_valid_db $db] TRUE + +# Init globals (no data) +set nkeys [db_init $db 0] +puts "Initial number of keys: $nkeys" +error_check_good db_init $nkeys $nentries +tclsleep 5 + +proc get_lock { k } { + global dbenv + global procid + global klock + global DB_LOCK_WRITE + global DB_LOCK_NOWAIT + global errorInfo + global exception_handled + # Make sure that the key isn't in the middle of + # a delete operation + if {[catch {$dbenv lock_get -nowait write $procid $k} klock] != 0 } { + set exception_handled 1 + + error_check_good \ + get_lock [is_substr $errorInfo "DB_LOCK_NOTGRANTED"] 1 + puts "Warning: key $k locked" + set klock NOLOCK + return 1 + } else { + error_check_good get_lock [is_valid_lock $klock $dbenv] TRUE + } + return 0 +} + +# On each iteration we're going to randomly pick a key. +# 1. We'll either get it (verifying that its contents are reasonable). +# 2. Put it (using an overwrite to make the data be datastr:ID). +# 3. Get it and do a put through the cursor, tacking our ID on to +# 4. Get it, read forward some random number of keys. +# 5. Get it, read forward some random number of keys and do a put (replace). +# 6. Get it, read forward some random number of keys and do a del. And then +# do a put of the key. +set gets 0 +set getput 0 +set overwrite 0 +set seqread 0 +set seqput 0 +set seqdel 0 +set dlen [string length $datastr] + +for { set i 0 } { $i < $iter } { incr i } { + set op [berkdb random_int 0 5] + puts "iteration $i operation $op" + flush stdout + if {[catch { + switch $op { + 0 { + incr gets + set k [rand_key $method $nkeys $renum $procs] + if {[is_record_based $method] == 1} { + set key $k + } else { + set key [lindex $l_keys $k] + } + + if { [get_lock $key] == 1 } { + incr i -1 + continue; + } + + set rec [eval {$db get} $txn $gflags {$key}] + error_check_bad "$db get $key" [llength $rec] 0 + set partial [string range \ + [lindex [lindex $rec 0] 1] 0 [expr $dlen - 1]] + error_check_good \ + "$db get $key" $partial [pad_data $method $datastr] + } + 1 { + incr overwrite + set k [rand_key $method $nkeys $renum $procs] + if {[is_record_based $method] == 1} { + set key $k + } else { + set key [lindex $l_keys $k] + } + + set data $datastr:$procid + set ret [eval {$db put} \ + $txn $pflags {$key [chop_data $method $data]}] + error_check_good "$db put $key" $ret 0 + } + 2 { + incr getput + set dbc [$db cursor -update] + error_check_good "$db cursor" \ + [is_valid_cursor $dbc $db] TRUE + set close_cursor 1 + set k [rand_key $method $nkeys $renum $procs] + if {[is_record_based $method] == 1} { + set key $k + } else { + set key [lindex $l_keys $k] + } + + if { [get_lock $key] == 1 } { + incr i -1 + error_check_good "$dbc close" \ + [$dbc close] 0 + set close_cursor 0 + continue; + } + + set ret [$dbc get -set $key] + error_check_good \ + "$dbc get $key" [llength [lindex $ret 0]] 2 + set rec [lindex [lindex $ret 0] 1] + set partial [string range $rec 0 [expr $dlen - 1]] + error_check_good \ + "$dbc get $key" $partial [pad_data $method $datastr] + append rec ":$procid" + set ret [$dbc put \ + -current [chop_data $method $rec]] + error_check_good "$dbc put $key" $ret 0 + error_check_good "$dbc close" [$dbc close] 0 + set close_cursor 0 + } + 3 - + 4 - + 5 { + if { $op == 3 } { + set flags "" + } else { + set flags -update + } + set dbc [eval {$db cursor} $flags] + error_check_good "$db cursor" \ + [is_valid_cursor $dbc $db] TRUE + set close_cursor 1 + set k [rand_key $method $nkeys $renum $procs] + if {[is_record_based $method] == 1} { + set key $k + } else { + set key [lindex $l_keys $k] + } + + if { [get_lock $key] == 1 } { + incr i -1 + error_check_good "$dbc close" \ + [$dbc close] 0 + set close_cursor 0 + continue; + } + + set ret [$dbc get -set $key] + error_check_good \ + "$dbc get $key" [llength [lindex $ret 0]] 2 + + # Now read a few keys sequentially + set nloop [berkdb random_int 0 10] + if { [berkdb random_int 0 1] == 0 } { + set flags -next + } else { + set flags -prev + } + while { $nloop > 0 } { + set lastret $ret + set ret [eval {$dbc get} $flags] + # Might read beginning/end of file + if { [llength $ret] == 0} { + set ret $lastret + break + } + incr nloop -1 + } + switch $op { + 3 { + incr seqread + } + 4 { + incr seqput + set rec [lindex [lindex $ret 0] 1] + set partial [string range $rec 0 \ + [expr $dlen - 1]] + error_check_good "$dbc get $key" \ + $partial [pad_data $method $datastr] + append rec ":$procid" + set ret [$dbc put -current \ + [chop_data $method $rec]] + error_check_good \ + "$dbc put $key" $ret 0 + } + 5 { + incr seqdel + set k [lindex [lindex $ret 0] 0] + # We need to lock the item we're + # deleting so that someone else can't + # try to do a get while we're + # deleting + error_check_good "$klock put" \ + [$klock put] 0 + set klock NOLOCK + set cur [$dbc get -current] + error_check_bad get_current \ + [llength $cur] 0 + set key [lindex [lindex $cur 0] 0] + if { [get_lock $key] == 1 } { + incr i -1 + error_check_good "$dbc close" \ + [$dbc close] 0 + set close_cursor 0 + continue + } + set ret [$dbc del] + error_check_good "$dbc del" $ret 0 + set rec $datastr + append rec ":$procid" + if { $renum == 1 } { + set ret [$dbc put -before \ + [chop_data $method $rec]] + error_check_good \ + "$dbc put $k" $ret $k + } elseif { \ + [is_record_based $method] == 1 } { + error_check_good "$dbc close" \ + [$dbc close] 0 + set close_cursor 0 + set ret [$db put $k \ + [chop_data $method $rec]] + error_check_good \ + "$db put $k" $ret 0 + } else { + set ret [$dbc put -keylast $k \ + [chop_data $method $rec]] + error_check_good \ + "$dbc put $k" $ret 0 + } + } + } + if { $close_cursor == 1 } { + error_check_good \ + "$dbc close" [$dbc close] 0 + set close_cursor 0 + } + } + } + } res] != 0} { + global errorInfo; + global exception_handled; + + puts $errorInfo + + set fnl [string first "\n" $errorInfo] + set theError [string range $errorInfo 0 [expr $fnl - 1]] + + flush stdout + if { [string compare $klock NOLOCK] != 0 } { + catch {$klock put} + } + if {$close_cursor == 1} { + catch {$dbc close} + set close_cursor 0 + } + + if {[string first FAIL $theError] == 0 && \ + $exception_handled != 1} { + error "FAIL:[timestamp] test042: key $k: $theError" + } + set exception_handled 0 + } else { + flush stdout + if { [string compare $klock NOLOCK] != 0 } { + error_check_good "$klock put" [$klock put] 0 + set klock NOLOCK + } + } +} + +if {[catch {$db close} ret] != 0 } { + error_check_good close [is_substr $errorInfo "DB_INCOMPLETE"] 1 + puts "Warning: sync incomplete on close ([pid])" +} else { + error_check_good close $ret 0 +} +$dbenv close + +exit + +puts "[timestamp] [pid] Complete" +puts "Successful ops: " +puts "\t$gets gets" +puts "\t$overwrite overwrites" +puts "\t$getput getputs" +puts "\t$seqread seqread" +puts "\t$seqput seqput" +puts "\t$seqdel seqdel" +flush stdout diff --git a/db/test/mpool.tcl b/db/test/mpool.tcl new file mode 100644 index 000000000..b2eb22520 --- /dev/null +++ b/db/test/mpool.tcl @@ -0,0 +1,420 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: mpool.tcl,v 11.34 2001/01/18 04:58:07 krinsky Exp $ +# +# Options are: +# -cachesize {gbytes bytes ncache} +# -nfiles +# -iterations +# -pagesize +# -dir +# -stat +proc memp_usage {} { + puts "memp -cachesize {gbytes bytes ncache}" + puts "\t-nfiles " + puts "\t-iterations " + puts "\t-pagesize " + puts "\t-dir " + puts "\t-mem {private system}" + return +} + +proc mpool { args } { + source ./include.tcl + global errorCode + + puts "mpool {$args} running" + # Set defaults + set cachearg " -cachesize {0 200000 3}" + set nfiles 5 + set iterations 500 + set pagesize "512 1024 2048 4096 8192" + set npages 100 + set procs 4 + set seeds "" + set shm_key 1 + set dostat 0 + set flags "" + for { set i 0 } { $i < [llength $args] } {incr i} { + switch -regexp -- [lindex $args $i] { + -c.* { + incr i + set cachesize [lindex $args $i] + set cachearg " -cachesize $cachesize" + } + -d.* { incr i; set testdir [lindex $args $i] } + -i.* { incr i; set iterations [lindex $args $i] } + -me.* { + incr i + if { [string \ + compare [lindex $args $i] private] == 0 } { + set flags -private + } elseif { [string \ + compare [lindex $args $i] system] == 0 } { + # + # We need to use a shm id. Use one + # that is the same each time so that + # we do not grow segments infinitely. + set flags "-system_mem -shm_key $shm_key" + } else { + puts -nonewline \ + "FAIL:[timestamp] Usage: " + memp_usage + return + } + } + -nf.* { incr i; set nfiles [lindex $args $i] } + -np.* { incr i; set npages [lindex $args $i] } + -pa.* { incr i; set pagesize [lindex $args $i] } + -pr.* { incr i; set procs [lindex $args $i] } + -se.* { incr i; set seeds [lindex $args $i] } + -st.* { set dostat 1 } + default { + puts -nonewline "FAIL:[timestamp] Usage: " + memp_usage + return + } + } + } + + # Clean out old directory + env_cleanup $testdir + + # Open the memp with region init specified + set ret [catch {eval {berkdb env -create -mode 0644}\ + $cachearg {-region_init -home $testdir} $flags} res] + if { $ret == 0 } { + set env $res + } else { + # If the env open failed, it may be because we're on a platform + # such as HP-UX 10 that won't support mutexes in shmget memory. + # Or QNX, which doesn't support system memory at all. + # Verify that the return value was EINVAL or EOPNOTSUPP + # and bail gracefully. + error_check_good is_shm_test [is_substr $flags -system_mem] 1 + error_check_good returned_error [expr \ + [is_substr $errorCode EINVAL] || \ + [is_substr $errorCode EOPNOTSUPP]] 1 + puts "Warning:\ + platform does not support mutexes in shmget memory." + puts "Skipping shared memory mpool test." + return + } + error_check_good env_open [is_substr $env env] 1 + + reset_env $env + env_cleanup $testdir + + # Now open without region init + set env [eval {berkdb env -create -mode 0644}\ + $cachearg {-home $testdir} $flags] + error_check_good evn_open [is_substr $env env] 1 + + memp001 $env \ + $testdir $nfiles $iterations [lindex $pagesize 0] $dostat $flags + reset_env $env + set ret [berkdb envremove -home $testdir] + error_check_good env_remove $ret 0 + env_cleanup $testdir + + memp002 $testdir \ + $procs $pagesize $iterations $npages $seeds $dostat $flags + set ret [berkdb envremove -home $testdir] + error_check_good env_remove $ret 0 + env_cleanup $testdir + + memp003 $testdir $iterations $flags + set ret [berkdb envremove -home $testdir] + error_check_good env_remove $ret 0 + + env_cleanup $testdir +} + +proc memp001 {env dir n iter psize dostat flags} { + source ./include.tcl + global rand_init + + puts "Memp001: {$flags} random update $iter iterations on $n files." + + # Open N memp files + for {set i 1} {$i <= $n} {incr i} { + set fname "data_file.$i" + file_create $dir/$fname 50 $psize + + set mpools($i) \ + [$env mpool -create -pagesize $psize -mode 0644 $fname] + error_check_good mp_open [is_substr $mpools($i) $env.mp] 1 + } + + # Now, loop, picking files at random + berkdb srand $rand_init + for {set i 0} {$i < $iter} {incr i} { + set mpool $mpools([berkdb random_int 1 $n]) + set p1 [get_range $mpool 10] + set p2 [get_range $mpool 10] + set p3 [get_range $mpool 10] + set p1 [replace $mpool $p1] + set p3 [replace $mpool $p3] + set p4 [get_range $mpool 20] + set p4 [replace $mpool $p4] + set p5 [get_range $mpool 10] + set p6 [get_range $mpool 20] + set p7 [get_range $mpool 10] + set p8 [get_range $mpool 20] + set p5 [replace $mpool $p5] + set p6 [replace $mpool $p6] + set p9 [get_range $mpool 40] + set p9 [replace $mpool $p9] + set p10 [get_range $mpool 40] + set p7 [replace $mpool $p7] + set p8 [replace $mpool $p8] + set p9 [replace $mpool $p9] + set p10 [replace $mpool $p10] + } + + if { $dostat == 1 } { + puts [$env mpool_stat] + for {set i 1} {$i <= $n} {incr i} { + error_check_good mp_sync [$mpools($i) fsync] 0 + } + } + + # Close N memp files + for {set i 1} {$i <= $n} {incr i} { + error_check_good memp_close:$mpools($i) [$mpools($i) close] 0 + fileremove -f $dir/data_file.$i + } +} + +proc file_create { fname nblocks blocksize } { + set fid [open $fname w] + for {set i 0} {$i < $nblocks} {incr i} { + seek $fid [expr $i * $blocksize] start + puts -nonewline $fid $i + } + seek $fid [expr $nblocks * $blocksize - 1] + + # We don't end the file with a newline, because some platforms (like + # Windows) emit CR/NL. There does not appear to be a BINARY open flag + # that prevents this. + puts -nonewline $fid "Z" + close $fid + + # Make sure it worked + if { [file size $fname] != $nblocks * $blocksize } { + error "FAIL: file_create could not create correct file size" + } +} + +proc get_range { mpool max } { + set pno [berkdb random_int 0 $max] + set p [$mpool get $pno] + error_check_good page [is_valid_page $p $mpool] TRUE + set got [$p pgnum] + if { $got != $pno } { + puts "Get_range: Page mismatch page |$pno| val |$got|" + } + set ret [$p init "Page is pinned by [pid]"] + error_check_good page_init $ret 0 + + return $p +} + +proc replace { mpool p } { + set pgno [$p pgnum] + + set ret [$p init "Page is unpinned by [pid]"] + error_check_good page_init $ret 0 + + set ret [$p put -dirty] + error_check_good page_put $ret 0 + + set p2 [$mpool get $pgno] + error_check_good page [is_valid_page $p2 $mpool] TRUE + + return $p2 +} + +proc memp002 { dir procs psizes iterations npages seeds dostat flags } { + source ./include.tcl + + puts "Memp002: {$flags} Multiprocess mpool tester" + + if { [is_substr $flags -private] != 0 } { + puts "Memp002 skipping\ + multiple processes not supported by private memory" + return + } + set iter [expr $iterations / $procs] + + # Clean up old stuff and create new. + env_cleanup $dir + + for { set i 0 } { $i < [llength $psizes] } { incr i } { + fileremove -f $dir/file$i + } + set e [eval {berkdb env -create -lock -home $dir} $flags] + error_check_good dbenv [is_valid_widget $e env] TRUE + + set pidlist {} + for { set i 0 } { $i < $procs } {incr i} { + if { [llength $seeds] == $procs } { + set seed [lindex $seeds $i] + } else { + set seed -1 + } + + puts "$tclsh_path\ + $test_path/mpoolscript.tcl $dir $i $procs \ + $iter $psizes $npages 3 $flags > \ + $dir/memp002.$i.out &" + set p [exec $tclsh_path $test_path/wrap.tcl \ + mpoolscript.tcl $dir/memp002.$i.out $dir $i $procs \ + $iter $psizes $npages 3 $flags &] + lappend pidlist $p + } + puts "Memp002: $procs independent processes now running" + watch_procs + + reset_env $e +} + +# Test reader-only/writer process combinations; we use the access methods +# for testing. +proc memp003 { dir {nentries 10000} flags } { + global alphabet + source ./include.tcl + + puts "Memp003: {$flags} Reader/Writer tests" + + if { [is_substr $flags -private] != 0 } { + puts "Memp003 skipping\ + multiple processes not supported by private memory" + return + } + + env_cleanup $dir + set psize 1024 + set testfile mpool.db + set t1 $dir/t1 + + # Create an environment that the two processes can share + set c [list 0 [expr $psize * 10] 3] + set dbenv [eval {berkdb env \ + -create -lock -home $dir -cachesize $c} $flags] + error_check_good dbenv [is_valid_env $dbenv] TRUE + + # First open and create the file. + + set db [berkdb_open -env $dbenv -create -truncate \ + -mode 0644 -pagesize $psize -btree $testfile] + error_check_good dbopen/RW [is_valid_db $db] TRUE + + set did [open $dict] + set txn "" + set count 0 + + puts "\tMemp003.a: create database" + set keys "" + # Here is the loop where we put and get each key/data pair + while { [gets $did str] != -1 && $count < $nentries } { + lappend keys $str + + set ret [eval {$db put} $txn {$str $str}] + error_check_good put $ret 0 + + set ret [eval {$db get} $txn {$str}] + error_check_good get $ret [list [list $str $str]] + + incr count + } + close $did + error_check_good close [$db close] 0 + + # Now open the file for read-only + set db [berkdb_open -env $dbenv -rdonly $testfile] + error_check_good dbopen/RO [is_substr $db db] 1 + + puts "\tMemp003.b: verify a few keys" + # Read and verify a couple of keys; saving them to check later + set testset "" + for { set i 0 } { $i < 10 } { incr i } { + set ndx [berkdb random_int 0 [expr $nentries - 1]] + set key [lindex $keys $ndx] + if { [lsearch $testset $key] != -1 } { + incr i -1 + continue; + } + + # The remote process stuff is unhappy with + # zero-length keys; make sure we don't pick one. + if { [llength $key] == 0 } { + incr i -1 + continue + } + + lappend testset $key + + set ret [eval {$db get} $txn {$key}] + error_check_good get/RO $ret [list [list $key $key]] + } + + puts "\tMemp003.c: retrieve and modify keys in remote process" + # Now open remote process where we will open the file RW + set f1 [open |$tclsh_path r+] + puts $f1 "source $test_path/test.tcl" + puts $f1 "flush stdout" + flush $f1 + + set c [concat "{" [list 0 [expr $psize * 10] 3] "}" ] + set remote_env [send_cmd $f1 \ + "berkdb env -create -lock -home $dir -cachesize $c $flags"] + error_check_good remote_dbenv [is_valid_env $remote_env] TRUE + + set remote_db [send_cmd $f1 "berkdb_open -env $remote_env $testfile"] + error_check_good remote_dbopen [is_valid_db $remote_db] TRUE + + foreach k $testset { + # Get the key + set ret [send_cmd $f1 "$remote_db get $k"] + error_check_good remote_get $ret [list [list $k $k]] + + # Now replace the key + set ret [send_cmd $f1 "$remote_db put $k $k$k"] + error_check_good remote_put $ret 0 + } + + puts "\tMemp003.d: verify changes in local process" + foreach k $testset { + set ret [eval {$db get} $txn {$key}] + error_check_good get_verify/RO $ret [list [list $key $key$key]] + } + + puts "\tMemp003.e: Fill up the cache with dirty buffers" + foreach k $testset { + # Now rewrite the keys with BIG data + set data [replicate $alphabet 32] + set ret [send_cmd $f1 "$remote_db put $k $data"] + error_check_good remote_put $ret 0 + } + + puts "\tMemp003.f: Get more pages for the read-only file" + dump_file $db $txn $t1 nop + + puts "\tMemp003.g: Sync from the read-only file" + error_check_good db_sync [$db sync] 0 + error_check_good db_close [$db close] 0 + + set ret [send_cmd $f1 "$remote_db close"] + error_check_good remote_get $ret 0 + + # Close the environment both remotely and locally. + set ret [send_cmd $f1 "$remote_env close"] + error_check_good remote:env_close $ret 0 + close $f1 + + reset_env $dbenv +} diff --git a/db/test/mpoolscript.tcl b/db/test/mpoolscript.tcl new file mode 100644 index 000000000..8695254c2 --- /dev/null +++ b/db/test/mpoolscript.tcl @@ -0,0 +1,170 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: mpoolscript.tcl,v 11.12 2000/05/05 15:23:47 sue Exp $ +# +# Random multiple process mpool tester. +# Usage: mpoolscript dir id numiters numfiles numpages sleepint +# dir: lock directory. +# id: Unique identifier for this process. +# maxprocs: Number of procs in this test. +# numiters: Total number of iterations. +# pgsizes: Pagesizes for the different files. Length of this item indicates +# how many files to use. +# numpages: Number of pages per file. +# sleepint: Maximum sleep interval. +# flags: Flags for env open + +source ./include.tcl +source $test_path/test.tcl +source $test_path/testutils.tcl + +set usage \ + "mpoolscript dir id maxprocs numiters pgsizes numpages sleepint flags" + +# Verify usage +if { $argc != 8 } { + puts stderr "FAIL:[timestamp] Usage: $usage" + puts $argc + exit +} + +# Initialize arguments +set dir [lindex $argv 0] +set id [lindex $argv 1] +set maxprocs [lindex $argv 2] +set numiters [ lindex $argv 3 ] +set pgsizes [ lindex $argv 4 ] +set numpages [ lindex $argv 5 ] +set sleepint [ lindex $argv 6 ] +set flags [ lindex $argv 7] + +# Initialize seed +global rand_init +berkdb srand $rand_init + +# Give time for all processes to start up. +tclsleep 10 + +puts -nonewline "Beginning execution for $id: $maxprocs $dir $numiters" +puts " $pgsizes $numpages $sleepint" +flush stdout + +# Figure out how small/large to make the cache +set max 0 +foreach i $pgsizes { + if { $i > $max } { + set max $i + } +} + +set cache [list 0 [expr $maxprocs * ([lindex $pgsizes 0] + $max)] 1] +set env_cmd {berkdb env -lock -cachesize $cache -home $dir} +set e [eval $env_cmd $flags] +error_check_good env_open [is_valid_env $e] TRUE + +# Now open files +set mpools {} +set nfiles 0 +foreach psize $pgsizes { + set mp [$e mpool -create -mode 0644 -pagesize $psize file$nfiles] + error_check_good memp_fopen:$nfiles [is_valid_mpool $mp $e] TRUE + lappend mpools $mp + incr nfiles +} + +puts "Establishing long-term pin on file 0 page $id for process $id" + +# Set up the long-pin page +set lock [$e lock_get write $id 0:$id] +error_check_good lock_get [is_valid_lock $lock $e] TRUE + +set mp [lindex $mpools 0] +set master_page [$mp get -create $id] +error_check_good mp_get:$master_page [is_valid_page $master_page $mp] TRUE + +set r [$master_page init MASTER$id] +error_check_good page_init $r 0 + +# Release the lock but keep the page pinned +set r [$lock put] +error_check_good lock_put $r 0 + +# Main loop. On each iteration, we'll check every page in each of +# of the files. On any file, if we see the appropriate tag in the +# field, we'll rewrite the page, else we won't. Keep track of +# how many pages we actually process. +set pages 0 +for { set iter 0 } { $iter < $numiters } { incr iter } { + puts "[timestamp]: iteration $iter, $pages pages set so far" + flush stdout + for { set fnum 1 } { $fnum < $nfiles } { incr fnum } { + if { [expr $fnum % 2 ] == 0 } { + set pred [expr ($id + $maxprocs - 1) % $maxprocs] + } else { + set pred [expr ($id + $maxprocs + 1) % $maxprocs] + } + + set mpf [lindex $mpools $fnum] + for { set p 0 } { $p < $numpages } { incr p } { + set lock [$e lock_get write $id $fnum:$p] + error_check_good lock_get:$fnum:$p \ + [is_valid_lock $lock $e] TRUE + + # Now, get the page + set pp [$mpf get -create $p] + error_check_good page_get:$fnum:$p \ + [is_valid_page $pp $mpf] TRUE + + if { [$pp is_setto $pred] == 0 || [$pp is_setto 0] == 0 } { + # Set page to self. + set r [$pp init $id] + error_check_good page_init:$fnum:$p $r 0 + incr pages + set r [$pp put -dirty] + error_check_good page_put:$fnum:$p $r 0 + } else { + error_check_good page_put:$fnum:$p [$pp put] 0 + } + error_check_good lock_put:$fnum:$p [$lock put] 0 + } + } + tclsleep [berkdb random_int 1 $sleepint] +} + +# Now verify your master page, release its pin, then verify everyone else's +puts "$id: End of run verification of master page" +set r [$master_page is_setto MASTER$id] +error_check_good page_check $r 1 +set r [$master_page put -dirty] +error_check_good page_put $r 0 + +set i [expr ($id + 1) % $maxprocs] +set mpf [lindex $mpools 0] + +while { $i != $id } { + set p [$mpf get -create $i] + error_check_good mp_get [is_valid_page $p $mpf] TRUE + + if { [$p is_setto MASTER$i] != 1 } { + puts "Warning: Master page $i not set." + } + error_check_good page_put:$p [$p put] 0 + + set i [expr ($i + 1) % $maxprocs] +} + +# Close files +foreach i $mpools { + set r [$i close] + error_check_good mpf_close $r 0 +} + +# Close environment system +set r [$e close] +error_check_good env_close $r 0 + +puts "[timestamp] $id Complete" +flush stdout diff --git a/db/test/mutex.tcl b/db/test/mutex.tcl new file mode 100644 index 000000000..5300fb0c4 --- /dev/null +++ b/db/test/mutex.tcl @@ -0,0 +1,225 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: mutex.tcl,v 11.18 2000/09/01 19:24:59 krinsky Exp $ +# +# Exercise mutex functionality. +# Options are: +# -dir +# -iter +# -mdegree +# -nmutex +# -procs +# -wait +proc mutex_usage {} { + puts stderr "mutex\n\t-dir \n\t-iter " + puts stderr "\t-mdegree \n\t-nmutex " + puts stderr "\t-procs " + puts stderr "\n\t-wait " + return +} + +proc mutex { args } { + source ./include.tcl + + set dir db + set iter 500 + set mdegree 3 + set nmutex 20 + set procs 5 + set wait 2 + + for { set i 0 } { $i < [llength $args] } {incr i} { + switch -regexp -- [lindex $args $i] { + -d.* { incr i; set testdir [lindex $args $i] } + -i.* { incr i; set iter [lindex $args $i] } + -m.* { incr i; set mdegree [lindex $args $i] } + -n.* { incr i; set nmutex [lindex $args $i] } + -p.* { incr i; set procs [lindex $args $i] } + -w.* { incr i; set wait [lindex $args $i] } + default { + puts -nonewline "FAIL:[timestamp] Usage: " + mutex_usage + return + } + } + } + + if { [file exists $testdir/$dir] != 1 } { + file mkdir $testdir/$dir + } elseif { [file isdirectory $testdir/$dir ] != 1 } { + error "$testdir/$dir is not a directory" + } + + # Basic sanity tests + mutex001 $testdir $nmutex + + # Basic synchronization tests + mutex002 $testdir $nmutex + + # Multiprocess tests + mutex003 $testdir $iter $nmutex $procs $mdegree $wait +} + +proc mutex001 { dir nlocks } { + source ./include.tcl + + puts "Mutex001: Basic functionality" + env_cleanup $dir + + # Test open w/out create; should fail + error_check_bad \ + env_open [catch {berkdb env -lock -home $dir} env] 0 + + # Now open for real + set env [berkdb env -create -mode 0644 -lock -home $dir] + error_check_good env_open [is_valid_env $env] TRUE + + set m [$env mutex 0644 $nlocks] + error_check_good mutex_init [is_valid_mutex $m $env] TRUE + + # Get, set each mutex; sleep, then get Release + for { set i 0 } { $i < $nlocks } { incr i } { + set r [$m get $i ] + error_check_good mutex_get $r 0 + + set r [$m setval $i $i] + error_check_good mutex_setval $r 0 + } + tclsleep 5 + for { set i 0 } { $i < $nlocks } { incr i } { + set r [$m getval $i] + error_check_good mutex_getval $r $i + + set r [$m release $i ] + error_check_good mutex_get $r 0 + } + + error_check_good mutex_close [$m close] 0 + error_check_good env_close [$env close] 0 + puts "Mutex001: completed successfully." +} + +# Test basic synchronization +proc mutex002 { dir nlocks } { + source ./include.tcl + + puts "Mutex002: Basic synchronization" + env_cleanup $dir + + # Fork off child before we open any files. + set f1 [open |$tclsh_path r+] + puts $f1 "source $test_path/test.tcl" + flush $f1 + + # Open the environment and the mutex locally + set local_env [berkdb env -create -mode 0644 -lock -home $dir] + error_check_good env_open [is_valid_env $local_env] TRUE + + set local_mutex [$local_env mutex 0644 $nlocks] + error_check_good \ + mutex_init [is_valid_mutex $local_mutex $local_env] TRUE + + # Open the environment and the mutex remotely + set remote_env [send_cmd $f1 "berkdb env -lock -home $dir"] + error_check_good remote:env_open [is_valid_env $remote_env] TRUE + + set remote_mutex [send_cmd $f1 "$remote_env mutex 0644 $nlocks"] + error_check_good \ + mutex_init [is_valid_mutex $remote_mutex $remote_env] TRUE + + # Do a get here, then set the value to be pid. + # On the remote side fire off a get and getval. + set r [$local_mutex get 1] + error_check_good lock_get $r 0 + + set r [$local_mutex setval 1 [pid]] + error_check_good lock_get $r 0 + + # Now have the remote side request the lock and check its + # value. Then wait 5 seconds, release the mutex and see + # what the remote side returned. + send_timed_cmd $f1 1 "$remote_mutex get 1" + send_timed_cmd $f1 1 "set ret \[$remote_mutex getval 1\]" + + # Now sleep before resetting and releasing lock + tclsleep 5 + set newv [expr [pid] - 1] + set r [$local_mutex setval 1 $newv] + error_check_good mutex_setval $r 0 + + set r [$local_mutex release 1] + error_check_good mutex_release $r 0 + + # Now get the result from the other script + # Timestamp + set result [rcv_result $f1] + error_check_good lock_get:remote_time [expr $result > 4] 1 + + # Timestamp + set result [rcv_result $f1] + + # Mutex value + set result [send_cmd $f1 "puts \$ret"] + error_check_good lock_get:remote_getval $result $newv + + # Close down the remote + set ret [send_cmd $f1 "$remote_mutex close" 5] + # Not sure why we need this, but we do... an extra blank line + # someone gets output somewhere + gets $f1 ret + error_check_good remote:mutex_close $ret 0 + + set ret [send_cmd $f1 "$remote_env close"] + error_check_good remote:env_close $ret 0 + + catch { close $f1 } result + + set ret [$local_mutex close] + error_check_good local:mutex_close $ret 0 + + set ret [$local_env close] + error_check_good local:env_close $ret 0 + + puts "Mutex002: completed successfully." +} + +# Generate a bunch of parallel +# testers that try to randomly obtain locks. +proc mutex003 { dir iter nmutex procs mdegree wait } { + source ./include.tcl + + puts "Mutex003: Multi-process random mutex test ($procs processes)" + + env_cleanup $dir + + # Now open the region we'll use for multiprocess testing. + set env [berkdb env -create -mode 0644 -lock -home $dir] + error_check_good env_open [is_valid_env $env] TRUE + + set mutex [$env mutex 0644 $nmutex] + error_check_good mutex_init [is_valid_mutex $mutex $env] TRUE + + error_check_good mutex_close [$mutex close] 0 + + # Now spawn off processes + set proclist {} + for { set i 0 } {$i < $procs} {incr i} { + puts "$tclsh_path\ + $test_path/mutexscript.tcl $dir\ + $iter $nmutex $wait $mdegree > $testdir/$i.mutexout &" + set p [exec $tclsh_path $test_path/wrap.tcl \ + mutexscript.tcl $testdir/$i.mutexout $dir\ + $iter $nmutex $wait $mdegree &] + lappend proclist $p + } + puts "Mutex003: $procs independent processes now running" + watch_procs + error_check_good env_close [$env close] 0 + # Remove output files + for { set i 0 } {$i < $procs} {incr i} { + fileremove -f $dir/$i.mutexout + } +} diff --git a/db/test/mutexscript.tcl b/db/test/mutexscript.tcl new file mode 100644 index 000000000..9a49e4711 --- /dev/null +++ b/db/test/mutexscript.tcl @@ -0,0 +1,91 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: mutexscript.tcl,v 11.12 2000/11/21 22:14:56 dda Exp $ +# +# Random mutex tester. +# Usage: mutexscript dir numiters mlocks sleepint degree +# dir: dir in which all the mutexes live. +# numiters: Total number of iterations. +# nmutex: Total number of mutexes. +# sleepint: Maximum sleep interval. +# degree: Maximum number of locks to acquire at once + +source ./include.tcl +source $test_path/test.tcl +source $test_path/testutils.tcl + +set usage "mutexscript dir numiters nmutex sleepint degree" + +# Verify usage +if { $argc != 5 } { + puts stderr "FAIL:[timestamp] Usage: $usage" + exit +} + +# Initialize arguments +set dir [lindex $argv 0] +set numiters [ lindex $argv 1 ] +set nmutex [ lindex $argv 2 ] +set sleepint [ lindex $argv 3 ] +set degree [ lindex $argv 4 ] +set locker [pid] +set mypid [sanitized_pid] + +# Initialize seed +global rand_init +berkdb srand $rand_init + +puts -nonewline "Mutexscript: Beginning execution for $locker:" +puts " $numiters $nmutex $sleepint $degree" +flush stdout + +# Open the environment and the mutex +set e [berkdb env -create -mode 0644 -lock -home $dir] +error_check_good evn_open [is_valid_env $e] TRUE + +set mutex [$e mutex 0644 $nmutex] +error_check_good mutex_init [is_valid_mutex $mutex $e] TRUE + +# Sleep for awhile to make sure that everyone has gotten in +tclsleep 5 + +for { set iter 0 } { $iter < $numiters } { incr iter } { + set nlocks [berkdb random_int 1 $degree] + # We will always lock objects in ascending order to avoid + # deadlocks. + set lastobj 1 + set mlist {} + for { set lnum 0 } { $lnum < $nlocks } { incr lnum } { + # Pick lock parameters + set obj [berkdb random_int $lastobj [expr $nmutex - 1]] + set lastobj [expr $obj + 1] + puts "[timestamp] $locker $lnum: $obj" + + # Do get, set its val to own pid, and then add to list + error_check_good mutex_get:$obj [$mutex get $obj] 0 + error_check_good mutex_setval:$obj [$mutex setval $obj $mypid] 0 + lappend mlist $obj + if {$lastobj >= $nmutex} { + break + } + } + + # Pick sleep interval + tclsleep [ berkdb random_int 1 $sleepint ] + + # Now release locks + foreach i $mlist { + error_check_good mutex_getval:$i [$mutex getval $i] $mypid + error_check_good mutex_setval:$i \ + [$mutex setval $i [expr 0 - $mypid]] 0 + error_check_good mutex_release:$i [$mutex release $i] 0 + } + puts "[timestamp] $locker released mutexes" + flush stdout +} + +puts "[timestamp] $locker Complete" +flush stdout diff --git a/db/test/ndbm.tcl b/db/test/ndbm.tcl new file mode 100644 index 000000000..a6286de02 --- /dev/null +++ b/db/test/ndbm.tcl @@ -0,0 +1,141 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: ndbm.tcl,v 11.13 2000/08/25 14:21:51 sue Exp $ +# +# Historic NDBM interface test. +# Use the first 1000 entries from the dictionary. +# Insert each with self as key and data; retrieve each. +# After all are entered, retrieve all; compare output to original. +# Then reopen the file, re-retrieve everything. +# Finally, delete everything. +proc ndbm { { nentries 1000 } } { + source ./include.tcl + + puts "NDBM interfaces test: $nentries" + + # Create the database and open the dictionary + set testfile $testdir/ndbmtest + set t1 $testdir/t1 + set t2 $testdir/t2 + set t3 $testdir/t3 + cleanup $testdir NULL + + set db [berkdb ndbm_open -create -truncate -mode 0644 $testfile] + error_check_good ndbm_open [is_substr $db ndbm] 1 + set did [open $dict] + + error_check_good rdonly_false [$db rdonly] 0 + + set flags 0 + set txn 0 + set count 0 + set skippednullkey 0 + + puts "\tNDBM.a: put/get loop" + # Here is the loop where we put and get each key/data pair + while { [gets $did str] != -1 && $count < $nentries } { + # NDBM can't handle zero-length keys + if { [string length $str] == 0 } { + set skippednullkey 1 + continue + } + + set ret [$db store $str $str insert] + error_check_good ndbm_store $ret 0 + + set d [$db fetch $str] + error_check_good ndbm_fetch $d $str + incr count + } + close $did + + # Now we will get each key from the DB and compare the results + # to the original. + puts "\tNDBM.b: dump file" + set oid [open $t1 w] + for { set key [$db firstkey] } { $key != -1 } { + set key [$db nextkey] } { + puts $oid $key + set d [$db fetch $key] + error_check_good ndbm_refetch $d $key + } + + # If we had to skip a zero-length key, juggle things to cover up + # this fact in the dump. + if { $skippednullkey == 1 } { + puts $oid "" + incr nentries 1 + } + close $oid + + # Now compare the keys to see if they match the dictionary (or ints) + set q q + filehead $nentries $dict $t3 + filesort $t3 $t2 + filesort $t1 $t3 + + error_check_good NDBM:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 + + puts "\tNDBM.c: pagf/dirf test" + set fd [$db pagfno] + error_check_bad pagf $fd -1 + set fd [$db dirfno] + error_check_bad dirf $fd -1 + + puts "\tNDBM.d: close, open, and dump file" + + # Now, reopen the file and run the last test again. + error_check_good ndbm_close [$db close] 0 + set db [berkdb ndbm_open -rdonly $testfile] + error_check_good ndbm_open2 [is_substr $db ndbm] 1 + set oid [open $t1 w] + + error_check_good rdonly_true [$db rdonly] "rdonly:not owner" + + for { set key [$db firstkey] } { $key != -1 } { + set key [$db nextkey] } { + puts $oid $key + set d [$db fetch $key] + error_check_good ndbm_refetch2 $d $key + } + if { $skippednullkey == 1 } { + puts $oid "" + } + close $oid + + # Now compare the keys to see if they match the dictionary (or ints) + filesort $t1 $t3 + + error_check_good NDBM:diff($t2,$t3) \ + [filecmp $t2 $t3] 0 + + # Now, reopen the file and delete each entry + puts "\tNDBM.e: sequential scan and delete" + + error_check_good ndbm_close [$db close] 0 + set db [berkdb ndbm_open $testfile] + error_check_good ndbm_open3 [is_substr $db ndbm] 1 + set oid [open $t1 w] + + for { set key [$db firstkey] } { $key != -1 } { + set key [$db nextkey] } { + puts $oid $key + set ret [$db delete $key] + error_check_good ndbm_delete $ret 0 + } + if { $skippednullkey == 1 } { + puts $oid "" + } + close $oid + + # Now compare the keys to see if they match the dictionary (or ints) + filesort $t1 $t3 + + error_check_good NDBM:diff($t2,$t3) \ + [filecmp $t2 $t3] 0 + error_check_good ndbm_close [$db close] 0 +} diff --git a/db/test/recd001.tcl b/db/test/recd001.tcl new file mode 100644 index 000000000..bbf515901 --- /dev/null +++ b/db/test/recd001.tcl @@ -0,0 +1,180 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: recd001.tcl,v 11.28 2000/12/07 19:13:46 sue Exp $ +# +# Recovery Test 1. +# These are the most basic recovery tests. We do individual recovery +# tests for each operation in the access method interface. First we +# create a file and capture the state of the database (i.e., we copy +# it. Then we run a transaction containing a single operation. In +# one test, we abort the transaction and compare the outcome to the +# original copy of the file. In the second test, we restore the +# original copy of the database and then run recovery and compare +# this against the actual database. +proc recd001 { method {select 0} args} { + global fixed_len + source ./include.tcl + + set orig_fixed_len $fixed_len + set opts [convert_args $method $args] + set omethod [convert_method $method] + + puts "Recd001: $method operation/transaction tests" + + # Create the database and environment. + env_cleanup $testdir + + # The recovery tests were originally written to + # do a command, abort, do it again, commit, and then + # repeat the sequence with another command. Each command + # tends to require that the previous command succeeded and + # left the database a certain way. To avoid cluttering up the + # op_recover interface as well as the test code, we create two + # databases; one does abort and then commit for each op, the + # other does prepare, prepare-abort, and prepare-commit for each + # op. If all goes well, this allows each command to depend + # exactly one successful iteration of the previous command. + set testfile recd001.db + set testfile2 recd001-2.db + + set flags "-create -txn -home $testdir" + + puts "\tRecd001.a.0: creating environment" + set env_cmd "berkdb env $flags" + set dbenv [eval $env_cmd] + error_check_good dbenv [is_valid_env $dbenv] TRUE + + # + # We need to create a database to get the pagesize (either + # the default or whatever might have been specified). + # Then remove it so we can compute fixed_len and create the + # real database. + set oflags "-create $omethod -mode 0644 \ + -env $dbenv $opts $testfile" + set db [eval {berkdb_open} $oflags] + error_check_good db_open [is_valid_db $db] TRUE + set stat [$db stat] + # + # Compute the fixed_len based on the pagesize being used. + # We want the fixed_len to be 1/4 the pagesize. + # + set pg [get_pagesize $stat] + error_check_bad get_pagesize $pg -1 + set fixed_len [expr $pg / 4] + error_check_good db_close [$db close] 0 + error_check_good dbremove [berkdb dbremove -env $dbenv $testfile] 0 + + # Convert the args again because fixed_len is now real. + # Create the databases and close the environment. + # cannot specify db truncate in txn protected env!!! + set opts [convert_args $method ""] + set omethod [convert_method $method] + set oflags "-create $omethod -mode 0644 \ + -env $dbenv $opts $testfile" + set db [eval {berkdb_open} $oflags] + error_check_good db_open [is_valid_db $db] TRUE + error_check_good db_close [$db close] 0 + + set oflags "-create $omethod -mode 0644 \ + -env $dbenv $opts $testfile2" + set db [eval {berkdb_open} $oflags] + error_check_good db_open [is_valid_db $db] TRUE + error_check_good db_close [$db close] 0 + + error_check_good env_close [$dbenv close] 0 + + puts "\tRecd001.a.1: Verify db_printlog can read logfile" + set tmpfile $testdir/printlog.out + set stat [catch {exec $util_path/db_printlog -h $testdir \ + > $tmpfile} ret] + error_check_good db_printlog $stat 0 + fileremove $tmpfile + + # List of recovery tests: {CMD MSG} pairs. + set rlist { + { {DB put -txn TXNID $key $data} "Recd001.b: put"} + { {DB del -txn TXNID $key} "Recd001.c: delete"} + { {DB put -txn TXNID $bigkey $data} "Recd001.d: big key put"} + { {DB del -txn TXNID $bigkey} "Recd001.e: big key delete"} + { {DB put -txn TXNID $key $bigdata} "Recd001.f: big data put"} + { {DB del -txn TXNID $key} "Recd001.g: big data delete"} + { {DB put -txn TXNID $key $data} "Recd001.h: put (change state)"} + { {DB put -txn TXNID $key $newdata} "Recd001.i: overwrite"} + { {DB put -txn TXNID -partial {$off $len} $key $partial_grow} + "Recd001.j: partial put growing"} + { {DB put -txn TXNID $key $newdata} "Recd001.k: overwrite (fix)"} + { {DB put -txn TXNID -partial {$off $len} $key $partial_shrink} + "Recd001.l: partial put shrinking"} + { {DB put -txn TXNID -append $data} "Recd001.m: put -append"} + { {DB get -txn TXNID -consume} "Recd001.n: db get -consume"} + } + + # These are all the data values that we're going to need to read + # through the operation table and run the recovery tests. + + if { [is_record_based $method] == 1 } { + set key 1 + } else { + set key recd001_key + } + set data recd001_data + set newdata NEWrecd001_dataNEW + set off 3 + set len 12 + set partial_grow replacement_record_grow + set partial_shrink xxx + if { [is_fixed_length $method] == 1 } { + set len [string length $partial_grow] + set partial_shrink $partial_grow + } + set bigdata [replicate $key $fixed_len] + if { [is_record_based $method] == 1 } { + set bigkey $fixed_len + } else { + set bigkey [replicate $key $fixed_len] + } + + foreach pair $rlist { + set cmd [subst [lindex $pair 0]] + set msg [lindex $pair 1] + if { $select != 0 } { + set tag [lindex $msg 0] + set tail [expr [string length $tag] - 2] + set tag [string range $tag $tail $tail] + if { [lsearch $select $tag] == -1 } { + continue + } + } + + if { [is_queue $method] != 1 } { + if { [string first append $cmd] != -1 } { + continue + } + if { [string first consume $cmd] != -1 } { + continue + } + } + +# if { [is_fixed_length $method] == 1 } { +# if { [string first partial $cmd] != -1 } { +# continue +# } +# } + op_recover abort $testdir $env_cmd $testfile $cmd $msg + op_recover commit $testdir $env_cmd $testfile $cmd $msg + op_recover prepare $testdir $env_cmd $testfile2 $cmd $msg + op_recover prepare-abort $testdir $env_cmd $testfile2 $cmd $msg + op_recover prepare-commit $testdir $env_cmd $testfile2 $cmd $msg + } + set fixed_len $orig_fixed_len + + puts "\tRecd001.o: Verify db_printlog can read logfile" + set tmpfile $testdir/printlog.out + set stat [catch {exec $util_path/db_printlog -h $testdir \ + > $tmpfile} ret] + error_check_good db_printlog $stat 0 + fileremove $tmpfile +} diff --git a/db/test/recd002.tcl b/db/test/recd002.tcl new file mode 100644 index 000000000..ffcec6527 --- /dev/null +++ b/db/test/recd002.tcl @@ -0,0 +1,96 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: recd002.tcl,v 11.22 2000/12/11 17:24:54 sue Exp $ +# +# Recovery Test #2. Verify that splits can be recovered. +proc recd002 { method {select 0} args} { + source ./include.tcl + global rand_init + + set args [convert_args $method $args] + set omethod [convert_method $method] + + set pgindex [lsearch -exact $args "-pagesize"] + if { $pgindex != -1 } { + puts "Recd002: skipping for specific pagesizes" + return + } + berkdb srand $rand_init + + # Queues don't do splits, so we don't really need the small page + # size and the small page size is smaller than the record, so it's + # a problem. + if { [string compare $omethod "-queue"] == 0 } { + set pagesize 4096 + } else { + set pagesize 512 + } + puts "Recd002: $method split recovery tests" + + env_cleanup $testdir + set testfile recd002.db + set testfile2 recd002-2.db + set eflags \ + "-create -txn -lock_max 2000 -home $testdir" + + puts "\tRecd002.a: creating environment" + set env_cmd "berkdb env $eflags" + set dbenv [eval $env_cmd] + error_check_bad dbenv $dbenv NULL + + # Create the databases. We will use a small page size so that splits + # happen fairly quickly. + set oflags "-create $args $omethod -mode 0644 -env $dbenv\ + -pagesize $pagesize $testfile" + set db [eval {berkdb_open} $oflags] + error_check_bad db_open $db NULL + error_check_good db_open [is_substr $db db] 1 + error_check_good db_close [$db close] 0 + set oflags "-create $args $omethod -mode 0644 -env $dbenv\ + -pagesize $pagesize $testfile2" + set db [eval {berkdb_open} $oflags] + error_check_bad db_open $db NULL + error_check_good db_open [is_substr $db db] 1 + error_check_good db_close [$db close] 0 + reset_env $dbenv + + # List of recovery tests: {CMD MSG} pairs + set slist { + { {populate DB $omethod TXNID $n 0 0} "Recd002.b: splits"} + { {unpopulate DB TXNID $r} "Recd002.c: Remove keys"} + } + + # If pages are 512 bytes, then adding 512 key/data pairs + # should be more than sufficient. + set n 512 + set r [expr $n / 2 ] + foreach pair $slist { + set cmd [subst [lindex $pair 0]] + set msg [lindex $pair 1] + if { $select != 0 } { + set tag [lindex $msg 0] + set tail [expr [string length $tag] - 2] + set tag [string range $tag $tail $tail] + if { [lsearch $select $tag] == -1 } { + continue + } + } + op_recover abort $testdir $env_cmd $testfile $cmd $msg + op_recover commit $testdir $env_cmd $testfile $cmd $msg + op_recover prepare $testdir $env_cmd $testfile2 $cmd $msg + op_recover prepare-abort $testdir $env_cmd $testfile2 \ + $cmd $msg + op_recover prepare-commit $testdir $env_cmd $testfile2 \ + $cmd $msg + } + + puts "\tRecd002.d: Verify db_printlog can read logfile" + set tmpfile $testdir/printlog.out + set stat [catch {exec $util_path/db_printlog -h $testdir \ + > $tmpfile} ret] + error_check_good db_printlog $stat 0 + fileremove $tmpfile +} diff --git a/db/test/recd003.tcl b/db/test/recd003.tcl new file mode 100644 index 000000000..af7097c89 --- /dev/null +++ b/db/test/recd003.tcl @@ -0,0 +1,111 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: recd003.tcl,v 11.22 2000/12/07 19:13:46 sue Exp $ +# +# Recovery Test 3. +# Test all the duplicate log messages and recovery operations. We make +# sure that we exercise all possible recovery actions: redo, undo, undo +# but no fix necessary and redo but no fix necessary. +proc recd003 { method {select 0} args } { + source ./include.tcl + global rand_init + + set largs [convert_args $method $args] + set omethod [convert_method $method] + + if { [is_record_based $method] == 1 || [is_rbtree $method] == 1 } { + puts "Recd003 skipping for method $method" + return + } + puts "Recd003: $method duplicate recovery tests" + + berkdb srand $rand_init + + env_cleanup $testdir + # See comment in recd001.tcl for why there are two database files... + set testfile recd003.db + set testfile2 recd003-2.db + set eflags "-create -txn -home $testdir" + + puts "\tRecd003.a: creating environment" + set env_cmd "berkdb env $eflags" + set dbenv [eval $env_cmd] + error_check_bad dbenv $dbenv NULL + + # Create the databases. + set oflags \ + "-create $largs -mode 0644 $omethod -dup -env $dbenv $testfile" + set db [eval {berkdb_open} $oflags] + error_check_bad db_open $db NULL + error_check_good db_open [is_substr $db db] 1 + error_check_good db_close [$db close] 0 + set oflags \ + "-create $largs -mode 0644 $omethod -dup -env $dbenv $testfile2" + set db [eval {berkdb_open} $oflags] + error_check_bad db_open $db NULL + error_check_good db_open [is_substr $db db] 1 + error_check_good db_close [$db close] 0 + reset_env $dbenv + + # These are all the data values that we're going to need to read + # through the operation table and run the recovery tests. + set n 10 + set dupn 2000 + set bign 500 + + # List of recovery tests: {CMD MSG} pairs + set dlist { + { {populate DB $omethod TXNID $n 1 0} + "Recd003.b: add dups"} + { {DB del -txn TXNID duplicate_key} + "Recd003.c: remove dups all at once"} + { {populate DB $omethod TXNID $n 1 0} + "Recd003.d: add dups (change state)"} + { {unpopulate DB TXNID 0} + "Recd003.e: remove dups 1 at a time"} + { {populate DB $omethod TXNID $dupn 1 0} + "Recd003.f: dup split"} + { {DB del -txn TXNID duplicate_key} + "Recd003.g: remove dups (change state)"} + { {populate DB $omethod TXNID $n 1 1} + "Recd003.h: add big dup"} + { {DB del -txn TXNID duplicate_key} + "Recd003.i: remove big dup all at once"} + { {populate DB $omethod TXNID $n 1 1} + "Recd003.j: add big dup (change state)"} + { {unpopulate DB TXNID 0} + "Recd003.k: remove big dup 1 at a time"} + { {populate DB $omethod TXNID $bign 1 1} + "Recd003.l: split big dup"} + } + + foreach pair $dlist { + set cmd [subst [lindex $pair 0]] + set msg [lindex $pair 1] + if { $select != 0 } { + set tag [lindex $msg 0] + set tail [expr [string length $tag] - 2] + set tag [string range $tag $tail $tail] + if { [lsearch $select $tag] == -1 } { + continue + } + } + op_recover abort $testdir $env_cmd $testfile $cmd $msg + op_recover commit $testdir $env_cmd $testfile $cmd $msg + op_recover prepare $testdir $env_cmd $testfile2 $cmd $msg + op_recover prepare-abort $testdir $env_cmd $testfile2 \ + $cmd $msg + op_recover prepare-commit $testdir $env_cmd $testfile2 \ + $cmd $msg + } + + puts "\tRecd003.m: Verify db_printlog can read logfile" + set tmpfile $testdir/printlog.out + set stat [catch {exec $util_path/db_printlog -h $testdir \ + > $tmpfile} ret] + error_check_good db_printlog $stat 0 + fileremove $tmpfile +} diff --git a/db/test/recd004.tcl b/db/test/recd004.tcl new file mode 100644 index 000000000..012dd80f6 --- /dev/null +++ b/db/test/recd004.tcl @@ -0,0 +1,90 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: recd004.tcl,v 11.21 2000/12/11 17:24:55 sue Exp $ +# +# Recovery Test #4. +# Verify that we work correctly when big keys get elevated. +proc recd004 { method {select 0} args} { + source ./include.tcl + global rand_init + + set opts [convert_args $method $args] + set omethod [convert_method $method] + + set pgindex [lsearch -exact $args "-pagesize"] + if { $pgindex != -1 } { + puts "Recd004: skipping for specific pagesizes" + return + } + if { [is_record_based $method] == 1 } { + puts "Recd004 skipping for method $method" + return + } + puts "Recd004: $method big-key on internal page recovery tests" + + berkdb srand $rand_init + + env_cleanup $testdir + set testfile recd004.db + set testfile2 recd004-2.db + set eflags "-create -txn -home $testdir" + puts "\tRecd004.a: creating environment" + set env_cmd "berkdb env $eflags" + set dbenv [eval $env_cmd] + error_check_bad dbenv $dbenv NULL + + # Create the databases. We will use a small page size so that we + # elevate quickly + set oflags "-create -mode 0644 \ + $omethod -env $dbenv $opts -pagesize 512 $testfile" + set db [eval {berkdb_open} $oflags] + error_check_bad db_open $db NULL + error_check_good db_open [is_substr $db db] 1 + error_check_good db_close [$db close] 0 + set oflags "-create -mode 0644 \ + $omethod -env $dbenv $opts -pagesize 512 $testfile2" + set db [eval {berkdb_open} $oflags] + error_check_bad db_open $db NULL + error_check_good db_open [is_substr $db db] 1 + error_check_good db_close [$db close] 0 + reset_env $dbenv + + # List of recovery tests: {CMD MSG} pairs + set slist { + { {big_populate DB TXNID $n} "Recd004.b: big key elevation"} + { {unpopulate DB TXNID 0} "Recd004.c: Remove keys"} + } + + # If pages are 512 bytes, then adding 512 key/data pairs + # should be more than sufficient. + set n 512 + foreach pair $slist { + set cmd [subst [lindex $pair 0]] + set msg [lindex $pair 1] + if { $select != 0 } { + set tag [lindex $msg 0] + set tail [expr [string length $tag] - 2] + set tag [string range $tag $tail $tail] + if { [lsearch $select $tag] == -1 } { + continue + } + } + op_recover abort $testdir $env_cmd $testfile $cmd $msg + op_recover commit $testdir $env_cmd $testfile $cmd $msg + op_recover prepare $testdir $env_cmd $testfile2 $cmd $msg + op_recover prepare-abort $testdir $env_cmd $testfile2 \ + $cmd $msg + op_recover prepare-commit $testdir $env_cmd $testfile2 \ + $cmd $msg + } + + puts "\tRecd004.d: Verify db_printlog can read logfile" + set tmpfile $testdir/printlog.out + set stat [catch {exec $util_path/db_printlog -h $testdir \ + > $tmpfile} ret] + error_check_good db_printlog $stat 0 + fileremove $tmpfile +} diff --git a/db/test/recd005.tcl b/db/test/recd005.tcl new file mode 100644 index 000000000..06a346f44 --- /dev/null +++ b/db/test/recd005.tcl @@ -0,0 +1,231 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: recd005.tcl,v 11.27 2000/12/15 21:41:38 ubell Exp $ +# +# Recovery Test 5. +# Make sure that we can do catastrophic recovery even if we open +# files using the same log file id. +proc recd005 { method args} { + source ./include.tcl + global rand_init + + set args [convert_args $method $args] + set omethod [convert_method $method] + + puts "Recd005: $method catastropic recovery" + + berkdb srand $rand_init + + set testfile1 recd005.1.db + set testfile2 recd005.2.db + set eflags \ + "-create -txn -lock_max 2000 -lock_max_objects 2000 -home $testdir" + + set tnum 0 + foreach sizes "{1000 10} {10 1000}" { + foreach ops "{abort abort} {abort commit} {commit abort} \ + {commit commit}" { + env_cleanup $testdir + incr tnum + + set s1 [lindex $sizes 0] + set s2 [lindex $sizes 1] + set op1 [lindex $ops 0] + set op2 [lindex $ops 1] + puts "\tRecd005.$tnum: $s1 $s2 $op1 $op2" + + puts "\tRecd005.$tnum.a: creating environment" + set env_cmd "berkdb env $eflags" + set dbenv [eval $env_cmd] + error_check_bad dbenv $dbenv NULL + + # Create the two databases. + set oflags \ + "-create -mode 0644 -env $dbenv $args $omethod" + set db1 [eval {berkdb_open} $oflags $testfile1] + error_check_bad db_open $db1 NULL + error_check_good db_open [is_substr $db1 db] 1 + error_check_good db_close [$db1 close] 0 + + set db2 [eval {berkdb_open} $oflags $testfile2] + error_check_bad db_open $db2 NULL + error_check_good db_open [is_substr $db2 db] 1 + error_check_good db_close [$db2 close] 0 + $dbenv close + + set dbenv [eval $env_cmd] + puts "\tRecd005.$tnum.b: Populating databases" + do_one_file \ + $testdir $method $dbenv $env_cmd $testfile1 $s1 $op1 + do_one_file \ + $testdir $method $dbenv $env_cmd $testfile2 $s2 $op2 + + puts "\tRecd005.$tnum.c: Verifying initial population" + check_file $testdir $env_cmd $testfile1 $op1 + check_file $testdir $env_cmd $testfile2 $op2 + + # Now, close the environment (so that recovery will work + # on NT which won't allow delete of an open file). + reset_env $dbenv + + berkdb debug_check + puts -nonewline \ + "\tRecd005.$tnum.d: About to run recovery ... " + flush stdout + + set stat [catch \ + {exec $util_path/db_recover -h $testdir -c} \ + result] + if { $stat == 1 } { + error "Recovery error: $result." + } + puts "complete" + + # Substitute a file that will need recovery and try + # running recovery again. + if { $op1 == "abort" } { + file copy -force $testdir/$testfile1.afterop \ + $testdir/$testfile1 + move_file_extent $testdir $testfile1 \ + afterop copy + } else { + file copy -force $testdir/$testfile1.init \ + $testdir/$testfile1 + move_file_extent $testdir $testfile1 init copy + } + if { $op2 == "abort" } { + file copy -force $testdir/$testfile2.afterop \ + $testdir/$testfile2 + move_file_extent $testdir $testfile2 \ + afterop copy + } else { + file copy -force $testdir/$testfile2.init \ + $testdir/$testfile2 + move_file_extent $testdir $testfile2 init copy + } + + berkdb debug_check + puts -nonewline "\tRecd005.$tnum.e:\ + About to run recovery on pre-op database ... " + flush stdout + + set stat \ + [catch {exec $util_path/db_recover \ + -h $testdir -c} result] + if { $stat == 1 } { + error "Recovery error: $result." + } + puts "complete" + + set dbenv [eval $env_cmd] + check_file $testdir $env_cmd $testfile1 $op1 + check_file $testdir $env_cmd $testfile2 $op2 + reset_env $dbenv + + puts "\tRecd005.$tnum.f:\ + Verify db_printlog can read logfile" + set tmpfile $testdir/printlog.out + set stat [catch \ + {exec $util_path/db_printlog -h $testdir \ + > $tmpfile} ret] + error_check_good db_printlog $stat 0 + fileremove $tmpfile + } + } +} + +proc do_one_file { dir method env env_cmd filename num op } { + source ./include.tcl + + set init_file $dir/$filename.t1 + set afterop_file $dir/$filename.t2 + set final_file $dir/$filename.t3 + + # Save the initial file and open the environment and the first file + file copy -force $dir/$filename $dir/$filename.init + copy_extent_file $dir $filename init + set oflags "-unknown -env $env" + set db [eval {berkdb_open} $oflags $filename] + + # Dump out file contents for initial case + set tflags "" + open_and_dump_file $filename $env $tflags $init_file nop \ + dump_file_direction "-first" "-next" + + set txn [$env txn] + error_check_bad txn_begin $txn NULL + error_check_good txn_begin [is_substr $txn $env] 1 + + # Now fill in the db and the txnid in the command + populate $db $method $txn $num 0 0 + + # Sync the file so that we can capture a snapshot to test + # recovery. + error_check_good sync:$db [$db sync] 0 + file copy -force $dir/$filename $dir/$filename.afterop + copy_extent_file $dir $filename afterop + open_and_dump_file $testdir/$filename.afterop NULL $tflags \ + $afterop_file nop dump_file_direction "-first" "-next" + error_check_good txn_$op:$txn [$txn $op] 0 + + if { $op == "commit" } { + puts "\t\tFile $filename executed and committed." + } else { + puts "\t\tFile $filename executed and aborted." + } + + # Dump out file and save a copy. + error_check_good sync:$db [$db sync] 0 + open_and_dump_file $testdir/$filename NULL $tflags $final_file nop \ + dump_file_direction "-first" "-next" + file copy -force $dir/$filename $dir/$filename.final + copy_extent_file $dir $filename final + + # If this is an abort, it should match the original file. + # If this was a commit, then this file should match the + # afterop file. + if { $op == "abort" } { + filesort $init_file $init_file.sort + filesort $final_file $final_file.sort + error_check_good \ + diff(initial,post-$op):diff($init_file,$final_file) \ + [filecmp $init_file.sort $final_file.sort] 0 + } else { + filesort $afterop_file $afterop_file.sort + filesort $final_file $final_file.sort + error_check_good \ + diff(post-$op,pre-commit):diff($afterop_file,$final_file) \ + [filecmp $afterop_file.sort $final_file.sort] 0 + } + + error_check_good close:$db [$db close] 0 +} + +proc check_file { dir env_cmd filename op } { + source ./include.tcl + + set init_file $dir/$filename.t1 + set afterop_file $dir/$filename.t2 + set final_file $dir/$filename.t3 + + set tflags "" + open_and_dump_file $testdir/$filename NULL $tflags $final_file nop \ + dump_file_direction "-first" "-next" + if { $op == "abort" } { + filesort $init_file $init_file.sort + filesort $final_file $final_file.sort + error_check_good \ + diff(initial,post-$op):diff($init_file,$final_file) \ + [filecmp $init_file.sort $final_file.sort] 0 + } else { + filesort $afterop_file $afterop_file.sort + filesort $final_file $final_file.sort + error_check_good \ + diff(pre-commit,post-$op):diff($afterop_file,$final_file) \ + [filecmp $afterop_file.sort $final_file.sort] 0 + } + +} diff --git a/db/test/recd006.tcl b/db/test/recd006.tcl new file mode 100644 index 000000000..14f01cc0b --- /dev/null +++ b/db/test/recd006.tcl @@ -0,0 +1,262 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: recd006.tcl,v 11.21 2000/12/07 19:13:46 sue Exp $ +# +# Recovery Test 6. +# Test nested transactions. +proc recd006 { method {select 0} args} { + global kvals + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + + if { [is_record_based $method] == 1 || [is_rbtree $method] == 1 } { + puts "Recd006 skipping for method $method" + return + } + puts "Recd006: $method nested transactions" + + # Create the database and environment. + env_cleanup $testdir + + set dbfile recd006.db + set testfile $testdir/$dbfile + + puts "\tRecd006.a: create database" + set oflags "-create $args $omethod $testfile" + set db [eval {berkdb_open} $oflags] + error_check_good dbopen [is_valid_db $db] TRUE + + # Make sure that we have enough entries to span a couple of + # different pages. + set did [open $dict] + set count 0 + while { [gets $did str] != -1 && $count < 1000 } { + if { [string compare $omethod "-recno"] == 0 } { + set key [expr $count + 1] + } else { + set key $str + } + + set ret [$db put -nooverwrite $key $str] + error_check_good put $ret 0 + + incr count + } + close $did + + # Variables used below: + # p1: a pair of keys that are likely to be on the same page. + # p2: a pair of keys that are likely to be on the same page, + # but on a page different than those in p1. + set dbc [$db cursor] + error_check_good dbc [is_substr $dbc $db] 1 + + set ret [$dbc get -first] + error_check_bad dbc_get:DB_FIRST [llength $ret] 0 + set p1 [lindex [lindex $ret 0] 0] + set kvals($p1) [lindex [lindex $ret 0] 1] + + set ret [$dbc get -next] + error_check_bad dbc_get:DB_NEXT [llength $ret] 0 + lappend p1 [lindex [lindex $ret 0] 0] + set kvals([lindex [lindex $ret 0] 0]) [lindex [lindex $ret 0] 1] + + set ret [$dbc get -last] + error_check_bad dbc_get:DB_LAST [llength $ret] 0 + set p2 [lindex [lindex $ret 0] 0] + set kvals($p2) [lindex [lindex $ret 0] 1] + + set ret [$dbc get -prev] + error_check_bad dbc_get:DB_PREV [llength $ret] 0 + lappend p2 [lindex [lindex $ret 0] 0] + set kvals([lindex [lindex $ret 0] 0]) [lindex [lindex $ret 0] 1] + + error_check_good dbc_close [$dbc close] 0 + error_check_good db_close [$db close] 0 + + # Now create the full transaction environment. + set eflags "-create -txn -home $testdir" + + puts "\tRecd006.b: creating environment" + set env_cmd "berkdb env $eflags" + set dbenv [eval $env_cmd] + error_check_bad dbenv $dbenv NULL + + # Reset the environment. + reset_env $dbenv + + set p1 [list $p1] + set p2 [list $p2] + + # List of recovery tests: {CMD MSG} pairs + set rlist { + { {nesttest DB TXNID ENV 1 $p1 $p2 commit commit} + "Recd006.c: children (commit commit)"} + { {nesttest DB TXNID ENV 0 $p1 $p2 commit commit} + "Recd006.d: children (commit commit)"} + { {nesttest DB TXNID ENV 1 $p1 $p2 commit abort} + "Recd006.e: children (commit abort)"} + { {nesttest DB TXNID ENV 0 $p1 $p2 commit abort} + "Recd006.f: children (commit abort)"} + { {nesttest DB TXNID ENV 1 $p1 $p2 abort abort} + "Recd006.g: children (abort abort)"} + { {nesttest DB TXNID ENV 0 $p1 $p2 abort abort} + "Recd006.h: children (abort abort)"} + { {nesttest DB TXNID ENV 1 $p1 $p2 abort commit} + "Recd006.i: children (abort commit)"} + { {nesttest DB TXNID ENV 0 $p1 $p2 abort commit} + "Recd006.j: children (abort commit)"} + } + + foreach pair $rlist { + set cmd [subst [lindex $pair 0]] + set msg [lindex $pair 1] + if { $select != 0 } { + set tag [lindex $msg 0] + set tail [expr [string length $tag] - 2] + set tag [string range $tag $tail $tail] + if { [lsearch $select $tag] == -1 } { + continue + } + } + op_recover abort $testdir $env_cmd $dbfile $cmd $msg + op_recover commit $testdir $env_cmd $dbfile $cmd $msg + } + + puts "\tRecd006.k: Verify db_printlog can read logfile" + set tmpfile $testdir/printlog.out + set stat [catch {exec $util_path/db_printlog -h $testdir \ + > $tmpfile} ret] + error_check_good db_printlog $stat 0 + fileremove $tmpfile +} + +# Do the nested transaction test. +# We want to make sure that children inherit properly from their +# parents and that locks are properly handed back to parents +# and that the right thing happens on commit/abort. +# In particular: +# Write lock on parent, properly acquired by child. +# Committed operation on child gives lock to parent so that +# other child can also get the lock. +# Aborted op by child releases lock so other child can get it. +# Correct database state if child commits +# Correct database state if child aborts +proc nesttest { db parent env do p1 p2 child1 child2} { + global kvals + source ./include.tcl + + if { $do == 1 } { + set func toupper + } else { + set func tolower + } + + # Do an RMW on the parent to get a write lock. + set p10 [lindex $p1 0] + set p11 [lindex $p1 1] + set p20 [lindex $p2 0] + set p21 [lindex $p2 1] + + set ret [$db get -rmw -txn $parent $p10] + set res $ret + set Dret [lindex [lindex $ret 0] 1] + if { [string compare $Dret $kvals($p10)] == 0 || + [string compare $Dret [string toupper $kvals($p10)]] == 0 } { + set val 0 + } else { + set val $Dret + } + error_check_good get_parent_RMW $val 0 + + # OK, do child 1 + set kid1 [$env txn -parent $parent] + error_check_good kid1 [is_valid_widget $kid1 $env.txn] TRUE + + # Reading write-locked parent object should be OK + #puts "\tRead write-locked parent object for kid1." + set ret [$db get -txn $kid1 $p10] + error_check_good kid1_get10 $ret $res + + # Now update this child + set data [lindex [lindex [string $func $ret] 0] 1] + set ret [$db put -txn $kid1 $p10 $data] + error_check_good kid1_put10 $ret 0 + + #puts "\tKid1 successful put." + + # Now start child2 + #puts "\tBegin txn for kid2." + set kid2 [$env txn -parent $parent] + error_check_good kid2 [is_valid_widget $kid2 $env.txn] TRUE + + # Getting anything in the p1 set should deadlock, so let's + # work on the p2 set. + set data [string $func $kvals($p20)] + #puts "\tPut data for kid2." + set ret [$db put -txn $kid2 $p20 $data] + error_check_good kid2_put20 $ret 0 + + #puts "\tKid2 data put successful." + + # Now let's do the right thing to kid1 + puts -nonewline "\tKid1 $child1..." + if { [string compare $child1 "commit"] == 0 } { + error_check_good kid1_commit [$kid1 commit] 0 + } else { + error_check_good kid1_abort [$kid1 abort] 0 + } + puts "complete" + + # In either case, child2 should now be able to get the + # lock, either because it is inherited by the parent + # (commit) or because it was released (abort). + set data [string $func $kvals($p11)] + set ret [$db put -txn $kid2 $p11 $data] + error_check_good kid2_put11 $ret 0 + + # Now let's do the right thing to kid2 + puts -nonewline "\tKid2 $child2..." + if { [string compare $child2 "commit"] == 0 } { + error_check_good kid2_commit [$kid2 commit] 0 + } else { + error_check_good kid2_abort [$kid2 abort] 0 + } + puts "complete" + + # Now, let parent check that the right things happened. + # First get all four values + set p10_check [lindex [lindex [$db get -txn $parent $p10] 0] 0] + set p11_check [lindex [lindex [$db get -txn $parent $p11] 0] 0] + set p20_check [lindex [lindex [$db get -txn $parent $p20] 0] 0] + set p21_check [lindex [lindex [$db get -txn $parent $p21] 0] 0] + + if { [string compare $child1 "commit"] == 0 } { + error_check_good parent_kid1 $p10_check \ + [string tolower [string $func $kvals($p10)]] + } else { + error_check_good \ + parent_kid1 $p10_check [string tolower $kvals($p10)] + } + if { [string compare $child2 "commit"] == 0 } { + error_check_good parent_kid2 $p11_check \ + [string tolower [string $func $kvals($p11)]] + error_check_good parent_kid2 $p20_check \ + [string tolower [string $func $kvals($p20)]] + } else { + error_check_good parent_kid2 $p11_check $kvals($p11) + error_check_good parent_kid2 $p20_check $kvals($p20) + } + + # Now do a write on the parent for 21 whose lock it should + # either have or should be available. + set ret [$db put -txn $parent $p21 [string $func $kvals($p21)]] + error_check_good parent_put21 $ret 0 + + return 0 +} diff --git a/db/test/recd007.tcl b/db/test/recd007.tcl new file mode 100644 index 000000000..d077ae19f --- /dev/null +++ b/db/test/recd007.tcl @@ -0,0 +1,723 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: recd007.tcl,v 11.38 2000/12/20 21:39:23 krinsky Exp $ +# +# Recovery Test 7. +# This is a recovery test for create/delete of databases. We have +# hooks in the database so that we can abort the process at various +# points and make sure that the transaction doesn't commit. We +# then need to recover and make sure the file is correctly existing +# or not, as the case may be. +proc recd007 { method args} { + global fixed_len + source ./include.tcl + + set orig_fixed_len $fixed_len + set opts [convert_args $method $args] + set omethod [convert_method $method] + + puts "Recd007: $method operation/transaction tests" + + # Create the database and environment. + env_cleanup $testdir + + set testfile recd007.db + set flags "-create -txn -home $testdir" + + puts "\tRecd007.a: creating environment" + set env_cmd "berkdb env $flags" + + set env [eval $env_cmd] + # + # We need to create a database to get the pagesize (either + # the default or whatever might have been specified). + # Then remove it so we can compute fixed_len and create the + # real database. + set oflags "-create $omethod -mode 0644 -env $env $opts $testfile" + set db [eval {berkdb_open} $oflags] + error_check_good db_open [is_valid_db $db] TRUE + set stat [$db stat] + # + # Compute the fixed_len based on the pagesize being used. + # We want the fixed_len to be 1/4 the pagesize. + # + set pg [get_pagesize $stat] + error_check_bad get_pagesize $pg -1 + set fixed_len [expr $pg / 4] + error_check_good db_close [$db close] 0 + error_check_good dbremove [berkdb dbremove -env $env $testfile] 0 + error_check_good envclose [$env close] 0 + + # Convert the args again because fixed_len is now real. + set opts [convert_args $method ""] + + # + # List of recovery tests: {HOOKS MSG} pairs + # Where each HOOK is a list of {COPY ABORT} + # + set rlist { + { {"none" "preopen"} "Recd007.b0: none/preopen"} + { {"none" "postopen"} "Recd007.b1: none/postopen"} + { {"none" "postlogmeta"} "Recd007.b2: none/postlogmeta"} + { {"none" "postlog"} "Recd007.b3: none/postlog"} + { {"none" "postsync"} "Recd007.b4: none/postsync"} + { {"postopen" "none"} "Recd007.c0: postopen/none"} + { {"postlogmeta" "none"} "Recd007.c1: postlogmeta/none"} + { {"postlog" "none"} "Recd007.c2: postlog/none"} + { {"postsync" "none"} "Recd007.c3: postsync/none"} + { {"postopen" "postopen"} "Recd007.d: postopen/postopen"} + { {"postopen" "postlogmeta"} "Recd007.e: postopen/postlogmeta"} + { {"postopen" "postlog"} "Recd007.f: postopen/postlog"} + { {"postlog" "postlog"} "Recd007.g: postlog/postlog"} + { {"postlogmeta" "postlogmeta"} "Recd007.h: postlogmeta/postlogmeta"} + { {"postlogmeta" "postlog"} "Recd007.i: postlogmeta/postlog"} + { {"postlog" "postsync"} "Recd007.j: postlog/postsync"} + { {"postsync" "postsync"} "Recd007.k: postsync/postsync"} + } + + # These are all the data values that we're going to need to read + # through the operation table and run the recovery tests. + + foreach pair $rlist { + set cmd [lindex $pair 0] + set msg [lindex $pair 1] + file_recover_create $testdir $env_cmd $omethod \ + $opts $testfile $cmd $msg + } + + set rlist { + { {"none" "prerename"} "Recd007.l0: none/prerename"} + { {"none" "postrename"} "Recd007.l1: none/postrename"} + { {"prerename" "none"} "Recd007.m0: prerename/none"} + { {"postrename" "none"} "Recd007.m1: postrename/none"} + { {"prerename" "prerename"} "Recd007.n: prerename/prerename"} + { {"prerename" "postrename"} "Recd007.o: prerename/postrename"} + { {"postrename" "postrename"} "Recd007.p: postrename/postrename"} + } + foreach op { dbremove dbrename } { + foreach pair $rlist { + set cmd [lindex $pair 0] + set msg [lindex $pair 1] + file_recover_delete $testdir $env_cmd $omethod \ + $opts $testfile $cmd $msg $op + } + } + + if { $is_windows_test != 1 } { + do_file_recover_delmk $testdir $env_cmd $omethod $opts $testfile + } + + puts "\tRecd007.r: Verify db_printlog can read logfile" + set tmpfile $testdir/printlog.out + set stat [catch {exec $util_path/db_printlog -h $testdir \ + > $tmpfile} ret] + error_check_good db_printlog $stat 0 + fileremove $tmpfile +} + +proc file_recover_create { dir env_cmd method opts dbfile cmd msg } { + # + # We run this test on each of these scenarios: + # 1. Creating just a database + # 2. Creating a database with a subdb + # 3. Creating a 2nd subdb in a database + puts "\t$msg create with a database" + do_file_recover_create $dir $env_cmd $method $opts $dbfile \ + 0 $cmd $msg + if { [is_queue $method] == 1 } { + puts "\tSkipping subdatabase tests for method $method" + return + } + puts "\t$msg create with a database and subdb" + do_file_recover_create $dir $env_cmd $method $opts $dbfile \ + 1 $cmd $msg + puts "\t$msg create with a database and 2nd subdb" + do_file_recover_create $dir $env_cmd $method $opts $dbfile \ + 2 $cmd $msg + +} + +proc do_file_recover_create { dir env_cmd method opts dbfile sub cmd msg } { + global log_log_record_types + source ./include.tcl + + # Keep track of the log types we've seen + if { $log_log_record_types == 1} { + logtrack_read $dir + } + + env_cleanup $dir + # Open the environment and set the copy/abort locations + set env [eval $env_cmd] + set copy [lindex $cmd 0] + set abort [lindex $cmd 1] + error_check_good copy_location [is_valid_create_loc $copy] 1 + error_check_good abort_location [is_valid_create_loc $abort] 1 + + if {([string first "logmeta" $copy] != -1 || \ + [string first "logmeta" $abort] != -1) && \ + [is_btree $method] == 0 } { + puts "\tSkipping for method $method" + $env test copy none + $env test abort none + error_check_good env_close [$env close] 0 + return + } + + # + # Basically non-existence is our initial state. When we + # abort, it is also our final state. + # + switch $sub { + 0 { + set oflags "-create $method -mode 0644 \ + -env $env $opts $dbfile" + } + 1 { + set oflags "-create $method -mode 0644 \ + -env $env $opts $dbfile sub0" + } + 2 { + # + # If we are aborting here, then we need to + # create a first subdb, then create a second + # + set oflags "-create $method -mode 0644 \ + -env $env $opts $dbfile sub0" + set db [eval {berkdb_open} $oflags] + error_check_good db_open [is_valid_db $db] TRUE + error_check_good db_close [$db close] 0 + set init_file $dir/$dbfile.init + catch { file copy -force $dir/$dbfile $init_file } res + set oflags "-create $method -mode 0644 \ + -env $env $opts $dbfile sub1" + } + default { + puts "\tBad value $sub for sub" + return + } + } + # + # Set our locations to copy and abort + # + set ret [eval $env test copy $copy] + error_check_good test_copy $ret 0 + set ret [eval $env test abort $abort] + error_check_good test_abort $ret 0 + + puts "\t\tExecuting command" + set ret [catch {eval {berkdb_open} $oflags} db] + + # Sync the mpool so any changes to the file that are + # in mpool get written to the disk file before the + # diff. + puts "\t\tSyncing" + $env mpool_sync "0 0" + + # + # If we don't abort, then we expect success. + # If we abort, we expect no file created. + # + if {[string first "none" $abort] == -1} { + # + # Operation was aborted, verify it does + # not exist. + # + puts "\t\tCommand executed and aborted." + error_check_bad db_open ret 0 + + # + # Check that the file does not exist. Final state. + # + if { $sub != 2 } { + error_check_good db_open:exists \ + [file exists $dir/$dbfile] 0 + } else { + error_check_good \ + diff(init,postcreate):diff($init_file,$dir/$dbfile)\ + [dbdump_diff $init_file $dir/$dbfile] 0 + } + } else { + # + # Operation was committed, verify it exists. + # + puts "\t\tCommand executed and committed." + error_check_good db_open [is_valid_db $db] TRUE + error_check_good db_close [$db close] 0 + + # + # Check that the file exists. + # + error_check_good db_open [file exists $dir/$dbfile] 1 + set init_file $dir/$dbfile.init + catch { file copy -force $dir/$dbfile $init_file } res + + if { [is_queue $method] == 1 } { + copy_extent_file $dir $dbfile init + } + } + error_check_good env_close [$env close] 0 + + # + # Run recovery here. Should be a no-op. Verify that + # the file still doesn't exist or change (depending on sub) + # when we are done. + # + berkdb debug_check + puts -nonewline "\t\tAbout to run recovery ... " + flush stdout + + set stat [catch {exec $util_path/db_recover -h $dir -c} result] + if { $stat == 1 } { + error "FAIL: Recovery error: $result." + return + } + puts "complete" + if { $sub != 2 && [string first "none" $abort] == -1} { + # + # Operation was aborted, verify it still does + # not exist. Only done with file creations. + # + error_check_good after_recover1 [file exists $dir/$dbfile] 0 + } else { + # + # Operation was committed or just a subdb was aborted. + # Verify it did not change. + # + error_check_good \ + diff(initial,post-recover1):diff($init_file,$dir/$dbfile) \ + [dbdump_diff $init_file $dir/$dbfile] 0 + # + # Need a new copy to get the right LSN into the file. + # + catch { file copy -force $dir/$dbfile $init_file } res + + if { [is_queue $method] == 1 } { + copy_extent_file $dir $dbfile init + } + } + + # + # If we didn't make a copy, then we are done. + # + if {[string first "none" $copy] != -1} { + return + } + + # + # Now move the .afterop file to $dbfile. Run recovery again. + # + file copy -force $dir/$dbfile.afterop $dir/$dbfile + + if { [is_queue $method] == 1 } { + move_file_extent $dir $dbfile afterop copy + } + + berkdb debug_check + puts -nonewline "\t\tAbout to run recovery ... " + flush stdout + + set stat [catch {exec $util_path/db_recover -h $dir -c} result] + if { $stat == 1 } { + error "FAIL: Recovery error: $result." + return + } + puts "complete" + if { $sub != 2 && [string first "none" $abort] == -1} { + # + # Operation was aborted, verify it still does + # not exist. Only done with file creations. + # + error_check_good after_recover2 [file exists $dir/$dbfile] 0 + } else { + # + # Operation was committed or just a subdb was aborted. + # Verify it did not change. + # + error_check_good \ + diff(initial,post-recover2):diff($init_file,$dir/$dbfile) \ + [dbdump_diff $init_file $dir/$dbfile] 0 + } + +} + +proc file_recover_delete { dir env_cmd method opts dbfile cmd msg op } { + # + # We run this test on each of these scenarios: + # 1. Deleting/Renaming just a database + # 2. Deleting/Renaming a database with a subdb + # 3. Deleting/Renaming a 2nd subdb in a database + puts "\t$msg $op with a database" + do_file_recover_delete $dir $env_cmd $method $opts $dbfile \ + 0 $cmd $msg $op + if { [is_queue $method] == 1 } { + puts "\tSkipping subdatabase tests for method $method" + return + } + puts "\t$msg $op with a database and subdb" + do_file_recover_delete $dir $env_cmd $method $opts $dbfile \ + 1 $cmd $msg $op + puts "\t$msg $op with a database and 2nd subdb" + do_file_recover_delete $dir $env_cmd $method $opts $dbfile \ + 2 $cmd $msg $op + +} + +proc do_file_recover_delete { dir env_cmd method opts dbfile sub cmd msg op } { + global log_log_record_types + source ./include.tcl + + # Keep track of the log types we've seen + if { $log_log_record_types == 1} { + logtrack_read $dir + } + + env_cleanup $dir + # Open the environment and set the copy/abort locations + set env [eval $env_cmd] + set copy [lindex $cmd 0] + set abort [lindex $cmd 1] + error_check_good copy_location [is_valid_delete_loc $copy] 1 + error_check_good abort_location [is_valid_delete_loc $abort] 1 + + if { [is_record_based $method] == 1 } { + set key 1 + } else { + set key recd007_key + } + set data1 recd007_data + set data2 NEWrecd007_data2 + + # + # Depending on what sort of subdb we want, if any, our + # args to the open call will be different (and if we + # want a 2nd subdb, we create the first here. + # + switch $sub { + 0 { + set oflags "-create $method -mode 0644 \ + -env $env $opts $dbfile" + } + 1 { + set oflags "-create $method -mode 0644 \ + -env $env $opts $dbfile sub0" + } + 2 { + # + # If we are aborting here, then we need to + # create a first subdb, then create a second + # + set oflags "-create $method -mode 0644 \ + -env $env $opts $dbfile sub0" + set db [eval {berkdb_open} $oflags] + error_check_good db_open [is_valid_db $db] TRUE + set txn [$env txn] + set ret [$db put -txn $txn $key $data2] + error_check_good db_put $ret 0 + error_check_good commit [$txn commit] 0 + error_check_good db_close [$db close] 0 + set oflags "-create $method -mode 0644 \ + -env $env $opts $dbfile sub1" + } + default { + puts "\tBad value $sub for sub" + return + } + } + + # + # Set our locations to copy and abort + # + set ret [eval $env test copy $copy] + error_check_good test_copy $ret 0 + set ret [eval $env test abort $abort] + error_check_good test_abort $ret 0 + + # + # Open our db, add some data, close and copy as our + # init file. + # + set db [eval {berkdb_open} $oflags] + error_check_good db_open [is_valid_db $db] TRUE + set txn [$env txn] + set ret [$db put -txn $txn $key $data1] + error_check_good db_put $ret 0 + error_check_good commit [$txn commit] 0 + error_check_good db_close [$db close] 0 + + set init_file $dir/$dbfile.init + catch { file copy -force $dir/$dbfile $init_file } res + + if { [is_queue $method] == 1} { + copy_extent_file $dir $dbfile init + } + + # + # If we don't abort, then we expect success. + # If we abort, we expect no file removed. + # + if { [string compare $op dbremove] == 0 } { + set ret [catch { berkdb $op -env $env $dbfile } remret] + } else { + set ret [catch { berkdb $op -env $env $dbfile $dbfile.new } \ + remret] + } + if {[string first "none" $abort] == -1} { + # + # Operation was aborted, verify it did not change. + # + puts "\t\tCommand executed and aborted." + error_check_good $op $ret 1 + + # + # Check that the file exists. Final state. + # Compare against initial file. + # + error_check_good post$op.1 [file exists $dir/$dbfile] 1 + error_check_good \ + diff(init,post$op.2):diff($init_file,$dir/$dbfile)\ + [dbdump_diff $init_file $dir/$dbfile] 0 + } else { + # + # Operation was committed, verify it does + # not exist. + # + puts "\t\tCommand executed and committed." + error_check_good $op $ret 0 + # + # Check that the file does not exist or correct + # file exists. + # + error_check_good $op [file exists $dir/$dbfile] 0 + if { [string compare $op dbrename] == 0 } { + error_check_good $op [file exists $dir/$dbfile.new] 1 + } + } + error_check_good env_close [$env close] 0 + catch { file copy -force $dir/$dbfile $init_file } res + + if { [is_queue $method] == 1} { + copy_extent_file $dir $dbfile init + } + + # + # Run recovery here. Should be a no-op. Verify that + # the file still doesn't exist or change (depending on abort) + # when we are done. + # + berkdb debug_check + puts -nonewline "\t\tAbout to run recovery ... " + flush stdout + + set stat [catch {exec $util_path/db_recover -h $dir -c} result] + if { $stat == 1 } { + error "FAIL: Recovery error: $result." + return + } + puts "complete" + if { [string first "none" $abort] != -1} { + # + # Operation was committed, verify it still does + # not exist. + # + error_check_good after_recover1 [file exists $dir/$dbfile] 0 + } else { + # + # Operation was aborted, verify it did not change. + # + error_check_good \ + diff(initial,post-recover1):diff($init_file,$dir/$dbfile) \ + [dbdump_diff $init_file $dir/$dbfile] 0 + } + + # + # If we didn't make a copy, then we are done. + # + if {[string first "none" $copy] != -1} { + return + } + + # + # Now move the .afterop file to $dbfile. Run recovery again. + # + set filecopy [glob $dir/*.afterop] + set afterop [lindex $filecopy 0] + file rename -force $afterop $dir/$dbfile + set afterop [string range $afterop \ + [expr [string last "/" $afterop] + 1] \ + [string last "." $afterop]] + move_file_extent $dir $dbfile afterop rename + + berkdb debug_check + puts -nonewline "\t\tAbout to run recovery ... " + flush stdout + + set stat [catch {exec $util_path/db_recover -h $dir -c} result] + if { $stat == 1 } { + error "FAIL: Recovery error: $result." + return + } + puts "complete" + + if { [string first "none" $abort] != -1} { + # + # Operation was committed, verify it still does + # not exist. + # + error_check_good after_recover2 [file exists $dir/$dbfile] 0 + } else { + # + # Operation was aborted, verify it did not change. + # + error_check_good \ + diff(initial,post-recover2):diff($init_file,$dir/$dbfile) \ + [dbdump_diff $init_file $dir/$dbfile] 0 + } + +} + +# +# This function tests a specific case of recovering after a db removal. +# This is for SR #2538. Basically we want to test that: +# - Make an env. +# - Make/close a db. +# - Remove the db. +# - Create another db of same name. +# - Sync db but leave open. +# - Run recovery. +# - Verify no recovery errors and that new db is there. +proc do_file_recover_delmk { dir env_cmd method opts dbfile } { + global log_log_record_types + source ./include.tcl + + # Keep track of the log types we've seen + if { $log_log_record_types == 1} { + logtrack_read $dir + } + + puts "\tRecd007.q: Delete and recreate a database" + env_cleanup $dir + # Open the environment and set the copy/abort locations + set env [eval $env_cmd] + + if { [is_record_based $method] == 1 } { + set key 1 + } else { + set key recd007_key + } + set data1 recd007_data + set data2 NEWrecd007_data2 + + set oflags "-create $method -mode 0644 -env $env $opts $dbfile" + + # + # Open our db, add some data, close and copy as our + # init file. + # + set db [eval {berkdb_open} $oflags] + error_check_good db_open [is_valid_db $db] TRUE + set txn [$env txn] + set ret [$db put -txn $txn $key $data1] + error_check_good db_put $ret 0 + error_check_good commit [$txn commit] 0 + error_check_good db_close [$db close] 0 + + set ret [catch { berkdb dbremove -env $env $dbfile } remret] + # + # Operation was committed, verify it does + # not exist. + # + puts "\t\tCommand executed and committed." + error_check_good dbremove $ret 0 + error_check_good dbremove.1 [file exists $dir/$dbfile] 0 + + # + # Now create a new db with the same name. + # + set db [eval {berkdb_open} $oflags] + error_check_good db_open [is_valid_db $db] TRUE + set txn [$env txn] + set ret [$db put -txn $txn $key $data1] + error_check_good db_put $ret 0 + error_check_good commit [$txn commit] 0 + error_check_good db_sync [$db sync] 0 + + berkdb debug_check + puts -nonewline "\t\tAbout to run recovery ... " + flush stdout + + set stat [catch {exec $util_path/db_recover -h $dir -c} result] + if { $stat == 1 } { + error "FAIL: Recovery error: $result." + return + } + puts "complete" + error_check_good db_recover $stat 0 + error_check_good db_recover.1 [file exists $dir/$dbfile] 1 + # + # Since we ran recovery on the open db/env, we need to + # catch these calls. Basically they are there to clean + # up the Tcl widgets. + # + set stat [catch {$db close} ret] + set stat [catch {$env close} ret] + +} +proc is_valid_create_loc { loc } { + switch $loc { + none - + preopen - + postopen - + postlogmeta - + postlog - + postsync + { return 1 } + default + { return 0 } + } +} + +proc is_valid_delete_loc { loc } { + switch $loc { + none - + prerename - + postrename - + postremcall + { return 1 } + default + { return 0 } + } +} + +# Do a logical diff on the db dump files. We expect that either +# the files are identical, or if they differ, that it is exactly +# just a free/invalid page. +# Return 1 if they are different, 0 if logically the same (or identical). +# +proc dbdump_diff { initfile dbfile } { + source ./include.tcl + + set initdump $initfile.dump + set dbdump $dbfile.dump + + set stat [catch {exec $util_path/db_dump -dar -f $initdump \ + $initfile} ret] + error_check_good dbdump.init $stat 0 + + # Do a dump without the freelist which should eliminate any + # recovery differences. + set stat [catch {exec $util_path/db_dump -dar -f $dbdump $dbfile} \ + ret] + error_check_good dbdump.db $stat 0 + + set stat [filecmp $dbdump $initdump] + + if {$stat == 0} { + return 0 + } + puts "diff: $dbdump $initdump gives:\n$ret" + return 1 +} diff --git a/db/test/recd008.tcl b/db/test/recd008.tcl new file mode 100644 index 000000000..b75605b04 --- /dev/null +++ b/db/test/recd008.tcl @@ -0,0 +1,227 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: recd008.tcl,v 1.22 2000/12/07 19:13:46 sue Exp $ +# +# Recovery Test 8. +# Test deeply nested transactions and many-child transactions. +proc recd008 { method {breadth 4} {depth 4} args} { + global kvals + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + + if { [is_record_based $method] == 1 } { + puts "Recd008 skipping for method $method" + return + } + puts "Recd008: $method $breadth X $depth deeply nested transactions" + + # Create the database and environment. + env_cleanup $testdir + + set dbfile recd008.db + + puts "\tRecd008.a: create database" + set db [eval {berkdb_open -create} $args $omethod $testdir/$dbfile] + error_check_good dbopen [is_valid_db $db] TRUE + + # Make sure that we have enough entries to span a couple of + # different pages. + set did [open $dict] + set count 0 + while { [gets $did str] != -1 && $count < 1000 } { + if { [string compare $omethod "-recno"] == 0 } { + set key [expr $count + 1] + } else { + set key $str + } + if { $count == 500} { + set p1 $key + set kvals($p1) $str + } + set ret [$db put $key $str] + error_check_good put $ret 0 + + incr count + } + close $did + error_check_good db_close [$db close] 0 + + set txn_max [expr int([expr pow($breadth,$depth)])] + if { $txn_max < 20 } { + set txn_max 20 + } + puts "\tRecd008.b: create environment for $txn_max transactions" + + set eflags "-mode 0644 -create -txn_max $txn_max \ + -txn -home $testdir" + set env_cmd "berkdb env $eflags" + set dbenv [eval $env_cmd] + error_check_good env_open [is_valid_env $dbenv] TRUE + + reset_env $dbenv + + set rlist { + { {recd008_parent abort ENV DB $p1 TXNID 1 1 $breadth $depth} + "Recd008.c: child abort parent" } + { {recd008_parent commit ENV DB $p1 TXNID 1 1 $breadth $depth} + "Recd008.d: child commit parent" } + } + foreach pair $rlist { + set cmd [subst [lindex $pair 0]] + set msg [lindex $pair 1] + op_recover abort $testdir $env_cmd $dbfile $cmd $msg + recd008_setkval $dbfile $p1 + op_recover commit $testdir $env_cmd $dbfile $cmd $msg + recd008_setkval $dbfile $p1 + } + + puts "\tRecd008.e: Verify db_printlog can read logfile" + set tmpfile $testdir/printlog.out + set stat [catch {exec $util_path/db_printlog -h $testdir \ + > $tmpfile} ret] + error_check_good db_printlog $stat 0 + fileremove $tmpfile +} + +proc recd008_setkval { dbfile p1 } { + global kvals + source ./include.tcl + + set db [berkdb_open $testdir/$dbfile] + error_check_good dbopen [is_valid_db $db] TRUE + set ret [$db get $p1] + set kvals($p1) [lindex [lindex $ret 0] 1] +} + +# This is a lot like the op_recover procedure. We cannot use that +# because it was not meant to be called recursively. This proc +# knows about depth/breadth and file naming so that recursive calls +# don't overwrite various initial and afterop files, etc. +# +# The basic flow of this is: +# (Initial file) +# Parent begin transaction (in op_recover) +# Parent starts children +# Recursively call recd008_recover +# (children modify p1) +# Parent modifies p1 +# (Afterop file) +# Parent commit/abort (in op_recover) +# (Final file) +# Recovery test (in op_recover) +proc recd008_parent { op env db p1key parent b0 d0 breadth depth } { + global kvals + source ./include.tcl + + # + # Save copy of original data + # Acquire lock on data + # + set olddata $kvals($p1key) + set ret [$db get -rmw -txn $parent $p1key] + set Dret [lindex [lindex $ret 0] 1] + error_check_good get_parent_RMW $Dret $olddata + + # + # Parent spawns off children + # + set ret [recd008_txn $op $env $db $p1key $parent \ + $b0 $d0 $breadth $depth] + + puts "Child runs complete. Parent modifies data." + + # + # Parent modifies p1 + # + set newdata $olddata.parent + set ret [$db put -txn $parent $p1key $newdata] + error_check_good db_put $ret 0 + + # + # Save value in kvals for later comparison + # + switch $op { + "commit" { + set kvals($p1key) $newdata + } + "abort" { + set kvals($p1key) $olddata + } + } + return 0 +} + +proc recd008_txn { op env db p1key parent b0 d0 breadth depth } { + global log_log_record_types + global kvals + source ./include.tcl + + for {set d 1} {$d < $d0} {incr d} { + puts -nonewline "\t" + } + puts "Recd008_txn: $op parent:$parent $breadth $depth ($b0 $d0)" + + # Save the initial file and open the environment and the file + for {set b $b0} {$b <= $breadth} {incr b} { + # + # Begin child transaction + # + set t [$env txn -parent $parent] + error_check_bad txn_begin $t NULL + error_check_good txn_begin [is_valid_txn $t $env] TRUE + set startd [expr $d0 + 1] + set child $b:$startd:$t + set olddata $kvals($p1key) + set newdata $olddata.$child + set ret [$db get -rmw -txn $t $p1key] + set Dret [lindex [lindex $ret 0] 1] + error_check_good get_parent_RMW $Dret $olddata + + # + # Recursively call to set up nested transactions/children + # + for {set d $startd} {$d <= $depth} {incr d} { + set ret [recd008_txn commit $env $db $p1key $t \ + $b $d $breadth $depth] + set ret [recd008_txn abort $env $db $p1key $t \ + $b $d $breadth $depth] + } + # + # Modifies p1. + # + set ret [$db put -txn $t $p1key $newdata] + error_check_good db_put $ret 0 + + # + # Commit or abort + # + for {set d 1} {$d < $startd} {incr d} { + puts -nonewline "\t" + } + puts "Executing txn_$op:$t" + error_check_good txn_$op:$t [$t $op] 0 + for {set d 1} {$d < $startd} {incr d} { + puts -nonewline "\t" + } + set ret [$db get -rmw -txn $parent $p1key] + set Dret [lindex [lindex $ret 0] 1] + switch $op { + "commit" { + puts "Command executed and committed." + error_check_good get_parent_RMW $Dret $newdata + set kvals($p1key) $newdata + } + "abort" { + puts "Command executed and aborted." + error_check_good get_parent_RMW $Dret $olddata + set kvals($p1key) $olddata + } + } + } + return 0 +} diff --git a/db/test/recd009.tcl b/db/test/recd009.tcl new file mode 100644 index 000000000..2b4943734 --- /dev/null +++ b/db/test/recd009.tcl @@ -0,0 +1,181 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: recd009.tcl,v 1.13 2000/12/07 19:13:46 sue Exp $ +# +# Recovery Test 9. +# Test stability of record numbers across splits +# and reverse splits and across recovery. +proc recd009 { method {select 0} args} { + global fixed_len + source ./include.tcl + + if { [is_rbtree $method] != 1 && [is_rrecno $method] != 1} { + puts "Recd009 skipping for method $method." + return + } + + set opts [convert_args $method $args] + set method [convert_method $method] + + puts "\tRecd009: Test record numbers across splits and recovery" + + set testfile recd009.db + env_cleanup $testdir + set mkeys 1000 + set nkeys 5 + set data "data" + + puts "\tRecd009.a: Create $method environment and database." + set flags "-create -txn -home $testdir" + + set env_cmd "berkdb env $flags" + set dbenv [eval $env_cmd] + error_check_good dbenv [is_valid_env $dbenv] TRUE + + set oflags "-env $dbenv -create -mode 0644 $opts $method" + set db [eval {berkdb_open} $oflags $testfile] + error_check_good dbopen [is_valid_db $db] TRUE + + # Fill page with small key/data pairs. Keep at leaf. + puts "\tRecd009.b: Fill page with $nkeys small key/data pairs." + for { set i 1 } { $i <= $nkeys } { incr i } { + if { [is_recno $method] == 1 } { + set key $i + } else { + set key key000$i + } + set ret [$db put $key $data$i] + error_check_good dbput $ret 0 + } + error_check_good db_close [$db close] 0 + error_check_good env_close [$dbenv close] 0 + + set newnkeys [expr $nkeys + 1] + # List of recovery tests: {CMD MSG} pairs. + set rlist { + { {recd009_split DB TXNID 1 $method $newnkeys $mkeys} + "Recd009.c: split"} + { {recd009_split DB TXNID 0 $method $newnkeys $mkeys} + "Recd009.d: reverse split"} + } + + foreach pair $rlist { + set cmd [subst [lindex $pair 0]] + set msg [lindex $pair 1] + if { $select != 0 } { + set tag [lindex $msg 0] + set tail [expr [string length $tag] - 2] + set tag [string range $tag $tail $tail] + if { [lsearch $select $tag] == -1 } { + continue + } + } + set reverse [string first "reverse" $msg] + if { $reverse == -1 } { + set abortkeys $nkeys + set commitkeys $mkeys + set abortpg 0 + set commitpg 1 + } else { + set abortkeys $mkeys + set commitkeys $nkeys + set abortpg 1 + set commitpg 0 + } + op_recover abort $testdir $env_cmd $testfile $cmd $msg + recd009_recnocheck $testdir $testfile $opts $abortkeys $abortpg + op_recover commit $testdir $env_cmd $testfile $cmd $msg + recd009_recnocheck $testdir $testfile $opts \ + $commitkeys $commitpg + } + puts "\tRecd009.e: Verify db_printlog can read logfile" + set tmpfile $testdir/printlog.out + set stat [catch {exec $util_path/db_printlog -h $testdir \ + > $tmpfile} ret] + error_check_good db_printlog $stat 0 + fileremove $tmpfile +} + +# +# This procedure verifies that the database has only numkeys number +# of keys and that they are in order. +# +proc recd009_recnocheck { tdir testfile opts numkeys numpg} { + source ./include.tcl + + set db [eval {berkdb_open} $opts $tdir/$testfile] + error_check_good dbopen [is_valid_db $db] TRUE + + puts "\tRecd009_recnocheck: Verify page count of $numpg on split." + set stat [$db stat] + error_check_bad stat:check-split [is_substr $stat \ + "{{Internal pages} 0}"] $numpg + + set type [$db get_type] + set dbc [$db cursor] + error_check_good dbcursor [is_valid_cursor $dbc $db] TRUE + set i 1 + puts "\tRecd009_recnocheck: Checking $numkeys record numbers." + for {set d [$dbc get -first]} { [llength $d] != 0 } { + set d [$dbc get -next]} { + if { [is_btree $type] } { + set thisi [$dbc get -get_recno] + } else { + set thisi [lindex [lindex $d 0] 0] + } + error_check_good recno_check $i $thisi + error_check_good record_count [expr $i <= $numkeys] 1 + incr i + } + error_check_good curs_close [$dbc close] 0 + error_check_good db_close [$db close] 0 +} + +proc recd009_split { db txn split method nkeys mkeys } { + global errorCode + source ./include.tcl + + set data "data" + + set isrecno [is_recno $method] + # if mkeys is above 1000, need to adjust below for lexical order + if { $split == 1 } { + puts "\tRecd009_split: Add $mkeys pairs to force split." + for {set i $nkeys} { $i <= $mkeys } { incr i } { + if { $isrecno == 1 } { + set key $i + } else { + if { $i >= 100 } { + set key key0$i + } elseif { $i >= 10 } { + set key key00$i + } else { + set key key000$i + } + } + set ret [$db put -txn $txn $key $data$i] + error_check_good dbput:more $ret 0 + } + } else { + puts "\tRecd009_split: Delete added keys to force reverse split." + # Since rrecno renumbers, we delete downward. + for {set i $mkeys} { $i >= $nkeys } { set i [expr $i - 1] } { + if { $isrecno == 1 } { + set key $i + } else { + if { $i >= 100 } { + set key key0$i + } elseif { $i >= 10 } { + set key key00$i + } else { + set key key000$i + } + } + error_check_good db_del:$i [$db del -txn $txn $key] 0 + } + } + return 0 +} diff --git a/db/test/recd010.tcl b/db/test/recd010.tcl new file mode 100644 index 000000000..4fd1aefbb --- /dev/null +++ b/db/test/recd010.tcl @@ -0,0 +1,235 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: recd010.tcl,v 1.14 2000/12/11 17:24:55 sue Exp $ +# +# Recovery Test 10. +# Test stability of btree duplicates across btree off-page dup splits +# and reverse splits and across recovery. +proc recd010 { method {select 0} args} { + global fixed_len + global kvals + global kvals_dups + source ./include.tcl + + if { [is_dbtree $method] != 1 && [is_ddbtree $method] != 1} { + puts "Recd010 skipping for method $method." + return + } + + set pgindex [lsearch -exact $args "-pagesize"] + if { $pgindex != -1 } { + puts "Recd010: skipping for specific pagesizes" + return + } + + set opts [convert_args $method $args] + set method [convert_method $method] + + puts "\tRecd010 ($opts): Test duplicates across splits and recovery" + + set testfile recd010.db + env_cleanup $testdir + # + # Set pagesize small to generate lots of off-page dups + # + set page 512 + set mkeys 1000 + set firstkeys 5 + set data "data" + set key "recd010_key" + + puts "\tRecd010.a: Create $method environment and database." + set flags "-create -txn -home $testdir" + + set env_cmd "berkdb env $flags" + set dbenv [eval $env_cmd] + error_check_good dbenv [is_valid_env $dbenv] TRUE + + set oflags "-env $dbenv -create -mode 0644 $opts $method" + set db [eval {berkdb_open} -pagesize $page $oflags $testfile] + error_check_good dbopen [is_valid_db $db] TRUE + + # Fill page with small key/data pairs. Keep at leaf. + puts "\tRecd010.b: Fill page with $firstkeys small dups." + for { set i 1 } { $i <= $firstkeys } { incr i } { + set ret [$db put $key $data$i] + error_check_good dbput $ret 0 + } + set kvals 1 + set kvals_dups $firstkeys + error_check_good db_close [$db close] 0 + error_check_good env_close [$dbenv close] 0 + + # List of recovery tests: {CMD MSG} pairs. + if { $mkeys < 100 } { + puts "Recd010 mkeys of $mkeys too small" + return + } + set rlist { + { {recd010_split DB TXNID 1 $method 2 $mkeys} + "Recd010.c: btree split 2 large dups"} + { {recd010_split DB TXNID 0 $method 2 $mkeys} + "Recd010.d: btree reverse split 2 large dups"} + { {recd010_split DB TXNID 1 $method 10 $mkeys} + "Recd010.e: btree split 10 dups"} + { {recd010_split DB TXNID 0 $method 10 $mkeys} + "Recd010.f: btree reverse split 10 dups"} + { {recd010_split DB TXNID 1 $method 100 $mkeys} + "Recd010.g: btree split 100 dups"} + { {recd010_split DB TXNID 0 $method 100 $mkeys} + "Recd010.h: btree reverse split 100 dups"} + } + + foreach pair $rlist { + set cmd [subst [lindex $pair 0]] + set msg [lindex $pair 1] + if { $select != 0 } { + set tag [lindex $msg 0] + set tail [expr [string length $tag] - 2] + set tag [string range $tag $tail $tail] + if { [lsearch $select $tag] == -1 } { + continue + } + } + set reverse [string first "reverse" $msg] + op_recover abort $testdir $env_cmd $testfile $cmd $msg + recd010_check $testdir $testfile $opts abort $reverse $firstkeys + op_recover commit $testdir $env_cmd $testfile $cmd $msg + recd010_check $testdir $testfile $opts commit $reverse $firstkeys + } + puts "\tRecd010.e: Verify db_printlog can read logfile" + set tmpfile $testdir/printlog.out + set stat [catch {exec $util_path/db_printlog -h $testdir \ + > $tmpfile} ret] + error_check_good db_printlog $stat 0 + fileremove $tmpfile +} + +# +# This procedure verifies that the database has only numkeys number +# of keys and that they are in order. +# +proc recd010_check { tdir testfile opts op reverse origdups } { + global kvals + global kvals_dups + source ./include.tcl + + set db [eval {berkdb_open} $opts $tdir/$testfile] + error_check_good dbopen [is_valid_db $db] TRUE + + set data "data" + + if { $reverse == -1 } { + puts "\tRecd010_check: Verify split after $op" + } else { + puts "\tRecd010_check: Verify reverse split after $op" + } + + set stat [$db stat] + if { [expr ([string compare $op "abort"] == 0 && $reverse == -1) || \ + ([string compare $op "commit"] == 0 && $reverse != -1)]} { + set numkeys 0 + set allkeys [expr $numkeys + 1] + set numdups $origdups + # + # If we abort the adding of dups, or commit + # the removal of dups, either way check that + # we are back at the beginning. Check that: + # - We have 0 internal pages. + # - We have only 1 key (the original we primed the db + # with at the beginning of the test). + # - We have only the original number of dups we primed + # the db with at the beginning of the test. + # + error_check_good stat:orig0 [is_substr $stat \ + "{{Internal pages} 0}"] 1 + error_check_good stat:orig1 [is_substr $stat \ + "{{Number of keys} 1}"] 1 + error_check_good stat:orig2 [is_substr $stat \ + "{{Number of records} $origdups}"] 1 + } else { + set numkeys $kvals + set allkeys [expr $numkeys + 1] + set numdups $kvals_dups + # + # If we abort the removal of dups, or commit the + # addition of dups, check that: + # - We have > 0 internal pages. + # - We have the number of keys. + # + error_check_bad stat:new0 [is_substr $stat \ + "{{Internal pages} 0}"] 1 + error_check_good stat:new1 [is_substr $stat \ + "{{Number of keys} $allkeys}"] 1 + } + + set dbc [$db cursor] + error_check_good dbcursor [is_valid_cursor $dbc $db] TRUE + puts "\tRecd010_check: Checking key and duplicate values" + set key "recd010_key" + # + # Check dups are there as they should be. + # + for {set ki 0} {$ki < $numkeys} {incr ki} { + set datacnt 0 + for {set d [$dbc get -set $key$ki]} { [llength $d] != 0 } { + set d [$dbc get -nextdup]} { + set thisdata [lindex [lindex $d 0] 1] + error_check_good dup_check $thisdata $data$datacnt + incr datacnt + } + error_check_good dup_count $datacnt $numdups + } + # + # Check that the number of expected keys (allkeys) are + # all of the ones that exist in the database. + # + set dupkeys 0 + set lastkey "" + for {set d [$dbc get -first]} { [llength $d] != 0 } { + set d [$dbc get -next]} { + set thiskey [lindex [lindex $d 0] 0] + if { [string compare $lastkey $thiskey] != 0 } { + incr dupkeys + } + set lastkey $thiskey + } + error_check_good key_check $allkeys $dupkeys + error_check_good curs_close [$dbc close] 0 + error_check_good db_close [$db close] 0 +} + +proc recd010_split { db txn split method nkeys mkeys } { + global errorCode + global kvals + global kvals_dups + source ./include.tcl + + set data "data" + set key "recd010_key" + + set numdups [expr $mkeys / $nkeys] + + set kvals $nkeys + set kvals_dups $numdups + if { $split == 1 } { + puts \ +"\tRecd010_split: Add $nkeys keys, with $numdups duplicates each to force split." + for {set k 0} { $k < $nkeys } { incr k } { + for {set i 0} { $i < $numdups } { incr i } { + set ret [$db put -txn $txn $key$k $data$i] + error_check_good dbput:more $ret 0 + } + } + } else { + puts \ +"\tRecd010_split: Delete $nkeys keys to force reverse split." + for {set k 0} { $k < $nkeys } { incr k } { + error_check_good db_del:$k [$db del -txn $txn $key$k] 0 + } + } + return 0 +} diff --git a/db/test/recd011.tcl b/db/test/recd011.tcl new file mode 100644 index 000000000..a6fc26974 --- /dev/null +++ b/db/test/recd011.tcl @@ -0,0 +1,115 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: recd011.tcl,v 11.13 2000/12/06 17:09:54 sue Exp $ +# +# Recovery Test 11. +# Test recovery to a specific timestamp. +proc recd011 { method {niter 200} {ckpt_freq 15} {sleep_time 1} args } { + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + set tnum 11 + + puts "Recd0$tnum ($args): Test recovery to a specific timestamp." + + set testfile recd0$tnum.db + env_cleanup $testdir + + set i 0 + if { [is_record_based $method] == 1 } { + set key 1 + } else { + set key KEY + } + + puts "\tRecd0$tnum.a: Create environment and database." + set flags "-create -txn -home $testdir" + + set env_cmd "berkdb env $flags" + set dbenv [eval $env_cmd] + error_check_good dbenv [is_valid_env $dbenv] TRUE + + set oflags "-env $dbenv -create -mode 0644 $args $omethod" + set db [eval {berkdb_open} $oflags $testfile] + error_check_good dbopen [is_valid_db $db] TRUE + + # Main loop: every second or so, increment the db in a txn. + puts "\t\tInitial Checkpoint" + error_check_good "Initial Checkpoint" [$dbenv txn_checkpoint] 0 + + puts "\tRecd0$tnum.b ($niter iterations):\ + Transaction-protected increment loop." + for { set i 0 } { $i <= $niter } { incr i } { + set data $i + + # Put, in a txn. + set txn [$dbenv txn] + error_check_good txn_begin [is_valid_txn $txn $dbenv] TRUE + error_check_good db_put \ + [$db put -txn $txn $key [chop_data $method $data]] 0 + error_check_good txn_commit [$txn commit] 0 + + set timeof($i) [timestamp -r] + + # If an appropriate period has elapsed, checkpoint. + if { $i % $ckpt_freq == $ckpt_freq - 1 } { + puts "\t\tIteration $i: Checkpointing." + error_check_good ckpt($i) [$dbenv txn_checkpoint] 0 + } + + # sleep for N seconds. + tclsleep $sleep_time + } + error_check_good db_close [$db close] 0 + error_check_good env_close [$dbenv close] 0 + + # Now, loop through and recover to each timestamp, verifying the + # expected increment. + puts "\tRecd0$tnum.c: Recover to each timestamp and check." + for { set i 0 } { $i <= $niter } { incr i } { + + # Run db_recover. + berkdb debug_check + set t [clock format $timeof($i) -format "%y%m%d%H%M.%S"] + set ret [catch {exec $util_path/db_recover -h $testdir -t $t} r] + error_check_good db_recover($i,$t) $ret 0 + + # Now open the db and check the timestamp. + set db [eval {berkdb_open} $testdir/$testfile] + error_check_good db_open($i) [is_valid_db $db] TRUE + + set dbt [$db get $key] + set datum [lindex [lindex $dbt 0] 1] + error_check_good timestamp_recover $datum [pad_data $method $i] + + error_check_good db_close [$db close] 0 + } + + # Finally, recover to a time well before the first timestamp + # and well after the last timestamp. The latter should + # be just like the last timestamp; the former should fail. + puts "\tRecd0$tnum.d: Recover to before the first timestamp." + set t [clock format [expr $timeof(0) - 1000] -format "%y%m%d%H%M.%S"] + set ret [catch {exec $util_path/db_recover -h $testdir -t $t} r] + error_check_bad db_recover(before,$t) $ret 0 + + puts "\tRecd0$tnum.e: Recover to after the last timestamp." + set t [clock format \ + [expr $timeof($niter) + 1000] -format "%y%m%d%H%M.%S"] + set ret [catch {exec $util_path/db_recover -h $testdir -t $t} r] + error_check_good db_recover(after,$t) $ret 0 + + # Now open the db and check the timestamp. + set db [eval {berkdb_open} $testdir/$testfile] + error_check_good db_open(after) [is_valid_db $db] TRUE + + set dbt [$db get $key] + set datum [lindex [lindex $dbt 0] 1] + + error_check_good timestamp_recover $datum [pad_data $method $niter] + error_check_good db_close [$db close] 0 +} diff --git a/db/test/recd012.tcl b/db/test/recd012.tcl new file mode 100644 index 000000000..19dd7b011 --- /dev/null +++ b/db/test/recd012.tcl @@ -0,0 +1,423 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: recd012.tcl,v 11.14 2000/12/11 17:24:55 sue Exp $ +# +# Recovery Test 12. +# Test recovery handling of file opens and closes. +proc recd012 { method {start 0} \ + {niter 49} {noutiter 25} {niniter 100} {ndbs 5} args } { + source ./include.tcl + + set tnum 12 + set pagesize 512 + + if { $is_qnx_test } { + set niter 40 + } + + puts "Recd0$tnum $method ($args): Test recovery file management." + set pgindex [lsearch -exact $args "-pagesize"] + if { $pgindex != -1 } { + puts "Recd012: skipping for specific pagesizes" + return + } + + for { set i $start } { $i <= $niter } { incr i } { + + env_cleanup $testdir + + # For repeatability, we pass in the iteration number + # as a parameter and use that in recd012_body to seed + # the random number generator to randomize our operations. + # This lets us re-run a potentially failing iteration + # without having to start from the beginning and work + # our way to it. + # + # The number of databases ranges from 4 to 8 and is + # a function of $niter +# set ndbs [expr ($i % 5) + 4] + + recd012_body \ + $method $ndbs $i $noutiter $niniter $pagesize $tnum $args + } +} + +proc recd012_body { method {ndbs 5} iter noutiter niniter psz tnum {largs ""} } { + global alphabet rand_init fixed_len recd012_ofkey recd012_ofckptkey + source ./include.tcl + + set largs [convert_args $method $largs] + set omethod [convert_method $method] + + puts "\tRecd0$tnum $method ($largs): Iteration $iter" + puts "\t\tRecd0$tnum.a: Create environment and $ndbs databases." + + set flags "-create -txn -home $testdir" + set env_cmd "berkdb env $flags" + error_check_good env_remove [berkdb envremove -home $testdir] 0 + set dbenv [eval $env_cmd] + error_check_good dbenv [is_valid_env $dbenv] TRUE + + # Initialize random number generator based on $iter. + berkdb srand [expr $iter + $rand_init] + + # Initialize database that keeps track of number of open files (so + # we don't run out of descriptors). + set ofname of.db + set ofdb [berkdb_open -env $dbenv\ + -create -dup -mode 0644 -btree -pagesize 512 $ofname] + error_check_good of_open [is_valid_db $ofdb] TRUE + set oftxn [$dbenv txn] + error_check_good of_txn [is_valid_txn $oftxn $dbenv] TRUE + error_check_good of_put [$ofdb put -txn $oftxn $recd012_ofkey 1] 0 + error_check_good of_put2 [$ofdb put -txn $oftxn $recd012_ofckptkey 0] 0 + error_check_good of_put3 [$ofdb put -txn $oftxn $recd012_ofckptkey 0] 0 + error_check_good of_txn_commit [$oftxn commit] 0 + error_check_good of_close [$ofdb close] 0 + + # Create ndbs databases to work in, and a file listing db names to + # pick from. + set f [open TESTDIR/dblist w] + set oflags \ + "-env $dbenv -create -mode 0644 -pagesize $psz $largs $omethod" + for { set i 0 } { $i < $ndbs } { incr i } { + # 50-50 chance of being a subdb, unless we're a queue. + if { [berkdb random_int 0 1] || [is_queue $method] } { + # not a subdb + set dbname recd0$tnum-$i.db + } else { + # subdb + set dbname "recd0$tnum-subdb.db s$i" + } + puts $f $dbname + set db [eval berkdb_open $oflags $dbname] + error_check_good db($i) [is_valid_db $db] TRUE + error_check_good db($i)_close [$db close] 0 + } + close $f + + error_check_good env_close [$dbenv close] 0 + + # Now we get to the meat of things. Our goal is to do some number + # of opens, closes, updates, and shutdowns (simulated here by a + # close of all open handles and a close/reopen of the environment, + # with or without an envremove), matching the regular expression + # + # ((O[OUC]+S)+R+V) + # + # We'll repeat the inner + a random number up to $niniter times, + # and the outer + a random number up to $noutiter times. + # + # In order to simulate shutdowns, we'll perform the opens, closes, + # and updates in a separate process, which we'll exit without closing + # all handles properly. The environment will be left lying around + # before we run recovery 50% of the time. + set out [berkdb random_int 1 $noutiter] + puts "\t\tRecd0$tnum.b: Performing $out recoveries of up to $niniter\ + ops." + for { set i 0 } { $i < $out } { incr i } { + set child [open "|$tclsh_path" w] + + # For performance, don't source everything, + # just what we'll need. + puts $child "load $tcllib" + puts $child "set fixed_len $fixed_len" + puts $child "source ../test/testutils.tcl" + puts $child "source ../test/recd0$tnum.tcl" + + set rnd [expr $iter * 10000 + $i * 100 + $rand_init] + + # Go. + # puts "recd012_dochild {$env_cmd} $rnd $i $niniter\ + # $ndbs $tnum $method $ofname $largs" + puts $child "recd012_dochild {$env_cmd} $rnd $i $niniter\ + $ndbs $tnum $method $ofname $largs" + close $child + + # Run recovery 0-3 times. + set nrecs [berkdb random_int 0 3] + for { set j 0 } { $j < $nrecs } { incr j } { + set ret [catch {exec $util_path/db_recover \ + -h $testdir} res] + if { $ret != 0 } { + puts "FAIL: db_recover returned with nonzero\ + exit status, output as follows:" + file mkdir /tmp/12out + set fd [open /tmp/12out/[pid] w] + puts $fd $res + close $fd + } + error_check_good recover($j) $ret 0 + } + + } + + # Run recovery one final time; it doesn't make sense to + # check integrity if we do not. + set ret [catch {exec $util_path/db_recover -h $testdir} res] + if { $ret != 0 } { + puts "FAIL: db_recover returned with nonzero\ + exit status, output as follows:" + puts $res + } + + # Make sure each datum is the correct filename. + puts "\t\tRecd0$tnum.c: Checking data integrity." + set dbenv [berkdb env -create -private -home $testdir] + error_check_good env_open_integrity [is_valid_env $dbenv] TRUE + set f [open TESTDIR/dblist r] + set i 0 + while { [gets $f dbinfo] > 0 } { + set db [eval berkdb_open -env $dbenv $dbinfo] + error_check_good dbopen($dbinfo) [is_valid_db $db] TRUE + + set dbc [$db cursor] + error_check_good cursor [is_valid_cursor $dbc $db] TRUE + + for { set dbt [$dbc get -first] } { [llength $dbt] > 0 } \ + { set dbt [$dbc get -next] } { + error_check_good integrity [lindex [lindex $dbt 0] 1] \ + [pad_data $method $dbinfo] + } + error_check_good dbc_close [$dbc close] 0 + error_check_good db_close [$db close] 0 + } + close $f + error_check_good env_close_integrity [$dbenv close] 0 + + + # Verify + error_check_good verify [verify_dir $testdir "\t\tRecd0$tnum.d: "] 0 +} + + +proc recd012_dochild { env_cmd rnd outiter niniter ndbs tnum method\ + ofname args } { + global recd012_ofkey + if { [is_record_based $method] } { + set keybase "" + } else { + set keybase .[repeat abcdefghijklmnopqrstuvwxyz 4] + } + + # Initialize our random number generator, repeatably based on an arg. + berkdb srand $rnd + + # Open our env. + set dbenv [eval $env_cmd] + error_check_good env_open [is_valid_env $dbenv] TRUE + + # Find out how many databases appear to be open in the log--we + # don't want recovery to run out of filehandles. + set ofdb [berkdb_open -env $dbenv $ofname] + set oftxn [$dbenv txn] + error_check_good of_txn [is_valid_txn $oftxn $dbenv] TRUE + set dbt [$ofdb get -txn $oftxn $recd012_ofkey] + error_check_good of_get [lindex [lindex $dbt 0] 0] $recd012_ofkey + set nopenfiles [lindex [lindex $dbt 0] 1] + + error_check_good of_commit [$oftxn commit] 0 + + # Read our dbnames + set f [open TESTDIR/dblist r] + set i 0 + while { [gets $f dbname($i)] > 0 } { + incr i + } + close $f + + # We now have $ndbs extant databases. + # Open one of them, just to get us started. + set opendbs {} + set oflags "-env $dbenv $args" + + # Start a transaction, just to get us started. + set curtxn [$dbenv txn] + error_check_good txn [is_valid_txn $curtxn $dbenv] TRUE + + # Inner loop. Do $in iterations of a random open, close, or + # update, where $in is between 1 and $niniter. + set in [berkdb random_int 1 $niniter] + for { set j 0 } { $j < $in } { incr j } { + set op [berkdb random_int 0 2] + switch $op { + 0 { + # Open. + recd012_open + } + 1 { + # Update. Put random-number$keybase as key, + # filename as data, into random database. + set num_open [llength $opendbs] + if { $num_open == 0 } { + # If none are open, do an open first. + + recd012_open + } + set n [berkdb random_int 0 [expr $num_open - 1]] + set pair [lindex $opendbs $n] + set udb [lindex $pair 0] + set uname [lindex $pair 1] + + set key [berkdb random_int 1000 1999]$keybase + set data [chop_data $method $uname] + error_check_good put($uname,$udb,$key,$data) \ + [$udb put -txn $curtxn $key $data] 0 + + # One time in four, commit the transaction. + if { [berkdb random_int 0 3] == 0 && 0 } { + error_check_good txn_recommit \ + [$curtxn commit] 0 + set curtxn [$dbenv txn] + error_check_good txn_reopen \ + [is_valid_txn $curtxn $dbenv] TRUE + } + } + 2 { + # Close. + + if { [llength $opendbs] == 0 } { + # If none are open, open instead of closing. + recd012_open + continue + } + + # Commit curtxn first, lest we self-deadlock. + error_check_good txn_recommit \ + [$curtxn commit] 0 + + # Do it. + set which [berkdb random_int 0 \ + [expr [llength $opendbs] - 1]] + + set db [lindex [lindex $opendbs $which] 0] + error_check_good db_choice [is_valid_db $db] TRUE + global errorCode errorInfo + + error_check_good db_close \ + [[lindex [lindex $opendbs $which] 0] close] 0 + set opendbs [lreplace $opendbs $which $which] + incr nopenfiles -1 + + + # Reopen txn. + set curtxn [$dbenv txn] + error_check_good txn_reopen \ + [is_valid_txn $curtxn $dbenv] TRUE + + } + } + + # One time in two hundred, checkpoint. + if { [berkdb random_int 0 199] == 0 } { + puts "\t\t\tRecd0$tnum:\ + Random checkpoint after operation $outiter.$j." + error_check_good txn_ckpt \ + [$dbenv txn_checkpoint] 0 + set nopenfiles \ + [recd012_nopenfiles_ckpt $dbenv $ofdb $nopenfiles] + } + } + + # We have to commit curtxn. It'd be kind of nice not to, but + # if we start in again without running recovery, we may block + # ourselves. + error_check_good curtxn_commit [$curtxn commit] 0 + + # Put back the new number of open files. + set oftxn [$dbenv txn] + error_check_good of_txn [is_valid_txn $oftxn $dbenv] TRUE + error_check_good of_del [$ofdb del -txn $oftxn $recd012_ofkey] 0 + error_check_good of_put \ + [$ofdb put -txn $oftxn $recd012_ofkey $nopenfiles] 0 + error_check_good of_commit [$oftxn commit] 0 + error_check_good ofdb_close [$ofdb close] 0 +} + +proc recd012_open { } { + # This is basically an inline and has to modify curtxn, + # so use upvars. + upvar curtxn curtxn + upvar ndbs ndbs + upvar dbname dbname + upvar dbenv dbenv + upvar oflags oflags + upvar opendbs opendbs + upvar nopenfiles nopenfiles + + # Return without an open if we've already opened too many files-- + # we don't want to make recovery run out of filehandles. + if { $nopenfiles > 30 } { + #puts "skipping--too many open files" + return -code break + } + + # Commit curtxn first, lest we self-deadlock. + error_check_good txn_recommit \ + [$curtxn commit] 0 + + # Do it. + set which [berkdb random_int 0 [expr $ndbs - 1]] + set db [eval berkdb_open \ + $oflags $dbname($which)] + lappend opendbs [list $db $dbname($which)] + + # Reopen txn. + set curtxn [$dbenv txn] + error_check_good txn_reopen \ + [is_valid_txn $curtxn $dbenv] TRUE + + incr nopenfiles +} + +# Update the database containing the number of files that db_recover has +# to contend with--we want to avoid letting it run out of file descriptors. +# We do this by keeping track of the number of unclosed opens since the +# checkpoint before last. +# $recd012_ofkey stores this current value; the two dups available +# at $recd012_ofckptkey store the number of opens since the last checkpoint +# previous. +# Thus, if the current value is 17 when we do a checkpoint, and the +# stored values are 3 and 8, the new current value (which we return) +# is 14, and the new stored values are 8 and 6. +proc recd012_nopenfiles_ckpt { env db nopenfiles } { + global recd012_ofckptkey + set txn [$env txn] + error_check_good nopenfiles_ckpt_txn [is_valid_txn $txn $env] TRUE + + set dbc [$db cursor -txn $txn] + error_check_good db_cursor [is_valid_cursor $dbc $db] TRUE + + # Get the first ckpt value and delete it. + set dbt [$dbc get -set $recd012_ofckptkey] + error_check_good set [llength $dbt] 1 + + set discard [lindex [lindex $dbt 0] 1] + error_check_good del [$dbc del] 0 + + set nopenfiles [expr $nopenfiles - $discard] + + # Get the next ckpt value + set dbt [$dbc get -nextdup] + error_check_good set2 [llength $dbt] 1 + + # Calculate how many opens we've had since this checkpoint before last. + set onlast [lindex [lindex $dbt 0] 1] + set sincelast [expr $nopenfiles - $onlast] + + # Put this new number at the end of the dup set. + error_check_good put [$dbc put -keylast $recd012_ofckptkey $sincelast] 0 + + # We should never deadlock since we're the only one in this db. + error_check_good dbc_close [$dbc close] 0 + error_check_good txn_commit [$txn commit] 0 + + return $nopenfiles +} + +# globals -- it's not worth passing these around, as they're constants +set recd012_ofkey OPENFILES +set recd012_ofckptkey CKPTS diff --git a/db/test/recd013.tcl b/db/test/recd013.tcl new file mode 100644 index 000000000..d134d487f --- /dev/null +++ b/db/test/recd013.tcl @@ -0,0 +1,244 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: recd013.tcl,v 11.10 2000/12/11 17:24:55 sue Exp $ +# +# Recovery Test 13. +# Smoke test of aborted cursor adjustments. +# +# XXX +# Other tests that cover more specific variants of the same issue +# are in the access method tests for now. This is probably wrong; we +# put this one here because they're closely based on and intertwined +# with other, non-transactional cursor stability tests that are among +# the access method tests, and because we need at least one test to +# fit under recd and keep logtrack from complaining. We'll sort out the mess +# later; the important thing, for now, is that everything that needs to gets +# tested. (This really shouldn't be under recd at all, since it doesn't +# run recovery!) +proc recd013 { method { nitems 100 } args } { + source ./include.tcl + global alphabet log_log_record_types + + set args [convert_args $method $args] + set omethod [convert_method $method] + set tnum 13 + set pgsz 512 + + puts "Recd0$tnum $method ($args): Test of aborted cursor adjustments." + set pgindex [lsearch -exact $args "-pagesize"] + if { $pgindex != -1 } { + puts "Recd013: skipping for specific pagesizes" + return + } + + set testfile recd0$tnum.db + env_cleanup $testdir + + set i 0 + if { [is_record_based $method] == 1 } { + set keybase "" + } else { + set keybase "key" + } + + puts "\tRecd0$tnum.a:\ + Create environment, database, and parent transaction." + set flags "-create -txn -home $testdir" + + set env_cmd "berkdb env $flags" + set env [eval $env_cmd] + error_check_good dbenv [is_valid_env $env] TRUE + + set oflags "-env $env -create -mode 0644 -pagesize $pgsz $args $omethod" + set db [eval {berkdb_open} $oflags $testfile] + error_check_good dbopen [is_valid_db $db] TRUE + + # Create a database containing $nitems items, numbered with odds. + # We'll then put the even numbers during the body of the test. + set txn [$env txn] + error_check_good init_txn [is_valid_txn $txn $env] TRUE + for { set i 1 } { $i <= 2 * $nitems } { incr i 2 } { + set key $keybase$i + set data [chop_data $method $i$alphabet] + error_check_good init_put($i) [$db put -txn $txn $key $data] 0 + } + error_check_good init_txn_commit [$txn commit] 0 + + # Create an initial txn; set a cursor of that txn to each item. + set txn [$env txn] + error_check_good txn [is_valid_txn $txn $env] TRUE + for { set i 1 } { $i <= 2 * $nitems } { incr i 2 } { + set dbc($i) [$db cursor -txn $txn] + error_check_good dbc_getset($i) [$dbc($i) get -set $keybase$i] \ + [list [list $keybase$i [pad_data $method $i$alphabet]]] + } + + puts "\tRecd0$tnum.b: Put test." + puts "\t\tRecd0$tnum.b.1: Put items." + set ctxn [$env txn -parent $txn] + error_check_good txn [is_valid_txn $ctxn $env] TRUE + for { set i 2 } { $i <= 2 * $nitems } { incr i 2 } { + set key $keybase$i + set data [chop_data $method $i$alphabet] + error_check_good child_put($i) [$db put -txn $ctxn $key $data] 0 + + # If we're a renumbering recno, this is uninteresting. + # Stir things up by putting a few additional records at + # the beginning. + if { [is_rrecno $method] == 1 } { + set curs [$db cursor -txn $ctxn] + error_check_bad llength_get_first \ + [llength [$curs get -first]] 0 + error_check_good cursor [is_valid_cursor $curs $db] TRUE + # expect a recno! + error_check_good rrecno_put($i) \ + [$curs put -before ADDITIONAL.$i] 1 + error_check_good curs_close [$curs close] 0 + } + } + + puts "\t\tRecd0$tnum.b.2: Verify cursor stability after abort." + error_check_good ctxn_abort [$ctxn abort] 0 + + for { set i 1 } { $i <= 2 * $nitems } { incr i 2 } { + error_check_good dbc_get($i) [$dbc($i) get -current] \ + [list [list $keybase$i [pad_data $method $i$alphabet]]] + } + + # Clean up cursors. + for { set i 1 } { $i <= 2 * $nitems } { incr i 2 } { + error_check_good dbc($i)_close [$dbc($i) close] 0 + } + + # Sync and verify. + error_check_good txn_commit [$txn commit] 0 + set txn [$env txn] + error_check_good txn [is_valid_txn $txn $env] TRUE + + error_check_good db_sync [$db sync] 0 + error_check_good db_verify \ + [verify_dir $testdir "\t\tRecd0$tnum.b.3: "] 0 + + # Now put back all the even records, this time in the parent. + # Commit and re-begin the transaction so we can abort and + # get back to a nice full database. + for { set i 2 } { $i <= 2 * $nitems } { incr i 2 } { + set key $keybase$i + set data [chop_data $method $i$alphabet] + error_check_good child_put($i) [$db put -txn $txn $key $data] 0 + } + error_check_good txn_commit [$txn commit] 0 + set txn [$env txn] + error_check_good txn [is_valid_txn $txn $env] TRUE + + # Delete test. Set a cursor to each record. Delete the even ones + # in the parent and check cursor stability. Then open a child + # transaction, and delete the odd ones. Verify that the database + # is empty + puts "\tRecd0$tnum.c: Delete test." + unset dbc + + # Create cursors pointing at each item. + for { set i 1 } { $i <= 2 * $nitems } { incr i } { + set dbc($i) [$db cursor -txn $txn] + error_check_good dbc($i)_create [is_valid_cursor $dbc($i) $db] \ + TRUE + error_check_good dbc_getset($i) [$dbc($i) get -set $keybase$i] \ + [list [list $keybase$i [pad_data $method $i$alphabet]]] + } + + puts "\t\tRecd0$tnum.c.1: Delete even items in parent txn." + if { [is_rrecno $method] != 1 } { + set init 2 + set bound [expr 2 * $nitems] + set step 2 + } else { + # In rrecno, deletes will renumber the items, so we have + # to take that into account when we delete by recno. + set init 2 + set bound [expr $nitems + 1] + set step 1 + } + for { set i $init } { $i <= $bound } { incr i $step } { + error_check_good del($i) [$db del -txn $txn $keybase$i] 0 + } + + # Verify that even items are deleted and odd items are not. + for { set i 1 } { $i <= 2 * $nitems } { incr i 2 } { + if { [is_rrecno $method] != 1 } { + set j $i + } else { + set j [expr ($i - 1) / 2 + 1] + } + error_check_good dbc_get($i) [$dbc($i) get -current] \ + [list [list $keybase$j [pad_data $method $i$alphabet]]] + } + for { set i 2 } { $i <= 2 * $nitems } { incr i 2 } { + error_check_good dbc_get($i) [$dbc($i) get -current] \ + [list [list "" ""]] + } + + puts "\t\tRecd0$tnum.c.2: Delete odd items in child txn." + + set ctxn [$env txn -parent $txn] + + for { set i 1 } { $i <= 2 * $nitems } { incr i 2 } { + if { [is_rrecno $method] != 1 } { + set j $i + } else { + # If this is an rrecno, just delete the first + # item repeatedly--the renumbering will make + # that delete everything. + set j 1 + } + error_check_good del($i) [$db del -txn $ctxn $keybase$j] 0 + } + + # Verify that everyone's deleted. + for { set i 1 } { $i <= 2 * $nitems } { incr i } { + error_check_good get_deleted($i) \ + [llength [$db get -txn $ctxn $keybase$i]] 0 + } + + puts "\t\tRecd0$tnum.c.3: Verify cursor stability after abort." + error_check_good ctxn_abort [$ctxn abort] 0 + + # Verify that even items are deleted and odd items are not. + for { set i 1 } { $i <= 2 * $nitems } { incr i 2 } { + if { [is_rrecno $method] != 1 } { + set j $i + } else { + set j [expr ($i - 1) / 2 + 1] + } + error_check_good dbc_get($i) [$dbc($i) get -current] \ + [list [list $keybase$j [pad_data $method $i$alphabet]]] + } + for { set i 2 } { $i <= 2 * $nitems } { incr i 2 } { + error_check_good dbc_get($i) [$dbc($i) get -current] \ + [list [list "" ""]] + } + + # Clean up cursors. + for { set i 1 } { $i <= 2 * $nitems } { incr i } { + error_check_good dbc($i)_close [$dbc($i) close] 0 + } + + # Sync and verify. + error_check_good db_sync [$db sync] 0 + error_check_good db_verify \ + [verify_dir $testdir "\t\tRecd0$tnum.c.4: "] 0 + + puts "\tRecd0$tnum.d: Clean up." + error_check_good txn_commit [$txn commit] 0 + error_check_good db_close [$db close] 0 + error_check_good env_close [$env close] 0 + error_check_good verify_dir \ + [verify_dir $testdir "\t\tRecd0$tnum.d.1: "] 0 + + if { $log_log_record_types == 1 } { + logtrack_read $testdir + } +} diff --git a/db/test/recd014.tcl b/db/test/recd014.tcl new file mode 100644 index 000000000..83b3920de --- /dev/null +++ b/db/test/recd014.tcl @@ -0,0 +1,467 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: recd014.tcl,v 1.9 2001/01/11 17:16:04 sue Exp $ +# +# Recovery Test 14. +# This is a recovery test for create/delete of queue extents. We have +# hooks in the database so that we can abort the process at various +# points and make sure that the extent file does or does not exist. We +# then need to recover and make sure the file is correctly existing +# or not, as the case may be. +proc recd014 { method args} { + global fixed_len + source ./include.tcl + + if { ![is_queueext $method] == 1 } { + puts "Recd014: Skipping for method $method" + return + } + set pgindex [lsearch -exact $args "-pagesize"] + if { $pgindex != -1 } { + puts "Recd014: skipping for specific pagesizes" + return + } + + set orig_fixed_len $fixed_len + # + # We will use 512-byte pages, to be able to control + # when extents get created/removed. + # + set fixed_len 300 + + set opts [convert_args $method $args] + set omethod [convert_method $method] + # + # We want to set -extent 1 instead of what + # convert_args gave us. + # + set exti [lsearch -exact $opts "-extent"] + incr exti + set opts [lreplace $opts $exti $exti 1] + + puts "Recd014: $method extent creation/deletion tests" + + # Create the database and environment. + env_cleanup $testdir + + set testfile recd014.db + set flags "-create -txn -home $testdir" + + puts "\tRecd014.a: creating environment" + set env_cmd "berkdb env $flags" + + puts "\tRecd014.b: Create test commit" + ext_recover_create $testdir $env_cmd $omethod \ + $opts $testfile commit + puts "\tRecd014.b: Create test abort" + ext_recover_create $testdir $env_cmd $omethod \ + $opts $testfile abort + + puts "\tRecd014.c: Consume test commit" + ext_recover_delete $testdir $env_cmd $omethod \ + $opts $testfile consume commit + puts "\tRecd014.c: Consume test abort" + ext_recover_delete $testdir $env_cmd $omethod \ + $opts $testfile consume abort + + puts "\tRecd014.d: Delete test commit" + ext_recover_delete $testdir $env_cmd $omethod \ + $opts $testfile delete commit + puts "\tRecd014.d: Delete test abort" + ext_recover_delete $testdir $env_cmd $omethod \ + $opts $testfile delete abort + + set fixed_len $orig_fixed_len + puts "\tRecd014.e: Verify db_printlog can read logfile" + set tmpfile $testdir/printlog.out + set stat [catch {exec $util_path/db_printlog -h $testdir \ + > $tmpfile} ret] + error_check_good db_printlog $stat 0 + fileremove $tmpfile +} + +proc ext_recover_create { dir env_cmd method opts dbfile txncmd } { + global log_log_record_types + global fixed_len + global alphabet + source ./include.tcl + + # Keep track of the log types we've seen + if { $log_log_record_types == 1} { + logtrack_read $dir + } + + env_cleanup $dir + # Open the environment and set the copy/abort locations + set env [eval $env_cmd] + + set init_file $dir/$dbfile.init + set noenvflags "-create $method -mode 0644 -pagesize 512 $opts $dbfile" + set oflags "-env $env $noenvflags" + + set t [$env txn] + error_check_good txn_begin [is_valid_txn $t $env] TRUE + + set ret [catch {eval {berkdb_open} $oflags} db] + + # + # The command to execute to create an extent is a put. + # We are just creating the first one, so our extnum is 0. + # + set extnum 0 + set data [chop_data $method [replicate $alphabet 512]] + puts "\t\tExecuting command" + set putrecno [$db put -txn $t -append $data] + error_check_good db_put $putrecno 1 + + # Sync the db so any changes to the file that are + # in mpool get written to the disk file before the + # diff. + puts "\t\tSyncing" + error_check_good db_sync [$db sync] 0 + + catch { file copy -force $dir/$dbfile $dir/$dbfile.afterop } res + copy_extent_file $dir $dbfile afterop + + error_check_good txn_$txncmd:$t [$t $txncmd] 0 + # + # If we don't abort, then we expect success. + # If we abort, we expect no file created. + # + set dbq [make_ext_filename $dir $dbfile $extnum] + error_check_good extput:exists1 [file exists $dbq] 1 + set ret [$db get $putrecno] + if {$txncmd == "abort"} { + # + # Operation was aborted. Verify our entry is not there. + # + puts "\t\tCommand executed and aborted." + error_check_good db_get [llength $ret] 0 + } else { + # + # Operation was committed, verify it exists. + # + puts "\t\tCommand executed and committed." + error_check_good db_get [llength $ret] 1 + catch { file copy -force $dir/$dbfile $init_file } res + copy_extent_file $dir $dbfile init + } + error_check_good db_close [$db close] 0 + error_check_good env_close [$env close] 0 + + # + # Run recovery here. Should be a no-op. Verify that + # the file still does/n't exist when we are done. + # + berkdb debug_check + puts -nonewline "\t\tAbout to run recovery (no-op) ... " + flush stdout + + set stat [catch {exec $util_path/db_recover -h $dir -c} result] + if { $stat == 1 } { + error "FAIL: Recovery error: $result." + return + } + puts "complete" + # + # Verify it did not change. + # + error_check_good extput:exists2 [file exists $dbq] 1 + ext_create_check $dir $txncmd $init_file $dbfile $noenvflags $putrecno + + # + # Need a new copy to get the right LSN into the file. + # + catch { file copy -force $dir/$dbfile $init_file } res + copy_extent_file $dir $dbfile init + + # + # Undo. + # Now move the .afterop file to $dbfile. Run recovery again. + # + file copy -force $dir/$dbfile.afterop $dir/$dbfile + move_file_extent $dir $dbfile afterop copy + + berkdb debug_check + puts -nonewline "\t\tAbout to run recovery (afterop) ... " + flush stdout + + set stat [catch {exec $util_path/db_recover -h $dir -c} result] + if { $stat == 1 } { + error "FAIL: Recovery error: $result." + return + } + puts "complete" + ext_create_check $dir $txncmd $init_file $dbfile $noenvflags $putrecno + + # + # To redo, remove the dbfiles. Run recovery again. + # + catch { file rename -force $dir/$dbfile $dir/$dbfile.renamed } res + copy_extent_file $dir $dbfile renamed rename + + berkdb debug_check + puts -nonewline "\t\tAbout to run recovery (init) ... " + flush stdout + + set stat [catch {exec $util_path/db_recover -h $dir -c} result] + # + # !!! + # Even though db_recover exits with status 0, it should print out + # a warning because the file didn't exist. Db_recover writes this + # to stderr. Tcl assumes that ANYTHING written to stderr is an + # error, so even though we exit with 0 status, we still get an + # error back from 'catch'. Look for the warning. + # + if { $stat == 1 && [is_substr $result "warning"] == 0 } { + error "FAIL: Recovery error: $result." + return + } + puts "complete" + + # + # Verify it was redone. However, since we removed the files + # to begin with, recovery with abort will not recreate the + # extent. Recovery with commit will. + # + if {$txncmd == "abort"} { + error_check_good extput:exists3 [file exists $dbq] 0 + } else { + error_check_good extput:exists3 [file exists $dbq] 1 + } +} + +proc ext_create_check { dir txncmd init_file dbfile oflags putrecno } { + if { $txncmd == "commit" } { + # + # Operation was committed. Verify it did not change. + # + error_check_good \ + diff(initial,post-recover2):diff($init_file,$dir/$dbfile) \ + [dbdump_diff $init_file $dir/$dbfile] 0 + } else { + # + # Operation aborted. The file is there, but make + # sure the item is not. + # + set xdb [eval {berkdb_open} $oflags] + error_check_good db_open [is_valid_db $xdb] TRUE + set ret [$xdb get $putrecno] + error_check_good db_get [llength $ret] 0 + error_check_good db_close [$xdb close] 0 + } +} + + +proc ext_recover_delete { dir env_cmd method opts dbfile op txncmd} { + global log_log_record_types + global alphabet + source ./include.tcl + + # Keep track of the log types we've seen + if { $log_log_record_types == 1} { + logtrack_read $dir + } + + env_cleanup $dir + # Open the environment and set the copy/abort locations + set env [eval $env_cmd] + + set oflags "-create $method -mode 0644 -pagesize 512 \ + -env $env $opts $dbfile" + + # + # Open our db, add some data, close and copy as our + # init file. + # + set db [eval {berkdb_open} $oflags] + error_check_good db_open [is_valid_db $db] TRUE + + set extnum 0 + set data [chop_data $method [replicate $alphabet 512]] + + set txn [$env txn] + error_check_good txn_begin [is_valid_txn $txn $env] TRUE + set putrecno [$db put -append $data] + error_check_good db_put $putrecno 1 + error_check_good commit [$txn commit] 0 + error_check_good db_close [$db close] 0 + + puts "\t\tExecuting command" + + set init_file $dir/$dbfile.init + catch { file copy -force $dir/$dbfile $init_file } res + copy_extent_file $dir $dbfile init + + # + # If we don't abort, then we expect success. + # If we abort, we expect no file removed until recovery is run. + # + set db [eval {berkdb_open} $oflags] + error_check_good db_open [is_valid_db $db] TRUE + + set t [$env txn] + error_check_good txn_begin [is_valid_txn $t $env] TRUE + + if { [string compare $op "delete"] == 0 } { + set dbcmd "$db del -txn $t $putrecno" + } else { + set dbcmd "$db get -txn $t -consume" + } + set ret [eval $dbcmd] + error_check_good db_sync [$db sync] 0 + + catch { file copy -force $dir/$dbfile $dir/$dbfile.afterop } res + copy_extent_file $dir $dbfile afterop + + error_check_good txn_$txncmd:$t [$t $txncmd] 0 + set dbq [make_ext_filename $dir $dbfile $extnum] + if {$txncmd == "abort"} { + # + # Operation was aborted, verify ext did not change. + # + puts "\t\tCommand executed and aborted." + + # + # Check that the file exists. Final state. + # Since we aborted the txn, we should be able + # to get to our original entry. + # + error_check_good post$op.1 [file exists $dbq] 1 + + set xdb [eval {berkdb_open} $oflags] + error_check_good db_open [is_valid_db $xdb] TRUE + set kd [$xdb get $putrecno] + set key [lindex [lindex $kd 0] 0] + error_check_good dbget_key $key $putrecno + set retdata [lindex [lindex $kd 0] 1] + error_check_good dbget_data $data $retdata + error_check_good db_close [$xdb close] 0 + + error_check_good \ + diff(init,post$op.2):diff($init_file,$dir/$dbfile)\ + [dbdump_diff $init_file $dir/$dbfile] 0 + } else { + # + # Operation was committed, verify it does + # not exist. + # + puts "\t\tCommand executed and committed." + # + # Check file existence. Consume operations remove + # the extent when we move off, which we should have + # done. Delete operations won't remove the extent + # until we run recovery. + # + if { [string compare $op "delete"] == 0 } { + error_check_good ${op}_exists [file exists $dbq] 1 + } else { + error_check_good ${op}_exists [file exists $dbq] 0 + } + } + error_check_good db_close [$db close] 0 + error_check_good env_close [$env close] 0 + + # + # Run recovery here on what we ended up with. Should be a no-op. + # + berkdb debug_check + puts -nonewline "\t\tAbout to run recovery (no-op) ... " + flush stdout + + set stat [catch {exec $util_path/db_recover -h $dir -c} result] + if { $stat == 1 } { + error "FAIL: Recovery error: $result." + return + } + puts "complete" + if { $txncmd == "abort"} { + # + # Operation was aborted, verify it did not change. + # + error_check_good \ + diff(initial,post-recover1):diff($init_file,$dir/$dbfile) \ + [dbdump_diff $init_file $dir/$dbfile] 0 + } else { + # + # Operation was committed, verify it does + # not exist. Both operations should result + # in no file existing now that we've run recovery. + # + error_check_good after_recover1 [file exists $dbq] 0 + } + + # + # Run recovery here. Re-do the operation. + # Verify that the file doesn't exist + # (if we committed) or change (if we aborted) + # when we are done. + # + catch { file copy -force $dir/$dbfile $init_file } res + copy_extent_file $dir $dbfile init + berkdb debug_check + puts -nonewline "\t\tAbout to run recovery (init) ... " + flush stdout + + set stat [catch {exec $util_path/db_recover -h $dir -c} result] + if { $stat == 1 } { + error "FAIL: Recovery error: $result." + return + } + puts "complete" + if { $txncmd == "abort"} { + # + # Operation was aborted, verify it did not change. + # + error_check_good \ + diff(initial,post-recover1):diff($init_file,$dir/$dbfile) \ + [dbdump_diff $init_file $dir/$dbfile] 0 + } else { + # + # Operation was committed, verify it does + # not exist. Both operations should result + # in no file existing now that we've run recovery. + # + error_check_good after_recover1 [file exists $dbq] 0 + } + + # + # Now move the .afterop file to $dbfile. Run recovery again. + # + set filecopy [glob $dir/*.afterop] + set afterop [lindex $filecopy 0] + file rename -force $afterop $dir/$dbfile + set afterop [string range $afterop \ + [expr [string last "/" $afterop] + 1] \ + [string last "." $afterop]] + move_file_extent $dir $dbfile afterop rename + + berkdb debug_check + puts -nonewline "\t\tAbout to run recovery (afterop) ... " + flush stdout + + set stat [catch {exec $util_path/db_recover -h $dir -c} result] + if { $stat == 1 } { + error "FAIL: Recovery error: $result." + return + } + puts "complete" + + if { $txncmd == "abort"} { + # + # Operation was aborted, verify it did not change. + # + error_check_good \ + diff(initial,post-recover2):diff($init_file,$dir/$dbfile) \ + [dbdump_diff $init_file $dir/$dbfile] 0 + } else { + # + # Operation was committed, verify it still does + # not exist. + # + error_check_good after_recover2 [file exists $dbq] 0 + } +} diff --git a/db/test/rpc001.tcl b/db/test/rpc001.tcl new file mode 100644 index 000000000..331a18cfb --- /dev/null +++ b/db/test/rpc001.tcl @@ -0,0 +1,444 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: rpc001.tcl,v 11.23 2001/01/02 20:04:56 sue Exp $ +# +# Test RPC specifics, primarily that unsupported functions return +# errors and such. +# +proc rpc001 { } { + global __debug_on + global __debug_print + global errorInfo + source ./include.tcl + + # + # First test timeouts on server. + # + set ttime 5 + set itime 10 + puts "Rpc001: Server timeouts: resource $ttime sec, idle $itime sec" + if { [string compare $rpc_server "localhost"] == 0 } { + set dpid [exec $util_path/berkeley_db_svc \ + -h $rpc_testdir -t $ttime -I $itime &] + } else { + set dpid [exec rsh $rpc_server $rpc_path/berkeley_db_svc \ + -h $rpc_testdir -t $ttime -I $itime&] + } + puts "\tRpc001.a: Started server, pid $dpid" + + tclsleep 2 + remote_cleanup $rpc_server $rpc_testdir $testdir + puts "\tRpc001.b: Creating environment" + + set testfile "rpc001.db" + set home [file tail $rpc_testdir] + + set env [eval {berkdb env -create -mode 0644 -home $home \ + -server $rpc_server -client_timeout 10000 -txn}] + error_check_good lock_env:open [is_valid_env $env] TRUE + + puts "\tRpc001.c: Opening a database" + # + # NOTE: the type of database doesn't matter, just use btree. + set db [eval {berkdb_open -create -btree -mode 0644} \ + -env $env $testfile] + error_check_good dbopen [is_valid_db $db] TRUE + + set curs_list {} + set txn_list {} + puts "\tRpc001.d: Basic timeout test" + puts "\tRpc001.d1: Starting a transaction" + set txn [$env txn] + error_check_good txn_begin [is_valid_txn $txn $env] TRUE + lappend txn_list $txn + + puts "\tRpc001.d2: Open a cursor in that transaction" + set dbc [$db cursor -txn $txn] + error_check_good db_cursor [is_valid_cursor $dbc $db] TRUE + lappend curs_list $dbc + + puts "\tRpc001.d3: Duplicate that cursor" + set dbc [$dbc dup] + error_check_good db_cursor [is_valid_cursor $dbc $db] TRUE + lappend curs_list $dbc + + puts "\tRpc001.d4: Starting a nested transaction" + set txn [$env txn -parent $txn] + error_check_good txn_begin [is_valid_txn $txn $env] TRUE + set txn_list [linsert $txn_list 0 $txn] + + puts "\tRpc001.d5: Create a cursor, no transaction" + set dbc [$db cursor] + error_check_good db_cursor [is_valid_cursor $dbc $db] TRUE + lappend curs_list $dbc + + puts "\tRpc001.d6: Timeout cursor and transactions" + set sleeptime [expr $ttime + 2] + tclsleep $sleeptime + + # + # Perform a generic db operations to cause the timeout routine + # to trigger. + # + set stat [catch {$db stat} ret] + error_check_good dbstat $stat 0 + + # + # Check that every handle we opened above is timed out + # + foreach c $curs_list { + set stat [catch {$c close} ret] + error_check_good dbc_close:$c $stat 1 + error_check_good dbc_timeout:$c \ + [is_substr $errorInfo "DB_NOSERVER_ID"] 1 + } + foreach t $txn_list { + set stat [catch {$t commit} ret] + error_check_good txn_commit:$t $stat 1 + error_check_good txn_timeout:$t \ + [is_substr $errorInfo "DB_NOSERVER_ID"] 1 + } + + set txn_list {} + set ntxns 8 + puts "\tRpc001.e: Nested ($ntxns x $ntxns) transaction activity test" + puts "\tRpc001.e1: Starting parent transaction" + set txn [$env txn] + error_check_good txn_begin [is_valid_txn $txn $env] TRUE + set txn_list [linsert $txn_list 0 $txn] + set last_txn $txn + set parent_txn $txn + + # + # First set a breadth of 'ntxns' + # We need 2 from this set for testing later on. Just set them + # up separately first. + # + puts "\tRpc001.e2: Creating $ntxns child transactions" + set child0 [$env txn -parent $parent_txn] + error_check_good txn_begin [is_valid_txn $child0 $env] TRUE + set child1 [$env txn -parent $parent_txn] + error_check_good txn_begin [is_valid_txn $child1 $env] TRUE + + for {set i 2} {$i < $ntxns} {incr i} { + set txn [$env txn -parent $parent_txn] + error_check_good txn_begin [is_valid_txn $txn $env] TRUE + set txn_list [linsert $txn_list 0 $txn] + } + + # + # Now make one 'ntxns' deeply nested. + # Add one more for testing later on separately. + # + puts "\tRpc001.e3: Creating $ntxns nested child transactions" + for {set i 0} {$i < $ntxns} {incr i} { + set txn [$env txn -parent $last_txn] + error_check_good txn_begin [is_valid_txn $txn $env] TRUE + set txn_list [linsert $txn_list 0 $txn] + set last_txn $txn + } + set last_parent $last_txn + set last_txn [$env txn -parent $last_parent] + error_check_good txn_begin [is_valid_txn $last_txn $env] TRUE + + puts "\tRpc001.e4: Open a cursor in deepest transaction" + set dbc [$db cursor -txn $last_txn] + error_check_good db_cursor [is_valid_cursor $dbc $db] TRUE + + puts "\tRpc001.e5: Duplicate that cursor" + set dbcdup [$dbc dup] + error_check_good db_cursor [is_valid_cursor $dbcdup $db] TRUE + lappend curs_list $dbcdup + + puts "\tRpc001.f: Timeout then activate duplicate cursor" + tclsleep $sleeptime + set stat [catch {$dbcdup close} ret] + error_check_good dup_close:$dbcdup $stat 0 + error_check_good dup_close:$dbcdup $ret 0 + + # + # Make sure that our parent txn is not timed out. We will + # try to begin another child tnx using the parent. We expect + # that to succeed. Immediately commit that txn. + # + set stat [catch {$env txn -parent $parent_txn} newchild] + error_check_good newchildtxn $stat 0 + error_check_good newcommit [$newchild commit] 0 + + puts "\tRpc001.g: Timeout, then activate cursor" + tclsleep $sleeptime + set stat [catch {$dbc close} ret] + error_check_good dbc_close:$dbc $stat 0 + error_check_good dbc_close:$dbc $ret 0 + + # + # Make sure that our parent txn is not timed out. We will + # try to begin another child tnx using the parent. We expect + # that to succeed. Immediately commit that txn. + # + set stat [catch {$env txn -parent $parent_txn} newchild] + error_check_good newchildtxn $stat 0 + error_check_good newcommit [$newchild commit] 0 + + puts "\tRpc001.h: Timeout, then activate child txn" + tclsleep $sleeptime + set stat [catch {$child0 commit} ret] + error_check_good child_commit $stat 0 + error_check_good child_commit:$child0 $ret 0 + + # + # + # Make sure that our nested txn is not timed out. We will + # try to begin another child tnx using the parent. We expect + # that to succeed. Immediately commit that txn. + # + set stat [catch {$env txn -parent $last_parent} newchild] + error_check_good newchildtxn $stat 0 + error_check_good newcommit [$newchild commit] 0 + + puts "\tRpc001.i: Timeout, then activate nested txn" + tclsleep $sleeptime + set stat [catch {$last_txn commit} ret] + error_check_good lasttxn_commit $stat 0 + error_check_good lasttxn_commit:$child0 $ret 0 + + # + # Make sure that our child txn is not timed out. We should + # be able to commit it. + # + set stat [catch {$child1 commit} ret] + error_check_good child_commit:$child1 $stat 0 + error_check_good child_commit:$child1 $ret 0 + + # + # Clean up. They were inserted in LIFO order, so we should + # just be able to commit them all. + foreach t $txn_list { + set stat [catch {$t commit} ret] + error_check_good txn_commit:$t $stat 0 + error_check_good txn_commit:$t $ret 0 + } + + set stat [catch {$db close} ret] + error_check_good db_close $stat 0 + + rpc_timeoutjoin $env "Rpc001.j" $sleeptime 0 + rpc_timeoutjoin $env "Rpc001.k" $sleeptime 1 + + # + # We need a 2nd env just to do an op to timeout the env. + # + set env1 [eval {berkdb env -create -mode 0644 -home $home \ + -server $rpc_server -client_timeout 10000 -txn}] + error_check_good lock_env:open [is_valid_env $env1] TRUE + + puts "\tRpc001.l: Timeout idle env handle" + set sleeptime [expr $itime + 2] + tclsleep $sleeptime + + set stat [catch {$env1 close} ret] + error_check_good env1_close $stat 0 + + set stat [catch {$env close} ret] + error_check_good env_close $stat 1 + error_check_good env_timeout \ + [is_substr $errorInfo "DB_NOSERVER_ID"] 1 + + exec $KILL $dpid +} + +proc rpc_timeoutjoin {env msg sleeptime use_txn} { + # + # Check join cursors now. + # + puts -nonewline "\t$msg: Test join cursors and timeouts" + if { $use_txn } { + puts " (using txns)" + } else { + puts " (without txns)" + } + # + # Set up a simple set of join databases + # + puts "\t${msg}0: Set up join databases" + set fruit { + {blue blueberry} + {red apple} {red cherry} {red raspberry} + {yellow lemon} {yellow pear} + } + set price { + {expen blueberry} {expen cherry} {expen raspberry} + {inexp apple} {inexp lemon} {inexp pear} + } + set dessert { + {blueberry cobbler} {cherry cobbler} {pear cobbler} + {apple pie} {raspberry pie} {lemon pie} + } + set fdb [eval {berkdb_open -create -btree -mode 0644} \ + -env $env -dup fruit.db] + error_check_good dbopen [is_valid_db $fdb] TRUE + set pdb [eval {berkdb_open -create -btree -mode 0644} \ + -env $env -dup price.db] + error_check_good dbopen [is_valid_db $pdb] TRUE + set ddb [eval {berkdb_open -create -btree -mode 0644} \ + -env $env -dup dessert.db] + error_check_good dbopen [is_valid_db $ddb] TRUE + foreach kd $fruit { + set k [lindex $kd 0] + set d [lindex $kd 1] + set ret [$fdb put $k $d] + error_check_good fruit_put $ret 0 + } + error_check_good sync [$fdb sync] 0 + foreach kd $price { + set k [lindex $kd 0] + set d [lindex $kd 1] + set ret [$pdb put $k $d] + error_check_good price_put $ret 0 + } + error_check_good sync [$pdb sync] 0 + foreach kd $dessert { + set k [lindex $kd 0] + set d [lindex $kd 1] + set ret [$ddb put $k $d] + error_check_good dessert_put $ret 0 + } + error_check_good sync [$ddb sync] 0 + + rpc_join $env $msg $sleeptime $fdb $pdb $ddb $use_txn 0 + rpc_join $env $msg $sleeptime $fdb $pdb $ddb $use_txn 1 + + error_check_good ddb:close [$ddb close] 0 + error_check_good pdb:close [$pdb close] 0 + error_check_good fdb:close [$fdb close] 0 +} + +proc rpc_join {env msg sleep fdb pdb ddb use_txn op} { + global errorInfo + + # + # Start a parent and child transaction. We'll do our join in + # the child transaction just to make sure everything gets timed + # out correctly. + # + set curs_list {} + set txn_list {} + set msgnum [expr $op * 2 + 1] + if { $use_txn } { + puts "\t$msg$msgnum: Set up txns and join cursor" + set txn [$env txn] + error_check_good txn_begin [is_valid_txn $txn $env] TRUE + set txn_list [linsert $txn_list 0 $txn] + set child0 [$env txn -parent $txn] + error_check_good txn_begin [is_valid_txn $child0 $env] TRUE + set txn_list [linsert $txn_list 0 $child0] + set child1 [$env txn -parent $txn] + error_check_good txn_begin [is_valid_txn $child1 $env] TRUE + set txn_list [linsert $txn_list 0 $child1] + set txncmd "-txn $child0" + } else { + puts "\t$msg$msgnum: Set up join cursor" + set txncmd "" + } + + # + # Start a cursor, (using txn child0 in the fruit and price dbs, if + # needed). # Just pick something simple to join on. + # Then call join on the dessert db. + # + set fkey yellow + set pkey inexp + set fdbc [eval $fdb cursor $txncmd] + error_check_good fdb_cursor [is_valid_cursor $fdbc $fdb] TRUE + set ret [$fdbc get -set $fkey] + error_check_bad fget:set [llength $ret] 0 + set k [lindex [lindex $ret 0] 0] + error_check_good fget:set:key $k $fkey + set curs_list [linsert $curs_list 0 $fdbc] + + set pdbc [eval $pdb cursor $txncmd] + error_check_good pdb_cursor [is_valid_cursor $pdbc $pdb] TRUE + set ret [$pdbc get -set $pkey] + error_check_bad pget:set [llength $ret] 0 + set k [lindex [lindex $ret 0] 0] + error_check_good pget:set:key $k $pkey + set curs_list [linsert $curs_list 0 $pdbc] + + set jdbc [$ddb join $fdbc $pdbc] + error_check_good join_cursor [is_valid_cursor $jdbc $ddb] TRUE + set ret [$jdbc get] + error_check_bad jget [llength $ret] 0 + + set msgnum [expr $op * 2 + 2] + if { $op == 1 } { + puts -nonewline "\t$msg$msgnum: Timeout all cursors" + if { $use_txn } { + puts " and txns" + } else { + puts "" + } + } else { + puts "\t$msg$msgnum: Timeout, then activate join cursor" + } + + tclsleep $sleep + + if { $op == 1 } { + # + # Perform a generic db operations to cause the timeout routine + # to trigger. + # + set stat [catch {$fdb stat} ret] + error_check_good fdbstat $stat 0 + + # + # Check that join cursor is timed out. + # + set stat [catch {$jdbc close} ret] + error_check_good dbc_close:$jdbc $stat 1 + error_check_good dbc_timeout:$jdbc \ + [is_substr $errorInfo "DB_NOSERVER_ID"] 1 + + # + # Now the server may or may not timeout constituent + # cursors when it times out the join cursor. So, just + # sleep again and then they should timeout. + # + tclsleep $sleep + set stat [catch {$fdb stat} ret] + error_check_good fdbstat $stat 0 + + foreach c $curs_list { + set stat [catch {$c close} ret] + error_check_good dbc_close:$c $stat 1 + error_check_good dbc_timeout:$c \ + [is_substr $errorInfo "DB_NOSERVER_ID"] 1 + } + + foreach t $txn_list { + set stat [catch {$t commit} ret] + error_check_good txn_commit:$t $stat 1 + error_check_good txn_timeout:$t \ + [is_substr $errorInfo "DB_NOSERVER_ID"] 1 + } + } else { + set stat [catch {$jdbc get} ret] + error_check_good jget.stat $stat 0 + error_check_bad jget [llength $ret] 0 + set curs_list [linsert $curs_list 0 $jdbc] + foreach c $curs_list { + set stat [catch {$c close} ret] + error_check_good dbc_close:$c $stat 0 + error_check_good dbc_close:$c $ret 0 + } + + foreach t $txn_list { + set stat [catch {$t commit} ret] + error_check_good txn_commit:$t $stat 0 + error_check_good txn_commit:$t $ret 0 + } + } +} diff --git a/db/test/rpc002.tcl b/db/test/rpc002.tcl new file mode 100644 index 000000000..6b11914c2 --- /dev/null +++ b/db/test/rpc002.tcl @@ -0,0 +1,144 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: rpc002.tcl,v 1.7 2000/10/27 13:23:56 sue Exp $ +# +# RPC Test 2 +# Test invalid RPC functions and make sure we error them correctly +proc rpc002 { } { + global __debug_on + global __debug_print + global errorInfo + source ./include.tcl + + set testfile "rpc002.db" + set home [file tail $rpc_testdir] + # + # First start the server. + # + puts "Rpc002: Unsupported interface test" + if { [string compare $rpc_server "localhost"] == 0 } { + set dpid [exec $util_path/berkeley_db_svc -h $rpc_testdir &] + } else { + set dpid [exec rsh $rpc_server $rpc_path/berkeley_db_svc \ + -h $rpc_testdir &] + } + puts "\tRpc002.a: Started server, pid $dpid" + tclsleep 2 + remote_cleanup $rpc_server $rpc_testdir $testdir + + puts "\tRpc002.b: Unsupported env options" + # + # Test each "pre-open" option for env's. These need to be + # tested on the 'berkdb env' line. + # + set rlist { + { "-data_dir $rpc_testdir" "Rpc002.b0"} + { "-log_buffer 512" "Rpc002.b1"} + { "-log_dir $rpc_testdir" "Rpc002.b2"} + { "-log_max 100" "Rpc002.b3"} + { "-lock_conflict {3 {0 0 0 0 0 1 0 1 1}}" "Rpc002.b4"} + { "-lock_detect default" "Rpc002.b5"} + { "-lock_max 100" "Rpc002.b6"} + { "-mmapsize 100" "Rpc002.b7"} + { "-shm_key 100" "Rpc002.b9"} + { "-tmp_dir $rpc_testdir" "Rpc002.b10"} + { "-txn_max 100" "Rpc002.b11"} + { "-txn_timestamp 100" "Rpc002.b12"} + { "-verbose {recovery on}" "Rpc002.b13"} + } + + set e "berkdb env -create -mode 0644 -home $home -server $rpc_server \ + -client_timeout 10000 -txn" + foreach pair $rlist { + set cmd [lindex $pair 0] + set msg [lindex $pair 1] + puts "\t$msg: $cmd" + + set stat [catch {eval $e $cmd} ret] + error_check_good $cmd $stat 1 + error_check_good $cmd.err \ + [is_substr $errorInfo "meaningless in RPC env"] 1 + } + + # + # Open an env with all the subsystems (-txn implies all + # the rest) + # + puts "\tRpc002.c: Unsupported env related interfaces" + set env [eval {berkdb env -create -mode 0644 -home $home \ + -server $rpc_server -client_timeout 10000 -txn}] + error_check_good envopen [is_valid_env $env] TRUE + set dbcmd "berkdb_open_noerr -create -btree -mode 0644 -env $env \ + $testfile" + set db [eval $dbcmd] + error_check_good dbopen [is_valid_db $db] TRUE + + # + # Test each "post-open" option relating to envs, txns, locks, + # logs and mpools. + # + set rlist { + { " lock_detect default" "Rpc002.c0"} + { " lock_get read 1 $env" "Rpc002.c1"} + { " lock_id" "Rpc002.c2"} + { " lock_stat" "Rpc002.c3"} + { " lock_vec 1 {get $env read}" "Rpc002.c4"} + { " log_archive" "Rpc002.c5"} + { " log_file {0 0}" "Rpc002.c6"} + { " log_flush" "Rpc002.c7"} + { " log_get -current" "Rpc002.c8"} + { " log_register $db $testfile" "Rpc002.c9"} + { " log_stat" "Rpc002.c10"} + { " log_unregister $db" "Rpc002.c11"} + { " mpool -create -pagesize 512" "Rpc002.c12"} + { " mpool_stat" "Rpc002.c13"} + { " mpool_sync {0 0}" "Rpc002.c14"} + { " mpool_trickle 50" "Rpc002.c15"} + { " txn_checkpoint -min 1" "Rpc002.c16"} + { " txn_stat" "Rpc002.c17"} + } + + foreach pair $rlist { + set cmd [lindex $pair 0] + set msg [lindex $pair 1] + puts "\t$msg: $cmd" + + set stat [catch {eval $env $cmd} ret] + error_check_good $cmd $stat 1 + error_check_good $cmd.err \ + [is_substr $errorInfo "meaningless in RPC env"] 1 + } + error_check_good dbclose [$db close] 0 + + # + # The database operations that aren't supported are few + # because mostly they are the ones Tcl doesn't support + # either so we have no way to get at them. Test what we can. + # + puts "\tRpc002.d: Unsupported database related interfaces" + # + # NOTE: the type of database doesn't matter, just use btree. + # + puts "\tRpc002.d0: -cachesize" + set dbcmd "berkdb_open_noerr -create -btree -mode 0644 -env $env \ + -cachesize {0 65536 0} $testfile" + set stat [catch {eval $dbcmd} ret] + error_check_good dbopen_cache $stat 1 + error_check_good dbopen_cache_err \ + [is_substr $errorInfo "meaningless in RPC env"] 1 + + puts "\tRpc002.d1: Try to upgrade a database" + # + # NOTE: the type of database doesn't matter, just use btree. + set stat [catch {eval {berkdb upgrade -env} $env $testfile} ret] + error_check_good dbupgrade $stat 1 + error_check_good dbupgrade_err \ + [is_substr $errorInfo "meaningless in RPC env"] 1 + + error_check_good envclose [$env close] 0 + + exec $KILL $dpid +} diff --git a/db/test/rsrc001.tcl b/db/test/rsrc001.tcl new file mode 100644 index 000000000..6d76044f4 --- /dev/null +++ b/db/test/rsrc001.tcl @@ -0,0 +1,223 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: rsrc001.tcl,v 11.18 2001/01/18 06:41:03 krinsky Exp $ +# +# Recno backing file test. +# Try different patterns of adding records and making sure that the +# corresponding file matches +proc rsrc001 { } { + source ./include.tcl + + puts "Rsrc001: Basic recno backing file writeback tests" + + # We run this test essentially twice, once with a db file + # and once without (an in-memory database). + set rec1 "This is record 1" + set rec2 "This is record 2 This is record 2" + set rec3 "This is record 3 This is record 3 This is record 3" + set rec4 [replicate "This is record 4 " 512] + + foreach testfile { "$testdir/rsrc001.db" "" } { + + cleanup $testdir NULL + + if { $testfile == "" } { + puts "Rsrc001: Testing with in-memory database." + } else { + puts "Rsrc001: Testing with disk-backed database." + } + + # Create backing file for the empty-file test. + set oid1 [open $testdir/rsrc.txt w] + close $oid1 + + puts "\tRsrc001.a: Put to empty file." + set db [eval {berkdb_open -create -mode 0644\ + -recno -source $testdir/rsrc.txt} $testfile] + error_check_good dbopen [is_valid_db $db] TRUE + set txn "" + + set ret [eval {$db put} $txn {1 $rec1}] + error_check_good put_to_empty $ret 0 + error_check_good db_close [$db close] 0 + + # Now fill out the backing file and create the check file. + set oid1 [open $testdir/rsrc.txt a] + set oid2 [open $testdir/check.txt w] + + # This one was already put into rsrc.txt. + puts $oid2 $rec1 + + # These weren't. + puts $oid1 $rec2 + puts $oid2 $rec2 + puts $oid1 $rec3 + puts $oid2 $rec3 + puts $oid1 $rec4 + puts $oid2 $rec4 + close $oid1 + close $oid2 + + puts -nonewline "\tRsrc001.b: Read file, rewrite last record;" + puts " write it out and diff" + set db [eval {berkdb_open -create -mode 0644\ + -recno -source $testdir/rsrc.txt} $testfile] + error_check_good dbopen [is_valid_db $db] TRUE + + # Read the last record; replace it (but we won't change it). + # Then close the file and diff the two files. + set dbc [eval {$db cursor} $txn] + error_check_good db_cursor [is_valid_cursor $dbc $db] TRUE + + set rec [$dbc get -last] + error_check_good get_last [llength [lindex $rec 0]] 2 + set key [lindex [lindex $rec 0] 0] + set data [lindex [lindex $rec 0] 1] + + # Get the last record from the text file + set oid [open $testdir/rsrc.txt] + set laststr "" + while { [gets $oid str] != -1 } { + set laststr $str + } + close $oid + set data [sanitize_record $data] + error_check_good getlast $data $laststr + + set ret [eval {$db put} $txn {$key $data}] + error_check_good replace_last $ret 0 + + error_check_good curs_close [$dbc close] 0 + error_check_good db_sync [$db sync] 0 + error_check_good db_sync [$db sync] 0 + error_check_good \ + Rsrc001:diff($testdir/rsrc.txt,$testdir/check.txt) \ + [filecmp $testdir/rsrc.txt $testdir/check.txt] 0 + + puts -nonewline "\tRsrc001.c: " + puts "Append some records in tree and verify in file." + set oid [open $testdir/check.txt a] + for {set i 1} {$i < 10} {incr i} { + set rec [replicate "New Record $i" $i] + puts $oid $rec + incr key + set ret [eval {$db put} $txn {-append $rec}] + error_check_good put_append $ret $key + } + error_check_good db_sync [$db sync] 0 + error_check_good db_sync [$db sync] 0 + close $oid + set ret [filecmp $testdir/rsrc.txt $testdir/check.txt] + error_check_good \ + Rsrc001:diff($testdir/{rsrc.txt,check.txt}) $ret 0 + + puts "\tRsrc001.d: Append by record number" + set oid [open $testdir/check.txt a] + for {set i 1} {$i < 10} {incr i} { + set rec [replicate "New Record (set 2) $i" $i] + puts $oid $rec + incr key + set ret [eval {$db put} $txn {$key $rec}] + error_check_good put_byno $ret 0 + } + + error_check_good db_sync [$db sync] 0 + error_check_good db_sync [$db sync] 0 + close $oid + set ret [filecmp $testdir/rsrc.txt $testdir/check.txt] + error_check_good \ + Rsrc001:diff($testdir/{rsrc.txt,check.txt}) $ret 0 + + puts "\tRsrc001.e: Put beyond end of file." + set oid [open $testdir/check.txt a] + for {set i 1} {$i < 10} {incr i} { + puts $oid "" + incr key + } + set rec "Last Record" + puts $oid $rec + incr key + + set ret [eval {$db put} $txn {$key $rec}] + error_check_good put_byno $ret 0 + + puts "\tRsrc001.f: Put beyond end of file, after reopen." + + error_check_good db_close [$db close] 0 + set db [eval {berkdb_open -create -mode 0644\ + -recno -source $testdir/rsrc.txt} $testfile] + error_check_good dbopen [is_valid_db $db] TRUE + + set rec "Last record with reopen" + puts $oid $rec + + incr key + set ret [eval {$db put} $txn {$key $rec}] + error_check_good put_byno_with_reopen $ret 0 + + puts "\tRsrc001.g:\ + Put several beyond end of file, after reopen." + error_check_good db_close [$db close] 0 + set db [eval {berkdb_open -create -mode 0644\ + -recno -source $testdir/rsrc.txt} $testfile] + error_check_good dbopen [is_valid_db $db] TRUE + + set rec "Really really last record with reopen" + puts $oid "" + puts $oid "" + puts $oid "" + puts $oid $rec + + incr key + incr key + incr key + incr key + + set ret [eval {$db put} $txn {$key $rec}] + error_check_good put_byno_with_reopen $ret 0 + + + + error_check_good db_sync [$db sync] 0 + error_check_good db_sync [$db sync] 0 + + close $oid + set ret [filecmp $testdir/rsrc.txt $testdir/check.txt] + error_check_good \ + Rsrc001:diff($testdir/{rsrc.txt,check.txt}) $ret 0 + + puts "\tRsrc001.h: Verify proper syncing of changes on close." + error_check_good Rsrc001:db_close [$db close] 0 + set db [eval {berkdb_open -create -mode 0644 -recno \ + -source $testdir/rsrc.txt} $testfile] + set oid [open $testdir/check.txt a] + for {set i 1} {$i < 10} {incr i} { + set rec [replicate "New Record $i" $i] + puts $oid $rec + set ret [eval {$db put} $txn {-append $rec}] + # Don't bother checking return; we don't know what + # the key number is, and we'll pick up a failure + # when we compare. + } + error_check_good Rsrc001:db_close [$db close] 0 + close $oid + set ret [filecmp $testdir/rsrc.txt $testdir/check.txt] + error_check_good Rsrc001:diff($testdir/{rsrc,check}.txt) $ret 0 + } +} + +# Strip CRs from a record. +# Needed on Windows when a file is created as text (with CR/LF) +# but read as binary (where CR is read as a separate character) +proc sanitize_record { rec } { + source ./include.tcl + + if { $is_windows_test != 1 } { + return $rec + } + regsub -all \15 $rec "" data + return $data +} diff --git a/db/test/rsrc002.tcl b/db/test/rsrc002.tcl new file mode 100644 index 000000000..d3b45c9a7 --- /dev/null +++ b/db/test/rsrc002.tcl @@ -0,0 +1,65 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: rsrc002.tcl,v 11.11 2000/11/29 15:01:06 sue Exp $ +# +# Recno backing file test #2: test of set_re_delim. +# Specify a backing file with colon-delimited records, +# and make sure they are correctly interpreted. +proc rsrc002 { } { + source ./include.tcl + + puts "Rsrc002: Alternate variable-length record delimiters." + + # We run this test essentially twice, once with a db file + # and once without (an in-memory database). + foreach testfile { "$testdir/rsrc002.db" "" } { + + cleanup $testdir NULL + + # Create the starting files + set oid1 [open $testdir/rsrc.txt w] + set oid2 [open $testdir/check.txt w] + puts -nonewline $oid1 "ostrich:emu:kiwi:moa:cassowary:rhea:" + puts -nonewline $oid2 "ostrich:emu:kiwi:penguin:cassowary:rhea:" + close $oid1 + close $oid2 + + if { $testfile == "" } { + puts "Rsrc002: Testing with in-memory database." + } else { + puts "Rsrc002: Testing with disk-backed database." + } + + puts "\tRsrc002.a: Read file, verify correctness." + set db [eval {berkdb_open -create -mode 0644 -delim 58 \ + -recno -source $testdir/rsrc.txt} $testfile] + error_check_good dbopen [is_valid_db $db] TRUE + + # Read the last record; replace it (but we won't change it). + # Then close the file and diff the two files. + set txn "" + set dbc [eval {$db cursor} $txn] + error_check_good db_cursor [is_valid_cursor $dbc $db] TRUE + + set rec [$dbc get -first] + error_check_good get_first $rec [list [list 1 "ostrich"]] + set rec [$dbc get -next] + error_check_good get_next $rec [list [list 2 "emu"]] + + puts "\tRsrc002.b: Write record, verify correctness." + + eval {$dbc get -set 4} + set ret [$dbc put -current "penguin"] + error_check_good dbc_put $ret 0 + + error_check_good dbc_close [$dbc close] 0 + error_check_good db_close [$db close] 0 + + error_check_good \ + Rsrc002:diff($testdir/rsrc.txt,$testdir/check.txt) \ + [filecmp $testdir/rsrc.txt $testdir/check.txt] 0 + } +} diff --git a/db/test/rsrc003.tcl b/db/test/rsrc003.tcl new file mode 100644 index 000000000..c93b3bbde --- /dev/null +++ b/db/test/rsrc003.tcl @@ -0,0 +1,174 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: rsrc003.tcl,v 11.1 2000/11/29 18:28:49 sue Exp $ +# +# Recno backing file test. +# Try different patterns of adding records and making sure that the +# corresponding file matches +proc rsrc003 { } { + source ./include.tcl + global fixed_len + + puts "Rsrc003: Basic recno backing file writeback tests fixed length" + + # We run this test essentially twice, once with a db file + # and once without (an in-memory database). + # + # Then run with big fixed-length records + set rec1 "This is record 1" + set rec2 "This is record 2" + set rec3 "This is record 3" + set bigrec1 [replicate "This is record 1 " 512] + set bigrec2 [replicate "This is record 2 " 512] + set bigrec3 [replicate "This is record 3 " 512] + + set orig_fixed_len $fixed_len + set rlist { + {{$rec1 $rec2 $rec3} "small records" } + {{$bigrec1 $bigrec2 $bigrec3} "large records" }} + + foreach testfile { "$testdir/rsrc003.db" "" } { + + foreach rec $rlist { + cleanup $testdir NULL + + set recs [lindex $rec 0] + set msg [lindex $rec 1] + # Create the starting files + # Note that for the rest of the test, we are going + # to append a LF when we 'put' via DB to maintain + # file structure and allow us to use 'gets'. + set oid1 [open $testdir/rsrc.txt w] + set oid2 [open $testdir/check.txt w] + foreach record $recs { + set r [subst $record] + set fixed_len [string length $r] + puts $oid1 $r + puts $oid2 $r + } + close $oid1 + close $oid2 + + set reclen [expr $fixed_len + 1] + if { $reclen > [string length $rec1] } { + set repl 512 + } else { + set repl 2 + } + if { $testfile == "" } { + puts \ +"Rsrc003: Testing with in-memory database with $msg." + } else { + puts \ +"Rsrc003: Testing with disk-backed database with $msg." + } + + puts -nonewline \ + "\tRsrc003.a: Read file, rewrite last record;" + puts " write it out and diff" + set db [eval {berkdb_open -create -mode 0644 -recno \ + -len $reclen -source $testdir/rsrc.txt} $testfile] + error_check_good dbopen [is_valid_db $db] TRUE + + # Read the last record; replace it (don't change it). + # Then close the file and diff the two files. + set txn "" + set dbc [eval {$db cursor} $txn] + error_check_good db_cursor \ + [is_valid_cursor $dbc $db] TRUE + + set rec [$dbc get -last] + error_check_good get_last [llength [lindex $rec 0]] 2 + set key [lindex [lindex $rec 0] 0] + set data [lindex [lindex $rec 0] 1] + + # Get the last record from the text file + set oid [open $testdir/rsrc.txt] + set laststr "" + while { [gets $oid str] != -1 } { + append str \12 + set laststr $str + } + close $oid + set data [sanitize_record $data] + error_check_good getlast $data $laststr + + set ret [eval {$db put} $txn {$key $data}] + error_check_good replace_last $ret 0 + + error_check_good curs_close [$dbc close] 0 + error_check_good db_sync [$db sync] 0 + error_check_good db_sync [$db sync] 0 + error_check_good \ + diff1($testdir/rsrc.txt,$testdir/check.txt) \ + [filecmp $testdir/rsrc.txt $testdir/check.txt] 0 + + puts -nonewline "\tRsrc003.b: " + puts "Append some records in tree and verify in file." + set oid [open $testdir/check.txt a] + for {set i 1} {$i < 10} {incr i} { + set rec [chop_data -frecno [replicate \ + "This is New Record $i" $repl]] + puts $oid $rec + append rec \12 + incr key + set ret [eval {$db put} $txn {-append $rec}] + error_check_good put_append $ret $key + } + error_check_good db_sync [$db sync] 0 + error_check_good db_sync [$db sync] 0 + close $oid + set ret [filecmp $testdir/rsrc.txt $testdir/check.txt] + error_check_good \ + diff2($testdir/{rsrc.txt,check.txt}) $ret 0 + + puts "\tRsrc003.c: Append by record number" + set oid [open $testdir/check.txt a] + for {set i 1} {$i < 10} {incr i} { + set rec [chop_data -frecno [replicate \ + "New Record (set 2) $i" $repl]] + puts $oid $rec + append rec \12 + incr key + set ret [eval {$db put} $txn {$key $rec}] + error_check_good put_byno $ret 0 + } + + error_check_good db_sync [$db sync] 0 + error_check_good db_sync [$db sync] 0 + close $oid + set ret [filecmp $testdir/rsrc.txt $testdir/check.txt] + error_check_good \ + diff3($testdir/{rsrc.txt,check.txt}) $ret 0 + + puts \ +"\tRsrc003.d: Verify proper syncing of changes on close." + error_check_good Rsrc003:db_close [$db close] 0 + set db [eval {berkdb_open -create -mode 0644 -recno \ + -len $reclen -source $testdir/rsrc.txt} $testfile] + set oid [open $testdir/check.txt a] + for {set i 1} {$i < 10} {incr i} { + set rec [chop_data -frecno [replicate \ + "New Record (set 3) $i" $repl]] + puts $oid $rec + append rec \12 + set ret [eval {$db put} $txn {-append $rec}] + # Don't bother checking return; + # we don't know what + # the key number is, and we'll pick up a failure + # when we compare. + } + error_check_good Rsrc003:db_close [$db close] 0 + close $oid + set ret [filecmp $testdir/rsrc.txt $testdir/check.txt] + error_check_good \ + diff5($testdir/{rsrc,check}.txt) $ret 0 + } + } + set fixed_len $orig_fixed_len + return +} + diff --git a/db/test/sdb001.tcl b/db/test/sdb001.tcl new file mode 100644 index 000000000..938b6c10c --- /dev/null +++ b/db/test/sdb001.tcl @@ -0,0 +1,123 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: sdb001.tcl,v 11.12 2000/08/25 14:21:52 sue Exp $ +# +# Sub DB Test 1 {access method} +# Test non-subdb and subdb operations +# Test naming (filenames begin with -) +# Test existence (cannot create subdb of same name with -excl) +proc subdb001 { method args } { + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + + puts "Subdb001: $method ($args) subdb and non-subdb tests" + + # Create the database and open the dictionary + set testfile $testdir/subdb001.db + set subdb subdb0 + cleanup $testdir NULL + puts "\tSubdb001.a: Non-subdb database and subdb operations" + # + # Create a db with no subdbs. Add some data. Close. Try to + # open/add with a subdb. Should fail. + # + puts "\tSubdb001.a.0: Create db, add data, close, try subdb" + set db [eval {berkdb_open -create -truncate -mode 0644} \ + $args {$omethod $testfile}] + error_check_good dbopen [is_valid_db $db] TRUE + + set did [open $dict] + + set pflags "" + set gflags "" + set txn "" + set count 0 + + if { [is_record_based $method] == 1 } { + append gflags " -recno" + } + while { [gets $did str] != -1 && $count < 5 } { + if { [is_record_based $method] == 1 } { + global kvals + + set key [expr $count + 1] + set kvals($key) $str + } else { + set key $str + } + set ret [eval \ + {$db put} $txn $pflags {$key [chop_data $method $str]}] + error_check_good put $ret 0 + + set ret [eval {$db get} $gflags {$key}] + error_check_good \ + get $ret [list [list $key [pad_data $method $str]]] + incr count + } + close $did + error_check_good db_close [$db close] 0 + set ret [catch {eval {berkdb_open_noerr -create -mode 0644} $args \ + {$omethod $testfile $subdb}} db] + error_check_bad dbopen $ret 0 + # + # Create a db with no subdbs. Add no data. Close. Try to + # open/add with a subdb. Should fail. + # + set testfile $testdir/subdb001a.db + puts "\tSubdb001.a.1: Create db, close, try subdb" + set db [eval {berkdb_open -create -truncate -mode 0644} $args \ + {$omethod $testfile}] + error_check_good dbopen [is_valid_db $db] TRUE + error_check_good db_close [$db close] 0 + + set ret [catch {eval {berkdb_open_noerr -create -mode 0644} $args \ + {$omethod $testfile $subdb}} db] + error_check_bad dbopen $ret 0 + + if { [is_queue $method] == 1 } { + puts "Subdb001: skipping remainder of test for method $method" + return + } + + # + # Test naming, db and subdb names beginning with -. + # + puts "\tSubdb001.b: Naming" + set cwd [pwd] + cd $testdir + set testfile1 -subdb001.db + set subdb -subdb + puts "\tSubdb001.b.0: Create db and subdb with -name, no --" + set ret [catch {eval {berkdb_open -create -mode 0644} $args \ + {$omethod $testfile1 $subdb}} db] + error_check_bad dbopen $ret 0 + puts "\tSubdb001.b.1: Create db and subdb with -name, with --" + set db [eval {berkdb_open -create -mode 0644} $args \ + {$omethod -- $testfile1 $subdb}] + error_check_good dbopen [is_valid_db $db] TRUE + error_check_good db_close [$db close] 0 + + cd $cwd + + # + # Create 1 db with 1 subdb. Try to create another subdb of + # the same name. Should fail. + # + puts "\tSubdb001.c: Existence check" + set testfile $testdir/subdb001c.db + set subdb subdb + set ret [catch {eval {berkdb_open -create -excl -mode 0644} $args \ + {$omethod $testfile $subdb}} db] + error_check_good dbopen [is_valid_db $db] TRUE + set ret [catch {eval {berkdb_open_noerr -create -excl -mode 0644} \ + $args {$omethod $testfile $subdb}} db1] + error_check_bad dbopen $ret 0 + error_check_good db_close [$db close] 0 + + return +} diff --git a/db/test/sdb002.tcl b/db/test/sdb002.tcl new file mode 100644 index 000000000..11547195c --- /dev/null +++ b/db/test/sdb002.tcl @@ -0,0 +1,167 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: sdb002.tcl,v 11.20 2000/09/20 13:22:04 sue Exp $ +# +# Sub DB Test 2 {access method} +# Use the first 10,000 entries from the dictionary. +# Insert each with self as key and data; retrieve each. +# After all are entered, retrieve all; compare output to original. +# Close file, reopen, do retrieve and re-verify. +# Then repeat using an environment. +proc subdb002 { method {nentries 10000} args } { + source ./include.tcl + + set largs [convert_args $method $args] + set omethod [convert_method $method] + + env_cleanup $testdir + + puts "Subdb002: $method ($largs) basic subdb tests" + set testfile $testdir/subdb002.db + subdb002_body $method $omethod $nentries $largs $testfile NULL + + cleanup $testdir NULL + set env [berkdb env -create -mode 0644 -txn -home $testdir] + error_check_good env_open [is_valid_env $env] TRUE + puts "Subdb002: $method ($largs) basic subdb tests in an environment" + + # We're in an env--use default path to database rather than specifying + # it explicitly. + set testfile subdb002.db + subdb002_body $method $omethod $nentries $largs $testfile $env + error_check_good env_close [$env close] 0 +} + +proc subdb002_body { method omethod nentries largs testfile env } { + source ./include.tcl + + # Create the database and open the dictionary + set subdb subdb0 + set t1 $testdir/t1 + set t2 $testdir/t2 + set t3 $testdir/t3 + + if { [is_queue $omethod] == 1 } { + set sdb002_open berkdb_open_noerr + } else { + set sdb002_open berkdb_open + } + + if { $env == "NULL" } { + set ret [catch {eval {$sdb002_open -create -mode 0644} $largs \ + {$omethod $testfile $subdb}} db] + } else { + set ret [catch {eval {$sdb002_open -create -mode 0644} $largs \ + {-env $env $omethod $testfile $subdb}} db] + } + + # + # If -queue method, we need to make sure that trying to + # create a subdb fails. + if { [is_queue $method] == 1 } { + error_check_bad dbopen $ret 0 + puts "Subdb002: skipping remainder of test for method $method" + return + } + + error_check_good dbopen $ret 0 + error_check_good dbopen [is_valid_db $db] TRUE + + set did [open $dict] + + set pflags "" + set gflags "" + set txn "" + set count 0 + + if { [is_record_based $method] == 1 } { + set checkfunc subdb002_recno.check + append gflags " -recno" + } else { + set checkfunc subdb002.check + } + puts "\tSubdb002.a: put/get loop" + # Here is the loop where we put and get each key/data pair + while { [gets $did str] != -1 && $count < $nentries } { + if { [is_record_based $method] == 1 } { + global kvals + + set key [expr $count + 1] + set kvals($key) [pad_data $method $str] + } else { + set key $str + } + set ret [eval \ + {$db put} $txn $pflags {$key [chop_data $method $str]}] + error_check_good put $ret 0 + + set ret [eval {$db get} $gflags {$key}] + error_check_good \ + get $ret [list [list $key [pad_data $method $str]]] + incr count + } + close $did + # Now we will get each key from the DB and compare the results + # to the original. + puts "\tSubdb002.b: dump file" + dump_file $db $txn $t1 $checkfunc + error_check_good db_close [$db close] 0 + + # Now compare the keys to see if they match the dictionary (or ints) + if { [is_record_based $method] == 1 } { + set oid [open $t2 w] + for {set i 1} {$i <= $nentries} {set i [incr i]} { + puts $oid $i + } + close $oid + file rename -force $t1 $t3 + } else { + set q q + filehead $nentries $dict $t3 + filesort $t3 $t2 + filesort $t1 $t3 + } + + error_check_good Subdb002:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 + + puts "\tSubdb002.c: close, open, and dump file" + # Now, reopen the file and run the last test again. + open_and_dump_subfile $testfile $env $txn $t1 $checkfunc \ + dump_file_direction "-first" "-next" $subdb + if { [is_record_based $method] != 1 } { + filesort $t1 $t3 + } + + error_check_good Subdb002:diff($t2,$t3) \ + [filecmp $t2 $t3] 0 + + # Now, reopen the file and run the last test again in the + # reverse direction. + puts "\tSubdb002.d: close, open, and dump file in reverse direction" + open_and_dump_subfile $testfile $env $txn $t1 $checkfunc \ + dump_file_direction "-last" "-prev" $subdb + + if { [is_record_based $method] != 1 } { + filesort $t1 $t3 + } + + error_check_good Subdb002:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 +} + +# Check function for Subdb002; keys and data are identical +proc subdb002.check { key data } { + error_check_good "key/data mismatch" $data $key +} + +proc subdb002_recno.check { key data } { + global dict + global kvals + + error_check_good key"$key"_exists [info exists kvals($key)] 1 + error_check_good "key/data mismatch, key $key" $data $kvals($key) +} diff --git a/db/test/sdb003.tcl b/db/test/sdb003.tcl new file mode 100644 index 000000000..32bb93d52 --- /dev/null +++ b/db/test/sdb003.tcl @@ -0,0 +1,137 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: sdb003.tcl,v 11.17 2000/08/25 14:21:52 sue Exp $ +# +# Sub DB Test 3 {access method} +# Use the first 10,000 entries from the dictionary as subdbnames. +# Insert each with entry as name of subdatabase and a partial list as key/data. +# After all are entered, retrieve all; compare output to original. +# Close file, reopen, do retrieve and re-verify. +proc subdb003 { method {nentries 1000} args } { + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + + if { [is_queue $method] == 1 } { + puts "Subdb003: skipping for method $method" + return + } + + puts "Subdb003: $method ($args) many subdb tests" + + # Create the database and open the dictionary + set testfile $testdir/subdb003.db + set t1 $testdir/t1 + set t2 $testdir/t2 + set t3 $testdir/t3 + cleanup $testdir NULL + + set pflags "" + set gflags "" + set txn "" + set fcount 0 + + if { [is_record_based $method] == 1 } { + set checkfunc subdb003_recno.check + append gflags " -recno" + } else { + set checkfunc subdb003.check + } + + # Here is the loop where we put and get each key/data pair + set ndataent 10 + set fdid [open $dict] + while { [gets $fdid str] != -1 && $fcount < $nentries } { + set subdb $str + set db [eval {berkdb_open -create -mode 0644} \ + $args {$omethod $testfile $subdb}] + error_check_good dbopen [is_valid_db $db] TRUE + + set count 0 + set did [open $dict] + while { [gets $did str] != -1 && $count < $ndataent } { + if { [is_record_based $method] == 1 } { + global kvals + + set key [expr $count + 1] + set kvals($key) [pad_data $method $str] + } else { + set key $str + } + set ret [eval {$db put} \ + $txn $pflags {$key [chop_data $method $str]}] + error_check_good put $ret 0 + + set ret [eval {$db get} $gflags {$key}] + error_check_good get $ret [list [list $key [pad_data $method $str]]] + incr count + } + close $did + incr fcount + + dump_file $db $txn $t1 $checkfunc + error_check_good db_close [$db close] 0 + + # Now compare the keys to see if they match + if { [is_record_based $method] == 1 } { + set oid [open $t2 w] + for {set i 1} {$i <= $ndataent} {set i [incr i]} { + puts $oid $i + } + close $oid + file rename -force $t1 $t3 + } else { + set q q + filehead $ndataent $dict $t3 + filesort $t3 $t2 + filesort $t1 $t3 + } + + error_check_good Subdb003:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 + + # Now, reopen the file and run the last test again. + open_and_dump_subfile $testfile NULL $txn $t1 $checkfunc \ + dump_file_direction "-first" "-next" $subdb + if { [is_record_based $method] != 1 } { + filesort $t1 $t3 + } + + error_check_good Subdb003:diff($t2,$t3) \ + [filecmp $t2 $t3] 0 + + # Now, reopen the file and run the last test again in the + # reverse direction. + open_and_dump_subfile $testfile NULL $txn $t1 $checkfunc \ + dump_file_direction "-last" "-prev" $subdb + + if { [is_record_based $method] != 1 } { + filesort $t1 $t3 + } + + error_check_good Subdb003:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 + if { [expr $fcount % 100] == 0 } { + puts -nonewline "$fcount " + flush stdout + } + } + puts "" +} + +# Check function for Subdb003; keys and data are identical +proc subdb003.check { key data } { + error_check_good "key/data mismatch" $data $key +} + +proc subdb003_recno.check { key data } { + global dict + global kvals + + error_check_good key"$key"_exists [info exists kvals($key)] 1 + error_check_good "key/data mismatch, key $key" $data $kvals($key) +} diff --git a/db/test/sdb004.tcl b/db/test/sdb004.tcl new file mode 100644 index 000000000..fb63f9d6d --- /dev/null +++ b/db/test/sdb004.tcl @@ -0,0 +1,179 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: sdb004.tcl,v 11.14 2000/08/25 14:21:53 sue Exp $ +# +# SubDB Test 4 {access method} +# Create 1 db with many large subdbs. Use the contents as subdb names. +# Take the source files and dbtest executable and enter their names as the +# key with their contents as data. After all are entered, retrieve all; +# compare output to original. Close file, reopen, do retrieve and re-verify. +proc subdb004 { method args} { + global names + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + + if { [is_queue $method] == 1 || [is_fixed_length $method] == 1 } { + puts "Subdb004: skipping for method $method" + return + } + + puts "Subdb004: $method ($args) \ + filecontents=subdbname filename=key filecontents=data pairs" + + # Create the database and open the dictionary + set testfile $testdir/subdb004.db + set t1 $testdir/t1 + set t2 $testdir/t2 + set t3 $testdir/t3 + set t4 $testdir/t4 + + cleanup $testdir NULL + set pflags "" + set gflags "" + set txn "" + if { [is_record_based $method] == 1 } { + set checkfunc subdb004_recno.check + append gflags "-recno" + } else { + set checkfunc subdb004.check + } + + # Here is the loop where we put and get each key/data pair + set file_list [glob ../*/*.c ./libdb.so.3.0 ./libtool ./libtool.exe] + set fcount [llength $file_list] + + set count 0 + if { [is_record_based $method] == 1 } { + set oid [open $t2 w] + for {set i 1} {$i <= $fcount} {set i [incr i]} { + puts $oid $i + } + close $oid + } else { + set oid [open $t2.tmp w] + foreach f $file_list { + puts $oid $f + } + close $oid + filesort $t2.tmp $t2 + } + puts "\tSubdb004.a: Set/Check each subdb" + foreach f $file_list { + if { [is_record_based $method] == 1 } { + set key [expr $count + 1] + set names([expr $count + 1]) $f + } else { + set key $f + } + # Should really catch errors + set fid [open $f r] + fconfigure $fid -translation binary + set data [read $fid] + set subdb $data + close $fid + set db [eval {berkdb_open -create -mode 0644} \ + $args {$omethod $testfile $subdb}] + error_check_good dbopen [is_valid_db $db] TRUE + set ret [eval \ + {$db put} $txn $pflags {$key [chop_data $method $data]}] + error_check_good put $ret 0 + + # Should really catch errors + set fid [open $t4 w] + fconfigure $fid -translation binary + if [catch {eval {$db get} $gflags {$key}} data] { + puts -nonewline $fid $data + } else { + # Data looks like {{key data}} + set key [lindex [lindex $data 0] 0] + set data [lindex [lindex $data 0] 1] + puts -nonewline $fid $data + } + close $fid + + error_check_good Subdb004:diff($f,$t4) \ + [filecmp $f $t4] 0 + + incr count + + # Now we will get each key from the DB and compare the results + # to the original. + # puts "\tSubdb004.b: dump file" + dump_bin_file $db $txn $t1 $checkfunc + error_check_good db_close [$db close] 0 + + } + + # + # Now for each file, check that the subdb name is the same + # as the data in that subdb and that the filename is the key. + # + puts "\tSubdb004.b: Compare subdb names with key/data" + set db [berkdb_open -rdonly $testfile] + error_check_good dbopen [is_valid_db $db] TRUE + set c [eval {$db cursor} $txn] + error_check_good db_cursor [is_valid_cursor $c $db] TRUE + + for {set d [$c get -first] } { [llength $d] != 0 } \ + {set d [$c get -next] } { + set subdbname [lindex [lindex $d 0] 0] + set subdb [berkdb_open $testfile $subdbname] + error_check_good dbopen [is_valid_db $db] TRUE + + # Output the subdb name + set ofid [open $t3 w] + fconfigure $ofid -translation binary + set subdbname [string trimright $subdbname \0] + puts -nonewline $ofid $subdbname + close $ofid + + # Output the data + set subc [eval {$subdb cursor} $txn] + error_check_good db_cursor [is_valid_cursor $subc $subdb] TRUE + set d [$subc get -first] + error_check_good dbc_get [expr [llength $d] != 0] 1 + set key [lindex [lindex $d 0] 0] + set data [lindex [lindex $d 0] 1] + + set ofid [open $t1 w] + fconfigure $ofid -translation binary + puts -nonewline $ofid $data + close $ofid + + $checkfunc $key $t1 + $checkfunc $key $t3 + + error_check_good Subdb004:diff($t3,$t1) \ + [filecmp $t3 $t1] 0 + error_check_good curs_close [$subc close] 0 + error_check_good db_close [$subdb close] 0 + } + error_check_good curs_close [$c close] 0 + error_check_good db_close [$db close] 0 + + if { [is_record_based $method] != 1 } { + fileremove $t2.tmp + } +} + +# Check function for subdb004; key should be file name; data should be contents +proc subdb004.check { binfile tmpfile } { + source ./include.tcl + + error_check_good Subdb004:datamismatch($binfile,$tmpfile) \ + [filecmp $binfile $tmpfile] 0 +} +proc subdb004_recno.check { binfile tmpfile } { + global names + source ./include.tcl + + set fname $names($binfile) + error_check_good key"$binfile"_exists [info exists names($binfile)] 1 + error_check_good Subdb004:datamismatch($fname,$tmpfile) \ + [filecmp $fname $tmpfile] 0 +} diff --git a/db/test/sdb005.tcl b/db/test/sdb005.tcl new file mode 100644 index 000000000..22e4083c4 --- /dev/null +++ b/db/test/sdb005.tcl @@ -0,0 +1,109 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: sdb005.tcl,v 11.12 2000/08/25 14:21:53 sue Exp $ +# +# Test cursor operations between subdbs. +# +# We should test this on all btrees, all hash, and a combination thereof +proc subdb005 {method {nentries 100} args } { + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + + if { [is_queue $method] == 1 } { + puts "Subdb005: skipping for method $method" + return + } + + puts "Subdb005: $method ( $args ) subdb cursor operations test" + set txn "" + cleanup $testdir NULL + set psize 8192 + set testfile $testdir/subdb005.db + set duplist {-1 -1 -1 -1 -1} + build_all_subdb \ + $testfile [list $method] [list $psize] $duplist $nentries $args + set numdb [llength $duplist] + # + # Get a cursor in each subdb and move past the end of each + # subdb. Make sure we don't end up in another subdb. + # + puts "\tSubdb005.a: Cursor ops - first/prev and last/next" + for {set i 0} {$i < $numdb} {incr i} { + set db [berkdb_open -unknown $testfile sub$i.db] + error_check_good dbopen [is_valid_db $db] TRUE + set db_handle($i) $db + # Used in 005.c test + lappend subdbnames sub$i.db + + set dbc [eval {$db cursor} $txn] + error_check_good db_cursor [is_valid_cursor $dbc $db] TRUE + set d [$dbc get -first] + error_check_good dbc_get [expr [llength $d] != 0] 1 + + # Used in 005.b test + set db_key($i) [lindex [lindex $d 0] 0] + + set d [$dbc get -prev] + error_check_good dbc_get [expr [llength $d] == 0] 1 + set d [$dbc get -last] + error_check_good dbc_get [expr [llength $d] != 0] 1 + set d [$dbc get -next] + error_check_good dbc_get [expr [llength $d] == 0] 1 + } + # + # Get a key from each subdb and try to get this key in a + # different subdb. Make sure it fails + # + puts "\tSubdb005.b: Get keys in different subdb's" + for {set i 0} {$i < $numdb} {incr i} { + set n [expr $i + 1] + if {$n == $numdb} { + set n 0 + } + set db $db_handle($i) + if { [is_record_based $method] == 1 } { + set d [$db get -recno $db_key($n)] + error_check_good \ + db_get [expr [llength $d] == 0] 1 + } else { + set d [$db get $db_key($n)] + error_check_good db_get [expr [llength $d] == 0] 1 + } + } + + # + # Clean up + # + for {set i 0} {$i < $numdb} {incr i} { + error_check_good db_close [$db_handle($i) close] 0 + } + + # + # Check contents of DB for subdb names only. Makes sure that + # every subdbname is there and that nothing else is there. + # + puts "\tSubdb005.c: Check DB is read-only" + error_check_bad dbopen [catch \ + {berkdb_open_noerr -unknown $testfile} ret] 0 + + puts "\tSubdb005.d: Check contents of DB for subdb names only" + set db [berkdb_open -unknown -rdonly $testfile] + error_check_good dbopen [is_valid_db $db] TRUE + set subdblist [$db get -glob *] + foreach kd $subdblist { + # subname also used in subdb005.e,f below + set subname [lindex $kd 0] + set i [lsearch $subdbnames $subname] + error_check_good subdb_search [expr $i != -1] 1 + set subdbnames [lreplace $subdbnames $i $i] + } + error_check_good subdb_done [llength $subdbnames] 0 + + error_check_good db_close [$db close] 0 + return +} diff --git a/db/test/sdb006.tcl b/db/test/sdb006.tcl new file mode 100644 index 000000000..70dee5c73 --- /dev/null +++ b/db/test/sdb006.tcl @@ -0,0 +1,130 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: sdb006.tcl,v 11.12 2000/09/20 13:22:03 sue Exp $ +# +# We'll test 2-way, 3-way, and 4-way joins and figure that if those work, +# everything else does as well. We'll create test databases called +# sub1.db, sub2.db, sub3.db, and sub4.db. The number on the database +# describes the duplication -- duplicates are of the form 0, N, 2N, 3N, ... +# where N is the number of the database. Primary.db is the primary database, +# and sub0.db is the database that has no matching duplicates. All of +# these are within a single database. +# +# We should test this on all btrees, all hash, and a combination thereof +proc subdb006 {method {nentries 100} args } { + source ./include.tcl + global rand_init + + # NB: these flags are internal only, ok + set args [convert_args $method $args] + set omethod [convert_method $method] + + if { [is_record_based $method] == 1 || [is_rbtree $method] } { + puts "\tSubdb006 skipping for method $method." + return + } + + berkdb srand $rand_init + + foreach opt {" -dup" " -dupsort"} { + append args $opt + + puts "Subdb006: $method ( $args ) Intra-subdb join" + set txn "" + # + # Get a cursor in each subdb and move past the end of each + # subdb. Make sure we don't end up in another subdb. + # + puts "\tSubdb006.a: Intra-subdb join" + + cleanup $testdir NULL + set testfile $testdir/subdb006.db + + set psize [list 8192] + set duplist {0 50 25 16 12} + set numdb [llength $duplist] + build_all_subdb $testfile [list $method] $psize \ + $duplist $nentries $args + + # Build the primary + puts "Subdb006: Building the primary database $method" + set oflags "-create -mode 0644 [conv $omethod \ + [berkdb random_int 1 2]]" + set db [eval {berkdb_open} $oflags $testfile primary.db] + error_check_good dbopen [is_valid_db $db] TRUE + for { set i 0 } { $i < 1000 } { incr i } { + set key [format "%04d" $i] + set ret [$db put $key stub] + error_check_good "primary put" $ret 0 + } + error_check_good "primary close" [$db close] 0 + set did [open $dict] + gets $did str + do_join_subdb $testfile primary.db "1 0" $str + gets $did str + do_join_subdb $testfile primary.db "2 0" $str + gets $did str + do_join_subdb $testfile primary.db "3 0" $str + gets $did str + do_join_subdb $testfile primary.db "4 0" $str + gets $did str + do_join_subdb $testfile primary.db "1" $str + gets $did str + do_join_subdb $testfile primary.db "2" $str + gets $did str + do_join_subdb $testfile primary.db "3" $str + gets $did str + do_join_subdb $testfile primary.db "4" $str + gets $did str + do_join_subdb $testfile primary.db "1 2" $str + gets $did str + do_join_subdb $testfile primary.db "1 2 3" $str + gets $did str + do_join_subdb $testfile primary.db "1 2 3 4" $str + gets $did str + do_join_subdb $testfile primary.db "2 1" $str + gets $did str + do_join_subdb $testfile primary.db "3 2 1" $str + gets $did str + do_join_subdb $testfile primary.db "4 3 2 1" $str + gets $did str + do_join_subdb $testfile primary.db "1 3" $str + gets $did str + do_join_subdb $testfile primary.db "3 1" $str + gets $did str + do_join_subdb $testfile primary.db "1 4" $str + gets $did str + do_join_subdb $testfile primary.db "4 1" $str + gets $did str + do_join_subdb $testfile primary.db "2 3" $str + gets $did str + do_join_subdb $testfile primary.db "3 2" $str + gets $did str + do_join_subdb $testfile primary.db "2 4" $str + gets $did str + do_join_subdb $testfile primary.db "4 2" $str + gets $did str + do_join_subdb $testfile primary.db "3 4" $str + gets $did str + do_join_subdb $testfile primary.db "4 3" $str + gets $did str + do_join_subdb $testfile primary.db "2 3 4" $str + gets $did str + do_join_subdb $testfile primary.db "3 4 1" $str + gets $did str + do_join_subdb $testfile primary.db "4 2 1" $str + gets $did str + do_join_subdb $testfile primary.db "0 2 1" $str + gets $did str + do_join_subdb $testfile primary.db "3 2 0" $str + gets $did str + do_join_subdb $testfile primary.db "4 3 2 1" $str + gets $did str + do_join_subdb $testfile primary.db "4 3 0 1" $str + + close $did + } +} diff --git a/db/test/sdb007.tcl b/db/test/sdb007.tcl new file mode 100644 index 000000000..6b56fd411 --- /dev/null +++ b/db/test/sdb007.tcl @@ -0,0 +1,123 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: sdb007.tcl,v 11.13 2000/12/11 17:24:55 sue Exp $ +# +# Sub DB Test 7 {access method} +# Use the first 10,000 entries from the dictionary spread across each subdb. +# Use a different page size for every subdb. +# Insert each with self as key and data; retrieve each. +# After all are entered, retrieve all; compare output to original. +# Close file, reopen, do retrieve and re-verify. +proc subdb007 { method {nentries 10000} args } { + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + + if { [is_queue $method] == 1 } { + puts "Subdb007: skipping for method $method" + return + } + set pgindex [lsearch -exact $args "-pagesize"] + if { $pgindex != -1 } { + puts "Subdb007: skipping for specific pagesizes" + return + } + + puts "Subdb007: $method ($args) subdb tests with different pagesizes" + + # Create the database and open the dictionary + set testfile $testdir/subdb007.db + set t1 $testdir/t1 + set t2 $testdir/t2 + set t3 $testdir/t3 + set t4 $testdir/t4 + cleanup $testdir NULL + + set txn "" + set count 0 + + if { [is_record_based $method] == 1 } { + set checkfunc subdb007_recno.check + } else { + set checkfunc subdb007.check + } + puts "\tSubdb007.a: create subdbs of different page sizes" + set psize {8192 4096 2048 1024 512} + set nsubdbs [llength $psize] + for { set i 0 } { $i < $nsubdbs } { incr i } { + lappend duplist -1 + } + set newent [expr $nentries / $nsubdbs] + build_all_subdb $testfile [list $method] $psize $duplist $newent $args + + # Now we will get each key from the DB and compare the results + # to the original. + for { set subdb 0 } { $subdb < $nsubdbs } { incr subdb } { + puts "\tSubdb007.b: dump file sub$subdb.db" + set db [berkdb_open -unknown $testfile sub$subdb.db] + dump_file $db $txn $t1 $checkfunc + error_check_good db_close [$db close] 0 + + # Now compare the keys to see if they match the dictionary + # (or ints) + if { [is_record_based $method] == 1 } { + set oid [open $t2 w] + for {set i 1} {$i <= $newent} {incr i} { + puts $oid [expr $subdb * $newent + $i] + } + close $oid + file rename -force $t1 $t3 + } else { + set beg [expr $subdb * $newent] + incr beg + set end [expr $beg + $newent - 1] + filehead $end $dict $t3 $beg + filesort $t3 $t2 + filesort $t1 $t3 + } + + error_check_good Subdb007:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 + + puts "\tSubdb007.c: sub$subdb.db: close, open, and dump file" + # Now, reopen the file and run the last test again. + open_and_dump_subfile $testfile NULL $txn $t1 $checkfunc \ + dump_file_direction "-first" "-next" sub$subdb.db + if { [is_record_based $method] != 1 } { + filesort $t1 $t3 + } + + error_check_good Subdb007:diff($t2,$t3) \ + [filecmp $t2 $t3] 0 + + # Now, reopen the file and run the last test again in the + # reverse direction. + puts "\tSubdb007.d: sub$subdb.db:\ + close, open, and dump file in reverse direction" + open_and_dump_subfile $testfile NULL $txn $t1 $checkfunc \ + dump_file_direction "-last" "-prev" sub$subdb.db + + if { [is_record_based $method] != 1 } { + filesort $t1 $t3 + } + + error_check_good Subdb007:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 + } +} + +# Check function for Subdb007; keys and data are identical +proc subdb007.check { key data } { + error_check_good "key/data mismatch" $data $key +} + +proc subdb007_recno.check { key data } { +global dict +global kvals + error_check_good key"$key"_exists [info exists kvals($key)] 1 + error_check_good "key/data mismatch, key $key" $data $kvals($key) +} diff --git a/db/test/sdb008.tcl b/db/test/sdb008.tcl new file mode 100644 index 000000000..b005f0093 --- /dev/null +++ b/db/test/sdb008.tcl @@ -0,0 +1,151 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: sdb008.tcl,v 11.14 2000/08/25 14:21:53 sue Exp $ +# +# Sub DB Test 8 {access method} +# Use the first 10,000 entries from the dictionary. +# Use a different or random lorder for each subdb. +# Insert each with self as key and data; retrieve each. +# After all are entered, retrieve all; compare output to original. +# Close file, reopen, do retrieve and re-verify. +proc subdb008 { method {nentries 10000} args } { + source ./include.tcl + global rand_init + + set args [convert_args $method $args] + set omethod [convert_method $method] + + if { [is_queue $method] == 1 } { + puts "Subdb008: skipping for method $method" + return + } + + berkdb srand $rand_init + + puts "Subdb008: $method ($args) subdb lorder tests" + + # Create the database and open the dictionary + set testfile $testdir/subdb008.db + set t1 $testdir/t1 + set t2 $testdir/t2 + set t3 $testdir/t3 + set t4 $testdir/t4 + cleanup $testdir NULL + + set txn "" + set pflags "" + set gflags "" + + if { [is_record_based $method] == 1 } { + set checkfunc subdb008_recno.check + } else { + set checkfunc subdb008.check + } + set nsubdbs 4 + set lo [list 4321 1234] + puts "\tSubdb008.a: put/get loop" + # Here is the loop where we put and get each key/data pair + for { set i 0 } { $i < $nsubdbs } { incr i } { + set subdb sub$i.db + if { $i >= [llength $lo]} { + set r [berkdb random_int 0 1] + set order [lindex $lo $r] + } else { + set order [lindex $lo $i] + } + set db [eval {berkdb_open -create -mode 0644} \ + $args {-lorder $order $omethod $testfile $subdb}] + set did [open $dict] + set count 0 + while { [gets $did str] != -1 && $count < $nentries } { + if { [is_record_based $method] == 1 } { + global kvals + + set gflags "-recno" + set key [expr $i * $nentries] + set key [expr $key + $count + 1] + set kvals($key) [pad_data $method $str] + } else { + set key $str + } + set ret [eval {$db put} \ + $txn $pflags {$key [chop_data $method $str]}] + error_check_good put $ret 0 + + set ret [eval {$db get} $gflags {$key}] + error_check_good \ + get $ret [list [list $key [pad_data $method $str]]] + incr count + } + close $did + error_check_good db_close [$db close] 0 + } + + # Now we will get each key from the DB and compare the results + # to the original. + for { set subdb 0 } { $subdb < $nsubdbs } { incr subdb } { + puts "\tSubdb008.b: dump file sub$subdb.db" + set db [berkdb_open -unknown $testfile sub$subdb.db] + dump_file $db $txn $t1 $checkfunc + error_check_good db_close [$db close] 0 + + # Now compare the keys to see if they match the dictionary + # (or ints) + if { [is_record_based $method] == 1 } { + set oid [open $t2 w] + for {set i 1} {$i <= $nentries} {incr i} { + puts $oid [expr $subdb * $nentries + $i] + } + close $oid + file rename -force $t1 $t3 + } else { + set q q + filehead $nentries $dict $t3 + filesort $t3 $t2 + filesort $t1 $t3 + } + + error_check_good Subdb008:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 + + puts "\tSubdb008.c: sub$subdb.db: close, open, and dump file" + # Now, reopen the file and run the last test again. + open_and_dump_subfile $testfile NULL $txn $t1 $checkfunc \ + dump_file_direction "-first" "-next" sub$subdb.db + if { [is_record_based $method] != 1 } { + filesort $t1 $t3 + } + + error_check_good Subdb008:diff($t2,$t3) \ + [filecmp $t2 $t3] 0 + + # Now, reopen the file and run the last test again in the + # reverse direction. + puts "\tSubdb008.d: sub$subdb.db:\ + close, open, and dump file in reverse direction" + open_and_dump_subfile $testfile NULL $txn $t1 $checkfunc \ + dump_file_direction "-last" "-prev" sub$subdb.db + + if { [is_record_based $method] != 1 } { + filesort $t1 $t3 + } + + error_check_good Subdb008:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 + } +} + +# Check function for Subdb008; keys and data are identical +proc subdb008.check { key data } { + error_check_good "key/data mismatch" $data $key +} + +proc subdb008_recno.check { key data } { +global dict +global kvals + error_check_good key"$key"_exists [info exists kvals($key)] 1 + error_check_good "key/data mismatch, key $key" $data $kvals($key) +} diff --git a/db/test/sdb009.tcl b/db/test/sdb009.tcl new file mode 100644 index 000000000..060bea643 --- /dev/null +++ b/db/test/sdb009.tcl @@ -0,0 +1,77 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: sdb009.tcl,v 11.4 2000/08/25 14:21:53 sue Exp $ +# +# Subdatabase Test 9 (replacement) +# Test the DB->rename method. +proc subdb009 { method args } { + global errorCode + source ./include.tcl + set omethod [convert_method $method] + set args [convert_args $method $args] + + puts "Subdb009: $method ($args): Test of DB->rename()" + + if { [is_queue $method] == 1 } { + puts "\tSubdb009: Skipping for method $method." + return + } + + set file $testdir/subdb009.db + set oldsdb OLDDB + set newsdb NEWDB + + # Make sure we're starting from a clean slate. + cleanup $testdir NULL + error_check_bad "$file exists" [file exists $file] 1 + + puts "\tSubdb009.a: Create/rename file" + puts "\t\tSubdb009.a.1: create" + set db [eval {berkdb_open -create -mode 0644}\ + $omethod $args $file $oldsdb] + error_check_good dbopen [is_valid_db $db] TRUE + + # The nature of the key and data are unimportant; use numeric key + # so record-based methods don't need special treatment. + set key 1 + set data [pad_data $method data] + + error_check_good dbput [$db put $key $data] 0 + error_check_good dbclose [$db close] 0 + + puts "\t\tSubdb009.a.2: rename" + error_check_good rename_file [eval {berkdb dbrename} $file \ + $oldsdb $newsdb] 0 + + puts "\t\tSubdb009.a.3: check" + # Open again with create to make sure we've really completely + # disassociated the subdb from the old name. + set odb [eval {berkdb_open -create -mode 0644}\ + $omethod $args $file $oldsdb] + error_check_good odb_open [is_valid_db $odb] TRUE + set odbt [$odb get $key] + error_check_good odb_close [$odb close] 0 + + set ndb [eval {berkdb_open -create -mode 0644}\ + $omethod $args $file $newsdb] + error_check_good ndb_open [is_valid_db $ndb] TRUE + set ndbt [$ndb get $key] + error_check_good ndb_close [$ndb close] 0 + + # The DBT from the "old" database should be empty, not the "new" one. + error_check_good odbt_empty [llength $odbt] 0 + error_check_bad ndbt_empty [llength $ndbt] 0 + error_check_good ndbt [lindex [lindex $ndbt 0] 1] $data + + # Now there's both an old and a new. Rename the "new" to the "old" + # and make sure that fails. + puts "\tSubdb009.b: Make sure rename fails instead of overwriting" + set ret [catch {eval {berkdb dbrename} $file $oldsdb $newsdb} res] + error_check_bad rename_overwrite $ret 0 + error_check_good rename_overwrite_ret [is_substr $errorCode EEXIST] 1 + + puts "\tSubdb009 succeeded." +} diff --git a/db/test/sdb010.tcl b/db/test/sdb010.tcl new file mode 100644 index 000000000..6bec78d37 --- /dev/null +++ b/db/test/sdb010.tcl @@ -0,0 +1,46 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: sdb010.tcl,v 11.4 2000/08/25 14:21:53 sue Exp $ +# +# Subdatabase Test 10 {access method} +# Test of dbremove +proc subdb010 { method args } { + global errorCode + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + + puts "Subdb010: Test of DB->remove()" + + if { [is_queue $method] == 1 } { + puts "\tSubdb010: Skipping for method $method." + return + } + + cleanup $testdir NULL + + set testfile $testdir/subdb010.db + set testdb DATABASE + + set db [eval {berkdb_open -create -truncate -mode 0644} $omethod \ + $args $testfile $testdb] + error_check_good db_open [is_valid_db $db] TRUE + error_check_good db_close [$db close] 0 + + error_check_good file_exists_before [file exists $testfile] 1 + error_check_good db_remove [berkdb dbremove $testfile $testdb] 0 + + # File should still exist. + error_check_good file_exists_after [file exists $testfile] 1 + + # But database should not. + set ret [catch {eval berkdb_open $omethod $args $testfile $testdb} res] + error_check_bad open_failed ret 0 + error_check_good open_failed_ret [is_substr $errorCode ENOENT] 1 + + puts "\tSubdb010 succeeded." +} diff --git a/db/test/sdbscript.tcl b/db/test/sdbscript.tcl new file mode 100644 index 000000000..1b099520e --- /dev/null +++ b/db/test/sdbscript.tcl @@ -0,0 +1,47 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: sdbscript.tcl,v 11.7 2000/04/21 18:36:23 krinsky Exp $ +# +# Usage: subdbscript testfile subdbnumber factor +# testfile: name of DB itself +# subdbnumber: n, subdb indicator, of form sub$n.db +# factor: Delete over factor'th + n'th from my subdb. +# +# I.e. if factor is 10, and n is 0, remove entries, 0, 10, 20, ... +# if factor is 10 and n is 1, remove entries 1, 11, 21, ... +source ./include.tcl +source $test_path/test.tcl + +set usage "subdbscript testfile subdbnumber factor" + +# Verify usage +if { $argc != 3 } { + puts stderr "FAIL:[timestamp] Usage: $usage" + exit +} + +# Initialize arguments +set testfile [lindex $argv 0] +set n [ lindex $argv 1 ] +set factor [ lindex $argv 2 ] + +set db [berkdb_open -unknown $testfile sub$n.db] +error_check_good db_open [is_valid_db $db] TRUE + +set dbc [$db cursor] +error_check_good db_cursor [is_valid_cursor $dbc $db] TRUE +set i 1 +for {set d [$dbc get -first]} {[llength $d] != 0} {set d [$dbc get -next]} { + set x [expr $i - $n] + if { $x >= 0 && [expr $x % $factor] == 0 } { + puts "Deleting $d" + error_check_good dbc_del [$dbc del] 0 + } + incr i +} +error_check_good db_close [$db close] 0 + +exit diff --git a/db/test/sdbtest001.tcl b/db/test/sdbtest001.tcl new file mode 100644 index 000000000..e3ff2b032 --- /dev/null +++ b/db/test/sdbtest001.tcl @@ -0,0 +1,133 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: sdbtest001.tcl,v 11.13 2000/08/25 14:21:53 sue Exp $ +# +# Sub DB All-Method Test 1 +# Make several subdb's of different access methods all in one DB. +# Rotate methods and repeat [#762]. +# Use the first 10,000 entries from the dictionary. +# Insert each with self as key and data; retrieve each. +# After all are entered, retrieve all; compare output to original. +# Close file, reopen, do retrieve and re-verify. +proc subdbtest001 { {nentries 10000} } { + source ./include.tcl + + puts "Subdbtest001: many different subdb access methods in one" + + # Create the database and open the dictionary + set testfile $testdir/subdbtest001.db + set t1 $testdir/t1 + set t2 $testdir/t2 + set t3 $testdir/t3 + set t4 $testdir/t4 + + set txn "" + set count 0 + + # Set up various methods to rotate through + lappend method_list [list "-rrecno" "-rbtree" "-hash" "-recno" "-btree"] + lappend method_list [list "-recno" "-hash" "-btree" "-rbtree" "-rrecno"] + lappend method_list [list "-btree" "-recno" "-rbtree" "-rrecno" "-hash"] + lappend method_list [list "-hash" "-recno" "-rbtree" "-rrecno" "-btree"] + lappend method_list [list "-rbtree" "-hash" "-btree" "-rrecno" "-recno"] + lappend method_list [list "-rrecno" "-recno"] + lappend method_list [list "-recno" "-rrecno"] + lappend method_list [list "-hash" "-dhash"] + lappend method_list [list "-dhash" "-hash"] + lappend method_list [list "-rbtree" "-btree" "-dbtree" "-ddbtree"] + lappend method_list [list "-btree" "-rbtree" "-ddbtree" "-dbtree"] + lappend method_list [list "-dbtree" "-ddbtree" "-btree" "-rbtree"] + lappend method_list [list "-ddbtree" "-dbtree" "-rbtree" "-btree"] + foreach methods $method_list { + cleanup $testdir NULL + puts "\tSubdbtest001.a: create subdbs of different access methods:" + puts "\tSubdbtest001.a: $methods" + set psize {8192 4096} + set nsubdbs [llength $methods] + set duplist "" + for { set i 0 } { $i < $nsubdbs } { incr i } { + lappend duplist -1 + } + set newent [expr $nentries / $nsubdbs] + build_all_subdb $testfile $methods $psize $duplist $newent + + # Now we will get each key from the DB and compare the results + # to the original. + for { set subdb 0 } { $subdb < $nsubdbs } { incr subdb } { + + set method [lindex $methods $subdb] + set method [convert_method $method] + if { [is_record_based $method] == 1 } { + set checkfunc subdbtest001_recno.check + } else { + set checkfunc subdbtest001.check + } + + puts "\tSubdbtest001.b: dump file sub$subdb.db" + set db [berkdb_open -unknown $testfile sub$subdb.db] + dump_file $db $txn $t1 $checkfunc + error_check_good db_close [$db close] 0 + + # Now compare the keys to see if they match the + # dictionary (or ints) + if { [is_record_based $method] == 1 } { + set oid [open $t2 w] + for {set i 1} {$i <= $newent} {incr i} { + puts $oid [expr $subdb * $newent + $i] + } + close $oid + file rename -force $t1 $t3 + } else { + # filehead uses 1-based line numbers + set beg [expr $subdb * $newent] + incr beg + set end [expr $beg + $newent - 1] + filehead $end $dict $t3 $beg + filesort $t3 $t2 + filesort $t1 $t3 + } + + error_check_good Subdbtest001:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 + + puts "\tSubdbtest001.c: sub$subdb.db: close, open, and dump file" + # Now, reopen the file and run the last test again. + open_and_dump_subfile $testfile NULL $txn $t1 $checkfunc \ + dump_file_direction "-first" "-next" sub$subdb.db + if { [string compare $method "-recno"] != 0 } { + filesort $t1 $t3 + } + + error_check_good Subdbtest001:diff($t2,$t3) \ + [filecmp $t2 $t3] 0 + + # Now, reopen the file and run the last test again in the + # reverse direction. + puts "\tSubdbtest001.d: sub$subdb.db: close, open, and dump file in reverse direction" + open_and_dump_subfile $testfile NULL $txn $t1 $checkfunc \ + dump_file_direction "-last" "-prev" sub$subdb.db + + if { [string compare $method "-recno"] != 0 } { + filesort $t1 $t3 + } + + error_check_good Subdbtest001:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 + } + } +} + +# Check function for Subdbtest001; keys and data are identical +proc subdbtest001.check { key data } { + error_check_good "key/data mismatch" $data $key +} + +proc subdbtest001_recno.check { key data } { +global dict +global kvals + error_check_good key"$key"_exists [info exists kvals($key)] 1 + error_check_good "key/data mismatch, key $key" $data $kvals($key) +} diff --git a/db/test/sdbtest002.tcl b/db/test/sdbtest002.tcl new file mode 100644 index 000000000..b8bad4e70 --- /dev/null +++ b/db/test/sdbtest002.tcl @@ -0,0 +1,163 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: sdbtest002.tcl,v 11.19 2000/08/25 14:21:53 sue Exp $ +# +# Sub DB All-Method Test 2 +# Make several subdb's of different access methods all in one DB. +# Fork of some child procs to each manipulate one subdb and when +# they are finished, verify the contents of the databases. +# Use the first 10,000 entries from the dictionary. +# Insert each with self as key and data; retrieve each. +# After all are entered, retrieve all; compare output to original. +# Close file, reopen, do retrieve and re-verify. +proc subdbtest002 { {nentries 10000} } { + source ./include.tcl + + puts "Subdbtest002: many different subdb access methods in one" + + # Create the database and open the dictionary + set testfile $testdir/subdbtest002.db + set t1 $testdir/t1 + set t2 $testdir/t2 + set t3 $testdir/t3 + set t4 $testdir/t4 + + set txn "" + set count 0 + + # Set up various methods to rotate through + set methods \ + [list "-rbtree" "-recno" "-btree" "-btree" "-recno" "-rbtree"] + cleanup $testdir NULL + puts "\tSubdbtest002.a: create subdbs of different access methods:" + puts "\t\t$methods" + set psize {8192 4096} + set nsubdbs [llength $methods] + set duplist "" + for { set i 0 } { $i < $nsubdbs } { incr i } { + lappend duplist -1 + } + set newent [expr $nentries / $nsubdbs] + + # + # XXX We need dict sorted to figure out what was deleted + # since things are stored sorted in the btree. + # + filesort $dict $t4 + set dictorig $dict + set dict $t4 + + build_all_subdb $testfile $methods $psize $duplist $newent + + # Now we will get each key from the DB and compare the results + # to the original. + set pidlist "" + puts "\tSubdbtest002.b: create $nsubdbs procs to delete some keys" + for { set subdb 0 } { $subdb < $nsubdbs } { incr subdb } { + puts "$tclsh_path\ + $test_path/sdbscript.tcl $testfile \ + $subdb $nsubdbs >& $testdir/subdb002.log.$subdb" + set p [exec $tclsh_path $test_path/wrap.tcl \ + sdbscript.tcl \ + $testdir/subdb002.log.$subdb $testfile $subdb $nsubdbs &] + lappend pidlist $p + } + watch_procs 5 + + for { set subdb 0 } { $subdb < $nsubdbs } { incr subdb } { + set method [lindex $methods $subdb] + set method [convert_method $method] + if { [is_record_based $method] == 1 } { + set checkfunc subdbtest002_recno.check + } else { + set checkfunc subdbtest002.check + } + + puts "\tSubdbtest002.b: dump file sub$subdb.db" + set db [berkdb_open -unknown $testfile sub$subdb.db] + error_check_good db_open [is_valid_db $db] TRUE + dump_file $db $txn $t1 $checkfunc + error_check_good db_close [$db close] 0 + # + # This is just so that t2 is there and empty + # since we are only appending below. + # + exec > $t2 + + # Now compare the keys to see if they match the dictionary (or ints) + if { [is_record_based $method] == 1 } { + set oid [open $t2 w] + for {set i 1} {$i <= $newent} {incr i} { + set x [expr $i - $subdb] + if { [expr $x % $nsubdbs] != 0 } { + puts $oid [expr $subdb * $newent + $i] + } + } + close $oid + file rename -force $t1 $t3 + } else { + set oid [open $t4 r] + for {set i 1} {[gets $oid line] >= 0} {incr i} { + set farr($i) $line + } + close $oid + + set oid [open $t2 w] + for {set i 1} {$i <= $newent} {incr i} { + # Sed uses 1-based line numbers + set x [expr $i - $subdb] + if { [expr $x % $nsubdbs] != 0 } { + set beg [expr $subdb * $newent] + set beg [expr $beg + $i] + puts $oid $farr($beg) + } + } + close $oid + filesort $t1 $t3 + } + + error_check_good Subdbtest002:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 + + puts "\tSubdbtest002.c: sub$subdb.db: close, open, and dump file" + # Now, reopen the file and run the last test again. + open_and_dump_subfile $testfile NULL $txn $t1 $checkfunc \ + dump_file_direction "-first" "-next" sub$subdb.db + if { [string compare $method "-recno"] != 0 } { + filesort $t1 $t3 + } + + error_check_good Subdbtest002:diff($t2,$t3) \ + [filecmp $t2 $t3] 0 + + # Now, reopen the file and run the last test again in the + # reverse direction. + puts "\tSubdbtest002.d: sub$subdb.db: close, open, and dump file in reverse direction" + open_and_dump_subfile $testfile NULL $txn $t1 $checkfunc \ + dump_file_direction "-last" "-prev" sub$subdb.db + + if { [string compare $method "-recno"] != 0 } { + filesort $t1 $t3 + } + + error_check_good Subdbtest002:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 + } + set dict $dictorig + return +} + +# Check function for Subdbtest002; keys and data are identical +proc subdbtest002.check { key data } { + error_check_good "key/data mismatch" $data $key +} + +proc subdbtest002_recno.check { key data } { +global dict +global kvals + error_check_good key"$key"_exists [info exists kvals($key)] 1 + error_check_good "key/data mismatch, key $key" $data $kvals($key) +} diff --git a/db/test/sdbutils.tcl b/db/test/sdbutils.tcl new file mode 100644 index 000000000..0cb33b286 --- /dev/null +++ b/db/test/sdbutils.tcl @@ -0,0 +1,171 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: sdbutils.tcl,v 11.9 2000/05/22 12:51:38 bostic Exp $ +# +proc build_all_subdb { dbname methods psize dups {nentries 100} {dbargs ""}} { + set nsubdbs [llength $dups] + set plen [llength $psize] + set mlen [llength $methods] + set savearg $dbargs + for {set i 0} {$i < $nsubdbs} { incr i } { + set m [lindex $methods [expr $i % $mlen]] + set dbargs $savearg + set p [lindex $psize [expr $i % $plen]] + subdb_build $dbname $nentries [lindex $dups $i] \ + $i $m $p sub$i.db $dbargs + } +} + +proc subdb_build { name nkeys ndups dup_interval method psize subdb dbargs} { + source ./include.tcl + + set dbargs [convert_args $method $dbargs] + set omethod [convert_method $method] + + puts "Method: $method" + + # Create the database and open the dictionary + set oflags "-create -mode 0644 $omethod \ + -pagesize $psize $dbargs $name $subdb" + set db [eval {berkdb_open} $oflags] + error_check_good dbopen [is_valid_db $db] TRUE + set did [open $dict] + set count 0 + if { $ndups >= 0 } { + puts "\tBuilding $method $name $subdb. \ + $nkeys keys with $ndups duplicates at interval of $dup_interval" + } + if { $ndups < 0 } { + puts "\tBuilding $method $name $subdb. \ + $nkeys unique keys of pagesize $psize" + # + # If ndups is < 0, we want unique keys in each subdb, + # so skip ahead in the dict by nkeys * iteration + # + for { set count 0 } \ + { $count < [expr $nkeys * $dup_interval] } { + incr count} { + set ret [gets $did str] + if { $ret == -1 } { + break + } + } + } + for { set count 0 } { [gets $did str] != -1 && $count < $nkeys } { + incr count} { + for { set i 0 } { $i < $ndups } { incr i } { + set data [format "%04d" [expr $i * $dup_interval]] + set ret [$db put $str [chop_data $method $data]] + error_check_good put $ret 0 + } + + if { $ndups == 0 } { + set ret [$db put $str [chop_data $method NODUP]] + error_check_good put $ret 0 + } elseif { $ndups < 0 } { + if { [is_record_based $method] == 1 } { + global kvals + + set num [expr $nkeys * $dup_interval] + set num [expr $num + $count + 1] + set ret [$db put $num [chop_data $method $str]] + set kvals($num) [pad_data $method $str] + error_check_good put $ret 0 + } else { + set ret [$db put $str [chop_data $method $str]] + error_check_good put $ret 0 + } + } + } + close $did + error_check_good close:$name [$db close] 0 +} + +proc do_join_subdb { db primary subdbs key } { + source ./include.tcl + + puts "\tJoining: $subdbs on $key" + + # Open all the databases + set p [berkdb_open -unknown $db $primary] + error_check_good "primary open" [is_valid_db $p] TRUE + + set dblist "" + set curslist "" + + foreach i $subdbs { + set jdb [berkdb_open -unknown $db sub$i.db] + error_check_good "sub$i.db open" [is_valid_db $jdb] TRUE + + lappend jlist [list $jdb $key] + lappend dblist $jdb + + } + + set join_res [eval {$p get_join} $jlist] + set ndups [llength $join_res] + + # Calculate how many dups we expect. + # We go through the list of indices. If we find a 0, then we + # expect 0 dups. For everything else, we look at pairs of numbers, + # if the are relatively prime, multiply them and figure out how + # many times that goes into 50. If they aren't relatively prime, + # take the number of times the larger goes into 50. + set expected 50 + set last 1 + foreach n $subdbs { + if { $n == 0 } { + set expected 0 + break + } + if { $last == $n } { + continue + } + + if { [expr $last % $n] == 0 || [expr $n % $last] == 0 } { + if { $n > $last } { + set last $n + set expected [expr 50 / $last] + } + } else { + set last [expr $n * $last / [gcd $n $last]] + set expected [expr 50 / $last] + } + } + + error_check_good number_of_dups:$subdbs $ndups $expected + + # + # If we get here, we have the number expected, now loop + # through each and see if it is what we expected. + # + for { set i 0 } { $i < $ndups } { incr i } { + set pair [lindex $join_res $i] + set k [lindex $pair 0] + foreach j $subdbs { + error_check_bad valid_dup:$j:$subdbs $j 0 + set kval [string trimleft $k 0] + if { [string length $kval] == 0 } { + set kval 0 + } + error_check_good \ + valid_dup:$j:$subdbs [expr $kval % $j] 0 + } + } + + error_check_good close_primary [$p close] 0 + foreach i $dblist { + error_check_good close_index:$i [$i close] 0 + } +} + +proc n_to_subname { n } { + if { $n == 0 } { + return null.db; + } else { + return sub$n.db; + } +} diff --git a/db/test/sysscript.tcl b/db/test/sysscript.tcl new file mode 100644 index 000000000..1b7545e4c --- /dev/null +++ b/db/test/sysscript.tcl @@ -0,0 +1,283 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: sysscript.tcl,v 11.12 2000/05/22 12:51:38 bostic Exp $ +# +# System integration test script. +# This script runs a single process that tests the full functionality of +# the system. The database under test contains nfiles files. Each process +# randomly generates a key and some data. Both keys and data are bimodally +# distributed between small keys (1-10 characters) and large keys (the avg +# length is indicated via the command line parameter. +# The process then decides on a replication factor between 1 and nfiles. +# It writes the key and data to that many files and tacks on the file ids +# of the files it writes to the data string. For example, let's say that +# I randomly generate the key dog and data cat. Then I pick a replication +# factor of 3. I pick 3 files from the set of n (say 1, 3, and 5). I then +# rewrite the data as 1:3:5:cat. I begin a transaction, add the key/data +# pair to each file and then commit. Notice that I may generate replication +# of the form 1:3:3:cat in which case I simply add a duplicate to file 3. +# +# Usage: sysscript dir nfiles key_avg data_avg +# +# dir: DB_HOME directory +# nfiles: number of files in the set +# key_avg: average big key size +# data_avg: average big data size + +source ./include.tcl +source $test_path/test.tcl +source $test_path/testutils.tcl + +set alphabet "abcdefghijklmnopqrstuvwxyz" +set mypid [pid] + +set usage "sysscript dir nfiles key_avg data_avg method" + +# Verify usage +if { $argc != 5 } { + puts stderr "FAIL:[timestamp] Usage: $usage" + exit +} + +puts [concat "Argc: " $argc " Argv: " $argv] + +# Initialize arguments +set dir [lindex $argv 0] +set nfiles [ lindex $argv 1 ] +set key_avg [ lindex $argv 2 ] +set data_avg [ lindex $argv 3 ] +set method [ lindex $argv 4 ] + +# Initialize seed +global rand_init +berkdb srand $rand_init + +puts "Beginning execution for $mypid" +puts "$dir DB_HOME" +puts "$nfiles files" +puts "$key_avg average key length" +puts "$data_avg average data length" + +flush stdout + +# Create local environment +set dbenv [berkdb env -txn -home $dir] +set err [catch {error_check_good $mypid:dbenv [is_substr $dbenv env] 1} ret] +if {$err != 0} { + puts $ret + return +} + +# Now open the files +for { set i 0 } { $i < $nfiles } { incr i } { + set file test044.$i.db + set db($i) [berkdb open -env $dbenv $method $file] + set err [catch {error_check_bad $mypid:dbopen $db($i) NULL} ret] + if {$err != 0} { + puts $ret + return + } + set err [catch {error_check_bad $mypid:dbopen [is_substr $db($i) \ + error] 1} ret] + if {$err != 0} { + puts $ret + return + } +} + +set record_based [is_record_based $method] +while { 1 } { + # Decide if we're going to create a big key or a small key + # We give small keys a 70% chance. + if { [berkdb random_int 1 10] < 8 } { + set k [random_data 5 0 0 $record_based] + } else { + set k [random_data $key_avg 0 0 $record_based] + } + set data [chop_data $method [random_data $data_avg 0 0]] + + set txn [$dbenv txn] + set err [catch {error_check_good $mypid:txn_begin [is_substr $txn \ + $dbenv.txn] 1} ret] + if {$err != 0} { + puts $ret + return + } + + # Open cursors + for { set f 0 } {$f < $nfiles} {incr f} { + set cursors($f) [$db($f) cursor -txn $txn] + set err [catch {error_check_good $mypid:cursor_open \ + [is_substr $cursors($f) $db($f)] 1} ret] + if {$err != 0} { + puts $ret + return + } + } + set aborted 0 + + # Check to see if key is already in database + set found 0 + for { set i 0 } { $i < $nfiles } { incr i } { + set r [$db($i) get -txn $txn $k] + set r [$db($i) get -txn $txn $k] + if { $r == "-1" } { + for {set f 0 } {$f < $nfiles} {incr f} { + set err [catch {error_check_good \ + $mypid:cursor_close \ + [$cursors($f) close] 0} ret] + if {$err != 0} { + puts $ret + return + } + } + set err [catch {error_check_good $mypid:txn_abort \ + [$txn abort] 0} ret] + if {$err != 0} { + puts $ret + return + } + set aborted 1 + set found 2 + break + } elseif { $r != "Key $k not found." } { + set found 1 + break + } + } + switch $found { + 2 { + # Transaction aborted, no need to do anything. + } + 0 { + # Key was not found, decide how much to replicate + # and then create a list of that many file IDs. + set repl [berkdb random_int 1 $nfiles] + set fset "" + for { set i 0 } { $i < $repl } {incr i} { + set f [berkdb random_int 0 [expr $nfiles - 1]] + lappend fset $f + set data [chop_data $method $f:$data] + } + + foreach i $fset { + set r [$db($i) put -txn $txn $k $data] + if {$r == "-1"} { + for {set f 0 } {$f < $nfiles} {incr f} { + set err [catch {error_check_good \ + $mypid:cursor_close \ + [$cursors($f) close] 0} ret] + if {$err != 0} { + puts $ret + return + } + } + set err [catch {error_check_good \ + $mypid:txn_abort [$txn abort] 0} ret] + if {$err != 0} { + puts $ret + return + } + set aborted 1 + break + } + } + } + 1 { + # Key was found. Make sure that all the data values + # look good. + set f [zero_list $nfiles] + set data $r + while { [set ndx [string first : $r]] != -1 } { + set fnum [string range $r 0 [expr $ndx - 1]] + if { [lindex $f $fnum] == 0 } { + #set flag -set + set full [record $cursors($fnum) get -set $k] + } else { + #set flag -next + set full [record $cursors($fnum) get -next] + } + if {[llength $full] == 0} { + for {set f 0 } {$f < $nfiles} {incr f} { + set err [catch {error_check_good \ + $mypid:cursor_close \ + [$cursors($f) close] 0} ret] + if {$err != 0} { + puts $ret + return + } + } + set err [catch {error_check_good \ + $mypid:txn_abort [$txn abort] 0} ret] + if {$err != 0} { + puts $ret + return + } + set aborted 1 + break + } + set err [catch {error_check_bad \ + $mypid:curs_get($k,$data,$fnum,$flag) \ + [string length $full] 0} ret] + if {$err != 0} { + puts $ret + return + } + set key [lindex [lindex $full 0] 0] + set rec [pad_data $method [lindex [lindex $full 0] 1]] + set err [catch {error_check_good \ + $mypid:dbget_$fnum:key $key $k} ret] + if {$err != 0} { + puts $ret + return + } + set err [catch {error_check_good \ + $mypid:dbget_$fnum:data($k) $rec $data} ret] + if {$err != 0} { + puts $ret + return + } + set f [lreplace $f $fnum $fnum 1] + incr ndx + set r [string range $r $ndx end] + } + } + } + if { $aborted == 0 } { + for {set f 0 } {$f < $nfiles} {incr f} { + set err [catch {error_check_good $mypid:cursor_close \ + [$cursors($f) close] 0} ret] + if {$err != 0} { + puts $ret + return + } + } + set err [catch {error_check_good $mypid:commit [$txn commit] \ + 0} ret] + if {$err != 0} { + puts $ret + return + } + } +} + +# Close files +for { set i 0 } { $i < $nfiles} { incr i } { + set r [$db($i) close] + set err [catch {error_check_good $mypid:db_close:$i $r 0} ret] + if {$err != 0} { + puts $ret + return + } +} + +# Close tm and environment +$dbenv close + +puts "[timestamp] [pid] Complete" +flush stdout + +filecheck $file 0 diff --git a/db/test/test.tcl b/db/test/test.tcl new file mode 100644 index 000000000..7678f2fcb --- /dev/null +++ b/db/test/test.tcl @@ -0,0 +1,1297 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test.tcl,v 11.114 2001/01/09 21:28:52 sue Exp $ + +source ./include.tcl + +# Load DB's TCL API. +load $tcllib + +if { [file exists $testdir] != 1 } { + file mkdir $testdir +} + +global __debug_print +global __debug_on +global util_path + +# +# Test if utilities work to figure out the path. Most systems +# use ., but QNX has a problem with execvp of shell scripts which +# causes it to break. +# +set stat [catch {exec ./db_printlog -?} ret] +if { [string first "exec format error" $ret] != -1 } { + set util_path ./.libs +} else { + set util_path . +} +set __debug_print 0 +set __debug_on 0 + +# This is where the test numbering and parameters now live. +source $test_path/testparams.tcl + +for { set i 1 } { $i <= $deadtests } {incr i} { + set name [format "dead%03d.tcl" $i] + source $test_path/$name +} +for { set i 1 } { $i <= $envtests } {incr i} { + set name [format "env%03d.tcl" $i] + source $test_path/$name +} +for { set i 1 } { $i <= $recdtests } {incr i} { + set name [format "recd%03d.tcl" $i] + source $test_path/$name +} +for { set i 1 } { $i <= $rpctests } {incr i} { + set name [format "rpc%03d.tcl" $i] + source $test_path/$name +} +for { set i 1 } { $i <= $rsrctests } {incr i} { + set name [format "rsrc%03d.tcl" $i] + source $test_path/$name +} +for { set i 1 } { $i <= $runtests } {incr i} { + set name [format "test%03d.tcl" $i] + # Test numbering may be sparse. + if { [file exists $test_path/$name] == 1 } { + source $test_path/$name + } +} +for { set i 1 } { $i <= $subdbtests } {incr i} { + set name [format "sdb%03d.tcl" $i] + source $test_path/$name +} + +source $test_path/archive.tcl +source $test_path/byteorder.tcl +source $test_path/dbm.tcl +source $test_path/hsearch.tcl +source $test_path/join.tcl +source $test_path/lock001.tcl +source $test_path/lock002.tcl +source $test_path/lock003.tcl +source $test_path/log.tcl +source $test_path/logtrack.tcl +source $test_path/mpool.tcl +source $test_path/mutex.tcl +source $test_path/ndbm.tcl +source $test_path/sdbtest001.tcl +source $test_path/sdbtest002.tcl +source $test_path/sdbutils.tcl +source $test_path/testutils.tcl +source $test_path/txn.tcl +source $test_path/upgrade.tcl + +set dict $test_path/wordlist +set alphabet "abcdefghijklmnopqrstuvwxyz" + +# Random number seed. +global rand_init +set rand_init 1013 + +# Default record length and padding character for +# fixed record length access method(s) +set fixed_len 20 +set fixed_pad 0 + +set recd_debug 0 +set log_log_record_types 0 +set ohandles {} + +# Set up any OS-specific values +global tcl_platform +set is_windows_test [is_substr $tcl_platform(os) "Win"] +set is_hp_test [is_substr $tcl_platform(os) "HP-UX"] +set is_qnx_test [is_substr $tcl_platform(os) "QNX"] + +# From here on out, test.tcl contains the procs that are used to +# run all or part of the test suite. + +proc run_am { } { + global runtests + source ./include.tcl + + fileremove -f ALL.OUT + + # Access method tests. + # + # XXX + # Broken up into separate tclsh instantiations so we don't require + # so much memory. + foreach i "btree rbtree hash queue queueext recno frecno rrecno" { + puts "Running $i tests" + for { set j 1 } { $j <= $runtests } {incr j} { + if [catch {exec $tclsh_path \ + << "source $test_path/test.tcl; \ + run_method -$i $j $j" >>& ALL.OUT } res] { + set o [open ALL.OUT a] + puts $o "FAIL: [format "test%03d" $j] $i" + close $o + } + } + if [catch {exec $tclsh_path \ + << "source $test_path/test.tcl; \ + subdb -$i 0 1" >>& ALL.OUT } res] { + set o [open ALL.OUT a] + puts $o "FAIL: subdb -$i test" + close $o + } + } +} + +proc run_std { args } { + global runtests + global subdbtests + source ./include.tcl + + set exflgs [eval extractflags $args] + set args [lindex $exflgs 0] + set flags [lindex $exflgs 1] + + set display 1 + set run 1 + set am_only 0 + set std_only 1 + set rflags {--} + foreach f $flags { + switch $f { + A { + set std_only 0 + } + m { + set am_only 1 + puts "run_std: access method tests only." + } + n { + set display 1 + set run 0 + set rflags [linsert $rflags 0 "-n"] + } + } + } + + if { $std_only == 1 } { + fileremove -f ALL.OUT + + set o [open ALL.OUT a] + if { $run == 1 } { + puts -nonewline "Test suite run started at: " + puts [clock format [clock seconds] -format "%H:%M %D"] + puts [berkdb version -string] + + puts -nonewline $o "Test suite run started at: " + puts $o [clock format [clock seconds] -format "%H:%M %D"] + puts $o [berkdb version -string] + } + close $o + } + + set test_list { + {"environment" "env"} + {"archive" "archive"} + {"locking" "lock"} + {"logging" "log"} + {"memory pool" "mpool"} + {"mutex" "mutex"} + {"transaction" "txn"} + {"deadlock detection" "dead"} + {"subdatabase" "subdb_gen"} + {"byte-order" "byte"} + {"recno backing file" "rsrc"} + {"DBM interface" "dbm"} + {"NDBM interface" "ndbm"} + {"Hsearch interface" "hsearch"} + } + + if { $am_only == 0 } { + + foreach pair $test_list { + set msg [lindex $pair 0] + set cmd [lindex $pair 1] + puts "Running $msg tests" + if [catch {exec $tclsh_path \ + << "source $test_path/test.tcl; r $rflags $cmd" \ + >>& ALL.OUT } res] { + set o [open ALL.OUT a] + puts $o "FAIL: $cmd test" + close $o + } + } + + # Run recovery tests. + # + # XXX These too are broken into separate tclsh instantiations + # so we don't require so much memory, but I think it's cleaner + # and more useful to do it down inside proc r than here, + # since "r recd" gets done a lot and needs to work. + puts "Running recovery tests" + if [catch {exec $tclsh_path \ + << "source $test_path/test.tcl; \ + r $rflags recd" >>& ALL.OUT } res] { + set o [open ALL.OUT a] + puts $o "FAIL: recd test" + close $o + } + + # Run join test + # + # XXX + # Broken up into separate tclsh instantiations so we don't + # require so much memory. + puts "Running join test" + foreach i "join1 join2 join3 join4 join5 join6" { + if [catch {exec $tclsh_path \ + << "source $test_path/test.tcl; r $rflags $i" \ + >>& ALL.OUT } res] { + set o [open ALL.OUT a] + puts $o "FAIL: $i test" + close $o + } + } + } + + # Access method tests. + # + # XXX + # Broken up into separate tclsh instantiations so we don't require + # so much memory. + foreach i "btree rbtree hash queue queueext recno frecno rrecno" { + puts "Running $i tests" + for { set j 1 } { $j <= $runtests } {incr j} { + if { $run == 0 } { + set o [open ALL.OUT a] + run_method -$i $j $j $display $run $o + close $o + } + if { $run } { + if [catch {exec $tclsh_path \ + << "source $test_path/test.tcl; \ + run_method -$i $j $j $display $run" \ + >>& ALL.OUT } res] { + set o [open ALL.OUT a] + puts $o \ + "FAIL: [format "test%03d" $j] $i" + close $o + } + } + } + if [catch {exec $tclsh_path \ + << "source $test_path/test.tcl; \ + subdb -$i $display $run" >>& ALL.OUT } res] { + set o [open ALL.OUT a] + puts $o "FAIL: subdb -$i test" + close $o + } + } + + # If not actually running, no need to check for failure. + # If running in the context of the larger 'run_all' we don't + # check for failure here either. + if { $run == 0 || $std_only == 0 } { + return + } + + set failed 0 + set o [open ALL.OUT r] + while { [gets $o line] >= 0 } { + if { [regexp {^FAIL} $line] != 0 } { + set failed 1 + } + } + close $o + set o [open ALL.OUT a] + if { $failed == 0 } { + puts "Regression Tests Succeeded" + puts $o "Regression Tests Succeeded" + } else { + puts "Regression Tests Failed; see ALL.OUT for log" + puts $o "Regression Tests Failed" + } + + puts -nonewline "Test suite run completed at: " + puts [clock format [clock seconds] -format "%H:%M %D"] + puts -nonewline $o "Test suite run completed at: " + puts $o [clock format [clock seconds] -format "%H:%M %D"] + close $o +} + +proc r { args } { + global envtests + global recdtests + global subdbtests + global deadtests + source ./include.tcl + + set exflgs [eval extractflags $args] + set args [lindex $exflgs 0] + set flags [lindex $exflgs 1] + + set display 1 + set run 1 + set saveflags "--" + foreach f $flags { + switch $f { + n { + set display 1 + set run 0 + set saveflags "-n $saveflags" + } + } + } + + if {[catch { + set l [ lindex $args 0 ] + switch $l { + archive { + if { $display } { + puts "eval archive [lrange $args 1 end]" + } + if { $run } { + check_handles + eval archive [lrange $args 1 end] + } + } + byte { + foreach method \ + "-hash -btree -recno -queue -queueext -frecno" { + if { $display } { + puts "byteorder $method" + } + if { $run } { + check_handles + byteorder $method + } + } + } + dbm { + if { $display } { + puts "dbm" + } + if { $run } { + check_handles + dbm + } + } + dead { + for { set i 1 } { $i <= $deadtests } \ + { incr i } { + if { $display } { + puts "eval dead00$i\ + [lrange $args 1 end]" + } + if { $run } { + check_handles + eval dead00$i\ + [lrange $args 1 end] + } + } + } + env { + for { set i 1 } { $i <= $envtests } {incr i} { + if { $display } { + puts "eval env00$i" + } + if { $run } { + check_handles + eval env00$i + } + } + } + hsearch { + if { $display } { puts "hsearch" } + if { $run } { + check_handles + hsearch + } + } + join { + eval r $saveflags join1 + eval r $saveflags join2 + eval r $saveflags join3 + eval r $saveflags join4 + eval r $saveflags join5 + eval r $saveflags join6 + } + join1 { + if { $display } { puts jointest } + if { $run } { + check_handles + jointest + } + } + joinbench { + puts "[timestamp]" + eval r $saveflags join1 + eval r $saveflags join2 + puts "[timestamp]" + } + join2 { + if { $display } { puts "jointest 512" } + if { $run } { + check_handles + jointest 512 + } + } + join3 { + if { $display } { + puts "jointest 8192 0 -join_item" + } + if { $run } { + check_handles + jointest 8192 0 -join_item + } + } + join4 { + if { $display } { puts "jointest 8192 2" } + if { $run } { + check_handles + jointest 8192 2 + } + } + join5 { + if { $display } { puts "jointest 8192 3" } + if { $run } { + check_handles + jointest 8192 3 + } + } + join6 { + if { $display } { puts "jointest 512 3" } + if { $run } { + check_handles + jointest 512 3 + } + } + lock { + if { $display } { + puts \ + "eval locktest [lrange $args 1 end]" + } + if { $run } { + check_handles + eval locktest [lrange $args 1 end] + } + } + log { + if { $display } { + puts "eval logtest [lrange $args 1 end]" + } + if { $run } { + check_handles + eval logtest [lrange $args 1 end] + } + } + mpool { + eval r $saveflags mpool1 + eval r $saveflags mpool2 + eval r $saveflags mpool3 + } + mpool1 { + if { $display } { + puts "eval mpool [lrange $args 1 end]" + } + if { $run } { + check_handles + eval mpool [lrange $args 1 end] + } + } + mpool2 { + if { $display } { + puts "eval mpool\ + -mem system [lrange $args 1 end]" + } + if { $run } { + check_handles + eval mpool\ + -mem system [lrange $args 1 end] + } + } + mpool3 { + if { $display } { + puts "eval mpool\ + -mem private [lrange $args 1 end]" + } + if { $run } { + eval mpool\ + -mem private [lrange $args 1 end] + } + } + mutex { + if { $display } { + puts "eval mutex [lrange $args 1 end]" + } + if { $run } { + check_handles + eval mutex [lrange $args 1 end] + } + } + ndbm { + if { $display } { puts ndbm } + if { $run } { + check_handles + ndbm + } + } + recd { + if { $display } { puts run_recds } + if { $run } { + check_handles + run_recds + } + } + rpc { + # RPC must be run as one unit due to server, + # so just print "r rpc" in the display case. + if { $display } { puts "r rpc" } + if { $run } { + check_handles + eval rpc001 + check_handles + eval rpc002 + if { [catch {run_rpcmethod -txn} ret]\ + != 0 } { + puts $ret + } + foreach method \ + "hash queue queueext recno frecno rrecno rbtree btree" { + if { [catch {run_rpcmethod \ + -$method} ret] != 0 } { + puts $ret + } + } + } + } + rsrc { + if { $display } { puts "rsrc001\nrsrc002" } + if { $run } { + check_handles + rsrc001 + check_handles + rsrc002 + } + } + subdb { + eval r $saveflags subdb_gen + + foreach method \ + "btree rbtree hash queue queueext recno frecno rrecno" { + check_handles + eval subdb -$method $display $run + } + } + subdb_gen { + if { $display } { + puts "subdbtest001 ; verify_dir" + puts "subdbtest002 ; verify_dir" + } + if { $run } { + check_handles + eval subdbtest001 + verify_dir + check_handles + eval subdbtest002 + verify_dir + } + } + txn { + if { $display } { + puts "txntest [lrange $args 1 end]" + } + if { $run } { + check_handles + eval txntest [lrange $args 1 end] + } + } + + btree - + rbtree - + hash - + queue - + queueext - + recno - + frecno - + rrecno { + eval run_method [lindex $args 0] \ + 1 0 $display $run [lrange $args 1 end] + } + + default { + error \ + "FAIL:[timestamp] r: $args: unknown command" + } + } + flush stdout + flush stderr + } res] != 0} { + global errorInfo; + + set fnl [string first "\n" $errorInfo] + set theError [string range $errorInfo 0 [expr $fnl - 1]] + if {[string first FAIL $errorInfo] == -1} { + error "FAIL:[timestamp] r: $args: $theError" + } else { + error $theError; + } + } +} + +proc run_method { method {start 1} {stop 0} {display 0} {run 1} \ + { outfile stdout } args } { + global __debug_on + global __debug_print + global parms + global runtests + source ./include.tcl + + if { $stop == 0 } { + set stop $runtests + } + if { $run == 1 } { + puts $outfile "run_method: $method $start $stop $args" + } + + if {[catch { + for { set i $start } { $i <= $stop } {incr i} { + set name [format "test%03d" $i] + if { [info exists parms($name)] != 1 } { + puts "[format Test%03d $i] disabled in\ + testparams.tcl; skipping." + continue + } + if { $display } { + puts -nonewline $outfile "eval $name $method" + puts -nonewline $outfile " $parms($name) $args" + puts $outfile " ; verify_dir $testdir \"\" 1" + } + if { $run } { + check_handles $outfile + puts $outfile "[timestamp]" + eval $name $method $parms($name) $args + if { $__debug_print != 0 } { + puts $outfile "" + } + # verify all databases the test leaves behind + verify_dir $testdir "" 1 + if { $__debug_on != 0 } { + debug + } + } + flush stdout + flush stderr + } + } res] != 0} { + global errorInfo; + + set fnl [string first "\n" $errorInfo] + set theError [string range $errorInfo 0 [expr $fnl - 1]] + if {[string first FAIL $errorInfo] == -1} { + error "FAIL:[timestamp]\ + run_method: $method $i: $theError" + } else { + error $theError; + } + } +} + +proc run_rpcmethod { type {start 1} {stop 0} {largs ""} } { + global __debug_on + global __debug_print + global parms + global runtests + source ./include.tcl + + if { $stop == 0 } { + set stop $runtests + } + puts "run_rpcmethod: $type $start $stop $largs" + + set save_largs $largs + if { [string compare $rpc_server "localhost"] == 0 } { + set dpid [exec $util_path/berkeley_db_svc -h $rpc_testdir &] + } else { + set dpid [exec rsh $rpc_server $rpc_path/berkeley_db_svc \ + -h $rpc_testdir &] + } + puts "\tRun_rpcmethod.a: starting server, pid $dpid" + tclsleep 2 + remote_cleanup $rpc_server $rpc_testdir $testdir + + set home [file tail $rpc_testdir] + + set txn "" + set use_txn 0 + if { [string first "txn" $type] != -1 } { + set use_txn 1 + } + if { $use_txn == 1 } { + if { $start == 1 } { + set ntxns 32 + } else { + set ntxns $start + } + set i 1 + check_handles + remote_cleanup $rpc_server $rpc_testdir $testdir + set env [eval {berkdb env -create -mode 0644 -home $home \ + -server $rpc_server -client_timeout 10000} -txn] + error_check_good env_open [is_valid_env $env] TRUE + + set stat [catch {eval txn001_suba $ntxns $env} res] + if { $stat == 0 } { + set stat [catch {eval txn001_subb $ntxns $env} res] + } + error_check_good envclose [$env close] 0 + } else { + set stat [catch { + for { set i $start } { $i <= $stop } {incr i} { + check_handles + set name [format "test%03d" $i] + if { [info exists parms($name)] != 1 } { + puts "[format Test%03d $i] disabled in\ + testparams.tcl; skipping." + continue + } + remote_cleanup $rpc_server $rpc_testdir $testdir + # + # Set server cachesize to 1Mb. Otherwise some + # tests won't fit (like test084 -btree). + # + set env [eval {berkdb env -create -mode 0644 \ + -home $home -server $rpc_server \ + -client_timeout 10000 \ + -cachesize {0 1048576 1} }] + error_check_good env_open \ + [is_valid_env $env] TRUE + append largs " -env $env " + + puts "[timestamp]" + eval $name $type $parms($name) $largs + if { $__debug_print != 0 } { + puts "" + } + if { $__debug_on != 0 } { + debug + } + flush stdout + flush stderr + set largs $save_largs + error_check_good envclose [$env close] 0 + } + } res] + } + if { $stat != 0} { + global errorInfo; + + set fnl [string first "\n" $errorInfo] + set theError [string range $errorInfo 0 [expr $fnl - 1]] + exec $KILL $dpid + if {[string first FAIL $errorInfo] == -1} { + error "FAIL:[timestamp]\ + run_rpcmethod: $type $i: $theError" + } else { + error $theError; + } + } + exec $KILL $dpid + +} + +proc run_rpcnoserver { type {start 1} {stop 0} {largs ""} } { + global __debug_on + global __debug_print + global parms + global runtests + source ./include.tcl + + if { $stop == 0 } { + set stop $runtests + } + puts "run_rpcnoserver: $type $start $stop $largs" + + set save_largs $largs + remote_cleanup $rpc_server $rpc_testdir $testdir + set home [file tail $rpc_testdir] + + set txn "" + set use_txn 0 + if { [string first "txn" $type] != -1 } { + set use_txn 1 + } + if { $use_txn == 1 } { + if { $start == 1 } { + set ntxns 32 + } else { + set ntxns $start + } + set i 1 + check_handles + remote_cleanup $rpc_server $rpc_testdir $testdir + set env [eval {berkdb env -create -mode 0644 -home $home \ + -server $rpc_server -client_timeout 10000} -txn] + error_check_good env_open [is_valid_env $env] TRUE + + set stat [catch {eval txn001_suba $ntxns $env} res] + if { $stat == 0 } { + set stat [catch {eval txn001_subb $ntxns $env} res] + } + error_check_good envclose [$env close] 0 + } else { + set stat [catch { + for { set i $start } { $i <= $stop } {incr i} { + check_handles + set name [format "test%03d" $i] + if { [info exists parms($name)] != 1 } { + puts "[format Test%03d $i] disabled in\ + testparams.tcl; skipping." + continue + } + remote_cleanup $rpc_server $rpc_testdir $testdir + # + # Set server cachesize to 1Mb. Otherwise some + # tests won't fit (like test084 -btree). + # + set env [eval {berkdb env -create -mode 0644 \ + -home $home -server $rpc_server \ + -client_timeout 10000 \ + -cachesize {0 1048576 1} }] + error_check_good env_open \ + [is_valid_env $env] TRUE + append largs " -env $env " + + puts "[timestamp]" + eval $name $type $parms($name) $largs + if { $__debug_print != 0 } { + puts "" + } + if { $__debug_on != 0 } { + debug + } + flush stdout + flush stderr + set largs $save_largs + error_check_good envclose [$env close] 0 + } + } res] + } + if { $stat != 0} { + global errorInfo; + + set fnl [string first "\n" $errorInfo] + set theError [string range $errorInfo 0 [expr $fnl - 1]] + if {[string first FAIL $errorInfo] == -1} { + error "FAIL:[timestamp]\ + run_rpcnoserver: $type $i: $theError" + } else { + error $theError; + } + } + +} + +# +# Run method tests in one environment. (As opposed to run_envmethod1 +# which runs each test in its own, new environment.) +# +proc run_envmethod { type {start 1} {stop 0} {largs ""} } { + global __debug_on + global __debug_print + global parms + global runtests + source ./include.tcl + + if { $stop == 0 } { + set stop $runtests + } + puts "run_envmethod: $type $start $stop $largs" + + set save_largs $largs + env_cleanup $testdir + set txn "" + set stat [catch { + for { set i $start } { $i <= $stop } {incr i} { + check_handles + set env [eval {berkdb env -create -mode 0644 \ + -home $testdir}] + error_check_good env_open [is_valid_env $env] TRUE + append largs " -env $env " + + puts "[timestamp]" + set name [format "test%03d" $i] + if { [info exists parms($name)] != 1 } { + puts "[format Test%03d $i] disabled in\ + testparams.tcl; skipping." + continue + } + eval $name $type $parms($name) $largs + if { $__debug_print != 0 } { + puts "" + } + if { $__debug_on != 0 } { + debug + } + flush stdout + flush stderr + set largs $save_largs + error_check_good envclose [$env close] 0 + error_check_good envremove [berkdb envremove \ + -home $testdir] 0 + } + } res] + if { $stat != 0} { + global errorInfo; + + set fnl [string first "\n" $errorInfo] + set theError [string range $errorInfo 0 [expr $fnl - 1]] + if {[string first FAIL $errorInfo] == -1} { + error "FAIL:[timestamp]\ + run_envmethod: $type $i: $theError" + } else { + error $theError; + } + } + +} + +proc subdb { method display run {outfile stdout} args} { + global subdbtests testdir + global parms + + for { set i 1 } {$i <= $subdbtests} {incr i} { + set name [format "subdb%03d" $i] + if { [info exists parms($name)] != 1 } { + puts "[format Subdb%03d $i] disabled in\ + testparams.tcl; skipping." + continue + } + if { $display } { + puts -nonewline $outfile "eval $name $method" + puts -nonewline $outfile " $parms($name) $args;" + puts $outfile "verify_dir $testdir \"\" 1" + } + if { $run } { + check_handles $outfile + eval $name $method $parms($name) $args + verify_dir $testdir "" 1 + } + flush stdout + flush stderr + } +} + +proc run_recd { method {start 1} {stop 0} args } { + global __debug_on + global __debug_print + global parms + global recdtests + global log_log_record_types + source ./include.tcl + + if { $stop == 0 } { + set stop $recdtests + } + puts "run_recd: $method $start $stop $args" + + if {[catch { + for { set i $start } { $i <= $stop } {incr i} { + check_handles + puts "[timestamp]" + set name [format "recd%03d" $i] + # By redirecting stdout to stdout, we make exec + # print output rather than simply returning it. + exec $tclsh_path << "source $test_path/test.tcl; \ + set log_log_record_types $log_log_record_types; \ + eval $name $method" >@ stdout + if { $__debug_print != 0 } { + puts "" + } + if { $__debug_on != 0 } { + debug + } + flush stdout + flush stderr + } + } res] != 0} { + global errorInfo; + + set fnl [string first "\n" $errorInfo] + set theError [string range $errorInfo 0 [expr $fnl - 1]] + if {[string first FAIL $errorInfo] == -1} { + error "FAIL:[timestamp]\ + run_recd: $method $i: $theError" + } else { + error $theError; + } + } +} + +proc run_recds { } { + global log_log_record_types + + set log_log_record_types 1 + logtrack_init + foreach method \ + "btree rbtree hash queue queueext recno frecno rrecno" { + check_handles + if { [catch \ + {run_recd -$method} ret ] != 0 } { + puts $ret + } + } + logtrack_summary + set log_log_record_types 0 +} + +proc run_all { args } { + global runtests + global subdbtests + source ./include.tcl + + fileremove -f ALL.OUT + + set exflgs [eval extractflags $args] + set flags [lindex $exflgs 1] + set display 1 + set run 1 + set am_only 0 + set rflags {--} + foreach f $flags { + switch $f { + m { + set am_only 1 + } + n { + set display 1 + set run 0 + set rflags [linsert $rflags 0 "-n"] + } + } + } + + set o [open ALL.OUT a] + if { $run == 1 } { + puts -nonewline "Test suite run started at: " + puts [clock format [clock seconds] -format "%H:%M %D"] + puts [berkdb version -string] + + puts -nonewline $o "Test suite run started at: " + puts $o [clock format [clock seconds] -format "%H:%M %D"] + puts $o [berkdb version -string] + } + close $o + # + # First run standard tests. Send in a -A to let run_std know + # that it is part of the "run_all" run, so that it doesn't + # print out start/end times. + # + lappend args -A + eval {run_std} $args + + set test_pagesizes { 512 8192 65536 } + set args [lindex $exflgs 0] + set save_args $args + + foreach pgsz $test_pagesizes { + set args $save_args + append args " -pagesize $pgsz" + if { $am_only == 0 } { + # Run recovery tests. + # + # XXX These too are broken into separate tclsh + # instantiations so we don't require so much + # memory, but I think it's cleaner + # and more useful to do it down inside proc r than here, + # since "r recd" gets done a lot and needs to work. + puts "Running recovery tests with pagesize $pgsz" + if [catch {exec $tclsh_path \ + << "source $test_path/test.tcl; \ + r $rflags recd $args" >>& ALL.OUT } res] { + set o [open ALL.OUT a] + puts $o "FAIL: recd test" + close $o + } + } + + # Access method tests. + # + # XXX + # Broken up into separate tclsh instantiations so + # we don't require so much memory. + foreach i \ + "btree rbtree hash queue queueext recno frecno rrecno" { + puts "Running $i tests with pagesize $pgsz" + for { set j 1 } { $j <= $runtests } {incr j} { + if { $run == 0 } { + set o [open ALL.OUT a] + run_method -$i $j $j $display \ + $run $o $args + close $o + } + if { $run } { + if [catch {exec $tclsh_path \ + << "source $test_path/test.tcl; \ + run_method -$i $j $j $display \ + $run stdout $args" \ + >>& ALL.OUT } res] { + set o [open ALL.OUT a] + puts $o \ + "FAIL: [format \ + "test%03d" $j] $i" + close $o + } + } + } + + # + # Run subdb tests with varying pagesizes too. + # + if { $run == 0 } { + set o [open ALL.OUT a] + subdb -$i $display $run $o $args + close $o + } + if { $run == 1 } { + if [catch {exec $tclsh_path \ + << "source $test_path/test.tcl; \ + subdb -$i $display $run stdout $args" \ + >>& ALL.OUT } res] { + set o [open ALL.OUT a] + puts $o "FAIL: subdb -$i test" + close $o + } + } + } + } + set args $save_args + # + # Run access method tests at default page size in one env. + # + foreach i "btree rbtree hash queue queueext recno frecno rrecno" { + puts "Running $i tests in an env" + if { $run == 0 } { + set o [open ALL.OUT a] + run_envmethod1 -$i 1 $runtests $display \ + $run $o $args + close $o + } + if { $run } { + if [catch {exec $tclsh_path \ + << "source $test_path/test.tcl; \ + run_envmethod1 -$i 1 $runtests $display \ + $run stdout $args" \ + >>& ALL.OUT } res] { + set o [open ALL.OUT a] + puts $o \ + "FAIL: run_envmethod1 $i" + close $o + } + } + } + + # If not actually running, no need to check for failure. + if { $run == 0 } { + return + } + + set failed 0 + set o [open ALL.OUT r] + while { [gets $o line] >= 0 } { + if { [regexp {^FAIL} $line] != 0 } { + set failed 1 + } + } + close $o + set o [open ALL.OUT a] + if { $failed == 0 } { + puts "Regression Tests Succeeded" + puts $o "Regression Tests Succeeded" + } else { + puts "Regression Tests Failed; see ALL.OUT for log" + puts $o "Regression Tests Failed" + } + + puts -nonewline "Test suite run completed at: " + puts [clock format [clock seconds] -format "%H:%M %D"] + puts -nonewline $o "Test suite run completed at: " + puts $o [clock format [clock seconds] -format "%H:%M %D"] + close $o +} + +# +# Run method tests in one environment. (As opposed to run_envmethod +# which runs each test in its own, new environment.) +# +proc run_envmethod1 { method {start 1} {stop 0} {display 0} {run 1} \ + { outfile stdout } args } { + global __debug_on + global __debug_print + global parms + global runtests + source ./include.tcl + + if { $stop == 0 } { + set stop $runtests + } + if { $run == 1 } { + puts "run_envmethod1: $method $start $stop $args" + } + + set txn "" + if { $run == 1 } { + check_handles + env_cleanup $testdir + error_check_good envremove [berkdb envremove -home $testdir] 0 + set env [eval {berkdb env -create -mode 0644 -home $testdir}] + error_check_good env_open [is_valid_env $env] TRUE + append largs " -env $env " + } + + set stat [catch { + for { set i $start } { $i <= $stop } {incr i} { + set name [format "test%03d" $i] + if { [info exists parms($name)] != 1 } { + puts "[format Test%03d $i] disabled in\ + testparams.tcl; skipping." + continue + } + if { $display } { + puts -nonewline $outfile "eval $name $method" + puts -nonewline $outfile " $parms($name) $args" + puts $outfile " ; verify_dir $testdir \"\" 1" + } + if { $run } { + check_handles $outfile + puts $outfile "[timestamp]" + eval $name $method $parms($name) $largs + if { $__debug_print != 0 } { + puts $outfile "" + } + if { $__debug_on != 0 } { + debug + } + } + flush stdout + flush stderr + } + } res] + if { $run == 1 } { + error_check_good envclose [$env close] 0 + } + if { $stat != 0} { + global errorInfo; + + set fnl [string first "\n" $errorInfo] + set theError [string range $errorInfo 0 [expr $fnl - 1]] + if {[string first FAIL $errorInfo] == -1} { + error "FAIL:[timestamp]\ + run_envmethod1: $method $i: $theError" + } else { + error $theError; + } + } + +} diff --git a/db/test/test001.tcl b/db/test/test001.tcl new file mode 100644 index 000000000..fa8e112d1 --- /dev/null +++ b/db/test/test001.tcl @@ -0,0 +1,157 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test001.tcl,v 11.17 2000/12/06 16:08:05 bostic Exp $ +# +# DB Test 1 {access method} +# Use the first 10,000 entries from the dictionary. +# Insert each with self as key and data; retrieve each. +# After all are entered, retrieve all; compare output to original. +# Close file, reopen, do retrieve and re-verify. +proc test001 { method {nentries 10000} {start 0} {tnum "01"} args } { + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + + puts "Test0$tnum: $method ($args) $nentries equal key/data pairs" + if { $start != 0 } { + puts "\tStarting at $start" + } + + # Create the database and open the dictionary + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test0$tnum.db + set env NULL + } else { + set testfile test0$tnum.db + incr eindex + set env [lindex $args $eindex] + } + set t1 $testdir/t1 + set t2 $testdir/t2 + set t3 $testdir/t3 + cleanup $testdir $env + set db [eval {berkdb_open \ + -create -truncate -mode 0644} $args $omethod $testfile] + error_check_good dbopen [is_valid_db $db] TRUE + set did [open $dict] + + set pflags "" + set gflags "" + set txn "" + + set nentries [expr $nentries + $start] + + if { [is_record_based $method] == 1 } { + set checkfunc test001_recno.check + append gflags " -recno" + } else { + set checkfunc test001.check + } + puts "\tTest0$tnum.a: put/get loop" + # Here is the loop where we put and get each key/data pair + set count $start + while { [gets $did str] != -1 && $count < $nentries } { + if { [is_record_based $method] == 1 } { + global kvals + + set key [expr $count + 1] + set kvals($key) [pad_data $method $str] + } else { + set key $str + set str [reverse $str] + } + set ret [eval \ + {$db put} $txn $pflags {$key [chop_data $method $str]}] + error_check_good put $ret 0 + + set ret [eval {$db get} $gflags {$key}] + error_check_good \ + get $ret [list [list $key [pad_data $method $str]]] + + # Test DB_GET_BOTH for success + set ret [$db get -get_both $key [pad_data $method $str]] + error_check_good \ + getboth $ret [list [list $key [pad_data $method $str]]] + + # Test DB_GET_BOTH for failure + set ret [$db get -get_both $key [pad_data $method BAD$str]] + error_check_good getbothBAD [llength $ret] 0 + + incr count + if { [expr $count + 1] == 0 } { + incr count + } + } + close $did + # Now we will get each key from the DB and compare the results + # to the original. + puts "\tTest0$tnum.b: dump file" + dump_file $db $txn $t1 $checkfunc + error_check_good db_close [$db close] 0 + + # Now compare the keys to see if they match the dictionary (or ints) + if { [is_record_based $method] == 1 } { + set oid [open $t2 w] + for {set i [expr $start + 1]} {$i <= $nentries} {set i [incr i]} { + if { $i == 0 } { + incr i + } + puts $oid $i + } + close $oid + } else { + set q q + filehead $nentries $dict $t2 + } + filesort $t2 $t3 + file rename -force $t3 $t2 + filesort $t1 $t3 + + error_check_good Test0$tnum:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 + + puts "\tTest0$tnum.c: close, open, and dump file" + # Now, reopen the file and run the last test again. + open_and_dump_file $testfile $env $txn $t1 $checkfunc \ + dump_file_direction "-first" "-next" + if { [string compare $omethod "-recno"] != 0 } { + filesort $t1 $t3 + } + + error_check_good Test0$tnum:diff($t2,$t3) \ + [filecmp $t2 $t3] 0 + + # Now, reopen the file and run the last test again in the + # reverse direction. + puts "\tTest0$tnum.d: close, open, and dump file in reverse direction" + open_and_dump_file $testfile $env $txn $t1 $checkfunc \ + dump_file_direction "-last" "-prev" + + if { [string compare $omethod "-recno"] != 0 } { + filesort $t1 $t3 + } + + error_check_good Test0$tnum:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 +} + +# Check function for test001; keys and data are identical +proc test001.check { key data } { + error_check_good "key/data mismatch" $data [reverse $key] +} + +proc test001_recno.check { key data } { + global dict + global kvals + + error_check_good key"$key"_exists [info exists kvals($key)] 1 + error_check_good "key/data mismatch, key $key" $data $kvals($key) +} diff --git a/db/test/test002.tcl b/db/test/test002.tcl new file mode 100644 index 000000000..882240b77 --- /dev/null +++ b/db/test/test002.tcl @@ -0,0 +1,128 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test002.tcl,v 11.13 2000/08/25 14:21:53 sue Exp $ +# +# DB Test 2 {access method} +# Use the first 10,000 entries from the dictionary. +# Insert each with self as key and a fixed, medium length data string; +# retrieve each. After all are entered, retrieve all; compare output +# to original. Close file, reopen, do retrieve and re-verify. + +set datastr abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz + +proc test002 { method {nentries 10000} args } { + global datastr + global pad_datastr + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + + puts "Test002: $method ($args) $nentries key pairs" + + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test002.db + set env NULL + } else { + set testfile test002.db + incr eindex + set env [lindex $args $eindex] + } + # Create the database and open the dictionary + set t1 $testdir/t1 + set t2 $testdir/t2 + set t3 $testdir/t3 + cleanup $testdir $env + set db [eval {berkdb_open \ + -create -truncate -mode 0644} $args {$omethod $testfile}] + error_check_good dbopen [is_valid_db $db] TRUE + set did [open $dict] + + set pflags "" + set gflags "" + set txn "" + set count 0 + + # Here is the loop where we put and get each key/data pair + + if { [is_record_based $method] == 1 } { + append gflags "-recno" + } + set pad_datastr [pad_data $method $datastr] + puts "\tTest002.a: put/get loop" + while { [gets $did str] != -1 && $count < $nentries } { + if { [is_record_based $method] == 1 } { + set key [expr $count + 1] + } else { + set key $str + } + set ret [eval {$db put} $txn $pflags {$key [chop_data $method $datastr]}] + error_check_good put $ret 0 + + set ret [eval {$db get} $gflags {$key}] + + error_check_good get $ret [list [list $key [pad_data $method $datastr]]] + incr count + } + close $did + + # Now we will get each key from the DB and compare the results + # to the original. + puts "\tTest002.b: dump file" + dump_file $db $txn $t1 test002.check + error_check_good db_close [$db close] 0 + + # Now compare the keys to see if they match the dictionary + if { [is_record_based $method] == 1 } { + set oid [open $t2 w] + for {set i 1} {$i <= $nentries} {set i [incr i]} { + puts $oid $i + } + close $oid + filesort $t2 $t3 + file rename -force $t3 $t2 + } else { + set q q + filehead $nentries $dict $t3 + filesort $t3 $t2 + } + filesort $t1 $t3 + + error_check_good Test002:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 + + # Now, reopen the file and run the last test again. + puts "\tTest002.c: close, open, and dump file" + open_and_dump_file $testfile $env $txn $t1 test002.check \ + dump_file_direction "-first" "-next" + + if { [string compare $omethod "-recno"] != 0 } { + filesort $t1 $t3 + } + error_check_good Test002:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 + + # Now, reopen the file and run the last test again in reverse direction. + puts "\tTest002.d: close, open, and dump file in reverse direction" + open_and_dump_file $testfile $env $txn $t1 test002.check \ + dump_file_direction "-last" "-prev" + + if { [string compare $omethod "-recno"] != 0 } { + filesort $t1 $t3 + } + error_check_good Test002:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 +} + +# Check function for test002; data should be fixed are identical +proc test002.check { key data } { + global pad_datastr + error_check_good "data mismatch for key $key" $data $pad_datastr +} diff --git a/db/test/test003.tcl b/db/test/test003.tcl new file mode 100644 index 000000000..013af2d41 --- /dev/null +++ b/db/test/test003.tcl @@ -0,0 +1,177 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test003.tcl,v 11.18 2000/08/25 14:21:54 sue Exp $ +# +# DB Test 3 {access method} +# Take the source files and dbtest executable and enter their names as the +# key with their contents as data. After all are entered, retrieve all; +# compare output to original. Close file, reopen, do retrieve and re-verify. +proc test003 { method args} { + global names + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + + if {[is_fixed_length $method] == 1} { + puts "Test003 skipping for method $method" + return + } + puts "Test003: $method ($args) filename=key filecontents=data pairs" + + # Create the database and open the dictionary + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test003.db + set env NULL + } else { + set testfile test003.db + incr eindex + set env [lindex $args $eindex] + } + set t1 $testdir/t1 + set t2 $testdir/t2 + set t3 $testdir/t3 + set t4 $testdir/t4 + + cleanup $testdir $env + set db [eval {berkdb_open \ + -create -truncate -mode 0644} $args $omethod $testfile] + error_check_good dbopen [is_valid_db $db] TRUE + set pflags "" + set gflags "" + set txn "" + if { [is_record_based $method] == 1 } { + set checkfunc test003_recno.check + append gflags "-recno" + } else { + set checkfunc test003.check + } + + # Here is the loop where we put and get each key/data pair + set file_list [ glob \ + { $test_path/../*/*.[ch] } $test_path/*.tcl *.{a,o,lo,exe} \ + $test_path/file.1 ] + + puts "\tTest003.a: put/get loop" + set count 0 + foreach f $file_list { + if { [string compare [file type $f] "file"] != 0 } { + continue + } + + if { [is_record_based $method] == 1 } { + set key [expr $count + 1] + set names([expr $count + 1]) $f + } else { + set key $f + } + + # Should really catch errors + set fid [open $f r] + fconfigure $fid -translation binary + set data [read $fid] + close $fid + set ret [eval {$db put} \ + $txn $pflags {$key [chop_data $method $data]}] + error_check_good put $ret 0 + + # Should really catch errors + set fid [open $t4 w] + fconfigure $fid -translation binary + if [catch {eval {$db get} $gflags {$key}} data] { + puts -nonewline $fid $data + } else { + # Data looks like {{key data}} + set key [lindex [lindex $data 0] 0] + set data [lindex [lindex $data 0] 1] + puts -nonewline $fid [pad_data $method $data] + } + close $fid + + error_check_good \ + Test003:diff($f,$t4) [filecmp $f $t4] 0 + + incr count + } + + # Now we will get each key from the DB and compare the results + # to the original. + puts "\tTest003.b: dump file" + dump_bin_file $db $txn $t1 $checkfunc + error_check_good db_close [$db close] 0 + + # Now compare the keys to see if they match the entries in the + # current directory + if { [is_record_based $method] == 1 } { + set oid [open $t2 w] + for {set i 1} {$i <= $count} {set i [incr i]} { + puts $oid $i + } + close $oid + file rename -force $t1 $t3 + } else { + set oid [open $t2.tmp w] + foreach f $file_list { + if { [string compare [file type $f] "file"] != 0 } { + continue + } + puts $oid $f + } + close $oid + filesort $t2.tmp $t2 + fileremove $t2.tmp + filesort $t1 $t3 + } + + error_check_good \ + Test003:diff($t3,$t2) [filecmp $t3 $t2] 0 + + # Now, reopen the file and run the last test again. + puts "\tTest003.c: close, open, and dump file" + open_and_dump_file $testfile $env $txn $t1 $checkfunc \ + dump_bin_file_direction "-first" "-next" + + if { [is_record_based $method] == 1 } { + filesort $t1 $t3 -n + } + + error_check_good \ + Test003:diff($t3,$t2) [filecmp $t3 $t2] 0 + + # Now, reopen the file and run the last test again in reverse direction. + puts "\tTest003.d: close, open, and dump file in reverse direction" + + open_and_dump_file $testfile $env $txn $t1 $checkfunc \ + dump_bin_file_direction "-last" "-prev" + + if { [is_record_based $method] == 1 } { + filesort $t1 $t3 -n + } + + error_check_good \ + Test003:diff($t3,$t2) [filecmp $t3 $t2] 0 +} + +# Check function for test003; key should be file name; data should be contents +proc test003.check { binfile tmpfile } { + source ./include.tcl + + error_check_good Test003:datamismatch($binfile,$tmpfile) \ + [filecmp $binfile $tmpfile] 0 +} +proc test003_recno.check { binfile tmpfile } { + global names + source ./include.tcl + + set fname $names($binfile) + error_check_good key"$binfile"_exists [info exists names($binfile)] 1 + error_check_good Test003:datamismatch($fname,$tmpfile) \ + [filecmp $fname $tmpfile] 0 +} diff --git a/db/test/test004.tcl b/db/test/test004.tcl new file mode 100644 index 000000000..0b076d6cf --- /dev/null +++ b/db/test/test004.tcl @@ -0,0 +1,134 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test004.tcl,v 11.15 2000/08/25 14:21:54 sue Exp $ +# +# DB Test 4 {access method} +# Check that cursor operations work. Create a database. +# Read through the database sequentially using cursors and +# delete each element. +proc test004 { method {nentries 10000} {reopen 4} {build_only 0} args} { + source ./include.tcl + + set do_renumber [is_rrecno $method] + set args [convert_args $method $args] + set omethod [convert_method $method] + + set tnum test00$reopen + + puts -nonewline "$tnum:\ + $method ($args) $nentries delete small key; medium data pairs" + if {$reopen == 5} { + puts "(with close)" + } else { + puts "" + } + + # Create the database and open the dictionary + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test004.db + set env NULL + } else { + set testfile test004.db + incr eindex + set env [lindex $args $eindex] + } + # Create the database and open the dictionary + set t1 $testdir/t1 + set t2 $testdir/t2 + set t3 $testdir/t3 + cleanup $testdir $env + set db [eval {berkdb_open -create -truncate -mode 0644} $args {$omethod $testfile}] + error_check_good dbopen [is_valid_db $db] TRUE + + set did [open $dict] + + set pflags "" + set gflags "" + set txn "" + set count 0 + + if { [is_record_based $method] == 1 } { + append gflags " -recno" + } + + # Here is the loop where we put and get each key/data pair + set kvals "" + puts "\tTest00$reopen.a: put/get loop" + while { [gets $did str] != -1 && $count < $nentries } { + if { [is_record_based $method] == 1 } { + set key [expr $count + 1] + lappend kvals $str + } else { + set key $str + } + + set datastr [ make_data_str $str ] + + set ret [eval {$db put} $txn $pflags {$key [chop_data $method $datastr]}] + error_check_good put $ret 0 + + set ret [eval {$db get} $gflags {$key}] + error_check_good "$tnum:put" $ret \ + [list [list $key [pad_data $method $datastr]]] + incr count + } + close $did + if { $build_only == 1 } { + return $db + } + if { $reopen == 5 } { + error_check_good db_close [$db close] 0 + + set db [eval {berkdb_open} $args {$testfile}] + error_check_good dbopen [is_valid_db $db] TRUE + } + puts "\tTest00$reopen.b: get/delete loop" + # Now we will get each key from the DB and compare the results + # to the original, then delete it. + set outf [open $t1 w] + set c [eval {$db cursor} $txn] + + set count 0 + for {set d [$c get -first] } { [llength $d] != 0 } { + set d [$c get -next] } { + set k [lindex [lindex $d 0] 0] + set d2 [lindex [lindex $d 0] 1] + if { [is_record_based $method] == 1 } { + set datastr \ + [make_data_str [lindex $kvals [expr $k - 1]]] + } else { + set datastr [make_data_str $k] + } + error_check_good $tnum:$k $d2 [pad_data $method $datastr] + puts $outf $k + $c del + if { [is_record_based $method] == 1 && \ + $do_renumber == 1 } { + set kvals [lreplace $kvals 0 0] + } + incr count + } + close $outf + error_check_good curs_close [$c close] 0 + + # Now compare the keys to see if they match the dictionary + if { [is_record_based $method] == 1 } { + error_check_good test00$reopen:keys_deleted $count $nentries + } else { + set q q + filehead $nentries $dict $t3 + filesort $t3 $t2 + filesort $t1 $t3 + error_check_good Test00$reopen:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 + } + + error_check_good db_close [$db close] 0 +} diff --git a/db/test/test005.tcl b/db/test/test005.tcl new file mode 100644 index 000000000..4cb5d88df --- /dev/null +++ b/db/test/test005.tcl @@ -0,0 +1,14 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test005.tcl,v 11.4 2000/05/22 12:51:38 bostic Exp $ +# +# DB Test 5 {access method} +# Check that cursor operations work. Create a database; close database and +# reopen it. Then read through the database sequentially using cursors and +# delete each element. +proc test005 { method {nentries 10000} args } { + eval {test004 $method $nentries 5 0} $args +} diff --git a/db/test/test006.tcl b/db/test/test006.tcl new file mode 100644 index 000000000..9364d2a4f --- /dev/null +++ b/db/test/test006.tcl @@ -0,0 +1,118 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test006.tcl,v 11.13 2000/08/25 14:21:54 sue Exp $ +# +# DB Test 6 {access method} +# Keyed delete test. +# Create database. +# Go through database, deleting all entries by key. +proc test006 { method {nentries 10000} {reopen 0} {tnum 6} args} { + source ./include.tcl + + set do_renumber [is_rrecno $method] + set args [convert_args $method $args] + set omethod [convert_method $method] + + if { $tnum < 10 } { + set tname Test00$tnum + set dbname test00$tnum + } else { + set tname Test0$tnum + set dbname test0$tnum + } + puts -nonewline "$tname: $method ($args) " + puts -nonewline "$nentries equal small key; medium data pairs" + if {$reopen == 1} { + puts " (with close)" + } else { + puts "" + } + + # Create the database and open the dictionary + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/$dbname.db + set env NULL + } else { + set testfile $dbname.db + incr eindex + set env [lindex $args $eindex] + } + + set pflags "" + set gflags "" + set txn "" + set count 0 + if { [is_record_based $method] == 1 } { + append gflags " -recno" + } + + # Here is the loop where we put and get each key/data pair + + cleanup $testdir $env + set db [eval {berkdb_open \ + -create -truncate -mode 0644} $args {$omethod $testfile}] + error_check_good dbopen [is_valid_db $db] TRUE + + set did [open $dict] + while { [gets $did str] != -1 && $count < $nentries } { + if { [is_record_based $method] == 1 } { + set key [expr $count + 1 ] + } else { + set key $str + } + + set datastr [make_data_str $str] + + set ret [eval {$db put} \ + $txn $pflags {$key [chop_data $method $datastr]}] + error_check_good put $ret 0 + + set ret [eval {$db get} $gflags {$key}] + error_check_good "$tname: put $datastr got $ret" \ + $ret [list [list $key [pad_data $method $datastr]]] + incr count + } + close $did + + if { $reopen == 1 } { + error_check_good db_close [$db close] 0 + + set db [eval {berkdb_open} $args {$testfile}] + error_check_good dbopen [is_valid_db $db] TRUE + } + + # Now we will get each key from the DB and compare the results + # to the original, then delete it. + set count 0 + set did [open $dict] + set key 0 + while { [gets $did str] != -1 && $count < $nentries } { + if { $do_renumber == 1 } { + set key 1 + } elseif { [is_record_based $method] == 1 } { + incr key + } else { + set key $str + } + + set datastr [make_data_str $str] + + set ret [eval {$db get} $gflags {$key}] + error_check_good "$tname: get $datastr got $ret" \ + $ret [list [list $key [pad_data $method $datastr]]] + + set ret [eval {$db del} $txn {$key}] + error_check_good db_del:$key $ret 0 + incr count + } + close $did + + error_check_good db_close [$db close] 0 +} diff --git a/db/test/test007.tcl b/db/test/test007.tcl new file mode 100644 index 000000000..305740f03 --- /dev/null +++ b/db/test/test007.tcl @@ -0,0 +1,13 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test007.tcl,v 11.5 2000/05/22 12:51:38 bostic Exp $ +# +# DB Test 7 {access method} +# Check that delete operations work. Create a database; close database and +# reopen it. Then issues delete by key for each entry. +proc test007 { method {nentries 10000} {tnum 7} args} { + eval {test006 $method $nentries 1 $tnum} $args +} diff --git a/db/test/test008.tcl b/db/test/test008.tcl new file mode 100644 index 000000000..34144391c --- /dev/null +++ b/db/test/test008.tcl @@ -0,0 +1,138 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test008.tcl,v 11.17 2000/10/19 17:35:39 sue Exp $ +# +# DB Test 8 {access method} +# Take the source files and dbtest executable and enter their names as the +# key with their contents as data. After all are entered, begin looping +# through the entries; deleting some pairs and then readding them. +proc test008 { method {nentries 10000} {reopen 8} {debug 0} args} { + source ./include.tcl + + set tnum test00$reopen + set args [convert_args $method $args] + set omethod [convert_method $method] + + if { [is_record_based $method] == 1 } { + puts "Test00$reopen skipping for method $method" + return + } + + puts -nonewline "$tnum: $method filename=key filecontents=data pairs" + if {$reopen == 9} { + puts "(with close)" + } else { + puts "" + } + + # Create the database and open the dictionary + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/$tnum.db + set env NULL + } else { + set testfile $tnum.db + incr eindex + set env [lindex $args $eindex] + } + set t1 $testdir/t1 + set t2 $testdir/t2 + set t3 $testdir/t3 + set t4 $testdir/t4 + + cleanup $testdir $env + + set db [eval {berkdb_open -create -truncate -mode 0644} \ + $args {$omethod $testfile}] + error_check_good dbopen [is_valid_db $db] TRUE + + set pflags "" + set gflags "" + set txn "" + + # Here is the loop where we put and get each key/data pair + set file_list [glob ../*/*.c ./*.o ./*.lo ./*.exe] + + set count 0 + puts "\tTest00$reopen.a: Initial put/get loop" + foreach f $file_list { + set names($count) $f + set key $f + + put_file $db $txn $pflags $f + + get_file $db $txn $gflags $f $t4 + + error_check_good Test00$reopen:diff($f,$t4) \ + [filecmp $f $t4] 0 + + incr count + } + + if {$reopen == 9} { + error_check_good db_close [$db close] 0 + + set db [eval {berkdb_open} $args $testfile] + error_check_good dbopen [is_valid_db $db] TRUE + } + + # Now we will get step through keys again (by increments) and + # delete all the entries, then re-insert them. + + puts "\tTest00$reopen.b: Delete re-add loop" + foreach i "1 2 4 8 16" { + for {set ndx 0} {$ndx < $count} { incr ndx $i} { + set r [eval {$db del} $txn {$names($ndx)}] + error_check_good db_del:$names($ndx) $r 0 + } + for {set ndx 0} {$ndx < $count} { incr ndx $i} { + put_file $db $txn $pflags $names($ndx) + } + } + + if {$reopen == 9} { + error_check_good db_close [$db close] 0 + set db [eval {berkdb_open} $args $testfile] + error_check_good dbopen [is_valid_db $db] TRUE + } + + # Now, reopen the file and make sure the key/data pairs look right. + puts "\tTest00$reopen.c: Dump contents forward" + dump_bin_file $db $txn $t1 test008.check + + set oid [open $t2.tmp w] + foreach f $file_list { + puts $oid $f + } + close $oid + filesort $t2.tmp $t2 + fileremove $t2.tmp + filesort $t1 $t3 + + error_check_good Test00$reopen:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 + + # Now, reopen the file and run the last test again in reverse direction. + puts "\tTest00$reopen.d: Dump contents backward" + dump_bin_file_direction $db $txn $t1 test008.check "-last" "-prev" + + filesort $t1 $t3 + + error_check_good Test00$reopen:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 + error_check_good close:$db [$db close] 0 +} + +proc test008.check { binfile tmpfile } { + global tnum + source ./include.tcl + + error_check_good diff($binfile,$tmpfile) \ + [filecmp $binfile $tmpfile] 0 +} diff --git a/db/test/test009.tcl b/db/test/test009.tcl new file mode 100644 index 000000000..e9c01875f --- /dev/null +++ b/db/test/test009.tcl @@ -0,0 +1,15 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test009.tcl,v 11.4 2000/05/22 12:51:38 bostic Exp $ +# +# DB Test 9 {access method} +# Check that we reuse overflow pages. Create database with lots of +# big key/data pairs. Go through and delete and add keys back +# randomly. Then close the DB and make sure that we have everything +# we think we should. +proc test009 { method {nentries 10000} args} { + eval {test008 $method $nentries 9 0} $args +} diff --git a/db/test/test010.tcl b/db/test/test010.tcl new file mode 100644 index 000000000..b3aedb2be --- /dev/null +++ b/db/test/test010.tcl @@ -0,0 +1,126 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test010.tcl,v 11.14 2000/08/25 14:21:54 sue Exp $ +# +# DB Test 10 {access method} +# Use the first 10,000 entries from the dictionary. +# Insert each with self as key and data; add duplicate +# records for each. +# After all are entered, retrieve all; verify output. +# Close file, reopen, do retrieve and re-verify. +# This does not work for recno +proc test010 { method {nentries 10000} {ndups 5} {tnum 10} args } { + source ./include.tcl + + set omethod $method + set args [convert_args $method $args] + set omethod [convert_method $method] + + if { [is_record_based $method] == 1 || \ + [is_rbtree $method] == 1 } { + puts "Test0$tnum skipping for method $method" + return + } + + puts "Test0$tnum: $method ($args) $nentries small dup key/data pairs" + + # Create the database and open the dictionary + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test0$tnum.db + set env NULL + } else { + set testfile test0$tnum.db + incr eindex + set env [lindex $args $eindex] + } + set t1 $testdir/t1 + set t2 $testdir/t2 + set t3 $testdir/t3 + + cleanup $testdir $env + + set db [eval {berkdb_open \ + -create -truncate -mode 0644 -dup} $args {$omethod $testfile}] + error_check_good dbopen [is_valid_db $db] TRUE + + set did [open $dict] + + set pflags "" + set gflags "" + set txn "" + set count 0 + + # Here is the loop where we put and get each key/data pair + set dbc [eval {$db cursor} $txn] + while { [gets $did str] != -1 && $count < $nentries } { + for { set i 1 } { $i <= $ndups } { incr i } { + set datastr $i:$str + set ret [eval {$db put} \ + $txn $pflags {$str [chop_data $method $datastr]}] + error_check_good put $ret 0 + } + + # Now retrieve all the keys matching this key + set x 1 + for {set ret [$dbc get "-set" $str]} \ + {[llength $ret] != 0} \ + {set ret [$dbc get "-next"] } { + if {[llength $ret] == 0} { + break + } + set k [lindex [lindex $ret 0] 0] + if { [string compare $k $str] != 0 } { + break + } + set datastr [lindex [lindex $ret 0] 1] + set d [data_of $datastr] + error_check_good "Test0$tnum:get" $d $str + set id [ id_of $datastr ] + error_check_good "Test0$tnum:dup#" $id $x + incr x + } + error_check_good "Test0$tnum:ndups:$str" [expr $x - 1] $ndups + incr count + } + error_check_good cursor_close [$dbc close] 0 + close $did + + # Now we will get each key from the DB and compare the results + # to the original. + puts "\tTest0$tnum.a: Checking file for correct duplicates" + set dlist "" + for { set i 1 } { $i <= $ndups } {incr i} { + lappend dlist $i + } + dup_check $db $txn $t1 $dlist + + # Now compare the keys to see if they match the dictionary entries + set q q + filehead $nentries $dict $t3 + filesort $t3 $t2 + filesort $t1 $t3 + + error_check_good Test0$tnum:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 + + error_check_good db_close [$db close] 0 + set db [eval {berkdb_open} $args $testfile] + error_check_good dbopen [is_valid_db $db] TRUE + + puts "\tTest0$tnum.b: Checking file for correct duplicates after close" + dup_check $db $txn $t1 $dlist + + # Now compare the keys to see if they match the dictionary entries + filesort $t1 $t3 + error_check_good Test0$tnum:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 + + error_check_good db_close [$db close] 0 +} diff --git a/db/test/test011.tcl b/db/test/test011.tcl new file mode 100644 index 000000000..444f6240e --- /dev/null +++ b/db/test/test011.tcl @@ -0,0 +1,349 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test011.tcl,v 11.20 2000/08/25 14:21:54 sue Exp $ +# +# DB Test 11 {access method} +# Use the first 10,000 entries from the dictionary. +# Insert each with self as key and data; add duplicate +# records for each. +# Then do some key_first/key_last add_before, add_after operations. +# This does not work for recno +# To test if dups work when they fall off the main page, run this with +# a very tiny page size. +proc test011 { method {nentries 10000} {ndups 5} {tnum 11} args } { + global dlist + global rand_init + source ./include.tcl + + set dlist "" + + if { [is_rbtree $method] == 1 } { + puts "Test0$tnum skipping for method $method" + return + } + if { [is_record_based $method] == 1 } { + test011_recno $method $nentries $tnum $args + return + } else { + puts -nonewline "Test0$tnum: $method $nentries small dup " + puts "key/data pairs, cursor ops" + } + if {$ndups < 5} { + set ndups 5 + } + + set args [convert_args $method $args] + set omethod [convert_method $method] + + berkdb srand $rand_init + + # Create the database and open the dictionary + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test0$tnum.db + set env NULL + } else { + set testfile test0$tnum.db + incr eindex + set env [lindex $args $eindex] + } + set t1 $testdir/t1 + set t2 $testdir/t2 + set t3 $testdir/t3 + cleanup $testdir $env + + set db [eval {berkdb_open -create -truncate \ + -mode 0644} [concat $args "-dup"] {$omethod $testfile}] + error_check_good dbopen [is_valid_db $db] TRUE + + set did [open $dict] + + set pflags "" + set gflags "" + set txn "" + set count 0 + + # Here is the loop where we put and get each key/data pair + # We will add dups with values 1, 3, ... $ndups. Then we'll add + # 0 and $ndups+1 using keyfirst/keylast. We'll add 2 and 4 using + # add before and add after. + puts "\tTest0$tnum.a: put and get duplicate keys." + set dbc [eval {$db cursor} $txn] + set i "" + for { set i 1 } { $i <= $ndups } { incr i 2 } { + lappend dlist $i + } + set maxodd $i + while { [gets $did str] != -1 && $count < $nentries } { + for { set i 1 } { $i <= $ndups } { incr i 2 } { + set datastr $i:$str + set ret [eval {$db put} $txn $pflags {$str $datastr}] + error_check_good put $ret 0 + } + + # Now retrieve all the keys matching this key + set x 1 + for {set ret [$dbc get "-set" $str ]} \ + {[llength $ret] != 0} \ + {set ret [$dbc get "-next"] } { + if {[llength $ret] == 0} { + break + } + set k [lindex [lindex $ret 0] 0] + if { [string compare $k $str] != 0 } { + break + } + set datastr [lindex [lindex $ret 0] 1] + set d [data_of $datastr] + + error_check_good Test0$tnum:put $d $str + set id [ id_of $datastr ] + error_check_good Test0$tnum:dup# $id $x + incr x 2 + } + error_check_good Test0$tnum:numdups $x $maxodd + incr count + } + error_check_good curs_close [$dbc close] 0 + close $did + + # Now we will get each key from the DB and compare the results + # to the original. + puts "\tTest0$tnum.b: \ + traverse entire file checking duplicates before close." + dup_check $db $txn $t1 $dlist + + # Now compare the keys to see if they match the dictionary entries + set q q + filehead $nentries $dict $t3 + filesort $t3 $t2 + filesort $t1 $t3 + + error_check_good Test0$tnum:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 + + error_check_good db_close [$db close] 0 + + set db [eval {berkdb_open} $args $testfile] + error_check_good dbopen [is_valid_db $db] TRUE + + puts "\tTest0$tnum.c: \ + traverse entire file checking duplicates after close." + dup_check $db $txn $t1 $dlist + + # Now compare the keys to see if they match the dictionary entries + filesort $t1 $t3 + error_check_good Test0$tnum:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 + + puts "\tTest0$tnum.d: Testing key_first functionality" + add_dup $db $txn $nentries "-keyfirst" 0 0 + set dlist [linsert $dlist 0 0] + dup_check $db $txn $t1 $dlist + + puts "\tTest0$tnum.e: Testing key_last functionality" + add_dup $db $txn $nentries "-keylast" [expr $maxodd - 1] 0 + lappend dlist [expr $maxodd - 1] + dup_check $db $txn $t1 $dlist + + puts "\tTest0$tnum.f: Testing add_before functionality" + add_dup $db $txn $nentries "-before" 2 3 + set dlist [linsert $dlist 2 2] + dup_check $db $txn $t1 $dlist + + puts "\tTest0$tnum.g: Testing add_after functionality" + add_dup $db $txn $nentries "-after" 4 4 + set dlist [linsert $dlist 4 4] + dup_check $db $txn $t1 $dlist + + error_check_good db_close [$db close] 0 +} + +proc add_dup {db txn nentries flag dataval iter} { + source ./include.tcl + + set dbc [eval {$db cursor} $txn] + set did [open $dict] + set count 0 + while { [gets $did str] != -1 && $count < $nentries } { + set datastr $dataval:$str + set ret [$dbc get "-set" $str] + error_check_bad "cget(SET)" [is_substr $ret Error] 1 + for { set i 1 } { $i < $iter } { incr i } { + set ret [$dbc get "-next"] + error_check_bad "cget(NEXT)" [is_substr $ret Error] 1 + } + + if { [string compare $flag "-before"] == 0 || + [string compare $flag "-after"] == 0 } { + set ret [$dbc put $flag $datastr] + } else { + set ret [$dbc put $flag $str $datastr] + } + error_check_good "$dbc put $flag" $ret 0 + incr count + } + close $did + $dbc close +} + +proc test011_recno { method {nentries 10000} {tnum 11} largs } { + global dlist + source ./include.tcl + + set largs [convert_args $method $largs] + set omethod [convert_method $method] + set renum [is_rrecno $method] + + puts "Test0$tnum: \ + $method ($largs) $nentries test cursor insert functionality" + + # Create the database and open the dictionary + set eindex [lsearch -exact $largs "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test0$tnum.db + set env NULL + } else { + set testfile test0$tnum.db + incr eindex + set env [lindex $largs $eindex] + } + set t1 $testdir/t1 + set t2 $testdir/t2 + set t3 $testdir/t3 + cleanup $testdir $env + + if {$renum == 1} { + append largs " -renumber" + } + set db [eval {berkdb_open \ + -create -truncate -mode 0644} $largs {$omethod $testfile}] + error_check_good dbopen [is_valid_db $db] TRUE + + set did [open $dict] + + set pflags "" + set gflags "" + set txn "" + set count 0 + + # The basic structure of the test is that we pick a random key + # in the database and then add items before, after, ?? it. The + # trickiness is that with RECNO, these are not duplicates, they + # are creating new keys. Therefore, every time we do this, the + # keys assigned to other values change. For this reason, we'll + # keep the database in tcl as a list and insert properly into + # it to verify that the right thing is happening. If we do not + # have renumber set, then the BEFORE and AFTER calls should fail. + + # Seed the database with an initial record + gets $did str + set ret [eval {$db put} $txn {1 [chop_data $method $str]}] + error_check_good put $ret 0 + set count 1 + + set dlist "NULL $str" + + # Open a cursor + set dbc [eval {$db cursor} $txn] + puts "\tTest0$tnum.a: put and get entries" + while { [gets $did str] != -1 && $count < $nentries } { + # Pick a random key + set key [berkdb random_int 1 $count] + set ret [$dbc get -set $key] + set k [lindex [lindex $ret 0] 0] + set d [lindex [lindex $ret 0] 1] + error_check_good cget:SET:key $k $key + error_check_good \ + cget:SET $d [pad_data $method [lindex $dlist $key]] + + # Current + set ret [$dbc put -current [chop_data $method $str]] + error_check_good cput:$key $ret 0 + set dlist [lreplace $dlist $key $key [pad_data $method $str]] + + # Before + if { [gets $did str] == -1 } { + continue; + } + + if { $renum == 1 } { + set ret [$dbc put \ + -before [chop_data $method $str]] + error_check_good cput:$key:BEFORE $ret $key + set dlist [linsert $dlist $key $str] + incr count + + # After + if { [gets $did str] == -1 } { + continue; + } + set ret [$dbc put \ + -after [chop_data $method $str]] + error_check_good cput:$key:AFTER $ret [expr $key + 1] + set dlist [linsert $dlist [expr $key + 1] $str] + incr count + } + + # Now verify that the keys are in the right place + set i 0 + for {set ret [$dbc get "-set" $key]} \ + {[string length $ret] != 0 && $i < 3} \ + {set ret [$dbc get "-next"] } { + set check_key [expr $key + $i] + + set k [lindex [lindex $ret 0] 0] + error_check_good cget:$key:loop $k $check_key + + set d [lindex [lindex $ret 0] 1] + error_check_good cget:data $d \ + [pad_data $method [lindex $dlist $check_key]] + incr i + } + } + close $did + error_check_good cclose [$dbc close] 0 + + # Create check key file. + set oid [open $t2 w] + for {set i 1} {$i <= $count} {incr i} { + puts $oid $i + } + close $oid + + puts "\tTest0$tnum.b: dump file" + dump_file $db $txn $t1 test011_check + error_check_good Test0$tnum:diff($t2,$t1) \ + [filecmp $t2 $t1] 0 + + error_check_good db_close [$db close] 0 + + puts "\tTest0$tnum.c: close, open, and dump file" + open_and_dump_file $testfile $env $txn $t1 test011_check \ + dump_file_direction "-first" "-next" + error_check_good Test0$tnum:diff($t2,$t1) \ + [filecmp $t2 $t1] 0 + + puts "\tTest0$tnum.d: close, open, and dump file in reverse direction" + open_and_dump_file $testfile $env $txn $t1 test011_check \ + dump_file_direction "-last" "-prev" + + filesort $t1 $t3 -n + error_check_good Test0$tnum:diff($t2,$t3) \ + [filecmp $t2 $t3] 0 +} + +proc test011_check { key data } { + global dlist + + error_check_good "get key $key" $data [lindex $dlist $key] +} diff --git a/db/test/test012.tcl b/db/test/test012.tcl new file mode 100644 index 000000000..87127901e --- /dev/null +++ b/db/test/test012.tcl @@ -0,0 +1,113 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test012.tcl,v 11.14 2000/08/25 14:21:54 sue Exp $ +# +# DB Test 12 {access method} +# Take the source files and dbtest executable and enter their contents as +# the key with their names as data. After all are entered, retrieve all; +# compare output to original. Close file, reopen, do retrieve and re-verify. +proc test012 { method args} { + global names + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + + if { [is_record_based $method] == 1 } { + puts "Test012 skipping for method $method" + return + } + + puts "Test012: $method ($args) filename=data filecontents=key pairs" + + # Create the database and open the dictionary + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test012.db + set env NULL + } else { + set testfile test012.db + incr eindex + set env [lindex $args $eindex] + } + set t1 $testdir/t1 + set t2 $testdir/t2 + set t3 $testdir/t3 + set t4 $testdir/t4 + + cleanup $testdir $env + + set db [eval {berkdb_open \ + -create -truncate -mode 0644} $args {$omethod $testfile}] + error_check_good dbopen [is_valid_db $db] TRUE + + set pflags "" + set gflags "" + set txn "" + + # Here is the loop where we put and get each key/data pair + set file_list [glob $test_path/../\[a-z\]*/*.c \ + $test_path/./*.lo ./*.exe] + + puts "\tTest012.a: put/get loop" + set count 0 + foreach f $file_list { + put_file_as_key $db $txn $pflags $f + + set kd [get_file_as_key $db $txn $gflags $f] + incr count + } + + # Now we will get each key from the DB and compare the results + # to the original. + puts "\tTest012.b: dump file" + dump_binkey_file $db $txn $t1 test012.check + error_check_good db_close [$db close] 0 + + # Now compare the data to see if they match the .o and dbtest files + set oid [open $t2.tmp w] + foreach f $file_list { + puts $oid $f + } + close $oid + filesort $t2.tmp $t2 + fileremove $t2.tmp + filesort $t1 $t3 + + error_check_good Test012:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 + + # Now, reopen the file and run the last test again. + puts "\tTest012.c: close, open, and dump file" + open_and_dump_file $testfile $env $txn $t1 test012.check \ + dump_binkey_file_direction "-first" "-next" + + filesort $t1 $t3 + + error_check_good Test012:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 + + # Now, reopen the file and run the last test again in reverse direction. + puts "\tTest012.d: close, open, and dump file in reverse direction" + open_and_dump_file $testfile $env $txn $t1 test012.check\ + dump_binkey_file_direction "-last" "-prev" + + filesort $t1 $t3 + + error_check_good Test012:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 +} + +# Check function for test012; key should be file name; data should be contents +proc test012.check { binfile tmpfile } { + source ./include.tcl + + error_check_good Test012:diff($binfile,$tmpfile) \ + [filecmp $binfile $tmpfile] 0 +} diff --git a/db/test/test013.tcl b/db/test/test013.tcl new file mode 100644 index 000000000..5812cf8f6 --- /dev/null +++ b/db/test/test013.tcl @@ -0,0 +1,193 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test013.tcl,v 11.18 2000/08/25 14:21:54 sue Exp $ +# +# DB Test 13 {access method} +# +# 1. Insert 10000 keys and retrieve them (equal key/data pairs). +# 2. Attempt to overwrite keys with NO_OVERWRITE set (expect error). +# 3. Actually overwrite each one with its datum reversed. +# +# No partial testing here. +proc test013 { method {nentries 10000} args } { + global errorCode + global errorInfo + global fixed_pad + global fixed_len + + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + + puts "Test013: $method ($args) $nentries equal key/data pairs, put test" + + # Create the database and open the dictionary + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test013.db + set env NULL + } else { + set testfile test013.db + incr eindex + set env [lindex $args $eindex] + } + set t1 $testdir/t1 + set t2 $testdir/t2 + set t3 $testdir/t3 + cleanup $testdir $env + + set db [eval {berkdb_open \ + -create -truncate -mode 0644} $args {$omethod $testfile}] + error_check_good dbopen [is_valid_db $db] TRUE + + set did [open $dict] + + set pflags "" + set gflags "" + set txn "" + set count 0 + + if { [is_record_based $method] == 1 } { + set checkfunc test013_recno.check + append gflags " -recno" + global kvals + } else { + set checkfunc test013.check + } + puts "\tTest013.a: put/get loop" + # Here is the loop where we put and get each key/data pair + while { [gets $did str] != -1 && $count < $nentries } { + if { [is_record_based $method] == 1 } { + set key [expr $count + 1] + set kvals($key) [pad_data $method $str] + } else { + set key $str + } + set ret [eval {$db put} \ + $txn $pflags {$key [chop_data $method $str]}] + error_check_good put $ret 0 + + set ret [eval {$db get} $gflags $txn {$key}] + error_check_good \ + get $ret [list [list $key [pad_data $method $str]]] + incr count + } + close $did + + # Now we will try to overwrite each datum, but set the + # NOOVERWRITE flag. + puts "\tTest013.b: overwrite values with NOOVERWRITE flag." + set did [open $dict] + set count 0 + while { [gets $did str] != -1 && $count < $nentries } { + if { [is_record_based $method] == 1 } { + set key [expr $count + 1] + } else { + set key $str + } + + set ret [eval {$db put} $txn $pflags \ + {-nooverwrite $key [chop_data $method $str]}] + error_check_good put [is_substr $ret "DB_KEYEXIST"] 1 + + # Value should be unchanged. + set ret [eval {$db get} $txn $gflags {$key}] + error_check_good \ + get $ret [list [list $key [pad_data $method $str]]] + incr count + } + close $did + + # Now we will replace each item with its datum capitalized. + puts "\tTest013.c: overwrite values with capitalized datum" + set did [open $dict] + set count 0 + while { [gets $did str] != -1 && $count < $nentries } { + if { [is_record_based $method] == 1 } { + set key [expr $count + 1] + } else { + set key $str + } + set rstr [string toupper $str] + set r [eval {$db put} \ + $txn $pflags {$key [chop_data $method $rstr]}] + error_check_good put $r 0 + + # Value should be changed. + set ret [eval {$db get} $txn $gflags {$key}] + error_check_good \ + get $ret [list [list $key [pad_data $method $rstr]]] + incr count + } + close $did + + # Now make sure that everything looks OK + puts "\tTest013.d: check entire file contents" + dump_file $db $txn $t1 $checkfunc + error_check_good db_close [$db close] 0 + + # Now compare the keys to see if they match the dictionary (or ints) + if { [is_record_based $method] == 1 } { + set oid [open $t2 w] + for {set i 1} {$i <= $nentries} {incr i} { + puts $oid $i + } + close $oid + file rename -force $t1 $t3 + } else { + set q q + filehead $nentries $dict $t3 + filesort $t3 $t2 + filesort $t1 $t3 + } + + error_check_good \ + Test013:diff($t3,$t2) [filecmp $t3 $t2] 0 + + puts "\tTest013.e: close, open, and dump file" + # Now, reopen the file and run the last test again. + open_and_dump_file $testfile $env $txn $t1 $checkfunc \ + dump_file_direction "-first" "-next" + + if { [is_record_based $method] == 0 } { + filesort $t1 $t3 + } + + error_check_good \ + Test013:diff($t3,$t2) [filecmp $t3 $t2] 0 + + # Now, reopen the file and run the last test again in the + # reverse direction. + puts "\tTest013.f: close, open, and dump file in reverse direction" + open_and_dump_file $testfile $env $txn $t1 $checkfunc \ + dump_file_direction "-last" "-prev" + + if { [is_record_based $method] == 0 } { + filesort $t1 $t3 + } + + error_check_good \ + Test013:diff($t3,$t2) [filecmp $t3 $t2] 0 +} + +# Check function for test013; keys and data are identical +proc test013.check { key data } { + error_check_good \ + "key/data mismatch for $key" $data [string toupper $key] +} + +proc test013_recno.check { key data } { + global dict + global kvals + + error_check_good key"$key"_exists [info exists kvals($key)] 1 + error_check_good \ + "data mismatch for $key" $data [string toupper $kvals($key)] +} diff --git a/db/test/test014.tcl b/db/test/test014.tcl new file mode 100644 index 000000000..3ad5335dd --- /dev/null +++ b/db/test/test014.tcl @@ -0,0 +1,204 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test014.tcl,v 11.19 2000/08/25 14:21:54 sue Exp $ +# +# DB Test 14 {access method} +# +# Partial put test, small data, replacing with same size. The data set +# consists of the first nentries of the dictionary. We will insert them +# (and retrieve them) as we do in test 1 (equal key/data pairs). Then +# we'll try to perform partial puts of some characters at the beginning, +# some at the end, and some at the middle. +proc test014 { method {nentries 10000} args } { + set fixed 0 + set args [convert_args $method $args] + + if { [is_fixed_length $method] == 1 } { + set fixed 1 + } + + puts "Test014: $method ($args) $nentries equal key/data pairs, put test" + + # flagp indicates whether this is a postpend or a + # normal partial put + set flagp 0 + + eval {test014_body $method $flagp 1 1 $nentries} $args + eval {test014_body $method $flagp 1 4 $nentries} $args + eval {test014_body $method $flagp 2 4 $nentries} $args + eval {test014_body $method $flagp 1 128 $nentries} $args + eval {test014_body $method $flagp 2 16 $nentries} $args + if { $fixed == 0 } { + eval {test014_body $method $flagp 0 1 $nentries} $args + eval {test014_body $method $flagp 0 4 $nentries} $args + eval {test014_body $method $flagp 0 128 $nentries} $args + + # POST-PENDS : + # partial put data after the end of the existent record + # chars: number of empty spaces that will be padded with null + # increase: is the length of the str to be appended (after pad) + # + set flagp 1 + eval {test014_body $method $flagp 1 1 $nentries} $args + eval {test014_body $method $flagp 4 1 $nentries} $args + eval {test014_body $method $flagp 128 1 $nentries} $args + eval {test014_body $method $flagp 1 4 $nentries} $args + eval {test014_body $method $flagp 1 128 $nentries} $args + } + puts "Test014 complete." +} + +proc test014_body { method flagp chars increase {nentries 10000} args } { + source ./include.tcl + + set omethod [convert_method $method] + + if { [is_fixed_length $method] == 1 && $chars != $increase } { + puts "Test014: $method: skipping replace\ + $chars chars with string $increase times larger." + return + } + + if { $flagp == 1} { + puts "Test014: Postpending string of len $increase with \ + gap $chars." + } else { + puts "Test014: Replace $chars chars with string \ + $increase times larger" + } + + # Create the database and open the dictionary + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test014.db + set env NULL + } else { + set testfile test014.db + incr eindex + set env [lindex $args $eindex] + } + set t1 $testdir/t1 + set t2 $testdir/t2 + set t3 $testdir/t3 + cleanup $testdir $env + + set db [eval {berkdb_open \ + -create -truncate -mode 0644} $args {$omethod $testfile}] + error_check_good dbopen [is_valid_db $db] TRUE + + set gflags "" + set pflags "" + set txn "" + set count 0 + + if { [is_record_based $method] == 1 } { + append gflags " -recno" + } + + puts "\tTest014.a: put/get loop" + # Here is the loop where we put and get each key/data pair + # We will do the initial put and then three Partial Puts + # for the beginning, middle and end of the string. + set did [open $dict] + while { [gets $did str] != -1 && $count < $nentries } { + if { [is_record_based $method] == 1 } { + set key [expr $count + 1] + } else { + set key $str + } + if { $flagp == 1 } { + # this is for postpend only + global dvals + + # initial put + set ret [$db put $key $str] + error_check_good dbput $ret 0 + + set offset [string length $str] + + # increase is the actual number of new bytes + # to be postpended (besides the null padding) + set data [repeat "P" $increase] + + # chars is the amount of padding in between + # the old data and the new + set len [expr $offset + $chars + $increase] + set dvals($key) [binary format \ + a[set offset]x[set chars]a[set increase] \ + $str $data] + set offset [expr $offset + $chars] + set ret [$db put -partial [list $offset 0] $key $data] + error_check_good dbput:post $ret 0 + } else { + partial_put $method $db $txn \ + $gflags $key $str $chars $increase + } + incr count + } + close $did + + # Now make sure that everything looks OK + puts "\tTest014.b: check entire file contents" + dump_file $db $txn $t1 test014.check + error_check_good db_close [$db close] 0 + + # Now compare the keys to see if they match the dictionary (or ints) + if { [is_record_based $method] == 1 } { + set oid [open $t2 w] + for {set i 1} {$i <= $nentries} {set i [incr i]} { + puts $oid $i + } + close $oid + file rename -force $t1 $t3 + } else { + set q q + filehead $nentries $dict $t3 + filesort $t3 $t2 + filesort $t1 $t3 + } + + error_check_good \ + Test014:diff($t3,$t2) [filecmp $t3 $t2] 0 + + puts "\tTest014.c: close, open, and dump file" + # Now, reopen the file and run the last test again. + open_and_dump_file $testfile $env $txn \ + $t1 test014.check dump_file_direction "-first" "-next" + + if { [string compare $omethod "-recno"] != 0 } { + filesort $t2 $t3 + file rename -force $t3 $t2 + filesort $t1 $t3 + } + + error_check_good \ + Test014:diff($t3,$t2) [filecmp $t3 $t2] 0 + # Now, reopen the file and run the last test again in the + # reverse direction. + puts "\tTest014.d: close, open, and dump file in reverse direction" + open_and_dump_file $testfile $env $txn $t1 \ + test014.check dump_file_direction "-last" "-prev" + + if { [string compare $omethod "-recno"] != 0 } { + filesort $t2 $t3 + file rename -force $t3 $t2 + filesort $t1 $t3 + } + + error_check_good \ + Test014:diff($t3,$t2) [filecmp $t3 $t2] 0 +} + +# Check function for test014; keys and data are identical +proc test014.check { key data } { + global dvals + + error_check_good key"$key"_exists [info exists dvals($key)] 1 + error_check_good "data mismatch for key $key" $data $dvals($key) +} diff --git a/db/test/test015.tcl b/db/test/test015.tcl new file mode 100644 index 000000000..61abddd37 --- /dev/null +++ b/db/test/test015.tcl @@ -0,0 +1,235 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test015.tcl,v 11.20 2000/08/25 14:21:54 sue Exp $ +# +# DB Test 15 {access method} +# Partial put test when item does not exist. +proc test015 { method {nentries 7500} { start 0 } args } { + global fixed_len + + set low_range 50 + set mid_range 100 + set high_range 1000 + + if { [is_fixed_length $method] } { + set low_range [expr $fixed_len/2 - 2] + set mid_range [expr $fixed_len/2] + set high_range $fixed_len + } + + set t_table { + { 1 { 1 1 1 } } + { 2 { 1 1 5 } } + { 3 { 1 1 $low_range } } + { 4 { 1 $mid_range 1 } } + { 5 { $mid_range $high_range 5 } } + { 6 { 1 $mid_range $low_range } } + } + + puts "Test015: \ + $method ($args) $nentries equal key/data pairs, partial put test" + test015_init + if { $start == 0 } { + set start { 1 2 3 4 5 6 } + } + foreach entry $t_table { + set this [lindex $entry 0] + if { [lsearch $start $this] == -1 } { + continue + } + puts -nonewline "$this: " + eval [concat test015_body $method [lindex $entry 1] \ + $nentries $args] + } +} + +proc test015_init { } { + global rand_init + + berkdb srand $rand_init +} + +proc test015_body { method off_low off_hi rcount {nentries 10000} args } { + global dvals + global fixed_len + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + + set checkfunc test015.check + + if { [is_fixed_length $method] && \ + [string compare $omethod "-recno"] == 0} { + # is fixed recno method + set checkfunc test015.check + } + + puts "Put $rcount strings random offsets between $off_low and $off_hi" + + # Create the database and open the dictionary + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test015.db + set env NULL + } else { + set testfile test015.db + incr eindex + set env [lindex $args $eindex] + } + set t1 $testdir/t1 + set t2 $testdir/t2 + set t3 $testdir/t3 + cleanup $testdir $env + + set db [eval {berkdb_open \ + -create -truncate -mode 0644} $args {$omethod $testfile}] + error_check_good dbopen [is_valid_db $db] TRUE + + set pflags "" + set gflags "" + set txn "" + set count 0 + + puts "\tTest015.a: put/get loop" + + # Here is the loop where we put and get each key/data pair + # Each put is a partial put of a record that does not exist. + set did [open $dict] + while { [gets $did str] != -1 && $count < $nentries } { + if { [is_record_based $method] == 1 } { + if { [string length $str] > $fixed_len } { + continue + } + set key [expr $count + 1] + } else { + set key $str + } + + if { 0 } { + set data [replicate $str $rcount] + set off [ berkdb random_int $off_low $off_hi ] + set offn [expr $off + 1] + if { [is_fixed_length $method] && \ + [expr [string length $data] + $off] >= $fixed_len} { + set data [string range $data 0 [expr $fixed_len-$offn]] + } + set dvals($key) [partial_shift $data $off right] + } else { + set data [chop_data $method [replicate $str $rcount]] + + # This is a hack. In DB we will store the records with + # some padding, but these will get lost if we just return + # them in TCL. As a result, we're going to have to hack + # get to check for 0 padding and return a list consisting + # of the number of 0's and the actual data. + set off [ berkdb random_int $off_low $off_hi ] + + # There is no string concatenation function in Tcl + # (although there is one in TclX), so we have to resort + # to this hack. Ugh. + set slen [string length $data] + if {[is_fixed_length $method] && \ + $slen > $fixed_len - $off} { + set $slen [expr $fixed_len - $off] + } + set a "a" + set dvals($key) [pad_data \ + $method [eval "binary format x$off$a$slen" {$data}]] + } + if {[is_fixed_length $method] && \ + [string length $data] > ($fixed_len - $off)} { + set slen [expr $fixed_len - $off] + set data [eval "binary format a$slen" {$data}] + } + set ret [eval {$db put} \ + {-partial [list $off [string length $data]] $key $data}] + error_check_good put $ret 0 + + incr count + } + close $did + + # Now make sure that everything looks OK + puts "\tTest015.b: check entire file contents" + dump_file $db $txn $t1 $checkfunc + error_check_good db_close [$db close] 0 + + # Now compare the keys to see if they match the dictionary (or ints) + if { [is_record_based $method] == 1 } { + set oid [open $t2 w] + for {set i 1} {$i <= $nentries} {set i [incr i]} { + puts $oid $i + } + close $oid + filesort $t2 $t3 + file rename -force $t3 $t2 + filesort $t1 $t3 + } else { + set q q + filehead $nentries $dict $t3 + filesort $t3 $t2 + filesort $t1 $t3 + } + + error_check_good Test015:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 + + puts "\tTest015.c: close, open, and dump file" + # Now, reopen the file and run the last test again. + open_and_dump_file $testfile $env $txn $t1 \ + $checkfunc dump_file_direction "-first" "-next" + + if { [string compare $omethod "-recno"] != 0 } { + filesort $t1 $t3 + } + + error_check_good Test015:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 + + # Now, reopen the file and run the last test again in the + # reverse direction. + puts "\tTest015.d: close, open, and dump file in reverse direction" + open_and_dump_file $testfile $env $txn $t1 \ + $checkfunc dump_file_direction "-last" "-prev" + + if { [string compare $omethod "-recno"] != 0 } { + filesort $t1 $t3 + } + + error_check_good Test015:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 + + unset dvals +} + +# Check function for test015; keys and data are identical +proc test015.check { key data } { + global dvals + + error_check_good key"$key"_exists [info exists dvals($key)] 1 + binary scan $data "c[string length $data]" a + binary scan $dvals($key) "c[string length $dvals($key)]" b + error_check_good "mismatch on padding for key $key" $a $b +} + +proc test015.fixed.check { key data } { + global dvals + global fixed_len + + error_check_good key"$key"_exists [info exists dvals($key)] 1 + if { [string length $data] > $fixed_len } { + error_check_bad \ + "data length:[string length $data] \ + for fixed:$fixed_len" 1 1 + } + puts "$data : $dvals($key)" + error_check_good compare_data($data,$dvals($key) \ + $dvals($key) $data +} diff --git a/db/test/test016.tcl b/db/test/test016.tcl new file mode 100644 index 000000000..def3c1146 --- /dev/null +++ b/db/test/test016.tcl @@ -0,0 +1,170 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test016.tcl,v 11.17 2000/08/25 14:21:54 sue Exp $ +# +# DB Test 16 {access method} +# Partial put test where partial puts make the record smaller. +# Use the first 10,000 entries from the dictionary. +# Insert each with self as key and a fixed, medium length data string; +# retrieve each. After all are entered, go back and do partial puts, +# replacing a random-length string with the key value. +# Then verify. + +set datastr abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz + +proc test016 { method {nentries 10000} args } { + global datastr + global dvals + global rand_init + source ./include.tcl + + berkdb srand $rand_init + + set args [convert_args $method $args] + set omethod [convert_method $method] + + if { [is_fixed_length $method] == 1 } { + puts "Test016: skipping for method $method" + return + } + + puts "Test016: $method ($args) $nentries partial put shorten" + + # Create the database and open the dictionary + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test016.db + set env NULL + } else { + set testfile test016.db + incr eindex + set env [lindex $args $eindex] + } + set t1 $testdir/t1 + set t2 $testdir/t2 + set t3 $testdir/t3 + cleanup $testdir $env + set db [eval {berkdb_open \ + -create -truncate -mode 0644} $args {$omethod $testfile}] + error_check_good dbopen [is_valid_db $db] TRUE + + set pflags "" + set gflags "" + set txn "" + set count 0 + + if { [is_record_based $method] == 1 } { + append gflags " -recno" + } + + # Here is the loop where we put and get each key/data pair + + puts "\tTest016.a: put/get loop" + set did [open $dict] + while { [gets $did str] != -1 && $count < $nentries } { + if { [is_record_based $method] == 1 } { + set key [expr $count + 1] + } else { + set key $str + } + set ret [eval {$db put} \ + $txn $pflags {$key [chop_data $method $datastr]}] + error_check_good put $ret 0 + + set ret [eval {$db get} $txn $gflags {$key}] + error_check_good \ + get $ret [list [list $key [pad_data $method $datastr]]] + incr count + } + close $did + + # Next we will do a partial put replacement, making the data + # shorter + puts "\tTest016.b: partial put loop" + set did [open $dict] + set count 0 + set len [string length $datastr] + while { [gets $did str] != -1 && $count < $nentries } { + if { [is_record_based $method] == 1 } { + set key [expr $count + 1] + } else { + set key $str + } + + set repl_len [berkdb random_int [string length $key] $len] + set repl_off [berkdb random_int 0 [expr $len - $repl_len] ] + set s1 [string range $datastr 0 [ expr $repl_off - 1] ] + set s2 [string toupper $key] + set s3 [string range $datastr [expr $repl_off + $repl_len] end ] + set dvals($key) [pad_data $method $s1$s2$s3] + set ret [eval {$db put} $txn {-partial \ + [list $repl_off $repl_len] $key [chop_data $method $s2]}] + error_check_good put $ret 0 + set ret [eval {$db get} $txn $gflags {$key}] + error_check_good \ + put $ret [list [list $key [pad_data $method $s1$s2$s3]]] + incr count + } + close $did + + # Now we will get each key from the DB and compare the results + # to the original. + puts "\tTest016.c: dump file" + dump_file $db $txn $t1 test016.check + error_check_good db_close [$db close] 0 + + # Now compare the keys to see if they match the dictionary + if { [is_record_based $method] == 1 } { + set oid [open $t2 w] + for {set i 1} {$i <= $nentries} {set i [incr i]} { + puts $oid $i + } + close $oid + file rename -force $t1 $t3 + } else { + set q q + filehead $nentries $dict $t3 + filesort $t3 $t2 + filesort $t1 $t3 + } + + error_check_good Test016:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 + + # Now, reopen the file and run the last test again. + puts "\tTest016.d: close, open, and dump file" + open_and_dump_file $testfile $env $txn $t1 test016.check \ + dump_file_direction "-first" "-next" + + if { [ is_record_based $method ] == 0 } { + filesort $t1 $t3 + } + error_check_good Test016:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 + + # Now, reopen the file and run the last test again in reverse direction. + puts "\tTest016.e: close, open, and dump file in reverse direction" + open_and_dump_file $testfile $env $txn $t1 test016.check \ + dump_file_direction "-last" "-prev" + + if { [ is_record_based $method ] == 0 } { + filesort $t1 $t3 + } + error_check_good Test016:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 +} + +# Check function for test016; data should be whatever is set in dvals +proc test016.check { key data } { + global datastr + global dvals + + error_check_good key"$key"_exists [info exists dvals($key)] 1 + error_check_good "data mismatch for key $key" $data $dvals($key) +} diff --git a/db/test/test017.tcl b/db/test/test017.tcl new file mode 100644 index 000000000..95fe82e08 --- /dev/null +++ b/db/test/test017.tcl @@ -0,0 +1,237 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test017.tcl,v 11.13 2000/12/11 17:42:18 sue Exp $ +# +# DB Test 17 {access method} +# Run duplicates with small page size so that we test off page duplicates. +# Then after we have an off-page database, test with overflow pages too. +# +proc test017 { method {contents 0} {ndups 19} {tnum 17} args } { + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + + if { [is_record_based $method] == 1 || \ + [is_rbtree $method] == 1 } { + puts "Test0$tnum skipping for method $method" + return + } + set pgindex [lsearch -exact $args "-pagesize"] + if { $pgindex != -1 } { + incr pgindex + if { [lindex $args $pgindex] > 8192 } { + puts "Test0$tnum: Skipping for large pagesizes" + return + } + } + + puts "Test0$tnum: $method ($args) Off page duplicate tests with $ndups duplicates" + + # Create the database and open the dictionary + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test0$tnum.db + set env NULL + } else { + set testfile test0$tnum.db + incr eindex + set env [lindex $args $eindex] + } + set t1 $testdir/t1 + set t2 $testdir/t2 + set t3 $testdir/t3 + set t4 $testdir/t4 + + cleanup $testdir $env + + set db [eval {berkdb_open \ + -create -truncate -mode 0644 -dup} $args {$omethod $testfile}] + error_check_good dbopen [is_valid_db $db] TRUE + + set pflags "" + set gflags "" + set txn "" + set count 0 + + set ovfl "" + # Here is the loop where we put and get each key/data pair + set dbc [eval {$db cursor} $txn] + puts -nonewline \ + "\tTest0$tnum.a: Creating duplicates with " + if { $contents != 0 } { + puts "file contents as key/data" + } else { + puts "file name as key/data" + } + set file_list [glob ../*/*.c ./*.lo] + foreach f $file_list { + if { $contents != 0 } { + set fid [open $f r] + fconfigure $fid -translation binary + # + # Prepend file name to guarantee uniqueness + set filecont [read $fid] + set str $f:$filecont + close $fid + } else { + set str $f + } + for { set i 1 } { $i <= $ndups } { incr i } { + set datastr $i:$str + set ret [eval {$db put} \ + $txn $pflags {$str [chop_data $method $datastr]}] + error_check_good put $ret 0 + } + + # + # Save 10% files for overflow test + # + if { $contents == 0 && [expr $count % 10] == 0 } { + lappend ovfl $f + } + # Now retrieve all the keys matching this key + set ret [$db get $str] + error_check_bad $f:dbget_dups [llength $ret] 0 + error_check_good $f:dbget_dups1 [llength $ret] $ndups + set x 1 + for {set ret [$dbc get "-set" $str]} \ + {[llength $ret] != 0} \ + {set ret [$dbc get "-next"] } { + set k [lindex [lindex $ret 0] 0] + if { [string compare $k $str] != 0 } { + break + } + set datastr [lindex [lindex $ret 0] 1] + set d [data_of $datastr] + if {[string length $d] == 0} { + break + } + error_check_good "Test0$tnum:get" $d $str + set id [ id_of $datastr ] + error_check_good "Test0$tnum:$f:dup#" $id $x + incr x + } + error_check_good "Test0$tnum:ndups:$str" [expr $x - 1] $ndups + incr count + } + error_check_good cursor_close [$dbc close] 0 + + # Now we will get each key from the DB and compare the results + # to the original. + puts "\tTest0$tnum.b: Checking file for correct duplicates" + set dlist "" + for { set i 1 } { $i <= $ndups } {incr i} { + lappend dlist $i + } + set oid [open $t2.tmp w] + set o1id [open $t4.tmp w] + foreach f $file_list { + for {set i 1} {$i <= $ndups} {incr i} { + puts $o1id $f + } + puts $oid $f + } + close $oid + close $o1id + filesort $t2.tmp $t2 + filesort $t4.tmp $t4 + fileremove $t2.tmp + fileremove $t4.tmp + + dup_check $db $txn $t1 $dlist + if {$contents == 0} { + filesort $t1 $t3 + + error_check_good Test0$tnum:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 + + # Now compare the keys to see if they match the file names + dump_file $db $txn $t1 test017.check + filesort $t1 $t3 + + error_check_good Test0$tnum:diff($t3,$t4) \ + [filecmp $t3 $t4] 0 + } + + error_check_good db_close [$db close] 0 + set db [eval {berkdb_open} $args $testfile] + error_check_good dbopen [is_valid_db $db] TRUE + + puts "\tTest0$tnum.c: Checking file for correct duplicates after close" + dup_check $db $txn $t1 $dlist + + if {$contents == 0} { + # Now compare the keys to see if they match the filenames + filesort $t1 $t3 + error_check_good Test0$tnum:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 + } + error_check_good db_close [$db close] 0 + + puts "\tTest0$tnum.d: Verify off page duplicates and overflow status" + set db [eval {berkdb_open} $args $testfile] + error_check_good dbopen [is_valid_db $db] TRUE + set stat [$db stat] + if { [is_btree $method] } { + error_check_bad stat:offpage \ + [is_substr $stat "{{Internal pages} 0}"] 1 + } + if {$contents == 0} { + # This check doesn't work in hash, since overflow + # pages count extra pages in buckets as well as true + # P_OVERFLOW pages. + if { [is_hash $method] == 0 } { + error_check_good overflow \ + [is_substr $stat "{{Overflow pages} 0}"] 1 + } + } else { + error_check_bad overflow \ + [is_substr $stat "{{Overflow pages} 0}"] 1 + } + + # + # If doing overflow test, do that now. Else we are done. + # Add overflow pages by adding a large entry to a duplicate. + # + if { [llength $ovfl] == 0} { + error_check_good db_close [$db close] 0 + return + } + puts "\tTest0$tnum.e: Add overflow duplicate entries" + set ovfldup [expr $ndups + 1] + foreach f $ovfl { + # + # This is just like put_file, but prepends the dup number + # + set fid [open $f r] + fconfigure $fid -translation binary + set fdata [read $fid] + close $fid + set data $ovfldup:$fdata + + set ret [eval {$db put} $txn $pflags {$f $data}] + error_check_good ovfl_put $ret 0 + } + puts "\tTest0$tnum.f: Verify overflow duplicate entries" + dup_check $db $txn $t1 $dlist $ovfldup + filesort $t1 $t3 + error_check_good Test0$tnum:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 + + set stat [$db stat] + error_check_bad overflow1 \ + [is_substr $stat "{{Overflow pages} 0}"] 1 + error_check_good db_close [$db close] 0 +} + +# Check function; verify data contains key +proc test017.check { key data } { + error_check_good "data mismatch for key $key" $key [data_of $data] +} diff --git a/db/test/test018.tcl b/db/test/test018.tcl new file mode 100644 index 000000000..95493da2d --- /dev/null +++ b/db/test/test018.tcl @@ -0,0 +1,13 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test018.tcl,v 11.3 2000/02/14 03:00:18 bostic Exp $ +# +# DB Test 18 {access method} +# Run duplicates with small page size so that we test off page duplicates. +proc test018 { method {nentries 10000} args} { + puts "Test018: Off page duplicate tests" + eval {test011 $method $nentries 19 18 -pagesize 512} $args +} diff --git a/db/test/test019.tcl b/db/test/test019.tcl new file mode 100644 index 000000000..4031ae2dc --- /dev/null +++ b/db/test/test019.tcl @@ -0,0 +1,107 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test019.tcl,v 11.14 2000/08/25 14:21:54 sue Exp $ +# +# Test019 { access_method nentries } +# Test the partial get functionality. +proc test019 { method {nentries 10000} args } { + global fixed_len + global rand_init + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + puts "Test019: $method ($args) $nentries partial get test" + + # Create the database and open the dictionary + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test019.db + set env NULL + } else { + set testfile test019.db + incr eindex + set env [lindex $args $eindex] + } + cleanup $testdir $env + + set db [eval {berkdb_open \ + -create -truncate -mode 0644} $args {$omethod $testfile}] + error_check_good dbopen [is_valid_db $db] TRUE + set did [open $dict] + berkdb srand $rand_init + + set pflags "" + set gflags "" + set txn "" + set count 0 + + if { [is_record_based $method] == 1 } { + append gflags " -recno" + } + + puts "\tTest019.a: put/get loop" + for { set i 0 } { [gets $did str] != -1 && $i < $nentries } \ + { incr i } { + + if { [is_record_based $method] == 1 } { + set key [expr $i + 1] + } else { + set key $str + } + set repl [berkdb random_int $fixed_len 100] + set data [chop_data $method [replicate $str $repl]] + set ret [eval {$db put} $txn {-nooverwrite $key $data}] + error_check_good dbput:$key $ret 0 + + set ret [eval {$db get} $txn $gflags {$key}] + error_check_good \ + dbget:$key $ret [list [list $key [pad_data $method $data]]] + set kvals($key) $repl + } + close $did + + puts "\tTest019.b: partial get loop" + set did [open $dict] + for { set i 0 } { [gets $did str] != -1 && $i < $nentries } \ + { incr i } { + if { [is_record_based $method] == 1 } { + set key [expr $i + 1] + } else { + set key $str + } + set data [replicate $str $kvals($key)] + + if { [is_fixed_length $method] == 1 } { + set maxndx $fixed_len + } else { + set maxndx [expr [string length $data] - 1] + } + set beg [berkdb random_int 0 [expr $maxndx - 1]] + set len [berkdb random_int 1 [expr $maxndx - $beg]] + + set ret [eval {$db get} \ + $txn {-partial [list $beg $len]} $gflags {$key}] + + # In order for tcl to handle this, we have to overwrite the + # last character with a NULL. That makes the length one less + # than we expect. + set k [lindex [lindex $ret 0] 0] + set d [lindex [lindex $ret 0] 1] + error_check_good dbget_key $k $key + # If $d contains some of the padding, we want to get rid of it. + set firstnull [string first "\0" $d] + if { $firstnull == -1 } { set firstnull [string length $d] } + error_check_good dbget_data \ + [string range $d 0 [expr $firstnull - 1]] \ + [string range $data $beg [expr $beg + $len - 1]] + } + error_check_good db_close [$db close] 0 + close $did +} diff --git a/db/test/test020.tcl b/db/test/test020.tcl new file mode 100644 index 000000000..1961d0e02 --- /dev/null +++ b/db/test/test020.tcl @@ -0,0 +1,108 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test020.tcl,v 11.12 2000/10/19 23:15:22 ubell Exp $ +# +# DB Test 20 {access method} +# Test in-memory databases. +proc test020 { method {nentries 10000} args } { + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + if { [is_queueext $method] == 1 || \ + [is_rbtree $method] == 1 } { + puts "Test020 skipping for method $method" + return + } + puts "Test020: $method ($args) $nentries equal key/data pairs" + + # Create the database and open the dictionary + set t1 $testdir/t1 + set t2 $testdir/t2 + set t3 $testdir/t3 + set eindex [lsearch -exact $args "-env"] + # + # Check if we are using an env. + if { $eindex == -1 } { + set env NULL + } else { + incr eindex + set env [lindex $args $eindex] + } + cleanup $testdir $env + set db [eval {berkdb_open \ + -create -truncate -mode 0644} $args {$omethod}] + error_check_good dbopen [is_valid_db $db] TRUE + set did [open $dict] + + set pflags "" + set gflags "" + set txn "" + set count 0 + + if { [is_record_based $method] == 1 } { + set checkfunc test020_recno.check + append gflags " -recno" + } else { + set checkfunc test020.check + } + puts "\tTest020.a: put/get loop" + # Here is the loop where we put and get each key/data pair + while { [gets $did str] != -1 && $count < $nentries } { + if { [is_record_based $method] == 1 } { + global kvals + + set key [expr $count + 1] + set kvals($key) [pad_data $method $str] + } else { + set key $str + } + set ret [eval {$db put} \ + $txn $pflags {$key [chop_data $method $str]}] + error_check_good put $ret 0 + set ret [eval {$db get} $txn $gflags {$key}] + error_check_good \ + get $ret [list [list $key [pad_data $method $str]]] + incr count + } + close $did + # Now we will get each key from the DB and compare the results + # to the original. + puts "\tTest020.b: dump file" + dump_file $db $txn $t1 $checkfunc + error_check_good db_close [$db close] 0 + + # Now compare the keys to see if they match the dictionary (or ints) + if { [is_record_based $method] == 1 } { + set oid [open $t2 w] + for {set i 1} {$i <= $nentries} {set i [incr i]} { + puts $oid $i + } + close $oid + file rename -force $t1 $t3 + } else { + set q q + filehead $nentries $dict $t3 + filesort $t3 $t2 + filesort $t1 $t3 + } + + error_check_good Test020:diff($t3,$t2) \ + [filecmp $t3 $t2] 0 +} + +# Check function for test020; keys and data are identical +proc test020.check { key data } { + error_check_good "key/data mismatch" $data $key +} + +proc test020_recno.check { key data } { + global dict + global kvals + + error_check_good key"$key"_exists [info exists kvals($key)] 1 + error_check_good "data mismatch: key $key" $data $kvals($key) +} diff --git a/db/test/test021.tcl b/db/test/test021.tcl new file mode 100644 index 000000000..f9a1fe32f --- /dev/null +++ b/db/test/test021.tcl @@ -0,0 +1,130 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test021.tcl,v 11.10 2000/08/25 14:21:55 sue Exp $ +# +# DB Test 21 {access method} +# Use the first 10,000 entries from the dictionary. +# Insert each with self, reversed as key and self as data. +# After all are entered, retrieve each using a cursor SET_RANGE, and getting +# about 20 keys sequentially after it (in some cases we'll run out towards +# the end of the file). +proc test021 { method {nentries 10000} args } { + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + + puts "Test021: $method ($args) $nentries equal key/data pairs" + + # Create the database and open the dictionary + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test021.db + set env NULL + } else { + set testfile test021.db + incr eindex + set env [lindex $args $eindex] + } + set t1 $testdir/t1 + set t2 $testdir/t2 + set t3 $testdir/t3 + cleanup $testdir $env + set db [eval {berkdb_open \ + -create -truncate -mode 0644} $args {$omethod $testfile}] + error_check_good dbopen [is_valid_db $db] TRUE + + set did [open $dict] + + set pflags "" + set gflags "" + set txn "" + set count 0 + + if { [is_record_based $method] == 1 } { + set checkfunc test021_recno.check + append gflags " -recno" + } else { + set checkfunc test021.check + } + puts "\tTest021.a: put loop" + # Here is the loop where we put each key/data pair + while { [gets $did str] != -1 && $count < $nentries } { + if { [is_record_based $method] == 1 } { + global kvals + + set key [expr $count + 1] + set kvals($key) [pad_data $method $str] + } else { + set key [reverse $str] + } + + set r [eval {$db put} \ + $txn $pflags {$key [chop_data $method $str]}] + error_check_good db_put $r 0 + incr count + } + close $did + + # Now we will get each key from the DB and retrieve about 20 + # records after it. + error_check_good db_close [$db close] 0 + + puts "\tTest021.b: test ranges" + set db [eval {berkdb_open -rdonly} $args $omethod $testfile ] + error_check_good dbopen [is_valid_db $db] TRUE + + # Open a cursor + set dbc [eval {$db cursor} $txn] + error_check_good db_cursor [is_substr $dbc $db] 1 + + set did [open $dict] + set i 0 + while { [gets $did str] != -1 && $i < $count } { + if { [is_record_based $method] == 1 } { + set key [expr $i + 1] + } else { + set key [reverse $str] + } + + set r [$dbc get -set_range $key] + error_check_bad dbc_get:$key [string length $r] 0 + set k [lindex [lindex $r 0] 0] + set d [lindex [lindex $r 0] 1] + $checkfunc $k $d + + for { set nrecs 0 } { $nrecs < 20 } { incr nrecs } { + set r [$dbc get "-next"] + # no error checking because we may run off the end + # of the database + if { [llength $r] == 0 } { + continue; + } + set k [lindex [lindex $r 0] 0] + set d [lindex [lindex $r 0] 1] + $checkfunc $k $d + } + incr i + } + error_check_good db_close [$db close] 0 + close $did +} + +# Check function for test021; keys and data are reversed +proc test021.check { key data } { + error_check_good "key/data mismatch for $key" $data [reverse $key] +} + +proc test021_recno.check { key data } { + global dict + global kvals + + error_check_good key"$key"_exists [info exists kvals($key)] 1 + error_check_good "data mismatch: key $key" $data $kvals($key) +} diff --git a/db/test/test022.tcl b/db/test/test022.tcl new file mode 100644 index 000000000..f9a4c9663 --- /dev/null +++ b/db/test/test022.tcl @@ -0,0 +1,55 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test022.tcl,v 11.10 2000/08/25 14:21:55 sue Exp $ +# +# Test022: Test of DB->get_byteswapped +proc test022 { method args } { + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + + puts "Test022 ($args) $omethod: DB->getbyteswapped()" + + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile1 "$testdir/test022a.db" + set testfile2 "$testdir/test022b.db" + set env NULL + } else { + set testfile1 "test022a.db" + set testfile2 "test022b.db" + incr eindex + set env [lindex $args $eindex] + } + cleanup $testdir $env + + # Create two databases, one in each byte order. + set db1 [eval {berkdb_open -create \ + -mode 0644} $omethod $args {-lorder 1234} $testfile1] + error_check_good db1_open [is_valid_db $db1] TRUE + + set db2 [eval {berkdb_open -create \ + -mode 0644} $omethod $args {-lorder 4321} $testfile2] + error_check_good db2_open [is_valid_db $db2] TRUE + + # Call DB->get_byteswapped on both of them. + set db1_order [$db1 is_byteswapped] + set db2_order [$db2 is_byteswapped] + + # Make sure that both answers are either 1 or 0, + # and that exactly one of them is 1. + error_check_good is_byteswapped_sensible_1 \ + [expr ($db1_order == 1 && $db2_order == 0) || \ + ($db1_order == 0 && $db2_order == 1)] 1 + + error_check_good db1_close [$db1 close] 0 + error_check_good db2_close [$db2 close] 0 + puts "\tTest022 complete." +} diff --git a/db/test/test023.tcl b/db/test/test023.tcl new file mode 100644 index 000000000..c222bdd83 --- /dev/null +++ b/db/test/test023.tcl @@ -0,0 +1,204 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test023.tcl,v 11.13 2000/08/25 14:21:55 sue Exp $ +# +# Duplicate delete test. +# Add a key with duplicates (first time on-page, second time off-page) +# Number the dups. +# Delete dups and make sure that CURRENT/NEXT/PREV work correctly. +proc test023 { method args } { + global alphabet + global dupnum + global dupstr + global errorInfo + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + puts "Test023: $method delete duplicates/check cursor operations" + if { [is_record_based $method] == 1 || \ + [is_rbtree $method] == 1 } { + puts "Test023: skipping for method $omethod" + return + } + + # Create the database and open the dictionary + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test023.db + set env NULL + } else { + set testfile test023.db + incr eindex + set env [lindex $args $eindex] + } + set t1 $testdir/t1 + cleanup $testdir $env + set db [eval {berkdb_open \ + -create -truncate -mode 0644 -dup} $args {$omethod $testfile}] + error_check_good dbopen [is_valid_db $db] TRUE + + set pflags "" + set gflags "" + set txn "" + + set dbc [eval {$db cursor} $txn] + error_check_good db_cursor [is_substr $dbc $db] 1 + + foreach i { onpage offpage } { + if { $i == "onpage" } { + set dupstr DUP + } else { + set dupstr [repeat $alphabet 50] + } + puts "\tTest023.a: Insert key w/$i dups" + set key "duplicate_val_test" + for { set count 0 } { $count < 20 } { incr count } { + set ret \ + [eval {$db put} $txn $pflags {$key $count$dupstr}] + error_check_good db_put $ret 0 + } + + # Now let's get all the items and make sure they look OK. + puts "\tTest023.b: Check initial duplicates" + set dupnum 0 + dump_file $db $txn $t1 test023.check + + # Delete a couple of random items (FIRST, LAST one in middle) + # Make sure that current returns an error and that NEXT and + # PREV do the right things. + + set ret [$dbc get -set $key] + error_check_bad dbc_get:SET [llength $ret] 0 + + puts "\tTest023.c: Delete first and try gets" + # This should be the first duplicate + error_check_good \ + dbc_get:SET $ret [list [list duplicate_val_test 0$dupstr]] + + # Now delete it. + set ret [$dbc del] + error_check_good dbc_del:FIRST $ret 0 + + # Now current should fail + set ret [$dbc get -current] + error_check_good dbc_get:CURRENT $ret [list [list [] []]] + + # Now Prev should fail + set ret [$dbc get -prev] + error_check_good dbc_get:prev0 [llength $ret] 0 + + # Now 10 nexts should work to get us in the middle + for { set j 1 } { $j <= 10 } { incr j } { + set ret [$dbc get -next] + error_check_good \ + dbc_get:next [llength [lindex $ret 0]] 2 + error_check_good \ + dbc_get:next [lindex [lindex $ret 0] 1] $j$dupstr + } + + puts "\tTest023.d: Delete middle and try gets" + # Now do the delete on the current key. + set ret [$dbc del] + error_check_good dbc_del:10 $ret 0 + + # Now current should fail + set ret [$dbc get -current] + error_check_good \ + dbc_get:deleted $ret [list [list [] []]] + + # Prev and Next should work + set ret [$dbc get -next] + error_check_good dbc_get:next [llength [lindex $ret 0]] 2 + error_check_good \ + dbc_get:next [lindex [lindex $ret 0] 1] 11$dupstr + + set ret [$dbc get -prev] + error_check_good dbc_get:next [llength [lindex $ret 0]] 2 + error_check_good \ + dbc_get:next [lindex [lindex $ret 0] 1] 9$dupstr + + # Now go to the last one + for { set j 11 } { $j <= 19 } { incr j } { + set ret [$dbc get -next] + error_check_good \ + dbc_get:next [llength [lindex $ret 0]] 2 + error_check_good \ + dbc_get:next [lindex [lindex $ret 0] 1] $j$dupstr + } + + puts "\tTest023.e: Delete last and try gets" + # Now do the delete on the current key. + set ret [$dbc del] + error_check_good dbc_del:LAST $ret 0 + + # Now current should fail + set ret [$dbc get -current] + error_check_good \ + dbc_get:deleted $ret [list [list [] []]] + + # Next should fail + set ret [$dbc get -next] + error_check_good dbc_get:next19 [llength $ret] 0 + + # Prev should work + set ret [$dbc get -prev] + error_check_good dbc_get:next [llength [lindex $ret 0]] 2 + error_check_good \ + dbc_get:next [lindex [lindex $ret 0] 1] 18$dupstr + + # Now overwrite the current one, then count the number + # of data items to make sure that we have the right number. + + puts "\tTest023.f: Count keys, overwrite current, count again" + # At this point we should have 17 keys the (initial 20 minus + # 3 deletes) + set dbc2 [$db cursor] + error_check_good db_cursor:2 [is_substr $dbc2 $db] 1 + + set count_check 0 + for { set rec [$dbc2 get -first] } { + [llength $rec] != 0 } { set rec [$dbc2 get -next] } { + incr count_check + } + error_check_good numdups $count_check 17 + + set ret [$dbc put -current OVERWRITE] + error_check_good dbc_put:current $ret 0 + + set count_check 0 + for { set rec [$dbc2 get -first] } { + [llength $rec] != 0 } { set rec [$dbc2 get -next] } { + incr count_check + } + error_check_good numdups $count_check 17 + + # Done, delete all the keys for next iteration + set ret [eval {$db del} $txn {$key}] + error_check_good db_delete $ret 0 + + # database should be empty + + set ret [$dbc get -first] + error_check_good first_after_empty [llength $ret] 0 + } + + error_check_good dbc_close [$dbc close] 0 + error_check_good db_close [$db close] 0 + +} + +# Check function for test023; keys and data are identical +proc test023.check { key data } { + global dupnum + global dupstr + error_check_good "bad key" $key duplicate_val_test + error_check_good "data mismatch for $key" $data $dupnum$dupstr + incr dupnum +} diff --git a/db/test/test024.tcl b/db/test/test024.tcl new file mode 100644 index 000000000..f0b6762cd --- /dev/null +++ b/db/test/test024.tcl @@ -0,0 +1,206 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test024.tcl,v 11.14 2000/08/25 14:21:55 sue Exp $ +# +# DB Test 24 {method nentries} +# Test the Btree and Record number get-by-number functionality. +proc test024 { method {nentries 10000} args} { + source ./include.tcl + global rand_init + + set do_renumber [is_rrecno $method] + set args [convert_args $method $args] + set omethod [convert_method $method] + + puts "Test024: $method ($args)" + + if { [string compare $omethod "-hash"] == 0 } { + puts "Test024 skipping for method HASH" + return + } + + berkdb srand $rand_init + + # Create the database and open the dictionary + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test024.db + set env NULL + } else { + set testfile test024.db + incr eindex + set env [lindex $args $eindex] + } + set t1 $testdir/t1 + set t2 $testdir/t2 + set t3 $testdir/t3 + + cleanup $testdir $env + + # Read the first nentries dictionary elements and reverse them. + # Keep a list of these (these will be the keys). + puts "\tTest024.a: initialization" + set keys "" + set did [open $dict] + set count 0 + while { [gets $did str] != -1 && $count < $nentries } { + lappend keys [reverse $str] + incr count + } + close $did + + # Generate sorted order for the keys + set sorted_keys [lsort $keys] + # Create the database + if { [string compare $omethod "-btree"] == 0 } { + set db [eval {berkdb_open -create -truncate \ + -mode 0644 -recnum} $args {$omethod $testfile}] + error_check_good dbopen [is_valid_db $db] TRUE + } else { + set db [eval {berkdb_open -create -truncate \ + -mode 0644} $args {$omethod $testfile}] + error_check_good dbopen [is_valid_db $db] TRUE + } + + set pflags "" + set gflags "" + set txn "" + + if { [is_record_based $method] == 1 } { + set gflags " -recno" + } + + puts "\tTest024.b: put/get loop" + foreach k $keys { + if { [is_record_based $method] == 1 } { + set key [lsearch $sorted_keys $k] + incr key + } else { + set key $k + } + set ret [eval {$db put} \ + $txn $pflags {$key [chop_data $method $k]}] + error_check_good put $ret 0 + set ret [eval {$db get} $txn $gflags {$key}] + error_check_good \ + get $ret [list [list $key [pad_data $method $k]]] + } + + # Now we will get each key from the DB and compare the results + # to the original. + puts "\tTest024.c: dump file" + + # Put sorted keys in file + set oid [open $t1 w] + foreach k $sorted_keys { + puts $oid [pad_data $method $k] + } + close $oid + + # Instead of using dump_file; get all the keys by keynum + set oid [open $t2 w] + if { [string compare $omethod "-btree"] == 0 } { + set do_renumber 1 + } + + set gflags " -recno" + + for { set k 1 } { $k <= $count } { incr k } { + set ret [eval {$db get} $txn $gflags {$k}] + puts $oid [lindex [lindex $ret 0] 1] + error_check_good recnum_get [lindex [lindex $ret 0] 1] \ + [pad_data $method [lindex $sorted_keys [expr $k - 1]]] + } + close $oid + error_check_good db_close [$db close] 0 + + error_check_good Test024.c:diff($t1,$t2) \ + [filecmp $t1 $t2] 0 + + # Now, reopen the file and run the last test again. + puts "\tTest024.d: close, open, and dump file" + set db [eval {berkdb_open -rdonly} $args $testfile] + error_check_good dbopen [is_valid_db $db] TRUE + set oid [open $t2 w] + for { set k 1 } { $k <= $count } { incr k } { + set ret [eval {$db get} $txn $gflags {$k}] + puts $oid [lindex [lindex $ret 0] 1] + error_check_good recnum_get [lindex [lindex $ret 0] 1] \ + [pad_data $method [lindex $sorted_keys [expr $k - 1]]] + } + close $oid + error_check_good db_close [$db close] 0 + error_check_good Test024.d:diff($t1,$t2) \ + [filecmp $t1 $t2] 0 + + # Now, reopen the file and run the last test again in reverse direction. + puts "\tTest024.e: close, open, and dump file in reverse direction" + set db [eval {berkdb_open -rdonly} $args $testfile] + error_check_good dbopen [is_valid_db $db] TRUE + # Put sorted keys in file + set rsorted "" + foreach k $sorted_keys { + set rsorted [linsert $rsorted 0 $k] + } + set oid [open $t1 w] + foreach k $rsorted { + puts $oid [pad_data $method $k] + } + close $oid + + set oid [open $t2 w] + for { set k $count } { $k > 0 } { incr k -1 } { + set ret [eval {$db get} $txn $gflags {$k}] + puts $oid [lindex [lindex $ret 0] 1] + error_check_good recnum_get [lindex [lindex $ret 0] 1] \ + [pad_data $method [lindex $sorted_keys [expr $k - 1]]] + } + close $oid + error_check_good db_close [$db close] 0 + error_check_good Test024.e:diff($t1,$t2) \ + [filecmp $t1 $t2] 0 + + # Now try deleting elements and making sure they work + puts "\tTest024.f: delete test" + set db [eval {berkdb_open} $args $testfile] + error_check_good dbopen [is_valid_db $db] TRUE + while { $count > 0 } { + set kndx [berkdb random_int 1 $count] + set kval [lindex $keys [expr $kndx - 1]] + set recno [expr [lsearch $sorted_keys $kval] + 1] + + if { [is_record_based $method] == 1 } { + set ret [eval {$db del} $txn {$recno}] + } else { + set ret [eval {$db del} $txn {$kval}] + } + error_check_good delete $ret 0 + + # Remove the key from the key list + set ndx [expr $kndx - 1] + set keys [lreplace $keys $ndx $ndx] + + if { $do_renumber == 1 } { + set r [expr $recno - 1] + set sorted_keys [lreplace $sorted_keys $r $r] + } + + # Check that the keys after it have been renumbered + if { $do_renumber == 1 && $recno != $count } { + set r [expr $recno - 1] + set ret [eval {$db get} $txn $gflags {$recno}] + error_check_good get_after_del \ + [lindex [lindex $ret 0] 1] [lindex $sorted_keys $r] + } + + # Decrement count + incr count -1 + } + error_check_good db_close [$db close] 0 +} diff --git a/db/test/test025.tcl b/db/test/test025.tcl new file mode 100644 index 000000000..9f8deecb4 --- /dev/null +++ b/db/test/test025.tcl @@ -0,0 +1,105 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test025.tcl,v 11.11 2000/11/16 23:56:18 ubell Exp $ +# +# DB Test 25 {method nentries} +# Test the DB_APPEND flag. +proc test025 { method {nentries 10000} {start 0 } {tnum "25" } args} { + global kvals + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + puts "Test0$tnum: $method ($args)" + + if { [string compare $omethod "-btree"] == 0 } { + puts "Test0$tnum skipping for method BTREE" + return + } + if { [string compare $omethod "-hash"] == 0 } { + puts "Test0$tnum skipping for method HASH" + return + } + + # Create the database and open the dictionary + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test0$tnum.db + set env NULL + } else { + set testfile test0$tnum.db + incr eindex + set env [lindex $args $eindex] + } + set t1 $testdir/t1 + + cleanup $testdir $env + set db [eval {berkdb_open \ + -create -truncate -mode 0644} $args {$omethod $testfile}] + error_check_good dbopen [is_valid_db $db] TRUE + set did [open $dict] + + puts "\tTest0$tnum.a: put/get loop" + set gflags " -recno" + set pflags " -append" + set txn "" + set checkfunc test025_check + + # Here is the loop where we put and get each key/data pair + set count $start + set nentries [expr $start + $nentries] + if { $count != 0 } { + gets $did str + set k [expr $count + 1] + set kvals($k) [pad_data $method $str] + set ret [eval {$db put} $txn $k {[chop_data $method $str]}] + error_check_good db_put $ret 0 + incr count + } + + while { [gets $did str] != -1 && $count < $nentries } { + set k [expr $count + 1] + set kvals($k) [pad_data $method $str] + set ret [eval {$db put} $txn $pflags {[chop_data $method $str]}] + error_check_good db_put $ret $k + + set ret [eval {$db get} $txn $gflags {$k}] + error_check_good \ + get $ret [list [list $k [pad_data $method $str]]] + incr count + if { [expr $count + 1] == 0 } { + incr count + } + } + close $did + + # Now we will get each key from the DB and compare the results + # to the original. + puts "\tTest0$tnum.b: dump file" + dump_file $db $txn $t1 $checkfunc + error_check_good db_close [$db close] 0 + + puts "\tTest0$tnum.c: close, open, and dump file" + # Now, reopen the file and run the last test again. + open_and_dump_file $testfile $env $txn $t1 $checkfunc \ + dump_file_direction -first -next + + # Now, reopen the file and run the last test again in the + # reverse direction. + puts "\tTest0$tnum.d: close, open, and dump file in reverse direction" + open_and_dump_file $testfile $env $txn $t1 $checkfunc \ + dump_file_direction -last -prev +} + +proc test025_check { key data } { + global kvals + + error_check_good key"$key"_exists [info exists kvals($key)] 1 + error_check_good " key/data mismatch for |$key|" $data $kvals($key) +} diff --git a/db/test/test026.tcl b/db/test/test026.tcl new file mode 100644 index 000000000..6c19c60a2 --- /dev/null +++ b/db/test/test026.tcl @@ -0,0 +1,112 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test026.tcl,v 11.13 2000/11/17 19:07:51 sue Exp $ +# +# DB Test 26 {access method} +# Keyed delete test through cursor. +# If ndups is small; this will test on-page dups; if it's large, it +# will test off-page dups. +proc test026 { method {nentries 2000} {ndups 5} {tnum 26} args} { + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + + if { [is_record_based $method] == 1 || \ + [is_rbtree $method] == 1 } { + puts "Test0$tnum skipping for method $method" + return + } + puts "Test0$tnum: $method ($args) $nentries keys\ + with $ndups dups; cursor delete test" + + # Create the database and open the dictionary + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test0$tnum.db + set env NULL + } else { + set testfile test0$tnum.db + incr eindex + set env [lindex $args $eindex] + } + cleanup $testdir $env + + set pflags "" + set gflags "" + set txn "" + set count 0 + + # Here is the loop where we put and get each key/data pair + + puts "\tTest0$tnum.a: Put loop" + set db [eval {berkdb_open -create -truncate \ + -mode 0644} $args {$omethod -dup $testfile}] + error_check_good dbopen [is_valid_db $db] TRUE + set did [open $dict] + while { [gets $did str] != -1 && $count < [expr $nentries * $ndups] } { + set datastr [ make_data_str $str ] + for { set j 1 } { $j <= $ndups} {incr j} { + set ret [eval {$db put} \ + $txn $pflags {$str [chop_data $method $j$datastr]}] + error_check_good db_put $ret 0 + incr count + } + } + close $did + + error_check_good db_close [$db close] 0 + set db [eval {berkdb_open} $args $testfile] + error_check_good dbopen [is_valid_db $db] TRUE + + # Now we will sequentially traverse the database getting each + # item and deleting it. + set count 0 + set dbc [eval {$db cursor} $txn] + error_check_good db_cursor [is_substr $dbc $db] 1 + + puts "\tTest0$tnum.b: Get/delete loop" + set i 1 + for { set ret [$dbc get -first] } { + [string length $ret] != 0 } { + set ret [$dbc get -next] } { + + set key [lindex [lindex $ret 0] 0] + set data [lindex [lindex $ret 0] 1] + if { $i == 1 } { + set curkey $key + } + error_check_good seq_get:key $key $curkey + error_check_good \ + seq_get:data $data [pad_data $method $i[make_data_str $key]] + + if { $i == $ndups } { + set i 1 + } else { + incr i + } + + # Now delete the key + set ret [$dbc del] + error_check_good db_del:$key $ret 0 + } + error_check_good dbc_close [$dbc close] 0 + error_check_good db_close [$db close] 0 + + puts "\tTest0$tnum.c: Verify empty file" + # Double check that file is now empty + set db [eval {berkdb_open} $args $testfile] + error_check_good dbopen [is_valid_db $db] TRUE + set dbc [eval {$db cursor} $txn] + error_check_good db_cursor [is_substr $dbc $db] 1 + set ret [$dbc get -first] + error_check_good get_on_empty [string length $ret] 0 + error_check_good dbc_close [$dbc close] 0 + error_check_good db_close [$db close] 0 +} diff --git a/db/test/test027.tcl b/db/test/test027.tcl new file mode 100644 index 000000000..ae4bf64fb --- /dev/null +++ b/db/test/test027.tcl @@ -0,0 +1,13 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test027.tcl,v 11.4 2000/05/22 12:51:39 bostic Exp $ +# +# DB Test 27 {access method} +# Check that delete operations work. Create a database; close database and +# reopen it. Then issues delete by key for each entry. +proc test027 { method {nentries 100} args} { + eval {test026 $method $nentries 100 27} $args +} diff --git a/db/test/test028.tcl b/db/test/test028.tcl new file mode 100644 index 000000000..b460dd53a --- /dev/null +++ b/db/test/test028.tcl @@ -0,0 +1,208 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test028.tcl,v 11.12 2000/08/25 14:21:55 sue Exp $ +# +# Put after cursor delete test. +proc test028 { method args } { + global dupnum + global dupstr + global alphabet + global errorInfo + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + + puts "Test028: $method put after cursor delete test" + + if { [is_rbtree $method] == 1 } { + puts "Test028 skipping for method $method" + return + } + if { [is_record_based $method] == 1 } { + set key 10 + } else { + append args " -dup" + set key "put_after_cursor_del" + } + + # Create the database and open the dictionary + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test028.db + set env NULL + } else { + set testfile test028.db + incr eindex + set env [lindex $args $eindex] + } + set t1 $testdir/t1 + cleanup $testdir $env + set db [eval {berkdb_open \ + -create -truncate -mode 0644} $args {$omethod $testfile}] + error_check_good dbopen [is_valid_db $db] TRUE + + set ndups 20 + set txn "" + set pflags "" + set gflags "" + + if { [is_record_based $method] == 1 } { + set gflags " -recno" + } + + set dbc [eval {$db cursor} $txn] + error_check_good db_cursor [is_substr $dbc $db] 1 + + foreach i { offpage onpage } { + foreach b { bigitem smallitem } { + if { $i == "onpage" } { + if { $b == "bigitem" } { + set dupstr [repeat $alphabet 100] + } else { + set dupstr DUP + } + } else { + if { $b == "bigitem" } { + set dupstr [repeat $alphabet 100] + } else { + set dupstr [repeat $alphabet 50] + } + } + + if { $b == "bigitem" } { + set dupstr [repeat $dupstr 10] + } + puts "\tTest028: $i/$b" + + puts "\tTest028.a: Insert key with single data item" + set ret [eval {$db put} \ + $txn $pflags {$key [chop_data $method $dupstr]}] + error_check_good db_put $ret 0 + + # Now let's get the item and make sure its OK. + puts "\tTest028.b: Check initial entry" + set ret [eval {$db get} $txn $gflags {$key}] + error_check_good db_get \ + $ret [list [list $key [pad_data $method $dupstr]]] + + # Now try a put with NOOVERWRITE SET (should be error) + puts "\tTest028.c: No_overwrite test" + set ret [eval {$db put} $txn \ + {-nooverwrite $key [chop_data $method $dupstr]}] + error_check_good \ + db_put [is_substr $ret "DB_KEYEXIST"] 1 + + # Now delete the item with a cursor + puts "\tTest028.d: Delete test" + set ret [$dbc get -set $key] + error_check_bad dbc_get:SET [llength $ret] 0 + + set ret [$dbc del] + error_check_good dbc_del $ret 0 + + puts "\tTest028.e: Reput the item" + set ret [eval {$db put} $txn \ + {-nooverwrite $key [chop_data $method $dupstr]}] + error_check_good db_put $ret 0 + + puts "\tTest028.f: Retrieve the item" + set ret [eval {$db get} $txn $gflags {$key}] + error_check_good db_get $ret \ + [list [list $key [pad_data $method $dupstr]]] + + # Delete the key to set up for next test + set ret [eval {$db del} $txn {$key}] + error_check_good db_del $ret 0 + + # Now repeat the above set of tests with + # duplicates (if not RECNO). + if { [is_record_based $method] == 1 } { + continue; + } + + puts "\tTest028.g: Insert key with duplicates" + for { set count 0 } { $count < $ndups } { incr count } { + set ret [eval {$db put} \ + $txn {$key [chop_data $method $count$dupstr]}] + error_check_good db_put $ret 0 + } + + puts "\tTest028.h: Check dups" + set dupnum 0 + dump_file $db $txn $t1 test028.check + + # Try no_overwrite + puts "\tTest028.i: No_overwrite test" + set ret [eval {$db put} \ + $txn {-nooverwrite $key $dupstr}] + error_check_good \ + db_put [is_substr $ret "DB_KEYEXIST"] 1 + + # Now delete all the elements with a cursor + puts "\tTest028.j: Cursor Deletes" + set count 0 + for { set ret [$dbc get -set $key] } { + [string length $ret] != 0 } { + set ret [$dbc get -next] } { + set k [lindex [lindex $ret 0] 0] + set d [lindex [lindex $ret 0] 1] + error_check_good db_seq(key) $k $key + error_check_good db_seq(data) $d $count$dupstr + set ret [$dbc del] + error_check_good dbc_del $ret 0 + incr count + if { $count == [expr $ndups - 1] } { + puts "\tTest028.k:\ + Duplicate No_Overwrite test" + set $errorInfo "" + set ret [eval {$db put} $txn \ + {-nooverwrite $key $dupstr}] + error_check_good db_put [is_substr \ + $ret "DB_KEYEXIST"] 1 + } + } + + # Make sure all the items are gone + puts "\tTest028.l: Get after delete" + set ret [$dbc get -set $key] + error_check_good get_after_del [string length $ret] 0 + + puts "\tTest028.m: Reput the item" + set ret [eval {$db put} \ + $txn {-nooverwrite $key 0$dupstr}] + error_check_good db_put $ret 0 + for { set count 1 } { $count < $ndups } { incr count } { + set ret [eval {$db put} $txn {$key $count$dupstr}] + error_check_good db_put $ret 0 + } + + puts "\tTest028.n: Retrieve the item" + set dupnum 0 + dump_file $db $txn $t1 test028.check + + # Clean out in prep for next test + set ret [eval {$db del} $txn {$key}] + error_check_good db_del $ret 0 + } + } + + error_check_good dbc_close [$dbc close] 0 + error_check_good db_close [$db close] 0 + +} + +# Check function for test028; keys and data are identical +proc test028.check { key data } { + global dupnum + global dupstr + error_check_good "Bad key" $key put_after_cursor_del + error_check_good "data mismatch for $key" $data $dupnum$dupstr + incr dupnum +} diff --git a/db/test/test029.tcl b/db/test/test029.tcl new file mode 100644 index 000000000..c10815b0b --- /dev/null +++ b/db/test/test029.tcl @@ -0,0 +1,192 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test029.tcl,v 11.13 2000/08/25 14:21:55 sue Exp $ +# +# DB Test 29 {method nentries} +# Test the Btree and Record number renumbering. +proc test029 { method {nentries 10000} args} { + source ./include.tcl + + set do_renumber [is_rrecno $method] + set args [convert_args $method $args] + set omethod [convert_method $method] + + puts "Test029: $method ($args)" + + if { [string compare $omethod "-hash"] == 0 } { + puts "Test029 skipping for method HASH" + return + } + if { [is_record_based $method] == 1 && $do_renumber != 1 } { + puts "Test029 skipping for method RECNO (w/out renumbering)" + return + } + + # Create the database and open the dictionary + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test029.db + set env NULL + } else { + set testfile test029.db + incr eindex + set env [lindex $args $eindex] + } + cleanup $testdir $env + + # Read the first nentries dictionary elements and reverse them. + # Keep a list of these (these will be the keys). + puts "\tTest029.a: initialization" + set keys "" + set did [open $dict] + set count 0 + while { [gets $did str] != -1 && $count < $nentries } { + lappend keys [reverse $str] + incr count + } + close $did + + # Generate sorted order for the keys + set sorted_keys [lsort $keys] + + # Save the first and last keys + set last_key [lindex $sorted_keys end] + set last_keynum [llength $sorted_keys] + + set first_key [lindex $sorted_keys 0] + set first_keynum 1 + + # Create the database + if { [string compare $omethod "-btree"] == 0 } { + set db [eval {berkdb_open -create -truncate \ + -mode 0644 -recnum} $args {$omethod $testfile}] + error_check_good dbopen [is_valid_db $db] TRUE + } else { + set db [eval {berkdb_open -create -truncate \ + -mode 0644} $args {$omethod $testfile}] + error_check_good dbopen [is_valid_db $db] TRUE + } + + set pflags "" + set gflags "" + set txn "" + + if { [is_record_based $method] == 1 } { + append gflags " -recno" + } + + puts "\tTest029.b: put/get loop" + foreach k $keys { + if { [is_record_based $method] == 1 } { + set key [lsearch $sorted_keys $k] + incr key + } else { + set key $k + } + set ret [eval {$db put} \ + $txn $pflags {$key [chop_data $method $k]}] + error_check_good dbput $ret 0 + + set ret [eval {$db get} $txn $gflags {$key}] + if { [string compare [lindex [lindex $ret 0] 1] $k] != 0 } { + puts "Test029: put key-data $key $k got $ret" + return + } + } + + # Now delete the first key in the database + puts "\tTest029.c: delete and verify renumber" + + # Delete the first key in the file + if { [is_record_based $method] == 1 } { + set key $first_keynum + } else { + set key $first_key + } + + set ret [eval {$db del} $txn {$key}] + error_check_good db_del $ret 0 + + # Now we are ready to retrieve records based on + # record number + if { [string compare $omethod "-btree"] == 0 } { + append gflags " -recno" + } + + # First try to get the old last key (shouldn't exist) + set ret [eval {$db get} $txn $gflags {$last_keynum}] + error_check_good get_after_del $ret [list] + + # Now try to get what we think should be the last key + set ret [eval {$db get} $txn $gflags {[expr $last_keynum - 1]}] + error_check_good \ + getn_last_after_del [lindex [lindex $ret 0] 1] $last_key + + # Create a cursor; we need it for the next test and we + # need it for recno here. + set dbc [eval {$db cursor} $txn] + error_check_good db_cursor [is_substr $dbc $db] 1 + + # OK, now re-put the first key and make sure that we + # renumber the last key appropriately. + if { [string compare $omethod "-btree"] == 0 } { + set ret [eval {$db put} $txn {$key [chop_data $method $first_key]}] + error_check_good db_put $ret 0 + } else { + # Recno + set ret [eval {$dbc get} $txn {-first}] + set ret [eval {$dbc put} $txn $pflags {-before $first_key}] + error_check_bad dbc_put:DB_BEFORE $ret 0 + } + + # Now check that the last record matches the last record number + set ret [eval {$db get} $txn $gflags {$last_keynum}] + error_check_good \ + getn_last_after_put [lindex [lindex $ret 0] 1] $last_key + + # Now delete the first key in the database using a cursor + puts "\tTest029.d: delete with cursor and verify renumber" + + set ret [eval {$dbc get} $txn {-first}] + error_check_good dbc_first $ret [list [list $key $first_key]] + + # Now delete at the cursor + set ret [$dbc del] + error_check_good dbc_del $ret 0 + + # Now check the record numbers of the last keys again. + # First try to get the old last key (shouldn't exist) + set ret [eval {$db get} $txn $gflags {$last_keynum}] + error_check_good get_last_after_cursor_del:$ret $ret [list] + + # Now try to get what we think should be the last key + set ret [eval {$db get} $txn $gflags {[expr $last_keynum - 1]}] + error_check_good \ + getn_after_cursor_del [lindex [lindex $ret 0] 1] $last_key + + # Re-put the first key and make sure that we renumber the last + # key appropriately. + puts "\tTest029.e: put with cursor and verify renumber" + if { [string compare $omethod "-btree"] == 0 } { + set ret [eval {$dbc put} \ + $txn $pflags {-current $first_key}] + error_check_good dbc_put:DB_CURRENT $ret 0 + } else { + set ret [eval {$dbc put} $txn $pflags {-before $first_key}] + error_check_bad dbc_put:DB_BEFORE $ret 0 + } + + # Now check that the last record matches the last record number + set ret [eval {$db get} $txn $gflags {$last_keynum}] + error_check_good \ + get_after_cursor_reput [lindex [lindex $ret 0] 1] $last_key + + error_check_good dbc_close [$dbc close] 0 + error_check_good db_close [$db close] 0 +} diff --git a/db/test/test030.tcl b/db/test/test030.tcl new file mode 100644 index 000000000..7395adf82 --- /dev/null +++ b/db/test/test030.tcl @@ -0,0 +1,191 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test030.tcl,v 11.13 2000/08/25 14:21:55 sue Exp $ +# +# DB Test 30: Test DB_NEXT_DUP Functionality. +proc test030 { method {nentries 10000} args } { + global rand_init + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + + if { [is_record_based $method] == 1 || + [is_rbtree $method] == 1 } { + puts "Test030 skipping for method $method" + return + } + + puts "Test030: $method ($args) $nentries DB_NEXT_DUP testing" + berkdb srand $rand_init + + # Create the database and open the dictionary + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test030.db + set cntfile $testdir/cntfile.db + set env NULL + } else { + set testfile test030.db + set cntfile cntfile.db + incr eindex + set env [lindex $args $eindex] + } + set t1 $testdir/t1 + set t2 $testdir/t2 + set t3 $testdir/t3 + cleanup $testdir $env + + set db [eval {berkdb_open -create -truncate \ + -mode 0644 -dup} $args {$omethod $testfile}] + error_check_good dbopen [is_valid_db $db] TRUE + + # Use a second DB to keep track of how many duplicates + # we enter per key + + set cntdb [eval {berkdb_open -create -truncate \ + -mode 0644} $args {-btree $cntfile}] + error_check_good dbopen:cntfile [is_valid_db $db] TRUE + + set pflags "" + set gflags "" + set txn "" + set count 0 + + # Here is the loop where we put and get each key/data pair + # We will add between 1 and 10 dups with values 1 ... dups + # We'll verify each addition. + + set did [open $dict] + puts "\tTest030.a: put and get duplicate keys." + set dbc [eval {$db cursor} $txn] + + while { [gets $did str] != -1 && $count < $nentries } { + set ndup [berkdb random_int 1 10] + + for { set i 1 } { $i <= $ndup } { incr i 1 } { + set ret [eval {$cntdb put} \ + $txn $pflags {$str [chop_data $method $ndup]}] + error_check_good put_cnt $ret 0 + set datastr $i:$str + set ret [eval {$db put} \ + $txn $pflags {$str [chop_data $method $datastr]}] + error_check_good put $ret 0 + } + + # Now retrieve all the keys matching this key + set x 0 + for {set ret [$dbc get -set $str]} \ + {[llength $ret] != 0} \ + {set ret [$dbc get -nextdup] } { + incr x + + if { [llength $ret] == 0 } { + break + } + + set k [lindex [lindex $ret 0] 0] + if { [string compare $k $str] != 0 } { + break + } + + set datastr [lindex [lindex $ret 0] 1] + set d [data_of $datastr] + error_check_good Test030:put $d $str + + set id [ id_of $datastr ] + error_check_good Test030:dup# $id $x + } + error_check_good Test030:numdups $x $ndup + incr count + } + close $did + + # Verify on sequential pass of entire file + puts "\tTest030.b: sequential check" + + # We can't just set lastkey to a null string, since that might + # be a key now! + set lastkey "THIS STRING WILL NEVER BE A KEY" + + for {set ret [$dbc get -first]} \ + {[llength $ret] != 0} \ + {set ret [$dbc get -next] } { + + # Outer loop should always get a new key + + set k [lindex [lindex $ret 0] 0] + error_check_bad outer_get_loop:key $k $lastkey + + set datastr [lindex [lindex $ret 0] 1] + set d [data_of $datastr] + set id [ id_of $datastr ] + + error_check_good outer_get_loop:data $d $k + error_check_good outer_get_loop:id $id 1 + + set lastkey $k + # Figure out how may dups we should have + set ret [eval {$cntdb get} $txn $pflags {$k}] + set ndup [lindex [lindex $ret 0] 1] + + set howmany 1 + for { set ret [$dbc get -nextdup] } \ + { [llength $ret] != 0 } \ + { set ret [$dbc get -nextdup] } { + incr howmany + + set k [lindex [lindex $ret 0] 0] + error_check_good inner_get_loop:key $k $lastkey + + set datastr [lindex [lindex $ret 0] 1] + set d [data_of $datastr] + set id [ id_of $datastr ] + + error_check_good inner_get_loop:data $d $k + error_check_good inner_get_loop:id $id $howmany + + } + error_check_good ndups_found $howmany $ndup + } + + # Verify on key lookup + puts "\tTest030.c: keyed check" + set cnt_dbc [$cntdb cursor] + for {set ret [$cnt_dbc get -first]} \ + {[llength $ret] != 0} \ + {set ret [$cnt_dbc get -next] } { + set k [lindex [lindex $ret 0] 0] + + set howmany [lindex [lindex $ret 0] 1] + error_check_bad cnt_seq:data [string length $howmany] 0 + + set i 0 + for {set ret [$dbc get -set $k]} \ + {[llength $ret] != 0} \ + {set ret [$dbc get -nextdup] } { + incr i + + set k [lindex [lindex $ret 0] 0] + + set datastr [lindex [lindex $ret 0] 1] + set d [data_of $datastr] + set id [ id_of $datastr ] + + error_check_good inner_get_loop:data $d $k + error_check_good inner_get_loop:id $id $i + } + error_check_good keyed_count $i $howmany + + } + error_check_good cnt_curs_close [$cnt_dbc close] 0 + error_check_good db_curs_close [$dbc close] 0 + error_check_good cnt_file_close [$cntdb close] 0 + error_check_good db_file_close [$db close] 0 +} diff --git a/db/test/test031.tcl b/db/test/test031.tcl new file mode 100644 index 000000000..35041541f --- /dev/null +++ b/db/test/test031.tcl @@ -0,0 +1,196 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test031.tcl,v 11.17 2000/11/06 19:31:55 sue Exp $ +# +# DB Test 31 {access method} +# Use the first 10,000 entries from the dictionary. +# Insert each with self as key and "ndups" duplicates +# For the data field, prepend random five-char strings (see test032) +# that we force the duplicate sorting code to do something. +# Along the way, test that we cannot insert duplicate duplicates +# using DB_NODUPDATA. +# By setting ndups large, we can make this an off-page test +# After all are entered, retrieve all; verify output. +# Close file, reopen, do retrieve and re-verify. +# This does not work for recno +proc test031 { method {nentries 10000} {ndups 5} {tnum 31} args } { + global alphabet + global rand_init + source ./include.tcl + + berkdb srand $rand_init + + set args [convert_args $method $args] + set omethod [convert_method $method] + + # Create the database and open the dictionary + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test0$tnum.db + set checkdb $testdir/checkdb.db + set env NULL + } else { + set testfile test0$tnum.db + set checkdb checkdb.db + incr eindex + set env [lindex $args $eindex] + } + set t1 $testdir/t1 + set t2 $testdir/t2 + set t3 $testdir/t3 + cleanup $testdir $env + + puts "Test0$tnum: \ + $method ($args) $nentries small sorted dup key/data pairs" + if { [is_record_based $method] == 1 || \ + [is_rbtree $method] == 1 } { + puts "Test0$tnum skipping for method $omethod" + return + } + set db [eval {berkdb_open -create -truncate \ + -mode 0644} $args {$omethod -dup -dupsort $testfile}] + error_check_good dbopen [is_valid_db $db] TRUE + set did [open $dict] + + set check_db [eval {berkdb_open \ + -create -truncate -mode 0644} $args {-hash $checkdb}] + error_check_good dbopen:check_db [is_valid_db $check_db] TRUE + + set pflags "" + set gflags "" + set txn "" + set count 0 + + # Here is the loop where we put and get each key/data pair + puts "\tTest0$tnum.a: Put/get loop, check nodupdata" + set dbc [eval {$db cursor} $txn] + error_check_good cursor_open [is_substr $dbc $db] 1 + while { [gets $did str] != -1 && $count < $nentries } { + # Re-initialize random string generator + randstring_init $ndups + + set dups "" + for { set i 1 } { $i <= $ndups } { incr i } { + set pref [randstring] + set dups $dups$pref + set datastr $pref:$str + if { $i == 2 } { + set nodupstr $datastr + } + set ret [eval {$db put} \ + $txn $pflags {$str [chop_data $method $datastr]}] + error_check_good put $ret 0 + } + + # Test DB_NODUPDATA using the DB handle + set ret [eval {$db put -nodupdata} \ + $txn $pflags {$str [chop_data $method $nodupstr]}] + error_check_good db_nodupdata [is_substr $ret "DB_KEYEXIST"] 1 + + set ret [eval {$check_db put} \ + $txn $pflags {$str [chop_data $method $dups]}] + error_check_good checkdb_put $ret 0 + + # Now retrieve all the keys matching this key + set x 0 + set lastdup "" + # Test DB_NODUPDATA using cursor handle + set ret [$dbc get -set $str] + error_check_bad dbc_get [llength $ret] 0 + set datastr [lindex [lindex $ret 0] 1] + error_check_bad dbc_data [string length $datastr] 0 + set ret [eval {$dbc put -nodupdata} \ + {$str [chop_data $method $datastr]}] + error_check_good dbc_nodupdata [is_substr $ret "DB_KEYEXIST"] 1 + + for {set ret [$dbc get -set $str]} \ + {[llength $ret] != 0} \ + {set ret [$dbc get -nextdup] } { + set k [lindex [lindex $ret 0] 0] + if { [string compare $k $str] != 0 } { + break + } + set datastr [lindex [lindex $ret 0] 1] + if {[string length $datastr] == 0} { + break + } + if {[string compare \ + $lastdup [pad_data $method $datastr]] > 0} { + error_check_good \ + sorted_dups($lastdup,$datastr) 0 1 + } + incr x + set lastdup $datastr + } + error_check_good "Test0$tnum:ndups:$str" $x $ndups + incr count + } + error_check_good cursor_close [$dbc close] 0 + close $did + + # Now we will get each key from the DB and compare the results + # to the original. + puts "\tTest0$tnum.b: Checking file for correct duplicates" + set dbc [eval {$db cursor} $txn] + error_check_good cursor_open(2) [is_substr $dbc $db] 1 + + set lastkey "THIS WILL NEVER BE A KEY VALUE" + # no need to delete $lastkey + set firsttimethru 1 + for {set ret [$dbc get -first]} \ + {[llength $ret] != 0} \ + {set ret [$dbc get -next] } { + set k [lindex [lindex $ret 0] 0] + set d [lindex [lindex $ret 0] 1] + error_check_bad data_check:$d [string length $d] 0 + + if { [string compare $k $lastkey] != 0 } { + # Remove last key from the checkdb + if { $firsttimethru != 1 } { + error_check_good check_db:del:$lastkey \ + [eval {$check_db del} $txn {$lastkey}] 0 + } + set firsttimethru 0 + set lastdup "" + set lastkey $k + set dups [lindex [lindex [eval {$check_db get} \ + $txn {$k}] 0] 1] + error_check_good check_db:get:$k \ + [string length $dups] [expr $ndups * 4] + } + + if { [string compare $lastdup $d] > 0 } { + error_check_good dup_check:$k:$d 0 1 + } + set lastdup $d + + set pref [string range $d 0 3] + set ndx [string first $pref $dups] + error_check_good valid_duplicate [expr $ndx >= 0] 1 + set a [string range $dups 0 [expr $ndx - 1]] + set b [string range $dups [expr $ndx + 4] end] + set dups $a$b + } + # Remove last key from the checkdb + if { [string length $lastkey] != 0 } { + error_check_good check_db:del:$lastkey \ + [eval {$check_db del} $txn {$lastkey}] 0 + } + + # Make sure there is nothing left in check_db + + set check_c [eval {$check_db cursor} $txn] + set ret [$check_c get -first] + error_check_good check_c:get:$ret [llength $ret] 0 + error_check_good check_c:close [$check_c close] 0 + error_check_good check_db:close [$check_db close] 0 + + error_check_good dbc_close [$dbc close] 0 + error_check_good db_close [$db close] 0 +} diff --git a/db/test/test032.tcl b/db/test/test032.tcl new file mode 100644 index 000000000..1504ec5cc --- /dev/null +++ b/db/test/test032.tcl @@ -0,0 +1,195 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test032.tcl,v 11.15 2000/08/25 14:21:55 sue Exp $ +# +# DB Test 32 {access method} +# Use the first 10,000 entries from the dictionary. +# Insert each with self as key and "ndups" duplicates +# For the data field, prepend the letters of the alphabet +# in a random order so that we force the duplicate sorting +# code to do something. +# By setting ndups large, we can make this an off-page test +# After all are entered; test the DB_GET_BOTH functionality +# first by retrieving each dup in the file explicitly. Then +# test the failure case. +proc test032 { method {nentries 10000} {ndups 5} {tnum 32} args } { + global alphabet rand_init + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + + berkdb srand $rand_init + + # Create the database and open the dictionary + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test0$tnum.db + set checkdb $testdir/checkdb.db + set env NULL + } else { + set testfile test0$tnum.db + set checkdb checkdb.db + incr eindex + set env [lindex $args $eindex] + } + set t1 $testdir/t1 + set t2 $testdir/t2 + set t3 $testdir/t3 + cleanup $testdir $env + + puts "Test0$tnum:\ + $method ($args) $nentries small sorted dup key/data pairs" + if { [is_record_based $method] == 1 || \ + [is_rbtree $method] == 1 } { + puts "Test0$tnum skipping for method $omethod" + return + } + set db [eval {berkdb_open -create -truncate -mode 0644 \ + $omethod -dup -dupsort} $args {$testfile} ] + error_check_good dbopen [is_valid_db $db] TRUE + set did [open $dict] + + set check_db [eval {berkdb_open \ + -create -truncate -mode 0644} $args {-hash $checkdb}] + error_check_good dbopen:check_db [is_valid_db $check_db] TRUE + + set pflags "" + set gflags "" + set txn "" + set count 0 + + # Here is the loop where we put and get each key/data pair + puts "\tTest0$tnum.a: Put/get loop" + set dbc [eval {$db cursor} $txn] + error_check_good cursor_open [is_substr $dbc $db] 1 + while { [gets $did str] != -1 && $count < $nentries } { + # Re-initialize random string generator + randstring_init $ndups + + set dups "" + for { set i 1 } { $i <= $ndups } { incr i } { + set pref [randstring] + set dups $dups$pref + set datastr $pref:$str + set ret [eval {$db put} \ + $txn $pflags {$str [chop_data $method $datastr]}] + error_check_good put $ret 0 + } + set ret [eval {$check_db put} \ + $txn $pflags {$str [chop_data $method $dups]}] + error_check_good checkdb_put $ret 0 + + # Now retrieve all the keys matching this key + set x 0 + set lastdup "" + for {set ret [$dbc get -set $str]} \ + {[llength $ret] != 0} \ + {set ret [$dbc get -nextdup] } { + set k [lindex [lindex $ret 0] 0] + if { [string compare $k $str] != 0 } { + break + } + set datastr [lindex [lindex $ret 0] 1] + if {[string length $datastr] == 0} { + break + } + if {[string compare $lastdup $datastr] > 0} { + error_check_good sorted_dups($lastdup,$datastr)\ + 0 1 + } + incr x + set lastdup $datastr + } + + error_check_good "Test0$tnum:ndups:$str" $x $ndups + incr count + } + error_check_good cursor_close [$dbc close] 0 + close $did + + # Now we will get each key from the DB and compare the results + # to the original. + puts "\tTest0$tnum.b: Checking file for correct duplicates (no cursor)" + set check_c [eval {$check_db cursor} $txn] + error_check_good check_c_open(2) \ + [is_substr $check_c $check_db] 1 + + for {set ndx 0} {$ndx < [expr 4 * $ndups]} {incr ndx 4} { + for {set ret [$check_c get -first]} \ + {[llength $ret] != 0} \ + {set ret [$check_c get -next] } { + set k [lindex [lindex $ret 0] 0] + set d [lindex [lindex $ret 0] 1] + error_check_bad data_check:$d [string length $d] 0 + + set pref [string range $d $ndx [expr $ndx + 3]] + set data $pref:$k + set ret [eval {$db get} $txn {-get_both $k $data}] + error_check_good \ + get_both_data:$k $ret [list [list $k $data]] + } + } + + $db sync + # Now repeat the above test using cursor ops + puts "\tTest0$tnum.c: Checking file for correct duplicates (cursor)" + set dbc [eval {$db cursor} $txn] + error_check_good cursor_open [is_substr $dbc $db] 1 + + for {set ndx 0} {$ndx < [expr 4 * $ndups]} {incr ndx 4} { + for {set ret [$check_c get -first]} \ + {[llength $ret] != 0} \ + {set ret [$check_c get -next] } { + set k [lindex [lindex $ret 0] 0] + set d [lindex [lindex $ret 0] 1] + error_check_bad data_check:$d [string length $d] 0 + + set pref [string range $d $ndx [expr $ndx + 3]] + set data $pref:$k + set ret [eval {$dbc get} {-get_both $k $data}] + error_check_good \ + get_both_key:$k $ret [list [list $k $data]] + } + } + + # Now check the error case + puts "\tTest0$tnum.d: Check error case (no cursor)" + for {set ret [$check_c get -first]} \ + {[llength $ret] != 0} \ + {set ret [$check_c get -next] } { + set k [lindex [lindex $ret 0] 0] + set d [lindex [lindex $ret 0] 1] + error_check_bad data_check:$d [string length $d] 0 + + set data XXX$k + set ret [eval {$db get} $txn {-get_both $k $data}] + error_check_good error_case:$k [llength $ret] 0 + } + + # Now check the error case + puts "\tTest0$tnum.e: Check error case (cursor)" + for {set ret [$check_c get -first]} \ + {[llength $ret] != 0} \ + {set ret [$check_c get -next] } { + set k [lindex [lindex $ret 0] 0] + set d [lindex [lindex $ret 0] 1] + error_check_bad data_check:$d [string length $d] 0 + + set data XXX$k + set ret [eval {$dbc get} {-get_both $k $data}] + error_check_good error_case:$k [llength $ret] 0 + } + + error_check_good check_c:close [$check_c close] 0 + error_check_good check_db:close [$check_db close] 0 + + error_check_good dbc_close [$dbc close] 0 + error_check_good db_close [$db close] 0 +} diff --git a/db/test/test033.tcl b/db/test/test033.tcl new file mode 100644 index 000000000..ed46e6bda --- /dev/null +++ b/db/test/test033.tcl @@ -0,0 +1,103 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test033.tcl,v 11.11 2000/10/25 15:45:20 sue Exp $ +# +# DB Test 33 {access method} +# Use the first 10,000 entries from the dictionary. +# Insert each with self as key and data; add duplicate +# records for each. +# After all are entered, retrieve all; verify output by doing +# DB_GET_BOTH on existing and non-existing keys. +# This does not work for recno +proc test033 { method {nentries 10000} {ndups 5} {tnum 33} args } { + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + + puts "Test0$tnum: $method ($args) $nentries small dup key/data pairs" + if { [is_record_based $method] == 1 || \ + [is_rbtree $method] == 1 } { + puts "Test0$tnum skipping for method $omethod" + return + } + + # Create the database and open the dictionary + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test0$tnum.db + set env NULL + } else { + set testfile test0$tnum.db + incr eindex + set env [lindex $args $eindex] + } + set t1 $testdir/t1 + set t2 $testdir/t2 + set t3 $testdir/t3 + cleanup $testdir $env + + set db [eval {berkdb_open -create -truncate -mode 0644 \ + $omethod -dup} $args {$testfile}] + error_check_good dbopen [is_valid_db $db] TRUE + set did [open $dict] + + set pflags "" + set gflags "" + set txn "" + set count 0 + + puts "\tTest0$tnum.a: Put/get loop." + # Here is the loop where we put and get each key/data pair + while { [gets $did str] != -1 && $count < $nentries } { + for { set i 1 } { $i <= $ndups } { incr i } { + set datastr $i:$str + set ret [eval {$db put} \ + $txn $pflags {$str [chop_data $method $datastr]}] + error_check_good db_put $ret 0 + } + + # Now retrieve all the keys matching this key and dup + for {set i 1} {$i <= $ndups } { incr i } { + set datastr $i:$str + set ret [eval {$db get} $txn {-get_both $str $datastr}] + error_check_good "Test0$tnum:dup#" [lindex \ + [lindex $ret 0] 1] [pad_data $method $datastr] + } + + # Now retrieve non-existent dup (i is ndups + 1) + set datastr $i:$str + set ret [eval {$db get} $txn {-get_both $str $datastr}] + error_check_good Test0$tnum:dupfailure [llength $ret] 0 + incr count + } + close $did + + set did [open $dict] + set count 0 + puts "\tTest0$tnum.b: Verifying DB_GET_BOTH after creation." + while { [gets $did str] != -1 && $count < $nentries } { + # Now retrieve all the keys matching this key and dup + for {set i 1} {$i <= $ndups } { incr i } { + set datastr $i:$str + set ret [eval {$db get} $txn {-get_both $str $datastr}] + error_check_good "Test0$tnum:dup#" \ + [lindex [lindex $ret 0] 1] $datastr + } + + # Now retrieve non-existent dup (i is ndups + 1) + set datastr $i:$str + set ret [eval {$db get} $txn {-get_both $str $datastr}] + error_check_good Test0$tnum:dupfailure [llength $ret] 0 + incr count + } + close $did + + error_check_good db_close [$db close] 0 +} diff --git a/db/test/test034.tcl b/db/test/test034.tcl new file mode 100644 index 000000000..b82f369f7 --- /dev/null +++ b/db/test/test034.tcl @@ -0,0 +1,16 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test034.tcl,v 11.4 2000/02/14 03:00:19 bostic Exp $ +# +# DB Test 34 {access method} +# DB_GET_BOTH functionality with off-page duplicates. +proc test034 { method {nentries 10000} args} { + # Test with off-page duplicates + eval {test032 $method $nentries 20 34 -pagesize 512} $args + + # Test with multiple pages of off-page duplicates + eval {test032 $method [expr $nentries / 10] 100 34 -pagesize 512} $args +} diff --git a/db/test/test035.tcl b/db/test/test035.tcl new file mode 100644 index 000000000..e2afef4af --- /dev/null +++ b/db/test/test035.tcl @@ -0,0 +1,16 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test035.tcl,v 11.3 2000/02/14 03:00:19 bostic Exp $ +# +# DB Test 35 {access method} +# DB_GET_BOTH functionality with off-page duplicates. +proc test035 { method {nentries 10000} args} { + # Test with off-page duplicates + eval {test033 $method $nentries 20 35 -pagesize 512} $args + + # Test with multiple pages of off-page duplicates + eval {test033 $method [expr $nentries / 10] 100 35 -pagesize 512} $args +} diff --git a/db/test/test036.tcl b/db/test/test036.tcl new file mode 100644 index 000000000..4d859c065 --- /dev/null +++ b/db/test/test036.tcl @@ -0,0 +1,135 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test036.tcl,v 11.13 2000/08/25 14:21:55 sue Exp $ +# +# DB Test 36 {access method} +# Put nentries key/data pairs (from the dictionary) using a cursor +# and KEYFIRST and KEYLAST (this tests the case where use use cursor +# put for non-existent keys). +proc test036 { method {nentries 10000} args } { + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + + puts "Test036: $method ($args) $nentries equal key/data pairs" + if { [is_record_based $method] == 1 } { + puts "Test036 skipping for method recno" + return + } + + # Create the database and open the dictionary + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test036.db + set env NULL + } else { + set testfile test036.db + incr eindex + set env [lindex $args $eindex] + } + set t1 $testdir/t1 + set t2 $testdir/t2 + set t3 $testdir/t3 + cleanup $testdir $env + set db [eval {berkdb_open \ + -create -truncate -mode 0644} $args {$omethod $testfile}] + error_check_good dbopen [is_valid_db $db] TRUE + set did [open $dict] + + set pflags "" + set gflags "" + set txn "" + set count 0 + + if { [is_record_based $method] == 1 } { + set checkfunc test036_recno.check + append gflags " -recno" + } else { + set checkfunc test036.check + } + puts "\tTest036.a: put/get loop KEYFIRST" + # Here is the loop where we put and get each key/data pair + set dbc [eval {$db cursor} $txn] + error_check_good cursor [is_substr $dbc $db] 1 + while { [gets $did str] != -1 && $count < $nentries } { + if { [is_record_based $method] == 1 } { + global kvals + + set key [expr $count + 1] + set kvals($key) $str + } else { + set key $str + } + set ret [eval {$dbc put} $txn $pflags {-keyfirst $key $str}] + error_check_good put $ret 0 + + set ret [eval {$db get} $txn $gflags {$key}] + error_check_good get [lindex [lindex $ret 0] 1] $str + incr count + } + error_check_good dbc_close [$dbc close] 0 + + puts "\tTest036.a: put/get loop KEYLAST" + set dbc [eval {$db cursor} $txn] + error_check_good cursor [is_substr $dbc $db] 1 + while { [gets $did str] != -1 && $count < $nentries } { + if { [is_record_based $method] == 1 } { + global kvals + + set key [expr $count + 1] + set kvals($key) $str + } else { + set key $str + } + set ret [eval {$dbc put} $txn $pflags {-keylast $key $str}] + error_check_good put $ret 0 + + set ret [eval {$db get} $txn $gflags {$key}] + error_check_good get [lindex [lindex $ret 0] 1] $str + incr count + } + error_check_good dbc_close [$dbc close] 0 + close $did + + # Now we will get each key from the DB and compare the results + # to the original. + puts "\tTest036.c: dump file" + dump_file $db $txn $t1 $checkfunc + error_check_good db_close [$db close] 0 + + # Now compare the keys to see if they match the dictionary (or ints) + if { [is_record_based $method] == 1 } { + set oid [open $t2 w] + for {set i 1} {$i <= $nentries} {set i [incr i]} { + puts $oid $i + } + close $oid + file rename -force $t1 $t3 + } else { + set q q + filehead $nentries $dict $t3 + filesort $t3 $t2 + filesort $t1 $t3 + } + +} + +# Check function for test036; keys and data are identical +proc test036.check { key data } { + error_check_good "key/data mismatch" $data $key +} + +proc test036_recno.check { key data } { + global dict + global kvals + + error_check_good key"$key"_exists [info exists kvals($key)] 1 + error_check_good "key/data mismatch, key $key" $data $kvals($key) +} diff --git a/db/test/test037.tcl b/db/test/test037.tcl new file mode 100644 index 000000000..31528c6ee --- /dev/null +++ b/db/test/test037.tcl @@ -0,0 +1,191 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test037.tcl,v 11.11 2000/08/25 14:21:55 sue Exp $ +# +# Test037: RMW functionality. +proc test037 { method {nentries 100} args } { + source ./include.tcl + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then skip this test. It needs its own. + if { $eindex != -1 } { + incr eindex + set env [lindex $args $eindex] + puts "Test037 skipping for env $env" + return + } + + puts "Test037: RMW $method" + + set args [convert_args $method $args] + set omethod [convert_method $method] + + # Create the database + env_cleanup $testdir + set testfile test037.db + + set local_env \ + [berkdb env -create -mode 0644 -txn -home $testdir] + error_check_good dbenv [is_valid_env $local_env] TRUE + + set db [eval {berkdb_open \ + -env $local_env -create -mode 0644 $omethod} $args {$testfile}] + error_check_good dbopen [is_valid_db $db] TRUE + + set did [open $dict] + set count 0 + + set pflags "" + set gflags "" + set txn "" + + if { [is_record_based $method] == 1 } { + append gflags " -recno" + } + + puts "\tTest037.a: Creating database" + # Here is the loop where we put and get each key/data pair + while { [gets $did str] != -1 && $count < $nentries } { + if { [is_record_based $method] == 1 } { + global kvals + + set key [expr $count + 1] + set kvals($key) [pad_data $method $str] + } else { + set key $str + } + set ret [eval {$db put} \ + $txn $pflags {$key [chop_data $method $str]}] + error_check_good put $ret 0 + + set ret [eval {$db get} $txn $gflags {$key}] + error_check_good get \ + [lindex [lindex $ret 0] 1] [pad_data $method $str] + incr count + } + close $did + error_check_good dbclose [$db close] 0 + error_check_good envclode [$local_env close] 0 + + puts "\tTest037.b: Setting up environments" + + # Open local environment + set env_cmd [concat berkdb env -create -txn -home $testdir] + set local_env [eval $env_cmd] + error_check_good dbenv [is_valid_widget $local_env env] TRUE + + # Open local transaction + set local_txn [$local_env txn] + error_check_good txn_open [is_valid_txn $local_txn $local_env] TRUE + + # Open remote environment + set f1 [open |$tclsh_path r+] + puts $f1 "source $test_path/test.tcl" + + set remote_env [send_cmd $f1 $env_cmd] + error_check_good remote:env_open [is_valid_env $remote_env] TRUE + + # Open remote transaction + set remote_txn [send_cmd $f1 "$remote_env txn"] + error_check_good \ + remote:txn_open [is_valid_txn $remote_txn $remote_env] TRUE + + # Now try put test without RMW. Gets on one site should not + # lock out gets on another. + + # Open databases and dictionary + puts "\tTest037.c: Opening databases" + set did [open $dict] + set rkey 0 + + set db [berkdb_open -env $local_env $testfile] + error_check_good dbopen [is_valid_db $db] TRUE + set rdb [send_cmd $f1 \ + "berkdb_open -env $remote_env -mode 0644 $testfile"] + error_check_good remote:dbopen [is_valid_widget $rdb db] TRUE + + puts "\tTest037.d: Testing without RMW" + + # Now, get a key and try to "get" it from both DBs. + error_check_bad "gets on new open" [gets $did str] -1 + incr rkey + if { [is_record_based $method] == 1 } { + set key $rkey + } else { + set key $str + } + + set rec [eval {$db get -txn $local_txn} $gflags {$key}] + error_check_good local_get [lindex [lindex $rec 0] 1] \ + [pad_data $method $str] + + set r [send_timed_cmd $f1 0 "$rdb get -txn $remote_txn $gflags $key"] + error_check_good remote_send $r 0 + + # Now sleep before releasing local record lock + tclsleep 5 + error_check_good local_commit [$local_txn commit] 0 + + # Now get the remote result + set remote_time [rcv_result $f1] + error_check_good no_rmw_get:remote_time [expr $remote_time <= 1] 1 + + # Commit the remote + set r [send_cmd $f1 "$remote_txn commit"] + error_check_good remote_commit $r 0 + + puts "\tTest037.e: Testing with RMW" + + # Open local transaction + set local_txn [$local_env txn] + error_check_good \ + txn_open [is_valid_widget $local_txn $local_env.txn] TRUE + + # Open remote transaction + set remote_txn [send_cmd $f1 "$remote_env txn"] + error_check_good remote:txn_open \ + [is_valid_widget $remote_txn $remote_env.txn] TRUE + + # Now, get a key and try to "get" it from both DBs. + error_check_bad "gets on new open" [gets $did str] -1 + incr rkey + if { [is_record_based $method] == 1 } { + set key $rkey + } else { + set key $str + } + + set rec [eval {$db get -txn $local_txn -rmw} $gflags {$key}] + error_check_good \ + local_get [lindex [lindex $rec 0] 1] [pad_data $method $str] + + set r [send_timed_cmd $f1 0 "$rdb get -txn $remote_txn $gflags $key"] + error_check_good remote_send $r 0 + + # Now sleep before releasing local record lock + tclsleep 5 + error_check_good local_commit [$local_txn commit] 0 + + # Now get the remote result + set remote_time [rcv_result $f1] + error_check_good rmw_get:remote_time [expr $remote_time > 4] 1 + + # Commit the remote + set r [send_cmd $f1 "$remote_txn commit"] + error_check_good remote_commit $r 0 + + # Close everything up: remote first + set r [send_cmd $f1 "$rdb close"] + error_check_good remote_db_close $r 0 + + set r [send_cmd $f1 "$remote_env close"] + + # Close locally + error_check_good db_close [$db close] 0 + $local_env close + close $did + close $f1 +} diff --git a/db/test/test038.tcl b/db/test/test038.tcl new file mode 100644 index 000000000..2a726f1bc --- /dev/null +++ b/db/test/test038.tcl @@ -0,0 +1,174 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test038.tcl,v 11.12 2000/08/25 14:21:56 sue Exp $ +# +# DB Test 38 {access method} +# Use the first 10,000 entries from the dictionary. +# Insert each with self as key and "ndups" duplicates +# For the data field, prepend the letters of the alphabet +# in a random order so that we force the duplicate sorting +# code to do something. +# By setting ndups large, we can make this an off-page test +# After all are entered; test the DB_GET_BOTH functionality +# first by retrieving each dup in the file explicitly. Then +# remove each duplicate and try DB_GET_BOTH again. +proc test038 { method {nentries 10000} {ndups 5} {tnum 38} args } { + global alphabet + global rand_init + source ./include.tcl + + berkdb srand $rand_init + + set args [convert_args $method $args] + set omethod [convert_method $method] + + # Create the database and open the dictionary + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test0$tnum.db + set checkdb $testdir/checkdb.db + set env NULL + } else { + set testfile test0$tnum.db + set checkdb checkdb.db + incr eindex + set env [lindex $args $eindex] + } + set t1 $testdir/t1 + set t2 $testdir/t2 + set t3 $testdir/t3 + cleanup $testdir $env + + puts "Test0$tnum: \ + $method ($args) $nentries small sorted dup key/data pairs" + if { [is_record_based $method] == 1 || \ + [is_rbtree $method] == 1 } { + puts "Test0$tnum skipping for method $method" + return + } + set db [eval {berkdb_open -create -truncate -mode 0644 \ + $omethod -dup -dupsort} $args {$testfile}] + error_check_good dbopen [is_valid_db $db] TRUE + set did [open $dict] + + set check_db [berkdb_open \ + -create -truncate -mode 0644 -hash $checkdb] + error_check_good dbopen:check_db [is_valid_db $check_db] TRUE + + set pflags "" + set gflags "" + set txn "" + set count 0 + + # Here is the loop where we put and get each key/data pair + puts "\tTest0$tnum.a: Put/get loop" + set dbc [eval {$db cursor} $txn] + error_check_good cursor_open [is_substr $dbc $db] 1 + while { [gets $did str] != -1 && $count < $nentries } { + set dups "" + for { set i 1 } { $i <= $ndups } { incr i } { + set pref \ + [string index $alphabet [berkdb random_int 0 25]] + set pref $pref[string \ + index $alphabet [berkdb random_int 0 25]] + while { [string first $pref $dups] != -1 } { + set pref [string toupper $pref] + if { [string first $pref $dups] != -1 } { + set pref [string index $alphabet \ + [berkdb random_int 0 25]] + set pref $pref[string index $alphabet \ + [berkdb random_int 0 25]] + } + } + if { [string length $dups] == 0 } { + set dups $pref + } else { + set dups "$dups $pref" + } + set datastr $pref:$str + set ret [eval {$db put} \ + $txn $pflags {$str [chop_data $method $datastr]}] + error_check_good put $ret 0 + } + set ret [eval {$check_db put} \ + $txn $pflags {$str [chop_data $method $dups]}] + error_check_good checkdb_put $ret 0 + + # Now retrieve all the keys matching this key + set x 0 + set lastdup "" + for {set ret [$dbc get -set $str]} \ + {[llength $ret] != 0} \ + {set ret [$dbc get -nextdup] } { + set k [lindex [lindex $ret 0] 0] + if { [string compare $k $str] != 0 } { + break + } + set datastr [lindex [lindex $ret 0] 1] + if {[string length $datastr] == 0} { + break + } + if {[string compare $lastdup $datastr] > 0} { + error_check_good sorted_dups($lastdup,$datastr)\ + 0 1 + } + incr x + set lastdup $datastr + } + error_check_good "Test0$tnum:ndups:$str" $x $ndups + incr count + } + error_check_good cursor_close [$dbc close] 0 + close $did + + # Now check the duplicates, then delete then recheck + puts "\tTest0$tnum.b: Checking and Deleting duplicates" + set dbc [eval {$db cursor} $txn] + error_check_good cursor_open [is_substr $dbc $db] 1 + set check_c [eval {$check_db cursor} $txn] + error_check_good cursor_open [is_substr $check_c $check_db] 1 + + for {set ndx 0} {$ndx < $ndups} {incr ndx} { + for {set ret [$check_c get -first]} \ + {[llength $ret] != 0} \ + {set ret [$check_c get -next] } { + set k [lindex [lindex $ret 0] 0] + set d [lindex [lindex $ret 0] 1] + error_check_bad data_check:$d [string length $d] 0 + + set nn [expr $ndx * 3] + set pref [string range $d $nn [expr $nn + 1]] + set data $pref:$k + set ret [eval {$dbc get} $txn {-get_both $k $data}] + error_check_good \ + get_both_key:$k [lindex [lindex $ret 0] 0] $k + error_check_good \ + get_both_data:$k [lindex [lindex $ret 0] 1] $data + set ret [$dbc del] + error_check_good del $ret 0 + set ret [eval {$db get} $txn {-get_both $k $data}] + error_check_good error_case:$k [llength $ret] 0 + + if {$ndx != 0} { + set n [expr ($ndx - 1) * 3] + set pref [string range $d $n [expr $n + 1]] + set data $pref:$k + set ret \ + [eval {$db get} $txn {-get_both $k $data}] + error_check_good error_case:$k [llength $ret] 0 + } + } + } + + error_check_good check_c:close [$check_c close] 0 + error_check_good check_db:close [$check_db close] 0 + + error_check_good dbc_close [$dbc close] 0 + error_check_good db_close [$db close] 0 +} diff --git a/db/test/test039.tcl b/db/test/test039.tcl new file mode 100644 index 000000000..957468ce5 --- /dev/null +++ b/db/test/test039.tcl @@ -0,0 +1,177 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test039.tcl,v 11.11 2000/08/25 14:21:56 sue Exp $ +# +# DB Test 39 {access method} +# Use the first 10,000 entries from the dictionary. +# Insert each with self as key and "ndups" duplicates +# For the data field, prepend the letters of the alphabet +# in a random order so that we force the duplicate sorting +# code to do something. +# By setting ndups large, we can make this an off-page test +# After all are entered; test the DB_GET_BOTH functionality +# first by retrieving each dup in the file explicitly. Then +# remove each duplicate and try DB_GET_BOTH again. +proc test039 { method {nentries 10000} {ndups 5} {tnum 39} args } { + global alphabet + global rand_init + source ./include.tcl + + berkdb srand $rand_init + + set args [convert_args $method $args] + set omethod [convert_method $method] + + # Create the database and open the dictionary + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test0$tnum.db + set checkdb $testdir/checkdb.db + set env NULL + } else { + set testfile test0$tnum.db + set checkdb checkdb.db + incr eindex + set env [lindex $args $eindex] + } + set t1 $testdir/t1 + set t2 $testdir/t2 + set t3 $testdir/t3 + cleanup $testdir $env + + puts "Test0$tnum: $method $nentries small unsorted dup key/data pairs" + if { [is_record_based $method] == 1 || \ + [is_rbtree $method] == 1 } { + puts "Test0$tnum skipping for method $method" + return + } + + set db [eval {berkdb_open -create -truncate -mode 0644 \ + $omethod -dup} $args {$testfile}] + error_check_good dbopen [is_valid_db $db] TRUE + set did [open $dict] + + set check_db \ + [berkdb_open -create -truncate -mode 0644 -hash $checkdb] + error_check_good dbopen:check_db [is_valid_db $check_db] TRUE + + set pflags "" + set gflags "" + set txn "" + set count 0 + + # Here is the loop where we put and get each key/data pair + puts "\tTest0$tnum.a: Put/get loop" + set dbc [eval {$db cursor} $txn] + error_check_good cursor_open [is_substr $dbc $db] 1 + while { [gets $did str] != -1 && $count < $nentries } { + set dups "" + for { set i 1 } { $i <= $ndups } { incr i } { + set pref \ + [string index $alphabet [berkdb random_int 0 25]] + set pref $pref[string \ + index $alphabet [berkdb random_int 0 25]] + while { [string first $pref $dups] != -1 } { + set pref [string toupper $pref] + if { [string first $pref $dups] != -1 } { + set pref [string index $alphabet \ + [berkdb random_int 0 25]] + set pref $pref[string index $alphabet \ + [berkdb random_int 0 25]] + } + } + if { [string length $dups] == 0 } { + set dups $pref + } else { + set dups "$dups $pref" + } + set datastr $pref:$str + set ret [eval {$db put} \ + $txn $pflags {$str [chop_data $method $datastr]}] + error_check_good put $ret 0 + } + set ret [eval {$check_db put} \ + $txn $pflags {$str [chop_data $method $dups]}] + error_check_good checkdb_put $ret 0 + + # Now retrieve all the keys matching this key + set x 0 + set lastdup "" + for {set ret [$dbc get -set $str]} \ + {[llength $ret] != 0} \ + {set ret [$dbc get -nextdup] } { + set k [lindex [lindex $ret 0] 0] + if { [string compare $k $str] != 0 } { + break + } + set datastr [lindex [lindex $ret 0] 1] + if {[string length $datastr] == 0} { + break + } + set xx [expr $x * 3] + set check_data \ + [string range $dups $xx [expr $xx + 1]]:$k + error_check_good retrieve $datastr $check_data + incr x + } + error_check_good "Test0$tnum:ndups:$str" $x $ndups + incr count + } + error_check_good cursor_close [$dbc close] 0 + close $did + + # Now check the duplicates, then delete then recheck + puts "\tTest0$tnum.b: Checking and Deleting duplicates" + set dbc [eval {$db cursor} $txn] + error_check_good cursor_open [is_substr $dbc $db] 1 + set check_c [eval {$check_db cursor} $txn] + error_check_good cursor_open [is_substr $check_c $check_db] 1 + + for {set ndx 0} {$ndx < $ndups} {incr ndx} { + for {set ret [$check_c get -first]} \ + {[llength $ret] != 0} \ + {set ret [$check_c get -next] } { + set k [lindex [lindex $ret 0] 0] + set d [lindex [lindex $ret 0] 1] + error_check_bad data_check:$d [string length $d] 0 + + set nn [expr $ndx * 3] + set pref [string range $d $nn [expr $nn + 1]] + set data $pref:$k + set ret \ + [eval {$dbc get} $txn $gflags {-get_both $k $data}] + error_check_good \ + get_both_key:$k [lindex [lindex $ret 0] 0] $k + error_check_good \ + get_both_data:$k [lindex [lindex $ret 0] 1] $data + + set ret [$dbc del] + error_check_good del $ret 0 + + set ret \ + [eval {$dbc get} $txn $gflags {-get_both $k $data}] + error_check_good error_case:$k [llength $ret] 0 + + if {$ndx != 0} { + set n [expr ($ndx - 1) * 3] + set pref [string range $d $n [expr $n + 1]] + set data $pref:$k + set ret [eval {$dbc get} \ + $txn $gflags {-get_both $k $data}] + error_check_good error_case:$k [llength $ret] 0 + } + } + } + + error_check_good check_c:close [$check_c close] 0 + error_check_good check_db:close [$check_db close] 0 + + error_check_good dbc_close [$dbc close] 0 + error_check_good db_close [$db close] 0 +} diff --git a/db/test/test040.tcl b/db/test/test040.tcl new file mode 100644 index 000000000..912e1735d --- /dev/null +++ b/db/test/test040.tcl @@ -0,0 +1,16 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test040.tcl,v 11.3 2000/02/14 03:00:20 bostic Exp $ +# +# DB Test 40 {access method} +# DB_GET_BOTH functionality with off-page duplicates. +proc test040 { method {nentries 10000} args} { + # Test with off-page duplicates + eval {test038 $method $nentries 20 40 -pagesize 512} $args + + # Test with multiple pages of off-page duplicates + eval {test038 $method [expr $nentries / 10] 100 40 -pagesize 512} $args +} diff --git a/db/test/test041.tcl b/db/test/test041.tcl new file mode 100644 index 000000000..bba89f49b --- /dev/null +++ b/db/test/test041.tcl @@ -0,0 +1,16 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test041.tcl,v 11.3 2000/02/14 03:00:20 bostic Exp $ +# +# DB Test 41 {access method} +# DB_GET_BOTH functionality with off-page duplicates. +proc test041 { method {nentries 10000} args} { + # Test with off-page duplicates + eval {test039 $method $nentries 20 41 -pagesize 512} $args + + # Test with multiple pages of off-page duplicates + eval {test039 $method [expr $nentries / 10] 100 41 -pagesize 512} $args +} diff --git a/db/test/test042.tcl b/db/test/test042.tcl new file mode 100644 index 000000000..232cb3a6b --- /dev/null +++ b/db/test/test042.tcl @@ -0,0 +1,149 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test042.tcl,v 11.24 2000/08/25 14:21:56 sue Exp $ +# +# DB Test 42 {access method} +# +# Multiprocess DB test; verify that locking is working for the concurrent +# access method product. +# +# Use the first "nentries" words from the dictionary. Insert each with self +# as key and a fixed, medium length data string. Then fire off multiple +# processes that bang on the database. Each one should try to read and write +# random keys. When they rewrite, they'll append their pid to the data string +# (sometimes doing a rewrite sometimes doing a partial put). Some will use +# cursors to traverse through a few keys before finding one to write. + +set datastr abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz + +proc test042 { method {nentries 1000} args } { + global datastr + source ./include.tcl + + # + # If we are using an env, then skip this test. It needs its own. + set eindex [lsearch -exact $args "-env"] + if { $eindex != -1 } { + incr eindex + set env [lindex $args $eindex] + puts "Test042 skipping for env $env" + return + } + set args [convert_args $method $args] + set omethod [convert_method $method] + + puts "Test042: CDB Test $method $nentries" + + # Set initial parameters + set do_exit 0 + set iter 10000 + set procs 5 + + # Process arguments + set oargs "" + for { set i 0 } { $i < [llength $args] } {incr i} { + switch -regexp -- [lindex $args $i] { + -dir { incr i; set testdir [lindex $args $i] } + -iter { incr i; set iter [lindex $args $i] } + -procs { incr i; set procs [lindex $args $i] } + -exit { set do_exit 1 } + default { append oargs " " [lindex $args $i] } + } + } + + # Create the database and open the dictionary + set testfile test042.db + set t1 $testdir/t1 + set t2 $testdir/t2 + set t3 $testdir/t3 + + env_cleanup $testdir + + set env [berkdb env -create -cdb -home $testdir] + error_check_good dbenv [is_valid_widget $env env] TRUE + + set db [eval {berkdb_open -env $env -create -truncate \ + -mode 0644 $omethod} $oargs {$testfile}] + error_check_good dbopen [is_valid_widget $db db] TRUE + + set did [open $dict] + + set pflags "" + set gflags "" + set txn "" + set count 0 + + # Here is the loop where we put each key/data pair + puts "\tTest042.a: put/get loop" + while { [gets $did str] != -1 && $count < $nentries } { + if { [is_record_based $method] == 1 } { + set key [expr $count + 1] + } else { + set key $str + } + set ret [eval {$db put} \ + $txn $pflags {$key [chop_data $method $datastr]}] + error_check_good put:$db $ret 0 + incr count + } + close $did + error_check_good close:$db [$db close] 0 + + # Database is created, now set up environment + + # Remove old mpools and Open/create the lock and mpool regions + error_check_good env:close:$env [$env close] 0 + set ret [berkdb envremove -home $testdir] + error_check_good env_remove $ret 0 + + set env [berkdb env -create -cdb -home $testdir] + error_check_good dbenv [is_valid_widget $env env] TRUE + + if { $do_exit == 1 } { + return + } + + # Now spawn off processes + berkdb debug_check + puts "\tTest042.b: forking off $procs children" + set pidlist {} + + for { set i 0 } {$i < $procs} {incr i} { + puts "exec $tclsh_path $test_path/wrap.tcl \ + mdbscript.tcl $testdir/test042.$i.log \ + $method $testdir $testfile $nentries $iter $i $procs &" + set p [exec $tclsh_path $test_path/wrap.tcl \ + mdbscript.tcl $testdir/test042.$i.log $method \ + $testdir $testfile $nentries $iter $i $procs &] + lappend pidlist $p + } + puts "Test042: $procs independent processes now running" + watch_procs + + # Check for test failure + set e [eval findfail [glob $testdir/test042.*.log]] + error_check_good "FAIL: error message(s) in log files" $e 0 + + # Test is done, blow away lock and mpool region + reset_env $env +} + +# If we are renumbering, then each time we delete an item, the number of +# items in the file is temporarily decreased, so the highest record numbers +# do not exist. To make sure this doesn't happen, we never generate the +# highest few record numbers as keys. +# +# For record-based methods, record numbers begin at 1, while for other keys, +# we begin at 0 to index into an array. +proc rand_key { method nkeys renum procs} { + if { $renum == 1 } { + return [berkdb random_int 1 [expr $nkeys - $procs]] + } elseif { [is_record_based $method] == 1 } { + return [berkdb random_int 1 $nkeys] + } else { + return [berkdb random_int 0 [expr $nkeys - 1]] + } +} diff --git a/db/test/test043.tcl b/db/test/test043.tcl new file mode 100644 index 000000000..274ec1b71 --- /dev/null +++ b/db/test/test043.tcl @@ -0,0 +1,162 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test043.tcl,v 11.12 2000/08/25 14:21:56 sue Exp $ +# +# DB Test 43 {method nentries} +# Test the Record number implicit creation and renumbering options. +proc test043 { method {nentries 10000} args} { + source ./include.tcl + + set do_renumber [is_rrecno $method] + set args [convert_args $method $args] + set omethod [convert_method $method] + + puts "Test043: $method ($args)" + + if { [is_record_based $method] != 1 } { + puts "Test043 skipping for method $method" + return + } + + # Create the database and open the dictionary + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test043.db + set env NULL + } else { + set testfile test043.db + incr eindex + set env [lindex $args $eindex] + } + cleanup $testdir $env + + # Create the database + set db [eval {berkdb_open -create -truncate -mode 0644} $args \ + {$omethod $testfile}] + error_check_good dbopen [is_valid_db $db] TRUE + + set pflags "" + set gflags " -recno" + set txn "" + + # First test implicit creation and retrieval + set count 1 + set interval 5 + if { $nentries < $interval } { + set nentries [expr $interval + 1] + } + puts "\tTest043.a: insert keys at $interval record intervals" + while { $count <= $nentries } { + set ret [eval {$db put} \ + $txn $pflags {$count [chop_data $method $count]}] + error_check_good "$db put $count" $ret 0 + set last $count + incr count $interval + } + + puts "\tTest043.b: get keys using DB_FIRST/DB_NEXT" + set dbc [eval {$db cursor} $txn] + error_check_good "$db cursor" [is_substr $dbc $db] 1 + + set check 1 + for { set rec [$dbc get -first] } { [llength $rec] != 0 } { + set rec [$dbc get -next] } { + set k [lindex [lindex $rec 0] 0] + set d [pad_data $method [lindex [lindex $rec 0] 1]] + error_check_good "$dbc get key==data" [pad_data $method $k] $d + error_check_good "$dbc get sequential" $k $check + if { $k > $nentries } { + error_check_good "$dbc get key too large" $k $nentries + } + incr check $interval + } + + # Now make sure that we get DB_KEYEMPTY for non-existent keys + puts "\tTest043.c: Retrieve non-existent keys" + global errorInfo + + set check 1 + for { set rec [$dbc get -first] } { [llength $rec] != 0 } { + set rec [$dbc get -next] } { + set k [lindex [lindex $rec 0] 0] + + set ret [eval {$db get} $txn $gflags {[expr $k + 1]}] + error_check_good "$db \ + get [expr $k + 1]" $ret [list] + + incr check $interval + # Make sure we don't do a retrieve past the end of file + if { $check >= $last } { + break + } + } + + # Now try deleting and make sure the right thing happens. + puts "\tTest043.d: Delete tests" + set rec [$dbc get -first] + error_check_bad "$dbc get -first" [llength $rec] 0 + error_check_good "$dbc get -first key" [lindex [lindex $rec 0] 0] 1 + error_check_good "$dbc get -first data" \ + [lindex [lindex $rec 0] 1] [pad_data $method 1] + + # Delete the first item + error_check_good "$dbc del" [$dbc del] 0 + + # Retrieving 1 should always fail + set ret [eval {$db get} $txn $gflags {1}] + error_check_good "$db get 1" $ret [list] + + # Now, retrieving other keys should work; keys will vary depending + # upon renumbering. + if { $do_renumber == 1 } { + set count [expr 0 + $interval] + set max [expr $nentries - 1] + } else { + set count [expr 1 + $interval] + set max $nentries + } + + while { $count <= $max } { + set rec [eval {$db get} $txn $gflags {$count}] + if { $do_renumber == 1 } { + set data [expr $count + 1] + } else { + set data $count + } + error_check_good "$db get $count" \ + [pad_data $method $data] [lindex [lindex $rec 0] 1] + incr count $interval + } + set max [expr $count - $interval] + + puts "\tTest043.e: Verify LAST/PREV functionality" + set count $max + for { set rec [$dbc get -last] } { [llength $rec] != 0 } { + set rec [$dbc get -prev] } { + set k [lindex [lindex $rec 0] 0] + set d [lindex [lindex $rec 0] 1] + if { $do_renumber == 1 } { + set data [expr $k + 1] + } else { + set data $k + } + error_check_good \ + "$dbc get key==data" [pad_data $method $data] $d + error_check_good "$dbc get sequential" $k $count + if { $k > $nentries } { + error_check_good "$dbc get key too large" $k $nentries + } + set count [expr $count - $interval] + if { $count < 1 } { + break + } + } + error_check_good dbc_close [$dbc close] 0 + error_check_good db_close [$db close] 0 +} diff --git a/db/test/test044.tcl b/db/test/test044.tcl new file mode 100644 index 000000000..0be7a7049 --- /dev/null +++ b/db/test/test044.tcl @@ -0,0 +1,243 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test044.tcl,v 11.26 2000/10/27 13:23:56 sue Exp $ +# +# DB Test 44 {access method} +# System integration DB test: verify that locking, recovery, checkpoint, +# and all the other utilities basically work. +# +# The test consists of $nprocs processes operating on $nfiles files. A +# transaction consists of adding the same key/data pair to some random +# number of these files. We generate a bimodal distribution in key +# size with 70% of the keys being small (1-10 characters) and the +# remaining 30% of the keys being large (uniform distribution about +# mean $key_avg). If we generate a key, we first check to make sure +# that the key is not already in the dataset. If it is, we do a lookup. +# +# XXX This test uses grow-only files currently! +proc test044 { method {nprocs 5} {nfiles 10} {cont 0} args } { + source ./include.tcl + global rand_init + + set args [convert_args $method $args] + set omethod [convert_method $method] + + berkdb srand $rand_init + + # If we are using an env, then skip this test. It needs its own. + set eindex [lsearch -exact $args "-env"] + if { $eindex != -1 } { + incr eindex + set env [lindex $args $eindex] + puts "Test044 skipping for env $env" + return + } + + puts "Test044: system integration test db $method $nprocs processes \ + on $nfiles files" + + # Parse options + set otherargs "" + set key_avg 10 + set data_avg 20 + set do_exit 0 + for { set i 0 } { $i < [llength $args] } {incr i} { + switch -regexp -- [lindex $args $i] { + -key_avg { incr i; set key_avg [lindex $args $i] } + -data_avg { incr i; set data_avg [lindex $args $i] } + -testdir { incr i; set testdir [lindex $args $i] } + -x.* { set do_exit 1 } + default { + lappend otherargs [lindex $args $i] + } + } + } + + if { $cont == 0 } { + # Create the database and open the dictionary + env_cleanup $testdir + + # Create an environment + puts "\tTest044.a: creating environment and $nfiles files" + set dbenv [berkdb env -create -txn -home $testdir] + error_check_good env_open [is_valid_env $dbenv] TRUE + + # Create a bunch of files + set m $method + + for { set i 0 } { $i < $nfiles } { incr i } { + if { $method == "all" } { + switch [berkdb random_int 1 2] { + 1 { set m -btree } + 2 { set m -hash } + } + } else { + set m $omethod + } + + set db [eval {berkdb_open -env $dbenv -create \ + -mode 0644 $m} $otherargs {test044.$i.db}] + error_check_good dbopen [is_valid_db $db] TRUE + error_check_good db_close [$db close] 0 + } + } + + # Close the environment + $dbenv close + + if { $do_exit == 1 } { + return + } + + # Database is created, now fork off the kids. + puts "\tTest044.b: forking off $nprocs processes and utilities" + set cycle 1 + set ncycles 3 + while { $cycle <= $ncycles } { + set dbenv [berkdb env -create -txn -home $testdir] + error_check_good env_open [is_valid_env $dbenv] TRUE + + # Fire off deadlock detector and checkpointer + puts "Beginning cycle $cycle" + set ddpid [exec $util_path/db_deadlock -h $testdir -t 5 &] + set cppid [exec $util_path/db_checkpoint -h $testdir -p 2 &] + puts "Deadlock detector: $ddpid Checkpoint daemon $cppid" + + set pidlist {} + for { set i 0 } {$i < $nprocs} {incr i} { + set p [exec $tclsh_path \ + $test_path/sysscript.tcl $testdir \ + $nfiles $key_avg $data_avg $omethod \ + >& $testdir/test044.$i.log &] + lappend pidlist $p + } + set sleep [berkdb random_int 300 600] + puts \ +"[timestamp] $nprocs processes running $pidlist for $sleep seconds" + tclsleep $sleep + + # Now simulate a crash + puts "[timestamp] Crashing" + + # + # The environment must remain open until this point to get + # proper sharing (using the paging file) on Win/9X. [#2342] + # + error_check_good env_close [$dbenv close] 0 + + exec $KILL -9 $ddpid + exec $KILL -9 $cppid + # + # Use catch so that if any of the children died, we don't + # stop the script + # + foreach p $pidlist { + set e [catch {eval exec \ + [concat $KILL -9 $p]} res] + } + # Check for test failure + set e [eval findfail [glob $testdir/test044.*.log]] + error_check_good "FAIL: error message(s) in log files" $e 0 + + # Now run recovery + test044_verify $testdir $nfiles + incr cycle + } +} + +proc test044_usage { } { + puts -nonewline "test044 method nentries [-d directory] [-i iterations]" + puts " [-p procs] -x" +} + +proc test044_verify { dir nfiles } { + source ./include.tcl + + # Save everything away in case something breaks +# for { set f 0 } { $f < $nfiles } {incr f} { +# file copy -force $dir/test044.$f.db $dir/test044.$f.save1 +# } +# foreach f [glob $dir/log.*] { +# if { [is_substr $f save] == 0 } { +# file copy -force $f $f.save1 +# } +# } + + # Run recovery and then read through all the database files to make + # sure that they all look good. + + puts "\tTest044.verify: Running recovery and verifying file contents" + set stat [catch {exec $util_path/db_recover -h $dir} result] + if { $stat == 1 } { + error "FAIL: Recovery error: $result." + } + + # Save everything away in case something breaks +# for { set f 0 } { $f < $nfiles } {incr f} { +# file copy -force $dir/test044.$f.db $dir/test044.$f.save2 +# } +# foreach f [glob $dir/log.*] { +# if { [is_substr $f save] == 0 } { +# file copy -force $f $f.save2 +# } +# } + + for { set f 0 } { $f < $nfiles } { incr f } { + set db($f) [berkdb_open $dir/test044.$f.db] + error_check_good $f:dbopen [is_valid_db $db($f)] TRUE + + set cursors($f) [$db($f) cursor] + error_check_bad $f:cursor_open $cursors($f) NULL + error_check_good \ + $f:cursor_open [is_substr $cursors($f) $db($f)] 1 + } + + for { set f 0 } { $f < $nfiles } { incr f } { + for {set d [$cursors($f) get -first] } \ + { [string length $d] != 0 } \ + { set d [$cursors($f) get -next] } { + + set k [lindex [lindex $d 0] 0] + set d [lindex [lindex $d 0] 1] + + set flist [zero_list $nfiles] + set r $d + while { [set ndx [string first : $r]] != -1 } { + set fnum [string range $r 0 [expr $ndx - 1]] + if { [lindex $flist $fnum] == 0 } { + set fl "-set" + } else { + set fl "-next" + } + + if { $fl != "-set" || $fnum != $f } { + if { [string compare $fl "-set"] == 0} { + set full [$cursors($fnum) \ + get -set $k] + } else { + set full [$cursors($fnum) \ + get -next] + } + set key [lindex [lindex $full 0] 0] + set rec [lindex [lindex $full 0] 1] + error_check_good \ + $f:dbget_$fnum:key $key $k + error_check_good \ + $f:dbget_$fnum:data $rec $d + } + + set flist [lreplace $flist $fnum $fnum 1] + incr ndx + set r [string range $r $ndx end] + } + } + } + + for { set f 0 } { $f < $nfiles } { incr f } { + error_check_good $cursors($f) [$cursors($f) close] 0 + error_check_good db_close:$f [$db($f) close] 0 + } +} diff --git a/db/test/test045.tcl b/db/test/test045.tcl new file mode 100644 index 000000000..65f031d02 --- /dev/null +++ b/db/test/test045.tcl @@ -0,0 +1,117 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test045.tcl,v 11.17 2000/10/19 23:15:22 ubell Exp $ +# +# DB Test 45 Run the random db tester on the specified access method. +# Options are: +# -adds +# -cursors +# -dataavg +# -delete +# -dups +# -errpct +# -init +# -keyavg +proc test045 { method {nops 10000} args } { + source ./include.tcl + + if { [is_frecno $method] == 1 } { + puts "\tSkipping Test045 for method $method." + return + } + + # + # If we are using an env, then skip this test. It needs its own. + set eindex [lsearch -exact $args "-env"] + if { $eindex != -1 } { + incr eindex + set env [lindex $args $eindex] + puts "Test045 skipping for env $env" + return + } + set args [convert_args $method $args] + set omethod [convert_method $method] + + puts "Test045: Random tester on $method for $nops operations" + + # Set initial parameters + set adds [expr $nops * 10] + set cursors 5 + set dataavg 40 + set delete $nops + set dups 0 + set errpct 0 + set init 0 + if { [is_record_based $method] == 1 } { + set keyavg 10 + } else { + set keyavg 25 + } + + # Process arguments + set oargs "" + for { set i 0 } { $i < [llength $args] } {incr i} { + switch -regexp -- [lindex $args $i] { + -adds { incr i; set adds [lindex $args $i] } + -cursors { incr i; set cursors [lindex $args $i] } + -dataavg { incr i; set dataavg [lindex $args $i] } + -delete { incr i; set delete [lindex $args $i] } + -dups { incr i; set dups [lindex $args $i] } + -errpct { incr i; set errpct [lindex $args $i] } + -init { incr i; set init [lindex $args $i] } + -keyavg { incr i; set keyavg [lindex $args $i] } + -extent { incr i; + lappend oargs "-extent" "100" } + default { lappend oargs [lindex $args $i] } + } + } + + # Create the database and and initialize it. + set root $testdir/test045 + set f $root.db + env_cleanup $testdir + + # Run the script with 3 times the number of initial elements to + # set it up. + set db [eval {berkdb_open \ + -create -truncate -mode 0644 $omethod} $oargs {$f}] + error_check_good dbopen:$f [is_valid_db $db] TRUE + + set r [$db close] + error_check_good dbclose:$f $r 0 + + # We redirect standard out, but leave standard error here so we + # can see errors. + + puts "\tTest045.a: Initializing database" + if { $init != 0 } { + set n [expr 3 * $init] + exec $tclsh_path \ + $test_path/dbscript.tcl $f $n \ + 1 $init $n $keyavg $dataavg $dups 0 -1 \ + > $testdir/test045.init + } + # Check for test failure + set e [findfail $testdir/test045.init] + error_check_good "FAIL: error message(s) in init file" $e 0 + + puts "\tTest045.b: Now firing off berkdb rand dbscript, running: " + # Now the database is initialized, run a test + puts "$tclsh_path\ + $test_path/dbscript.tcl $f $nops $cursors $delete $adds \ + $keyavg $dataavg $dups $errpct > $testdir/test045.log" + + exec $tclsh_path \ + $test_path/dbscript.tcl $f \ + $nops $cursors $delete $adds $keyavg \ + $dataavg $dups $errpct \ + > $testdir/test045.log + + # Check for test failure + set e [findfail $testdir/test045.log] + error_check_good "FAIL: error message(s) in log file" $e 0 + +} diff --git a/db/test/test046.tcl b/db/test/test046.tcl new file mode 100644 index 000000000..3bfed3ef5 --- /dev/null +++ b/db/test/test046.tcl @@ -0,0 +1,717 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test046.tcl,v 11.26 2000/08/25 14:21:56 sue Exp $ +# +# DB Test 46: Overwrite test of small/big key/data with cursor checks. +proc test046 { method args } { + global alphabet + global errorInfo + global errorCode + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + + puts "\tTest046: Overwrite test with cursor and small/big key/data." + puts "\tTest046:\t$method $args" + + if { [is_rrecno $method] == 1} { + puts "\tTest046: skipping for method $method." + return + } + + set key "key" + set data "data" + set txn "" + set flags "" + + if { [is_record_based $method] == 1} { + set key "" + } + + puts "\tTest046: Create $method database." + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test046.db + set env NULL + } else { + set testfile test046.db + incr eindex + set env [lindex $args $eindex] + } + set t1 $testdir/t1 + cleanup $testdir $env + + set oflags "-create -mode 0644 $args $omethod" + set db [eval {berkdb_open} $oflags $testfile.a] + error_check_good dbopen [is_valid_db $db] TRUE + + # open curs to db + set dbc [$db cursor] + error_check_good db_cursor [is_substr $dbc $db] 1 + + # keep nkeys even + set nkeys 20 + + # Fill page w/ small key/data pairs + puts "\tTest046: Fill page with $nkeys small key/data pairs." + for { set i 1 } { $i <= $nkeys } { incr i } { + if { [is_record_based $method] == 1} { + set ret [$db put $i $data$i] + } elseif { $i < 10 } { + set ret [$db put [set key]00$i [set data]00$i] + } elseif { $i < 100 } { + set ret [$db put [set key]0$i [set data]0$i] + } else { + set ret [$db put $key$i $data$i] + } + error_check_good dbput $ret 0 + } + + # get db order of keys + for {set i 1; set ret [$dbc get -first]} { [llength $ret] != 0} { \ + set ret [$dbc get -next]} { + set key_set($i) [lindex [lindex $ret 0] 0] + set data_set($i) [lindex [lindex $ret 0] 1] + incr i + } + + puts "\tTest046.a: Deletes by key." + puts "\t\tTest046.a.1: Get data with SET, then delete before cursor." + # get key in middle of page, call this the nth set curr to it + set i [expr $nkeys/2] + set ret [$dbc get -set $key_set($i)] + error_check_bad dbc_get:set [llength $ret] 0 + set curr $ret + + # delete before cursor(n-1), make sure it is gone + set i [expr $i - 1] + error_check_good db_del [$db del $key_set($i)] 0 + + # use set_range to get first key starting at n-1, should + # give us nth--but only works for btree + if { [is_btree $method] == 1 } { + set ret [$dbc get -set_range $key_set($i)] + } else { + if { [is_record_based $method] == 1 } { + set ret [$dbc get -set $key_set($i)] + error_check_good \ + dbc_get:deleted(recno) [llength [lindex $ret 1]] 0 + #error_check_good \ + # catch:get [catch {$dbc get -set $key_set($i)} ret] 1 + #error_check_good \ + # dbc_get:deleted(recno) [is_substr $ret "KEYEMPTY"] 1 + } else { + set ret [$dbc get -set $key_set($i)] + error_check_good dbc_get:deleted [llength $ret] 0 + } + set ret [$dbc get -set $key_set([incr i])] + incr i -1 + } + error_check_bad dbc_get:set(R)(post-delete) [llength $ret] 0 + error_check_good dbc_get(match):set $ret $curr + + puts "\t\tTest046.a.2: Delete cursor item by key." + # nth key, which cursor should be on now + set i [incr i] + set ret [$db del $key_set($i)] + error_check_good db_del $ret 0 + + # this should return n+1 key/data, curr has nth key/data + if { [string compare $omethod "-btree"] == 0 } { + set ret [$dbc get -set_range $key_set($i)] + } else { + if { [is_record_based $method] == 1 } { + set ret [$dbc get -set $key_set($i)] + error_check_good \ + dbc_get:deleted(recno) [llength [lindex $ret 1]] 0 + #error_check_good \ + # catch:get [catch {$dbc get -set $key_set($i)} ret] 1 + #error_check_good \ + # dbc_get:deleted(recno) [is_substr $ret "KEYEMPTY"] 1 + } else { + set ret [$dbc get -set $key_set($i)] + error_check_good dbc_get:deleted [llength $ret] 0 + } + set ret [$dbc get -set $key_set([expr $i+1])] + } + error_check_bad dbc_get(post-delete):set_range [llength $ret] 0 + error_check_bad dbc_get(no-match):set_range $ret $curr + + puts "\t\tTest046.a.3: Delete item after cursor." + # we'll delete n+2, since we have deleted n-1 and n + # i still equal to nth, cursor on n+1 + set i [incr i] + set ret [$dbc get -set $key_set($i)] + error_check_bad dbc_get:set [llength $ret] 0 + set curr [$dbc get -next] + error_check_bad dbc_get:next [llength $curr] 0 + set ret [$dbc get -prev] + error_check_bad dbc_get:prev [llength $curr] 0 + # delete *after* cursor pos. + error_check_good db:del [$db del $key_set([incr i])] 0 + + # make sure item is gone, try to get it + if { [string compare $omethod "-btree"] == 0} { + set ret [$dbc get -set_range $key_set($i)] + } else { + if { [is_record_based $method] == 1 } { + set ret [$dbc get -set $key_set($i)] + error_check_good \ + dbc_get:deleted(recno) [llength [lindex $ret 1]] 0 + #error_check_good \ + # catch:get [catch {$dbc get -set $key_set($i)} ret] 1 + #error_check_good \ + # dbc_get:deleted(recno) [is_substr $ret "KEYEMPTY"] 1 + } else { + set ret [$dbc get -set $key_set($i)] + error_check_good dbc_get:deleted [llength $ret] 0 + } + set ret [$dbc get -set $key_set([expr $i +1])] + } + error_check_bad dbc_get:set(_range) [llength $ret] 0 + error_check_bad dbc_get:set(_range) $ret $curr + error_check_good dbc_get:set [lindex [lindex $ret 0] 0] \ + $key_set([expr $i+1]) + + puts "\tTest046.b: Deletes by cursor." + puts "\t\tTest046.b.1: Delete, do DB_NEXT." + error_check_good dbc:del [$dbc del] 0 + set ret [$dbc get -next] + error_check_bad dbc_get:next [llength $ret] 0 + set i [expr $i+2] + # i = n+4 + error_check_good dbc_get:next(match) \ + [lindex [lindex $ret 0] 0] $key_set($i) + + puts "\t\tTest046.b.2: Delete, do DB_PREV." + error_check_good dbc:del [$dbc del] 0 + set ret [$dbc get -prev] + error_check_bad dbc_get:prev [llength $ret] 0 + set i [expr $i-3] + # i = n+1 (deleted all in between) + error_check_good dbc_get:prev(match) \ + [lindex [lindex $ret 0] 0] $key_set($i) + + puts "\t\tTest046.b.3: Delete, do DB_CURRENT." + error_check_good dbc:del [$dbc del] 0 + # we just deleted, so current item should be KEYEMPTY, throws err + set ret [$dbc get -current] + error_check_good dbc_get:curr:deleted [llength [lindex $ret 1]] 0 + #error_check_good catch:get:current [catch {$dbc get -current} ret] 1 + #error_check_good dbc_get:curr:deleted [is_substr $ret "DB_KEYEMPTY"] 1 + + puts "\tTest046.c: Inserts (before/after), by key then cursor." + puts "\t\tTest046.c.1: Insert by key before the cursor." + # i is at curs pos, i=n+1, we want to go BEFORE + set i [incr i -1] + set ret [$db put $key_set($i) $data_set($i)] + error_check_good db_put:before $ret 0 + + puts "\t\tTest046.c.2: Insert by key after the cursor." + set i [incr i +2] + set ret [$db put $key_set($i) $data_set($i)] + error_check_good db_put:after $ret 0 + + puts "\t\tTest046.c.3: Insert by curs with deleted curs (should fail)." + # cursor is on n+1, we'll change i to match + set i [incr i -1] + + error_check_good dbc:close [$dbc close] 0 + error_check_good db:close [$db close] 0 + if { [is_record_based $method] == 1} { + puts "\t\tSkipping the rest of test for method $method." + puts "\tTest046 ($method) complete." + return + } else { + # Reopen without printing __db_errs. + set db [eval {berkdb_open_noerr} $oflags $testfile.a] + error_check_good dbopen [is_valid_db $db] TRUE + set dbc [$db cursor] + error_check_good cursor [is_valid_cursor $dbc $db] TRUE + + # should fail with EINVAL (deleted cursor) + set errorCode NONE + error_check_good catch:put:before 1 \ + [catch {$dbc put -before $data_set($i)} ret] + error_check_good dbc_put:deleted:before \ + [is_substr $errorCode "EINVAL"] 1 + + # should fail with EINVAL + set errorCode NONE + error_check_good catch:put:after 1 \ + [catch {$dbc put -after $data_set($i)} ret] + error_check_good dbc_put:deleted:after \ + [is_substr $errorCode "EINVAL"] 1 + + puts "\t\tTest046.c.4:\ + Insert by cursor before/after existent cursor." + # can't use before after w/o dup except renumber in recno + # first, restore an item so they don't fail + #set ret [$db put $key_set($i) $data_set($i)] + #error_check_good db_put $ret 0 + + #set ret [$dbc get -set $key_set($i)] + #error_check_bad dbc_get:set [llength $ret] 0 + #set i [incr i -2] + # i = n - 1 + #set ret [$dbc get -prev] + #set ret [$dbc put -before $key_set($i) $data_set($i)] + #error_check_good dbc_put:before $ret 0 + # cursor pos is adjusted to match prev, recently inserted + #incr i + # i = n + #set ret [$dbc put -after $key_set($i) $data_set($i)] + #error_check_good dbc_put:after $ret 0 + } + + # For the next part of the test, we need a db with no dups to test + # overwrites + puts "\tTest046.d.0: Cleanup, close db, open new db with no dups." + error_check_good dbc:close [$dbc close] 0 + error_check_good db:close [$db close] 0 + + set db [eval {berkdb_open} $oflags $testfile.d] + error_check_good dbopen [is_valid_db $db] TRUE + set dbc [$db cursor] + error_check_good db_cursor [is_substr $dbc $db] 1 + set nkeys 20 + + # Fill page w/ small key/data pairs + puts "\tTest046.d.0: Fill page with $nkeys small key/data pairs." + for { set i 1 } { $i < $nkeys } { incr i } { + set ret [$db put $key$i $data$i] + error_check_good dbput $ret 0 + } + + # Prepare cursor on item + set ret [$dbc get -first] + error_check_bad dbc_get:first [llength $ret] 0 + + # Prepare unique big/small values for an initial + # and an overwrite set of key/data + foreach ptype {init over} { + foreach size {big small} { + if { [string compare $size big] == 0 } { + set key_$ptype$size \ + KEY_$size[repeat alphabet 250] + set data_$ptype$size \ + DATA_$size[repeat alphabet 250] + } else { + set key_$ptype$size \ + KEY_$size[repeat alphabet 10] + set data_$ptype$size \ + DATA_$size[repeat alphabet 10] + } + } + } + + set i 0 + # Do all overwrites for key and cursor + foreach type {key_over curs_over} { + # Overwrite (i=initial) four different kinds of pairs + incr i + puts "\tTest046.d: Overwrites $type." + foreach i_pair {\ + {small small} {big small} {small big} {big big} } { + # Overwrite (w=write) with four different kinds of data + foreach w_pair {\ + {small small} {big small} {small big} {big big} } { + + # we can only overwrite if key size matches + if { [string compare [lindex \ + $i_pair 0] [lindex $w_pair 0]] != 0} { + continue + } + + # first write the initial key/data + set ret [$dbc put -keyfirst \ + key_init[lindex $i_pair 0] \ + data_init[lindex $i_pair 1]] + error_check_good \ + dbc_put:curr:init:$i_pair $ret 0 + set ret [$dbc get -current] + error_check_bad dbc_get:curr [llength $ret] 0 + error_check_good dbc_get:curr:data \ + [lindex [lindex $ret 0] 1] \ + data_init[lindex $i_pair 1] + + # Now, try to overwrite: dups not supported in + # this db + if { [string compare $type key_over] == 0 } { + puts "\t\tTest046.d.$i: Key\ + Overwrite:($i_pair) by ($w_pair)." + set ret [$db put \ + $"key_init[lindex $i_pair 0]" \ + $"data_over[lindex $w_pair 1]"] + error_check_good \ + dbput:over:i($i_pair):o($w_pair) $ret 0 + # check value + set ret [$db \ + get $"key_init[lindex $i_pair 0]"] + error_check_bad \ + db:get:check [llength $ret] 0 + error_check_good db:get:compare_data \ + [lindex [lindex $ret 0] 1] \ + $"data_over[lindex $w_pair 1]" + } else { + # This is a cursor overwrite + puts \ + "\t\tTest046.d.$i:Curs Overwrite:($i_pair) by ($w_pair)." + set ret [$dbc put -current \ + $"data_over[lindex $w_pair 1]"] + error_check_good \ + dbcput:over:i($i_pair):o($w_pair) $ret 0 + # check value + set ret [$dbc get -current] + error_check_bad \ + dbc_get:curr [llength $ret] 0 + error_check_good dbc_get:curr:data \ + [lindex [lindex $ret 0] 1] \ + $"data_over[lindex $w_pair 1]" + } + } ;# foreach write pair + } ;# foreach initial pair + } ;# foreach type big/small + + puts "\tTest046.d.3: Cleanup for next part of test." + error_check_good dbc_close [$dbc close] 0 + error_check_good db_close [$db close] 0 + + if { [is_rbtree $method] == 1} { + puts "\tSkipping the rest of Test046 for method $method." + puts "\tTest046 complete." + return + } + + puts "\tTest046.e.1: Open db with sorted dups." + set db [eval {berkdb_open_noerr} $oflags -dup -dupsort $testfile.e] + error_check_good dbopen [is_valid_db $db] TRUE + + # open curs to db + set dbc [$db cursor] + error_check_good db_cursor [is_substr $dbc $db] 1 + + # keep nkeys even + set nkeys 20 + set ndups 20 + + # Fill page w/ small key/data pairs + puts "\tTest046.e.2:\ + Put $nkeys small key/data pairs and $ndups sorted dups." + for { set i 0 } { $i < $nkeys } { incr i } { + if { $i < 10 } { + set ret [$db put [set key]0$i [set data]0$i] + } else { + set ret [$db put $key$i $data$i] + } + error_check_good dbput $ret 0 + } + + # get db order of keys + for {set i 0; set ret [$dbc get -first]} { [llength $ret] != 0} { \ + set ret [$dbc get -next]} { + set key_set($i) [lindex [lindex $ret 0] 0] + set data_set($i) [lindex [lindex $ret 0] 1] + incr i + } + + # put 20 sorted duplicates on key in middle of page + set i [expr $nkeys/2] + set ret [$dbc get -set $key_set($i)] + error_check_bad dbc_get:set [llength $ret] 0 + + set keym $key_set($i) + + for { set i 0 } { $i < $ndups } { incr i } { + if { $i < 10 } { + set ret [$db put $keym DUPLICATE_0$i] + } else { + set ret [$db put $keym DUPLICATE_$i] + } + error_check_good db_put:DUP($i) $ret 0 + } + + puts "\tTest046.e.3: Check duplicate duplicates" + set ret [$db put $keym DUPLICATE_00] + error_check_good dbput:dupdup [is_substr $ret "DB_KEYEXIST"] 1 + + # get dup ordering + for {set i 0; set ret [$dbc get -set $keym]} { [llength $ret] != 0} {\ + set ret [$dbc get -nextdup] } { + set dup_set($i) [lindex [lindex $ret 0] 1] + incr i + } + + # put cursor on item in middle of dups + set i [expr $ndups/2] + set ret [$dbc get -get_both $keym $dup_set($i)] + error_check_bad dbc_get:get_both [llength $ret] 0 + + puts "\tTest046.f: Deletes by cursor." + puts "\t\tTest046.f.1: Delete by cursor, do a DB_NEXT, check cursor." + set ret [$dbc get -current] + error_check_bad dbc_get:current [llength $ret] 0 + error_check_good dbc:del [$dbc del] 0 + set ret [$dbc get -next] + error_check_bad dbc_get:next [llength $ret] 0 + error_check_good \ + dbc_get:nextdup [lindex [lindex $ret 0] 1] $dup_set([incr i]) + + puts "\t\tTest046.f.2: Delete by cursor, do DB_PREV, check cursor." + error_check_good dbc:del [$dbc del] 0 + set ret [$dbc get -prev] + error_check_bad dbc_get:prev [llength $ret] 0 + set i [incr i -2] + error_check_good dbc_get:prev [lindex [lindex $ret 0] 1] $dup_set($i) + + puts "\t\tTest046.f.3: Delete by cursor, do DB_CURRENT, check cursor." + error_check_good dbc:del [$dbc del] 0 + set ret [$dbc get -current] + error_check_good dbc_get:current:deleted [llength [lindex $ret 1]] 0 + #error_check_good catch:dbc_get:curr [catch {$dbc get -current} ret] 1 + #error_check_good \ + # dbc_get:current:deleted [is_substr $ret "DB_KEYEMPTY"] 1 + error_check_good dbc_close [$dbc close] 0 + + # restore deleted keys + error_check_good db_put:1 [$db put $keym $dup_set($i)] 0 + error_check_good db_put:2 [$db put $keym $dup_set([incr i])] 0 + error_check_good db_put:3 [$db put $keym $dup_set([incr i])] 0 + + # tested above + + # Reopen database without __db_err, reset cursor + error_check_good dbclose [$db close] 0 + set db [eval {berkdb_open_noerr} $oflags -dup -dupsort $testfile.e] + error_check_good dbopen [is_valid_db $db] TRUE + error_check_good db_cursor [is_substr [set dbc [$db cursor]] $db] 1 + + set ret [$dbc get -set $keym] + error_check_bad dbc_get:set [llength $ret] 0 + set ret2 [$dbc get -current] + error_check_bad dbc_get:current [llength $ret2] 0 + # match + error_check_good dbc_get:current/set(match) $ret $ret2 + # right one? + error_check_good \ + dbc_get:curr/set(matchdup) [lindex [lindex $ret 0] 1] $dup_set(0) + + # cursor is on first dup + set ret [$dbc get -next] + error_check_bad dbc_get:next [llength $ret] 0 + # now on second dup + error_check_good dbc_get:next [lindex [lindex $ret 0] 1] $dup_set(1) + # check cursor + set ret [$dbc get -current] + error_check_bad dbc_get:curr [llength $ret] 0 + error_check_good \ + dbcget:curr(compare) [lindex [lindex $ret 0] 1] $dup_set(1) + + puts "\tTest046.g: Inserts." + puts "\t\tTest046.g.1: Insert by key before cursor." + set i 0 + + # use "spam" to prevent a duplicate duplicate. + set ret [$db put $keym $dup_set($i)spam] + error_check_good db_put:before $ret 0 + # make sure cursor was maintained + set ret [$dbc get -current] + error_check_bad dbc_get:curr [llength $ret] 0 + error_check_good \ + dbc_get:current(post-put) [lindex [lindex $ret 0] 1] $dup_set(1) + + puts "\t\tTest046.g.2: Insert by key after cursor." + set i [expr $i + 2] + # use "eggs" to prevent a duplicate duplicate + set ret [$db put $keym $dup_set($i)eggs] + error_check_good db_put:after $ret 0 + # make sure cursor was maintained + set ret [$dbc get -current] + error_check_bad dbc_get:curr [llength $ret] 0 + error_check_good \ + dbc_get:curr(post-put,after) [lindex [lindex $ret 0] 1] $dup_set(1) + + puts "\t\tTest046.g.3: Insert by curs before/after curs (should fail)." + # should return EINVAL (dupsort specified) + error_check_good dbc_put:before:catch \ + [catch {$dbc put -before $dup_set([expr $i -1])} ret] 1 + error_check_good \ + dbc_put:before:deleted [is_substr $errorCode "EINVAL"] 1 + error_check_good dbc_put:after:catch \ + [catch {$dbc put -after $dup_set([expr $i +2])} ret] 1 + error_check_good \ + dbc_put:after:deleted [is_substr $errorCode "EINVAL"] 1 + + puts "\tTest046.h: Cursor overwrites." + puts "\t\tTest046.h.1: Test that dupsort disallows current overwrite." + set ret [$dbc get -set $keym] + error_check_bad dbc_get:set [llength $ret] 0 + error_check_good \ + catch:dbc_put:curr [catch {$dbc put -current DATA_OVERWRITE} ret] 1 + error_check_good dbc_put:curr:dupsort [is_substr $errorCode EINVAL] 1 + + puts "\t\tTest046.h.2: New db (no dupsort)." + error_check_good dbc_close [$dbc close] 0 + error_check_good db_close [$db close] 0 + + set db [berkdb_open \ + -create -dup $omethod -mode 0644 -truncate $testfile.h] + error_check_good db_open [is_valid_db $db] TRUE + set dbc [$db cursor] + error_check_good db_cursor [is_substr $dbc $db] 1 + + for {set i 0} {$i < $nkeys} {incr i} { + if { $i < 10 } { + error_check_good db_put [$db put key0$i datum0$i] 0 + } else { + error_check_good db_put [$db put key$i datum$i] 0 + } + if { $i == 0 } { + for {set j 0} {$j < $ndups} {incr j} { + if { $i < 10 } { + set keyput key0$i + } else { + set keyput key$i + } + if { $j < 10 } { + set ret [$db put $keyput DUP_datum0$j] + } else { + set ret [$db put $keyput DUP_datum$j] + } + error_check_good dbput:dup $ret 0 + } + } + } + + for {set i 0; set ret [$dbc get -first]} { [llength $ret] != 0} { \ + set ret [$dbc get -next]} { + set key_set($i) [lindex [lindex $ret 0] 0] + set data_set($i) [lindex [lindex $ret 0] 1] + incr i + } + + for {set i 0; set ret [$dbc get -set key00]} {\ + [llength $ret] != 0} {set ret [$dbc get -nextdup]} { + set dup_set($i) [lindex [lindex $ret 0] 1] + incr i + } + set i 0 + set keym key0$i + set ret [$dbc get -set $keym] + error_check_bad dbc_get:set [llength $ret] 0 + error_check_good \ + dbc_get:set(match) [lindex [lindex $ret 0] 1] $dup_set($i) + + set ret [$dbc get -nextdup] + error_check_bad dbc_get:nextdup [llength $ret] 0 + error_check_good dbc_get:nextdup(match) \ + [lindex [lindex $ret 0] 1] $dup_set([expr $i + 1]) + + puts "\t\tTest046.h.3: Insert by cursor before cursor (DB_BEFORE)." + set ret [$dbc put -before BEFOREPUT] + error_check_good dbc_put:before $ret 0 + set ret [$dbc get -current] + error_check_bad dbc_get:curr [llength $ret] 0 + error_check_good \ + dbc_get:curr:match [lindex [lindex $ret 0] 1] BEFOREPUT + # make sure that this is actually a dup w/ dup before + set ret [$dbc get -prev] + error_check_bad dbc_get:prev [llength $ret] 0 + error_check_good dbc_get:prev:match \ + [lindex [lindex $ret 0] 1] $dup_set($i) + set ret [$dbc get -prev] + # should not be a dup + error_check_bad dbc_get:prev(no_dup) \ + [lindex [lindex $ret 0] 0] $keym + + puts "\t\tTest046.h.4: Insert by cursor after cursor (DB_AFTER)." + set ret [$dbc get -set $keym] + + # delete next 3 when fix + #puts "[$dbc get -current]\ + # [$dbc get -next] [$dbc get -next] [$dbc get -next] [$dbc get -next]" + #set ret [$dbc get -set $keym] + + error_check_bad dbc_get:set [llength $ret] 0 + set ret [$dbc put -after AFTERPUT] + error_check_good dbc_put:after $ret 0 + #puts [$dbc get -current] + + # delete next 3 when fix + #set ret [$dbc get -set $keym] + #puts "[$dbc get -current] next: [$dbc get -next] [$dbc get -next]" + #set ret [$dbc get -set AFTERPUT] + #set ret [$dbc get -set $keym] + #set ret [$dbc get -next] + #puts $ret + + set ret [$dbc get -current] + error_check_bad dbc_get:curr [llength $ret] 0 + error_check_good dbc_get:curr:match [lindex [lindex $ret 0] 1] AFTERPUT + set ret [$dbc get -prev] + # now should be on first item (non-dup) of keym + error_check_bad dbc_get:prev1 [llength $ret] 0 + error_check_good \ + dbc_get:match [lindex [lindex $ret 0] 1] $dup_set($i) + set ret [$dbc get -next] + error_check_bad dbc_get:next [llength $ret] 0 + error_check_good \ + dbc_get:match2 [lindex [lindex $ret 0] 1] AFTERPUT + set ret [$dbc get -next] + error_check_bad dbc_get:next [llength $ret] 0 + # this is the dup we added previously + error_check_good \ + dbc_get:match3 [lindex [lindex $ret 0] 1] BEFOREPUT + + # now get rid of the dups we added + error_check_good dbc_del [$dbc del] 0 + set ret [$dbc get -prev] + error_check_bad dbc_get:prev2 [llength $ret] 0 + error_check_good dbc_del2 [$dbc del] 0 + # put cursor on first dup item for the rest of test + set ret [$dbc get -set $keym] + error_check_bad dbc_get:first [llength $ret] 0 + error_check_good \ + dbc_get:first:check [lindex [lindex $ret 0] 1] $dup_set($i) + + puts "\t\tTest046.h.5: Overwrite small by small." + set ret [$dbc put -current DATA_OVERWRITE] + error_check_good dbc_put:current:overwrite $ret 0 + set ret [$dbc get -current] + error_check_good dbc_get:current(put,small/small) \ + [lindex [lindex $ret 0] 1] DATA_OVERWRITE + + puts "\t\tTest046.h.6: Overwrite small with big." + set ret [$dbc put -current DATA_BIG_OVERWRITE[repeat $alphabet 200]] + error_check_good dbc_put:current:overwrite:big $ret 0 + set ret [$dbc get -current] + error_check_good dbc_get:current(put,small/big) \ + [is_substr [lindex [lindex $ret 0] 1] DATA_BIG_OVERWRITE] 1 + + puts "\t\tTest046.h.7: Overwrite big with big." + set ret [$dbc put -current DATA_BIG_OVERWRITE2[repeat $alphabet 200]] + error_check_good dbc_put:current:overwrite(2):big $ret 0 + set ret [$dbc get -current] + error_check_good dbc_get:current(put,big/big) \ + [is_substr [lindex [lindex $ret 0] 1] DATA_BIG_OVERWRITE2] 1 + + puts "\t\tTest046.h.8: Overwrite big with small." + set ret [$dbc put -current DATA_OVERWRITE2] + error_check_good dbc_put:current:overwrite:small $ret 0 + set ret [$dbc get -current] + error_check_good dbc_get:current(put,big/small) \ + [is_substr [lindex [lindex $ret 0] 1] DATA_OVERWRITE2] 1 + + puts "\tTest046.i: Cleaning up from test." + error_check_good dbc_close [$dbc close] 0 + error_check_good db_close [$db close] 0 + + puts "\tTest046 complete." +} diff --git a/db/test/test047.tcl b/db/test/test047.tcl new file mode 100644 index 000000000..9d11cd3db --- /dev/null +++ b/db/test/test047.tcl @@ -0,0 +1,192 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test047.tcl,v 11.10 2000/08/25 14:21:56 sue Exp $ +# +# DB Test 47: test of the SET_RANGE interface to DB->c_get. +proc test047 { method args } { + source ./include.tcl + + set tstn 047 + + if { [is_btree $method] != 1 } { + puts "Test$tstn skipping for method $method" + return + } + + set method "-btree" + + puts "\tTest$tstn: Test of SET_RANGE interface to DB->c_get ($method)." + + set key "key" + set data "data" + set txn "" + set flags "" + + puts "\tTest$tstn.a: Create $method database." + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test0$tstn.db + set testfile1 $testdir/test0$tstn.a.db + set testfile2 $testdir/test0$tstn.b.db + set env NULL + } else { + set testfile test0$tstn.db + set testfile1 test0$tstn.a.db + set testfile2 test0$tstn.b.db + incr eindex + set env [lindex $args $eindex] + } + set t1 $testdir/t1 + cleanup $testdir $env + + set oflags "-create -truncate -mode 0644 -dup $args $method" + set db [eval {berkdb_open} $oflags $testfile] + error_check_good dbopen [is_valid_db $db] TRUE + + # open curs to db + set dbc [$db cursor] + error_check_good db_cursor [is_substr $dbc $db] 1 + + set nkeys 20 + # Fill page w/ small key/data pairs + # + puts "\tTest$tstn.b: Fill page with $nkeys small key/data pairs." + for { set i 0 } { $i < $nkeys } { incr i } { + set ret [$db put $key$i $data$i] + error_check_good dbput $ret 0 + } + + puts "\tTest$tstn.c: Get data with SET_RANGE, then delete by cursor." + set i 0 + set ret [$dbc get -set_range $key$i] + error_check_bad dbc_get:set_range [llength $ret] 0 + set curr $ret + + # delete by cursor, make sure it is gone + error_check_good dbc_del [$dbc del] 0 + + set ret [$dbc get -set_range $key$i] + error_check_bad dbc_get(post-delete):set_range [llength $ret] 0 + error_check_bad dbc_get(no-match):set_range $ret $curr + + puts "\tTest$tstn.d: \ + Use another cursor to fix item on page, delete by db." + set dbcurs2 [$db cursor] + error_check_good db:cursor2 [is_substr $dbcurs2 $db] 1 + + set ret [$dbcurs2 get -set [lindex [lindex $ret 0] 0]] + error_check_bad dbc_get(2):set [llength $ret] 0 + set curr $ret + error_check_good db:del [$db del [lindex [lindex $ret 0] 0]] 0 + + # make sure item is gone + set ret [$dbcurs2 get -set_range [lindex [lindex $curr 0] 0]] + error_check_bad dbc2_get:set_range [llength $ret] 0 + error_check_bad dbc2_get:set_range $ret $curr + + puts "\tTest$tstn.e: Close for second part of test, close db/cursors." + error_check_good dbc:close [$dbc close] 0 + error_check_good dbc2:close [$dbcurs2 close] 0 + error_check_good dbclose [$db close] 0 + + # open db + set db [eval {berkdb_open} $oflags $testfile1] + error_check_good dbopen2 [is_valid_db $db] TRUE + + set nkeys 10 + puts "\tTest$tstn.f: Fill page with $nkeys pairs, one set of dups." + for {set i 0} { $i < $nkeys } {incr i} { + # a pair + set ret [$db put $key$i $data$i] + error_check_good dbput($i) $ret 0 + } + + set j 0 + for {set i 0} { $i < $nkeys } {incr i} { + # a dup set for same 1 key + set ret [$db put $key$i DUP_$data$i] + error_check_good dbput($i):dup $ret 0 + } + + puts "\tTest$tstn.g: \ + Get dups key w/ SET_RANGE, pin onpage with another cursor." + set i 0 + set dbc [$db cursor] + error_check_good db_cursor [is_substr $dbc $db] 1 + set ret [$dbc get -set_range $key$i] + error_check_bad dbc_get:set_range [llength $ret] 0 + + set dbc2 [$db cursor] + error_check_good db_cursor2 [is_substr $dbc2 $db] 1 + set ret2 [$dbc2 get -set_range $key$i] + error_check_bad dbc2_get:set_range [llength $ret] 0 + + error_check_good dbc_compare $ret $ret2 + puts "\tTest$tstn.h: \ + Delete duplicates' key, use SET_RANGE to get next dup." + set ret [$dbc2 del] + error_check_good dbc2_del $ret 0 + set ret [$dbc get -set_range $key$i] + error_check_bad dbc_get:set_range [llength $ret] 0 + error_check_bad dbc_get:set_range $ret $ret2 + + error_check_good dbc_close [$dbc close] 0 + error_check_good dbc2_close [$dbc2 close] 0 + error_check_good db_close [$db close] 0 + + set db [eval {berkdb_open} $oflags $testfile2] + error_check_good dbopen [is_valid_db $db] TRUE + set dbc [$db cursor] + error_check_good db_cursor [is_substr $dbc $db] 1 + set dbc2 [$db cursor] + error_check_good db_cursor2 [is_substr $dbc2 $db] 1 + + set nkeys 10 + set ndups 1000 + + puts "\tTest$tstn.i: Fill page with $nkeys pairs and $ndups dups." + for {set i 0} { $i < $nkeys } { incr i} { + # a pair + set ret [$db put $key$i $data$i] + error_check_good dbput $ret 0 + + # dups for single pair + if { $i == 0} { + for {set j 0} { $j < $ndups } { incr j } { + set ret [$db put $key$i DUP_$data$i:$j] + error_check_good dbput:dup $ret 0 + } + } + } + set i 0 + puts "\tTest$tstn.j: \ + Get key of first dup with SET_RANGE, fix with 2 curs." + set ret [$dbc get -set_range $key$i] + error_check_bad dbc_get:set_range [llength $ret] 0 + + set ret2 [$dbc2 get -set_range $key$i] + error_check_bad dbc2_get:set_range [llength $ret] 0 + set curr $ret2 + + error_check_good dbc_compare $ret $ret2 + + puts "\tTest$tstn.k: Delete item by cursor, use SET_RANGE to verify." + set ret [$dbc2 del] + error_check_good dbc2_del $ret 0 + set ret [$dbc get -set_range $key$i] + error_check_bad dbc_get:set_range [llength $ret] 0 + error_check_bad dbc_get:set_range $ret $curr + + puts "\tTest$tstn.l: Cleanup." + error_check_good dbc_close [$dbc close] 0 + error_check_good dbc2_close [$dbc2 close] 0 + error_check_good db_close [$db close] 0 + + puts "\tTest$tstn complete." +} diff --git a/db/test/test048.tcl b/db/test/test048.tcl new file mode 100644 index 000000000..84c7c47b7 --- /dev/null +++ b/db/test/test048.tcl @@ -0,0 +1,139 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test048.tcl,v 11.11 2000/12/11 17:42:18 sue Exp $ +# +# Test048: Cursor stability across btree splits. +proc test048 { method args } { + global errorCode + source ./include.tcl + + set tstn 048 + + if { [is_btree $method] != 1 } { + puts "Test$tstn skipping for method $method." + return + } + set pgindex [lsearch -exact $args "-pagesize"] + if { $pgindex != -1 } { + incr pgindex + if { [lindex $args $pgindex] > 8192 } { + puts "Test048: Skipping for large pagesizes" + return + } + } + + set method "-btree" + + puts "\tTest$tstn: Test of cursor stability across btree splits." + + set key "key" + set data "data" + set txn "" + set flags "" + + puts "\tTest$tstn.a: Create $method database." + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test0$tstn.db + set env NULL + } else { + set testfile test0$tstn.db + incr eindex + set env [lindex $args $eindex] + } + set t1 $testdir/t1 + cleanup $testdir $env + + set oflags "-create -truncate -mode 0644 $args $method" + set db [eval {berkdb_open} $oflags $testfile] + error_check_good dbopen [is_valid_db $db] TRUE + + set nkeys 5 + # Fill page w/ small key/data pairs, keep at leaf + # + puts "\tTest$tstn.b: Fill page with $nkeys small key/data pairs." + for { set i 0 } { $i < $nkeys } { incr i } { + set ret [$db put key000$i $data$i] + error_check_good dbput $ret 0 + } + + # get db ordering, set cursors + puts "\tTest$tstn.c: Set cursors on each of $nkeys pairs." + for {set i 0; set ret [$db get key000$i]} {\ + $i < $nkeys && [llength $ret] != 0} {\ + incr i; set ret [$db get key000$i]} { + set key_set($i) [lindex [lindex $ret 0] 0] + set data_set($i) [lindex [lindex $ret 0] 1] + set dbc [$db cursor] + set dbc_set($i) $dbc + error_check_good db_cursor:$i [is_substr $dbc_set($i) $db] 1 + set ret [$dbc_set($i) get -set $key_set($i)] + error_check_bad dbc_set($i)_get:set [llength $ret] 0 + } + + # if mkeys is above 1000, need to adjust below for lexical order + set mkeys 1000 + puts "\tTest$tstn.d: Add $mkeys pairs to force split." + for {set i $nkeys} { $i < $mkeys } { incr i } { + if { $i >= 100 } { + set ret [$db put key0$i $data$i] + } elseif { $i >= 10 } { + set ret [$db put key00$i $data$i] + } else { + set ret [$db put key000$i $data$i] + } + error_check_good dbput:more $ret 0 + } + + puts "\tTest$tstn.e: Make sure split happened." + error_check_bad stat:check-split [is_substr [$db stat] \ + "{{Internal pages} 0}"] 1 + + puts "\tTest$tstn.f: Check to see that cursors maintained reference." + for {set i 0} { $i < $nkeys } {incr i} { + set ret [$dbc_set($i) get -current] + error_check_bad dbc$i:get:current [llength $ret] 0 + set ret2 [$dbc_set($i) get -set $key_set($i)] + error_check_bad dbc$i:get:set [llength $ret2] 0 + error_check_good dbc$i:get(match) $ret $ret2 + } + + puts "\tTest$tstn.g: Delete added keys to force reverse split." + for {set i $nkeys} { $i < $mkeys } { incr i } { + if { $i >= 100 } { + error_check_good db_del:$i [$db del key0$i] 0 + } elseif { $i >= 10 } { + error_check_good db_del:$i [$db del key00$i] 0 + } else { + error_check_good db_del:$i [$db del key000$i] 0 + } + } + + puts "\tTest$tstn.h: Verify reverse split." + error_check_good stat:check-reverse_split [is_substr [$db stat] \ + "{{Internal pages} 0}"] 1 + + puts "\tTest$tstn.i: Verify cursor reference." + for {set i 0} { $i < $nkeys } {incr i} { + set ret [$dbc_set($i) get -current] + error_check_bad dbc$i:get:current [llength $ret] 0 + set ret2 [$dbc_set($i) get -set $key_set($i)] + error_check_bad dbc$i:get:set [llength $ret2] 0 + error_check_good dbc$i:get(match) $ret $ret2 + } + + puts "\tTest$tstn.j: Cleanup." + # close cursors + for {set i 0} { $i < $nkeys } {incr i} { + error_check_good dbc_close:$i [$dbc_set($i) close] 0 + } + error_check_good dbclose [$db close] 0 + + puts "\tTest$tstn complete." +} diff --git a/db/test/test049.tcl b/db/test/test049.tcl new file mode 100644 index 000000000..aaea3b200 --- /dev/null +++ b/db/test/test049.tcl @@ -0,0 +1,160 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test049.tcl,v 11.15 2000/08/25 14:21:56 sue Exp $ +# +# Test 049: Test of each cursor routine with unitialized cursors +proc test049 { method args } { + global errorInfo + global errorCode + source ./include.tcl + + set tstn 049 + set renum [is_rrecno $method] + + set args [convert_args $method $args] + set omethod [convert_method $method] + + puts "\tTest$tstn: Test of cursor routines with unitialized cursors." + + set key "key" + set data "data" + set txn "" + set flags "" + set rflags "" + + if { [is_record_based $method] == 1 } { + set key "" + } + + puts "\tTest$tstn.a: Create $method database." + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test0$tstn.db + set env NULL + } else { + set testfile test0$tstn.db + incr eindex + set env [lindex $args $eindex] + } + set t1 $testdir/t1 + cleanup $testdir $env + + set oflags "-create -truncate -mode 0644 $rflags $omethod $args" + if { [is_record_based $method] == 0 && [is_rbtree $method] != 1 } { + append oflags " -dup" + } + set db [eval {berkdb_open_noerr} $oflags $testfile] + error_check_good dbopen [is_valid_db $db] TRUE + + set dbc_u [$db cursor] + error_check_good db:cursor [is_substr $dbc_u $db] 1 + + set nkeys 10 + puts "\tTest$tstn.b: Fill page with $nkeys small key/data pairs." + for { set i 1 } { $i <= $nkeys } { incr i } { + set ret [$db put $key$i $data$i] + error_check_good dbput:$i $ret 0 + if { $i == 1 } { + for {set j 0} { $j < [expr $nkeys / 2]} {incr j} { + set ret [$db put $key$i DUPLICATE$j] + error_check_good dbput:dup:$j $ret 0 + } + } + } + + # DBC GET + puts "\tTest$tstn.c: Test dbc->get interfaces..." + set i 0 + foreach flag { current first last next prev nextdup} { + puts "\t\t...dbc->get($flag)" + catch {$dbc_u get -$flag} ret + error_check_good dbc:get:$flag [is_substr $errorCode EINVAL] 1 + } + + foreach flag { set set_range get_both} { + puts "\t\t...dbc->get($flag)" + if { [string compare $flag get_both] == 0} { + catch {$dbc_u get -$flag $key$i data0} ret + } else { + catch {$dbc_u get -$flag $key$i} ret + } + error_check_good dbc:get:$flag [is_substr $errorCode EINVAL] 1 + } + + puts "\t\t...dbc->get(current, partial)" + catch {$dbc_u get -current -partial {0 0}} ret + error_check_good dbc:get:partial [is_substr $errorCode EINVAL] 1 + + puts "\t\t...dbc->get(current, rmw)" + catch {$dbc_u get -rmw -current } ret + error_check_good dbc_get:rmw [is_substr $errorCode EINVAL] 1 + + puts "\tTest$tstn.d: Test dbc->put interface..." + # partial...depends on another + foreach flag { after before current keyfirst keylast } { + puts "\t\t...dbc->put($flag)" + if { [string match key* $flag] == 1 } { + if { [is_record_based $method] == 1 } { + # keyfirst/keylast not allowed in recno + puts "\t\t...Skipping dbc->put($flag) for $method." + continue + } else { + # keyfirst/last should succeed + puts "\t\t...dbc->put($flag)...should succeed for $method" + error_check_good dbcput:$flag \ + [$dbc_u put -$flag $key$i data0] 0 + + # now uninitialize cursor + error_check_good dbc_close [$dbc_u close] 0 + set dbc_u [$db cursor] + error_check_good \ + db_cursor [is_substr $dbc_u $db] 1 + } + } elseif { [string compare $flag before ] == 0 || + [string compare $flag after ] == 0 } { + if { [is_record_based $method] == 0 && + [is_rbtree $method] == 0} { + set ret [$dbc_u put -$flag data0] + error_check_good "$dbc_u:put:-$flag" $ret 0 + } elseif { $renum == 1 } { + # Renumbering recno will return a record number + set currecno \ + [lindex [lindex [$dbc_u get -current] 0] 0] + set ret [$dbc_u put -$flag data0] + if { [string compare $flag after] == 0 } { + error_check_good "$dbc_u put $flag" \ + $ret [expr $currecno + 1] + } else { + error_check_good "$dbc_u put $flag" \ + $ret $currecno + } + } else { + puts "\t\tSkipping $flag for $method" + } + } else { + set ret [$dbc_u put -$flag data0] + error_check_good "$dbc_u:put:-$flag" $ret 0 + } + } + # and partial + puts "\t\t...dbc->put(partial)" + catch {$dbc_u put -partial {0 0} $key$i $data$i} ret + error_check_good dbc_put:partial [is_substr $errorCode EINVAL] 1 + + # XXX dbc->dup, db->join (dbc->get join_item) + # dbc del + puts "\tTest$tstn.e: Test dbc->del interface." + catch {$dbc_u del} ret + error_check_good dbc_del [is_substr $errorCode EINVAL] 1 + + error_check_good dbc_close [$dbc_u close] 0 + error_check_good db_close [$db close] 0 + + puts "\tTest$tstn complete." +} diff --git a/db/test/test050.tcl b/db/test/test050.tcl new file mode 100644 index 000000000..4a2d8c8fd --- /dev/null +++ b/db/test/test050.tcl @@ -0,0 +1,191 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test050.tcl,v 11.15 2000/08/25 14:21:57 sue Exp $ +# +# Test050: Overwrite test of small/big key/data with cursor checks for RECNO +proc test050 { method args } { + global alphabet + global errorInfo + global errorCode + source ./include.tcl + + set tstn 050 + + set args [convert_args $method $args] + set omethod [convert_method $method] + + if { [is_rrecno $method] != 1 } { + puts "Test$tstn skipping for method $method." + return + } + + puts "\tTest$tstn:\ + Overwrite test with cursor and small/big key/data ($method)." + + set data "data" + set txn "" + set flags "" + + puts "\tTest$tstn: Create $method database." + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test0$tstn.db + set env NULL + } else { + set testfile test0$tstn.db + incr eindex + set env [lindex $args $eindex] + } + set t1 $testdir/t1 + cleanup $testdir $env + + set oflags "-create -truncate -mode 0644 $args $omethod" + set db [eval {berkdb_open_noerr} $oflags $testfile] + error_check_good dbopen [is_valid_db $db] TRUE + + # open curs to db + set dbc [$db cursor] + error_check_good db_cursor [is_substr $dbc $db] 1 + + # keep nkeys even + set nkeys 20 + + # Fill page w/ small key/data pairs + # + puts "\tTest$tstn: Fill page with $nkeys small key/data pairs." + for { set i 1 } { $i <= $nkeys } { incr i } { + set ret [$db put $i [chop_data $method $data$i]] + error_check_good dbput $ret 0 + } + + # get db order of keys + for {set i 0; set ret [$dbc get -first]} { [llength $ret] != 0} { \ + set ret [$dbc get -next]} { + set key_set($i) [lindex [lindex $ret 0] 0] + set data_set($i) [lindex [lindex $ret 0] 1] + incr i + } + + # verify ordering: should be unnecessary, but hey, why take chances? + # key_set is zero indexed but keys start at 1 + for {set i 0} { $i < $nkeys } {incr i} { + error_check_good \ + verify_order:$i $key_set($i) [pad_data $method [expr $i+1]] + } + + puts "\tTest$tstn.a: Inserts before/after by cursor." + puts "\t\tTest$tstn.a.1:\ + Insert with uninitialized cursor (should fail)." + error_check_good dbc_close [$dbc close] 0 + set dbc [$db cursor] + error_check_good db_cursor [is_substr $dbc $db] 1 + catch {$dbc put -before DATA1} ret + error_check_good dbc_put:before:uninit [is_substr $errorCode EINVAL] 1 + + catch {$dbc put -after DATA2} ret + error_check_good dbc_put:after:uninit [is_substr $errorCode EINVAL] 1 + + puts "\t\tTest$tstn.a.2: Insert with deleted cursor (should succeed)." + set ret [$dbc get -first] + error_check_bad dbc_get:first [llength $ret] 0 + error_check_good dbc_del [$dbc del] 0 + set ret [$dbc put -current DATAOVER1] + error_check_good dbc_put:current:deleted $ret 0 + + puts "\t\tTest$tstn.a.3: Insert by cursor before cursor (DB_BEFORE)." + set currecno [lindex [lindex [$dbc get -current] 0] 0] + set ret [$dbc put -before DATAPUTBEFORE] + error_check_good dbc_put:before $ret $currecno + set old1 [$dbc get -next] + error_check_bad dbc_get:next [llength $old1] 0 + error_check_good \ + dbc_get:next(compare) [lindex [lindex $old1 0] 1] DATAOVER1 + + puts "\t\tTest$tstn.a.4: Insert by cursor after cursor (DB_AFTER)." + set ret [$dbc get -first] + error_check_bad dbc_get:first [llength $ret] 0 + error_check_good dbc_get:first [lindex [lindex $ret 0] 1] DATAPUTBEFORE + set currecno [lindex [lindex [$dbc get -current] 0] 0] + set ret [$dbc put -after DATAPUTAFTER] + error_check_good dbc_put:after $ret [expr $currecno + 1] + set ret [$dbc get -prev] + error_check_bad dbc_get:prev [llength $ret] 0 + error_check_good \ + dbc_get:prev [lindex [lindex $ret 0] 1] DATAPUTBEFORE + + puts "\t\tTest$tstn.a.5: Verify that all keys have been renumbered." + # should be $nkeys + 2 keys, starting at 1 + for {set i 1; set ret [$dbc get -first]} { \ + $i <= $nkeys && [llength $ret] != 0 } {\ + incr i; set ret [$dbc get -next]} { + error_check_good check_renumber $i [lindex [lindex $ret 0] 0] + } + + # tested above + + puts "\tTest$tstn.b: Overwrite tests (cursor and key)." + # For the next part of the test, we need a db with no dups to test + # overwrites + # + # we should have ($nkeys + 2) keys, ordered: + # DATAPUTBEFORE, DATAPUTAFTER, DATAOVER1, data1, ..., data$nkeys + # + # Prepare cursor on item + # + set ret [$dbc get -first] + error_check_bad dbc_get:first [llength $ret] 0 + + # Prepare unique big/small values for an initial + # and an overwrite set of data + set databig DATA_BIG_[repeat alphabet 250] + set datasmall DATA_SMALL + + # Now, we want to overwrite data: + # by key and by cursor + # 1. small by small + # 2. small by big + # 3. big by small + # 4. big by big + # + set i 0 + # Do all overwrites for key and cursor + foreach type { by_key by_cursor } { + incr i + puts "\tTest$tstn.b.$i: Overwrites $type." + foreach pair { {small small} \ + {small big} {big small} {big big} } { + # put in initial type + set data $data[lindex $pair 0] + set ret [$dbc put -current $data] + error_check_good dbc_put:curr:init:($pair) $ret 0 + + # Now, try to overwrite: dups not supported in this db + if { [string compare $type by_key] == 0 } { + puts "\t\tTest$tstn.b.$i:\ + Overwrite:($pair):$type" + set ret [$db put \ + 1 OVER$pair$data[lindex $pair 1]] + error_check_good dbput:over:($pair) $ret 0 + } else { + # This is a cursor overwrite + puts "\t\tTest$tstn.b.$i:\ + Overwrite:($pair) by cursor." + set ret [$dbc put \ + -current OVER$pair$data[lindex $pair 1]] + error_check_good dbcput:over:($pair) $ret 0 + } + } ;# foreach pair + } ;# foreach type key/cursor + + puts "\tTest$tstn.c: Cleanup and close cursor." + error_check_good dbc_close [$dbc close] 0 + error_check_good db_close [$db close] 0 + + puts "\tTest$tstn complete." +} diff --git a/db/test/test051.tcl b/db/test/test051.tcl new file mode 100644 index 000000000..6994526e2 --- /dev/null +++ b/db/test/test051.tcl @@ -0,0 +1,191 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test051.tcl,v 11.14 2000/08/25 14:21:57 sue Exp $ +# +# Test51: +# Test of the fixed recno method. +# 0. Test various flags (legal and illegal) to open +# 1. Test partial puts where dlen != size (should fail) +# 2. Partial puts for existent record -- replaces at beg, mid, and +# end of record, as well as full replace +# +proc test051 { method { args "" } } { + global fixed_len + global errorInfo + global errorCode + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + + puts "Test051: Test of the fixed length records." + if { [is_fixed_length $method] != 1 } { + puts "Test051: skipping for method $method" + return + } + + # Create the database and open the dictionary + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test051.db + set testfile1 $testdir/test051a.db + set env NULL + } else { + set testfile test051.db + set testfile1 test051a.db + incr eindex + set env [lindex $args $eindex] + } + cleanup $testdir $env + set oflags "-create -truncate -mode 0644 $args" + + # Test various flags (legal and illegal) to open + puts "\tTest051.a: Test correct flag behavior on open." + set errorCode NONE + foreach f { "-dup" "-dup -dupsort" "-recnum" } { + puts "\t\tTest051.a: Test flag $f" + error_check_good dbopen:flagtest:catch \ + [catch {set db \ + [eval {berkdb_open_noerr} $oflags $f $omethod \ + $testfile]} ret] 1 + error_check_good \ + dbopen:flagtest:$f [is_substr $errorCode EINVAL] 1 + set errorCode NONE + } + set f "-renumber" + puts "\t\tTest051.a: Test $f" + if { [is_frecno $method] == 1 } { + set db [eval {berkdb_open} $oflags $f $omethod $testfile] + error_check_good dbopen:flagtest:$f [is_valid_db $db] TRUE + $db close + } else { + error_check_good \ + dbopen:flagtest:catch [catch {set db [eval \ + {berkdb_open_noerr} $oflags $f \ + $omethod $testfile]} ret] 1 + error_check_good \ + dbopen:flagtest:$f [is_substr $errorCode EINVAL] 1 + } + + + # Test partial puts where dlen != size (should fail) + # it is an error to specify a partial put w/ different + # dlen and size in fixed length recno/queue + set key 1 + set data "" + set test_char "a" + + set db [eval {berkdb_open_noerr} $oflags $omethod $testfile1] + error_check_good dbopen [is_valid_db $db] TRUE + + puts "\tTest051.b: Partial puts with dlen != size." + foreach dlen { 1 16 20 32 } { + foreach doff { 0 10 20 32 } { + # dlen < size + puts "\t\tTest051.e: dlen: $dlen, doff: $doff, \ + size: [expr $dlen+1]" + set data [repeat $test_char [expr $dlen + 1]] + error_check_good catch:put 1 [catch {$db \ + put -partial [list $doff $dlen] $key $data} ret] + # + # We don't get back the server error string just + # the result. + # + if { $eindex == -1 } { + error_check_good "dbput:partial: dlen < size" \ + [is_substr $errorInfo "Length improper"] 1 + } else { + error_check_good "dbput:partial: dlen < size" \ + [is_substr $errorCode "EINVAL"] 1 + } + + # dlen > size + puts "\t\tTest051.e: dlen: $dlen, doff: $doff, \ + size: [expr $dlen-1]" + set data [repeat $test_char [expr $dlen - 1]] + error_check_good catch:put 1 [catch {$db \ + put -partial [list $doff $dlen] $key $data} ret] + if { $eindex == -1 } { + error_check_good "dbput:partial: dlen > size" \ + [is_substr $errorInfo "Length improper"] 1 + } else { + error_check_good "dbput:partial: dlen < size" \ + [is_substr $errorCode "EINVAL"] 1 + } + } + } + + $db close + + # Partial puts for existent record -- replaces at beg, mid, and + # end of record, as well as full replace + puts "\tTest051.f: Partial puts within existent record." + set db [eval {berkdb_open} $oflags $omethod $testfile] + error_check_good dbopen [is_valid_db $db] TRUE + + puts "\t\tTest051.f: First try a put and then a full replace." + set data [repeat "a" $fixed_len] + + set ret [$db put 1 $data] + error_check_good dbput $ret 0 + error_check_good dbget $data [lindex [lindex [$db get -recno 1] 0] 1] + + set data [repeat "b" $fixed_len] + set ret [$db put -partial [list 0 $fixed_len] 1 $data] + error_check_good dbput $ret 0 + error_check_good dbget $data [lindex [lindex [$db get -recno 1] 0] 1] + + set data "InitialData" + set pdata "PUT" + set dlen [string length $pdata] + set ilen [string length $data] + set mid [expr $ilen/2] + + # put initial data + set key 0 + + set offlist [list 0 $mid [expr $ilen -1] [expr $fixed_len - $dlen]] + puts "\t\tTest051.g: Now replace at different offsets ($offlist)." + foreach doff $offlist { + incr key + set ret [$db put $key $data] + error_check_good dbput:init $ret 0 + + puts "\t\t Test051.g: Replace at offset $doff." + set ret [$db put -partial [list $doff $dlen] $key $pdata] + error_check_good dbput:partial $ret 0 + + if { $doff == 0} { + set beg "" + set end [string range $data $dlen $ilen] + } else { + set beg [string range $data 0 [expr $doff - 1]] + set end [string range $data [expr $doff + $dlen] $ilen] + } + if { $doff > $ilen } { + # have to put padding between record and inserted + # string + set newdata [format %s%s $beg $end] + set diff [expr $doff - $ilen] + set nlen [string length $newdata] + set newdata [binary \ + format a[set nlen]x[set diff]a$dlen $newdata $pdata] + } else { + set newdata [make_fixed_length \ + frecno [format %s%s%s $beg $pdata $end]] + } + set ret [$db get -recno $key] + error_check_good compare($newdata,$ret) \ + [binary_compare [lindex [lindex $ret 0] 1] $newdata] 0 + } + + $db close + + puts "\tTest051 complete." +} diff --git a/db/test/test052.tcl b/db/test/test052.tcl new file mode 100644 index 000000000..820c99a2b --- /dev/null +++ b/db/test/test052.tcl @@ -0,0 +1,254 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test052.tcl,v 11.10 2000/10/06 19:29:52 krinsky Exp $ +# +# Test52 +# Renumbering recno test. +proc test052 { method args } { + global alphabet + global errorInfo + global errorCode + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + + puts "Test052: Test of renumbering recno." + if { [is_rrecno $method] != 1} { + puts "Test052: skipping for method $method." + return + } + + set data "data" + set txn "" + set flags "" + + puts "\tTest052: Create $method database." + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test052.db + set env NULL + } else { + set testfile test052.db + incr eindex + set env [lindex $args $eindex] + } + set t1 $testdir/t1 + cleanup $testdir $env + + set oflags "-create -truncate -mode 0644 $args $omethod" + set db [eval {berkdb_open} $oflags $testfile] + error_check_good dbopen [is_valid_db $db] TRUE + + # open curs to db + set dbc [$db cursor] + error_check_good db_cursor [is_substr $dbc $db] 1 + + # keep nkeys even + set nkeys 20 + + # Fill page w/ small key/data pairs + puts "\tTest052: Fill page with $nkeys small key/data pairs." + for { set i 1 } { $i <= $nkeys } { incr i } { + set ret [$db put $i $data$i] + error_check_good dbput $ret 0 + } + + # get db order of keys + for {set i 1; set ret [$dbc get -first]} { [llength $ret] != 0} { \ + set ret [$dbc get -next]} { + set keys($i) [lindex [lindex $ret 0] 0] + set darray($i) [lindex [lindex $ret 0] 1] + incr i + } + + puts "\tTest052: Deletes by key." + puts "\t Test052.a: Get data with SET, then delete before cursor." + # get key in middle of page, call this the nth set curr to it + set i [expr $nkeys/2] + set k $keys($i) + set ret [$dbc get -set $k] + error_check_bad dbc_get:set [llength $ret] 0 + error_check_good dbc_get:set [lindex [lindex $ret 0] 1] $darray($i) + + # delete by key before current + set i [incr i -1] + error_check_good db_del:before [$db del $keys($i)] 0 + # with renumber, current's data should be constant, but key==--key + set i [incr i +1] + error_check_good dbc:data \ + [lindex [lindex [$dbc get -current] 0] 1] $darray($i) + error_check_good dbc:keys \ + [lindex [lindex [$dbc get -current] 0] 0] $keys([expr $nkeys/2 - 1]) + + puts "\t Test052.b: Delete cursor item by key." + set i [expr $nkeys/2 ] + + set ret [$dbc get -set $keys($i)] + error_check_bad dbc:get [llength $ret] 0 + error_check_good dbc:get:curs [lindex [lindex $ret 0] 1] \ + $darray([expr $i + 1]) + error_check_good db_del:curr [$db del $keys($i)] 0 + set ret [$dbc get -current] + + # After a delete, cursor should return DB_NOTFOUND. + error_check_good dbc:get:key [llength [lindex [lindex $ret 0] 0]] 0 + error_check_good dbc:get:data [llength [lindex [lindex $ret 0] 1]] 0 + + # And the item after the cursor should now be + # key: $nkeys/2, data: $nkeys/2 + 2 + set ret [$dbc get -next] + error_check_bad dbc:getnext [llength $ret] 0 + error_check_good dbc:getnext:data \ + [lindex [lindex $ret 0] 1] $darray([expr $i + 2]) + error_check_good dbc:getnext:keys \ + [lindex [lindex $ret 0] 0] $keys($i) + + puts "\t Test052.c: Delete item after cursor." + # should be { keys($nkeys/2), darray($nkeys/2 + 2) } + set i [expr $nkeys/2] + # deleting data for key after current (key $nkeys/2 + 1) + error_check_good db_del [$db del $keys([expr $i + 1])] 0 + + # current should be constant + set ret [$dbc get -current] + error_check_bad dbc:get:current [llength $ret] 0 + error_check_good dbc:get:keys [lindex [lindex $ret 0] 0] \ + $keys($i) + error_check_good dbc:get:data [lindex [lindex $ret 0] 1] \ + $darray([expr $i + 2]) + + puts "\tTest052: Deletes by cursor." + puts "\t Test052.d: Delete, do DB_NEXT." + set i 1 + set ret [$dbc get -first] + error_check_bad dbc_get:first [llength $ret] 0 + error_check_good dbc_get:first [lindex [lindex $ret 0] 1] $darray($i) + error_check_good dbc_del [$dbc del] 0 + set ret [$dbc get -current] + error_check_bad dbc_get:current [llength $ret] 0 + error_check_good dbc:getcurrent:key \ + [llength [lindex [lindex $ret 0] 0]] 0 + error_check_good dbc:getcurrent:data \ + [llength [lindex [lindex $ret 0] 1]] 0 + + set ret [$dbc get -next] + error_check_bad dbc_get:next [llength $ret] 0 + error_check_good dbc:get:curs \ + [lindex [lindex $ret 0] 1] $darray([expr $i + 1]) + error_check_good dbc:get:keys \ + [lindex [lindex $ret 0] 0] $keys($i) + + # Move one more forward, so we're not on the first item. + error_check_bad dbc:getnext [llength [$dbc get -next]] 0 + + puts "\t Test052.e: Delete, do DB_PREV." + error_check_good dbc:del [$dbc del] 0 + set ret [$dbc get -current] + error_check_bad dbc:get:curr [llength $ret] 0 + error_check_good dbc:getcurrent:key \ + [llength [lindex [lindex $ret 0] 0]] 0 + error_check_good dbc:getcurrent:data \ + [llength [lindex [lindex $ret 0] 1]] 0 + + # next should now reference the record that was previously after + # old current + set ret [$dbc get -next] + error_check_bad get:next [llength $ret] 0 + error_check_good dbc:get:next:data \ + [lindex [lindex $ret 0] 1] $darray([expr $i + 3]) + error_check_good dbc:get:next:keys \ + [lindex [lindex $ret 0] 0] $keys([expr $i + 1]) + + set ret [$dbc get -prev] + error_check_bad dbc:get:curr [llength $ret] 0 + error_check_good dbc:get:curr:compare \ + [lindex [lindex $ret 0] 1] $darray([expr $i + 1]) + error_check_good dbc:get:curr:keys \ + [lindex [lindex $ret 0] 0] $keys($i) + + # The rest of the test was written with the old rrecno semantics, + # which required a separate c_del(CURRENT) test; to leave + # the database in the expected state, we now delete the first item. + set ret [$dbc get -first] + error_check_bad getfirst [llength $ret] 0 + error_check_good delfirst [$dbc del] 0 + + puts "\tTest052: Inserts." + puts "\t Test052.g: Insert before (DB_BEFORE)." + set i 1 + set ret [$dbc get -first] + error_check_bad dbc:get:first [llength $ret] 0 + error_check_good dbc_get:first \ + [lindex [lindex $ret 0] 0] $keys($i) + error_check_good dbc_get:first:data \ + [lindex [lindex $ret 0] 1] $darray([expr $i + 3]) + + set ret [$dbc put -before $darray($i)] + # should return new key, which should be $keys($i) + error_check_good dbc_put:before $ret $keys($i) + # cursor should adjust to point to new item + set ret [$dbc get -current] + error_check_bad dbc_get:curr [llength $ret] 0 + error_check_good dbc_put:before:keys \ + [lindex [lindex $ret 0] 0] $keys($i) + error_check_good dbc_put:before:data \ + [lindex [lindex $ret 0] 1] $darray($i) + + set ret [$dbc get -next] + error_check_bad dbc_get:next [llength $ret] 0 + error_check_good dbc_get:next:compare \ + $ret [list [list $keys([expr $i + 1]) $darray([expr $i + 3])]] + set ret [$dbc get -prev] + error_check_bad dbc_get:prev [llength $ret] 0 + + puts "\t Test052.h: Insert by cursor after (DB_AFTER)." + set i [incr i] + set ret [$dbc put -after $darray($i)] + # should return new key, which should be $keys($i) + error_check_good dbcput:after $ret $keys($i) + # cursor should reference new item + set ret [$dbc get -current] + error_check_good dbc:get:current:keys \ + [lindex [lindex $ret 0] 0] $keys($i) + error_check_good dbc:get:current:data \ + [lindex [lindex $ret 0] 1] $darray($i) + + # items after curs should be adjusted + set ret [$dbc get -next] + error_check_bad dbc:get:next [llength $ret] 0 + error_check_good dbc:get:next:compare \ + $ret [list [list $keys([expr $i + 1]) $darray([expr $i + 2])]] + + puts "\t Test052.i: Insert (overwrite) current item (DB_CURRENT)." + set i 1 + set ret [$dbc get -first] + error_check_bad dbc_get:first [llength $ret] 0 + # choose a datum that is not currently in db + set ret [$dbc put -current $darray([expr $i + 2])] + error_check_good dbc_put:curr $ret 0 + # curs should be on new item + set ret [$dbc get -current] + error_check_bad dbc_get:current [llength $ret] 0 + error_check_good dbc_get:curr:keys \ + [lindex [lindex $ret 0] 0] $keys($i) + error_check_good dbc_get:curr:data \ + [lindex [lindex $ret 0] 1] $darray([expr $i + 2]) + + set ret [$dbc get -next] + error_check_bad dbc_get:next [llength $ret] 0 + set i [incr i] + error_check_good dbc_get:next \ + $ret [list [list $keys($i) $darray($i)]] + + error_check_good dbc_close [$dbc close] 0 + error_check_good db_close [$db close] 0 + + puts "\tTest052 complete." +} diff --git a/db/test/test053.tcl b/db/test/test053.tcl new file mode 100644 index 000000000..e3a908c90 --- /dev/null +++ b/db/test/test053.tcl @@ -0,0 +1,194 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test053.tcl,v 11.12 2000/12/11 17:24:55 sue Exp $ +# +# Test53: test of the DB_REVSPLITOFF flag in the btree and +# Btree-w-recnum methods +proc test053 { method args } { + global alphabet + global errorCode + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + + puts "\tTest053: Test of cursor stability across btree splits." + if { [is_btree $method] != 1 && [is_rbtree $method] != 1 } { + puts "Test053: skipping for method $method." + return + } + + set pgindex [lsearch -exact $args "-pagesize"] + if { $pgindex != -1 } { + puts "Test053: skipping for specific pagesizes" + return + } + + set txn "" + set flags "" + + puts "\tTest053.a: Create $omethod $args database." + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test053.db + set env NULL + } else { + set testfile test053.db + incr eindex + set env [lindex $args $eindex] + } + set t1 $testdir/t1 + cleanup $testdir $env + + set oflags \ + "-create -truncate -revsplitoff -pagesize 1024 $args $omethod" + set db [eval {berkdb_open} $oflags $testfile] + error_check_good dbopen [is_valid_db $db] TRUE + + set nkeys 8 + set npages 15 + + # We want to create a db with npages leaf pages, and have each page + # be near full with keys that we can predict. We set pagesize above + # to 1024 bytes, it should breakdown as follows (per page): + # + # ~20 bytes overhead + # key: ~4 bytes overhead, XXX0N where X is a letter, N is 0-9 + # data: ~4 bytes overhead, + 100 bytes + # + # then, with 8 keys/page we should be just under 1024 bytes + puts "\tTest053.b: Create $npages pages with $nkeys pairs on each." + set keystring [string range $alphabet 0 [expr $npages -1]] + set data [repeat DATA 22] + for { set i 0 } { $i < $npages } {incr i } { + set key "" + set keyroot \ + [repeat [string toupper [string range $keystring $i $i]] 3] + set key_set($i) $keyroot + for {set j 0} { $j < $nkeys} {incr j} { + if { $j < 10 } { + set key [set keyroot]0$j + } else { + set key $keyroot$j + } + set ret [$db put $key $data] + error_check_good dbput $ret 0 + } + } + + puts "\tTest053.c: Check page count." + error_check_good page_count:check \ + [is_substr [$db stat] "{Leaf pages} $npages"] 1 + + puts "\tTest053.d: Delete all but one key per page." + for {set i 0} { $i < $npages } {incr i } { + for {set j 1} { $j < $nkeys } {incr j } { + set ret [$db del $key_set($i)0$j] + error_check_good dbdel $ret 0 + } + } + puts "\tTest053.e: Check to make sure all pages are still there." + error_check_good page_count:check \ + [is_substr [$db stat] "{Leaf pages} $npages"] 1 + + set dbc [$db cursor] + error_check_good db:cursor [is_substr $dbc $db] 1 + + # walk cursor through tree forward, backward. + # delete one key, repeat + for {set i 0} { $i < $npages} {incr i} { + puts -nonewline \ + "\tTest053.f.$i: Walk curs through tree: forward..." + for { set j $i; set curr [$dbc get -first]} { $j < $npages} { \ + incr j; set curr [$dbc get -next]} { + error_check_bad dbc:get:next [llength $curr] 0 + error_check_good dbc:get:keys \ + [lindex [lindex $curr 0] 0] $key_set($j)00 + } + puts -nonewline "backward..." + for { set j [expr $npages - 1]; set curr [$dbc get -last]} { \ + $j >= $i } { \ + set j [incr j -1]; set curr [$dbc get -prev]} { + error_check_bad dbc:get:prev [llength $curr] 0 + error_check_good dbc:get:keys \ + [lindex [lindex $curr 0] 0] $key_set($j)00 + } + puts "complete." + + if { [is_rbtree $method] == 1} { + puts "\t\tTest053.f.$i:\ + Walk through tree with record numbers." + for {set j 1} {$j <= [expr $npages - $i]} {incr j} { + set curr [$db get -recno $j] + error_check_bad \ + db_get:recno:$j [llength $curr] 0 + error_check_good db_get:recno:keys:$j \ + [lindex [lindex $curr 0] 0] \ + $key_set([expr $j + $i - 1])00 + } + } + puts "\tTest053.g.$i:\ + Delete single key ([expr $npages - $i] keys left)." + set ret [$db del $key_set($i)00] + error_check_good dbdel $ret 0 + error_check_good del:check \ + [llength [$db get $key_set($i)00]] 0 + } + + # end for loop, verify db_notfound + set ret [$dbc get -first] + error_check_good dbc:get:verify [llength $ret] 0 + + # loop: until single key restored on each page + for {set i 0} { $i < $npages} {incr i} { + puts "\tTest053.i.$i:\ + Restore single key ([expr $i + 1] keys in tree)." + set ret [$db put $key_set($i)00 $data] + error_check_good dbput $ret 0 + + puts -nonewline \ + "\tTest053.j: Walk cursor through tree: forward..." + for { set j 0; set curr [$dbc get -first]} { $j <= $i} {\ + incr j; set curr [$dbc get -next]} { + error_check_bad dbc:get:next [llength $curr] 0 + error_check_good dbc:get:keys \ + [lindex [lindex $curr 0] 0] $key_set($j)00 + } + error_check_good dbc:get:next [llength $curr] 0 + + puts -nonewline "backward..." + for { set j $i; set curr [$dbc get -last]} { \ + $j >= 0 } { \ + set j [incr j -1]; set curr [$dbc get -prev]} { + error_check_bad dbc:get:prev [llength $curr] 0 + error_check_good dbc:get:keys \ + [lindex [lindex $curr 0] 0] $key_set($j)00 + } + puts "complete." + error_check_good dbc:get:prev [llength $curr] 0 + + if { [is_rbtree $method] == 1} { + puts "\t\tTest053.k.$i:\ + Walk through tree with record numbers." + for {set j 1} {$j <= [expr $i + 1]} {incr j} { + set curr [$db get -recno $j] + error_check_bad \ + db_get:recno:$j [llength $curr] 0 + error_check_good db_get:recno:keys:$j \ + [lindex [lindex $curr 0] 0] \ + $key_set([expr $j - 1])00 + } + } + } + + error_check_good dbc_close [$dbc close] 0 + error_check_good db_close [$db close] 0 + + puts "Test053 complete." +} diff --git a/db/test/test054.tcl b/db/test/test054.tcl new file mode 100644 index 000000000..7308f9956 --- /dev/null +++ b/db/test/test054.tcl @@ -0,0 +1,369 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test054.tcl,v 11.15 2000/08/25 14:21:57 sue Exp $ +# +# Test054: +# +# This test checks for cursor maintenance in the presence of deletes. +# There are N different scenarios to tests: +# 1. No duplicates. Cursor A deletes a key, do a GET for the key. +# 2. No duplicates. Cursor is positioned right before key K, Delete K, +# do a next on the cursor. +# 3. No duplicates. Cursor is positioned on key K, do a regular delete of K. +# do a current get on K. +# 4. Repeat 3 but do a next instead of current. +# +# 5. Duplicates. Cursor A is on the first item of a duplicate set, A +# does a delete. Then we do a non-cursor get. +# 6. Duplicates. Cursor A is in a duplicate set and deletes the item. +# do a delete of the entire Key. Test cursor current. +# 7. Continue last test and try cursor next. +# 8. Duplicates. Cursor A is in a duplicate set and deletes the item. +# Cursor B is in the same duplicate set and deletes a different item. +# Verify that the cursor is in the right place. +# 9. Cursors A and B are in the place in the same duplicate set. A deletes +# its item. Do current on B. +# 10. Continue 8 and do a next on B. +proc test054 { method args } { + global errorInfo + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + + append args " -create -truncate -mode 0644" + puts "Test054 ($method $args):\ + interspersed cursor and normal operations" + if { [is_record_based $method] == 1 } { + puts "Test054 skipping for method $method" + return + } + + # Create the database and open the dictionary + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test054.db + set env NULL + } else { + set testfile test054.db + incr eindex + set env [lindex $args $eindex] + } + cleanup $testdir $env + + set flags "" + set txn "" + + puts "\tTest054.a: No Duplicate Tests" + set db [eval {berkdb_open} $args {$omethod $testfile}] + error_check_good db_open:nodup [is_valid_db $db] TRUE + + set curs [eval {$db cursor} $txn] + error_check_good curs_open:nodup [is_substr $curs $db] 1 + + # Put three keys in the database + for { set key 1 } { $key <= 3 } {incr key} { + set r [eval {$db put} $txn $flags {$key datum$key}] + error_check_good put $r 0 + } + + # Retrieve keys sequentially so we can figure out their order + set i 1 + for {set d [$curs get -first] } \ + {[llength $d] != 0 } \ + {set d [$curs get -next] } { + set key_set($i) [lindex [lindex $d 0] 0] + incr i + } + + # TEST CASE 1 + puts "\tTest054.a1: Delete w/cursor, regular get" + + # Now set the cursor on the middle on. + set r [$curs get -set $key_set(2)] + error_check_bad cursor_get:DB_SET [llength $r] 0 + set k [lindex [lindex $r 0] 0] + set d [lindex [lindex $r 0] 1] + error_check_good curs_get:DB_SET:key $k $key_set(2) + error_check_good curs_get:DB_SET:data $d datum$key_set(2) + + # Now do the delete + set r [eval {$curs del} $txn] + error_check_good curs_del $r 0 + + # Now do the get + set r [eval {$db get} $txn {$key_set(2)}] + error_check_good get_after_del [llength $r] 0 + + # Free up the cursor. + error_check_good cursor_close [eval {$curs close}] 0 + + # TEST CASE 2 + puts "\tTest054.a2: Cursor before K, delete K, cursor next" + + # Replace key 2 + set r [eval {$db put} $txn {$key_set(2) datum$key_set(2)}] + error_check_good put $r 0 + + # Open and position cursor on first item. + set curs [eval {$db cursor} $txn] + error_check_good curs_open:nodup [is_substr $curs $db] 1 + + # Retrieve keys sequentially so we can figure out their order + set i 1 + for {set d [eval {$curs get} -first] } \ + {[llength $d] != 0 } \ + {set d [$curs get -nextdup] } { + set key_set($i) [lindex [lindex $d 0] 0] + incr i + } + + set r [eval {$curs get} -set {$key_set(1)} ] + error_check_bad cursor_get:DB_SET [llength $r] 0 + set k [lindex [lindex $r 0] 0] + set d [lindex [lindex $r 0] 1] + error_check_good curs_get:DB_SET:key $k $key_set(1) + error_check_good curs_get:DB_SET:data $d datum$key_set(1) + + # Now delete (next item) $key_set(2) + error_check_good \ + db_del:$key_set(2) [eval {$db del} $txn {$key_set(2)}] 0 + + # Now do next on cursor + set r [$curs get -next] + error_check_bad cursor_get:DB_NEXT [llength $r] 0 + set k [lindex [lindex $r 0] 0] + set d [lindex [lindex $r 0] 1] + error_check_good curs_get:DB_NEXT:key $k $key_set(3) + error_check_good curs_get:DB_NEXT:data $d datum$key_set(3) + + # TEST CASE 3 + puts "\tTest054.a3: Cursor on K, delete K, cursor current" + + # delete item 3 + error_check_good \ + db_del:$key_set(3) [eval {$db del} $txn {$key_set(3)}] 0 + # NEEDS TO COME BACK IN, BUG CHECK + set ret [$curs get -current] + error_check_good current_after_del $ret [list [list [] []]] + error_check_good cursor_close [$curs close] 0 + + puts "\tTest054.a4: Cursor on K, delete K, cursor next" + + # Restore keys 2 and 3 + set r [eval {$db put} $txn {$key_set(2) datum$key_set(2)}] + error_check_good put $r 0 + set r [eval {$db put} $txn {$key_set(3) datum$key_set(3)}] + error_check_good put $r 0 + + # Create the new cursor and put it on 1 + set curs [eval {$db cursor} $txn] + error_check_good curs_open:nodup [is_substr $curs $db] 1 + set r [$curs get -set $key_set(1)] + error_check_bad cursor_get:DB_SET [llength $r] 0 + set k [lindex [lindex $r 0] 0] + set d [lindex [lindex $r 0] 1] + error_check_good curs_get:DB_SET:key $k $key_set(1) + error_check_good curs_get:DB_SET:data $d datum$key_set(1) + + # Delete 2 + error_check_good \ + db_del:$key_set(2) [eval {$db del} $txn {$key_set(2)}] 0 + + # Now do next on cursor + set r [$curs get -next] + error_check_bad cursor_get:DB_NEXT [llength $r] 0 + set k [lindex [lindex $r 0] 0] + set d [lindex [lindex $r 0] 1] + error_check_good curs_get:DB_NEXT:key $k $key_set(3) + error_check_good curs_get:DB_NEXT:data $d datum$key_set(3) + + # Close cursor + error_check_good curs_close [$curs close] 0 + error_check_good db_close [$db close] 0 + + # Now get ready for duplicate tests + + if { [is_rbtree $method] == 1 } { + puts "Test054: skipping remainder of test for method $method." + return + } + + puts "\tTest054.b: Duplicate Tests" + append args " -dup" + set db [eval {berkdb_open} $args {$omethod $testfile}] + error_check_good db_open:dup [is_valid_db $db] TRUE + + set curs [eval {$db cursor} $txn] + error_check_good curs_open:dup [is_substr $curs $db] 1 + + # Put three keys in the database + for { set key 1 } { $key <= 3 } {incr key} { + set r [eval {$db put} $txn $flags {$key datum$key}] + error_check_good put $r 0 + } + + # Retrieve keys sequentially so we can figure out their order + set i 1 + for {set d [$curs get -first] } \ + {[llength $d] != 0 } \ + {set d [$curs get -nextdup] } { + set key_set($i) [lindex [lindex $d 0] 0] + incr i + } + + # Now put in a bunch of duplicates for key 2 + for { set d 1 } { $d <= 5 } {incr d} { + set r [eval {$db put} $txn $flags {$key_set(2) dup_$d}] + error_check_good dup:put $r 0 + } + + # TEST CASE 5 + puts "\tTest054.b1: Delete dup w/cursor on first item. Get on key." + + # Now set the cursor on the first of the duplicate set. + set r [eval {$curs get} -set {$key_set(2)}] + error_check_bad cursor_get:DB_SET [llength $r] 0 + set k [lindex [lindex $r 0] 0] + set d [lindex [lindex $r 0] 1] + error_check_good curs_get:DB_SET:key $k $key_set(2) + error_check_good curs_get:DB_SET:data $d datum$key_set(2) + + # Now do the delete + set r [$curs del] + error_check_good curs_del $r 0 + + # Now do the get + set r [eval {$db get} $txn {$key_set(2)}] + error_check_good get_after_del [lindex [lindex $r 0] 1] dup_1 + + # TEST CASE 6 + puts "\tTest054.b2: Now get the next duplicate from the cursor." + + # Now do next on cursor + set r [$curs get -nextdup] + error_check_bad cursor_get:DB_NEXT [llength $r] 0 + set k [lindex [lindex $r 0] 0] + set d [lindex [lindex $r 0] 1] + error_check_good curs_get:DB_NEXT:key $k $key_set(2) + error_check_good curs_get:DB_NEXT:data $d dup_1 + + # TEST CASE 3 + puts "\tTest054.b3: Two cursors in set; each delete different items" + + # Open a new cursor. + set curs2 [eval {$db cursor} $txn] + error_check_good curs_open [is_substr $curs2 $db] 1 + + # Set on last of duplicate set. + set r [$curs2 get -set $key_set(3)] + error_check_bad cursor_get:DB_SET [llength $r] 0 + set k [lindex [lindex $r 0] 0] + set d [lindex [lindex $r 0] 1] + error_check_good curs_get:DB_SET:key $k $key_set(3) + error_check_good curs_get:DB_SET:data $d datum$key_set(3) + + set r [$curs2 get -prev] + error_check_bad cursor_get:DB_PREV [llength $r] 0 + set k [lindex [lindex $r 0] 0] + set d [lindex [lindex $r 0] 1] + error_check_good curs_get:DB_PREV:key $k $key_set(2) + error_check_good curs_get:DB_PREV:data $d dup_5 + + # Delete the item at cursor 1 (dup_1) + error_check_good curs1_del [$curs del] 0 + + # Verify curs1 and curs2 + # current should fail + set ret [$curs get -current] + error_check_good \ + curs1_get_after_del $ret [list [list [] []]] + + set r [$curs2 get -current] + error_check_bad curs2_get [llength $r] 0 + set k [lindex [lindex $r 0] 0] + set d [lindex [lindex $r 0] 1] + error_check_good curs_get:DB_CURRENT:key $k $key_set(2) + error_check_good curs_get:DB_CURRENT:data $d dup_5 + + # Now delete the item at cursor 2 (dup_5) + error_check_good curs2_del [$curs2 del] 0 + + # Verify curs1 and curs2 + set ret [$curs get -current] + error_check_good curs1_get:del2 $ret [list [list [] []]] + + set ret [$curs2 get -current] + error_check_good curs2_get:del2 $ret [list [list [] []]] + + # Now verify that next and prev work. + + set r [$curs2 get -prev] + error_check_bad cursor_get:DB_PREV [llength $r] 0 + set k [lindex [lindex $r 0] 0] + set d [lindex [lindex $r 0] 1] + error_check_good curs_get:DB_PREV:key $k $key_set(2) + error_check_good curs_get:DB_PREV:data $d dup_4 + + set r [$curs get -next] + error_check_bad cursor_get:DB_NEXT [llength $r] 0 + set k [lindex [lindex $r 0] 0] + set d [lindex [lindex $r 0] 1] + error_check_good curs_get:DB_NEXT:key $k $key_set(2) + error_check_good curs_get:DB_NEXT:data $d dup_2 + + puts "\tTest054.b4: Two cursors same item, one delete, one get" + + # Move curs2 onto dup_2 + set r [$curs2 get -prev] + error_check_bad cursor_get:DB_PREV [llength $r] 0 + set k [lindex [lindex $r 0] 0] + set d [lindex [lindex $r 0] 1] + error_check_good curs_get:DB_PREV:key $k $key_set(2) + error_check_good curs_get:DB_PREV:data $d dup_3 + + set r [$curs2 get -prev] + error_check_bad cursor_get:DB_PREV [llength $r] 0 + set k [lindex [lindex $r 0] 0] + set d [lindex [lindex $r 0] 1] + error_check_good curs_get:DB_PREV:key $k $key_set(2) + error_check_good curs_get:DB_PREV:data $d dup_2 + + # delete on curs 1 + error_check_good curs1_del [$curs del] 0 + + # Verify gets on both 1 and 2 + set ret [$curs get -current] + error_check_good \ + curs1_get:deleted $ret [list [list [] []]] + set ret [$curs2 get -current] + error_check_good \ + curs2_get:deleted $ret [list [list [] []]] + + puts "\tTest054.b5: Now do a next on both cursors" + + set r [$curs get -next] + error_check_bad cursor_get:DB_NEXT [llength $r] 0 + set k [lindex [lindex $r 0] 0] + set d [lindex [lindex $r 0] 1] + error_check_good curs_get:DB_NEXT:key $k $key_set(2) + error_check_good curs_get:DB_NEXT:data $d dup_3 + + set r [$curs2 get -next] + error_check_bad cursor_get:DB_NEXT [llength $r] 0 + set k [lindex [lindex $r 0] 0] + set d [lindex [lindex $r 0] 1] + error_check_good curs_get:DB_NEXT:key $k $key_set(2) + error_check_good curs_get:DB_NEXT:data $d dup_3 + + # Close cursor + error_check_good curs_close [$curs close] 0 + error_check_good curs2_close [$curs2 close] 0 + error_check_good db_close [$db close] 0 +} diff --git a/db/test/test055.tcl b/db/test/test055.tcl new file mode 100644 index 000000000..fc5ce4e98 --- /dev/null +++ b/db/test/test055.tcl @@ -0,0 +1,118 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test055.tcl,v 11.11 2000/08/25 14:21:57 sue Exp $ +# +# Test055: +# This test checks basic cursor operations. +# There are N different scenarios to tests: +# 1. (no dups) Set cursor, retrieve current. +# 2. (no dups) Set cursor, retrieve next. +# 3. (no dups) Set cursor, retrieve prev. +proc test055 { method args } { + global errorInfo + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + + puts "Test055: $method interspersed cursor and normal operations" + + # Create the database and open the dictionary + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test055.db + set env NULL + } else { + set testfile test055.db + incr eindex + set env [lindex $args $eindex] + } + cleanup $testdir $env + + set flags "" + set txn "" + + puts "\tTest055.a: No duplicates" + set db [eval {berkdb_open -create -truncate -mode 0644 $omethod } \ + $args {$testfile}] + error_check_good db_open:nodup [is_valid_db $db] TRUE + + set curs [eval {$db cursor} $txn] + error_check_good curs_open:nodup [is_substr $curs $db] 1 + + # Put three keys in the database + for { set key 1 } { $key <= 3 } {incr key} { + set r [eval {$db put} $txn $flags {$key datum$key}] + error_check_good put $r 0 + } + + # Retrieve keys sequentially so we can figure out their order + set i 1 + for {set d [$curs get -first] } { [llength $d] != 0 } {\ + set d [$curs get -next] } { + set key_set($i) [lindex [lindex $d 0] 0] + incr i + } + + # TEST CASE 1 + puts "\tTest055.a1: Set cursor, retrieve current" + + # Now set the cursor on the middle on. + set r [$curs get -set $key_set(2)] + error_check_bad cursor_get:DB_SET [llength $r] 0 + set k [lindex [lindex $r 0] 0] + set d [lindex [lindex $r 0] 1] + error_check_good curs_get:DB_SET:key $k $key_set(2) + error_check_good \ + curs_get:DB_SET:data $d [pad_data $method datum$key_set(2)] + + # Now retrieve current + set r [$curs get -current] + error_check_bad cursor_get:DB_CURRENT [llength $r] 0 + set k [lindex [lindex $r 0] 0] + set d [lindex [lindex $r 0] 1] + error_check_good curs_get:DB_CURRENT:key $k $key_set(2) + error_check_good \ + curs_get:DB_CURRENT:data $d [pad_data $method datum$key_set(2)] + + # TEST CASE 2 + puts "\tTest055.a2: Set cursor, retrieve previous" + set r [$curs get -prev] + error_check_bad cursor_get:DB_PREV [llength $r] 0 + set k [lindex [lindex $r 0] 0] + set d [lindex [lindex $r 0] 1] + error_check_good curs_get:DB_PREV:key $k $key_set(1) + error_check_good \ + curs_get:DB_PREV:data $d [pad_data $method datum$key_set(1)] + + #TEST CASE 3 + puts "\tTest055.a2: Set cursor, retrieve next" + + # Now set the cursor on the middle on. + set r [$curs get -set $key_set(2)] + error_check_bad cursor_get:DB_SET [llength $r] 0 + set k [lindex [lindex $r 0] 0] + set d [lindex [lindex $r 0] 1] + error_check_good curs_get:DB_SET:key $k $key_set(2) + error_check_good \ + curs_get:DB_SET:data $d [pad_data $method datum$key_set(2)] + + # Now retrieve next + set r [$curs get -next] + error_check_bad cursor_get:DB_NEXT [llength $r] 0 + set k [lindex [lindex $r 0] 0] + set d [lindex [lindex $r 0] 1] + error_check_good curs_get:DB_NEXT:key $k $key_set(3) + error_check_good \ + curs_get:DB_NEXT:data $d [pad_data $method datum$key_set(3)] + + # Close cursor and database. + error_check_good curs_close [$curs close] 0 + error_check_good db_close [$db close] 0 +} diff --git a/db/test/test056.tcl b/db/test/test056.tcl new file mode 100644 index 000000000..ade3890c3 --- /dev/null +++ b/db/test/test056.tcl @@ -0,0 +1,145 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test056.tcl,v 11.13 2000/08/25 14:21:57 sue Exp $ +# +# Test056 +# Check if deleting a key when a cursor is on a duplicate of that key works. +proc test056 { method args } { + global errorInfo + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + + append args " -create -truncate -mode 0644 -dup " + if { [is_record_based $method] == 1 || [is_rbtree $method] } { + puts "Test056: skipping for method $method" + return + } + puts "Test056: $method delete of key in presence of cursor" + + # Create the database and open the dictionary + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test056.db + set env NULL + } else { + set testfile test056.db + incr eindex + set env [lindex $args $eindex] + } + cleanup $testdir $env + + set flags "" + set txn "" + + set db [eval {berkdb_open} $args {$omethod $testfile}] + error_check_good db_open:dup [is_valid_db $db] TRUE + + set curs [eval {$db cursor} $txn] + error_check_good curs_open:dup [is_substr $curs $db] 1 + + puts "\tTest056.a: Key delete with cursor on duplicate." + # Put three keys in the database + for { set key 1 } { $key <= 3 } {incr key} { + set r [eval {$db put} $txn $flags {$key datum$key}] + error_check_good put $r 0 + } + + # Retrieve keys sequentially so we can figure out their order + set i 1 + for {set d [$curs get -first] } { [llength $d] != 0 } { + set d [$curs get -next] } { + set key_set($i) [lindex [lindex $d 0] 0] + incr i + } + + # Now put in a bunch of duplicates for key 2 + for { set d 1 } { $d <= 5 } {incr d} { + set r [eval {$db put} $txn $flags {$key_set(2) dup_$d}] + error_check_good dup:put $r 0 + } + + # Now put the cursor on a duplicate of key 2 + + # Now set the cursor on the first of the duplicate set. + set r [$curs get -set $key_set(2)] + error_check_bad cursor_get:DB_SET [llength $r] 0 + set k [lindex [lindex $r 0] 0] + set d [lindex [lindex $r 0] 1] + error_check_good curs_get:DB_SET:key $k $key_set(2) + error_check_good curs_get:DB_SET:data $d datum$key_set(2) + + # Now do two nexts + set r [$curs get -next] + error_check_bad cursor_get:DB_NEXT [llength $r] 0 + set k [lindex [lindex $r 0] 0] + set d [lindex [lindex $r 0] 1] + error_check_good curs_get:DB_NEXT:key $k $key_set(2) + error_check_good curs_get:DB_NEXT:data $d dup_1 + + set r [$curs get -next] + error_check_bad cursor_get:DB_NEXT [llength $r] 0 + set k [lindex [lindex $r 0] 0] + set d [lindex [lindex $r 0] 1] + error_check_good curs_get:DB_NEXT:key $k $key_set(2) + error_check_good curs_get:DB_NEXT:data $d dup_2 + + # Now do the delete + set r [eval {$db del} $txn $flags {$key_set(2)}] + error_check_good delete $r 0 + + # Now check the get current on the cursor. + set ret [$curs get -current] + error_check_good curs_after_del $ret [list [list [] []]] + + # Now check that the rest of the database looks intact. There + # should be only two keys, 1 and 3. + + set r [$curs get -first] + error_check_bad cursor_get:DB_FIRST [llength $r] 0 + set k [lindex [lindex $r 0] 0] + set d [lindex [lindex $r 0] 1] + error_check_good curs_get:DB_FIRST:key $k $key_set(1) + error_check_good curs_get:DB_FIRST:data $d datum$key_set(1) + + set r [$curs get -next] + error_check_bad cursor_get:DB_NEXT [llength $r] 0 + set k [lindex [lindex $r 0] 0] + set d [lindex [lindex $r 0] 1] + error_check_good curs_get:DB_NEXT:key $k $key_set(3) + error_check_good curs_get:DB_NEXT:data $d datum$key_set(3) + + set r [$curs get -next] + error_check_good cursor_get:DB_NEXT [llength $r] 0 + + puts "\tTest056.b:\ + Cursor delete of first item, followed by cursor FIRST" + # Set to beginning + set r [$curs get -first] + error_check_bad cursor_get:DB_FIRST [llength $r] 0 + set k [lindex [lindex $r 0] 0] + set d [lindex [lindex $r 0] 1] + error_check_good curs_get:DB_FIRST:key $k $key_set(1) + error_check_good curs_get:DB_FIRST:data $d datum$key_set(1) + + # Now do delete + error_check_good curs_del [$curs del] 0 + + # Now do DB_FIRST + set r [$curs get -first] + error_check_bad cursor_get:DB_FIRST [llength $r] 0 + set k [lindex [lindex $r 0] 0] + set d [lindex [lindex $r 0] 1] + error_check_good curs_get:DB_FIRST:key $k $key_set(3) + error_check_good curs_get:DB_FIRST:data $d datum$key_set(3) + + error_check_good curs_close [$curs close] 0 + error_check_good db_close [$db close] 0 +} diff --git a/db/test/test057.tcl b/db/test/test057.tcl new file mode 100644 index 000000000..1dc350e32 --- /dev/null +++ b/db/test/test057.tcl @@ -0,0 +1,225 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test057.tcl,v 11.17 2000/08/25 14:21:57 sue Exp $ +# +# Test057: +# Check if we handle the case where we delete a key with the cursor on it +# and then add the same key. The cursor should not get the new item +# returned, but the item shouldn't disappear. +# Run test tests, one where the overwriting put is done with a put and +# one where it's done with a cursor put. +proc test057 { method args } { + global errorInfo + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + + append args " -create -truncate -mode 0644 -dup " + if { [is_record_based $method] == 1 || [is_rbtree $method] == 1 } { + puts "Test057: skipping for method $method" + return + } + puts "Test057: $method delete and replace in presence of cursor." + + # Create the database and open the dictionary + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test057.db + set env NULL + } else { + set testfile test057.db + incr eindex + set env [lindex $args $eindex] + } + cleanup $testdir $env + + set flags "" + set txn "" + + set db [eval {berkdb_open} $args {$omethod $testfile}] + error_check_good dbopen:dup [is_valid_db $db] TRUE + + set curs [eval {$db cursor} $txn] + error_check_good curs_open:dup [is_substr $curs $db] 1 + + puts "\tTest057.a: Set cursor, delete cursor, put with key." + # Put three keys in the database + for { set key 1 } { $key <= 3 } {incr key} { + set r [eval {$db put} $txn $flags {$key datum$key}] + error_check_good put $r 0 + } + + # Retrieve keys sequentially so we can figure out their order + set i 1 + for {set d [$curs get -first] } {[llength $d] != 0 } {\ + set d [$curs get -next] } { + set key_set($i) [lindex [lindex $d 0] 0] + incr i + } + + # Now put in a bunch of duplicates for key 2 + for { set d 1 } { $d <= 5 } {incr d} { + set r [eval {$db put} $txn $flags {$key_set(2) dup_$d}] + error_check_good dup:put $r 0 + } + + # Now put the cursor on key 1 + + # Now set the cursor on the first of the duplicate set. + set r [$curs get -set $key_set(1)] + error_check_bad cursor_get:DB_SET [llength $r] 0 + set k [lindex [lindex $r 0] 0] + set d [lindex [lindex $r 0] 1] + error_check_good curs_get:DB_SET:key $k $key_set(1) + error_check_good curs_get:DB_SET:data $d datum$key_set(1) + + # Now do the delete + set r [$curs del] + error_check_good delete $r 0 + + # Now check the get current on the cursor. + error_check_good curs_get:del [$curs get -current] [list [list [] []]] + + # Now do a put on the key + set r [eval {$db put} $txn $flags {$key_set(1) new_datum$key_set(1)}] + error_check_good put $r 0 + + # Do a get + set r [eval {$db get} $txn {$key_set(1)}] + error_check_good get [lindex [lindex $r 0] 1] new_datum$key_set(1) + + # Recheck cursor + error_check_good curs_get:deleted [$curs get -current] [list [list [] []]] + + # Move cursor and see if we get the key. + set r [$curs get -first] + error_check_bad cursor_get:DB_FIRST [llength $r] 0 + set k [lindex [lindex $r 0] 0] + set d [lindex [lindex $r 0] 1] + error_check_good curs_get:DB_FIRST:key $k $key_set(1) + error_check_good curs_get:DB_FIRST:data $d new_datum$key_set(1) + + puts "\tTest057.b: Set two cursor on a key, delete one, overwrite other" + set curs2 [eval {$db cursor} $txn] + error_check_good curs2_open [is_substr $curs2 $db] 1 + + # Set both cursors on the 4rd key + set r [$curs get -set $key_set(3)] + error_check_bad cursor_get:DB_SET [llength $r] 0 + set k [lindex [lindex $r 0] 0] + set d [lindex [lindex $r 0] 1] + error_check_good curs_get:DB_SET:key $k $key_set(3) + error_check_good curs_get:DB_SET:data $d datum$key_set(3) + + set r [$curs2 get -set $key_set(3)] + error_check_bad cursor2_get:DB_SET [llength $r] 0 + set k [lindex [lindex $r 0] 0] + set d [lindex [lindex $r 0] 1] + error_check_good curs2_get:DB_SET:key $k $key_set(3) + error_check_good curs2_get:DB_SET:data $d datum$key_set(3) + + # Now delete through cursor 1 + error_check_good curs1_del [$curs del] 0 + + # Verify gets on both 1 and 2 + error_check_good curs_get:deleted [$curs get -current] \ + [list [list [] []]] + error_check_good curs_get:deleted [$curs2 get -current] \ + [list [list [] []]] + + # Now do a replace through cursor 2 + set pflags "-current" + if {[is_hash $method] == 1} { + error_check_good curs1_get_after_del [is_substr \ + [$curs2 put $pflags new_datum$key_set(3)] "DB_NOTFOUND"] 1 + + # Gets fail + error_check_good curs1_get:deleted \ + [$curs get -current] \ + [list [list [] []]] + error_check_good curs2_get:deleted \ + [$curs get -current] \ + [list [list [] []]] + } else { + # btree only, recno is skipped this test + set ret [$curs2 put $pflags new_datum$key_set(3)] + error_check_good curs_replace $ret 0 + } + + # Gets fail + #error_check_good curs1_get:deleted [catch {$curs get -current} r] 1 + #error_check_good curs1_get_after_del \ + [is_substr $errorInfo "DB_KEYEMPTY"] 1 + #error_check_good curs2_get:deleted [catch {$curs2 get -current} r] 1 + #error_check_good curs2_get_after_del \ + [is_substr $errorInfo "DB_KEYEMPTY"] 1 + + puts "\tTest057.c:\ + Set two cursors on a dup, delete one, overwrite other" + + # Set both cursors on the 2nd duplicate of key 2 + set r [$curs get -set $key_set(2)] + error_check_bad cursor_get:DB_SET [llength $r] 0 + set k [lindex [lindex $r 0] 0] + set d [lindex [lindex $r 0] 1] + error_check_good curs_get:DB_SET:key $k $key_set(2) + error_check_good curs_get:DB_SET:data $d datum$key_set(2) + + set r [$curs get -next] + error_check_bad cursor_get:DB_NEXT [llength $r] 0 + set k [lindex [lindex $r 0] 0] + set d [lindex [lindex $r 0] 1] + error_check_good curs_get:DB_NEXT:key $k $key_set(2) + error_check_good curs_get:DB_NEXT:data $d dup_1 + + set r [$curs2 get -set $key_set(2)] + error_check_bad cursor2_get:DB_SET [llength $r] 0 + set k [lindex [lindex $r 0] 0] + set d [lindex [lindex $r 0] 1] + error_check_good curs2_get:DB_SET:key $k $key_set(2) + error_check_good curs2_get:DB_SET:data $d datum$key_set(2) + + set r [$curs2 get -next] + error_check_bad cursor2_get:DB_NEXT [llength $r] 0 + set k [lindex [lindex $r 0] 0] + set d [lindex [lindex $r 0] 1] + error_check_good curs2_get:DB_NEXT:key $k $key_set(2) + error_check_good curs2_get:DB_NEXT:data $d dup_1 + + # Now delete through cursor 1 + error_check_good curs1_del [$curs del] 0 + + # Verify gets on both 1 and 2 + error_check_good curs_get:deleted [$curs get -current] \ + [list [list [] []]] + error_check_good curs_get:deleted [$curs2 get -current] \ + [list [list [] []]] + + # Now do a replace through cursor 2 -- this will work on btree but + # not on hash + if {[is_hash $method] == 1} { + error_check_good hash_replace \ + [is_substr [$curs2 put -current new_dup_1] "DB_NOTFOUND"] 1 + } else { + error_check_good curs_replace [$curs2 put -current new_dup_1] 0 + } + + # Both gets should fail + #error_check_good curs1_get:deleted [catch {$curs get -current} r] 1 + #error_check_good curs1_get_after_del \ + [is_substr $errorInfo "DB_KEYEMPTY"] 1 + #error_check_good curs2_get:deleted [catch {$curs2 get -current} r] 1 + #error_check_good curs2_get_after_del \ + [is_substr $errorInfo "DB_KEYEMPTY"] 1 + + error_check_good curs2_close [$curs2 close] 0 + error_check_good curs_close [$curs close] 0 + error_check_good db_close [$db close] 0 +} diff --git a/db/test/test058.tcl b/db/test/test058.tcl new file mode 100644 index 000000000..00870a6b5 --- /dev/null +++ b/db/test/test058.tcl @@ -0,0 +1,99 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test058.tcl,v 11.14 2000/08/25 14:21:57 sue Exp $ +# +proc test058 { method args } { + source ./include.tcl + + # + # If we are using an env, then skip this test. It needs its own. + set eindex [lsearch -exact $args "-env"] + if { $eindex != -1 } { + incr eindex + set env [lindex $args $eindex] + puts "Test058 skipping for env $env" + return + } + set args [convert_args $method $args] + set omethod [convert_method $method] + + if { [is_record_based $method] == 1 || [is_rbtree $method] == 1 } { + puts "Test058: skipping for method $method" + return + } + puts "Test058: $method delete dups after inserting after duped key." + + # environment + env_cleanup $testdir + set eflags "-create -txn -home $testdir" + set env [eval {berkdb env} $eflags] + error_check_good env [is_valid_env $env] TRUE + + # db open + set flags "-create -mode 0644 -dup -env $env $args" + set db [eval {berkdb_open} $flags $omethod "test058.db"] + error_check_good dbopen [is_valid_db $db] TRUE + + set tn "" + set tid "" + set tn [$env txn] + set tflags "-txn $tn" + + puts "\tTest058.a: Adding 10 duplicates" + # Add a bunch of dups + for { set i 0 } { $i < 10 } {incr i} { + set ret \ + [eval {$db put} $tflags {doghouse $i"DUPLICATE_DATA_VALUE"}] + error_check_good db_put $ret 0 + } + + puts "\tTest058.b: Adding key after duplicates" + # Now add one more key/data AFTER the dup set. + set ret [eval {$db put} $tflags {zebrahouse NOT_A_DUP}] + error_check_good db_put $ret 0 + + error_check_good txn_commit [$tn commit] 0 + + set tn [$env txn] + error_check_good txnbegin [is_substr $tn $env] 1 + set tflags "-txn $tn" + + # Now delete everything + puts "\tTest058.c: Deleting duplicated key" + set ret [eval {$db del} $tflags {doghouse}] + error_check_good del $ret 0 + + # Now reput everything + set pad \ + abcdefghijklmnopqrtsuvabcdefghijklmnopqrtsuvabcdefghijklmnopqrtsuvabcdefghijklmnopqrtsuvabcdefghijklmnopqrtsuvabcdefghijklmnopqrtsuvabcdefghijklmnopqrtsuvabcdefghijklmnopqrtsuvabcdefghijklmnopqrtsuvabcdefghijklmnopqrtsuv + + puts "\tTest058.d: Reputting duplicates with big data vals" + for { set i 0 } { $i < 10 } {incr i} { + set ret [eval {$db put} \ + $tflags {doghouse $i"DUPLICATE_DATA_VALUE"$pad}] + error_check_good db_put $ret 0 + } + error_check_good txn_commit [$tn commit] 0 + + # Check duplicates for order + set dbc [$db cursor] + error_check_good db_cursor [is_substr $dbc $db] 1 + + puts "\tTest058.e: Verifying that duplicates are in order." + set i 0 + for { set ret [$dbc get -set doghouse] } \ + {$i < 10 && [llength $ret] != 0} \ + { set ret [$dbc get -nextdup] } { + set data [lindex [lindex $ret 0] 1] + error_check_good \ + duplicate_value $data $i"DUPLICATE_DATA_VALUE"$pad + incr i + } + + error_check_good dbc_close [$dbc close] 0 + error_check_good db_close [$db close] 0 + reset_env $env +} diff --git a/db/test/test059.tcl b/db/test/test059.tcl new file mode 100644 index 000000000..f9988c4e2 --- /dev/null +++ b/db/test/test059.tcl @@ -0,0 +1,128 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test059.tcl,v 11.12 2000/08/25 14:21:57 sue Exp $ +# +# Test059: +# Make sure that we handle retrieves of zero-length data items correctly. +# The following ops, should allow a partial data retrieve of 0-length. +# db_get +# db_cget FIRST, NEXT, LAST, PREV, CURRENT, SET, SET_RANGE +# +proc test059 { method args } { + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + + puts "Test059: $method 0-length partial data retrieval" + + # Create the database and open the dictionary + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test059.db + set env NULL + } else { + set testfile test059.db + incr eindex + set env [lindex $args $eindex] + } + cleanup $testdir $env + + set pflags "" + set gflags "" + set txn "" + set count 0 + + if { [is_record_based $method] == 1 } { + append gflags " -recno" + } + + puts "\tTest059.a: Populate a database" + set oflags "-create -truncate -mode 0644 $omethod $args $testfile" + set db [eval {berkdb_open} $oflags] + error_check_good db_create [is_substr $db db] 1 + + # Put ten keys in the database + for { set key 1 } { $key <= 10 } {incr key} { + set r [eval {$db put} $txn $pflags {$key datum$key}] + error_check_good put $r 0 + } + + # Retrieve keys sequentially so we can figure out their order + set i 1 + set curs [$db cursor] + error_check_good db_curs [is_substr $curs $db] 1 + + for {set d [$curs get -first] } { [llength $d] != 0 } { + set d [$curs get -next] } { + set key_set($i) [lindex [lindex $d 0] 0] + incr i + } + + puts "\tTest059.a: db get with 0 partial length retrieve" + + # Now set the cursor on the middle one. + set ret [eval {$db get -partial {0 0}} $gflags {$key_set(5)}] + error_check_bad db_get_0 [llength $ret] 0 + + puts "\tTest059.a: db cget FIRST with 0 partial length retrieve" + set ret [$curs get -first -partial {0 0}] + set data [lindex [lindex $ret 0] 1] + set key [lindex [lindex $ret 0] 0] + error_check_good key_check_first $key $key_set(1) + error_check_good db_cget_first [string length $data] 0 + + puts "\tTest059.b: db cget NEXT with 0 partial length retrieve" + set ret [$curs get -next -partial {0 0}] + set data [lindex [lindex $ret 0] 1] + set key [lindex [lindex $ret 0] 0] + error_check_good key_check_next $key $key_set(2) + error_check_good db_cget_next [string length $data] 0 + + puts "\tTest059.c: db cget LAST with 0 partial length retrieve" + set ret [$curs get -last -partial {0 0}] + set data [lindex [lindex $ret 0] 1] + set key [lindex [lindex $ret 0] 0] + error_check_good key_check_last $key $key_set(10) + error_check_good db_cget_last [string length $data] 0 + + puts "\tTest059.d: db cget PREV with 0 partial length retrieve" + set ret [$curs get -prev -partial {0 0}] + set data [lindex [lindex $ret 0] 1] + set key [lindex [lindex $ret 0] 0] + error_check_good key_check_prev $key $key_set(9) + error_check_good db_cget_prev [string length $data] 0 + + puts "\tTest059.e: db cget CURRENT with 0 partial length retrieve" + set ret [$curs get -current -partial {0 0}] + set data [lindex [lindex $ret 0] 1] + set key [lindex [lindex $ret 0] 0] + error_check_good key_check_current $key $key_set(9) + error_check_good db_cget_current [string length $data] 0 + + puts "\tTest059.f: db cget SET with 0 partial length retrieve" + set ret [$curs get -set -partial {0 0} $key_set(7)] + set data [lindex [lindex $ret 0] 1] + set key [lindex [lindex $ret 0] 0] + error_check_good key_check_set $key $key_set(7) + error_check_good db_cget_set [string length $data] 0 + + if {[is_btree $method] == 1} { + puts "\tTest059.g:\ + db cget SET_RANGE with 0 partial length retrieve" + set ret [$curs get -set_range -partial {0 0} $key_set(5)] + set data [lindex [lindex $ret 0] 1] + set key [lindex [lindex $ret 0] 0] + error_check_good key_check_set $key $key_set(5) + error_check_good db_cget_set [string length $data] 0 + } + + error_check_good curs_close [$curs close] 0 + error_check_good db_close [$db close] 0 +} diff --git a/db/test/test060.tcl b/db/test/test060.tcl new file mode 100644 index 000000000..7f7cc71f0 --- /dev/null +++ b/db/test/test060.tcl @@ -0,0 +1,53 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test060.tcl,v 11.6 2000/08/25 14:21:57 sue Exp $ +# +# Test060: Test of the DB_EXCL flag to DB->open. +# 1) Attempt to open and create a nonexistent database; verify success. +# 2) Attempt to reopen it; verify failure. +proc test060 { method args } { + global errorCode + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + + puts "Test060: $method ($args) Test of the DB_EXCL flag to DB->open" + + # Set the database location and make sure the db doesn't exist yet + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test060.db + set env NULL + } else { + set testfile test060.db + incr eindex + set env [lindex $args $eindex] + } + cleanup $testdir $env + + # Create the database and check success + puts "\tTest060.a: open and close non-existent file with DB_EXCL" + set db [eval {berkdb_open \ + -create -excl -mode 0644} $args {$omethod $testfile}] + error_check_good dbopen:excl [is_valid_db $db] TRUE + + # Close it and check success + error_check_good db_close [$db close] 0 + + # Try to open it again, and make sure the open fails + puts "\tTest060.b: open it again with DB_EXCL and make sure it fails" + set errorCode NONE + error_check_good open:excl:catch [catch { \ + set db [eval {berkdb_open_noerr \ + -create -excl -mode 0644} $args {$omethod $testfile}] + } ret ] 1 + + error_check_good dbopen:excl [is_substr $errorCode EEXIST] 1 +} diff --git a/db/test/test061.tcl b/db/test/test061.tcl new file mode 100644 index 000000000..c3187268e --- /dev/null +++ b/db/test/test061.tcl @@ -0,0 +1,215 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test061.tcl,v 11.12 2000/10/27 13:23:56 sue Exp $ +# +# Test061: Test of transaction abort and commit for in-memory databases. +# a) Put + abort: verify absence of data +# b) Put + commit: verify presence of data +# c) Overwrite + abort: verify that data is unchanged +# d) Overwrite + commit: verify that data has changed +# e) Delete + abort: verify that data is still present +# f) Delete + commit: verify that data has been deleted +proc test061 { method args } { + global alphabet + global errorCode + source ./include.tcl + + # + # If we are using an env, then skip this test. It needs its own. + set eindex [lsearch -exact $args "-env"] + if { $eindex != -1 } { + incr eindex + set env [lindex $args $eindex] + puts "Test061 skipping for env $env" + return + } + set args [convert_args $method $args] + set omethod [convert_method $method] + if { [is_queueext $method] == 1} { + puts "Test061 skipping for method $method" + return + } + + puts "Test061: Transaction abort and commit test for in-memory data." + puts "Test061: $method $args" + + set key "key" + set data "data" + set otherdata "otherdata" + set txn "" + set flags "" + set gflags "" + + if { [is_record_based $method] == 1} { + set key 1 + set gflags " -recno" + } + + puts "\tTest061: Create environment and $method database." + env_cleanup $testdir + + # create environment + set eflags "-create -txn -home $testdir" + set dbenv [eval {berkdb env} $eflags] + error_check_good dbenv [is_valid_env $dbenv] TRUE + + # db open -- no file specified, in-memory database + set flags "-create $args $omethod" + set db [eval {berkdb_open -env} $dbenv $flags] + error_check_good dbopen [is_valid_db $db] TRUE + + # Here we go with the six test cases. Since we need to verify + # a different thing each time, and since we can't just reuse + # the same data if we're to test overwrite, we just + # plow through rather than writing some impenetrable loop code; + # each of the cases is only a few lines long, anyway. + + puts "\tTest061.a: put/abort" + + # txn_begin + set txn [$dbenv txn] + error_check_good txn_begin [is_valid_txn $txn $dbenv] TRUE + + # put a key + set ret [eval {$db put} -txn $txn {$key [chop_data $method $data]}] + error_check_good db_put $ret 0 + + # check for existence + set ret [eval {$db get} -txn $txn $gflags {$key}] + error_check_good get $ret [list [list $key [pad_data $method $data]]] + + # abort + error_check_good txn_abort [$txn abort] 0 + + # check for *non*-existence + set ret [eval {$db get} $gflags {$key}] + error_check_good get $ret {} + + puts "\tTest061.b: put/commit" + + # txn_begin + set txn [$dbenv txn] + error_check_good txn_begin [is_valid_txn $txn $dbenv] TRUE + + # put a key + set ret [eval {$db put} -txn $txn {$key [chop_data $method $data]}] + error_check_good db_put $ret 0 + + # check for existence + set ret [eval {$db get} -txn $txn $gflags {$key}] + error_check_good get $ret [list [list $key [pad_data $method $data]]] + + # commit + error_check_good txn_commit [$txn commit] 0 + + # check again for existence + set ret [eval {$db get} $gflags {$key}] + error_check_good get $ret [list [list $key [pad_data $method $data]]] + + puts "\tTest061.c: overwrite/abort" + + # txn_begin + set txn [$dbenv txn] + error_check_good txn_begin [is_valid_txn $txn $dbenv] TRUE + + # overwrite {key,data} with {key,otherdata} + set ret [eval {$db put} -txn $txn {$key [chop_data $method $otherdata]}] + error_check_good db_put $ret 0 + + # check for existence + set ret [eval {$db get} -txn $txn $gflags {$key}] + error_check_good get $ret \ + [list [list $key [pad_data $method $otherdata]]] + + # abort + error_check_good txn_abort [$txn abort] 0 + + # check that data is unchanged ($data not $otherdata) + set ret [eval {$db get} $gflags {$key}] + error_check_good get $ret [list [list $key [pad_data $method $data]]] + + puts "\tTest061.d: overwrite/commit" + + # txn_begin + set txn [$dbenv txn] + error_check_good txn_begin [is_valid_txn $txn $dbenv] TRUE + + # overwrite {key,data} with {key,otherdata} + set ret [eval {$db put} -txn $txn {$key [chop_data $method $otherdata]}] + error_check_good db_put $ret 0 + + # check for existence + set ret [eval {$db get} -txn $txn $gflags {$key}] + error_check_good get $ret \ + [list [list $key [pad_data $method $otherdata]]] + + # commit + error_check_good txn_commit [$txn commit] 0 + + # check that data has changed ($otherdata not $data) + set ret [eval {$db get} $gflags {$key}] + error_check_good get $ret \ + [list [list $key [pad_data $method $otherdata]]] + + puts "\tTest061.e: delete/abort" + + # txn_begin + set txn [$dbenv txn] + error_check_good txn_begin [is_valid_txn $txn $dbenv] TRUE + + # delete + set ret [eval {$db del} -txn $txn {$key}] + error_check_good db_put $ret 0 + + # check for nonexistence + set ret [eval {$db get} -txn $txn $gflags {$key}] + error_check_good get $ret {} + + # abort + error_check_good txn_abort [$txn abort] 0 + + # check for existence + set ret [eval {$db get} $gflags {$key}] + error_check_good get $ret \ + [list [list $key [pad_data $method $otherdata]]] + + puts "\tTest061.f: delete/commit" + + # txn_begin + set txn [$dbenv txn] + error_check_good txn_begin [is_valid_txn $txn $dbenv] TRUE + + # put a key + set ret [eval {$db del} -txn $txn {$key}] + error_check_good db_put $ret 0 + + # check for nonexistence + set ret [eval {$db get} -txn $txn $gflags {$key}] + error_check_good get $ret {} + + # commit + error_check_good txn_commit [$txn commit] 0 + + # check for continued nonexistence + set ret [eval {$db get} $gflags {$key}] + error_check_good get $ret {} + + # We're done; clean up. + error_check_good db_close [eval {$db close}] 0 + error_check_good env_close [eval {$dbenv close}] 0 + + # Now run db_recover and ensure that it runs cleanly. + puts "\tTest061.g: Running db_recover -h" + set ret [catch {exec $util_path/db_recover -h $testdir} res] + if { $ret != 0 } { + puts "FAIL: db_recover outputted $res" + } + error_check_good db_recover $ret 0 + + puts "\tTest061.h: Running db_recover -c -h" + set ret [catch {exec $util_path/db_recover -c -h $testdir} res] + error_check_good db_recover-c $ret 0 +} diff --git a/db/test/test062.tcl b/db/test/test062.tcl new file mode 100644 index 000000000..43a5e1d39 --- /dev/null +++ b/db/test/test062.tcl @@ -0,0 +1,125 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test062.tcl,v 11.13 2000/12/20 19:02:36 sue Exp $ +# +# DB Test 62: Test of partial puts onto duplicate pages. +# Insert the first 200 words into the dictionary 200 times each with +# self as key and :self as data. Use partial puts to +# append self again to data; verify correctness. +proc test062 { method {nentries 200} {ndups 200} {tnum 62} args } { + global alphabet + global rand_init + source ./include.tcl + + berkdb srand $rand_init + + set args [convert_args $method $args] + set omethod [convert_method $method] + + # Create the database and open the dictionary + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test0$tnum.db + set env NULL + } else { + set testfile test0$tnum.db + incr eindex + set env [lindex $args $eindex] + } + cleanup $testdir $env + + puts "Test0$tnum:\ + $method ($args) Partial puts and duplicates." + if { [is_record_based $method] == 1 || [is_rbtree $method] == 1 } { + puts "Test0$tnum skipping for method $omethod" + return + } + set db [eval {berkdb_open -create -truncate -mode 0644 \ + $omethod -dup} $args {$testfile} ] + error_check_good dbopen [is_valid_db $db] TRUE + set did [open $dict] + + set pflags "" + set gflags "" + set txn "" + set count 0 + + # Here is the loop where we put each key/data pair + puts "\tTest0$tnum.a: Put loop (initialize database)" + set dbc [eval {$db cursor} $txn] + error_check_good cursor_open [is_substr $dbc $db] 1 + while { [gets $did str] != -1 && $count < $nentries } { + for { set i 1 } { $i <= $ndups } { incr i } { + set pref \ + [string index $alphabet [berkdb random_int 0 25]] + set datastr $pref:$str + set ret [eval {$db put} \ + $txn $pflags {$str [chop_data $method $datastr]}] + error_check_good put $ret 0 + } + set keys($count) $str + + incr count + } + error_check_good cursor_close [$dbc close] 0 + close $did + + puts "\tTest0$tnum.b: Partial puts." + set dbc [eval {$db cursor} $txn] + error_check_good cursor_open [is_substr $dbc $db] 1 + + # Do a partial write to extend each datum in + # the regular db by the corresponding dictionary word. + # We have to go through each key's dup set using -set + # because cursors are not stable in the hash AM and we + # want to make sure we hit all the keys. + for { set i 0 } { $i < $count } { incr i } { + set key $keys($i) + for {set ret [$dbc get -set $key]} \ + {[llength $ret] != 0} \ + {set ret [$dbc get -nextdup]} { + + set k [lindex [lindex $ret 0] 0] + set orig_d [lindex [lindex $ret 0] 1] + set d [string range $orig_d 2 end] + set doff [expr [string length $d] + 2] + set dlen 0 + error_check_good data_and_key_sanity $d $k + + set ret [$dbc get -current] + error_check_good before_sanity \ + [lindex [lindex $ret 0] 0] \ + [string range [lindex [lindex $ret 0] 1] 2 end] + + error_check_good partial_put [eval {$dbc put -current \ + -partial [list $doff $dlen] $d}] 0 + + set ret [$dbc get -current] + error_check_good partial_put_correct \ + [lindex [lindex $ret 0] 1] $orig_d$d + } + } + + puts "\tTest0$tnum.c: Double-checking get loop." + # Double-check that each datum in the regular db has + # been appropriately modified. + + for {set ret [$dbc get -first]} \ + {[llength $ret] != 0} \ + {set ret [$dbc get -next]} { + + set k [lindex [lindex $ret 0] 0] + set d [lindex [lindex $ret 0] 1] + error_check_good modification_correct \ + [string range $d 2 end] [repeat $k 2] + } + + error_check_good dbc_close [$dbc close] 0 + error_check_good db_close [$db close] 0 +} diff --git a/db/test/test063.tcl b/db/test/test063.tcl new file mode 100644 index 000000000..2b9c4c4c7 --- /dev/null +++ b/db/test/test063.tcl @@ -0,0 +1,141 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test063.tcl,v 11.11 2000/08/25 14:21:58 sue Exp $ +# +# DB Test 63: Test that the DB_RDONLY flag is respected. +# Attempt to both DB->put and DBC->c_put into a database +# that has been opened DB_RDONLY, and check for failure. +proc test063 { method args } { + global errorCode + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + set tnum 63 + + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test0$tnum.db + set env NULL + } else { + set testfile test0$tnum.db + incr eindex + set env [lindex $args $eindex] + } + cleanup $testdir $env + + set key "key" + set data "data" + set key2 "another_key" + set data2 "more_data" + + set gflags "" + + if { [is_record_based $method] == 1 } { + set key "1" + set key2 "2" + append gflags " -recno" + } + + puts "Test0$tnum: $method ($args) DB_RDONLY test." + + # Create a test database. + puts "\tTest0$tnum.a: Creating test database." + set db [eval {berkdb_open_noerr -create -truncate -mode 0644} \ + $omethod $args $testfile] + error_check_good db_create [is_valid_db $db] TRUE + + # Put and get an item so it's nonempty. + set ret [eval {$db put} $key [chop_data $method $data]] + error_check_good initial_put $ret 0 + + set dbt [eval {$db get} $gflags $key] + error_check_good initial_get $dbt \ + [list [list $key [pad_data $method $data]]] + + error_check_good db_close [$db close] 0 + + if { $eindex == -1 } { + # Confirm that database is writable. If we are + # using an env (that may be remote on a server) + # we cannot do this check. + error_check_good writable [file writable $testfile] 1 + } + + puts "\tTest0$tnum.b: Re-opening DB_RDONLY and attempting to put." + + # Now open it read-only and make sure we can get but not put. + set db [eval {berkdb_open_noerr -rdonly} $args {$testfile}] + error_check_good db_open [is_valid_db $db] TRUE + + set dbt [eval {$db get} $gflags $key] + error_check_good db_get $dbt \ + [list [list $key [pad_data $method $data]]] + + set ret [catch {eval {$db put} $key2 [chop_data $method $data]} res] + error_check_good put_failed $ret 1 + error_check_good db_put_rdonly [is_substr $errorCode "EACCES"] 1 + + set errorCode "NONE" + + puts "\tTest0$tnum.c: Attempting cursor put." + + set dbc [$db cursor] + error_check_good cursor_create [is_valid_cursor $dbc $db] TRUE + + error_check_good cursor_set [$dbc get -first] $dbt + set ret [catch {eval {$dbc put} -current $data} res] + error_check_good c_put_failed $ret 1 + error_check_good dbc_put_rdonly [is_substr $errorCode "EACCES"] 1 + + set dbt [eval {$db get} $gflags $key2] + error_check_good db_get_key2 $dbt "" + + puts "\tTest0$tnum.d: Attempting ordinary delete." + + set errorCode "NONE" + set ret [catch {eval {$db del} $key} 1] + error_check_good del_failed $ret 1 + error_check_good db_del_rdonly [is_substr $errorCode "EACCES"] 1 + + set dbt [eval {$db get} $gflags $key] + error_check_good db_get_key $dbt \ + [list [list $key [pad_data $method $data]]] + + puts "\tTest0$tnum.e: Attempting cursor delete." + # Just set the cursor to the beginning; we don't care what's there... + # yet. + set dbt2 [$dbc get -first] + error_check_good db_get_first_key $dbt2 $dbt + set errorCode "NONE" + set ret [catch {$dbc del} res] + error_check_good c_del_failed $ret 1 + error_check_good dbc_del_rdonly [is_substr $errorCode "EACCES"] 1 + + set dbt2 [$dbc get -current] + error_check_good db_get_key $dbt2 $dbt + + puts "\tTest0$tnum.f: Close, reopen db; verify unchanged." + + error_check_good dbc_close [$dbc close] 0 + error_check_good db_close [$db close] 0 + + set db [eval {berkdb_open} $omethod $args $testfile] + error_check_good db_reopen [is_valid_db $db] TRUE + + set dbc [$db cursor] + error_check_good cursor_create [is_valid_cursor $dbc $db] TRUE + + error_check_good first_there [$dbc get -first] \ + [list [list $key [pad_data $method $data]]] + error_check_good nomore_there [$dbc get -next] "" + + error_check_good dbc_close [$dbc close] 0 + error_check_good db_close [$db close] 0 +} diff --git a/db/test/test064.tcl b/db/test/test064.tcl new file mode 100644 index 000000000..ad39f4b22 --- /dev/null +++ b/db/test/test064.tcl @@ -0,0 +1,62 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test064.tcl,v 11.8 2000/08/25 14:21:58 sue Exp $ +# +# DB Test 64: Test of DB->get_type +# Create a database of type specified by method. +# Make sure DB->get_type returns the right thing with both a +# normal and DB_UNKNOWN open. +proc test064 { method args } { + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + set tnum 64 + + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test0$tnum.db + set env NULL + } else { + set testfile test0$tnum.db + incr eindex + set env [lindex $args $eindex] + } + cleanup $testdir $env + + puts "Test0$tnum: $method ($args) DB->get_type test." + + # Create a test database. + puts "\tTest0$tnum.a: Creating test database of type $method." + set db [eval {berkdb_open -create -truncate -mode 0644} \ + $omethod $args $testfile] + error_check_good db_create [is_valid_db $db] TRUE + + error_check_good db_close [$db close] 0 + + puts "\tTest0$tnum.b: get_type after method specifier." + + set db [eval {berkdb_open} $omethod $args {$testfile}] + error_check_good db_open [is_valid_db $db] TRUE + + set type [$db get_type] + error_check_good get_type $type [string range $omethod 1 end] + + error_check_good db_close [$db close] 0 + + puts "\tTest0$tnum.c: get_type after DB_UNKNOWN." + + set db [eval {berkdb_open} $args $testfile] + error_check_good db_open [is_valid_db $db] TRUE + + set type [$db get_type] + error_check_good get_type $type [string range $omethod 1 end] + + error_check_good db_close [$db close] 0 +} diff --git a/db/test/test065.tcl b/db/test/test065.tcl new file mode 100644 index 000000000..5f236ebbd --- /dev/null +++ b/db/test/test065.tcl @@ -0,0 +1,146 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test065.tcl,v 11.8 2000/08/25 14:21:58 sue Exp $ +# +# DB Test 65: Test of DB->stat(DB_RECORDCOUNT) +proc test065 { method args } { + source ./include.tcl + global errorCode + global alphabet + + set args [convert_args $method $args] + set omethod [convert_method $method] + set tnum 65 + + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test0$tnum.db + set env NULL + } else { + set testfile test0$tnum.db + incr eindex + set env [lindex $args $eindex] + } + cleanup $testdir $env + + puts "Test0$tnum: $method ($args) DB->stat(DB_RECORDCOUNT) test." + + puts "\tTest0$tnum.a: Create database and check it while empty." + + set db [eval {berkdb_open_noerr -create -truncate -mode 0644} \ + $omethod $args $testfile] + error_check_good db_open [is_valid_db $db] TRUE + + set ret [catch {eval $db stat -recordcount} res] + + error_check_good db_close [$db close] 0 + + if { ([is_record_based $method] && ![is_queue $method]) \ + || [is_rbtree $method] } { + error_check_good recordcount_ok [lindex [lindex $res 0] 1] 0 + } else { + error_check_good \ + recordcount_notok [is_substr $errorCode "EINVAL"] 1 + puts "\tTest0$tnum: Test complete for method $method." + return + } + + # If we've got this far, we're on an access method for + # which DB_RECORDCOUNT makes sense. Thus, we no longer + # catch EINVALs, and no longer care about __db_errs. + set db [eval {berkdb_open -create -mode 0644} $omethod $args $testfile] + + puts "\tTest0$tnum.b: put 10000 keys." + + if { [is_record_based $method] } { + set gflags " -recno " + set keypfx "" + } else { + set gflags "" + set keypfx "key" + } + + set data [pad_data $method $alphabet] + + for { set ndx 1 } { $ndx <= 10000 } { incr ndx } { + set ret [eval {$db put} $keypfx$ndx $data] + error_check_good db_put $ret 0 + } + + set ret [$db stat -recordcount] + error_check_good \ + recordcount_after_puts [lindex [lindex $ret 0] 1] 10000 + + puts "\tTest0$tnum.c: delete 9000 keys." + for { set ndx 1 } { $ndx <= 9000 } { incr ndx } { + if { [is_rrecno $method] == 1 } { + # if we're renumbering, when we hit key 5001 we'll + # have deleted 5000 and we'll croak! So delete key + # 1, repeatedly. + set ret [eval {$db del} [concat $keypfx 1]] + } else { + set ret [eval {$db del} $keypfx$ndx] + } + error_check_good db_del $ret 0 + } + + set ret [$db stat -recordcount] + if { [is_rrecno $method] == 1 || [is_rbtree $method] == 1 } { + # We allow renumbering--thus the stat should return 1000 + error_check_good \ + recordcount_after_dels [lindex [lindex $ret 0] 1] 1000 + } else { + # No renumbering--no change in RECORDCOUNT! + error_check_good \ + recordcount_after_dels [lindex [lindex $ret 0] 1] 10000 + } + + puts "\tTest0$tnum.d: put 8000 new keys at the beginning." + for { set ndx 1 } { $ndx <= 8000 } {incr ndx } { + set ret [eval {$db put} $keypfx$ndx $data] + error_check_good db_put_beginning $ret 0 + } + + set ret [$db stat -recordcount] + if { [is_rrecno $method] == 1 } { + # With renumbering we're back up to 8000 + error_check_good \ + recordcount_after_dels [lindex [lindex $ret 0] 1] 8000 + } elseif { [is_rbtree $method] == 1 } { + # Total records in a btree is now 9000 + error_check_good \ + recordcount_after_dels [lindex [lindex $ret 0] 1] 9000 + } else { + # No renumbering--still no change in RECORDCOUNT. + error_check_good \ + recordcount_after_dels [lindex [lindex $ret 0] 1] 10000 + } + + puts "\tTest0$tnum.e: put 8000 new keys off the end." + for { set ndx 9001 } { $ndx <= 17000 } {incr ndx } { + set ret [eval {$db put} $keypfx$ndx $data] + error_check_good db_put_end $ret 0 + } + + set ret [$db stat -recordcount] + if { [is_rbtree $method] != 1 } { + # If this is a recno database, the record count should + # be up to 17000, the largest number we've seen, with + # or without renumbering. + error_check_good \ + recordcount_after_dels [lindex [lindex $ret 0] 1] 17000 + } else { + # In an rbtree, 1000 of those keys were overwrites, + # so there are 7000 new keys + 9000 old keys == 16000 + error_check_good \ + recordcount_after_dels [lindex [lindex $ret 0] 1] 16000 + } + + error_check_good db_close [$db close] 0 +} diff --git a/db/test/test066.tcl b/db/test/test066.tcl new file mode 100644 index 000000000..591c51a4c --- /dev/null +++ b/db/test/test066.tcl @@ -0,0 +1,73 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test066.tcl,v 11.7 2000/08/25 14:21:58 sue Exp $ +# +# DB Test 66: Make sure a cursor put to DB_CURRENT acts as an overwrite in +# a database with duplicates +proc test066 { method args } { + set omethod [convert_method $method] + set args [convert_args $method $args] + + set tnum 66 + + if { [is_record_based $method] || [is_rbtree $method] } { + puts "Test0$tnum: Skipping for method $method." + return + } + + puts "Test0$tnum: Test of cursor put to DB_CURRENT with duplicates." + + source ./include.tcl + + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test066.db + set env NULL + } else { + set testfile test066.db + incr eindex + set env [lindex $args $eindex] + } + cleanup $testdir $env + + set key "test" + set data "olddata" + + set db [eval {berkdb_open -create -mode 0644 -dup} $omethod $args \ + $testfile] + error_check_good db_open [is_valid_db $db] TRUE + + set ret [eval {$db put} $key [chop_data $method $data]] + error_check_good db_put $ret 0 + + set dbc [$db cursor] + error_check_good db_cursor [is_valid_cursor $dbc $db] TRUE + + set ret [$dbc get -first] + error_check_good db_get $ret [list [list $key [pad_data $method $data]]] + + set newdata "newdata" + set ret [$dbc put -current [chop_data $method $newdata]] + error_check_good dbc_put $ret 0 + + # There should be only one (key,data) pair in the database, and this + # is it. + set ret [$dbc get -first] + error_check_good db_get_first $ret \ + [list [list $key [pad_data $method $newdata]]] + + # and this one should come up empty. + set ret [$dbc get -next] + error_check_good db_get_next $ret "" + + error_check_good dbc_close [$dbc close] 0 + error_check_good db_close [$db close] 0 + + puts "\tTest0$tnum: Test completed successfully." +} diff --git a/db/test/test067.tcl b/db/test/test067.tcl new file mode 100644 index 000000000..c287d7b1e --- /dev/null +++ b/db/test/test067.tcl @@ -0,0 +1,114 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test067.tcl,v 11.12 2000/08/25 14:21:58 sue Exp $ +# +# DB Test 67: Test of DB_CURRENT partial puts on almost-empty duplicate pages. +# This test was written to address the following issue, #2 in the list of +# issues relating to bug #0820: +# 2. DBcursor->put, DB_CURRENT flag, off-page duplicates, hash and btree: +# In Btree, the DB_CURRENT overwrite of off-page duplicate records +# first deletes the record and then puts the new one -- this could +# be a problem if the removal of the record causes a reverse split. +# Suggested solution is to acquire a cursor to lock down the current +# record, put a new record after that record, and then delete using +# the held cursor. +# It also tests the following, #5 in the same list of issues: +# 5. DBcursor->put, DB_AFTER/DB_BEFORE/DB_CURRENT flags, DB_DBT_PARTIAL set, +# duplicate comparison routine specified. +# The partial change does not change how data items sort, but the +# record to be put isn't built yet, and that record supplied is the +# one that's checked for ordering compatibility. +proc test067 { method {ndups 1000} {tnum 67} args } { + source ./include.tcl + global alphabet + global errorCode + + set args [convert_args $method $args] + set omethod [convert_method $method] + + set eindex [lsearch -exact $args "-env"] + + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test0$tnum.db + set env NULL + } else { + set testfile test0$tnum.db + incr eindex + set env [lindex $args $eindex] + } + + puts "Test0$tnum:\ + $method ($args) Partial puts on near-empty duplicate pages." + if { [is_record_based $method] == 1 || [is_rbtree $method] == 1 } { + puts "\tTest0$tnum: skipping for method $method." + return + } + + foreach dupopt { "-dup" "-dup -dupsort" } { + cleanup $testdir $env + set db [eval {berkdb_open -create -truncate -mode 0644 \ + $omethod} $args $dupopt {$testfile}] + error_check_good db_open [is_valid_db $db] TRUE + + puts "\tTest0$tnum.a ($dupopt): Put $ndups duplicates." + + set key "key_test$tnum" + + for { set ndx 0 } { $ndx < $ndups } { incr ndx } { + set data $alphabet$ndx + + # No need for pad_data since we're skipping recno. + set ret [eval {$db put} $key $data] + error_check_good put($key,$data) $ret 0 + } + + # Sync so we can inspect database if the next section bombs. + error_check_good db_sync [$db sync] 0 + puts "\tTest0$tnum.b ($dupopt):\ + Deleting dups (last first), overwriting each." + + set dbc [$db cursor] + error_check_good cursor_create [is_valid_cursor $dbc $db] TRUE + + set count 0 + while { $count < $ndups - 1 } { + # set cursor to last item in db + set ret [$dbc get -last] + error_check_good \ + verify_key [lindex [lindex $ret 0] 0] $key + + # for error reporting + set currdatum [lindex [lindex $ret 0] 1] + + # partial-overwrite it + # (overwrite offsets 1-4 with "bcde"--which they + # already are) + + # Even though we expect success, we catch this + # since it might return EINVAL, and we want that + # to FAIL. + set errorCode NONE + set ret [catch {eval $dbc put -current \ + {-partial [list 1 4]} "bcde"} \ + res] + error_check_good \ + partial_put_valid($currdatum) $errorCode NONE + error_check_good partial_put($currdatum) $res 0 + + # delete it + error_check_good dbc_del [$dbc del] 0 + + #puts $currdatum + + incr count + } + + error_check_good dbc_close [$dbc close] 0 + error_check_good db_close [$db close] 0 + } +} diff --git a/db/test/test068.tcl b/db/test/test068.tcl new file mode 100644 index 000000000..587cd2078 --- /dev/null +++ b/db/test/test068.tcl @@ -0,0 +1,181 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test068.tcl,v 11.11 2000/08/25 14:21:58 sue Exp $ +# +# DB Test 68: Test of DB_BEFORE and DB_AFTER and partial puts. +# Make sure DB_BEFORE and DB_AFTER work properly with partial puts, +# and check that they return EINVAL if DB_DUPSORT is set or if DB_DUP is not. +proc test068 { method args } { + source ./include.tcl + global alphabet + global errorCode + + set tnum 68 + set nkeys 1000 + + set args [convert_args $method $args] + set omethod [convert_method $method] + + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test0$tnum.db + set env NULL + } else { + set testfile test0$tnum.db + incr eindex + set env [lindex $args $eindex] + } + + puts "Test0$tnum:\ + $method ($args) Test of DB_BEFORE/DB_AFTER and partial puts." + if { [is_record_based $method] == 1 } { + puts "\tTest0$tnum: skipping for method $method." + return + } + + # Create a list of $nkeys words to insert into db. + puts "\tTest0$tnum.a: Initialize word list." + set wordlist {} + set count 0 + set did [open $dict] + while { [gets $did str] != -1 && $count < $nkeys } { + lappend wordlist $str + incr count + } + close $did + + # Sanity check: did we get $nkeys words? + error_check_good enough_keys [llength $wordlist] $nkeys + + # rbtree can't handle dups, so just test the non-dup case + # if it's the current method. + if { [is_rbtree $method] == 1 } { + set dupoptlist { "" } + } else { + set dupoptlist { "" "-dup" "-dup -dupsort" } + } + + foreach dupopt $dupoptlist { + cleanup $testdir $env + set db [eval {berkdb_open_noerr -create -truncate -mode 0644 \ + $omethod} $args $dupopt {$testfile}] + error_check_good db_open [is_valid_db $db] TRUE + + puts "\tTest0$tnum.b ($dupopt): DB initialization: put loop." + foreach word $wordlist { + error_check_good db_put [$db put $word $word] 0 + } + + puts "\tTest0$tnum.c ($dupopt): get loop." + foreach word $wordlist { + # Make sure that the Nth word has been correctly + # inserted, and also that the Nth word is the + # Nth one we pull out of the database using a cursor. + + set dbt [$db get $word] + error_check_good get_key [list [list $word $word]] $dbt + } + + set dbc [$db cursor] + error_check_good cursor_open [is_valid_cursor $dbc $db] TRUE + + puts "\tTest0$tnum.d ($dupopt): DBC->put w/ DB_AFTER." + + # Set cursor to the first key; make sure it succeeds. + # With an unsorted wordlist, we can't be sure that the + # first item returned will equal the first item in the + # wordlist, so we just make sure it got something back. + set dbt [eval {$dbc get -first}] + error_check_good \ + dbc_get_first [llength $dbt] 1 + + # If -dup is not set, or if -dupsort is set too, we + # need to verify that DB_BEFORE and DB_AFTER fail + # and then move on to the next $dupopt. + if { $dupopt != "-dup" } { + set errorCode "NONE" + set ret [catch {eval $dbc put -after \ + {-partial [list 6 0]} "after"} res] + error_check_good dbc_put_after_fail $ret 1 + error_check_good dbc_put_after_einval \ + [is_substr $errorCode EINVAL] 1 + puts "\tTest0$tnum ($dupopt): DB_AFTER returns EINVAL." + set errorCode "NONE" + set ret [catch {eval $dbc put -before \ + {-partial [list 6 0]} "before"} res] + error_check_good dbc_put_before_fail $ret 1 + error_check_good dbc_put_before_einval \ + [is_substr $errorCode EINVAL] 1 + puts "\tTest0$tnum ($dupopt): DB_BEFORE returns EINVAL." + puts "\tTest0$tnum ($dupopt): Correct error returns,\ + skipping further test." + # continue with broad foreach + error_check_good db_close [$db close] 0 + continue + } + + puts "\tTest0$tnum.e ($dupopt): DBC->put(DB_AFTER) loop." + foreach word $wordlist { + # set cursor to $word + set dbt [$dbc get -set $word] + error_check_good \ + dbc_get_set $dbt [list [list $word $word]] + # put after it + set ret [$dbc put -after -partial {4 0} after] + error_check_good dbc_put_after $ret 0 + } + + puts "\tTest0$tnum.f ($dupopt): DBC->put(DB_BEFORE) loop." + foreach word $wordlist { + # set cursor to $word + set dbt [$dbc get -set $word] + error_check_good \ + dbc_get_set $dbt [list [list $word $word]] + # put before it + set ret [$dbc put -before -partial {6 0} before] + error_check_good dbc_put_before $ret 0 + } + + error_check_good dbc_close [$dbc close] 0 + + eval $db sync + puts "\tTest0$tnum.g ($dupopt): Verify correctness." + + set dbc [$db cursor] + error_check_good db_cursor [is_valid_cursor $dbc $db] TRUE + + # loop through the whole db beginning to end, + # make sure we have, in order, {$word "\0\0\0\0\0\0before"}, + # {$word $word}, {$word "\0\0\0\0after"} for each word. + set count 0 + while { $count < $nkeys } { + # Get the first item of each set of three. + # We don't know what the word is, but set $word to + # the key and check that the data is + # "\0\0\0\0\0\0before". + set dbt [$dbc get -next] + set word [lindex [lindex $dbt 0] 0] + + error_check_good dbc_get_one $dbt \ + [list [list $word "\0\0\0\0\0\0before"]] + + set dbt [$dbc get -next] + error_check_good \ + dbc_get_two $dbt [list [list $word $word]] + + set dbt [$dbc get -next] + error_check_good dbc_get_three $dbt \ + [list [list $word "\0\0\0\0after"]] + + incr count + } + error_check_good dbc_close [$dbc close] 0 + error_check_good db_close [$db close] 0 + } +} diff --git a/db/test/test069.tcl b/db/test/test069.tcl new file mode 100644 index 000000000..f3b839de7 --- /dev/null +++ b/db/test/test069.tcl @@ -0,0 +1,14 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test069.tcl,v 11.4 2000/02/14 03:00:21 bostic Exp $ +# +# DB Test 69: Run DB Test 67 with a small number of dups, +# to ensure that partial puts to DB_CURRENT work correctly in +# the absence of duplicate pages. + +proc test069 { method {ndups 50} {tnum 69} args } { + eval test067 $method $ndups $tnum $args +} diff --git a/db/test/test070.tcl b/db/test/test070.tcl new file mode 100644 index 000000000..befec9ce1 --- /dev/null +++ b/db/test/test070.tcl @@ -0,0 +1,120 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test070.tcl,v 11.18 2000/12/18 20:04:47 sue Exp $ +# +# DB Test 70: Test of DB_CONSUME. +# Fork off six processes, four consumers and two producers. +# The producers will each put 20000 records into a queue; +# the consumers will each get 10000. +# Then, verify that no record was lost or retrieved twice. +proc test070 { method {nconsumers 4} {nproducers 2} \ + {nitems 1000} {mode CONSUME } {start 0} {txn -txn} {tnum 70} args } { + source ./include.tcl + global alphabet + + # + # If we are using an env, then skip this test. It needs its own. + set eindex [lsearch -exact $args "-env"] + if { $eindex != -1 } { + incr eindex + set env [lindex $args $eindex] + puts "Test0$tnum skipping for env $env" + return + } + set omethod [convert_method $method] + set args [convert_args $method $args] + + puts "Test0$tnum: $method ($args) Test of DB_$mode flag to DB->get." + puts "\tUsing $txn environment." + + error_check_good enough_consumers [expr $nconsumers > 0] 1 + error_check_good enough_producers [expr $nproducers > 0] 1 + + if { [is_queue $method] != 1 } { + puts "\tSkipping Test0$tnum for method $method." + return + } + + env_cleanup $testdir + set testfile test0$tnum.db + + # Create environment + set dbenv [eval {berkdb env -create $txn -home } $testdir] + error_check_good dbenv_create [is_valid_env $dbenv] TRUE + + # Create database + set db [eval {berkdb_open -create -mode 0644 -queue}\ + -env $dbenv $args $testfile] + error_check_good db_open [is_valid_db $db] TRUE + + if { $start != 0 } { + error_check_good set_seed [$db put $start "consumer data"] 0 + puts "\tStarting at $start." + } else { + incr start + } + + set pidlist {} + + # Divvy up the total number of records amongst the consumers and + # producers. + error_check_good cons_div_evenly [expr $nitems % $nconsumers] 0 + error_check_good prod_div_evenly [expr $nitems % $nproducers] 0 + set nperconsumer [expr $nitems / $nconsumers] + set nperproducer [expr $nitems / $nproducers] + + set consumerlog $testdir/CONSUMERLOG. + + # Fork consumer processes (we want them to be hungry) + for { set ndx 0 } { $ndx < $nconsumers } { incr ndx } { + set output $consumerlog$ndx + set p [exec $tclsh_path $test_path/wrap.tcl \ + conscript.tcl $testdir/conscript.log.consumer$ndx \ + $testdir $testfile $mode $nperconsumer $output $tnum \ + $args &] + lappend pidlist $p + } + for { set ndx 0 } { $ndx < $nproducers } { incr ndx } { + set p [exec $tclsh_path $test_path/wrap.tcl \ + conscript.tcl $testdir/conscript.log.producer$ndx \ + $testdir $testfile PRODUCE $nperproducer "" $tnum \ + $args &] + lappend pidlist $p + } + + # Wait for all children. + watch_procs 10 + + # Verify: slurp all record numbers into list, sort, and make + # sure each appears exactly once. + puts "\tTest0$tnum: Verifying results." + set reclist {} + for { set ndx 0 } { $ndx < $nconsumers } { incr ndx } { + set input $consumerlog$ndx + set iid [open $input r] + while { [gets $iid str] != -1 } { + lappend reclist $str + } + close $iid + } + set sortreclist [lsort -integer $reclist] + + set nitems [expr $start + $nitems] + for { set ndx $start } { $ndx < $nitems } { incr ndx } { + # Skip 0 if we are wrapping around + if { $ndx == 0 } { + incr ndx + incr nitems + } + # Be sure to convert ndx to a number before comparing. + error_check_good pop_num [lindex $sortreclist 0] [expr $ndx + 0] + set sortreclist [lreplace $sortreclist 0 0] + } + error_check_good list_ends_empty $sortreclist {} + error_check_good dbenv_close [$dbenv close] 0 + + puts "\tTest0$tnum completed successfully." +} diff --git a/db/test/test071.tcl b/db/test/test071.tcl new file mode 100644 index 000000000..376c902ec --- /dev/null +++ b/db/test/test071.tcl @@ -0,0 +1,15 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test071.tcl,v 11.6 2000/12/01 04:28:36 ubell Exp $ +# +# DB Test 71: Test of DB_CONSUME. +# This is DB Test 70, with one consumer, one producers, and 10000 items. +proc test071 { method {nconsumers 1} {nproducers 1}\ + {nitems 10000} {mode CONSUME} {start 0 } {txn -txn} {tnum 71} args } { + + eval test070 $method \ + $nconsumers $nproducers $nitems $mode $start $txn $tnum $args +} diff --git a/db/test/test072.tcl b/db/test/test072.tcl new file mode 100644 index 000000000..3ca7415a2 --- /dev/null +++ b/db/test/test072.tcl @@ -0,0 +1,225 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test072.tcl,v 11.13 2000/12/11 17:24:55 sue Exp $ +# +# DB Test 72: Test of cursor stability when duplicates are moved off-page. +proc test072 { method {pagesize 512} {ndups 20} {tnum 72} args } { + source ./include.tcl + global alphabet + + set omethod [convert_method $method] + set args [convert_args $method $args] + + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test0$tnum.db + set env NULL + } else { + set testfile test0$tnum.db + incr eindex + set env [lindex $args $eindex] + } + cleanup $testdir $env + + # Keys must sort $prekey < $key < $postkey. + set prekey "a key" + set key "the key" + set postkey "z key" + + # Make these distinguishable from each other and from the + # alphabets used for the $key's data. + set predatum "1234567890" + set postdatum "0987654321" + + append args " -pagesize $pagesize " + + puts -nonewline "Test0$tnum $omethod ($args): " + if { [is_record_based $method] || [is_rbtree $method] } { + puts "Skipping for method $method." + return + } else { + puts "\n Test of cursor stability when\ + duplicates are moved off-page." + } + set pgindex [lsearch -exact $args "-pagesize"] + if { $pgindex != -1 } { + puts "Test0$tnum: skipping for specific pagesizes" + return + } + + foreach dupopt { "-dup" "-dup -dupsort" } { + set db [eval {berkdb_open -create -truncate -mode 0644} \ + $omethod $args $dupopt $testfile] + error_check_good "db open" [is_valid_db $db] TRUE + + puts \ +"\tTest0$tnum.a: ($dupopt) Set up surrounding keys and cursors." + error_check_good pre_put [$db put $prekey $predatum] 0 + error_check_good post_put [$db put $postkey $postdatum] 0 + set precursor [$db cursor] + error_check_good precursor [is_valid_cursor $precursor \ + $db] TRUE + set postcursor [$db cursor] + error_check_good postcursor [is_valid_cursor $postcursor \ + $db] TRUE + error_check_good preset [$precursor get -set $prekey] \ + [list [list $prekey $predatum]] + error_check_good postset [$postcursor get -set $postkey] \ + [list [list $postkey $postdatum]] + + puts "\tTest0$tnum.b: Put/create cursor/verify all cursor loop." + + for { set i 0 } { $i < $ndups } { incr i } { + set datum [format "%4d$alphabet" [expr $i + 1000]] + set data($i) $datum + + # Uncomment these lines to see intermediate steps. + error_check_good db_sync($i) [$db sync] 0 + error_check_good db_dump($i) \ + [catch {exec $util_path/db_dump \ + -da $testfile > TESTDIR/out.$i}] 0 + + error_check_good "db put ($i)" [$db put $key $datum] 0 + + set dbc($i) [$db cursor] + error_check_good "db cursor ($i)"\ + [is_valid_cursor $dbc($i) $db] TRUE + + error_check_good "dbc get -get_both ($i)"\ + [$dbc($i) get -get_both $key $datum]\ + [list [list $key $datum]] + + for { set j 0 } { $j < $i } { incr j } { + set dbt [$dbc($j) get -current] + set k [lindex [lindex $dbt 0] 0] + set d [lindex [lindex $dbt 0] 1] + + #puts "cursor $j after $i: $d" + + eval {$db sync} + + error_check_good\ + "cursor $j key correctness after $i puts" \ + $k $key + error_check_good\ + "cursor $j data correctness after $i puts" \ + $d $data($j) + } + + # Check correctness of pre- and post- cursors. Do an + # error_check_good on the lengths first so that we don't + # spew garbage as the "got" field and screw up our + # terminal. (It's happened here.) + set pre_dbt [$precursor get -current] + set post_dbt [$postcursor get -current] + error_check_good \ + "key earlier cursor correctness after $i puts" \ + [string length [lindex [lindex $pre_dbt 0] 0]] \ + [string length $prekey] + error_check_good \ + "data earlier cursor correctness after $i puts" \ + [string length [lindex [lindex $pre_dbt 0] 1]] \ + [string length $predatum] + error_check_good \ + "key later cursor correctness after $i puts" \ + [string length [lindex [lindex $post_dbt 0] 0]] \ + [string length $postkey] + error_check_good \ + "data later cursor correctness after $i puts" \ + [string length [lindex [lindex $post_dbt 0] 1]]\ + [string length $postdatum] + + + error_check_good \ + "earlier cursor correctness after $i puts" \ + $pre_dbt [list [list $prekey $predatum]] + error_check_good \ + "later cursor correctness after $i puts" \ + $post_dbt [list [list $postkey $postdatum]] + } + + puts "\tTest0$tnum.c: Reverse Put/create cursor/verify all cursor loop." + set end [expr $ndups * 2 - 1] + for { set i $end } { $i > $ndups } { set i [expr $i - 1] } { + set datum [format "%4d$alphabet" [expr $i + 1000]] + set data($i) $datum + + # Uncomment these lines to see intermediate steps. + error_check_good db_sync($i) [$db sync] 0 + error_check_good db_dump($i) \ + [catch {exec $util_path/db_dump \ + -da $testfile > TESTDIR/out.$i}] 0 + + error_check_good "db put ($i)" [$db put $key $datum] 0 + + set dbc($i) [$db cursor] + error_check_good "db cursor ($i)"\ + [is_valid_cursor $dbc($i) $db] TRUE + + error_check_good "dbc get -get_both ($i)"\ + [$dbc($i) get -get_both $key $datum]\ + [list [list $key $datum]] + + for { set j $i } { $j < $end } { incr j } { + set dbt [$dbc($j) get -current] + set k [lindex [lindex $dbt 0] 0] + set d [lindex [lindex $dbt 0] 1] + + #puts "cursor $j after $i: $d" + + eval {$db sync} + + error_check_good\ + "cursor $j key correctness after $i puts" \ + $k $key + error_check_good\ + "cursor $j data correctness after $i puts" \ + $d $data($j) + } + + # Check correctness of pre- and post- cursors. Do an + # error_check_good on the lengths first so that we don't + # spew garbage as the "got" field and screw up our + # terminal. (It's happened here.) + set pre_dbt [$precursor get -current] + set post_dbt [$postcursor get -current] + error_check_good \ + "key earlier cursor correctness after $i puts" \ + [string length [lindex [lindex $pre_dbt 0] 0]] \ + [string length $prekey] + error_check_good \ + "data earlier cursor correctness after $i puts" \ + [string length [lindex [lindex $pre_dbt 0] 1]] \ + [string length $predatum] + error_check_good \ + "key later cursor correctness after $i puts" \ + [string length [lindex [lindex $post_dbt 0] 0]] \ + [string length $postkey] + error_check_good \ + "data later cursor correctness after $i puts" \ + [string length [lindex [lindex $post_dbt 0] 1]]\ + [string length $postdatum] + + + error_check_good \ + "earlier cursor correctness after $i puts" \ + $pre_dbt [list [list $prekey $predatum]] + error_check_good \ + "later cursor correctness after $i puts" \ + $post_dbt [list [list $postkey $postdatum]] + } + + # Close cursors. + puts "\tTest0$tnum.d: Closing cursors." + for { set i 0 } { $i < $ndups } { incr i } { + error_check_good "dbc close ($i)" [$dbc($i) close] 0 + } + error_check_good "db close" [$db close] 0 + } +} diff --git a/db/test/test073.tcl b/db/test/test073.tcl new file mode 100644 index 000000000..12a48b0e4 --- /dev/null +++ b/db/test/test073.tcl @@ -0,0 +1,265 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test073.tcl,v 11.17 2000/12/11 17:24:55 sue Exp $ +# +# DB Test 73: Test of cursor stability on duplicate pages. +# Does the following: +# a. Initialize things by DB->putting ndups dups and +# setting a reference cursor to point to each. +# b. c_put ndups dups (and correspondingly expanding +# the set of reference cursors) after the last one, making sure +# after each step that all the reference cursors still point to +# the right item. +# c. Ditto, but before the first one. +# d. Ditto, but after each one in sequence first to last. +# e. Ditto, but after each one in sequence from last to first. +# occur relative to the new datum) +# f. Ditto for the two sequence tests, only doing a +# DBC->c_put(DB_CURRENT) of a larger datum instead of adding a +# new one. +proc test073 { method {pagesize 512} {ndups 50} {tnum 73} args } { + source ./include.tcl + global alphabet + + set omethod [convert_method $method] + set args [convert_args $method $args] + + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test0$tnum.db + set env NULL + } else { + set testfile test0$tnum.db + incr eindex + set env [lindex $args $eindex] + } + cleanup $testdir $env + + set key "the key" + + + puts -nonewline "Test0$tnum $omethod ($args): " + if { [is_record_based $method] || [is_rbtree $method] } { + puts "Skipping for method $method." + return + } else { + puts "cursor stability on duplicate pages." + } + set pgindex [lsearch -exact $args "-pagesize"] + if { $pgindex != -1 } { + puts "Test073: skipping for specific pagesizes" + return + } + + append args " -pagesize $pagesize -dup" + + set db [eval {berkdb_open \ + -create -truncate -mode 0644} $omethod $args $testfile] + error_check_good "db open" [is_valid_db $db] TRUE + + # Number of outstanding keys. + set keys 0 + + puts "\tTest0$tnum.a.1: Initializing put loop; $ndups dups, short data." + + for { set i 0 } { $i < $ndups } { incr i } { + set datum [makedatum_t73 $i 0] + + error_check_good "db put ($i)" [$db put $key $datum] 0 + + set is_long($i) 0 + incr keys + } + + puts "\tTest0$tnum.a.2: Initializing cursor get loop; $keys dups." + for { set i 0 } { $i < $keys } { incr i } { + set datum [makedatum_t73 $i 0] + + set dbc($i) [$db cursor] + error_check_good "db cursor ($i)"\ + [is_valid_cursor $dbc($i) $db] TRUE + error_check_good "dbc get -get_both ($i)"\ + [$dbc($i) get -get_both $key $datum]\ + [list [list $key $datum]] + } + + puts "\tTest0$tnum.b: Cursor put (DB_KEYLAST); $ndups new dups,\ + short data." + + for { set i 0 } { $i < $ndups } { incr i } { + # !!! keys contains the number of the next dup + # to be added (since they start from zero) + + set datum [makedatum_t73 $keys 0] + set curs [$db cursor] + error_check_good "db cursor create" [is_valid_cursor $curs $db]\ + TRUE + error_check_good "c_put(DB_KEYLAST, $keys)"\ + [$curs put -keylast $key $datum] 0 + + set dbc($keys) $curs + set is_long($keys) 0 + incr keys + + verify_t73 is_long dbc $keys $key + } + + puts "\tTest0$tnum.c: Cursor put (DB_KEYFIRST); $ndups new dups,\ + short data." + + for { set i 0 } { $i < $ndups } { incr i } { + # !!! keys contains the number of the next dup + # to be added (since they start from zero) + + set datum [makedatum_t73 $keys 0] + set curs [$db cursor] + error_check_good "db cursor create" [is_valid_cursor $curs $db]\ + TRUE + error_check_good "c_put(DB_KEYFIRST, $keys)"\ + [$curs put -keyfirst $key $datum] 0 + + set dbc($keys) $curs + set is_long($keys) 0 + incr keys + + verify_t73 is_long dbc $keys $key + } + + puts "\tTest0$tnum.d: Cursor put (DB_AFTER) first to last;\ + $keys new dups, short data" + # We want to add a datum after each key from 0 to the current + # value of $keys, which we thus need to save. + set keysnow $keys + for { set i 0 } { $i < $keysnow } { incr i } { + set datum [makedatum_t73 $keys 0] + set curs [$db cursor] + error_check_good "db cursor create" [is_valid_cursor $curs $db]\ + TRUE + + # Which datum to insert this guy after. + set curdatum [makedatum_t73 $i 0] + error_check_good "c_get(DB_GET_BOTH, $i)"\ + [$curs get -get_both $key $curdatum]\ + [list [list $key $curdatum]] + error_check_good "c_put(DB_AFTER, $i)"\ + [$curs put -after $datum] 0 + + set dbc($keys) $curs + set is_long($keys) 0 + incr keys + + verify_t73 is_long dbc $keys $key + } + + puts "\tTest0$tnum.e: Cursor put (DB_BEFORE) last to first;\ + $keys new dups, short data" + + for { set i [expr $keys - 1] } { $i >= 0 } { incr i -1 } { + set datum [makedatum_t73 $keys 0] + set curs [$db cursor] + error_check_good "db cursor create" [is_valid_cursor $curs $db]\ + TRUE + + # Which datum to insert this guy before. + set curdatum [makedatum_t73 $i 0] + error_check_good "c_get(DB_GET_BOTH, $i)"\ + [$curs get -get_both $key $curdatum]\ + [list [list $key $curdatum]] + error_check_good "c_put(DB_BEFORE, $i)"\ + [$curs put -before $datum] 0 + + set dbc($keys) $curs + set is_long($keys) 0 + incr keys + + if { $i % 10 == 1 } { + verify_t73 is_long dbc $keys $key + } + } + verify_t73 is_long dbc $keys $key + + puts "\tTest0$tnum.f: Cursor put (DB_CURRENT), first to last,\ + growing $keys data." + set keysnow $keys + for { set i 0 } { $i < $keysnow } { incr i } { + set olddatum [makedatum_t73 $i 0] + set newdatum [makedatum_t73 $i 1] + set curs [$db cursor] + error_check_good "db cursor create" [is_valid_cursor $curs $db]\ + TRUE + + error_check_good "c_get(DB_GET_BOTH, $i)"\ + [$curs get -get_both $key $olddatum]\ + [list [list $key $olddatum]] + error_check_good "c_put(DB_CURRENT, $i)"\ + [$curs put -current $newdatum] 0 + + error_check_good "cursor close" [$curs close] 0 + + set is_long($i) 1 + + if { $i % 10 == 1 } { + verify_t73 is_long dbc $keys $key + } + } + verify_t73 is_long dbc $keys $key + + # Close cursors. + puts "\tTest0$tnum.g: Closing cursors." + for { set i 0 } { $i < $keys } { incr i } { + error_check_good "dbc close ($i)" [$dbc($i) close] 0 + } + error_check_good "db close" [$db close] 0 +} + +# !!!: This procedure is also used by test087. +proc makedatum_t73 { num is_long } { + global alphabet + if { $is_long == 1 } { + set a $alphabet$alphabet$alphabet + } else { + set a abcdefghijklm + } + + # format won't do leading zeros, alas. + if { $num / 1000 > 0 } { + set i $num + } elseif { $num / 100 > 0 } { + set i 0$num + } elseif { $num / 10 > 0 } { + set i 00$num + } else { + set i 000$num + } + + return $i$a +} + +# !!!: This procedure is also used by test087. +proc verify_t73 { is_long_array curs_array numkeys key } { + upvar $is_long_array is_long + upvar $curs_array dbc + upvar db db + + #useful for debugging, perhaps. + eval $db sync + + for { set j 0 } { $j < $numkeys } { incr j } { + set dbt [$dbc($j) get -current] + set k [lindex [lindex $dbt 0] 0] + set d [lindex [lindex $dbt 0] 1] + + error_check_good\ + "cursor $j key correctness (with $numkeys total items)"\ + $k $key + error_check_good\ + "cursor $j data correctness (with $numkeys total items)"\ + $d [makedatum_t73 $j $is_long($j)] + } +} diff --git a/db/test/test074.tcl b/db/test/test074.tcl new file mode 100644 index 000000000..ddc5f1642 --- /dev/null +++ b/db/test/test074.tcl @@ -0,0 +1,221 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test074.tcl,v 11.10 2000/08/25 14:21:58 sue Exp $ +# +# DB Test 74: Test of DB_NEXT_NODUP. +proc test074 { method {dir -nextnodup} {pagesize 512} {nitems 100} {tnum 74} args } { + source ./include.tcl + global alphabet + global rand_init + + set omethod [convert_method $method] + set args [convert_args $method $args] + + berkdb srand $rand_init + + # Data prefix--big enough that we get a mix of on-page, off-page, + # and multi-off-page dups with the default nitems + if { [is_fixed_length $method] == 1 } { + set globaldata "somedata" + } else { + set globaldata [repeat $alphabet 4] + } + + puts "Test0$tnum $omethod ($args): Test of $dir" + + # First, test non-dup (and not-very-interesting) case with + # all db types. + + puts "\tTest0$tnum.a: No duplicates." + + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test0$tnum-nodup.db + set env NULL + } else { + set testfile test0$tnum-nodup.db + incr eindex + set env [lindex $args $eindex] + } + cleanup $testdir $env + set db [eval {berkdb_open -create -truncate -mode 0644} $omethod\ + $args {$testfile}] + error_check_good db_open [is_valid_db $db] TRUE + + # Insert nitems items. + puts "\t\tTest0$tnum.a.1: Put loop." + for {set i 1} {$i <= $nitems} {incr i} { + # + # If record based, set key to $i * 2 to leave + # holes/unused entries for further testing. + # + if {[is_record_based $method] == 1} { + set key [expr $i * 2] + } else { + set key "key$i" + } + set data "$globaldata$i" + error_check_good put($i) [$db put $key\ + [chop_data $method $data]] 0 + } + + puts "\t\tTest0$tnum.a.2: Get($dir)" + + # foundarray($i) is set when key number i is found in the database + set dbc [$db cursor] + error_check_good db_cursor [is_valid_cursor $dbc $db] TRUE + + # Initialize foundarray($i) to zero for all $i + for {set i 1} {$i < $nitems} {incr i} { + set foundarray($i) 0 + } + + # Walk database using $dir and record each key gotten. + for {set i 1} {$i <= $nitems} {incr i} { + set dbt [$dbc get $dir] + set key [lindex [lindex $dbt 0] 0] + if {[is_record_based $method] == 1} { + set num [expr $key / 2] + set desired_key $key + error_check_good $method:num $key [expr $num * 2] + } else { + set num [string range $key 3 end] + set desired_key key$num + } + + error_check_good dbt_correct($i) $dbt\ + [list [list $desired_key\ + [pad_data $method $globaldata$num]]] + + set foundarray($num) 1 + } + + puts "\t\tTest0$tnum.a.3: Final key." + error_check_good last_db_get [$dbc get $dir] [list] + + puts "\t\tTest0$tnum.a.4: Verify loop." + for { set i 1 } { $i <= $nitems } { incr i } { + error_check_good found_key($i) $foundarray($i) 1 + } + + error_check_good dbc_close(nodup) [$dbc close] 0 + + # If we are a method that doesn't allow dups, verify that + # we get an empty list if we try to use DB_NEXT_DUP + if { [is_record_based $method] == 1 || [is_rbtree $method] == 1 } { + puts "\t\tTest0$tnum.a.5: Check DB_NEXT_DUP for $method." + set dbc [$db cursor] + error_check_good db_cursor [is_valid_cursor $dbc $db] TRUE + + set dbt [$dbc get $dir] + error_check_good $method:nextdup [$dbc get -nextdup] [list] + error_check_good dbc_close(nextdup) [$dbc close] 0 + } + error_check_good db_close(nodup) [$db close] 0 + + # Quit here if we're a method that won't allow dups. + if { [is_record_based $method] == 1 || [is_rbtree $method] == 1 } { + puts "\tTest0$tnum: Skipping remainder for method $method." + return + } + + foreach opt { "-dup" "-dupsort" } { + + # + # If we are using an env, then testfile should just be the + # db name. Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test0$tnum$opt.db + } else { + set testfile test0$tnum$opt.db + } + + if { [string compare $opt "-dupsort"] == 0 } { + set opt "-dup -dupsort" + } + + puts "\tTest0$tnum.b: Duplicates ($opt)." + + puts "\t\tTest0$tnum.b.1 ($opt): Put loop." + set db [eval {berkdb_open -create -truncate -mode 0644}\ + $opt $omethod $args {$testfile}] + error_check_good db_open [is_valid_db $db] TRUE + + # Insert nitems different keys such that key i has i dups. + for {set i 1} {$i <= $nitems} {incr i} { + set key key$i + + for {set j 1} {$j <= $i} {incr j} { + if { $j < 10 } { + set data "${globaldata}00$j" + } elseif { $j < 100 } { + set data "${globaldata}0$j" + } else { + set data "$globaldata$j" + } + + error_check_good put($i,$j) \ + [$db put $key $data] 0 + } + } + + # Initialize foundarray($i) to 0 for all i. + unset foundarray + for { set i 1 } { $i <= $nitems } { incr i } { + set foundarray($i) 0 + } + + # Get loop--after each get, move forward a random increment + # within the duplicate set. + puts "\t\tTest0$tnum.b.2 ($opt): Get loop." + set one "001" + set dbc [$db cursor] + error_check_good dbc($opt) [is_valid_cursor $dbc $db] TRUE + for { set i 1 } { $i <= $nitems } { incr i } { + set dbt [$dbc get $dir] + set key [lindex [lindex $dbt 0] 0] + set num [string range $key 3 end] + + set desired_key key$num + if { [string compare $dir "-prevnodup"] == 0 } { + if { $num < 10 } { + set one "00$num" + } elseif { $num < 100 } { + set one "0$num" + } else { + set one $num + } + } + + error_check_good dbt_correct($i) $dbt\ + [list [list $desired_key\ + "$globaldata$one"]] + + set foundarray($num) 1 + + # Go forward by some number w/i dup set. + set inc [berkdb random_int 0 [expr $num - 1]] + for { set j 0 } { $j < $inc } { incr j } { + eval {$dbc get -nextdup} + } + } + + puts "\t\tTest0$tnum.b.3 ($opt): Final key." + error_check_good last_db_get($opt) [$dbc get $dir] [list] + + # Verify + puts "\t\tTest0$tnum.b.4 ($opt): Verify loop." + for { set i 1 } { $i <= $nitems } { incr i } { + error_check_good found_key($i) $foundarray($i) 1 + } + + error_check_good dbc_close [$dbc close] 0 + error_check_good db_close [$db close] 0 + } +} diff --git a/db/test/test075.tcl b/db/test/test075.tcl new file mode 100644 index 000000000..2aa0e1e25 --- /dev/null +++ b/db/test/test075.tcl @@ -0,0 +1,195 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test075.tcl,v 11.9 2000/08/25 14:21:58 sue Exp $ +# +# DB Test 75 (replacement) +# Test the DB->rename method. +proc test075 { method { tnum 75 } args } { + global errorCode + source ./include.tcl + set omethod [convert_method $method] + set args [convert_args $method $args] + + puts "Test0$tnum: $method ($args): Test of DB->rename()" + + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + set eindex [lsearch -exact $args "-env"] + if { $eindex == -1 } { + set oldfile $testdir/test0$tnum-old.db + set newfile $testdir/test0$tnum.db + set env NULL + set renargs "" + } else { + set oldfile test0$tnum-old.db + set newfile test0$tnum.db + # File existence checks won't work in an env, since $oldfile + # and $newfile won't be in the current working directory. + # We use this to skip them, and turn our secondary check + # (opening the dbs and seeing that all is well) into the main + # one. + incr eindex + set env [lindex $args $eindex] + set renargs " -env $env" + } + + # Make sure we're starting from a clean slate. + cleanup $testdir $env + if { $env == "NULL" } { + error_check_bad "$oldfile exists" [file exists $oldfile] 1 + error_check_bad "$newfile exists" [file exists $newfile] 1 + } + + puts "\tTest0$tnum.a: Create/rename file" + puts "\t\tTest0$tnum.a.1: create" + set db [eval {berkdb_open -create -mode 0644} $omethod $args $oldfile] + error_check_good dbopen [is_valid_db $db] TRUE + + if { $env == "NULL" } { + error_check_bad "$oldfile exists" [file exists $oldfile] 0 + error_check_bad "$newfile exists" [file exists $newfile] 1 + } + + # The nature of the key and data are unimportant; use numeric key + # so record-based methods don't need special treatment. + set key 1 + set data [pad_data $method data] + + error_check_good dbput [$db put $key $data] 0 + error_check_good dbclose [$db close] 0 + + puts "\t\tTest0$tnum.a.2: rename" + if { $env == "NULL" } { + error_check_bad "$oldfile exists" [file exists $oldfile] 0 + error_check_bad "$newfile exists" [file exists $newfile] 1 + } + error_check_good rename_file [eval {berkdb dbrename}\ + $renargs $oldfile $newfile] 0 + if { $env == "NULL" } { + error_check_bad "$oldfile exists" [file exists $oldfile] 1 + error_check_bad "$newfile exists" [file exists $newfile] 0 + } + + puts "\t\tTest0$tnum.a.3: check" + # Open again with create to make sure we're not caching or anything + # silly. In the normal case (no env), we already know the file doesn't + # exist. + set odb [eval {berkdb_open -create -mode 0644} $omethod $args $oldfile] + set ndb [eval {berkdb_open -create -mode 0644} $omethod $args $newfile] + error_check_good odb_open [is_valid_db $odb] TRUE + error_check_good ndb_open [is_valid_db $ndb] TRUE + + set odbt [$odb get $key] + set ndbt [$ndb get $key] + + # The DBT from the "old" database should be empty, not the "new" one. + error_check_good odbt_empty [llength $odbt] 0 + error_check_bad ndbt_empty [llength $ndbt] 0 + + error_check_good ndbt [lindex [lindex $ndbt 0] 1] $data + + error_check_good odb_close [$odb close] 0 + error_check_good ndb_close [$ndb close] 0 + + if { $env != "NULL" } { + puts "\tTest0$tnum: External environment present; \ + skipping remainder" + return + } + + # Now there's both an old and a new. Rename the "new" to the "old" + # and make sure that fails. + # + # XXX Ideally we'd do this test even when there's an external + # environment, but that env has errpfx/errfile set now. :-( + puts "\tTest0$tnum.b: Make sure rename fails instead of overwriting" + set ret [catch {eval {berkdb dbrename} $renargs $newfile $oldfile} res] + error_check_bad rename_overwrite $ret 0 + error_check_good rename_overwrite_ret [is_substr $errorCode EEXIST] 1 + + # Verify and then start over from a clean slate. + verify_dir $testdir "\tTest0$tnum.c: " + cleanup $testdir $env + error_check_bad "$oldfile exists" [file exists $oldfile] 1 + error_check_bad "$newfile exists" [file exists $newfile] 1 + + set oldfile test0$tnum-old.db + set newfile test0$tnum.db + + puts "\tTest0$tnum.d: Create/rename file in environment" + + set env [berkdb env -create -home $testdir] + error_check_good env_open [is_valid_env $env] TRUE + error_check_bad "$oldfile exists" [file exists $oldfile] 1 + error_check_bad "$newfile exists" [file exists $newfile] 1 + + puts "\t\tTest0$tnum.d.1: create" + set db [eval {berkdb_open -create -mode 0644} -env $env\ + $omethod $args $oldfile] + error_check_good dbopen [is_valid_db $db] TRUE + + # We need to make sure that it didn't create/rename into the + # current directory. + error_check_bad "$oldfile exists" [file exists $oldfile] 1 + error_check_bad "$newfile exists" [file exists $newfile] 1 + error_check_bad "$testdir/$oldfile exists"\ + [file exists $testdir/$oldfile] 0 + error_check_bad "$testdir/$newfile exists"\ + [file exists $testdir/$newfile] 1 + + error_check_good dbput [$db put $key $data] 0 + error_check_good dbclose [$db close] 0 + + puts "\t\tTest0$tnum.d.2: rename" + + error_check_good rename_file [berkdb dbrename -env $env\ + $oldfile $newfile] 0 + error_check_bad "$oldfile exists" [file exists $oldfile] 1 + error_check_bad "$newfile exists" [file exists $newfile] 1 + error_check_bad "$testdir/$oldfile exists"\ + [file exists $testdir/$oldfile] 1 + error_check_bad "$testdir/$newfile exists"\ + [file exists $testdir/$newfile] 0 + + puts "\t\tTest0$tnum.d.3: check" + # Open again with create to make sure we're not caching or anything + # silly. + set odb [eval {berkdb_open -create -mode 0644} -env $env\ + $omethod $args $oldfile] + set ndb [eval {berkdb_open -create -mode 0644} -env $env\ + $omethod $args $newfile] + error_check_good odb_open [is_valid_db $odb] TRUE + error_check_good ndb_open [is_valid_db $ndb] TRUE + + set odbt [$odb get $key] + set ndbt [$ndb get $key] + + # The DBT from the "old" database should be empty, not the "new" one. + error_check_good odbt_empty [llength $odbt] 0 + error_check_bad ndbt_empty [llength $ndbt] 0 + + error_check_good ndbt [lindex [lindex $ndbt 0] 1] $data + + error_check_good odb_close [$odb close] 0 + error_check_good ndb_close [$ndb close] 0 + + # XXX + # We need to close and reopen the env since berkdb_open has + # set its errfile/errpfx, and we can't unset that. + error_check_good env_close [$env close] 0 + set env [berkdb env -home $testdir] + error_check_good env_open2 [is_valid_env $env] TRUE + + puts "\tTest0$tnum.e:\ + Make sure rename fails instead of overwriting in env" + set ret [catch {eval {berkdb dbrename} -env $env $newfile $oldfile} res] + error_check_bad rename_overwrite $ret 0 + error_check_good rename_overwrite_ret [is_substr $errorCode EEXIST] 1 + + error_check_good env_close [$env close] 0 + + puts "\tTest0$tnum succeeded." +} diff --git a/db/test/test076.tcl b/db/test/test076.tcl new file mode 100644 index 000000000..13a919011 --- /dev/null +++ b/db/test/test076.tcl @@ -0,0 +1,59 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test076.tcl,v 1.7 2000/08/25 14:21:58 sue Exp $ +# +# DB Test 76: Test creation of many small databases in an env +proc test076 { method { ndbs 1000 } { tnum 76 } args } { + source ./include.tcl + + set omethod [convert_method $method] + set args [convert_args $method $args] + + + if { [is_record_based $method] == 1 } { + set key "" + } else { + set key "key" + } + set data "datamoredatamoredata" + + puts -nonewline "Test0$tnum $method ($args): " + puts -nonewline "Create $ndbs" + puts " small databases in one env." + + # Create an env if we weren't passed one. + set eindex [lsearch -exact $args "-env"] + if { $eindex == -1 } { + set deleteenv 1 + set env [eval {berkdb env -create -home} $testdir \ + {-cachesize {0 102400 1}}] + error_check_good env [is_valid_env $env] TRUE + set args "$args -env $env" + } else { + set deleteenv 0 + incr eindex + set env [lindex $args $eindex] + } + cleanup $testdir $env + + for { set i 1 } { $i <= $ndbs } { incr i } { + set testfile test0$tnum.$i.db + + set db [eval {berkdb_open -create -truncate -mode 0644}\ + $args $omethod $testfile] + error_check_good db_open($i) [is_valid_db $db] TRUE + + error_check_good db_put($i) [$db put $key$i \ + [chop_data $method $data$i]] 0 + error_check_good db_close($i) [$db close] 0 + } + + if { $deleteenv == 1 } { + error_check_good env_close [$env close] 0 + } + + puts "\tTest0$tnum passed." +} diff --git a/db/test/test077.tcl b/db/test/test077.tcl new file mode 100644 index 000000000..47248a309 --- /dev/null +++ b/db/test/test077.tcl @@ -0,0 +1,68 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test077.tcl,v 1.4 2000/08/25 14:21:58 sue Exp $ +# +# DB Test 77: Test of DB_GET_RECNO [#1206]. +proc test077 { method { nkeys 1000 } { pagesize 512 } { tnum 77 } args } { + source ./include.tcl + global alphabet + + set omethod [convert_method $method] + set args [convert_args $method $args] + + puts "Test0$tnum: Test of DB_GET_RECNO." + + if { [is_rbtree $method] != 1 } { + puts "\tTest0$tnum: Skipping for method $method." + return + } + + set data $alphabet + + set eindex [lsearch -exact $args "-env"] + if { $eindex == -1 } { + set testfile $testdir/test0$tnum.db + set env NULL + } else { + set testfile test0$tnum.db + incr eindex + set env [lindex $args $eindex] + } + cleanup $testdir $env + + set db [eval {berkdb_open -create -truncate -mode 0644\ + -pagesize $pagesize} $omethod $args {$testfile}] + error_check_good db_open [is_valid_db $db] TRUE + + puts "\tTest0$tnum.a: Populating database." + + for { set i 1 } { $i <= $nkeys } { incr i } { + set key [format %5d $i] + error_check_good db_put($key) [$db put $key $data] 0 + } + + puts "\tTest0$tnum.b: Verifying record numbers." + + set dbc [$db cursor] + error_check_good dbc_open [is_valid_cursor $dbc $db] TRUE + + set i 1 + for { set dbt [$dbc get -first] } \ + { [string length $dbt] != 0 } \ + { set dbt [$dbc get -next] } { + set recno [$dbc get -get_recno] + set keynum [expr [lindex [lindex $dbt 0] 0]] + + # Verify that i, the number that is the key, and recno + # are all equal. + error_check_good key($i) $keynum $i + error_check_good recno($i) $recno $i + incr i + } + + error_check_good dbc_close [$dbc close] 0 + error_check_good db_close [$db close] 0 +} diff --git a/db/test/test078.tcl b/db/test/test078.tcl new file mode 100644 index 000000000..9642096fa --- /dev/null +++ b/db/test/test078.tcl @@ -0,0 +1,90 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test078.tcl,v 1.9 2000/12/11 17:24:55 sue Exp $ +# +# DB Test 78: Test of DBC->c_count(). [#303] +proc test078 { method { nkeys 100 } { pagesize 512 } { tnum 78 } args } { + source ./include.tcl + global alphabet rand_init + + set args [convert_args $method $args] + set omethod [convert_method $method] + + puts "Test0$tnum: Test of key counts." + + berkdb srand $rand_init + + set eindex [lsearch -exact $args "-env"] + if { $eindex == -1 } { + set testfile $testdir/test0$tnum.db + set env NULL + } else { + set testfile test0$tnum.db + incr eindex + set env [lindex $args $eindex] + } + cleanup $testdir $env + + puts "\tTest0$tnum.a: No duplicates, trivial answer." + set pgindex [lsearch -exact $args "-pagesize"] + if { $pgindex != -1 } { + puts "Test078: skipping for specific pagesizes" + return + } + + set db [eval {berkdb_open -create -truncate -mode 0644\ + -pagesize $pagesize} $omethod $args {$testfile}] + error_check_good db_open [is_valid_db $db] TRUE + + for { set i 1 } { $i <= $nkeys } { incr i } { + error_check_good put.a($i) [$db put $i\ + [pad_data $method $alphabet$i]] 0 + error_check_good count.a [$db count $i] 1 + } + error_check_good db_close.a [$db close] 0 + + if { [is_record_based $method] == 1 || [is_rbtree $method] == 1 } { + puts \ + "\tTest0$tnum.b: Duplicates not supported in $method, skipping." + return + } + + foreach tuple {{b sorted "-dup -dupsort"} {c unsorted "-dup"}} { + set letter [lindex $tuple 0] + set dupopt [lindex $tuple 2] + + puts "\tTest0$tnum.$letter: Duplicates ([lindex $tuple 1])." + + puts "\t\tTest0$tnum.$letter.1: Populating database." + + set db [eval {berkdb_open -create -truncate -mode 0644\ + -pagesize $pagesize} $dupopt $omethod $args {$testfile}] + error_check_good db_open [is_valid_db $db] TRUE + + for { set i 1 } { $i <= $nkeys } { incr i } { + for { set j 0 } { $j < $i } { incr j } { + error_check_good put.$letter,$i [$db put $i\ + [pad_data $method $j$alphabet]] 0 + } + } + + puts -nonewline "\t\tTest0$tnum.$letter.2: " + puts "Verifying dup counts on first dup." + for { set i 1 } { $i < $nkeys } { incr i } { + error_check_good count.$letter,$i \ + [$db count $i] $i + } + + puts -nonewline "\t\tTest0$tnum.$letter.3: " + puts "Verifying dup counts on random dup." + for { set i 1 } { $i < $nkeys } { incr i } { + set key [berkdb random_int 1 $nkeys] + error_check_good count.$letter,$i \ + [$db count $i] $i + } + error_check_good db_close.$letter [$db close] 0 + } +} diff --git a/db/test/test079.tcl b/db/test/test079.tcl new file mode 100644 index 000000000..fe7b978a3 --- /dev/null +++ b/db/test/test079.tcl @@ -0,0 +1,18 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test079.tcl,v 11.5 2000/11/16 23:56:18 ubell Exp $ +# +# DB Test 79 {access method} +# Check that delete operations work in large btrees. 10000 entries and +# a pagesize of 512 push this out to a four-level btree, with a small fraction +# of the entries going on overflow pages. +proc test079 { method {nentries 10000} {pagesize 512} {tnum 79} args} { + if { [ is_queueext $method ] == 1 } { + set method "queue"; + lappend args "-extent" "20" + } + eval {test006 $method $nentries 1 $tnum -pagesize $pagesize} $args +} diff --git a/db/test/test080.tcl b/db/test/test080.tcl new file mode 100644 index 000000000..02a6a7242 --- /dev/null +++ b/db/test/test080.tcl @@ -0,0 +1,41 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test080.tcl,v 11.7 2000/10/19 23:15:22 ubell Exp $ +# +# DB Test 80 {access method} +# Test of dbremove +proc test080 { method {tnum 80} args } { + source ./include.tcl + + set args [convert_args $method $args] + set omethod [convert_method $method] + + puts "Test0$tnum: Test of DB->remove()" + + + set eindex [lsearch -exact $args "-env"] + if { $eindex != -1 } { + puts "\tTest0$tnum: Skipping in the presence of an environment" + return + } + cleanup $testdir NULL + + set testfile $testdir/test0$tnum.db + set db [eval {berkdb_open -create -truncate -mode 0644} $omethod \ + $args {$testfile}] + error_check_good db_open [is_valid_db $db] TRUE + for {set i 1} { $i < 1000 } {incr i} { + $db put $i $i + } + error_check_good db_close [$db close] 0 + + error_check_good file_exists_before [file exists $testfile] 1 + + error_check_good db_remove [berkdb dbremove $testfile] 0 + error_check_good file_exists_after [file exists $testfile] 0 + + puts "\tTest0$tnum succeeded." +} diff --git a/db/test/test081.tcl b/db/test/test081.tcl new file mode 100644 index 000000000..44e708c5d --- /dev/null +++ b/db/test/test081.tcl @@ -0,0 +1,16 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test081.tcl,v 11.3 2000/03/01 15:13:59 krinsky Exp $ +# +# Test 81. +# Test off-page duplicates and overflow pages together with +# very large keys (key/data as file contents). +# +proc test081 { method {ndups 13} {tnum 81} args} { + source ./include.tcl + + eval {test017 $method 1 $ndups $tnum} $args +} diff --git a/db/test/test082.tcl b/db/test/test082.tcl new file mode 100644 index 000000000..e8bd4f975 --- /dev/null +++ b/db/test/test082.tcl @@ -0,0 +1,15 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test082.tcl,v 11.1 2000/04/30 05:05:26 krinsky Exp $ +# +# Test 82. +# Test of DB_PREV_NODUP +proc test082 { method {dir -prevnodup} {pagesize 512} {nitems 100}\ + {tnum 82} args} { + source ./include.tcl + + eval {test074 $method $dir $pagesize $nitems $tnum} $args +} diff --git a/db/test/test083.tcl b/db/test/test083.tcl new file mode 100644 index 000000000..7565a5a74 --- /dev/null +++ b/db/test/test083.tcl @@ -0,0 +1,136 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test083.tcl,v 11.6 2000/12/11 17:24:55 sue Exp $ +# +# Test 83. +# Test of DB->key_range +proc test083 { method {pgsz 512} {maxitems 5000} {step 2} args} { + source ./include.tcl + set omethod [convert_method $method] + set args [convert_args $method $args] + + puts "Test083 $method ($args): Test of DB->key_range" + if { [is_btree $method] != 1 } { + puts "\tTest083: Skipping for method $method." + return + } + set pgindex [lsearch -exact $args "-pagesize"] + if { $pgindex != -1 } { + puts "Test083: skipping for specific pagesizes" + return + } + + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + set eindex [lsearch -exact $args "-env"] + if { $eindex == -1 } { + set testfile $testdir/test083.db + set env NULL + } else { + set testfile test083.db + incr eindex + set env [lindex $args $eindex] + } + + # We assume that numbers will be at most six digits wide + error_check_bad maxitems_range [expr $maxitems > 999999] 1 + + # We want to test key_range on a variety of sizes of btree. + # Start at ten keys and work up to $maxitems keys, at each step + # multiplying the number of keys by $step. + for { set nitems 10 } { $nitems <= $maxitems }\ + { set nitems [expr $nitems * $step] } { + + puts "\tTest083.a: Opening new database" + cleanup $testdir $env + set db [eval {berkdb_open -create -truncate -mode 0644} \ + -pagesize $pgsz $omethod $args $testfile] + error_check_good dbopen [is_valid_db $db] TRUE + + t83_build $db $nitems + t83_test $db $nitems + + error_check_good db_close [$db close] 0 + } +} + +proc t83_build { db nitems } { + source ./include.tcl + + puts "\tTest083.b: Populating database with $nitems keys" + + set keylist {} + puts "\t\tTest083.b.1: Generating key list" + for { set i 0 } { $i < $nitems } { incr i } { + lappend keylist $i + } + + # With randomly ordered insertions, the range of errors we + # get from key_range can be unpredictably high [#2134]. For now, + # just skip the randomization step. + #puts "\t\tTest083.b.2: Randomizing key list" + #set keylist [randomize_list $keylist] + + #puts "\t\tTest083.b.3: Populating database with randomized keys" + + puts "\t\tTest083.b.2: Populating database" + set data [repeat . 50] + + foreach keynum $keylist { + error_check_good db_put [$db put key[format %6d $keynum] \ + $data] 0 + } +} + +proc t83_test { db nitems } { + # Look at the first key, then at keys about 1/4, 1/2, 3/4, and + # all the way through the database. Make sure the key_ranges + # aren't off by more than 10%. + + set dbc [$db cursor] + error_check_good dbc [is_valid_cursor $dbc $db] TRUE + + puts "\tTest083.c: Verifying ranges..." + + for { set i 0 } { $i < $nitems } \ + { incr i [expr $nitems / [berkdb random_int 3 16]] } { + puts "\t\t...key $i" + error_check_bad key0 [llength [set dbt [$dbc get -first]]] 0 + + for { set j 0 } { $j < $i } { incr j } { + error_check_bad key$j \ + [llength [set dbt [$dbc get -next]]] 0 + } + + set ranges [$db keyrange [lindex [lindex $dbt 0] 0]] + + #puts $ranges + error_check_good howmanyranges [llength $ranges] 3 + + set lessthan [lindex $ranges 0] + set morethan [lindex $ranges 2] + + set rangesum [expr $lessthan + [lindex $ranges 1] + $morethan] + + roughly_equal $rangesum 1 0.05 + + # Wild guess. + if { $nitems < 500 } { + set tol 0.3 + } elseif { $nitems > 500 } { + set tol 0.15 + } + + roughly_equal $lessthan [expr $i * 1.0 / $nitems] $tol + + } + + error_check_good dbc_close [$dbc close] 0 +} + +proc roughly_equal { a b tol } { + error_check_good "$a =~ $b" [expr $a - $b < $tol] 1 +} diff --git a/db/test/test084.tcl b/db/test/test084.tcl new file mode 100644 index 000000000..0efd0d17c --- /dev/null +++ b/db/test/test084.tcl @@ -0,0 +1,48 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test084.tcl,v 11.6 2000/12/11 17:24:55 sue Exp $ +# +# Test 84. +# Basic sanity test (test001) with large (64K) pages. +# +proc test084 { method {nentries 10000} {tnum 84} {pagesize 65536} args} { + source ./include.tcl + + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test0$tnum-empty.db + set env NULL + } else { + set testfile test0$tnum-empty.db + incr eindex + set env [lindex $args $eindex] + } + + set pgindex [lsearch -exact $args "-pagesize"] + if { $pgindex != -1 } { + puts "Test084: skipping for specific pagesizes" + return + } + + cleanup $testdir $env + + set args "-pagesize $pagesize $args" + + eval {test001 $method $nentries 0 $tnum} $args + + set omethod [convert_method $method] + set args [convert_args $method $args] + + # For good measure, create a second database that's empty + # with the large page size. (There was a verifier bug that + # choked on empty 64K pages. [#2408]) + set db [eval {berkdb_open -create -mode 0644} $args $omethod $testfile] + error_check_good empty_db [is_valid_db $db] TRUE + error_check_good empty_db_close [$db close] 0 +} diff --git a/db/test/test085.tcl b/db/test/test085.tcl new file mode 100644 index 000000000..09134a00f --- /dev/null +++ b/db/test/test085.tcl @@ -0,0 +1,274 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test085.tcl,v 1.4 2000/12/11 17:24:55 sue Exp $ +# +# DB Test 85: Test of cursor behavior when a cursor is pointing to a deleted +# btree key which then has duplicates added. +proc test085 { method {pagesize 512} {onp 3} {offp 10} {tnum 85} args } { + source ./include.tcl + global alphabet + + set omethod [convert_method $method] + set args [convert_args $method $args] + + + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test0$tnum.db + set env NULL + } else { + set testfile test0$tnum.db + incr eindex + set env [lindex $args $eindex] + } + + set pgindex [lsearch -exact $args "-pagesize"] + if { $pgindex != -1 } { + puts "Test085: skipping for specific pagesizes" + return + } + cleanup $testdir $env + + # Keys must sort $prekey < $key < $postkey. + set prekey "AA" + set key "BBB" + set postkey "CCCC" + + # Make these distinguishable from each other and from the + # alphabets used for the $key's data. + set predatum "1234567890" + set datum $alphabet + set postdatum "0987654321" + + append args " -pagesize $pagesize -dup" + + puts -nonewline "Test0$tnum $omethod ($args): " + + # Skip for all non-btrees. (Rbtrees don't count as btrees, for + # now, since they don't support dups.) + if { [is_btree $method] != 1 } { + puts "Skipping for method $method." + return + } else { + puts "Duplicates w/ deleted item cursor." + } + + # Repeat the test with both on-page and off-page numbers of dups. + foreach ndups "$onp $offp" { + # Put operations we want to test on a cursor set to the + # deleted item, the key to use with them, and what should + # come before and after them given a placement of + # the deleted item at the beginning or end of the dupset. + set final [expr $ndups - 1] + set putops { + {{-before} "" $predatum {[test085_ddatum 0]} beginning} + {{-before} "" {[test085_ddatum $final]} $postdatum end} + {{-current} "" $predatum {[test085_ddatum 0]} beginning} + {{-current} "" {[test085_ddatum $final]} $postdatum end} + {{-keyfirst} $key $predatum {[test085_ddatum 0]} beginning} + {{-keyfirst} $key $predatum {[test085_ddatum 0]} end} + {{-keylast} $key {[test085_ddatum $final]} $postdatum beginning} + {{-keylast} $key {[test085_ddatum $final]} $postdatum end} + {{-after} "" $predatum {[test085_ddatum 0]} beginning} + {{-after} "" {[test085_ddatum $final]} $postdatum end} + } + + # Get operations we want to test on a cursor set to the + # deleted item, any args to get, and the expected key/data pair. + set getops { + {{-current} "" "" "" beginning} + {{-current} "" "" "" end} + {{-next} "" $key {[test085_ddatum 0]} beginning} + {{-next} "" $postkey $postdatum end} + {{-prev} "" $prekey $predatum beginning} + {{-prev} "" $key {[test085_ddatum $final]} end} + {{-first} "" $prekey $predatum beginning} + {{-first} "" $prekey $predatum end} + {{-last} "" $postkey $postdatum beginning} + {{-last} "" $postkey $postdatum end} + {{-nextdup} "" $key {[test085_ddatum 0]} beginning} + {{-nextdup} "" EMPTYLIST "" end} + {{-nextnodup} "" $postkey $postdatum beginning} + {{-nextnodup} "" $postkey $postdatum end} + {{-prevnodup} "" $prekey $predatum beginning} + {{-prevnodup} "" $prekey $predatum end} + } + + foreach pair $getops { + set op [lindex $pair 0] + puts "\tTest0$tnum: Get ($op) with $ndups duplicates,\ + cursor at the [lindex $pair 4]." + set db [eval {berkdb_open -create \ + -truncate -mode 0644} $omethod $args $testfile] + error_check_good "db open" [is_valid_db $db] TRUE + + set dbc [test085_setup $db] + + set beginning [expr [string compare \ + [lindex $pair 4] "beginning"] == 0] + + for { set i 0 } { $i < $ndups } { incr i } { + if { $beginning } { + error_check_good db_put($i) \ + [$db put $key [test085_ddatum $i]] 0 + } else { + set c [$db cursor] + set j [expr $ndups - $i - 1] + error_check_good db_cursor($j) \ + [is_valid_cursor $c $db] TRUE + set d [test085_ddatum $j] + error_check_good dbc_put($j) \ + [$c put -keyfirst $key $d] 0 + error_check_good c_close [$c close] 0 + } + } + + set gargs [lindex $pair 1] + set ekey "" + set edata "" + eval set ekey [lindex $pair 2] + eval set edata [lindex $pair 3] + + set dbt [eval $dbc get $op $gargs] + if { [string compare $ekey EMPTYLIST] == 0 } { + error_check_good dbt($op,$ndups) \ + [llength $dbt] 0 + } else { + error_check_good dbt($op,$ndups) $dbt \ + [list [list $ekey $edata]] + } + error_check_good "dbc close" [$dbc close] 0 + error_check_good "db close" [$db close] 0 + verify_dir $testdir "\t\t" + } + + foreach pair $putops { + # Open and set up database. + set op [lindex $pair 0] + puts "\tTest0$tnum: Put ($op) with $ndups duplicates,\ + cursor at the [lindex $pair 4]." + set db [eval {berkdb_open -create \ + -truncate -mode 0644} $omethod $args $testfile] + error_check_good "db open" [is_valid_db $db] TRUE + + set beginning [expr [string compare \ + [lindex $pair 4] "beginning"] == 0] + + set dbc [test085_setup $db] + + # Put duplicates. + for { set i 0 } { $i < $ndups } { incr i } { + if { $beginning } { + error_check_good db_put($i) \ + [$db put $key [test085_ddatum $i]] 0 + } else { + set c [$db cursor] + set j [expr $ndups - $i - 1] + error_check_good db_cursor($j) \ + [is_valid_cursor $c $db] TRUE + set d [test085_ddatum $j] + error_check_good dbc_put($j) \ + [$c put -keyfirst $key $d] 0 + error_check_good c_close [$c close] 0 + } + } + + # Set up cursors for stability test. + set pre_dbc [$db cursor] + error_check_good pre_set [$pre_dbc get -set $prekey] \ + [list [list $prekey $predatum]] + set post_dbc [$db cursor] + error_check_good post_set [$post_dbc get -set $postkey]\ + [list [list $postkey $postdatum]] + set first_dbc [$db cursor] + error_check_good first_set \ + [$first_dbc get -get_both $key [test085_ddatum 0]] \ + [list [list $key [test085_ddatum 0]]] + set last_dbc [$db cursor] + error_check_good last_set \ + [$last_dbc get -get_both $key [test085_ddatum \ + [expr $ndups - 1]]] \ + [list [list $key [test085_ddatum [expr $ndups -1]]]] + + set k [lindex $pair 1] + set d_before "" + set d_after "" + eval set d_before [lindex $pair 2] + eval set d_after [lindex $pair 3] + set newdatum "NewDatum" + error_check_good dbc_put($op,$ndups) \ + [eval $dbc put $op $k $newdatum] 0 + error_check_good dbc_prev($op,$ndups) \ + [lindex [lindex [$dbc get -prev] 0] 1] \ + $d_before + error_check_good dbc_current($op,$ndups) \ + [lindex [lindex [$dbc get -next] 0] 1] \ + $newdatum + + error_check_good dbc_next($op,$ndups) \ + [lindex [lindex [$dbc get -next] 0] 1] \ + $d_after + + # Verify stability of pre- and post- cursors. + error_check_good pre_stable [$pre_dbc get -current] \ + [list [list $prekey $predatum]] + error_check_good post_stable [$post_dbc get -current] \ + [list [list $postkey $postdatum]] + error_check_good first_stable \ + [$first_dbc get -current] \ + [list [list $key [test085_ddatum 0]]] + error_check_good last_stable \ + [$last_dbc get -current] \ + [list [list $key [test085_ddatum [expr $ndups -1]]]] + + + foreach c "$pre_dbc $post_dbc $first_dbc $last_dbc" { + error_check_good ${c}_close [$c close] 0 + } + + error_check_good "dbc close" [$dbc close] 0 + error_check_good "db close" [$db close] 0 + verify_dir $testdir "\t\t" + } + } +} + + +# Set up the test database; put $prekey, $key, and $postkey with their +# respective data, and then delete $key with a new cursor. Return that +# cursor, still pointing to the deleted item. +proc test085_setup { db } { + upvar key key + upvar prekey prekey + upvar postkey postkey + upvar predatum predatum + upvar postdatum postdatum + + # no one else should ever see this one! + set datum "bbbbbbbb" + + error_check_good pre_put [$db put $prekey $predatum] 0 + error_check_good main_put [$db put $key $datum] 0 + error_check_good post_put [$db put $postkey $postdatum] 0 + + set dbc [$db cursor] + error_check_good db_cursor [is_valid_cursor $dbc $db] TRUE + + error_check_good dbc_getset [$dbc get -get_both $key $datum] \ + [list [list $key $datum]] + + error_check_good dbc_del [$dbc del] 0 + + return $dbc +} + +proc test085_ddatum { a } { + global alphabet + return $a$alphabet +} diff --git a/db/test/test086.tcl b/db/test/test086.tcl new file mode 100644 index 000000000..dc30de8ec --- /dev/null +++ b/db/test/test086.tcl @@ -0,0 +1,162 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test086.tcl,v 11.2 2000/08/25 14:21:58 sue Exp $ + +# Test086: Cursor stability across btree splits w/ subtransaction abort [#2373]. +proc test086 { method args } { + global errorCode + source ./include.tcl + + set tstn 086 + + if { [is_btree $method] != 1 } { + puts "Test$tstn skipping for method $method." + return + } + + set method "-btree" + + puts "\tTest$tstn: Test of cursor stability across aborted\ + btree splits." + + set key "key" + set data "data" + set txn "" + set flags "" + + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then this test won't work. + if { $eindex == -1 } { + # But we will be using our own env... + set testfile test0$tstn.db + } else { + puts "\tTest$tstn: Environment provided; skipping test." + return + } + set t1 $testdir/t1 + env_cleanup $testdir + + set env [berkdb env -create -home $testdir -txn] + error_check_good berkdb_env [is_valid_env $env] TRUE + + puts "\tTest$tstn.a: Create $method database." + set oflags "-create -env $env -mode 0644 $args $method" + set db [eval {berkdb_open} $oflags $testfile] + error_check_good dbopen [is_valid_db $db] TRUE + + set nkeys 5 + # Fill page w/ small key/data pairs, keep at leaf + # + puts "\tTest$tstn.b: Fill page with $nkeys small key/data pairs." + set txn [$env txn] + error_check_good txn [is_valid_txn $txn $env] TRUE + for { set i 0 } { $i < $nkeys } { incr i } { + set ret [$db put -txn $txn key000$i $data$i] + error_check_good dbput $ret 0 + } + error_check_good commit [$txn commit] 0 + + # get db ordering, set cursors + puts "\tTest$tstn.c: Set cursors on each of $nkeys pairs." + set txn [$env txn] + error_check_good txn [is_valid_txn $txn $env] TRUE + for {set i 0; set ret [$db get -txn $txn key000$i]} {\ + $i < $nkeys && [llength $ret] != 0} {\ + incr i; set ret [$db get -txn $txn key000$i]} { + set key_set($i) [lindex [lindex $ret 0] 0] + set data_set($i) [lindex [lindex $ret 0] 1] + set dbc [$db cursor -txn $txn] + set dbc_set($i) $dbc + error_check_good db_cursor:$i [is_substr $dbc_set($i) $db] 1 + set ret [$dbc_set($i) get -set $key_set($i)] + error_check_bad dbc_set($i)_get:set [llength $ret] 0 + } + + # Create child txn. + set ctxn [$env txn -parent $txn] + error_check_good ctxn [is_valid_txn $txn $env] TRUE + + # if mkeys is above 1000, need to adjust below for lexical order + set mkeys 1000 + puts "\tTest$tstn.d: Add $mkeys pairs to force split." + for {set i $nkeys} { $i < $mkeys } { incr i } { + if { $i >= 100 } { + set ret [$db put -txn $ctxn key0$i $data$i] + } elseif { $i >= 10 } { + set ret [$db put -txn $ctxn key00$i $data$i] + } else { + set ret [$db put -txn $ctxn key000$i $data$i] + } + error_check_good dbput:more $ret 0 + } + + puts "\tTest$tstn.e: Abort." + error_check_good ctxn_abort [$ctxn abort] 0 + + + puts "\tTest$tstn.f: Check and see that cursors maintained reference." + for {set i 0} { $i < $nkeys } {incr i} { + set ret [$dbc_set($i) get -current] + error_check_bad dbc$i:get:current [llength $ret] 0 + set ret2 [$dbc_set($i) get -set $key_set($i)] + error_check_bad dbc$i:get:set [llength $ret2] 0 + error_check_good dbc$i:get(match) $ret $ret2 + } + + # Put (and this time keep) the keys that caused the split. + # We'll delete them to test reverse splits. + puts "\tTest$tstn.g: Put back added keys." + for {set i $nkeys} { $i < $mkeys } { incr i } { + if { $i >= 100 } { + set ret [$db put -txn $txn key0$i $data$i] + } elseif { $i >= 10 } { + set ret [$db put -txn $txn key00$i $data$i] + } else { + set ret [$db put -txn $txn key000$i $data$i] + } + error_check_good dbput:more $ret 0 + } + + puts "\tTest$tstn.h: Delete added keys to force reverse split." + set ctxn [$env txn -parent $txn] + error_check_good ctxn [is_valid_txn $txn $env] TRUE + for {set i $nkeys} { $i < $mkeys } { incr i } { + if { $i >= 100 } { + error_check_good db_del:$i [$db del -txn $ctxn key0$i] 0 + } elseif { $i >= 10 } { + error_check_good db_del:$i \ + [$db del -txn $ctxn key00$i] 0 + } else { + error_check_good db_del:$i \ + [$db del -txn $ctxn key000$i] 0 + } + } + + puts "\tTest$tstn.i: Abort." + error_check_good ctxn_abort [$ctxn abort] 0 + + puts "\tTest$tstn.j: Verify cursor reference." + for {set i 0} { $i < $nkeys } {incr i} { + set ret [$dbc_set($i) get -current] + error_check_bad dbc$i:get:current [llength $ret] 0 + set ret2 [$dbc_set($i) get -set $key_set($i)] + error_check_bad dbc$i:get:set [llength $ret2] 0 + error_check_good dbc$i:get(match) $ret $ret2 + } + + puts "\tTest$tstn.j: Cleanup." + # close cursors + for {set i 0} { $i < $nkeys } {incr i} { + error_check_good dbc_close:$i [$dbc_set($i) close] 0 + } + + error_check_good commit [$txn commit] 0 + error_check_good dbclose [$db close] 0 + error_check_good envclose [$env close] 0 + + puts "\tTest$tstn complete." +} diff --git a/db/test/test087.tcl b/db/test/test087.tcl new file mode 100644 index 000000000..7096e6c1c --- /dev/null +++ b/db/test/test087.tcl @@ -0,0 +1,278 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test087.tcl,v 11.6 2000/12/11 17:24:55 sue Exp $ +# +# DB Test 87: Test of cursor stability on duplicate pages w/aborts. +# Does the following: +# a. Initialize things by DB->putting ndups dups and +# setting a reference cursor to point to each. +# b. c_put ndups dups (and correspondingly expanding +# the set of reference cursors) after the last one, making sure +# after each step that all the reference cursors still point to +# the right item. +# c. Ditto, but before the first one. +# d. Ditto, but after each one in sequence first to last. +# e. Ditto, but after each one in sequence from last to first. +# occur relative to the new datum) +# f. Ditto for the two sequence tests, only doing a +# DBC->c_put(DB_CURRENT) of a larger datum instead of adding a +# new one. +proc test087 { method {pagesize 512} {ndups 50} {tnum 87} args } { + source ./include.tcl + global alphabet + + set omethod [convert_method $method] + set args [convert_args $method $args] + + puts "Test0$tnum $omethod ($args): " + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then return + if { $eindex != -1 } { + puts "Environment specified; skipping." + return + } + set pgindex [lsearch -exact $args "-pagesize"] + if { $pgindex != -1 } { + puts "Test087: skipping for specific pagesizes" + return + } + env_cleanup $testdir + set testfile test0$tnum.db + set key "the key" + append args " -pagesize $pagesize -dup" + + if { [is_record_based $method] || [is_rbtree $method] } { + puts "Skipping for method $method." + return + } else { + puts "Cursor stability on dup. pages w/ aborts." + } + + set env [berkdb env -create -home $testdir -txn] + error_check_good env_create [is_valid_env $env] TRUE + + set db [eval {berkdb_open -env $env \ + -create -mode 0644} $omethod $args $testfile] + error_check_good "db open" [is_valid_db $db] TRUE + + # Number of outstanding keys. + set keys 0 + + puts "\tTest0$tnum.a.1: Initializing put loop; $ndups dups, short data." + set txn [$env txn] + error_check_good txn [is_valid_txn $txn $env] TRUE + for { set i 0 } { $i < $ndups } { incr i } { + set datum [makedatum_t73 $i 0] + + error_check_good "db put ($i)" [$db put -txn $txn $key $datum] 0 + + set is_long($i) 0 + incr keys + } + error_check_good txn_commit [$txn commit] 0 + + puts "\tTest0$tnum.a.2: Initializing cursor get loop; $keys dups." + set txn [$env txn] + error_check_good txn [is_valid_txn $txn $env] TRUE + for { set i 0 } { $i < $keys } { incr i } { + set datum [makedatum_t73 $i 0] + + set dbc($i) [$db cursor -txn $txn] + error_check_good "db cursor ($i)"\ + [is_valid_cursor $dbc($i) $db] TRUE + error_check_good "dbc get -get_both ($i)"\ + [$dbc($i) get -get_both $key $datum]\ + [list [list $key $datum]] + } + + puts "\tTest0$tnum.b: Cursor put (DB_KEYLAST); $ndups new dups,\ + short data." + + set ctxn [$env txn -parent $txn] + error_check_good ctxn($i) [is_valid_txn $ctxn $env] TRUE + for { set i 0 } { $i < $ndups } { incr i } { + # !!! keys contains the number of the next dup + # to be added (since they start from zero) + + set datum [makedatum_t73 $keys 0] + set curs [$db cursor -txn $ctxn] + error_check_good "db cursor create" [is_valid_cursor $curs $db]\ + TRUE + error_check_good "c_put(DB_KEYLAST, $keys)"\ + [$curs put -keylast $key $datum] 0 + + # We can't do a verification while a child txn is active, + # or we'll run into trouble when DEBUG_ROP is enabled. + # If this test has trouble, though, uncommenting this + # might be illuminating--it makes things a bit more rigorous + # and works fine when DEBUG_ROP is not enabled. + # verify_t73 is_long dbc $keys $key + error_check_good curs_close [$curs close] 0 + } + error_check_good ctxn_abort [$ctxn abort] 0 + verify_t73 is_long dbc $keys $key + + puts "\tTest0$tnum.c: Cursor put (DB_KEYFIRST); $ndups new dups,\ + short data." + + set ctxn [$env txn -parent $txn] + error_check_good ctxn($i) [is_valid_txn $ctxn $env] TRUE + for { set i 0 } { $i < $ndups } { incr i } { + # !!! keys contains the number of the next dup + # to be added (since they start from zero) + + set datum [makedatum_t73 $keys 0] + set curs [$db cursor -txn $ctxn] + error_check_good "db cursor create" [is_valid_cursor $curs $db]\ + TRUE + error_check_good "c_put(DB_KEYFIRST, $keys)"\ + [$curs put -keyfirst $key $datum] 0 + + # verify_t73 is_long dbc $keys $key + error_check_good curs_close [$curs close] 0 + } + # verify_t73 is_long dbc $keys $key + # verify_t73 is_long dbc $keys $key + error_check_good ctxn_abort [$ctxn abort] 0 + verify_t73 is_long dbc $keys $key + + puts "\tTest0$tnum.d: Cursor put (DB_AFTER) first to last;\ + $keys new dups, short data" + # We want to add a datum after each key from 0 to the current + # value of $keys, which we thus need to save. + set ctxn [$env txn -parent $txn] + error_check_good ctxn($i) [is_valid_txn $ctxn $env] TRUE + set keysnow $keys + for { set i 0 } { $i < $keysnow } { incr i } { + set datum [makedatum_t73 $keys 0] + set curs [$db cursor -txn $ctxn] + error_check_good "db cursor create" [is_valid_cursor $curs $db]\ + TRUE + + # Which datum to insert this guy after. + set curdatum [makedatum_t73 $i 0] + error_check_good "c_get(DB_GET_BOTH, $i)"\ + [$curs get -get_both $key $curdatum]\ + [list [list $key $curdatum]] + error_check_good "c_put(DB_AFTER, $i)"\ + [$curs put -after $datum] 0 + + # verify_t73 is_long dbc $keys $key + error_check_good curs_close [$curs close] 0 + } + error_check_good ctxn_abort [$ctxn abort] 0 + verify_t73 is_long dbc $keys $key + + puts "\tTest0$tnum.e: Cursor put (DB_BEFORE) last to first;\ + $keys new dups, short data" + set ctxn [$env txn -parent $txn] + error_check_good ctxn($i) [is_valid_txn $ctxn $env] TRUE + for { set i [expr $keys - 1] } { $i >= 0 } { incr i -1 } { + set datum [makedatum_t73 $keys 0] + set curs [$db cursor -txn $ctxn] + error_check_good "db cursor create" [is_valid_cursor $curs $db]\ + TRUE + + # Which datum to insert this guy before. + set curdatum [makedatum_t73 $i 0] + error_check_good "c_get(DB_GET_BOTH, $i)"\ + [$curs get -get_both $key $curdatum]\ + [list [list $key $curdatum]] + error_check_good "c_put(DB_BEFORE, $i)"\ + [$curs put -before $datum] 0 + + # verify_t73 is_long dbc $keys $key + error_check_good curs_close [$curs close] 0 + } + error_check_good ctxn_abort [$ctxn abort] 0 + verify_t73 is_long dbc $keys $key + + puts "\tTest0$tnum.f: Cursor put (DB_CURRENT), first to last,\ + growing $keys data." + set ctxn [$env txn -parent $txn] + error_check_good ctxn($i) [is_valid_txn $ctxn $env] TRUE + for { set i 0 } { $i < $keysnow } { incr i } { + set olddatum [makedatum_t73 $i 0] + set newdatum [makedatum_t73 $i 1] + set curs [$db cursor -txn $ctxn] + error_check_good "db cursor create" [is_valid_cursor $curs $db]\ + TRUE + + error_check_good "c_get(DB_GET_BOTH, $i)"\ + [$curs get -get_both $key $olddatum]\ + [list [list $key $olddatum]] + error_check_good "c_put(DB_CURRENT, $i)"\ + [$curs put -current $newdatum] 0 + + set is_long($i) 1 + + # verify_t73 is_long dbc $keys $key + error_check_good curs_close [$curs close] 0 + } + error_check_good ctxn_abort [$ctxn abort] 0 + for { set i 0 } { $i < $keysnow } { incr i } { + set is_long($i) 0 + } + verify_t73 is_long dbc $keys $key + + # Now delete the first item, abort the deletion, and make sure + # we're still sane. + puts "\tTest0$tnum.g: Cursor delete first item, then abort delete." + set ctxn [$env txn -parent $txn] + error_check_good ctxn($i) [is_valid_txn $ctxn $env] TRUE + set curs [$db cursor -txn $ctxn] + error_check_good "db cursor create" [is_valid_cursor $curs $db] TRUE + set datum [makedatum_t73 0 0] + error_check_good "c_get(DB_GET_BOTH, 0)"\ + [$curs get -get_both $key $datum] [list [list $key $datum]] + error_check_good "c_del(0)" [$curs del] 0 + error_check_good curs_close [$curs close] 0 + error_check_good ctxn_abort [$ctxn abort] 0 + verify_t73 is_long dbc $keys $key + + # Ditto, for the last item. + puts "\tTest0$tnum.h: Cursor delete last item, then abort delete." + set ctxn [$env txn -parent $txn] + error_check_good ctxn($i) [is_valid_txn $ctxn $env] TRUE + set curs [$db cursor -txn $ctxn] + error_check_good "db cursor create" [is_valid_cursor $curs $db] TRUE + set datum [makedatum_t73 [expr $keys - 1] 0] + error_check_good "c_get(DB_GET_BOTH, [expr $keys - 1])"\ + [$curs get -get_both $key $datum] [list [list $key $datum]] + error_check_good "c_del(0)" [$curs del] 0 + error_check_good curs_close [$curs close] 0 + error_check_good ctxn_abort [$ctxn abort] 0 + verify_t73 is_long dbc $keys $key + + # Ditto, for all the items. + puts "\tTest0$tnum.i: Cursor delete all items, then abort delete." + set ctxn [$env txn -parent $txn] + error_check_good ctxn($i) [is_valid_txn $ctxn $env] TRUE + set curs [$db cursor -txn $ctxn] + error_check_good "db cursor create" [is_valid_cursor $curs $db] TRUE + set datum [makedatum_t73 0 0] + error_check_good "c_get(DB_GET_BOTH, 0)"\ + [$curs get -get_both $key $datum] [list [list $key $datum]] + error_check_good "c_del(0)" [$curs del] 0 + for { set i 1 } { $i < $keys } { incr i } { + error_check_good "c_get(DB_NEXT, $i)"\ + [$curs get -next] [list [list $key [makedatum_t73 $i 0]]] + error_check_good "c_del($i)" [$curs del] 0 + } + error_check_good curs_close [$curs close] 0 + error_check_good ctxn_abort [$ctxn abort] 0 + verify_t73 is_long dbc $keys $key + + # Close cursors. + puts "\tTest0$tnum.j: Closing cursors." + for { set i 0 } { $i < $keys } { incr i } { + error_check_good "dbc close ($i)" [$dbc($i) close] 0 + } + error_check_good txn_commit [$txn commit] 0 + error_check_good "db close" [$db close] 0 + error_check_good "env close" [$env close] 0 +} diff --git a/db/test/test088.tcl b/db/test/test088.tcl new file mode 100644 index 000000000..d7b0f815a --- /dev/null +++ b/db/test/test088.tcl @@ -0,0 +1,142 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test088.tcl,v 11.4 2000/12/11 17:24:55 sue Exp $ +# +# Test088: Cursor stability across btree splits with very deep trees. +# (Variant of test048, SR #2514.) +proc test088 { method args } { + global errorCode alphabet + source ./include.tcl + + set tstn 088 + + if { [is_btree $method] != 1 } { + puts "Test$tstn skipping for method $method." + return + } + set pgindex [lsearch -exact $args "-pagesize"] + if { $pgindex != -1 } { + puts "Test088: skipping for specific pagesizes" + return + } + + set method "-btree" + + puts "\tTest$tstn: Test of cursor stability across btree splits." + + set key "key$alphabet$alphabet$alphabet" + set data "data$alphabet$alphabet$alphabet" + set txn "" + set flags "" + + puts "\tTest$tstn.a: Create $method database." + set eindex [lsearch -exact $args "-env"] + # + # If we are using an env, then testfile should just be the db name. + # Otherwise it is the test directory and the name. + if { $eindex == -1 } { + set testfile $testdir/test$tstn.db + set env NULL + } else { + set testfile test$tstn.db + incr eindex + set env [lindex $args $eindex] + } + set t1 $testdir/t1 + cleanup $testdir $env + + set ps 512 + set oflags "-create -pagesize $ps -truncate -mode 0644 $args $method" + set db [eval {berkdb_open} $oflags $testfile] + error_check_good dbopen [is_valid_db $db] TRUE + + set nkeys 5 + # Fill page w/ key/data pairs. + # + puts "\tTest$tstn.b: Fill page with $nkeys small key/data pairs." + for { set i 0 } { $i < $nkeys } { incr i } { + set ret [$db put ${key}00000$i $data$i] + error_check_good dbput $ret 0 + } + + # get db ordering, set cursors + puts "\tTest$tstn.c: Set cursors on each of $nkeys pairs." + for {set i 0; set ret [$db get ${key}00000$i]} {\ + $i < $nkeys && [llength $ret] != 0} {\ + incr i; set ret [$db get ${key}00000$i]} { + set key_set($i) [lindex [lindex $ret 0] 0] + set data_set($i) [lindex [lindex $ret 0] 1] + set dbc [$db cursor] + set dbc_set($i) $dbc + error_check_good db_cursor:$i [is_substr $dbc_set($i) $db] 1 + set ret [$dbc_set($i) get -set $key_set($i)] + error_check_bad dbc_set($i)_get:set [llength $ret] 0 + } + + # if mkeys is above 1000, need to adjust below for lexical order + set mkeys 30000 + puts "\tTest$tstn.d: Add $mkeys pairs to force splits." + for {set i $nkeys} { $i < $mkeys } { incr i } { + if { $i >= 10000 } { + set ret [$db put ${key}0$i $data$i] + } elseif { $i >= 1000 } { + set ret [$db put ${key}00$i $data$i] + } elseif { $i >= 100 } { + set ret [$db put ${key}000$i $data$i] + } elseif { $i >= 10 } { + set ret [$db put ${key}0000$i $data$i] + } else { + set ret [$db put ${key}00000$i $data$i] + } + error_check_good dbput:more $ret 0 + } + + puts "\tTest$tstn.e: Make sure splits happened." + error_check_bad stat:check-split [is_substr [$db stat] \ + "{{Internal pages} 0}"] 1 + + puts "\tTest$tstn.f: Check to see that cursors maintained reference." + for {set i 0} { $i < $nkeys } {incr i} { + set ret [$dbc_set($i) get -current] + error_check_bad dbc$i:get:current [llength $ret] 0 + set ret2 [$dbc_set($i) get -set $key_set($i)] + error_check_bad dbc$i:get:set [llength $ret2] 0 + error_check_good dbc$i:get(match) $ret $ret2 + } + + puts "\tTest$tstn.g: Delete added keys to force reverse splits." + for {set i $nkeys} { $i < $mkeys } { incr i } { + if { $i >= 10000 } { + error_check_good db_del:$i [$db del ${key}0$i] 0 + } elseif { $i >= 1000 } { + error_check_good db_del:$i [$db del ${key}00$i] 0 + } elseif { $i >= 100 } { + error_check_good db_del:$i [$db del ${key}000$i] 0 + } elseif { $i >= 10 } { + error_check_good db_del:$i [$db del ${key}0000$i] 0 + } else { + error_check_good db_del:$i [$db del ${key}00000$i] 0 + } + } + + puts "\tTest$tstn.h: Verify cursor reference." + for {set i 0} { $i < $nkeys } {incr i} { + set ret [$dbc_set($i) get -current] + error_check_bad dbc$i:get:current [llength $ret] 0 + set ret2 [$dbc_set($i) get -set $key_set($i)] + error_check_bad dbc$i:get:set [llength $ret2] 0 + error_check_good dbc$i:get(match) $ret $ret2 + } + + puts "\tTest$tstn.i: Cleanup." + # close cursors + for {set i 0} { $i < $nkeys } {incr i} { + error_check_good dbc_close:$i [$dbc_set($i) close] 0 + } + error_check_good dbclose [$db close] 0 + + puts "\tTest$tstn complete." +} diff --git a/db/test/test090.tcl b/db/test/test090.tcl new file mode 100644 index 000000000..ed6ec9632 --- /dev/null +++ b/db/test/test090.tcl @@ -0,0 +1,20 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test090.tcl,v 11.4 2000/12/11 17:24:56 sue Exp $ +# +# DB Test 90 {access method} +# Check for functionality near the end of the queue. +# +# +proc test090 { method {nentries 1000} {txn -txn} {tnum "90"} args} { + if { [is_queueext $method ] == 0 } { + puts "Skipping test0$tnum for $method." + return; + } + eval {test001 $method $nentries 4294967000 $tnum} $args + eval {test025 $method $nentries 4294967000 $tnum} $args + eval {test070 $method 4 2 $nentries WAIT 4294967000 $txn $tnum} $args +} diff --git a/db/test/test091.tcl b/db/test/test091.tcl new file mode 100644 index 000000000..9420b571c --- /dev/null +++ b/db/test/test091.tcl @@ -0,0 +1,21 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: test091.tcl,v 11.4 2000/12/01 04:28:36 ubell Exp $ +# +# DB Test 91 {access method} +# Check for CONSUME_WAIT functionality +# +proc test091 { method {nconsumers 4} \ + {nproducers 2} {nitems 1000} {start 0 } {tnum "91"} args} { + if { [is_queue $method ] == 0 } { + puts "Skipping test0$tnum for $method." + return; + } + eval {test070 $method \ + $nconsumers $nproducers $nitems WAIT $start -txn $tnum } $args + eval {test070 $method \ + $nconsumers $nproducers $nitems WAIT $start -cdb $tnum } $args +} diff --git a/db/test/testparams.tcl b/db/test/testparams.tcl new file mode 100644 index 000000000..2def6a9d0 --- /dev/null +++ b/db/test/testparams.tcl @@ -0,0 +1,115 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: testparams.tcl,v 11.39 2001/01/11 17:29:42 sue Exp $ + +set deadtests 3 +set envtests 8 +set recdtests 13 +set rsrctests 3 +set runtests 93 +set subdbtests 10 +set rpctests 2 + +set parms(subdb001) "" +set parms(subdb002) 10000 +set parms(subdb003) 1000 +set parms(subdb004) "" +set parms(subdb005) 100 +set parms(subdb006) 100 +set parms(subdb007) 10000 +set parms(subdb008) 10000 +set parms(subdb009) "" +set parms(subdb010) "" +set parms(test001) {10000 0 "01"} +set parms(test002) 10000 +set parms(test003) "" +set parms(test004) {10000 4 0} +set parms(test005) 10000 +set parms(test006) {10000 0 6} +set parms(test007) {10000 7} +set parms(test008) {10000 8 0} +set parms(test009) 10000 +set parms(test010) {10000 5 10} +set parms(test011) {10000 5 11} +set parms(test012) "" +set parms(test013) 10000 +set parms(test014) 10000 +set parms(test015) {7500 0} +set parms(test016) 10000 +set parms(test017) {0 19 17} +set parms(test018) 10000 +set parms(test019) 10000 +set parms(test020) 10000 +set parms(test021) 10000 +set parms(test022) "" +set parms(test023) "" +set parms(test024) 10000 +set parms(test025) {10000 0 25} +set parms(test026) {2000 5 26} +set parms(test027) {100} +set parms(test028) "" +set parms(test029) 10000 +set parms(test030) 10000 +set parms(test031) {10000 5 31} +set parms(test032) {10000 5 32} +set parms(test033) {10000 5 33} +set parms(test034) 10000 +set parms(test035) 10000 +set parms(test036) 10000 +set parms(test037) 100 +set parms(test038) {10000 5 38} +set parms(test039) {10000 5 39} +set parms(test040) 10000 +set parms(test041) 10000 +set parms(test042) 1000 +set parms(test043) 10000 +set parms(test044) {5 10 0} +set parms(test045) 1000 +set parms(test046) "" +set parms(test047) "" +set parms(test048) "" +set parms(test049) "" +set parms(test050) "" +set parms(test051) "" +set parms(test052) "" +set parms(test053) "" +set parms(test054) "" +set parms(test055) "" +set parms(test056) "" +set parms(test057) "" +set parms(test058) "" +set parms(test059) "" +set parms(test060) "" +set parms(test061) "" +set parms(test062) {200 200 62} +set parms(test063) "" +set parms(test064) "" +set parms(test065) "" +set parms(test066) "" +set parms(test067) {1000 67} +set parms(test068) "" +set parms(test069) {50 69} +set parms(test070) {4 2 1000 CONSUME 0 -txn 70} +set parms(test071) {1 1 10000 CONSUME 0 -txn 71} +set parms(test072) {512 20 72} +set parms(test073) {512 50 73} +set parms(test074) {-nextnodup 512 100 74} +set parms(test075) {75} +set parms(test076) {1000 76} +set parms(test077) {1000 512 77} +set parms(test078) {100 512 78} +set parms(test079) {10000 512 79} +set parms(test080) {80} +set parms(test081) {13 81} +set parms(test082) {-prevnodup 512 100 82} +set parms(test083) {512 5000 2} +set parms(test084) {10000 84 65536} +set parms(test085) {512 3 10 85} +set parms(test086) "" +set parms(test087) {512 50 87} +set parms(test088) "" +set parms(test090) {1000 -txn 90} +set parms(test091) {4 2 1000 0 91} diff --git a/db/test/testutils.tcl b/db/test/testutils.tcl new file mode 100644 index 000000000..c5edaef7f --- /dev/null +++ b/db/test/testutils.tcl @@ -0,0 +1,2380 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: testutils.tcl,v 11.86 2001/01/18 23:21:14 krinsky Exp $ +# +# Test system utilities +# +# Timestamp -- print time along with elapsed time since last invocation +# of timestamp. +proc timestamp {{opt ""}} { + global __timestamp_start + + if {[string compare $opt "-r"] == 0} { + clock seconds + } elseif {[string compare $opt "-t"] == 0} { + # -t gives us the current time in the format expected by + # db_recover -t. + return [clock format [clock seconds] -format "%y%m%d%H%M.%S"] + } else { + set now [clock seconds] + + if {[catch {set start $__timestamp_start}] != 0} { + set __timestamp_start $now + } + set start $__timestamp_start + + set elapsed [expr $now - $start] + set the_time [clock format $now -format ""] + set __timestamp_start $now + + format "%02d:%02d:%02d (%02d:%02d:%02d)" \ + [__fix_num [clock format $now -format "%H"]] \ + [__fix_num [clock format $now -format "%M"]] \ + [__fix_num [clock format $now -format "%S"]] \ + [expr $elapsed / 3600] \ + [expr ($elapsed % 3600) / 60] \ + [expr ($elapsed % 3600) % 60] + } +} + +proc __fix_num { num } { + set num [string trimleft $num "0"] + if {[string length $num] == 0} { + set num "0" + } + return $num +} + +# Add a {key,data} pair to the specified database where +# key=filename and data=file contents. +proc put_file { db txn flags file } { + source ./include.tcl + + set fid [open $file r] + fconfigure $fid -translation binary + set data [read $fid] + close $fid + + set ret [eval {$db put} $txn $flags {$file $data}] + error_check_good put_file $ret 0 +} + +# Get a {key,data} pair from the specified database where +# key=filename and data=file contents and then write the +# data to the specified file. +proc get_file { db txn flags file outfile } { + source ./include.tcl + + set fid [open $outfile w] + fconfigure $fid -translation binary + if [catch {eval {$db get} $txn $flags {$file}} data] { + puts -nonewline $fid $data + } else { + # Data looks like {{key data}} + set data [lindex [lindex $data 0] 1] + puts -nonewline $fid $data + } + close $fid +} + +# Add a {key,data} pair to the specified database where +# key=file contents and data=file name. +proc put_file_as_key { db txn flags file } { + source ./include.tcl + + set fid [open $file r] + fconfigure $fid -translation binary + set filecont [read $fid] + close $fid + + # Use not the file contents, but the file name concatenated + # before the file contents, as a key, to ensure uniqueness. + set data $file$filecont + + set ret [eval {$db put} $txn $flags {$data $file}] + error_check_good put_file $ret 0 +} + +# Get a {key,data} pair from the specified database where +# key=file contents and data=file name +proc get_file_as_key { db txn flags file} { + source ./include.tcl + + set fid [open $file r] + fconfigure $fid -translation binary + set filecont [read $fid] + close $fid + + set data $file$filecont + + return [eval {$db get} $txn $flags {$data}] +} + +# open file and call dump_file to dumpkeys to tempfile +proc open_and_dump_file { + dbname dbenv txn outfile checkfunc dump_func beg cont} { + source ./include.tcl + if { $dbenv == "NULL" } { + set db [berkdb open -rdonly -unknown $dbname] + error_check_good dbopen [is_valid_db $db] TRUE + } else { + set db [berkdb open -env $dbenv -rdonly -unknown $dbname] + error_check_good dbopen [is_valid_db $db] TRUE + } + $dump_func $db $txn $outfile $checkfunc $beg $cont + error_check_good db_close [$db close] 0 +} + +# open file and call dump_file to dumpkeys to tempfile +proc open_and_dump_subfile { + dbname dbenv txn outfile checkfunc dump_func beg cont subdb} { + source ./include.tcl + + if { $dbenv == "NULL" } { + set db [berkdb open -rdonly -unknown $dbname $subdb] + error_check_good dbopen [is_valid_db $db] TRUE + } else { + set db [berkdb open -env $dbenv -rdonly -unknown $dbname $subdb] + error_check_good dbopen [is_valid_db $db] TRUE + } + $dump_func $db $txn $outfile $checkfunc $beg $cont + error_check_good db_close [$db close] 0 +} + +# Sequentially read a file and call checkfunc on each key/data pair. +# Dump the keys out to the file specified by outfile. +proc dump_file { db txn outfile checkfunc } { + source ./include.tcl + + dump_file_direction $db $txn $outfile $checkfunc "-first" "-next" +} + +proc dump_file_direction { db txn outfile checkfunc start continue } { + source ./include.tcl + + set outf [open $outfile w] + # Now we will get each key from the DB and dump to outfile + set c [eval {$db cursor} $txn] + error_check_good db_cursor [is_valid_cursor $c $db] TRUE + for {set d [$c get $start] } { [llength $d] != 0 } { + set d [$c get $continue] } { + set kd [lindex $d 0] + set k [lindex $kd 0] + set d2 [lindex $kd 1] + $checkfunc $k $d2 + puts $outf $k + # XXX: Geoff Mainland + # puts $outf "$k $d2" + } + close $outf + error_check_good curs_close [$c close] 0 +} + +proc dump_binkey_file { db txn outfile checkfunc } { + source ./include.tcl + + dump_binkey_file_direction $db $txn $outfile $checkfunc \ + "-first" "-next" +} +proc dump_bin_file { db txn outfile checkfunc } { + source ./include.tcl + + dump_bin_file_direction $db $txn $outfile $checkfunc "-first" "-next" +} + +# Note: the following procedure assumes that the binary-file-as-keys were +# inserted into the database by put_file_as_key, and consist of the file +# name followed by the file contents as key, to ensure uniqueness. +proc dump_binkey_file_direction { db txn outfile checkfunc begin cont } { + source ./include.tcl + + set d1 $testdir/d1 + + set outf [open $outfile w] + + # Now we will get each key from the DB and dump to outfile + set c [eval {$db cursor} $txn] + error_check_good db_cursor [is_valid_cursor $c $db] TRUE + + set inf $d1 + for {set d [$c get $begin] } { [llength $d] != 0 } \ + {set d [$c get $cont] } { + set kd [lindex $d 0] + set keyfile [lindex $kd 0] + set data [lindex $kd 1] + + set ofid [open $d1 w] + fconfigure $ofid -translation binary + + # Chop off the first few bytes--that's the file name, + # added for uniqueness in put_file_as_key, which we don't + # want in the regenerated file. + set namelen [string length $data] + set keyfile [string range $keyfile $namelen end] + puts -nonewline $ofid $keyfile + close $ofid + + $checkfunc $data $d1 + puts $outf $data + flush $outf + } + close $outf + error_check_good curs_close [$c close] 0 + fileremove $d1 +} + +proc dump_bin_file_direction { db txn outfile checkfunc begin cont } { + source ./include.tcl + + set d1 $testdir/d1 + + set outf [open $outfile w] + + # Now we will get each key from the DB and dump to outfile + set c [eval {$db cursor} $txn] + + for {set d [$c get $begin] } \ + { [llength $d] != 0 } {set d [$c get $cont] } { + set k [lindex [lindex $d 0] 0] + set data [lindex [lindex $d 0] 1] + set ofid [open $d1 w] + fconfigure $ofid -translation binary + puts -nonewline $ofid $data + close $ofid + + $checkfunc $k $d1 + puts $outf $k + } + close $outf + error_check_good curs_close [$c close] 0 + fileremove -f $d1 +} + +proc make_data_str { key } { + set datastr "" + for {set i 0} {$i < 10} {incr i} { + append datastr $key + } + return $datastr +} + +proc error_check_bad { func result bad {txn 0}} { + if { [binary_compare $result $bad] == 0 } { + if { $txn != 0 } { + $txn abort + } + flush stdout + flush stderr + error "FAIL:[timestamp] $func returned error value $bad" + } +} + +proc error_check_good { func result desired {txn 0} } { + if { [binary_compare $desired $result] != 0 } { + if { $txn != 0 } { + $txn abort + } + flush stdout + flush stderr + error "FAIL:[timestamp]\ + $func: expected $desired, got $result" + } +} + +# Locks have the prefix of their manager. +proc is_substr { l mgr } { + if { [string first $mgr $l] == -1 } { + return 0 + } else { + return 1 + } +} + +proc release_list { l } { + + # Now release all the locks + foreach el $l { + set ret [$el put] + error_check_good lock_put $ret 0 + } +} + +proc debug { {stop 0} } { + global __debug_on + global __debug_print + global __debug_test + + set __debug_on 1 + set __debug_print 1 + set __debug_test $stop +} + +# Check if each key appears exactly [llength dlist] times in the file with +# the duplicate tags matching those that appear in dlist. +proc dup_check { db txn tmpfile dlist {extra 0}} { + source ./include.tcl + + set outf [open $tmpfile w] + # Now we will get each key from the DB and dump to outfile + set c [eval {$db cursor} $txn] + set lastkey "" + set done 0 + while { $done != 1} { + foreach did $dlist { + set rec [$c get "-next"] + if { [string length $rec] == 0 } { + set done 1 + break + } + set key [lindex [lindex $rec 0] 0] + set fulldata [lindex [lindex $rec 0] 1] + set id [id_of $fulldata] + set d [data_of $fulldata] + if { [string compare $key $lastkey] != 0 && \ + $id != [lindex $dlist 0] } { + set e [lindex $dlist 0] + error "FAIL: \tKey \ + $key, expected dup id $e, got $id" + } + error_check_good dupget.data $d $key + error_check_good dupget.id $id $did + set lastkey $key + } + # + # Some tests add an extra dup (like overflow entries) + # Check id if it exists. + if { $extra != 0} { + set okey $key + set rec [$c get "-next"] + if { [string length $rec] != 0 } { + set key [lindex [lindex $rec 0] 0] + # + # If this key has no extras, go back for + # next iteration. + if { [string compare $key $lastkey] != 0 } { + set key $okey + set rec [$c get "-prev"] + } else { + set fulldata [lindex [lindex $rec 0] 1] + set id [id_of $fulldata] + set d [data_of $fulldata] + error_check_bad dupget.data1 $d $key + error_check_good dupget.id1 $id $extra + } + } + } + if { $done != 1 } { + puts $outf $key + } + } + close $outf + error_check_good curs_close [$c close] 0 +} + +# Parse duplicate data entries of the form N:data. Data_of returns +# the data part; id_of returns the numerical part +proc data_of {str} { + set ndx [string first ":" $str] + if { $ndx == -1 } { + return "" + } + return [ string range $str [expr $ndx + 1] end] +} + +proc id_of {str} { + set ndx [string first ":" $str] + if { $ndx == -1 } { + return "" + } + + return [ string range $str 0 [expr $ndx - 1]] +} + +proc nop { {args} } { + return +} + +# Partial put test procedure. +# Munges a data val through three different partial puts. Stores +# the final munged string in the dvals array so that you can check +# it later (dvals should be global). We take the characters that +# are being replaced, make them capitals and then replicate them +# some number of times (n_add). We do this at the beginning of the +# data, at the middle and at the end. The parameters are: +# db, txn, key -- as per usual. Data is the original data element +# from which we are starting. n_replace is the number of characters +# that we will replace. n_add is the number of times we will add +# the replaced string back in. +proc partial_put { method db txn gflags key data n_replace n_add } { + global dvals + source ./include.tcl + + # Here is the loop where we put and get each key/data pair + # We will do the initial put and then three Partial Puts + # for the beginning, middle and end of the string. + + eval {$db put} $txn {$key [chop_data $method $data]} + + # Beginning change + set s [string range $data 0 [ expr $n_replace - 1 ] ] + set repl [ replicate [string toupper $s] $n_add ] + + # This is gross, but necessary: if this is a fixed-length + # method, and the chopped length of $repl is zero, + # it's because the original string was zero-length and our data item + # is all nulls. Set repl to something non-NULL. + if { [is_fixed_length $method] && \ + [string length [chop_data $method $repl]] == 0 } { + set repl [replicate "." $n_add] + } + + set newstr [chop_data $method $repl[string range $data $n_replace end]] + set ret [eval {$db put} $txn {-partial [list 0 $n_replace] \ + $key [chop_data $method $repl]}] + error_check_good put $ret 0 + + set ret [eval {$db get} $gflags $txn {$key}] + error_check_good get $ret [list [list $key [pad_data $method $newstr]]] + + # End Change + set len [string length $newstr] + set spl [expr $len - $n_replace] + # Handle case where $n_replace > $len + if { $spl < 0 } { + set spl 0 + } + + set s [string range $newstr [ expr $len - $n_replace ] end ] + # Handle zero-length keys + if { [string length $s] == 0 } { set s "A" } + + set repl [ replicate [string toupper $s] $n_add ] + set newstr [chop_data $method \ + [string range $newstr 0 [expr $spl - 1 ] ]$repl] + + set ret [eval {$db put} $txn \ + {-partial [list $spl $n_replace] $key [chop_data $method $repl]}] + error_check_good put $ret 0 + + set ret [eval {$db get} $gflags $txn {$key}] + error_check_good get $ret [list [list $key [pad_data $method $newstr]]] + + # Middle Change + set len [string length $newstr] + set mid [expr $len / 2 ] + set beg [expr $mid - [expr $n_replace / 2] ] + set end [expr $beg + $n_replace - 1] + set s [string range $newstr $beg $end] + set repl [ replicate [string toupper $s] $n_add ] + set newstr [chop_data $method [string range $newstr 0 \ + [expr $beg - 1 ] ]$repl[string range $newstr [expr $end + 1] end]] + + set ret [eval {$db put} $txn {-partial [list $beg $n_replace] \ + $key [chop_data $method $repl]}] + error_check_good put $ret 0 + + set ret [eval {$db get} $gflags $txn {$key}] + error_check_good get $ret [list [list $key [pad_data $method $newstr]]] + + set dvals($key) [pad_data $method $newstr] +} + +proc replicate { str times } { + set res $str + for { set i 1 } { $i < $times } { set i [expr $i * 2] } { + append res $res + } + return $res +} + +proc repeat { str n } { + set ret "" + while { $n > 0 } { + set ret $str$ret + incr n -1 + } + return $ret +} + +proc isqrt { l } { + set s [expr sqrt($l)] + set ndx [expr [string first "." $s] - 1] + return [string range $s 0 $ndx] +} + +# If we run watch_procs multiple times without an intervening +# testdir cleanup, it's possible that old sentinel files will confuse +# us. Make sure they're wiped out before we spawn any other processes. +proc sentinel_init { } { + source ./include.tcl + + set filelist {} + set ret [catch {glob $testdir/begin.*} result] + if { $ret == 0 } { + set filelist $result + } + + set ret [catch {glob $testdir/end.*} result] + if { $ret == 0 } { + set filelist [concat $filelist $result] + } + + foreach f $filelist { + fileremove $f + } +} + +proc watch_procs { {delay 30} {max 3600} } { + source ./include.tcl + + set elapsed 0 + while { 1 } { + + tclsleep $delay + incr elapsed $delay + + # Find the list of processes withoutstanding sentinel + # files (i.e. a begin.pid and no end.pid). + set beginlist {} + set endlist {} + set ret [catch {glob $testdir/begin.*} result] + if { $ret == 0 } { + set beginlist $result + } + set ret [catch {glob $testdir/end.*} result] + if { $ret == 0 } { + set endlist $result + } + + set bpids {} + catch {unset epids} + foreach begfile $beginlist { + lappend bpids [string range $begfile \ + [string length $testdir/begin.] end] + } + foreach endfile $endlist { + set epids([string range $endfile \ + [string length $testdir/end.] end]) 1 + } + + # The set of processes that we still want to watch, $l, + # is the set of pids that have begun but not ended + # according to their sentinel files. + set l {} + foreach p $bpids { + if { [info exists epids($p)] == 0 } { + lappend l $p + } + } + + set rlist {} + foreach i $l { + set r [ catch { exec $KILL -0 $i } result ] + if { $r == 0 } { + lappend rlist $i + } + } + if { [ llength $rlist] == 0 } { + break + } else { + puts "[timestamp] processes running: $rlist" + } + + if { $elapsed > $max } { + # We have exceeded the limit; kill processes + # and report an error + set rlist {} + foreach i $l { + set r [catch { exec $KILL $i } result] + if { $r == 0 } { + lappend rlist $i + } + } + error_check_good "Processes still running" \ + [llength $rlist] 0 + } + } + puts "All processes have exited." +} + +# These routines are all used from within the dbscript.tcl tester. +proc db_init { dbp do_data } { + global a_keys + global l_keys + source ./include.tcl + + set txn "" + set nk 0 + set lastkey "" + + set a_keys() BLANK + set l_keys "" + + set c [$dbp cursor] + for {set d [$c get -first] } { [llength $d] != 0 } { + set d [$c get -next] } { + set k [lindex [lindex $d 0] 0] + set d2 [lindex [lindex $d 0] 1] + incr nk + if { $do_data == 1 } { + if { [info exists a_keys($k)] } { + lappend a_keys($k) $d2] + } else { + set a_keys($k) $d2 + } + } + + lappend l_keys $k + } + error_check_good curs_close [$c close] 0 + + return $nk +} + +proc pick_op { min max n } { + if { $n == 0 } { + return add + } + + set x [berkdb random_int 1 12] + if {$n < $min} { + if { $x <= 4 } { + return put + } elseif { $x <= 8} { + return get + } else { + return add + } + } elseif {$n > $max} { + if { $x <= 4 } { + return put + } elseif { $x <= 8 } { + return get + } else { + return del + } + + } elseif { $x <= 3 } { + return del + } elseif { $x <= 6 } { + return get + } elseif { $x <= 9 } { + return put + } else { + return add + } +} + +# random_data: Generate a string of random characters. +# If recno is 0 - Use average to pick a length between 1 and 2 * avg. +# If recno is non-0, generate a number between 1 and 2 ^ (avg * 2), +# that will fit into a 32-bit integer. +# If the unique flag is 1, then make sure that the string is unique +# in the array "where". +proc random_data { avg unique where {recno 0} } { + upvar #0 $where arr + global debug_on + set min 1 + set max [expr $avg+$avg-1] + if { $recno } { + # + # Tcl seems to have problems with values > 30. + # + if { $max > 30 } { + set max 30 + } + set maxnum [expr int(pow(2, $max))] + } + while {1} { + set len [berkdb random_int $min $max] + set s "" + if {$recno} { + set s [berkdb random_int 1 $maxnum] + } else { + for {set i 0} {$i < $len} {incr i} { + append s [int_to_char [berkdb random_int 0 25]] + } + } + + if { $unique == 0 || [info exists arr($s)] == 0 } { + break + } + } + + return $s +} + +proc random_key { } { + global l_keys + global nkeys + set x [berkdb random_int 0 [expr $nkeys - 1]] + return [lindex $l_keys $x] +} + +proc is_err { desired } { + set x [berkdb random_int 1 100] + if { $x <= $desired } { + return 1 + } else { + return 0 + } +} + +proc pick_cursput { } { + set x [berkdb random_int 1 4] + switch $x { + 1 { return "-keylast" } + 2 { return "-keyfirst" } + 3 { return "-before" } + 4 { return "-after" } + } +} + +proc random_cursor { curslist } { + global l_keys + global nkeys + + set x [berkdb random_int 0 [expr [llength $curslist] - 1]] + set dbc [lindex $curslist $x] + + # We want to randomly set the cursor. Pick a key. + set k [random_key] + set r [$dbc get "-set" $k] + error_check_good cursor_get:$k [is_substr Error $r] 0 + + # Now move forward or backward some hops to randomly + # position the cursor. + set dist [berkdb random_int -10 10] + + set dir "-next" + set boundary "-first" + if { $dist < 0 } { + set dir "-prev" + set boundary "-last" + set dist [expr 0 - $dist] + } + + for { set i 0 } { $i < $dist } { incr i } { + set r [ record $dbc get $dir $k ] + if { [llength $d] == 0 } { + set r [ record $dbc get $k $boundary ] + } + error_check_bad dbcget [llength $r] 0 + } + return { [linsert r 0 $dbc] } +} + +proc record { args } { +# Recording every operation makes tests ridiculously slow on +# NT, so we are commenting this out; for debugging purposes, +# it will undoubtedly be useful to uncomment this. +# puts $args +# flush stdout + return [eval $args] +} + +proc newpair { k data } { + global l_keys + global a_keys + global nkeys + + set a_keys($k) $data + lappend l_keys $k + incr nkeys +} + +proc rempair { k } { + global l_keys + global a_keys + global nkeys + + unset a_keys($k) + set n [lsearch $l_keys $k] + error_check_bad rempair:$k $n -1 + set l_keys [lreplace $l_keys $n $n] + incr nkeys -1 +} + +proc changepair { k data } { + global l_keys + global a_keys + global nkeys + + set a_keys($k) $data +} + +proc changedup { k olddata newdata } { + global l_keys + global a_keys + global nkeys + + set d $a_keys($k) + error_check_bad changedup:$k [llength $d] 0 + + set n [lsearch $d $olddata] + error_check_bad changedup:$k $n -1 + + set a_keys($k) [lreplace $a_keys($k) $n $n $newdata] +} + +# Insert a dup into the a_keys array with DB_KEYFIRST. +proc adddup { k olddata newdata } { + global l_keys + global a_keys + global nkeys + + set d $a_keys($k) + if { [llength $d] == 0 } { + lappend l_keys $k + incr nkeys + set a_keys($k) { $newdata } + } + + set ndx 0 + + set d [linsert d $ndx $newdata] + set a_keys($k) $d +} + +proc remdup { k data } { + global l_keys + global a_keys + global nkeys + + set d [$a_keys($k)] + error_check_bad changedup:$k [llength $d] 0 + + set n [lsearch $d $olddata] + error_check_bad changedup:$k $n -1 + + set a_keys($k) [lreplace $a_keys($k) $n $n] +} + +proc dump_full_file { db txn outfile checkfunc start continue } { + source ./include.tcl + + set outf [open $outfile w] + # Now we will get each key from the DB and dump to outfile + set c [eval {$db cursor} $txn] + error_check_good dbcursor [is_valid_cursor $c $db] TRUE + + for {set d [$c get $start] } { [string length $d] != 0 } { + set d [$c get $continue] } { + set k [lindex [lindex $d 0] 0] + set d2 [lindex [lindex $d 0] 1] + $checkfunc $k $d2 + puts $outf "$k\t$d2" + } + close $outf + error_check_good curs_close [$c close] 0 +} + +proc int_to_char { i } { + global alphabet + + return [string index $alphabet $i] +} + +proc dbcheck { key data } { + global l_keys + global a_keys + global nkeys + global check_array + + if { [lsearch $l_keys $key] == -1 } { + error "FAIL: Key |$key| not in list of valid keys" + } + + set d $a_keys($key) + + if { [info exists check_array($key) ] } { + set check $check_array($key) + } else { + set check {} + } + + if { [llength $d] > 1 } { + if { [llength $check] != [llength $d] } { + # Make the check array the right length + for { set i [llength $check] } { $i < [llength $d] } \ + {incr i} { + lappend check 0 + } + set check_array($key) $check + } + + # Find this data's index + set ndx [lsearch $d $data] + if { $ndx == -1 } { + error "FAIL: \ + Data |$data| not found for key $key. Found |$d|" + } + + # Set the bit in the check array + set check_array($key) [lreplace $check_array($key) $ndx $ndx 1] + } elseif { [string compare $d $data] != 0 } { + error "FAIL: \ + Invalid data |$data| for key |$key|. Expected |$d|." + } else { + set check_array($key) 1 + } +} + +# Dump out the file and verify it +proc filecheck { file txn } { + global check_array + global l_keys + global nkeys + global a_keys + source ./include.tcl + + if { [info exists check_array] == 1 } { + unset check_array + } + + open_and_dump_file $file NULL $txn $file.dump dbcheck dump_full_file \ + "-first" "-next" + + # Check that everything we checked had all its data + foreach i [array names check_array] { + set count 0 + foreach j $check_array($i) { + if { $j != 1 } { + puts -nonewline "Key |$i| never found datum" + puts " [lindex $a_keys($i) $count]" + } + incr count + } + } + + # Check that all keys appeared in the checked array + set count 0 + foreach k $l_keys { + if { [info exists check_array($k)] == 0 } { + puts "filecheck: key |$k| not found. Data: $a_keys($k)" + } + incr count + } + + if { $count != $nkeys } { + puts "filecheck: Got $count keys; expected $nkeys" + } +} + +proc esetup { dir } { + source ./include.tcl + + set ret [berkdb envremove -home $dir] + + fileremove -f $dir/file0 $dir/file1 $dir/file2 $dir/file3 + set mp [memp $dir 0644 -create -cachesize { 0 10240 }] + set lp [lock_open "" -create 0644] + error_check_good memp_close [$mp close] 0 + error_check_good lock_close [$lp close] 0 +} + +proc cleanup { dir env } { + global gen_upgrade + global upgrade_dir + global upgrade_be + global upgrade_method + global upgrade_name + source ./include.tcl + + if { $gen_upgrade == 1 } { + set vers [berkdb version] + set maj [lindex $vers 0] + set min [lindex $vers 1] + + if { $upgrade_be == 1 } { + set version_dir "$maj.${min}be" + } else { + set version_dir "$maj.${min}le" + } + + set dest $upgrade_dir/$version_dir/$upgrade_method/$upgrade_name + + catch {exec mkdir -p $dest} + catch {exec sh -c "mv $dir/*.db $dest"} + catch {exec sh -c "mv $dir/__dbq.* $dest"} + } + +# check_handles + set remfiles {} + set ret [catch { glob $dir/* } result] + if { $ret == 0 } { + foreach file $result { + # + # We: + # - Ignore any env-related files, which are + # those that have __db.* or log.* if we are + # running in an env. + # - Call 'dbremove' on any databases. + # Remove any remaining temp files. + # + switch -glob -- $file { + */__db.* - + */log.* { + if { $env != "NULL" } { + continue + } else { + lappend remfiles $file + } + } + *.db { + set envargs "" + if { $env != "NULL"} { + set file [file tail $file] + set envargs " -env $env " + } + + # If a database is left in a corrupt + # state, dbremove might not be able to handle + # it (it does an open before the remove). + # Be prepared for this, and if necessary, + # just forcibly remove the file with a warning + # message. + set ret [catch \ + {eval {berkdb dbremove} $envargs $file} res] + if { $ret != 0 } { + puts \ + "FAIL: dbremove in cleanup failed: $res" + lappend remfiles $file + } + } + default { + lappend remfiles $file + } + } + } + if {[llength $remfiles] > 0} { + eval fileremove -f $remfiles + } + } +} + +proc log_cleanup { dir } { + source ./include.tcl + + set files [glob -nocomplain $dir/log.*] + if { [llength $files] != 0} { + foreach f $files { + fileremove -f $f + } + } +} + +proc env_cleanup { dir } { + source ./include.tcl + + set stat [catch {berkdb envremove -home $dir} ret] + # + # If something failed and we are left with a region entry + # in /dev/shmem that is zero-length, the envremove will + # succeed, and the shm_unlink will succeed, but it will not + # remove the zero-length entry from /dev/shmem. Remove it + # using fileremove or else all other tests using an env + # will immediately fail. + # + if { $is_qnx_test == 1 } { + set region_files [glob -nocomplain /dev/shmem/$dir*] + if { [llength $region_files] != 0 } { + foreach f $region_files { + fileremove -f $f + } + } + } + log_cleanup $dir + cleanup $dir NULL +} + +proc remote_cleanup { server dir localdir } { + set home [file tail $dir] + error_check_good cleanup:remove [berkdb envremove -home $home \ + -server $server] 0 + catch {exec rsh $server rm -f $dir/*} ret + cleanup $localdir NULL +} + +proc help { cmd } { + if { [info command $cmd] == $cmd } { + set is_proc [lsearch [info procs $cmd] $cmd] + if { $is_proc == -1 } { + # Not a procedure; must be a C command + # Let's hope that it takes some parameters + # and that it prints out a message + puts "Usage: [eval $cmd]" + } else { + # It is a tcl procedure + puts -nonewline "Usage: $cmd" + set args [info args $cmd] + foreach a $args { + set is_def [info default $cmd $a val] + if { $is_def != 0 } { + # Default value + puts -nonewline " $a=$val" + } elseif {$a == "args"} { + # Print out flag values + puts " options" + args + } else { + # No default value + puts -nonewline " $a" + } + } + puts "" + } + } else { + puts "$cmd is not a command" + } +} + +# Run a recovery test for a particular operation +# Notice that we catch the return from CP and do not do anything with it. +# This is because Solaris CP seems to exit non-zero on occasion, but +# everything else seems to run just fine. +proc op_recover { encodedop dir env_cmd dbfile cmd msg } { + global log_log_record_types + global recd_debug + global recd_id + global recd_op + source ./include.tcl + + #puts "op_recover: $encodedop $dir $env_cmd $dbfile $cmd $msg" + + set init_file $dir/t1 + set afterop_file $dir/t2 + set final_file $dir/t3 + + set op "" + set op2 "" + if { $encodedop == "prepare-abort" } { + set op "prepare" + set op2 "abort" + } elseif { $encodedop == "prepare-commit" } { + set op "prepare" + set op2 "commit" + } else { + set op $encodedop + } + + puts "\t$msg $encodedop" + + # Keep track of the log types we've seen + if { $log_log_record_types == 1} { + logtrack_read $dir + } + + # Save the initial file and open the environment and the file + catch { file copy -force $dir/$dbfile $dir/$dbfile.init } res + copy_extent_file $dir $dbfile init + + set env [eval $env_cmd] + set db [berkdb open -env $env $dbfile] + error_check_good dbopen [is_valid_db $db] TRUE + + # Dump out file contents for initial case + set tflags "" + open_and_dump_file $dbfile $env $tflags $init_file nop \ + dump_file_direction "-first" "-next" + + set t [$env txn] + error_check_bad txn_begin $t NULL + error_check_good txn_begin [is_substr $t "txn"] 1 + + # Now fill in the db, tmgr, and the txnid in the command + set exec_cmd $cmd + + set i [lsearch $cmd ENV] + if { $i != -1 } { + set exec_cmd [lreplace $exec_cmd $i $i $env] + } + + set i [lsearch $cmd TXNID] + if { $i != -1 } { + set exec_cmd [lreplace $exec_cmd $i $i $t] + } + + set i [lsearch $exec_cmd DB] + if { $i != -1 } { + set exec_cmd [lreplace $exec_cmd $i $i $db] + } + + # To test DB_CONSUME, we need to expect a record return, not "0". + set i [lsearch $exec_cmd "-consume"] + if { $i != -1 } { + set record_exec_cmd_ret 1 + } else { + set record_exec_cmd_ret 0 + } + + # For the DB_APPEND test, we need to expect a return other than + # 0; set this flag to be more lenient in the error_check_good. + set i [lsearch $exec_cmd "-append"] + if { $i != -1 } { + set lenient_exec_cmd_ret 1 + } else { + set lenient_exec_cmd_ret 0 + } + + # Execute command and commit/abort it. + set ret [eval $exec_cmd] + if { $record_exec_cmd_ret == 1 } { + error_check_good "\"$exec_cmd\"" [llength [lindex $ret 0]] 2 + } elseif { $lenient_exec_cmd_ret == 1 } { + error_check_good "\"$exec_cmd\"" [expr $ret > 0] 1 + } else { + error_check_good "\"$exec_cmd\"" $ret 0 + } + + set record_exec_cmd_ret 0 + set lenient_exec_cmd_ret 0 + + # Sync the file so that we can capture a snapshot to test + # recovery. + error_check_good sync:$db [$db sync] 0 + + catch { file copy -force $dir/$dbfile $dir/$dbfile.afterop } res + copy_extent_file $dir $dbfile afterop + + #set tflags "-txn $t" + open_and_dump_file $dir/$dbfile.afterop NULL $tflags \ + $afterop_file nop dump_file_direction \ + "-first" "-next" + #puts "\t\t\tExecuting txn_$op:$t" + error_check_good txn_$op:$t [$t $op] 0 + if { $op2 != "" } { + #puts "\t\t\tExecuting txn_$op2:$t" + error_check_good txn_$op2:$t [$t $op2] 0 + } + + switch $encodedop { + "commit" { puts "\t\tCommand executed and committed." } + "abort" { puts "\t\tCommand executed and aborted." } + "prepare" { puts "\t\tCommand executed and prepared." } + "prepare-commit" { + puts "\t\tCommand executed, prepared, and committed." + } + "prepare-abort" { + puts "\t\tCommand executed, prepared, and aborted." + } + } + + # Dump out file and save a copy. + error_check_good sync:$db [$db sync] 0 + open_and_dump_file $dir/$dbfile NULL $tflags $final_file nop \ + dump_file_direction "-first" "-next" + + catch { file copy -force $dir/$dbfile $dir/$dbfile.final } res + copy_extent_file $dir $dbfile final + + # If this is an abort or prepare-abort, it should match the + # original file. + # If this was a commit or prepare-commit, then this file should + # match the afterop file. + # If this was a prepare without an abort or commit, we still + # have transactions active, and peering at the database from + # another environment will show data from uncommitted transactions. + # Thus we just skip this in the prepare-only case; what + # we care about are the results of a prepare followed by a + # recovery, which we test later. + if { $op == "commit" || $op2 == "commit" } { + filesort $afterop_file $afterop_file.sort + filesort $final_file $final_file.sort + error_check_good \ + diff(post-$op,pre-commit):diff($afterop_file,$final_file) \ + [filecmp $afterop_file.sort $final_file.sort] 0 + } elseif { $op == "abort" || $op2 == "abort" } { + filesort $init_file $init_file.sort + filesort $final_file $final_file.sort + error_check_good \ + diff(initial,post-$op):diff($init_file,$final_file) \ + [filecmp $init_file.sort $final_file.sort] 0 + } else { + # Make sure this really is a prepare-only + error_check_good assert:prepare-only $encodedop "prepare" + } + + # Running recovery on this database should not do anything. + # Flush all data to disk, close the environment and save the + # file. + error_check_good close:$db [$db close] 0 + + # If all we've done is a prepare, then there's still a + # transaction active, and an env close will return DB_RUNRECOVERY + if { $encodedop == "prepare" } { + catch {$env close} ret + error_check_good env_close \ + [is_substr $ret DB_RUNRECOVERY] 1 + } else { + reset_env $env + } + + berkdb debug_check + puts -nonewline "\t\tRunning recovery ... " + flush stdout + + set stat [catch {exec $util_path/db_recover -h $dir -c} result] + if { $stat == 1 } { + error "FAIL: Recovery error: $result." + } + puts -nonewline "complete ... " + + error_check_good db_verify [verify_dir $testdir "\t\t" 0 1] 0 + + puts "verified" + + berkdb debug_check + set env [eval $env_cmd] + error_check_good dbenv [is_valid_widget $env env] TRUE + open_and_dump_file $dir/$dbfile NULL $tflags $final_file nop \ + dump_file_direction "-first" "-next" + if { $op == "commit" || $op2 == "commit" } { + filesort $afterop_file $afterop_file.sort + filesort $final_file $final_file.sort + error_check_good \ + diff(post-$op,pre-commit):diff($afterop_file,$final_file) \ + [filecmp $afterop_file.sort $final_file.sort] 0 + } else { + filesort $init_file $init_file.sort + filesort $final_file $final_file.sort + error_check_good \ + diff(initial,post-$op):diff($init_file,$final_file) \ + [filecmp $init_file.sort $final_file.sort] 0 + } + + # Now close the environment, substitute a file that will need + # recovery and try running recovery again. + reset_env $env + if { $op == "commit" || $op2 == "commit" } { + catch { file copy -force $dir/$dbfile.init $dir/$dbfile } res + move_file_extent $dir $dbfile init copy + } else { + catch { file copy -force $dir/$dbfile.afterop $dir/$dbfile } res + move_file_extent $dir $dbfile afterop copy + } + + berkdb debug_check + puts -nonewline \ + "\t\tRunning recovery on pre-op database ... " + flush stdout + + set stat [catch {exec $util_path/db_recover -h $dir -c} result] + if { $stat == 1 } { + error "FAIL: Recovery error: $result." + } + puts -nonewline "complete ... " + + error_check_good db_verify_preop [verify_dir $testdir "\t\t" 0 1] 0 + + puts "verified" + + set env [eval $env_cmd] + + open_and_dump_file $dir/$dbfile NULL $tflags $final_file nop \ + dump_file_direction "-first" "-next" + if { $op == "commit" || $op2 == "commit" } { + filesort $final_file $final_file.sort + filesort $afterop_file $afterop_file.sort + error_check_good \ + diff(post-$op,recovered):diff($afterop_file,$final_file) \ + [filecmp $afterop_file.sort $final_file.sort] 0 + } else { + filesort $init_file $init_file.sort + filesort $final_file $final_file.sort + error_check_good \ + diff(initial,post-$op):diff($init_file,$final_file) \ + [filecmp $init_file.sort $final_file.sort] 0 + } + + # This should just close the environment, not blow it away. + reset_env $env +} + +proc populate { db method txn n dups bigdata } { + source ./include.tcl + + set did [open $dict] + set count 0 + while { [gets $did str] != -1 && $count < $n } { + if { [is_record_based $method] == 1 } { + set key [expr $count + 1] + } elseif { $dups == 1 } { + set key duplicate_key + } else { + set key $str + } + if { $bigdata == 1 && [berkdb random_int 1 3] == 1} { + set str [replicate $str 1000] + } + + set ret [$db put -txn $txn $key $str] + error_check_good db_put:$key $ret 0 + incr count + } + close $did + return 0 +} + +proc big_populate { db txn n } { + source ./include.tcl + + set did [open $dict] + set count 0 + while { [gets $did str] != -1 && $count < $n } { + set key [replicate $str 50] + set ret [$db put -txn $txn $key $str] + error_check_good db_put:$key $ret 0 + incr count + } + close $did + return 0 +} + +proc unpopulate { db txn num } { + source ./include.tcl + + set c [eval {$db cursor} "-txn $txn"] + error_check_bad $db:cursor $c NULL + error_check_good $db:cursor [is_substr $c $db] 1 + + set i 0 + for {set d [$c get -first] } { [llength $d] != 0 } { + set d [$c get -next] } { + $c del + incr i + if { $num != 0 && $ >= $num } { + break + } + } + error_check_good cursor_close [$c close] 0 + return 0 +} + +proc reset_env { env } { + error_check_good env_close [$env close] 0 +} + +# This routine will let us obtain a ring of deadlocks. +# Each locker will get a lock on obj_id, then sleep, and +# then try to lock (obj_id + 1) % num. +# When the lock is finally granted, we release our locks and +# return 1 if we got both locks and DEADLOCK if we deadlocked. +# The results here should be that 1 locker deadlocks and the +# rest all finish successfully. +proc ring { myenv locker_id obj_id num } { + source ./include.tcl + + if {[catch {$myenv lock_get write $locker_id $obj_id} lock1] != 0} { + puts $errorInfo + return ERROR + } else { + error_check_good lockget:$obj_id [is_substr $lock1 $myenv] 1 + } + + tclsleep 30 + set nextobj [expr ($obj_id + 1) % $num] + set ret 1 + if {[catch {$myenv lock_get write $locker_id $nextobj} lock2] != 0} { + if {[string match "*DEADLOCK*" $lock2] == 1} { + set ret DEADLOCK + } else { + set ret ERROR + } + } else { + error_check_good lockget:$obj_id [is_substr $lock2 $myenv] 1 + } + + # Now release the first lock + error_check_good lockput:$lock1 [$lock1 put] 0 + + if {$ret == 1} { + error_check_bad lockget:$obj_id $lock2 NULL + error_check_good lockget:$obj_id [is_substr $lock2 $myenv] 1 + error_check_good lockput:$lock2 [$lock2 put] 0 + } + return $ret +} + +# This routine will create massive deadlocks. +# Each locker will get a readlock on obj_id, then sleep, and +# then try to upgrade the readlock to a write lock. +# When the lock is finally granted, we release our first lock and +# return 1 if we got both locks and DEADLOCK if we deadlocked. +# The results here should be that 1 locker succeeds in getting all +# the locks and everyone else deadlocks. +proc clump { myenv locker_id obj_id num } { + source ./include.tcl + + set obj_id 10 + if {[catch {$myenv lock_get read $locker_id $obj_id} lock1] != 0} { + puts $errorInfo + return ERROR + } else { + error_check_good lockget:$obj_id \ + [is_valid_lock $lock1 $myenv] TRUE + } + + tclsleep 30 + set ret 1 + if {[catch {$myenv lock_get write $locker_id $obj_id} lock2] != 0} { + if {[string match "*DEADLOCK*" $lock2] == 1} { + set ret DEADLOCK + } else { + set ret ERROR + } + } else { + error_check_good \ + lockget:$obj_id [is_valid_lock $lock2 $myenv] TRUE + } + + # Now release the first lock + error_check_good lockput:$lock1 [$lock1 put] 0 + + if {$ret == 1} { + error_check_good \ + lockget:$obj_id [is_valid_lock $lock2 $myenv] TRUE + error_check_good lockput:$lock2 [$lock2 put] 0 + } + return $ret + } + +proc dead_check { t procs dead clean other } { + error_check_good $t:$procs:other $other 0 + switch $t { + ring { + error_check_good $t:$procs:deadlocks $dead 1 + error_check_good $t:$procs:success $clean \ + [expr $procs - 1] + } + clump { + error_check_good $t:$procs:deadlocks $dead \ + [expr $procs - 1] + error_check_good $t:$procs:success $clean 1 + } + default { + error "Test $t not implemented" + } + } +} + +proc rdebug { id op where } { + global recd_debug + global recd_id + global recd_op + + set recd_debug $where + set recd_id $id + set recd_op $op +} + +proc rtag { msg id } { + set tag [lindex $msg 0] + set tail [expr [string length $tag] - 2] + set tag [string range $tag $tail $tail] + if { $id == $tag } { + return 1 + } else { + return 0 + } +} + +proc zero_list { n } { + set ret "" + while { $n > 0 } { + lappend ret 0 + incr n -1 + } + return $ret +} + +proc check_dump { k d } { + puts "key: $k data: $d" +} + +proc reverse { s } { + set res "" + for { set i 0 } { $i < [string length $s] } { incr i } { + set res "[string index $s $i]$res" + } + + return $res +} + +proc is_valid_widget { w expected } { + # First N characters must match "expected" + set l [string length $expected] + incr l -1 + if { [string compare [string range $w 0 $l] $expected] != 0 } { + return $w + } + + # Remaining characters must be digits + incr l 1 + for { set i $l } { $i < [string length $w] } { incr i} { + set c [string index $w $i] + if { $c < "0" || $c > "9" } { + return $w + } + } + + return TRUE +} + +proc is_valid_db { db } { + return [is_valid_widget $db db] +} + +proc is_valid_env { env } { + return [is_valid_widget $env env] +} + +proc is_valid_cursor { dbc db } { + return [is_valid_widget $dbc $db.c] +} + +proc is_valid_lock { lock env } { + return [is_valid_widget $lock $env.lock] +} + +proc is_valid_mpool { mpool env } { + return [is_valid_widget $mpool $env.mp] +} + +proc is_valid_page { page mpool } { + return [is_valid_widget $page $mpool.pg] +} + +proc is_valid_txn { txn env } { + return [is_valid_widget $txn $env.txn] +} + +proc is_valid_mutex { m env } { + return [is_valid_widget $m $env.mutex] +} + +proc send_cmd { fd cmd {sleep 2}} { + source ./include.tcl + + puts $fd "set v \[$cmd\]" + puts $fd "puts \$v" + puts $fd "flush stdout" + flush $fd + berkdb debug_check + tclsleep $sleep + + set r [rcv_result $fd] + return $r +} + +proc rcv_result { fd } { + set r [gets $fd result] + error_check_bad remote_read $r -1 + + return $result +} + +proc send_timed_cmd { fd rcv_too cmd } { + set c1 "set start \[timestamp -r\]; " + set c2 "puts \[expr \[timestamp -r\] - \$start\]" + set full_cmd [concat $c1 $cmd ";" $c2] + + puts $fd $full_cmd + puts $fd "flush stdout" + flush $fd + return 0 +} + +# +# The rationale behind why we have *two* "data padding" routines is outlined +# below: +# +# Both pad_data and chop_data truncate data that is too long. However, +# pad_data also adds the pad character to pad data out to the fixed length +# record length. +# +# Which routine you call does not depend on the length of the data you're +# using, but on whether you're doing a put or a get. When we do a put, we +# have to make sure the data isn't longer than the size of a record because +# otherwise we'll get an error (use chop_data). When we do a get, we want to +# check that db padded everything correctly (use pad_data on the value against +# which we are comparing). +# +# We don't want to just use the pad_data routine for both purposes, because +# we want to be able to test whether or not db is padding correctly. For +# example, the queue access method had a bug where when a record was +# overwritten (*not* a partial put), only the first n bytes of the new entry +# were written, n being the new entry's (unpadded) length. So, if we did +# a put with key,value pair (1, "abcdef") and then a put (1, "z"), we'd get +# back (1,"zbcdef"). If we had used pad_data instead of chop_data, we would +# have gotten the "correct" result, but we wouldn't have found this bug. +proc chop_data {method data} { + global fixed_len + + if {[is_fixed_length $method] == 1 && \ + [string length $data] > $fixed_len} { + return [eval {binary format a$fixed_len $data}] + } else { + return $data + } +} + +proc pad_data {method data} { + global fixed_len + + if {[is_fixed_length $method] == 1} { + return [eval {binary format a$fixed_len $data}] + } else { + return $data + } +} + +proc make_fixed_length {method data {pad 0}} { + global fixed_len + global fixed_pad + + if {[is_fixed_length $method] == 1} { + if {[string length $data] > $fixed_len } { + error_check_bad make_fixed_len:TOO_LONG 1 1 + } + while { [string length $data] < $fixed_len } { + set data [format $data%c $fixed_pad] + } + } + return $data +} + +# shift data for partial +# pad with fixed pad (which is NULL) +proc partial_shift { data offset direction} { + global fixed_len + + set len [expr $fixed_len - 1] + + if { [string compare $direction "right"] == 0 } { + for { set i 1} { $i <= $offset } {incr i} { + set data [binary format x1a$len $data] + } + } elseif { [string compare $direction "left"] == 0 } { + for { set i 1} { $i <= $offset } {incr i} { + set data [string range $data 1 end] + set data [binary format a$len $data] + } + } + return $data +} + +# string compare does not always work to compare +# this data, nor does expr (==) +# specialized routine for comparison +# (for use in fixed len recno and q) +proc binary_compare { data1 data2 } { + if { [string length $data1] != [string length $data2] || \ + [string compare -length \ + [string length $data1] $data1 $data2] != 0 } { + return 1 + } else { + return 0 + } +} + +proc convert_method { method } { + switch -- $method { + -btree - + -dbtree - + -ddbtree - + -rbtree - + BTREE - + DB_BTREE - + DB_RBTREE - + RBTREE - + bt - + btree - + db_btree - + db_rbtree - + rbt - + rbtree { return "-btree" } + + -dhash - + -hash - + DB_HASH - + HASH - + db_hash - + h - + hash { return "-hash" } + + -queue - + DB_QUEUE - + QUEUE - + db_queue - + q - + qam - + queue { return "-queue" } + + -queueextent - + QUEUEEXTENT - + qe - + qamext - + -queueext - + queueextent - + queueext { return "-queue" } + + -frecno - + -recno - + -rrecno - + DB_FRECNO - + DB_RECNO - + DB_RRECNO - + FRECNO - + RECNO - + RRECNO - + db_frecno - + db_recno - + db_rrecno - + frec - + frecno - + rec - + recno - + rrec - + rrecno { return "-recno" } + + default { error "FAIL:[timestamp] $method: unknown method" } + } +} + +# If recno-with-renumbering or btree-with-renumbering is specified, then +# fix the arguments to specify the DB_RENUMBER/DB_RECNUM option for the +# -flags argument. +proc convert_args { method {largs ""} } { + global fixed_len + global fixed_pad + global gen_upgrade + global upgrade_be + source ./include.tcl + + if { [string first - $largs] == -1 &&\ + [string compare $largs ""] != 0 } { + set errstring "args must contain a hyphen; does this test\ + have no numeric args?" + puts "FAIL:[timestamp] $errstring" + return -code return + } + + if { $gen_upgrade == 1 && $upgrade_be == 1 } { + append largs " -lorder 4321 " + } elseif { $gen_upgrade == 1 && $upgrade_be != 1 } { + append largs " -lorder 1234 " + } + + if { [is_rrecno $method] == 1 } { + append largs " -renumber " + } elseif { [is_rbtree $method] == 1 } { + append largs " -recnum " + } elseif { [is_dbtree $method] == 1 } { + append largs " -dup " + } elseif { [is_ddbtree $method] == 1 } { + append largs " -dup " + append largs " -dupsort " + } elseif { [is_dhash $method] == 1 } { + append largs " -dup " + } elseif { [is_queueext $method] == 1 } { + append largs " -extent 2 " + } + + if {[is_fixed_length $method] == 1} { + append largs " -len $fixed_len -pad $fixed_pad " + } + return $largs +} + +proc is_btree { method } { + set names { -btree BTREE DB_BTREE bt btree } + if { [lsearch $names $method] >= 0 } { + return 1 + } else { + return 0 + } +} + +proc is_dbtree { method } { + set names { -dbtree } + if { [lsearch $names $method] >= 0 } { + return 1 + } else { + return 0 + } +} + +proc is_ddbtree { method } { + set names { -ddbtree } + if { [lsearch $names $method] >= 0 } { + return 1 + } else { + return 0 + } +} + +proc is_rbtree { method } { + set names { -rbtree rbtree RBTREE db_rbtree DB_RBTREE rbt } + if { [lsearch $names $method] >= 0 } { + return 1 + } else { + return 0 + } +} + +proc is_recno { method } { + set names { -recno DB_RECNO RECNO db_recno rec recno} + if { [lsearch $names $method] >= 0 } { + return 1 + } else { + return 0 + } +} + +proc is_rrecno { method } { + set names { -rrecno rrecno RRECNO db_rrecno DB_RRECNO rrec } + if { [lsearch $names $method] >= 0 } { + return 1 + } else { + return 0 + } +} + +proc is_frecno { method } { + set names { -frecno frecno frec FRECNO db_frecno DB_FRECNO} + if { [lsearch $names $method] >= 0 } { + return 1 + } else { + return 0 + } +} + +proc is_hash { method } { + set names { -hash DB_HASH HASH db_hash h hash } + if { [lsearch $names $method] >= 0 } { + return 1 + } else { + return 0 + } +} + +proc is_dhash { method } { + set names { -dhash } + if { [lsearch $names $method] >= 0 } { + return 1 + } else { + return 0 + } +} + +proc is_queue { method } { + if { [is_queueext $method] == 1 } { + return 1 + } + + set names { -queue DB_QUEUE QUEUE db_queue q queue qam } + if { [lsearch $names $method] >= 0 } { + return 1 + } else { + return 0 + } +} + +proc is_queueext { method } { + set names { -queueextent queueextent QUEUEEXTENT qe qamext \ + queueext -queueext } + if { [lsearch $names $method] >= 0 } { + return 1 + } else { + return 0 + } +} + +proc is_record_based { method } { + if { [is_recno $method] || [is_frecno $method] || + [is_rrecno $method] || [is_queue $method] } { + return 1 + } else { + return 0 + } +} + +proc is_fixed_length { method } { + if { [is_queue $method] || [is_frecno $method] } { + return 1 + } else { + return 0 + } +} + +# Sort lines in file $in and write results to file $out. +# This is a more portable alternative to execing the sort command, +# which has assorted issues on NT [#1576]. +# The addition of a "-n" argument will sort numerically. +proc filesort { in out { arg "" } } { + set i [open $in r] + + set ilines {} + while { [gets $i line] >= 0 } { + lappend ilines $line + } + + if { [string compare $arg "-n"] == 0 } { + set olines [lsort -integer $ilines] + } else { + set olines [lsort $ilines] + } + + close $i + + set o [open $out w] + foreach line $olines { + puts $o $line + } + + close $o +} + +# Print lines up to the nth line of infile out to outfile, inclusive. +# The optional beg argument tells us where to start. +proc filehead { n infile outfile { beg 0 } } { + set in [open $infile r] + set out [open $outfile w] + + # Sed uses 1-based line numbers, and so we do too. + for { set i 1 } { $i < $beg } { incr i } { + if { [gets $in junk] < 0 } { + break + } + } + + for { } { $i <= $n } { incr i } { + if { [gets $in line] < 0 } { + break + } + puts $out $line + } + + close $in + close $out +} + +# Remove file (this replaces $RM). +# Usage: fileremove filenames =~ rm; fileremove -f filenames =~ rm -rf. +proc fileremove { args } { + set forceflag "" + foreach a $args { + if { [string first - $a] == 0 } { + # It's a flag. Better be f. + if { [string first f $a] != 1 } { + return -code error "bad flag to fileremove" + } else { + set forceflag "-force" + } + } else { + eval {file delete $forceflag $a} + } + } +} + +proc findfail { args } { + foreach a $args { + if { [file exists $a] == 0 } { + continue + } + set f [open $a r] + while { [gets $f line] >= 0 } { + if { [string first FAIL $line] == 0 } { + close $f + return 1 + } + } + close $f + } + return 0 +} + +# Sleep for s seconds. +proc tclsleep { s } { + # On Windows, the system time-of-day clock may update as much + # as 55 ms late due to interrupt timing. Don't take any + # chances; sleep extra-long so that when tclsleep 1 returns, + # it's guaranteed to be a new second. + after [expr $s * 1000 + 56] +} + +# Compare two files, a la diff. Returns 1 if non-identical, 0 if identical. +proc filecmp { file_a file_b } { + set fda [open $file_a r] + set fdb [open $file_b r] + + set nra 0 + set nrb 0 + + # The gets can't be in the while condition because we'll + # get short-circuit evaluated. + while { $nra >= 0 && $nrb >= 0 } { + set nra [gets $fda aline] + set nrb [gets $fdb bline] + + if { $nra != $nrb || [string compare $aline $bline] != 0} { + close $fda + close $fdb + return 1 + } + } + + close $fda + close $fdb + return 0 +} + +# Verify all .db files in the specified directory. +proc verify_dir { \ + {directory "./TESTDIR"} { pref "" } { noredo 0 } { quiet 0 } } { + # If we're doing database verification between tests, we don't + # want to do verification twice without an intervening cleanup--some + # test was skipped. Always verify by default (noredo == 0) so + # that explicit calls to verify_dir during tests don't require + # cleanup commands. + if { $noredo == 1 } { + if { [file exists $directory/NOREVERIFY] == 1 } { + if { $quiet == 0 } { + puts "Skipping verification." + } + return + } + set f [open $directory/NOREVERIFY w] + close $f + } + + if { [catch {glob $directory/*.db} dbs] != 0 } { + # No files matched + return + } + if { [file exists /dev/stderr] == 1 } { + set errfilearg "-errfile /dev/stderr " + } else { + set errfilearg "" + } + set errpfxarg {-errpfx "FAIL: verify" } + set errarg $errfilearg$errpfxarg + set ret 0 + foreach db $dbs { + if { [catch {eval {berkdb dbverify} $errarg $db} res] != 0 } { + puts $res + puts "FAIL:[timestamp] Verification of $db failed." + set ret 1 + } else { + error_check_good verify:$db $res 0 + if { $quiet == 0 } { + puts "${pref}Verification of $db succeeded." + } + } + } + return $ret +} + +# Generate randomly ordered, guaranteed-unique four-character strings that can +# be used to differentiate duplicates without creating duplicate duplicates. +# (test031 & test032) randstring_init is required before the first call to +# randstring and initializes things for up to $i distinct strings; randstring +# gets the next string. +proc randstring_init { i } { + global rs_int_list alphabet + + # Fail if we can't generate sufficient unique strings. + if { $i > [expr 26 * 26 * 26 * 26] } { + set errstring\ + "Duplicate set too large for random string generator" + puts "FAIL:[timestamp] $errstring" + return -code return $errstring + } + + set rs_int_list {} + + # generate alphabet array + for { set j 0 } { $j < 26 } { incr j } { + set a($j) [string index $alphabet $j] + } + + # Generate a list with $i elements, { aaaa, aaab, ... aaaz, aaba ...} + for { set d1 0 ; set j 0 } { $d1 < 26 && $j < $i } { incr d1 } { + for { set d2 0 } { $d2 < 26 && $j < $i } { incr d2 } { + for { set d3 0 } { $d3 < 26 && $j < $i } { incr d3 } { + for { set d4 0 } { $d4 < 26 && $j < $i } \ + { incr d4 } { + lappend rs_int_list \ + $a($d1)$a($d2)$a($d3)$a($d4) + incr j + } + } + } + } + + # Randomize the list. + set rs_int_list [randomize_list $rs_int_list] +} + +# Randomize a list. Returns a randomly-reordered copy of l. +proc randomize_list { l } { + set i [llength $l] + + for { set j 0 } { $j < $i } { incr j } { + # Pick a random element from $j to the end + set k [berkdb random_int $j [expr $i - 1]] + + # Swap it with element $j + set t1 [lindex $l $j] + set t2 [lindex $l $k] + + set l [lreplace $l $j $j $t2] + set l [lreplace $l $k $k $t1] + } + + return $l +} + +proc randstring {} { + global rs_int_list + + if { [info exists rs_int_list] == 0 || [llength $rs_int_list] == 0 } { + set errstring "randstring uninitialized or used too often" + puts "FAIL:[timestamp] $errstring" + return -code return $errstring + } + + set item [lindex $rs_int_list 0] + set rs_int_list [lreplace $rs_int_list 0 0] + + return $item +} + +# Takes a variable-length arg list, and returns a list containing the list of +# the non-hyphenated-flag arguments, followed by a list of each alphanumeric +# flag it finds. +proc extractflags { args } { + set inflags 1 + set flags {} + while { $inflags == 1 } { + set curarg [lindex $args 0] + if { [string first "-" $curarg] == 0 } { + set i 1 + while {[string length [set f \ + [string index $curarg $i]]] > 0 } { + incr i + if { [string compare $f "-"] == 0 } { + set inflags 0 + break + } else { + lappend flags $f + } + } + set args [lrange $args 1 end] + } else { + set inflags 0 + } + } + return [list $args $flags] +} + +# Wrapper for berkdb open, used throughout the test suite so that we can +# set an errfile/errpfx as appropriate. +proc berkdb_open { args } { + set errargs {} + if { [file exists /dev/stderr] == 1 } { + append errargs " -errfile /dev/stderr " + append errargs " -errpfx \\F\\A\\I\\L " + } + + eval {berkdb open} $errargs $args +} + +# Version without errpfx/errfile, used when we're expecting a failure. +proc berkdb_open_noerr { args } { + eval {berkdb open} $args +} + +proc check_handles { {outf stdout} } { + global ohandles + + set handles [berkdb handles] + if {[llength $handles] != [llength $ohandles]} { + puts $outf "WARNING: Open handles during cleanup: $handles" + } + set ohandles $handles +} + +proc open_handles { } { + return [llength [berkdb handles]] +} + +proc move_file_extent { dir dbfile tag op } { + set files [get_extfiles $dir $dbfile $tag] + foreach extfile $files { + set i [string last "." $extfile] + incr i + set extnum [string range $extfile $i end] + set dbq [make_ext_filename $dir $dbfile $extnum] + # + # We can either copy or rename + # + file $op -force $extfile $dbq + } +} + +proc copy_extent_file { dir dbfile tag { op copy } } { + set files [get_extfiles $dir $dbfile ""] + foreach extfile $files { + set i [string last "." $extfile] + incr i + set extnum [string range $extfile $i end] + file $op -force $extfile $dir/__dbq.$dbfile.$tag.$extnum + } +} + +proc get_extfiles { dir dbfile tag } { + if { $tag == "" } { + set filepat $dir/__dbq.$dbfile.\[0-9\]* + } else { + set filepat $dir/__dbq.$dbfile.$tag.\[0-9\]* + } + return [glob -nocomplain -- $filepat] +} + +proc make_ext_filename { dir dbfile extnum } { + return $dir/__dbq.$dbfile.$extnum +} + +# All pids for Windows 9X are negative values. When we want to have +# unsigned int values, unique to the process, we'll take the absolute +# value of the pid. This avoids unsigned/signed mistakes, yet +# guarantees uniqueness, since each system has pids that are all +# either positive or negative. +# +proc sanitized_pid { } { + set mypid [pid] + if { $mypid < 0 } { + set mypid [expr - $mypid] + } + puts "PID: [pid] $mypid\n" + return $mypid +} + +# +# Extract the page size field from a stat record. Return -1 if +# none is found. +# +proc get_pagesize { stat } { + foreach field $stat { + set title [lindex $field 0] + if {[string compare $title "Page size"] == 0} { + return [lindex $field 1] + } + } + return -1 +} diff --git a/db/test/txn.tcl b/db/test/txn.tcl new file mode 100644 index 000000000..904ef5fdc --- /dev/null +++ b/db/test/txn.tcl @@ -0,0 +1,181 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1996, 1997, 1998, 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: txn.tcl,v 11.12 2000/12/31 19:26:23 bostic Exp $ +# +# Options are: +# -dir +# -max +# -iterations +# -stat +proc txn_usage {} { + puts "txn -dir -iterations \ + -max -stat" +} + +proc txntest { args } { + source ./include.tcl + + # Set defaults + set iterations 50 + set max 1024 + set dostat 0 + set flags "" + for { set i 0 } { $i < [llength $args] } {incr i} { + switch -regexp -- [lindex $args $i] { + -d.* { incr i; set testdir [lindex $args $i] } + -f.* { incr i; set flags [lindex $args $i] } + -i.* { incr i; set iterations [lindex $args $i] } + -m.* { incr i; set max [lindex $args $i] } + -s.* { set dostat 1 } + default { + puts -nonewline "FAIL:[timestamp] Usage: " + txn_usage + return + } + } + } + if { $max < $iterations } { + set max $iterations + } + + # Now run the various functionality tests + txn001 $testdir $max $iterations $flags + txn002 $testdir $max $iterations +} + +proc txn001 { dir max ntxns flags} { + source ./include.tcl + + puts "Txn001: Basic begin, commit, abort" + + # Open environment + env_cleanup $dir + + set env [eval {berkdb \ + env -create -mode 0644 -txn -txn_max $max -home $dir} $flags] + error_check_good evn_open [is_valid_env $env] TRUE + txn001_suba $ntxns $env + txn001_subb $ntxns $env + txn001_subc $ntxns $env + # Close and unlink the file + error_check_good env_close:$env [$env close] 0 +} + +proc txn001_suba { ntxns env } { + source ./include.tcl + + # We will create a bunch of transactions and commit them. + set txn_list {} + set tid_list {} + puts "Txn001.a: Beginning/Committing $ntxns Transactions in $env" + for { set i 0 } { $i < $ntxns } { incr i } { + set txn [$env txn] + error_check_good txn_begin [is_valid_txn $txn $env] TRUE + + lappend txn_list $txn + + set tid [$txn id] + error_check_good tid_check [lsearch $tid_list $tid] -1 + + lappend tid_list $tid + } + + # Now commit them all + foreach t $txn_list { + error_check_good txn_commit:$t [$t commit] 0 + } +} + +proc txn001_subb { ntxns env } { + # We will create a bunch of transactions and abort them. + set txn_list {} + set tid_list {} + puts "Txn001.b: Beginning/Aborting Transactions" + for { set i 0 } { $i < $ntxns } { incr i } { + set txn [$env txn] + error_check_good txn_begin [is_valid_txn $txn $env] TRUE + + lappend txn_list $txn + + set tid [$txn id] + error_check_good tid_check [lsearch $tid_list $tid] -1 + + lappend tid_list $tid + } + + # Now abort them all + foreach t $txn_list { + error_check_good txn_abort:$t [$t abort] 0 + } +} + +proc txn001_subc { ntxns env } { + # We will create a bunch of transactions and commit them. + set txn_list {} + set tid_list {} + puts "Txn001.c: Beginning/Prepare/Committing Transactions" + for { set i 0 } { $i < $ntxns } { incr i } { + set txn [$env txn] + error_check_good txn_begin [is_valid_txn $txn $env] TRUE + + lappend txn_list $txn + + set tid [$txn id] + error_check_good tid_check [lsearch $tid_list $tid] -1 + + lappend tid_list $tid + } + + # Now prepare them all + foreach t $txn_list { + error_check_good txn_prepare:$t [$t prepare] 0 + } + + # Now commit them all + foreach t $txn_list { + error_check_good txn_commit:$t [$t commit] 0 + } + +} + +# Verify that read-only transactions do not create any log records +proc txn002 { dir max ntxns } { + source ./include.tcl + + puts "Txn002: Read-only transaction test" + + env_cleanup $dir + set env [berkdb \ + env -create -mode 0644 -txn -txn_max $max -home $dir] + error_check_good dbenv [is_valid_env $env] TRUE + + # We will create a bunch of transactions and commit them. + set txn_list {} + set tid_list {} + puts "Txn002.a: Beginning/Committing Transactions" + for { set i 0 } { $i < $ntxns } { incr i } { + set txn [$env txn] + error_check_good txn_begin [is_valid_txn $txn $env] TRUE + + lappend txn_list $txn + + set tid [$txn id] + error_check_good tid_check [lsearch $tid_list $tid] -1 + + lappend tid_list $tid + } + + # Now commit them all + foreach t $txn_list { + error_check_good txn_commit:$t [$t commit] 0 + } + + # Now verify that there aren't any log records. + set r [$env log_get -first] + error_check_good log_get:$r [llength $r] 0 + + error_check_good env_close:$r [$env close] 0 +} diff --git a/db/test/update.tcl b/db/test/update.tcl new file mode 100644 index 000000000..81fc9ba9e --- /dev/null +++ b/db/test/update.tcl @@ -0,0 +1,92 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: update.tcl,v 11.9 2000/10/27 13:23:56 sue Exp $ +source ./include.tcl +global update_dir +set update_dir "$test_path/update_test" + +proc update { } { + source ./include.tcl + global update_dir + + foreach version [glob $update_dir/*] { + regexp \[^\/\]*$ $version version + foreach method [glob $update_dir/$version/*] { + regexp \[^\/\]*$ $method method + foreach file [glob $update_dir/$version/$method/*] { + regexp (\[^\/\]*)\.tar\.gz$ $file dummy name + foreach endianness {"le" "be"} { + puts "Update:\ + $version $method $name $endianness" + set ret [catch {_update $update_dir $testdir $version $method $name $endianness 1 1} message] + if { $ret != 0 } { + puts $message + } + } + } + } + } +} + +proc _update { source_dir temp_dir \ + version method file endianness do_db_load_test do_update_test } { + source include.tcl + global errorInfo + + cleanup $temp_dir NULL + + exec sh -c \ +"gzcat $source_dir/$version/$method/$file.tar.gz | (cd $temp_dir && tar xf -)" + + if { $do_db_load_test } { + set ret [catch \ + {exec $util_path/db_load -f "$temp_dir/$file.dump" \ + "$temp_dir/update.db"} message] + error_check_good \ + "Update load: $version $method $file $message" $ret 0 + + set ret [catch \ + {exec $util_path/db_dump -f "$temp_dir/update.dump" \ + "$temp_dir/update.db"} message] + error_check_good \ + "Update dump: $version $method $file $message" $ret 0 + + error_check_good "Update diff.1.1: $version $method $file" \ + [filecmp "$temp_dir/$file.dump" "$temp_dir/update.dump"] 0 + error_check_good \ + "Update diff.1.2: $version $method $file" $ret "" + } + + if { $do_update_test } { + set ret [catch \ + {berkdb open -update "$temp_dir/$file-$endianness.db"} db] + if { $ret == 1 } { + if { ![is_substr $errorInfo "version upgrade"] } { + set fnl [string first "\n" $errorInfo] + set theError \ + [string range $errorInfo 0 [expr $fnl - 1]] + error $theError + } + } else { + error_check_good dbopen [is_valid_db $db] TRUE + error_check_good dbclose [$db close] 0 + + set ret [catch \ + {exec $util_path/db_dump -f \ + "$temp_dir/update.dump" \ + "$temp_dir/$file-$endianness.db"} message] + error_check_good "Update\ + dump: $version $method $file $message" $ret 0 + + error_check_good \ + "Update diff.2: $version $method $file" \ + [filecmp "$temp_dir/$file.dump" \ + "$temp_dir/update.dump"] 0 + error_check_good \ + "Update diff.2: $version $method $file" $ret "" + } + } +} diff --git a/db/test/upgrade.tcl b/db/test/upgrade.tcl new file mode 100644 index 000000000..0d2f656bc --- /dev/null +++ b/db/test/upgrade.tcl @@ -0,0 +1,279 @@ +# See the file LICENSE for redistribution information. +# +# Copyright (c) 1999, 2000 +# Sleepycat Software. All rights reserved. +# +# $Id: upgrade.tcl,v 11.16 2000/10/27 13:23:56 sue Exp $ + +source ./include.tcl + +global upgrade_dir +# set upgrade_dir "$test_path/upgrade_test" +set upgrade_dir "$test_path/upgrade/databases" + +global gen_upgrade +set gen_upgrade 0 + +global upgrade_dir +global upgrade_be +global upgrade_method + +proc upgrade { { archived_test_loc "DEFAULT" } } { + source ./include.tcl + global upgrade_dir + + set saved_upgrade_dir $upgrade_dir + + puts -nonewline "Upgrade test: " + if { $archived_test_loc == "DEFAULT" } { + puts "using default archived databases in $upgrade_dir." + } else { + set upgrade_dir $archived_test_loc + puts "using archived databases in $upgrade_dir." + } + + foreach version [glob $upgrade_dir/*] { + if { [string first CVS $version] != -1 } { continue } + regexp \[^\/\]*$ $version version + foreach method [glob $upgrade_dir/$version/*] { + regexp \[^\/\]*$ $method method + foreach file [glob $upgrade_dir/$version/$method/*] { + regexp (\[^\/\]*)\.tar\.gz$ $file dummy name + + cleanup $testdir NULL + #puts "$upgrade_dir/$version/$method/$name.tar.gz" + set curdir [pwd] + cd $testdir + set tarfd [open "|tar xf -" w] + cd $curdir + + catch {exec gunzip -c "$upgrade_dir/$version/$method/$name.tar.gz" >@$tarfd} + close $tarfd + + set f [open $testdir/$name.tcldump {RDWR CREAT}] + close $f + + # It may seem suboptimal to exec a separate + # tclsh for each subtest, but this is + # necessary to keep the testing process + # from consuming a tremendous amount of + # memory. + if { [file exists $testdir/$name-le.db] } { + set ret [catch {exec $tclsh_path\ + << "source $test_path/test.tcl;\ + _upgrade_test $testdir $version\ + $method\ + $name le"} message] + puts $message + if { $ret != 0 } { + #exit + } + } + + if { [file exists $testdir/$name-be.db] } { + set ret [catch {exec $tclsh_path\ + << "source $test_path/test.tcl;\ + _upgrade_test $testdir $version\ + $method\ + $name be"} message] + puts $message + if { $ret != 0 } { + #exit + } + } + + set ret [catch {exec $tclsh_path\ + << "source $test_path/test.tcl;\ + _db_load_test $testdir $version $method\ + $name"} message] + puts $message + if { $ret != 0 } { + #exit + } + + } + } + } + set upgrade_dir $saved_upgrade_dir + + # Don't provide a return value. + return +} + +proc _upgrade_test { temp_dir version method file endianness } { + source include.tcl + global errorInfo + + puts "Upgrade: $version $method $file $endianness" + + set ret [berkdb upgrade "$temp_dir/$file-$endianness.db"] + error_check_good dbupgrade $ret 0 + + upgrade_dump "$temp_dir/$file-$endianness.db" "$temp_dir/temp.dump" + + error_check_good "Upgrade diff.$endianness: $version $method $file" \ + [filecmp "$temp_dir/$file.tcldump" "$temp_dir/temp.dump"] 0 +} + +proc _db_load_test { temp_dir version method file } { + source include.tcl + global errorInfo + + puts "db_load: $version $method $file" + + set ret [catch \ + {exec $util_path/db_load -f "$temp_dir/$file.dump" \ + "$temp_dir/upgrade.db"} message] + error_check_good \ + "Upgrade load: $version $method $file $message" $ret 0 + + upgrade_dump "$temp_dir/upgrade.db" "$temp_dir/temp.dump" + + error_check_good "Upgrade diff.1.1: $version $method $file" \ + [filecmp "$temp_dir/$file.tcldump" "$temp_dir/temp.dump"] 0 +} + +proc gen_upgrade { dir } { + global gen_upgrade + global upgrade_dir + global upgrade_be + global upgrade_method + global runtests + source ./include.tcl + + set gen_upgrade 1 + set upgrade_dir $dir + + foreach upgrade_be { 0 1 } { + foreach i "btree rbtree hash recno rrecno queue frecno" { + puts "Running $i tests" + set upgrade_method $i + set start 1 + for { set j $start } { $j <= $runtests } {incr j} { + if [catch {exec $tclsh_path \ + << "source $test_path/test.tcl;\ + global upgrade_be;\ + set upgrade_be $upgrade_be;\ + run_method -$i $j $j"} res] { + puts "FAIL: [format "test%03d" $j] $i" + } + puts $res + cleanup $testdir NULL + } + } + } + + set gen_upgrade 0 +} + +proc upgrade_dump { database file {stripnulls 0} } { + global errorInfo + + set db [berkdb open $database] + set dbc [$db cursor] + + set f [open $file w+] + fconfigure $f -encoding binary -translation binary + + # + # Get a sorted list of keys + # + set key_list "" + set pair [$dbc get -first] + + while { 1 } { + if { [llength $pair] == 0 } { + break + } + set k [lindex [lindex $pair 0] 0] + lappend key_list $k + set pair [$dbc get -next] + } + + # Discard duplicated keys; we now have a key for each + # duplicate, not each unique key, and we don't want to get each + # duplicate multiple times when we iterate over key_list. + set uniq_keys "" + foreach key $key_list { + if { [info exists existence_list($key)] == 0 } { + lappend uniq_keys $key + } + set existence_list($key) 1 + } + set key_list $uniq_keys + + set key_list [lsort -command _comp $key_list] + + # + # Get the data for each key + # + set i 0 + foreach key $key_list { + set pair [$dbc get -set $key] + if { $stripnulls != 0 } { + # the Tcl interface to db versions before 3.X + # added nulls at the end of all keys and data, so + # we provide functionality to strip that out. + set key [strip_null $key] + } + set data_list {} + catch { while { [llength $pair] != 0 } { + set data [lindex [lindex $pair 0] 1] + if { $stripnulls != 0 } { + set data [strip_null $data] + } + lappend data_list [list $data] + set pair [$dbc get -nextdup] + } } + #lsort -command _comp data_list + set data_list [lsort -command _comp $data_list] + puts -nonewline $f [binary format i [string length $key]] + puts -nonewline $f $key + puts -nonewline $f [binary format i [llength $data_list]] + for { set j 0 } { $j < [llength $data_list] } { incr j } { + puts -nonewline $f [binary format i [string length [concat [lindex $data_list $j]]]] + puts -nonewline $f [concat [lindex $data_list $j]] + } + if { [llength $data_list] == 0 } { + puts "WARNING: zero-length data list" + } + incr i + } + + close $f +} + +proc _comp { a b } { + if { 0 } { + # XXX + set a [strip_null [concat $a]] + set b [strip_null [concat $b]] + #return [expr [concat $a] < [concat $b]] + } else { + set an [string first "\0" $a] + set bn [string first "\0" $b] + + if { $an != -1 } { + set a [string range $a 0 [expr $an - 1]] + } + if { $bn != -1 } { + set b [string range $b 0 [expr $bn - 1]] + } + } + #puts "$a $b" + return [string compare $a $b] +} + +proc strip_null { str } { + set len [string length $str] + set last [expr $len - 1] + + set termchar [string range $str $last $last] + if { [string compare $termchar \0] == 0 } { + set ret [string range $str 0 [expr $last - 1]] + } else { + set ret $str + } + + return $ret +} diff --git a/db/test/upgrade/README b/db/test/upgrade/README new file mode 100644 index 000000000..1afada2ec --- /dev/null +++ b/db/test/upgrade/README @@ -0,0 +1,85 @@ + The Berkeley DB Upgrade Tests + +Quick ref: + + Running the tests: + (in tclsh) + % source ../test/test.tcl + % upgrade + + Generating the test databases: + (in tclsh) + % source ../test/test.tcl + % gen_upgrade /where/you/want/them + + (in your shell) + $ cd /where/you/want/them + $ perl $db_dir/upgrade/scripts/pack-3.0.pl + $ mv 3.0 $db_dir/upgrade/databases + +What they are: + +The DB upgrade tests are a framework for testing two main features of +Berkeley DB: the db_dump utility, and the "DB_UPGRADE" flag to DB->open. +They work by taking a tarred, gzipped set of test databases and dumps, and +verifying that the set of items is the same in the original database (as +dumped by the version of DB that created it) as in the upgraded one, +and is the same in the original database and in a new database generated by +db_loading a db_dump. + +In db 3.X and higher, the upgrade test is repeated on a database with +the opposite endianness to the system the database was generated on. + +How to generate test databases: + +Ordinarily, this is something that only very rarely has to occur; +an archive of upgrade test databases can and should be kept, so ideally +the generation step only needs to be done once for each major DB release. + +To generate the test databases, execute the command "gen_upgrade " +inside a tclsh. The method tests will run twice, once for each endianness, +and all the databases will be saved in a hierarchy named by . + +Once the databases have been built, the archives expected by the upgrade tests +must be built using the "pack" script, in upgrade/scripts/pack-.pl. +This script must be edited slightly to specify the location on a given system +of the DB source tree and utilities; it then converts the set of databases +under the current working directory into a set of .tar.gz files containing +the databases as well as flat files with their contents in item-by-item and +db_dump formats. + +How to run the upgrade tests: + +Run "upgrade" from tclsh in the DB build directory. By default, this +looks in upgrade/databases, in the DB source tree. An optional first argument +can be used to specify an alternate directory. + +A note on 2.X tests: + +The 2.X packing script, as well as a patch against a 2.6.6 test directory +to allow it to generate test databases, is in upgrade/generate-2.X. + +Note that the upgrade tests can be *run* on an the 2.X test archives +without anything in this directory. It is provided only for +archival reasons, in case there is ever reason to generate a new +set of test databases. + +XXX: Note also that it quite likely has paths hard-coded for a specific +system that is not yours. + +Known Issues: + +1. The following 2.X databases trigger a bug in the db 2.X hash code. +This bug affects only empty and near-empty databases, and has been +corrected in db 3.X, but it will prevent the following from passing +the db_dump test. (They have been removed from the canonical database +collection.) + + 2.X hash -- test026 + 2.X hash -- test038 + 2.X hash -- test039 + 2.X hash -- test040 + +2. The 2.X recno versions of test043 cannot be made to pass the db_dump +test because the 2.X version of db_dump has no -k flag and cannot preserve +sparsely populated databases. diff --git a/db/test/upgrade/generate-2.X/pack-2.6.6.pl b/db/test/upgrade/generate-2.X/pack-2.6.6.pl new file mode 100644 index 000000000..f031d46ca --- /dev/null +++ b/db/test/upgrade/generate-2.X/pack-2.6.6.pl @@ -0,0 +1,114 @@ +#!/usr/bin/perl + +use strict; +use Archive::Tar; + +my $subdir; +my $file; +my $archive_name; + +my $version = "2.6.6"; +my $build_dir = "/work/db/upgrade/db-2.6.6/build_unix"; +my $db_dump_path = "$build_dir/db_dump"; +my $pwd = `pwd`; + +$| = 1; + +chomp( $pwd ); + +opendir( DIR, $version . "le" ) || die; +while( $subdir = readdir( DIR ) ) +{ + if( $subdir !~ m{^\.\.?$} ) + { + opendir( SUBDIR, $version . "le/$subdir" ) || die; + while( $file = readdir( SUBDIR ) ) + { + if( $file !~ m{^\.\.?$} ) + { + print "[" . localtime() . "] " . "$subdir $file", "\n"; + + eval + { + my $data; + my $archive; + + system( "mkdir", "-p", "$version/$subdir" ); + $file =~ m{(.*)\.}; + $archive_name = "$1"; + $archive_name =~ s{Test}{test}; + $archive = Archive::Tar->new(); + $archive->add_data( "$archive_name-le.db", + read_file( $version . "le/$subdir/$file" ) ); +# $archive->add_data( "$archive_name-be.db", +# read_file( $version . "be/$subdir/$file" ) ); + $archive->add_data( "$archive_name.dump", + db_dump( "$pwd/$version" . "le/$subdir/$file" ) ); + $data = tcl_dump( "$pwd/$version" . "le/$subdir/$file" ); + $archive->add_data( "$archive_name.tcldump", $data ); + $archive->write( "$version/$subdir/$archive_name.tar.gz", 9 ); + }; + if( $@ ) + { + print( "Could not process $file: $@\n" ); + } + } + } + } +} + +sub read_file +{ + my ($file) = @_; + my $data; + + open( FILE, "<$file" ) || die; + read( FILE, $data, -s $file ); + close( file ); + + return $data; +} + +sub db_dump +{ + my ($file) = @_; + + #print $file, "\n"; + unlink( "temp.dump" ); + system( "sh", "-c", "$db_dump_path $file >temp.dump" ) && die; + if( -e "temp.dump" ) + { + return read_file( "temp.dump" ); + } + else + { + die "db_dump failure: $file\n"; + } +} + +sub tcl_dump +{ + my ($file) = @_; + my $up_dump_args = ""; + + if ($file =~ /test012/) { + $up_dump_args .= "1"; + } + + unlink( "temp.dump" ); + open( TCL, "|$build_dir/dbtest" ); +print TCL < 0 } { ++ set d "\0$d" ++ incr numnul -1 ++ } ++ ++ # The old Tcl getbin and the old Tcl partial put ++ # interface are incompatible; we'll wind up returning ++ # the datum twice if we try a getbin now. So ++ # set a flag to avoid it. ++ set is_partial 1 ++ ++ } else { ++ set d $data ++ } ++ ++ ++ if { $is_partial != 1 } { ++ ++ # Stick a null on the end. ++ set d "$d\0" ++ ++ set tmp $testdir/gb1 ++ ++ # Attempt a dbc getbin to get any additional parts of the datum ++ # the Tcl interface has neglected. ++ set dbt [$dbc getbin $tmp 0 $DB_CURRENT] ++ ++ set tmpid [open $tmp r] ++ fconfigure $tmpid -encoding binary -translation binary ++ set cont [read $tmpid] ++ ++ set d $d$cont ++ ++ #puts "$data->$d" ++ ++ close $tmpid ++ } ++ ++ return [list $d] ++ } ++ ++ # Implement the DB_SET functionality, stupidly, in terms of DB_NEXT and ++ # manual comparisons. We have to use this instead of DB_SET with ++ # binary keys, as the old Tcl interface can't handle binary keys but DB_SET ++ # requires them. So instead, we page through using DB_NEXT, which returns ++ # the binary keys only up to the first null, and compare to our specified ++ # key, which is similarly truncated. ++ # ++ # This is really slow, but is seldom used. ++ proc _search_binkey { key dbc } { ++ #puts "doing _search_binkey $key $dbc" ++ source ./include.tcl ++ set dbt [$dbc get 0 $DB_FIRST] ++ while { [llength $dbt] != 0 } { ++ set curkey [lindex $dbt 0] ++ if { [string compare $key $curkey] == 0 } { ++ return $dbt ++ } ++ set dbt [$dbc get 0 $DB_NEXT] ++ } ++ ++ # We didn't find it. Return an empty list. ++ return {} ++ } diff --git a/db/test/wordlist b/db/test/wordlist new file mode 100644 index 000000000..03ea15f72 --- /dev/null +++ b/db/test/wordlist @@ -0,0 +1,10001 @@ +cooperate +benighted +apologist's +addresser +cataract +colonially +atoned +avow +bathroom +anaesthesia +columnated +bogs +astral +barbed +captives +acclaims +adjutants +affidavits +baptisms +bubbling +classic +allaying +component +battlement +backtrack + +courage +bore +advertisement +attests +bunny's +airlifts +cajole +cataloging +airily +collected +abridged +compel +aftermath +barrow +approve +chillier +bequest +attendant +abjures +adjudication +banished +asymptotes +borrower +caustic +claim +cohabitation +corporacies +buoy +benchmark's +averting +anecdote's +caress +annihilate +cajoles +anywhere +apparitions +coves +bribed +casually +clue's +asserted +architects +abstained +attitude +accumulating +coalesced +angelic +agnostic +breathed +bother +congregating +amatory +caging +countryside +chapel +buttonhole +bartenders +bridging +bombardment +accurately +confirmed +alleviated +acquiring +bruise +antelope +albums +allusive +corker +cavity's +compliment +climb +caterpillar +almond +authenticated +balkan +assembly's +acidity +abases +bonny +been +abbots +abductor's +aerials +cancels +chalked +beeps +affirms +contrariness +clearest +appropriations +critiquing +affluence +bouts +abiding +comprises +brunches +biology +conceptualization's +assaying +abutter +adorable +beatable +appenders +aggressors +agrarian +bottleneck +angled +beholds +bereaved +creation +animated +candied +bar +aeronautics +cousin's +cleaver +alienation +billet +bungler +contention +businessman +braids +assert +boisterous +consolidate +breathing +ballot +averted +conscientiously +bellow +brazenness +coaches +bulldog +classify +checksum +almond's +cornered +caskets +capacitors +beefer +connoisseurs +consisted +adore +circumvented +colonels +addenda +boost +compatibility's +bumblebee +commonest +containment +active +absorption's +creaks +administer +beset +aborted +aforesaid +aridity +broken +azimuths +aerial +addition's +aggrieve +anthology +circuitous +checks +alley's +beam +boss +corrupting +absolutes +asteroid's +bandstands +beatitude's +analogue's +busts +confession +bedstead +affairs +blackmailers +collared +buckboard +assassin +accessor +adjudging +binders +constituent's +blister +aromas +approved +absorbent +barbarously +cat's +builder +brandish +assailing +constitute +christening +acutely +amount +blurry +blocks +advertise +chain +brigade's +confusion +beds +arrangers +colonizers +beautifying +bankruptcy +bedazzles +candidates +clearness +admonishment's +behind +abbreviations +basting +ballasts +amateurism +celled +constituted +bonfire +bugled +advisee's +battled +budded +burners +causeway's +calibrate +brambly +befuddles +azure +busiest +admiringly +appropriator +accumulator +cables +abhor +civil +botulinus +creaked +bismuth +astronomical +abscissas +bodice +aunt +cascades +cares +comradeship +assemblages +boater +bellmen +admission's +ambitious +baldness +abortive +controlled +chinked +coded +courtrooms +arteriolar +cooler's +cared +brewer +christians +barbecues +contacts +blackjack's +buzzing +blasters +accords +braziers +allegretto +catered +breveting +cleaning +amicably +bummed +consulted +allegro's +accumulator's +compartmented +condemned +concludes +bitwise +cheered +appropriator's +accessors +casting +carolina's +accompanying +budding +correspond +bach's +angel's +bearing +arresters +biweekly +character +badgering +cantankerous +avalanching +adjudges +barometer +append +continuations +burped +boxtop's +abstention +amp +axiomatized +bimonthlies +aghast +arresting +breakwater's +continuing +bridle +bobbin's +antagonistically +blindly +biochemical +biologically +antifundamentalist +confer +cloudiness +bonded +comfortingly +caption +blackmailed +bidders +breakpoint +brigadier +criminals +coyotes +casserole's +annex +cereals +breadboxes +belgian +conductivity +counterexample +anarchist +couches +atavistic +clipped +button +axiomatic +capping +correcting +chase +chastise +angle +burnished +beauteously +antipodes +crippling +crowns +amends +bah +brigadiers +alleged +correctives +bristles +buzzards +barbs +bagel +adaptation +caliber +browner +apprehensions +bonnet +anachronistically +composites +bothered +assurer +arc +chaser +bastards +calmed +bunches +apocalypse +countably +crowned +contrivance +boomerang's +airplane's +boarded +consumption +attuning +blamed +cooing +annihilation +abused +absence +coin +coronaries +applicatively +binomial +ablates +banishes +boating +companions +bilking +captivate +comment +claimants +admonish +ameliorated +bankruptcies +author +cheat +chocolates +botch +averring +beneath +crudely +creeping +acolytes +ass's +cheese's +checksum's +chillers +bracelet +archenemy +assistantship +baroque +butterfly +coolie's +anecdote +coring +cleansing +accreditation +ceaselessly +attitudes +bag +belong +assented +aped +constrains +balalaikas +consent +carpeting +conspiracy +allude +contradictory +adverb's +constitutive +arterial +admirable +begot +affectation +antiquate +attribution +competition's +bovine +commodores +alerters +abatements +corks +battlements +cave +buoys +credible +bowdlerizes +connector +amorphously +boredom +bashing +creams +arthropods +amalgamated +ballets +chafe +autograph +age +aid +colleague's +atrocious +carbonizing +chutes +barbecued +circuits +bandages +corporations +beehive +bandwagon +accommodated +councillor's +belted +airdrop +confrontations +chieftain's +canonicalization +amyl +abjectness +choke +consider +adjuster +crossover's +agreeing +consolations +capitalizers +binges +annihilating +callers +coordinate +banshees +biscuits +absorbency +corollary +corresponded +aristocrat's +banally +cruiser +bathtub's +abbreviated +balkiness +crew +acidulous +air +birdies +canvassing +concretion +blackjacks +controller's +aquarius +charm +clip +awarder +consistently +calibrated +bushwhacking +avaricious +ceaselessness +basically +accolades +adduction +commending +consulates +certifiable +admire +bankers +appropriateness +bandlimits +chill +adds +constable +chirping +cologne +cowardice +baklava +amusedly +blackberry +crises +bedeviling +botching +backbend +attaining +continuity +artistry +beginner +cleaner's +adores +commemorating +amusement +burial +bungalow's +abstinence +contractually +advancement's +conjecture +buckling +conferrer +cherub's +belonged +classifications +baseball +carbonation +craved +bans +aphid +arbor +ague +acropolis +applied +aspired +calibrating +abundance +appeased +chanted +ascent +convenes +beep +bottles +aborigines +clips +acquainting +aiming +creditor's +abolitionists +cloves +containments +bungling +bunt +anchors +brazed +communicator's +brew +accumulate +addicting +actively +befog +anachronisms +bumblers +closest +calculators +absurdity +colleagues +college +assesses +conflicted +associational +betide +conceptualization +adjutant +alliances +corresponding +barometers +cot +brooch's +coiled +arboreal +convicted +artless +certificates +bourbon +astonish +bust +correlate +amounts +anal +abstraction's +corns +conqueror's +boldly +bob's +beer +blanks +corpses +contingent +blackly +backed +appearances +cancers +actuating +apprehension's +colorings +anglicanism +armament +armer +bizarre +begotten +actions +archly +capriciously +clue +contractor +contributions +agendas +coached +blamable +annoyers +coupons +brooked +assortment +axes +celebrates +courageously +baroqueness +blasphemous +asserter +contents +correctly +challenged +bulldoze +casement +acknowledge +bitterness +belongs +allotments +chalice's +bequest's +adjacent +consumer's +conservatively +coalition +background's +backache +befouls +brushfire's +analysts +branch +airways +awaiting +breakfast +anoints +baying +contrary +bilge +chasm's +babes +afresh +centerpiece's +barked +coffin +assumed +actresses +accentuating +aching +abet +balancers +consumptively +cagers +backing +angiography +chord's +cheapened +bewailed +arson +begged +convergent +bowlers +conflicting +confiscated +bitch +bloody +brushfires +bleach +computation's +choppers +circuitously +chancing +bunker +concept's +alacrity +boyhood +ammo +bobwhites +carter +ardent +bier +airway's +brownies +aura +cannibalizing +confirms +australian +barrage +closures +assertive +abstainer +bicarbonate +clone +back +cipher +crown +cannibalizes +away +crafty +airings +amtrak +comical +burnish +continuum +apparition +apologizing +blot +blacker +characters +built +apparent +applicative +assiduous +attorneys +affectionately +bobbing +baggy +comic's +attempt +appealers +amortize +bonanza +backwards +bowers +anemometer +ambulance's +creeps +abduction's +coal +chiller +adjudications +clogging +ascending +bookkeeper +crawlers +battery's +artifacts +attributions +amusements +aftermost +allophones +bemoaned +comptroller +bugger's +buoyancy +booboo +award +amplifying +certify +bivariate +attunes +asteroidal +chant +collectively +chasteness +chapels +copiousness +benign +armies +competing +buss +awakened +breakpoint's +conceptualizing +cleansers +acorns +conveyance's +bluer +battle +budges +characteristically +be +contour +beguiling +awarding +armhole +airship's +bathtub +breathable +crowded +compiles +certain +brutalizing +bacteria +baronies +abode +blacksmith +brinkmanship +capitalizations +cousin +botany +avionic +companion +consists +connoisseur's +avalanched +claimant's +backstitches +affixes +bikes +atomically +cowed +asleep +becomingly +acorn's +complainers +appreciated +cross +cringed +booting +attitudinal +broadcasting +childishly +breeze's +craven +boll +clause's +burden +appendages +atemporal +allah +carnival's +anchorage +adjures +besought +abounding +crucifying +arrangements +antiquarians +burrows +antipode +canvas +constable's +coopers +ascended +companionship +bakery's +bayonets +conclusively +boasters +beneficiaries +conspicuous +contriver +architecture +breakthroughs +brownie's +blur +academics +antagonist +contemplates +arena +caravan's +administers +comprehensively +convey +bigot +blitz +bibliography's +coerced +assail +amazons +banned +alabaster +concluding +bouquet +barks +acquaintances +astonishment +constraint +backpack's +breakthroughes +blocking +accomplishers +catastrophe +bushels +algae +ailment's +anemometers +beginning's +chefs +converse +cornerstone +astound +assuring +adornment +anyone +alumni +club +bestselling +businessmen +constructed +attendee's +cooped +ablute +chronicler +alaska +clam +canonicals +concerned +aligned +creek +burrow +allay +admirals +blackens +compressing +confirm +cows +battleship's +belched +affixing +chalices +choirs +absentee's +baseboard's +apportionment +adheres +accounts +chef +access +clearings +accompanists +concentrating +ado +bathos +bailiff +continuance +ball +bearer +congress +cites +can't +balloon +crams +consults +bungled +bike's +apes +assassinations +colt's +consecrate +ancients +chick +analyst +adsorbing +burntly +accompanist's +apprehensive +bengal +boughs +ankles +anchored +benefits +accommodation +amiss +brink +chewers +blueberry's +chairs +adjoin +bivalve +autobiography's +automated +comparisons +climbed +artists +congruent +cold +atonement +cashier +armageddon +allocations +bereavements +bumblebees +blew +busboys +bottoming +alternations +apprenticed +bestial +cinder's +consumption's +abbey's +amended +continued +birefringent +barbados +ability's +compulsory +antler +centerpieces +accountant's +arrogant +ballads +ascenders +appliers +adjustment's +blabbed +baits +activity's +clod's +adjudicating +bleak +commutes +bumming +beating +cohesiveness +branded +acknowledger +communications +blockhouses +booklets +consenters +creek's +consulting +binary +coaster +ascription +bushwhack +boggles +affidavit's +arrangement's +congressionally +convenient +avoider +abaft +bootlegger's +befriending +ceases +carbonizes +clumps +commented +competence +conversing +butting +astonishing +armful +allegory's +crisis +critiques +concurred +conservative +aristotelian +blizzard's +corner +amateur's +compare +affiliations +bestseller +batch +cleanly +assayed +bravos +bowls +conceptualized +babe's +algorithm's +baptist +cheeks +conquerer +bidder's +behaving +briefcase's +analogues +amply +attitude's +apple +crossable +ambushed +besmirches +creditors +bandwagons +continentally +adjuncts +concerns +agers +cop +amoebas +bisected +bombing +appendices +cocking +bused +babied +compounds +asserts +believably +alert +apostate +catalysts +aureomycin +convex +beetle's +banishing +agitating +bystanders +bow +connotes +blanch +charmingly +animal's +baritones +brier +astronomer +company's +balding +actually +aunt's +avalanches +acquisition +base +compilations +bathtubs +actualization +chanced +atom +banged +befuddled +apologized +componentwise +britisher +began +conservationist +actuate +crosser +appended +bitten +ambivalence +acetate +conversions +buzzwords +askance +abolishing +birdied +creeds +anglers +colossal +bereft +chock +apprentice +cooper +besmirching +allocating +antiques +bikini's +bonders +afflictive +augmentation +atheist +bucket +bibliophile +annexes +beguiles +birdbaths +amendments +animators +asymptotically +communally +barber +biographers +arguable +confidant +apologies +adorns +contacting +coarsest +artichokes +arraign +absorbing +alden +commercially +cabbage's +coincides +clumping +cents +alleviater +buzzard +braked +anesthetized +bugling +capitalist +befriended +appreciatively +boomtown's +cozier +critic's +correspondent +bard +attenuator +bake +brings +chews +anechoic +brutal +colder +buckshot +canvassers +analytic +allies +alloys +awake +alienates +bin's +crimes +constructible +classifiers +bulb +cream +banquet +axiomatize +adjourn +converted +auditioned +comfortably +bandwidth +cannibalize +ascensions +bussing +balloons +contenders +commemoration +aspersions +consultation +cashes +belting +augurs +architectural +bluebird's +breastworks +absconded +bullets +bloodstain's +blunder +astronautics +coo +approves +authority +assure +amsterdam +acquitted +adversity +celebrate +bred +bridged +bloc's +bullied +affinity +breezes +baptistry's +constitutions +avouch +amazingly +consolation +abnormality +clashes +buttes +buzzard's +breathers +chipmunk +contented +carol's +armers +amazedly +comprehends +canonicalize +breakthrough +arbitrator +butterfat +cases +besiegers +affianced +amelia +bush +airplane +annulled +bike +alternated +attackers +convene +aficionado +anachronism's +crude +carelessness +akin +combated +assisting +clocker +attacked +briefed +antic's +attendants +attracting +cope +allotting +bandwidths +add +assaulting +breakage +climes +arrival's +burp +accelerator +capacitance +arabians +bankruptcy's +archeological +coins +browbeating +chasm +cardinalities +compartmentalize +courter +assess +abreaction +brakes +compatibly +compression +characterizable +briefing's +alto's +classifiable +contrast +correlation +colonial +applying +authorizers +contesters +basely +cherries +clicking +cornfield's +alarmingly +conferences +business's +banker +bloomed +airfield +attracts +building +commutative +atomization +competitions +boatsmen +acquirable +arkansas +command +beings +compactors +anodize +arguments +conforming +adsorption +accustomed +blends +bowstring's +blackout +appender +buggy +bricklaying +chart +calmer +cage +attractive +causation's +athenian +advise +cranks +containers +besotter +beret +attender +cone +bills +aligns +brushlike +brownest +bosom's +berth +accountably +bequeathed +affirmatively +boundless +alleyways +commute +bendable +abhors +calculation +affidavit +answerable +bellicose +counterfeiting +admiral's +chisel +bridesmaids +believers +aggregated +conspicuously +abased +armenian +conspirator +canonical +assignable +barrage's +clearance's +casts +administratively +befoul +chaffer +amazer +colorer +broaching +crevice +aniline +coursing +compassionate +adhesive +bibliographies +corrects +augments +between +causer +amorist +cellist's +acoustical +baseless +cigarettes +astuteness +appropriators +convincing +bellhop's +bemoaning +calmingly +chronologically +castles +algebraically +appointees +academic +blunderings +assassins +barrel +accuracy +amortized +ballpark +acrobat's +brazier's +abortively +coarser +airfields +contester +circus's +creased +amorphous +accomplisher +blabs +butchers +crackles +bachelor +aviators +chariot's +circumflex +binocular +alienating +artificially +agreement's +aglow +afghan +abrupt +annihilates +apologetic +barge +betters +algorithms +conjurer +chargeable +brindle +alphabetizes +coder +availing +bandpass +arrogance +convent's +advertiser +connected +basso +breakfaster +comic +congenial +beau +courters +adapters +abruptly +chemicals +bringed +creaming +butterer +attained +actuals +averred +brainwash +centerpiece +blabbermouth +byproduct's +adaptable +automata +art +cheery +beheld +beehive's +claimed +crucial +brokenness +agility +combating +cleft +amenity +after +configuration +contrasting +coarsely +brass +barnstormed +bowel +bridesmaid's +cornfield +crazing +autocracies +adult +conceptualizations +corroboration +bedders +arroyo +alarmist +boatman +chests +burglary +budgets +canary's +arraigning +chin +barnstorms +blamers +brimful +calculate +cellular +contended +challenges +brusque +bikinis +arithmetics +chairpersons +class +aircraft +capably +centralize +awhile +compacting +courteous +archaeologist's +cram +adagio +affronts +amplitude's +bureau's +audaciously +autism +blueberries +an +chips +confiner +chopper's +chronology +breaching +bead +amass +camouflage +compensation +aspect +broker +atrophy +balk +bloodless +barnyard +benefactor's +airdrops +caused +anthem +activist's +bottomless +arrogates +avoided +bouncy +clarified +articulate +almoner +communists +blokes +butternut +clockings +barium +blows +criticism's +associations +brute +bleeds +alliteration's +bluestocking +boxwood +clearer +allegiance +conceptualizes +captivating +bolshevik's +belabored +biographic +contaminates +chanticleer's +adjusted +childhood +arguing +cape +conversantly +compensating +collaborations +arraignment's +blasted +charging +aggregation +apprentices +bird +codifiers +ballistic +breve +bells +carolina +chalk +buckles +boyfriend's +adorn +accoutrements +availability +antisymmetry +blades +alluded +asterisks +bookcases +additive +consents +advanced +balalaika +coders +caliph +alundum +are +controllable +blazing +clattered +asiatic +axiomatizes +ace +coining +column +auditor's +carol +concatenated +arrayed +capital +cautioner +clan +beauteous +abbreviate +asteroids +canal's +consolidation +closets +concealer +crevices +abed +complex +conviction's +abide +arrests +begrudges +adolescent +conceals +cells +circles +bravest +compromiser +bagels +areas +afore +allergies +arrangement +attraction's +amulets +abstraction +captured +crouched +brothers +cash +achieving +bastard +compete +boiling +beaching +amphetamines +clerking +congestion +alleviates +angry +bared +comprehended +bloodstain +constituency's +automating +aerial's +counterfeit +besotted +basses +biofeedback +compilation's +band +consulate +appellant +cough +antennae +contend +anniversary +boor +artifactually +aerobics +booths +chubbiest +consumable +assignments +bromide's +confined +breakers +alongside +courtier +boisterously +bilaterally +alternation +auspiciously +arbitrated +condemning +burns +correspondents +composition +cavalierly +coverlets +capacities +clatter +apotheoses +cartography +ceased +capitalized +auditor +appendicitis +chops +barony +anemometry +befouled +briefer +chest +begetting +bloats +bookseller's +commitment +confides +carcass's +battering +altruistically +ballots +adornments +broaden +angularly +coefficient +cataloged +brae +advantage +anthems +calculated +counseling +agitate +accentuated +camel +ambivalent +bedposts +beacons +chubbier +cheerer +assumes +concord +autumns +convention's +alpha +adulterates +arbiters +archaically +criteria +achilles +cheaper +bulling +associators +bloater +brawler +ability +adherents +commonwealth +coyote's +centrally +bequeathing +abandonment +circumstantially +courteously +borrow +countermeasure's +capricious +allied +anagram's +absorptive +assuage +asset +booked +aspects +commits +crates +capacitive +condones +assimilates +carriage +competitor's +cocoons +aggravated +caravans +arbitrator's +baked +balanced +annihilated +addressable +autonomous +bandwagon's +contesting +burrowing +coroutines +abjection +correctable +applauded +bragged +code +aggressiveness +cluttered +attacking +chide +am +coasters +blizzard +contentment +altruism +certifier +capturing +combinators +carefree +activate +blindfolding +assassinating +approximate +biplane's +aplenty +arteriosclerosis +concentrates +antisymmetric +assurances +anarchist's +ascend +advancing +atrocities +butt's +bearable +craftiness +categorized +barn +contributor's +arises +bushy +bisque +coasted +bargaining +area's +couples +cabs +barter +bulletin +chisels +broadcasters +contingency +bywords +antimicrobial +coexisted +blinding +arithmetize +coweringly +convince +competed +bauble's +crab +boggling +advocacy +atlas +assembled +ancient +bloodstream +balking +bin +bully +affirm +cruelest +atone +conserved +confession's +bat +captive +aster +blames +colonel's +bones +borderline +cleanses +classified +crudest +contiguity +bailing +ablaze +bender +attendee +clobbers +aliasing +autopilot +coolers +cache +allayed +barnyards +britons +appointment +adaptor +blockers +abridges +bloodiest +betrothal +bombards +bony +bus +canary +antinomy +awash +comrades +ablating +collectible +boats +brand +church +bandy +adhering +barred +ammunition +chime +accompaniment's +battleground's +composing +caveats +armor +amoeba +composure +collides +avowed +banding +counsels +asymmetric +abbreviates +balky +adjudicates +anointing +accursed +copse +action +construction's +accents +ambition's +caressing +cosmetic +accession +clutters +censures +allusions +belittled +armchair +abode's +conception's +ascribe +aliases +ancestry +ax +companionable +aright +boxed +brighteners +alloy's +checkable +arraignments +bed +bunkhouses +abbeys +ceasing +companies +cherishing +chunk's +barony's +chinning +burdens +briskness +beggarly +beloved +clambered +constitutionality +beguiled +archers +alleyway +apostle's +consulate's +antiformant +categories +construct +aliments +acquired +blotted +alterations +adolescent's +cranes +bluntest +accusation +chafer +airstrips +abolished +bothersome +churchly +airy +bedded +awareness +alliterative +arose +amputates +civilization's +arenas +certifying +aspirators +carbon's +bunching +aerates +bilked +checking +cloned +administrations +canvasses +colorless +chamber +circumspectly +benedictine +advisedly +classifier +approachable +banners +concurrently +chores +agape +convention +bindings +budget +comedies +ants +ambassadors +chroniclers +carrots +colorful +bulkhead's +coherence +buyer +aggressions +congressional +commoners +cheapen +concealed +columnates +anarchy +actress's +baseboards +creature's +centuries +barbarian +concrete +bicycles +acceptably +acclimating +biceps +bloodhound's +becalmed +apostle +bible +conjunctive +comb +ballers +bickering +adulterous +austrian +applicable +blackberries +creasing +catalogs +avert +asparagus +cambridge +bird's +belgians +admonished +admirations +conscientious +crescent's +connectives +blissful +commenting +bagged +assimilate +abounded +copyright's +advancement +axiom's +compilation +circumlocution's +catheter +chances +concretely +codification +browned +clustering +bum's +clauses +boundlessness +arteriole's +alfresco +begrudged +blustered +anglican +adjoined +bamboo +bathed +consortium +carrot's +cloak +album +bunglers +approbate +colored +aim +cowboy +alienate +cleverest +ambiguous +confrontation's +clear +africa +bowline's +astronauts +belayed +censorship +animation +bedrooms +chasms +compared +cogitated +barbarians +accomplices +columnizes +beaming +busied +counterpointing +aluminum +coconut's +acclamation +chokers +biomedicine +basalt +buckwheat +cardinality's +bafflers +arid +chap's +abound +biblical +backbone +anticipation +condemner +angular +advisability +believing +boiler +arclike +abetter +bespeaks +axiomatically +coarse +auditions +bludgeoning +clam's +chief +arrow +cementing +anxiety +aberrations +brushes +cherub +corollary's +bunters +beefers +barbiturate +circumlocution +conjoined +charities +coverage +campaigner +burrowed +barracks +bristling +accomplice +abandoned +bull +caked +century's +bantu +bristled +airer +bench +bevy +chamberlain's +attention +cloning +camouflaging +alder +counter +credibly +approvingly +breakup +artillery +celestially +bail +baker +bullish +canvass +conversationally +bringers +augment +creditably +butterers +botswana +contemptible +bribing +adumbrate +barb +calico +alludes +amplified +chills +cloak's +aver +arthropod's +budgeter +bereavement +cellars +crewing +blackmailer +ayes +bedsteads +breachers +bazaar +centered +celebrity +blameless +abscissa +aerators +awaited +british +adversary +cowslip +buttons +confusing +buggy's +belts +canceled +addresses +bribes +condoning +bonneted +coarsen +amazement +angels +chemise +carbonates +apostolic +bandit's +contending +consummate +counterclockwise +beneficence +benefitted +contradicts +comfortabilities +anemone +conductive +articles +bookcase +burst +baptizes +countless +costs +agonizes +byte +creeper +begs +bunnies +attract +able +calories +baskets +american +brunt +cognition +closing +chef's +backbone's +complicates +cloister +bedsprings +arrays +brigs +archbishop +buckler +clove +catholic's +bellboys +chairmen +clap +clarifications +ambuscade +bight +bellyfull +allowance's +academy's +acquiescence +ambush +catches +at +billion +contact +bees +adopters +approximately +chiseled +attributively +criers +codification's +cowslips +contradictions +buttock's +categorically +counterpart's +confessor +appreciably +adjusts +altitude +construe +cancer +bay +aristocratic +alleviaters +binoculars +axiomatizing +changer +bustle +civic +bostonians +crops +authorizations +cogitation +baptize +caressed +abase +ariser +axiomatization +aggravates +confiscation +bowdlerize +backspaced +alters +clarity +blots +bland +belligerent's +burgher +cardinally +bookcase's +buggers +byte's +avarice +crowding +beriberi +allegories +coronets +cell +calculative +adduce +amperes +bladders +adages +contests +cognizant +actuates +ambiguity +brighten +concert +conviction +booty +ashtray +braves +blouses +avoiders +confederate +bombings +couplings +convictions +attractiveness +chronicled +corers +anger +covertly +aural +asynchrony +arrowheads +breakdown's +bulletins +ceremonialness +clipper +bracelets +anthropomorphically +benedict +connecting +bacterium +achievers +abutter's +autocorrelate +coupling +blanketer +continental +assignment +conundrum +arab +besides +cheerful +blowup +bastion +arrive +combines +agar +cookie +astronaut's +constraint's +article's +confiscations +bounded +adjudicate +belligerently +boron +brownness +adept +creep +abduction +accosting +asylum +autographed +clash +chiseler +clumsily +capitally +braking +absenting +bagatelle's +comet +basked +anything +buffeted +absentia +bounty +carols +characteristic's +constructive +comforting +aflame +brainwashed +booby +aspirations +adjudge +behaviorism +computability +assessment +consultations +bowstring +acknowledgment +arranger +chancellor +attest +compresses +concessions +asymmetrically +administering +clamoring +arraigned +archived +admonition +actor's +aimers +colorers +booklet +calibers +affix +bushel's +atomizes +creeks +bleedings +casuals +archives +certainly +animate +cons +affiliate +answered +coyote +coughed +alligator's +antagonized +arousal +assisted +aerated +competently +conquering +acclaimed +assign +announcer +controllers +amalgamation +comfort +antihistorical +availed +balsa +annoyed +basted +asymptomatically +cropped +combinational +barging +conversant +causality +botches +bedspread +considerately +bookstores +climate +blessing +accordion's +cdr +bonanza's +construing +bearings +bluster +backspaces +babyish +countermeasure +crime +battered +audit +associating +corps +application +archangel's +aided +breasted +compelled +acrobats +breakfasts +chronologies +beet's +averts +convergence +attributable +adverbial +churns +arrest +breastwork +beefs +brownie +create +contradistinctions +coordinators +abandoning +byline +beatitude +autosuggestibility +bipartite +annals +assents +conceives +amalgams +cleft's +clicked +appointers +bible's +boots +caret +attaches +controversy's +combinatorial +bazaars +cardinals +bored +catering +christian's +ashman +consequence's +austere +clay +birthday's +amongst +arbitrariness +brainstorms +chateaus +coaxer +applause +cautiousness +adorned +compromises +creatures +compliance +apartheid +archiving +amoeba's +communal +comedian's +aggressive +crop +ante +better +chalice +aristocrats +circling +belittle +abortion's +coldly +certification +befriends +courthouse +anesthesia +accorder +athletic +blithe +bedder +abasements +councils +beware +abductor +assonant +clench +aspersion +abortion +abating +birches +breakpoints +acyclic +ablate +canners +cistern +boxtop +composite +cloudless +computation +chastely +abusing +bunker's +compounding +alveolar +chaplains +bias +audiological +capability's +bangle +barren +antidote's +cranking +baptizing +bond +borders +automobile's +allegoric +chargers +baltic +autumn +columns +absolute +connoisseur +cranberry +contiguous +consoled +confirmations +argot +blouse +annotated +callous +astounded +crashed +autonavigators +chivalry +columnating +beefed +convincer +allegorical +bagger +assume +containable +artistically +calibration +architectonic +campaigns +addressability +crazier +buy +brightener +bastion's +blurb +awaits +commands +chocolate +bleaching +antenna +blowers +chorused +composers +assigners +aspires +coils +bid +application's +clamped +bedding +awkwardly +coppers +costumes +borax +caged +candler +badges +clutches +consign +apprised +buys +adiabatically +aggregately +canned +abstract +acrimony +coax +analytically +absurd +alluring +contradicted +aspersion's +bribe +boos +chattererz +backache's +complying +continent +cohabitate +causation +astronomer's +cities +bookie +bleating +cracking +bicameral +convoluted +adjustable +ambulance +can +boulders +consideration +announces +briars +antipode's +bartered +ancestor +biplanes +characterize +crested +bum +bridling +consolable +bungles +coffee +buffets +congratulation +commitment's +adequately +clown +capacitor's +broomsticks +agglutinate +activations +asians +canon's +authenticity +complexities +cripple +bracket +counselor's +beatably +bounced +baton's +crankiest +barbell's +caster +casseroles +ballad's +bob +batched +attenuated +beakers +biologist +bleary +condescend +blondes +augustness +boldface +battlefronts +acumen +bolting +articulatory +butyrate +bowel's +backwater's +colonel +creating +authorized +bijection +accruing +admirably +correctness +citadels +clasps +bandlimit +bib +appalachia +contrives +bundle +audiology +circumventing +blinker +choked +bilks +clears +affirmations +arbitrating +bites +bootstraps +capitals +commuters +billeted +authentication +choice +attentively +aggressor +arterioles +crowds +chestnut +backstitched +attachments +assimilating +bewilderment +atrophied +chintz +blackjack +armadillos +bonfire's +ballast +agonies +busier +coefficient's +adventurous +ballet's +coil +chewed +come +bonder +catalogue +coursed +arise +biennium +ceremony's +blanching +appraisers +acolyte +argues +beholden +appanage +astatine +banana's +coons +civilians +bodyguard +archipelago +bug's +candles +antique's +accidently +blighted +belgium +besieged +burned +abuse +asian +chute +awkwardness +abasing +bottler +ardently +blab +breakwater +cavity +cheated +befall +according +chronicle +airframes +bats +choring +authorize +consumed +chatter +annunciated +capers +anomalous +clustered +burner +acquaintance's +badger's +basic +affectations +buzzy +coast +attendances +activating +beams +cohesive +attainable +barbecueing +beautiful +acronyms +communion +client +atypical +antagonists +conservations +arguers +agglomerate +antigen +battalion +ambition +countered +assistant +classed +arming +alveoli +buff's +backplanes +busted +bermuda +converting +brutish +boot +acidities +confrontation +chapel's +berlin +ascender +behead +buddy's +commandment +actuated +brilliancy +chance +bedrock's +bridgeheads +arable +avid +arteries +caresser +ballyhoo +attested +african +comradely +consciences +commencing +antennas +annulments +bobolink's +advisee +acceptance +crack +ascendent +appendage's +accommodates +accumulated +clones +apocryphal +ages +cluster +capitols +camper +beading +amble +buffeting +circumspect +advances +analyzes +courier's +aperiodic +appealer +atonally +attentive +conspire +appropriating +armed +allergic +agglomeration +consternation +blinks +audibly +aspirins +bunions +adverbs +armload +bet's +caring +carryover +coordinator's +afterthoughts +allays +abided +brownish +baiting +capitalism +coined +conspirators +automatic +contradistinction +conductor's +backstitching +conjure +casings +accountant +clinched +constrain +alcohol +bee +anticompetitive +britain +bade +camera's +antimony +activated +burglarizes +compatible +cotyledon's +artificiality +bath +citadel +archivist +chandelier +addiction +ampersand +bitterer +constructively +afield +bing +attractor's +cringe +allergy's +bigots +assimilation +ate +capitalization +abridge +buzzword +befit +bandlimited +commandant +alabama +acculturated +brightening +bulldozing +cooky +bunks +centers +bespectacled +adherent's +abducts +another's +condensation +billeting +bye +chess +craziest +ballgown's +archaism +consorted +chinned +cowl +beat +bootlegger +bravado +classically +bulging +browbeat +accommodate +borne +bronzed +artifice +arcade +become +backlog +addressers +amphitheaters +befogging +crochet +aiding +celebrated +conversational +backbends +authentications +advertisement's +blockade +bulldozes +contraction's +bricklayer's +brain +conveying +anemia +chronology's +channeling +caution +commanding +crosses +artisan +conditions +admired +authenticator +airships +blunter +bridesmaid +counseled +cheeriness +chiefs +boils +clerical +atrocity's +balls +ambled +canvases +consoles +abscessed +abetting +blitzkrieg +bottlers +beveled +condemn +alumna +cords +admittance +annotates +citing +corrector +appreciative +branching +betrays +buttoned +ailment +boulevards +bottlenecks +chamberlains +bedbug +covenant's +crispness +considering +broadcasts +audubon +arousing +correction +barrack +closure +contrastingly +brittleness +assassin's +bursa +bungalows +balked +conceptual +carcasses +arabia +blueprint's +affectingly +consorting +buses +auger +appointed +brute's +bosoms +anyway +arrowed +anaphorically +clarify +approachability +assistance +buzzes +commonplace +bluebonnet's +adroitness +availers +aquifers +architecture's +action's +backgrounds +abduct +attired +briber +admissibility +cease +beck +auctioneers +birdbath's +atomic +crossing +considerate +biconvex +bulge +bedridden +arising +aggression's +cherish +bureaucratic +abater +amputating +atop +climber +clutched +afford +bisections +bonnets +commendations +bloke +abundant +clamp +aloes +aboard +atheistic +advantageously +buffs +chimney's +cheerily +benefactor +ample +bushwhacked +captain +buckskins +contextually +antiquarian's +browns +bubble +ban's +brine +acculturates +anhydrously +beaver's +advantaged +bibliographic +clasping +clattering +coerce +colorado +airmen +bandlimiting +balks +boners +attached +chosen +convened +bordello +composer +botanist +backtracks +civilization +commutativity +bloodshed +cohere +bunkhouse +archdiocese +boycotted +crosswords +bedspread's +anteaters +cove +apothecary +chute's +addressee +climatically +blower +bane +cask's +beetling +ambiguities +before +abstain +arachnids +bucket's +amateurs +blackouts +adverb +butchery +conjunction's +barricade +audiologists +aphorism +complete +butts +bishops +allotment's +confusingly +channeller's +blanches +bragging +bathe +comedians +celestial +citizens +couple +backpack +aphasic +brothels +axles +cancellations +bonus's +consolidates +authoritative +axle's +acclimatization +carolinas +chime's +antibiotic +bisons +biographically +achieve +bleachers +bicentennial +behavioral +accomplish +concealment +biddies +antitoxins +arriving +apprehend +affluent +cliffs +bleached +astronomers +connection +bride +backs +bog's +casket's +continual +ampere +cat +alternator +cotton +athletes +communicant's +best +befuddling +benefactors +appease +annoyingly +context +astonished +cracked +amnesty +autumn's +binder +babying +contributory +assumption +cowls +cocks +airless +consummated +atypically +beneficially +chairing +accusative +commanded +bufferrer's +alerter +arbiter +civilly +charms +backscattering +cheater +bushes +caverns +chieftain +calf +comparing +aurora +butyl +cower +bemoans +baptistry +carpenter's +capes +bordered +arrows +blocker +crest +appeal +arabic +conventions +axis +brains +bookkeeper's +circle +cooks +circumlocutions +adventists +barringer +affording +anatomically +basements +barbarities +configuration's +contributes +collaborating +beach +comet's +bakes +assigns +ballerina +cheapens +clinging +conquered +bisecting +closenesses +bugle +boatmen +beatings +complicator +bight's +banister's +archaic +anthropologists +clams +beginners +committee's +communicants +alone +bounteously +bastes +ascertain +alphabetical +bringing +batters +amazon's +constituent +benders +being +constitutionally +audiometric +blast +copings +bailiffs +colts +coolies +airlift's +boomerang +bifocal +clothes +cashiers +congenially +billows +boilerplate +biochemistry +betting +brimmed +complementers +breading +bragger +adducting +bisectors +abrogates +criticized +comrade +bucolic +birthright +blurs +challenger +complicated +bluebonnet +biscuit's +classmates +campus's +boundary +bedbug's +adjustor's +acre +bicycling +awe +additions +baiter +authorizes +beautify +copier +buffet +belfries +acquisitions +brooch +crickets +caterpillars +beefsteak +complicating +bedpost +criminal +celebrity's +bookseller +christened +coerces +clamors +all +boatyard's +canoe's +begin +anaerobic +bushing +agreers +concedes +countermeasures +beg +agglutinin +bunted +ammonium +aspiration's +bathrobes +changeable +beached +bestowal +beaner +catsup +admires +clockwise +agile +alarms +ached +chinks +buffer's +cartesian +annunciate +chanticleer +avenue +anchor +alliterations +blanking +bargained +breathtaking +crime's +assiduity +argentina +contiguously +aqua +bested +borderlands +appetite +captive's +bipolar +conceal +counters +costumed +arrestingly +bunting +blight +champagne +brusquely +address +bloodhounds +associative +creed +arithmetical +balustrade's +belabors +complementing +checkout +archivers +badlands +behaviors +ampoules +bridgehead's +antiquarian +clumsiness +considerable +apportions +anglicans +appealingly +barfly's +absorptions +awards +congregates +cloister's +armour +avoid +correctively +chucks +burps +bums +berry +batches +administration +atones +bishop's +blonde's +casualty's +cores +bodied +alter +assonance +apprise +antitoxin +avariciously +checkpoint's +affirmative +conjures +angstrom +aesthetically +canyon +binge +crazed +breastwork's +aids +boston +conceits +announcement's +beechen +accessory +authorities +constrained +automation +anaplasmosis +commander +commendation's +belabor +cornfields +artemis +asphalt +contracted +brochure +crafted +allegedly +alien's +auditory +blowfish +adducible +confederations +annuals +britches +acquaintance +appallingly +abounds +burglarproof +crossers +bayous +brisk +authority's +covetousness +averse +accomplished +aromatic +admiral +bijective +avenging +bran +boatyards +beseeching +challenging +bares +acts +abductions +compendium +compulsion's +calendar's +clad +blockage +conventional +craze +cajoling +acceptability +bungalow +buff +cramps +attackable +calculator's +asp +braved +colors +balling +contaminate +crackling +comes +complimenters +across +astronomy +aborigine +bobwhite's +autopilot's +chattered +appall +autonavigator +bashed +acoustics +beachhead's +apartments +convenience +blackout's +bands +autonomously +amounters +centripetal +achievable +astringency +attuned +concatenating +copyright +coding +assumption's +anastomoses +confiscate +asking +beneficial +adhesions +busboy +bronzes +audacity +bruises +crash +beau's +circuit's +aborts +baubles +beliefs +assuaged +costed +blinking +characterized +bowled +block +conquests +confesses +amusers +ceiling +berets +berliner +abstentions +child +authoritatively +closeness +bushel +considered +communicates +cheerlessly +autofluorescence +aquarium +affects +appurtenances +airbag +approaches +admonishments +bets +bounden +courtly +bodybuilder's +campus +brainstorm +americans +chairperson's +botanical +askew +amazon +bleed +clime's +cooperations +commonness +boatloads +blinked +courtyard +adapted +aforethought +backwater +burr +cathode +awaking +buzzed +bridgeable +arrives +adventuring +beseech +attrition +copied +colon +client's +bandstand's +advice +baptistries +antithetical +alcohol's +contradicting +ambidextrous +belches +category +bluntness +coupon's +assimilations +comfortable +caller +affliction's +attends +compactest +baler +beacon +blind +bleakness +beseeches +courts +couch +consequential +adulterers +craving +biggest +astray +bigoted +barfly +charges +ambiguity's +commentary +crankily +cowerer +carnival +bachelor's +bituminous +continuance's +calamities +claws +apiece +century +ascendancy +charts +animations +aggression +chickadee's +carve +confidence +actor +bubbled +becalming +convulsion +chivalrous +brightest +centralized +beautifies +amateurishness +birthrights +alligator +circumstantial +constructors +conceptions +arranging +cart +cent +ager +congruence +carrot +chariots +cloudier +captivity +conquerers +compartmentalizes +condensing +celebrities +chalks +accordance +chilled +conversations +apples +conceiving +average +blessed +creator +ant +cling +annoyer +aviation +cohesively +correspondences +boor's +apprehended +bessel +both +characterizes +bards +cots +acculturating +cemeteries +carting +alcohols +bitterest +ascetic's +conducts +caking +airspace +autocrats +ashes +chimes +broadcaster +commuter +basket +borderland's +broadened +boyish +allegretto's +ban +bidder +christen +blessings +bury +arranged +choir's +apathetic +boring +aryan +appearing +binds +cooperates +bounces +airspeed +complicators +adapting +babbled +agglomerates +bedraggled +addictions +bolt +calmly +blur's +boatload's +anesthetic +bugs +colt +completing +boxer +billers +affronting +absurdity's +chides +comparatively +braided +clipper's +cot's +calves +articulations +branchings +attraction +concatenates +alligators +cake +boom +crashing +afar +abler +beamed +adverse +adrenaline +agriculture +beehives +crankier +courthouses +advises +consigns +bisect +azimuth's +carpets +arthropod +brewery's +commonalities +altruist +astride +appreciate +carved +briefs +admitter +celery +congregate +clocking +assassinated +adding +canvasser +civics +contemptuously +calculates +advisees +bumbling +algorithmically +cloudy +algebras +addiction's +cop's +assurers +confidently +affector +analyzers +chimneys +burdening +antitrust +admix +avoidance +choking +coexists +accustoms +cellar +anchovy +constructor's +confinements +consequently +accelerations +accoutrement +churchman +biller +affected +brigades +cremating +corridor's +bagging +ah +berating +collective +acuteness +arrestors +cab's +border +agitation +animism +arches +alveolus +cessation's +averrer +abash +counterrevolution +attesting +animateness +bawdy +americana +bloodstained +applicator +annotating +annunciator +clamored +acting +aerosols +axiomatization's +brags +coalesces +avocation +combining +crazily +bravery +burying +adored +airfield's +accounting +broadeners +anise +chimney +added +avenges +bellicosity +cranberries +arsenic +communities +comparable +bunkered +architect +alphabetically +beautified +apogees +communist +anatomical +complexity +accost +autographing +browsing +ameliorate +bookers +bandaging +clinical +appellants +counteract +clairvoyantly +bootstrap's +canner +boastful +attainer +ash +beaded +brake +barest +befriend +burglarproofing +allegorically +bunts +believes +accession's +buck +boathouse's +byword's +anthracite +accuse +conjunction +burping +commandant's +creativity +affirming +bark +amuses +balcony's +auditors +counsel +clamber +borates +cowboy's +bickered +boors +combing +biting +breeze +crowder +corn +bloke's +bombast +bookstore +blared +bedlam +carbohydrate +coops +bundles +blistering +antarctic +anterior +bilinear +chocolate's +context's +alternating +annoyance +constancy +ambivalently +buddy +brutalize +bobbin +alleles +commotion +attributes +airborne +creed's +bolstering +coaxed +airframe +breaker +accept +abashes +attentional +contributor +comparability +auscultating +cocked +computationally +buffered +career's +analyzable +absently +courtyard's +buildups +apportioned +balkanized +annulling +cremation +buffetings +conditional +confided +airliner +bulldozer +approaching +anagram +apollonian +canaries +bloat +bluebird +collision +cool +connectedness +abasement +artisan's +avoidably +clerks +afflict +briton +corroborates +cameras +counted +boldest +burglars +brutes +brows +abhorrent +configuring +averaged +ace's +buying +abandon +bayou +cottons +auditioning +amplifies +clippers +brainstorm's +alto +brutalities +bunch +agricultural +bursts +blunting +archer +activity +carefulness +bedroom's +concomitant +balm's +artificer +barking +breathy +babies +acacia +bodies +cap's +criticised +conversed +crewed +ascendant +budgeting +coroutine's +charmed +bellboy's +conservatism +butler +acculturation +conclusion's +adapt +cellist +contempt +adumbrates +borrowed +confounds +allegiance's +blabbermouths +accrues +captor +coop +baseballs +cottages +apartment's +assertiveness +assent +artfully +bagger's +abolishment +acetylene +accessory's +blackbird +baptist's +consist +cavern +buttock +corporal's +autoregressive +bailiff's +birds +corder +bracketing +antlered +barbiturates +county's +addicted +agglutinated +abashed +competitively +captains +bloating +accepts +choose +ashamed +backyard's +apiary +contradiction +balalaika's +arctic +broom +anvils +coffee's +alliance's +agitator's +change +adjusters +cremates +complexes +bodyguard's +burl +antithyroid +ambient +airfoil +apricots +athleticism +abjectly +bankrupts +answerers +alternatively +confronter +breaking +baronial +cannibalized +appetites +breaded +blackboard's +battlegrounds +cosine +barrenness +abbreviation +budging +boolean +acrobatics +again +ashtrays +clashed +contingent's +compulsion +bedazzled +collapsing +comparison's +businesses +compassionately +achievement +buffering +candlesticks +austerely +awls +associate +absolved +annexed +airway +clipping +counselors +conscience +attempters +constructing +biases +cautioners +comma's +cosines +char +auscultates +afire +comely +amity +beverage's +anew +ballplayer's +adulterated +authorship +alterers +burdened +attributive +afflictions +blinded +barrier's +attachment +brotherhood +bridegroom +atoms +cobweb's +copes +controversies +complexion +crawling +atomized +adjust +accuracies +concern +cinders +authorization +appraisingly +bladder's +cooked +cowers +batter +commissioner +close +burglar's +allocated +anvil +aftershock +abrogating +chemistries +advisable +conduct +committee +blaring +appalling +braveness +alertly +artificialities +brevet +collision's +arizona +bower +creamers +awnings +arsenals +crane +city +contemplative +catheters +administrators +attorney +churned +attractions +columnation +bobbed +centipedes +bostonian's +apprises +buries +allege +botulism +adobe +ambassador's +covenants +boon +asynchronously +bigness +axial +chaffing +battleships +ant's +anthropological +accent +brushing +brassy +consumptions +battleship +absorb +beckons +brook +connectors +clinches +accesses +beaters +archaicness +bursitis +chided +bomb +assimilated +addicts +convening +arianists +counting +altar's +confusions +attachment's +clipping's +amazing +corset +bossed +attach +commandingly +animatedly +allegations +assuages +annulment +compress +aptitude +absurdities +autobiographic +aspect's +concentrator +burgesses +anagrams +bedeviled +assemblers +convinced +commentary's +agglomerated +biological +callousness +axolotl's +atmospheres +authoritarian +cancer's +above +charting +aldermen +battler +cistern's +bouncer +amassed +conquest +altering +arrogantly +brokenly +comparator +counsellor's +attenders +cackle +criticize +authored +ably +believed +compelling +accepter +cleansed +afflicted +backslash +computed +almighty +attache +braes +carriage's +benediction +brigadier's +contemporariness +boomtown +amplitudes +breakwaters +clod +catch +bar's +activist +caves +assenting +camp +attainments +brotherliness +continuances +appearance +applicator's +browbeats +banjos +addendum +became +adduces +armadillo +brothel +almanac +courageous +assault +chunk +coaching +atheist's +blunted +aperiodicity +congresses +boastfully +burglarproofed +broadest +bashfulness +affect +acne +bottleneck's +criticisms +corrupts +colonized +closeted +canonicalizing +auditorium +antenna's +awfully +anti +consumes +agonize +algebra's +championing +blush +bugger +antagonize +beethoven +blase +boycotts +compensatory +bugged +boroughs +anatomic +batons +arguably +affricates +appreciations +cavalry +alumna's +arcing +backpacks +braces +contextual +coupon +chillingly +allocates +abuts +contribution +commodity +admonishing +coolly +cabinet's +collapsed +confessions +adjured +capriciousness +chastising +babe +aerodynamics +accepting +concept +contour's +consequentialities +birthday +bankrupted +birthed +benefit +concentrations +azalea +channels +chestnuts +contenting +antedate +censors +contagious +abbot's +channellers +apt +commend +avocation's +admonition's +abolition +confederation +carried +clumsy +coincidences +bumper +burr's +bugles +bribers +attainably +consume +comma +creativeness +accuser +bombs +abbey +baffled +aside +clip's +appeases +compass +bundling +abstractionism +confide +creases +apropos +confronted +corrective +concurrencies +autocratic +alien +attending +antagonistic +broadcast +asymptote's +belied +breasts +contrapositives +coiner +accordingly +cohering +computers +cow +bibs +ancestral +controller +attacker +alerts +coconut +agency +alerted +alcoholism +ammoniac +actinometers +acquitter +bud +cessation +alleging +centralizes +articulators +council's +carvings +arduously +blown +anode's +arrogate +bisects +centimeters +burgeoning +course +appointee's +ascribable +communicate +contrivance's +adoptions +attune +acres +abyss's +corporal +certifiers +analyze +augusta +bestseller's +checkpoint +coexist +attainers +argon +bearded +crudeness +averaging +brick +adducing +annulment's +chicks +blocked +cisterns +afoul +affiliates +briskly +adhesion +ascertainable +appeasement +blueprints +agreements +blindfolds +communicator +characterization +annoyances +breeches +brushed +clinic +competes +chuckled +cradled +balmy +antisubmarine +alternate +armpits +barn's +conjuncts +adhere +allows +counteracted +appetizer +capturers +cleanse +avant +abbe +corpse's +arduousness +badge +begets +contemplated +caveat +copiously +athena +aggrieving +alibi +accumulation +basket's +aftershocks +bass +conjuncted +chaps +brunch +colonials +bibbed +clusters +antagonizing +constituencies +combings +bearish +continuously +adequacy +brow's +catalog +alderman +comedic +chemists +concernedly +conceded +alarm +arced +buckle +confidingly +coherent +closes +buffoon +brace +adjustably +crackers +contamination +burgess's +aerobic +constitutes +baptismal +broadness +blimps +concatenation +claiming +bard's +aerosolize +adjoins +copies +coats +boggle +corroborated +concreteness +bill +cautions +bantam +bearably +armchair's +birthright's +cravat's +cone's +courtiers +asunder +bulletin's +biopsies +alley +contrive +blasphemies +amuser +ballerinas +blushed +causticly +brandy +blinkers +complimenting +crimsoning +angola +apprehensiveness +bolster +columnate +byproducts +berths +accusal +chubby +arrived +camps +blemish's +anaconda +cook +airfoils +atlantic +boosted +converge +availer +appalachians +coffin's +boarding +alga +crouch +columnizing +consul's +chastises +angling +apple's +billiard +attentiveness +adroit +apprehensible +cereal +blouse's +browning +bodybuilder +coaxing +assertion's +connective's +commemorated +accountability +crooked +blips +chandeliers +aristocracy +bangs +coke +abutment +community +calculus +congregated +crepe +compromised +airlines +contributing +contingencies +coordinated +alginate +batted +contender +alma +antagonisms +accompanied +airport +administrator's +appraisal +breadbox +condemnation +backlog's +available +consequents +crooks +commonwealths +barring +channeller +crucially +archaeological +charming +adventist +credits +appetizing +breads +clients +climbing +aloneness +abstractness +appearer +astute +clockers +antagonizes +agonized +bastard's +conjectured +aqueducts +aureole +boatswains +conjured +chauffeur +complementer +behold +bustards +bivouac +cluck +anus +bless +catastrophic +bounty's +allowed +answer +concealers +brainchild's +coercion +buzzword's +bordellos +appertain +applier +couriers +aesthetic's +craft +capacitances +capped +coupler +category's +anvil's +conquest's +checksums +clucking +bronchus +acrimonious +changeably +accenting +argued +conditioning +brewing +backwardness +cascaded +atomize +contours +arianist +apart +conflict +carefully +banshee's +conveys +arbitrates +amphitheater's +amen +alimony +bound +buzz +courtroom +apparently +coalescing +circulating +amounter +bypasses +breadth +choral +completion +arisen +anticipating +bilges +contractions +bedspring +commune +blacklisted +beagle +alkaline +atolls +carelessly +blimp +corking +brevity +alterable +canada +bear +bluntly +cartridges +connoted +countries +corroborate +consecration +corrupted +appreciating +combatant's +alkalis +affecting +blues +casserole +ballad +bewitches +common +as +because +bathroom's +anchorages +beguile +connect +convenience's +counteracting +assorted +care +contains +centimeter +ancestors +briefings +busses +churchyards +breakable +amortizing +courthouse's +click +courses +ajar +county +covet +confidences +capitalizer +agog +backtracking +copious +bestsellers +chilliness +bringer +browse +centipede +bawled +bricklayer +breath +assailants +abysses +command's +characterizer +calculating +america's +aurally +contain +alias +commentators +confounded +appending +accidents +chatters +coordinates +bleeder +blueness +badger +bolsters +astounding +capitalist's +conservation's +commences +aimed +bun +comparators +competition +bauble +backbend's +bled +assassinate +chop +anemometer's +cobbler +coldness +audiometry +affinity's +amalgamates +cowardly +consolidating +beads +brackish +bookings +accuses +bog +compartmentalizing +clutching +calming +collars +clambers +banqueting +beaked +authoring +correspondence +apostrophes +affirmation's +bespeak +costing +brought +complainer +battalions +asymmetry +boathouse +canyon's +awarded +amplitude +anarchical +anticipatory +bolder +cooperatives +caterer +adviser +balkanizing +augur +cannibal's +balustrades +attaching +collector's +commercials +capaciously +coincidence's +bumps +ascot +bale +blackmail +baby +aftereffect +bloomers +buttresses +avenues +climaxes +aqueduct +cater +brainchild +avail +bypassed +bowl +california +cements +boxes +brained +bedevils +captors +acuity +ascends +breakthrough's +assigner +caner +bequests +ceilings +axers +bookshelf +autistic +celebrations +axons +chiding +asterisk +allophonic +blindingly +cherubim +boaster +confining +anxious +clowning +advisement +approach +anesthetic's +crescent +alertedly +birdbath +beardless +bras +auspices +choosers +approval's +afflicts +corrosion +arpeggio's +bodyweight +cranky +battlefront +affirmation +churchyard's +aeroacoustic +anders +adjustment +baneful +citation's +acetone +blend +binuclear +boner +annotation +announce +claimable +contemporary +clothing +acquitting +choosing +attacher +bananas +binaural +arrestor's +aches +conclude +collaborators +await +blaspheme +bequeaths +crows +balconies +begging +conducting +abstracts +assignee's +causations +approximation +articulated +considerably +apricot's +afferent +assertively +bonding +calms +cranberry's +cost +captaining +agenda +corridors +complaint +christens +aggravate +countess +arbitrators +ascribing +breech's +bellwether's +burglarized +confinement's +animating +adjectives +cannister's +bemoan +cleanest +acme +cheapest +activities +allophone +boy +belaboring +captions +compactor's +actuator's +befouling +arachnid's +computerizes +compile +absorption +bridled +absorber +convicts +birch +alkaloid's +cannot +bacilli +charitableness +abated +ceaseless +beavers +bookshelves +commensurate +appreciates +basil +cartoons +aides +buxom +cages +cantor's +acceptances +antiquated +amalgamate +babyhood +beers +conforms +bouquets +canner's +baste +cashed +argue +butcher +backbones +absolve +crib's +cafes +abstracted +book +committees +authentically +conference +antisera +bourgeoisie +attribute +biddy +autobiographies +chivalrousness +coverlet +ambiguously +calorie +anhydrous +alignments +around +archfool +advance +bedpost's +affective +contained +amain +bromides +clogs +bricker +arduous +consistent +amidst +confess +complain +anniversaries +coasting +cobwebs +aries +benchmark +aviaries +bombard +boxers +ashtray's +assyriology +blaze +ablative +chaos +burro +arguer +ashamedly +crier +allocator's +aggressively +carts +advisory +airship +alkali's +backup +chaining +continue +cartoon +circumference +breadwinners +autonomy +banking +armored +cabin +chunks +antigens +blistered +airers +breakaway +belief's +belays +coveting +auburn +careful +anybody +bumbled +cautious +adopter +ballplayers +anteater +citadel's +avails +agent's +caliphs +bridgehead +already +caterpillar's +coachman +centralizing +alphabet +concede +barbell +breadboard +ballast's +activators +attendance +blandly +calculator +codeword +addressee's +avenue's +alcoves +alternately +admonishes +concentrate +crossbars +adjoining +basset +carbons +beast +blonde +castle +clarification +bitch's +abrasion's +books +amputate +bicycler +aphonic +arraigns +acquiesce +buster +chaperon +advisements +buyer's +attack +birthdays +blazed +confuser +crag +ballet +airports +bison +counterexamples +arteriole +colony's +adamantly +blunders +chivalrously +adult's +authors +amplifiers +counterfeited +complicity +astrophysical +axolotl +bash +battleground +butterfly's +axioms +allegory +blitzes +blindfold +bufferrers +approximating +byways +computations +alight +avoiding +assurance's +barrages +canonicalized +callously +auditing +authenticating +bag's +asters +artistic +bonanzas +applaud +certainties +auto's +concession's +cascade +chubbiness +churchyard +afternoons +antigen's +baron's +amphibian +banister +capitalize +approval +appropriated +bureaucrat's +covets +cloisters +circulate +bivalve's +beta +collector +among +cane +birdlike +attenuating +conjunctions +appliance's +coral +crucify +abnormal +combined +classroom +buckskin +commissions +abolishments +arching +croak +americium +associates +car's +assuringly +agreer +anticoagulation +closure's +corkers +attend +alphabet's +awakening +composedly +attracted +construed +cricket's +applicability +autonavigator's +chloroplast's +ashen +beggars +corporation +another +conflicts +bootlegs +archeologist +alcove's +agitates +cargoes +creditor +cops +advisably +coronation +bourgeois +crochets +cropper's +cramp's +adulterer's +corroborations +changing +combinatorics +calm +comprehensible +blooms +coolness +copying +blacksmiths +commodore +compulsions +clump +afterward +crucified +brooder +buckets +accelerating +accented +boat +adventitious +baseline's +courier +calamity's +atoll's +brutalizes +bundled +chairperson +cheeses +continuation +celebrating +apologists +behest +bumpers +consonants +circulation +betraying +commuting +breezily +circumstance +coughing +benefiting +conquerors +chemically +commencement +adjustors +angel +congratulate +conspired +causally +bud's +conquers +augmented +bereaving +advisor +articulation +angler +admission +bide +competitors +amusement's +collecting +adder +arithmetized +cheek's +apostrophe +blockages +clockwork +bubbly +apricot +adjudicated +banter +amused +breacher +bracketed +aimer +comprehending +bunkers +canton +arcane +absent +capitol +consequence +cognitive +abjuring +clever +coronet +anathema +artichoke +controls +credulous +acid +crawled +coupled +boomtowns +aspen +acted +anyhow +burdensome +backdrop's +apocalyptic +cornerstone's +cautiously +blisters +conveniences +arbor's +accessories +alleges +clubs +accompaniment +blazes +annually +clique's +beamers +ballgown +autumnal +acreage +conjunct +balances +consoling +canvas's +competent +aggrieves +although +afraid +clearly +cognizance +acoustic +colleague +causing +absences +closers +airs +cinder +adversaries +altruistic +brews +ceremonially +appraisal's +commissioners +army's +assists +acceptor +comparison +cooling +conveniently +couching +changes +clinic's +confronting +adjunct's +blandness +alternates +bunter +consequent +clean +autos +accumulators +carver +aprons +awful +bobbins +blasphemy +assuming +abscess +assemble +cabinet +atomics +blacklists +audacious +assay +anthropology +barnstorm +awl +bumping +assembles +capture +compensates +coverable +amend +array +continually +absented +cigarette +antiresonance +backspace +branched +appellate +courtroom's +alienated +austerity +cement +asked +antelopes +cottager +bluebonnets +booze +amendment's +backslashes +begun +bijections +cafe's +boatload +collect +appeals +belittles +befit's +beauty +arrogated +academia +contagion +blemishes +coverlet's +comfortability +antecedent +controllably +congressman +complicate +coincide +arrears +clumped +credited +buffoon's +catholic +accompanist +beauty's +aster's +blatantly +bothering +bewilder +canceling +carbonizer +accentuation +backstairs +anticipations +bestowed +civilian +blooming +blunts +airlocks +argo +blueprint +aristocrat +cakes +complements +ale +camping +army +adrift +bengali +barely +blasphemes +briefcase +brooches +ailments +blazers +crevice's +bankrupt +archiver +articulator +alphabets +bonds +colliding +candidate +cashier's +bellwethers +airstrip +announcers +calendars +corrupter +aqueduct's +axiom +bathing +blusters +ascribed +admittedly +angrily +analytical +contraption +convertibility +abysmal +cathedral's +aversion's +algol +articulately +breveted +bickers +chatterer +adoptive +bijectively +cloudiest +coarseness +carted +cocktail's +capacious +anion +buffoons +bleeding +bedrock +adventurer +compositions +camouflages +brittle +chip's +aloe +chorus +cargo +critical +biographer's +abject +blasphemousness +charmer +betray +blacking +awoke +allele +bags +claimant +clover +biographies +confound +advertises +crafter +cripples +bygone +concentric +couldn't +contentions +acrid +costume +aft +aesthetic +bandits +adducts +constellations +coffer's +created +commercial +art's +cookie's +ammonia +adjunct +articulateness +congratulated +crags +brandishes +annual +byword +affection's +college's +aboriginal +bikini +buttering +allotter +console +advent +activates +beverage +april +acceptable +barrel's +boys +attractor +azimuth +critics +ballooner +aren't +adulterating +criticise +abeyance +automatically +collaborative +capabilities +crawls +anomaly's +climaxed +animately +aroma +belie +attires +argumentation +baseboard +bluebirds +cactus +byproduct +balancer +beholder +conservationist's +betrayer +agony +accusingly +convict +coaxes +breeds +agitated +championship +brevets +auscultate +counselling +cornerstones +america +canoes +aspirator +compensate +antiseptic +bereave +absinthe +compose +collide +alabamian +candid +civilized +clamps +authoritarianism +colonist +bugging +bins +abashing +battlers +canning +berate +assembler +amateurish +boasted +angriest +bluffs +colonize +balcony +bleat +bustard's +attenuate +contagiously +bicep +babel +beatniks +brush +analogy's +audiologist +assessment's +camera +arbitrary +alleyway's +concession +constructions +accompanies +accretion's +aroused +charcoaled +belated +bottom +bloodshot +bisques +advocate +arabs +cathodes +adamant +challenge +absurdly +abolitionist +cleavers +bludgeons +bassinet +clause +coiling +cask +boob +azalea's +afghanistan +carriages +blade's +bobby +asinine +acclaiming +absorbed +blacken +cheating +bootleg +anonymous +addict +astonishes +awry +adequate +categorization +casks +blaster +aspirants +abscesses +airing +assumptions +capitalists +board +asynchronism +body +aye +contraction +athens +arsine +cohabitations +below +bows +aviator's +ampoule +connective +adapter +authenticate +blackboard +brilliant +appoints +attics +conquer +boning +comestible +camped +blonds +aisle +coals +billboards +characterizers +crow +clout +admirer +actuarially +abstruse +accessing +bonfires +clenched +characteristic +catching +chars +canons +barrier +championed +butterflies +completely +calendar +artwork +abjections +burgher's +correlates +arrivals +accepters +circuses +breadboards +accomplishment +analyzed +appropriates +cancel +bordering +aperture +civilizing +assortments +blackest +blitz's +copy +commenced +admirers +cheers +croppers +cliff's +circumstance's +bibles +buttressed +consecutively +birefringence +automaton +cheerless +chopping +ballooned +convent +acknowledgers +appointing +belies +comeliness +bangle's +communication +bisector +avocations +clique +brainstem +campusses +allocators +bramble's +assaults +commemorate +appendix +agent +apportioning +bottled +artifact's +block's +archery +bagatelles +candies +catched +cognitively +creepers +concentrated +bout +balustrade +abodes +carrying +confirming +cannibal +chinners +carbonate +anguish +butt +colons +ablated +corporation's +cock +convincers +beret's +bluish +compressive +authenticates +commemorative +bureaucracies +coinage +coach +assigning +concentrators +capitalizing +appraisals +belaying +candy +blossomed +bricks +atonal +analogue +caters +barbaric +applique +clink +audio +actress +assyrian +apprehension +conversation +apsis +bedevil +comics +affricate +comings +buttress +angering +buckboards +bombed +adversely +adequacies +commended +causeways +adherers +codes +aquaria +ape +bulks +compactly +brainwashes +bleats +commandants +conditionally +adjourns +clobbering +allowances +buildings +complemented +blanker +algeria +brief +creak +adductor +categorizer +approacher +argument's +clocked +bedazzle +cause +coordinator +buildup +countenance +abhorrer +backtracked +bogus +closer +broilers +chirps +adjournment +belles +bitingly +befogged +contexts +amorous +breeding +abortions +blockage's +alternatives +bouncing +beryl +ballistics +banters +carpenters +auction +bowdlerizing +brazen +bonuses +circulated +adultery +archival +bears +baptized +burglaries +borrowing +barbarous +casher +adolescents +atrophic +busily +aerating +coatings +athenians +casing +consuming +alphanumeric +beaches +bisection's +conjecturing +aspirate +biography's +accompany +bureaucrat +broomstick's +colony +coalesce +clock +bequeath +collaborates +belonging +configured +burlesques +anode +consenter +bug +counterpoint +counts +bangladesh +analogical +accident +bulky +affinities +abysmally +boorish +assiduously +cannisters +autocollimator +bassinet's +barrelling +blurts +carbonize +candle +act +addressees +constraints +boast +complaining +coziness +avocado +coolest +blank +beadles +anytime +covetous +appellant's +angers +academies +ageless +chased +constitution +consonant's +boosting +ascetics +aerosol +apse +blushes +clang +confers +confidentiality +coolie +colon's +chickadees +badminton +argonaut +constituting +aloha +contracts +broomstick +brackets +attendant's +connection's +conciseness +abstractor's +composes +chaste +assures +conjuring +barbital +bunion +bases +clowns +barrelled +audience +auctioneer +complexly +aviator +conjectures +backscatters +cheerfulness +communicating +agreement +bricklayers +bilabial +abstruseness +cobol +cooperating +admit +blundering +accelerates +assaulted +concealing +anachronism +bowels +butane +anniversary's +converts +convoyed +climates +barriers +clubbing +additives +bask +confessing +caravan +colonizes +continuous +cheerlessness +boggled +armpit's +bridgework +allegro +cricket +cannon +adoption +clanging +auscultations +billowed +alphabetize +airlift +appointee +boyfriend +chaotic +corrections +bonus +contrasted +convulsion's +confessors +adumbrating +autocrat's +coronary +authentic +barley +brawling +aegis +appends +bolshevism +charted +applicant +aileron +considers +chin's +alkyl +amendment +boulevard's +avian +breather +canyons +cannon's +apportion +badgered +augers +advisers +censuses +beveling +aught +arthogram +anonymity +appliance +atmospheric +anesthetizing +ambulances +blustering +burnt +chestnut's +collects +aliment +anxieties +championship's +channeled +arrival +amassing +corpse +bedtime +blackbirds +cats +constants +chemistry +brewery +brother's +boasts +accentual +bellwether +bely +courted +baroness +configure +collection +aviary +achieves +belfry's +beech +baseman +bacterial +contestable +blond +contracting +comparably +consultation's +booster +conspiracies +belief +candidate's +boardinghouses +connectivity +check +crazy +collided +assistant's +critic +bilateral +cheapening +appalled +autopsy +balled +abnormally +acquires +aloofness +backwaters +combative +computerizing +craters +contributorily +behaved +comers +axiomatizations +analogously +banjo's +cleanser +capitalizes +chamberlain +aggregates +amenorrhea +begins +condone +cleaved +bustard +adsorb +airedale +bridles +audited +could +amour +checkbooks +admiring +arrested +commerce +asbestos +can's +clamping +bathers +acknowledgments +census +acrobat +bargains +apogee +creaking +busboy's +additional +chants +circumvents +afloat +anyplace +alumnae +anions +classroom's +ballerina's +convents +angered +climbers +citation +cools +clamor +capaciousness +beatific +abrades +advocating +coverings +claims +brethren +advertised +atrophies +coffer +beagle's +brazenly +bitterly +clergyman +braiding +compressible +convicting +agreeableness +antithesis +cogently +botanist's +bidirectional +bewilders +airlock +costumer +blamelessness +agglutinins +catalyst's +allocation +annunciates +borderings +accomplishes +confronters +clinically +breadbox's +canvassed +communicative +coercing +backpointer's +bramble +congregations +crave +courtesy's +cocoon's +admitting +chieftains +acclimate +consequences +cones +contradict +axolotls +contractual +artist +atrociously +consecutive +berated +bluing +attacks +choruses +blatant +balance +amplifier +assist +analyst's +ambler +conveyance +compromising +baffler +corridor +bed's +condoned +boulevard +anomie +averages +basics +apologia +cabbages +concretes +alcoholic +aliased +chocks +balsam +collies +censor +arouses +conundrum's +academically +bent +codings +coastal +allots +acclaim +citations +cantor +circularly +boarder +caribou +biologist's +cowling +connects +chasing +bootstrap +backscatter +abstractly +corrupt +alleviating +biasing +abrade +arraignment +beaten +blanketing +compactness +adage +coincided +borate +bra's +concepts +bootleger +christian +argos +basal +abate +campuses +abridging +confusers +cabin's +audition's +amphibians +attractively +adhesive's +ascendency +beforehand +ache +brokers +bowler +criminally +american's +chock's +artillerist +appropriation +characterization's +artifices +annoys +constituents +bottle +beaned +consisting +beholding +ceremony +carpeted +absolutely +anorexia +accredited +azaleas +amaze +commit +afflicting +contriving +adventure +blood +blabbing +absoluteness +appreciable +approachers +bumptious +behavioristic +anticipates +adults +barnyard's +banging +banana +bilge's +aware +coheres +bronchi +commissioned +arrogation +confines +core +attenuation +afterwards +clearing +applies +alphabetized +cemetery's +campaigning +abolishes +brig +cheer +combers +backtracker +clinker +clouds +clog +berries +advising +childish +clobbered +bride's +astrophysics +canker +concatenate +bite +chagrin +bodybuilders +calamity +admiralty +councillors +competitive +assessments +copper's +cabling +casket +conducted +backplane +boyfriends +bingo +broader +confiscates +communicated +baton +cocktails +albanians +boardinghouse's +brats +akimbo +categorizers +comparator's +blackbird's +accidentally +companion's +clippings +accosted +bell's +burly +aggregations +boathouses +airmails +abreactions +changers +carbon +cleaners +bookkeeping +correlations +backer +conclusions +brainstem's +anecdotes +chateau +cogitating +amphibious +compounded +completeness +comptroller's +boatswain's +bolstered +acquiescing +actors +calorie's +adaptability +abstractor +bimolecular +belly's +automobile +automotive +analyticities +awesome +colonizer +approximated +chemist +coronet's +classmate +anteater's +altars +adulthood +amid +assails +blizzards +corroborative +biographer +compartment +blooded +bipartisan +bluff +aloof +bronchiole +clincher +congratulations +ablation +caught +collier +chooses +antidotes +artery +clearance +civility +basketball +auscultated +behaviorally +crowning +autobiographical +cheaply +brutally +agonizing +clerk +comprising +baller +confuses +acquiesced +astonishingly +birthplace +covered +chopper +combinator +benignly +bedside +blasts +billboard +appraise +aboveground +comforter +credulousness +battlefield +barefoot +cleverness +apparatus +bartering +bromine +aerodynamic +crabs +chains +airflow +allegrettos +armchairs +blacklist +approvals +bait +collections +antecedent's +airbags +casted +content +conferrer's +crouching +coughs +canal +amphetamine +augustly +bedraggle +arithmetic +cataloger +alluding +credulity +coffees +crueler +beautifully +caresses +correlative +consul +criticizing +couched +baths +alchemy +bargain +accomplishments +conveyer +benevolence +broil +chilling +axed +attire +collisions +categorizes +cited +aeration +accommodating +coordinations +boxcar +cattle +bullion +afternoon's +captures +afghans +comets +component's +ark +bounds +adjusting +bravely +capability +chap +absolving +aspirating +arcs +conspires +collaborated +admonishment +astounds +brasses +compromise +changed +consumers +connoting +buttonholes +cordial +anionic +chastisers +archive +alleviate +burglarize +acquainted +copiers +cashers +antisocial +creations +bookie's +censure +beadle's +banded +circled +bulged +cheapness +attorney's +chewer +bookshelf's +councillor +assertion +broom's +contemplations +club's +balkans +cherubs +alas +chair +apologizes +compartments +beyond +aptly +censured +allegros +boosts +card +arithmetizes +attainment's +arrester +anding +asker +compatibilities +confidentially +commissioning +cleaner +aversion +cooperative +battalion's +cemented +charity's +conceited +capable +anymore +computing +aping +chiefly +affair +beaners +allying +caption's +antipathy +causal +abyss +botchers +burglarizing +confidant's +activator +continent's +census's +brat's +antagonism +bedspring's +antiserum +charge +connector's +alike +believable +belfry +cast's +bureaus +beneficiary +abolisher +artichoke's +broadly +concurrent +alteration +bookies +crafts +bays +ass +bouquet's +ave +chords +crazes +anemic +appoint +beets +billing +contest +assassination +allot +brindled +acute +absolves +adsorbed +auxiliaries +belatedly +businesslike +assassinates +bookkeepers +bevel +adders +automate +archangels +breakfasted +changeability +contested +cradles +combatants +besieging +certainty +attempts +bankrupting +compiler's +complications +banquets +ancestor's +ail +abbreviating +compacter +approvers +acknowledges +comically +almonds +counsellors +calmness +assailed +crane's +baser +big +corruption +circuitry +briefness +community's +banquetings +alms +bass's +bellowing +adoption's +blockading +compellingly +builders +befallen +bombproof +cartons +chore +crimson +anther +clucks +assemblies +beatitudes +aspiration +compels +angst +balancing +bowstrings +bayonet's +butte +biomedical +casualness +accolade +blackberry's +bunched +affright +clung +burlesque +bare +corrected +arbitrate +cropping +coherently +bloodhound +circularity +courtesies +articulating +concluded +analogy +brutalized +airmail +cooperator +cousins +centralization +bibbing +beside +bravo +abductors +cars +bovines +bump +absconding +chins +chasers +boundary's +antecedents +awed +counselled +aback +attenuator's +blazer +bettered +awaken +abreast +beagles +artisans +buckled +credence +control's +bewhiskered +calloused +breathe +collaring +blossoms +bring +actualities +bivalves +animals +cowboys +constituency +affordable +acrobatic +attiring +boatswain +concurrence +abrasions +babel's +cowerers +chiffon +bostonian +criterion +blinds +cased +affections +conditioners +clutter +accrued +attractors +botcher +compunction +bludgeoned +censored +allah's +chronic +burrs +commodity's +appraiser +asserters +cheaters +besting +anchorite +combine +afforded +cigarette's +bathrooms +apostles +chloroplast +bootlegging +bibliographical +beans +bylaw +benefited +brochure's +cordially +brashly +beastly +bologna +alderman's +burning +billow +convert +buffaloes +comparatives +assistances +camouflaged +announcement +bobwhite +brawl +adducted +cavern's +affectation's +bandying +brunette +architect's +aphorisms +cremate +bray +billed +conception +battlefield's +bandaged +broaches +bazaar's +beatification +bigotry +clergy +abstains +befits +bantering +conceivable +attachers +analogies +bimonthly +august +additionally +confirmation's +ballooning +cardboard +belle's +counterparts +candor +bishop +comprehension +affronted +bravura +courting +antidote +buggies +arisings +appendix's +bright +categorize +cooking +agnostic's +billets +amok +bewitching +audiograms +column's +bussed +checkbook +alteration's +atherosclerosis +broached +based +cacti +boardinghouse +bowdlerized +anchoritism +achievement's +bald +cover +codifications +capacitor +brashness +causes +acyclically +argument +boarders +audiometer +compute +contribute +crisply +bitters +circumvent +assailant +bosun +buyers +alibis +blurting +coasts +bivouacs +arrogating +albanian +attempted +acquisitiveness +applauding +alfalfa +cantors +canonicalizes +alkaloid +bruising +associativity +budgetary +carbolic +clashing +buffalo +acorn +analyzing +backyards +comedian +betwixt +aces +chartered +additivity +becalm +combat +characterizations +clinics +bulbs +bloc +amenable +civilian's +breech +attainment +bounding +compiler +cotyledons +billboard's +caper +aphasia +chester +combats +biddable +articulates +caps +assignees +bifocals +beady +chinese +assertions +allegation +championships +accrue +containment's +croaking +classifying +annum +brightened +bits +appointer +besieger +citizen's +cerebral +canto +bakers +capitol's +authorizer +blockaded +anodizes +alarmed +buttressing +attenuates +bumptiously +chronological +colleges +coward +contraption's +abstractions +controversial +boric +bids +agents +backpointer +bumped +bottoms +bowlines +captivated +article +cliche's +chases +choker +bremsstrahlung +consult +adjudged +auctioneer's +covers +accurateness +clues +bugler +bareness +cedar +alleviation +anesthetically +backpointers +arched +administered +arrowhead +continues +asks +confessor's +allure +backlogs +childishness +appointive +covering +conscience's +bellows +blanked +considerations +appalachian +aerate +budged +city's +accordion +cliche +collectors +comprehensive +boomed +chariot +baffling +bunkmate's +bumbles +contaminating +corroborating +applications +bursting +cabbage +befalling +acquittal +compromisers +components +arpeggio +brothel's +credibility +begrudge +confirmation +academy +appertains +calibrates +bureaucrats +bawl +costuming +biography +adoration +cloaks +aggregating +business +aphorism's +carters +admixture +coexistence +anomalously +adapts +amide +affiliation +capillary +biscuit +brainy +bellhops +chartings +cohered +austria +champions +basin's +cascading +consultants +bison's +admixed +arithmetically +clothed +betterments +conspirator's +addition +adolescence +bolsheviks +abominable +breathless +cozy +arouse +bumble +about +apace +astronaut +asteroid +cable +crab's +beachhead +assets +analyses +bisection +coconuts +alleys +armament's +bloodstains +arpeggios +apologist +blithely +anabaptist's +beadle +channelled +confuse +annoy +beautifiers +cheats +clenches +amuse +bewail +constitutional +birth +appendixes +amazed +berry's +bilingual +blustery +amplification +clogged +blackmailing +breakables +adduct +bondsmen +conferred +codewords +bequeathal +abundantly +banner's +atrocity +congested +closely +absolution +concatenations +anarchic +crag's +communicators +cavities +comptrollers +backstage +bewailing +charcoal +conveyances +collar +bores +briefest +comments +awning's +associator's +antarctica +correspondingly +bidden +ad +clings +bit's +apollo +bulldogs +chateau's +amounting +cogitates +bellhop +bookish +bout's +cannister +bicep's +asses +beef +battlefields +consort +auspicious +breezy +buried +beverages +approximates +conduction +bleakly +blanketers +ascertained +absentminded +bolivia +births +behave +bilk +breaths +charter +abstaining +appareled +boulder's +breadwinner's +correct +accessed +befitted +adulterer +axe +activation +betrothed +asymptote +bullet's +clusterings +baud +bustling +ballplayer +constraining +cleared +brown +affirmed +agencies +churches +backyard +burntness +bronchioles +charmers +backscattered +abridgment +claw +blow +adjourning +constantly +brightens +autobiography +cards +bypassing +alcibiades +concurrency +chuckles +bests +belligerents +adjustments +bolshevik +cabins +astronomically +cartridge +boxcars +boned +bottomed +burgeoned +adjourned +apprenticeship +chastiser +breached +boycott +butchered +coordinating +cottage +brainwashing +confinement +bandies +absentee +collapses +cruel +along +alloy +convoying +assignment's +crisp +ambidextrously +blindfolded +chilly +condenses +avers +broiler +anesthetics +beaker +cholera +brag +coffins +cranked +allocator +brutality +acquire +blushing +briar +abolish +crossovers +broiling +consolers +beatify +almanac's +cooled +commencements +clasp +committing +condemnations +altar +by +bombastic +confederates +bong +concerted +compilers +counterproductive +brig's +accurate +avidity +cleavage +blame +conceive +assessor +consolingly +concise +computes +alliance +clucked +axon's +annunciating +baseball's +allusion +brays +auras +blond's +bronchitis +ciphers +blowing +broth +canonically +baseness +byline's +appetite's +colonists +condensed +cawing +beaning +broadening +colonist's +apocrypha +chauffeured +cored +branding +carrier +assessed +collegiate +chirped +accounted +clubbed +antibodies +behalf +alphabetizing +conqueror +alpine +budgeters +casements +appropriate +compliments +cast +accountancy +cathedral +conserve +accorders +arbitrarily +cowing +bars +bagel's +climax +attention's +cautioning +centipede's +almost +abstractionist +carpenter +containing +arab's +courtesy +carton +accelerated +bowman +boastings +banal +bucking +accomplishment's +classification +baldly +abruptness +calibrations +blocs +biking +assenter +adversities +compartmentalized +chemical +attic +audiogram's +applauds +crests +bad +bounce +accelerators +contemptuous +attentions +cancellation +battles +aging +advantages +anthologies +answers +bruised +castes +any +coped +arcade's +adaptively +arsenal's +confessed +controllability +acceptor's +abrogated +abutted +amusingly +apology +broils +court +boundaries +bode +collie +adiabatic +ambitions +charged +awfulness +consorts +botanists +blurring +absents +batten +backwoods +breaks +certified +chattering +admitted +bathrobe's +analogous +corporacy +bijection's +combatant +checked +condition +amoral +bayed +bedroom +chanting +antics +charity +blip's +biped +brilliance +catchers +booted +anabaptist +clothe +comforted +complaints +coacher +admissible +bang +concisely +cookery +capita +assurance +codifying +benchmarks +aunts +commentaries +anon +applicators +constructor +associated +abuses +choicest +confiding +antislavery +apron +ashore +cheerfully +betterment +administration's +campaign +cremated +ambulatory +bleacher +afterthought +barkers +choir +crossly +conducive +cache's +battery +actinium +countryman +cajoled +appeasing +beamer +cleaves +anthem's +clearing's +cooperated +barker +crowing +apprising +accusation's +beginning +associator +booking +caved +amicable +codify +clairvoyant +bevels +becalms +brawn +bunkhouse's +arms +antiredeposition +belt +antiphonal +cried +brae's +bridal +acronym +clay's +checkers +auxiliary +bind +compares +agilely +askers +blankly +antagonist's +bimodal +captivation +creditable +concentration +calling +bartender's +autopsied +correspondent's +carnivals +abjure +bystander's +bungle +chanticleers +conceding +burghers +boards +accessions +compensations +arabian +churn +crowed +centering +abnormalities +courtier's +congregation +aberrant +annexing +blockhouse +anthropomorphic +bedder's +abutting +conundrums +affiliated +cancellation's +bolts +ballgowns +augmenting +bureaucracy's +bootlegged +audiometers +blueberry +affliction +appreciation +codifier +amasses +countering +crackle +canoe +consuls +breathes +broiled +amalgam's +bodes +ballooners +coating +corollaries +amphibology +agenda's +chafing +alcoholics +accredit +anisotropy +anchovies +carriers +acceptors +betrayed +buttocks +busy +bunny +cropper +accreditations +bumblebee's +adhesives +civilize +accedes +abroad +arch +crept +cotyledon +alphabetic +braille +amateur +adjure +ascertaining +budge +adulterate +additive's +cardiac +born +brewed +borneo +bun's +blue +cackled +acclimates +airline +blinder +brokerage +communicant +central +aggrieved +asynchronous +bough's +acidly +archaeology +complementary +animator's +bodyguards +climbs +apathy +constellation's +acculturate +archaeologists +contingents +control +anglophilia +billings +corporate +athlete +accusing +appear +announcing +accordions +computerize +combinations +bile +abut +charger +columnize +computer +blacks +converges +blamer +bulked +convincingly +checker +correspondence's +accelerate +accessible +conceivably +abscissa's +adsorbs +anglophobia +anomic +casters +churning +crease +brood +appendage +bulwark +bombers +arcaded +breadboard's +aphrodite +color +commodore's +answerer +bobolink +cloth +conversion +clime +artery's +birthplaces +compiled +arrack +beetles +bobs +compatibility +cocoon +counterpart +audible +colonies +airport's +beige +cogent +bromide +begrudging +acids +crucifies +beggary +archipelagoes +availably +counterfeiter +blanketed +amending +accelerometer's +advisors +byway +alignment +amber +austin +copyrights +beaus +brigantine +comforts +appointment's +crawler +bangles +contemplation +concur +characterizing +censoring +charters +catalogues +appropriately +builds +aeronautic +confused +comber +axially +cackler +coercive +ambassador +arcades +brash +amorality +belittling +battling +bloodied +acrylic +bantered +clasped +carcass +archangel +annunciators +aristotle +boulder +burglarproofs +chooser +abilities +calmest +bach +always +blaspheming +crossover +bakeries +clocks +ankle's +accidental +arbitration +chirp +aeronautical +boy's +acidic +bowline +anonymously +cod +couplers +beautifications +bluffing +backarrows +brow +covenant +acronym's +banning +albeit +ascetic +burn +animator +beatnik's +coveted +cipher's +broke +cap +bellman +bulldozed +clarifies +bathes +blip +availabilities +booth +clangs +audiences +cathedrals +confounding +bigot's +beecher +arts +company +attributed +avenged +bawling +caustics +alee +bordello's +banks +affords +complied +commas +collaborate +aquatic +ambitiously +burro's +beard +bittersweet +candlestick +bylaws +broadcastings +believe +barrels +braying +certifications +contrasts +crashes +audition +confine +bucks +abates +bureaucracy +ambles +besiege +broccoli +antibiotics +attenuators +accelerometer +caste +bib's +browbeaten +appurtenance +bauxite +asceticism +case +chewing +aerator +achievements +barricade's +agglutinates +bewildering +cartridge's +children +bufferrer +actuator +converging +bolted +chat +combs +chemist's +adduced +algebraic +circular +bloated +conclusion +burgess +certifies +absconds +comprise +benzedrine +bumbler +banjo +allow +appealing +cooperation +abraded +chaperoned +biracial +braced +censurer +acoustician +appraised +benefitting +constructs +convertible +administrative +asocial +area +creature +besetting +crater +begrudgingly +blanket +ablest +alba +airplanes +allowing +briefly +beneficences +concurring +adjective's +cork +aerospace +anomalies +asher +auger's +boilers +abhorring +broadenings +bladder +belay +approver +abdominal +commends +cringing +billiards +beater +auspice +contrasters +bights +absentees +atoll +cooler +activator's +basement +burgeon +allusiveness +codeword's +bandage +contemplate +adopted +coping +carving +baptism +colds +altos +background +closet +commuted +acre's +aliens +council +cans +cheese +ally +aseptic +belgian's +crossbar +addressed +commons +call +careers +breakfasting +brazilian +catholics +bachelors +consultant +brighter +crossword's +burglar +avoidable +batting +cigar +amps +axiological +combed +comforters +albumin +cookies +booming +archaize +canton's +bunkmate +combination +bondsman +anxiously +affixed +associatively +cigar's +backstitch +calls +captivates +commodities +atmosphere's +asserting +beaver +beatnik +container +activists +consoler +commoner +buttonhole's +abhorred +aggregate +cliff +antidisestablishmentarianism +broach +ambling +comer +bited +advocated +behaves +bosom +continents +conserves +bashful +ago +backarrow +circumventable +avocados +briar's +annuls +barnstorming +aired +carry +crossbar's +aspire +beards +abides +cliques +completes +brassiere +absorbs +annul +chairman +baron +battens +africans +abatement +colonization +carries +borough +allurement +breakfasters +alkali +acoustically +corners +capturer +casualties +asphyxia +animized +administrator +belying +basketballs +bylines +bandit +autopsies +braining +contradiction's +antic +butted +bacillus +blurt +conditioned +backers +agreeable +almanacs +cider +chicken +chambers +clutch +assailant's +conveyers +amazers +beribboned +breeder +caveat's +buffers +combination's +ampersand's +crafting +clanged +caving +aspirant +butlers +adjective +auckland +announced +creators +caches +baseline +codifies +baptism's +coarsened +cohesion +airman +avenge +backaches +budgeted +armpit +bicycled +converged +besmirched +autonomic +coming +assemblage's +chained +admissions +alcoholic's +branches +bunk +anciently +bloods +adventurers +amazes +coloring +abstractors +adaptation's +boar +amulet +agglutination +conquerable +booker +confronts +barometer's +bedbugs +barricades +cheap +bewitch +circus +backward +archeology +automobiles +bending +amino +beckoning +admits +berliners +borer +clambering +atomizing +banner +blissfully +catchable +breakdown +abjured +computerized +chaplain's +amphitheater +ballot's +craziness +croaks +counties +adopting +breast +airstrip's +basin +contemplating +commitments +critique +appears +bellies +baccalaureate +abducted +blackened +animosity +appraising +antiquity +assistants +asthma +bootstrapping +bounties +agleam +advertisements +benches +artful +broadens +chuck's +betrayal +blasphemed +brooms +castled +coroutine +conscious +beetle +banshee +advertising +baring +awakens +balm +billions +compromisingly +ballroom's +burrower +bayou's +ambiance +beheading +bought +adagios +adornment's +anointed +abolishment's +anesthetizes +badly +boyishness +consultant's +cheek +cannibals +breakdowns +assured +agates +bicker +appliances +cafe +bagpipes +adrenal +combinatorially +belligerence +bricked +adjacency +aimless +crook +cherry's +assessing +brushfire +cormorant +captained +blundered +conceptually +congress's +contraster +ambushes +bronze +autotransformer +corded +brisker +contently +announcements +bullet +apportionments +columnized +canon +conservation +algaecide +blackening +compassion +beaks +constructibility +chapter +abscond +costly +bacon +coldest +aptness +billionth +altercation +approbation +alternator's +criticizes +befell +canopy +buoyant +brazil +anticipate +absenteeism +champion +aesthetics +cadence +betroth +confidants +bean +braid +aphids +cluttering +cantankerously +bloom +barbarity +clawing +bogged +agreed +asia +abrasion +corporals +baselines +box +chartering +apotheosis +ampersands +conceit +creamer +adhered +circuit +carpet +accompaniments +boomerangs +blindness +chipmunks +bewitched +allocate +bicycle +compacted +cab +calcium +cellists +apex +borrows +completed +brightly +constables +ascertains +conspiracy's +badgers +bunion's +anabaptists +broadband +clefts +accepted +benched +catalogued +cadenced +alliteration +acquiesces +boxcar's +athlete's +bracing +cremations +analysis +crossings +assorts +apologize +brazier +configurable +basking +craves +belle +conversation's +belligerent +anesthetize +brewers +cackles +adventures +airlock's +booklet's +apply +anecdotal +bewails +computer's +autographs +acclimated +coefficients +avidly +beckoned +broadener +bulk +blacklisting +belly +acquit +convoy +achiever +aversions +advisor's +captor's +camel's +asset's +advantageous +basement's +confident +crescents +compiling +butler's +cartoon's +adaptive +chlorine +abets +cruelly +amiable +baleful +ceiling's +adumbrated +cherry +aspirant's +cashing +candidly +chaff +bitter +brim +alcove +bulb's +carbonizers +citizen +attic's +breed +consumer +conferrers +accommodations +contrapositive +beget +brilliantly +attentionality +continuation's +bosses +brave +configurations +benediction's +conferring +accessor's +bobolinks +bulled +cleanness +algorithm +advancements +altogether +accumulations +albacore +bowing +belching +apical +consequentiality +bagpipe's +ambrosial +bullying +cleans +attendance's +complimenter +blink +cager +assembling +coat +allowable +astringent +antiresonator +cardinal +clicks +commentator's +blossom +categorizing +amphibian's +commonality +consonant +classics +affable +accorded +aimlessly +archetype +administerings +boldness +anatomy +apprehensively +absence's +actuality +attempting +categorical +checkpoints +allemande +corer +behoove +bleaches +bough +blended +blotting +baptists +courtship +benevolent +bumptiousness +chum +anguished +auto +career +bookstore's +carbonized +autocratically +cherishes +attendees +contends +anastomotic +attributing +abbot +came +blunt +battlement's +affection +coordination +annotate +besets +bucked +boasting +benedictions +adherent +blimp's +acknowledging +cleverly +applejack +annexation +bat's +cantons +beetled +closed +country +creatively +bakery +blasphemously +chalking +bold +attended +crasher +backtrackers +artist's +bracelet's +allowably +affiliating +arrant +brayed +barbells +consigned +abolishers +climatic +atrophying +amigo +arsenal +ascribes +converses +aura's +allotted +bliss +classical +bigger +ahead +chopped +blade +casualty +acceded +bottling +axon +casement's +battlefront's +convinces +alerting +advertisers +blemish +agglutinating +commonplaces +autocorrelation +armistice +crediting +besmirch +amplify +auscultation +befalls +called +alnico +arbiter's +abort +argonauts +cessations +cribs +blare +aforementioned +condemners +contaminated +complained +bootstrapped +criticism +cooperatively +binding +bullies +basins +contrived +assort +adulterously +booms +abandons +also +appealed +count +contributed +beet +crashers +carryovers +clays +blackness +cosmetics +awkward +blurted +bothers +analyzer +backups +alarming +bicyclers +credit +abrogate +audience's +architecturally +alibi's +complicator's +chuckle +corporately +banishment +communist's +birdie +asymptotic +break +braze +benzene +bridgework's +beak +agitators +collateral +arranges +bayonet +breathlessly +counsellor +creates +convulsions +backdrops +applicants +altercation's +commission +breathtakingly +corresponds +backdrop +armaments +build +biannual +buttoning +computational +chaired +bather +critically +amanuensis +bantus +confidential +annoyance's +carder +authorizing +acquits +bipeds +cocktail +cinnamon +burros +brocade +abdomen's +creative +acquisition's +abdomen +baited +aristocratically +alive +committed +arrestor +cleaving +comedy's +baggage +bra +adaptors +afoot +bulls +contoured +amalgam +comprehensibility +amortizes +biographical +confront +covert +cravat +animates +booksellers +bypass +bootleggers +bedfast +affair's +buzzer +bellowed +aligning +bystander +acclimatized +accomplishing +against +blankness +adopt +addressing +croaked +boaters +behooves +audits +boatyard +cruise +agnostics +ailing +anchorage's +adaptations +conceptualize +advised +cries +bank +actuators +brazing +catalyst +beachheads +aplomb +compressed +amputated +contractor's +bedspreads +bowed +coon +chaplain +cannons +coffers +assembly +bouffant +converters +ampoule's +borderland +archaeologist +blankets +conserving +avalanche +assortment's +aspic +axle +bereaves +allowance +carbonization +bartender +clawed +coincidental +appeared +chipmunk's +countable +authenticators +bestow +alps +caw +aniseikonic +avows +blackmails +controlling +correlating +audiologist's +bit +approving +collapse +coon's +cleave +atheists +brigade +autopilots +bounteous +commercialness +accede +cavalierness +accustoming +burnishing +clobber +aspirates +brochures +cellar's +communes +berkelium +chickadee +cobweb +circumstances +chose +comprehend +baritone's +aggravation +adopts +cruelty +and +axer +cautioned +carbonic +babbles +bet +charitable +computable +cardinality +amenities +confiscating +catcher +audaciousness +complaint's +cooperator's +buddies +baking +constant +classmate's +accentuate +choices +crop's +authorization's +comedy +brushy +brotherly +canals +ads +causeway +abrading +cemetery +autocrat +briefing +abdomens +apparition's +consummately +alkaloids +bulkheads +cravats +bales +campaigners +bagpipe +accentuates +arm +barometric +bas +agitator +behavior +abutters +blockades +alertness +civilizes +chinner +anthropologist +artificialness +balkanize +automates +cackling +anarchists +amounted +cereal's +anodized +cobblers +acknowledgment's +blear +copper +alphabetics +blackboards +apish +answering +afternoon +arbors +accused +chickens +agency's +contractors +contraptions +cosmology +anomaly +bandstand +attempter +account +challengers +admiration +calculations +autocracy +analyticity +accord +buildup's +commonly +babbling +adjudication's +attain +ameliorating +candlestick's +chronicles +align +consensus +agate +adulation +aspirated +conclusive +biologists +cracks +conform +chambered +beryllium +connote +amusing +aquifer +ankle +batteries +conservationists +accountants +apiaries +actinometer +beckon +clearances +clouded +antitoxin's +consolation's +collectives +boxtops +bombarded +bombarding +bluest +allusion's +construction +ballpark's +codified +coincidence +celebration +chip +beginner's +algerian +boo +athletics +condenser +bytes +beauties +concerts +conductors +awl's +agitations +buttered +codifier's +armory +ascii +aspirin +arthritis +bylaw's +conformity +blasting +coinciding +aphid's +ceremonial +banisters +bristle +bid's +buckboard's +bandied +biopsy +ballrooms +chloroplasts +bidding +boil +algebra +constellation +chuck +cringes +cleanliness +apron's +cosmopolitan +bashes +abusive +believer +conductor +butters +breweries +allotment +artfulness +bunkmates +blares +connections +anticipated +classifies +commandments +beginnings +bend +brambles +blacked +basketball's +affectionate +cocoa +anacondas +busing +bone +birchen +creamed +aged +commemorates +brother +aberration +crawl +actuarial +apology's +alumnus +adversary's +anaphoric +aspiring +consciousness +cokes +assignee +boxing +blanched +camels +contemporaries +carnivorous +assigned +apologetically +corpus +accusations +beefing +champaign +claps +adherence +aloft +complication +citizenship +becomes +compound +arabesque +bronchiole's +appraises +breach +collection's +botched +bitches +biblically +bronchial +amalgamating +commoner's +barbarian's +arrange +cradle +conformed +complimentary +anodes +cowering +anoint +brocaded +bedazzling +avionics +burnishes +bulkhead +chink +consciously +contract +clinch +applicant's +awning +aloud +chandelier's +cathode's +babble +arachnid +biplane +clamorous +assuredly +consented +axing +avenger +commence +braving +brandishing +careless +burningly +boatsman +channelling +clarifying +beggar +berates +cite +cowered +buffer +condescending +admixes +bettering +bedazzlement +cord +burglary's +characteristics +aptitudes +adieu +agree +bends +ceremonies +accustom +accessibly +commanders +ask +cavalier +brayer +affront +courser +becoming +carves +configures +beasts +biters +conditionals +bodybuilding +accretions +chapter's +cleverer +corning +brat +classes +almsman +consumptive +antique +comprised +beholders +anthropologically +buns +bridge +accretion +acceptance's +confederacy +armorer +argumentative +crossword +cowslip's +analog +counselor +chastised +barters +clerked +americas +cloud +aide +alternators +admitters +bagatelle +bridges +civilizations +anion's +briton's +apartment +acquaints +consummation +chord +coated +barer +carnivorously +cheering +allergy +capacity +classrooms +assistantships +complimented +amphibiously +commandment's +audiogram +corked +badness +bewildered +assemblage +backplane's +asterisk's +blob +coexisting +approximations +counteractive +barns +adherer +aborigine's +brooding +conceived +adjustor +cabled +belongings +breadwinner +blot's +brightness +consigning +barflies +bisector's +basing +complement +conditioner +brazes +crank +antinomian +crowd +accelerometers +befitting +backlash +bastions +acceleration +briefcases +correlated +baffle +chew +accosts +agreeably +bassinets +cogitate +concerning +contouring +broadside +compact +brainstems +atom's +bondage +biter +archdioceses +basis +bellboy +blobs +barons +clods +campaigned +assessors +bubbles +annal +casual +altercations +clog's +biased +arianism +ancillary +collaborator +butter +bureau +blending +antiquities +brands +activism +crews +beats +broad +buds +baggers +cobbler's +condemns +cabinets +bomber +blinders +center +contacted +bewilderingly +circulates +burnings +achieved +belch +barbecue +angles +comparative +befuddle +cherished +chapters +chanter +allegation's +armstrong +converter +combinatoric +angrier +brooks +clinked +blubber +appointments +compactor +cleaned +car +contention's +artificial +cramp +consistency +aborting +collaboration +awarders +crippled +anaphora +creamy +buoyed +baptistery +altered +anchoring +alterer +adjuring +beacon's +commencement's +ascension +candidness +clouding +cigars +boiled +christmas +contingency's +alum +apparel +contributors +anisotropic +annotations +bushwhacks +brides +continuities +carton's +blurred +antibody +aorta +blankest +combinator's +banish +breaches +accumulates +bowling +braver +antibacterial +cooperators +banked +compensated +chartable +conjunctively +antelope's +bluefish +annoying +composed +barges +biconcave +australia +ballparks +bearers +acknowledged +advocates +crossed +competitor +blaming +andorra +baritone +collaborator's +accessibility +complains +commentator +bibliography +conference's +atmosphere +agrees +bedstead's +ardor +character's +conventionally +arena's +chokes +channel +bludgeon +convoys +condense +beautifier +ailerons +compacts +black +bell +completions +ballroom +besotting +conservatives +adventured +bulldog's +conversely +arroyos +compositional +alternative +association +broods +beefy +consolidated +balms +acquaint +animal +certificate +combustion +aims +cracker +abetted +cautionings +bread +attains +agriculturally +courtyards +bawls +country's +creator's +checkbook's +cliches +colonizing +biennial +aqueous +craftsman +contrivances +algorithmic +crate +barefooted +bodily +anthropologist's +but +climate's +campers +crackled +awakes +conveyed +borrowers +approached +avoids +crib +albania +bathrobe +admonitions +architectures +consenting +anastomosis +blob's +actual +arrowhead's +accountable +allegiances +commendation +appearers +comply +concurs +controversy +abstracting +artifact diff --git a/db/test/wrap.tcl b/db/test/wrap.tcl new file mode 100644 index 000000000..4a5c825d8 --- /dev/null +++ b/db/test/wrap.tcl @@ -0,0 +1,58 @@ +# Sentinel file wrapper for multi-process tests. +# This is designed to avoid a set of nasty bugs, primarily on Windows, +# where pid reuse causes watch_procs to sit around waiting for some +# random process that's not DB's and is not exiting. + +source ./include.tcl + +# Arguments: +# +if { $argc < 3 } { + puts "FAIL: wrap.tcl: Usage: wrap.tcl script log scriptargs" + exit +} + +set script [lindex $argv 0] +set logfile [lindex $argv 1] +set args [lrange $argv 2 end] + +# Create a sentinel file to mark our creation and signal that watch_procs +# should look for us. +set parentpid [pid] +set parentsentinel $testdir/begin.$parentpid +set f [open $parentsentinel w] +close $f + +# Create a Tcl subprocess that will actually run the test. +set t [open "|$tclsh_path >& $logfile" w] + +# Create a sentinel for the subprocess. +set childpid [pid $t] +puts "Script watcher process $parentpid launching $script process $childpid." +set childsentinel $testdir/begin.$childpid +set f [open $childsentinel w] +close $f + +# Set up argv for the subprocess, since the args aren't passed in as true +# arguments thanks to the pipe structure. +puts $t "set argc [llength $args]" +puts $t "set argv [list $args]" + +# Command the test to run. +puts $t "source $test_path/$script" + +# Close the pipe. This will flush the above commands and actually run the +# test, and will also return an error a la exec if anything bad happens +# to the subprocess. The magic here is that closing a pipe blocks +# and waits for the exit of processes in the pipeline, at least according +# to Ousterhout (p. 115). + +set ret [catch {close $t} res] + +# Write ending sentinel files--we're done. +set f [open $testdir/end.$childpid w] +close $f +set f [open $testdir/end.$parentpid w] +close $f + +exit $ret diff --git a/db/txn/txn.c b/db/txn/txn.c new file mode 100644 index 000000000..0f6d894c1 --- /dev/null +++ b/db/txn/txn.c @@ -0,0 +1,869 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1995, 1996 + * The President and Fellows of Harvard University. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Margo Seltzer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: txn.c,v 11.61 2001/01/10 18:18:52 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#if TIME_WITH_SYS_TIME +#include +#include +#else +#if HAVE_SYS_TIME_H +#include +#else +#include +#endif +#endif + +#include +#endif + +#ifdef HAVE_RPC +#include "db_server.h" +#endif + +#include "db_int.h" +#include "db_shash.h" +#include "txn.h" +#include "lock.h" +#include "log.h" +#include "db_dispatch.h" +#include "db_page.h" +#include "db_ext.h" + +#ifdef HAVE_RPC +#include "gen_client_ext.h" +#include "rpc_client_ext.h" +#endif + +static int __txn_begin __P((DB_TXN *)); +static int __txn_isvalid __P((const DB_TXN *, TXN_DETAIL **, u_int32_t)); +static int __txn_undo __P((DB_TXN *)); + +/* + * txn_begin -- + * This is a wrapper to the actual begin process. Normal txn_begin() + * allocates a DB_TXN structure for the caller, while txn_xa_begin() does + * not. Other than that, both call into the common __txn_begin code(). + * + * Internally, we use TXN_DETAIL structures, but the DB_TXN structure + * provides access to the transaction ID and the offset in the transaction + * region of the TXN_DETAIL structure. + */ +int +txn_begin(dbenv, parent, txnpp, flags) + DB_ENV *dbenv; + DB_TXN *parent, **txnpp; + u_int32_t flags; +{ + DB_TXN *txn; + int ret; + +#ifdef HAVE_RPC + if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) + return (__dbcl_txn_begin(dbenv, parent, txnpp, flags)); +#endif + + PANIC_CHECK(dbenv); + ENV_REQUIRES_CONFIG(dbenv, dbenv->tx_handle, DB_INIT_TXN); + + if ((ret = __db_fchk(dbenv, + "txn_begin", flags, + DB_TXN_NOWAIT | DB_TXN_NOSYNC | DB_TXN_SYNC)) != 0) + return (ret); + if ((ret = __db_fcchk(dbenv, + "txn_begin", flags, DB_TXN_NOSYNC, DB_TXN_SYNC)) != 0) + return (ret); + + if ((ret = __os_calloc(dbenv, 1, sizeof(DB_TXN), &txn)) != 0) + return (ret); + + txn->mgrp = dbenv->tx_handle; + txn->parent = parent; + TAILQ_INIT(&txn->kids); + txn->flags = TXN_MALLOC; + if (LF_ISSET(DB_TXN_NOSYNC)) + F_SET(txn, TXN_NOSYNC); + if (LF_ISSET(DB_TXN_SYNC)) + F_SET(txn, TXN_SYNC); + if (LF_ISSET(DB_TXN_NOWAIT)) + F_SET(txn, TXN_NOWAIT); + + if ((ret = __txn_begin(txn)) != 0) { + __os_free(txn, sizeof(DB_TXN)); + txn = NULL; + } + + if (txn != NULL && parent != NULL) + TAILQ_INSERT_HEAD(&parent->kids, txn, klinks); + + *txnpp = txn; + return (ret); +} + +/* + * __txn_xa_begin -- + * XA version of txn_begin. + * + * PUBLIC: int __txn_xa_begin __P((DB_ENV *, DB_TXN *)); + */ +int +__txn_xa_begin(dbenv, txn) + DB_ENV *dbenv; + DB_TXN *txn; +{ + PANIC_CHECK(dbenv); + + memset(txn, 0, sizeof(DB_TXN)); + + txn->mgrp = dbenv->tx_handle; + + return (__txn_begin(txn)); +} + +/* + * __txn_begin -- + * Normal DB version of txn_begin. + */ +static int +__txn_begin(txn) + DB_TXN *txn; +{ + DB_ENV *dbenv; + DB_LSN begin_lsn; + DB_TXNMGR *mgr; + DB_TXNREGION *region; + TXN_DETAIL *td; + size_t off; + u_int32_t id; + int ret; + + mgr = txn->mgrp; + dbenv = mgr->dbenv; + region = mgr->reginfo.primary; + + /* + * We do not have to write begin records (and if we do not, then we + * need never write records for read-only transactions). However, + * we do need to find the current LSN so that we can store it in the + * transaction structure, so we can know where to take checkpoints. + */ + if (LOGGING_ON(dbenv) && + (ret = log_put(dbenv, &begin_lsn, NULL, DB_CURLSN)) != 0) + goto err2; + + R_LOCK(dbenv, &mgr->reginfo); + + /* Make sure that last_txnid is not going to wrap around. */ + if (region->last_txnid == TXN_INVALID) { + __db_err(dbenv, +"txn_begin: transaction ID wrapped. Exit the database environment\nand restart the application as if application failure had occurred"); + ret = EINVAL; + goto err1; + } + + /* Allocate a new transaction detail structure. */ + if ((ret = + __db_shalloc(mgr->reginfo.addr, sizeof(TXN_DETAIL), 0, &td)) != 0) { + __db_err(dbenv, + "Unable to allocate memory for transaction detail"); + goto err1; + } + + /* Place transaction on active transaction list. */ + SH_TAILQ_INSERT_HEAD(®ion->active_txn, td, links, __txn_detail); + + id = ++region->last_txnid; + ++region->nbegins; + if (++region->nactive > region->maxnactive) + region->maxnactive = region->nactive; + + td->txnid = id; + td->begin_lsn = begin_lsn; + ZERO_LSN(td->last_lsn); + td->status = TXN_RUNNING; + if (txn->parent != NULL) + td->parent = txn->parent->off; + else + td->parent = INVALID_ROFF; + + off = R_OFFSET(&mgr->reginfo, td); + R_UNLOCK(dbenv, &mgr->reginfo); + + ZERO_LSN(txn->last_lsn); + txn->txnid = id; + txn->off = off; + + /* + * If this is a transaction family, we must link the child to the + * maximal grandparent in the lock table for deadlock detection. + */ + if (txn->parent != NULL && LOCKING_ON(dbenv)) + if ((ret = __lock_addfamilylocker(dbenv, + txn->parent->txnid, txn->txnid)) != 0) + goto err2; + + if (F_ISSET(txn, TXN_MALLOC)) { + MUTEX_THREAD_LOCK(dbenv, mgr->mutexp); + TAILQ_INSERT_TAIL(&mgr->txn_chain, txn, links); + MUTEX_THREAD_UNLOCK(dbenv, mgr->mutexp); + } + + return (0); + +err1: R_UNLOCK(dbenv, &mgr->reginfo); + +err2: return (ret); +} + +/* + * txn_commit -- + * Commit a transaction. + */ +int +txn_commit(txnp, flags) + DB_TXN *txnp; + u_int32_t flags; +{ + DB_ENV *dbenv; + DB_TXN *kid; + int is_commit, ret, t_ret; + + dbenv = txnp->mgrp->dbenv; + +#ifdef HAVE_RPC + if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) + return (__dbcl_txn_commit(txnp, flags)); +#endif + + PANIC_CHECK(dbenv); + + if ((ret = __txn_isvalid(txnp, NULL, TXN_COMMITTED)) != 0) + return (ret); + + /* + * We clear flags that are incorrect, ignoring any flag errors, and + * default to synchronous operations. By definition, transaction + * handles are dead when we return, and this error should never + * happen, but we don't want to fail in the field 'cause the app is + * specifying the wrong flag for some reason. + */ + if (__db_fchk(dbenv, + "txn_commit", flags, DB_TXN_NOSYNC | DB_TXN_SYNC) != 0) + flags = DB_TXN_SYNC; + if (__db_fcchk(dbenv, + "txn_commit", flags, DB_TXN_NOSYNC, DB_TXN_SYNC) != 0) + flags = DB_TXN_SYNC; + if (LF_ISSET(DB_TXN_NOSYNC)) { + F_CLR(txnp, TXN_SYNC); + F_SET(txnp, TXN_NOSYNC); + } + if (LF_ISSET(DB_TXN_SYNC)) { + F_CLR(txnp, TXN_NOSYNC); + F_SET(txnp, TXN_SYNC); + } + + /* + * Commit any unresolved children. If there's an error, abort any + * unresolved children and the parent. + */ + while ((kid = TAILQ_FIRST(&txnp->kids)) != NULL) + if ((ret = txn_commit(kid, flags)) != 0) { + while ((kid = TAILQ_FIRST(&txnp->kids)) != NULL) + (void)txn_abort(kid); + (void)txn_abort(txnp); + goto err; + } + + /* + * If there are any log records, write a log record and sync the log, + * else do no log writes. If the commit is for a child transaction, + * we do not need to commit the child synchronously since it may still + * abort (if its parent aborts), and otherwise its parent or ultimate + * ancestor will write synchronously. + * + * I'd rather return a logging error than a flag-wrong error, so if + * the log routines fail, set "ret" without regard to previous value. + */ + if (LOGGING_ON(dbenv) && !IS_ZERO_LSN(txnp->last_lsn)) { + if (txnp->parent == NULL) { + if ((t_ret = __txn_regop_log(dbenv, + txnp, &txnp->last_lsn, + (F_ISSET(dbenv, DB_ENV_TXN_NOSYNC) && + !F_ISSET(txnp, TXN_SYNC)) || + F_ISSET(txnp, TXN_NOSYNC) ? 0 : DB_FLUSH, + TXN_COMMIT, (int32_t)time(NULL))) != 0) { + ret = t_ret; + goto err; + } + } else { + /* Log the commit in the parent! */ + if ((t_ret = __txn_child_log(dbenv, + txnp->parent, &txnp->parent->last_lsn, + 0, txnp->txnid, &txnp->last_lsn)) != 0) { + ret = t_ret; + goto err; + } + + F_SET(txnp->parent, TXN_CHILDCOMMIT); + } + } + + is_commit = 1; + if (0) { +err: is_commit = 0; + } + if ((t_ret = __txn_end(txnp, is_commit)) != 0 && ret == 0) + ret = t_ret; + return (ret); +} + +/* + * txn_abort -- + * Abort a transaction. + */ +int +txn_abort(txnp) + DB_TXN *txnp; +{ + DB_ENV *dbenv; + DB_TXN *kid; + int ret, t_ret; + + dbenv = txnp->mgrp->dbenv; + +#ifdef HAVE_RPC + if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) + return (__dbcl_txn_abort(txnp)); +#endif + + PANIC_CHECK(dbenv); + + if ((ret = __txn_isvalid(txnp, NULL, TXN_ABORTED)) != 0) + return (ret); + + /* Abort any unresolved children. */ + while ((kid = TAILQ_FIRST(&txnp->kids)) != NULL) + if ((t_ret = txn_abort(kid)) != 0 && ret == 0) + ret = t_ret; + + if ((t_ret = __txn_undo(txnp)) != 0 && ret == 0) + ret = t_ret; + + if ((t_ret = __txn_end(txnp, 0)) != 0 && ret == 0) + ret = t_ret; + return (ret); +} + +/* + * txn_prepare -- + * Flush the log so a future commit is guaranteed to succeed. + */ +int +txn_prepare(txnp) + DB_TXN *txnp; +{ + DBT xid; + DB_ENV *dbenv; + DB_TXN *kid; + TXN_DETAIL *td; + int ret; + + dbenv = txnp->mgrp->dbenv; + +#ifdef HAVE_RPC + if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) + return (__dbcl_txn_prepare(txnp)); +#endif + + PANIC_CHECK(dbenv); + + if ((ret = __txn_isvalid(txnp, &td, TXN_PREPARED)) != 0) + return (ret); + + /* Prepare any unresolved children. */ + while ((kid = TAILQ_FIRST(&txnp->kids)) != NULL) + if ((ret = txn_prepare(kid)) != 0) + return (ret); + + /* + * We indicate that a transaction is an XA transaction by putting + * a valid size in the xid.size fiels. XA requires that the transaction + * be either ENDED or SUSPENDED when prepare is called, so we know + * that if the xa_status isn't in one of those states, but we are + * calling prepare that we are not an XA transaction. + */ + + if (LOGGING_ON(dbenv)) { + memset(&xid, 0, sizeof(xid)); + xid.data = td->xid; + xid.size = td->xa_status != TXN_XA_ENDED && + td->xa_status != TXN_XA_SUSPENDED ? 0 : sizeof(td->xid); + if ((ret = __txn_xa_regop_log(dbenv, txnp, &txnp->last_lsn, + (F_ISSET(dbenv, DB_ENV_TXN_NOSYNC) && + !F_ISSET(txnp, TXN_SYNC)) || + F_ISSET(txnp, TXN_NOSYNC) ? 0 : DB_FLUSH, TXN_PREPARE, + &xid, td->format, td->gtrid, td->bqual, + &td->begin_lsn)) != 0) { + __db_err(dbenv, "txn_prepare: log_write failed %s", + db_strerror(ret)); + return (ret); + } + if (txnp->parent != NULL) + F_SET(txnp->parent, TXN_CHILDCOMMIT); + } + + MUTEX_THREAD_LOCK(dbenv, txnp->mgrp->mutexp); + td->status = TXN_PREPARED; + MUTEX_THREAD_UNLOCK(dbenv, txnp->mgrp->mutexp); + return (0); +} + +/* + * txn_id -- + * Return the transaction ID. + */ +u_int32_t +txn_id(txnp) + DB_TXN *txnp; +{ + return (txnp->txnid); +} + +/* + * __txn_isvalid -- + * Return 0 if the txnp is reasonable, otherwise panic. + */ +static int +__txn_isvalid(txnp, tdp, op) + const DB_TXN *txnp; + TXN_DETAIL **tdp; + u_int32_t op; +{ + DB_TXNMGR *mgrp; + TXN_DETAIL *tp; + + mgrp = txnp->mgrp; + + /* Check for live cursors. */ + if (txnp->cursors != 0) { + __db_err(mgrp->dbenv, "transaction has active cursors"); + goto err; + } + + /* Check transaction's status. */ + tp = (TXN_DETAIL *)R_ADDR(&mgrp->reginfo, txnp->off); + if (tdp != NULL) + *tdp = tp; + + switch (tp->status) { + case TXN_ABORTED: + case TXN_COMMITTED: + default: + __db_err(mgrp->dbenv, "transaction already %s", + tp->status == TXN_COMMITTED ? "committed" : "aborted"); + goto err; + case TXN_PREPARED: + if (op == TXN_PREPARED) { + __db_err(mgrp->dbenv, "transaction already prepared"); + goto err; + } + case TXN_RUNNING: + break; + } + + return (0); + +err: /* + * If there's a serious problem with the transaction, panic. TXN + * handles are dead by definition when we return, and if you use + * a cursor you forgot to close, we have no idea what will happen. + */ + return (__db_panic(mgrp->dbenv, EINVAL)); +} + +/* + * __txn_end -- + * Internal transaction end routine. + * + * PUBLIC: int __txn_end __P((DB_TXN *, int)); + */ +int +__txn_end(txnp, is_commit) + DB_TXN *txnp; + int is_commit; +{ + DB_ENV *dbenv; + DB_LOCKREQ request; + DB_TXNMGR *mgr; + DB_TXNREGION *region; + TXN_DETAIL *tp; + int ret; + + mgr = txnp->mgrp; + dbenv = mgr->dbenv; + region = mgr->reginfo.primary; + + /* Release the locks. */ + request.op = txnp->parent == NULL || + is_commit == 0 ? DB_LOCK_PUT_ALL : DB_LOCK_INHERIT; + + if (LOCKING_ON(dbenv)) { + ret = lock_vec(dbenv, txnp->txnid, 0, &request, 1, NULL); + if (ret != 0 && (ret != DB_LOCK_DEADLOCK || is_commit)) { + __db_err(dbenv, "%s: release locks failed %s", + is_commit ? "txn_commit" : "txn_abort", + db_strerror(ret)); + __db_panic(dbenv, ret); + } + } + + /* End the transaction. */ + R_LOCK(dbenv, &mgr->reginfo); + + tp = (TXN_DETAIL *)R_ADDR(&mgr->reginfo, txnp->off); + SH_TAILQ_REMOVE(®ion->active_txn, tp, links, __txn_detail); + __db_shalloc_free(mgr->reginfo.addr, tp); + + if (is_commit) + region->ncommits++; + else + region->naborts++; + --region->nactive; + + R_UNLOCK(dbenv, &mgr->reginfo); + + /* + * The transaction cannot get more locks, remove its locker info. + */ + if (LOCKING_ON(dbenv)) + __lock_freefamilylocker(dbenv->lk_handle, txnp->txnid); + if (txnp->parent != NULL) + TAILQ_REMOVE(&txnp->parent->kids, txnp, klinks); + + /* Free the space. */ + if (F_ISSET(txnp, TXN_MALLOC)) { + MUTEX_THREAD_LOCK(dbenv, mgr->mutexp); + TAILQ_REMOVE(&mgr->txn_chain, txnp, links); + MUTEX_THREAD_UNLOCK(dbenv, mgr->mutexp); + + __os_free(txnp, sizeof(*txnp)); + } + + return (0); +} + +/* + * __txn_undo -- + * Undo the transaction with id txnid. Returns 0 on success and + * errno on failure. + */ +static int +__txn_undo(txnp) + DB_TXN *txnp; +{ + DBT rdbt; + DB_ENV *dbenv; + DB_LSN key_lsn; + DB_TXNMGR *mgr; + void *txnlist; + int ret, threaded; + + mgr = txnp->mgrp; + dbenv = mgr->dbenv; + txnlist = NULL; + + if (!LOGGING_ON(dbenv)) + return (0); + + /* + * This is the simplest way to code this, but if the mallocs during + * recovery turn out to be a performance issue, we can do the + * allocation here and use DB_DBT_USERMEM. + */ + memset(&rdbt, 0, sizeof(rdbt)); + threaded = F_ISSET(dbenv, DB_ENV_THREAD) ? 1 : 0; + if (threaded) + F_SET(&rdbt, DB_DBT_MALLOC); + + key_lsn = txnp->last_lsn; + + /* Allocate a transaction list for children or aborted page creates. */ + if ((ret = __db_txnlist_init(dbenv, &txnlist)) != 0) + return (ret); + + if (F_ISSET(txnp, TXN_CHILDCOMMIT) && + (ret = __db_txnlist_lsninit(dbenv, + txnlist, &txnp->last_lsn)) != 0) + return (ret); + + for (ret = 0; ret == 0 && !IS_ZERO_LSN(key_lsn);) { + /* + * The dispatch routine returns the lsn of the record + * before the current one in the key_lsn argument. + */ + if ((ret = log_get(dbenv, &key_lsn, &rdbt, DB_SET)) == 0) { + ret = __db_dispatch(dbenv, + &rdbt, &key_lsn, DB_TXN_ABORT, txnlist); + if (threaded && rdbt.data != NULL) { + __os_free(rdbt.data, rdbt.size); + rdbt.data = NULL; + } + if (F_ISSET(txnp, TXN_CHILDCOMMIT)) + (void)__db_txnlist_lsnadd(dbenv, + txnlist, &key_lsn, 0); + } + if (ret != 0) { + __db_err(txnp->mgrp->dbenv, + "txn_abort: Log undo failed for LSN: %lu %lu: %s", + (u_long)key_lsn.file, (u_long)key_lsn.offset, + db_strerror(ret)); + if (txnlist != NULL) + __db_txnlist_end(dbenv, txnlist); + return (ret); + } + } + + if (txnlist != NULL) { + __db_do_the_limbo(dbenv, txnlist); + __db_txnlist_end(dbenv, txnlist); + } + + return (ret); +} + +/* + * Transaction checkpoint. + * If either kbytes or minutes is non-zero, then we only take the checkpoint + * more than "minutes" minutes have passed since the last checkpoint or if + * more than "kbytes" of log data have been written since the last checkpoint. + * When taking a checkpoint, find the oldest active transaction and figure out + * its first LSN. This is the lowest LSN we can checkpoint, since any record + * written after since that point may be involved in a transaction and may + * therefore need to be undone in the case of an abort. + */ +int +txn_checkpoint(dbenv, kbytes, minutes, flags) + DB_ENV *dbenv; + u_int32_t kbytes, minutes, flags; +{ + DB_LOG *dblp; + DB_LSN ckp_lsn, sync_lsn, last_ckp; + DB_TXNMGR *mgr; + DB_TXNREGION *region; + LOG *lp; + TXN_DETAIL *txnp; + time_t last_ckp_time, now; + u_int32_t bytes, mbytes; + int interval, ret; + +#ifdef HAVE_RPC + if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) + return (__dbcl_txn_checkpoint(dbenv, kbytes, minutes)); +#endif + PANIC_CHECK(dbenv); + ENV_REQUIRES_CONFIG(dbenv, dbenv->tx_handle, DB_INIT_TXN); + + mgr = dbenv->tx_handle; + region = mgr->reginfo.primary; + dblp = dbenv->lg_handle; + lp = dblp->reginfo.primary; + + /* + * Check if we need to checkpoint. + */ + ZERO_LSN(ckp_lsn); + + if (LF_ISSET(DB_FORCE)) + goto do_ckp; + + R_LOCK(dbenv, &dblp->reginfo); + mbytes = lp->stat.st_wc_mbytes; + /* + * We add the current buffer offset so as to count bytes that + * have not yet been written, but are sitting in the log buffer. + */ + bytes = lp->stat.st_wc_bytes + lp->b_off; + ckp_lsn = lp->lsn; + R_UNLOCK(dbenv, &dblp->reginfo); + + /* Don't checkpoint a quiescent database. */ + if (bytes == 0 && mbytes == 0) + return (0); + + if (kbytes != 0 && mbytes * 1024 + bytes / 1024 >= (u_int32_t)kbytes) + goto do_ckp; + + if (minutes != 0) { + (void)time(&now); + + R_LOCK(dbenv, &mgr->reginfo); + last_ckp_time = region->time_ckp; + R_UNLOCK(dbenv, &mgr->reginfo); + + if (now - last_ckp_time >= (time_t)(minutes * 60)) + goto do_ckp; + } + + /* + * If we checked time and data and didn't go to checkpoint, + * we're done. + */ + if (minutes != 0 || kbytes != 0) + return (0); + +do_ckp: + if (IS_ZERO_LSN(ckp_lsn)) { + R_LOCK(dbenv, &dblp->reginfo); + ckp_lsn = lp->lsn; + R_UNLOCK(dbenv, &dblp->reginfo); + } + + /* + * We have to find an LSN such that all transactions begun + * before that LSN are complete. + */ + R_LOCK(dbenv, &mgr->reginfo); + + if (IS_ZERO_LSN(region->pending_ckp)) { + for (txnp = + SH_TAILQ_FIRST(®ion->active_txn, __txn_detail); + txnp != NULL; + txnp = SH_TAILQ_NEXT(txnp, links, __txn_detail)) { + + /* + * Look through the active transactions for the + * lowest begin lsn. + */ + if (!IS_ZERO_LSN(txnp->begin_lsn) && + log_compare(&txnp->begin_lsn, &ckp_lsn) < 0) + ckp_lsn = txnp->begin_lsn; + } + region->pending_ckp = ckp_lsn; + } else + ckp_lsn = region->pending_ckp; + + R_UNLOCK(dbenv, &mgr->reginfo); + + /* + * Try three times to sync the mpool buffers up to the specified LSN, + * sleeping 1, 2 and 4 seconds between attempts. + */ + if (MPOOL_ON(dbenv)) + for (interval = 1;;) { + /* + * memp_sync may change the lsn you pass it, so don't + * pass it the actual ckp_lsn, pass it a local instead. + */ + sync_lsn = ckp_lsn; + if ((ret = memp_sync(dbenv, &sync_lsn)) == 0) + break; + + /* + * ret == DB_INCOMPLETE means there are still buffers + * to flush, the checkpoint is not complete. + */ + if (ret == DB_INCOMPLETE) { + if (interval > 4) + return (ret); + + (void)__os_sleep(dbenv, interval, 0); + interval *= 2; + } else { + __db_err(dbenv, + "txn_checkpoint: failure in memp_sync %s", + db_strerror(ret)); + return (ret); + } + } + + if (LOGGING_ON(dbenv)) { + R_LOCK(dbenv, &mgr->reginfo); + last_ckp = region->last_ckp; + ZERO_LSN(region->pending_ckp); + R_UNLOCK(dbenv, &mgr->reginfo); + + if ((ret = __txn_ckp_log(dbenv, + NULL, &ckp_lsn, DB_CHECKPOINT, &ckp_lsn, + &last_ckp, (int32_t)time(NULL))) != 0) { + __db_err(dbenv, + "txn_checkpoint: log failed at LSN [%ld %ld] %s", + (long)ckp_lsn.file, (long)ckp_lsn.offset, + db_strerror(ret)); + return (ret); + } + + R_LOCK(dbenv, &mgr->reginfo); + region->last_ckp = ckp_lsn; + (void)time(®ion->time_ckp); + R_UNLOCK(dbenv, &mgr->reginfo); + } + return (0); +} + +/* + * __txn_activekids -- + * Return if this transaction has any active children. + * + * PUBLIC: int __txn_activekids __P((DB_ENV *, u_int32_t, DB_TXN *)); + */ +int +__txn_activekids(dbenv, rectype, txnp) + DB_ENV *dbenv; + u_int32_t rectype; + DB_TXN *txnp; +{ + /* + * On a child commit, we know that there are children (i.e., the + * commiting child at the least. In that case, skip this check. + */ + if (rectype == DB_txn_child) + return (0); + + if (TAILQ_FIRST(&txnp->kids) != NULL) { + __db_err(dbenv, "Child transaction is active"); + return (EPERM); + } + return (0); +} diff --git a/db/txn/txn.src b/db/txn/txn.src new file mode 100644 index 000000000..b1e131c2b --- /dev/null +++ b/db/txn/txn.src @@ -0,0 +1,114 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + * + * $Id: txn.src,v 11.10 2001/01/02 00:58:33 margo Exp $ + */ + +PREFIX txn + +INCLUDE #include "db_config.h" +INCLUDE +INCLUDE #ifndef NO_SYSTEM_INCLUDES +INCLUDE #include +INCLUDE +INCLUDE #include +INCLUDE #include +INCLUDE #include +INCLUDE #endif +INCLUDE +INCLUDE #include "db_int.h" +INCLUDE #include "db_page.h" +INCLUDE #include "db_dispatch.h" +INCLUDE #include "db_am.h" +INCLUDE #include "txn.h" +INCLUDE + +/* + * DEPRECATED in 3.1 to add timestamps. + */ +DEPRECATED old_regop 6 +ARG opcode u_int32_t lu +END + +/* + * This is the standard log operation for commit. + * Note that we are using an int32_t for the timestamp. This means that + * in 2039 we will need to deprecate this log record and create one that + * either changes the Epoch or has a 64-bit offset. + */ +BEGIN regop 10 +ARG opcode u_int32_t lu +ARG timestamp int32_t ld +END + +DEPRECATED old_ckp 7 +POINTER ckp_lsn DB_LSN * lu +POINTER last_ckp DB_LSN * lu +END + +/* + * This is the checkpoint record. It contains the lsn that the checkpoint + * guarantees and a pointer to the last checkpoint so we can walk backwards + * by checkpoint. + * + * ckp_lsn: + * The lsn in the log of the most recent point at which all begun + * transactions have been aborted. This is the point for which + * the checkpoint is relevant. + * last_ckp: + * The previous checkpoint. + * timestamp: + * See comment in commit about timestamps. + */ +BEGIN ckp 11 +POINTER ckp_lsn DB_LSN * lu +POINTER last_ckp DB_LSN * lu +ARG timestamp int32_t ld +END + +/* + * This is the standard log operation for prepare (since right now + * we only use prepare in an XA environment). + */ +DEPRECATED xa_regop_old 8 +ARG opcode u_int32_t lu +DBT xid DBT s +ARG formatID int32_t ld +ARG gtrid u_int32_t u +ARG bqual u_int32_t u +END + +/* + * This is the standard log operation for prepare (since right now + * we only use prepare in an XA environment). + */ +BEGIN xa_regop 13 +ARG opcode u_int32_t lu +DBT xid DBT s +ARG formatID int32_t ld +ARG gtrid u_int32_t u +ARG bqual u_int32_t u +POINTER begin_lsn DB_LSN * lu +END + +/* + * This is the log operation for a child commit. + */ +DEPRECATED child_old 9 +ARG opcode u_int32_t lu +ARG parent u_int32_t lx +END + +/* + * This is the (new) log operation for a child commit. It is + * logged as a record in the PARENT. The child field contains + * the transaction ID of the child committing and the c_lsn is + * the last LSN of the child's log trail. + */ +BEGIN child 12 +ARG child u_int32_t lx +POINTER c_lsn DB_LSN * lu +END diff --git a/db/txn/txn_auto.c b/db/txn/txn_auto.c new file mode 100644 index 000000000..cbfa53673 --- /dev/null +++ b/db/txn/txn_auto.c @@ -0,0 +1,893 @@ +/* Do not edit: automatically built by gen_rec.awk. */ +#include "db_config.h" + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "db_dispatch.h" +#include "db_am.h" +#include "txn.h" + +int +__txn_old_regop_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __txn_old_regop_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __txn_old_regop_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]txn_old_regop: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\topcode: %lu\n", (u_long)argp->opcode); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__txn_old_regop_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __txn_old_regop_args **argpp; +{ + __txn_old_regop_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__txn_old_regop_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->opcode, bp, sizeof(argp->opcode)); + bp += sizeof(argp->opcode); + *argpp = argp; + return (0); +} + +int +__txn_regop_log(dbenv, txnid, ret_lsnp, flags, + opcode, timestamp) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + u_int32_t opcode; + int32_t timestamp; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_txn_regop; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(opcode) + + sizeof(timestamp); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &opcode, sizeof(opcode)); + bp += sizeof(opcode); + memcpy(bp, ×tamp, sizeof(timestamp)); + bp += sizeof(timestamp); + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__txn_regop_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __txn_regop_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __txn_regop_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]txn_regop: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\topcode: %lu\n", (u_long)argp->opcode); + printf("\ttimestamp: %ld\n", (long)argp->timestamp); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__txn_regop_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __txn_regop_args **argpp; +{ + __txn_regop_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__txn_regop_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->opcode, bp, sizeof(argp->opcode)); + bp += sizeof(argp->opcode); + memcpy(&argp->timestamp, bp, sizeof(argp->timestamp)); + bp += sizeof(argp->timestamp); + *argpp = argp; + return (0); +} + +int +__txn_old_ckp_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __txn_old_ckp_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __txn_old_ckp_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]txn_old_ckp: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tckp_lsn: [%lu][%lu]\n", + (u_long)argp->ckp_lsn.file, (u_long)argp->ckp_lsn.offset); + printf("\tlast_ckp: [%lu][%lu]\n", + (u_long)argp->last_ckp.file, (u_long)argp->last_ckp.offset); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__txn_old_ckp_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __txn_old_ckp_args **argpp; +{ + __txn_old_ckp_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__txn_old_ckp_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->ckp_lsn, bp, sizeof(argp->ckp_lsn)); + bp += sizeof(argp->ckp_lsn); + memcpy(&argp->last_ckp, bp, sizeof(argp->last_ckp)); + bp += sizeof(argp->last_ckp); + *argpp = argp; + return (0); +} + +int +__txn_ckp_log(dbenv, txnid, ret_lsnp, flags, + ckp_lsn, last_ckp, timestamp) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + DB_LSN * ckp_lsn; + DB_LSN * last_ckp; + int32_t timestamp; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_txn_ckp; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(*ckp_lsn) + + sizeof(*last_ckp) + + sizeof(timestamp); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + if (ckp_lsn != NULL) + memcpy(bp, ckp_lsn, sizeof(*ckp_lsn)); + else + memset(bp, 0, sizeof(*ckp_lsn)); + bp += sizeof(*ckp_lsn); + if (last_ckp != NULL) + memcpy(bp, last_ckp, sizeof(*last_ckp)); + else + memset(bp, 0, sizeof(*last_ckp)); + bp += sizeof(*last_ckp); + memcpy(bp, ×tamp, sizeof(timestamp)); + bp += sizeof(timestamp); + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__txn_ckp_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __txn_ckp_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __txn_ckp_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]txn_ckp: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tckp_lsn: [%lu][%lu]\n", + (u_long)argp->ckp_lsn.file, (u_long)argp->ckp_lsn.offset); + printf("\tlast_ckp: [%lu][%lu]\n", + (u_long)argp->last_ckp.file, (u_long)argp->last_ckp.offset); + printf("\ttimestamp: %ld\n", (long)argp->timestamp); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__txn_ckp_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __txn_ckp_args **argpp; +{ + __txn_ckp_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__txn_ckp_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->ckp_lsn, bp, sizeof(argp->ckp_lsn)); + bp += sizeof(argp->ckp_lsn); + memcpy(&argp->last_ckp, bp, sizeof(argp->last_ckp)); + bp += sizeof(argp->last_ckp); + memcpy(&argp->timestamp, bp, sizeof(argp->timestamp)); + bp += sizeof(argp->timestamp); + *argpp = argp; + return (0); +} + +int +__txn_xa_regop_old_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __txn_xa_regop_old_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __txn_xa_regop_old_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]txn_xa_regop_old: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\topcode: %lu\n", (u_long)argp->opcode); + printf("\txid: "); + for (i = 0; i < argp->xid.size; i++) { + ch = ((u_int8_t *)argp->xid.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\tformatID: %ld\n", (long)argp->formatID); + printf("\tgtrid: %u\n", argp->gtrid); + printf("\tbqual: %u\n", argp->bqual); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__txn_xa_regop_old_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __txn_xa_regop_old_args **argpp; +{ + __txn_xa_regop_old_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__txn_xa_regop_old_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->opcode, bp, sizeof(argp->opcode)); + bp += sizeof(argp->opcode); + memset(&argp->xid, 0, sizeof(argp->xid)); + memcpy(&argp->xid.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->xid.data = bp; + bp += argp->xid.size; + memcpy(&argp->formatID, bp, sizeof(argp->formatID)); + bp += sizeof(argp->formatID); + memcpy(&argp->gtrid, bp, sizeof(argp->gtrid)); + bp += sizeof(argp->gtrid); + memcpy(&argp->bqual, bp, sizeof(argp->bqual)); + bp += sizeof(argp->bqual); + *argpp = argp; + return (0); +} + +int +__txn_xa_regop_log(dbenv, txnid, ret_lsnp, flags, + opcode, xid, formatID, gtrid, bqual, begin_lsn) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + u_int32_t opcode; + const DBT *xid; + int32_t formatID; + u_int32_t gtrid; + u_int32_t bqual; + DB_LSN * begin_lsn; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t zero; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_txn_xa_regop; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(opcode) + + sizeof(u_int32_t) + (xid == NULL ? 0 : xid->size) + + sizeof(formatID) + + sizeof(gtrid) + + sizeof(bqual) + + sizeof(*begin_lsn); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &opcode, sizeof(opcode)); + bp += sizeof(opcode); + if (xid == NULL) { + zero = 0; + memcpy(bp, &zero, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + } else { + memcpy(bp, &xid->size, sizeof(xid->size)); + bp += sizeof(xid->size); + memcpy(bp, xid->data, xid->size); + bp += xid->size; + } + memcpy(bp, &formatID, sizeof(formatID)); + bp += sizeof(formatID); + memcpy(bp, >rid, sizeof(gtrid)); + bp += sizeof(gtrid); + memcpy(bp, &bqual, sizeof(bqual)); + bp += sizeof(bqual); + if (begin_lsn != NULL) + memcpy(bp, begin_lsn, sizeof(*begin_lsn)); + else + memset(bp, 0, sizeof(*begin_lsn)); + bp += sizeof(*begin_lsn); + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__txn_xa_regop_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __txn_xa_regop_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __txn_xa_regop_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]txn_xa_regop: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\topcode: %lu\n", (u_long)argp->opcode); + printf("\txid: "); + for (i = 0; i < argp->xid.size; i++) { + ch = ((u_int8_t *)argp->xid.data)[i]; + if (isprint(ch) || ch == 0xa) + putchar(ch); + else + printf("%#x ", ch); + } + printf("\n"); + printf("\tformatID: %ld\n", (long)argp->formatID); + printf("\tgtrid: %u\n", argp->gtrid); + printf("\tbqual: %u\n", argp->bqual); + printf("\tbegin_lsn: [%lu][%lu]\n", + (u_long)argp->begin_lsn.file, (u_long)argp->begin_lsn.offset); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__txn_xa_regop_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __txn_xa_regop_args **argpp; +{ + __txn_xa_regop_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__txn_xa_regop_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->opcode, bp, sizeof(argp->opcode)); + bp += sizeof(argp->opcode); + memset(&argp->xid, 0, sizeof(argp->xid)); + memcpy(&argp->xid.size, bp, sizeof(u_int32_t)); + bp += sizeof(u_int32_t); + argp->xid.data = bp; + bp += argp->xid.size; + memcpy(&argp->formatID, bp, sizeof(argp->formatID)); + bp += sizeof(argp->formatID); + memcpy(&argp->gtrid, bp, sizeof(argp->gtrid)); + bp += sizeof(argp->gtrid); + memcpy(&argp->bqual, bp, sizeof(argp->bqual)); + bp += sizeof(argp->bqual); + memcpy(&argp->begin_lsn, bp, sizeof(argp->begin_lsn)); + bp += sizeof(argp->begin_lsn); + *argpp = argp; + return (0); +} + +int +__txn_child_old_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __txn_child_old_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __txn_child_old_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]txn_child_old: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\topcode: %lu\n", (u_long)argp->opcode); + printf("\tparent: 0x%lx\n", (u_long)argp->parent); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__txn_child_old_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __txn_child_old_args **argpp; +{ + __txn_child_old_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__txn_child_old_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->opcode, bp, sizeof(argp->opcode)); + bp += sizeof(argp->opcode); + memcpy(&argp->parent, bp, sizeof(argp->parent)); + bp += sizeof(argp->parent); + *argpp = argp; + return (0); +} + +int +__txn_child_log(dbenv, txnid, ret_lsnp, flags, + child, c_lsn) + DB_ENV *dbenv; + DB_TXN *txnid; + DB_LSN *ret_lsnp; + u_int32_t flags; + u_int32_t child; + DB_LSN * c_lsn; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn; + u_int32_t rectype, txn_num; + int ret; + u_int8_t *bp; + + rectype = DB_txn_child; + if (txnid != NULL && + TAILQ_FIRST(&txnid->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + return (ret); + txn_num = txnid == NULL ? 0 : txnid->txnid; + if (txnid == NULL) { + ZERO_LSN(null_lsn); + lsnp = &null_lsn; + } else + lsnp = &txnid->last_lsn; + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(child) + + sizeof(*c_lsn); + if ((ret = __os_malloc(dbenv, logrec.size, NULL, &logrec.data)) != 0) + return (ret); + + bp = logrec.data; + memcpy(bp, &rectype, sizeof(rectype)); + bp += sizeof(rectype); + memcpy(bp, &txn_num, sizeof(txn_num)); + bp += sizeof(txn_num); + memcpy(bp, lsnp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(bp, &child, sizeof(child)); + bp += sizeof(child); + if (c_lsn != NULL) + memcpy(bp, c_lsn, sizeof(*c_lsn)); + else + memset(bp, 0, sizeof(*c_lsn)); + bp += sizeof(*c_lsn); + DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) == logrec.size); + ret = log_put(dbenv, ret_lsnp, (DBT *)&logrec, flags); + if (txnid != NULL) + txnid->last_lsn = *ret_lsnp; + __os_free(logrec.data, logrec.size); + return (ret); +} + +int +__txn_child_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __txn_child_args *argp; + u_int32_t i; + u_int ch; + int ret; + + i = 0; + ch = 0; + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __txn_child_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + printf("[%lu][%lu]txn_child: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, + (u_long)lsnp->offset, + (u_long)argp->type, + (u_long)argp->txnid->txnid, + (u_long)argp->prev_lsn.file, + (u_long)argp->prev_lsn.offset); + printf("\tchild: 0x%lx\n", (u_long)argp->child); + printf("\tc_lsn: [%lu][%lu]\n", + (u_long)argp->c_lsn.file, (u_long)argp->c_lsn.offset); + printf("\n"); + __os_free(argp, 0); + return (0); +} + +int +__txn_child_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + __txn_child_args **argpp; +{ + __txn_child_args *argp; + u_int8_t *bp; + int ret; + + ret = __os_malloc(dbenv, sizeof(__txn_child_args) + + sizeof(DB_TXN), NULL, &argp); + if (ret != 0) + return (ret); + argp->txnid = (DB_TXN *)&argp[1]; + bp = recbuf; + memcpy(&argp->type, bp, sizeof(argp->type)); + bp += sizeof(argp->type); + memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); + bp += sizeof(argp->txnid->txnid); + memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); + bp += sizeof(DB_LSN); + memcpy(&argp->child, bp, sizeof(argp->child)); + bp += sizeof(argp->child); + memcpy(&argp->c_lsn, bp, sizeof(argp->c_lsn)); + bp += sizeof(argp->c_lsn); + *argpp = argp; + return (0); +} + +int +__txn_init_print(dbenv) + DB_ENV *dbenv; +{ + int ret; + + if ((ret = __db_add_recovery(dbenv, + __txn_old_regop_print, DB_txn_old_regop)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __txn_regop_print, DB_txn_regop)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __txn_old_ckp_print, DB_txn_old_ckp)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __txn_ckp_print, DB_txn_ckp)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __txn_xa_regop_old_print, DB_txn_xa_regop_old)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __txn_xa_regop_print, DB_txn_xa_regop)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __txn_child_old_print, DB_txn_child_old)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __txn_child_print, DB_txn_child)) != 0) + return (ret); + return (0); +} + +int +__txn_init_recover(dbenv) + DB_ENV *dbenv; +{ + int ret; + + if ((ret = __db_add_recovery(dbenv, + __deprecated_recover, DB_txn_old_regop)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __txn_regop_recover, DB_txn_regop)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __deprecated_recover, DB_txn_old_ckp)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __txn_ckp_recover, DB_txn_ckp)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __deprecated_recover, DB_txn_xa_regop_old)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __txn_xa_regop_recover, DB_txn_xa_regop)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __deprecated_recover, DB_txn_child_old)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, + __txn_child_recover, DB_txn_child)) != 0) + return (ret); + return (0); +} + diff --git a/db/txn/txn_rec.c b/db/txn/txn_rec.c new file mode 100644 index 000000000..bed20d98e --- /dev/null +++ b/db/txn/txn_rec.c @@ -0,0 +1,339 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1996 + * The President and Fellows of Harvard University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: txn_rec.c,v 11.15 2001/01/11 18:19:55 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#endif + +#include "db_int.h" +#include "db_page.h" +#include "txn.h" +#include "db_am.h" +#include "db_dispatch.h" +#include "log.h" +#include "common_ext.h" + +static int __txn_restore_txn __P((DB_ENV *, DB_LSN *, __txn_xa_regop_args *)); + +#define IS_XA_TXN(R) (R->xid.size != 0) + +/* + * PUBLIC: int __txn_regop_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + * + * These records are only ever written for commits. Normally, we redo any + * committed transaction, however if we are doing recovery to a timestamp, then + * we may treat transactions that commited after the timestamp as aborted. + */ +int +__txn_regop_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __txn_regop_args *argp; + int ret; + +#ifdef DEBUG_RECOVER + (void)__txn_regop_print(dbenv, dbtp, lsnp, op, info); +#endif + + if ((ret = __txn_regop_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + + if (argp->opcode != TXN_COMMIT) { + ret = EINVAL; + goto err; + } + + if (op == DB_TXN_FORWARD_ROLL) + ret = __db_txnlist_remove(info, argp->txnid->txnid); + else if (dbenv->tx_timestamp == 0 || + argp->timestamp <= (int32_t)dbenv->tx_timestamp) + /* + * We know this is the backward roll case because we + * are never called during ABORT or OPENFILES. + */ + ret = __db_txnlist_add(dbenv, info, argp->txnid->txnid, 0); + else + /* + * This is commit record, but we failed the timestamp check + * so we should treat it as an abort and add it to the list + * as an aborted record. + */ + ret = __db_txnlist_add(dbenv, info, argp->txnid->txnid, 1); + + if (ret == 0) + *lsnp = argp->prev_lsn; +err: __os_free(argp, 0); + + return (ret); +} + +/* + * PUBLIC: int __txn_xa_regop_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + * + * These records are only ever written for prepares. + */ +int +__txn_xa_regop_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __txn_xa_regop_args *argp; + int ret; + +#ifdef DEBUG_RECOVER + (void)__txn_xa_regop_print(dbenv, dbtp, lsnp, op, info); +#endif + + if ((ret = __txn_xa_regop_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + + if (argp->opcode != TXN_PREPARE) { + ret = EINVAL; + goto err; + } + + ret = __db_txnlist_find(info, argp->txnid->txnid); + + /* + * If we are rolling forward, then an aborted prepare + * indicates that this is the last record we'll see for + * this transaction ID and we should remove it from the + * list. + */ + + if (op == DB_TXN_FORWARD_ROLL && ret == 1) + ret = __db_txnlist_remove(info, argp->txnid->txnid); + else if (op == DB_TXN_BACKWARD_ROLL && ret != 0) { + /* + * On the backward pass, we have three possibilities: + * 1. The transaction is already committed, no-op. + * 2. The transaction is not committed and we are XA, treat + * like commited and roll forward so that can be committed + * or aborted late. + * 3. The transaction is not committed and we are not XA + * mark the transaction as aborted. + * + * Cases 2 and 3 are handled here. + */ + + /* + * Should never have seen this transaction unless it was + * commited. + */ + DB_ASSERT(ret == DB_NOTFOUND); + + if (IS_XA_TXN(argp)) { + /* + * This is an XA prepared, but not yet committed + * transaction. We need to add it to the + * transaction list, so that it gets rolled + * forward. We also have to add it to the region's + * internal state so it can be properly aborted + * or recovered. + */ + if ((ret = __db_txnlist_add(dbenv, + info, argp->txnid->txnid, 0)) == 0) + ret = __txn_restore_txn(dbenv, lsnp, argp); + } else + ret = __db_txnlist_add(dbenv, + info, argp->txnid->txnid, 1); + } else + ret = 0; + + if (ret == 0) + *lsnp = argp->prev_lsn; + +err: __os_free(argp, 0); + + return (ret); +} + +/* + * PUBLIC: int __txn_ckp_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__txn_ckp_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __txn_ckp_args *argp; + int ret; + +#ifdef DEBUG_RECOVER + __txn_ckp_print(dbenv, dbtp, lsnp, op, info); +#endif + COMPQUIET(dbenv, NULL); + + if ((ret = __txn_ckp_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + + /* + * Check for 'restart' checkpoint record. This occurs when the + * checkpoint lsn is equal to the lsn of the checkpoint record + * and means that we could set the transaction ID back to 1, so + * that we don't exhaust the transaction ID name space. + */ + if (argp->ckp_lsn.file == lsnp->file && + argp->ckp_lsn.offset == lsnp->offset) + __db_txnlist_gen(info, DB_REDO(op) ? -1 : 1); + + *lsnp = argp->last_ckp; + __os_free(argp, 0); + return (DB_TXN_CKP); +} + +/* + * __txn_child_recover + * Recover a commit record for a child transaction. + * + * PUBLIC: int __txn_child_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__txn_child_recover(dbenv, dbtp, lsnp, op, info) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __txn_child_args *argp; + int ret; + +#ifdef DEBUG_RECOVER + (void)__txn_child_print(dbenv, dbtp, lsnp, op, info); +#endif + if ((ret = __txn_child_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + + /* + * This is a record in a PARENT's log trail indicating that a + * child commited. If we are aborting, we need to update the + * parent's LSN array. If we are in recovery, then if the + * parent is commiting, we set ourselves up to commit, else + * we do nothing. + */ + if (op == DB_TXN_ABORT) { + /* Note that __db_txnlist_lsnadd rewrites its LSN + * parameter, so you cannot reuse the argp->c_lsn field. + */ + ret = __db_txnlist_lsnadd(dbenv, + info, &argp->c_lsn, TXNLIST_NEW); + } else if (op == DB_TXN_BACKWARD_ROLL) { + if (__db_txnlist_find(info, argp->txnid->txnid) == 0) + ret = __db_txnlist_add(dbenv, info, argp->child, 0); + else + ret = __db_txnlist_add(dbenv, info, argp->child, 1); + } else + ret = __db_txnlist_remove(info, argp->child); + + if (ret == 0) + *lsnp = argp->prev_lsn; + + __os_free(argp, 0); + + return (ret); +} + +/* + * __txn_restore_txn -- + * Using only during XA recovery. If we find any transactions that are + * prepared, but not yet committed, then we need to restore the transaction's + * state into the shared region, because the TM is going to issue a txn_abort + * or txn_commit and we need to respond correctly. + * + * lsnp is the LSN of the returned LSN + * argp is the perpare record (in an appropriate structure) + */ +static int +__txn_restore_txn(dbenv, lsnp, argp) + DB_ENV *dbenv; + DB_LSN *lsnp; + __txn_xa_regop_args *argp; +{ + DB_TXNMGR *mgr; + TXN_DETAIL *td; + DB_TXNREGION *region; + int ret; + + if (argp->xid.size == 0) + return (0); + + mgr = dbenv->tx_handle; + region = mgr->reginfo.primary; + R_LOCK(dbenv, &mgr->reginfo); + + /* Allocate a new transaction detail structure. */ + if ((ret = + __db_shalloc(mgr->reginfo.addr, sizeof(TXN_DETAIL), 0, &td)) != 0) + return (ret); + + /* Place transaction on active transaction list. */ + SH_TAILQ_INSERT_HEAD(®ion->active_txn, td, links, __txn_detail); + + td->txnid = argp->txnid->txnid; + td->begin_lsn = argp->begin_lsn; + td->last_lsn = *lsnp; + td->parent = 0; + td->status = TXN_PREPARED; + td->xa_status = TXN_XA_PREPARED; + memcpy(td->xid, argp->xid.data, argp->xid.size); + td->bqual = argp->bqual; + td->gtrid = argp->gtrid; + td->format = argp->formatID; + + R_UNLOCK(dbenv, &mgr->reginfo); + return (0); +} diff --git a/db/txn/txn_region.c b/db/txn/txn_region.c new file mode 100644 index 000000000..77ce3d08f --- /dev/null +++ b/db/txn/txn_region.c @@ -0,0 +1,393 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: txn_region.c,v 11.36 2001/01/11 18:19:55 bostic Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#if TIME_WITH_SYS_TIME +#include +#include +#else +#if HAVE_SYS_TIME_H +#include +#else +#include +#endif +#endif + +#include +#endif + +#ifdef HAVE_RPC +#include "db_server.h" +#endif + +#include "db_int.h" +#include "db_page.h" +#include "log.h" /* for __log_lastckp */ +#include "txn.h" +#include "db_am.h" + +#ifdef HAVE_RPC +#include "gen_client_ext.h" +#include "rpc_client_ext.h" +#endif + +static int __txn_init __P((DB_ENV *, DB_TXNMGR *)); +static int __txn_set_tx_max __P((DB_ENV *, u_int32_t)); +static int __txn_set_tx_recover __P((DB_ENV *, + int (*)(DB_ENV *, DBT *, DB_LSN *, db_recops))); +static int __txn_set_tx_timestamp __P((DB_ENV *, time_t *)); + +/* + * __txn_dbenv_create -- + * Transaction specific initialization of the DB_ENV structure. + * + * PUBLIC: void __txn_dbenv_create __P((DB_ENV *)); + */ +void +__txn_dbenv_create(dbenv) + DB_ENV *dbenv; +{ + dbenv->tx_max = DEF_MAX_TXNS; + + dbenv->set_tx_max = __txn_set_tx_max; + dbenv->set_tx_recover = __txn_set_tx_recover; + dbenv->set_tx_timestamp = __txn_set_tx_timestamp; + +#ifdef HAVE_RPC + /* + * If we have a client, overwrite what we just setup to point to + * client functions. + */ + if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) { + dbenv->set_tx_max = __dbcl_set_tx_max; + dbenv->set_tx_recover = __dbcl_set_tx_recover; + dbenv->set_tx_timestamp = __dbcl_set_tx_timestamp; + } +#endif +} + +/* + * __txn_set_tx_max -- + * Set the size of the transaction table. + */ +static int +__txn_set_tx_max(dbenv, tx_max) + DB_ENV *dbenv; + u_int32_t tx_max; +{ + ENV_ILLEGAL_AFTER_OPEN(dbenv, "set_tx_max"); + + dbenv->tx_max = tx_max; + return (0); +} + +/* + * __txn_set_tx_recover -- + * Set the transaction abort recover function. + */ +static int +__txn_set_tx_recover(dbenv, tx_recover) + DB_ENV *dbenv; + int (*tx_recover) __P((DB_ENV *, DBT *, DB_LSN *, db_recops)); +{ + dbenv->tx_recover = tx_recover; + return (0); +} + +/* + * __txn_set_tx_timestamp -- + * Set the transaction recovery timestamp. + */ +static int +__txn_set_tx_timestamp(dbenv, timestamp) + DB_ENV *dbenv; + time_t *timestamp; +{ + ENV_ILLEGAL_AFTER_OPEN(dbenv, "set_tx_timestamp"); + + dbenv->tx_timestamp = *timestamp; + return (0); +} + +/* + * __txn_open -- + * Open a transaction region. + * + * PUBLIC: int __txn_open __P((DB_ENV *)); + */ +int +__txn_open(dbenv) + DB_ENV *dbenv; +{ + DB_TXNMGR *tmgrp; + int ret; + + /* Create/initialize the transaction manager structure. */ + if ((ret = __os_calloc(dbenv, 1, sizeof(DB_TXNMGR), &tmgrp)) != 0) + return (ret); + TAILQ_INIT(&tmgrp->txn_chain); + tmgrp->dbenv = dbenv; + + /* Join/create the txn region. */ + tmgrp->reginfo.type = REGION_TYPE_TXN; + tmgrp->reginfo.id = INVALID_REGION_ID; + tmgrp->reginfo.mode = dbenv->db_mode; + tmgrp->reginfo.flags = REGION_JOIN_OK; + if (F_ISSET(dbenv, DB_ENV_CREATE)) + F_SET(&tmgrp->reginfo, REGION_CREATE_OK); + if ((ret = __db_r_attach(dbenv, + &tmgrp->reginfo, TXN_REGION_SIZE(dbenv->tx_max))) != 0) + goto err; + + /* If we created the region, initialize it. */ + if (F_ISSET(&tmgrp->reginfo, REGION_CREATE)) + if ((ret = __txn_init(dbenv, tmgrp)) != 0) + goto err; + + /* Set the local addresses. */ + tmgrp->reginfo.primary = + R_ADDR(&tmgrp->reginfo, tmgrp->reginfo.rp->primary); + + /* Acquire a mutex to protect the active TXN list. */ + if (F_ISSET(dbenv, DB_ENV_THREAD)) { + if ((ret = __db_mutex_alloc( + dbenv, &tmgrp->reginfo, &tmgrp->mutexp)) != 0) + goto err; + if ((ret = __db_mutex_init( + dbenv, tmgrp->mutexp, 0, MUTEX_THREAD)) != 0) + goto err; + } + + R_UNLOCK(dbenv, &tmgrp->reginfo); + + dbenv->tx_handle = tmgrp; + return (0); + +err: if (tmgrp->reginfo.addr != NULL) { + if (F_ISSET(&tmgrp->reginfo, REGION_CREATE)) + ret = __db_panic(dbenv, ret); + R_UNLOCK(dbenv, &tmgrp->reginfo); + + (void)__db_r_detach(dbenv, &tmgrp->reginfo, 0); + } + if (tmgrp->mutexp != NULL) + __db_mutex_free(dbenv, &tmgrp->reginfo, tmgrp->mutexp); + __os_free(tmgrp, sizeof(*tmgrp)); + return (ret); +} + +/* + * __txn_init -- + * Initialize a transaction region in shared memory. + */ +static int +__txn_init(dbenv, tmgrp) + DB_ENV *dbenv; + DB_TXNMGR *tmgrp; +{ + DB_LSN last_ckp; + DB_TXNREGION *region; + int ret; + + ZERO_LSN(last_ckp); + /* + * If possible, fetch the last checkpoint LSN from the log system + * so that the backwards chain of checkpoints is unbroken when + * the environment is removed and recreated. [#2865] + */ + if (LOGGING_ON(dbenv) && (ret = __log_lastckp(dbenv, &last_ckp)) != 0) + return (ret); + + if ((ret = __db_shalloc(tmgrp->reginfo.addr, + sizeof(DB_TXNREGION), 0, &tmgrp->reginfo.primary)) != 0) { + __db_err(dbenv, + "Unable to allocate memory for the transaction region"); + return (ret); + } + tmgrp->reginfo.rp->primary = + R_OFFSET(&tmgrp->reginfo, tmgrp->reginfo.primary); + region = tmgrp->reginfo.primary; + memset(region, 0, sizeof(*region)); + + region->maxtxns = dbenv->tx_max; + region->last_txnid = TXN_MINIMUM; + ZERO_LSN(region->pending_ckp); + region->last_ckp = last_ckp; + region->time_ckp = time(NULL); + + /* + * XXX + * If we ever do more types of locking and logging, this changes. + */ + region->logtype = 0; + region->locktype = 0; + region->naborts = 0; + region->ncommits = 0; + region->nbegins = 0; + region->nactive = 0; + region->maxnactive = 0; + + SH_TAILQ_INIT(®ion->active_txn); + + return (0); +} + +/* + * __txn_close -- + * Close a transaction region. + * + * PUBLIC: int __txn_close __P((DB_ENV *)); + */ +int +__txn_close(dbenv) + DB_ENV *dbenv; +{ + DB_TXN *txnp; + DB_TXNMGR *tmgrp; + u_int32_t txnid; + int ret, t_ret; + + ret = 0; + tmgrp = dbenv->tx_handle; + + /* + * This function can only be called once per process (i.e., not + * once per thread), so no synchronization is required. + * + * The caller is doing something wrong if close is called with + * active transactions. Try and abort any active transactions, + * but it's quite likely the aborts will fail because recovery + * won't find open files. If we can't abort any transaction, + * panic, we have to run recovery to get back to a known state. + */ + if (TAILQ_FIRST(&tmgrp->txn_chain) != NULL) { + __db_err(dbenv, + "Error: closing the transaction region with active transactions\n"); + ret = EINVAL; + while ((txnp = TAILQ_FIRST(&tmgrp->txn_chain)) != NULL) { + txnid = txnp->txnid; + if ((t_ret = txn_abort(txnp)) != 0) { + __db_err(dbenv, + "Unable to abort transaction 0x%x: %s\n", + txnid, db_strerror(t_ret)); + ret = __db_panic(dbenv, t_ret); + } + } + } + + /* Flush the log. */ + if (LOGGING_ON(dbenv) && + (t_ret = log_flush(dbenv, NULL)) != 0 && ret == 0) + ret = t_ret; + + /* Discard the per-thread lock. */ + if (tmgrp->mutexp != NULL) + __db_mutex_free(dbenv, &tmgrp->reginfo, tmgrp->mutexp); + + /* Detach from the region. */ + if ((t_ret = __db_r_detach(dbenv, &tmgrp->reginfo, 0)) != 0 && ret == 0) + ret = t_ret; + + __os_free(tmgrp, sizeof(*tmgrp)); + + dbenv->tx_handle = NULL; + return (ret); +} + +int +txn_stat(dbenv, statp, db_malloc) + DB_ENV *dbenv; + DB_TXN_STAT **statp; + void *(*db_malloc) __P((size_t)); +{ + DB_TXNMGR *mgr; + DB_TXNREGION *region; + DB_TXN_STAT *stats; + TXN_DETAIL *txnp; + size_t nbytes; + u_int32_t nactive, ndx; + int ret, slop; + +#ifdef HAVE_RPC + if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) + return (__dbcl_txn_stat(dbenv, statp, db_malloc)); +#endif + + PANIC_CHECK(dbenv); + ENV_REQUIRES_CONFIG(dbenv, dbenv->tx_handle, DB_INIT_TXN); + + *statp = NULL; + + slop = 200; + mgr = dbenv->tx_handle; + region = mgr->reginfo.primary; + +retry: R_LOCK(dbenv, &mgr->reginfo); + nactive = region->nactive; + R_UNLOCK(dbenv, &mgr->reginfo); + + /* + * Allocate extra active structures to handle any transactions that + * are created while we have the region unlocked. + */ + nbytes = sizeof(DB_TXN_STAT) + sizeof(DB_TXN_ACTIVE) * (nactive + slop); + if ((ret = __os_malloc(dbenv, nbytes, db_malloc, &stats)) != 0) + return (ret); + + R_LOCK(dbenv, &mgr->reginfo); + stats->st_last_txnid = region->last_txnid; + stats->st_last_ckp = region->last_ckp; + stats->st_maxtxns = region->maxtxns; + stats->st_naborts = region->naborts; + stats->st_nbegins = region->nbegins; + stats->st_ncommits = region->ncommits; + stats->st_pending_ckp = region->pending_ckp; + stats->st_time_ckp = region->time_ckp; + stats->st_nactive = region->nactive; + if (stats->st_nactive > nactive + 200) { + R_UNLOCK(dbenv, &mgr->reginfo); + slop *= 2; + goto retry; + } + stats->st_maxnactive = region->maxnactive; + stats->st_txnarray = (DB_TXN_ACTIVE *)&stats[1]; + + ndx = 0; + for (txnp = SH_TAILQ_FIRST(®ion->active_txn, __txn_detail); + txnp != NULL; + txnp = SH_TAILQ_NEXT(txnp, links, __txn_detail)) { + stats->st_txnarray[ndx].txnid = txnp->txnid; + if (txnp->parent == INVALID_ROFF) + stats->st_txnarray[ndx].parentid = TXN_INVALID_ID; + else + stats->st_txnarray[ndx].parentid = + ((TXN_DETAIL *)R_ADDR(&mgr->reginfo, + txnp->parent))->txnid; + stats->st_txnarray[ndx].lsn = txnp->begin_lsn; + ndx++; + + if (ndx >= stats->st_nactive) + break; + } + + stats->st_region_wait = mgr->reginfo.rp->mutex.mutex_set_wait; + stats->st_region_nowait = mgr->reginfo.rp->mutex.mutex_set_nowait; + stats->st_regsize = mgr->reginfo.rp->size; + + R_UNLOCK(dbenv, &mgr->reginfo); + + *statp = stats; + return (0); +} diff --git a/db/xa/xa.c b/db/xa/xa.c new file mode 100644 index 000000000..b13a6d503 --- /dev/null +++ b/db/xa/xa.c @@ -0,0 +1,661 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: xa.c,v 11.10 2000/12/14 07:39:14 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#include +#endif + +#include "db_int.h" +#include "db_page.h" +#include "log.h" +#include "txn.h" +#include "db_am.h" +#include "db_dispatch.h" + +static int __db_xa_close __P((char *, int, long)); +static int __db_xa_commit __P((XID *, int, long)); +static int __db_xa_complete __P((int *, int *, int, long)); +static int __db_xa_end __P((XID *, int, long)); +static int __db_xa_forget __P((XID *, int, long)); +static int __db_xa_open __P((char *, int, long)); +static int __db_xa_prepare __P((XID *, int, long)); +static int __db_xa_recover __P((XID *, long, int, long)); +static int __db_xa_rollback __P((XID *, int, long)); +static int __db_xa_start __P((XID *, int, long)); +static void __xa_txn_end __P((DB_ENV *)); +static void __xa_txn_init __P((DB_ENV *, TXN_DETAIL *, size_t)); + +/* + * Possible flag values: + * Dynamic registration 0 => no dynamic registration + * TMREGISTER => dynamic registration + * Asynchronous operation 0 => no support for asynchrony + * TMUSEASYNC => async support + * Migration support 0 => migration of transactions across + * threads is possible + * TMNOMIGRATE => no migration across threads + */ +const struct xa_switch_t db_xa_switch = { + "Berkeley DB", /* name[RMNAMESZ] */ + TMNOMIGRATE, /* flags */ + 0, /* version */ + __db_xa_open, /* xa_open_entry */ + __db_xa_close, /* xa_close_entry */ + __db_xa_start, /* xa_start_entry */ + __db_xa_end, /* xa_end_entry */ + __db_xa_rollback, /* xa_rollback_entry */ + __db_xa_prepare, /* xa_prepare_entry */ + __db_xa_commit, /* xa_commit_entry */ + __db_xa_recover, /* xa_recover_entry */ + __db_xa_forget, /* xa_forget_entry */ + __db_xa_complete /* xa_complete_entry */ +}; + +/* + * __db_xa_open -- + * The open call in the XA protocol. The rmid field is an id number + * that the TM assigned us and will pass us on every xa call. We need to + * map that rmid number into a dbenv structure that we create during + * initialization. Since this id number is thread specific, we do not + * need to store it in shared memory. The file xa_map.c implements all + * such xa->db mappings. + * The xa_info field is instance specific information. We require + * that the value of DB_HOME be passed in xa_info. Since xa_info is the + * only thing that we get to pass to db_env_create, any config information + * will have to be done via a config file instead of via the db_env_create + * call. + */ +static int +__db_xa_open(xa_info, rmid, flags) + char *xa_info; + int rmid; + long flags; +{ + DB_ENV *env; + + if (LF_ISSET(TMASYNC)) + return (XAER_ASYNC); + if (flags != TMNOFLAGS) + return (XAER_INVAL); + + /* Verify if we already have this environment open. */ + if (__db_rmid_to_env(rmid, &env) == 0) + return (XA_OK); + if (__os_calloc(env, 1, sizeof(DB_ENV), &env) != 0) + return (XAER_RMERR); + + /* Open a new environment. */ +#define XA_FLAGS \ + DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN + if (db_env_create(&env, 0) != 0) + return (XAER_RMERR); + if (env->open(env, xa_info, XA_FLAGS, 0) != 0) + goto err; + + /* Create the mapping. */ + if (__db_map_rmid(rmid, env) != 0) + goto err; + + /* Allocate space for the current transaction. */ + if (__os_calloc(env, 1, sizeof(DB_TXN), &env->xa_txn) != 0) + goto err; + env->xa_txn->txnid = TXN_INVALID; + + return (XA_OK); + +err: (void)env->close(env, 0); + + return (XAER_RMERR); +} + +/* + * __db_xa_close -- + * The close call of the XA protocol. The only trickiness here + * is that if there are any active transactions, we must fail. It is + * *not* an error to call close on an environment that has already been + * closed (I am interpreting that to mean it's OK to call close on an + * environment that has never been opened). + */ +static int +__db_xa_close(xa_info, rmid, flags) + char *xa_info; + int rmid; + long flags; +{ + DB_ENV *env; + int ret, t_ret; + + COMPQUIET(xa_info, NULL); + + if (LF_ISSET(TMASYNC)) + return (XAER_ASYNC); + if (flags != TMNOFLAGS) + return (XAER_INVAL); + + /* If the environment is closed, then we're done. */ + if (__db_rmid_to_env(rmid, &env) != 0) + return (XA_OK); + + /* Check if there are any pending transactions. */ + if (env->xa_txn != NULL && env->xa_txn->txnid != TXN_INVALID) + return (XAER_PROTO); + + /* Destroy the mapping. */ + ret = __db_unmap_rmid(rmid); + + /* Discard space held for the current transaction. */ + if (env->xa_txn != NULL) + __os_free(env->xa_txn, sizeof(DB_TXN)); + + /* Close the environment. */ + if ((t_ret = env->close(env, 0)) != 0 && ret == 0) + ret = t_ret; + + return (ret == 0 ? XA_OK : XAER_RMERR); +} + +/* + * __db_xa_start -- + * Begin a transaction for the current resource manager. + */ +static int +__db_xa_start(xid, rmid, flags) + XID *xid; + int rmid; + long flags; +{ + DB_ENV *env; + TXN_DETAIL *td; + size_t off; + int is_known; + +#define OK_FLAGS (TMJOIN | TMRESUME | TMNOWAIT | TMASYNC | TMNOFLAGS) + if (LF_ISSET(~OK_FLAGS)) + return (XAER_INVAL); + + if (LF_ISSET(TMJOIN) && LF_ISSET(TMRESUME)) + return (XAER_INVAL); + + if (LF_ISSET(TMASYNC)) + return (XAER_ASYNC); + + if (__db_rmid_to_env(rmid, &env) != 0) + return (XAER_PROTO); + + is_known = __db_xid_to_txn(env, xid, &off) == 0; + + if (is_known && !LF_ISSET(TMRESUME) && !LF_ISSET(TMJOIN)) + return (XAER_DUPID); + + if (!is_known && LF_ISSET(TMRESUME | TMJOIN)) + return (XAER_NOTA); + + /* + * This can't block, so we can ignore TMNOWAIT. + * + * Other error conditions: RMERR, RMFAIL, OUTSIDE, PROTO, RB* + */ + if (is_known) { + td = (TXN_DETAIL *) + R_ADDR(&((DB_TXNMGR *)env->tx_handle)->reginfo, off); + if (td->xa_status == TXN_XA_SUSPENDED && + !LF_ISSET(TMRESUME | TMJOIN)) + return (XAER_PROTO); + if (td->xa_status == TXN_XA_DEADLOCKED) + return (XA_RBDEADLOCK); + if (td->xa_status == TXN_XA_ABORTED) + return (XA_RBOTHER); + + /* Now, fill in the global transaction structure. */ + __xa_txn_init(env, td, off); + td->xa_status = TXN_XA_STARTED; + } else { + if (__txn_xa_begin(env, env->xa_txn) != 0) + return (XAER_RMERR); + (void)__db_map_xid(env, xid, env->xa_txn->off); + td = (TXN_DETAIL *) + R_ADDR(&((DB_TXNMGR *)env->tx_handle)->reginfo, + env->xa_txn->off); + td->xa_status = TXN_XA_STARTED; + } + return (XA_OK); +} + +/* + * __db_xa_end -- + * Disassociate the current transaction from the current process. + */ +static int +__db_xa_end(xid, rmid, flags) + XID *xid; + int rmid; + long flags; +{ + DB_ENV *env; + DB_TXN *txn; + TXN_DETAIL *td; + size_t off; + + if (flags != TMNOFLAGS && !LF_ISSET(TMSUSPEND | TMSUCCESS | TMFAIL)) + return (XAER_INVAL); + + if (__db_rmid_to_env(rmid, &env) != 0) + return (XAER_PROTO); + + if (__db_xid_to_txn(env, xid, &off) != 0) + return (XAER_NOTA); + + txn = env->xa_txn; + if (off != txn->off) + return (XAER_PROTO); + + td = (TXN_DETAIL *)R_ADDR(&((DB_TXNMGR *)env->tx_handle)->reginfo, off); + if (td->xa_status == TXN_XA_DEADLOCKED) + return (XA_RBDEADLOCK); + + if (td->status == TXN_ABORTED) + return (XA_RBOTHER); + + if (td->xa_status != TXN_XA_STARTED) + return (XAER_PROTO); + + /* Update the shared memory last_lsn field */ + td->last_lsn = txn->last_lsn; + + /* + * If we ever support XA migration, we cannot keep SUSPEND/END + * status in the shared region; it would have to be process local. + */ + if (LF_ISSET(TMSUSPEND)) + td->xa_status = TXN_XA_SUSPENDED; + else + td->xa_status = TXN_XA_ENDED; + + txn->txnid = TXN_INVALID; + return (XA_OK); +} + +/* + * __db_xa_prepare -- + * Sync the log to disk so we can guarantee recoverability. + */ +static int +__db_xa_prepare(xid, rmid, flags) + XID *xid; + int rmid; + long flags; +{ + DB_ENV *env; + TXN_DETAIL *td; + size_t off; + + if (LF_ISSET(TMASYNC)) + return (XAER_ASYNC); + if (flags != TMNOFLAGS) + return (XAER_INVAL); + + /* + * We need to know if we've ever called prepare on this. + * As part of the prepare, we set the xa_status field to + * reflect that fact that prepare has been called, and if + * it's ever called again, it's an error. + */ + if (__db_rmid_to_env(rmid, &env) != 0) + return (XAER_PROTO); + + if (__db_xid_to_txn(env, xid, &off) != 0) + return (XAER_NOTA); + + td = (TXN_DETAIL *)R_ADDR(&((DB_TXNMGR *)env->tx_handle)->reginfo, off); + if (td->xa_status == TXN_XA_DEADLOCKED) + return (XA_RBDEADLOCK); + + if (td->xa_status != TXN_XA_ENDED && td->xa_status != TXN_XA_SUSPENDED) + return (XAER_PROTO); + + /* Now, fill in the global transaction structure. */ + __xa_txn_init(env, td, off); + + if (txn_prepare(env->xa_txn) != 0) + return (XAER_RMERR); + + td->xa_status = TXN_XA_PREPARED; + + /* No fatal value that would require an XAER_RMFAIL. */ + __xa_txn_end(env); + return (XA_OK); +} + +/* + * __db_xa_commit -- + * Commit the transaction + */ +static int +__db_xa_commit(xid, rmid, flags) + XID *xid; + int rmid; + long flags; +{ + DB_ENV *env; + TXN_DETAIL *td; + size_t off; + + if (LF_ISSET(TMASYNC)) + return (XAER_ASYNC); +#undef OK_FLAGS +#define OK_FLAGS (TMNOFLAGS | TMNOWAIT | TMONEPHASE) + if (LF_ISSET(~OK_FLAGS)) + return (XAER_INVAL); + + /* + * We need to know if we've ever called prepare on this. + * We can verify this by examining the xa_status field. + */ + if (__db_rmid_to_env(rmid, &env) != 0) + return (XAER_PROTO); + + if (__db_xid_to_txn(env, xid, &off) != 0) + return (XAER_NOTA); + + td = (TXN_DETAIL *)R_ADDR(&((DB_TXNMGR *)env->tx_handle)->reginfo, off); + if (td->xa_status == TXN_XA_DEADLOCKED) + return (XA_RBDEADLOCK); + + if (td->xa_status == TXN_XA_ABORTED) + return (XA_RBOTHER); + + if (LF_ISSET(TMONEPHASE) && + td->xa_status != TXN_XA_ENDED && td->xa_status != TXN_XA_SUSPENDED) + return (XAER_PROTO); + + if (!LF_ISSET(TMONEPHASE) && td->xa_status != TXN_XA_PREPARED) + return (XAER_PROTO); + + /* Now, fill in the global transaction structure. */ + __xa_txn_init(env, td, off); + + if (txn_commit(env->xa_txn, 0) != 0) + return (XAER_RMERR); + + /* No fatal value that would require an XAER_RMFAIL. */ + __xa_txn_end(env); + return (XA_OK); +} + +/* + * __db_xa_recover -- + * Returns a list of prepared and heuristically completed transactions. + * + * The return value is the number of xids placed into the xid array (less + * than or equal to the count parameter). The flags are going to indicate + * whether we are starting a scan or continuing one. + */ +static int +__db_xa_recover(xids, count, rmid, flags) + XID *xids; + long count, flags; + int rmid; +{ + __txn_xa_regop_args *argp; + DBT data; + DB_ENV *env; + DB_LOG *log; + XID *xidp; + int err, ret; + u_int32_t rectype, txnid; + + ret = 0; + xidp = xids; + + /* If the environment is closed, then we're done. */ + if (__db_rmid_to_env(rmid, &env) != 0) + return (XAER_PROTO); + + /* + * If we are starting a scan, then we need to figure out where + * to begin. If we are not starting a scan, we'll start from + * wherever the log cursor is. Since XA apps cannot be threaded, + * we don't have to worry about someone else having moved it. + */ + log = env->lg_handle; + if (LF_ISSET(TMSTARTRSCAN)) { + if ((err = __log_findckp(env, &log->xa_first)) == DB_NOTFOUND) { + /* + * If there were no log files, then we have no + * transactions to return, so we simply return 0. + */ + return (0); + } + if ((err = __db_txnlist_init(env, &log->xa_info)) != 0) + return (XAER_RMERR); + } else { + /* + * If we are not starting a scan, the log cursor had + * better be set. + */ + if (IS_ZERO_LSN(log->xa_lsn)) + return (XAER_PROTO); + } + + /* + * At this point log->xa_first contains the point in the log + * to which we need to roll back. If we are starting a scan, + * we'll start at the last record; if we're continuing a scan, + * we'll have to start at log->xa_lsn. + */ + + memset(&data, 0, sizeof(data)); + for (err = log_get(env, &log->xa_lsn, &data, + LF_ISSET(TMSTARTRSCAN) ? DB_LAST : DB_SET); + err == 0 && log_compare(&log->xa_lsn, &log->xa_first) > 0; + err = log_get(env, &log->xa_lsn, &data, DB_PREV)) { + memcpy(&rectype, data.data, sizeof(rectype)); + + /* + * The only record type we care about is an DB_txn_xa_regop. + * If it's a commit, we have to add it to a txnlist. If it's + * a prepare, and we don't have a commit, then we return it. + * We are redoing some of what's in the xa_regop_recovery + * code, but we have to do it here so we can get at the xid + * in the record. + */ + if (rectype != DB_txn_xa_regop && rectype != DB_txn_regop) + continue; + + memcpy(&txnid, (u_int8_t *)data.data + sizeof(rectype), + sizeof(txnid)); + err = __db_txnlist_find(log->xa_info, txnid); + switch (rectype) { + case DB_txn_regop: + if (err == DB_NOTFOUND) + __db_txnlist_add(env, log->xa_info, txnid, 0); + err = 0; + break; + case DB_txn_xa_regop: + /* + * This transaction is committed, so we needn't read + * the record and do anything. + */ + if (err == 0) + break; + if ((err = + __txn_xa_regop_read(env, data.data, &argp)) != 0) { + ret = XAER_RMERR; + goto out; + } + + xidp->formatID = argp->formatID; + xidp->gtrid_length = argp->gtrid; + xidp->bqual_length = argp->bqual; + memcpy(xidp->data, argp->xid.data, argp->xid.size); + ret++; + xidp++; + __os_free(argp, sizeof(*argp)); + if (ret == count) + goto done; + break; + } + } + + if (err != 0 && err != DB_NOTFOUND) + goto out; + +done: if (LF_ISSET(TMENDRSCAN)) { + ZERO_LSN(log->xa_lsn); + ZERO_LSN(log->xa_first); + +out: __db_txnlist_end(env, log->xa_info); + log->xa_info = NULL; + } + return (ret); +} + +/* + * __db_xa_rollback + * Abort an XA transaction. + */ +static int +__db_xa_rollback(xid, rmid, flags) + XID *xid; + int rmid; + long flags; +{ + DB_ENV *env; + TXN_DETAIL *td; + size_t off; + + if (LF_ISSET(TMASYNC)) + return (XAER_ASYNC); + if (flags != TMNOFLAGS) + return (XAER_INVAL); + + if (__db_rmid_to_env(rmid, &env) != 0) + return (XAER_PROTO); + + if (__db_xid_to_txn(env, xid, &off) != 0) + return (XAER_NOTA); + + td = (TXN_DETAIL *)R_ADDR(&((DB_TXNMGR *)env->tx_handle)->reginfo, off); + if (td->xa_status == TXN_XA_DEADLOCKED) + return (XA_RBDEADLOCK); + + if (td->xa_status == TXN_XA_ABORTED) + return (XA_RBOTHER); + + if (td->xa_status != TXN_XA_ENDED && td->xa_status != TXN_XA_SUSPENDED + && td->xa_status != TXN_XA_PREPARED) + return (XAER_PROTO); + + /* Now, fill in the global transaction structure. */ + __xa_txn_init(env, td, off); + if (txn_abort(env->xa_txn) != 0) + return (XAER_RMERR); + + /* No fatal value that would require an XAER_RMFAIL. */ + __xa_txn_end(env); + return (XA_OK); +} + +/* + * __db_xa_forget -- + * Forget about an XID for a transaction that was heuristically + * completed. Since we do not heuristically complete anything, I + * don't think we have to do anything here, but we should make sure + * that we reclaim the slots in the txnid table. + */ +static int +__db_xa_forget(xid, rmid, flags) + XID *xid; + int rmid; + long flags; +{ + DB_ENV *env; + size_t off; + + if (LF_ISSET(TMASYNC)) + return (XAER_ASYNC); + if (flags != TMNOFLAGS) + return (XAER_INVAL); + + if (__db_rmid_to_env(rmid, &env) != 0) + return (XAER_PROTO); + + /* + * If mapping is gone, then we're done. + */ + if (__db_xid_to_txn(env, xid, &off) != 0) + return (XA_OK); + + __db_unmap_xid(env, xid, off); + + /* No fatal value that would require an XAER_RMFAIL. */ + return (XA_OK); +} + +/* + * __db_xa_complete -- + * Used to wait for asynchronous operations to complete. Since we're + * not doing asynch, this is an invalid operation. + */ +static int +__db_xa_complete(handle, retval, rmid, flags) + int *handle, *retval, rmid; + long flags; +{ + COMPQUIET(handle, NULL); + COMPQUIET(retval, NULL); + COMPQUIET(rmid, 0); + COMPQUIET(flags, 0); + + return (XAER_INVAL); +} + +/* + * __xa_txn_init -- + * Fill in the fields of the local transaction structure given + * the detail transaction structure. + */ +static void +__xa_txn_init(env, td, off) + DB_ENV *env; + TXN_DETAIL *td; + size_t off; +{ + DB_TXN *txn; + + txn = env->xa_txn; + txn->mgrp = env->tx_handle; + txn->parent = NULL; + txn->last_lsn = td->last_lsn; + txn->txnid = td->txnid; + txn->off = off; + txn->flags = 0; +} + +/* + * __xa_txn_end -- + * Invalidate a transaction structure that was generated by xa_txn_init. + */ +static void +__xa_txn_end(env) + DB_ENV *env; +{ + DB_TXN *txn; + + txn = env->xa_txn; + if (txn != NULL) + txn->txnid = TXN_INVALID; +} diff --git a/db/xa/xa_db.c b/db/xa/xa_db.c new file mode 100644 index 000000000..ba3dbfedd --- /dev/null +++ b/db/xa/xa_db.c @@ -0,0 +1,182 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: xa_db.c,v 11.9 2000/09/06 18:57:59 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include +#endif + +#include "db_int.h" +#include "xa.h" +#include "xa_ext.h" +#include "txn.h" + +static int __xa_close __P((DB *, u_int32_t)); +static int __xa_cursor __P((DB *, DB_TXN *, DBC **, u_int32_t)); +static int __xa_del __P((DB *, DB_TXN *, DBT *, u_int32_t)); +static int __xa_get __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t)); +static int __xa_open __P((DB *, + const char *, const char *, DBTYPE, u_int32_t, int)); +static int __xa_put __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t)); + +typedef struct __xa_methods { + int (*close) __P((DB *, u_int32_t)); + int (*cursor) __P((DB *, DB_TXN *, DBC **, u_int32_t)); + int (*del) __P((DB *, DB_TXN *, DBT *, u_int32_t)); + int (*get) __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t)); + int (*open) __P((DB *, + const char *, const char *, DBTYPE, u_int32_t, int)); + int (*put) __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t)); +} XA_METHODS; + +/* + * __db_xa_create -- + * DB XA constructor. + * + * PUBLIC: int __db_xa_create __P((DB *)); + */ +int +__db_xa_create(dbp) + DB *dbp; +{ + XA_METHODS *xam; + int ret; + + /* + * Interpose XA routines in front of any method that takes a TXN + * ID as an argument. + */ + if ((ret = __os_calloc(dbp->dbenv, 1, sizeof(XA_METHODS), &xam)) != 0) + return (ret); + + dbp->xa_internal = xam; + xam->open = dbp->open; + dbp->open = __xa_open; + xam->close = dbp->close; + dbp->close = __xa_close; + + return (0); +} + +/* + * __xa_open -- + * XA open wrapper. + */ + +static int +__xa_open(dbp, name, subdb, type, flags, mode) + DB *dbp; + const char *name, *subdb; + DBTYPE type; + u_int32_t flags; + int mode; +{ + XA_METHODS *xam; + int ret; + + xam = (XA_METHODS *)dbp->xa_internal; + + if ((ret = xam->open(dbp, name, subdb, type, flags, mode)) != 0) + return (ret); + + xam->cursor = dbp->cursor; + xam->del = dbp->del; + xam->get = dbp->get; + xam->put = dbp->put; + dbp->cursor = __xa_cursor; + dbp->del = __xa_del; + dbp->get = __xa_get; + dbp->put = __xa_put; + + return (0); +} + +static int +__xa_cursor(dbp, txn, dbcp, flags) + DB *dbp; + DB_TXN *txn; + DBC **dbcp; + u_int32_t flags; +{ + DB_TXN *t; + + t = txn != NULL && txn == dbp->open_txn ? txn : dbp->dbenv->xa_txn; + if (t->txnid == TXN_INVALID) + t = NULL; + + return (((XA_METHODS *)dbp->xa_internal)->cursor (dbp, t, dbcp, flags)); +} + +static int +__xa_del(dbp, txn, key, flags) + DB *dbp; + DB_TXN *txn; + DBT *key; + u_int32_t flags; +{ + DB_TXN *t; + + t = txn != NULL && txn == dbp->open_txn ? txn : dbp->dbenv->xa_txn; + if (t->txnid == TXN_INVALID) + t = NULL; + + return (((XA_METHODS *)dbp->xa_internal)->del(dbp, t, key, flags)); +} + +static int +__xa_close(dbp, flags) + DB *dbp; + u_int32_t flags; +{ + int (*real_close) __P((DB *, u_int32_t)); + + real_close = ((XA_METHODS *)dbp->xa_internal)->close; + + __os_free(dbp->xa_internal, sizeof(XA_METHODS)); + dbp->xa_internal = NULL; + + return (real_close(dbp, flags)); +} + +static int +__xa_get(dbp, txn, key, data, flags) + DB *dbp; + DB_TXN *txn; + DBT *key, *data; + u_int32_t flags; +{ + DB_TXN *t; + + t = txn != NULL && txn == dbp->open_txn ? txn : dbp->dbenv->xa_txn; + if (t->txnid == TXN_INVALID) + t = NULL; + + return (((XA_METHODS *)dbp->xa_internal)->get + (dbp, t, key, data, flags)); +} + +static int +__xa_put(dbp, txn, key, data, flags) + DB *dbp; + DB_TXN *txn; + DBT *key, *data; + u_int32_t flags; +{ + DB_TXN *t; + + t = txn != NULL && txn == dbp->open_txn ? txn : dbp->dbenv->xa_txn; + if (t->txnid == TXN_INVALID) + t = NULL; + + return (((XA_METHODS *)dbp->xa_internal)->put + (dbp, t, key, data, flags)); +} diff --git a/db/xa/xa_map.c b/db/xa/xa_map.c new file mode 100644 index 000000000..1af268477 --- /dev/null +++ b/db/xa/xa_map.c @@ -0,0 +1,189 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Sleepycat Software. All rights reserved. + */ + +#include "db_config.h" + +#ifndef lint +static const char revid[] = "$Id: xa_map.c,v 11.5 2000/11/30 00:58:46 ubell Exp $"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include + +#include +#endif + +#include "db_int.h" +#include "txn.h" + +/* + * This file contains all the mapping information that we need to support + * the DB/XA interface. + */ + +/* + * __db_rmid_to_env + * Return the environment associated with a given XA rmid. + * + * PUBLIC: int __db_rmid_to_env __P((int rmid, DB_ENV **envp)); + */ +int +__db_rmid_to_env(rmid, envp) + int rmid; + DB_ENV **envp; +{ + DB_ENV *env; + + env = TAILQ_FIRST(&DB_GLOBAL(db_envq)); + if (env != NULL && env->xa_rmid == rmid) { + *envp = env; + return (0); + } + + /* + * When we map an rmid, move that environment to be the first one in + * the list of environments, so we acquire the correct environment + * in DB->open. + */ + for (; env != NULL; env = TAILQ_NEXT(env, links)) + if (env->xa_rmid == rmid) { + TAILQ_REMOVE(&DB_GLOBAL(db_envq), env, links); + TAILQ_INSERT_HEAD(&DB_GLOBAL(db_envq), env, links); + *envp = env; + return (0); + } + + return (1); +} + +/* + * __db_xid_to_txn + * Return the txn that corresponds to this XID. + * + * PUBLIC: int __db_xid_to_txn __P((DB_ENV *, XID *, size_t *)); + */ +int +__db_xid_to_txn(dbenv, xid, offp) + DB_ENV *dbenv; + XID *xid; + size_t *offp; +{ + DB_TXNMGR *mgr; + DB_TXNREGION *tmr; + struct __txn_detail *td; + + mgr = dbenv->tx_handle; + tmr = mgr->reginfo.primary; + + /* + * Search the internal active transaction table to find the + * matching xid. If this is a performance hit, then we + * can create a hash table, but I doubt it's worth it. + */ + R_LOCK(dbenv, &mgr->reginfo); + for (td = SH_TAILQ_FIRST(&tmr->active_txn, __txn_detail); + td != NULL; + td = SH_TAILQ_NEXT(td, links, __txn_detail)) + if (memcmp(xid->data, td->xid, XIDDATASIZE) == 0) + break; + R_UNLOCK(dbenv, &mgr->reginfo); + + if (td == NULL) + return (EINVAL); + + *offp = R_OFFSET(&mgr->reginfo, td); + return (0); +} + +/* + * __db_map_rmid + * Create a mapping between the specified rmid and environment. + * + * PUBLIC: int __db_map_rmid __P((int, DB_ENV *)); + */ +int +__db_map_rmid(rmid, env) + int rmid; + DB_ENV *env; +{ + env->xa_rmid = rmid; + TAILQ_INSERT_TAIL(&DB_GLOBAL(db_envq), env, links); + return (0); +} + +/* + * __db_unmap_rmid + * Destroy the mapping for the given rmid. + * + * PUBLIC: int __db_unmap_rmid __P((int)); + */ +int +__db_unmap_rmid(rmid) + int rmid; +{ + DB_ENV *e; + + for (e = TAILQ_FIRST(&DB_GLOBAL(db_envq)); + e->xa_rmid != rmid; + e = TAILQ_NEXT(e, links)); + + if (e == NULL) + return (EINVAL); + + TAILQ_REMOVE(&DB_GLOBAL(db_envq), e, links); + return (0); +} + +/* + * __db_map_xid + * Create a mapping between this XID and the transaction at + * "off" in the shared region. + * + * PUBLIC: int __db_map_xid __P((DB_ENV *, XID *, size_t)); + */ +int +__db_map_xid(env, xid, off) + DB_ENV *env; + XID *xid; + size_t off; +{ + REGINFO *infop; + TXN_DETAIL *td; + + infop = &((DB_TXNMGR *)env->tx_handle)->reginfo; + td = (TXN_DETAIL *)R_ADDR(infop, off); + + R_LOCK(env, infop); + memcpy(td->xid, xid->data, XIDDATASIZE); + td->bqual = (u_int32_t)xid->bqual_length; + td->gtrid = (u_int32_t)xid->gtrid_length; + td->format = (int32_t)xid->formatID; + R_UNLOCK(env, infop); + + return (0); +} + +/* + * __db_unmap_xid + * Destroy the mapping for the specified XID. + * + * PUBLIC: void __db_unmap_xid __P((DB_ENV *, XID *, size_t)); + */ + +void +__db_unmap_xid(env, xid, off) + DB_ENV *env; + XID *xid; + size_t off; +{ + TXN_DETAIL *td; + + COMPQUIET(xid, NULL); + + td = (TXN_DETAIL *)R_ADDR(&((DB_TXNMGR *)env->tx_handle)->reginfo, off); + memset(td->xid, 0, sizeof(td->xid)); +} -- cgit v1.2.3